Blame view

drivers/regulator/tps65023-regulator.c 16.8 KB
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  /*
   * tps65023-regulator.c
   *
   * Supports TPS65023 Regulator
   *
   * Copyright (C) 2009 Texas Instrument Incorporated - http://www.ti.com/
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License as
   * published by the Free Software Foundation version 2.
   *
   * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
   * whether express or implied; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/err.h>
  #include <linux/platform_device.h>
  #include <linux/regulator/driver.h>
  #include <linux/regulator/machine.h>
  #include <linux/i2c.h>
  #include <linux/delay.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
27
  #include <linux/slab.h>
90923351d   Mark Brown   regulator: Conver...
28
  #include <linux/regmap.h>
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  
  /* Register definitions */
  #define	TPS65023_REG_VERSION		0
  #define	TPS65023_REG_PGOODZ		1
  #define	TPS65023_REG_MASK		2
  #define	TPS65023_REG_REG_CTRL		3
  #define	TPS65023_REG_CON_CTRL		4
  #define	TPS65023_REG_CON_CTRL2		5
  #define	TPS65023_REG_DEF_CORE		6
  #define	TPS65023_REG_DEFSLEW		7
  #define	TPS65023_REG_LDO_CTRL		8
  
  /* PGOODZ bitfields */
  #define	TPS65023_PGOODZ_PWRFAILZ	BIT(7)
  #define	TPS65023_PGOODZ_LOWBATTZ	BIT(6)
  #define	TPS65023_PGOODZ_VDCDC1		BIT(5)
  #define	TPS65023_PGOODZ_VDCDC2		BIT(4)
  #define	TPS65023_PGOODZ_VDCDC3		BIT(3)
  #define	TPS65023_PGOODZ_LDO2		BIT(2)
  #define	TPS65023_PGOODZ_LDO1		BIT(1)
  
  /* MASK bitfields */
  #define	TPS65023_MASK_PWRFAILZ		BIT(7)
  #define	TPS65023_MASK_LOWBATTZ		BIT(6)
  #define	TPS65023_MASK_VDCDC1		BIT(5)
  #define	TPS65023_MASK_VDCDC2		BIT(4)
  #define	TPS65023_MASK_VDCDC3		BIT(3)
  #define	TPS65023_MASK_LDO2		BIT(2)
  #define	TPS65023_MASK_LDO1		BIT(1)
  
  /* REG_CTRL bitfields */
  #define TPS65023_REG_CTRL_VDCDC1_EN	BIT(5)
  #define TPS65023_REG_CTRL_VDCDC2_EN	BIT(4)
  #define TPS65023_REG_CTRL_VDCDC3_EN	BIT(3)
  #define TPS65023_REG_CTRL_LDO2_EN	BIT(2)
  #define TPS65023_REG_CTRL_LDO1_EN	BIT(1)
fc999b837   Marcus Folkesson   regulator: tps650...
65
66
67
68
  /* REG_CTRL2 bitfields */
  #define TPS65023_REG_CTRL2_GO		BIT(7)
  #define TPS65023_REG_CTRL2_CORE_ADJ	BIT(6)
  #define TPS65023_REG_CTRL2_DCDC2	BIT(2)
f068ad8cc   Marcus Folkesson   regulator: tps650...
69
70
  #define TPS65023_REG_CTRL2_DCDC1	BIT(1)
  #define TPS65023_REG_CTRL2_DCDC3	BIT(0)
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  /* LDO_CTRL bitfields */
  #define TPS65023_LDO_CTRL_LDOx_SHIFT(ldo_id)	((ldo_id)*4)
  #define TPS65023_LDO_CTRL_LDOx_MASK(ldo_id)	(0xF0 >> ((ldo_id)*4))
  
  /* Number of step-down converters available */
  #define TPS65023_NUM_DCDC		3
  /* Number of LDO voltage regulators  available */
  #define TPS65023_NUM_LDO		2
  /* Number of total regulators available */
  #define TPS65023_NUM_REGULATOR	(TPS65023_NUM_DCDC + TPS65023_NUM_LDO)
  
  /* DCDCs */
  #define TPS65023_DCDC_1			0
  #define TPS65023_DCDC_2			1
  #define TPS65023_DCDC_3			2
  /* LDOs */
  #define TPS65023_LDO_1			3
  #define TPS65023_LDO_2			4
  
  #define TPS65023_MAX_REG_ID		TPS65023_LDO_2
  
  /* Supported voltage values for regulators */
