xref: /freebsd/sys/arm/ti/twl/twl_vreg.c (revision 19fae0f66023a97a9b464b3beeeabb2081f575b3)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2011
5  *	Ben Gray <ben.r.gray@gmail.com>.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 /*
34  * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management.
35  *
36  * This driver covers the voltages regulators (LDO), allows for enabling &
37  * disabling the voltage output and adjusting the voltage level.
38  *
39  * Voltage regulators can belong to different power groups, in this driver we
40  * put the regulators under our control in the "Application power group".
41  *
42  *
43  * FLATTENED DEVICE TREE (FDT)
44  * Startup override settings can be specified in the FDT, if they are they
45  * should be under the twl parent device and take the following form:
46  *
47  *    voltage-regulators = "name1", "millivolts1",
48  *                         "name2", "millivolts2";
49  *
50  * Each override should be a pair, the first entry is the name of the regulator
51  * the second is the voltage (in millivolts) to set for the given regulator.
52  *
53  */
54 
55 #include <sys/param.h>
56 #include <sys/systm.h>
57 #include <sys/kernel.h>
58 #include <sys/lock.h>
59 #include <sys/module.h>
60 #include <sys/bus.h>
61 #include <sys/resource.h>
62 #include <sys/rman.h>
63 #include <sys/sysctl.h>
64 #include <sys/sx.h>
65 #include <sys/malloc.h>
66 
67 #include <machine/bus.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  * Power Groups bits for the 4030 and 6030 devices
81  */
82 #define TWL4030_P3_GRP		0x80	/* Peripherals, power group */
83 #define TWL4030_P2_GRP		0x40	/* Modem power group */
84 #define TWL4030_P1_GRP		0x20	/* Application power group (FreeBSD control) */
85 
86 #define TWL6030_P3_GRP		0x04	/* Modem power group */
87 #define TWL6030_P2_GRP		0x02	/* Connectivity power group */
88 #define TWL6030_P1_GRP		0x01	/* Application power group (FreeBSD control) */
89 
90 /*
91  * Register offsets within a LDO regulator register set
92  */
93 #define TWL_VREG_GRP		0x00	/* Regulator GRP register */
94 #define TWL_VREG_STATE		0x02
95 #define TWL_VREG_VSEL		0x03	/* Voltage select register */
96 
97 #define UNDF  0xFFFF
98 
99 static const uint16_t twl6030_voltages[] = {
100 	0000, 1000, 1100, 1200, 1300, 1400, 1500, 1600,
101 	1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400,
102 	2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200,
103 	3300, UNDF, UNDF, UNDF, UNDF, UNDF, UNDF, 2750
104 };
105 
106 static const uint16_t twl4030_vaux1_voltages[] = {
107 	1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
108 };
109 static const uint16_t twl4030_vaux2_voltages[] = {
110 	1700, 1700, 1900, 1300, 1500, 1800, 2000, 2500,
111 	2100, 2800, 2200, 2300, 2400, 2400, 2400, 2400
112 };
113 static const uint16_t twl4030_vaux3_voltages[] = {
114 	1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
115 };
116 static const uint16_t twl4030_vaux4_voltages[] = {
117 	700,  1000, 1200, 1300, 1500, 1800, 1850, 2500,
118 	2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
119 };
120 static const uint16_t twl4030_vmmc1_voltages[] = {
121 	1850, 2850, 3000, 3150
122 };
123 static const uint16_t twl4030_vmmc2_voltages[] = {
124 	1000, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
125 	2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
126 };
127 static const uint16_t twl4030_vpll1_voltages[] = {
128 	1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
129 };
130 static const uint16_t twl4030_vpll2_voltages[] = {
131 	700,  1000, 1200, 1300, 1500, 1800, 1850, 2500,
132 	2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
133 };
134 static const uint16_t twl4030_vsim_voltages[] = {
135 	1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
136 };
137 static const uint16_t twl4030_vdac_voltages[] = {
138 	1200, 1300, 1800, 1800
139 };
140 #if 0 /* vdd1, vdd2, vdio, not currently used. */
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 #endif
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 #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  *	twl_vreg_read_1 - read single register from the TWL device
252  *	twl_vreg_write_1 - write a single register in the TWL device
253  *	@sc: device context
254  *	@clk: the clock device we're reading from / writing to
255  *	@off: offset within the clock's register set
256  *	@val: the value to write or a pointer to a variable to store the result
257  *
258  *	RETURNS:
259  *	Zero on success or an error code on failure.
260  */
261 static inline int
262 twl_vreg_read_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
263 	uint8_t off, uint8_t *val)
264 {
265 	return (twl_read(sc->sc_pdev, regulator->sub_dev,
266 	    regulator->reg_off + off, val, 1));
267 }
268 
269 static inline int
270 twl_vreg_write_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
271 	uint8_t off, uint8_t val)
272 {
273 	return (twl_write(sc->sc_pdev, regulator->sub_dev,
274 	    regulator->reg_off + off, &val, 1));
275 }
276 
277 /**
278  *	twl_millivolt_to_vsel - gets the vsel bit value to write into the register
279  *	                        for a desired voltage and regulator
280  *	@sc: the device soft context
281  *	@regulator: pointer to the regulator device
282  *	@millivolts: the millivolts to find the bit value for
283  *	@vsel: upon return will contain the corresponding register value
284  *
285  *	Accepts a (milli)voltage value and tries to find the closest match to the
286  *	actual supported voltages for the given regulator.  If a match is found
287  *	within 100mv of the target, @vsel is written with the match and 0 is
288  *	returned. If no voltage match is found the function returns an non-zero
289  *	value.
290  *
291  *	RETURNS:
292  *	Zero on success or an error code on failure.
293  */
294 static int
295 twl_vreg_millivolt_to_vsel(struct twl_vreg_softc *sc,
296 	struct twl_regulator_entry *regulator, int millivolts, uint8_t *vsel)
297 {
298 	int delta, smallest_delta;
299 	unsigned i, closest_idx;
300 
301 	TWL_VREG_ASSERT_LOCKED(sc);
302 
303 	if (regulator->supp_voltages == NULL)
304 		return (EINVAL);
305 
306 	/* Loop over the support voltages and try and find the closest match */
307 	closest_idx = 0;
308 	smallest_delta = 0x7fffffff;
309 	for (i = 0; i < regulator->num_supp_voltages; i++) {
310 		/* Ignore undefined values */
311 		if (regulator->supp_voltages[i] == UNDF)
312 			continue;
313 
314 		/* Calculate the difference */
315 		delta = millivolts - (int)regulator->supp_voltages[i];
316 		if (abs(delta) < smallest_delta) {
317 			smallest_delta = abs(delta);
318 			closest_idx = i;
319 		}
320 	}
321 
322 	/* Check we got a voltage that was within 100mv of the actual target, this
323 	 * is just a value I picked out of thin air.
324 	 */
325 	if ((smallest_delta > 100) && (closest_idx < 0x100))
326 		return (EINVAL);
327 
328 	*vsel = closest_idx;
329 	return (0);
330 }
331 
332 /**
333  *	twl_vreg_is_regulator_enabled - returns the enabled status of the regulator
334  *	@sc: the device soft context
335  *	@regulator: pointer to the regulator device
336  *	@enabled: stores the enabled status, zero disabled, non-zero enabled
337  *
338  *	LOCKING:
339  *	On entry expects the TWL VREG lock to be held. Will upgrade the lock to
340  *	exclusive if not already but, if so, it will be downgraded again before
341  *	returning.
342  *
343  *	RETURNS:
344  *	Zero on success or an error code on failure.
345  */
346 static int
347 twl_vreg_is_regulator_enabled(struct twl_vreg_softc *sc,
348 	struct twl_regulator_entry *regulator, int *enabled)
349 {
350 	int err;
351 	uint8_t grp;
352 	uint8_t state;
353 	int xlocked;
354 
355 	if (enabled == NULL)
356 		return (EINVAL);
357 
358 	TWL_VREG_ASSERT_LOCKED(sc);
359 
360 	xlocked = sx_xlocked(&sc->sc_sx);
361 	if (!xlocked)
362 		TWL_VREG_LOCK_UPGRADE(sc);
363 
364 	/* The status reading is different for the different devices */
365 	if (twl_is_4030(sc->sc_pdev)) {
366 		err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &state);
367 		if (err)
368 			goto done;
369 
370 		*enabled = (state & TWL4030_P1_GRP);
371 
372 	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
373 		/* Check the regulator is in the application group */
374 		if (twl_is_6030(sc->sc_pdev)) {
375 			err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
376 			if (err)
377 				goto done;
378 
379 			if (!(grp & TWL6030_P1_GRP)) {
380 				*enabled = 0; /* disabled */
381 				goto done;
382 			}
383 		}
384 
385 		/* Read the application mode state and verify it's ON */
386 		err = twl_vreg_read_1(sc, regulator, TWL_VREG_STATE, &state);
387 		if (err)
388 			goto done;
389 
390 		*enabled = ((state & 0x0C) == 0x04);
391 
392 	} else {
393 		err = EINVAL;
394 	}
395 
396 done:
397 	if (!xlocked)
398 		TWL_VREG_LOCK_DOWNGRADE(sc);
399 
400 	return (err);
401 }
402 
403 /**
404  *	twl_vreg_disable_regulator - disables a voltage regulator
405  *	@sc: the device soft context
406  *	@regulator: pointer to the regulator device
407  *
408  *	Disables the regulator which will stop the output drivers.
409  *
410  *	LOCKING:
411  *	On entry expects the TWL VREG lock to be held. Will upgrade the lock to
412  *	exclusive if not already but, if so, it will be downgraded again before
413  *	returning.
414  *
415  *	RETURNS:
416  *	Zero on success or a positive error code on failure.
417  */
418 static int
419 twl_vreg_disable_regulator(struct twl_vreg_softc *sc,
420 	struct twl_regulator_entry *regulator)
421 {
422 	int err = 0;
423 	uint8_t grp;
424 	int xlocked;
425 
426 	TWL_VREG_ASSERT_LOCKED(sc);
427 
428 	xlocked = sx_xlocked(&sc->sc_sx);
429 	if (!xlocked)
430 		TWL_VREG_LOCK_UPGRADE(sc);
431 
432 	if (twl_is_4030(sc->sc_pdev)) {
433 		/* Read the regulator CFG_GRP register */
434 		err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
435 		if (err)
436 			goto done;
437 
438 		/* On the TWL4030 we just need to remove the regulator from all the
439 		 * power groups.
440 		 */
441 		grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
442 		err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
443 
444 	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
445 		/* On TWL6030 we need to make sure we disable power for all groups */
446 		if (twl_is_6030(sc->sc_pdev))
447 			grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP;
448 		else
449 			grp = 0x00;
450 
451 		/* Write the resource state to "OFF" */
452 		err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5));
453 	}
454 
455 done:
456 	if (!xlocked)
457 		TWL_VREG_LOCK_DOWNGRADE(sc);
458 
459 	return (err);
460 }
461 
462 /**
463  *	twl_vreg_enable_regulator - enables the voltage regulator
464  *	@sc: the device soft context
465  *	@regulator: pointer to the regulator device
466  *
467  *	Enables the regulator which will enable the voltage out at the currently
468  *	set voltage.  Set the voltage before calling this function to avoid
469  *	driving the voltage too high/low by mistake.
470  *
471  *	LOCKING:
472  *	On entry expects the TWL VREG lock to be held. Will upgrade the lock to
473  *	exclusive if not already but, if so, it will be downgraded again before
474  *	returning.
475  *
476  *	RETURNS:
477  *	Zero on success or a positive error code on failure.
478  */
479 static int
480 twl_vreg_enable_regulator(struct twl_vreg_softc *sc,
481     struct twl_regulator_entry *regulator)
482 {
483 	int err;
484 	uint8_t grp;
485 	int xlocked;
486 
487 	TWL_VREG_ASSERT_LOCKED(sc);
488 
489 	xlocked = sx_xlocked(&sc->sc_sx);
490 	if (!xlocked)
491 		TWL_VREG_LOCK_UPGRADE(sc);
492 
493 	err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
494 	if (err)
495 		goto done;
496 
497 	/* Enable the regulator by ensuring it's in the application power group
498 	 * and is in the "on" state.
499 	 */
500 	if (twl_is_4030(sc->sc_pdev)) {
501 		/* On the TWL4030 we just need to ensure the regulator is in the right
502 		 * power domain, don't need to turn on explicitly like TWL6030.
503 		 */
504 		grp |= TWL4030_P1_GRP;
505 		err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
506 
507 	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
508 		if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) {
509 			grp |= TWL6030_P1_GRP;
510 			err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
511 			if (err)
512 				goto done;
513 		}
514 
515 		/* Write the resource state to "ON" */
516 		err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5) | 0x01);
517 	}
518 
519 done:
520 	if (!xlocked)
521 		TWL_VREG_LOCK_DOWNGRADE(sc);
522 
523 	return (err);
524 }
525 
526 /**
527  *	twl_vreg_write_regulator_voltage - sets the voltage level on a regulator
528  *	@sc: the device soft context
529  *	@regulator: pointer to the regulator structure
530  *	@millivolts: the voltage to set
531  *
532  *	Sets the voltage output on a given regulator, if the regulator is not
533  *	enabled, it will be enabled.
534  *
535  *	LOCKING:
536  *	On entry expects the TWL VREG lock to be held, may upgrade the lock to
537  *	exclusive but if so it will be downgraded once again before returning.
538  *
539  *	RETURNS:
540  *	Zero on success or an error code on failure.
541  */
542 static int
543 twl_vreg_write_regulator_voltage(struct twl_vreg_softc *sc,
544     struct twl_regulator_entry *regulator, int millivolts)
545 {
546 	int err;
547 	uint8_t vsel;
548 	int xlocked;
549 
550 	TWL_VREG_ASSERT_LOCKED(sc);
551 
552 	/* If millivolts is zero then we simply disable the output */
553 	if (millivolts == 0)
554 		return (twl_vreg_disable_regulator(sc, regulator));
555 
556 	/* If the regulator has a fixed voltage then check the setting matches
557 	 * and simply enable.
558 	 */
559 	if (regulator->supp_voltages == NULL || regulator->num_supp_voltages == 0) {
560 		if (millivolts != regulator->fixed_voltage)
561 			return (EINVAL);
562 
563 		return (twl_vreg_enable_regulator(sc, regulator));
564 	}
565 
566 	/* Get the VSEL value for the given voltage */
567 	err = twl_vreg_millivolt_to_vsel(sc, regulator, millivolts, &vsel);
568 	if (err)
569 		return (err);
570 
571 	/* Need to upgrade because writing the voltage and enabling should be atomic */
572 	xlocked = sx_xlocked(&sc->sc_sx);
573 	if (!xlocked)
574 		TWL_VREG_LOCK_UPGRADE(sc);
575 
576 	/* Set voltage and enable (atomically) */
577 	err = twl_vreg_write_1(sc, regulator, TWL_VREG_VSEL, (vsel & 0x1f));
578 	if (!err) {
579 		err = twl_vreg_enable_regulator(sc, regulator);
580 	}
581 
582 	if (!xlocked)
583 		TWL_VREG_LOCK_DOWNGRADE(sc);
584 
585 	if ((twl_vreg_debug > 1) && !err)
586 		device_printf(sc->sc_dev, "%s : setting voltage to %dmV (vsel: 0x%x)\n",
587 		    regulator->name, millivolts, vsel);
588 
589 	return (err);
590 }
591 
592 /**
593  *	twl_vreg_read_regulator_voltage - reads the voltage on a given regulator
594  *	@sc: the device soft context
595  *	@regulator: pointer to the regulator structure
596  *	@millivolts: upon return will contain the voltage on the regulator
597  *
598  *	LOCKING:
599  *	On entry expects the TWL VREG lock to be held. It will upgrade the lock to
600  *	exclusive if not already, but if so, it will be downgraded again before
601  *	returning.
602  *
603  *	RETURNS:
604  *	Zero on success, or otherwise an error code.
605  */
606 static int
607 twl_vreg_read_regulator_voltage(struct twl_vreg_softc *sc,
608     struct twl_regulator_entry *regulator, int *millivolts)
609 {
610 	int err;
611 	int en = 0;
612 	int xlocked;
613 	uint8_t vsel;
614 
615 	TWL_VREG_ASSERT_LOCKED(sc);
616 
617 	/* Need to upgrade the lock because checking enabled state and voltage
618 	 * should be atomic.
619 	 */
620 	xlocked = sx_xlocked(&sc->sc_sx);
621 	if (!xlocked)
622 		TWL_VREG_LOCK_UPGRADE(sc);
623 
624 	/* Check if the regulator is currently enabled */
625 	err = twl_vreg_is_regulator_enabled(sc, regulator, &en);
626 	if (err)
627 		goto done;
628 
629 	*millivolts = 0;
630 	if (!en)
631 		goto done;
632 
633 	/* Not all voltages are adjustable */
634 	if (regulator->supp_voltages == NULL || !regulator->num_supp_voltages) {
635 		*millivolts = regulator->fixed_voltage;
636 		goto done;
637 	}
638 
639 	/* For variable voltages read the voltage register */
640 	err = twl_vreg_read_1(sc, regulator, TWL_VREG_VSEL, &vsel);
641 	if (err)
642 		goto done;
643 
644 	vsel &= (regulator->num_supp_voltages - 1);
645 	if (regulator->supp_voltages[vsel] == UNDF) {
646 		err = EINVAL;
647 		goto done;
648 	}
649 
650 	*millivolts = regulator->supp_voltages[vsel];
651 
652 done:
653 	if (!xlocked)
654 		TWL_VREG_LOCK_DOWNGRADE(sc);
655 
656 	if ((twl_vreg_debug > 1) && !err)
657 		device_printf(sc->sc_dev, "%s : reading voltage is %dmV (vsel: 0x%x)\n",
658 		    regulator->name, *millivolts, vsel);
659 
660 	return (err);
661 }
662 
663 /**
664  *	twl_vreg_get_voltage - public interface to read the voltage on a regulator
665  *	@dev: TWL VREG device
666  *	@name: the name of the regulator to read the voltage of
667  *	@millivolts: pointer to an integer that upon return will contain the mV
668  *
669  *	If the regulator is disabled the function will set the @millivolts to zero.
670  *
671  *	LOCKING:
672  *	Internally the function takes and releases the TWL VREG lock.
673  *
674  *	RETURNS:
675  *	Zero on success or a negative error code on failure.
676  */
677 int
678 twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts)
679 {
680 	struct twl_vreg_softc *sc;
681 	struct twl_regulator_entry *regulator;
682 	int err = EINVAL;
683 
684 	if (millivolts == NULL)
685 		return (EINVAL);
686 
687 	sc = device_get_softc(dev);
688 
689 	TWL_VREG_SLOCK(sc);
690 
691 	LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
692 		if (strcmp(regulator->name, name) == 0) {
693 			err = twl_vreg_read_regulator_voltage(sc, regulator, millivolts);
694 			break;
695 		}
696 	}
697 
698 	TWL_VREG_SUNLOCK(sc);
699 
700 	return (err);
701 }
702 
703 /**
704  *	twl_vreg_set_voltage - public interface to write the voltage on a regulator
705  *	@dev: TWL VREG device
706  *	@name: the name of the regulator to read the voltage of
707  *	@millivolts: the voltage to set in millivolts
708  *
709  *	Sets the output voltage on a given regulator. If the regulator is a fixed
710  *	voltage reg then the @millivolts value should match the fixed voltage. If
711  *	a variable regulator then the @millivolt value must fit within the max/min
712  *	range of the given regulator.
713  *
714  *	LOCKING:
715  *	Internally the function takes and releases the TWL VREG lock.
716  *
717  *	RETURNS:
718  *	Zero on success or a negative error code on failure.
719  */
720 int
721 twl_vreg_set_voltage(device_t dev, const char *name, int millivolts)
722 {
723 	struct twl_vreg_softc *sc;
724 	struct twl_regulator_entry *regulator;
725 	int err = EINVAL;
726 
727 	sc = device_get_softc(dev);
728 
729 	TWL_VREG_SLOCK(sc);
730 
731 	LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
732 		if (strcmp(regulator->name, name) == 0) {
733 			err = twl_vreg_write_regulator_voltage(sc, regulator, millivolts);
734 			break;
735 		}
736 	}
737 
738 	TWL_VREG_SUNLOCK(sc);
739 
740 	return (err);
741 }
742 
743 /**
744  *	twl_sysctl_voltage - reads or writes the voltage for a regulator
745  *	@SYSCTL_HANDLER_ARGS: arguments for the callback
746  *
747  *	Callback for the sysctl entry for the regulator, simply used to return
748  *	the voltage on a particular regulator.
749  *
750  *	LOCKING:
751  *	Takes the TWL_VREG shared lock internally.
752  *
753  *	RETURNS:
754  *	Zero on success or an error code on failure.
755  */
756 static int
757 twl_vreg_sysctl_voltage(SYSCTL_HANDLER_ARGS)
758 {
759 	struct twl_vreg_softc *sc = (struct twl_vreg_softc*)arg1;
760 	struct twl_regulator_entry *regulator;
761 	int voltage;
762 	int found = 0;
763 
764 	TWL_VREG_SLOCK(sc);
765 
766 	/* Find the regulator with the matching name */
767 	LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
768 		if (strcmp(regulator->name, oidp->oid_name) == 0) {
769 			found = 1;
770 			break;
771 		}
772 	}
773 
774 	/* Sanity check that we found the regulator */
775 	if (!found) {
776 		TWL_VREG_SUNLOCK(sc);
777 		return (EINVAL);
778 	}
779 
780 	twl_vreg_read_regulator_voltage(sc, regulator, &voltage);
781 
782 	TWL_VREG_SUNLOCK(sc);
783 
784 	return sysctl_handle_int(oidp, &voltage, 0, req);
785 }
786 
787 /**
788  *	twl_add_regulator - adds single voltage regulator sysctls for the device
789  *	@sc: device soft context
790  *	@name: the name of the regulator
791  *	@nsub: the number of the subdevice
792  *	@regbase: the base address of the voltage regulator registers
793  *	@fixed_voltage: if a fixed voltage regulator this defines it's voltage
794  *	@voltages: if a variable voltage regulator, an array of possible voltages
795  *	@num_voltages: the number of entries @voltages
796  *
797  *	Adds a voltage regulator to the device and also a sysctl interface for the
798  *	regulator.
799  *
800  *	LOCKING:
801  *	The TWL_VEG exclusive lock must be held while this function is called.
802  *
803  *	RETURNS:
804  *	Pointer to the new regulator entry on success, otherwise on failure NULL.
805  */
806 static struct twl_regulator_entry*
807 twl_vreg_add_regulator(struct twl_vreg_softc *sc, const char *name,
808 	uint8_t nsub, uint8_t regbase, uint16_t fixed_voltage,
809 	const uint16_t *voltages, uint32_t num_voltages)
810 {
811 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
812 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
813 	struct twl_regulator_entry *new;
814 
815 	new = malloc(sizeof(struct twl_regulator_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
816 	if (new == NULL)
817 		return (NULL);
818 
819 	strncpy(new->name, name, TWL_VREG_MAX_NAMELEN);
820 	new->name[TWL_VREG_MAX_NAMELEN - 1] = '\0';
821 
822 	new->sub_dev = nsub;
823 	new->reg_off = regbase;
824 
825 	new->fixed_voltage = fixed_voltage;
826 
827 	new->supp_voltages = voltages;
828 	new->num_supp_voltages = num_voltages;
829 
830 	/* Add a sysctl entry for the voltage */
831 	new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name,
832 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
833 	    twl_vreg_sysctl_voltage, "I", "voltage regulator");
834 
835 	/* Finally add the regulator to list of supported regulators */
836 	LIST_INSERT_HEAD(&sc->sc_vreg_list, new, entries);
837 
838 	return (new);
839 }
840 
841 /**
842  *	twl_vreg_add_regulators - adds any voltage regulators to the device
843  *	@sc: device soft context
844  *	@chip: the name of the chip used in the hints
845  *	@regulators: the list of possible voltage regulators
846  *
847  *	Loops over the list of regulators and matches up with the FDT values,
848  *	adjusting the actual voltage based on the supplied values.
849  *
850  *	LOCKING:
851  *	The TWL_VEG exclusive lock must be held while this function is called.
852  *
853  *	RETURNS:
854  *	Always returns 0.
855  */
856 static int
857 twl_vreg_add_regulators(struct twl_vreg_softc *sc,
858 	const struct twl_regulator *regulators)
859 {
860 	int err;
861 	int millivolts;
862 	const struct twl_regulator *walker;
863 	struct twl_regulator_entry *entry;
864 	phandle_t child;
865 	char rnames[256];
866 	char *name, *voltage;
867 	int len = 0, prop_len;
868 
869 	/* Add the regulators from the list */
870 	walker = &regulators[0];
871 	while (walker->name != NULL) {
872 		/* Add the regulator to the list */
873 		entry = twl_vreg_add_regulator(sc, walker->name, walker->subdev,
874 		    walker->regbase, walker->fixedvoltage,
875 		    walker->voltages, walker->num_voltages);
876 		if (entry == NULL)
877 			continue;
878 
879 		walker++;
880 	}
881 
882 	/* Check if the FDT is telling us to set any voltages */
883 	child = ofw_bus_get_node(sc->sc_pdev);
884 	if (child) {
885 		prop_len = OF_getprop(child, "voltage-regulators", rnames, sizeof(rnames));
886 		while (len < prop_len) {
887 			name = rnames + len;
888 			len += strlen(name) + 1;
889 			if ((len >= prop_len) || (name[0] == '\0'))
890 				break;
891 
892 			voltage = rnames + len;
893 			len += strlen(voltage) + 1;
894 			if (voltage[0] == '\0')
895 				break;
896 
897 			millivolts = strtoul(voltage, NULL, 0);
898 
899 			LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
900 				if (strcmp(entry->name, name) == 0) {
901 					twl_vreg_write_regulator_voltage(sc, entry, millivolts);
902 					break;
903 				}
904 			}
905 		}
906 	}
907 
908 	if (twl_vreg_debug) {
909 		LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
910 			err = twl_vreg_read_regulator_voltage(sc, entry, &millivolts);
911 			if (!err)
912 				device_printf(sc->sc_dev, "%s : %d mV\n", entry->name, millivolts);
913 		}
914 	}
915 
916 	return (0);
917 }
918 
919 /**
920  *	twl_vreg_init - initialises the list of regulators
921  *	@dev: the twl_vreg device
922  *
923  *	This function is called as an intrhook once interrupts have been enabled,
924  *	this is done so that the driver has the option to enable/disable or set
925  *	the voltage level based on settings providied in the FDT.
926  *
927  *	LOCKING:
928  *	Takes the exclusive lock in the function.
929  */
930 static void
931 twl_vreg_init(void *dev)
932 {
933 	struct twl_vreg_softc *sc;
934 
935 	sc = device_get_softc((device_t)dev);
936 
937 	TWL_VREG_XLOCK(sc);
938 
939 	if (twl_is_4030(sc->sc_pdev))
940 		twl_vreg_add_regulators(sc, twl4030_regulators);
941 	else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev))
942 		twl_vreg_add_regulators(sc, twl6030_regulators);
943 
944 	TWL_VREG_XUNLOCK(sc);
945 
946 	config_intrhook_disestablish(&sc->sc_init_hook);
947 }
948 
949 static int
950 twl_vreg_probe(device_t dev)
951 {
952 	if (twl_is_4030(device_get_parent(dev)))
953 		device_set_desc(dev, "TI TWL4030 PMIC Voltage Regulators");
954 	else if (twl_is_6025(device_get_parent(dev)) ||
955 	         twl_is_6030(device_get_parent(dev)))
956 		device_set_desc(dev, "TI TWL6025/TWL6030 PMIC Voltage Regulators");
957 	else
958 		return (ENXIO);
959 
960 	return (0);
961 }
962 
963 static int
964 twl_vreg_attach(device_t dev)
965 {
966 	struct twl_vreg_softc *sc;
967 
968 	sc = device_get_softc(dev);
969 	sc->sc_dev = dev;
970 	sc->sc_pdev = device_get_parent(dev);
971 
972 	TWL_VREG_LOCK_INIT(sc);
973 
974 	LIST_INIT(&sc->sc_vreg_list);
975 
976 	/* We have to wait until interrupts are enabled. I2C read and write
977 	 * only works if the interrupts are available.
978 	 */
979 	sc->sc_init_hook.ich_func = twl_vreg_init;
980 	sc->sc_init_hook.ich_arg = dev;
981 
982 	if (config_intrhook_establish(&sc->sc_init_hook) != 0)
983 		return (ENOMEM);
984 
985 	return (0);
986 }
987 
988 static int
989 twl_vreg_detach(device_t dev)
990 {
991 	struct twl_vreg_softc *sc;
992 	struct twl_regulator_entry *regulator;
993 	struct twl_regulator_entry *tmp;
994 
995 	sc = device_get_softc(dev);
996 
997 	/* Take the lock and free all the added regulators */
998 	TWL_VREG_XLOCK(sc);
999 
1000 	LIST_FOREACH_SAFE(regulator, &sc->sc_vreg_list, entries, tmp) {
1001 		LIST_REMOVE(regulator, entries);
1002 		sysctl_remove_oid(regulator->oid, 1, 0);
1003 		free(regulator, M_DEVBUF);
1004 	}
1005 
1006 	TWL_VREG_XUNLOCK(sc);
1007 
1008 	TWL_VREG_LOCK_DESTROY(sc);
1009 
1010 	return (0);
1011 }
1012 
1013 static device_method_t twl_vreg_methods[] = {
1014 	DEVMETHOD(device_probe,		twl_vreg_probe),
1015 	DEVMETHOD(device_attach,	twl_vreg_attach),
1016 	DEVMETHOD(device_detach,	twl_vreg_detach),
1017 
1018 	{0, 0},
1019 };
1020 
1021 static driver_t twl_vreg_driver = {
1022 	"twl_vreg",
1023 	twl_vreg_methods,
1024 	sizeof(struct twl_vreg_softc),
1025 };
1026 
1027 DRIVER_MODULE(twl_vreg, twl, twl_vreg_driver, 0, 0);
1028 MODULE_VERSION(twl_vreg, 1);
1029