xref: /openbmc/linux/drivers/regulator/tps6507x-regulator.c (revision d7399fa88847ae93203ff5618edd97d94d36c762)
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 static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDCx_VSEL_table),
943fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(VDCDCx_VSEL_table),
953fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(VDCDCx_VSEL_table),
963fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(LDO1_VSEL_table),
973fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(LDO2_VSEL_table)};
983fa5b8e0SAnuj Aggarwal 
993fa5b8e0SAnuj Aggarwal struct tps_info {
1003fa5b8e0SAnuj Aggarwal 	const char *name;
1013fa5b8e0SAnuj Aggarwal 	unsigned min_uV;
1023fa5b8e0SAnuj Aggarwal 	unsigned max_uV;
1033fa5b8e0SAnuj Aggarwal 	u8 table_len;
1043fa5b8e0SAnuj Aggarwal 	const u16 *table;
1057d14831eSAnuj Aggarwal 
1067d14831eSAnuj Aggarwal 	/* Does DCDC high or the low register defines output voltage? */
1077d14831eSAnuj Aggarwal 	bool defdcdc_default;
1083fa5b8e0SAnuj Aggarwal };
1093fa5b8e0SAnuj Aggarwal 
1107d14831eSAnuj Aggarwal static struct tps_info tps6507x_pmic_regs[] = {
11131dd6a26STodd Fischer 	{
11231dd6a26STodd Fischer 		.name = "VDCDC1",
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 = "VDCDC2",
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 = "VDCDC3",
12731dd6a26STodd Fischer 		.min_uV = 725000,
12831dd6a26STodd Fischer 		.max_uV = 3300000,
12931dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
13031dd6a26STodd Fischer 		.table = VDCDCx_VSEL_table,
13131dd6a26STodd Fischer 	},
13231dd6a26STodd Fischer 	{
13331dd6a26STodd Fischer 		.name = "LDO1",
13431dd6a26STodd Fischer 		.min_uV = 1000000,
13531dd6a26STodd Fischer 		.max_uV = 3300000,
13631dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
13731dd6a26STodd Fischer 		.table = LDO1_VSEL_table,
13831dd6a26STodd Fischer 	},
13931dd6a26STodd Fischer 	{
14031dd6a26STodd Fischer 		.name = "LDO2",
14131dd6a26STodd Fischer 		.min_uV = 725000,
14231dd6a26STodd Fischer 		.max_uV = 3300000,
14331dd6a26STodd Fischer 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
14431dd6a26STodd Fischer 		.table = LDO2_VSEL_table,
14531dd6a26STodd Fischer 	},
14631dd6a26STodd Fischer };
14731dd6a26STodd Fischer 
1484ce5ba5bSTodd Fischer struct tps6507x_pmic {
1493fa5b8e0SAnuj Aggarwal 	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
15031dd6a26STodd Fischer 	struct tps6507x_dev *mfd;
1513fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
1527d14831eSAnuj Aggarwal 	struct tps_info *info[TPS6507X_NUM_REGULATOR];
1533fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
1543fa5b8e0SAnuj Aggarwal };
1554ce5ba5bSTodd Fischer static inline int tps6507x_pmic_read(struct tps6507x_pmic *tps, u8 reg)
1563fa5b8e0SAnuj Aggarwal {
15731dd6a26STodd Fischer 	u8 val;
15831dd6a26STodd Fischer 	int err;
15931dd6a26STodd Fischer 
16031dd6a26STodd Fischer 	err = tps->mfd->read_dev(tps->mfd, reg, 1, &val);
16131dd6a26STodd Fischer 
16231dd6a26STodd Fischer 	if (err)
16331dd6a26STodd Fischer 		return err;
16431dd6a26STodd Fischer 
16531dd6a26STodd Fischer 	return val;
1663fa5b8e0SAnuj Aggarwal }
1673fa5b8e0SAnuj Aggarwal 
1684ce5ba5bSTodd Fischer static inline int tps6507x_pmic_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
1693fa5b8e0SAnuj Aggarwal {
17031dd6a26STodd Fischer 	return tps->mfd->write_dev(tps->mfd, reg, 1, &val);
1713fa5b8e0SAnuj Aggarwal }
1723fa5b8e0SAnuj Aggarwal 
1734ce5ba5bSTodd Fischer static int tps6507x_pmic_set_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1743fa5b8e0SAnuj Aggarwal {
1753fa5b8e0SAnuj Aggarwal 	int err, data;
1763fa5b8e0SAnuj Aggarwal 
1773fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1783fa5b8e0SAnuj Aggarwal 
1794ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
1803fa5b8e0SAnuj Aggarwal 	if (data < 0) {
18131dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
1823fa5b8e0SAnuj Aggarwal 		err = data;
1833fa5b8e0SAnuj Aggarwal 		goto out;
1843fa5b8e0SAnuj Aggarwal 	}
1853fa5b8e0SAnuj Aggarwal 
1863fa5b8e0SAnuj Aggarwal 	data |= mask;
1874ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
1883fa5b8e0SAnuj Aggarwal 	if (err)
18931dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
1903fa5b8e0SAnuj Aggarwal 
1913fa5b8e0SAnuj Aggarwal out:
1923fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
1933fa5b8e0SAnuj Aggarwal 	return err;
1943fa5b8e0SAnuj Aggarwal }
1953fa5b8e0SAnuj Aggarwal 
1964ce5ba5bSTodd Fischer static int tps6507x_pmic_clear_bits(struct tps6507x_pmic *tps, u8 reg, u8 mask)
1973fa5b8e0SAnuj Aggarwal {
1983fa5b8e0SAnuj Aggarwal 	int err, data;
1993fa5b8e0SAnuj Aggarwal 
2003fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2013fa5b8e0SAnuj Aggarwal 
2024ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
2033fa5b8e0SAnuj Aggarwal 	if (data < 0) {
20431dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
2053fa5b8e0SAnuj Aggarwal 		err = data;
2063fa5b8e0SAnuj Aggarwal 		goto out;
2073fa5b8e0SAnuj Aggarwal 	}
2083fa5b8e0SAnuj Aggarwal 
2093fa5b8e0SAnuj Aggarwal 	data &= ~mask;
2104ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, data);
2113fa5b8e0SAnuj Aggarwal 	if (err)
21231dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2133fa5b8e0SAnuj Aggarwal 
2143fa5b8e0SAnuj Aggarwal out:
2153fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2163fa5b8e0SAnuj Aggarwal 	return err;
2173fa5b8e0SAnuj Aggarwal }
2183fa5b8e0SAnuj Aggarwal 
2194ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_read(struct tps6507x_pmic *tps, u8 reg)
2203fa5b8e0SAnuj Aggarwal {
2213fa5b8e0SAnuj Aggarwal 	int data;
2223fa5b8e0SAnuj Aggarwal 
2233fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2243fa5b8e0SAnuj Aggarwal 
2254ce5ba5bSTodd Fischer 	data = tps6507x_pmic_read(tps, reg);
2263fa5b8e0SAnuj Aggarwal 	if (data < 0)
22731dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Read from reg 0x%x failed\n", reg);
2283fa5b8e0SAnuj Aggarwal 
2293fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2303fa5b8e0SAnuj Aggarwal 	return data;
2313fa5b8e0SAnuj Aggarwal }
2323fa5b8e0SAnuj Aggarwal 
2334ce5ba5bSTodd Fischer static int tps6507x_pmic_reg_write(struct tps6507x_pmic *tps, u8 reg, u8 val)
2343fa5b8e0SAnuj Aggarwal {
2353fa5b8e0SAnuj Aggarwal 	int err;
2363fa5b8e0SAnuj Aggarwal 
2373fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2383fa5b8e0SAnuj Aggarwal 
2394ce5ba5bSTodd Fischer 	err = tps6507x_pmic_write(tps, reg, val);
2403fa5b8e0SAnuj Aggarwal 	if (err < 0)
24131dd6a26STodd Fischer 		dev_err(tps->mfd->dev, "Write for reg 0x%x failed\n", reg);
2423fa5b8e0SAnuj Aggarwal 
2433fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2443fa5b8e0SAnuj Aggarwal 	return err;
2453fa5b8e0SAnuj Aggarwal }
2463fa5b8e0SAnuj Aggarwal 
2474ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_is_enabled(struct regulator_dev *dev)
2483fa5b8e0SAnuj Aggarwal {
2494ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
2503fa5b8e0SAnuj Aggarwal 	int data, dcdc = rdev_get_id(dev);
2513fa5b8e0SAnuj Aggarwal 	u8 shift;
2523fa5b8e0SAnuj Aggarwal 
2533fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
2543fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2553fa5b8e0SAnuj Aggarwal 
2563fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
2574ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2583fa5b8e0SAnuj Aggarwal 
2593fa5b8e0SAnuj Aggarwal 	if (data < 0)
2603fa5b8e0SAnuj Aggarwal 		return data;
2613fa5b8e0SAnuj Aggarwal 	else
2623fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2633fa5b8e0SAnuj Aggarwal }
2643fa5b8e0SAnuj Aggarwal 
2654ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_is_enabled(struct regulator_dev *dev)
2663fa5b8e0SAnuj Aggarwal {
2674ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
2683fa5b8e0SAnuj Aggarwal 	int data, ldo = rdev_get_id(dev);
2693fa5b8e0SAnuj Aggarwal 	u8 shift;
2703fa5b8e0SAnuj Aggarwal 
2713fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
2723fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2733fa5b8e0SAnuj Aggarwal 
2743fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
2754ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2763fa5b8e0SAnuj Aggarwal 
2773fa5b8e0SAnuj Aggarwal 	if (data < 0)
2783fa5b8e0SAnuj Aggarwal 		return data;
2793fa5b8e0SAnuj Aggarwal 	else
2803fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2813fa5b8e0SAnuj Aggarwal }
2823fa5b8e0SAnuj Aggarwal 
2834ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_enable(struct regulator_dev *dev)
2843fa5b8e0SAnuj Aggarwal {
2854ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
2863fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
2873fa5b8e0SAnuj Aggarwal 	u8 shift;
2883fa5b8e0SAnuj Aggarwal 
2893fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
2903fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2913fa5b8e0SAnuj Aggarwal 
2923fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
2934ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
2943fa5b8e0SAnuj Aggarwal }
2953fa5b8e0SAnuj Aggarwal 
2964ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_disable(struct regulator_dev *dev)
2973fa5b8e0SAnuj Aggarwal {
2984ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
2993fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
3003fa5b8e0SAnuj Aggarwal 	u8 shift;
3013fa5b8e0SAnuj Aggarwal 
3023fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
3033fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3043fa5b8e0SAnuj Aggarwal 
3053fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
3064ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
3074ce5ba5bSTodd Fischer 					1 << shift);
3083fa5b8e0SAnuj Aggarwal }
3093fa5b8e0SAnuj Aggarwal 
3104ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_enable(struct regulator_dev *dev)
3113fa5b8e0SAnuj Aggarwal {
3124ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
3133fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
3143fa5b8e0SAnuj Aggarwal 	u8 shift;
3153fa5b8e0SAnuj Aggarwal 
3163fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
3173fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3183fa5b8e0SAnuj Aggarwal 
3193fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
3204ce5ba5bSTodd Fischer 	return tps6507x_pmic_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
3213fa5b8e0SAnuj Aggarwal }
3223fa5b8e0SAnuj Aggarwal 
3234ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_disable(struct regulator_dev *dev)
3243fa5b8e0SAnuj Aggarwal {
3254ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
3263fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
3273fa5b8e0SAnuj Aggarwal 	u8 shift;
3283fa5b8e0SAnuj Aggarwal 
3293fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
3303fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3313fa5b8e0SAnuj Aggarwal 
3323fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
3334ce5ba5bSTodd Fischer 	return tps6507x_pmic_clear_bits(tps, TPS6507X_REG_CON_CTRL1,
3344ce5ba5bSTodd Fischer 					1 << shift);
3353fa5b8e0SAnuj Aggarwal }
3363fa5b8e0SAnuj Aggarwal 
3374ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_get_voltage(struct regulator_dev *dev)
3383fa5b8e0SAnuj Aggarwal {
3394ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
3403fa5b8e0SAnuj Aggarwal 	int data, dcdc = rdev_get_id(dev);
3413fa5b8e0SAnuj Aggarwal 	u8 reg;
3423fa5b8e0SAnuj Aggarwal 
3433fa5b8e0SAnuj Aggarwal 	switch (dcdc) {
3443fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3453fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
3463fa5b8e0SAnuj Aggarwal 		break;
3473fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
3487d14831eSAnuj Aggarwal 		if (tps->info[dcdc]->defdcdc_default)
3497d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3507d14831eSAnuj Aggarwal 		else
3513fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
3523fa5b8e0SAnuj Aggarwal 		break;
3533fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
3547d14831eSAnuj Aggarwal 		if (tps->info[dcdc]->defdcdc_default)
3557d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3567d14831eSAnuj Aggarwal 		else
3573fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
3583fa5b8e0SAnuj Aggarwal 		break;
3593fa5b8e0SAnuj Aggarwal 	default:
3603fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3613fa5b8e0SAnuj Aggarwal 	}
3623fa5b8e0SAnuj Aggarwal 
3634ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
3643fa5b8e0SAnuj Aggarwal 	if (data < 0)
3653fa5b8e0SAnuj Aggarwal 		return data;
3663fa5b8e0SAnuj Aggarwal 
3673fa5b8e0SAnuj Aggarwal 	data &= TPS6507X_DEFDCDCX_DCDC_MASK;
3683fa5b8e0SAnuj Aggarwal 	return tps->info[dcdc]->table[data] * 1000;
3693fa5b8e0SAnuj Aggarwal }
3703fa5b8e0SAnuj Aggarwal 
3714ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_set_voltage(struct regulator_dev *dev,
3723fa5b8e0SAnuj Aggarwal 				int min_uV, int max_uV)
3733fa5b8e0SAnuj Aggarwal {
3744ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
3753fa5b8e0SAnuj Aggarwal 	int data, vsel, dcdc = rdev_get_id(dev);
3763fa5b8e0SAnuj Aggarwal 	u8 reg;
3773fa5b8e0SAnuj Aggarwal 
3783fa5b8e0SAnuj Aggarwal 	switch (dcdc) {
3793fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3803fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
3813fa5b8e0SAnuj Aggarwal 		break;
3823fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
3837d14831eSAnuj Aggarwal 		if (tps->info[dcdc]->defdcdc_default)
3847d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_HIGH;
3857d14831eSAnuj Aggarwal 		else
3863fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC2_LOW;
3873fa5b8e0SAnuj Aggarwal 		break;
3883fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
3897d14831eSAnuj Aggarwal 		if (tps->info[dcdc]->defdcdc_default)
3907d14831eSAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_HIGH;
3917d14831eSAnuj Aggarwal 		else
3923fa5b8e0SAnuj Aggarwal 			reg = TPS6507X_REG_DEFDCDC3_LOW;
3933fa5b8e0SAnuj Aggarwal 		break;
3943fa5b8e0SAnuj Aggarwal 	default:
3953fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3963fa5b8e0SAnuj Aggarwal 	}
3973fa5b8e0SAnuj Aggarwal 
3983fa5b8e0SAnuj Aggarwal 	if (min_uV < tps->info[dcdc]->min_uV
3993fa5b8e0SAnuj Aggarwal 		|| min_uV > tps->info[dcdc]->max_uV)
4003fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4013fa5b8e0SAnuj Aggarwal 	if (max_uV < tps->info[dcdc]->min_uV
4023fa5b8e0SAnuj Aggarwal 		|| max_uV > tps->info[dcdc]->max_uV)
4033fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4043fa5b8e0SAnuj Aggarwal 
4053fa5b8e0SAnuj Aggarwal 	for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
4063fa5b8e0SAnuj Aggarwal 		int mV = tps->info[dcdc]->table[vsel];
4073fa5b8e0SAnuj Aggarwal 		int uV = mV * 1000;
4083fa5b8e0SAnuj Aggarwal 
4093fa5b8e0SAnuj Aggarwal 		/* Break at the first in-range value */
4103fa5b8e0SAnuj Aggarwal 		if (min_uV <= uV && uV <= max_uV)
4113fa5b8e0SAnuj Aggarwal 			break;
4123fa5b8e0SAnuj Aggarwal 	}
4133fa5b8e0SAnuj Aggarwal 
4143fa5b8e0SAnuj Aggarwal 	/* write to the register in case we found a match */
4153fa5b8e0SAnuj Aggarwal 	if (vsel == tps->info[dcdc]->table_len)
4163fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4173fa5b8e0SAnuj Aggarwal 
4184ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
4193fa5b8e0SAnuj Aggarwal 	if (data < 0)
4203fa5b8e0SAnuj Aggarwal 		return data;
4213fa5b8e0SAnuj Aggarwal 
4223fa5b8e0SAnuj Aggarwal 	data &= ~TPS6507X_DEFDCDCX_DCDC_MASK;
4233fa5b8e0SAnuj Aggarwal 	data |= vsel;
4243fa5b8e0SAnuj Aggarwal 
4254ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
4263fa5b8e0SAnuj Aggarwal }
4273fa5b8e0SAnuj Aggarwal 
4284ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_get_voltage(struct regulator_dev *dev)
4293fa5b8e0SAnuj Aggarwal {
4304ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
4313fa5b8e0SAnuj Aggarwal 	int data, ldo = rdev_get_id(dev);
4323fa5b8e0SAnuj Aggarwal 	u8 reg, mask;
4333fa5b8e0SAnuj Aggarwal 
4343fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
4353fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4363fa5b8e0SAnuj Aggarwal 	else {
4373fa5b8e0SAnuj Aggarwal 		reg = (ldo == TPS6507X_LDO_1 ?
4383fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
4393fa5b8e0SAnuj Aggarwal 		mask = (ldo == TPS6507X_LDO_1 ?
4403fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
4413fa5b8e0SAnuj Aggarwal 				TPS6507X_REG_DEFLDO2_LDO2_MASK);
4423fa5b8e0SAnuj Aggarwal 	}
4433fa5b8e0SAnuj Aggarwal 
4444ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
4453fa5b8e0SAnuj Aggarwal 	if (data < 0)
4463fa5b8e0SAnuj Aggarwal 		return data;
4473fa5b8e0SAnuj Aggarwal 
4483fa5b8e0SAnuj Aggarwal 	data &= mask;
4493fa5b8e0SAnuj Aggarwal 	return tps->info[ldo]->table[data] * 1000;
4503fa5b8e0SAnuj Aggarwal }
4513fa5b8e0SAnuj Aggarwal 
4524ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_set_voltage(struct regulator_dev *dev,
4533fa5b8e0SAnuj Aggarwal 				int min_uV, int max_uV)
4543fa5b8e0SAnuj Aggarwal {
4554ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
4563fa5b8e0SAnuj Aggarwal 	int data, vsel, ldo = rdev_get_id(dev);
4573fa5b8e0SAnuj Aggarwal 	u8 reg, mask;
4583fa5b8e0SAnuj Aggarwal 
4593fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
4603fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4613fa5b8e0SAnuj Aggarwal 	else {
4623fa5b8e0SAnuj Aggarwal 		reg = (ldo == TPS6507X_LDO_1 ?
4633fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
4643fa5b8e0SAnuj Aggarwal 		mask = (ldo == TPS6507X_LDO_1 ?
4653fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
4663fa5b8e0SAnuj Aggarwal 				TPS6507X_REG_DEFLDO2_LDO2_MASK);
4673fa5b8e0SAnuj Aggarwal 	}
4683fa5b8e0SAnuj Aggarwal 
4693fa5b8e0SAnuj Aggarwal 	if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
4703fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4713fa5b8e0SAnuj Aggarwal 	if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
4723fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4733fa5b8e0SAnuj Aggarwal 
4743fa5b8e0SAnuj Aggarwal 	for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
4753fa5b8e0SAnuj Aggarwal 		int mV = tps->info[ldo]->table[vsel];
4763fa5b8e0SAnuj Aggarwal 		int uV = mV * 1000;
4773fa5b8e0SAnuj Aggarwal 
4783fa5b8e0SAnuj Aggarwal 		/* Break at the first in-range value */
4793fa5b8e0SAnuj Aggarwal 		if (min_uV <= uV && uV <= max_uV)
4803fa5b8e0SAnuj Aggarwal 			break;
4813fa5b8e0SAnuj Aggarwal 	}
4823fa5b8e0SAnuj Aggarwal 
4833fa5b8e0SAnuj Aggarwal 	if (vsel == tps->info[ldo]->table_len)
4843fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4853fa5b8e0SAnuj Aggarwal 
4864ce5ba5bSTodd Fischer 	data = tps6507x_pmic_reg_read(tps, reg);
4873fa5b8e0SAnuj Aggarwal 	if (data < 0)
4883fa5b8e0SAnuj Aggarwal 		return data;
4893fa5b8e0SAnuj Aggarwal 
4903fa5b8e0SAnuj Aggarwal 	data &= ~mask;
4913fa5b8e0SAnuj Aggarwal 	data |= vsel;
4923fa5b8e0SAnuj Aggarwal 
4934ce5ba5bSTodd Fischer 	return tps6507x_pmic_reg_write(tps, reg, data);
4943fa5b8e0SAnuj Aggarwal }
4953fa5b8e0SAnuj Aggarwal 
4964ce5ba5bSTodd Fischer static int tps6507x_pmic_dcdc_list_voltage(struct regulator_dev *dev,
4973fa5b8e0SAnuj Aggarwal 					unsigned selector)
4983fa5b8e0SAnuj Aggarwal {
4994ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
5003fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
5013fa5b8e0SAnuj Aggarwal 
5023fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
5033fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5043fa5b8e0SAnuj Aggarwal 
5053fa5b8e0SAnuj Aggarwal 	if (selector >= tps->info[dcdc]->table_len)
5063fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5073fa5b8e0SAnuj Aggarwal 	else
5083fa5b8e0SAnuj Aggarwal 		return tps->info[dcdc]->table[selector] * 1000;
5093fa5b8e0SAnuj Aggarwal }
5103fa5b8e0SAnuj Aggarwal 
5114ce5ba5bSTodd Fischer static int tps6507x_pmic_ldo_list_voltage(struct regulator_dev *dev,
5123fa5b8e0SAnuj Aggarwal 					unsigned selector)
5133fa5b8e0SAnuj Aggarwal {
5144ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps = rdev_get_drvdata(dev);
5153fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
5163fa5b8e0SAnuj Aggarwal 
5173fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
5183fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5193fa5b8e0SAnuj Aggarwal 
5203fa5b8e0SAnuj Aggarwal 	if (selector >= tps->info[ldo]->table_len)
5213fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5223fa5b8e0SAnuj Aggarwal 	else
5233fa5b8e0SAnuj Aggarwal 		return tps->info[ldo]->table[selector] * 1000;
5243fa5b8e0SAnuj Aggarwal }
5253fa5b8e0SAnuj Aggarwal 
5263fa5b8e0SAnuj Aggarwal /* Operations permitted on VDCDCx */
5274ce5ba5bSTodd Fischer static struct regulator_ops tps6507x_pmic_dcdc_ops = {
5284ce5ba5bSTodd Fischer 	.is_enabled = tps6507x_pmic_dcdc_is_enabled,
5294ce5ba5bSTodd Fischer 	.enable = tps6507x_pmic_dcdc_enable,
5304ce5ba5bSTodd Fischer 	.disable = tps6507x_pmic_dcdc_disable,
5314ce5ba5bSTodd Fischer 	.get_voltage = tps6507x_pmic_dcdc_get_voltage,
5324ce5ba5bSTodd Fischer 	.set_voltage = tps6507x_pmic_dcdc_set_voltage,
5334ce5ba5bSTodd Fischer 	.list_voltage = tps6507x_pmic_dcdc_list_voltage,
5343fa5b8e0SAnuj Aggarwal };
5353fa5b8e0SAnuj Aggarwal 
5363fa5b8e0SAnuj Aggarwal /* Operations permitted on LDOx */
5374ce5ba5bSTodd Fischer static struct regulator_ops tps6507x_pmic_ldo_ops = {
5384ce5ba5bSTodd Fischer 	.is_enabled = tps6507x_pmic_ldo_is_enabled,
5394ce5ba5bSTodd Fischer 	.enable = tps6507x_pmic_ldo_enable,
5404ce5ba5bSTodd Fischer 	.disable = tps6507x_pmic_ldo_disable,
5414ce5ba5bSTodd Fischer 	.get_voltage = tps6507x_pmic_ldo_get_voltage,
5424ce5ba5bSTodd Fischer 	.set_voltage = tps6507x_pmic_ldo_set_voltage,
5434ce5ba5bSTodd Fischer 	.list_voltage = tps6507x_pmic_ldo_list_voltage,
5443fa5b8e0SAnuj Aggarwal };
5453fa5b8e0SAnuj Aggarwal 
54631dd6a26STodd Fischer static __devinit
54731dd6a26STodd Fischer int tps6507x_pmic_probe(struct platform_device *pdev)
5483fa5b8e0SAnuj Aggarwal {
54931dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = dev_get_drvdata(pdev->dev.parent);
5503fa5b8e0SAnuj Aggarwal 	static int desc_id;
5517d14831eSAnuj Aggarwal 	struct tps_info *info = &tps6507x_pmic_regs[0];
5523fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
5533fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
5544ce5ba5bSTodd Fischer 	struct tps6507x_pmic *tps;
5550bc20bbaSTodd Fischer 	struct tps6507x_board *tps_board;
5563fa5b8e0SAnuj Aggarwal 	int i;
55756c23492SDmitry Torokhov 	int error;
5583fa5b8e0SAnuj Aggarwal 
5593fa5b8e0SAnuj Aggarwal 	/**
5600bc20bbaSTodd Fischer 	 * tps_board points to pmic related constants
5610bc20bbaSTodd Fischer 	 * coming from the board-evm file.
5620bc20bbaSTodd Fischer 	 */
5630bc20bbaSTodd Fischer 
56431dd6a26STodd Fischer 	tps_board = dev_get_platdata(tps6507x_dev->dev);
5650bc20bbaSTodd Fischer 	if (!tps_board)
5660bc20bbaSTodd Fischer 		return -EINVAL;
5670bc20bbaSTodd Fischer 
5680bc20bbaSTodd Fischer 	/**
5693fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
5703fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
5713fa5b8e0SAnuj Aggarwal 	 */
5720bc20bbaSTodd Fischer 	init_data = tps_board->tps6507x_pmic_init_data;
5733fa5b8e0SAnuj Aggarwal 	if (!init_data)
5740bc20bbaSTodd Fischer 		return -EINVAL;
5753fa5b8e0SAnuj Aggarwal 
5763fa5b8e0SAnuj Aggarwal 	tps = kzalloc(sizeof(*tps), GFP_KERNEL);
5773fa5b8e0SAnuj Aggarwal 	if (!tps)
5783fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
5793fa5b8e0SAnuj Aggarwal 
5803fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
5813fa5b8e0SAnuj Aggarwal 
5823fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
58331dd6a26STodd Fischer 	tps->mfd = tps6507x_dev;
5843fa5b8e0SAnuj Aggarwal 
5853fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
5863fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
5873fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
5887d14831eSAnuj Aggarwal 		if (init_data->driver_data) {
5897d14831eSAnuj Aggarwal 			struct tps6507x_reg_platform_data *data =
5907d14831eSAnuj Aggarwal 							init_data->driver_data;
5917d14831eSAnuj Aggarwal 			tps->info[i]->defdcdc_default = data->defdcdc_default;
5927d14831eSAnuj Aggarwal 		}
5937d14831eSAnuj Aggarwal 
5943fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
5953fa5b8e0SAnuj Aggarwal 		tps->desc[i].id = desc_id++;
5963fa5b8e0SAnuj Aggarwal 		tps->desc[i].n_voltages = num_voltages[i];
5973fa5b8e0SAnuj Aggarwal 		tps->desc[i].ops = (i > TPS6507X_DCDC_3 ?
5984ce5ba5bSTodd Fischer 		&tps6507x_pmic_ldo_ops : &tps6507x_pmic_dcdc_ops);
5993fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
6003fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
6013fa5b8e0SAnuj Aggarwal 
6023fa5b8e0SAnuj Aggarwal 		rdev = regulator_register(&tps->desc[i],
60331dd6a26STodd Fischer 					tps6507x_dev->dev, init_data, tps);
6043fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
60531dd6a26STodd Fischer 			dev_err(tps6507x_dev->dev,
60631dd6a26STodd Fischer 				"failed to register %s regulator\n",
60731dd6a26STodd Fischer 				pdev->name);
60856c23492SDmitry Torokhov 			error = PTR_ERR(rdev);
60956c23492SDmitry Torokhov 			goto fail;
6103fa5b8e0SAnuj Aggarwal 		}
6113fa5b8e0SAnuj Aggarwal 
6123fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
6133fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
6143fa5b8e0SAnuj Aggarwal 	}
6153fa5b8e0SAnuj Aggarwal 
61631dd6a26STodd Fischer 	tps6507x_dev->pmic = tps;
617*d7399fa8SAxel Lin 	platform_set_drvdata(pdev, tps6507x_dev);
6183fa5b8e0SAnuj Aggarwal 
6193fa5b8e0SAnuj Aggarwal 	return 0;
62056c23492SDmitry Torokhov 
62156c23492SDmitry Torokhov fail:
62256c23492SDmitry Torokhov 	while (--i >= 0)
62356c23492SDmitry Torokhov 		regulator_unregister(tps->rdev[i]);
62456c23492SDmitry Torokhov 
62556c23492SDmitry Torokhov 	kfree(tps);
62656c23492SDmitry Torokhov 	return error;
6273fa5b8e0SAnuj Aggarwal }
6283fa5b8e0SAnuj Aggarwal 
6293fa5b8e0SAnuj Aggarwal /**
6304ce5ba5bSTodd Fischer  * tps6507x_remove - TPS6507x driver i2c remove handler
6313fa5b8e0SAnuj Aggarwal  * @client: i2c driver client device structure
6323fa5b8e0SAnuj Aggarwal  *
6333fa5b8e0SAnuj Aggarwal  * Unregister TPS driver as an i2c client device driver
6343fa5b8e0SAnuj Aggarwal  */
63531dd6a26STodd Fischer static int __devexit tps6507x_pmic_remove(struct platform_device *pdev)
6363fa5b8e0SAnuj Aggarwal {
63731dd6a26STodd Fischer 	struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
63831dd6a26STodd Fischer 	struct tps6507x_pmic *tps = tps6507x_dev->pmic;
6393fa5b8e0SAnuj Aggarwal 	int i;
6403fa5b8e0SAnuj Aggarwal 
6413fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
6423fa5b8e0SAnuj Aggarwal 		regulator_unregister(tps->rdev[i]);
6433fa5b8e0SAnuj Aggarwal 
6443fa5b8e0SAnuj Aggarwal 	kfree(tps);
6453fa5b8e0SAnuj Aggarwal 
6463fa5b8e0SAnuj Aggarwal 	return 0;
6473fa5b8e0SAnuj Aggarwal }
6483fa5b8e0SAnuj Aggarwal 
64931dd6a26STodd Fischer static struct platform_driver tps6507x_pmic_driver = {
6503fa5b8e0SAnuj Aggarwal 	.driver = {
65131dd6a26STodd Fischer 		.name = "tps6507x-pmic",
6523fa5b8e0SAnuj Aggarwal 		.owner = THIS_MODULE,
6533fa5b8e0SAnuj Aggarwal 	},
6544ce5ba5bSTodd Fischer 	.probe = tps6507x_pmic_probe,
6554ce5ba5bSTodd Fischer 	.remove = __devexit_p(tps6507x_pmic_remove),
6563fa5b8e0SAnuj Aggarwal };
6573fa5b8e0SAnuj Aggarwal 
6583fa5b8e0SAnuj Aggarwal /**
6594ce5ba5bSTodd Fischer  * tps6507x_pmic_init
6603fa5b8e0SAnuj Aggarwal  *
6613fa5b8e0SAnuj Aggarwal  * Module init function
6623fa5b8e0SAnuj Aggarwal  */
6634ce5ba5bSTodd Fischer static int __init tps6507x_pmic_init(void)
6643fa5b8e0SAnuj Aggarwal {
66531dd6a26STodd Fischer 	return platform_driver_register(&tps6507x_pmic_driver);
6663fa5b8e0SAnuj Aggarwal }
6674ce5ba5bSTodd Fischer subsys_initcall(tps6507x_pmic_init);
6683fa5b8e0SAnuj Aggarwal 
6693fa5b8e0SAnuj Aggarwal /**
6704ce5ba5bSTodd Fischer  * tps6507x_pmic_cleanup
6713fa5b8e0SAnuj Aggarwal  *
6723fa5b8e0SAnuj Aggarwal  * Module exit function
6733fa5b8e0SAnuj Aggarwal  */
6744ce5ba5bSTodd Fischer static void __exit tps6507x_pmic_cleanup(void)
6753fa5b8e0SAnuj Aggarwal {
67631dd6a26STodd Fischer 	platform_driver_unregister(&tps6507x_pmic_driver);
6773fa5b8e0SAnuj Aggarwal }
6784ce5ba5bSTodd Fischer module_exit(tps6507x_pmic_cleanup);
6793fa5b8e0SAnuj Aggarwal 
6803fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
6813fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
6823fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
68331dd6a26STodd Fischer MODULE_ALIAS("platform:tps6507x-pmic");
684