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