xref: /linux/drivers/regulator/tps6507x-regulator.c (revision 3fa5b8e08296b250088b1a6b8e3db500ab1b847d)
1*3fa5b8e0SAnuj Aggarwal /*
2*3fa5b8e0SAnuj Aggarwal  * tps6507x-regulator.c
3*3fa5b8e0SAnuj Aggarwal  *
4*3fa5b8e0SAnuj Aggarwal  * Regulator driver for TPS65073 PMIC
5*3fa5b8e0SAnuj Aggarwal  *
6*3fa5b8e0SAnuj Aggarwal  * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/
7*3fa5b8e0SAnuj Aggarwal  *
8*3fa5b8e0SAnuj Aggarwal  * This program is free software; you can redistribute it and/or
9*3fa5b8e0SAnuj Aggarwal  * modify it under the terms of the GNU General Public License as
10*3fa5b8e0SAnuj Aggarwal  * published by the Free Software Foundation version 2.
11*3fa5b8e0SAnuj Aggarwal  *
12*3fa5b8e0SAnuj Aggarwal  * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
13*3fa5b8e0SAnuj Aggarwal  * whether express or implied; without even the implied warranty of
14*3fa5b8e0SAnuj Aggarwal  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*3fa5b8e0SAnuj Aggarwal  * General Public License for more details.
16*3fa5b8e0SAnuj Aggarwal  */
17*3fa5b8e0SAnuj Aggarwal 
18*3fa5b8e0SAnuj Aggarwal #include <linux/kernel.h>
19*3fa5b8e0SAnuj Aggarwal #include <linux/module.h>
20*3fa5b8e0SAnuj Aggarwal #include <linux/init.h>
21*3fa5b8e0SAnuj Aggarwal #include <linux/err.h>
22*3fa5b8e0SAnuj Aggarwal #include <linux/platform_device.h>
23*3fa5b8e0SAnuj Aggarwal #include <linux/regulator/driver.h>
24*3fa5b8e0SAnuj Aggarwal #include <linux/regulator/machine.h>
25*3fa5b8e0SAnuj Aggarwal #include <linux/i2c.h>
26*3fa5b8e0SAnuj Aggarwal #include <linux/delay.h>
27*3fa5b8e0SAnuj Aggarwal 
28*3fa5b8e0SAnuj Aggarwal /* Register definitions */
29*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_PPATH1				0X01
30*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_INT				0X02
31*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CHGCONFIG0				0X03
32*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CHGCONFIG1				0X04
33*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CHGCONFIG2				0X05
34*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CHGCONFIG3				0X06
35*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_REG_ADCONFIG			0X07
36*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_TSCMODE				0X08
37*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_ADRESULT_1				0X09
38*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_ADRESULT_2				0X0A
39*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_PGOOD				0X0B
40*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_PGOODMASK				0X0C
41*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CON_CTRL1				0X0D
42*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CON_CTRL2				0X0E
43*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_CON_CTRL3				0X0F
44*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC1				0X10
45*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC2_LOW			0X11
46*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC2_HIGH			0X12
47*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC3_LOW			0X13
48*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFDCDC3_HIGH			0X14
49*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFSLEW				0X15
50*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_LDO_CTRL1				0X16
51*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_DEFLDO2				0X17
52*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_WLED_CTRL1				0X18
53*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_REG_WLED_CTRL2				0X19
54*3fa5b8e0SAnuj Aggarwal 
55*3fa5b8e0SAnuj Aggarwal /* CON_CTRL1 bitfields */
56*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_DCDC1_ENABLE		BIT(4)
57*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_DCDC2_ENABLE		BIT(3)
58*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_DCDC3_ENABLE		BIT(2)
59*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_LDO1_ENABLE		BIT(1)
60*3fa5b8e0SAnuj Aggarwal #define	TPS6507X_CON_CTRL1_LDO2_ENABLE		BIT(0)
61*3fa5b8e0SAnuj Aggarwal 
62*3fa5b8e0SAnuj Aggarwal /* DEFDCDC1 bitfields */
63*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC1_DCDC1_EXT_ADJ_EN	BIT(7)
64*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC1_DCDC1_MASK		0X3F
65*3fa5b8e0SAnuj Aggarwal 
66*3fa5b8e0SAnuj Aggarwal /* DEFDCDC2_LOW bitfields */
67*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC2_LOW_DCDC2_MASK	0X3F
68*3fa5b8e0SAnuj Aggarwal 
69*3fa5b8e0SAnuj Aggarwal /* DEFDCDC2_HIGH bitfields */
70*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC2_HIGH_DCDC2_MASK	0X3F
71*3fa5b8e0SAnuj Aggarwal 
72*3fa5b8e0SAnuj Aggarwal /* DEFDCDC3_LOW bitfields */
73*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC3_LOW_DCDC3_MASK	0X3F
74*3fa5b8e0SAnuj Aggarwal 
75*3fa5b8e0SAnuj Aggarwal /* DEFDCDC3_HIGH bitfields */
76*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDC3_HIGH_DCDC3_MASK	0X3F
77*3fa5b8e0SAnuj Aggarwal 
78*3fa5b8e0SAnuj Aggarwal /* TPS6507X_REG_LDO_CTRL1 bitfields */
79*3fa5b8e0SAnuj Aggarwal #define TPS6507X_REG_LDO_CTRL1_LDO1_MASK	0X0F
80*3fa5b8e0SAnuj Aggarwal 
81*3fa5b8e0SAnuj Aggarwal /* TPS6507X_REG_DEFLDO2 bitfields */
82*3fa5b8e0SAnuj Aggarwal #define TPS6507X_REG_DEFLDO2_LDO2_MASK		0X3F
83*3fa5b8e0SAnuj Aggarwal 
84*3fa5b8e0SAnuj Aggarwal /* VDCDC MASK */
85*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DEFDCDCX_DCDC_MASK		0X3F
86*3fa5b8e0SAnuj Aggarwal 
87*3fa5b8e0SAnuj Aggarwal /* DCDC's */
88*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_1				0
89*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_2				1
90*3fa5b8e0SAnuj Aggarwal #define TPS6507X_DCDC_3				2
91*3fa5b8e0SAnuj Aggarwal /* LDOs */
92*3fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_1				3
93*3fa5b8e0SAnuj Aggarwal #define TPS6507X_LDO_2				4
94*3fa5b8e0SAnuj Aggarwal 
95*3fa5b8e0SAnuj Aggarwal #define TPS6507X_MAX_REG_ID			TPS6507X_LDO_2
96*3fa5b8e0SAnuj Aggarwal 
97*3fa5b8e0SAnuj Aggarwal /* Number of step-down converters available */
98*3fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_DCDC			3
99*3fa5b8e0SAnuj Aggarwal /* Number of LDO voltage regulators  available */
100*3fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_LDO			2
101*3fa5b8e0SAnuj Aggarwal /* Number of total regulators available */
102*3fa5b8e0SAnuj Aggarwal #define TPS6507X_NUM_REGULATOR		(TPS6507X_NUM_DCDC + TPS6507X_NUM_LDO)
103*3fa5b8e0SAnuj Aggarwal 
104*3fa5b8e0SAnuj Aggarwal /* Supported voltage values for regulators (in milliVolts) */
105*3fa5b8e0SAnuj Aggarwal static const u16 VDCDCx_VSEL_table[] = {
106*3fa5b8e0SAnuj Aggarwal 	725, 750, 775, 800,
107*3fa5b8e0SAnuj Aggarwal 	825, 850, 875, 900,
108*3fa5b8e0SAnuj Aggarwal 	925, 950, 975, 1000,
109*3fa5b8e0SAnuj Aggarwal 	1025, 1050, 1075, 1100,
110*3fa5b8e0SAnuj Aggarwal 	1125, 1150, 1175, 1200,
111*3fa5b8e0SAnuj Aggarwal 	1225, 1250, 1275, 1300,
112*3fa5b8e0SAnuj Aggarwal 	1325, 1350, 1375, 1400,
113*3fa5b8e0SAnuj Aggarwal 	1425, 1450, 1475, 1500,
114*3fa5b8e0SAnuj Aggarwal 	1550, 1600, 1650, 1700,
115*3fa5b8e0SAnuj Aggarwal 	1750, 1800, 1850, 1900,
116*3fa5b8e0SAnuj Aggarwal 	1950, 2000, 2050, 2100,
117*3fa5b8e0SAnuj Aggarwal 	2150, 2200, 2250, 2300,
118*3fa5b8e0SAnuj Aggarwal 	2350, 2400, 2450, 2500,
119*3fa5b8e0SAnuj Aggarwal 	2550, 2600, 2650, 2700,
120*3fa5b8e0SAnuj Aggarwal 	2750, 2800, 2850, 2900,
121*3fa5b8e0SAnuj Aggarwal 	3000, 3100, 3200, 3300,
122*3fa5b8e0SAnuj Aggarwal };
123*3fa5b8e0SAnuj Aggarwal 
124*3fa5b8e0SAnuj Aggarwal static const u16 LDO1_VSEL_table[] = {
125*3fa5b8e0SAnuj Aggarwal 	1000, 1100, 1200, 1250,
126*3fa5b8e0SAnuj Aggarwal 	1300, 1350, 1400, 1500,
127*3fa5b8e0SAnuj Aggarwal 	1600, 1800, 2500, 2750,
128*3fa5b8e0SAnuj Aggarwal 	2800, 3000, 3100, 3300,
129*3fa5b8e0SAnuj Aggarwal };
130*3fa5b8e0SAnuj Aggarwal 
131*3fa5b8e0SAnuj Aggarwal static const u16 LDO2_VSEL_table[] = {
132*3fa5b8e0SAnuj Aggarwal 	725, 750, 775, 800,
133*3fa5b8e0SAnuj Aggarwal 	825, 850, 875, 900,
134*3fa5b8e0SAnuj Aggarwal 	925, 950, 975, 1000,
135*3fa5b8e0SAnuj Aggarwal 	1025, 1050, 1075, 1100,
136*3fa5b8e0SAnuj Aggarwal 	1125, 1150, 1175, 1200,
137*3fa5b8e0SAnuj Aggarwal 	1225, 1250, 1275, 1300,
138*3fa5b8e0SAnuj Aggarwal 	1325, 1350, 1375, 1400,
139*3fa5b8e0SAnuj Aggarwal 	1425, 1450, 1475, 1500,
140*3fa5b8e0SAnuj Aggarwal 	1550, 1600, 1650, 1700,
141*3fa5b8e0SAnuj Aggarwal 	1750, 1800, 1850, 1900,
142*3fa5b8e0SAnuj Aggarwal 	1950, 2000, 2050, 2100,
143*3fa5b8e0SAnuj Aggarwal 	2150, 2200, 2250, 2300,
144*3fa5b8e0SAnuj Aggarwal 	2350, 2400, 2450, 2500,
145*3fa5b8e0SAnuj Aggarwal 	2550, 2600, 2650, 2700,
146*3fa5b8e0SAnuj Aggarwal 	2750, 2800, 2850, 2900,
147*3fa5b8e0SAnuj Aggarwal 	3000, 3100, 3200, 3300,
148*3fa5b8e0SAnuj Aggarwal };
149*3fa5b8e0SAnuj Aggarwal 
150*3fa5b8e0SAnuj Aggarwal static unsigned int num_voltages[] = {ARRAY_SIZE(VDCDCx_VSEL_table),
151*3fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(VDCDCx_VSEL_table),
152*3fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(VDCDCx_VSEL_table),
153*3fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(LDO1_VSEL_table),
154*3fa5b8e0SAnuj Aggarwal 				ARRAY_SIZE(LDO2_VSEL_table)};
155*3fa5b8e0SAnuj Aggarwal 
156*3fa5b8e0SAnuj Aggarwal struct tps_info {
157*3fa5b8e0SAnuj Aggarwal 	const char *name;
158*3fa5b8e0SAnuj Aggarwal 	unsigned min_uV;
159*3fa5b8e0SAnuj Aggarwal 	unsigned max_uV;
160*3fa5b8e0SAnuj Aggarwal 	u8 table_len;
161*3fa5b8e0SAnuj Aggarwal 	const u16 *table;
162*3fa5b8e0SAnuj Aggarwal };
163*3fa5b8e0SAnuj Aggarwal 
164*3fa5b8e0SAnuj Aggarwal struct tps_pmic {
165*3fa5b8e0SAnuj Aggarwal 	struct regulator_desc desc[TPS6507X_NUM_REGULATOR];
166*3fa5b8e0SAnuj Aggarwal 	struct i2c_client *client;
167*3fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev[TPS6507X_NUM_REGULATOR];
168*3fa5b8e0SAnuj Aggarwal 	const struct tps_info *info[TPS6507X_NUM_REGULATOR];
169*3fa5b8e0SAnuj Aggarwal 	struct mutex io_lock;
170*3fa5b8e0SAnuj Aggarwal };
171*3fa5b8e0SAnuj Aggarwal 
172*3fa5b8e0SAnuj Aggarwal static inline int tps_6507x_read(struct tps_pmic *tps, u8 reg)
173*3fa5b8e0SAnuj Aggarwal {
174*3fa5b8e0SAnuj Aggarwal 	return i2c_smbus_read_byte_data(tps->client, reg);
175*3fa5b8e0SAnuj Aggarwal }
176*3fa5b8e0SAnuj Aggarwal 
177*3fa5b8e0SAnuj Aggarwal static inline int tps_6507x_write(struct tps_pmic *tps, u8 reg, u8 val)
178*3fa5b8e0SAnuj Aggarwal {
179*3fa5b8e0SAnuj Aggarwal 	return i2c_smbus_write_byte_data(tps->client, reg, val);
180*3fa5b8e0SAnuj Aggarwal }
181*3fa5b8e0SAnuj Aggarwal 
182*3fa5b8e0SAnuj Aggarwal static int tps_6507x_set_bits(struct tps_pmic *tps, u8 reg, u8 mask)
183*3fa5b8e0SAnuj Aggarwal {
184*3fa5b8e0SAnuj Aggarwal 	int err, data;
185*3fa5b8e0SAnuj Aggarwal 
186*3fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
187*3fa5b8e0SAnuj Aggarwal 
188*3fa5b8e0SAnuj Aggarwal 	data = tps_6507x_read(tps, reg);
189*3fa5b8e0SAnuj Aggarwal 	if (data < 0) {
190*3fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
191*3fa5b8e0SAnuj Aggarwal 		err = data;
192*3fa5b8e0SAnuj Aggarwal 		goto out;
193*3fa5b8e0SAnuj Aggarwal 	}
194*3fa5b8e0SAnuj Aggarwal 
195*3fa5b8e0SAnuj Aggarwal 	data |= mask;
196*3fa5b8e0SAnuj Aggarwal 	err = tps_6507x_write(tps, reg, data);
197*3fa5b8e0SAnuj Aggarwal 	if (err)
198*3fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
199*3fa5b8e0SAnuj Aggarwal 
200*3fa5b8e0SAnuj Aggarwal out:
201*3fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
202*3fa5b8e0SAnuj Aggarwal 	return err;
203*3fa5b8e0SAnuj Aggarwal }
204*3fa5b8e0SAnuj Aggarwal 
205*3fa5b8e0SAnuj Aggarwal static int tps_6507x_clear_bits(struct tps_pmic *tps, u8 reg, u8 mask)
206*3fa5b8e0SAnuj Aggarwal {
207*3fa5b8e0SAnuj Aggarwal 	int err, data;
208*3fa5b8e0SAnuj Aggarwal 
209*3fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
210*3fa5b8e0SAnuj Aggarwal 
211*3fa5b8e0SAnuj Aggarwal 	data = tps_6507x_read(tps, reg);
212*3fa5b8e0SAnuj Aggarwal 	if (data < 0) {
213*3fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
214*3fa5b8e0SAnuj Aggarwal 		err = data;
215*3fa5b8e0SAnuj Aggarwal 		goto out;
216*3fa5b8e0SAnuj Aggarwal 	}
217*3fa5b8e0SAnuj Aggarwal 
218*3fa5b8e0SAnuj Aggarwal 	data &= ~mask;
219*3fa5b8e0SAnuj Aggarwal 	err = tps_6507x_write(tps, reg, data);
220*3fa5b8e0SAnuj Aggarwal 	if (err)
221*3fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
222*3fa5b8e0SAnuj Aggarwal 
223*3fa5b8e0SAnuj Aggarwal out:
224*3fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
225*3fa5b8e0SAnuj Aggarwal 	return err;
226*3fa5b8e0SAnuj Aggarwal }
227*3fa5b8e0SAnuj Aggarwal 
228*3fa5b8e0SAnuj Aggarwal static int tps_6507x_reg_read(struct tps_pmic *tps, u8 reg)
229*3fa5b8e0SAnuj Aggarwal {
230*3fa5b8e0SAnuj Aggarwal 	int data;
231*3fa5b8e0SAnuj Aggarwal 
232*3fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
233*3fa5b8e0SAnuj Aggarwal 
234*3fa5b8e0SAnuj Aggarwal 	data = tps_6507x_read(tps, reg);
235*3fa5b8e0SAnuj Aggarwal 	if (data < 0)
236*3fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Read from reg 0x%x failed\n", reg);
237*3fa5b8e0SAnuj Aggarwal 
238*3fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
239*3fa5b8e0SAnuj Aggarwal 	return data;
240*3fa5b8e0SAnuj Aggarwal }
241*3fa5b8e0SAnuj Aggarwal 
242*3fa5b8e0SAnuj Aggarwal static int tps_6507x_reg_write(struct tps_pmic *tps, u8 reg, u8 val)
243*3fa5b8e0SAnuj Aggarwal {
244*3fa5b8e0SAnuj Aggarwal 	int err;
245*3fa5b8e0SAnuj Aggarwal 
246*3fa5b8e0SAnuj Aggarwal 	mutex_lock(&tps->io_lock);
247*3fa5b8e0SAnuj Aggarwal 
248*3fa5b8e0SAnuj Aggarwal 	err = tps_6507x_write(tps, reg, val);
249*3fa5b8e0SAnuj Aggarwal 	if (err < 0)
250*3fa5b8e0SAnuj Aggarwal 		dev_err(&tps->client->dev, "Write for reg 0x%x failed\n", reg);
251*3fa5b8e0SAnuj Aggarwal 
252*3fa5b8e0SAnuj Aggarwal 	mutex_unlock(&tps->io_lock);
253*3fa5b8e0SAnuj Aggarwal 	return err;
254*3fa5b8e0SAnuj Aggarwal }
255*3fa5b8e0SAnuj Aggarwal 
256*3fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_is_enabled(struct regulator_dev *dev)
257*3fa5b8e0SAnuj Aggarwal {
258*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
259*3fa5b8e0SAnuj Aggarwal 	int data, dcdc = rdev_get_id(dev);
260*3fa5b8e0SAnuj Aggarwal 	u8 shift;
261*3fa5b8e0SAnuj Aggarwal 
262*3fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
263*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
264*3fa5b8e0SAnuj Aggarwal 
265*3fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
266*3fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1);
267*3fa5b8e0SAnuj Aggarwal 
268*3fa5b8e0SAnuj Aggarwal 	if (data < 0)
269*3fa5b8e0SAnuj Aggarwal 		return data;
270*3fa5b8e0SAnuj Aggarwal 	else
271*3fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
272*3fa5b8e0SAnuj Aggarwal }
273*3fa5b8e0SAnuj Aggarwal 
274*3fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_is_enabled(struct regulator_dev *dev)
275*3fa5b8e0SAnuj Aggarwal {
276*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
277*3fa5b8e0SAnuj Aggarwal 	int data, ldo = rdev_get_id(dev);
278*3fa5b8e0SAnuj Aggarwal 	u8 shift;
279*3fa5b8e0SAnuj Aggarwal 
280*3fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
281*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
282*3fa5b8e0SAnuj Aggarwal 
283*3fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
284*3fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, TPS6507X_REG_CON_CTRL1);
285*3fa5b8e0SAnuj Aggarwal 
286*3fa5b8e0SAnuj Aggarwal 	if (data < 0)
287*3fa5b8e0SAnuj Aggarwal 		return data;
288*3fa5b8e0SAnuj Aggarwal 	else
289*3fa5b8e0SAnuj Aggarwal 		return (data & 1<<shift) ? 1 : 0;
290*3fa5b8e0SAnuj Aggarwal }
291*3fa5b8e0SAnuj Aggarwal 
292*3fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_enable(struct regulator_dev *dev)
293*3fa5b8e0SAnuj Aggarwal {
294*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
295*3fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
296*3fa5b8e0SAnuj Aggarwal 	u8 shift;
297*3fa5b8e0SAnuj Aggarwal 
298*3fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
299*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
300*3fa5b8e0SAnuj Aggarwal 
301*3fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
302*3fa5b8e0SAnuj Aggarwal 	return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
303*3fa5b8e0SAnuj Aggarwal }
304*3fa5b8e0SAnuj Aggarwal 
305*3fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_disable(struct regulator_dev *dev)
306*3fa5b8e0SAnuj Aggarwal {
307*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
308*3fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
309*3fa5b8e0SAnuj Aggarwal 	u8 shift;
310*3fa5b8e0SAnuj Aggarwal 
311*3fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
312*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
313*3fa5b8e0SAnuj Aggarwal 
314*3fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - dcdc;
315*3fa5b8e0SAnuj Aggarwal 	return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
316*3fa5b8e0SAnuj Aggarwal }
317*3fa5b8e0SAnuj Aggarwal 
318*3fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_enable(struct regulator_dev *dev)
319*3fa5b8e0SAnuj Aggarwal {
320*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
321*3fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
322*3fa5b8e0SAnuj Aggarwal 	u8 shift;
323*3fa5b8e0SAnuj Aggarwal 
324*3fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
325*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
326*3fa5b8e0SAnuj Aggarwal 
327*3fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
328*3fa5b8e0SAnuj Aggarwal 	return tps_6507x_set_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
329*3fa5b8e0SAnuj Aggarwal }
330*3fa5b8e0SAnuj Aggarwal 
331*3fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_disable(struct regulator_dev *dev)
332*3fa5b8e0SAnuj Aggarwal {
333*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
334*3fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
335*3fa5b8e0SAnuj Aggarwal 	u8 shift;
336*3fa5b8e0SAnuj Aggarwal 
337*3fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
338*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
339*3fa5b8e0SAnuj Aggarwal 
340*3fa5b8e0SAnuj Aggarwal 	shift = TPS6507X_MAX_REG_ID - ldo;
341*3fa5b8e0SAnuj Aggarwal 	return tps_6507x_clear_bits(tps, TPS6507X_REG_CON_CTRL1, 1 << shift);
342*3fa5b8e0SAnuj Aggarwal }
343*3fa5b8e0SAnuj Aggarwal 
344*3fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_get_voltage(struct regulator_dev *dev)
345*3fa5b8e0SAnuj Aggarwal {
346*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
347*3fa5b8e0SAnuj Aggarwal 	int data, dcdc = rdev_get_id(dev);
348*3fa5b8e0SAnuj Aggarwal 	u8 reg;
349*3fa5b8e0SAnuj Aggarwal 
350*3fa5b8e0SAnuj Aggarwal 	switch (dcdc) {
351*3fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
352*3fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
353*3fa5b8e0SAnuj Aggarwal 		break;
354*3fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
355*3fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC2_LOW;
356*3fa5b8e0SAnuj Aggarwal 		break;
357*3fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
358*3fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC3_LOW;
359*3fa5b8e0SAnuj Aggarwal 		break;
360*3fa5b8e0SAnuj Aggarwal 	default:
361*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
362*3fa5b8e0SAnuj Aggarwal 	}
363*3fa5b8e0SAnuj Aggarwal 
364*3fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, reg);
365*3fa5b8e0SAnuj Aggarwal 	if (data < 0)
366*3fa5b8e0SAnuj Aggarwal 		return data;
367*3fa5b8e0SAnuj Aggarwal 
368*3fa5b8e0SAnuj Aggarwal 	data &= TPS6507X_DEFDCDCX_DCDC_MASK;
369*3fa5b8e0SAnuj Aggarwal 	return tps->info[dcdc]->table[data] * 1000;
370*3fa5b8e0SAnuj Aggarwal }
371*3fa5b8e0SAnuj Aggarwal 
372*3fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_set_voltage(struct regulator_dev *dev,
373*3fa5b8e0SAnuj Aggarwal 				int min_uV, int max_uV)
374*3fa5b8e0SAnuj Aggarwal {
375*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
376*3fa5b8e0SAnuj Aggarwal 	int data, vsel, dcdc = rdev_get_id(dev);
377*3fa5b8e0SAnuj Aggarwal 	u8 reg;
378*3fa5b8e0SAnuj Aggarwal 
379*3fa5b8e0SAnuj Aggarwal 	switch (dcdc) {
380*3fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_1:
381*3fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC1;
382*3fa5b8e0SAnuj Aggarwal 		break;
383*3fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_2:
384*3fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC2_LOW;
385*3fa5b8e0SAnuj Aggarwal 		break;
386*3fa5b8e0SAnuj Aggarwal 	case TPS6507X_DCDC_3:
387*3fa5b8e0SAnuj Aggarwal 		reg = TPS6507X_REG_DEFDCDC3_LOW;
388*3fa5b8e0SAnuj Aggarwal 		break;
389*3fa5b8e0SAnuj Aggarwal 	default:
390*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
391*3fa5b8e0SAnuj Aggarwal 	}
392*3fa5b8e0SAnuj Aggarwal 
393*3fa5b8e0SAnuj Aggarwal 	if (min_uV < tps->info[dcdc]->min_uV
394*3fa5b8e0SAnuj Aggarwal 		|| min_uV > tps->info[dcdc]->max_uV)
395*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
396*3fa5b8e0SAnuj Aggarwal 	if (max_uV < tps->info[dcdc]->min_uV
397*3fa5b8e0SAnuj Aggarwal 		|| max_uV > tps->info[dcdc]->max_uV)
398*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
399*3fa5b8e0SAnuj Aggarwal 
400*3fa5b8e0SAnuj Aggarwal 	for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
401*3fa5b8e0SAnuj Aggarwal 		int mV = tps->info[dcdc]->table[vsel];
402*3fa5b8e0SAnuj Aggarwal 		int uV = mV * 1000;
403*3fa5b8e0SAnuj Aggarwal 
404*3fa5b8e0SAnuj Aggarwal 		/* Break at the first in-range value */
405*3fa5b8e0SAnuj Aggarwal 		if (min_uV <= uV && uV <= max_uV)
406*3fa5b8e0SAnuj Aggarwal 			break;
407*3fa5b8e0SAnuj Aggarwal 	}
408*3fa5b8e0SAnuj Aggarwal 
409*3fa5b8e0SAnuj Aggarwal 	/* write to the register in case we found a match */
410*3fa5b8e0SAnuj Aggarwal 	if (vsel == tps->info[dcdc]->table_len)
411*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
412*3fa5b8e0SAnuj Aggarwal 
413*3fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, reg);
414*3fa5b8e0SAnuj Aggarwal 	if (data < 0)
415*3fa5b8e0SAnuj Aggarwal 		return data;
416*3fa5b8e0SAnuj Aggarwal 
417*3fa5b8e0SAnuj Aggarwal 	data &= ~TPS6507X_DEFDCDCX_DCDC_MASK;
418*3fa5b8e0SAnuj Aggarwal 	data |= vsel;
419*3fa5b8e0SAnuj Aggarwal 
420*3fa5b8e0SAnuj Aggarwal 	return tps_6507x_reg_write(tps, reg, data);
421*3fa5b8e0SAnuj Aggarwal }
422*3fa5b8e0SAnuj Aggarwal 
423*3fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_get_voltage(struct regulator_dev *dev)
424*3fa5b8e0SAnuj Aggarwal {
425*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
426*3fa5b8e0SAnuj Aggarwal 	int data, ldo = rdev_get_id(dev);
427*3fa5b8e0SAnuj Aggarwal 	u8 reg, mask;
428*3fa5b8e0SAnuj Aggarwal 
429*3fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
430*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
431*3fa5b8e0SAnuj Aggarwal 	else {
432*3fa5b8e0SAnuj Aggarwal 		reg = (ldo == TPS6507X_LDO_1 ?
433*3fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
434*3fa5b8e0SAnuj Aggarwal 		mask = (ldo == TPS6507X_LDO_1 ?
435*3fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
436*3fa5b8e0SAnuj Aggarwal 				TPS6507X_REG_DEFLDO2_LDO2_MASK);
437*3fa5b8e0SAnuj Aggarwal 	}
438*3fa5b8e0SAnuj Aggarwal 
439*3fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, reg);
440*3fa5b8e0SAnuj Aggarwal 	if (data < 0)
441*3fa5b8e0SAnuj Aggarwal 		return data;
442*3fa5b8e0SAnuj Aggarwal 
443*3fa5b8e0SAnuj Aggarwal 	data &= mask;
444*3fa5b8e0SAnuj Aggarwal 	return tps->info[ldo]->table[data] * 1000;
445*3fa5b8e0SAnuj Aggarwal }
446*3fa5b8e0SAnuj Aggarwal 
447*3fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_set_voltage(struct regulator_dev *dev,
448*3fa5b8e0SAnuj Aggarwal 				int min_uV, int max_uV)
449*3fa5b8e0SAnuj Aggarwal {
450*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
451*3fa5b8e0SAnuj Aggarwal 	int data, vsel, ldo = rdev_get_id(dev);
452*3fa5b8e0SAnuj Aggarwal 	u8 reg, mask;
453*3fa5b8e0SAnuj Aggarwal 
454*3fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
455*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
456*3fa5b8e0SAnuj Aggarwal 	else {
457*3fa5b8e0SAnuj Aggarwal 		reg = (ldo == TPS6507X_LDO_1 ?
458*3fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1 : TPS6507X_REG_DEFLDO2);
459*3fa5b8e0SAnuj Aggarwal 		mask = (ldo == TPS6507X_LDO_1 ?
460*3fa5b8e0SAnuj Aggarwal 			TPS6507X_REG_LDO_CTRL1_LDO1_MASK :
461*3fa5b8e0SAnuj Aggarwal 				TPS6507X_REG_DEFLDO2_LDO2_MASK);
462*3fa5b8e0SAnuj Aggarwal 	}
463*3fa5b8e0SAnuj Aggarwal 
464*3fa5b8e0SAnuj Aggarwal 	if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
465*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
466*3fa5b8e0SAnuj Aggarwal 	if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
467*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
468*3fa5b8e0SAnuj Aggarwal 
469*3fa5b8e0SAnuj Aggarwal 	for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
470*3fa5b8e0SAnuj Aggarwal 		int mV = tps->info[ldo]->table[vsel];
471*3fa5b8e0SAnuj Aggarwal 		int uV = mV * 1000;
472*3fa5b8e0SAnuj Aggarwal 
473*3fa5b8e0SAnuj Aggarwal 		/* Break at the first in-range value */
474*3fa5b8e0SAnuj Aggarwal 		if (min_uV <= uV && uV <= max_uV)
475*3fa5b8e0SAnuj Aggarwal 			break;
476*3fa5b8e0SAnuj Aggarwal 	}
477*3fa5b8e0SAnuj Aggarwal 
478*3fa5b8e0SAnuj Aggarwal 	if (vsel == tps->info[ldo]->table_len)
479*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
480*3fa5b8e0SAnuj Aggarwal 
481*3fa5b8e0SAnuj Aggarwal 	data = tps_6507x_reg_read(tps, reg);
482*3fa5b8e0SAnuj Aggarwal 	if (data < 0)
483*3fa5b8e0SAnuj Aggarwal 		return data;
484*3fa5b8e0SAnuj Aggarwal 
485*3fa5b8e0SAnuj Aggarwal 	data &= ~mask;
486*3fa5b8e0SAnuj Aggarwal 	data |= vsel;
487*3fa5b8e0SAnuj Aggarwal 
488*3fa5b8e0SAnuj Aggarwal 	return tps_6507x_reg_write(tps, reg, data);
489*3fa5b8e0SAnuj Aggarwal }
490*3fa5b8e0SAnuj Aggarwal 
491*3fa5b8e0SAnuj Aggarwal static int tps6507x_dcdc_list_voltage(struct regulator_dev *dev,
492*3fa5b8e0SAnuj Aggarwal 					unsigned selector)
493*3fa5b8e0SAnuj Aggarwal {
494*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
495*3fa5b8e0SAnuj Aggarwal 	int dcdc = rdev_get_id(dev);
496*3fa5b8e0SAnuj Aggarwal 
497*3fa5b8e0SAnuj Aggarwal 	if (dcdc < TPS6507X_DCDC_1 || dcdc > TPS6507X_DCDC_3)
498*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
499*3fa5b8e0SAnuj Aggarwal 
500*3fa5b8e0SAnuj Aggarwal 	if (selector >= tps->info[dcdc]->table_len)
501*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
502*3fa5b8e0SAnuj Aggarwal 	else
503*3fa5b8e0SAnuj Aggarwal 		return tps->info[dcdc]->table[selector] * 1000;
504*3fa5b8e0SAnuj Aggarwal }
505*3fa5b8e0SAnuj Aggarwal 
506*3fa5b8e0SAnuj Aggarwal static int tps6507x_ldo_list_voltage(struct regulator_dev *dev,
507*3fa5b8e0SAnuj Aggarwal 					unsigned selector)
508*3fa5b8e0SAnuj Aggarwal {
509*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = rdev_get_drvdata(dev);
510*3fa5b8e0SAnuj Aggarwal 	int ldo = rdev_get_id(dev);
511*3fa5b8e0SAnuj Aggarwal 
512*3fa5b8e0SAnuj Aggarwal 	if (ldo < TPS6507X_LDO_1 || ldo > TPS6507X_LDO_2)
513*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
514*3fa5b8e0SAnuj Aggarwal 
515*3fa5b8e0SAnuj Aggarwal 	if (selector >= tps->info[ldo]->table_len)
516*3fa5b8e0SAnuj Aggarwal 		return -EINVAL;
517*3fa5b8e0SAnuj Aggarwal 	else
518*3fa5b8e0SAnuj Aggarwal 		return tps->info[ldo]->table[selector] * 1000;
519*3fa5b8e0SAnuj Aggarwal }
520*3fa5b8e0SAnuj Aggarwal 
521*3fa5b8e0SAnuj Aggarwal /* Operations permitted on VDCDCx */
522*3fa5b8e0SAnuj Aggarwal static struct regulator_ops tps6507x_dcdc_ops = {
523*3fa5b8e0SAnuj Aggarwal 	.is_enabled = tps6507x_dcdc_is_enabled,
524*3fa5b8e0SAnuj Aggarwal 	.enable = tps6507x_dcdc_enable,
525*3fa5b8e0SAnuj Aggarwal 	.disable = tps6507x_dcdc_disable,
526*3fa5b8e0SAnuj Aggarwal 	.get_voltage = tps6507x_dcdc_get_voltage,
527*3fa5b8e0SAnuj Aggarwal 	.set_voltage = tps6507x_dcdc_set_voltage,
528*3fa5b8e0SAnuj Aggarwal 	.list_voltage = tps6507x_dcdc_list_voltage,
529*3fa5b8e0SAnuj Aggarwal };
530*3fa5b8e0SAnuj Aggarwal 
531*3fa5b8e0SAnuj Aggarwal /* Operations permitted on LDOx */
532*3fa5b8e0SAnuj Aggarwal static struct regulator_ops tps6507x_ldo_ops = {
533*3fa5b8e0SAnuj Aggarwal 	.is_enabled = tps6507x_ldo_is_enabled,
534*3fa5b8e0SAnuj Aggarwal 	.enable = tps6507x_ldo_enable,
535*3fa5b8e0SAnuj Aggarwal 	.disable = tps6507x_ldo_disable,
536*3fa5b8e0SAnuj Aggarwal 	.get_voltage = tps6507x_ldo_get_voltage,
537*3fa5b8e0SAnuj Aggarwal 	.set_voltage = tps6507x_ldo_set_voltage,
538*3fa5b8e0SAnuj Aggarwal 	.list_voltage = tps6507x_ldo_list_voltage,
539*3fa5b8e0SAnuj Aggarwal };
540*3fa5b8e0SAnuj Aggarwal 
541*3fa5b8e0SAnuj Aggarwal static
542*3fa5b8e0SAnuj Aggarwal int tps_6507x_probe(struct i2c_client *client, const struct i2c_device_id *id)
543*3fa5b8e0SAnuj Aggarwal {
544*3fa5b8e0SAnuj Aggarwal 	static int desc_id;
545*3fa5b8e0SAnuj Aggarwal 	const struct tps_info *info = (void *)id->driver_data;
546*3fa5b8e0SAnuj Aggarwal 	struct regulator_init_data *init_data;
547*3fa5b8e0SAnuj Aggarwal 	struct regulator_dev *rdev;
548*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps;
549*3fa5b8e0SAnuj Aggarwal 	int i;
550*3fa5b8e0SAnuj Aggarwal 
551*3fa5b8e0SAnuj Aggarwal 	if (!i2c_check_functionality(client->adapter,
552*3fa5b8e0SAnuj Aggarwal 				I2C_FUNC_SMBUS_BYTE_DATA))
553*3fa5b8e0SAnuj Aggarwal 		return -EIO;
554*3fa5b8e0SAnuj Aggarwal 
555*3fa5b8e0SAnuj Aggarwal 	/**
556*3fa5b8e0SAnuj Aggarwal 	 * init_data points to array of regulator_init structures
557*3fa5b8e0SAnuj Aggarwal 	 * coming from the board-evm file.
558*3fa5b8e0SAnuj Aggarwal 	 */
559*3fa5b8e0SAnuj Aggarwal 	init_data = client->dev.platform_data;
560*3fa5b8e0SAnuj Aggarwal 
561*3fa5b8e0SAnuj Aggarwal 	if (!init_data)
562*3fa5b8e0SAnuj Aggarwal 		return -EIO;
563*3fa5b8e0SAnuj Aggarwal 
564*3fa5b8e0SAnuj Aggarwal 	tps = kzalloc(sizeof(*tps), GFP_KERNEL);
565*3fa5b8e0SAnuj Aggarwal 	if (!tps)
566*3fa5b8e0SAnuj Aggarwal 		return -ENOMEM;
567*3fa5b8e0SAnuj Aggarwal 
568*3fa5b8e0SAnuj Aggarwal 	mutex_init(&tps->io_lock);
569*3fa5b8e0SAnuj Aggarwal 
570*3fa5b8e0SAnuj Aggarwal 	/* common for all regulators */
571*3fa5b8e0SAnuj Aggarwal 	tps->client = client;
572*3fa5b8e0SAnuj Aggarwal 
573*3fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++, info++, init_data++) {
574*3fa5b8e0SAnuj Aggarwal 		/* Register the regulators */
575*3fa5b8e0SAnuj Aggarwal 		tps->info[i] = info;
576*3fa5b8e0SAnuj Aggarwal 		tps->desc[i].name = info->name;
577*3fa5b8e0SAnuj Aggarwal 		tps->desc[i].id = desc_id++;
578*3fa5b8e0SAnuj Aggarwal 		tps->desc[i].n_voltages = num_voltages[i];
579*3fa5b8e0SAnuj Aggarwal 		tps->desc[i].ops = (i > TPS6507X_DCDC_3 ?
580*3fa5b8e0SAnuj Aggarwal 				&tps6507x_ldo_ops : &tps6507x_dcdc_ops);
581*3fa5b8e0SAnuj Aggarwal 		tps->desc[i].type = REGULATOR_VOLTAGE;
582*3fa5b8e0SAnuj Aggarwal 		tps->desc[i].owner = THIS_MODULE;
583*3fa5b8e0SAnuj Aggarwal 
584*3fa5b8e0SAnuj Aggarwal 		rdev = regulator_register(&tps->desc[i],
585*3fa5b8e0SAnuj Aggarwal 					&client->dev, init_data, tps);
586*3fa5b8e0SAnuj Aggarwal 		if (IS_ERR(rdev)) {
587*3fa5b8e0SAnuj Aggarwal 			dev_err(&client->dev, "failed to register %s\n",
588*3fa5b8e0SAnuj Aggarwal 				id->name);
589*3fa5b8e0SAnuj Aggarwal 
590*3fa5b8e0SAnuj Aggarwal 			/* Unregister */
591*3fa5b8e0SAnuj Aggarwal 			while (i)
592*3fa5b8e0SAnuj Aggarwal 				regulator_unregister(tps->rdev[--i]);
593*3fa5b8e0SAnuj Aggarwal 
594*3fa5b8e0SAnuj Aggarwal 			tps->client = NULL;
595*3fa5b8e0SAnuj Aggarwal 
596*3fa5b8e0SAnuj Aggarwal 			/* clear the client data in i2c */
597*3fa5b8e0SAnuj Aggarwal 			i2c_set_clientdata(client, NULL);
598*3fa5b8e0SAnuj Aggarwal 
599*3fa5b8e0SAnuj Aggarwal 			kfree(tps);
600*3fa5b8e0SAnuj Aggarwal 			return PTR_ERR(rdev);
601*3fa5b8e0SAnuj Aggarwal 		}
602*3fa5b8e0SAnuj Aggarwal 
603*3fa5b8e0SAnuj Aggarwal 		/* Save regulator for cleanup */
604*3fa5b8e0SAnuj Aggarwal 		tps->rdev[i] = rdev;
605*3fa5b8e0SAnuj Aggarwal 	}
606*3fa5b8e0SAnuj Aggarwal 
607*3fa5b8e0SAnuj Aggarwal 	i2c_set_clientdata(client, tps);
608*3fa5b8e0SAnuj Aggarwal 
609*3fa5b8e0SAnuj Aggarwal 	return 0;
610*3fa5b8e0SAnuj Aggarwal }
611*3fa5b8e0SAnuj Aggarwal 
612*3fa5b8e0SAnuj Aggarwal /**
613*3fa5b8e0SAnuj Aggarwal  * tps_6507x_remove - TPS6507x driver i2c remove handler
614*3fa5b8e0SAnuj Aggarwal  * @client: i2c driver client device structure
615*3fa5b8e0SAnuj Aggarwal  *
616*3fa5b8e0SAnuj Aggarwal  * Unregister TPS driver as an i2c client device driver
617*3fa5b8e0SAnuj Aggarwal  */
618*3fa5b8e0SAnuj Aggarwal static int __devexit tps_6507x_remove(struct i2c_client *client)
619*3fa5b8e0SAnuj Aggarwal {
620*3fa5b8e0SAnuj Aggarwal 	struct tps_pmic *tps = i2c_get_clientdata(client);
621*3fa5b8e0SAnuj Aggarwal 	int i;
622*3fa5b8e0SAnuj Aggarwal 
623*3fa5b8e0SAnuj Aggarwal 	for (i = 0; i < TPS6507X_NUM_REGULATOR; i++)
624*3fa5b8e0SAnuj Aggarwal 		regulator_unregister(tps->rdev[i]);
625*3fa5b8e0SAnuj Aggarwal 
626*3fa5b8e0SAnuj Aggarwal 	tps->client = NULL;
627*3fa5b8e0SAnuj Aggarwal 
628*3fa5b8e0SAnuj Aggarwal 	/* clear the client data in i2c */
629*3fa5b8e0SAnuj Aggarwal 	i2c_set_clientdata(client, NULL);
630*3fa5b8e0SAnuj Aggarwal 	kfree(tps);
631*3fa5b8e0SAnuj Aggarwal 
632*3fa5b8e0SAnuj Aggarwal 	return 0;
633*3fa5b8e0SAnuj Aggarwal }
634*3fa5b8e0SAnuj Aggarwal 
635*3fa5b8e0SAnuj Aggarwal static const struct tps_info tps6507x_regs[] = {
636*3fa5b8e0SAnuj Aggarwal 	{
637*3fa5b8e0SAnuj Aggarwal 		.name = "VDCDC1",
638*3fa5b8e0SAnuj Aggarwal 		.min_uV = 725000,
639*3fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
640*3fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
641*3fa5b8e0SAnuj Aggarwal 		.table = VDCDCx_VSEL_table,
642*3fa5b8e0SAnuj Aggarwal 	},
643*3fa5b8e0SAnuj Aggarwal 	{
644*3fa5b8e0SAnuj Aggarwal 		.name = "VDCDC2",
645*3fa5b8e0SAnuj Aggarwal 		.min_uV = 725000,
646*3fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
647*3fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
648*3fa5b8e0SAnuj Aggarwal 		.table = VDCDCx_VSEL_table,
649*3fa5b8e0SAnuj Aggarwal 	},
650*3fa5b8e0SAnuj Aggarwal 	{
651*3fa5b8e0SAnuj Aggarwal 		.name = "VDCDC3",
652*3fa5b8e0SAnuj Aggarwal 		.min_uV = 725000,
653*3fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
654*3fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(VDCDCx_VSEL_table),
655*3fa5b8e0SAnuj Aggarwal 		.table = VDCDCx_VSEL_table,
656*3fa5b8e0SAnuj Aggarwal 	},
657*3fa5b8e0SAnuj Aggarwal 	{
658*3fa5b8e0SAnuj Aggarwal 		.name = "LDO1",
659*3fa5b8e0SAnuj Aggarwal 		.min_uV = 1000000,
660*3fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
661*3fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(LDO1_VSEL_table),
662*3fa5b8e0SAnuj Aggarwal 		.table = LDO1_VSEL_table,
663*3fa5b8e0SAnuj Aggarwal 	},
664*3fa5b8e0SAnuj Aggarwal 	{
665*3fa5b8e0SAnuj Aggarwal 		.name = "LDO2",
666*3fa5b8e0SAnuj Aggarwal 		.min_uV = 725000,
667*3fa5b8e0SAnuj Aggarwal 		.max_uV = 3300000,
668*3fa5b8e0SAnuj Aggarwal 		.table_len = ARRAY_SIZE(LDO2_VSEL_table),
669*3fa5b8e0SAnuj Aggarwal 		.table = LDO2_VSEL_table,
670*3fa5b8e0SAnuj Aggarwal 	},
671*3fa5b8e0SAnuj Aggarwal };
672*3fa5b8e0SAnuj Aggarwal 
673*3fa5b8e0SAnuj Aggarwal static const struct i2c_device_id tps_6507x_id = {
674*3fa5b8e0SAnuj Aggarwal 	.name = "tps6507x",
675*3fa5b8e0SAnuj Aggarwal 	.driver_data = (unsigned long) &tps6507x_regs[0],
676*3fa5b8e0SAnuj Aggarwal };
677*3fa5b8e0SAnuj Aggarwal MODULE_DEVICE_TABLE(i2c, tps_6507x_id);
678*3fa5b8e0SAnuj Aggarwal 
679*3fa5b8e0SAnuj Aggarwal static struct i2c_driver tps_6507x_i2c_driver = {
680*3fa5b8e0SAnuj Aggarwal 	.driver = {
681*3fa5b8e0SAnuj Aggarwal 		.name = "tps6507x",
682*3fa5b8e0SAnuj Aggarwal 		.owner = THIS_MODULE,
683*3fa5b8e0SAnuj Aggarwal 	},
684*3fa5b8e0SAnuj Aggarwal 	.probe = tps_6507x_probe,
685*3fa5b8e0SAnuj Aggarwal 	.remove = __devexit_p(tps_6507x_remove),
686*3fa5b8e0SAnuj Aggarwal 	.id_table = &tps_6507x_id,
687*3fa5b8e0SAnuj Aggarwal };
688*3fa5b8e0SAnuj Aggarwal 
689*3fa5b8e0SAnuj Aggarwal /**
690*3fa5b8e0SAnuj Aggarwal  * tps_6507x_init
691*3fa5b8e0SAnuj Aggarwal  *
692*3fa5b8e0SAnuj Aggarwal  * Module init function
693*3fa5b8e0SAnuj Aggarwal  */
694*3fa5b8e0SAnuj Aggarwal static int __init tps_6507x_init(void)
695*3fa5b8e0SAnuj Aggarwal {
696*3fa5b8e0SAnuj Aggarwal 	return i2c_add_driver(&tps_6507x_i2c_driver);
697*3fa5b8e0SAnuj Aggarwal }
698*3fa5b8e0SAnuj Aggarwal subsys_initcall(tps_6507x_init);
699*3fa5b8e0SAnuj Aggarwal 
700*3fa5b8e0SAnuj Aggarwal /**
701*3fa5b8e0SAnuj Aggarwal  * tps_6507x_cleanup
702*3fa5b8e0SAnuj Aggarwal  *
703*3fa5b8e0SAnuj Aggarwal  * Module exit function
704*3fa5b8e0SAnuj Aggarwal  */
705*3fa5b8e0SAnuj Aggarwal static void __exit tps_6507x_cleanup(void)
706*3fa5b8e0SAnuj Aggarwal {
707*3fa5b8e0SAnuj Aggarwal 	i2c_del_driver(&tps_6507x_i2c_driver);
708*3fa5b8e0SAnuj Aggarwal }
709*3fa5b8e0SAnuj Aggarwal module_exit(tps_6507x_cleanup);
710*3fa5b8e0SAnuj Aggarwal 
711*3fa5b8e0SAnuj Aggarwal MODULE_AUTHOR("Texas Instruments");
712*3fa5b8e0SAnuj Aggarwal MODULE_DESCRIPTION("TPS6507x voltage regulator driver");
713*3fa5b8e0SAnuj Aggarwal MODULE_LICENSE("GPLv2");
714