blob: 4bd25e75efa0e2ff7b7383e8dbb39387830296be [file] [log] [blame]
Bengt Jonsson1032fbf2011-04-01 14:43:33 +02001/*
2 * Copyright (C) ST-Ericsson SA 2010
3 *
4 * License Terms: GNU General Public License v2
5 * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
6 * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
7 *
8 * Power domain regulators on DB8500
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/err.h>
14#include <linux/spinlock.h>
15#include <linux/platform_device.h>
Mattias Nilsson73180f82011-08-12 10:28:10 +020016#include <linux/mfd/dbx500-prcmu.h>
Bengt Jonsson1032fbf2011-04-01 14:43:33 +020017#include <linux/regulator/driver.h>
18#include <linux/regulator/machine.h>
19#include <linux/regulator/db8500-prcmu.h>
Paul Gortmaker65602c32011-07-17 16:28:23 -040020#include <linux/module.h>
Bengt Jonsson38e96832012-01-13 16:30:31 +010021#include "dbx500-prcmu.h"
Bengt Jonsson1032fbf2011-04-01 14:43:33 +020022
23static int db8500_regulator_enable(struct regulator_dev *rdev)
24{
Bengt Jonsson38e96832012-01-13 16:30:31 +010025 struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +020026
27 if (info == NULL)
28 return -EINVAL;
29
30 dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n",
31 info->desc.name);
32
Bengt Jonsson38e96832012-01-13 16:30:31 +010033 if (!info->is_enabled) {
34 info->is_enabled = true;
35 if (!info->exclude_from_power_state)
36 power_state_active_enable();
37 }
Bengt Jonsson1032fbf2011-04-01 14:43:33 +020038
39 return 0;
40}
41
42static int db8500_regulator_disable(struct regulator_dev *rdev)
43{
Bengt Jonsson38e96832012-01-13 16:30:31 +010044 struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +020045 int ret = 0;
46
47 if (info == NULL)
48 return -EINVAL;
49
50 dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n",
51 info->desc.name);
52
Bengt Jonsson38e96832012-01-13 16:30:31 +010053 if (info->is_enabled) {
54 info->is_enabled = false;
55 if (!info->exclude_from_power_state)
56 ret = power_state_active_disable();
57 }
Bengt Jonsson1032fbf2011-04-01 14:43:33 +020058
59 return ret;
60}
61
62static int db8500_regulator_is_enabled(struct regulator_dev *rdev)
63{
Bengt Jonsson38e96832012-01-13 16:30:31 +010064 struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +020065
66 if (info == NULL)
67 return -EINVAL;
68
69 dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):"
70 " %i\n", info->desc.name, info->is_enabled);
71
72 return info->is_enabled;
73}
74
75/* db8500 regulator operations */
76static struct regulator_ops db8500_regulator_ops = {
77 .enable = db8500_regulator_enable,
78 .disable = db8500_regulator_disable,
79 .is_enabled = db8500_regulator_is_enabled,
80};
81
82/*
83 * EPOD control
84 */
85static bool epod_on[NUM_EPOD_ID];
86static bool epod_ramret[NUM_EPOD_ID];
87
88static int enable_epod(u16 epod_id, bool ramret)
89{
90 int ret;
91
92 if (ramret) {
93 if (!epod_on[epod_id]) {
94 ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
95 if (ret < 0)
96 return ret;
97 }
98 epod_ramret[epod_id] = true;
99 } else {
100 ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
101 if (ret < 0)
102 return ret;
103 epod_on[epod_id] = true;
104 }
105
106 return 0;
107}
108
109static int disable_epod(u16 epod_id, bool ramret)
110{
111 int ret;
112
113 if (ramret) {
114 if (!epod_on[epod_id]) {
115 ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
116 if (ret < 0)
117 return ret;
118 }
119 epod_ramret[epod_id] = false;
120 } else {
121 if (epod_ramret[epod_id]) {
122 ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
123 if (ret < 0)
124 return ret;
125 } else {
126 ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
127 if (ret < 0)
128 return ret;
129 }
130 epod_on[epod_id] = false;
131 }
132
133 return 0;
134}
135
136/*
137 * Regulator switch
138 */
139static int db8500_regulator_switch_enable(struct regulator_dev *rdev)
140{
Bengt Jonsson38e96832012-01-13 16:30:31 +0100141 struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200142 int ret;
143
144 if (info == NULL)
145 return -EINVAL;
146
147 dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n",
148 info->desc.name);
149
150 ret = enable_epod(info->epod_id, info->is_ramret);
151 if (ret < 0) {
152 dev_err(rdev_get_dev(rdev),
153 "regulator-switch-%s-enable: prcmu call failed\n",
154 info->desc.name);
155 goto out;
156 }
157
158 info->is_enabled = true;
159out:
160 return ret;
161}
162
163static int db8500_regulator_switch_disable(struct regulator_dev *rdev)
164{
Bengt Jonsson38e96832012-01-13 16:30:31 +0100165 struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200166 int ret;
167
168 if (info == NULL)
169 return -EINVAL;
170
171 dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n",
172 info->desc.name);
173
174 ret = disable_epod(info->epod_id, info->is_ramret);
175 if (ret < 0) {
176 dev_err(rdev_get_dev(rdev),
177 "regulator_switch-%s-disable: prcmu call failed\n",
178 info->desc.name);
179 goto out;
180 }
181
182 info->is_enabled = 0;
183out:
184 return ret;
185}
186
187static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev)
188{
Bengt Jonsson38e96832012-01-13 16:30:31 +0100189 struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200190
191 if (info == NULL)
192 return -EINVAL;
193
194 dev_vdbg(rdev_get_dev(rdev),
195 "regulator-switch-%s-is_enabled (is_enabled): %i\n",
196 info->desc.name, info->is_enabled);
197
198 return info->is_enabled;
199}
200
201static struct regulator_ops db8500_regulator_switch_ops = {
202 .enable = db8500_regulator_switch_enable,
203 .disable = db8500_regulator_switch_disable,
204 .is_enabled = db8500_regulator_switch_is_enabled,
205};
206
207/*
208 * Regulator information
209 */
Bengt Jonsson38e96832012-01-13 16:30:31 +0100210static struct dbx500_regulator_info
211dbx500_regulator_info[DB8500_NUM_REGULATORS] = {
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200212 [DB8500_REGULATOR_VAPE] = {
213 .desc = {
214 .name = "db8500-vape",
215 .id = DB8500_REGULATOR_VAPE,
216 .ops = &db8500_regulator_ops,
217 .type = REGULATOR_VOLTAGE,
218 .owner = THIS_MODULE,
219 },
220 },
221 [DB8500_REGULATOR_VARM] = {
222 .desc = {
223 .name = "db8500-varm",
224 .id = DB8500_REGULATOR_VARM,
225 .ops = &db8500_regulator_ops,
226 .type = REGULATOR_VOLTAGE,
227 .owner = THIS_MODULE,
228 },
229 },
230 [DB8500_REGULATOR_VMODEM] = {
231 .desc = {
232 .name = "db8500-vmodem",
233 .id = DB8500_REGULATOR_VMODEM,
234 .ops = &db8500_regulator_ops,
235 .type = REGULATOR_VOLTAGE,
236 .owner = THIS_MODULE,
237 },
238 },
239 [DB8500_REGULATOR_VPLL] = {
240 .desc = {
241 .name = "db8500-vpll",
242 .id = DB8500_REGULATOR_VPLL,
243 .ops = &db8500_regulator_ops,
244 .type = REGULATOR_VOLTAGE,
245 .owner = THIS_MODULE,
246 },
247 },
248 [DB8500_REGULATOR_VSMPS1] = {
249 .desc = {
250 .name = "db8500-vsmps1",
251 .id = DB8500_REGULATOR_VSMPS1,
252 .ops = &db8500_regulator_ops,
253 .type = REGULATOR_VOLTAGE,
254 .owner = THIS_MODULE,
255 },
256 },
257 [DB8500_REGULATOR_VSMPS2] = {
258 .desc = {
259 .name = "db8500-vsmps2",
260 .id = DB8500_REGULATOR_VSMPS2,
261 .ops = &db8500_regulator_ops,
262 .type = REGULATOR_VOLTAGE,
263 .owner = THIS_MODULE,
264 },
265 .exclude_from_power_state = true,
266 },
267 [DB8500_REGULATOR_VSMPS3] = {
268 .desc = {
269 .name = "db8500-vsmps3",
270 .id = DB8500_REGULATOR_VSMPS3,
271 .ops = &db8500_regulator_ops,
272 .type = REGULATOR_VOLTAGE,
273 .owner = THIS_MODULE,
274 },
275 },
276 [DB8500_REGULATOR_VRF1] = {
277 .desc = {
278 .name = "db8500-vrf1",
279 .id = DB8500_REGULATOR_VRF1,
280 .ops = &db8500_regulator_ops,
281 .type = REGULATOR_VOLTAGE,
282 .owner = THIS_MODULE,
283 },
284 },
285 [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
286 .desc = {
287 .name = "db8500-sva-mmdsp",
288 .id = DB8500_REGULATOR_SWITCH_SVAMMDSP,
289 .ops = &db8500_regulator_switch_ops,
290 .type = REGULATOR_VOLTAGE,
291 .owner = THIS_MODULE,
292 },
293 .epod_id = EPOD_ID_SVAMMDSP,
294 },
295 [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
296 .desc = {
297 .name = "db8500-sva-mmdsp-ret",
298 .id = DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
299 .ops = &db8500_regulator_switch_ops,
300 .type = REGULATOR_VOLTAGE,
301 .owner = THIS_MODULE,
302 },
303 .epod_id = EPOD_ID_SVAMMDSP,
304 .is_ramret = true,
305 },
306 [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
307 .desc = {
308 .name = "db8500-sva-pipe",
309 .id = DB8500_REGULATOR_SWITCH_SVAPIPE,
310 .ops = &db8500_regulator_switch_ops,
311 .type = REGULATOR_VOLTAGE,
312 .owner = THIS_MODULE,
313 },
314 .epod_id = EPOD_ID_SVAPIPE,
315 },
316 [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
317 .desc = {
318 .name = "db8500-sia-mmdsp",
319 .id = DB8500_REGULATOR_SWITCH_SIAMMDSP,
320 .ops = &db8500_regulator_switch_ops,
321 .type = REGULATOR_VOLTAGE,
322 .owner = THIS_MODULE,
323 },
324 .epod_id = EPOD_ID_SIAMMDSP,
325 },
326 [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
327 .desc = {
328 .name = "db8500-sia-mmdsp-ret",
329 .id = DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
330 .ops = &db8500_regulator_switch_ops,
331 .type = REGULATOR_VOLTAGE,
332 .owner = THIS_MODULE,
333 },
334 .epod_id = EPOD_ID_SIAMMDSP,
335 .is_ramret = true,
336 },
337 [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
338 .desc = {
339 .name = "db8500-sia-pipe",
340 .id = DB8500_REGULATOR_SWITCH_SIAPIPE,
341 .ops = &db8500_regulator_switch_ops,
342 .type = REGULATOR_VOLTAGE,
343 .owner = THIS_MODULE,
344 },
345 .epod_id = EPOD_ID_SIAPIPE,
346 },
347 [DB8500_REGULATOR_SWITCH_SGA] = {
348 .desc = {
349 .name = "db8500-sga",
350 .id = DB8500_REGULATOR_SWITCH_SGA,
351 .ops = &db8500_regulator_switch_ops,
352 .type = REGULATOR_VOLTAGE,
353 .owner = THIS_MODULE,
354 },
355 .epod_id = EPOD_ID_SGA,
356 },
357 [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
358 .desc = {
359 .name = "db8500-b2r2-mcde",
360 .id = DB8500_REGULATOR_SWITCH_B2R2_MCDE,
361 .ops = &db8500_regulator_switch_ops,
362 .type = REGULATOR_VOLTAGE,
363 .owner = THIS_MODULE,
364 },
365 .epod_id = EPOD_ID_B2R2_MCDE,
366 },
367 [DB8500_REGULATOR_SWITCH_ESRAM12] = {
368 .desc = {
369 .name = "db8500-esram12",
370 .id = DB8500_REGULATOR_SWITCH_ESRAM12,
371 .ops = &db8500_regulator_switch_ops,
372 .type = REGULATOR_VOLTAGE,
373 .owner = THIS_MODULE,
374 },
375 .epod_id = EPOD_ID_ESRAM12,
376 .is_enabled = true,
377 },
378 [DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
379 .desc = {
380 .name = "db8500-esram12-ret",
381 .id = DB8500_REGULATOR_SWITCH_ESRAM12RET,
382 .ops = &db8500_regulator_switch_ops,
383 .type = REGULATOR_VOLTAGE,
384 .owner = THIS_MODULE,
385 },
386 .epod_id = EPOD_ID_ESRAM12,
387 .is_ramret = true,
388 },
389 [DB8500_REGULATOR_SWITCH_ESRAM34] = {
390 .desc = {
391 .name = "db8500-esram34",
392 .id = DB8500_REGULATOR_SWITCH_ESRAM34,
393 .ops = &db8500_regulator_switch_ops,
394 .type = REGULATOR_VOLTAGE,
395 .owner = THIS_MODULE,
396 },
397 .epod_id = EPOD_ID_ESRAM34,
398 .is_enabled = true,
399 },
400 [DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
401 .desc = {
402 .name = "db8500-esram34-ret",
403 .id = DB8500_REGULATOR_SWITCH_ESRAM34RET,
404 .ops = &db8500_regulator_switch_ops,
405 .type = REGULATOR_VOLTAGE,
406 .owner = THIS_MODULE,
407 },
408 .epod_id = EPOD_ID_ESRAM34,
409 .is_ramret = true,
410 },
411};
412
413static int __devinit db8500_regulator_probe(struct platform_device *pdev)
414{
Samuel Ortiz17cf8b42011-05-26 10:06:31 +0200415 struct regulator_init_data *db8500_init_data =
416 dev_get_platdata(&pdev->dev);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200417 int i, err;
418
419 /* register all regulators */
Bengt Jonsson38e96832012-01-13 16:30:31 +0100420 for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
421 struct dbx500_regulator_info *info;
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200422 struct regulator_init_data *init_data = &db8500_init_data[i];
423
424 /* assign per-regulator data */
Bengt Jonsson38e96832012-01-13 16:30:31 +0100425 info = &dbx500_regulator_info[i];
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200426 info->dev = &pdev->dev;
427
428 /* register with the regulator framework */
429 info->rdev = regulator_register(&info->desc, &pdev->dev,
Rajendra Nayak2c043bc2011-11-18 16:47:19 +0530430 init_data, info, NULL);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200431 if (IS_ERR(info->rdev)) {
432 err = PTR_ERR(info->rdev);
433 dev_err(&pdev->dev, "failed to register %s: err %i\n",
434 info->desc.name, err);
435
436 /* if failing, unregister all earlier regulators */
Axel Lin90609502011-07-06 11:41:12 +0800437 while (--i >= 0) {
Bengt Jonsson38e96832012-01-13 16:30:31 +0100438 info = &dbx500_regulator_info[i];
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200439 regulator_unregister(info->rdev);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200440 }
441 return err;
442 }
443
444 dev_dbg(rdev_get_dev(info->rdev),
445 "regulator-%s-probed\n", info->desc.name);
446 }
Bengt Jonsson38e96832012-01-13 16:30:31 +0100447 err = ux500_regulator_debug_init(pdev,
448 dbx500_regulator_info,
449 ARRAY_SIZE(dbx500_regulator_info));
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200450
Bengt Jonsson38e96832012-01-13 16:30:31 +0100451 return err;
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200452}
453
454static int __exit db8500_regulator_remove(struct platform_device *pdev)
455{
456 int i;
457
Bengt Jonsson38e96832012-01-13 16:30:31 +0100458 ux500_regulator_debug_exit();
459
460 for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
461 struct dbx500_regulator_info *info;
462 info = &dbx500_regulator_info[i];
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200463
464 dev_vdbg(rdev_get_dev(info->rdev),
465 "regulator-%s-remove\n", info->desc.name);
466
467 regulator_unregister(info->rdev);
468 }
469
470 return 0;
471}
472
473static struct platform_driver db8500_regulator_driver = {
474 .driver = {
475 .name = "db8500-prcmu-regulators",
476 .owner = THIS_MODULE,
477 },
478 .probe = db8500_regulator_probe,
479 .remove = __exit_p(db8500_regulator_remove),
480};
481
482static int __init db8500_regulator_init(void)
483{
Axel Lin90609502011-07-06 11:41:12 +0800484 return platform_driver_register(&db8500_regulator_driver);
Bengt Jonsson1032fbf2011-04-01 14:43:33 +0200485}
486
487static void __exit db8500_regulator_exit(void)
488{
489 platform_driver_unregister(&db8500_regulator_driver);
490}
491
492arch_initcall(db8500_regulator_init);
493module_exit(db8500_regulator_exit);
494
495MODULE_AUTHOR("STMicroelectronics/ST-Ericsson");
496MODULE_DESCRIPTION("DB8500 regulator driver");
497MODULE_LICENSE("GPL v2");