diff options
author | Graeme Gregory <gg@slimlogic.co.uk> | 2011-05-02 17:20:08 -0400 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2011-05-27 05:49:08 -0400 |
commit | 518fb721de3685c8326e72746151b534a241feda (patch) | |
tree | 9791db510544af58eadd2f5f2754724df292be9a /drivers/regulator | |
parent | e3471bdc2784ee20a0d636c5904200c2d1148ef9 (diff) |
TPS65910: Add tps65910 regulator driver
The regulator module consists of 3 DCDCs and 8 LDOs. The output
voltages are configurable and are meant to supply power to the
main processor and other components
Signed-off-by: Graeme Gregory <gg@slimlogic.co.uk>
Signed-off-by: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
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/Kconfig | 6 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/tps65910-regulator.c | 705 |
3 files changed, 712 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index f0b13a0d1851..d7ed20f293d7 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
@@ -297,5 +297,11 @@ config REGULATOR_TPS6524X | |||
297 | serial interface currently supported on the sequencer serial | 297 | serial interface currently supported on the sequencer serial |
298 | port controller. | 298 | port controller. |
299 | 299 | ||
300 | config REGULATOR_TPS65910 | ||
301 | tristate "TI TPS65910 Power Regulator" | ||
302 | depends on MFD_TPS65910 | ||
303 | help | ||
304 | This driver supports TPS65910 voltage regulator chips. | ||
305 | |||
300 | endif | 306 | endif |
301 | 307 | ||
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 165ff5371e9e..3932d2ec38f3 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
@@ -42,5 +42,6 @@ obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o | |||
42 | obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o | 42 | obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o |
43 | obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o | 43 | obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o |
44 | obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o | 44 | obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o |
45 | obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o | ||
45 | 46 | ||
46 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG | 47 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG |
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c new file mode 100644 index 000000000000..d461fa7906b8 --- /dev/null +++ b/drivers/regulator/tps65910-regulator.c | |||
@@ -0,0 +1,705 @@ | |||
1 | /* | ||
2 | * tps65910.c -- TI tps65910 | ||
3 | * | ||
4 | * Copyright 2010 Texas Instruments Inc. | ||
5 | * | ||
6 | * Author: Graeme Gregory <gg@slimlogic.co.uk> | ||
7 | * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/driver.h> | ||
22 | #include <linux/regulator/machine.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/gpio.h> | ||
26 | #include <linux/mfd/tps65910.h> | ||
27 | |||
28 | #define TPS65910_REG_VRTC 0 | ||
29 | #define TPS65910_REG_VIO 1 | ||
30 | #define TPS65910_REG_VDD1 2 | ||
31 | #define TPS65910_REG_VDD2 3 | ||
32 | #define TPS65910_REG_VDD3 4 | ||
33 | #define TPS65910_REG_VDIG1 5 | ||
34 | #define TPS65910_REG_VDIG2 6 | ||
35 | #define TPS65910_REG_VPLL 7 | ||
36 | #define TPS65910_REG_VDAC 8 | ||
37 | #define TPS65910_REG_VAUX1 9 | ||
38 | #define TPS65910_REG_VAUX2 10 | ||
39 | #define TPS65910_REG_VAUX33 11 | ||
40 | #define TPS65910_REG_VMMC 12 | ||
41 | |||
42 | #define TPS65910_NUM_REGULATOR 13 | ||
43 | |||
44 | #define TPS65910_SUPPLY_STATE_ENABLED 0x1 | ||
45 | |||
46 | /* supported VIO voltages in milivolts */ | ||
47 | static const u16 VIO_VSEL_table[] = { | ||
48 | 1500, 1800, 2500, 3300, | ||
49 | }; | ||
50 | |||
51 | /* supported VIO voltages in milivolts */ | ||
52 | static const u16 VDD3_VSEL_table[] = { | ||
53 | 5000, | ||
54 | }; | ||
55 | |||
56 | /* supported VDIG1 voltages in milivolts */ | ||
57 | static const u16 VDIG1_VSEL_table[] = { | ||
58 | 1200, 1500, 1800, 2700, | ||
59 | }; | ||
60 | |||
61 | /* supported VDIG2 voltages in milivolts */ | ||
62 | static const u16 VDIG2_VSEL_table[] = { | ||
63 | 1000, 1100, 1200, 1800, | ||
64 | }; | ||
65 | |||
66 | /* supported VPLL voltages in milivolts */ | ||
67 | static const u16 VPLL_VSEL_table[] = { | ||
68 | 1000, 1100, 1800, 2500, | ||
69 | }; | ||
70 | |||
71 | /* supported VDAC voltages in milivolts */ | ||
72 | static const u16 VDAC_VSEL_table[] = { | ||
73 | 1800, 2600, 2800, 2850, | ||
74 | }; | ||
75 | |||
76 | /* supported VAUX1 voltages in milivolts */ | ||
77 | static const u16 VAUX1_VSEL_table[] = { | ||
78 | 1800, 2500, 2800, 2850, | ||
79 | }; | ||
80 | |||
81 | /* supported VAUX2 voltages in milivolts */ | ||
82 | static const u16 VAUX2_VSEL_table[] = { | ||
83 | 1800, 2800, 2900, 3300, | ||
84 | }; | ||
85 | |||
86 | /* supported VAUX33 voltages in milivolts */ | ||
87 | static const u16 VAUX33_VSEL_table[] = { | ||
88 | 1800, 2000, 2800, 3300, | ||
89 | }; | ||
90 | |||
91 | /* supported VMMC voltages in milivolts */ | ||
92 | static const u16 VMMC_VSEL_table[] = { | ||
93 | 1800, 2800, 3000, 3300, | ||
94 | }; | ||
95 | |||
96 | struct tps_info { | ||
97 | const char *name; | ||
98 | unsigned min_uV; | ||
99 | unsigned max_uV; | ||
100 | u8 table_len; | ||
101 | const u16 *table; | ||
102 | }; | ||
103 | |||
104 | static struct tps_info tps65910_regs[] = { | ||
105 | { | ||
106 | .name = "VRTC", | ||
107 | }, | ||
108 | { | ||
109 | .name = "VIO", | ||
110 | .min_uV = 1500000, | ||
111 | .max_uV = 3300000, | ||
112 | .table_len = ARRAY_SIZE(VIO_VSEL_table), | ||
113 | .table = VIO_VSEL_table, | ||
114 | }, | ||
115 | { | ||
116 | .name = "VDD1", | ||
117 | .min_uV = 600000, | ||
118 | .max_uV = 4500000, | ||
119 | }, | ||
120 | { | ||
121 | .name = "VDD2", | ||
122 | .min_uV = 600000, | ||
123 | .max_uV = 4500000, | ||
124 | }, | ||
125 | { | ||
126 | .name = "VDD3", | ||
127 | .min_uV = 5000000, | ||
128 | .max_uV = 5000000, | ||
129 | .table_len = ARRAY_SIZE(VDD3_VSEL_table), | ||
130 | .table = VDD3_VSEL_table, | ||
131 | }, | ||
132 | { | ||
133 | .name = "VDIG1", | ||
134 | .min_uV = 1200000, | ||
135 | .max_uV = 2700000, | ||
136 | .table_len = ARRAY_SIZE(VDIG1_VSEL_table), | ||
137 | .table = VDIG1_VSEL_table, | ||
138 | }, | ||
139 | { | ||
140 | .name = "VDIG2", | ||
141 | .min_uV = 1000000, | ||
142 | .max_uV = 1800000, | ||
143 | .table_len = ARRAY_SIZE(VDIG2_VSEL_table), | ||
144 | .table = VDIG2_VSEL_table, | ||
145 | }, | ||
146 | { | ||
147 | .name = "VPLL", | ||
148 | .min_uV = 1000000, | ||
149 | .max_uV = 2500000, | ||
150 | .table_len = ARRAY_SIZE(VPLL_VSEL_table), | ||
151 | .table = VPLL_VSEL_table, | ||
152 | }, | ||
153 | { | ||
154 | .name = "VDAC", | ||
155 | .min_uV = 1800000, | ||
156 | .max_uV = 2850000, | ||
157 | .table_len = ARRAY_SIZE(VDAC_VSEL_table), | ||
158 | .table = VDAC_VSEL_table, | ||
159 | }, | ||
160 | { | ||
161 | .name = "VAUX1", | ||
162 | .min_uV = 1800000, | ||
163 | .max_uV = 2850000, | ||
164 | .table_len = ARRAY_SIZE(VAUX1_VSEL_table), | ||
165 | .table = VAUX1_VSEL_table, | ||
166 | }, | ||
167 | { | ||
168 | .name = "VAUX2", | ||
169 | .min_uV = 1800000, | ||
170 | .max_uV = 3300000, | ||
171 | .table_len = ARRAY_SIZE(VAUX2_VSEL_table), | ||
172 | .table = VAUX2_VSEL_table, | ||
173 | }, | ||
174 | { | ||
175 | .name = "VAUX33", | ||
176 | .min_uV = 1800000, | ||
177 | .max_uV = 3300000, | ||
178 | .table_len = ARRAY_SIZE(VAUX33_VSEL_table), | ||
179 | .table = VAUX33_VSEL_table, | ||
180 | }, | ||
181 | { | ||
182 | .name = "VMMC", | ||
183 | .min_uV = 1800000, | ||
184 | .max_uV = 3300000, | ||
185 | .table_len = ARRAY_SIZE(VMMC_VSEL_table), | ||
186 | .table = VMMC_VSEL_table, | ||
187 | }, | ||
188 | }; | ||
189 | |||
190 | struct tps65910_reg { | ||
191 | struct regulator_desc desc[TPS65910_NUM_REGULATOR]; | ||
192 | struct tps65910 *mfd; | ||
193 | struct regulator_dev *rdev[TPS65910_NUM_REGULATOR]; | ||
194 | struct tps_info *info[TPS65910_NUM_REGULATOR]; | ||
195 | struct mutex mutex; | ||
196 | int mode; | ||
197 | }; | ||
198 | |||
199 | static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) | ||
200 | { | ||
201 | u8 val; | ||
202 | int err; | ||
203 | |||
204 | err = pmic->mfd->read(pmic->mfd, reg, 1, &val); | ||
205 | if (err) | ||
206 | return err; | ||
207 | |||
208 | return val; | ||
209 | } | ||
210 | |||
211 | static inline int tps65910_write(struct tps65910_reg *pmic, u8 reg, u8 val) | ||
212 | { | ||
213 | return pmic->mfd->write(pmic->mfd, reg, 1, &val); | ||
214 | } | ||
215 | |||
216 | static int tps65910_modify_bits(struct tps65910_reg *pmic, u8 reg, | ||
217 | u8 set_mask, u8 clear_mask) | ||
218 | { | ||
219 | int err, data; | ||
220 | |||
221 | mutex_lock(&pmic->mutex); | ||
222 | |||
223 | data = tps65910_read(pmic, reg); | ||
224 | if (data < 0) { | ||
225 | dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg); | ||
226 | err = data; | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | data &= ~clear_mask; | ||
231 | data |= set_mask; | ||
232 | err = tps65910_write(pmic, reg, data); | ||
233 | if (err) | ||
234 | dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); | ||
235 | |||
236 | out: | ||
237 | mutex_unlock(&pmic->mutex); | ||
238 | return err; | ||
239 | } | ||
240 | |||
241 | static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) | ||
242 | { | ||
243 | int data; | ||
244 | |||
245 | mutex_lock(&pmic->mutex); | ||
246 | |||
247 | data = tps65910_read(pmic, reg); | ||
248 | if (data < 0) | ||
249 | dev_err(pmic->mfd->dev, "Read from reg 0x%x failed\n", reg); | ||
250 | |||
251 | mutex_unlock(&pmic->mutex); | ||
252 | return data; | ||
253 | } | ||
254 | |||
255 | static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val) | ||
256 | { | ||
257 | int err; | ||
258 | |||
259 | mutex_lock(&pmic->mutex); | ||
260 | |||
261 | err = tps65910_write(pmic, reg, val); | ||
262 | if (err < 0) | ||
263 | dev_err(pmic->mfd->dev, "Write for reg 0x%x failed\n", reg); | ||
264 | |||
265 | mutex_unlock(&pmic->mutex); | ||
266 | return err; | ||
267 | } | ||
268 | |||
269 | static int tps65910_get_ctrl_register(int id) | ||
270 | { | ||
271 | switch (id) { | ||
272 | case TPS65910_REG_VRTC: | ||
273 | return TPS65910_VRTC; | ||
274 | case TPS65910_REG_VIO: | ||
275 | return TPS65910_VIO; | ||
276 | case TPS65910_REG_VDD1: | ||
277 | return TPS65910_VDD1; | ||
278 | case TPS65910_REG_VDD2: | ||
279 | return TPS65910_VDD2; | ||
280 | case TPS65910_REG_VDD3: | ||
281 | return TPS65910_VDD3; | ||
282 | case TPS65910_REG_VDIG1: | ||
283 | return TPS65910_VDIG1; | ||
284 | case TPS65910_REG_VDIG2: | ||
285 | return TPS65910_VDIG2; | ||
286 | case TPS65910_REG_VPLL: | ||
287 | return TPS65910_VPLL; | ||
288 | case TPS65910_REG_VDAC: | ||
289 | return TPS65910_VDAC; | ||
290 | case TPS65910_REG_VAUX1: | ||
291 | return TPS65910_VAUX1; | ||
292 | case TPS65910_REG_VAUX2: | ||
293 | return TPS65910_VAUX2; | ||
294 | case TPS65910_REG_VAUX33: | ||
295 | return TPS65910_VAUX33; | ||
296 | case TPS65910_REG_VMMC: | ||
297 | return TPS65910_VMMC; | ||
298 | default: | ||
299 | return -EINVAL; | ||
300 | } | ||
301 | } | ||
302 | |||
303 | static int tps65910_is_enabled(struct regulator_dev *dev) | ||
304 | { | ||
305 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
306 | int reg, value, id = rdev_get_id(dev); | ||
307 | |||
308 | reg = tps65910_get_ctrl_register(id); | ||
309 | if (reg < 0) | ||
310 | return reg; | ||
311 | |||
312 | value = tps65910_reg_read(pmic, reg); | ||
313 | if (value < 0) | ||
314 | return value; | ||
315 | |||
316 | return value & TPS65910_SUPPLY_STATE_ENABLED; | ||
317 | } | ||
318 | |||
319 | static int tps65910_enable(struct regulator_dev *dev) | ||
320 | { | ||
321 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
322 | struct tps65910 *mfd = pmic->mfd; | ||
323 | int reg, id = rdev_get_id(dev); | ||
324 | |||
325 | reg = tps65910_get_ctrl_register(id); | ||
326 | if (reg < 0) | ||
327 | return reg; | ||
328 | |||
329 | return tps65910_set_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); | ||
330 | } | ||
331 | |||
332 | static int tps65910_disable(struct regulator_dev *dev) | ||
333 | { | ||
334 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
335 | struct tps65910 *mfd = pmic->mfd; | ||
336 | int reg, id = rdev_get_id(dev); | ||
337 | |||
338 | reg = tps65910_get_ctrl_register(id); | ||
339 | if (reg < 0) | ||
340 | return reg; | ||
341 | |||
342 | return tps65910_clear_bits(mfd, reg, TPS65910_SUPPLY_STATE_ENABLED); | ||
343 | } | ||
344 | |||
345 | |||
346 | static int tps65910_set_mode(struct regulator_dev *dev, unsigned int mode) | ||
347 | { | ||
348 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
349 | struct tps65910 *mfd = pmic->mfd; | ||
350 | int reg, value, id = rdev_get_id(dev); | ||
351 | reg = tps65910_get_ctrl_register(id); | ||
352 | if (reg < 0) | ||
353 | return reg; | ||
354 | |||
355 | switch (mode) { | ||
356 | case REGULATOR_MODE_NORMAL: | ||
357 | return tps65910_modify_bits(pmic, reg, LDO_ST_ON_BIT, | ||
358 | LDO_ST_MODE_BIT); | ||
359 | case REGULATOR_MODE_IDLE: | ||
360 | value = LDO_ST_ON_BIT | LDO_ST_MODE_BIT; | ||
361 | return tps65910_set_bits(mfd, reg, value); | ||
362 | case REGULATOR_MODE_STANDBY: | ||
363 | return tps65910_clear_bits(mfd, reg, LDO_ST_ON_BIT); | ||
364 | } | ||
365 | |||
366 | return -EINVAL; | ||
367 | } | ||
368 | |||
369 | static unsigned int tps65910_get_mode(struct regulator_dev *dev) | ||
370 | { | ||
371 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
372 | int reg, value, id = rdev_get_id(dev); | ||
373 | |||
374 | reg = tps65910_get_ctrl_register(id); | ||
375 | if (reg < 0) | ||
376 | return reg; | ||
377 | |||
378 | value = tps65910_reg_read(pmic, reg); | ||
379 | if (value < 0) | ||
380 | return value; | ||
381 | |||
382 | if (value & LDO_ST_ON_BIT) | ||
383 | return REGULATOR_MODE_STANDBY; | ||
384 | else if (value & LDO_ST_MODE_BIT) | ||
385 | return REGULATOR_MODE_IDLE; | ||
386 | else | ||
387 | return REGULATOR_MODE_NORMAL; | ||
388 | } | ||
389 | |||
390 | static int tps65910_get_voltage_dcdc(struct regulator_dev *dev) | ||
391 | { | ||
392 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
393 | int id = rdev_get_id(dev), voltage = 0; | ||
394 | int opvsel = 0, srvsel = 0, mult = 0, sr = 0; | ||
395 | |||
396 | switch (id) { | ||
397 | case TPS65910_REG_VDD1: | ||
398 | opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP); | ||
399 | mult = tps65910_reg_read(pmic, TPS65910_VDD1); | ||
400 | mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT; | ||
401 | srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR); | ||
402 | sr = opvsel & VDD1_OP_CMD_MASK; | ||
403 | opvsel &= VDD1_OP_SEL_MASK; | ||
404 | srvsel &= VDD1_SR_SEL_MASK; | ||
405 | break; | ||
406 | case TPS65910_REG_VDD2: | ||
407 | opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP); | ||
408 | mult = tps65910_reg_read(pmic, TPS65910_VDD2); | ||
409 | mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT; | ||
410 | srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR); | ||
411 | sr = opvsel & VDD2_OP_CMD_MASK; | ||
412 | opvsel &= VDD2_OP_SEL_MASK; | ||
413 | srvsel &= VDD2_SR_SEL_MASK; | ||
414 | break; | ||
415 | } | ||
416 | |||
417 | /* multiplier 0 == 1 but 2,3 normal */ | ||
418 | if (!mult) | ||
419 | mult=1; | ||
420 | |||
421 | if (sr) { | ||
422 | /* Valid range is 3-75 so normalise */ | ||
423 | if (srvsel < 3) srvsel = 3; | ||
424 | if (srvsel > 75) srvsel = 75; | ||
425 | srvsel -= 3; | ||
426 | |||
427 | voltage = (srvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100; | ||
428 | } else { | ||
429 | |||
430 | /* Valid range is 3-75 so normalise */ | ||
431 | if (opvsel < 3) opvsel = 3; | ||
432 | if (opvsel > 75) opvsel = 75; | ||
433 | opvsel -= 3; | ||
434 | |||
435 | voltage = (opvsel * VDD1_2_OFFSET + VDD1_2_MIN_VOLT) * 100; | ||
436 | } | ||
437 | |||
438 | voltage *= mult; | ||
439 | |||
440 | return voltage; | ||
441 | } | ||
442 | |||
443 | static int tps65910_get_voltage(struct regulator_dev *dev) | ||
444 | { | ||
445 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
446 | int reg, value, id = rdev_get_id(dev), voltage = 0; | ||
447 | |||
448 | reg = tps65910_get_ctrl_register(id); | ||
449 | if (reg < 0) | ||
450 | return reg; | ||
451 | |||
452 | value = tps65910_reg_read(pmic, reg); | ||
453 | if (value < 0) | ||
454 | return value; | ||
455 | |||
456 | switch (id) { | ||
457 | case TPS65910_REG_VIO: | ||
458 | case TPS65910_REG_VDIG1: | ||
459 | case TPS65910_REG_VDIG2: | ||
460 | case TPS65910_REG_VPLL: | ||
461 | case TPS65910_REG_VDAC: | ||
462 | case TPS65910_REG_VAUX1: | ||
463 | case TPS65910_REG_VAUX2: | ||
464 | case TPS65910_REG_VAUX33: | ||
465 | case TPS65910_REG_VMMC: | ||
466 | value &= LDO_SEL_MASK; | ||
467 | value >>= LDO_SEL_SHIFT; | ||
468 | break; | ||
469 | default: | ||
470 | return -EINVAL; | ||
471 | } | ||
472 | |||
473 | voltage = pmic->info[id]->table[value] * 1000; | ||
474 | |||
475 | return voltage; | ||
476 | } | ||
477 | |||
478 | static int tps65910_get_voltage_vdd3(struct regulator_dev *dev) | ||
479 | { | ||
480 | return 5 * 1000 * 1000; | ||
481 | } | ||
482 | |||
483 | static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, | ||
484 | unsigned selector) | ||
485 | { | ||
486 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
487 | int id = rdev_get_id(dev), vsel; | ||
488 | int dcdc_mult; | ||
489 | |||
490 | /* Split vsel into appropriate registers */ | ||
491 | dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1; | ||
492 | if (dcdc_mult == 1) dcdc_mult--; | ||
493 | |||
494 | vsel = (selector % VDD1_2_NUM_VOLTS) + 3; | ||
495 | |||
496 | if (id == TPS65910_REG_VDD1) { | ||
497 | tps65910_modify_bits(pmic, TPS65910_VDD1, | ||
498 | (dcdc_mult << VDD1_VGAIN_SEL_SHIFT), | ||
499 | VDD1_VGAIN_SEL_MASK); | ||
500 | tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel); | ||
501 | } else { | ||
502 | tps65910_modify_bits(pmic, TPS65910_VDD2, | ||
503 | (dcdc_mult << VDD2_VGAIN_SEL_SHIFT), | ||
504 | VDD1_VGAIN_SEL_MASK); | ||
505 | tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel); | ||
506 | } | ||
507 | |||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static int tps65910_set_voltage(struct regulator_dev *dev, unsigned selector) | ||
512 | { | ||
513 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
514 | int reg, id = rdev_get_id(dev); | ||
515 | |||
516 | reg = tps65910_get_ctrl_register(id); | ||
517 | if (reg < 0) | ||
518 | return reg; | ||
519 | |||
520 | switch (id) { | ||
521 | case TPS65910_REG_VIO: | ||
522 | case TPS65910_REG_VDIG1: | ||
523 | case TPS65910_REG_VDIG2: | ||
524 | case TPS65910_REG_VPLL: | ||
525 | case TPS65910_REG_VDAC: | ||
526 | case TPS65910_REG_VAUX1: | ||
527 | case TPS65910_REG_VAUX2: | ||
528 | case TPS65910_REG_VAUX33: | ||
529 | case TPS65910_REG_VMMC: | ||
530 | return tps65910_modify_bits(pmic, reg, | ||
531 | (selector << LDO_SEL_SHIFT), LDO_SEL_MASK); | ||
532 | } | ||
533 | |||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | static int tps65910_list_voltage_dcdc(struct regulator_dev *dev, | ||
538 | unsigned selector) | ||
539 | { | ||
540 | int mult, volt; | ||
541 | |||
542 | mult = (selector / VDD1_2_NUM_VOLTS) + 1; | ||
543 | |||
544 | volt = VDD1_2_MIN_VOLT + (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET; | ||
545 | |||
546 | return volt * 100 * mult; | ||
547 | } | ||
548 | |||
549 | static int tps65910_list_voltage(struct regulator_dev *dev, | ||
550 | unsigned selector) | ||
551 | { | ||
552 | struct tps65910_reg *pmic = rdev_get_drvdata(dev); | ||
553 | int id = rdev_get_id(dev), voltage; | ||
554 | |||
555 | if (id < TPS65910_REG_VIO || id > TPS65910_REG_VMMC) | ||
556 | return -EINVAL; | ||
557 | |||
558 | if (selector >= pmic->info[id]->table_len) | ||
559 | return -EINVAL; | ||
560 | else | ||
561 | voltage = pmic->info[id]->table[selector] * 1000; | ||
562 | |||
563 | return voltage; | ||
564 | } | ||
565 | |||
566 | /* Regulator ops (except VRTC) */ | ||
567 | static struct regulator_ops tps65910_ops_dcdc = { | ||
568 | .is_enabled = tps65910_is_enabled, | ||
569 | .enable = tps65910_enable, | ||
570 | .disable = tps65910_disable, | ||
571 | .set_mode = tps65910_set_mode, | ||
572 | .get_mode = tps65910_get_mode, | ||
573 | .get_voltage = tps65910_get_voltage_dcdc, | ||
574 | .set_voltage_sel = tps65910_set_voltage_dcdc, | ||
575 | .list_voltage = tps65910_list_voltage_dcdc, | ||
576 | }; | ||
577 | |||
578 | static struct regulator_ops tps65910_ops_vdd3 = { | ||
579 | .is_enabled = tps65910_is_enabled, | ||
580 | .enable = tps65910_enable, | ||
581 | .disable = tps65910_disable, | ||
582 | .set_mode = tps65910_set_mode, | ||
583 | .get_mode = tps65910_get_mode, | ||
584 | .get_voltage = tps65910_get_voltage_vdd3, | ||
585 | .list_voltage = tps65910_list_voltage, | ||
586 | }; | ||
587 | |||
588 | static struct regulator_ops tps65910_ops = { | ||
589 | .is_enabled = tps65910_is_enabled, | ||
590 | .enable = tps65910_enable, | ||
591 | .disable = tps65910_disable, | ||
592 | .set_mode = tps65910_set_mode, | ||
593 | .get_mode = tps65910_get_mode, | ||
594 | .get_voltage = tps65910_get_voltage, | ||
595 | .set_voltage_sel = tps65910_set_voltage, | ||
596 | .list_voltage = tps65910_list_voltage, | ||
597 | }; | ||
598 | |||
599 | static __devinit int tps65910_probe(struct platform_device *pdev) | ||
600 | { | ||
601 | struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); | ||
602 | struct tps_info *info = tps65910_regs; | ||
603 | struct regulator_init_data *reg_data; | ||
604 | struct regulator_dev *rdev; | ||
605 | struct tps65910_reg *pmic; | ||
606 | struct tps65910_board *pmic_plat_data; | ||
607 | static int desc_id; | ||
608 | int i, err; | ||
609 | |||
610 | pmic_plat_data = dev_get_platdata(tps65910->dev); | ||
611 | if (!pmic_plat_data) | ||
612 | return -EINVAL; | ||
613 | |||
614 | reg_data = pmic_plat_data->tps65910_pmic_init_data; | ||
615 | |||
616 | pmic = kzalloc(sizeof(*pmic), GFP_KERNEL); | ||
617 | if (!pmic) | ||
618 | return -ENOMEM; | ||
619 | |||
620 | mutex_init(&pmic->mutex); | ||
621 | pmic->mfd = tps65910; | ||
622 | platform_set_drvdata(pdev, pmic); | ||
623 | |||
624 | /* Give control of all register to control port */ | ||
625 | tps65910_set_bits(pmic->mfd, TPS65910_DEVCTRL, | ||
626 | DEVCTRL_SR_CTL_I2C_SEL_MASK); | ||
627 | |||
628 | for (i = 0; i < TPS65910_NUM_REGULATOR; i++, info++, reg_data++) { | ||
629 | /* Register the regulators */ | ||
630 | pmic->info[i] = info; | ||
631 | |||
632 | pmic->desc[i].name = info->name; | ||
633 | pmic->desc[i].id = desc_id++; | ||
634 | pmic->desc[i].n_voltages = info->table_len; | ||
635 | |||
636 | if ((i == TPS65910_REG_VDD1) || (i == TPS65910_REG_VDD2)) | ||
637 | pmic->desc[i].ops = &tps65910_ops_dcdc; | ||
638 | else if (i == TPS65910_REG_VDD3) | ||
639 | pmic->desc[i].ops = &tps65910_ops_vdd3; | ||
640 | else | ||
641 | pmic->desc[i].ops = &tps65910_ops; | ||
642 | |||
643 | pmic->desc[i].type = REGULATOR_VOLTAGE; | ||
644 | pmic->desc[i].owner = THIS_MODULE; | ||
645 | |||
646 | rdev = regulator_register(&pmic->desc[i], | ||
647 | tps65910->dev, reg_data, pmic); | ||
648 | if (IS_ERR(rdev)) { | ||
649 | dev_err(tps65910->dev, | ||
650 | "failed to register %s regulator\n", | ||
651 | pdev->name); | ||
652 | err = PTR_ERR(rdev); | ||
653 | goto err; | ||
654 | } | ||
655 | |||
656 | /* Save regulator for cleanup */ | ||
657 | pmic->rdev[i] = rdev; | ||
658 | } | ||
659 | return 0; | ||
660 | |||
661 | err: | ||
662 | while (--i >= 0) | ||
663 | regulator_unregister(pmic->rdev[i]); | ||
664 | |||
665 | kfree(pmic); | ||
666 | return err; | ||
667 | } | ||
668 | |||
669 | static int __devexit tps65910_remove(struct platform_device *pdev) | ||
670 | { | ||
671 | struct tps65910_reg *tps65910_reg = platform_get_drvdata(pdev); | ||
672 | int i; | ||
673 | |||
674 | for (i = 0; i < TPS65910_NUM_REGULATOR; i++) | ||
675 | regulator_unregister(tps65910_reg->rdev[i]); | ||
676 | |||
677 | kfree(tps65910_reg); | ||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | static struct platform_driver tps65910_driver = { | ||
682 | .driver = { | ||
683 | .name = "tps65910-pmic", | ||
684 | .owner = THIS_MODULE, | ||
685 | }, | ||
686 | .probe = tps65910_probe, | ||
687 | .remove = __devexit_p(tps65910_remove), | ||
688 | }; | ||
689 | |||
690 | static int __init tps65910_init(void) | ||
691 | { | ||
692 | return platform_driver_register(&tps65910_driver); | ||
693 | } | ||
694 | subsys_initcall(tps65910_init); | ||
695 | |||
696 | static void __exit tps65910_cleanup(void) | ||
697 | { | ||
698 | platform_driver_unregister(&tps65910_driver); | ||
699 | } | ||
700 | module_exit(tps65910_cleanup); | ||
701 | |||
702 | MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); | ||
703 | MODULE_DESCRIPTION("TPS6507x voltage regulator driver"); | ||
704 | MODULE_LICENSE("GPL v2"); | ||
705 | MODULE_ALIAS("platform:tps65910-pmic"); | ||