1c3ede05d   Marcus Folkesson   regulator: tps650...
93
  static const u16 VCORE_VSEL_table[] = {
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
94
95
96
97
98
99
100
101
102
  	800, 825, 850, 875,
  	900, 925, 950, 975,
  	1000, 1025, 1050, 1075,
  	1100, 1125, 1150, 1175,
  	1200, 1225, 1250, 1275,
  	1300, 1325, 1350, 1375,
  	1400, 1425, 1450, 1475,
  	1500, 1525, 1550, 1600,
  };
437afd2ad   Marcus Folkesson   regulator: tps650...
103
104
105
106
107
  /* Supported voltage values for LDO regulators for tps65020 */
  static const u16 TPS65020_LDO1_VSEL_table[] = {
  	1000, 1050, 1100, 1300,
  	1800, 2500, 3000, 3300,
  };
1c3ede05d   Marcus Folkesson   regulator: tps650...
108

437afd2ad   Marcus Folkesson   regulator: tps650...
109
110
111
112
  static const u16 TPS65020_LDO2_VSEL_table[] = {
  	1000, 1050, 1100, 1300,
  	1800, 2500, 3000, 3300,
  };
1c3ede05d   Marcus Folkesson   regulator: tps650...
113
114
115
116
  
  /* Supported voltage values for LDO regulators
   * for tps65021 and tps65023 */
  static const u16 TPS65023_LDO1_VSEL_table[] = {
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
117
118
119
  	1000, 1100, 1300, 1800,
  	2200, 2600, 2800, 3150,
  };
1c3ede05d   Marcus Folkesson   regulator: tps650...
120
  static const u16 TPS65023_LDO2_VSEL_table[] = {
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
121
122
123
  	1050, 1200, 1300, 1800,
  	2500, 2800, 3000, 3300,
  };
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  /* Regulator specific details */
  struct tps_info {
  	const char *name;
  	unsigned min_uV;
  	unsigned max_uV;
  	bool fixed;
  	u8 table_len;
  	const u16 *table;
  };
  
  /* PMIC details */
  struct tps_pmic {
  	struct regulator_desc desc[TPS65023_NUM_REGULATOR];
  	struct i2c_client *client;
  	struct regulator_dev *rdev[TPS65023_NUM_REGULATOR];
  	const struct tps_info *info[TPS65023_NUM_REGULATOR];
90923351d   Mark Brown   regulator: Conver...
140
  	struct regmap *regmap;
1c3ede05d   Marcus Folkesson   regulator: tps650...
141
142
143
144
145
146
147
  	u8 core_regulator;
  };
  
  /* Struct passed as driver data */
  struct tps_driver_data {
  	const struct tps_info *info;
  	u8 core_regulator;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
148
  };
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
149
150
151
152
  static int tps65023_dcdc_is_enabled(struct regulator_dev *dev)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int data, dcdc = rdev_get_id(dev);
43530b69d   Jonghwan Choi   regulator: Use re...
153
  	int ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
154
155
156
157
158
159
  	u8 shift;
  
  	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
  		return -EINVAL;
  
  	shift = TPS65023_NUM_REGULATOR - dcdc;
43530b69d   Jonghwan Choi   regulator: Use re...
160
  	ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
161

43530b69d   Jonghwan Choi   regulator: Use re...
162
163
  	if (ret != 0)
  		return ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
164
165
166
167
168
169
170
171
  	else
  		return (data & 1<<shift) ? 1 : 0;
  }
  
  static int tps65023_ldo_is_enabled(struct regulator_dev *dev)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int data, ldo = rdev_get_id(dev);
43530b69d   Jonghwan Choi   regulator: Use re...
172
  	int ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
173
174
175
176
177
178
  	u8 shift;
  
  	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
  		return -EINVAL;
  
  	shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
43530b69d   Jonghwan Choi   regulator: Use re...
179
  	ret = regmap_read(tps->regmap, TPS65023_REG_REG_CTRL, &data);
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
180

