]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm/ti/twl/twl_vreg.c
MFV r315633, 315635:
[FreeBSD/FreeBSD.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/resource.h>
67 #include <machine/intr.h>
68
69 #include <dev/ofw/openfirm.h>
70 #include <dev/ofw/ofw_bus.h>
71
72 #include "twl.h"
73 #include "twl_vreg.h"
74
75 static int twl_vreg_debug = 1;
76
77
78 /*
79  * Power Groups bits for the 4030 and 6030 devices
80  */
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) */
84
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) */
88
89 /*
90  * Register offsets within a LDO regulator register set
91  */
92 #define TWL_VREG_GRP            0x00    /* Regulator GRP register */
93 #define TWL_VREG_STATE          0x02
94 #define TWL_VREG_VSEL           0x03    /* Voltage select register */
95
96 #define UNDF  0xFFFF
97
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
103 };
104
105 static const uint16_t twl4030_vaux1_voltages[] = {
106         1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
107 };
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
111 };
112 static const uint16_t twl4030_vaux3_voltages[] = {
113         1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
114 };
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
118 };
119 static const uint16_t twl4030_vmmc1_voltages[] = {
120         1850, 2850, 3000, 3150
121 };
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
125 };
126 static const uint16_t twl4030_vpll1_voltages[] = {
127         1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
128 };
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
132 };
133 static const uint16_t twl4030_vsim_voltages[] = {
134         1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
135 };
136 static const uint16_t twl4030_vdac_voltages[] = {
137         1200, 1300, 1800, 1800
138 };
139 #if 0 /* vdd1, vdd2, vdio, not currently used. */
140 static const uint16_t twl4030_vdd1_voltages[] = {
141         800, 1450
142 };
143 static const uint16_t twl4030_vdd2_voltages[] = {
144         800, 1450, 1500
145 };
146 static const uint16_t twl4030_vio_voltages[] = {
147         1800, 1850
148 };
149 #endif
150 static const uint16_t twl4030_vintana2_voltages[] = {
151         2500, 2750
152 };
153
154 /**
155  *  Support voltage regulators for the different IC's
156  */
157 struct twl_regulator {
158         const char      *name;
159         uint8_t         subdev;
160         uint8_t         regbase;
161
162         uint16_t        fixedvoltage;
163
164         const uint16_t  *voltages;
165         uint32_t        num_voltages;
166 };
167
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 }
172
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 }
191 };
192
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 } 
209 };
210
211 #define TWL_VREG_MAX_NAMELEN  32
212
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 */
222 };
223
224 struct twl_vreg_softc {
225         device_t        sc_dev;
226         device_t        sc_pdev;
227         struct sx       sc_sx;
228
229         struct intr_config_hook sc_init_hook;
230         LIST_HEAD(twl_regulator_list, twl_regulator_entry) sc_vreg_list;
231 };
232
233
234 #define TWL_VREG_XLOCK(_sc)                     sx_xlock(&(_sc)->sc_sx)
235 #define TWL_VREG_XUNLOCK(_sc)           sx_xunlock(&(_sc)->sc_sx)
236 #define TWL_VREG_SLOCK(_sc)                     sx_slock(&(_sc)->sc_sx)
237 #define TWL_VREG_SUNLOCK(_sc)           sx_sunlock(&(_sc)->sc_sx)
238 #define TWL_VREG_LOCK_INIT(_sc)         sx_init(&(_sc)->sc_sx, "twl_vreg")
239 #define TWL_VREG_LOCK_DESTROY(_sc)      sx_destroy(&(_sc)->sc_sx);
240
241 #define TWL_VREG_ASSERT_LOCKED(_sc)     sx_assert(&(_sc)->sc_sx, SA_LOCKED);
242
243 #define TWL_VREG_LOCK_UPGRADE(_sc)               \
244         do {                                         \
245                 while (!sx_try_upgrade(&(_sc)->sc_sx))   \
246                         pause("twl_vreg_ex", (hz / 100));    \
247         } while(0)
248 #define TWL_VREG_LOCK_DOWNGRADE(_sc)    sx_downgrade(&(_sc)->sc_sx);
249
250
251
252
253 /**
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
260  *
261  *      RETURNS:
262  *      Zero on success or an error code on failure.
263  */
264 static inline int
265 twl_vreg_read_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
266         uint8_t off, uint8_t *val)
267 {
268         return (twl_read(sc->sc_pdev, regulator->sub_dev, 
269             regulator->reg_off + off, val, 1));
270 }
271
272 static inline int
273 twl_vreg_write_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
274         uint8_t off, uint8_t val)
275 {
276         return (twl_write(sc->sc_pdev, regulator->sub_dev,
277             regulator->reg_off + off, &val, 1));
278 }
279
280 /**
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
287  *
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
292  *      value.
293  *
294  *      RETURNS:
295  *      Zero on success or an error code on failure.
296  */
297 static int
298 twl_vreg_millivolt_to_vsel(struct twl_vreg_softc *sc,
299         struct twl_regulator_entry *regulator, int millivolts, uint8_t *vsel)
300 {
301         int delta, smallest_delta;
302         unsigned i, closest_idx;
303
304         TWL_VREG_ASSERT_LOCKED(sc);
305
306         if (regulator->supp_voltages == NULL)
307                 return (EINVAL);
308
309         /* Loop over the support voltages and try and find the closest match */
310         closest_idx = 0;
311         smallest_delta = 0x7fffffff;
312         for (i = 0; i < regulator->num_supp_voltages; i++) {
313
314                 /* Ignore undefined values */
315                 if (regulator->supp_voltages[i] == UNDF)
316                         continue;
317
318                 /* Calculate the difference */
319                 delta = millivolts - (int)regulator->supp_voltages[i];
320                 if (abs(delta) < smallest_delta) {
321                         smallest_delta = abs(delta);
322                         closest_idx = i;
323                 }
324         }
325
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.
328          */
329         if ((smallest_delta > 100) && (closest_idx < 0x100))
330                 return (EINVAL);
331
332         *vsel = closest_idx;
333         return (0);
334 }
335
336 /**
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
341  *
342  *      LOCKING:
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
345  *      returning.
346  *
347  *      RETURNS:
348  *      Zero on success or an error code on failure.
349  */
350 static int
351 twl_vreg_is_regulator_enabled(struct twl_vreg_softc *sc,
352         struct twl_regulator_entry *regulator, int *enabled)
353 {
354         int err;
355         uint8_t grp;
356         uint8_t state;
357         int xlocked;
358         
359         if (enabled == NULL)
360                 return (EINVAL);
361
362         TWL_VREG_ASSERT_LOCKED(sc);
363
364         xlocked = sx_xlocked(&sc->sc_sx);
365         if (!xlocked)
366                 TWL_VREG_LOCK_UPGRADE(sc);
367
368         /* The status reading is different for the different devices */
369         if (twl_is_4030(sc->sc_pdev)) {
370
371                 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &state);
372                 if (err)
373                         goto done;
374
375                 *enabled = (state & TWL4030_P1_GRP);
376
377         } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
378
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);
382                         if (err)
383                                 goto done;
384
385                         if (!(grp & TWL6030_P1_GRP)) {
386                                 *enabled = 0; /* disabled */
387                                 goto done;
388                         }
389                 }
390
391                 /* Read the application mode state and verify it's ON */
392                 err = twl_vreg_read_1(sc, regulator, TWL_VREG_STATE, &state);
393                 if (err)
394                         goto done;
395
396                 *enabled = ((state & 0x0C) == 0x04);
397
398         } else {
399                 err = EINVAL;
400         }
401
402 done:
403         if (!xlocked)
404                 TWL_VREG_LOCK_DOWNGRADE(sc);
405
406         return (err);
407 }
408
409 /**
410  *      twl_vreg_disable_regulator - disables a voltage regulator
411  *      @sc: the device soft context
412  *      @regulator: pointer to the regulator device
413  *
414  *      Disables the regulator which will stop the output drivers.
415  *
416  *      LOCKING:
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
419  *      returning.
420  *
421  *      RETURNS:
422  *      Zero on success or a positive error code on failure.
423  */
424 static int
425 twl_vreg_disable_regulator(struct twl_vreg_softc *sc,
426         struct twl_regulator_entry *regulator)
427 {
428         int err = 0;
429         uint8_t grp;
430         int xlocked;
431
432         TWL_VREG_ASSERT_LOCKED(sc);
433
434         xlocked = sx_xlocked(&sc->sc_sx);
435         if (!xlocked)
436                 TWL_VREG_LOCK_UPGRADE(sc);
437
438         if (twl_is_4030(sc->sc_pdev)) {
439
440                 /* Read the regulator CFG_GRP register */
441                 err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
442                 if (err)
443                         goto done;
444
445                 /* On the TWL4030 we just need to remove the regulator from all the
446                  * power groups.
447                  */
448                 grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
449                 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
450
451         } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
452
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;
456                 else
457                         grp = 0x00;
458
459                 /* Write the resource state to "OFF" */
460                 err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5));
461         }
462
463 done:
464         if (!xlocked)
465                 TWL_VREG_LOCK_DOWNGRADE(sc);
466         
467         return (err);
468 }
469
470 /**
471  *      twl_vreg_enable_regulator - enables the voltage regulator
472  *      @sc: the device soft context
473  *      @regulator: pointer to the regulator device
474  *
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.
478  *
479  *      LOCKING:
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
482  *      returning.
483  *
484  *      RETURNS:
485  *      Zero on success or a positive error code on failure.
486  */
487 static int
488 twl_vreg_enable_regulator(struct twl_vreg_softc *sc,
489     struct twl_regulator_entry *regulator)
490 {
491         int err;
492         uint8_t grp;
493         int xlocked;
494
495         TWL_VREG_ASSERT_LOCKED(sc);
496
497         xlocked = sx_xlocked(&sc->sc_sx);
498         if (!xlocked)
499                 TWL_VREG_LOCK_UPGRADE(sc);
500
501
502         err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
503         if (err)
504                 goto done;
505
506         /* Enable the regulator by ensuring it's in the application power group
507          * and is in the "on" state.
508          */
509         if (twl_is_4030(sc->sc_pdev)) {
510
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.
513                  */
514                 grp |= TWL4030_P1_GRP;
515                 err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
516
517         } else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
518
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);
522                         if (err)
523                                 goto done;
524                 }
525
526                 /* Write the resource state to "ON" */
527                 err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5) | 0x01);
528         }
529
530 done:
531         if (!xlocked)
532                 TWL_VREG_LOCK_DOWNGRADE(sc);
533         
534         return (err);
535 }
536
537 /**
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
542  *
543  *      Sets the voltage output on a given regulator, if the regulator is not
544  *      enabled, it will be enabled.
545  *
546  *      LOCKING:
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.
549  *
550  *      RETURNS:
551  *      Zero on success or an error code on failure.
552  */
553 static int
554 twl_vreg_write_regulator_voltage(struct twl_vreg_softc *sc,
555     struct twl_regulator_entry *regulator, int millivolts)
556 {
557         int err;
558         uint8_t vsel;
559         int xlocked;
560
561         TWL_VREG_ASSERT_LOCKED(sc);
562
563         /* If millivolts is zero then we simply disable the output */
564         if (millivolts == 0)
565                 return (twl_vreg_disable_regulator(sc, regulator));
566
567         /* If the regulator has a fixed voltage then check the setting matches
568          * and simply enable.
569          */
570         if (regulator->supp_voltages == NULL || regulator->num_supp_voltages == 0) {
571                 if (millivolts != regulator->fixed_voltage)
572                         return (EINVAL);
573
574                 return (twl_vreg_enable_regulator(sc, regulator));
575         }
576
577         /* Get the VSEL value for the given voltage */
578         err = twl_vreg_millivolt_to_vsel(sc, regulator, millivolts, &vsel);
579         if (err)
580                 return (err);
581
582         
583         /* Need to upgrade because writing the voltage and enabling should be atomic */
584         xlocked = sx_xlocked(&sc->sc_sx);
585         if (!xlocked)
586                 TWL_VREG_LOCK_UPGRADE(sc);
587
588
589         /* Set voltage and enable (atomically) */
590         err = twl_vreg_write_1(sc, regulator, TWL_VREG_VSEL, (vsel & 0x1f));
591         if (!err) {
592                 err = twl_vreg_enable_regulator(sc, regulator);
593         }
594
595         if (!xlocked)
596                 TWL_VREG_LOCK_DOWNGRADE(sc);
597
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);
601
602         return (err);
603 }
604
605 /**
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
610  *
611  *      LOCKING:
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
614  *      returning.
615  *
616  *      RETURNS:
617  *      Zero on success, or otherwise an error code.
618  */
619 static int
620 twl_vreg_read_regulator_voltage(struct twl_vreg_softc *sc,
621     struct twl_regulator_entry *regulator, int *millivolts)
622 {
623         int err;
624         int en = 0;
625         int xlocked;
626         uint8_t vsel;
627         
628         TWL_VREG_ASSERT_LOCKED(sc);
629         
630         /* Need to upgrade the lock because checking enabled state and voltage
631          * should be atomic.
632          */
633         xlocked = sx_xlocked(&sc->sc_sx);
634         if (!xlocked)
635                 TWL_VREG_LOCK_UPGRADE(sc);
636
637
638         /* Check if the regulator is currently enabled */
639         err = twl_vreg_is_regulator_enabled(sc, regulator, &en);
640         if (err)
641                 goto done;
642
643         *millivolts = 0;        
644         if (!en)
645                 goto done;
646
647
648         /* Not all voltages are adjustable */
649         if (regulator->supp_voltages == NULL || !regulator->num_supp_voltages) {
650                 *millivolts = regulator->fixed_voltage;
651                 goto done;
652         }
653
654         /* For variable voltages read the voltage register */
655         err = twl_vreg_read_1(sc, regulator, TWL_VREG_VSEL, &vsel);
656         if (err)
657                 goto done;
658
659         vsel &= (regulator->num_supp_voltages - 1);
660         if (regulator->supp_voltages[vsel] == UNDF) {
661                 err = EINVAL;
662                 goto done;
663         }
664
665         *millivolts = regulator->supp_voltages[vsel];
666
667 done:
668         if (!xlocked)
669                 TWL_VREG_LOCK_DOWNGRADE(sc);
670         
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);
674
675         return (err);
676 }
677
678 /**
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
683  *
684  *      If the regulator is disabled the function will set the @millivolts to zero.
685  *
686  *      LOCKING:
687  *      Internally the function takes and releases the TWL VREG lock.
688  *
689  *      RETURNS:
690  *      Zero on success or a negative error code on failure.
691  */
692 int
693 twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts)
694 {
695         struct twl_vreg_softc *sc;
696         struct twl_regulator_entry *regulator;
697         int err = EINVAL;
698
699         if (millivolts == NULL)
700                 return (EINVAL);
701
702         sc = device_get_softc(dev);
703
704         TWL_VREG_SLOCK(sc);
705
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);
709                         break;
710                 }
711         }
712
713         TWL_VREG_SUNLOCK(sc);
714
715         return (err);
716 }
717
718 /**
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
723  *
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.
728  *
729  *      LOCKING:
730  *      Internally the function takes and releases the TWL VREG lock.
731  *
732  *      RETURNS:
733  *      Zero on success or a negative error code on failure.
734  */
735 int
736 twl_vreg_set_voltage(device_t dev, const char *name, int millivolts)
737 {
738         struct twl_vreg_softc *sc;
739         struct twl_regulator_entry *regulator;
740         int err = EINVAL;
741
742         sc = device_get_softc(dev);
743
744         TWL_VREG_SLOCK(sc);
745
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);
749                         break;
750                 }
751         }
752
753         TWL_VREG_SUNLOCK(sc);
754
755         return (err);
756 }
757
758 /**
759  *      twl_sysctl_voltage - reads or writes the voltage for a regulator
760  *      @SYSCTL_HANDLER_ARGS: arguments for the callback
761  *
762  *      Callback for the sysctl entry for the regulator, simply used to return
763  *      the voltage on a particular regulator.
764  *
765  *      LOCKING:
766  *      Takes the TWL_VREG shared lock internally.
767  *
768  *      RETURNS:
769  *      Zero on success or an error code on failure.
770  */
771 static int
772 twl_vreg_sysctl_voltage(SYSCTL_HANDLER_ARGS)
773 {
774         struct twl_vreg_softc *sc = (struct twl_vreg_softc*)arg1;
775         struct twl_regulator_entry *regulator;
776         int voltage;
777         int found = 0;
778
779         TWL_VREG_SLOCK(sc);
780
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) {
784                         found = 1;
785                         break;
786                 }
787         }
788
789         /* Sanity check that we found the regulator */
790         if (!found) {
791                 TWL_VREG_SUNLOCK(sc);
792                 return (EINVAL);
793         }
794
795         twl_vreg_read_regulator_voltage(sc, regulator, &voltage);
796
797         TWL_VREG_SUNLOCK(sc);
798
799         return sysctl_handle_int(oidp, &voltage, 0, req);
800 }
801
802 /**
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
811  *
812  *      Adds a voltage regulator to the device and also a sysctl interface for the
813  *      regulator.
814  *
815  *      LOCKING:
816  *      The TWL_VEG exclusive lock must be held while this function is called.
817  *
818  *      RETURNS:
819  *      Pointer to the new regulator entry on success, otherwise on failure NULL.
820  */
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)
825 {
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;
829
830         new = malloc(sizeof(struct twl_regulator_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
831         if (new == NULL)
832                 return (NULL);
833
834
835         strncpy(new->name, name, TWL_VREG_MAX_NAMELEN);
836         new->name[TWL_VREG_MAX_NAMELEN - 1] = '\0';
837
838         new->sub_dev = nsub;
839         new->reg_off = regbase;
840
841         new->fixed_voltage = fixed_voltage;
842
843         new->supp_voltages = voltages;
844         new->num_supp_voltages = num_voltages;
845
846
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");
851
852         /* Finally add the regulator to list of supported regulators */
853         LIST_INSERT_HEAD(&sc->sc_vreg_list, new, entries);
854
855         return (new);
856 }
857
858 /**
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
863  *
864  *      Loops over the list of regulators and matches up with the FDT values,
865  *      adjusting the actual voltage based on the supplied values.
866  *
867  *      LOCKING:
868  *      The TWL_VEG exclusive lock must be held while this function is called.
869  *
870  *      RETURNS:
871  *      Always returns 0.
872  */
873 static int
874 twl_vreg_add_regulators(struct twl_vreg_softc *sc,
875         const struct twl_regulator *regulators)
876 {
877         int err;
878         int millivolts;
879         const struct twl_regulator *walker;
880         struct twl_regulator_entry *entry;
881         phandle_t child;
882         char rnames[256];
883         char *name, *voltage;
884         int len = 0, prop_len;
885
886
887         /* Add the regulators from the list */
888         walker = &regulators[0];
889         while (walker->name != NULL) {
890
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);
895                 if (entry == NULL)
896                         continue;
897
898                 walker++;
899         }
900
901
902         /* Check if the FDT is telling us to set any voltages */
903         child = ofw_bus_get_node(sc->sc_pdev);
904         if (child) {
905
906                 prop_len = OF_getprop(child, "voltage-regulators", rnames, sizeof(rnames));
907                 while (len < prop_len) {
908                         name = rnames + len;
909                         len += strlen(name) + 1;
910                         if ((len >= prop_len) || (name[0] == '\0'))
911                                 break;
912                         
913                         voltage = rnames + len;
914                         len += strlen(voltage) + 1;
915                         if (voltage[0] == '\0')
916                                 break;
917                         
918                         millivolts = strtoul(voltage, NULL, 0);
919                         
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);
923                                         break;
924                                 }
925                         }
926                 }
927         }
928         
929         
930         if (twl_vreg_debug) {
931                 LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
932                         err = twl_vreg_read_regulator_voltage(sc, entry, &millivolts);
933                         if (!err)
934                                 device_printf(sc->sc_dev, "%s : %d mV\n", entry->name, millivolts);
935                 }
936         }
937
938         return (0);
939 }
940
941 /**
942  *      twl_vreg_init - initialises the list of regulators
943  *      @dev: the twl_vreg device
944  *
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.
948  *
949  *      LOCKING:
950  *      Takes the exclusive lock in the function.
951  */
952 static void
953 twl_vreg_init(void *dev)
954 {
955         struct twl_vreg_softc *sc;
956
957         sc = device_get_softc((device_t)dev);
958
959         TWL_VREG_XLOCK(sc);
960
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);
965
966         TWL_VREG_XUNLOCK(sc);
967
968         config_intrhook_disestablish(&sc->sc_init_hook);
969 }
970
971 static int
972 twl_vreg_probe(device_t dev)
973 {
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");
979         else
980                 return (ENXIO);
981
982         return (0);
983 }
984
985 static int
986 twl_vreg_attach(device_t dev)
987 {
988         struct twl_vreg_softc *sc;
989
990         sc = device_get_softc(dev);
991         sc->sc_dev = dev;
992         sc->sc_pdev = device_get_parent(dev);
993
994         TWL_VREG_LOCK_INIT(sc);
995
996         LIST_INIT(&sc->sc_vreg_list);
997
998         /* We have to wait until interrupts are enabled. I2C read and write
999          * only works if the interrupts are available.
1000          */
1001         sc->sc_init_hook.ich_func = twl_vreg_init;
1002         sc->sc_init_hook.ich_arg = dev;
1003
1004         if (config_intrhook_establish(&sc->sc_init_hook) != 0)
1005                 return (ENOMEM);
1006
1007         return (0);
1008 }
1009
1010 static int
1011 twl_vreg_detach(device_t dev)
1012 {
1013         struct twl_vreg_softc *sc;
1014         struct twl_regulator_entry *regulator;
1015         struct twl_regulator_entry *tmp;
1016
1017         sc = device_get_softc(dev);
1018
1019         /* Take the lock and free all the added regulators */
1020         TWL_VREG_XLOCK(sc);
1021
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);
1026         }
1027
1028         TWL_VREG_XUNLOCK(sc);
1029
1030         TWL_VREG_LOCK_DESTROY(sc);
1031
1032         return (0);
1033 }
1034
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),
1039
1040         {0, 0},
1041 };
1042
1043 static driver_t twl_vreg_driver = {
1044         "twl_vreg",
1045         twl_vreg_methods,
1046         sizeof(struct twl_vreg_softc),
1047 };
1048
1049 static devclass_t twl_vreg_devclass;
1050
1051 DRIVER_MODULE(twl_vreg, twl, twl_vreg_driver, twl_vreg_devclass, 0, 0);
1052 MODULE_VERSION(twl_vreg, 1);