1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011 5 * Ben Gray <ben.r.gray@gmail.com>. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 /* 32 * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management. 33 * 34 * This driver covers the voltages regulators (LDO), allows for enabling & 35 * disabling the voltage output and adjusting the voltage level. 36 * 37 * Voltage regulators can belong to different power groups, in this driver we 38 * put the regulators under our control in the "Application power group". 39 * 40 * 41 * FLATTENED DEVICE TREE (FDT) 42 * Startup override settings can be specified in the FDT, if they are they 43 * should be under the twl parent device and take the following form: 44 * 45 * voltage-regulators = "name1", "millivolts1", 46 * "name2", "millivolts2"; 47 * 48 * Each override should be a pair, the first entry is the name of the regulator 49 * the second is the voltage (in millivolts) to set for the given regulator. 50 * 51 */ 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/kernel.h> 56 #include <sys/lock.h> 57 #include <sys/module.h> 58 #include <sys/bus.h> 59 #include <sys/resource.h> 60 #include <sys/rman.h> 61 #include <sys/sysctl.h> 62 #include <sys/sx.h> 63 #include <sys/malloc.h> 64 65 #include <machine/bus.h> 66 #include <machine/resource.h> 67 #include <machine/intr.h> 68 69 #include <dev/ofw/openfirm.h> 70 #include <dev/ofw/ofw_bus.h> 71 72 #include "twl.h" 73 #include "twl_vreg.h" 74 75 static int twl_vreg_debug = 1; 76 77 /* 78 * Power Groups bits for the 4030 and 6030 devices 79 */ 80 #define TWL4030_P3_GRP 0x80 /* Peripherals, power group */ 81 #define TWL4030_P2_GRP 0x40 /* Modem power group */ 82 #define TWL4030_P1_GRP 0x20 /* Application power group (FreeBSD control) */ 83 84 #define TWL6030_P3_GRP 0x04 /* Modem power group */ 85 #define TWL6030_P2_GRP 0x02 /* Connectivity power group */ 86 #define TWL6030_P1_GRP 0x01 /* Application power group (FreeBSD control) */ 87 88 /* 89 * Register offsets within a LDO regulator register set 90 */ 91 #define TWL_VREG_GRP 0x00 /* Regulator GRP register */ 92 #define TWL_VREG_STATE 0x02 93 #define TWL_VREG_VSEL 0x03 /* Voltage select register */ 94 95 #define UNDF 0xFFFF 96 97 static const uint16_t twl6030_voltages[] = { 98 0000, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 99 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 100 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 101 3300, UNDF, UNDF, UNDF, UNDF, UNDF, UNDF, 2750 102 }; 103 104 static const uint16_t twl4030_vaux1_voltages[] = { 105 1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000 106 }; 107 static const uint16_t twl4030_vaux2_voltages[] = { 108 1700, 1700, 1900, 1300, 1500, 1800, 2000, 2500, 109 2100, 2800, 2200, 2300, 2400, 2400, 2400, 2400 110 }; 111 static const uint16_t twl4030_vaux3_voltages[] = { 112 1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000 113 }; 114 static const uint16_t twl4030_vaux4_voltages[] = { 115 700, 1000, 1200, 1300, 1500, 1800, 1850, 2500, 116 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150 117 }; 118 static const uint16_t twl4030_vmmc1_voltages[] = { 119 1850, 2850, 3000, 3150 120 }; 121 static const uint16_t twl4030_vmmc2_voltages[] = { 122 1000, 1000, 1200, 1300, 1500, 1800, 1850, 2500, 123 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150 124 }; 125 static const uint16_t twl4030_vpll1_voltages[] = { 126 1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000 127 }; 128 static const uint16_t twl4030_vpll2_voltages[] = { 129 700, 1000, 1200, 1300, 1500, 1800, 1850, 2500, 130 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150 131 }; 132 static const uint16_t twl4030_vsim_voltages[] = { 133 1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000 134 }; 135 static const uint16_t twl4030_vdac_voltages[] = { 136 1200, 1300, 1800, 1800 137 }; 138 #if 0 /* vdd1, vdd2, vdio, not currently used. */ 139 static const uint16_t twl4030_vdd1_voltages[] = { 140 800, 1450 141 }; 142 static const uint16_t twl4030_vdd2_voltages[] = { 143 800, 1450, 1500 144 }; 145 static const uint16_t twl4030_vio_voltages[] = { 146 1800, 1850 147 }; 148 #endif 149 static const uint16_t twl4030_vintana2_voltages[] = { 150 2500, 2750 151 }; 152 153 /** 154 * Support voltage regulators for the different IC's 155 */ 156 struct twl_regulator { 157 const char *name; 158 uint8_t subdev; 159 uint8_t regbase; 160 161 uint16_t fixedvoltage; 162 163 const uint16_t *voltages; 164 uint32_t num_voltages; 165 }; 166 167 #define TWL_REGULATOR_ADJUSTABLE(name, subdev, reg, voltages) \ 168 { name, subdev, reg, 0, voltages, (sizeof(voltages)/sizeof(voltages[0])) } 169 #define TWL_REGULATOR_FIXED(name, subdev, reg, voltage) \ 170 { name, subdev, reg, voltage, NULL, 0 } 171 172 static const struct twl_regulator twl4030_regulators[] = { 173 TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x17, twl4030_vaux1_voltages), 174 TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x1B, twl4030_vaux2_voltages), 175 TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x1F, twl4030_vaux3_voltages), 176 TWL_REGULATOR_ADJUSTABLE("vaux4", 0, 0x23, twl4030_vaux4_voltages), 177 TWL_REGULATOR_ADJUSTABLE("vmmc1", 0, 0x27, twl4030_vmmc1_voltages), 178 TWL_REGULATOR_ADJUSTABLE("vmmc2", 0, 0x2B, twl4030_vmmc2_voltages), 179 TWL_REGULATOR_ADJUSTABLE("vpll1", 0, 0x2F, twl4030_vpll1_voltages), 180 TWL_REGULATOR_ADJUSTABLE("vpll2", 0, 0x33, twl4030_vpll2_voltages), 181 TWL_REGULATOR_ADJUSTABLE("vsim", 0, 0x37, twl4030_vsim_voltages), 182 TWL_REGULATOR_ADJUSTABLE("vdac", 0, 0x3B, twl4030_vdac_voltages), 183 TWL_REGULATOR_ADJUSTABLE("vintana2", 0, 0x43, twl4030_vintana2_voltages), 184 TWL_REGULATOR_FIXED("vintana1", 0, 0x3F, 1500), 185 TWL_REGULATOR_FIXED("vintdig", 0, 0x47, 1500), 186 TWL_REGULATOR_FIXED("vusb1v5", 0, 0x71, 1500), 187 TWL_REGULATOR_FIXED("vusb1v8", 0, 0x74, 1800), 188 TWL_REGULATOR_FIXED("vusb3v1", 0, 0x77, 3100), 189 { NULL, 0, 0x00, 0, NULL, 0 } 190 }; 191 192 static const struct twl_regulator twl6030_regulators[] = { 193 TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x84, twl6030_voltages), 194 TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x89, twl6030_voltages), 195 TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x8C, twl6030_voltages), 196 TWL_REGULATOR_ADJUSTABLE("vmmc", 0, 0x98, twl6030_voltages), 197 TWL_REGULATOR_ADJUSTABLE("vpp", 0, 0x9C, twl6030_voltages), 198 TWL_REGULATOR_ADJUSTABLE("vusim", 0, 0xA4, twl6030_voltages), 199 TWL_REGULATOR_FIXED("vmem", 0, 0x64, 1800), 200 TWL_REGULATOR_FIXED("vusb", 0, 0xA0, 3300), 201 TWL_REGULATOR_FIXED("v1v8", 0, 0x46, 1800), 202 TWL_REGULATOR_FIXED("v2v1", 0, 0x4C, 2100), 203 TWL_REGULATOR_FIXED("v1v29", 0, 0x40, 1290), 204 TWL_REGULATOR_FIXED("vcxio", 0, 0x90, 1800), 205 TWL_REGULATOR_FIXED("vdac", 0, 0x94, 1800), 206 TWL_REGULATOR_FIXED("vana", 0, 0x80, 2100), 207 { NULL, 0, 0x00, 0, NULL, 0 } 208 }; 209 210 #define TWL_VREG_MAX_NAMELEN 32 211 212 struct twl_regulator_entry { 213 LIST_ENTRY(twl_regulator_entry) entries; 214 char name[TWL_VREG_MAX_NAMELEN]; 215 struct sysctl_oid *oid; 216 uint8_t sub_dev; /* TWL sub-device group */ 217 uint8_t reg_off; /* base register offset for the LDO */ 218 uint16_t fixed_voltage; /* the (milli)voltage if LDO is fixed */ 219 const uint16_t *supp_voltages; /* pointer to an array of possible voltages */ 220 uint32_t num_supp_voltages; /* the number of supplied voltages */ 221 }; 222 223 struct twl_vreg_softc { 224 device_t sc_dev; 225 device_t sc_pdev; 226 struct sx sc_sx; 227 228 struct intr_config_hook sc_init_hook; 229 LIST_HEAD(twl_regulator_list, twl_regulator_entry) sc_vreg_list; 230 }; 231 232 #define TWL_VREG_XLOCK(_sc) sx_xlock(&(_sc)->sc_sx) 233 #define TWL_VREG_XUNLOCK(_sc) sx_xunlock(&(_sc)->sc_sx) 234 #define TWL_VREG_SLOCK(_sc) sx_slock(&(_sc)->sc_sx) 235 #define TWL_VREG_SUNLOCK(_sc) sx_sunlock(&(_sc)->sc_sx) 236 #define TWL_VREG_LOCK_INIT(_sc) sx_init(&(_sc)->sc_sx, "twl_vreg") 237 #define TWL_VREG_LOCK_DESTROY(_sc) sx_destroy(&(_sc)->sc_sx); 238 239 #define TWL_VREG_ASSERT_LOCKED(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED); 240 241 #define TWL_VREG_LOCK_UPGRADE(_sc) \ 242 do { \ 243 while (!sx_try_upgrade(&(_sc)->sc_sx)) \ 244 pause("twl_vreg_ex", (hz / 100)); \ 245 } while(0) 246 #define TWL_VREG_LOCK_DOWNGRADE(_sc) sx_downgrade(&(_sc)->sc_sx); 247 248 /** 249 * twl_vreg_read_1 - read single register from the TWL device 250 * twl_vreg_write_1 - write a single register in the TWL device 251 * @sc: device context 252 * @clk: the clock device we're reading from / writing to 253 * @off: offset within the clock's register set 254 * @val: the value to write or a pointer to a variable to store the result 255 * 256 * RETURNS: 257 * Zero on success or an error code on failure. 258 */ 259 static inline int 260 twl_vreg_read_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator, 261 uint8_t off, uint8_t *val) 262 { 263 return (twl_read(sc->sc_pdev, regulator->sub_dev, 264 regulator->reg_off + off, val, 1)); 265 } 266 267 static inline int 268 twl_vreg_write_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator, 269 uint8_t off, uint8_t val) 270 { 271 return (twl_write(sc->sc_pdev, regulator->sub_dev, 272 regulator->reg_off + off, &val, 1)); 273 } 274 275 /** 276 * twl_millivolt_to_vsel - gets the vsel bit value to write into the register 277 * for a desired voltage and regulator 278 * @sc: the device soft context 279 * @regulator: pointer to the regulator device 280 * @millivolts: the millivolts to find the bit value for 281 * @vsel: upon return will contain the corresponding register value 282 * 283 * Accepts a (milli)voltage value and tries to find the closest match to the 284 * actual supported voltages for the given regulator. If a match is found 285 * within 100mv of the target, @vsel is written with the match and 0 is 286 * returned. If no voltage match is found the function returns an non-zero 287 * value. 288 * 289 * RETURNS: 290 * Zero on success or an error code on failure. 291 */ 292 static int 293 twl_vreg_millivolt_to_vsel(struct twl_vreg_softc *sc, 294 struct twl_regulator_entry *regulator, int millivolts, uint8_t *vsel) 295 { 296 int delta, smallest_delta; 297 unsigned i, closest_idx; 298 299 TWL_VREG_ASSERT_LOCKED(sc); 300 301 if (regulator->supp_voltages == NULL) 302 return (EINVAL); 303 304 /* Loop over the support voltages and try and find the closest match */ 305 closest_idx = 0; 306 smallest_delta = 0x7fffffff; 307 for (i = 0; i < regulator->num_supp_voltages; i++) { 308 /* Ignore undefined values */ 309 if (regulator->supp_voltages[i] == UNDF) 310 continue; 311 312 /* Calculate the difference */ 313 delta = millivolts - (int)regulator->supp_voltages[i]; 314 if (abs(delta) < smallest_delta) { 315 smallest_delta = abs(delta); 316 closest_idx = i; 317 } 318 } 319 320 /* Check we got a voltage that was within 100mv of the actual target, this 321 * is just a value I picked out of thin air. 322 */ 323 if ((smallest_delta > 100) && (closest_idx < 0x100)) 324 return (EINVAL); 325 326 *vsel = closest_idx; 327 return (0); 328 } 329 330 /** 331 * twl_vreg_is_regulator_enabled - returns the enabled status of the regulator 332 * @sc: the device soft context 333 * @regulator: pointer to the regulator device 334 * @enabled: stores the enabled status, zero disabled, non-zero enabled 335 * 336 * LOCKING: 337 * On entry expects the TWL VREG lock to be held. Will upgrade the lock to 338 * exclusive if not already but, if so, it will be downgraded again before 339 * returning. 340 * 341 * RETURNS: 342 * Zero on success or an error code on failure. 343 */ 344 static int 345 twl_vreg_is_regulator_enabled(struct twl_vreg_softc *sc, 346 struct twl_regulator_entry *regulator, int *enabled) 347 { 348 int err; 349 uint8_t grp; 350 uint8_t state; 351 int xlocked; 352 353 if (enabled == NULL) 354 return (EINVAL); 355 356 TWL_VREG_ASSERT_LOCKED(sc); 357 358 xlocked = sx_xlocked(&sc->sc_sx); 359 if (!xlocked) 360 TWL_VREG_LOCK_UPGRADE(sc); 361 362 /* The status reading is different for the different devices */ 363 if (twl_is_4030(sc->sc_pdev)) { 364 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &state); 365 if (err) 366 goto done; 367 368 *enabled = (state & TWL4030_P1_GRP); 369 370 } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) { 371 /* Check the regulator is in the application group */ 372 if (twl_is_6030(sc->sc_pdev)) { 373 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp); 374 if (err) 375 goto done; 376 377 if (!(grp & TWL6030_P1_GRP)) { 378 *enabled = 0; /* disabled */ 379 goto done; 380 } 381 } 382 383 /* Read the application mode state and verify it's ON */ 384 err = twl_vreg_read_1(sc, regulator, TWL_VREG_STATE, &state); 385 if (err) 386 goto done; 387 388 *enabled = ((state & 0x0C) == 0x04); 389 390 } else { 391 err = EINVAL; 392 } 393 394 done: 395 if (!xlocked) 396 TWL_VREG_LOCK_DOWNGRADE(sc); 397 398 return (err); 399 } 400 401 /** 402 * twl_vreg_disable_regulator - disables a voltage regulator 403 * @sc: the device soft context 404 * @regulator: pointer to the regulator device 405 * 406 * Disables the regulator which will stop the output drivers. 407 * 408 * LOCKING: 409 * On entry expects the TWL VREG lock to be held. Will upgrade the lock to 410 * exclusive if not already but, if so, it will be downgraded again before 411 * returning. 412 * 413 * RETURNS: 414 * Zero on success or a positive error code on failure. 415 */ 416 static int 417 twl_vreg_disable_regulator(struct twl_vreg_softc *sc, 418 struct twl_regulator_entry *regulator) 419 { 420 int err = 0; 421 uint8_t grp; 422 int xlocked; 423 424 TWL_VREG_ASSERT_LOCKED(sc); 425 426 xlocked = sx_xlocked(&sc->sc_sx); 427 if (!xlocked) 428 TWL_VREG_LOCK_UPGRADE(sc); 429 430 if (twl_is_4030(sc->sc_pdev)) { 431 /* Read the regulator CFG_GRP register */ 432 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp); 433 if (err) 434 goto done; 435 436 /* On the TWL4030 we just need to remove the regulator from all the 437 * power groups. 438 */ 439 grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP); 440 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp); 441 442 } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) { 443 /* On TWL6030 we need to make sure we disable power for all groups */ 444 if (twl_is_6030(sc->sc_pdev)) 445 grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP; 446 else 447 grp = 0x00; 448 449 /* Write the resource state to "OFF" */ 450 err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5)); 451 } 452 453 done: 454 if (!xlocked) 455 TWL_VREG_LOCK_DOWNGRADE(sc); 456 457 return (err); 458 } 459 460 /** 461 * twl_vreg_enable_regulator - enables the voltage regulator 462 * @sc: the device soft context 463 * @regulator: pointer to the regulator device 464 * 465 * Enables the regulator which will enable the voltage out at the currently 466 * set voltage. Set the voltage before calling this function to avoid 467 * driving the voltage too high/low by mistake. 468 * 469 * LOCKING: 470 * On entry expects the TWL VREG lock to be held. Will upgrade the lock to 471 * exclusive if not already but, if so, it will be downgraded again before 472 * returning. 473 * 474 * RETURNS: 475 * Zero on success or a positive error code on failure. 476 */ 477 static int 478 twl_vreg_enable_regulator(struct twl_vreg_softc *sc, 479 struct twl_regulator_entry *regulator) 480 { 481 int err; 482 uint8_t grp; 483 int xlocked; 484 485 TWL_VREG_ASSERT_LOCKED(sc); 486 487 xlocked = sx_xlocked(&sc->sc_sx); 488 if (!xlocked) 489 TWL_VREG_LOCK_UPGRADE(sc); 490 491 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp); 492 if (err) 493 goto done; 494 495 /* Enable the regulator by ensuring it's in the application power group 496 * and is in the "on" state. 497 */ 498 if (twl_is_4030(sc->sc_pdev)) { 499 /* On the TWL4030 we just need to ensure the regulator is in the right 500 * power domain, don't need to turn on explicitly like TWL6030. 501 */ 502 grp |= TWL4030_P1_GRP; 503 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp); 504 505 } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) { 506 if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) { 507 grp |= TWL6030_P1_GRP; 508 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp); 509 if (err) 510 goto done; 511 } 512 513 /* Write the resource state to "ON" */ 514 err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5) | 0x01); 515 } 516 517 done: 518 if (!xlocked) 519 TWL_VREG_LOCK_DOWNGRADE(sc); 520 521 return (err); 522 } 523 524 /** 525 * twl_vreg_write_regulator_voltage - sets the voltage level on a regulator 526 * @sc: the device soft context 527 * @regulator: pointer to the regulator structure 528 * @millivolts: the voltage to set 529 * 530 * Sets the voltage output on a given regulator, if the regulator is not 531 * enabled, it will be enabled. 532 * 533 * LOCKING: 534 * On entry expects the TWL VREG lock to be held, may upgrade the lock to 535 * exclusive but if so it will be downgraded once again before returning. 536 * 537 * RETURNS: 538 * Zero on success or an error code on failure. 539 */ 540 static int 541 twl_vreg_write_regulator_voltage(struct twl_vreg_softc *sc, 542 struct twl_regulator_entry *regulator, int millivolts) 543 { 544 int err; 545 uint8_t vsel; 546 int xlocked; 547 548 TWL_VREG_ASSERT_LOCKED(sc); 549 550 /* If millivolts is zero then we simply disable the output */ 551 if (millivolts == 0) 552 return (twl_vreg_disable_regulator(sc, regulator)); 553 554 /* If the regulator has a fixed voltage then check the setting matches 555 * and simply enable. 556 */ 557 if (regulator->supp_voltages == NULL || regulator->num_supp_voltages == 0) { 558 if (millivolts != regulator->fixed_voltage) 559 return (EINVAL); 560 561 return (twl_vreg_enable_regulator(sc, regulator)); 562 } 563 564 /* Get the VSEL value for the given voltage */ 565 err = twl_vreg_millivolt_to_vsel(sc, regulator, millivolts, &vsel); 566 if (err) 567 return (err); 568 569 /* Need to upgrade because writing the voltage and enabling should be atomic */ 570 xlocked = sx_xlocked(&sc->sc_sx); 571 if (!xlocked) 572 TWL_VREG_LOCK_UPGRADE(sc); 573 574 /* Set voltage and enable (atomically) */ 575 err = twl_vreg_write_1(sc, regulator, TWL_VREG_VSEL, (vsel & 0x1f)); 576 if (!err) { 577 err = twl_vreg_enable_regulator(sc, regulator); 578 } 579 580 if (!xlocked) 581 TWL_VREG_LOCK_DOWNGRADE(sc); 582 583 if ((twl_vreg_debug > 1) && !err) 584 device_printf(sc->sc_dev, "%s : setting voltage to %dmV (vsel: 0x%x)\n", 585 regulator->name, millivolts, vsel); 586 587 return (err); 588 } 589 590 /** 591 * twl_vreg_read_regulator_voltage - reads the voltage on a given regulator 592 * @sc: the device soft context 593 * @regulator: pointer to the regulator structure 594 * @millivolts: upon return will contain the voltage on the regulator 595 * 596 * LOCKING: 597 * On entry expects the TWL VREG lock to be held. It will upgrade the lock to 598 * exclusive if not already, but if so, it will be downgraded again before 599 * returning. 600 * 601 * RETURNS: 602 * Zero on success, or otherwise an error code. 603 */ 604 static int 605 twl_vreg_read_regulator_voltage(struct twl_vreg_softc *sc, 606 struct twl_regulator_entry *regulator, int *millivolts) 607 { 608 int err; 609 int en = 0; 610 int xlocked; 611 uint8_t vsel; 612 613 TWL_VREG_ASSERT_LOCKED(sc); 614 615 /* Need to upgrade the lock because checking enabled state and voltage 616 * should be atomic. 617 */ 618 xlocked = sx_xlocked(&sc->sc_sx); 619 if (!xlocked) 620 TWL_VREG_LOCK_UPGRADE(sc); 621 622 /* Check if the regulator is currently enabled */ 623 err = twl_vreg_is_regulator_enabled(sc, regulator, &en); 624 if (err) 625 goto done; 626 627 *millivolts = 0; 628 if (!en) 629 goto done; 630 631 /* Not all voltages are adjustable */ 632 if (regulator->supp_voltages == NULL || !regulator->num_supp_voltages) { 633 *millivolts = regulator->fixed_voltage; 634 goto done; 635 } 636 637 /* For variable voltages read the voltage register */ 638 err = twl_vreg_read_1(sc, regulator, TWL_VREG_VSEL, &vsel); 639 if (err) 640 goto done; 641 642 vsel &= (regulator->num_supp_voltages - 1); 643 if (regulator->supp_voltages[vsel] == UNDF) { 644 err = EINVAL; 645 goto done; 646 } 647 648 *millivolts = regulator->supp_voltages[vsel]; 649 650 done: 651 if (!xlocked) 652 TWL_VREG_LOCK_DOWNGRADE(sc); 653 654 if ((twl_vreg_debug > 1) && !err) 655 device_printf(sc->sc_dev, "%s : reading voltage is %dmV (vsel: 0x%x)\n", 656 regulator->name, *millivolts, vsel); 657 658 return (err); 659 } 660 661 /** 662 * twl_vreg_get_voltage - public interface to read the voltage on a regulator 663 * @dev: TWL VREG device 664 * @name: the name of the regulator to read the voltage of 665 * @millivolts: pointer to an integer that upon return will contain the mV 666 * 667 * If the regulator is disabled the function will set the @millivolts to zero. 668 * 669 * LOCKING: 670 * Internally the function takes and releases the TWL VREG lock. 671 * 672 * RETURNS: 673 * Zero on success or a negative error code on failure. 674 */ 675 int 676 twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts) 677 { 678 struct twl_vreg_softc *sc; 679 struct twl_regulator_entry *regulator; 680 int err = EINVAL; 681 682 if (millivolts == NULL) 683 return (EINVAL); 684 685 sc = device_get_softc(dev); 686 687 TWL_VREG_SLOCK(sc); 688 689 LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) { 690 if (strcmp(regulator->name, name) == 0) { 691 err = twl_vreg_read_regulator_voltage(sc, regulator, millivolts); 692 break; 693 } 694 } 695 696 TWL_VREG_SUNLOCK(sc); 697 698 return (err); 699 } 700 701 /** 702 * twl_vreg_set_voltage - public interface to write the voltage on a regulator 703 * @dev: TWL VREG device 704 * @name: the name of the regulator to read the voltage of 705 * @millivolts: the voltage to set in millivolts 706 * 707 * Sets the output voltage on a given regulator. If the regulator is a fixed 708 * voltage reg then the @millivolts value should match the fixed voltage. If 709 * a variable regulator then the @millivolt value must fit within the max/min 710 * range of the given regulator. 711 * 712 * LOCKING: 713 * Internally the function takes and releases the TWL VREG lock. 714 * 715 * RETURNS: 716 * Zero on success or a negative error code on failure. 717 */ 718 int 719 twl_vreg_set_voltage(device_t dev, const char *name, int millivolts) 720 { 721 struct twl_vreg_softc *sc; 722 struct twl_regulator_entry *regulator; 723 int err = EINVAL; 724 725 sc = device_get_softc(dev); 726 727 TWL_VREG_SLOCK(sc); 728 729 LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) { 730 if (strcmp(regulator->name, name) == 0) { 731 err = twl_vreg_write_regulator_voltage(sc, regulator, millivolts); 732 break; 733 } 734 } 735 736 TWL_VREG_SUNLOCK(sc); 737 738 return (err); 739 } 740 741 /** 742 * twl_sysctl_voltage - reads or writes the voltage for a regulator 743 * @SYSCTL_HANDLER_ARGS: arguments for the callback 744 * 745 * Callback for the sysctl entry for the regulator, simply used to return 746 * the voltage on a particular regulator. 747 * 748 * LOCKING: 749 * Takes the TWL_VREG shared lock internally. 750 * 751 * RETURNS: 752 * Zero on success or an error code on failure. 753 */ 754 static int 755 twl_vreg_sysctl_voltage(SYSCTL_HANDLER_ARGS) 756 { 757 struct twl_vreg_softc *sc = (struct twl_vreg_softc*)arg1; 758 struct twl_regulator_entry *regulator; 759 int voltage; 760 int found = 0; 761 762 TWL_VREG_SLOCK(sc); 763 764 /* Find the regulator with the matching name */ 765 LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) { 766 if (strcmp(regulator->name, oidp->oid_name) == 0) { 767 found = 1; 768 break; 769 } 770 } 771 772 /* Sanity check that we found the regulator */ 773 if (!found) { 774 TWL_VREG_SUNLOCK(sc); 775 return (EINVAL); 776 } 777 778 twl_vreg_read_regulator_voltage(sc, regulator, &voltage); 779 780 TWL_VREG_SUNLOCK(sc); 781 782 return sysctl_handle_int(oidp, &voltage, 0, req); 783 } 784 785 /** 786 * twl_add_regulator - adds single voltage regulator sysctls for the device 787 * @sc: device soft context 788 * @name: the name of the regulator 789 * @nsub: the number of the subdevice 790 * @regbase: the base address of the voltage regulator registers 791 * @fixed_voltage: if a fixed voltage regulator this defines it's voltage 792 * @voltages: if a variable voltage regulator, an array of possible voltages 793 * @num_voltages: the number of entries @voltages 794 * 795 * Adds a voltage regulator to the device and also a sysctl interface for the 796 * regulator. 797 * 798 * LOCKING: 799 * The TWL_VEG exclusive lock must be held while this function is called. 800 * 801 * RETURNS: 802 * Pointer to the new regulator entry on success, otherwise on failure NULL. 803 */ 804 static struct twl_regulator_entry* 805 twl_vreg_add_regulator(struct twl_vreg_softc *sc, const char *name, 806 uint8_t nsub, uint8_t regbase, uint16_t fixed_voltage, 807 const uint16_t *voltages, uint32_t num_voltages) 808 { 809 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); 810 struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); 811 struct twl_regulator_entry *new; 812 813 new = malloc(sizeof(struct twl_regulator_entry), M_DEVBUF, M_NOWAIT | M_ZERO); 814 if (new == NULL) 815 return (NULL); 816 817 strncpy(new->name, name, TWL_VREG_MAX_NAMELEN); 818 new->name[TWL_VREG_MAX_NAMELEN - 1] = '\0'; 819 820 new->sub_dev = nsub; 821 new->reg_off = regbase; 822 823 new->fixed_voltage = fixed_voltage; 824 825 new->supp_voltages = voltages; 826 new->num_supp_voltages = num_voltages; 827 828 /* Add a sysctl entry for the voltage */ 829 new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name, 830 CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0, 831 twl_vreg_sysctl_voltage, "I", "voltage regulator"); 832 833 /* Finally add the regulator to list of supported regulators */ 834 LIST_INSERT_HEAD(&sc->sc_vreg_list, new, entries); 835 836 return (new); 837 } 838 839 /** 840 * twl_vreg_add_regulators - adds any voltage regulators to the device 841 * @sc: device soft context 842 * @chip: the name of the chip used in the hints 843 * @regulators: the list of possible voltage regulators 844 * 845 * Loops over the list of regulators and matches up with the FDT values, 846 * adjusting the actual voltage based on the supplied values. 847 * 848 * LOCKING: 849 * The TWL_VEG exclusive lock must be held while this function is called. 850 * 851 * RETURNS: 852 * Always returns 0. 853 */ 854 static int 855 twl_vreg_add_regulators(struct twl_vreg_softc *sc, 856 const struct twl_regulator *regulators) 857 { 858 int err; 859 int millivolts; 860 const struct twl_regulator *walker; 861 struct twl_regulator_entry *entry; 862 phandle_t child; 863 char rnames[256]; 864 char *name, *voltage; 865 int len = 0, prop_len; 866 867 /* Add the regulators from the list */ 868 walker = ®ulators[0]; 869 while (walker->name != NULL) { 870 /* Add the regulator to the list */ 871 entry = twl_vreg_add_regulator(sc, walker->name, walker->subdev, 872 walker->regbase, walker->fixedvoltage, 873 walker->voltages, walker->num_voltages); 874 if (entry == NULL) 875 continue; 876 877 walker++; 878 } 879 880 /* Check if the FDT is telling us to set any voltages */ 881 child = ofw_bus_get_node(sc->sc_pdev); 882 if (child) { 883 prop_len = OF_getprop(child, "voltage-regulators", rnames, sizeof(rnames)); 884 while (len < prop_len) { 885 name = rnames + len; 886 len += strlen(name) + 1; 887 if ((len >= prop_len) || (name[0] == '\0')) 888 break; 889 890 voltage = rnames + len; 891 len += strlen(voltage) + 1; 892 if (voltage[0] == '\0') 893 break; 894 895 millivolts = strtoul(voltage, NULL, 0); 896 897 LIST_FOREACH(entry, &sc->sc_vreg_list, entries) { 898 if (strcmp(entry->name, name) == 0) { 899 twl_vreg_write_regulator_voltage(sc, entry, millivolts); 900 break; 901 } 902 } 903 } 904 } 905 906 if (twl_vreg_debug) { 907 LIST_FOREACH(entry, &sc->sc_vreg_list, entries) { 908 err = twl_vreg_read_regulator_voltage(sc, entry, &millivolts); 909 if (!err) 910 device_printf(sc->sc_dev, "%s : %d mV\n", entry->name, millivolts); 911 } 912 } 913 914 return (0); 915 } 916 917 /** 918 * twl_vreg_init - initialises the list of regulators 919 * @dev: the twl_vreg device 920 * 921 * This function is called as an intrhook once interrupts have been enabled, 922 * this is done so that the driver has the option to enable/disable or set 923 * the voltage level based on settings providied in the FDT. 924 * 925 * LOCKING: 926 * Takes the exclusive lock in the function. 927 */ 928 static void 929 twl_vreg_init(void *dev) 930 { 931 struct twl_vreg_softc *sc; 932 933 sc = device_get_softc((device_t)dev); 934 935 TWL_VREG_XLOCK(sc); 936 937 if (twl_is_4030(sc->sc_pdev)) 938 twl_vreg_add_regulators(sc, twl4030_regulators); 939 else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) 940 twl_vreg_add_regulators(sc, twl6030_regulators); 941 942 TWL_VREG_XUNLOCK(sc); 943 944 config_intrhook_disestablish(&sc->sc_init_hook); 945 } 946 947 static int 948 twl_vreg_probe(device_t dev) 949 { 950 if (twl_is_4030(device_get_parent(dev))) 951 device_set_desc(dev, "TI TWL4030 PMIC Voltage Regulators"); 952 else if (twl_is_6025(device_get_parent(dev)) || 953 twl_is_6030(device_get_parent(dev))) 954 device_set_desc(dev, "TI TWL6025/TWL6030 PMIC Voltage Regulators"); 955 else 956 return (ENXIO); 957 958 return (0); 959 } 960 961 static int 962 twl_vreg_attach(device_t dev) 963 { 964 struct twl_vreg_softc *sc; 965 966 sc = device_get_softc(dev); 967 sc->sc_dev = dev; 968 sc->sc_pdev = device_get_parent(dev); 969 970 TWL_VREG_LOCK_INIT(sc); 971 972 LIST_INIT(&sc->sc_vreg_list); 973 974 /* We have to wait until interrupts are enabled. I2C read and write 975 * only works if the interrupts are available. 976 */ 977 sc->sc_init_hook.ich_func = twl_vreg_init; 978 sc->sc_init_hook.ich_arg = dev; 979 980 if (config_intrhook_establish(&sc->sc_init_hook) != 0) 981 return (ENOMEM); 982 983 return (0); 984 } 985 986 static int 987 twl_vreg_detach(device_t dev) 988 { 989 struct twl_vreg_softc *sc; 990 struct twl_regulator_entry *regulator; 991 struct twl_regulator_entry *tmp; 992 993 sc = device_get_softc(dev); 994 995 /* Take the lock and free all the added regulators */ 996 TWL_VREG_XLOCK(sc); 997 998 LIST_FOREACH_SAFE(regulator, &sc->sc_vreg_list, entries, tmp) { 999 LIST_REMOVE(regulator, entries); 1000 sysctl_remove_oid(regulator->oid, 1, 0); 1001 free(regulator, M_DEVBUF); 1002 } 1003 1004 TWL_VREG_XUNLOCK(sc); 1005 1006 TWL_VREG_LOCK_DESTROY(sc); 1007 1008 return (0); 1009 } 1010 1011 static device_method_t twl_vreg_methods[] = { 1012 DEVMETHOD(device_probe, twl_vreg_probe), 1013 DEVMETHOD(device_attach, twl_vreg_attach), 1014 DEVMETHOD(device_detach, twl_vreg_detach), 1015 1016 {0, 0}, 1017 }; 1018 1019 static driver_t twl_vreg_driver = { 1020 "twl_vreg", 1021 twl_vreg_methods, 1022 sizeof(struct twl_vreg_softc), 1023 }; 1024 1025 DRIVER_MODULE(twl_vreg, twl, twl_vreg_driver, 0, 0); 1026 MODULE_VERSION(twl_vreg, 1); 1027