xref: /linux/drivers/regulator/tps6507x-regulator.c (revision 31dd6a2672e337f5de188df3e5169ee732798236)
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>
253fa5b8e0SAnuj Aggarwal #include <linux/delay.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 
463fa5b8e0SAnuj Aggarwal /* Supported voltage values for regulators (in milliVolts) */
473fa5b8e0SAnuj Aggarwal static const u16 VDCDCx_VSEL_table[] = {
483fa5b8e0SAnuj Aggarwal 	725, 750, 775, 800,
493fa5b8e0SAnuj Aggarwal 	825, 850, 875, 900,
503fa5b8e0SAnuj Aggarwal 	925, 950, 975, 1000,
513fa5b8e0SAnuj Aggarwal 	1025, 1050, 1075, 1100,
523fa5b8e0SAnuj Aggarwal 	1125, 1150, 1175, 1200,
533fa5b8e0SAnuj Aggarwal 	1225, 1250, 1275, 1300,
543fa5b8e0SAnuj Aggarwal 	1325, 1350, 1375, 1400,
553fa5b8e0SAnuj Aggarwal 	1425, 1450, 1475, 1500,
563fa5b8e0SAnuj Aggarwal 	1550, 1600, 1650, 1700,
573fa5b8e0SAnuj Aggarwal 	1750, 1800, 1850, 1900,
583fa5b8e0SAnuj Aggarwal 	1950, 2000, 2050, 2100,
593fa5b8e0SAnuj Aggarwal 	2150, 2200, 2250, 2300,
603fa5b8e0SAnuj Aggarwal 	2350, 2400, 2450, 2500,
613fa5b8e0SAnuj Aggarwal 	2550, 2600, 2650, 2700,
623fa5b8e0SAnuj Aggarwal 	2750, 2800, 2850, 2900,
633fa5b8e0SAnuj Aggarwal 	3000, 3100, 3200, 3300,
643fa5b8e0SAnuj Aggarwal };
653fa5b8e0SAnuj Aggarwal 
663fa5b8e0SAnuj Aggarwal static const u16 LDO1_VSEL_table[] = {
673fa5b8e0SAnuj Aggarwal 	1000, 1100, 1200, 1250,
683fa5b8e0SAnuj Aggarwal 	1300, 1350, 1400, 1500,
693fa5b8e0SAnuj Aggarwal 	1600, 1800, 2500, 2750,
703fa5b8e0SAnuj Aggarwal 	2800, 3000, 3100, 3300,
713fa5b8e0SAnuj Aggarwal };
723fa5b8e0SAnuj Aggarwal 
733fa5b8e0SAnuj Aggarwal static const u16 LDO2_VSEL_table[] = {
743fa5b8e0SAnuj Aggarwal 	725, 750, 775, 800,
753fa5b8e0SAnuj Aggarwal 	825, 850, 875, 900,
763fa5b8e0SAnuj Aggarwal 	925, 950, 975, 1000,
773fa5b8e0SAnuj Aggarwal 	1025, 1050, 1075, 1100,
783fa5b8e0SAnuj Aggarwal 	1125, 1150, 1175, 1200,
793fa5b8e0SAnuj Aggarwal 	1225, 1250, 1275, 1300,
803fa5b8e0SAnuj Aggarwal 	1325, 1350, 1375, 1400,
813fa5b8e0SAnuj Aggarwal 	1425, 1450, 1475, 1500,
823fa5b8e0SAnuj Aggarwal 	1550, 1600, 1650, 1700,
833fa5b8e0SAnuj Aggarwal 	1750, 1800, 1850, 1900,
843fa5b8e0SAnuj Aggarwal 	1950, 2000, 2050, 2100,
853fa5b8e0SAnuj Aggarwal 	2150, 2200, 2250, 2300,
863fa5b8e0SAnuj Aggarwal 	2350, 2400, 2450, 2500,
873fa5b8e0SAnuj Aggarwal 	2550, 2600, 2650, 2700,
883fa5b8e0SAnuj Aggarwal 	2750, 2800, 2850, 2900,
893fa5b8e0SAnuj Aggarwal 	3000, 3100, 3200, 3300,
903fa5b8e0SAnuj Aggarwal };
913fa5b8e0SAnuj Aggarwal 
923fa5b8e0SAnuj Aggarwal static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDCx_VSEL_table),
933fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(VDCDCx_VSEL_table),
943fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(VDCDCx_VSEL_table),
953fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(LDO1_VSEL_table),
963fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(LDO2_VSEL_table)};
973fa5b8e0SAnuj Aggarwal 
983fa5b8e0SAnuj Aggarwal struct tps_info {
993fa5b8e0SAnuj Aggarwal 	const char *name;
1003fa5b8e0SAnuj Aggarwal 	unsigned min_uV;
1013fa5b8e0SAnuj Aggarwal 	unsigned max_uV;
1023fa5b8e0SAnuj Aggarwal 	u8 table_len;
1033fa5b8e0SAnuj Aggarwal 	const u16 *table;
1043fa5b8e0SAnuj Aggarwal };
1053fa5b8e0SAnuj Aggarwal 
106*31dd6a26STodd Fischer static const struct tps_info tps6507x_pmic_regs[] = {
107*31dd6a26STodd Fischer 	{
108*31dd6a26STodd Fischer 		.name = "VDCDC1",
109*31dd6a26STodd Fischer 		.min_uV = 725000,
110*31dd6a26STodd Fischer 		.max_uV = 3300000,
111*31dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
112*31dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
113*31dd6a26STodd Fischer 	},
114*31dd6a26STodd Fischer 	{
115*31dd6a26STodd Fischer 		.name = "VDCDC2",
116*31dd6a26STodd Fischer 		.min_uV = 725000,
117*31dd6a26STodd Fischer 		.max_uV = 3300000,
118*31dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
119*31dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
120*31dd6a26STodd Fischer 	},
121*31dd6a26STodd Fischer 	{
122*31dd6a26STodd Fischer 		.name = "VDCDC3",
123*31dd6a26STodd Fischer 		.min_uV = 725000,
124*31dd6a26STodd Fischer 		.max_uV = 3300000,
125*31dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
126*31dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
127*31dd6a26STodd Fischer 	},
128*31dd6a26STodd Fischer 	{
129*31dd6a26STodd Fischer 		.name = "LDO1",
130*31dd6a26STodd Fischer 		.min_uV = 1000000,
131*31dd6a26STodd Fischer 		.max_uV = 3300000,
132*31dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
133*31dd6a26STodd Fischer 		.table = LDO1_VSEL_table,
134*31dd6a26STodd Fischer 	},
135*31dd6a26STodd Fischer 	{
136*31dd6a26STodd Fischer 		.name = "LDO2",
137*31dd6a26STodd Fischer 		.min_uV = 725000,
138*31dd6a26STodd Fischer 		.max_uV = 3300000,
139*31dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
140*31dd6a26STodd Fischer 		.table = LDO2_VSEL_table,
141*31dd6a26STodd Fischer 	},
142*31dd6a26STodd Fischer };
143*31dd6a26STodd Fischer 
1444ce5ba5bSTodd Fischer struct tps6507x_pmic {
1453fa5b8e0SAnuj Aggarwal 	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
146*31dd6a26STodd Fischer 	struct tps6507x_dev *mfd;
1473fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
1483fa5b8e0SAnuj Aggarwal 	const struct tps_info *info[TPS6507X_NUM_REGULATOR];
1493fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
1503fa5b8e0SAnuj Aggarwal };
1514ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
1523fa5b8e0SAnuj Aggarwal {
153*31dd6a26STodd Fischer 	u8 val;
154*31dd6a26STodd Fischer 	int err;
155*31dd6a26STodd Fischer 
156*31dd6a26STodd Fischer 	err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
157*31dd6a26STodd Fischer 
158*31dd6a26STodd Fischer 	if (err)
159*31dd6a26STodd Fischer 		return err;
160*31dd6a26STodd Fischer 
161*31dd6a26STodd Fischer 	return val;
1623fa5b8e0SAnuj Aggarwal }
1633fa5b8e0SAnuj Aggarwal 
1644ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1653fa5b8e0SAnuj Aggarwal {
166*31dd6a26STodd Fischer 	return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
1673fa5b8e0SAnuj Aggarwal }
1683fa5b8e0SAnuj Aggarwal 
1694ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1703fa5b8e0SAnuj Aggarwal {
1713fa5b8e0SAnuj Aggarwal 	int err, data;
1723fa5b8e0SAnuj Aggarwal 
1733fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1743fa5b8e0SAnuj Aggarwal 
1754ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1763fa5b8e0SAnuj Aggarwal 	if (data < 0) {
177*31dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1783fa5b8e0SAnuj Aggarwal 		err = data;
1793fa5b8e0SAnuj Aggarwal 		goto out;
1803fa5b8e0SAnuj Aggarwal 	}
1813fa5b8e0SAnuj Aggarwal 
1823fa5b8e0SAnuj Aggarwal 	data |= mask;
1834ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1843fa5b8e0SAnuj Aggarwal 	if (err)
185*31dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1863fa5b8e0SAnuj Aggarwal 
1873fa5b8e0SAnuj Aggarwal out:
1883fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1893fa5b8e0SAnuj Aggarwal 	return err;
1903fa5b8e0SAnuj Aggarwal }
1913fa5b8e0SAnuj Aggarwal 
1924ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1933fa5b8e0SAnuj Aggarwal {
1943fa5b8e0SAnuj Aggarwal 	int err, data;
1953fa5b8e0SAnuj Aggarwal 
1963fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1973fa5b8e0SAnuj Aggarwal 
1984ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1993fa5b8e0SAnuj Aggarwal 	if (data < 0) {
200*31dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
2013fa5b8e0SAnuj Aggarwal 		err = data;
2023fa5b8e0SAnuj Aggarwal 		goto out;
2033fa5b8e0SAnuj Aggarwal 	}
2043fa5b8e0SAnuj Aggarwal 
2053fa5b8e0SAnuj Aggarwal 	data &= ~mask;
2064ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
2073fa5b8e0SAnuj Aggarwal 	if (err)
208*31dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2093fa5b8e0SAnuj Aggarwal 
2103fa5b8e0SAnuj Aggarwal out:
2113fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2123fa5b8e0SAnuj Aggarwal 	return err;
2133fa5b8e0SAnuj Aggarwal }
2143fa5b8e0SAnuj Aggarwal 
2154ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
2163fa5b8e0SAnuj Aggarwal {
2173fa5b8e0SAnuj Aggarwal 	int data;
2183fa5b8e0SAnuj Aggarwal 
2193fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2203fa5b8e0SAnuj Aggarwal 
2214ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
2223fa5b8e0SAnuj Aggarwal 	if (data < 0)
223*31dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
2243fa5b8e0SAnuj Aggarwal 
2253fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2263fa5b8e0SAnuj Aggarwal 	return data;
2273fa5b8e0SAnuj Aggarwal }
2283fa5b8e0SAnuj Aggarwal 
2294ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
2303fa5b8e0SAnuj Aggarwal {
2313fa5b8e0SAnuj Aggarwal 	int err;
2323fa5b8e0SAnuj Aggarwal 
2333fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2343fa5b8e0SAnuj Aggarwal 
2354ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, val);
2363fa5b8e0SAnuj Aggarwal 	if (err < 0)
237*31dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2383fa5b8e0SAnuj Aggarwal 
2393fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2403fa5b8e0SAnuj Aggarwal 	return err;
2413fa5b8e0SAnuj Aggarwal }
2423fa5b8e0SAnuj Aggarwal 
2434ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_is_enabled(struct regulator_dev *dev)
2443fa5b8e0SAnuj Aggarwal {
2454ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
2463fa5b8e0SAnuj Aggarwal 	int data, dcdc = rdev_get_id(dev);
2473fa5b8e0SAnuj Aggarwal 	u8 shift;
2483fa5b8e0SAnuj Aggarwal 
2493fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
2503fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2513fa5b8e0SAnuj Aggarwal 
2523fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
2534ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2543fa5b8e0SAnuj Aggarwal 
2553fa5b8e0SAnuj Aggarwal 	if (data < 0)
2563fa5b8e0SAnuj Aggarwal 		return data;
2573fa5b8e0SAnuj Aggarwal 	else
2583fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2593fa5b8e0SAnuj Aggarwal }
2603fa5b8e0SAnuj Aggarwal 
2614ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_is_enabled(struct regulator_dev *dev)
2623fa5b8e0SAnuj Aggarwal {
2634ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
2643fa5b8e0SAnuj Aggarwal 	int data, ldo = rdev_get_id(dev);
2653fa5b8e0SAnuj Aggarwal 	u8 shift;
2663fa5b8e0SAnuj Aggarwal 
2673fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
2683fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2693fa5b8e0SAnuj Aggarwal 
2703fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
2714ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2723fa5b8e0SAnuj Aggarwal 
2733fa5b8e0SAnuj Aggarwal 	if (data < 0)
2743fa5b8e0SAnuj Aggarwal 		return data;
2753fa5b8e0SAnuj Aggarwal 	else
2763fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2773fa5b8e0SAnuj Aggarwal }
2783fa5b8e0SAnuj Aggarwal 
2794ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_enable(struct regulator_dev *dev)
2803fa5b8e0SAnuj Aggarwal {
2814ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
2823fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
2833fa5b8e0SAnuj Aggarwal 	u8 shift;
2843fa5b8e0SAnuj Aggarwal 
2853fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
2863fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2873fa5b8e0SAnuj Aggarwal 
2883fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
2894ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
2903fa5b8e0SAnuj Aggarwal }
2913fa5b8e0SAnuj Aggarwal 
2924ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_disable(struct regulator_dev *dev)
2933fa5b8e0SAnuj Aggarwal {
2944ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
2953fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
2963fa5b8e0SAnuj Aggarwal 	u8 shift;
2973fa5b8e0SAnuj Aggarwal 
2983fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
2993fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3003fa5b8e0SAnuj Aggarwal 
3013fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
3024ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
3034ce5ba5bSTodd Fischer 					1 << shift);
3043fa5b8e0SAnuj Aggarwal }
3053fa5b8e0SAnuj Aggarwal 
3064ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_enable(struct regulator_dev *dev)
3073fa5b8e0SAnuj Aggarwal {
3084ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
3093fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
3103fa5b8e0SAnuj Aggarwal 	u8 shift;
3113fa5b8e0SAnuj Aggarwal 
3123fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
3133fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3143fa5b8e0SAnuj Aggarwal 
3153fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
3164ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
3173fa5b8e0SAnuj Aggarwal }
3183fa5b8e0SAnuj Aggarwal 
3194ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_disable(struct regulator_dev *dev)
3203fa5b8e0SAnuj Aggarwal {
3214ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
3223fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
3233fa5b8e0SAnuj Aggarwal 	u8 shift;
3243fa5b8e0SAnuj Aggarwal 
3253fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
3263fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3273fa5b8e0SAnuj Aggarwal 
3283fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
3294ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
3304ce5ba5bSTodd Fischer 					1 << shift);
3313fa5b8e0SAnuj Aggarwal }
3323fa5b8e0SAnuj Aggarwal 
3334ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev)
3343fa5b8e0SAnuj Aggarwal {
3354ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
3363fa5b8e0SAnuj Aggarwal 	int data, dcdc = rdev_get_id(dev);
3373fa5b8e0SAnuj Aggarwal 	u8 reg;
3383fa5b8e0SAnuj Aggarwal 
3393fa5b8e0SAnuj Aggarwal 	switch (dcdc) {
3403fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3413fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
3423fa5b8e0SAnuj Aggarwal 		break;
3433fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
3443fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC2_LOW;
3453fa5b8e0SAnuj Aggarwal 		break;
3463fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
3473fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC3_LOW;
3483fa5b8e0SAnuj Aggarwal 		break;
3493fa5b8e0SAnuj Aggarwal 	default:
3503fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3513fa5b8e0SAnuj Aggarwal 	}
3523fa5b8e0SAnuj Aggarwal 
3534ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3543fa5b8e0SAnuj Aggarwal 	if (data < 0)
3553fa5b8e0SAnuj Aggarwal 		return data;
3563fa5b8e0SAnuj Aggarwal 
3573fa5b8e0SAnuj Aggarwal 	data &= TPS6507X_DEFDCDCX_DCDC_MASK;
3583fa5b8e0SAnuj Aggarwal 	return tps->info[dcdc]->table[data] * 1000;
3593fa5b8e0SAnuj Aggarwal }
3603fa5b8e0SAnuj Aggarwal 
3614ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev,
3623fa5b8e0SAnuj Aggarwal 				int min_uV, int max_uV)
3633fa5b8e0SAnuj Aggarwal {
3644ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
3653fa5b8e0SAnuj Aggarwal 	int data, vsel, dcdc = rdev_get_id(dev);
3663fa5b8e0SAnuj Aggarwal 	u8 reg;
3673fa5b8e0SAnuj Aggarwal 
3683fa5b8e0SAnuj Aggarwal 	switch (dcdc) {
3693fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3703fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
3713fa5b8e0SAnuj Aggarwal 		break;
3723fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
3733fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC2_LOW;
3743fa5b8e0SAnuj Aggarwal 		break;
3753fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
3763fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC3_LOW;
3773fa5b8e0SAnuj Aggarwal 		break;
3783fa5b8e0SAnuj Aggarwal 	default:
3793fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3803fa5b8e0SAnuj Aggarwal 	}
3813fa5b8e0SAnuj Aggarwal 
3823fa5b8e0SAnuj Aggarwal 	if (min_uV < tps->info[dcdc]->min_uV
3833fa5b8e0SAnuj Aggarwal 		|| min_uV > tps->info[dcdc]->max_uV)
3843fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3853fa5b8e0SAnuj Aggarwal 	if (max_uV < tps->info[dcdc]->min_uV
3863fa5b8e0SAnuj Aggarwal 		|| max_uV > tps->info[dcdc]->max_uV)
3873fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3883fa5b8e0SAnuj Aggarwal 
3893fa5b8e0SAnuj Aggarwal 	for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
3903fa5b8e0SAnuj Aggarwal 		int mV = tps->info[dcdc]->table[vsel];
3913fa5b8e0SAnuj Aggarwal 		int uV = mV * 1000;
3923fa5b8e0SAnuj Aggarwal 
3933fa5b8e0SAnuj Aggarwal 		/* Break at the first in-range value */
3943fa5b8e0SAnuj Aggarwal 		if (min_uV <= uV && uV <= max_uV)
3953fa5b8e0SAnuj Aggarwal 			break;
3963fa5b8e0SAnuj Aggarwal 	}
3973fa5b8e0SAnuj Aggarwal 
3983fa5b8e0SAnuj Aggarwal 	/* write to the register in case we found a match */
3993fa5b8e0SAnuj Aggarwal 	if (vsel == tps->info[dcdc]->table_len)
4003fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4013fa5b8e0SAnuj Aggarwal 
4024ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
4033fa5b8e0SAnuj Aggarwal 	if (data < 0)
4043fa5b8e0SAnuj Aggarwal 		return data;
4053fa5b8e0SAnuj Aggarwal 
4063fa5b8e0SAnuj Aggarwal 	data &= ~TPS6507X_DEFDCDCX_DCDC_MASK;
4073fa5b8e0SAnuj Aggarwal 	data |= vsel;
4083fa5b8e0SAnuj Aggarwal 
4094ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
4103fa5b8e0SAnuj Aggarwal }
4113fa5b8e0SAnuj Aggarwal 
4124ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_get_voltage(struct regulator_dev *dev)
4133fa5b8e0SAnuj Aggarwal {
4144ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
4153fa5b8e0SAnuj Aggarwal 	int data, ldo = rdev_get_id(dev);
4163fa5b8e0SAnuj Aggarwal 	u8 reg, mask;
4173fa5b8e0SAnuj Aggarwal 
4183fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
4193fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4203fa5b8e0SAnuj Aggarwal 	else {
4213fa5b8e0SAnuj Aggarwal 		reg = (ldo == TPS6507X_LDO_1 ?
4223fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
4233fa5b8e0SAnuj Aggarwal 		mask = (ldo == TPS6507X_LDO_1 ?
4243fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
4253fa5b8e0SAnuj Aggarwal 				TPS6507X_REG_DEFLDO2_LDO2_MASK);
4263fa5b8e0SAnuj Aggarwal 	}
4273fa5b8e0SAnuj Aggarwal 
4284ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
4293fa5b8e0SAnuj Aggarwal 	if (data < 0)
4303fa5b8e0SAnuj Aggarwal 		return data;
4313fa5b8e0SAnuj Aggarwal 
4323fa5b8e0SAnuj Aggarwal 	data &= mask;
4333fa5b8e0SAnuj Aggarwal 	return tps->info[ldo]->table[data] * 1000;
4343fa5b8e0SAnuj Aggarwal }
4353fa5b8e0SAnuj Aggarwal 
4364ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev,
4373fa5b8e0SAnuj Aggarwal 				int min_uV, int max_uV)
4383fa5b8e0SAnuj Aggarwal {
4394ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
4403fa5b8e0SAnuj Aggarwal 	int data, vsel, ldo = rdev_get_id(dev);
4413fa5b8e0SAnuj Aggarwal 	u8 reg, mask;
4423fa5b8e0SAnuj Aggarwal 
4433fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
4443fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4453fa5b8e0SAnuj Aggarwal 	else {
4463fa5b8e0SAnuj Aggarwal 		reg = (ldo == TPS6507X_LDO_1 ?
4473fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
4483fa5b8e0SAnuj Aggarwal 		mask = (ldo == TPS6507X_LDO_1 ?
4493fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
4503fa5b8e0SAnuj Aggarwal 				TPS6507X_REG_DEFLDO2_LDO2_MASK);
4513fa5b8e0SAnuj Aggarwal 	}
4523fa5b8e0SAnuj Aggarwal 
4533fa5b8e0SAnuj Aggarwal 	if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
4543fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4553fa5b8e0SAnuj Aggarwal 	if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
4563fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4573fa5b8e0SAnuj Aggarwal 
4583fa5b8e0SAnuj Aggarwal 	for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
4593fa5b8e0SAnuj Aggarwal 		int mV = tps->info[ldo]->table[vsel];
4603fa5b8e0SAnuj Aggarwal 		int uV = mV * 1000;
4613fa5b8e0SAnuj Aggarwal 
4623fa5b8e0SAnuj Aggarwal 		/* Break at the first in-range value */
4633fa5b8e0SAnuj Aggarwal 		if (min_uV <= uV && uV <= max_uV)
4643fa5b8e0SAnuj Aggarwal 			break;
4653fa5b8e0SAnuj Aggarwal 	}
4663fa5b8e0SAnuj Aggarwal 
4673fa5b8e0SAnuj Aggarwal 	if (vsel == tps->info[ldo]->table_len)
4683fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4693fa5b8e0SAnuj Aggarwal 
4704ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
4713fa5b8e0SAnuj Aggarwal 	if (data < 0)
4723fa5b8e0SAnuj Aggarwal 		return data;
4733fa5b8e0SAnuj Aggarwal 
4743fa5b8e0SAnuj Aggarwal 	data &= ~mask;
4753fa5b8e0SAnuj Aggarwal 	data |= vsel;
4763fa5b8e0SAnuj Aggarwal 
4774ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
4783fa5b8e0SAnuj Aggarwal }
4793fa5b8e0SAnuj Aggarwal 
4804ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_list_voltage(struct regulator_dev *dev,
4813fa5b8e0SAnuj Aggarwal 					unsigned selector)
4823fa5b8e0SAnuj Aggarwal {
4834ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
4843fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
4853fa5b8e0SAnuj Aggarwal 
4863fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
4873fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4883fa5b8e0SAnuj Aggarwal 
4893fa5b8e0SAnuj Aggarwal 	if (selector >= tps->info[dcdc]->table_len)
4903fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4913fa5b8e0SAnuj Aggarwal 	else
4923fa5b8e0SAnuj Aggarwal 		return tps->info[dcdc]->table[selector] * 1000;
4933fa5b8e0SAnuj Aggarwal }
4943fa5b8e0SAnuj Aggarwal 
4954ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_list_voltage(struct regulator_dev *dev,
4963fa5b8e0SAnuj Aggarwal 					unsigned selector)
4973fa5b8e0SAnuj Aggarwal {
4984ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
4993fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
5003fa5b8e0SAnuj Aggarwal 
5013fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
5023fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5033fa5b8e0SAnuj Aggarwal 
5043fa5b8e0SAnuj Aggarwal 	if (selector >= tps->info[ldo]->table_len)
5053fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5063fa5b8e0SAnuj Aggarwal 	else
5073fa5b8e0SAnuj Aggarwal 		return tps->info[ldo]->table[selector] * 1000;
5083fa5b8e0SAnuj Aggarwal }
5093fa5b8e0SAnuj Aggarwal 
5103fa5b8e0SAnuj Aggarwal /* Operations permitted on VDCDCx */
5114ce5ba5bSTodd Fischer static struct regulator_ops tps6507x_pmic_dcdc_ops = {
5124ce5ba5bSTodd Fischer 	.is_enabled = tps6507x_pmic_dcdc_is_enabled,
5134ce5ba5bSTodd Fischer 	.enable = tps6507x_pmic_dcdc_enable,
5144ce5ba5bSTodd Fischer 	.disable = tps6507x_pmic_dcdc_disable,
5154ce5ba5bSTodd Fischer 	.get_voltage = tps6507x_pmic_dcdc_get_voltage,
5164ce5ba5bSTodd Fischer 	.set_voltage = tps6507x_pmic_dcdc_set_voltage,
5174ce5ba5bSTodd Fischer 	.list_voltage = tps6507x_pmic_dcdc_list_voltage,
5183fa5b8e0SAnuj Aggarwal };
5193fa5b8e0SAnuj Aggarwal 
5203fa5b8e0SAnuj Aggarwal /* Operations permitted on LDOx */
5214ce5ba5bSTodd Fischer static struct regulator_ops tps6507x_pmic_ldo_ops = {
5224ce5ba5bSTodd Fischer 	.is_enabled = tps6507x_pmic_ldo_is_enabled,
5234ce5ba5bSTodd Fischer 	.enable = tps6507x_pmic_ldo_enable,
5244ce5ba5bSTodd Fischer 	.disable = tps6507x_pmic_ldo_disable,
5254ce5ba5bSTodd Fischer 	.get_voltage = tps6507x_pmic_ldo_get_voltage,
5264ce5ba5bSTodd Fischer 	.set_voltage = tps6507x_pmic_ldo_set_voltage,
5274ce5ba5bSTodd Fischer 	.list_voltage = tps6507x_pmic_ldo_list_voltage,
5283fa5b8e0SAnuj Aggarwal };
5293fa5b8e0SAnuj Aggarwal 
530*31dd6a26STodd Fischer static __devinit
531*31dd6a26STodd Fischer int tps6507x_pmic_probe(struct platform_device *pdev)
5323fa5b8e0SAnuj Aggarwal {
533*31dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
5343fa5b8e0SAnuj Aggarwal 	static int desc_id;
535*31dd6a26STodd Fischer 	const struct tps_info *info = &tps6507x_pmic_regs[0];
5363fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
5373fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
5384ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
5390bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
5403fa5b8e0SAnuj Aggarwal 	int i;
54156c23492SDmitry Torokhov 	int error;
5423fa5b8e0SAnuj Aggarwal 
5433fa5b8e0SAnuj Aggarwal 	/**
5440bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
5450bc20bbaSTodd Fischer 	 * coming from the board-evm file.
5460bc20bbaSTodd Fischer 	 */
5470bc20bbaSTodd Fischer 
548*31dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
5490bc20bbaSTodd Fischer 	if (!tps_board)
5500bc20bbaSTodd Fischer 		return -EINVAL;
5510bc20bbaSTodd Fischer 
5520bc20bbaSTodd Fischer 	/**
5533fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
5543fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
5553fa5b8e0SAnuj Aggarwal 	 */
5560bc20bbaSTodd Fischer 	init_data = tps_board->tps6507x_pmic_init_data;
5573fa5b8e0SAnuj Aggarwal 	if (!init_data)
5580bc20bbaSTodd Fischer 		return -EINVAL;
5593fa5b8e0SAnuj Aggarwal 
5603fa5b8e0SAnuj Aggarwal 	tps = kzalloc(sizeof(*tps), GFP_KERNEL);
5613fa5b8e0SAnuj Aggarwal 	if (!tps)
5623fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
5633fa5b8e0SAnuj Aggarwal 
5643fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
5653fa5b8e0SAnuj Aggarwal 
5663fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
567*31dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
5683fa5b8e0SAnuj Aggarwal 
5693fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
5703fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
5713fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
5723fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
5733fa5b8e0SAnuj Aggarwal 		tps->desc[i].id = desc_id++;
5743fa5b8e0SAnuj Aggarwal 		tps->desc[i].n_voltages = num_voltages[i];
5753fa5b8e0SAnuj Aggarwal 		tps->desc[i].ops = (i > TPS6507X_DCDC_3 ?
5764ce5ba5bSTodd Fischer 		&tps6507x_pmic_ldo_ops : &tps6507x_pmic_dcdc_ops);
5773fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
5783fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
5793fa5b8e0SAnuj Aggarwal 
5803fa5b8e0SAnuj Aggarwal 		rdev = regulator_register(&tps->desc[i],
581*31dd6a26STodd Fischer 					tps6507x_dev->dev, init_data, tps);
5823fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
583*31dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
584*31dd6a26STodd Fischer 				"failed to register %s regulator\n",
585*31dd6a26STodd Fischer 				pdev->name);
58656c23492SDmitry Torokhov 			error = PTR_ERR(rdev);
58756c23492SDmitry Torokhov 			goto fail;
5883fa5b8e0SAnuj Aggarwal 		}
5893fa5b8e0SAnuj Aggarwal 
5903fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
5913fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
5923fa5b8e0SAnuj Aggarwal 	}
5933fa5b8e0SAnuj Aggarwal 
594*31dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
5953fa5b8e0SAnuj Aggarwal 
5963fa5b8e0SAnuj Aggarwal 	return 0;
59756c23492SDmitry Torokhov 
59856c23492SDmitry Torokhov fail:
59956c23492SDmitry Torokhov 	while (--i >= 0)
60056c23492SDmitry Torokhov 		regulator_unregister(tps->rdev[i]);
60156c23492SDmitry Torokhov 
60256c23492SDmitry Torokhov 	kfree(tps);
60356c23492SDmitry Torokhov 	return error;
6043fa5b8e0SAnuj Aggarwal }
6053fa5b8e0SAnuj Aggarwal 
6063fa5b8e0SAnuj Aggarwal /**
6074ce5ba5bSTodd Fischer  * tps6507x_remove - TPS6507x driver i2c remove handler
6083fa5b8e0SAnuj Aggarwal  * @client: i2c driver client device structure
6093fa5b8e0SAnuj Aggarwal  *
6103fa5b8e0SAnuj Aggarwal  * Unregister TPS driver as an i2c client device driver
6113fa5b8e0SAnuj Aggarwal  */
612*31dd6a26STodd Fischer static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
6133fa5b8e0SAnuj Aggarwal {
614*31dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
615*31dd6a26STodd Fischer 	struct tps6507x_pmic *tps = tps6507x_dev->pmic;
6163fa5b8e0SAnuj Aggarwal 	int i;
6173fa5b8e0SAnuj Aggarwal 
6183fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
6193fa5b8e0SAnuj Aggarwal 		regulator_unregister(tps->rdev[i]);
6203fa5b8e0SAnuj Aggarwal 
6213fa5b8e0SAnuj Aggarwal 	kfree(tps);
6223fa5b8e0SAnuj Aggarwal 
6233fa5b8e0SAnuj Aggarwal 	return 0;
6243fa5b8e0SAnuj Aggarwal }
6253fa5b8e0SAnuj Aggarwal 
626*31dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
6273fa5b8e0SAnuj Aggarwal 	.driver = {
628*31dd6a26STodd Fischer 		.name = "tps6507x-pmic",
6293fa5b8e0SAnuj Aggarwal 		.owner = THIS_MODULE,
6303fa5b8e0SAnuj Aggarwal 	},
6314ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
6324ce5ba5bSTodd Fischer 	.remove = __devexit_p(tps6507x_pmic_remove),
6333fa5b8e0SAnuj Aggarwal };
6343fa5b8e0SAnuj Aggarwal 
6353fa5b8e0SAnuj Aggarwal /**
6364ce5ba5bSTodd Fischer  * tps6507x_pmic_init
6373fa5b8e0SAnuj Aggarwal  *
6383fa5b8e0SAnuj Aggarwal  * Module init function
6393fa5b8e0SAnuj Aggarwal  */
6404ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
6413fa5b8e0SAnuj Aggarwal {
642*31dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
6433fa5b8e0SAnuj Aggarwal }
6444ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
6453fa5b8e0SAnuj Aggarwal 
6463fa5b8e0SAnuj Aggarwal /**
6474ce5ba5bSTodd Fischer  * tps6507x_pmic_cleanup
6483fa5b8e0SAnuj Aggarwal  *
6493fa5b8e0SAnuj Aggarwal  * Module exit function
6503fa5b8e0SAnuj Aggarwal  */
6514ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
6523fa5b8e0SAnuj Aggarwal {
653*31dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
6543fa5b8e0SAnuj Aggarwal }
6554ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
6563fa5b8e0SAnuj Aggarwal 
6573fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
6583fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
6593fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
660*31dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
661