43530b69d   Jonghwan Choi   regulator: Use re...
181
182
  	if (ret != 0)
  		return ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  	else
  		return (data & 1<<shift) ? 1 : 0;
  }
  
  static int tps65023_dcdc_enable(struct regulator_dev *dev)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int dcdc = rdev_get_id(dev);
  	u8 shift;
  
  	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
  		return -EINVAL;
  
  	shift = TPS65023_NUM_REGULATOR - dcdc;
43530b69d   Jonghwan Choi   regulator: Use re...
197
  	return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
198
199
200
201
202
203
204
205
206
207
208
209
  }
  
  static int tps65023_dcdc_disable(struct regulator_dev *dev)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int dcdc = rdev_get_id(dev);
  	u8 shift;
  
  	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
  		return -EINVAL;
  
  	shift = TPS65023_NUM_REGULATOR - dcdc;
43530b69d   Jonghwan Choi   regulator: Use re...
210
  	return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
211
212
213
214
215
216
217
218
219
220
221
222
  }
  
  static int tps65023_ldo_enable(struct regulator_dev *dev)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int ldo = rdev_get_id(dev);
  	u8 shift;
  
  	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
  		return -EINVAL;
  
  	shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
43530b69d   Jonghwan Choi   regulator: Use re...
223
  	return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 1 << shift);
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
224
225
226
227
228
229
230
231
232
233
234
235
  }
  
  static int tps65023_ldo_disable(struct regulator_dev *dev)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int ldo = rdev_get_id(dev);
  	u8 shift;
  
  	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
  		return -EINVAL;
  
  	shift = (ldo == TPS65023_LDO_1 ? 1 : 2);
43530b69d   Jonghwan Choi   regulator: Use re...
236
  	return regmap_update_bits(tps->regmap, TPS65023_REG_REG_CTRL, 1 << shift, 0);
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
237
238
239
240
241
  }
  
  static int tps65023_dcdc_get_voltage(struct regulator_dev *dev)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
43530b69d   Jonghwan Choi   regulator: Use re...
242
  	int ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
243
244
245
246
  	int data, dcdc = rdev_get_id(dev);
  
  	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
  		return -EINVAL;
1c3ede05d   Marcus Folkesson   regulator: tps650...
247
  	if (dcdc == tps->core_regulator) {
43530b69d   Jonghwan Choi   regulator: Use re...
248
249
250
  		ret = regmap_read(tps->regmap, TPS65023_REG_DEF_CORE, &data);
  		if (ret != 0)
  			return ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
251
252
253
254
255
256
257
  		data &= (tps->info[dcdc]->table_len - 1);
  		return tps->info[dcdc]->table[data] * 1000;
  	} else
  		return tps->info[dcdc]->min_uV;
  }
  
  static int tps65023_dcdc_set_voltage(struct regulator_dev *dev,
3a93f2a9f   Mark Brown   regulator: Report...
258
259
  				     int min_uV, int max_uV,
  				     unsigned *selector)
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
260
261
262
263
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int dcdc = rdev_get_id(dev);
  	int vsel;
cc17ef3f0   Marcus Folkesson   regulator: tps650...
264
  	int ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
265

1c3ede05d   Marcus Folkesson   regulator: tps650...
266
  	if (dcdc != tps->core_regulator)
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
267
  		return -EINVAL;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  	if (min_uV < tps->info[dcdc]->min_uV
  			|| min_uV > tps->info[dcdc]->max_uV)
  		return -EINVAL;
  	if (max_uV < tps->info[dcdc]->min_uV
  			|| max_uV > tps->info[dcdc]->max_uV)
  		return -EINVAL;
  
  	for (vsel = 0; vsel < tps->info[dcdc]->table_len; vsel++) {
  		int mV = tps->info[dcdc]->table[vsel];
  		int uV = mV * 1000;
  
  		/* Break at the first in-range value */
  		if (min_uV <= uV && uV <= max_uV)
  			break;
  	}
3a93f2a9f   Mark Brown   regulator: Report...
283
  	*selector = vsel;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
284
  	if (vsel == tps->info[dcdc]->table_len)
cc17ef3f0   Marcus Folkesson   regulator: tps650...
285
  		goto failed;
43530b69d   Jonghwan Choi   regulator: Use re...
286
  	ret = regmap_write(tps->regmap, TPS65023_REG_DEF_CORE, vsel);
cc17ef3f0   Marcus Folkesson   regulator: tps650...
287
288
289
290
  
  	/* Tell the chip that we have changed the value in DEFCORE
  	 * and its time to update the core voltage
  	 */
