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