xref: /openbmc/linux/drivers/regulator/tps6507x-regulator.c (revision 93b07e7bcd50bb73d3d60043438fa68bd5a0988b)
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>
265a0e3ad6STejun Heo #include <linux/slab.h>
27d183fcc9STodd Fischer #include <linux/mfd/tps6507x.h>
283fa5b8e0SAnuj Aggarwal 
293fa5b8e0SAnuj Aggarwal /* DCDC's */
303fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_1				0
313fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_2				1
323fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_3				2
333fa5b8e0SAnuj Aggarwal /* LDOs */
343fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_1				3
353fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_2				4
363fa5b8e0SAnuj Aggarwal 
373fa5b8e0SAnuj Aggarwal #define TPS6507X_MAX_REG_ID			TPS6507X_LDO_2
383fa5b8e0SAnuj Aggarwal 
393fa5b8e0SAnuj Aggarwal /* Number of step-down converters available */
403fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_DCDC			3
413fa5b8e0SAnuj Aggarwal /* Number of LDO voltage regulators  available */
423fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_LDO			2
433fa5b8e0SAnuj Aggarwal /* Number of total regulators available */
443fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_REGULATOR		(TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
453fa5b8e0SAnuj Aggarwal 
46055917acSAxel Lin /* Supported voltage values for regulators (in microVolts) */
47055917acSAxel Lin static const unsigned int VDCDCx_VSEL_table[] = {
48055917acSAxel Lin 	725000, 750000, 775000, 800000,
49055917acSAxel Lin 	825000, 850000, 875000, 900000,
50055917acSAxel Lin 	925000, 950000, 975000, 1000000,
51055917acSAxel Lin 	1025000, 1050000, 1075000, 1100000,
52055917acSAxel Lin 	1125000, 1150000, 1175000, 1200000,
53055917acSAxel Lin 	1225000, 1250000, 1275000, 1300000,
54055917acSAxel Lin 	1325000, 1350000, 1375000, 1400000,
55055917acSAxel Lin 	1425000, 1450000, 1475000, 1500000,
56055917acSAxel Lin 	1550000, 1600000, 1650000, 1700000,
57055917acSAxel Lin 	1750000, 1800000, 1850000, 1900000,
58055917acSAxel Lin 	1950000, 2000000, 2050000, 2100000,
59055917acSAxel Lin 	2150000, 2200000, 2250000, 2300000,
60055917acSAxel Lin 	2350000, 2400000, 2450000, 2500000,
61055917acSAxel Lin 	2550000, 2600000, 2650000, 2700000,
62055917acSAxel Lin 	2750000, 2800000, 2850000, 2900000,
63055917acSAxel Lin 	3000000, 3100000, 3200000, 3300000,
643fa5b8e0SAnuj Aggarwal };
653fa5b8e0SAnuj Aggarwal 
66055917acSAxel Lin static const unsigned int LDO1_VSEL_table[] = {
67055917acSAxel Lin 	1000000, 1100000, 1200000, 1250000,
68055917acSAxel Lin 	1300000, 1350000, 1400000, 1500000,
69055917acSAxel Lin 	1600000, 1800000, 2500000, 2750000,
70055917acSAxel Lin 	2800000, 3000000, 3100000, 3300000,
713fa5b8e0SAnuj Aggarwal };
723fa5b8e0SAnuj Aggarwal 
73*93b07e7bSAxel Lin /* The voltage mapping table for LDO2 is the same as VDCDCx */
74*93b07e7bSAxel Lin #define LDO2_VSEL_table VDCDCx_VSEL_table
753fa5b8e0SAnuj Aggarwal 
763fa5b8e0SAnuj Aggarwal struct tps_info {
773fa5b8e0SAnuj Aggarwal 	const char *name;
783fa5b8e0SAnuj Aggarwal 	u8 table_len;
79055917acSAxel Lin 	const unsigned int *table;
807d14831eSAnuj Aggarwal 
817d14831eSAnuj Aggarwal 	/* Does DCDC high or the low register defines output voltage? */
827d14831eSAnuj Aggarwal 	bool defdcdc_default;
833fa5b8e0SAnuj Aggarwal };
843fa5b8e0SAnuj Aggarwal 
857d14831eSAnuj Aggarwal static struct tps_info tps6507x_pmic_regs[] = {
8631dd6a26STodd Fischer 	{
8731dd6a26STodd Fischer 		.name = "VDCDC1",
8831dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
8931dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
9031dd6a26STodd Fischer 	},
9131dd6a26STodd Fischer 	{
9231dd6a26STodd Fischer 		.name = "VDCDC2",
9331dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
9431dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
9531dd6a26STodd Fischer 	},
9631dd6a26STodd Fischer 	{
9731dd6a26STodd Fischer 		.name = "VDCDC3",
9831dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
9931dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
10031dd6a26STodd Fischer 	},
10131dd6a26STodd Fischer 	{
10231dd6a26STodd Fischer 		.name = "LDO1",
10331dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
10431dd6a26STodd Fischer 		.table = LDO1_VSEL_table,
10531dd6a26STodd Fischer 	},
10631dd6a26STodd Fischer 	{
10731dd6a26STodd Fischer 		.name = "LDO2",
10831dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
10931dd6a26STodd Fischer 		.table = LDO2_VSEL_table,
11031dd6a26STodd Fischer 	},
11131dd6a26STodd Fischer };
11231dd6a26STodd Fischer 
1134ce5ba5bSTodd Fischer struct tps6507x_pmic {
1143fa5b8e0SAnuj Aggarwal 	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
11531dd6a26STodd Fischer 	struct tps6507x_dev *mfd;
1163fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
1177d14831eSAnuj Aggarwal 	struct tps_info *info[TPS6507X_NUM_REGULATOR];
1183fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
1193fa5b8e0SAnuj Aggarwal };
1204ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
1213fa5b8e0SAnuj Aggarwal {
12231dd6a26STodd Fischer 	u8 val;
12331dd6a26STodd Fischer 	int err;
12431dd6a26STodd Fischer 
12531dd6a26STodd Fischer 	err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
12631dd6a26STodd Fischer 
12731dd6a26STodd Fischer 	if (err)
12831dd6a26STodd Fischer 		return err;
12931dd6a26STodd Fischer 
13031dd6a26STodd Fischer 	return val;
1313fa5b8e0SAnuj Aggarwal }
1323fa5b8e0SAnuj Aggarwal 
1334ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1343fa5b8e0SAnuj Aggarwal {
13531dd6a26STodd Fischer 	return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
1363fa5b8e0SAnuj Aggarwal }
1373fa5b8e0SAnuj Aggarwal 
1384ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1393fa5b8e0SAnuj Aggarwal {
1403fa5b8e0SAnuj Aggarwal 	int err, data;
1413fa5b8e0SAnuj Aggarwal 
1423fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1433fa5b8e0SAnuj Aggarwal 
1444ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1453fa5b8e0SAnuj Aggarwal 	if (data < 0) {
14631dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1473fa5b8e0SAnuj Aggarwal 		err = data;
1483fa5b8e0SAnuj Aggarwal 		goto out;
1493fa5b8e0SAnuj Aggarwal 	}
1503fa5b8e0SAnuj Aggarwal 
1513fa5b8e0SAnuj Aggarwal 	data |= mask;
1524ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1533fa5b8e0SAnuj Aggarwal 	if (err)
15431dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1553fa5b8e0SAnuj Aggarwal 
1563fa5b8e0SAnuj Aggarwal out:
1573fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1583fa5b8e0SAnuj Aggarwal 	return err;
1593fa5b8e0SAnuj Aggarwal }
1603fa5b8e0SAnuj Aggarwal 
1614ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1623fa5b8e0SAnuj Aggarwal {
1633fa5b8e0SAnuj Aggarwal 	int err, data;
1643fa5b8e0SAnuj Aggarwal 
1653fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1663fa5b8e0SAnuj Aggarwal 
1674ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1683fa5b8e0SAnuj Aggarwal 	if (data < 0) {
16931dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1703fa5b8e0SAnuj Aggarwal 		err = data;
1713fa5b8e0SAnuj Aggarwal 		goto out;
1723fa5b8e0SAnuj Aggarwal 	}
1733fa5b8e0SAnuj Aggarwal 
1743fa5b8e0SAnuj Aggarwal 	data &= ~mask;
1754ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1763fa5b8e0SAnuj Aggarwal 	if (err)
17731dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1783fa5b8e0SAnuj Aggarwal 
1793fa5b8e0SAnuj Aggarwal out:
1803fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1813fa5b8e0SAnuj Aggarwal 	return err;
1823fa5b8e0SAnuj Aggarwal }
1833fa5b8e0SAnuj Aggarwal 
1844ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
1853fa5b8e0SAnuj Aggarwal {
1863fa5b8e0SAnuj Aggarwal 	int data;
1873fa5b8e0SAnuj Aggarwal 
1883fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1893fa5b8e0SAnuj Aggarwal 
1904ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1913fa5b8e0SAnuj Aggarwal 	if (data < 0)
19231dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1933fa5b8e0SAnuj Aggarwal 
1943fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1953fa5b8e0SAnuj Aggarwal 	return data;
1963fa5b8e0SAnuj Aggarwal }
1973fa5b8e0SAnuj Aggarwal 
1984ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1993fa5b8e0SAnuj Aggarwal {
2003fa5b8e0SAnuj Aggarwal 	int err;
2013fa5b8e0SAnuj Aggarwal 
2023fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2033fa5b8e0SAnuj Aggarwal 
2044ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, val);
2053fa5b8e0SAnuj Aggarwal 	if (err < 0)
20631dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2073fa5b8e0SAnuj Aggarwal 
2083fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2093fa5b8e0SAnuj Aggarwal 	return err;
2103fa5b8e0SAnuj Aggarwal }
2113fa5b8e0SAnuj Aggarwal 
212f2933d33SAxel Lin static int tps6507x_pmic_is_enabled(struct regulator_dev *dev)
2133fa5b8e0SAnuj Aggarwal {
2144ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
215f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
2163fa5b8e0SAnuj Aggarwal 	u8 shift;
2173fa5b8e0SAnuj Aggarwal 
218f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2193fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2203fa5b8e0SAnuj Aggarwal 
221f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2224ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2233fa5b8e0SAnuj Aggarwal 
2243fa5b8e0SAnuj Aggarwal 	if (data < 0)
2253fa5b8e0SAnuj Aggarwal 		return data;
2263fa5b8e0SAnuj Aggarwal 	else
2273fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2283fa5b8e0SAnuj Aggarwal }
2293fa5b8e0SAnuj Aggarwal 
230f2933d33SAxel Lin static int tps6507x_pmic_enable(struct regulator_dev *dev)
2313fa5b8e0SAnuj Aggarwal {
2324ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
233f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2343fa5b8e0SAnuj Aggarwal 	u8 shift;
2353fa5b8e0SAnuj Aggarwal 
236f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2373fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2383fa5b8e0SAnuj Aggarwal 
239f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2404ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
2413fa5b8e0SAnuj Aggarwal }
2423fa5b8e0SAnuj Aggarwal 
243f2933d33SAxel Lin static int tps6507x_pmic_disable(struct regulator_dev *dev)
2443fa5b8e0SAnuj Aggarwal {
2454ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
246f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2473fa5b8e0SAnuj Aggarwal 	u8 shift;
2483fa5b8e0SAnuj Aggarwal 
249f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2503fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2513fa5b8e0SAnuj Aggarwal 
252f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2534ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
2544ce5ba5bSTodd Fischer 					1 << shift);
2553fa5b8e0SAnuj Aggarwal }
2563fa5b8e0SAnuj Aggarwal 
2577c842a1dSAxel Lin static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev)
2583fa5b8e0SAnuj Aggarwal {
2594ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
260f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
261f2933d33SAxel Lin 	u8 reg, mask;
2623fa5b8e0SAnuj Aggarwal 
263f2933d33SAxel Lin 	switch (rid) {
2643fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
2653fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
266f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2673fa5b8e0SAnuj Aggarwal 		break;
2683fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
269f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2707d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
2717d14831eSAnuj Aggarwal 		else
2723fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
273f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2743fa5b8e0SAnuj Aggarwal 		break;
2753fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
276f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2777d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
2787d14831eSAnuj Aggarwal 		else
2793fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
280f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
281f2933d33SAxel Lin 		break;
282f2933d33SAxel Lin 	case TPS6507X_LDO_1:
283f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
284f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
285f2933d33SAxel Lin 		break;
286f2933d33SAxel Lin 	case TPS6507X_LDO_2:
287f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
288f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
2893fa5b8e0SAnuj Aggarwal 		break;
2903fa5b8e0SAnuj Aggarwal 	default:
2913fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2923fa5b8e0SAnuj Aggarwal 	}
2933fa5b8e0SAnuj Aggarwal 
2944ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
2953fa5b8e0SAnuj Aggarwal 	if (data < 0)
2963fa5b8e0SAnuj Aggarwal 		return data;
2973fa5b8e0SAnuj Aggarwal 
298f2933d33SAxel Lin 	data &= mask;
2997c842a1dSAxel Lin 	return data;
3003fa5b8e0SAnuj Aggarwal }
3013fa5b8e0SAnuj Aggarwal 
302ca61a7bfSAxel Lin static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
303ca61a7bfSAxel Lin 					  unsigned selector)
3043fa5b8e0SAnuj Aggarwal {
3054ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
306ca61a7bfSAxel Lin 	int data, rid = rdev_get_id(dev);
307f2933d33SAxel Lin 	u8 reg, mask;
3083fa5b8e0SAnuj Aggarwal 
309f2933d33SAxel Lin 	switch (rid) {
3103fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3113fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
312f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3133fa5b8e0SAnuj Aggarwal 		break;
3143fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
315f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3167d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3177d14831eSAnuj Aggarwal 		else
3183fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
319f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3203fa5b8e0SAnuj Aggarwal 		break;
3213fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
322f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3237d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3247d14831eSAnuj Aggarwal 		else
3253fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
326f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
327f2933d33SAxel Lin 		break;
328f2933d33SAxel Lin 	case TPS6507X_LDO_1:
329f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
330f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
331f2933d33SAxel Lin 		break;
332f2933d33SAxel Lin 	case TPS6507X_LDO_2:
333f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
334f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
3353fa5b8e0SAnuj Aggarwal 		break;
3363fa5b8e0SAnuj Aggarwal 	default:
3373fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3383fa5b8e0SAnuj Aggarwal 	}
3393fa5b8e0SAnuj Aggarwal 
3404ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3413fa5b8e0SAnuj Aggarwal 	if (data < 0)
3423fa5b8e0SAnuj Aggarwal 		return data;
3433fa5b8e0SAnuj Aggarwal 
3443fa5b8e0SAnuj Aggarwal 	data &= ~mask;
345ca61a7bfSAxel Lin 	data |= selector;
3463fa5b8e0SAnuj Aggarwal 
3474ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
3483fa5b8e0SAnuj Aggarwal }
3493fa5b8e0SAnuj Aggarwal 
350f2933d33SAxel Lin static struct regulator_ops tps6507x_pmic_ops = {
351f2933d33SAxel Lin 	.is_enabled = tps6507x_pmic_is_enabled,
352f2933d33SAxel Lin 	.enable = tps6507x_pmic_enable,
353f2933d33SAxel Lin 	.disable = tps6507x_pmic_disable,
3547c842a1dSAxel Lin 	.get_voltage_sel = tps6507x_pmic_get_voltage_sel,
355ca61a7bfSAxel Lin 	.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
356055917acSAxel Lin 	.list_voltage = regulator_list_voltage_table,
3573fa5b8e0SAnuj Aggarwal };
3583fa5b8e0SAnuj Aggarwal 
359f2933d33SAxel Lin static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
3603fa5b8e0SAnuj Aggarwal {
36131dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
3627d14831eSAnuj Aggarwal 	struct tps_info *info = &tps6507x_pmic_regs[0];
363c172708dSMark Brown 	struct regulator_config config = { };
3643fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
3653fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
3664ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
3670bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
3683fa5b8e0SAnuj Aggarwal 	int i;
36956c23492SDmitry Torokhov 	int error;
3703fa5b8e0SAnuj Aggarwal 
3713fa5b8e0SAnuj Aggarwal 	/**
3720bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
3730bc20bbaSTodd Fischer 	 * coming from the board-evm file.
3740bc20bbaSTodd Fischer 	 */
3750bc20bbaSTodd Fischer 
37631dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
3770bc20bbaSTodd Fischer 	if (!tps_board)
3780bc20bbaSTodd Fischer 		return -EINVAL;
3790bc20bbaSTodd Fischer 
3800bc20bbaSTodd Fischer 	/**
3813fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
3823fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
3833fa5b8e0SAnuj Aggarwal 	 */
3840bc20bbaSTodd Fischer 	init_data = tps_board->tps6507x_pmic_init_data;
3853fa5b8e0SAnuj Aggarwal 	if (!init_data)
3860bc20bbaSTodd Fischer 		return -EINVAL;
3873fa5b8e0SAnuj Aggarwal 
3889eb0c421SAxel Lin 	tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL);
3893fa5b8e0SAnuj Aggarwal 	if (!tps)
3903fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
3913fa5b8e0SAnuj Aggarwal 
3923fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
3933fa5b8e0SAnuj Aggarwal 
3943fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
39531dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
3963fa5b8e0SAnuj Aggarwal 
3973fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
3983fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
3993fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
4007d14831eSAnuj Aggarwal 		if (init_data->driver_data) {
4017d14831eSAnuj Aggarwal 			struct tps6507x_reg_platform_data *data =
4027d14831eSAnuj Aggarwal 							init_data->driver_data;
4037d14831eSAnuj Aggarwal 			tps->info[i]->defdcdc_default = data->defdcdc_default;
4047d14831eSAnuj Aggarwal 		}
4057d14831eSAnuj Aggarwal 
4063fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
40777fa44d0SAxel Lin 		tps->desc[i].id = i;
4080fcdb109SAxel Lin 		tps->desc[i].n_voltages = info->table_len;
409055917acSAxel Lin 		tps->desc[i].volt_table = info->table;
410f2933d33SAxel Lin 		tps->desc[i].ops = &tps6507x_pmic_ops;
4113fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
4123fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
4133fa5b8e0SAnuj Aggarwal 
414c172708dSMark Brown 		config.dev = tps6507x_dev->dev;
415c172708dSMark Brown 		config.init_data = init_data;
416c172708dSMark Brown 		config.driver_data = tps;
417c172708dSMark Brown 
418c172708dSMark Brown 		rdev = regulator_register(&tps->desc[i], &config);
4193fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
42031dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
42131dd6a26STodd Fischer 				"failed to register %s regulator\n",
42231dd6a26STodd Fischer 				pdev->name);
42356c23492SDmitry Torokhov 			error = PTR_ERR(rdev);
42456c23492SDmitry Torokhov 			goto fail;
4253fa5b8e0SAnuj Aggarwal 		}
4263fa5b8e0SAnuj Aggarwal 
4273fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
4283fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
4293fa5b8e0SAnuj Aggarwal 	}
4303fa5b8e0SAnuj Aggarwal 
43131dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
432d7399fa8SAxel Lin 	platform_set_drvdata(pdev, tps6507x_dev);
4333fa5b8e0SAnuj Aggarwal 
4343fa5b8e0SAnuj Aggarwal 	return 0;
43556c23492SDmitry Torokhov 
43656c23492SDmitry Torokhov fail:
43756c23492SDmitry Torokhov 	while (--i >= 0)
43856c23492SDmitry Torokhov 		regulator_unregister(tps->rdev[i]);
43956c23492SDmitry Torokhov 	return error;
4403fa5b8e0SAnuj Aggarwal }
4413fa5b8e0SAnuj Aggarwal 
44231dd6a26STodd Fischer static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
4433fa5b8e0SAnuj Aggarwal {
44431dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
44531dd6a26STodd Fischer 	struct tps6507x_pmic *tps = tps6507x_dev->pmic;
4463fa5b8e0SAnuj Aggarwal 	int i;
4473fa5b8e0SAnuj Aggarwal 
4483fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
4493fa5b8e0SAnuj Aggarwal 		regulator_unregister(tps->rdev[i]);
4503fa5b8e0SAnuj Aggarwal 	return 0;
4513fa5b8e0SAnuj Aggarwal }
4523fa5b8e0SAnuj Aggarwal 
45331dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
4543fa5b8e0SAnuj Aggarwal 	.driver = {
45531dd6a26STodd Fischer 		.name = "tps6507x-pmic",
4563fa5b8e0SAnuj Aggarwal 		.owner = THIS_MODULE,
4573fa5b8e0SAnuj Aggarwal 	},
4584ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
4594ce5ba5bSTodd Fischer 	.remove = __devexit_p(tps6507x_pmic_remove),
4603fa5b8e0SAnuj Aggarwal };
4613fa5b8e0SAnuj Aggarwal 
4624ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
4633fa5b8e0SAnuj Aggarwal {
46431dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
4653fa5b8e0SAnuj Aggarwal }
4664ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
4673fa5b8e0SAnuj Aggarwal 
4684ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
4693fa5b8e0SAnuj Aggarwal {
47031dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
4713fa5b8e0SAnuj Aggarwal }
4724ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
4733fa5b8e0SAnuj Aggarwal 
4743fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
4753fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
4763fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
47731dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
478