xref: /openbmc/linux/drivers/regulator/tps6507x-regulator.c (revision 9eb0c4218aa444f863e7f54909351d5b4f0fac06)
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 
241f2933d33SAxel Lin static int tps6507x_pmic_is_enabled(struct regulator_dev *dev)
2423fa5b8e0SAnuj Aggarwal {
2434ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
244f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
2453fa5b8e0SAnuj Aggarwal 	u8 shift;
2463fa5b8e0SAnuj Aggarwal 
247f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2483fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2493fa5b8e0SAnuj Aggarwal 
250f2933d33SAxel 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 
259f2933d33SAxel Lin static int tps6507x_pmic_enable(struct regulator_dev *dev)
2603fa5b8e0SAnuj Aggarwal {
2614ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
262f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2633fa5b8e0SAnuj Aggarwal 	u8 shift;
2643fa5b8e0SAnuj Aggarwal 
265f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2663fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2673fa5b8e0SAnuj Aggarwal 
268f2933d33SAxel 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 
272f2933d33SAxel Lin static int tps6507x_pmic_disable(struct regulator_dev *dev)
2733fa5b8e0SAnuj Aggarwal {
2744ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
275f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2763fa5b8e0SAnuj Aggarwal 	u8 shift;
2773fa5b8e0SAnuj Aggarwal 
278f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2793fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2803fa5b8e0SAnuj Aggarwal 
281f2933d33SAxel 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 
286f2933d33SAxel Lin static int tps6507x_pmic_get_voltage(struct regulator_dev *dev)
2873fa5b8e0SAnuj Aggarwal {
2884ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
289f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
290f2933d33SAxel Lin 	u8 reg, mask;
2913fa5b8e0SAnuj Aggarwal 
292f2933d33SAxel Lin 	switch (rid) {
2933fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
2943fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
295f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2963fa5b8e0SAnuj Aggarwal 		break;
2973fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
298f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2997d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3007d14831eSAnuj Aggarwal 		else
3013fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
302f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3033fa5b8e0SAnuj Aggarwal 		break;
3043fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
305f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3067d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3077d14831eSAnuj Aggarwal 		else
3083fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
309f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
310f2933d33SAxel Lin 		break;
311f2933d33SAxel Lin 	case TPS6507X_LDO_1:
312f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
313f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
314f2933d33SAxel Lin 		break;
315f2933d33SAxel Lin 	case TPS6507X_LDO_2:
316f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
317f2933d33SAxel 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 
327f2933d33SAxel Lin 	data &= mask;
328f2933d33SAxel Lin 	return tps->info[rid]->table[data] * 1000;
3293fa5b8e0SAnuj Aggarwal }
3303fa5b8e0SAnuj Aggarwal 
331ca61a7bfSAxel Lin static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
332ca61a7bfSAxel Lin 					  unsigned selector)
3333fa5b8e0SAnuj Aggarwal {
3344ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
335ca61a7bfSAxel Lin 	int data, rid = rdev_get_id(dev);
336f2933d33SAxel Lin 	u8 reg, mask;
3373fa5b8e0SAnuj Aggarwal 
338f2933d33SAxel Lin 	switch (rid) {
3393fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3403fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
341f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3423fa5b8e0SAnuj Aggarwal 		break;
3433fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
344f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3457d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3467d14831eSAnuj Aggarwal 		else
3473fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
348f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3493fa5b8e0SAnuj Aggarwal 		break;
3503fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
351f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3527d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3537d14831eSAnuj Aggarwal 		else
3543fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
355f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
356f2933d33SAxel Lin 		break;
357f2933d33SAxel Lin 	case TPS6507X_LDO_1:
358f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
359f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
360f2933d33SAxel Lin 		break;
361f2933d33SAxel Lin 	case TPS6507X_LDO_2:
362f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
363f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
3643fa5b8e0SAnuj Aggarwal 		break;
3653fa5b8e0SAnuj Aggarwal 	default:
3663fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3673fa5b8e0SAnuj Aggarwal 	}
3683fa5b8e0SAnuj Aggarwal 
3694ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3703fa5b8e0SAnuj Aggarwal 	if (data < 0)
3713fa5b8e0SAnuj Aggarwal 		return data;
3723fa5b8e0SAnuj Aggarwal 
3733fa5b8e0SAnuj Aggarwal 	data &= ~mask;
374ca61a7bfSAxel Lin 	data |= selector;
3753fa5b8e0SAnuj Aggarwal 
3764ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
3773fa5b8e0SAnuj Aggarwal }
3783fa5b8e0SAnuj Aggarwal 
379f2933d33SAxel Lin static int tps6507x_pmic_list_voltage(struct regulator_dev *dev,
3803fa5b8e0SAnuj Aggarwal 					unsigned selector)
3813fa5b8e0SAnuj Aggarwal {
3824ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
383f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
3843fa5b8e0SAnuj Aggarwal 
385f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
3863fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3873fa5b8e0SAnuj Aggarwal 
388f2933d33SAxel Lin 	if (selector >= tps->info[rid]->table_len)
3893fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3903fa5b8e0SAnuj Aggarwal 	else
391f2933d33SAxel Lin 		return tps->info[rid]->table[selector] * 1000;
3923fa5b8e0SAnuj Aggarwal }
3933fa5b8e0SAnuj Aggarwal 
394f2933d33SAxel Lin static struct regulator_ops tps6507x_pmic_ops = {
395f2933d33SAxel Lin 	.is_enabled = tps6507x_pmic_is_enabled,
396f2933d33SAxel Lin 	.enable = tps6507x_pmic_enable,
397f2933d33SAxel Lin 	.disable = tps6507x_pmic_disable,
398f2933d33SAxel Lin 	.get_voltage = tps6507x_pmic_get_voltage,
399ca61a7bfSAxel Lin 	.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
400f2933d33SAxel Lin 	.list_voltage = tps6507x_pmic_list_voltage,
4013fa5b8e0SAnuj Aggarwal };
4023fa5b8e0SAnuj Aggarwal 
403f2933d33SAxel Lin static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
4043fa5b8e0SAnuj Aggarwal {
40531dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
4067d14831eSAnuj Aggarwal 	struct tps_info *info = &tps6507x_pmic_regs[0];
407c172708dSMark Brown 	struct regulator_config config = { };
4083fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
4093fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
4104ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
4110bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
4123fa5b8e0SAnuj Aggarwal 	int i;
41356c23492SDmitry Torokhov 	int error;
4143fa5b8e0SAnuj Aggarwal 
4153fa5b8e0SAnuj Aggarwal 	/**
4160bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
4170bc20bbaSTodd Fischer 	 * coming from the board-evm file.
4180bc20bbaSTodd Fischer 	 */
4190bc20bbaSTodd Fischer 
42031dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
4210bc20bbaSTodd Fischer 	if (!tps_board)
4220bc20bbaSTodd Fischer 		return -EINVAL;
4230bc20bbaSTodd Fischer 
4240bc20bbaSTodd Fischer 	/**
4253fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
4263fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
4273fa5b8e0SAnuj Aggarwal 	 */
4280bc20bbaSTodd Fischer 	init_data = tps_board->tps6507x_pmic_init_data;
4293fa5b8e0SAnuj Aggarwal 	if (!init_data)
4300bc20bbaSTodd Fischer 		return -EINVAL;
4313fa5b8e0SAnuj Aggarwal 
432*9eb0c421SAxel Lin 	tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL);
4333fa5b8e0SAnuj Aggarwal 	if (!tps)
4343fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
4353fa5b8e0SAnuj Aggarwal 
4363fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
4373fa5b8e0SAnuj Aggarwal 
4383fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
43931dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
4403fa5b8e0SAnuj Aggarwal 
4413fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
4423fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
4433fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
4447d14831eSAnuj Aggarwal 		if (init_data->driver_data) {
4457d14831eSAnuj Aggarwal 			struct tps6507x_reg_platform_data *data =
4467d14831eSAnuj Aggarwal 							init_data->driver_data;
4477d14831eSAnuj Aggarwal 			tps->info[i]->defdcdc_default = data->defdcdc_default;
4487d14831eSAnuj Aggarwal 		}
4497d14831eSAnuj Aggarwal 
4503fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
45177fa44d0SAxel Lin 		tps->desc[i].id = i;
4520fcdb109SAxel Lin 		tps->desc[i].n_voltages = info->table_len;
453f2933d33SAxel Lin 		tps->desc[i].ops = &tps6507x_pmic_ops;
4543fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
4553fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
4563fa5b8e0SAnuj Aggarwal 
457c172708dSMark Brown 		config.dev = tps6507x_dev->dev;
458c172708dSMark Brown 		config.init_data = init_data;
459c172708dSMark Brown 		config.driver_data = tps;
460c172708dSMark Brown 
461c172708dSMark Brown 		rdev = regulator_register(&tps->desc[i], &config);
4623fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
46331dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
46431dd6a26STodd Fischer 				"failed to register %s regulator\n",
46531dd6a26STodd Fischer 				pdev->name);
46656c23492SDmitry Torokhov 			error = PTR_ERR(rdev);
46756c23492SDmitry Torokhov 			goto fail;
4683fa5b8e0SAnuj Aggarwal 		}
4693fa5b8e0SAnuj Aggarwal 
4703fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
4713fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
4723fa5b8e0SAnuj Aggarwal 	}
4733fa5b8e0SAnuj Aggarwal 
47431dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
475d7399fa8SAxel Lin 	platform_set_drvdata(pdev, tps6507x_dev);
4763fa5b8e0SAnuj Aggarwal 
4773fa5b8e0SAnuj Aggarwal 	return 0;
47856c23492SDmitry Torokhov 
47956c23492SDmitry Torokhov fail:
48056c23492SDmitry Torokhov 	while (--i >= 0)
48156c23492SDmitry Torokhov 		regulator_unregister(tps->rdev[i]);
48256c23492SDmitry Torokhov 	return error;
4833fa5b8e0SAnuj Aggarwal }
4843fa5b8e0SAnuj Aggarwal 
48531dd6a26STodd Fischer static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
4863fa5b8e0SAnuj Aggarwal {
48731dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
48831dd6a26STodd Fischer 	struct tps6507x_pmic *tps = tps6507x_dev->pmic;
4893fa5b8e0SAnuj Aggarwal 	int i;
4903fa5b8e0SAnuj Aggarwal 
4913fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
4923fa5b8e0SAnuj Aggarwal 		regulator_unregister(tps->rdev[i]);
4933fa5b8e0SAnuj Aggarwal 	return 0;
4943fa5b8e0SAnuj Aggarwal }
4953fa5b8e0SAnuj Aggarwal 
49631dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
4973fa5b8e0SAnuj Aggarwal 	.driver = {
49831dd6a26STodd Fischer 		.name = "tps6507x-pmic",
4993fa5b8e0SAnuj Aggarwal 		.owner = THIS_MODULE,
5003fa5b8e0SAnuj Aggarwal 	},
5014ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
5024ce5ba5bSTodd Fischer 	.remove = __devexit_p(tps6507x_pmic_remove),
5033fa5b8e0SAnuj Aggarwal };
5043fa5b8e0SAnuj Aggarwal 
5054ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
5063fa5b8e0SAnuj Aggarwal {
50731dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
5083fa5b8e0SAnuj Aggarwal }
5094ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
5103fa5b8e0SAnuj Aggarwal 
5114ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
5123fa5b8e0SAnuj Aggarwal {
51331dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
5143fa5b8e0SAnuj Aggarwal }
5154ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
5163fa5b8e0SAnuj Aggarwal 
5173fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
5183fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
5193fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
52031dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
521