xref: /linux/drivers/regulator/tps6507x-regulator.c (revision 5a0e3ad6af8660be21ca98a971cd00f331318c05)
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/i2c.h>
263fa5b8e0SAnuj Aggarwal #include <linux/delay.h>
27*5a0e3ad6STejun Heo #include <linux/slab.h>
283fa5b8e0SAnuj Aggarwal 
293fa5b8e0SAnuj Aggarwal /* Register definitions */
303fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_PPATH1				0X01
313fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_INT				0X02
323fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CHGCONFIG0				0X03
333fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CHGCONFIG1				0X04
343fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CHGCONFIG2				0X05
353fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CHGCONFIG3				0X06
363fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_REG_ADCONFIG			0X07
373fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_TSCMODE				0X08
383fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_ADRESULT_1				0X09
393fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_ADRESULT_2				0X0A
403fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_PGOOD				0X0B
413fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_PGOODMASK				0X0C
423fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CON_CTRL1				0X0D
433fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CON_CTRL2				0X0E
443fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CON_CTRL3				0X0F
453fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC1				0X10
463fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC2_LOW			0X11
473fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC2_HIGH			0X12
483fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC3_LOW			0X13
493fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC3_HIGH			0X14
503fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFSLEW				0X15
513fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_LDO_CTRL1				0X16
523fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFLDO2				0X17
533fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_WLED_CTRL1				0X18
543fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_WLED_CTRL2				0X19
553fa5b8e0SAnuj Aggarwal 
563fa5b8e0SAnuj Aggarwal /* CON_CTRL1 bitfields */
573fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_DCDC1_ENABLE		BIT(4)
583fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_DCDC2_ENABLE		BIT(3)
593fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_DCDC3_ENABLE		BIT(2)
603fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_LDO1_ENABLE		BIT(1)
613fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_LDO2_ENABLE		BIT(0)
623fa5b8e0SAnuj Aggarwal 
633fa5b8e0SAnuj Aggarwal /* DEFDCDC1 bitfields */
643fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC1_DCDC1_EXT_ADJ_EN	BIT(7)
653fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC1_DCDC1_MASK		0X3F
663fa5b8e0SAnuj Aggarwal 
673fa5b8e0SAnuj Aggarwal /* DEFDCDC2_LOW bitfields */
683fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC2_LOW_DCDC2_MASK	0X3F
693fa5b8e0SAnuj Aggarwal 
703fa5b8e0SAnuj Aggarwal /* DEFDCDC2_HIGH bitfields */
713fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC2_HIGH_DCDC2_MASK	0X3F
723fa5b8e0SAnuj Aggarwal 
733fa5b8e0SAnuj Aggarwal /* DEFDCDC3_LOW bitfields */
743fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC3_LOW_DCDC3_MASK	0X3F
753fa5b8e0SAnuj Aggarwal 
763fa5b8e0SAnuj Aggarwal /* DEFDCDC3_HIGH bitfields */
773fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC3_HIGH_DCDC3_MASK	0X3F
783fa5b8e0SAnuj Aggarwal 
793fa5b8e0SAnuj Aggarwal /* TPS6507X_REG_LDO_CTRL1 bitfields */
803fa5b8e0SAnuj Aggarwal #define TPS6507X_REG_LDO_CTRL1_LDO1_MASK	0X0F
813fa5b8e0SAnuj Aggarwal 
823fa5b8e0SAnuj Aggarwal /* TPS6507X_REG_DEFLDO2 bitfields */
833fa5b8e0SAnuj Aggarwal #define TPS6507X_REG_DEFLDO2_LDO2_MASK		0X3F
843fa5b8e0SAnuj Aggarwal 
853fa5b8e0SAnuj Aggarwal /* VDCDC MASK */
863fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDCX_DCDC_MASK		0X3F
873fa5b8e0SAnuj Aggarwal 
883fa5b8e0SAnuj Aggarwal /* DCDC's */
893fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_1				0
903fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_2				1
913fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_3				2
923fa5b8e0SAnuj Aggarwal /* LDOs */
933fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_1				3
943fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_2				4
953fa5b8e0SAnuj Aggarwal 
963fa5b8e0SAnuj Aggarwal #define TPS6507X_MAX_REG_ID			TPS6507X_LDO_2
973fa5b8e0SAnuj Aggarwal 
983fa5b8e0SAnuj Aggarwal /* Number of step-down converters available */
993fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_DCDC			3
1003fa5b8e0SAnuj Aggarwal /* Number of LDO voltage regulators  available */
1013fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_LDO			2
1023fa5b8e0SAnuj Aggarwal /* Number of total regulators available */
1033fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_REGULATOR		(TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
1043fa5b8e0SAnuj Aggarwal 
1053fa5b8e0SAnuj Aggarwal /* Supported voltage values for regulators (in milliVolts) */
1063fa5b8e0SAnuj Aggarwal static const u16 VDCDCx_VSEL_table[] = {
1073fa5b8e0SAnuj Aggarwal 	725, 750, 775, 800,
1083fa5b8e0SAnuj Aggarwal 	825, 850, 875, 900,
1093fa5b8e0SAnuj Aggarwal 	925, 950, 975, 1000,
1103fa5b8e0SAnuj Aggarwal 	1025, 1050, 1075, 1100,
1113fa5b8e0SAnuj Aggarwal 	1125, 1150, 1175, 1200,
1123fa5b8e0SAnuj Aggarwal 	1225, 1250, 1275, 1300,
1133fa5b8e0SAnuj Aggarwal 	1325, 1350, 1375, 1400,
1143fa5b8e0SAnuj Aggarwal 	1425, 1450, 1475, 1500,
1153fa5b8e0SAnuj Aggarwal 	1550, 1600, 1650, 1700,
1163fa5b8e0SAnuj Aggarwal 	1750, 1800, 1850, 1900,
1173fa5b8e0SAnuj Aggarwal 	1950, 2000, 2050, 2100,
1183fa5b8e0SAnuj Aggarwal 	2150, 2200, 2250, 2300,
1193fa5b8e0SAnuj Aggarwal 	2350, 2400, 2450, 2500,
1203fa5b8e0SAnuj Aggarwal 	2550, 2600, 2650, 2700,
1213fa5b8e0SAnuj Aggarwal 	2750, 2800, 2850, 2900,
1223fa5b8e0SAnuj Aggarwal 	3000, 3100, 3200, 3300,
1233fa5b8e0SAnuj Aggarwal };
1243fa5b8e0SAnuj Aggarwal 
1253fa5b8e0SAnuj Aggarwal static const u16 LDO1_VSEL_table[] = {
1263fa5b8e0SAnuj Aggarwal 	1000, 1100, 1200, 1250,
1273fa5b8e0SAnuj Aggarwal 	1300, 1350, 1400, 1500,
1283fa5b8e0SAnuj Aggarwal 	1600, 1800, 2500, 2750,
1293fa5b8e0SAnuj Aggarwal 	2800, 3000, 3100, 3300,
1303fa5b8e0SAnuj Aggarwal };
1313fa5b8e0SAnuj Aggarwal 
1323fa5b8e0SAnuj Aggarwal static const u16 LDO2_VSEL_table[] = {
1333fa5b8e0SAnuj Aggarwal 	725, 750, 775, 800,
1343fa5b8e0SAnuj Aggarwal 	825, 850, 875, 900,
1353fa5b8e0SAnuj Aggarwal 	925, 950, 975, 1000,
1363fa5b8e0SAnuj Aggarwal 	1025, 1050, 1075, 1100,
1373fa5b8e0SAnuj Aggarwal 	1125, 1150, 1175, 1200,
1383fa5b8e0SAnuj Aggarwal 	1225, 1250, 1275, 1300,
1393fa5b8e0SAnuj Aggarwal 	1325, 1350, 1375, 1400,
1403fa5b8e0SAnuj Aggarwal 	1425, 1450, 1475, 1500,
1413fa5b8e0SAnuj Aggarwal 	1550, 1600, 1650, 1700,
1423fa5b8e0SAnuj Aggarwal 	1750, 1800, 1850, 1900,
1433fa5b8e0SAnuj Aggarwal 	1950, 2000, 2050, 2100,
1443fa5b8e0SAnuj Aggarwal 	2150, 2200, 2250, 2300,
1453fa5b8e0SAnuj Aggarwal 	2350, 2400, 2450, 2500,
1463fa5b8e0SAnuj Aggarwal 	2550, 2600, 2650, 2700,
1473fa5b8e0SAnuj Aggarwal 	2750, 2800, 2850, 2900,
1483fa5b8e0SAnuj Aggarwal 	3000, 3100, 3200, 3300,
1493fa5b8e0SAnuj Aggarwal };
1503fa5b8e0SAnuj Aggarwal 
1513fa5b8e0SAnuj Aggarwal static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDCx_VSEL_table),
1523fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(VDCDCx_VSEL_table),
1533fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(VDCDCx_VSEL_table),
1543fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(LDO1_VSEL_table),
1553fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(LDO2_VSEL_table)};
1563fa5b8e0SAnuj Aggarwal 
1573fa5b8e0SAnuj Aggarwal struct tps_info {
1583fa5b8e0SAnuj Aggarwal 	const char *name;
1593fa5b8e0SAnuj Aggarwal 	unsigned min_uV;
1603fa5b8e0SAnuj Aggarwal 	unsigned max_uV;
1613fa5b8e0SAnuj Aggarwal 	u8 table_len;
1623fa5b8e0SAnuj Aggarwal 	const u16 *table;
1633fa5b8e0SAnuj Aggarwal };
1643fa5b8e0SAnuj Aggarwal 
1653fa5b8e0SAnuj Aggarwal struct tps_pmic {
1663fa5b8e0SAnuj Aggarwal 	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
1673fa5b8e0SAnuj Aggarwal 	struct i2c_client *client;
1683fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
1693fa5b8e0SAnuj Aggarwal 	const struct tps_info *info[TPS6507X_NUM_REGULATOR];
1703fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
1713fa5b8e0SAnuj Aggarwal };
1723fa5b8e0SAnuj Aggarwal 
1733fa5b8e0SAnuj Aggarwal static inline int tps_6507x_read(struct tps_pmic *tps, u8 reg)
1743fa5b8e0SAnuj Aggarwal {
1753fa5b8e0SAnuj Aggarwal 	return i2c_smbus_read_byte_data(tps->client, reg);
1763fa5b8e0SAnuj Aggarwal }
1773fa5b8e0SAnuj Aggarwal 
1783fa5b8e0SAnuj Aggarwal static inline int tps_6507x_write(struct tps_pmic *tps, u8 reg, u8 val)
1793fa5b8e0SAnuj Aggarwal {
1803fa5b8e0SAnuj Aggarwal 	return i2c_smbus_write_byte_data(tps->client, reg, val);
1813fa5b8e0SAnuj Aggarwal }
1823fa5b8e0SAnuj Aggarwal 
1833fa5b8e0SAnuj Aggarwal static int tps_6507x_set_bits(struct tps_pmic *tps, u8 reg, u8 mask)
1843fa5b8e0SAnuj Aggarwal {
1853fa5b8e0SAnuj Aggarwal 	int err, data;
1863fa5b8e0SAnuj Aggarwal 
1873fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
1883fa5b8e0SAnuj Aggarwal 
1893fa5b8e0SAnuj Aggarwal 	data = tps_6507x_read(tps, reg);
1903fa5b8e0SAnuj Aggarwal 	if (data < 0) {
1913fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
1923fa5b8e0SAnuj Aggarwal 		err = data;
1933fa5b8e0SAnuj Aggarwal 		goto out;
1943fa5b8e0SAnuj Aggarwal 	}
1953fa5b8e0SAnuj Aggarwal 
1963fa5b8e0SAnuj Aggarwal 	data |= mask;
1973fa5b8e0SAnuj Aggarwal 	err = tps_6507x_write(tps, reg, data);
1983fa5b8e0SAnuj Aggarwal 	if (err)
1993fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
2003fa5b8e0SAnuj Aggarwal 
2013fa5b8e0SAnuj Aggarwal out:
2023fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2033fa5b8e0SAnuj Aggarwal 	return err;
2043fa5b8e0SAnuj Aggarwal }
2053fa5b8e0SAnuj Aggarwal 
2063fa5b8e0SAnuj Aggarwal static int tps_6507x_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask)
2073fa5b8e0SAnuj Aggarwal {
2083fa5b8e0SAnuj Aggarwal 	int err, data;
2093fa5b8e0SAnuj Aggarwal 
2103fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2113fa5b8e0SAnuj Aggarwal 
2123fa5b8e0SAnuj Aggarwal 	data = tps_6507x_read(tps, reg);
2133fa5b8e0SAnuj Aggarwal 	if (data < 0) {
2143fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
2153fa5b8e0SAnuj Aggarwal 		err = data;
2163fa5b8e0SAnuj Aggarwal 		goto out;
2173fa5b8e0SAnuj Aggarwal 	}
2183fa5b8e0SAnuj Aggarwal 
2193fa5b8e0SAnuj Aggarwal 	data &= ~mask;
2203fa5b8e0SAnuj Aggarwal 	err = tps_6507x_write(tps, reg, data);
2213fa5b8e0SAnuj Aggarwal 	if (err)
2223fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
2233fa5b8e0SAnuj Aggarwal 
2243fa5b8e0SAnuj Aggarwal out:
2253fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2263fa5b8e0SAnuj Aggarwal 	return err;
2273fa5b8e0SAnuj Aggarwal }
2283fa5b8e0SAnuj Aggarwal 
2293fa5b8e0SAnuj Aggarwal static int tps_6507x_reg_read(struct tps_pmic *tps, u8 reg)
2303fa5b8e0SAnuj Aggarwal {
2313fa5b8e0SAnuj Aggarwal 	int data;
2323fa5b8e0SAnuj Aggarwal 
2333fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2343fa5b8e0SAnuj Aggarwal 
2353fa5b8e0SAnuj Aggarwal 	data = tps_6507x_read(tps, reg);
2363fa5b8e0SAnuj Aggarwal 	if (data < 0)
2373fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
2383fa5b8e0SAnuj Aggarwal 
2393fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2403fa5b8e0SAnuj Aggarwal 	return data;
2413fa5b8e0SAnuj Aggarwal }
2423fa5b8e0SAnuj Aggarwal 
2433fa5b8e0SAnuj Aggarwal static int tps_6507x_reg_write(struct tps_pmic *tps, u8 reg, u8 val)
2443fa5b8e0SAnuj Aggarwal {
2453fa5b8e0SAnuj Aggarwal 	int err;
2463fa5b8e0SAnuj Aggarwal 
2473fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
2483fa5b8e0SAnuj Aggarwal 
2493fa5b8e0SAnuj Aggarwal 	err = tps_6507x_write(tps, reg, val);
2503fa5b8e0SAnuj Aggarwal 	if (err < 0)
2513fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
2523fa5b8e0SAnuj Aggarwal 
2533fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
2543fa5b8e0SAnuj Aggarwal 	return err;
2553fa5b8e0SAnuj Aggarwal }
2563fa5b8e0SAnuj Aggarwal 
2573fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_is_enabled(struct regulator_dev *dev)
2583fa5b8e0SAnuj Aggarwal {
2593fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
2603fa5b8e0SAnuj Aggarwal 	int data, dcdc = rdev_get_id(dev);
2613fa5b8e0SAnuj Aggarwal 	u8 shift;
2623fa5b8e0SAnuj Aggarwal 
2633fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
2643fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2653fa5b8e0SAnuj Aggarwal 
2663fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
2673fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2683fa5b8e0SAnuj Aggarwal 
2693fa5b8e0SAnuj Aggarwal 	if (data < 0)
2703fa5b8e0SAnuj Aggarwal 		return data;
2713fa5b8e0SAnuj Aggarwal 	else
2723fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2733fa5b8e0SAnuj Aggarwal }
2743fa5b8e0SAnuj Aggarwal 
2753fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_is_enabled(struct regulator_dev *dev)
2763fa5b8e0SAnuj Aggarwal {
2773fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
2783fa5b8e0SAnuj Aggarwal 	int data, ldo = rdev_get_id(dev);
2793fa5b8e0SAnuj Aggarwal 	u8 shift;
2803fa5b8e0SAnuj Aggarwal 
2813fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
2823fa5b8e0SAnuj Aggarwal 		return -EINVAL;
2833fa5b8e0SAnuj Aggarwal 
2843fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
2853fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1);
2863fa5b8e0SAnuj Aggarwal 
2873fa5b8e0SAnuj Aggarwal 	if (data < 0)
2883fa5b8e0SAnuj Aggarwal 		return data;
2893fa5b8e0SAnuj Aggarwal 	else
2903fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
2913fa5b8e0SAnuj Aggarwal }
2923fa5b8e0SAnuj Aggarwal 
2933fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_enable(struct regulator_dev *dev)
2943fa5b8e0SAnuj Aggarwal {
2953fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
2963fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
2973fa5b8e0SAnuj Aggarwal 	u8 shift;
2983fa5b8e0SAnuj Aggarwal 
2993fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
3003fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3013fa5b8e0SAnuj Aggarwal 
3023fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
3033fa5b8e0SAnuj Aggarwal 	return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
3043fa5b8e0SAnuj Aggarwal }
3053fa5b8e0SAnuj Aggarwal 
3063fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_disable(struct regulator_dev *dev)
3073fa5b8e0SAnuj Aggarwal {
3083fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
3093fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
3103fa5b8e0SAnuj Aggarwal 	u8 shift;
3113fa5b8e0SAnuj Aggarwal 
3123fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
3133fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3143fa5b8e0SAnuj Aggarwal 
3153fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
3163fa5b8e0SAnuj Aggarwal 	return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
3173fa5b8e0SAnuj Aggarwal }
3183fa5b8e0SAnuj Aggarwal 
3193fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_enable(struct regulator_dev *dev)
3203fa5b8e0SAnuj Aggarwal {
3213fa5b8e0SAnuj Aggarwal 	struct tps_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;
3293fa5b8e0SAnuj Aggarwal 	return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
3303fa5b8e0SAnuj Aggarwal }
3313fa5b8e0SAnuj Aggarwal 
3323fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_disable(struct regulator_dev *dev)
3333fa5b8e0SAnuj Aggarwal {
3343fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
3353fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
3363fa5b8e0SAnuj Aggarwal 	u8 shift;
3373fa5b8e0SAnuj Aggarwal 
3383fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
3393fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3403fa5b8e0SAnuj Aggarwal 
3413fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
3423fa5b8e0SAnuj Aggarwal 	return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
3433fa5b8e0SAnuj Aggarwal }
3443fa5b8e0SAnuj Aggarwal 
3453fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_get_voltage(struct regulator_dev *dev)
3463fa5b8e0SAnuj Aggarwal {
3473fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
3483fa5b8e0SAnuj Aggarwal 	int data, dcdc = rdev_get_id(dev);
3493fa5b8e0SAnuj Aggarwal 	u8 reg;
3503fa5b8e0SAnuj Aggarwal 
3513fa5b8e0SAnuj Aggarwal 	switch (dcdc) {
3523fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3533fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
3543fa5b8e0SAnuj Aggarwal 		break;
3553fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
3563fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC2_LOW;
3573fa5b8e0SAnuj Aggarwal 		break;
3583fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
3593fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC3_LOW;
3603fa5b8e0SAnuj Aggarwal 		break;
3613fa5b8e0SAnuj Aggarwal 	default:
3623fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3633fa5b8e0SAnuj Aggarwal 	}
3643fa5b8e0SAnuj Aggarwal 
3653fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, reg);
3663fa5b8e0SAnuj Aggarwal 	if (data < 0)
3673fa5b8e0SAnuj Aggarwal 		return data;
3683fa5b8e0SAnuj Aggarwal 
3693fa5b8e0SAnuj Aggarwal 	data &= TPS6507X_DEFDCDCX_DCDC_MASK;
3703fa5b8e0SAnuj Aggarwal 	return tps->info[dcdc]->table[data] * 1000;
3713fa5b8e0SAnuj Aggarwal }
3723fa5b8e0SAnuj Aggarwal 
3733fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_set_voltage(struct regulator_dev *dev,
3743fa5b8e0SAnuj Aggarwal 				int min_uV, int max_uV)
3753fa5b8e0SAnuj Aggarwal {
3763fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
3773fa5b8e0SAnuj Aggarwal 	int data, vsel, dcdc = rdev_get_id(dev);
3783fa5b8e0SAnuj Aggarwal 	u8 reg;
3793fa5b8e0SAnuj Aggarwal 
3803fa5b8e0SAnuj Aggarwal 	switch (dcdc) {
3813fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
3823fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
3833fa5b8e0SAnuj Aggarwal 		break;
3843fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
3853fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC2_LOW;
3863fa5b8e0SAnuj Aggarwal 		break;
3873fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
3883fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC3_LOW;
3893fa5b8e0SAnuj Aggarwal 		break;
3903fa5b8e0SAnuj Aggarwal 	default:
3913fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3923fa5b8e0SAnuj Aggarwal 	}
3933fa5b8e0SAnuj Aggarwal 
3943fa5b8e0SAnuj Aggarwal 	if (min_uV < tps->info[dcdc]->min_uV
3953fa5b8e0SAnuj Aggarwal 		|| min_uV > tps->info[dcdc]->max_uV)
3963fa5b8e0SAnuj Aggarwal 		return -EINVAL;
3973fa5b8e0SAnuj Aggarwal 	if (max_uV < tps->info[dcdc]->min_uV
3983fa5b8e0SAnuj Aggarwal 		|| max_uV > tps->info[dcdc]->max_uV)
3993fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4003fa5b8e0SAnuj Aggarwal 
4013fa5b8e0SAnuj Aggarwal 	for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
4023fa5b8e0SAnuj Aggarwal 		int mV = tps->info[dcdc]->table[vsel];
4033fa5b8e0SAnuj Aggarwal 		int uV = mV * 1000;
4043fa5b8e0SAnuj Aggarwal 
4053fa5b8e0SAnuj Aggarwal 		/* Break at the first in-range value */
4063fa5b8e0SAnuj Aggarwal 		if (min_uV <= uV && uV <= max_uV)
4073fa5b8e0SAnuj Aggarwal 			break;
4083fa5b8e0SAnuj Aggarwal 	}
4093fa5b8e0SAnuj Aggarwal 
4103fa5b8e0SAnuj Aggarwal 	/* write to the register in case we found a match */
4113fa5b8e0SAnuj Aggarwal 	if (vsel == tps->info[dcdc]->table_len)
4123fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4133fa5b8e0SAnuj Aggarwal 
4143fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, reg);
4153fa5b8e0SAnuj Aggarwal 	if (data < 0)
4163fa5b8e0SAnuj Aggarwal 		return data;
4173fa5b8e0SAnuj Aggarwal 
4183fa5b8e0SAnuj Aggarwal 	data &= ~TPS6507X_DEFDCDCX_DCDC_MASK;
4193fa5b8e0SAnuj Aggarwal 	data |= vsel;
4203fa5b8e0SAnuj Aggarwal 
4213fa5b8e0SAnuj Aggarwal 	return tps_6507x_reg_write(tps, reg, data);
4223fa5b8e0SAnuj Aggarwal }
4233fa5b8e0SAnuj Aggarwal 
4243fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_get_voltage(struct regulator_dev *dev)
4253fa5b8e0SAnuj Aggarwal {
4263fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
4273fa5b8e0SAnuj Aggarwal 	int data, ldo = rdev_get_id(dev);
4283fa5b8e0SAnuj Aggarwal 	u8 reg, mask;
4293fa5b8e0SAnuj Aggarwal 
4303fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
4313fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4323fa5b8e0SAnuj Aggarwal 	else {
4333fa5b8e0SAnuj Aggarwal 		reg = (ldo == TPS6507X_LDO_1 ?
4343fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
4353fa5b8e0SAnuj Aggarwal 		mask = (ldo == TPS6507X_LDO_1 ?
4363fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
4373fa5b8e0SAnuj Aggarwal 				TPS6507X_REG_DEFLDO2_LDO2_MASK);
4383fa5b8e0SAnuj Aggarwal 	}
4393fa5b8e0SAnuj Aggarwal 
4403fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, reg);
4413fa5b8e0SAnuj Aggarwal 	if (data < 0)
4423fa5b8e0SAnuj Aggarwal 		return data;
4433fa5b8e0SAnuj Aggarwal 
4443fa5b8e0SAnuj Aggarwal 	data &= mask;
4453fa5b8e0SAnuj Aggarwal 	return tps->info[ldo]->table[data] * 1000;
4463fa5b8e0SAnuj Aggarwal }
4473fa5b8e0SAnuj Aggarwal 
4483fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_set_voltage(struct regulator_dev *dev,
4493fa5b8e0SAnuj Aggarwal 				int min_uV, int max_uV)
4503fa5b8e0SAnuj Aggarwal {
4513fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
4523fa5b8e0SAnuj Aggarwal 	int data, vsel, ldo = rdev_get_id(dev);
4533fa5b8e0SAnuj Aggarwal 	u8 reg, mask;
4543fa5b8e0SAnuj Aggarwal 
4553fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
4563fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4573fa5b8e0SAnuj Aggarwal 	else {
4583fa5b8e0SAnuj Aggarwal 		reg = (ldo == TPS6507X_LDO_1 ?
4593fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
4603fa5b8e0SAnuj Aggarwal 		mask = (ldo == TPS6507X_LDO_1 ?
4613fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
4623fa5b8e0SAnuj Aggarwal 				TPS6507X_REG_DEFLDO2_LDO2_MASK);
4633fa5b8e0SAnuj Aggarwal 	}
4643fa5b8e0SAnuj Aggarwal 
4653fa5b8e0SAnuj Aggarwal 	if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
4663fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4673fa5b8e0SAnuj Aggarwal 	if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
4683fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4693fa5b8e0SAnuj Aggarwal 
4703fa5b8e0SAnuj Aggarwal 	for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
4713fa5b8e0SAnuj Aggarwal 		int mV = tps->info[ldo]->table[vsel];
4723fa5b8e0SAnuj Aggarwal 		int uV = mV * 1000;
4733fa5b8e0SAnuj Aggarwal 
4743fa5b8e0SAnuj Aggarwal 		/* Break at the first in-range value */
4753fa5b8e0SAnuj Aggarwal 		if (min_uV <= uV && uV <= max_uV)
4763fa5b8e0SAnuj Aggarwal 			break;
4773fa5b8e0SAnuj Aggarwal 	}
4783fa5b8e0SAnuj Aggarwal 
4793fa5b8e0SAnuj Aggarwal 	if (vsel == tps->info[ldo]->table_len)
4803fa5b8e0SAnuj Aggarwal 		return -EINVAL;
4813fa5b8e0SAnuj Aggarwal 
4823fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, reg);
4833fa5b8e0SAnuj Aggarwal 	if (data < 0)
4843fa5b8e0SAnuj Aggarwal 		return data;
4853fa5b8e0SAnuj Aggarwal 
4863fa5b8e0SAnuj Aggarwal 	data &= ~mask;
4873fa5b8e0SAnuj Aggarwal 	data |= vsel;
4883fa5b8e0SAnuj Aggarwal 
4893fa5b8e0SAnuj Aggarwal 	return tps_6507x_reg_write(tps, reg, data);
4903fa5b8e0SAnuj Aggarwal }
4913fa5b8e0SAnuj Aggarwal 
4923fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_list_voltage(struct regulator_dev *dev,
4933fa5b8e0SAnuj Aggarwal 					unsigned selector)
4943fa5b8e0SAnuj Aggarwal {
4953fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
4963fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
4973fa5b8e0SAnuj Aggarwal 
4983fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
4993fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5003fa5b8e0SAnuj Aggarwal 
5013fa5b8e0SAnuj Aggarwal 	if (selector >= tps->info[dcdc]->table_len)
5023fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5033fa5b8e0SAnuj Aggarwal 	else
5043fa5b8e0SAnuj Aggarwal 		return tps->info[dcdc]->table[selector] * 1000;
5053fa5b8e0SAnuj Aggarwal }
5063fa5b8e0SAnuj Aggarwal 
5073fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_list_voltage(struct regulator_dev *dev,
5083fa5b8e0SAnuj Aggarwal 					unsigned selector)
5093fa5b8e0SAnuj Aggarwal {
5103fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
5113fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
5123fa5b8e0SAnuj Aggarwal 
5133fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
5143fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5153fa5b8e0SAnuj Aggarwal 
5163fa5b8e0SAnuj Aggarwal 	if (selector >= tps->info[ldo]->table_len)
5173fa5b8e0SAnuj Aggarwal 		return -EINVAL;
5183fa5b8e0SAnuj Aggarwal 	else
5193fa5b8e0SAnuj Aggarwal 		return tps->info[ldo]->table[selector] * 1000;
5203fa5b8e0SAnuj Aggarwal }
5213fa5b8e0SAnuj Aggarwal 
5223fa5b8e0SAnuj Aggarwal /* Operations permitted on VDCDCx */
5233fa5b8e0SAnuj Aggarwal static struct regulator_ops tps6507x_dcdc_ops = {
5243fa5b8e0SAnuj Aggarwal 	.is_enabled = tps6507x_dcdc_is_enabled,
5253fa5b8e0SAnuj Aggarwal 	.enable = tps6507x_dcdc_enable,
5263fa5b8e0SAnuj Aggarwal 	.disable = tps6507x_dcdc_disable,
5273fa5b8e0SAnuj Aggarwal 	.get_voltage = tps6507x_dcdc_get_voltage,
5283fa5b8e0SAnuj Aggarwal 	.set_voltage = tps6507x_dcdc_set_voltage,
5293fa5b8e0SAnuj Aggarwal 	.list_voltage = tps6507x_dcdc_list_voltage,
5303fa5b8e0SAnuj Aggarwal };
5313fa5b8e0SAnuj Aggarwal 
5323fa5b8e0SAnuj Aggarwal /* Operations permitted on LDOx */
5333fa5b8e0SAnuj Aggarwal static struct regulator_ops tps6507x_ldo_ops = {
5343fa5b8e0SAnuj Aggarwal 	.is_enabled = tps6507x_ldo_is_enabled,
5353fa5b8e0SAnuj Aggarwal 	.enable = tps6507x_ldo_enable,
5363fa5b8e0SAnuj Aggarwal 	.disable = tps6507x_ldo_disable,
5373fa5b8e0SAnuj Aggarwal 	.get_voltage = tps6507x_ldo_get_voltage,
5383fa5b8e0SAnuj Aggarwal 	.set_voltage = tps6507x_ldo_set_voltage,
5393fa5b8e0SAnuj Aggarwal 	.list_voltage = tps6507x_ldo_list_voltage,
5403fa5b8e0SAnuj Aggarwal };
5413fa5b8e0SAnuj Aggarwal 
54256c23492SDmitry Torokhov static int __devinit tps_6507x_probe(struct i2c_client *client,
54356c23492SDmitry Torokhov 				     const struct i2c_device_id *id)
5443fa5b8e0SAnuj Aggarwal {
5453fa5b8e0SAnuj Aggarwal 	static int desc_id;
5463fa5b8e0SAnuj Aggarwal 	const struct tps_info *info = (void *)id->driver_data;
5473fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
5483fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
5493fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps;
5503fa5b8e0SAnuj Aggarwal 	int i;
55156c23492SDmitry Torokhov 	int error;
5523fa5b8e0SAnuj Aggarwal 
5533fa5b8e0SAnuj Aggarwal 	if (!i2c_check_functionality(client->adapter,
5543fa5b8e0SAnuj Aggarwal 				I2C_FUNC_SMBUS_BYTE_DATA))
5553fa5b8e0SAnuj Aggarwal 		return -EIO;
5563fa5b8e0SAnuj Aggarwal 
5573fa5b8e0SAnuj Aggarwal 	/**
5583fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
5593fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
5603fa5b8e0SAnuj Aggarwal 	 */
5613fa5b8e0SAnuj Aggarwal 	init_data = client->dev.platform_data;
5623fa5b8e0SAnuj Aggarwal 	if (!init_data)
5633fa5b8e0SAnuj Aggarwal 		return -EIO;
5643fa5b8e0SAnuj Aggarwal 
5653fa5b8e0SAnuj Aggarwal 	tps = kzalloc(sizeof(*tps), GFP_KERNEL);
5663fa5b8e0SAnuj Aggarwal 	if (!tps)
5673fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
5683fa5b8e0SAnuj Aggarwal 
5693fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
5703fa5b8e0SAnuj Aggarwal 
5713fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
5723fa5b8e0SAnuj Aggarwal 	tps->client = client;
5733fa5b8e0SAnuj Aggarwal 
5743fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
5753fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
5763fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
5773fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
5783fa5b8e0SAnuj Aggarwal 		tps->desc[i].id = desc_id++;
5793fa5b8e0SAnuj Aggarwal 		tps->desc[i].n_voltages = num_voltages[i];
5803fa5b8e0SAnuj Aggarwal 		tps->desc[i].ops = (i > TPS6507X_DCDC_3 ?
5813fa5b8e0SAnuj Aggarwal 				&tps6507x_ldo_ops : &tps6507x_dcdc_ops);
5823fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
5833fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
5843fa5b8e0SAnuj Aggarwal 
5853fa5b8e0SAnuj Aggarwal 		rdev = regulator_register(&tps->desc[i],
5863fa5b8e0SAnuj Aggarwal 					&client->dev, init_data, tps);
5873fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
5883fa5b8e0SAnuj Aggarwal 			dev_err(&client->dev, "failed to register %s\n",
5893fa5b8e0SAnuj Aggarwal 				id->name);
59056c23492SDmitry Torokhov 			error = PTR_ERR(rdev);
59156c23492SDmitry Torokhov 			goto fail;
5923fa5b8e0SAnuj Aggarwal 		}
5933fa5b8e0SAnuj Aggarwal 
5943fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
5953fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
5963fa5b8e0SAnuj Aggarwal 	}
5973fa5b8e0SAnuj Aggarwal 
5983fa5b8e0SAnuj Aggarwal 	i2c_set_clientdata(client, tps);
5993fa5b8e0SAnuj Aggarwal 
6003fa5b8e0SAnuj Aggarwal 	return 0;
60156c23492SDmitry Torokhov 
60256c23492SDmitry Torokhov fail:
60356c23492SDmitry Torokhov 	while (--i >= 0)
60456c23492SDmitry Torokhov 		regulator_unregister(tps->rdev[i]);
60556c23492SDmitry Torokhov 
60656c23492SDmitry Torokhov 	kfree(tps);
60756c23492SDmitry Torokhov 	return error;
6083fa5b8e0SAnuj Aggarwal }
6093fa5b8e0SAnuj Aggarwal 
6103fa5b8e0SAnuj Aggarwal /**
6113fa5b8e0SAnuj Aggarwal  * tps_6507x_remove - TPS6507x driver i2c remove handler
6123fa5b8e0SAnuj Aggarwal  * @client: i2c driver client device structure
6133fa5b8e0SAnuj Aggarwal  *
6143fa5b8e0SAnuj Aggarwal  * Unregister TPS driver as an i2c client device driver
6153fa5b8e0SAnuj Aggarwal  */
6163fa5b8e0SAnuj Aggarwal static int __devexit tps_6507x_remove(struct i2c_client *client)
6173fa5b8e0SAnuj Aggarwal {
6183fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = i2c_get_clientdata(client);
6193fa5b8e0SAnuj Aggarwal 	int i;
6203fa5b8e0SAnuj Aggarwal 
62156c23492SDmitry Torokhov 	/* clear the client data in i2c */
62256c23492SDmitry Torokhov 	i2c_set_clientdata(client, NULL);
62356c23492SDmitry Torokhov 
6243fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
6253fa5b8e0SAnuj Aggarwal 		regulator_unregister(tps->rdev[i]);
6263fa5b8e0SAnuj Aggarwal 
6273fa5b8e0SAnuj Aggarwal 	kfree(tps);
6283fa5b8e0SAnuj Aggarwal 
6293fa5b8e0SAnuj Aggarwal 	return 0;
6303fa5b8e0SAnuj Aggarwal }
6313fa5b8e0SAnuj Aggarwal 
6323fa5b8e0SAnuj Aggarwal static const struct tps_info tps6507x_regs[] = {
6333fa5b8e0SAnuj Aggarwal 	{
6343fa5b8e0SAnuj Aggarwal 		.name = "VDCDC1",
6353fa5b8e0SAnuj Aggarwal 		.min_uV = 725000,
6363fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
6373fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
6383fa5b8e0SAnuj Aggarwal 		.table = VDCDCx_VSEL_table,
6393fa5b8e0SAnuj Aggarwal 	},
6403fa5b8e0SAnuj Aggarwal 	{
6413fa5b8e0SAnuj Aggarwal 		.name = "VDCDC2",
6423fa5b8e0SAnuj Aggarwal 		.min_uV = 725000,
6433fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
6443fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
6453fa5b8e0SAnuj Aggarwal 		.table = VDCDCx_VSEL_table,
6463fa5b8e0SAnuj Aggarwal 	},
6473fa5b8e0SAnuj Aggarwal 	{
6483fa5b8e0SAnuj Aggarwal 		.name = "VDCDC3",
6493fa5b8e0SAnuj Aggarwal 		.min_uV = 725000,
6503fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
6513fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
6523fa5b8e0SAnuj Aggarwal 		.table = VDCDCx_VSEL_table,
6533fa5b8e0SAnuj Aggarwal 	},
6543fa5b8e0SAnuj Aggarwal 	{
6553fa5b8e0SAnuj Aggarwal 		.name = "LDO1",
6563fa5b8e0SAnuj Aggarwal 		.min_uV = 1000000,
6573fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
6583fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
6593fa5b8e0SAnuj Aggarwal 		.table = LDO1_VSEL_table,
6603fa5b8e0SAnuj Aggarwal 	},
6613fa5b8e0SAnuj Aggarwal 	{
6623fa5b8e0SAnuj Aggarwal 		.name = "LDO2",
6633fa5b8e0SAnuj Aggarwal 		.min_uV = 725000,
6643fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
6653fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
6663fa5b8e0SAnuj Aggarwal 		.table = LDO2_VSEL_table,
6673fa5b8e0SAnuj Aggarwal 	},
6683fa5b8e0SAnuj Aggarwal };
6693fa5b8e0SAnuj Aggarwal 
6709e108d33SLiam Girdwood static const struct i2c_device_id tps_6507x_id[] = {
6719e108d33SLiam Girdwood 	{.name = "tps6507x",
6729e108d33SLiam Girdwood 	.driver_data = (unsigned long) tps6507x_regs,},
6739e108d33SLiam Girdwood 	{ },
6743fa5b8e0SAnuj Aggarwal };
6753fa5b8e0SAnuj Aggarwal MODULE_DEVICE_TABLE(i2c, tps_6507x_id);
6763fa5b8e0SAnuj Aggarwal 
6773fa5b8e0SAnuj Aggarwal static struct i2c_driver tps_6507x_i2c_driver = {
6783fa5b8e0SAnuj Aggarwal 	.driver = {
6793fa5b8e0SAnuj Aggarwal 		.name = "tps6507x",
6803fa5b8e0SAnuj Aggarwal 		.owner = THIS_MODULE,
6813fa5b8e0SAnuj Aggarwal 	},
6823fa5b8e0SAnuj Aggarwal 	.probe = tps_6507x_probe,
6833fa5b8e0SAnuj Aggarwal 	.remove = __devexit_p(tps_6507x_remove),
6849e108d33SLiam Girdwood 	.id_table = tps_6507x_id,
6853fa5b8e0SAnuj Aggarwal };
6863fa5b8e0SAnuj Aggarwal 
6873fa5b8e0SAnuj Aggarwal /**
6883fa5b8e0SAnuj Aggarwal  * tps_6507x_init
6893fa5b8e0SAnuj Aggarwal  *
6903fa5b8e0SAnuj Aggarwal  * Module init function
6913fa5b8e0SAnuj Aggarwal  */
6923fa5b8e0SAnuj Aggarwal static int __init tps_6507x_init(void)
6933fa5b8e0SAnuj Aggarwal {
6943fa5b8e0SAnuj Aggarwal 	return i2c_add_driver(&tps_6507x_i2c_driver);
6953fa5b8e0SAnuj Aggarwal }
6963fa5b8e0SAnuj Aggarwal subsys_initcall(tps_6507x_init);
6973fa5b8e0SAnuj Aggarwal 
6983fa5b8e0SAnuj Aggarwal /**
6993fa5b8e0SAnuj Aggarwal  * tps_6507x_cleanup
7003fa5b8e0SAnuj Aggarwal  *
7013fa5b8e0SAnuj Aggarwal  * Module exit function
7023fa5b8e0SAnuj Aggarwal  */
7033fa5b8e0SAnuj Aggarwal static void __exit tps_6507x_cleanup(void)
7043fa5b8e0SAnuj Aggarwal {
7053fa5b8e0SAnuj Aggarwal 	i2c_del_driver(&tps_6507x_i2c_driver);
7063fa5b8e0SAnuj Aggarwal }
7073fa5b8e0SAnuj Aggarwal module_exit(tps_6507x_cleanup);
7083fa5b8e0SAnuj Aggarwal 
7093fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
7103fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
7113fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPL v2");
712