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