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