xref: /linux/drivers/regulator/tps6507x-regulator.c (revision 055917ac560a4185b75511b512f2db941b984672)
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 
46*055917acSAxel Lin /* Supported voltage values for regulators (in microVolts) */
47*055917acSAxel Lin static const unsigned int VDCDCx_VSEL_table[] = {
48*055917acSAxel Lin 	725000, 750000, 775000, 800000,
49*055917acSAxel Lin 	825000, 850000, 875000, 900000,
50*055917acSAxel Lin 	925000, 950000, 975000, 1000000,
51*055917acSAxel Lin 	1025000, 1050000, 1075000, 1100000,
52*055917acSAxel Lin 	1125000, 1150000, 1175000, 1200000,
53*055917acSAxel Lin 	1225000, 1250000, 1275000, 1300000,
54*055917acSAxel Lin 	1325000, 1350000, 1375000, 1400000,
55*055917acSAxel Lin 	1425000, 1450000, 1475000, 1500000,
56*055917acSAxel Lin 	1550000, 1600000, 1650000, 1700000,
57*055917acSAxel Lin 	1750000, 1800000, 1850000, 1900000,
58*055917acSAxel Lin 	1950000, 2000000, 2050000, 2100000,
59*055917acSAxel Lin 	2150000, 2200000, 2250000, 2300000,
60*055917acSAxel Lin 	2350000, 2400000, 2450000, 2500000,
61*055917acSAxel Lin 	2550000, 2600000, 2650000, 2700000,
62*055917acSAxel Lin 	2750000, 2800000, 2850000, 2900000,
63*055917acSAxel Lin 	3000000, 3100000, 3200000, 3300000,
643fa5b8e0SAnuj Aggarwal };
653fa5b8e0SAnuj Aggarwal 
66*055917acSAxel Lin static const unsigned int LDO1_VSEL_table[] = {
67*055917acSAxel Lin 	1000000, 1100000, 1200000, 1250000,
68*055917acSAxel Lin 	1300000, 1350000, 1400000, 1500000,
69*055917acSAxel Lin 	1600000, 1800000, 2500000, 2750000,
70*055917acSAxel Lin 	2800000, 3000000, 3100000, 3300000,
713fa5b8e0SAnuj Aggarwal };
723fa5b8e0SAnuj Aggarwal 
73*055917acSAxel Lin static const unsigned int LDO2_VSEL_table[] = {
74*055917acSAxel Lin 	725000, 750000, 775000, 800000,
75*055917acSAxel Lin 	825000, 850000, 875000, 900000,
76*055917acSAxel Lin 	925000, 950000, 975000, 1000000,
77*055917acSAxel Lin 	1025000, 1050000, 1075000, 1100000,
78*055917acSAxel Lin 	1125000, 1150000, 1175000, 1200000,
79*055917acSAxel Lin 	1225000, 1250000, 1275000, 1300000,
80*055917acSAxel Lin 	1325000, 1350000, 1375000, 1400000,
81*055917acSAxel Lin 	1425000, 1450000, 1475000, 1500000,
82*055917acSAxel Lin 	1550000, 1600000, 1650000, 1700000,
83*055917acSAxel Lin 	1750000, 1800000, 1850000, 1900000,
84*055917acSAxel Lin 	1950000, 2000000, 2050000, 2100000,
85*055917acSAxel Lin 	2150000, 2200000, 2250000, 2300000,
86*055917acSAxel Lin 	2350000, 2400000, 2450000, 2500000,
87*055917acSAxel Lin 	2550000, 2600000, 2650000, 2700000,
88*055917acSAxel Lin 	2750000, 2800000, 2850000, 2900000,
89*055917acSAxel Lin 	3000000, 3100000, 3200000, 3300000,
903fa5b8e0SAnuj Aggarwal };
913fa5b8e0SAnuj Aggarwal 
923fa5b8e0SAnuj Aggarwal struct tps_info {
933fa5b8e0SAnuj Aggarwal 	const char *name;
943fa5b8e0SAnuj Aggarwal 	unsigned min_uV;
953fa5b8e0SAnuj Aggarwal 	unsigned max_uV;
963fa5b8e0SAnuj Aggarwal 	u8 table_len;
97*055917acSAxel Lin 	const unsigned int *table;
987d14831eSAnuj Aggarwal 
997d14831eSAnuj Aggarwal 	/* Does DCDC high or the low register defines output voltage? */
1007d14831eSAnuj Aggarwal 	bool defdcdc_default;
1013fa5b8e0SAnuj Aggarwal };
1023fa5b8e0SAnuj Aggarwal 
1037d14831eSAnuj Aggarwal static struct tps_info tps6507x_pmic_regs[] = {
10431dd6a26STodd Fischer 	{
10531dd6a26STodd Fischer 		.name = "VDCDC1",
10631dd6a26STodd Fischer 		.min_uV = 725000,
10731dd6a26STodd Fischer 		.max_uV = 3300000,
10831dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
10931dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
11031dd6a26STodd Fischer 	},
11131dd6a26STodd Fischer 	{
11231dd6a26STodd Fischer 		.name = "VDCDC2",
11331dd6a26STodd Fischer 		.min_uV = 725000,
11431dd6a26STodd Fischer 		.max_uV = 3300000,
11531dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
11631dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
11731dd6a26STodd Fischer 	},
11831dd6a26STodd Fischer 	{
11931dd6a26STodd Fischer 		.name = "VDCDC3",
12031dd6a26STodd Fischer 		.min_uV = 725000,
12131dd6a26STodd Fischer 		.max_uV = 3300000,
12231dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
12331dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
12431dd6a26STodd Fischer 	},
12531dd6a26STodd Fischer 	{
12631dd6a26STodd Fischer 		.name = "LDO1",
12731dd6a26STodd Fischer 		.min_uV = 1000000,
12831dd6a26STodd Fischer 		.max_uV = 3300000,
12931dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
13031dd6a26STodd Fischer 		.table = LDO1_VSEL_table,
13131dd6a26STodd Fischer 	},
13231dd6a26STodd Fischer 	{
13331dd6a26STodd Fischer 		.name = "LDO2",
13431dd6a26STodd Fischer 		.min_uV = 725000,
13531dd6a26STodd Fischer 		.max_uV = 3300000,
13631dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
13731dd6a26STodd Fischer 		.table = LDO2_VSEL_table,
13831dd6a26STodd Fischer 	},
13931dd6a26STodd Fischer };
14031dd6a26STodd Fischer 
1414ce5ba5bSTodd Fischer struct tps6507x_pmic {
1423fa5b8e0SAnuj Aggarwal 	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
14331dd6a26STodd Fischer 	struct tps6507x_dev *mfd;
1443fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
1457d14831eSAnuj Aggarwal 	struct tps_info *info[TPS6507X_NUM_REGULATOR];
1463fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
1473fa5b8e0SAnuj Aggarwal };
1484ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
1493fa5b8e0SAnuj Aggarwal {
15031dd6a26STodd Fischer 	u8 val;
15131dd6a26STodd Fischer 	int err;
15231dd6a26STodd Fischer 
15331dd6a26STodd Fischer 	err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
15431dd6a26STodd Fischer 
15531dd6a26STodd Fischer 	if (err)
15631dd6a26STodd Fischer 		return err;
15731dd6a26STodd Fischer 
15831dd6a26STodd Fischer 	return val;
1593fa5b8e0SAnuj Aggarwal }
1603fa5b8e0SAnuj Aggarwal 
1614ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1623fa5b8e0SAnuj Aggarwal {
16331dd6a26STodd Fischer 	return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
1643fa5b8e0SAnuj Aggarwal }
1653fa5b8e0SAnuj Aggarwal 
1664ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1673fa5b8e0SAnuj Aggarwal {
1683fa5b8e0SAnuj Aggarwal 	int err, data;
1693fa5b8e0SAnuj Aggarwal 
1703fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1713fa5b8e0SAnuj Aggarwal 
1724ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1733fa5b8e0SAnuj Aggarwal 	if (data < 0) {
17431dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1753fa5b8e0SAnuj Aggarwal 		err = data;
1763fa5b8e0SAnuj Aggarwal 		goto out;
1773fa5b8e0SAnuj Aggarwal 	}
1783fa5b8e0SAnuj Aggarwal 
1793fa5b8e0SAnuj Aggarwal 	data |= mask;
1804ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1813fa5b8e0SAnuj Aggarwal 	if (err)
18231dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1833fa5b8e0SAnuj Aggarwal 
1843fa5b8e0SAnuj Aggarwal out:
1853fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1863fa5b8e0SAnuj Aggarwal 	return err;
1873fa5b8e0SAnuj Aggarwal }
1883fa5b8e0SAnuj Aggarwal 
1894ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1903fa5b8e0SAnuj Aggarwal {
1913fa5b8e0SAnuj Aggarwal 	int err, data;
1923fa5b8e0SAnuj Aggarwal 
1933fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1943fa5b8e0SAnuj Aggarwal 
1954ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1963fa5b8e0SAnuj Aggarwal 	if (data < 0) {
19731dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1983fa5b8e0SAnuj Aggarwal 		err = data;
1993fa5b8e0SAnuj Aggarwal 		goto out;
2003fa5b8e0SAnuj Aggarwal 	}
2013fa5b8e0SAnuj Aggarwal 
2023fa5b8e0SAnuj Aggarwal 	data &= ~mask;
2034ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
2043fa5b8e0SAnuj Aggarwal 	if (err)
20531dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2063fa5b8e0SAnuj Aggarwal 
2073fa5b8e0SAnuj Aggarwal out:
2083fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2093fa5b8e0SAnuj Aggarwal 	return err;
2103fa5b8e0SAnuj Aggarwal }
2113fa5b8e0SAnuj Aggarwal 
2124ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
2133fa5b8e0SAnuj Aggarwal {
2143fa5b8e0SAnuj Aggarwal 	int data;
2153fa5b8e0SAnuj Aggarwal 
2163fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2173fa5b8e0SAnuj Aggarwal 
2184ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
2193fa5b8e0SAnuj Aggarwal 	if (data < 0)
22031dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
2213fa5b8e0SAnuj Aggarwal 
2223fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2233fa5b8e0SAnuj Aggarwal 	return data;
2243fa5b8e0SAnuj Aggarwal }
2253fa5b8e0SAnuj Aggarwal 
2264ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
2273fa5b8e0SAnuj Aggarwal {
2283fa5b8e0SAnuj Aggarwal 	int err;
2293fa5b8e0SAnuj Aggarwal 
2303fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2313fa5b8e0SAnuj Aggarwal 
2324ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, val);
2333fa5b8e0SAnuj Aggarwal 	if (err < 0)
23431dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2353fa5b8e0SAnuj Aggarwal 
2363fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2373fa5b8e0SAnuj Aggarwal 	return err;
2383fa5b8e0SAnuj Aggarwal }
2393fa5b8e0SAnuj Aggarwal 
240f2933d33SAxel Lin static int tps6507x_pmic_is_enabled(struct regulator_dev *dev)
2413fa5b8e0SAnuj Aggarwal {
2424ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
243f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
2443fa5b8e0SAnuj Aggarwal 	u8 shift;
2453fa5b8e0SAnuj Aggarwal 
246f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2473fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2483fa5b8e0SAnuj Aggarwal 
249f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2504ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2513fa5b8e0SAnuj Aggarwal 
2523fa5b8e0SAnuj Aggarwal 	if (data < 0)
2533fa5b8e0SAnuj Aggarwal 		return data;
2543fa5b8e0SAnuj Aggarwal 	else
2553fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2563fa5b8e0SAnuj Aggarwal }
2573fa5b8e0SAnuj Aggarwal 
258f2933d33SAxel Lin static int tps6507x_pmic_enable(struct regulator_dev *dev)
2593fa5b8e0SAnuj Aggarwal {
2604ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
261f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2623fa5b8e0SAnuj Aggarwal 	u8 shift;
2633fa5b8e0SAnuj Aggarwal 
264f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2653fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2663fa5b8e0SAnuj Aggarwal 
267f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2684ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
2693fa5b8e0SAnuj Aggarwal }
2703fa5b8e0SAnuj Aggarwal 
271f2933d33SAxel Lin static int tps6507x_pmic_disable(struct regulator_dev *dev)
2723fa5b8e0SAnuj Aggarwal {
2734ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
274f2933d33SAxel Lin 	int rid = rdev_get_id(dev);
2753fa5b8e0SAnuj Aggarwal 	u8 shift;
2763fa5b8e0SAnuj Aggarwal 
277f2933d33SAxel Lin 	if (rid < TPS6507X_DCDC_1 || rid > TPS6507X_LDO_2)
2783fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2793fa5b8e0SAnuj Aggarwal 
280f2933d33SAxel Lin 	shift = TPS6507X_MAX_REG_ID - rid;
2814ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
2824ce5ba5bSTodd Fischer 					1 << shift);
2833fa5b8e0SAnuj Aggarwal }
2843fa5b8e0SAnuj Aggarwal 
2857c842a1dSAxel Lin static int tps6507x_pmic_get_voltage_sel(struct regulator_dev *dev)
2863fa5b8e0SAnuj Aggarwal {
2874ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
288f2933d33SAxel Lin 	int data, rid = rdev_get_id(dev);
289f2933d33SAxel Lin 	u8 reg, mask;
2903fa5b8e0SAnuj Aggarwal 
291f2933d33SAxel Lin 	switch (rid) {
2923fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
2933fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
294f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
2953fa5b8e0SAnuj Aggarwal 		break;
2963fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
297f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
2987d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
2997d14831eSAnuj Aggarwal 		else
3003fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
301f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3023fa5b8e0SAnuj Aggarwal 		break;
3033fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
304f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3057d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3067d14831eSAnuj Aggarwal 		else
3073fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
308f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
309f2933d33SAxel Lin 		break;
310f2933d33SAxel Lin 	case TPS6507X_LDO_1:
311f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
312f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
313f2933d33SAxel Lin 		break;
314f2933d33SAxel Lin 	case TPS6507X_LDO_2:
315f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
316f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
3173fa5b8e0SAnuj Aggarwal 		break;
3183fa5b8e0SAnuj Aggarwal 	default:
3193fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3203fa5b8e0SAnuj Aggarwal 	}
3213fa5b8e0SAnuj Aggarwal 
3224ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3233fa5b8e0SAnuj Aggarwal 	if (data < 0)
3243fa5b8e0SAnuj Aggarwal 		return data;
3253fa5b8e0SAnuj Aggarwal 
326f2933d33SAxel Lin 	data &= mask;
3277c842a1dSAxel Lin 	return data;
3283fa5b8e0SAnuj Aggarwal }
3293fa5b8e0SAnuj Aggarwal 
330ca61a7bfSAxel Lin static int tps6507x_pmic_set_voltage_sel(struct regulator_dev *dev,
331ca61a7bfSAxel Lin 					  unsigned selector)
3323fa5b8e0SAnuj Aggarwal {
3334ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
334ca61a7bfSAxel Lin 	int data, rid = rdev_get_id(dev);
335f2933d33SAxel Lin 	u8 reg, mask;
3363fa5b8e0SAnuj Aggarwal 
337f2933d33SAxel Lin 	switch (rid) {
3383fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3393fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
340f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3413fa5b8e0SAnuj Aggarwal 		break;
3423fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
343f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3447d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3457d14831eSAnuj Aggarwal 		else
3463fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
347f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
3483fa5b8e0SAnuj Aggarwal 		break;
3493fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
350f2933d33SAxel Lin 		if (tps->info[rid]->defdcdc_default)
3517d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3527d14831eSAnuj Aggarwal 		else
3533fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
354f2933d33SAxel Lin 		mask = TPS6507X_DEFDCDCX_DCDC_MASK;
355f2933d33SAxel Lin 		break;
356f2933d33SAxel Lin 	case TPS6507X_LDO_1:
357f2933d33SAxel Lin 		reg = TPS6507X_REG_LDO_CTRL1;
358f2933d33SAxel Lin 		mask = TPS6507X_REG_LDO_CTRL1_LDO1_MASK;
359f2933d33SAxel Lin 		break;
360f2933d33SAxel Lin 	case TPS6507X_LDO_2:
361f2933d33SAxel Lin 		reg = TPS6507X_REG_DEFLDO2;
362f2933d33SAxel Lin 		mask = TPS6507X_REG_DEFLDO2_LDO2_MASK;
3633fa5b8e0SAnuj Aggarwal 		break;
3643fa5b8e0SAnuj Aggarwal 	default:
3653fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3663fa5b8e0SAnuj Aggarwal 	}
3673fa5b8e0SAnuj Aggarwal 
3684ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3693fa5b8e0SAnuj Aggarwal 	if (data < 0)
3703fa5b8e0SAnuj Aggarwal 		return data;
3713fa5b8e0SAnuj Aggarwal 
3723fa5b8e0SAnuj Aggarwal 	data &= ~mask;
373ca61a7bfSAxel Lin 	data |= selector;
3743fa5b8e0SAnuj Aggarwal 
3754ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
3763fa5b8e0SAnuj Aggarwal }
3773fa5b8e0SAnuj Aggarwal 
378f2933d33SAxel Lin static struct regulator_ops tps6507x_pmic_ops = {
379f2933d33SAxel Lin 	.is_enabled = tps6507x_pmic_is_enabled,
380f2933d33SAxel Lin 	.enable = tps6507x_pmic_enable,
381f2933d33SAxel Lin 	.disable = tps6507x_pmic_disable,
3827c842a1dSAxel Lin 	.get_voltage_sel = tps6507x_pmic_get_voltage_sel,
383ca61a7bfSAxel Lin 	.set_voltage_sel = tps6507x_pmic_set_voltage_sel,
384*055917acSAxel Lin 	.list_voltage = regulator_list_voltage_table,
3853fa5b8e0SAnuj Aggarwal };
3863fa5b8e0SAnuj Aggarwal 
387f2933d33SAxel Lin static __devinit int tps6507x_pmic_probe(struct platform_device *pdev)
3883fa5b8e0SAnuj Aggarwal {
38931dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
3907d14831eSAnuj Aggarwal 	struct tps_info *info = &tps6507x_pmic_regs[0];
391c172708dSMark Brown 	struct regulator_config config = { };
3923fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
3933fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
3944ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
3950bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
3963fa5b8e0SAnuj Aggarwal 	int i;
39756c23492SDmitry Torokhov 	int error;
3983fa5b8e0SAnuj Aggarwal 
3993fa5b8e0SAnuj Aggarwal 	/**
4000bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
4010bc20bbaSTodd Fischer 	 * coming from the board-evm file.
4020bc20bbaSTodd Fischer 	 */
4030bc20bbaSTodd Fischer 
40431dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
4050bc20bbaSTodd Fischer 	if (!tps_board)
4060bc20bbaSTodd Fischer 		return -EINVAL;
4070bc20bbaSTodd Fischer 
4080bc20bbaSTodd Fischer 	/**
4093fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
4103fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
4113fa5b8e0SAnuj Aggarwal 	 */
4120bc20bbaSTodd Fischer 	init_data = tps_board->tps6507x_pmic_init_data;
4133fa5b8e0SAnuj Aggarwal 	if (!init_data)
4140bc20bbaSTodd Fischer 		return -EINVAL;
4153fa5b8e0SAnuj Aggarwal 
4169eb0c421SAxel Lin 	tps = devm_kzalloc(&pdev->dev, sizeof(*tps), GFP_KERNEL);
4173fa5b8e0SAnuj Aggarwal 	if (!tps)
4183fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
4193fa5b8e0SAnuj Aggarwal 
4203fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
4213fa5b8e0SAnuj Aggarwal 
4223fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
42331dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
4243fa5b8e0SAnuj Aggarwal 
4253fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
4263fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
4273fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
4287d14831eSAnuj Aggarwal 		if (init_data->driver_data) {
4297d14831eSAnuj Aggarwal 			struct tps6507x_reg_platform_data *data =
4307d14831eSAnuj Aggarwal 							init_data->driver_data;
4317d14831eSAnuj Aggarwal 			tps->info[i]->defdcdc_default = data->defdcdc_default;
4327d14831eSAnuj Aggarwal 		}
4337d14831eSAnuj Aggarwal 
4343fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
43577fa44d0SAxel Lin 		tps->desc[i].id = i;
4360fcdb109SAxel Lin 		tps->desc[i].n_voltages = info->table_len;
437*055917acSAxel Lin 		tps->desc[i].volt_table = info->table;
438f2933d33SAxel Lin 		tps->desc[i].ops = &tps6507x_pmic_ops;
4393fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
4403fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
4413fa5b8e0SAnuj Aggarwal 
442c172708dSMark Brown 		config.dev = tps6507x_dev->dev;
443c172708dSMark Brown 		config.init_data = init_data;
444c172708dSMark Brown 		config.driver_data = tps;
445c172708dSMark Brown 
446c172708dSMark Brown 		rdev = regulator_register(&tps->desc[i], &config);
4473fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
44831dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
44931dd6a26STodd Fischer 				"failed to register %s regulator\n",
45031dd6a26STodd Fischer 				pdev->name);
45156c23492SDmitry Torokhov 			error = PTR_ERR(rdev);
45256c23492SDmitry Torokhov 			goto fail;
4533fa5b8e0SAnuj Aggarwal 		}
4543fa5b8e0SAnuj Aggarwal 
4553fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
4563fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
4573fa5b8e0SAnuj Aggarwal 	}
4583fa5b8e0SAnuj Aggarwal 
45931dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
460d7399fa8SAxel Lin 	platform_set_drvdata(pdev, tps6507x_dev);
4613fa5b8e0SAnuj Aggarwal 
4623fa5b8e0SAnuj Aggarwal 	return 0;
46356c23492SDmitry Torokhov 
46456c23492SDmitry Torokhov fail:
46556c23492SDmitry Torokhov 	while (--i >= 0)
46656c23492SDmitry Torokhov 		regulator_unregister(tps->rdev[i]);
46756c23492SDmitry Torokhov 	return error;
4683fa5b8e0SAnuj Aggarwal }
4693fa5b8e0SAnuj Aggarwal 
47031dd6a26STodd Fischer static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
4713fa5b8e0SAnuj Aggarwal {
47231dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
47331dd6a26STodd Fischer 	struct tps6507x_pmic *tps = tps6507x_dev->pmic;
4743fa5b8e0SAnuj Aggarwal 	int i;
4753fa5b8e0SAnuj Aggarwal 
4763fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
4773fa5b8e0SAnuj Aggarwal 		regulator_unregister(tps->rdev[i]);
4783fa5b8e0SAnuj Aggarwal 	return 0;
4793fa5b8e0SAnuj Aggarwal }
4803fa5b8e0SAnuj Aggarwal 
48131dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
4823fa5b8e0SAnuj Aggarwal 	.driver = {
48331dd6a26STodd Fischer 		.name = "tps6507x-pmic",
4843fa5b8e0SAnuj Aggarwal 		.owner = THIS_MODULE,
4853fa5b8e0SAnuj Aggarwal 	},
4864ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
4874ce5ba5bSTodd Fischer 	.remove = __devexit_p(tps6507x_pmic_remove),
4883fa5b8e0SAnuj Aggarwal };
4893fa5b8e0SAnuj Aggarwal 
4904ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
4913fa5b8e0SAnuj Aggarwal {
49231dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
4933fa5b8e0SAnuj Aggarwal }
4944ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
4953fa5b8e0SAnuj Aggarwal 
4964ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
4973fa5b8e0SAnuj Aggarwal {
49831dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
4993fa5b8e0SAnuj Aggarwal }
5004ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
5013fa5b8e0SAnuj Aggarwal 
5023fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
5033fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
5043fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
50531dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
506