Root/
1 | /* |
2 | * tps65912.c -- TI tps65912 |
3 | * |
4 | * Copyright 2011 Texas Instruments Inc. |
5 | * |
6 | * Author: Margarita Olaya Cabrera <magi@slimlogic.co.uk> |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the |
10 | * Free Software Foundation; either version 2 of the License, or (at your |
11 | * option) any later version. |
12 | * |
13 | * This driver is based on wm8350 implementation. |
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/slab.h> |
24 | #include <linux/gpio.h> |
25 | #include <linux/mfd/tps65912.h> |
26 | |
27 | /* DCDC's */ |
28 | #define TPS65912_REG_DCDC1 0 |
29 | #define TPS65912_REG_DCDC2 1 |
30 | #define TPS65912_REG_DCDC3 2 |
31 | #define TPS65912_REG_DCDC4 3 |
32 | |
33 | /* LDOs */ |
34 | #define TPS65912_REG_LDO1 4 |
35 | #define TPS65912_REG_LDO2 5 |
36 | #define TPS65912_REG_LDO3 6 |
37 | #define TPS65912_REG_LDO4 7 |
38 | #define TPS65912_REG_LDO5 8 |
39 | #define TPS65912_REG_LDO6 9 |
40 | #define TPS65912_REG_LDO7 10 |
41 | #define TPS65912_REG_LDO8 11 |
42 | #define TPS65912_REG_LDO9 12 |
43 | #define TPS65912_REG_LDO10 13 |
44 | |
45 | /* Number of step-down converters available */ |
46 | #define TPS65912_NUM_DCDC 4 |
47 | |
48 | /* Number of LDO voltage regulators available */ |
49 | #define TPS65912_NUM_LDO 10 |
50 | |
51 | /* Number of total regulators available */ |
52 | #define TPS65912_NUM_REGULATOR (TPS65912_NUM_DCDC + TPS65912_NUM_LDO) |
53 | |
54 | #define TPS65912_REG_ENABLED 0x80 |
55 | #define OP_SELREG_MASK 0x40 |
56 | #define OP_SELREG_SHIFT 6 |
57 | |
58 | struct tps_info { |
59 | const char *name; |
60 | }; |
61 | |
62 | static struct tps_info tps65912_regs[] = { |
63 | { |
64 | .name = "DCDC1", |
65 | }, |
66 | { |
67 | .name = "DCDC2", |
68 | }, |
69 | { |
70 | .name = "DCDC3", |
71 | }, |
72 | { |
73 | .name = "DCDC4", |
74 | }, |
75 | { |
76 | .name = "LDO1", |
77 | }, |
78 | { |
79 | .name = "LDO2", |
80 | }, |
81 | { |
82 | .name = "LDO3", |
83 | }, |
84 | { |
85 | .name = "LDO4", |
86 | }, |
87 | { |
88 | .name = "LDO5", |
89 | }, |
90 | { |
91 | .name = "LDO6", |
92 | }, |
93 | { |
94 | .name = "LDO7", |
95 | }, |
96 | { |
97 | .name = "LDO8", |
98 | }, |
99 | { |
100 | .name = "LDO9", |
101 | }, |
102 | { |
103 | .name = "LDO10", |
104 | }, |
105 | }; |
106 | |
107 | struct tps65912_reg { |
108 | struct regulator_desc desc[TPS65912_NUM_REGULATOR]; |
109 | struct tps65912 *mfd; |
110 | struct regulator_dev *rdev[TPS65912_NUM_REGULATOR]; |
111 | struct tps_info *info[TPS65912_NUM_REGULATOR]; |
112 | /* for read/write access */ |
113 | struct mutex io_lock; |
114 | int mode; |
115 | int (*get_ctrl_reg)(int); |
116 | int dcdc_range[TPS65912_NUM_DCDC]; |
117 | int pwm_mode_reg; |
118 | int eco_reg; |
119 | }; |
120 | |
121 | static int tps65912_get_range(struct tps65912_reg *pmic, int id) |
122 | { |
123 | struct tps65912 *mfd = pmic->mfd; |
124 | int range; |
125 | |
126 | switch (id) { |
127 | case TPS65912_REG_DCDC1: |
128 | range = tps65912_reg_read(mfd, TPS65912_DCDC1_LIMIT); |
129 | break; |
130 | case TPS65912_REG_DCDC2: |
131 | range = tps65912_reg_read(mfd, TPS65912_DCDC2_LIMIT); |
132 | break; |
133 | case TPS65912_REG_DCDC3: |
134 | range = tps65912_reg_read(mfd, TPS65912_DCDC3_LIMIT); |
135 | break; |
136 | case TPS65912_REG_DCDC4: |
137 | range = tps65912_reg_read(mfd, TPS65912_DCDC4_LIMIT); |
138 | break; |
139 | default: |
140 | return 0; |
141 | } |
142 | |
143 | if (range >= 0) |
144 | range = (range & DCDC_LIMIT_RANGE_MASK) |
145 | >> DCDC_LIMIT_RANGE_SHIFT; |
146 | |
147 | pmic->dcdc_range[id] = range; |
148 | return range; |
149 | } |
150 | |
151 | static unsigned long tps65912_vsel_to_uv_range0(u8 vsel) |
152 | { |
153 | unsigned long uv; |
154 | |
155 | uv = ((vsel * 12500) + 500000); |
156 | return uv; |
157 | } |
158 | |
159 | static unsigned long tps65912_vsel_to_uv_range1(u8 vsel) |
160 | { |
161 | unsigned long uv; |
162 | |
163 | uv = ((vsel * 12500) + 700000); |
164 | return uv; |
165 | } |
166 | |
167 | static unsigned long tps65912_vsel_to_uv_range2(u8 vsel) |
168 | { |
169 | unsigned long uv; |
170 | |
171 | uv = ((vsel * 25000) + 500000); |
172 | return uv; |
173 | } |
174 | |
175 | static unsigned long tps65912_vsel_to_uv_range3(u8 vsel) |
176 | { |
177 | unsigned long uv; |
178 | |
179 | if (vsel == 0x3f) |
180 | uv = 3800000; |
181 | else |
182 | uv = ((vsel * 50000) + 500000); |
183 | |
184 | return uv; |
185 | } |
186 | |
187 | static unsigned long tps65912_vsel_to_uv_ldo(u8 vsel) |
188 | { |
189 | unsigned long uv = 0; |
190 | |
191 | if (vsel <= 32) |
192 | uv = ((vsel * 25000) + 800000); |
193 | else if (vsel > 32 && vsel <= 60) |
194 | uv = (((vsel - 32) * 50000) + 1600000); |
195 | else if (vsel > 60) |
196 | uv = (((vsel - 60) * 100000) + 3000000); |
197 | |
198 | return uv; |
199 | } |
200 | |
201 | static int tps65912_get_ctrl_register(int id) |
202 | { |
203 | if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4) |
204 | return id * 3 + TPS65912_DCDC1_AVS; |
205 | else if (id >= TPS65912_REG_LDO5 && id <= TPS65912_REG_LDO10) |
206 | return id - TPS65912_REG_LDO5 + TPS65912_LDO5; |
207 | else |
208 | return -EINVAL; |
209 | } |
210 | |
211 | static int tps65912_get_sel_register(struct tps65912_reg *pmic, int id) |
212 | { |
213 | struct tps65912 *mfd = pmic->mfd; |
214 | int opvsel; |
215 | u8 reg = 0; |
216 | |
217 | if (id >= TPS65912_REG_DCDC1 && id <= TPS65912_REG_LDO4) { |
218 | opvsel = tps65912_reg_read(mfd, id * 3 + TPS65912_DCDC1_OP); |
219 | if (opvsel & OP_SELREG_MASK) |
220 | reg = id * 3 + TPS65912_DCDC1_AVS; |
221 | else |
222 | reg = id * 3 + TPS65912_DCDC1_OP; |
223 | } else if (id >= TPS65912_REG_LDO5 && id <= TPS65912_REG_LDO10) { |
224 | reg = id - TPS65912_REG_LDO5 + TPS65912_LDO5; |
225 | } else { |
226 | return -EINVAL; |
227 | } |
228 | |
229 | return reg; |
230 | } |
231 | |
232 | static int tps65912_get_mode_regiters(struct tps65912_reg *pmic, int id) |
233 | { |
234 | switch (id) { |
235 | case TPS65912_REG_DCDC1: |
236 | pmic->pwm_mode_reg = TPS65912_DCDC1_CTRL; |
237 | pmic->eco_reg = TPS65912_DCDC1_AVS; |
238 | break; |
239 | case TPS65912_REG_DCDC2: |
240 | pmic->pwm_mode_reg = TPS65912_DCDC2_CTRL; |
241 | pmic->eco_reg = TPS65912_DCDC2_AVS; |
242 | break; |
243 | case TPS65912_REG_DCDC3: |
244 | pmic->pwm_mode_reg = TPS65912_DCDC3_CTRL; |
245 | pmic->eco_reg = TPS65912_DCDC3_AVS; |
246 | break; |
247 | case TPS65912_REG_DCDC4: |
248 | pmic->pwm_mode_reg = TPS65912_DCDC4_CTRL; |
249 | pmic->eco_reg = TPS65912_DCDC4_AVS; |
250 | break; |
251 | default: |
252 | return -EINVAL; |
253 | } |
254 | |
255 | return 0; |
256 | } |
257 | |
258 | static int tps65912_reg_is_enabled(struct regulator_dev *dev) |
259 | { |
260 | struct tps65912_reg *pmic = rdev_get_drvdata(dev); |
261 | struct tps65912 *mfd = pmic->mfd; |
262 | int reg, value, id = rdev_get_id(dev); |
263 | |
264 | if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_LDO10) |
265 | return -EINVAL; |
266 | |
267 | reg = pmic->get_ctrl_reg(id); |
268 | if (reg < 0) |
269 | return reg; |
270 | |
271 | value = tps65912_reg_read(mfd, reg); |
272 | if (value < 0) |
273 | return value; |
274 | |
275 | return value & TPS65912_REG_ENABLED; |
276 | } |
277 | |
278 | static int tps65912_reg_enable(struct regulator_dev *dev) |
279 | { |
280 | struct tps65912_reg *pmic = rdev_get_drvdata(dev); |
281 | struct tps65912 *mfd = pmic->mfd; |
282 | int id = rdev_get_id(dev); |
283 | int reg; |
284 | |
285 | if (id < TPS65912_REG_DCDC1 || id > TPS65912_REG_LDO10) |
286 | return -EINVAL; |
287 | |
288 | reg = pmic->get_ctrl_reg(id); |
289 | if (reg < 0) |
290 | return reg; |
291 | |
292 | return tps65912_set_bits(mfd, reg, TPS65912_REG_ENABLED); |
293 | } |
294 | |
295 | static int tps65912_reg_disable(struct regulator_dev *dev) |
296 | { |
297 | struct tps65912_reg *pmic = rdev_get_drvdata(dev); |
298 | struct tps65912 *mfd = pmic->mfd; |
299 | int id = rdev_get_id(dev), reg; |
300 | |
301 | reg = pmic->get_ctrl_reg(id); |
302 | if (reg < 0) |
303 | return reg; |
304 | |
305 | return tps65912_clear_bits(mfd, reg, TPS65912_REG_ENABLED); |
306 | } |
307 | |
308 | static int tps65912_set_mode(struct regulator_dev *dev, unsigned int mode) |
309 | { |
310 | struct tps65912_reg *pmic = rdev_get_drvdata(dev); |
311 | struct tps65912 *mfd = pmic->mfd; |
312 | int pwm_mode, eco, id = rdev_get_id(dev); |
313 | |
314 | tps65912_get_mode_regiters(pmic, id); |
315 | |
316 | pwm_mode = tps65912_reg_read(mfd, pmic->pwm_mode_reg); |
317 | eco = tps65912_reg_read(mfd, pmic->eco_reg); |
318 | |
319 | pwm_mode &= DCDCCTRL_DCDC_MODE_MASK; |
320 | eco &= DCDC_AVS_ECO_MASK; |
321 | |
322 | switch (mode) { |
323 | case REGULATOR_MODE_FAST: |
324 | /* Verify if mode alredy set */ |
325 | if (pwm_mode && !eco) |
326 | break; |
327 | tps65912_set_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK); |
328 | tps65912_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK); |
329 | break; |
330 | case REGULATOR_MODE_NORMAL: |
331 | case REGULATOR_MODE_IDLE: |
332 | if (!pwm_mode && !eco) |
333 | break; |
334 | tps65912_clear_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK); |
335 | tps65912_clear_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK); |
336 | break; |
337 | case REGULATOR_MODE_STANDBY: |
338 | if (!pwm_mode && eco) |
339 | break; |
340 | tps65912_clear_bits(mfd, pmic->pwm_mode_reg, DCDCCTRL_DCDC_MODE_MASK); |
341 | tps65912_set_bits(mfd, pmic->eco_reg, DCDC_AVS_ECO_MASK); |
342 | break; |
343 | default: |
344 | return -EINVAL; |
345 | } |
346 | |
347 | return 0; |
348 | } |
349 | |
350 | static unsigned int tps65912_get_mode(struct regulator_dev *dev) |
351 | { |
352 | struct tps65912_reg *pmic = rdev_get_drvdata(dev); |
353 | struct tps65912 *mfd = pmic->mfd; |
354 | int pwm_mode, eco, mode = 0, id = rdev_get_id(dev); |
355 | |
356 | tps65912_get_mode_regiters(pmic, id); |
357 | |
358 | pwm_mode = tps65912_reg_read(mfd, pmic->pwm_mode_reg); |
359 | eco = tps65912_reg_read(mfd, pmic->eco_reg); |
360 | |
361 | pwm_mode &= DCDCCTRL_DCDC_MODE_MASK; |
362 | eco &= DCDC_AVS_ECO_MASK; |
363 | |
364 | if (pwm_mode && !eco) |
365 | mode = REGULATOR_MODE_FAST; |
366 | else if (!pwm_mode && !eco) |
367 | mode = REGULATOR_MODE_NORMAL; |
368 | else if (!pwm_mode && eco) |
369 | mode = REGULATOR_MODE_STANDBY; |
370 | |
371 | return mode; |
372 | } |
373 | |
374 | static int tps65912_list_voltage(struct regulator_dev *dev, unsigned selector) |
375 | { |
376 | struct tps65912_reg *pmic = rdev_get_drvdata(dev); |
377 | int range, voltage = 0, id = rdev_get_id(dev); |
378 | |
379 | if (id >= TPS65912_REG_LDO1 && id <= TPS65912_REG_LDO10) |
380 | return tps65912_vsel_to_uv_ldo(selector); |
381 | |
382 | if (id > TPS65912_REG_DCDC4) |
383 | return -EINVAL; |
384 | |
385 | range = pmic->dcdc_range[id]; |
386 | |
387 | switch (range) { |
388 | case 0: |
389 | /* 0.5 - 1.2875V in 12.5mV steps */ |
390 | voltage = tps65912_vsel_to_uv_range0(selector); |
391 | break; |
392 | case 1: |
393 | /* 0.7 - 1.4875V in 12.5mV steps */ |
394 | voltage = tps65912_vsel_to_uv_range1(selector); |
395 | break; |
396 | case 2: |
397 | /* 0.5 - 2.075V in 25mV steps */ |
398 | voltage = tps65912_vsel_to_uv_range2(selector); |
399 | break; |
400 | case 3: |
401 | /* 0.5 - 3.8V in 50mV steps */ |
402 | voltage = tps65912_vsel_to_uv_range3(selector); |
403 | break; |
404 | } |
405 | return voltage; |
406 | } |
407 | |
408 | static int tps65912_get_voltage_sel(struct regulator_dev *dev) |
409 | { |
410 | struct tps65912_reg *pmic = rdev_get_drvdata(dev); |
411 | struct tps65912 *mfd = pmic->mfd; |
412 | int id = rdev_get_id(dev); |
413 | int reg, vsel; |
414 | |
415 | reg = tps65912_get_sel_register(pmic, id); |
416 | if (reg < 0) |
417 | return reg; |
418 | |
419 | vsel = tps65912_reg_read(mfd, reg); |
420 | vsel &= 0x3F; |
421 | |
422 | return vsel; |
423 | } |
424 | |
425 | static int tps65912_set_voltage_sel(struct regulator_dev *dev, |
426 | unsigned selector) |
427 | { |
428 | struct tps65912_reg *pmic = rdev_get_drvdata(dev); |
429 | struct tps65912 *mfd = pmic->mfd; |
430 | int id = rdev_get_id(dev); |
431 | int value; |
432 | u8 reg; |
433 | |
434 | reg = tps65912_get_sel_register(pmic, id); |
435 | value = tps65912_reg_read(mfd, reg); |
436 | value &= 0xC0; |
437 | return tps65912_reg_write(mfd, reg, selector | value); |
438 | } |
439 | |
440 | /* Operations permitted on DCDCx */ |
441 | static struct regulator_ops tps65912_ops_dcdc = { |
442 | .is_enabled = tps65912_reg_is_enabled, |
443 | .enable = tps65912_reg_enable, |
444 | .disable = tps65912_reg_disable, |
445 | .set_mode = tps65912_set_mode, |
446 | .get_mode = tps65912_get_mode, |
447 | .get_voltage_sel = tps65912_get_voltage_sel, |
448 | .set_voltage_sel = tps65912_set_voltage_sel, |
449 | .list_voltage = tps65912_list_voltage, |
450 | }; |
451 | |
452 | /* Operations permitted on LDOx */ |
453 | static struct regulator_ops tps65912_ops_ldo = { |
454 | .is_enabled = tps65912_reg_is_enabled, |
455 | .enable = tps65912_reg_enable, |
456 | .disable = tps65912_reg_disable, |
457 | .get_voltage_sel = tps65912_get_voltage_sel, |
458 | .set_voltage_sel = tps65912_set_voltage_sel, |
459 | .list_voltage = tps65912_list_voltage, |
460 | }; |
461 | |
462 | static int tps65912_probe(struct platform_device *pdev) |
463 | { |
464 | struct tps65912 *tps65912 = dev_get_drvdata(pdev->dev.parent); |
465 | struct regulator_config config = { }; |
466 | struct tps_info *info; |
467 | struct regulator_init_data *reg_data; |
468 | struct regulator_dev *rdev; |
469 | struct tps65912_reg *pmic; |
470 | struct tps65912_board *pmic_plat_data; |
471 | int i, err; |
472 | |
473 | pmic_plat_data = dev_get_platdata(tps65912->dev); |
474 | if (!pmic_plat_data) |
475 | return -EINVAL; |
476 | |
477 | reg_data = pmic_plat_data->tps65912_pmic_init_data; |
478 | |
479 | pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL); |
480 | if (!pmic) |
481 | return -ENOMEM; |
482 | |
483 | mutex_init(&pmic->io_lock); |
484 | pmic->mfd = tps65912; |
485 | platform_set_drvdata(pdev, pmic); |
486 | |
487 | pmic->get_ctrl_reg = &tps65912_get_ctrl_register; |
488 | info = tps65912_regs; |
489 | |
490 | for (i = 0; i < TPS65912_NUM_REGULATOR; i++, info++, reg_data++) { |
491 | int range = 0; |
492 | /* Register the regulators */ |
493 | pmic->info[i] = info; |
494 | |
495 | pmic->desc[i].name = info->name; |
496 | pmic->desc[i].id = i; |
497 | pmic->desc[i].n_voltages = 64; |
498 | pmic->desc[i].ops = (i > TPS65912_REG_DCDC4 ? |
499 | &tps65912_ops_ldo : &tps65912_ops_dcdc); |
500 | pmic->desc[i].type = REGULATOR_VOLTAGE; |
501 | pmic->desc[i].owner = THIS_MODULE; |
502 | range = tps65912_get_range(pmic, i); |
503 | |
504 | config.dev = tps65912->dev; |
505 | config.init_data = reg_data; |
506 | config.driver_data = pmic; |
507 | |
508 | rdev = regulator_register(&pmic->desc[i], &config); |
509 | if (IS_ERR(rdev)) { |
510 | dev_err(tps65912->dev, |
511 | "failed to register %s regulator\n", |
512 | pdev->name); |
513 | err = PTR_ERR(rdev); |
514 | goto err; |
515 | } |
516 | |
517 | /* Save regulator for cleanup */ |
518 | pmic->rdev[i] = rdev; |
519 | } |
520 | return 0; |
521 | |
522 | err: |
523 | while (--i >= 0) |
524 | regulator_unregister(pmic->rdev[i]); |
525 | return err; |
526 | } |
527 | |
528 | static int tps65912_remove(struct platform_device *pdev) |
529 | { |
530 | struct tps65912_reg *tps65912_reg = platform_get_drvdata(pdev); |
531 | int i; |
532 | |
533 | for (i = 0; i < TPS65912_NUM_REGULATOR; i++) |
534 | regulator_unregister(tps65912_reg->rdev[i]); |
535 | return 0; |
536 | } |
537 | |
538 | static struct platform_driver tps65912_driver = { |
539 | .driver = { |
540 | .name = "tps65912-pmic", |
541 | .owner = THIS_MODULE, |
542 | }, |
543 | .probe = tps65912_probe, |
544 | .remove = tps65912_remove, |
545 | }; |
546 | |
547 | static int __init tps65912_init(void) |
548 | { |
549 | return platform_driver_register(&tps65912_driver); |
550 | } |
551 | subsys_initcall(tps65912_init); |
552 | |
553 | static void __exit tps65912_cleanup(void) |
554 | { |
555 | platform_driver_unregister(&tps65912_driver); |
556 | } |
557 | module_exit(tps65912_cleanup); |
558 | |
559 | MODULE_AUTHOR("Margarita Olaya Cabrera <magi@slimlogic.co.uk>"); |
560 | MODULE_DESCRIPTION("TPS65912 voltage regulator driver"); |
561 | MODULE_LICENSE("GPL v2"); |
562 | MODULE_ALIAS("platform:tps65912-pmic"); |
563 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9