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