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