xref: /freebsd/sys/arm/ti/twl/twl_vreg.c (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
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 /*
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  * Power Groups bits for the 4030 and 6030 devices
79  */
80 #define TWL4030_P3_GRP		0x80	/* Peripherals, power group */
81 #define TWL4030_P2_GRP		0x40	/* Modem power group */
82 #define TWL4030_P1_GRP		0x20	/* Application power group (FreeBSD control) */
83 
84 #define TWL6030_P3_GRP		0x04	/* Modem power group */
85 #define TWL6030_P2_GRP		0x02	/* Connectivity power group */
86 #define TWL6030_P1_GRP		0x01	/* Application power group (FreeBSD control) */
87 
88 /*
89  * Register offsets within a LDO regulator register set
90  */
91 #define TWL_VREG_GRP		0x00	/* Regulator GRP register */
92 #define TWL_VREG_STATE		0x02
93 #define TWL_VREG_VSEL		0x03	/* Voltage select register */
94 
95 #define UNDF  0xFFFF
96 
97 static const uint16_t twl6030_voltages[] = {
98 	0000, 1000, 1100, 1200, 1300, 1400, 1500, 1600,
99 	1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400,
100 	2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200,
101 	3300, UNDF, UNDF, UNDF, UNDF, UNDF, UNDF, 2750
102 };
103 
104 static const uint16_t twl4030_vaux1_voltages[] = {
105 	1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
106 };
107 static const uint16_t twl4030_vaux2_voltages[] = {
108 	1700, 1700, 1900, 1300, 1500, 1800, 2000, 2500,
109 	2100, 2800, 2200, 2300, 2400, 2400, 2400, 2400
110 };
111 static const uint16_t twl4030_vaux3_voltages[] = {
112 	1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
113 };
114 static const uint16_t twl4030_vaux4_voltages[] = {
115 	700,  1000, 1200, 1300, 1500, 1800, 1850, 2500,
116 	2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
117 };
118 static const uint16_t twl4030_vmmc1_voltages[] = {
119 	1850, 2850, 3000, 3150
120 };
121 static const uint16_t twl4030_vmmc2_voltages[] = {
122 	1000, 1000, 1200, 1300, 1500, 1800, 1850, 2500,
123 	2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
124 };
125 static const uint16_t twl4030_vpll1_voltages[] = {
126 	1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
127 };
128 static const uint16_t twl4030_vpll2_voltages[] = {
129 	700,  1000, 1200, 1300, 1500, 1800, 1850, 2500,
130 	2600, 2800, 2850, 3000, 3150, 3150, 3150, 3150
131 };
132 static const uint16_t twl4030_vsim_voltages[] = {
133 	1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
134 };
135 static const uint16_t twl4030_vdac_voltages[] = {
136 	1200, 1300, 1800, 1800
137 };
138 #if 0 /* vdd1, vdd2, vdio, not currently used. */
139 static const uint16_t twl4030_vdd1_voltages[] = {
140 	800, 1450
141 };
142 static const uint16_t twl4030_vdd2_voltages[] = {
143 	800, 1450, 1500
144 };
145 static const uint16_t twl4030_vio_voltages[] = {
146 	1800, 1850
147 };
148 #endif
149 static const uint16_t twl4030_vintana2_voltages[] = {
150 	2500, 2750
151 };
152 
153 /**
154  *  Support voltage regulators for the different IC's
155  */
156 struct twl_regulator {
157 	const char	*name;
158 	uint8_t		subdev;
159 	uint8_t		regbase;
160 
161 	uint16_t	fixedvoltage;
162 
163 	const uint16_t	*voltages;
164 	uint32_t	num_voltages;
165 };
166 
167 #define TWL_REGULATOR_ADJUSTABLE(name, subdev, reg, voltages) \
168 	{ name, subdev, reg, 0, voltages, (sizeof(voltages)/sizeof(voltages[0])) }
169 #define TWL_REGULATOR_FIXED(name, subdev, reg, voltage) \
170 	{ name, subdev, reg, voltage, NULL, 0 }
171 
172 static const struct twl_regulator twl4030_regulators[] = {
173 	TWL_REGULATOR_ADJUSTABLE("vaux1",    0, 0x17, twl4030_vaux1_voltages),
174 	TWL_REGULATOR_ADJUSTABLE("vaux2",    0, 0x1B, twl4030_vaux2_voltages),
175 	TWL_REGULATOR_ADJUSTABLE("vaux3",    0, 0x1F, twl4030_vaux3_voltages),
176 	TWL_REGULATOR_ADJUSTABLE("vaux4",    0, 0x23, twl4030_vaux4_voltages),
177 	TWL_REGULATOR_ADJUSTABLE("vmmc1",    0, 0x27, twl4030_vmmc1_voltages),
178 	TWL_REGULATOR_ADJUSTABLE("vmmc2",    0, 0x2B, twl4030_vmmc2_voltages),
179 	TWL_REGULATOR_ADJUSTABLE("vpll1",    0, 0x2F, twl4030_vpll1_voltages),
180 	TWL_REGULATOR_ADJUSTABLE("vpll2",    0, 0x33, twl4030_vpll2_voltages),
181 	TWL_REGULATOR_ADJUSTABLE("vsim",     0, 0x37, twl4030_vsim_voltages),
182 	TWL_REGULATOR_ADJUSTABLE("vdac",     0, 0x3B, twl4030_vdac_voltages),
183 	TWL_REGULATOR_ADJUSTABLE("vintana2", 0, 0x43, twl4030_vintana2_voltages),
184 	TWL_REGULATOR_FIXED("vintana1", 0, 0x3F, 1500),
185 	TWL_REGULATOR_FIXED("vintdig",  0, 0x47, 1500),
186 	TWL_REGULATOR_FIXED("vusb1v5",  0, 0x71, 1500),
187 	TWL_REGULATOR_FIXED("vusb1v8",  0, 0x74, 1800),
188 	TWL_REGULATOR_FIXED("vusb3v1",  0, 0x77, 3100),
189 	{ NULL, 0, 0x00, 0, NULL, 0 }
190 };
191 
192 static const struct twl_regulator twl6030_regulators[] = {
193 	TWL_REGULATOR_ADJUSTABLE("vaux1", 0, 0x84, twl6030_voltages),
194 	TWL_REGULATOR_ADJUSTABLE("vaux2", 0, 0x89, twl6030_voltages),
195 	TWL_REGULATOR_ADJUSTABLE("vaux3", 0, 0x8C, twl6030_voltages),
196 	TWL_REGULATOR_ADJUSTABLE("vmmc",  0, 0x98, twl6030_voltages),
197 	TWL_REGULATOR_ADJUSTABLE("vpp",   0, 0x9C, twl6030_voltages),
198 	TWL_REGULATOR_ADJUSTABLE("vusim", 0, 0xA4, twl6030_voltages),
199 	TWL_REGULATOR_FIXED("vmem",  0, 0x64, 1800),
200 	TWL_REGULATOR_FIXED("vusb",  0, 0xA0, 3300),
201 	TWL_REGULATOR_FIXED("v1v8",  0, 0x46, 1800),
202 	TWL_REGULATOR_FIXED("v2v1",  0, 0x4C, 2100),
203 	TWL_REGULATOR_FIXED("v1v29", 0, 0x40, 1290),
204 	TWL_REGULATOR_FIXED("vcxio", 0, 0x90, 1800),
205 	TWL_REGULATOR_FIXED("vdac",  0, 0x94, 1800),
206 	TWL_REGULATOR_FIXED("vana",  0, 0x80, 2100),
207 	{ NULL, 0, 0x00, 0, NULL, 0 }
208 };
209 
210 #define TWL_VREG_MAX_NAMELEN  32
211 
212 struct twl_regulator_entry {
213 	LIST_ENTRY(twl_regulator_entry) entries;
214 	char                 name[TWL_VREG_MAX_NAMELEN];
215 	struct sysctl_oid   *oid;
216 	uint8_t          sub_dev;           /* TWL sub-device group */
217 	uint8_t          reg_off;           /* base register offset for the LDO */
218 	uint16_t         fixed_voltage;	    /* the (milli)voltage if LDO is fixed */
219 	const uint16_t  *supp_voltages;     /* pointer to an array of possible voltages */
220 	uint32_t         num_supp_voltages; /* the number of supplied voltages */
221 };
222 
223 struct twl_vreg_softc {
224 	device_t        sc_dev;
225 	device_t        sc_pdev;
226 	struct sx       sc_sx;
227 
228 	struct intr_config_hook sc_init_hook;
229 	LIST_HEAD(twl_regulator_list, twl_regulator_entry) sc_vreg_list;
230 };
231 
232 #define TWL_VREG_XLOCK(_sc)			sx_xlock(&(_sc)->sc_sx)
233 #define	TWL_VREG_XUNLOCK(_sc)		sx_xunlock(&(_sc)->sc_sx)
234 #define TWL_VREG_SLOCK(_sc)			sx_slock(&(_sc)->sc_sx)
235 #define	TWL_VREG_SUNLOCK(_sc)		sx_sunlock(&(_sc)->sc_sx)
236 #define TWL_VREG_LOCK_INIT(_sc)		sx_init(&(_sc)->sc_sx, "twl_vreg")
237 #define TWL_VREG_LOCK_DESTROY(_sc)	sx_destroy(&(_sc)->sc_sx);
238 
239 #define TWL_VREG_ASSERT_LOCKED(_sc)	sx_assert(&(_sc)->sc_sx, SA_LOCKED);
240 
241 #define TWL_VREG_LOCK_UPGRADE(_sc)               \
242 	do {                                         \
243 		while (!sx_try_upgrade(&(_sc)->sc_sx))   \
244 			pause("twl_vreg_ex", (hz / 100));    \
245 	} while(0)
246 #define TWL_VREG_LOCK_DOWNGRADE(_sc)	sx_downgrade(&(_sc)->sc_sx);
247 
248 /**
249  *	twl_vreg_read_1 - read single register from the TWL device
250  *	twl_vreg_write_1 - write a single register in the TWL device
251  *	@sc: device context
252  *	@clk: the clock device we're reading from / writing to
253  *	@off: offset within the clock's register set
254  *	@val: the value to write or a pointer to a variable to store the result
255  *
256  *	RETURNS:
257  *	Zero on success or an error code on failure.
258  */
259 static inline int
260 twl_vreg_read_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
261 	uint8_t off, uint8_t *val)
262 {
263 	return (twl_read(sc->sc_pdev, regulator->sub_dev,
264 	    regulator->reg_off + off, val, 1));
265 }
266 
267 static inline int
268 twl_vreg_write_1(struct twl_vreg_softc *sc, struct twl_regulator_entry *regulator,
269 	uint8_t off, uint8_t val)
270 {
271 	return (twl_write(sc->sc_pdev, regulator->sub_dev,
272 	    regulator->reg_off + off, &val, 1));
273 }
274 
275 /**
276  *	twl_millivolt_to_vsel - gets the vsel bit value to write into the register
277  *	                        for a desired voltage and regulator
278  *	@sc: the device soft context
279  *	@regulator: pointer to the regulator device
280  *	@millivolts: the millivolts to find the bit value for
281  *	@vsel: upon return will contain the corresponding register value
282  *
283  *	Accepts a (milli)voltage value and tries to find the closest match to the
284  *	actual supported voltages for the given regulator.  If a match is found
285  *	within 100mv of the target, @vsel is written with the match and 0 is
286  *	returned. If no voltage match is found the function returns an non-zero
287  *	value.
288  *
289  *	RETURNS:
290  *	Zero on success or an error code on failure.
291  */
292 static int
293 twl_vreg_millivolt_to_vsel(struct twl_vreg_softc *sc,
294 	struct twl_regulator_entry *regulator, int millivolts, uint8_t *vsel)
295 {
296 	int delta, smallest_delta;
297 	unsigned i, closest_idx;
298 
299 	TWL_VREG_ASSERT_LOCKED(sc);
300 
301 	if (regulator->supp_voltages == NULL)
302 		return (EINVAL);
303 
304 	/* Loop over the support voltages and try and find the closest match */
305 	closest_idx = 0;
306 	smallest_delta = 0x7fffffff;
307 	for (i = 0; i < regulator->num_supp_voltages; i++) {
308 		/* Ignore undefined values */
309 		if (regulator->supp_voltages[i] == UNDF)
310 			continue;
311 
312 		/* Calculate the difference */
313 		delta = millivolts - (int)regulator->supp_voltages[i];
314 		if (abs(delta) < smallest_delta) {
315 			smallest_delta = abs(delta);
316 			closest_idx = i;
317 		}
318 	}
319 
320 	/* Check we got a voltage that was within 100mv of the actual target, this
321 	 * is just a value I picked out of thin air.
322 	 */
323 	if ((smallest_delta > 100) && (closest_idx < 0x100))
324 		return (EINVAL);
325 
326 	*vsel = closest_idx;
327 	return (0);
328 }
329 
330 /**
331  *	twl_vreg_is_regulator_enabled - returns the enabled status of the regulator
332  *	@sc: the device soft context
333  *	@regulator: pointer to the regulator device
334  *	@enabled: stores the enabled status, zero disabled, non-zero enabled
335  *
336  *	LOCKING:
337  *	On entry expects the TWL VREG lock to be held. Will upgrade the lock to
338  *	exclusive if not already but, if so, it will be downgraded again before
339  *	returning.
340  *
341  *	RETURNS:
342  *	Zero on success or an error code on failure.
343  */
344 static int
345 twl_vreg_is_regulator_enabled(struct twl_vreg_softc *sc,
346 	struct twl_regulator_entry *regulator, int *enabled)
347 {
348 	int err;
349 	uint8_t grp;
350 	uint8_t state;
351 	int xlocked;
352 
353 	if (enabled == NULL)
354 		return (EINVAL);
355 
356 	TWL_VREG_ASSERT_LOCKED(sc);
357 
358 	xlocked = sx_xlocked(&sc->sc_sx);
359 	if (!xlocked)
360 		TWL_VREG_LOCK_UPGRADE(sc);
361 
362 	/* The status reading is different for the different devices */
363 	if (twl_is_4030(sc->sc_pdev)) {
364 		err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &state);
365 		if (err)
366 			goto done;
367 
368 		*enabled = (state & TWL4030_P1_GRP);
369 
370 	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
371 		/* Check the regulator is in the application group */
372 		if (twl_is_6030(sc->sc_pdev)) {
373 			err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
374 			if (err)
375 				goto done;
376 
377 			if (!(grp & TWL6030_P1_GRP)) {
378 				*enabled = 0; /* disabled */
379 				goto done;
380 			}
381 		}
382 
383 		/* Read the application mode state and verify it's ON */
384 		err = twl_vreg_read_1(sc, regulator, TWL_VREG_STATE, &state);
385 		if (err)
386 			goto done;
387 
388 		*enabled = ((state & 0x0C) == 0x04);
389 
390 	} else {
391 		err = EINVAL;
392 	}
393 
394 done:
395 	if (!xlocked)
396 		TWL_VREG_LOCK_DOWNGRADE(sc);
397 
398 	return (err);
399 }
400 
401 /**
402  *	twl_vreg_disable_regulator - disables a voltage regulator
403  *	@sc: the device soft context
404  *	@regulator: pointer to the regulator device
405  *
406  *	Disables the regulator which will stop the output drivers.
407  *
408  *	LOCKING:
409  *	On entry expects the TWL VREG lock to be held. Will upgrade the lock to
410  *	exclusive if not already but, if so, it will be downgraded again before
411  *	returning.
412  *
413  *	RETURNS:
414  *	Zero on success or a positive error code on failure.
415  */
416 static int
417 twl_vreg_disable_regulator(struct twl_vreg_softc *sc,
418 	struct twl_regulator_entry *regulator)
419 {
420 	int err = 0;
421 	uint8_t grp;
422 	int xlocked;
423 
424 	TWL_VREG_ASSERT_LOCKED(sc);
425 
426 	xlocked = sx_xlocked(&sc->sc_sx);
427 	if (!xlocked)
428 		TWL_VREG_LOCK_UPGRADE(sc);
429 
430 	if (twl_is_4030(sc->sc_pdev)) {
431 		/* Read the regulator CFG_GRP register */
432 		err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
433 		if (err)
434 			goto done;
435 
436 		/* On the TWL4030 we just need to remove the regulator from all the
437 		 * power groups.
438 		 */
439 		grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
440 		err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
441 
442 	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
443 		/* On TWL6030 we need to make sure we disable power for all groups */
444 		if (twl_is_6030(sc->sc_pdev))
445 			grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP;
446 		else
447 			grp = 0x00;
448 
449 		/* Write the resource state to "OFF" */
450 		err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5));
451 	}
452 
453 done:
454 	if (!xlocked)
455 		TWL_VREG_LOCK_DOWNGRADE(sc);
456 
457 	return (err);
458 }
459 
460 /**
461  *	twl_vreg_enable_regulator - enables the voltage regulator
462  *	@sc: the device soft context
463  *	@regulator: pointer to the regulator device
464  *
465  *	Enables the regulator which will enable the voltage out at the currently
466  *	set voltage.  Set the voltage before calling this function to avoid
467  *	driving the voltage too high/low by mistake.
468  *
469  *	LOCKING:
470  *	On entry expects the TWL VREG lock to be held. Will upgrade the lock to
471  *	exclusive if not already but, if so, it will be downgraded again before
472  *	returning.
473  *
474  *	RETURNS:
475  *	Zero on success or a positive error code on failure.
476  */
477 static int
478 twl_vreg_enable_regulator(struct twl_vreg_softc *sc,
479     struct twl_regulator_entry *regulator)
480 {
481 	int err;
482 	uint8_t grp;
483 	int xlocked;
484 
485 	TWL_VREG_ASSERT_LOCKED(sc);
486 
487 	xlocked = sx_xlocked(&sc->sc_sx);
488 	if (!xlocked)
489 		TWL_VREG_LOCK_UPGRADE(sc);
490 
491 	err = twl_vreg_read_1(sc, regulator, TWL_VREG_GRP, &grp);
492 	if (err)
493 		goto done;
494 
495 	/* Enable the regulator by ensuring it's in the application power group
496 	 * and is in the "on" state.
497 	 */
498 	if (twl_is_4030(sc->sc_pdev)) {
499 		/* On the TWL4030 we just need to ensure the regulator is in the right
500 		 * power domain, don't need to turn on explicitly like TWL6030.
501 		 */
502 		grp |= TWL4030_P1_GRP;
503 		err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
504 
505 	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
506 		if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) {
507 			grp |= TWL6030_P1_GRP;
508 			err = twl_vreg_write_1(sc, regulator, TWL_VREG_GRP, grp);
509 			if (err)
510 				goto done;
511 		}
512 
513 		/* Write the resource state to "ON" */
514 		err = twl_vreg_write_1(sc, regulator, TWL_VREG_STATE, (grp << 5) | 0x01);
515 	}
516 
517 done:
518 	if (!xlocked)
519 		TWL_VREG_LOCK_DOWNGRADE(sc);
520 
521 	return (err);
522 }
523 
524 /**
525  *	twl_vreg_write_regulator_voltage - sets the voltage level on a regulator
526  *	@sc: the device soft context
527  *	@regulator: pointer to the regulator structure
528  *	@millivolts: the voltage to set
529  *
530  *	Sets the voltage output on a given regulator, if the regulator is not
531  *	enabled, it will be enabled.
532  *
533  *	LOCKING:
534  *	On entry expects the TWL VREG lock to be held, may upgrade the lock to
535  *	exclusive but if so it will be downgraded once again before returning.
536  *
537  *	RETURNS:
538  *	Zero on success or an error code on failure.
539  */
540 static int
541 twl_vreg_write_regulator_voltage(struct twl_vreg_softc *sc,
542     struct twl_regulator_entry *regulator, int millivolts)
543 {
544 	int err;
545 	uint8_t vsel;
546 	int xlocked;
547 
548 	TWL_VREG_ASSERT_LOCKED(sc);
549 
550 	/* If millivolts is zero then we simply disable the output */
551 	if (millivolts == 0)
552 		return (twl_vreg_disable_regulator(sc, regulator));
553 
554 	/* If the regulator has a fixed voltage then check the setting matches
555 	 * and simply enable.
556 	 */
557 	if (regulator->supp_voltages == NULL || regulator->num_supp_voltages == 0) {
558 		if (millivolts != regulator->fixed_voltage)
559 			return (EINVAL);
560 
561 		return (twl_vreg_enable_regulator(sc, regulator));
562 	}
563 
564 	/* Get the VSEL value for the given voltage */
565 	err = twl_vreg_millivolt_to_vsel(sc, regulator, millivolts, &vsel);
566 	if (err)
567 		return (err);
568 
569 	/* Need to upgrade because writing the voltage and enabling should be atomic */
570 	xlocked = sx_xlocked(&sc->sc_sx);
571 	if (!xlocked)
572 		TWL_VREG_LOCK_UPGRADE(sc);
573 
574 	/* Set voltage and enable (atomically) */
575 	err = twl_vreg_write_1(sc, regulator, TWL_VREG_VSEL, (vsel & 0x1f));
576 	if (!err) {
577 		err = twl_vreg_enable_regulator(sc, regulator);
578 	}
579 
580 	if (!xlocked)
581 		TWL_VREG_LOCK_DOWNGRADE(sc);
582 
583 	if ((twl_vreg_debug > 1) && !err)
584 		device_printf(sc->sc_dev, "%s : setting voltage to %dmV (vsel: 0x%x)\n",
585 		    regulator->name, millivolts, vsel);
586 
587 	return (err);
588 }
589 
590 /**
591  *	twl_vreg_read_regulator_voltage - reads the voltage on a given regulator
592  *	@sc: the device soft context
593  *	@regulator: pointer to the regulator structure
594  *	@millivolts: upon return will contain the voltage on the regulator
595  *
596  *	LOCKING:
597  *	On entry expects the TWL VREG lock to be held. It will upgrade the lock to
598  *	exclusive if not already, but if so, it will be downgraded again before
599  *	returning.
600  *
601  *	RETURNS:
602  *	Zero on success, or otherwise an error code.
603  */
604 static int
605 twl_vreg_read_regulator_voltage(struct twl_vreg_softc *sc,
606     struct twl_regulator_entry *regulator, int *millivolts)
607 {
608 	int err;
609 	int en = 0;
610 	int xlocked;
611 	uint8_t vsel;
612 
613 	TWL_VREG_ASSERT_LOCKED(sc);
614 
615 	/* Need to upgrade the lock because checking enabled state and voltage
616 	 * should be atomic.
617 	 */
618 	xlocked = sx_xlocked(&sc->sc_sx);
619 	if (!xlocked)
620 		TWL_VREG_LOCK_UPGRADE(sc);
621 
622 	/* Check if the regulator is currently enabled */
623 	err = twl_vreg_is_regulator_enabled(sc, regulator, &en);
624 	if (err)
625 		goto done;
626 
627 	*millivolts = 0;
628 	if (!en)
629 		goto done;
630 
631 	/* Not all voltages are adjustable */
632 	if (regulator->supp_voltages == NULL || !regulator->num_supp_voltages) {
633 		*millivolts = regulator->fixed_voltage;
634 		goto done;
635 	}
636 
637 	/* For variable voltages read the voltage register */
638 	err = twl_vreg_read_1(sc, regulator, TWL_VREG_VSEL, &vsel);
639 	if (err)
640 		goto done;
641 
642 	vsel &= (regulator->num_supp_voltages - 1);
643 	if (regulator->supp_voltages[vsel] == UNDF) {
644 		err = EINVAL;
645 		goto done;
646 	}
647 
648 	*millivolts = regulator->supp_voltages[vsel];
649 
650 done:
651 	if (!xlocked)
652 		TWL_VREG_LOCK_DOWNGRADE(sc);
653 
654 	if ((twl_vreg_debug > 1) && !err)
655 		device_printf(sc->sc_dev, "%s : reading voltage is %dmV (vsel: 0x%x)\n",
656 		    regulator->name, *millivolts, vsel);
657 
658 	return (err);
659 }
660 
661 /**
662  *	twl_vreg_get_voltage - public interface to read the voltage on a regulator
663  *	@dev: TWL VREG device
664  *	@name: the name of the regulator to read the voltage of
665  *	@millivolts: pointer to an integer that upon return will contain the mV
666  *
667  *	If the regulator is disabled the function will set the @millivolts to zero.
668  *
669  *	LOCKING:
670  *	Internally the function takes and releases the TWL VREG lock.
671  *
672  *	RETURNS:
673  *	Zero on success or a negative error code on failure.
674  */
675 int
676 twl_vreg_get_voltage(device_t dev, const char *name, int *millivolts)
677 {
678 	struct twl_vreg_softc *sc;
679 	struct twl_regulator_entry *regulator;
680 	int err = EINVAL;
681 
682 	if (millivolts == NULL)
683 		return (EINVAL);
684 
685 	sc = device_get_softc(dev);
686 
687 	TWL_VREG_SLOCK(sc);
688 
689 	LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
690 		if (strcmp(regulator->name, name) == 0) {
691 			err = twl_vreg_read_regulator_voltage(sc, regulator, millivolts);
692 			break;
693 		}
694 	}
695 
696 	TWL_VREG_SUNLOCK(sc);
697 
698 	return (err);
699 }
700 
701 /**
702  *	twl_vreg_set_voltage - public interface to write the voltage on a regulator
703  *	@dev: TWL VREG device
704  *	@name: the name of the regulator to read the voltage of
705  *	@millivolts: the voltage to set in millivolts
706  *
707  *	Sets the output voltage on a given regulator. If the regulator is a fixed
708  *	voltage reg then the @millivolts value should match the fixed voltage. If
709  *	a variable regulator then the @millivolt value must fit within the max/min
710  *	range of the given regulator.
711  *
712  *	LOCKING:
713  *	Internally the function takes and releases the TWL VREG lock.
714  *
715  *	RETURNS:
716  *	Zero on success or a negative error code on failure.
717  */
718 int
719 twl_vreg_set_voltage(device_t dev, const char *name, int millivolts)
720 {
721 	struct twl_vreg_softc *sc;
722 	struct twl_regulator_entry *regulator;
723 	int err = EINVAL;
724 
725 	sc = device_get_softc(dev);
726 
727 	TWL_VREG_SLOCK(sc);
728 
729 	LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
730 		if (strcmp(regulator->name, name) == 0) {
731 			err = twl_vreg_write_regulator_voltage(sc, regulator, millivolts);
732 			break;
733 		}
734 	}
735 
736 	TWL_VREG_SUNLOCK(sc);
737 
738 	return (err);
739 }
740 
741 /**
742  *	twl_sysctl_voltage - reads or writes the voltage for a regulator
743  *	@SYSCTL_HANDLER_ARGS: arguments for the callback
744  *
745  *	Callback for the sysctl entry for the regulator, simply used to return
746  *	the voltage on a particular regulator.
747  *
748  *	LOCKING:
749  *	Takes the TWL_VREG shared lock internally.
750  *
751  *	RETURNS:
752  *	Zero on success or an error code on failure.
753  */
754 static int
755 twl_vreg_sysctl_voltage(SYSCTL_HANDLER_ARGS)
756 {
757 	struct twl_vreg_softc *sc = (struct twl_vreg_softc*)arg1;
758 	struct twl_regulator_entry *regulator;
759 	int voltage;
760 	int found = 0;
761 
762 	TWL_VREG_SLOCK(sc);
763 
764 	/* Find the regulator with the matching name */
765 	LIST_FOREACH(regulator, &sc->sc_vreg_list, entries) {
766 		if (strcmp(regulator->name, oidp->oid_name) == 0) {
767 			found = 1;
768 			break;
769 		}
770 	}
771 
772 	/* Sanity check that we found the regulator */
773 	if (!found) {
774 		TWL_VREG_SUNLOCK(sc);
775 		return (EINVAL);
776 	}
777 
778 	twl_vreg_read_regulator_voltage(sc, regulator, &voltage);
779 
780 	TWL_VREG_SUNLOCK(sc);
781 
782 	return sysctl_handle_int(oidp, &voltage, 0, req);
783 }
784 
785 /**
786  *	twl_add_regulator - adds single voltage regulator sysctls for the device
787  *	@sc: device soft context
788  *	@name: the name of the regulator
789  *	@nsub: the number of the subdevice
790  *	@regbase: the base address of the voltage regulator registers
791  *	@fixed_voltage: if a fixed voltage regulator this defines it's voltage
792  *	@voltages: if a variable voltage regulator, an array of possible voltages
793  *	@num_voltages: the number of entries @voltages
794  *
795  *	Adds a voltage regulator to the device and also a sysctl interface for the
796  *	regulator.
797  *
798  *	LOCKING:
799  *	The TWL_VEG exclusive lock must be held while this function is called.
800  *
801  *	RETURNS:
802  *	Pointer to the new regulator entry on success, otherwise on failure NULL.
803  */
804 static struct twl_regulator_entry*
805 twl_vreg_add_regulator(struct twl_vreg_softc *sc, const char *name,
806 	uint8_t nsub, uint8_t regbase, uint16_t fixed_voltage,
807 	const uint16_t *voltages, uint32_t num_voltages)
808 {
809 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
810 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
811 	struct twl_regulator_entry *new;
812 
813 	new = malloc(sizeof(struct twl_regulator_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
814 	if (new == NULL)
815 		return (NULL);
816 
817 	strncpy(new->name, name, TWL_VREG_MAX_NAMELEN);
818 	new->name[TWL_VREG_MAX_NAMELEN - 1] = '\0';
819 
820 	new->sub_dev = nsub;
821 	new->reg_off = regbase;
822 
823 	new->fixed_voltage = fixed_voltage;
824 
825 	new->supp_voltages = voltages;
826 	new->num_supp_voltages = num_voltages;
827 
828 	/* Add a sysctl entry for the voltage */
829 	new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name,
830 	    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, sc, 0,
831 	    twl_vreg_sysctl_voltage, "I", "voltage regulator");
832 
833 	/* Finally add the regulator to list of supported regulators */
834 	LIST_INSERT_HEAD(&sc->sc_vreg_list, new, entries);
835 
836 	return (new);
837 }
838 
839 /**
840  *	twl_vreg_add_regulators - adds any voltage regulators to the device
841  *	@sc: device soft context
842  *	@chip: the name of the chip used in the hints
843  *	@regulators: the list of possible voltage regulators
844  *
845  *	Loops over the list of regulators and matches up with the FDT values,
846  *	adjusting the actual voltage based on the supplied values.
847  *
848  *	LOCKING:
849  *	The TWL_VEG exclusive lock must be held while this function is called.
850  *
851  *	RETURNS:
852  *	Always returns 0.
853  */
854 static int
855 twl_vreg_add_regulators(struct twl_vreg_softc *sc,
856 	const struct twl_regulator *regulators)
857 {
858 	int err;
859 	int millivolts;
860 	const struct twl_regulator *walker;
861 	struct twl_regulator_entry *entry;
862 	phandle_t child;
863 	char rnames[256];
864 	char *name, *voltage;
865 	int len = 0, prop_len;
866 
867 	/* Add the regulators from the list */
868 	walker = &regulators[0];
869 	while (walker->name != NULL) {
870 		/* Add the regulator to the list */
871 		entry = twl_vreg_add_regulator(sc, walker->name, walker->subdev,
872 		    walker->regbase, walker->fixedvoltage,
873 		    walker->voltages, walker->num_voltages);
874 		if (entry == NULL)
875 			continue;
876 
877 		walker++;
878 	}
879 
880 	/* Check if the FDT is telling us to set any voltages */
881 	child = ofw_bus_get_node(sc->sc_pdev);
882 	if (child) {
883 		prop_len = OF_getprop(child, "voltage-regulators", rnames, sizeof(rnames));
884 		while (len < prop_len) {
885 			name = rnames + len;
886 			len += strlen(name) + 1;
887 			if ((len >= prop_len) || (name[0] == '\0'))
888 				break;
889 
890 			voltage = rnames + len;
891 			len += strlen(voltage) + 1;
892 			if (voltage[0] == '\0')
893 				break;
894 
895 			millivolts = strtoul(voltage, NULL, 0);
896 
897 			LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
898 				if (strcmp(entry->name, name) == 0) {
899 					twl_vreg_write_regulator_voltage(sc, entry, millivolts);
900 					break;
901 				}
902 			}
903 		}
904 	}
905 
906 	if (twl_vreg_debug) {
907 		LIST_FOREACH(entry, &sc->sc_vreg_list, entries) {
908 			err = twl_vreg_read_regulator_voltage(sc, entry, &millivolts);
909 			if (!err)
910 				device_printf(sc->sc_dev, "%s : %d mV\n", entry->name, millivolts);
911 		}
912 	}
913 
914 	return (0);
915 }
916 
917 /**
918  *	twl_vreg_init - initialises the list of regulators
919  *	@dev: the twl_vreg device
920  *
921  *	This function is called as an intrhook once interrupts have been enabled,
922  *	this is done so that the driver has the option to enable/disable or set
923  *	the voltage level based on settings providied in the FDT.
924  *
925  *	LOCKING:
926  *	Takes the exclusive lock in the function.
927  */
928 static void
929 twl_vreg_init(void *dev)
930 {
931 	struct twl_vreg_softc *sc;
932 
933 	sc = device_get_softc((device_t)dev);
934 
935 	TWL_VREG_XLOCK(sc);
936 
937 	if (twl_is_4030(sc->sc_pdev))
938 		twl_vreg_add_regulators(sc, twl4030_regulators);
939 	else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev))
940 		twl_vreg_add_regulators(sc, twl6030_regulators);
941 
942 	TWL_VREG_XUNLOCK(sc);
943 
944 	config_intrhook_disestablish(&sc->sc_init_hook);
945 }
946 
947 static int
948 twl_vreg_probe(device_t dev)
949 {
950 	if (twl_is_4030(device_get_parent(dev)))
951 		device_set_desc(dev, "TI TWL4030 PMIC Voltage Regulators");
952 	else if (twl_is_6025(device_get_parent(dev)) ||
953 	         twl_is_6030(device_get_parent(dev)))
954 		device_set_desc(dev, "TI TWL6025/TWL6030 PMIC Voltage Regulators");
955 	else
956 		return (ENXIO);
957 
958 	return (0);
959 }
960 
961 static int
962 twl_vreg_attach(device_t dev)
963 {
964 	struct twl_vreg_softc *sc;
965 
966 	sc = device_get_softc(dev);
967 	sc->sc_dev = dev;
968 	sc->sc_pdev = device_get_parent(dev);
969 
970 	TWL_VREG_LOCK_INIT(sc);
971 
972 	LIST_INIT(&sc->sc_vreg_list);
973 
974 	/* We have to wait until interrupts are enabled. I2C read and write
975 	 * only works if the interrupts are available.
976 	 */
977 	sc->sc_init_hook.ich_func = twl_vreg_init;
978 	sc->sc_init_hook.ich_arg = dev;
979 
980 	if (config_intrhook_establish(&sc->sc_init_hook) != 0)
981 		return (ENOMEM);
982 
983 	return (0);
984 }
985 
986 static int
987 twl_vreg_detach(device_t dev)
988 {
989 	struct twl_vreg_softc *sc;
990 	struct twl_regulator_entry *regulator;
991 	struct twl_regulator_entry *tmp;
992 
993 	sc = device_get_softc(dev);
994 
995 	/* Take the lock and free all the added regulators */
996 	TWL_VREG_XLOCK(sc);
997 
998 	LIST_FOREACH_SAFE(regulator, &sc->sc_vreg_list, entries, tmp) {
999 		LIST_REMOVE(regulator, entries);
1000 		sysctl_remove_oid(regulator->oid, 1, 0);
1001 		free(regulator, M_DEVBUF);
1002 	}
1003 
1004 	TWL_VREG_XUNLOCK(sc);
1005 
1006 	TWL_VREG_LOCK_DESTROY(sc);
1007 
1008 	return (0);
1009 }
1010 
1011 static device_method_t twl_vreg_methods[] = {
1012 	DEVMETHOD(device_probe,		twl_vreg_probe),
1013 	DEVMETHOD(device_attach,	twl_vreg_attach),
1014 	DEVMETHOD(device_detach,	twl_vreg_detach),
1015 
1016 	{0, 0},
1017 };
1018 
1019 static driver_t twl_vreg_driver = {
1020 	"twl_vreg",
1021 	twl_vreg_methods,
1022 	sizeof(struct twl_vreg_softc),
1023 };
1024 
1025 DRIVER_MODULE(twl_vreg, twl, twl_vreg_driver, 0, 0);
1026 MODULE_VERSION(twl_vreg, 1);
1027