xref: /freebsd/sys/arm/ti/twl/twl_vreg.c (revision a9e8641da961bcf3d24afc85fd657f2083a872a2)
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 static const uint16_t twl4030_vdd1_voltages[] = {
142 	800, 1450
143 };
144 static const uint16_t twl4030_vdd2_voltages[] = {
145 	800, 1450, 1500
146 };
147 static const uint16_t twl4030_vio_voltages[] = {
148 	1800, 1850
149 };
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);
1053