43530b69d   Jonghwan Choi   regulator: Use re...
291
292
  	regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
  			TPS65023_REG_CTRL2_GO, TPS65023_REG_CTRL2_GO);
cc17ef3f0   Marcus Folkesson   regulator: tps650...
293
294
295
296
297
  
  	return ret;
  
  failed:
  	return -EINVAL;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
298
299
300
301
302
303
  }
  
  static int tps65023_ldo_get_voltage(struct regulator_dev *dev)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int data, ldo = rdev_get_id(dev);
43530b69d   Jonghwan Choi   regulator: Use re...
304
  	int ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
305
306
307
  
  	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
  		return -EINVAL;
43530b69d   Jonghwan Choi   regulator: Use re...
308
309
310
  	ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
  	if (ret != 0)
  		return ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
311
312
313
314
315
316
317
  
  	data >>= (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1));
  	data &= (tps->info[ldo]->table_len - 1);
  	return tps->info[ldo]->table[data] * 1000;
  }
  
  static int tps65023_ldo_set_voltage(struct regulator_dev *dev,
3a93f2a9f   Mark Brown   regulator: Report...
318
  				    int min_uV, int max_uV, unsigned *selector)
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
319
320
321
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int data, vsel, ldo = rdev_get_id(dev);
43530b69d   Jonghwan Choi   regulator: Use re...
322
  	int ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  
  	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
  		return -EINVAL;
  
  	if (min_uV < tps->info[ldo]->min_uV || min_uV > tps->info[ldo]->max_uV)
  		return -EINVAL;
  	if (max_uV < tps->info[ldo]->min_uV || max_uV > tps->info[ldo]->max_uV)
  		return -EINVAL;
  
  	for (vsel = 0; vsel < tps->info[ldo]->table_len; vsel++) {
  		int mV = tps->info[ldo]->table[vsel];
  		int uV = mV * 1000;
  
  		/* Break at the first in-range value */
  		if (min_uV <= uV && uV <= max_uV)
  			break;
  	}
  
  	if (vsel == tps->info[ldo]->table_len)
  		return -EINVAL;
3a93f2a9f   Mark Brown   regulator: Report...
343
  	*selector = vsel;
43530b69d   Jonghwan Choi   regulator: Use re...
344
345
346
  	ret = regmap_read(tps->regmap, TPS65023_REG_LDO_CTRL, &data);
  	if (ret != 0)
  		return ret;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
347
348
349
  
  	data &= TPS65023_LDO_CTRL_LDOx_MASK(ldo - TPS65023_LDO_1);
  	data |= (vsel << (TPS65023_LDO_CTRL_LDOx_SHIFT(ldo - TPS65023_LDO_1)));
43530b69d   Jonghwan Choi   regulator: Use re...
350
  	return regmap_write(tps->regmap, TPS65023_REG_LDO_CTRL, data);
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
351
352
353
354
355
356
357
358
359
360
  }
  
  static int tps65023_dcdc_list_voltage(struct regulator_dev *dev,
  					unsigned selector)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int dcdc = rdev_get_id(dev);
  
  	if (dcdc < TPS65023_DCDC_1 || dcdc > TPS65023_DCDC_3)
  		return -EINVAL;
1c3ede05d   Marcus Folkesson   regulator: tps650...
361
  	if (dcdc == tps->core_regulator) {
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  		if (selector >= tps->info[dcdc]->table_len)
  			return -EINVAL;
  		else
  			return tps->info[dcdc]->table[selector] * 1000;
  	} else
  		return tps->info[dcdc]->min_uV;
  }
  
  static int tps65023_ldo_list_voltage(struct regulator_dev *dev,
  					unsigned selector)
  {
  	struct tps_pmic *tps = rdev_get_drvdata(dev);
  	int ldo = rdev_get_id(dev);
  
  	if (ldo < TPS65023_LDO_1 || ldo > TPS65023_LDO_2)
  		return -EINVAL;
  
  	if (selector >= tps->info[ldo]->table_len)
  		return -EINVAL;
  	else
  		return tps->info[ldo]->table[selector] * 1000;
  }
  
  /* Operations permitted on VDCDCx */
  static struct regulator_ops tps65023_dcdc_ops = {
  	.is_enabled = tps65023_dcdc_is_enabled,
  	.enable = tps65023_dcdc_enable,
  	.disable = tps65023_dcdc_disable,
  	.get_voltage = tps65023_dcdc_get_voltage,
  	.set_voltage = tps65023_dcdc_set_voltage,
  	.list_voltage = tps65023_dcdc_list_voltage,
  };
  
  /* Operations permitted on LDOx */
  static struct regulator_ops tps65023_ldo_ops = {
  	.is_enabled = tps65023_ldo_is_enabled,
  	.enable = tps65023_ldo_enable,
  	.disable = tps65023_ldo_disable,
  	.get_voltage = tps65023_ldo_get_voltage,
  	.set_voltage = tps65023_ldo_set_voltage,
  	.list_voltage = tps65023_ldo_list_voltage,
  };
