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