xref: /freebsd/sys/arm/ti/twl/twl_vreg.c (revision aa77200569e397d6ff1fdb4d255d0fa254d0a128)
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);
1054