xref: /linux/drivers/regulator/tps6507x-regulator.c (revision f2933d333118bff82e4b46fff605e31f799df5ce)
13fa5b8e0SAnuj Aggarwal /*
23fa5b8e0SAnuj Aggarwal  * tps6507x-regulator.c
33fa5b8e0SAnuj Aggarwal  *
43fa5b8e0SAnuj Aggarwal  * Regulator driver for TPS65073 PMIC
53fa5b8e0SAnuj Aggarwal  *
63fa5b8e0SAnuj Aggarwal  * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/
73fa5b8e0SAnuj Aggarwal  *
83fa5b8e0SAnuj Aggarwal  * This program is free software; you can redistribute it and/or
93fa5b8e0SAnuj Aggarwal  * modify it under the terms of the GNU General Public License as
103fa5b8e0SAnuj Aggarwal  * published by the Free Software Foundation version 2.
113fa5b8e0SAnuj Aggarwal  *
123fa5b8e0SAnuj Aggarwal  * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
133fa5b8e0SAnuj Aggarwal  * whether express or implied; without even the implied warranty of
143fa5b8e0SAnuj Aggarwal  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
153fa5b8e0SAnuj Aggarwal  * General Public License for more details.
163fa5b8e0SAnuj Aggarwal  */
173fa5b8e0SAnuj Aggarwal 
183fa5b8e0SAnuj Aggarwal #include <linux/kernel.h>
193fa5b8e0SAnuj Aggarwal #include <linux/module.h>
203fa5b8e0SAnuj Aggarwal #include <linux/init.h>
213fa5b8e0SAnuj Aggarwal #include <linux/err.h>
223fa5b8e0SAnuj Aggarwal #include <linux/platform_device.h>
233fa5b8e0SAnuj Aggarwal #include <linux/regulator/driver.h>
243fa5b8e0SAnuj Aggarwal #include <linux/regulator/machine.h>
257d14831eSAnuj Aggarwal #include <linux/regulator/tps6507x.h>
263fa5b8e0SAnuj Aggarwal #include <linux/delay.h>
275a0e3ad6STejun Heo #include <linux/slab.h>
28d183fcc9STodd Fischer #include <linux/mfd/tps6507x.h>
293fa5b8e0SAnuj Aggarwal 
303fa5b8e0SAnuj Aggarwal /* DCDC's */
313fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_1				0
323fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_2				1
333fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_3				2
343fa5b8e0SAnuj Aggarwal /* LDOs */
353fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_1				3
363fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_2				4
373fa5b8e0SAnuj Aggarwal 
383fa5b8e0SAnuj Aggarwal #define TPS6507X_MAX_REG_ID			TPS6507X_LDO_2
393fa5b8e0SAnuj Aggarwal 
403fa5b8e0SAnuj Aggarwal /* Number of step-down converters available */
413fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_DCDC			3
423fa5b8e0SAnuj Aggarwal /* Number of LDO voltage regulators  available */
433fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_LDO			2
443fa5b8e0SAnuj Aggarwal /* Number of total regulators available */
453fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_REGULATOR		(TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
463fa5b8e0SAnuj Aggarwal 
473fa5b8e0SAnuj Aggarwal /* Supported voltage values for regulators (in milliVolts) */
483fa5b8e0SAnuj Aggarwal static const u16 VDCDCx_VSEL_table[] = {
493fa5b8e0SAnuj Aggarwal 	725, 750, 775, 800,
503fa5b8e0SAnuj Aggarwal 	825, 850, 875, 900,
513fa5b8e0SAnuj Aggarwal 	925, 950, 975, 1000,
523fa5b8e0SAnuj Aggarwal 	1025, 1050, 1075, 1100,
533fa5b8e0SAnuj Aggarwal 	1125, 1150, 1175, 1200,
543fa5b8e0SAnuj Aggarwal 	1225, 1250, 1275, 1300,
553fa5b8e0SAnuj Aggarwal 	1325, 1350, 1375, 1400,
563fa5b8e0SAnuj Aggarwal 	1425, 1450, 1475, 1500,
573fa5b8e0SAnuj Aggarwal 	1550, 1600, 1650, 1700,
583fa5b8e0SAnuj Aggarwal 	1750, 1800, 1850, 1900,
593fa5b8e0SAnuj Aggarwal 	1950, 2000, 2050, 2100,
603fa5b8e0SAnuj Aggarwal 	2150, 2200, 2250, 2300,
613fa5b8e0SAnuj Aggarwal 	2350, 2400, 2450, 2500,
623fa5b8e0SAnuj Aggarwal 	2550, 2600, 2650, 2700,
633fa5b8e0SAnuj Aggarwal 	2750, 2800, 2850, 2900,
643fa5b8e0SAnuj Aggarwal 	3000, 3100, 3200, 3300,
653fa5b8e0SAnuj Aggarwal };
663fa5b8e0SAnuj Aggarwal 
673fa5b8e0SAnuj Aggarwal static const u16 LDO1_VSEL_table[] = {
683fa5b8e0SAnuj Aggarwal 	1000, 1100, 1200, 1250,
693fa5b8e0SAnuj Aggarwal 	1300, 1350, 1400, 1500,
703fa5b8e0SAnuj Aggarwal 	1600, 1800, 2500, 2750,
713fa5b8e0SAnuj Aggarwal 	2800, 3000, 3100, 3300,
723fa5b8e0SAnuj Aggarwal };
733fa5b8e0SAnuj Aggarwal 
743fa5b8e0SAnuj Aggarwal static const u16 LDO2_VSEL_table[] = {
753fa5b8e0SAnuj Aggarwal 	725, 750, 775, 800,
763fa5b8e0SAnuj Aggarwal 	825, 850, 875, 900,
773fa5b8e0SAnuj Aggarwal 	925, 950, 975, 1000,
783fa5b8e0SAnuj Aggarwal 	1025, 1050, 1075, 1100,
793fa5b8e0SAnuj Aggarwal 	1125, 1150, 1175, 1200,
803fa5b8e0SAnuj Aggarwal 	1225, 1250, 1275, 1300,
813fa5b8e0SAnuj Aggarwal 	1325, 1350, 1375, 1400,
823fa5b8e0SAnuj Aggarwal 	1425, 1450, 1475, 1500,
833fa5b8e0SAnuj Aggarwal 	1550, 1600, 1650, 1700,
843fa5b8e0SAnuj Aggarwal 	1750, 1800, 1850, 1900,
853fa5b8e0SAnuj Aggarwal 	1950, 2000, 2050, 2100,
863fa5b8e0SAnuj Aggarwal 	2150, 2200, 2250, 2300,
873fa5b8e0SAnuj Aggarwal 	2350, 2400, 2450, 2500,
883fa5b8e0SAnuj Aggarwal 	2550, 2600, 2650, 2700,
893fa5b8e0SAnuj Aggarwal 	2750, 2800, 2850, 2900,
903fa5b8e0SAnuj Aggarwal 	3000, 3100, 3200, 3300,
913fa5b8e0SAnuj Aggarwal };
923fa5b8e0SAnuj Aggarwal 
933fa5b8e0SAnuj Aggarwal struct tps_info {
943fa5b8e0SAnuj Aggarwal 	const char *name;
953fa5b8e0SAnuj Aggarwal 	unsigned min_uV;
963fa5b8e0SAnuj Aggarwal 	unsigned max_uV;
973fa5b8e0SAnuj Aggarwal 	u8 table_len;
983fa5b8e0SAnuj Aggarwal 	const u16 *table;
997d14831eSAnuj Aggarwal 
1007d14831eSAnuj Aggarwal 	/* Does DCDC high or the low register defines output voltage? */
1017d14831eSAnuj Aggarwal 	bool defdcdc_default;
1023fa5b8e0SAnuj Aggarwal };
1033fa5b8e0SAnuj Aggarwal 
1047d14831eSAnuj Aggarwal static struct tps_info tps6507x_pmic_regs[] = {
10531dd6a26STodd Fischer 	{
10631dd6a26STodd Fischer 		.name = "VDCDC1",
10731dd6a26STodd Fischer 		.min_uV = 725000,
10831dd6a26STodd Fischer 		.max_uV = 3300000,
10931dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
11031dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
11131dd6a26STodd Fischer 	},
11231dd6a26STodd Fischer 	{
11331dd6a26STodd Fischer 		.name = "VDCDC2",
11431dd6a26STodd Fischer 		.min_uV = 725000,
11531dd6a26STodd Fischer 		.max_uV = 3300000,
11631dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
11731dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
11831dd6a26STodd Fischer 	},
11931dd6a26STodd Fischer 	{
12031dd6a26STodd Fischer 		.name = "VDCDC3",
12131dd6a26STodd Fischer 		.min_uV = 725000,
12231dd6a26STodd Fischer 		.max_uV = 3300000,
12331dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
12431dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
12531dd6a26STodd Fischer 	},
12631dd6a26STodd Fischer 	{
12731dd6a26STodd Fischer 		.name = "LDO1",
12831dd6a26STodd Fischer 		.min_uV = 1000000,
12931dd6a26STodd Fischer 		.max_uV = 3300000,
13031dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
13131dd6a26STodd Fischer 		.table = LDO1_VSEL_table,
13231dd6a26STodd Fischer 	},
13331dd6a26STodd Fischer 	{
13431dd6a26STodd Fischer 		.name = "LDO2",
13531dd6a26STodd Fischer 		.min_uV = 725000,
13631dd6a26STodd Fischer 		.max_uV = 3300000,
13731dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
13831dd6a26STodd Fischer 		.table = LDO2_VSEL_table,
13931dd6a26STodd Fischer 	},
14031dd6a26STodd Fischer };
14131dd6a26STodd Fischer 
1424ce5ba5bSTodd Fischer struct tps6507x_pmic {
1433fa5b8e0SAnuj Aggarwal 	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
14431dd6a26STodd Fischer 	struct tps6507x_dev *mfd;
1453fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
1467d14831eSAnuj Aggarwal 	struct tps_info *info[TPS6507X_NUM_REGULATOR];
1473fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
1483fa5b8e0SAnuj Aggarwal };
1494ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
1503fa5b8e0SAnuj Aggarwal {
15131dd6a26STodd Fischer 	u8 val;
15231dd6a26STodd Fischer 	int err;
15331dd6a26STodd Fischer 
15431dd6a26STodd Fischer 	err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
15531dd6a26STodd Fischer 
15631dd6a26STodd Fischer 	if (err)
15731dd6a26STodd Fischer 		return err;
15831dd6a26STodd Fischer 
15931dd6a26STodd Fischer 	return val;
1603fa5b8e0SAnuj Aggarwal }
1613fa5b8e0SAnuj Aggarwal 
1624ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1633fa5b8e0SAnuj Aggarwal {
16431dd6a26STodd Fischer 	return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
1653fa5b8e0SAnuj Aggarwal }
1663fa5b8e0SAnuj Aggarwal 
1674ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1683fa5b8e0SAnuj Aggarwal {
1693fa5b8e0SAnuj Aggarwal 	int err, data;
1703fa5b8e0SAnuj Aggarwal 
1713fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1723fa5b8e0SAnuj Aggarwal 
1734ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1743fa5b8e0SAnuj Aggarwal 	if (data < 0) {
17531dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1763fa5b8e0SAnuj Aggarwal 		err = data;
1773fa5b8e0SAnuj Aggarwal 		goto out;
1783fa5b8e0SAnuj Aggarwal 	}
1793fa5b8e0SAnuj Aggarwal 
1803fa5b8e0SAnuj Aggarwal 	data |= mask;
1814ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1823fa5b8e0SAnuj Aggarwal 	if (err)
18331dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1843fa5b8e0SAnuj Aggarwal 
1853fa5b8e0SAnuj Aggarwal out:
1863fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1873fa5b8e0SAnuj Aggarwal 	return err;
1883fa5b8e0SAnuj Aggarwal }
1893fa5b8e0SAnuj Aggarwal 
1904ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1913fa5b8e0SAnuj Aggarwal {
1923fa5b8e0SAnuj Aggarwal 	int err, data;
1933fa5b8e0SAnuj Aggarwal 
1943fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1953fa5b8e0SAnuj Aggarwal 
1964ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1973fa5b8e0SAnuj Aggarwal 	if (data < 0) {
19831dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1993fa5b8e0SAnuj Aggarwal 		err = data;
2003fa5b8e0SAnuj Aggarwal 		goto out;
2013fa5b8e0SAnuj Aggarwal 	}
2023fa5b8e0SAnuj Aggarwal 
2033fa5b8e0SAnuj Aggarwal 	data &= ~mask;
2044ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
2053fa5b8e0SAnuj Aggarwal 	if (err)
20631dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2073fa5b8e0SAnuj Aggarwal 
2083fa5b8e0SAnuj Aggarwal out:
2093fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2103fa5b8e0SAnuj Aggarwal 	return err;
2113fa5b8e0SAnuj Aggarwal }
2123fa5b8e0SAnuj Aggarwal 
2134ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
2143fa5b8e0SAnuj Aggarwal {
2153fa5b8e0SAnuj Aggarwal 	int data;
2163fa5b8e0SAnuj Aggarwal 
2173fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2183fa5b8e0SAnuj Aggarwal 
2194ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
2203fa5b8e0SAnuj Aggarwal 	if (data < 0)
22131dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
2223fa5b8e0SAnuj Aggarwal 
2233fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2243fa5b8e0SAnuj Aggarwal 	return data;
2253fa5b8e0SAnuj Aggarwal }
2263fa5b8e0SAnuj Aggarwal 
2274ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
2283fa5b8e0SAnuj Aggarwal {
2293fa5b8e0SAnuj Aggarwal 	int err;
2303fa5b8e0SAnuj Aggarwal 
2313fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2323fa5b8e0SAnuj Aggarwal 
2334ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, val);
2343fa5b8e0SAnuj Aggarwal 	if (err < 0)
23531dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2363fa5b8e0SAnuj Aggarwal 
2373fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2383fa5b8e0SAnuj Aggarwal 	return err;
2393fa5b8e0SAnuj Aggarwal }
2403fa5b8e0SAnuj Aggarwal 
241*f2933d33SAxel Lin static int tps6507x_pmic_is_enabled(struct regulator_dev *dev)
2423fa5b8e0SAnuj Aggarwal {
2434ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
244*f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
2453fa5b8e0SAnuj Aggarwal 	u8 shift;
2463fa5b8e0SAnuj Aggarwal 
247*f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2483fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2493fa5b8e0SAnuj Aggarwal 
250*f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2514ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2523fa5b8e0SAnuj Aggarwal 
2533fa5b8e0SAnuj Aggarwal 	if (data < 0)
2543fa5b8e0SAnuj Aggarwal 		return data;
2553fa5b8e0SAnuj Aggarwal 	else
2563fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2573fa5b8e0SAnuj Aggarwal }
2583fa5b8e0SAnuj Aggarwal 
259*f2933d33SAxel Lin static int tps6507x_pmic_enable(struct regulator_dev *dev)
2603fa5b8e0SAnuj Aggarwal {
2614ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
262*f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2633fa5b8e0SAnuj Aggarwal 	u8 shift;
2643fa5b8e0SAnuj Aggarwal 
265*f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2663fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2673fa5b8e0SAnuj Aggarwal 
268*f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2694ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
2703fa5b8e0SAnuj Aggarwal }
2713fa5b8e0SAnuj Aggarwal 
272*f2933d33SAxel Lin static int tps6507x_pmic_disable(struct regulator_dev *dev)
2733fa5b8e0SAnuj Aggarwal {
2744ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
275*f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2763fa5b8e0SAnuj Aggarwal 	u8 shift;
2773fa5b8e0SAnuj Aggarwal 
278*f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2793fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2803fa5b8e0SAnuj Aggarwal 
281*f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2824ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
2834ce5ba5bSTodd Fischer 					1 << shift);
2843fa5b8e0SAnuj Aggarwal }
2853fa5b8e0SAnuj Aggarwal 
286*f2933d33SAxel Lin static int tps6507x_pmic_get_voltage(struct regulator_dev *dev)
2873fa5b8e0SAnuj Aggarwal {
2884ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
289*f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
290*f2933d33SAxel Lin 	u8 reg, mask;
2913fa5b8e0SAnuj Aggarwal 
292*f2933d33SAxel Lin 	switch (rid) {
2933fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
2943fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
295*f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2963fa5b8e0SAnuj Aggarwal 		break;
2973fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
298*f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2997d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3007d14831eSAnuj Aggarwal 		else
3013fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
302*f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3033fa5b8e0SAnuj Aggarwal 		break;
3043fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
305*f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3067d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3077d14831eSAnuj Aggarwal 		else
3083fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
309*f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
310*f2933d33SAxel Lin 		break;
311*f2933d33SAxel Lin 	case TPS6507X_LDO_1:
312*f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
313*f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
314*f2933d33SAxel Lin 		break;
315*f2933d33SAxel Lin 	case TPS6507X_LDO_2:
316*f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
317*f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
3183fa5b8e0SAnuj Aggarwal 		break;
3193fa5b8e0SAnuj Aggarwal 	default:
3203fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3213fa5b8e0SAnuj Aggarwal 	}
3223fa5b8e0SAnuj Aggarwal 
3234ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3243fa5b8e0SAnuj Aggarwal 	if (data < 0)
3253fa5b8e0SAnuj Aggarwal 		return data;
3263fa5b8e0SAnuj Aggarwal 
327*f2933d33SAxel Lin 	data &= mask;
328*f2933d33SAxel Lin 	return tps->info[rid]->table[data] * 1000;
3293fa5b8e0SAnuj Aggarwal }
3303fa5b8e0SAnuj Aggarwal 
331*f2933d33SAxel Lin static int tps6507x_pmic_set_voltage(struct regulator_dev *dev,
3323a93f2a9SMark Brown 					  int min_uV, int max_uV,
3333a93f2a9SMark Brown 					  unsigned *selector)
3343fa5b8e0SAnuj Aggarwal {
3354ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
336*f2933d33SAxel Lin 	int data, vsel, rid = rdev_get_id(dev);
337*f2933d33SAxel Lin 	u8 reg, mask;
3383fa5b8e0SAnuj Aggarwal 
339*f2933d33SAxel Lin 	switch (rid) {
3403fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3413fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
342*f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3433fa5b8e0SAnuj Aggarwal 		break;
3443fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
345*f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3467d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3477d14831eSAnuj Aggarwal 		else
3483fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
349*f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3503fa5b8e0SAnuj Aggarwal 		break;
3513fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
352*f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3537d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3547d14831eSAnuj Aggarwal 		else
3553fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
356*f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
357*f2933d33SAxel Lin 		break;
358*f2933d33SAxel Lin 	case TPS6507X_LDO_1:
359*f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
360*f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
361*f2933d33SAxel Lin 		break;
362*f2933d33SAxel Lin 	case TPS6507X_LDO_2:
363*f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
364*f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
3653fa5b8e0SAnuj Aggarwal 		break;
3663fa5b8e0SAnuj Aggarwal 	default:
3673fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3683fa5b8e0SAnuj Aggarwal 	}
3693fa5b8e0SAnuj Aggarwal 
370*f2933d33SAxel Lin 	if (min_uV < tps->info[rid]->min_uV || min_uV > tps->info[rid]->max_uV)
3713fa5b8e0SAnuj Aggarwal 		return -EINVAL;
372*f2933d33SAxel Lin 	if (max_uV < tps->info[rid]->min_uV || max_uV > tps->info[rid]->max_uV)
3733fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3743fa5b8e0SAnuj Aggarwal 
375*f2933d33SAxel Lin 	for (vsel = 0; vsel < tps->info[rid]->table_len; vsel++) {
376*f2933d33SAxel Lin 		int mV = tps->info[rid]->table[vsel];
3773fa5b8e0SAnuj Aggarwal 		int uV = mV * 1000;
3783fa5b8e0SAnuj Aggarwal 
3793fa5b8e0SAnuj Aggarwal 		/* Break at the first in-range value */
3803fa5b8e0SAnuj Aggarwal 		if (min_uV <= uV && uV <= max_uV)
3813fa5b8e0SAnuj Aggarwal 			break;
3823fa5b8e0SAnuj Aggarwal 	}
3833fa5b8e0SAnuj Aggarwal 
3843fa5b8e0SAnuj Aggarwal 	/* write to the register in case we found a match */
385*f2933d33SAxel Lin 	if (vsel == tps->info[rid]->table_len)
3863fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3873fa5b8e0SAnuj Aggarwal 
3883a93f2a9SMark Brown 	*selector = vsel;
3893a93f2a9SMark Brown 
3904ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3913fa5b8e0SAnuj Aggarwal 	if (data < 0)
3923fa5b8e0SAnuj Aggarwal 		return data;
3933fa5b8e0SAnuj Aggarwal 
3943fa5b8e0SAnuj Aggarwal 	data &= ~mask;
3953fa5b8e0SAnuj Aggarwal 	data |= vsel;
3963fa5b8e0SAnuj Aggarwal 
3974ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
3983fa5b8e0SAnuj Aggarwal }
3993fa5b8e0SAnuj Aggarwal 
400*f2933d33SAxel Lin static int tps6507x_pmic_list_voltage(struct regulator_dev *dev,
4013fa5b8e0SAnuj Aggarwal 					unsigned selector)
4023fa5b8e0SAnuj Aggarwal {
4034ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
404*f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
4053fa5b8e0SAnuj Aggarwal 
406*f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
4073fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4083fa5b8e0SAnuj Aggarwal 
409*f2933d33SAxel Lin 	if (selector >= tps->info[rid]->table_len)
4103fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4113fa5b8e0SAnuj Aggarwal 	else
412*f2933d33SAxel Lin 		return tps->info[rid]->table[selector] * 1000;
4133fa5b8e0SAnuj Aggarwal }
4143fa5b8e0SAnuj Aggarwal 
415*f2933d33SAxel Lin static struct regulator_ops tps6507x_pmic_ops = {
416*f2933d33SAxel Lin 	.is_enabled = tps6507x_pmic_is_enabled,
417*f2933d33SAxel Lin 	.enable = tps6507x_pmic_enable,
418*f2933d33SAxel Lin 	.disable = tps6507x_pmic_disable,
419*f2933d33SAxel Lin 	.get_voltage = tps6507x_pmic_get_voltage,
420*f2933d33SAxel Lin 	.set_voltage = tps6507x_pmic_set_voltage,
421*f2933d33SAxel Lin 	.list_voltage = tps6507x_pmic_list_voltage,
4223fa5b8e0SAnuj Aggarwal };
4233fa5b8e0SAnuj Aggarwal 
424*f2933d33SAxel Lin static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
4253fa5b8e0SAnuj Aggarwal {
42631dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
4277d14831eSAnuj Aggarwal 	struct tps_info *info = &tps6507x_pmic_regs[0];
4283fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
4293fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
4304ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
4310bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
4323fa5b8e0SAnuj Aggarwal 	int i;
43356c23492SDmitry Torokhov 	int error;
4343fa5b8e0SAnuj Aggarwal 
4353fa5b8e0SAnuj Aggarwal 	/**
4360bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
4370bc20bbaSTodd Fischer 	 * coming from the board-evm file.
4380bc20bbaSTodd Fischer 	 */
4390bc20bbaSTodd Fischer 
44031dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
4410bc20bbaSTodd Fischer 	if (!tps_board)
4420bc20bbaSTodd Fischer 		return -EINVAL;
4430bc20bbaSTodd Fischer 
4440bc20bbaSTodd Fischer 	/**
4453fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
4463fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
4473fa5b8e0SAnuj Aggarwal 	 */
4480bc20bbaSTodd Fischer 	init_data = tps_board->tps6507x_pmic_init_data;
4493fa5b8e0SAnuj Aggarwal 	if (!init_data)
4500bc20bbaSTodd Fischer 		return -EINVAL;
4513fa5b8e0SAnuj Aggarwal 
4523fa5b8e0SAnuj Aggarwal 	tps = kzalloc(sizeof(*tps), GFP_KERNEL);
4533fa5b8e0SAnuj Aggarwal 	if (!tps)
4543fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
4553fa5b8e0SAnuj Aggarwal 
4563fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
4573fa5b8e0SAnuj Aggarwal 
4583fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
45931dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
4603fa5b8e0SAnuj Aggarwal 
4613fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
4623fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
4633fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
4647d14831eSAnuj Aggarwal 		if (init_data->driver_data) {
4657d14831eSAnuj Aggarwal 			struct tps6507x_reg_platform_data *data =
4667d14831eSAnuj Aggarwal 							init_data->driver_data;
4677d14831eSAnuj Aggarwal 			tps->info[i]->defdcdc_default = data->defdcdc_default;
4687d14831eSAnuj Aggarwal 		}
4697d14831eSAnuj Aggarwal 
4703fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
47177fa44d0SAxel Lin 		tps->desc[i].id = i;
4720fcdb109SAxel Lin 		tps->desc[i].n_voltages = info->table_len;
473*f2933d33SAxel Lin 		tps->desc[i].ops = &tps6507x_pmic_ops;
4743fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
4753fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
4763fa5b8e0SAnuj Aggarwal 
4773fa5b8e0SAnuj Aggarwal 		rdev = regulator_register(&tps->desc[i],
4782c043bcbSRajendra Nayak 					tps6507x_dev->dev, init_data, tps, NULL);
4793fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
48031dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
48131dd6a26STodd Fischer 				"failed to register %s regulator\n",
48231dd6a26STodd Fischer 				pdev->name);
48356c23492SDmitry Torokhov 			error = PTR_ERR(rdev);
48456c23492SDmitry Torokhov 			goto fail;
4853fa5b8e0SAnuj Aggarwal 		}
4863fa5b8e0SAnuj Aggarwal 
4873fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
4883fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
4893fa5b8e0SAnuj Aggarwal 	}
4903fa5b8e0SAnuj Aggarwal 
49131dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
492d7399fa8SAxel Lin 	platform_set_drvdata(pdev, tps6507x_dev);
4933fa5b8e0SAnuj Aggarwal 
4943fa5b8e0SAnuj Aggarwal 	return 0;
49556c23492SDmitry Torokhov 
49656c23492SDmitry Torokhov fail:
49756c23492SDmitry Torokhov 	while (--i >= 0)
49856c23492SDmitry Torokhov 		regulator_unregister(tps->rdev[i]);
49956c23492SDmitry Torokhov 
50056c23492SDmitry Torokhov 	kfree(tps);
50156c23492SDmitry Torokhov 	return error;
5023fa5b8e0SAnuj Aggarwal }
5033fa5b8e0SAnuj Aggarwal 
50431dd6a26STodd Fischer static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
5053fa5b8e0SAnuj Aggarwal {
50631dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
50731dd6a26STodd Fischer 	struct tps6507x_pmic *tps = tps6507x_dev->pmic;
5083fa5b8e0SAnuj Aggarwal 	int i;
5093fa5b8e0SAnuj Aggarwal 
5103fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
5113fa5b8e0SAnuj Aggarwal 		regulator_unregister(tps->rdev[i]);
5123fa5b8e0SAnuj Aggarwal 
5133fa5b8e0SAnuj Aggarwal 	kfree(tps);
5143fa5b8e0SAnuj Aggarwal 
5153fa5b8e0SAnuj Aggarwal 	return 0;
5163fa5b8e0SAnuj Aggarwal }
5173fa5b8e0SAnuj Aggarwal 
51831dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
5193fa5b8e0SAnuj Aggarwal 	.driver = {
52031dd6a26STodd Fischer 		.name = "tps6507x-pmic",
5213fa5b8e0SAnuj Aggarwal 		.owner = THIS_MODULE,
5223fa5b8e0SAnuj Aggarwal 	},
5234ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
5244ce5ba5bSTodd Fischer 	.remove = __devexit_p(tps6507x_pmic_remove),
5253fa5b8e0SAnuj Aggarwal };
5263fa5b8e0SAnuj Aggarwal 
5274ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
5283fa5b8e0SAnuj Aggarwal {
52931dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
5303fa5b8e0SAnuj Aggarwal }
5314ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
5323fa5b8e0SAnuj Aggarwal 
5334ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
5343fa5b8e0SAnuj Aggarwal {
53531dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
5363fa5b8e0SAnuj Aggarwal }
5374ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
5383fa5b8e0SAnuj Aggarwal 
5393fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
5403fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
5413fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
54231dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
543