twl_vreg.c revision 263456
1/*-
2 * Copyright (c) 2011
3 *	Ben Gray <ben.r.gray@gmail.com>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: stable/10/sys/arm/ti/twl/twl_vreg.c 263456 2014-03-21 00:19:20Z dim $");
30
31/*
32 * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management.
33 *
34 * This driver covers the voltages regulators (LDO), allows for enabling &
35 * disabling the voltage output and adjusting the voltage level.
36 *
37 * Voltage regulators can belong to different power groups, in this driver we
38 * put the regulators under our control in the "Application power group".
39 *
40 *
41 * FLATTENED DEVICE TREE (FDT)
42 * Startup override settings can be specified in the FDT, if they are they
43 * should be under the twl parent device and take the following form:
44 *
45 *    voltage-regulators = "name1", "millivolts1",
46 *                         "name2", "millivolts2";
47 *
48 * Each override should be a pair, the first entry is the name of the regulator
49 * the second is the voltage (in millivolts) to set for the given regulator.
50 *
51 */
52
53#include <sys/param.h>
54#include <sys/systm.h>
55#include <sys/kernel.h>
56#include <sys/lock.h>
57#include <sys/module.h>
58#include <sys/bus.h>
59#include <sys/resource.h>
60#include <sys/rman.h>
61#include <sys/sysctl.h>
62#include <sys/sx.h>
63#include <sys/malloc.h>
64
65#include <machine/bus.h>
66#include <machine/cpu.h>
67#include <machine/cpufunc.h>
68#include <machine/resource.h>
69#include <machine/intr.h>
70
71#include <dev/ofw/openfirm.h>
72#include <dev/ofw/ofw_bus.h>
73
74#include "twl.h"
75#include "twl_vreg.h"
76
77static 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
100static 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
107static const uint16_t twl4030_vaux1_voltages[] = {
108	1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
109};
110static 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};
114static const uint16_t twl4030_vaux3_voltages[] = {
115	1500, 1800, 2500, 2800, 3000, 3000, 3000, 3000
116};
117static 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};
121static const uint16_t twl4030_vmmc1_voltages[] = {
122	1850, 2850, 3000, 3150
123};
124static 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};
128static const uint16_t twl4030_vpll1_voltages[] = {
129	1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
130};
131static 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};
135static const uint16_t twl4030_vsim_voltages[] = {
136	1000, 1200, 1300, 1800, 2800, 3000, 3000, 3000
137};
138static const uint16_t twl4030_vdac_voltages[] = {
139	1200, 1300, 1800, 1800
140};
141#if 0 /* vdd1, vdd2, vdio, not currently used. */
142static const uint16_t twl4030_vdd1_voltages[] = {
143	800, 1450
144};
145static const uint16_t twl4030_vdd2_voltages[] = {
146	800, 1450, 1500
147};
148static const uint16_t twl4030_vio_voltages[] = {
149	1800, 1850
150};
151#endif
152static const uint16_t twl4030_vintana2_voltages[] = {
153	2500, 2750
154};
155
156/**
157 *  Support voltage regulators for the different IC's
158 */
159struct 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
175static 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
195static 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
215struct 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
226struct 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 */
266static inline int
267twl_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
274static inline int
275twl_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 */
299static int
300twl_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 */
352static int
353twl_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
404done:
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 */
426static int
427twl_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
465done:
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 */
489static int
490twl_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
532done:
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 */
555static int
556twl_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 */
621static int
622twl_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
669done:
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 */
694int
695twl_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 */
737int
738twl_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 */
773static int
774twl_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 */
823static struct twl_regulator_entry*
824twl_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 */
875static int
876twl_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 */
954static void
955twl_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
973static int
974twl_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
987static int
988twl_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
1012static int
1013twl_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
1037static 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
1045static driver_t twl_vreg_driver = {
1046	"twl_vreg",
1047	twl_vreg_methods,
1048	sizeof(struct twl_vreg_softc),
1049};
1050
1051static devclass_t twl_vreg_devclass;
1052
1053DRIVER_MODULE(twl_vreg, twl, twl_vreg_driver, twl_vreg_devclass, 0, 0);
1054MODULE_VERSION(twl_vreg, 1);
1055