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