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