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