1 /*- 2 * Copyright 2016 Michal Meloun <mmel@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/param.h> 28 #include <sys/systm.h> 29 #include <sys/bus.h> 30 #include <sys/gpio.h> 31 #include <sys/kernel.h> 32 #include <sys/module.h> 33 #include <sys/malloc.h> 34 #include <sys/rman.h> 35 #include <sys/sx.h> 36 37 #include <machine/bus.h> 38 39 #include <dev/extres/regulator/regulator.h> 40 #include <dev/gpio/gpiobusvar.h> 41 42 #include <dt-bindings/mfd/as3722.h> 43 44 #include "as3722.h" 45 46 MALLOC_DEFINE(M_AS3722_REG, "AS3722 regulator", "AS3722 power regulator"); 47 48 #define DIV_ROUND_UP(n,d) howmany(n, d) 49 50 enum as3722_reg_id { 51 AS3722_REG_ID_SD0, 52 AS3722_REG_ID_SD1, 53 AS3722_REG_ID_SD2, 54 AS3722_REG_ID_SD3, 55 AS3722_REG_ID_SD4, 56 AS3722_REG_ID_SD5, 57 AS3722_REG_ID_SD6, 58 AS3722_REG_ID_LDO0, 59 AS3722_REG_ID_LDO1, 60 AS3722_REG_ID_LDO2, 61 AS3722_REG_ID_LDO3, 62 AS3722_REG_ID_LDO4, 63 AS3722_REG_ID_LDO5, 64 AS3722_REG_ID_LDO6, 65 AS3722_REG_ID_LDO7, 66 AS3722_REG_ID_LDO9, 67 AS3722_REG_ID_LDO10, 68 AS3722_REG_ID_LDO11, 69 }; 70 71 /* Regulator HW definition. */ 72 struct reg_def { 73 intptr_t id; /* ID */ 74 char *name; /* Regulator name */ 75 char *supply_name; /* Source property name */ 76 uint8_t volt_reg; 77 uint8_t volt_vsel_mask; 78 uint8_t enable_reg; 79 uint8_t enable_mask; 80 uint8_t ext_enable_reg; 81 uint8_t ext_enable_mask; 82 struct regulator_range *ranges; 83 int nranges; 84 }; 85 86 struct as3722_reg_sc { 87 struct regnode *regnode; 88 struct as3722_softc *base_sc; 89 struct reg_def *def; 90 phandle_t xref; 91 92 struct regnode_std_param *param; 93 int ext_control; 94 int enable_tracking; 95 96 int enable_usec; 97 }; 98 99 static struct regulator_range as3722_sd016_ranges[] = { 100 REG_RANGE_INIT(0x00, 0x00, 0, 0), 101 REG_RANGE_INIT(0x01, 0x5A, 610000, 10000), 102 }; 103 104 static struct regulator_range as3722_sd0_lv_ranges[] = { 105 REG_RANGE_INIT(0x00, 0x00, 0, 0), 106 REG_RANGE_INIT(0x01, 0x6E, 410000, 10000), 107 }; 108 109 static struct regulator_range as3722_sd_ranges[] = { 110 REG_RANGE_INIT(0x00, 0x00, 0, 0), 111 REG_RANGE_INIT(0x01, 0x40, 612500, 12500), 112 REG_RANGE_INIT(0x41, 0x70, 1425000, 25000), 113 REG_RANGE_INIT(0x71, 0x7F, 2650000, 50000), 114 }; 115 116 static struct regulator_range as3722_ldo3_ranges[] = { 117 REG_RANGE_INIT(0x00, 0x00, 0, 0), 118 REG_RANGE_INIT(0x01, 0x2D, 620000, 20000), 119 }; 120 121 static struct regulator_range as3722_ldo_ranges[] = { 122 REG_RANGE_INIT(0x00, 0x00, 0, 0), 123 REG_RANGE_INIT(0x01, 0x24, 825000, 25000), 124 REG_RANGE_INIT(0x40, 0x7F, 1725000, 25000), 125 }; 126 127 static struct reg_def as3722s_def[] = { 128 { 129 .id = AS3722_REG_ID_SD0, 130 .name = "sd0", 131 .volt_reg = AS3722_SD0_VOLTAGE, 132 .volt_vsel_mask = AS3722_SD_VSEL_MASK, 133 .enable_reg = AS3722_SD_CONTROL, 134 .enable_mask = AS3722_SDN_CTRL(0), 135 .ext_enable_reg = AS3722_ENABLE_CTRL1, 136 .ext_enable_mask = AS3722_SD0_EXT_ENABLE_MASK, 137 .ranges = as3722_sd016_ranges, 138 .nranges = nitems(as3722_sd016_ranges), 139 }, 140 { 141 .id = AS3722_REG_ID_SD1, 142 .name = "sd1", 143 .volt_reg = AS3722_SD1_VOLTAGE, 144 .volt_vsel_mask = AS3722_SD_VSEL_MASK, 145 .enable_reg = AS3722_SD_CONTROL, 146 .enable_mask = AS3722_SDN_CTRL(1), 147 .ext_enable_reg = AS3722_ENABLE_CTRL1, 148 .ext_enable_mask = AS3722_SD1_EXT_ENABLE_MASK, 149 .ranges = as3722_sd_ranges, 150 .nranges = nitems(as3722_sd_ranges), 151 }, 152 { 153 .id = AS3722_REG_ID_SD2, 154 .name = "sd2", 155 .supply_name = "vsup-sd2", 156 .volt_reg = AS3722_SD2_VOLTAGE, 157 .volt_vsel_mask = AS3722_SD_VSEL_MASK, 158 .enable_reg = AS3722_SD_CONTROL, 159 .enable_mask = AS3722_SDN_CTRL(2), 160 .ext_enable_reg = AS3722_ENABLE_CTRL1, 161 .ext_enable_mask = AS3722_SD2_EXT_ENABLE_MASK, 162 .ranges = as3722_sd_ranges, 163 .nranges = nitems(as3722_sd_ranges), 164 }, 165 { 166 .id = AS3722_REG_ID_SD3, 167 .name = "sd3", 168 .supply_name = "vsup-sd3", 169 .volt_reg = AS3722_SD3_VOLTAGE, 170 .volt_vsel_mask = AS3722_SD_VSEL_MASK, 171 .enable_reg = AS3722_SD_CONTROL, 172 .enable_mask = AS3722_SDN_CTRL(3), 173 .ext_enable_reg = AS3722_ENABLE_CTRL1, 174 .ext_enable_mask = AS3722_SD3_EXT_ENABLE_MASK, 175 .ranges = as3722_sd_ranges, 176 .nranges = nitems(as3722_sd_ranges), 177 }, 178 { 179 .id = AS3722_REG_ID_SD4, 180 .name = "sd4", 181 .supply_name = "vsup-sd4", 182 .volt_reg = AS3722_SD4_VOLTAGE, 183 .volt_vsel_mask = AS3722_SD_VSEL_MASK, 184 .enable_reg = AS3722_SD_CONTROL, 185 .enable_mask = AS3722_SDN_CTRL(4), 186 .ext_enable_reg = AS3722_ENABLE_CTRL2, 187 .ext_enable_mask = AS3722_SD4_EXT_ENABLE_MASK, 188 .ranges = as3722_sd_ranges, 189 .nranges = nitems(as3722_sd_ranges), 190 }, 191 { 192 .id = AS3722_REG_ID_SD5, 193 .name = "sd5", 194 .supply_name = "vsup-sd5", 195 .volt_reg = AS3722_SD5_VOLTAGE, 196 .volt_vsel_mask = AS3722_SD_VSEL_MASK, 197 .enable_reg = AS3722_SD_CONTROL, 198 .enable_mask = AS3722_SDN_CTRL(5), 199 .ext_enable_reg = AS3722_ENABLE_CTRL2, 200 .ext_enable_mask = AS3722_SD5_EXT_ENABLE_MASK, 201 .ranges = as3722_sd_ranges, 202 .nranges = nitems(as3722_sd_ranges), 203 }, 204 { 205 .id = AS3722_REG_ID_SD6, 206 .name = "sd6", 207 .volt_reg = AS3722_SD6_VOLTAGE, 208 .volt_vsel_mask = AS3722_SD_VSEL_MASK, 209 .enable_reg = AS3722_SD_CONTROL, 210 .enable_mask = AS3722_SDN_CTRL(6), 211 .ext_enable_reg = AS3722_ENABLE_CTRL2, 212 .ext_enable_mask = AS3722_SD6_EXT_ENABLE_MASK, 213 .ranges = as3722_sd016_ranges, 214 .nranges = nitems(as3722_sd016_ranges), 215 }, 216 { 217 .id = AS3722_REG_ID_LDO0, 218 .name = "ldo0", 219 .supply_name = "vin-ldo0", 220 .volt_reg = AS3722_LDO0_VOLTAGE, 221 .volt_vsel_mask = AS3722_LDO0_VSEL_MASK, 222 .enable_reg = AS3722_LDO_CONTROL0, 223 .enable_mask = AS3722_LDO0_CTRL, 224 .ext_enable_reg = AS3722_ENABLE_CTRL3, 225 .ext_enable_mask = AS3722_LDO0_EXT_ENABLE_MASK, 226 .ranges = as3722_ldo_ranges, 227 .nranges = nitems(as3722_ldo_ranges), 228 }, 229 { 230 .id = AS3722_REG_ID_LDO1, 231 .name = "ldo1", 232 .supply_name = "vin-ldo1-6", 233 .volt_reg = AS3722_LDO1_VOLTAGE, 234 .volt_vsel_mask = AS3722_LDO_VSEL_MASK, 235 .enable_reg = AS3722_LDO_CONTROL0, 236 .enable_mask = AS3722_LDO1_CTRL, 237 .ext_enable_reg = AS3722_ENABLE_CTRL3, 238 .ext_enable_mask = AS3722_LDO1_EXT_ENABLE_MASK, 239 .ranges = as3722_ldo_ranges, 240 .nranges = nitems(as3722_ldo_ranges), 241 }, 242 { 243 .id = AS3722_REG_ID_LDO2, 244 .name = "ldo2", 245 .supply_name = "vin-ldo2-5-7", 246 .volt_reg = AS3722_LDO2_VOLTAGE, 247 .volt_vsel_mask = AS3722_LDO_VSEL_MASK, 248 .enable_reg = AS3722_LDO_CONTROL0, 249 .enable_mask = AS3722_LDO2_CTRL, 250 .ext_enable_reg = AS3722_ENABLE_CTRL3, 251 .ext_enable_mask = AS3722_LDO2_EXT_ENABLE_MASK, 252 .ranges = as3722_ldo_ranges, 253 .nranges = nitems(as3722_ldo_ranges), 254 }, 255 { 256 .id = AS3722_REG_ID_LDO3, 257 .name = "ldo3", 258 .supply_name = "vin-ldo3-4", 259 .volt_reg = AS3722_LDO3_VOLTAGE, 260 .volt_vsel_mask = AS3722_LDO3_VSEL_MASK, 261 .enable_reg = AS3722_LDO_CONTROL0, 262 .enable_mask = AS3722_LDO3_CTRL, 263 .ext_enable_reg = AS3722_ENABLE_CTRL3, 264 .ext_enable_mask = AS3722_LDO3_EXT_ENABLE_MASK, 265 .ranges = as3722_ldo3_ranges, 266 .nranges = nitems(as3722_ldo3_ranges), 267 }, 268 { 269 .id = AS3722_REG_ID_LDO4, 270 .name = "ldo4", 271 .supply_name = "vin-ldo3-4", 272 .volt_reg = AS3722_LDO4_VOLTAGE, 273 .volt_vsel_mask = AS3722_LDO_VSEL_MASK, 274 .enable_reg = AS3722_LDO_CONTROL0, 275 .enable_mask = AS3722_LDO4_CTRL, 276 .ext_enable_reg = AS3722_ENABLE_CTRL4, 277 .ext_enable_mask = AS3722_LDO4_EXT_ENABLE_MASK, 278 .ranges = as3722_ldo_ranges, 279 .nranges = nitems(as3722_ldo_ranges), 280 }, 281 { 282 .id = AS3722_REG_ID_LDO5, 283 .name = "ldo5", 284 .supply_name = "vin-ldo2-5-7", 285 .volt_reg = AS3722_LDO5_VOLTAGE, 286 .volt_vsel_mask = AS3722_LDO_VSEL_MASK, 287 .enable_reg = AS3722_LDO_CONTROL0, 288 .enable_mask = AS3722_LDO5_CTRL, 289 .ext_enable_reg = AS3722_ENABLE_CTRL4, 290 .ext_enable_mask = AS3722_LDO5_EXT_ENABLE_MASK, 291 .ranges = as3722_ldo_ranges, 292 .nranges = nitems(as3722_ldo_ranges), 293 }, 294 { 295 .id = AS3722_REG_ID_LDO6, 296 .name = "ldo6", 297 .supply_name = "vin-ldo1-6", 298 .volt_reg = AS3722_LDO6_VOLTAGE, 299 .volt_vsel_mask = AS3722_LDO_VSEL_MASK, 300 .enable_reg = AS3722_LDO_CONTROL0, 301 .enable_mask = AS3722_LDO6_CTRL, 302 .ext_enable_reg = AS3722_ENABLE_CTRL4, 303 .ext_enable_mask = AS3722_LDO6_EXT_ENABLE_MASK, 304 .ranges = as3722_ldo_ranges, 305 .nranges = nitems(as3722_ldo_ranges), 306 }, 307 { 308 .id = AS3722_REG_ID_LDO7, 309 .name = "ldo7", 310 .supply_name = "vin-ldo2-5-7", 311 .volt_reg = AS3722_LDO7_VOLTAGE, 312 .volt_vsel_mask = AS3722_LDO_VSEL_MASK, 313 .enable_reg = AS3722_LDO_CONTROL0, 314 .enable_mask = AS3722_LDO7_CTRL, 315 .ext_enable_reg = AS3722_ENABLE_CTRL4, 316 .ext_enable_mask = AS3722_LDO7_EXT_ENABLE_MASK, 317 .ranges = as3722_ldo_ranges, 318 .nranges = nitems(as3722_ldo_ranges), 319 }, 320 { 321 .id = AS3722_REG_ID_LDO9, 322 .name = "ldo9", 323 .supply_name = "vin-ldo9-10", 324 .volt_reg = AS3722_LDO9_VOLTAGE, 325 .volt_vsel_mask = AS3722_LDO_VSEL_MASK, 326 .enable_reg = AS3722_LDO_CONTROL1, 327 .enable_mask = AS3722_LDO9_CTRL, 328 .ext_enable_reg = AS3722_ENABLE_CTRL5, 329 .ext_enable_mask = AS3722_LDO9_EXT_ENABLE_MASK, 330 .ranges = as3722_ldo_ranges, 331 .nranges = nitems(as3722_ldo_ranges), 332 }, 333 { 334 .id = AS3722_REG_ID_LDO10, 335 .name = "ldo10", 336 .supply_name = "vin-ldo9-10", 337 .volt_reg = AS3722_LDO10_VOLTAGE, 338 .volt_vsel_mask = AS3722_LDO_VSEL_MASK, 339 .enable_reg = AS3722_LDO_CONTROL1, 340 .enable_mask = AS3722_LDO10_CTRL, 341 .ext_enable_reg = AS3722_ENABLE_CTRL5, 342 .ext_enable_mask = AS3722_LDO10_EXT_ENABLE_MASK, 343 .ranges = as3722_ldo_ranges, 344 .nranges = nitems(as3722_ldo_ranges), 345 }, 346 { 347 .id = AS3722_REG_ID_LDO11, 348 .name = "ldo11", 349 .supply_name = "vin-ldo11", 350 .volt_reg = AS3722_LDO11_VOLTAGE, 351 .volt_vsel_mask = AS3722_LDO_VSEL_MASK, 352 .enable_reg = AS3722_LDO_CONTROL1, 353 .enable_mask = AS3722_LDO11_CTRL, 354 .ext_enable_reg = AS3722_ENABLE_CTRL5, 355 .ext_enable_mask = AS3722_LDO11_EXT_ENABLE_MASK, 356 .ranges = as3722_ldo_ranges, 357 .nranges = nitems(as3722_ldo_ranges), 358 }, 359 }; 360 361 struct as3722_regnode_init_def { 362 struct regnode_init_def reg_init_def; 363 int ext_control; 364 int enable_tracking; 365 }; 366 367 static int as3722_regnode_init(struct regnode *regnode); 368 static int as3722_regnode_enable(struct regnode *regnode, bool enable, 369 int *udelay); 370 static int as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, 371 int max_uvolt, int *udelay); 372 static int as3722_regnode_get_volt(struct regnode *regnode, int *uvolt); 373 static regnode_method_t as3722_regnode_methods[] = { 374 /* Regulator interface */ 375 REGNODEMETHOD(regnode_init, as3722_regnode_init), 376 REGNODEMETHOD(regnode_enable, as3722_regnode_enable), 377 REGNODEMETHOD(regnode_set_voltage, as3722_regnode_set_volt), 378 REGNODEMETHOD(regnode_get_voltage, as3722_regnode_get_volt), 379 REGNODEMETHOD_END 380 }; 381 DEFINE_CLASS_1(as3722_regnode, as3722_regnode_class, as3722_regnode_methods, 382 sizeof(struct as3722_reg_sc), regnode_class); 383 384 static int 385 as3722_read_sel(struct as3722_reg_sc *sc, uint8_t *sel) 386 { 387 int rv; 388 389 rv = RD1(sc->base_sc, sc->def->volt_reg, sel); 390 if (rv != 0) 391 return (rv); 392 *sel &= sc->def->volt_vsel_mask; 393 *sel >>= ffs(sc->def->volt_vsel_mask) - 1; 394 return (0); 395 } 396 397 static int 398 as3722_write_sel(struct as3722_reg_sc *sc, uint8_t sel) 399 { 400 int rv; 401 402 sel <<= ffs(sc->def->volt_vsel_mask) - 1; 403 sel &= sc->def->volt_vsel_mask; 404 405 rv = RM1(sc->base_sc, sc->def->volt_reg, 406 sc->def->volt_vsel_mask, sel); 407 if (rv != 0) 408 return (rv); 409 return (rv); 410 } 411 412 static bool 413 as3722_sd0_is_low_voltage(struct as3722_reg_sc *sc) 414 { 415 uint8_t val; 416 int rv; 417 418 rv = RD1(sc->base_sc, AS3722_FUSE7, &val); 419 if (rv != 0) 420 return (rv); 421 return (val & AS3722_FUSE7_SD0_LOW_VOLTAGE ? true : false); 422 } 423 424 static int 425 as3722_reg_extreg_setup(struct as3722_reg_sc *sc, int ext_pwr_ctrl) 426 { 427 uint8_t val; 428 int rv; 429 430 val = ext_pwr_ctrl << (ffs(sc->def->ext_enable_mask) - 1); 431 rv = RM1(sc->base_sc, sc->def->ext_enable_reg, 432 sc->def->ext_enable_mask, val); 433 return (rv); 434 } 435 436 static int 437 as3722_reg_enable(struct as3722_reg_sc *sc) 438 { 439 int rv; 440 441 rv = RM1(sc->base_sc, sc->def->enable_reg, 442 sc->def->enable_mask, sc->def->enable_mask); 443 return (rv); 444 } 445 446 static int 447 as3722_reg_disable(struct as3722_reg_sc *sc) 448 { 449 int rv; 450 451 rv = RM1(sc->base_sc, sc->def->enable_reg, 452 sc->def->enable_mask, 0); 453 return (rv); 454 } 455 456 static int 457 as3722_regnode_init(struct regnode *regnode) 458 { 459 struct as3722_reg_sc *sc; 460 int rv; 461 462 sc = regnode_get_softc(regnode); 463 464 sc->enable_usec = 500; 465 if (sc->def->id == AS3722_REG_ID_SD0) { 466 if (as3722_sd0_is_low_voltage(sc)) { 467 sc->def->ranges = as3722_sd0_lv_ranges; 468 sc->def->nranges = nitems(as3722_sd0_lv_ranges); 469 } 470 sc->enable_usec = 600; 471 } else if (sc->def->id == AS3722_REG_ID_LDO3) { 472 if (sc->enable_tracking) { 473 rv = RM1(sc->base_sc, sc->def->volt_reg, 474 AS3722_LDO3_MODE_MASK, 475 AS3722_LDO3_MODE_PMOS_TRACKING); 476 if (rv < 0) { 477 device_printf(sc->base_sc->dev, 478 "LDO3 tracking failed: %d\n", rv); 479 return (rv); 480 } 481 } 482 } 483 484 if (sc->ext_control) { 485 rv = as3722_reg_enable(sc); 486 if (rv < 0) { 487 device_printf(sc->base_sc->dev, 488 "Failed to enable %s regulator: %d\n", 489 sc->def->name, rv); 490 return (rv); 491 } 492 rv = as3722_reg_extreg_setup(sc, sc->ext_control); 493 if (rv < 0) { 494 device_printf(sc->base_sc->dev, 495 "%s ext control failed: %d", sc->def->name, rv); 496 return (rv); 497 } 498 } 499 return (0); 500 } 501 502 static void 503 as3722_fdt_parse(struct as3722_softc *sc, phandle_t node, struct reg_def *def, 504 struct as3722_regnode_init_def *init_def) 505 { 506 int rv; 507 phandle_t parent, supply_node; 508 char prop_name[64]; /* Maximum OFW property name length. */ 509 510 rv = regulator_parse_ofw_stdparam(sc->dev, node, 511 &init_def->reg_init_def); 512 513 rv = OF_getencprop(node, "ams,ext-control", &init_def->ext_control, 514 sizeof(init_def->ext_control)); 515 if (rv <= 0) 516 init_def->ext_control = 0; 517 if (init_def->ext_control > 3) { 518 device_printf(sc->dev, 519 "Invalid value for ams,ext-control property: %d\n", 520 init_def->ext_control); 521 init_def->ext_control = 0; 522 } 523 if (OF_hasprop(node, "ams,enable-tracking")) 524 init_def->enable_tracking = 1; 525 526 /* Get parent supply. */ 527 if (def->supply_name == NULL) 528 return; 529 530 parent = OF_parent(node); 531 snprintf(prop_name, sizeof(prop_name), "%s-supply", 532 def->supply_name); 533 rv = OF_getencprop(parent, prop_name, &supply_node, 534 sizeof(supply_node)); 535 if (rv <= 0) 536 return; 537 supply_node = OF_node_from_xref(supply_node); 538 rv = OF_getprop_alloc(supply_node, "regulator-name", 539 (void **)&init_def->reg_init_def.parent_name); 540 if (rv <= 0) 541 init_def->reg_init_def.parent_name = NULL; 542 } 543 544 static struct as3722_reg_sc * 545 as3722_attach(struct as3722_softc *sc, phandle_t node, struct reg_def *def) 546 { 547 struct as3722_reg_sc *reg_sc; 548 struct as3722_regnode_init_def init_def; 549 struct regnode *regnode; 550 551 bzero(&init_def, sizeof(init_def)); 552 553 as3722_fdt_parse(sc, node, def, &init_def); 554 init_def.reg_init_def.id = def->id; 555 init_def.reg_init_def.ofw_node = node; 556 regnode = regnode_create(sc->dev, &as3722_regnode_class, 557 &init_def.reg_init_def); 558 if (regnode == NULL) { 559 device_printf(sc->dev, "Cannot create regulator.\n"); 560 return (NULL); 561 } 562 reg_sc = regnode_get_softc(regnode); 563 564 /* Init regulator softc. */ 565 reg_sc->regnode = regnode; 566 reg_sc->base_sc = sc; 567 reg_sc->def = def; 568 reg_sc->xref = OF_xref_from_node(node); 569 570 reg_sc->param = regnode_get_stdparam(regnode); 571 reg_sc->ext_control = init_def.ext_control; 572 reg_sc->enable_tracking = init_def.enable_tracking; 573 574 regnode_register(regnode); 575 if (bootverbose) { 576 int volt, rv; 577 regnode_topo_slock(); 578 rv = regnode_get_voltage(regnode, &volt); 579 if (rv == ENODEV) { 580 device_printf(sc->dev, 581 " Regulator %s: parent doesn't exist yet.\n", 582 regnode_get_name(regnode)); 583 } else if (rv != 0) { 584 device_printf(sc->dev, 585 " Regulator %s: voltage: INVALID!!!\n", 586 regnode_get_name(regnode)); 587 } else { 588 device_printf(sc->dev, 589 " Regulator %s: voltage: %d uV\n", 590 regnode_get_name(regnode), volt); 591 } 592 regnode_topo_unlock(); 593 } 594 595 return (reg_sc); 596 } 597 598 int 599 as3722_regulator_attach(struct as3722_softc *sc, phandle_t node) 600 { 601 struct as3722_reg_sc *reg; 602 phandle_t child, rnode; 603 int i; 604 605 rnode = ofw_bus_find_child(node, "regulators"); 606 if (rnode <= 0) { 607 device_printf(sc->dev, " Cannot find regulators subnode\n"); 608 return (ENXIO); 609 } 610 611 sc->nregs = nitems(as3722s_def); 612 sc->regs = malloc(sizeof(struct as3722_reg_sc *) * sc->nregs, 613 M_AS3722_REG, M_WAITOK | M_ZERO); 614 615 /* Attach all known regulators if exist in DT. */ 616 for (i = 0; i < sc->nregs; i++) { 617 child = ofw_bus_find_child(rnode, as3722s_def[i].name); 618 if (child == 0) { 619 if (bootverbose) 620 device_printf(sc->dev, 621 "Regulator %s missing in DT\n", 622 as3722s_def[i].name); 623 continue; 624 } 625 reg = as3722_attach(sc, child, as3722s_def + i); 626 if (reg == NULL) { 627 device_printf(sc->dev, "Cannot attach regulator: %s\n", 628 as3722s_def[i].name); 629 return (ENXIO); 630 } 631 sc->regs[i] = reg; 632 } 633 return (0); 634 } 635 636 int 637 as3722_regulator_map(device_t dev, phandle_t xref, int ncells, 638 pcell_t *cells, int *num) 639 { 640 struct as3722_softc *sc; 641 int i; 642 643 sc = device_get_softc(dev); 644 for (i = 0; i < sc->nregs; i++) { 645 if (sc->regs[i] == NULL) 646 continue; 647 if (sc->regs[i]->xref == xref) { 648 *num = sc->regs[i]->def->id; 649 return (0); 650 } 651 } 652 return (ENXIO); 653 } 654 655 static int 656 as3722_regnode_enable(struct regnode *regnode, bool val, int *udelay) 657 { 658 struct as3722_reg_sc *sc; 659 int rv; 660 661 sc = regnode_get_softc(regnode); 662 663 if (val) 664 rv = as3722_reg_enable(sc); 665 else 666 rv = as3722_reg_disable(sc); 667 *udelay = sc->enable_usec; 668 return (rv); 669 } 670 671 static int 672 as3722_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt, 673 int *udelay) 674 { 675 struct as3722_reg_sc *sc; 676 uint8_t sel; 677 int rv; 678 679 sc = regnode_get_softc(regnode); 680 681 *udelay = 0; 682 rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges, 683 min_uvolt, max_uvolt, &sel); 684 if (rv != 0) 685 return (rv); 686 rv = as3722_write_sel(sc, sel); 687 return (rv); 688 689 } 690 691 static int 692 as3722_regnode_get_volt(struct regnode *regnode, int *uvolt) 693 { 694 struct as3722_reg_sc *sc; 695 uint8_t sel; 696 int rv; 697 698 sc = regnode_get_softc(regnode); 699 rv = as3722_read_sel(sc, &sel); 700 if (rv != 0) 701 return (rv); 702 703 /* LDO6 have bypass. */ 704 if (sc->def->id == AS3722_REG_ID_LDO6 && sel == AS3722_LDO6_SEL_BYPASS) 705 return (ENOENT); 706 rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges, 707 sel, uvolt); 708 return (rv); 709 } 710