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