90923351d   Mark Brown   regulator: Conver...
404
405
406
407
  static struct regmap_config tps65023_regmap_config = {
  	.reg_bits = 8,
  	.val_bits = 8,
  };
54d13ab10   Dmitry Torokhov   Regulators: tps65...
408
409
  static int __devinit tps_65023_probe(struct i2c_client *client,
  				     const struct i2c_device_id *id)
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
410
  {
1c3ede05d   Marcus Folkesson   regulator: tps650...
411
412
  	const struct tps_driver_data *drv_data = (void *)id->driver_data;
  	const struct tps_info *info = drv_data->info;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
413
414
415
416
  	struct regulator_init_data *init_data;
  	struct regulator_dev *rdev;
  	struct tps_pmic *tps;
  	int i;
54d13ab10   Dmitry Torokhov   Regulators: tps65...
417
  	int error;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
418
419
420
421
422
423
424
425
426
  
  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
  		return -EIO;
  
  	/**
  	 * init_data points to array of regulator_init structures
  	 * coming from the board-evm file.
  	 */
  	init_data = client->dev.platform_data;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
427
428
429
430
431
432
  	if (!init_data)
  		return -EIO;
  
  	tps = kzalloc(sizeof(*tps), GFP_KERNEL);
  	if (!tps)
  		return -ENOMEM;
90923351d   Mark Brown   regulator: Conver...
433
434
435
436
437
438
439
440
  	tps->regmap = regmap_init_i2c(client, &tps65023_regmap_config);
  	if (IS_ERR(tps->regmap)) {
  		error = PTR_ERR(tps->regmap);
  		dev_err(&client->dev, "Failed to allocate register map: %d
  ",
  			error);
  		goto fail_alloc;
  	}
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
441
442
443
  
  	/* common for all regulators */
  	tps->client = client;
1c3ede05d   Marcus Folkesson   regulator: tps650...
444
  	tps->core_regulator = drv_data->core_regulator;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
445
446
447
448
449
450
  
  	for (i = 0; i < TPS65023_NUM_REGULATOR; i++, info++, init_data++) {
  		/* Store regulator specific information */
  		tps->info[i] = info;
  
  		tps->desc[i].name = info->name;
77fa44d0e   Axel Lin   regulator: Fix de...
451
  		tps->desc[i].id = i;
1c3ede05d   Marcus Folkesson   regulator: tps650...
452
  		tps->desc[i].n_voltages = info->table_len;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
453
454
455
456
457
458
459
  		tps->desc[i].ops = (i > TPS65023_DCDC_3 ?
  					&tps65023_ldo_ops : &tps65023_dcdc_ops);
  		tps->desc[i].type = REGULATOR_VOLTAGE;
  		tps->desc[i].owner = THIS_MODULE;
  
  		/* Register the regulators */
  		rdev = regulator_register(&tps->desc[i], &client->dev,
2c043bcbf   Rajendra Nayak   regulator: pass a...
460
  					  init_data, tps, NULL);
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
461
462
463
464
  		if (IS_ERR(rdev)) {
  			dev_err(&client->dev, "failed to register %s
  ",
  				id->name);
54d13ab10   Dmitry Torokhov   Regulators: tps65...
465
466
  			error = PTR_ERR(rdev);
  			goto fail;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
467
468
469
470
471
472
473
  		}
  
  		/* Save regulator for cleanup */
  		tps->rdev[i] = rdev;
  	}
  
  	i2c_set_clientdata(client, tps);
fc999b837   Marcus Folkesson   regulator: tps650...
474
  	/* Enable setting output voltage by I2C */
43530b69d   Jonghwan Choi   regulator: Use re...
475
476
  	regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
  			TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ);
