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