3 * Ben Gray <ben.r.gray@gmail.com>.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
32 * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management.
34 * This driver covers the voltages regulators (LDO), allows for enabling &
35 * disabling the voltage output and adjusting the voltage level.
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".
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:
45 * voltage-regulators = "name1", "millivolts1",
46 * "name2", "millivolts2";
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.
53 #include <sys/param.h>
54 #include <sys/systm.h>
55 #include <sys/kernel.h>
57 #include <sys/module.h>
59 #include <sys/resource.h>
61 #include <sys/sysctl.h>
63 #include <sys/malloc.h>
65 #include <machine/bus.h>
66 #include <machine/resource.h>
67 #include <machine/intr.h>
69 #include <dev/ofw/openfirm.h>
70 #include <dev/ofw/ofw_bus.h>
75 static int twl_vreg_debug = 1;
79 * Power Groups bits for the 4030 and 6030 devices
81 #define TWL4030_P3_GRP 0x80 /* Peripherals, power group */
82 #define TWL4030_P2_GRP 0x40 /* Modem power group */
83 #define TWL4030_P1_GRP 0x20 /* Application power group (FreeBSD control) */
85 #define TWL6030_P3_GRP 0x04 /* Modem power group */
86 #define TWL6030_P2_GRP 0x02 /* Connectivity power group */
87 #define TWL6030_P1_GRP 0x01 /* Application power group (FreeBSD control) */
90 * Register offsets within a LDO regulator register set
92 #define TWL_VREG_GRP 0x00 /* Regulator GRP register */
93 #define TWL_VREG_STATE 0x02
94 #define TWL_VREG_VSEL 0x03 /* Voltage select register */
98 static const uint16_t twl6030_voltages[] = {
99 0000, 1000, 1100, 1200, 1300, 1400, 1500, 1600,
100 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400,
101 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200,
102 3300, UNDF, UNDF, UNDF, UNDF, UNDF, UNDF, 2750
105 static const uint16_t twl4030_vaux1_voltages[] = {
106 1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
108 static const uint16_t twl4030_vaux2_voltages[] = {
109 1700, 1700, 1900, 1300, 1500, 1800, 2000, 2500,
110 2100, 2800, 2200, 2300, 2400, 2400, 2400, 2400
112 static const uint16_t twl4030_vaux3_voltages[] = {
113 1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
115 static const uint16_t twl4030_vaux4_voltages[] = {
116 700, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
117 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
119 static const uint16_t twl4030_vmmc1_voltages[] = {
120 1850, 2850, 3000, 3150
122 static const uint16_t twl4030_vmmc2_voltages[] = {
123 1000, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
124 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
126 static const uint16_t twl4030_vpll1_voltages[] = {
127 1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
129 static const uint16_t twl4030_vpll2_voltages[] = {
130 700, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
131 2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
133 static const uint16_t twl4030_vsim_voltages[] = {
134 1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
136 static const uint16_t twl4030_vdac_voltages[] = {
137 1200, 1300, 1800, 1800
139 #if 0 /* vdd1, vdd2, vdio, not currently used. */
140 static const uint16_t twl4030_vdd1_voltages[] = {
143 static const uint16_t twl4030_vdd2_voltages[] = {
146 static const uint16_t twl4030_vio_voltages[] = {
150 static const uint16_t twl4030_vintana2_voltages[] = {
155 * Support voltage regulators for the different IC's
157 struct twl_regulator {
162 uint16_t fixedvoltage;
164 const uint16_t *voltages;
165 uint32_t num_voltages;
168 #define TWL_REGULATOR_ADJUSTABLE(name, subdev, reg, voltages) \
169 { name, subdev, reg, 0, voltages, (sizeof(voltages)/sizeof(voltages[0])) }
170 #define TWL_REGULATOR_FIXED(name, subdev, reg, voltage) \
171 { name, subdev, reg, voltage, NULL, 0 }
173 static const struct twl_regulator twl4030_regulators[] = {
174 TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x17, twl4030_vaux1_voltages),
175 TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x1B, twl4030_vaux2_voltages),
176 TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x1F, twl4030_vaux3_voltages),
177 TWL_REGULATOR_ADJUSTABLE("vaux4", 0, 0x23, twl4030_vaux4_voltages),
178 TWL_REGULATOR_ADJUSTABLE("vmmc1", 0, 0x27, twl4030_vmmc1_voltages),
179 TWL_REGULATOR_ADJUSTABLE("vmmc2", 0, 0x2B, twl4030_vmmc2_voltages),
180 TWL_REGULATOR_ADJUSTABLE("vpll1", 0, 0x2F, twl4030_vpll1_voltages),
181 TWL_REGULATOR_ADJUSTABLE("vpll2", 0, 0x33, twl4030_vpll2_voltages),
182 TWL_REGULATOR_ADJUSTABLE("vsim", 0, 0x37, twl4030_vsim_voltages),
183 TWL_REGULATOR_ADJUSTABLE("vdac", 0, 0x3B, twl4030_vdac_voltages),
184 TWL_REGULATOR_ADJUSTABLE("vintana2", 0, 0x43, twl4030_vintana2_voltages),
185 TWL_REGULATOR_FIXED("vintana1", 0, 0x3F, 1500),
186 TWL_REGULATOR_FIXED("vintdig", 0, 0x47, 1500),
187 TWL_REGULATOR_FIXED("vusb1v5", 0, 0x71, 1500),
188 TWL_REGULATOR_FIXED("vusb1v8", 0, 0x74, 1800),
189 TWL_REGULATOR_FIXED("vusb3v1", 0, 0x77, 3100),
190 { NULL, 0, 0x00, 0, NULL, 0 }
193 static const struct twl_regulator twl6030_regulators[] = {
194 TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x84, twl6030_voltages),
195 TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x89, twl6030_voltages),
196 TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x8C, twl6030_voltages),
197 TWL_REGULATOR_ADJUSTABLE("vmmc", 0, 0x98, twl6030_voltages),
198 TWL_REGULATOR_ADJUSTABLE("vpp", 0, 0x9C, twl6030_voltages),
199 TWL_REGULATOR_ADJUSTABLE("vusim", 0, 0xA4, twl6030_voltages),
200 TWL_REGULATOR_FIXED("vmem", 0, 0x64, 1800),
201 TWL_REGULATOR_FIXED("vusb", 0, 0xA0, 3300),
202 TWL_REGULATOR_FIXED("v1v8", 0, 0x46, 1800),
203 TWL_REGULATOR_FIXED("v2v1", 0, 0x4C, 2100),
204 TWL_REGULATOR_FIXED("v1v29", 0, 0x40, 1290),
205 TWL_REGULATOR_FIXED("vcxio", 0, 0x90, 1800),
206 TWL_REGULATOR_FIXED("vdac", 0, 0x94, 1800),
207 TWL_REGULATOR_FIXED("vana", 0, 0x80, 2100),
208 { NULL, 0, 0x00, 0, NULL, 0 }
211 #define TWL_VREG_MAX_NAMELEN 32
213 struct twl_regulator_entry {
214 LIST_ENTRY(twl_regulator_entry) entries;
215 char name[TWL_VREG_MAX_NAMELEN];
216 struct sysctl_oid *oid;
217 uint8_t sub_dev; /* TWL sub-device group */
218 uint8_t reg_off; /* base register offset for the LDO */
219 uint16_t fixed_voltage; /* the (milli)voltage if LDO is fixed */
220 const uint16_t *supp_voltages; /* pointer to an array of possible voltages */
221 uint32_t num_supp_voltages; /* the number of supplied voltages */
224 struct twl_vreg_softc {
229 struct intr_config_hook sc_init_hook;
230 LIST_HEAD(twl_regulator_list, twl_regulator_entry) sc_vreg_list;
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);
241 #define TWL_VREG_ASSERT_LOCKED(_sc) sx_assert(&(_sc)->sc_sx, SA_LOCKED);
243 #define TWL_VREG_LOCK_UPGRADE(_sc) \
245 while (!sx_try_upgrade(&(_sc)->sc_sx)) \
246 pause("twl_vreg_ex", (hz / 100)); \
248 #define TWL_VREG_LOCK_DOWNGRADE(_sc) sx_downgrade(&(_sc)->sc_sx);
254 * twl_vreg_read_1 - read single register from the TWL device
255 * twl_vreg_write_1 - write a single register in the TWL device
256 * @sc: device context
257 * @clk: the clock device we're reading from / writing to
258 * @off: offset within the clock's register set
259 * @val: the value to write or a pointer to a variable to store the result
262 * Zero on success or an error code on failure.
265 twl_vreg_read_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
266 uint8_t off, uint8_t *val)
268 return (twl_read(sc->sc_pdev, regulator->sub_dev,
269 regulator->reg_off + off, val, 1));
273 twl_vreg_write_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
274 uint8_t off, uint8_t val)
276 return (twl_write(sc->sc_pdev, regulator->sub_dev,
277 regulator->reg_off + off, &val, 1));
281 * twl_millivolt_to_vsel - gets the vsel bit value to write into the register
282 * for a desired voltage and regulator
283 * @sc: the device soft context
284 * @regulator: pointer to the regulator device
285 * @millivolts: the millivolts to find the bit value for
286 * @vsel: upon return will contain the corresponding register value
288 * Accepts a (milli)voltage value and tries to find the closest match to the
289 * actual supported voltages for the given regulator. If a match is found
290 * within 100mv of the target, @vsel is written with the match and 0 is
291 * returned. If no voltage match is found the function returns an non-zero
295 * Zero on success or an error code on failure.
298 twl_vreg_millivolt_to_vsel(struct twl_vreg_softc *sc,
299 struct twl_regulator_entry *regulator, int millivolts, uint8_t *vsel)
301 int delta, smallest_delta;
302 unsigned i, closest_idx;
304 TWL_VREG_ASSERT_LOCKED(sc);
306 if (regulator->supp_voltages == NULL)
309 /* Loop over the support voltages and try and find the closest match */
311 smallest_delta = 0x7fffffff;
312 for (i = 0; i < regulator->num_supp_voltages; i++) {
314 /* Ignore undefined values */
315 if (regulator->supp_voltages[i] == UNDF)
318 /* Calculate the difference */
319 delta = millivolts - (int)regulator->supp_voltages[i];
320 if (abs(delta) < smallest_delta) {
321 smallest_delta = abs(delta);
326 /* Check we got a voltage that was within 100mv of the actual target, this
327 * is just a value I picked out of thin air.
329 if ((smallest_delta > 100) && (closest_idx < 0x100))
337 * twl_vreg_is_regulator_enabled - returns the enabled status of the regulator
338 * @sc: the device soft context
339 * @regulator: pointer to the regulator device
340 * @enabled: stores the enabled status, zero disabled, non-zero enabled
343 * On entry expects the TWL VREG lock to be held. Will upgrade the lock to
344 * exclusive if not already but, if so, it will be downgraded again before
348 * Zero on success or an error code on failure.
351 twl_vreg_is_regulator_enabled(struct twl_vreg_softc *sc,
352 struct twl_regulator_entry *regulator, int *enabled)
362 TWL_VREG_ASSERT_LOCKED(sc);
364 xlocked = sx_xlocked(&sc->sc_sx);
366 TWL_VREG_LOCK_UPGRADE(sc);
368 /* The status reading is different for the different devices */
369 if (twl_is_4030(sc->sc_pdev)) {
371 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &state);
375 *enabled = (state & TWL4030_P1_GRP);
377 } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
379 /* Check the regulator is in the application group */
380 if (twl_is_6030(sc->sc_pdev)) {
381 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
385 if (!(grp & TWL6030_P1_GRP)) {
386 *enabled = 0; /* disabled */
391 /* Read the application mode state and verify it's ON */
392 err = twl_vreg_read_1(sc, regulator, TWL_VREG_STATE, &state);
396 *enabled = ((state & 0x0C) == 0x04);
404 TWL_VREG_LOCK_DOWNGRADE(sc);
410 * twl_vreg_disable_regulator - disables a voltage regulator
411 * @sc: the device soft context
412 * @regulator: pointer to the regulator device
414 * Disables the regulator which will stop the output drivers.
417 * On entry expects the TWL VREG lock to be held. Will upgrade the lock to
418 * exclusive if not already but, if so, it will be downgraded again before
422 * Zero on success or a positive error code on failure.
425 twl_vreg_disable_regulator(struct twl_vreg_softc *sc,
426 struct twl_regulator_entry *regulator)
432 TWL_VREG_ASSERT_LOCKED(sc);
434 xlocked = sx_xlocked(&sc->sc_sx);
436 TWL_VREG_LOCK_UPGRADE(sc);
438 if (twl_is_4030(sc->sc_pdev)) {
440 /* Read the regulator CFG_GRP register */
441 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
445 /* On the TWL4030 we just need to remove the regulator from all the
448 grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
449 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
451 } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
453 /* On TWL6030 we need to make sure we disable power for all groups */
454 if (twl_is_6030(sc->sc_pdev))
455 grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP;
459 /* Write the resource state to "OFF" */
460 err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5));
465 TWL_VREG_LOCK_DOWNGRADE(sc);
471 * twl_vreg_enable_regulator - enables the voltage regulator
472 * @sc: the device soft context
473 * @regulator: pointer to the regulator device
475 * Enables the regulator which will enable the voltage out at the currently
476 * set voltage. Set the voltage before calling this function to avoid
477 * driving the voltage too high/low by mistake.
480 * On entry expects the TWL VREG lock to be held. Will upgrade the lock to
481 * exclusive if not already but, if so, it will be downgraded again before
485 * Zero on success or a positive error code on failure.
488 twl_vreg_enable_regulator(struct twl_vreg_softc *sc,
489 struct twl_regulator_entry *regulator)
495 TWL_VREG_ASSERT_LOCKED(sc);
497 xlocked = sx_xlocked(&sc->sc_sx);
499 TWL_VREG_LOCK_UPGRADE(sc);
502 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
506 /* Enable the regulator by ensuring it's in the application power group
507 * and is in the "on" state.
509 if (twl_is_4030(sc->sc_pdev)) {
511 /* On the TWL4030 we just need to ensure the regulator is in the right
512 * power domain, don't need to turn on explicitly like TWL6030.
514 grp |= TWL4030_P1_GRP;
515 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
517 } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
519 if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) {
520 grp |= TWL6030_P1_GRP;
521 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
526 /* Write the resource state to "ON" */
527 err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5) | 0x01);
532 TWL_VREG_LOCK_DOWNGRADE(sc);
538 * twl_vreg_write_regulator_voltage - sets the voltage level on a regulator
539 * @sc: the device soft context
540 * @regulator: pointer to the regulator structure
541 * @millivolts: the voltage to set
543 * Sets the voltage output on a given regulator, if the regulator is not
544 * enabled, it will be enabled.
547 * On entry expects the TWL VREG lock to be held, may upgrade the lock to
548 * exclusive but if so it will be downgraded once again before returning.
551 * Zero on success or an error code on failure.
554 twl_vreg_write_regulator_voltage(struct twl_vreg_softc *sc,
555 struct twl_regulator_entry *regulator, int millivolts)
561 TWL_VREG_ASSERT_LOCKED(sc);
563 /* If millivolts is zero then we simply disable the output */
565 return (twl_vreg_disable_regulator(sc, regulator));
567 /* If the regulator has a fixed voltage then check the setting matches
570 if (regulator->supp_voltages == NULL || regulator->num_supp_voltages == 0) {
571 if (millivolts != regulator->fixed_voltage)
574 return (twl_vreg_enable_regulator(sc, regulator));
577 /* Get the VSEL value for the given voltage */
578 err = twl_vreg_millivolt_to_vsel(sc, regulator, millivolts, &vsel);
583 /* Need to upgrade because writing the voltage and enabling should be atomic */
584 xlocked = sx_xlocked(&sc->sc_sx);
586 TWL_VREG_LOCK_UPGRADE(sc);
589 /* Set voltage and enable (atomically) */
590 err = twl_vreg_write_1(sc, regulator, TWL_VREG_VSEL, (vsel & 0x1f));
592 err = twl_vreg_enable_regulator(sc, regulator);
596 TWL_VREG_LOCK_DOWNGRADE(sc);
598 if ((twl_vreg_debug > 1) && !err)
599 device_printf(sc->sc_dev, "%s : setting voltage to %dmV (vsel: 0x%x)\n",
600 regulator->name, millivolts, vsel);
606 * twl_vreg_read_regulator_voltage - reads the voltage on a given regulator
607 * @sc: the device soft context
608 * @regulator: pointer to the regulator structure
609 * @millivolts: upon return will contain the voltage on the regulator
612 * On entry expects the TWL VREG lock to be held. It will upgrade the lock to
613 * exclusive if not already, but if so, it will be downgraded again before
617 * Zero on success, or otherwise an error code.
620 twl_vreg_read_regulator_voltage(struct twl_vreg_softc *sc,
621 struct twl_regulator_entry *regulator, int *millivolts)
628 TWL_VREG_ASSERT_LOCKED(sc);
630 /* Need to upgrade the lock because checking enabled state and voltage
633 xlocked = sx_xlocked(&sc->sc_sx);
635 TWL_VREG_LOCK_UPGRADE(sc);
638 /* Check if the regulator is currently enabled */
639 err = twl_vreg_is_regulator_enabled(sc, regulator, &en);
648 /* Not all voltages are adjustable */
649 if (regulator->supp_voltages == NULL || !regulator->num_supp_voltages) {
650 *millivolts = regulator->fixed_voltage;
654 /* For variable voltages read the voltage register */
655 err = twl_vreg_read_1(sc, regulator, TWL_VREG_VSEL, &vsel);
659 vsel &= (regulator->num_supp_voltages - 1);
660 if (regulator->supp_voltages[vsel] == UNDF) {
665 *millivolts = regulator->supp_voltages[vsel];
669 TWL_VREG_LOCK_DOWNGRADE(sc);
671 if ((twl_vreg_debug > 1) && !err)
672 device_printf(sc->sc_dev, "%s : reading voltage is %dmV (vsel: 0x%x)\n",
673 regulator->name, *millivolts, vsel);
679 * twl_vreg_get_voltage - public interface to read the voltage on a regulator
680 * @dev: TWL VREG device
681 * @name: the name of the regulator to read the voltage of
682 * @millivolts: pointer to an integer that upon return will contain the mV
684 * If the regulator is disabled the function will set the @millivolts to zero.
687 * Internally the function takes and releases the TWL VREG lock.
690 * Zero on success or a negative error code on failure.
693 twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts)
695 struct twl_vreg_softc *sc;
696 struct twl_regulator_entry *regulator;
699 if (millivolts == NULL)
702 sc = device_get_softc(dev);
706 LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
707 if (strcmp(regulator->name, name) == 0) {
708 err = twl_vreg_read_regulator_voltage(sc, regulator, millivolts);
713 TWL_VREG_SUNLOCK(sc);
719 * twl_vreg_set_voltage - public interface to write the voltage on a regulator
720 * @dev: TWL VREG device
721 * @name: the name of the regulator to read the voltage of
722 * @millivolts: the voltage to set in millivolts
724 * Sets the output voltage on a given regulator. If the regulator is a fixed
725 * voltage reg then the @millivolts value should match the fixed voltage. If
726 * a variable regulator then the @millivolt value must fit within the max/min
727 * range of the given regulator.
730 * Internally the function takes and releases the TWL VREG lock.
733 * Zero on success or a negative error code on failure.
736 twl_vreg_set_voltage(device_t dev, const char *name, int millivolts)
738 struct twl_vreg_softc *sc;
739 struct twl_regulator_entry *regulator;
742 sc = device_get_softc(dev);
746 LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
747 if (strcmp(regulator->name, name) == 0) {
748 err = twl_vreg_write_regulator_voltage(sc, regulator, millivolts);
753 TWL_VREG_SUNLOCK(sc);
759 * twl_sysctl_voltage - reads or writes the voltage for a regulator
760 * @SYSCTL_HANDLER_ARGS: arguments for the callback
762 * Callback for the sysctl entry for the regulator, simply used to return
763 * the voltage on a particular regulator.
766 * Takes the TWL_VREG shared lock internally.
769 * Zero on success or an error code on failure.
772 twl_vreg_sysctl_voltage(SYSCTL_HANDLER_ARGS)
774 struct twl_vreg_softc *sc = (struct twl_vreg_softc*)arg1;
775 struct twl_regulator_entry *regulator;
781 /* Find the regulator with the matching name */
782 LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
783 if (strcmp(regulator->name, oidp->oid_name) == 0) {
789 /* Sanity check that we found the regulator */
791 TWL_VREG_SUNLOCK(sc);
795 twl_vreg_read_regulator_voltage(sc, regulator, &voltage);
797 TWL_VREG_SUNLOCK(sc);
799 return sysctl_handle_int(oidp, &voltage, 0, req);
803 * twl_add_regulator - adds single voltage regulator sysctls for the device
804 * @sc: device soft context
805 * @name: the name of the regulator
806 * @nsub: the number of the subdevice
807 * @regbase: the base address of the voltage regulator registers
808 * @fixed_voltage: if a fixed voltage regulator this defines it's voltage
809 * @voltages: if a variable voltage regulator, an array of possible voltages
810 * @num_voltages: the number of entries @voltages
812 * Adds a voltage regulator to the device and also a sysctl interface for the
816 * The TWL_VEG exclusive lock must be held while this function is called.
819 * Pointer to the new regulator entry on success, otherwise on failure NULL.
821 static struct twl_regulator_entry*
822 twl_vreg_add_regulator(struct twl_vreg_softc *sc, const char *name,
823 uint8_t nsub, uint8_t regbase, uint16_t fixed_voltage,
824 const uint16_t *voltages, uint32_t num_voltages)
826 struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
827 struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
828 struct twl_regulator_entry *new;
830 new = malloc(sizeof(struct twl_regulator_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
835 strncpy(new->name, name, TWL_VREG_MAX_NAMELEN);
836 new->name[TWL_VREG_MAX_NAMELEN - 1] = '\0';
839 new->reg_off = regbase;
841 new->fixed_voltage = fixed_voltage;
843 new->supp_voltages = voltages;
844 new->num_supp_voltages = num_voltages;
847 /* Add a sysctl entry for the voltage */
848 new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name,
849 CTLTYPE_INT | CTLFLAG_RD, sc, 0,
850 twl_vreg_sysctl_voltage, "I", "voltage regulator");
852 /* Finally add the regulator to list of supported regulators */
853 LIST_INSERT_HEAD(&sc->sc_vreg_list, new, entries);
859 * twl_vreg_add_regulators - adds any voltage regulators to the device
860 * @sc: device soft context
861 * @chip: the name of the chip used in the hints
862 * @regulators: the list of possible voltage regulators
864 * Loops over the list of regulators and matches up with the FDT values,
865 * adjusting the actual voltage based on the supplied values.
868 * The TWL_VEG exclusive lock must be held while this function is called.
874 twl_vreg_add_regulators(struct twl_vreg_softc *sc,
875 const struct twl_regulator *regulators)
879 const struct twl_regulator *walker;
880 struct twl_regulator_entry *entry;
883 char *name, *voltage;
884 int len = 0, prop_len;
887 /* Add the regulators from the list */
888 walker = ®ulators[0];
889 while (walker->name != NULL) {
891 /* Add the regulator to the list */
892 entry = twl_vreg_add_regulator(sc, walker->name, walker->subdev,
893 walker->regbase, walker->fixedvoltage,
894 walker->voltages, walker->num_voltages);
902 /* Check if the FDT is telling us to set any voltages */
903 child = ofw_bus_get_node(sc->sc_pdev);
906 prop_len = OF_getprop(child, "voltage-regulators", rnames, sizeof(rnames));
907 while (len < prop_len) {
909 len += strlen(name) + 1;
910 if ((len >= prop_len) || (name[0] == '\0'))
913 voltage = rnames + len;
914 len += strlen(voltage) + 1;
915 if (voltage[0] == '\0')
918 millivolts = strtoul(voltage, NULL, 0);
920 LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
921 if (strcmp(entry->name, name) == 0) {
922 twl_vreg_write_regulator_voltage(sc, entry, millivolts);
930 if (twl_vreg_debug) {
931 LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
932 err = twl_vreg_read_regulator_voltage(sc, entry, &millivolts);
934 device_printf(sc->sc_dev, "%s : %d mV\n", entry->name, millivolts);
942 * twl_vreg_init - initialises the list of regulators
943 * @dev: the twl_vreg device
945 * This function is called as an intrhook once interrupts have been enabled,
946 * this is done so that the driver has the option to enable/disable or set
947 * the voltage level based on settings providied in the FDT.
950 * Takes the exclusive lock in the function.
953 twl_vreg_init(void *dev)
955 struct twl_vreg_softc *sc;
957 sc = device_get_softc((device_t)dev);
961 if (twl_is_4030(sc->sc_pdev))
962 twl_vreg_add_regulators(sc, twl4030_regulators);
963 else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev))
964 twl_vreg_add_regulators(sc, twl6030_regulators);
966 TWL_VREG_XUNLOCK(sc);
968 config_intrhook_disestablish(&sc->sc_init_hook);
972 twl_vreg_probe(device_t dev)
974 if (twl_is_4030(device_get_parent(dev)))
975 device_set_desc(dev, "TI TWL4030 PMIC Voltage Regulators");
976 else if (twl_is_6025(device_get_parent(dev)) ||
977 twl_is_6030(device_get_parent(dev)))
978 device_set_desc(dev, "TI TWL6025/TWL6030 PMIC Voltage Regulators");
986 twl_vreg_attach(device_t dev)
988 struct twl_vreg_softc *sc;
990 sc = device_get_softc(dev);
992 sc->sc_pdev = device_get_parent(dev);
994 TWL_VREG_LOCK_INIT(sc);
996 LIST_INIT(&sc->sc_vreg_list);
998 /* We have to wait until interrupts are enabled. I2C read and write
999 * only works if the interrupts are available.
1001 sc->sc_init_hook.ich_func = twl_vreg_init;
1002 sc->sc_init_hook.ich_arg = dev;
1004 if (config_intrhook_establish(&sc->sc_init_hook) != 0)
1011 twl_vreg_detach(device_t dev)
1013 struct twl_vreg_softc *sc;
1014 struct twl_regulator_entry *regulator;
1015 struct twl_regulator_entry *tmp;
1017 sc = device_get_softc(dev);
1019 /* Take the lock and free all the added regulators */
1022 LIST_FOREACH_SAFE(regulator, &sc->sc_vreg_list, entries, tmp) {
1023 LIST_REMOVE(regulator, entries);
1024 sysctl_remove_oid(regulator->oid, 1, 0);
1025 free(regulator, M_DEVBUF);
1028 TWL_VREG_XUNLOCK(sc);
1030 TWL_VREG_LOCK_DESTROY(sc);
1035 static device_method_t twl_vreg_methods[] = {
1036 DEVMETHOD(device_probe, twl_vreg_probe),
1037 DEVMETHOD(device_attach, twl_vreg_attach),
1038 DEVMETHOD(device_detach, twl_vreg_detach),
1043 static driver_t twl_vreg_driver = {
1046 sizeof(struct twl_vreg_softc),
1049 static devclass_t twl_vreg_devclass;
1051 DRIVER_MODULE(twl_vreg, twl, twl_vreg_driver, twl_vreg_devclass, 0, 0);
1052 MODULE_VERSION(twl_vreg, 1);