fc999b837   Marcus Folkesson   regulator: tps650...
477

f068ad8cc   Marcus Folkesson   regulator: tps650...
478
  	/* Enable setting output voltage by I2C */
43530b69d   Jonghwan Choi   regulator: Use re...
479
480
  	regmap_update_bits(tps->regmap, TPS65023_REG_CON_CTRL2,
  			TPS65023_REG_CTRL2_CORE_ADJ, TPS65023_REG_CTRL2_CORE_ADJ);
f068ad8cc   Marcus Folkesson   regulator: tps650...
481

30e6599d3   Anuj Aggarwal   Regulator: Add TP...
482
  	return 0;
54d13ab10   Dmitry Torokhov   Regulators: tps65...
483
484
485
486
  
   fail:
  	while (--i >= 0)
  		regulator_unregister(tps->rdev[i]);
90923351d   Mark Brown   regulator: Conver...
487
488
  	regmap_exit(tps->regmap);
   fail_alloc:
54d13ab10   Dmitry Torokhov   Regulators: tps65...
489
490
  	kfree(tps);
  	return error;
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  }
  
  /**
   * tps_65023_remove - TPS65023 driver i2c remove handler
   * @client: i2c driver client device structure
   *
   * Unregister TPS driver as an i2c client device driver
   */
  static int __devexit tps_65023_remove(struct i2c_client *client)
  {
  	struct tps_pmic *tps = i2c_get_clientdata(client);
  	int i;
  
  	for (i = 0; i < TPS65023_NUM_REGULATOR; i++)
  		regulator_unregister(tps->rdev[i]);
90923351d   Mark Brown   regulator: Conver...
506
  	regmap_exit(tps->regmap);
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
507
508
509
510
  	kfree(tps);
  
  	return 0;
  }
437afd2ad   Marcus Folkesson   regulator: tps650...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
  static const struct tps_info tps65020_regs[] = {
  	{
  		.name = "VDCDC1",
  		.min_uV = 3300000,
  		.max_uV = 3300000,
  		.fixed	= 1,
  	},
  	{
  		.name = "VDCDC2",
  		.min_uV =  1800000,
  		.max_uV = 1800000,
  		.fixed = 1,
  	},
  	{
  		.name = "VDCDC3",
  		.min_uV =  800000,
  		.max_uV = 1600000,
  		.table_len = ARRAY_SIZE(VCORE_VSEL_table),
  		.table = VCORE_VSEL_table,
  	},
  
  	{
  		.name = "LDO1",
  		.min_uV = 1000000,
  		.max_uV = 3150000,
  		.table_len = ARRAY_SIZE(TPS65020_LDO1_VSEL_table),
  		.table = TPS65020_LDO1_VSEL_table,
  	},
  	{
  		.name = "LDO2",
  		.min_uV = 1050000,
  		.max_uV = 3300000,
  		.table_len = ARRAY_SIZE(TPS65020_LDO2_VSEL_table),
  		.table = TPS65020_LDO2_VSEL_table,
  	},
  };
1c3ede05d   Marcus Folkesson   regulator: tps650...
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
  static const struct tps_info tps65021_regs[] = {
  	{
  		.name = "VDCDC1",
  		.min_uV =  3300000,
  		.max_uV = 3300000,
  		.fixed = 1,
  	},
  	{
  		.name = "VDCDC2",
  		.min_uV =  1800000,
  		.max_uV = 1800000,
  		.fixed = 1,
  	},
  	{
  		.name = "VDCDC3",
  		.min_uV =  800000,
  		.max_uV = 1600000,
  		.table_len = ARRAY_SIZE(VCORE_VSEL_table),
  		.table = VCORE_VSEL_table,
  	},
  	{
  		.name = "LDO1",
  		.min_uV = 1000000,
  		.max_uV = 3150000,
  		.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
  		.table = TPS65023_LDO1_VSEL_table,
  	},
  	{
  		.name = "LDO2",
  		.min_uV = 1050000,
  		.max_uV = 3300000,
  		.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
  		.table = TPS65023_LDO2_VSEL_table,
  	},
  };
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
582
583
584
585
586
  static const struct tps_info tps65023_regs[] = {
  	{
  		.name = "VDCDC1",
  		.min_uV =  800000,
  		.max_uV = 1600000,
1c3ede05d   Marcus Folkesson   regulator: tps650...
587
588
  		.table_len = ARRAY_SIZE(VCORE_VSEL_table),
  		.table = VCORE_VSEL_table,
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
  	},
  	{
  		.name = "VDCDC2",
  		.min_uV =  3300000,
  		.max_uV = 3300000,
  		.fixed = 1,
  	},
  	{
  		.name = "VDCDC3",
  		.min_uV =  1800000,
  		.max_uV = 1800000,
  		.fixed = 1,
  	},
  	{
  		.name = "LDO1",
  		.min_uV = 1000000,
  		.max_uV = 3150000,
1c3ede05d   Marcus Folkesson   regulator: tps650...
606
607
  		.table_len = ARRAY_SIZE(TPS65023_LDO1_VSEL_table),
  		.table = TPS65023_LDO1_VSEL_table,
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
608
609
610
611
612
  	},
  	{
  		.name = "LDO2",
  		.min_uV = 1050000,
  		.max_uV = 3300000,
1c3ede05d   Marcus Folkesson   regulator: tps650...
613
614
  		.table_len = ARRAY_SIZE(TPS65023_LDO2_VSEL_table),
  		.table = TPS65023_LDO2_VSEL_table,
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
615
616
  	},
  };
437afd2ad   Marcus Folkesson   regulator: tps650...
617
618
619
620
  static struct tps_driver_data tps65020_drv_data = {
  	.info = tps65020_regs,
  	.core_regulator = TPS65023_DCDC_3,
  };
1c3ede05d   Marcus Folkesson   regulator: tps650...
621
622
623
624
625
626
627
628
629
  static struct tps_driver_data tps65021_drv_data = {
  		.info = tps65021_regs,
  		.core_regulator = TPS65023_DCDC_3,
  };
  
  static struct tps_driver_data tps65023_drv_data = {
  		.info = tps65023_regs,
  		.core_regulator = TPS65023_DCDC_1,
  };
9e108d33e   Liam Girdwood   regulator: tps650...
630
631
  static const struct i2c_device_id tps_65023_id[] = {
  	{.name = "tps65023",
1c3ede05d   Marcus Folkesson   regulator: tps650...
632
  	.driver_data = (unsigned long) &tps65023_drv_data},
1880a2fc5   Marek Vasut   tps65023: Allow r...
633
  	{.name = "tps65021",
1c3ede05d   Marcus Folkesson   regulator: tps650...
634
  	.driver_data = (unsigned long) &tps65021_drv_data,},
437afd2ad   Marcus Folkesson   regulator: tps650...
635
636
  	{.name = "tps65020",
  	.driver_data = (unsigned long) &tps65020_drv_data},
9e108d33e   Liam Girdwood   regulator: tps650...
637
  	{ },
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
638
639
640
641
642
643
644
645
646
647
648
  };
  
  MODULE_DEVICE_TABLE(i2c, tps_65023_id);
  
  static struct i2c_driver tps_65023_i2c_driver = {
  	.driver = {
  		.name = "tps65023",
  		.owner = THIS_MODULE,
  	},
  	.probe = tps_65023_probe,
  	.remove = __devexit_p(tps_65023_remove),
9e108d33e   Liam Girdwood   regulator: tps650...
649
  	.id_table = tps_65023_id,
30e6599d3   Anuj Aggarwal   Regulator: Add TP...
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
  };
  
  /**
   * tps_65023_init
   *
   * Module init function
   */
  static int __init tps_65023_init(void)
  {
  	return i2c_add_driver(&tps_65023_i2c_driver);
  }
  subsys_initcall(tps_65023_init);
  
  /**
   * tps_65023_cleanup
   *
   * Module exit function
   */
  static void __exit tps_65023_cleanup(void)
  {
  	i2c_del_driver(&tps_65023_i2c_driver);
  }
  module_exit(tps_65023_cleanup);
  
  MODULE_AUTHOR("Texas Instruments");
  MODULE_DESCRIPTION("TPS65023 voltage regulator driver");
9e108d33e   Liam Girdwood   regulator: tps650...
676
  MODULE_LICENSE("GPL v2");