Commit | Line | Data |
---|---|---|
0376148f | 1 | // SPDX-License-Identifier: GPL-2.0-only |
1032fbfd BJ |
2 | /* |
3 | * Copyright (C) ST-Ericsson SA 2010 | |
4 | * | |
1032fbfd BJ |
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> | |
73180f85 | 16 | #include <linux/mfd/dbx500-prcmu.h> |
1032fbfd BJ |
17 | #include <linux/regulator/driver.h> |
18 | #include <linux/regulator/machine.h> | |
19 | #include <linux/regulator/db8500-prcmu.h> | |
1bdd670a LJ |
20 | #include <linux/regulator/of_regulator.h> |
21 | #include <linux/of.h> | |
65602c32 | 22 | #include <linux/module.h> |
38e96838 | 23 | #include "dbx500-prcmu.h" |
1032fbfd BJ |
24 | |
25 | static int db8500_regulator_enable(struct regulator_dev *rdev) | |
26 | { | |
38e96838 | 27 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
1032fbfd BJ |
28 | |
29 | if (info == NULL) | |
30 | return -EINVAL; | |
31 | ||
32 | dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n", | |
33 | info->desc.name); | |
34 | ||
38e96838 BJ |
35 | if (!info->is_enabled) { |
36 | info->is_enabled = true; | |
37 | if (!info->exclude_from_power_state) | |
38 | power_state_active_enable(); | |
39 | } | |
1032fbfd BJ |
40 | |
41 | return 0; | |
42 | } | |
43 | ||
44 | static int db8500_regulator_disable(struct regulator_dev *rdev) | |
45 | { | |
38e96838 | 46 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
1032fbfd BJ |
47 | int ret = 0; |
48 | ||
49 | if (info == NULL) | |
50 | return -EINVAL; | |
51 | ||
52 | dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n", | |
53 | info->desc.name); | |
54 | ||
38e96838 BJ |
55 | if (info->is_enabled) { |
56 | info->is_enabled = false; | |
57 | if (!info->exclude_from_power_state) | |
58 | ret = power_state_active_disable(); | |
59 | } | |
1032fbfd BJ |
60 | |
61 | return ret; | |
62 | } | |
63 | ||
64 | static int db8500_regulator_is_enabled(struct regulator_dev *rdev) | |
65 | { | |
38e96838 | 66 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
1032fbfd BJ |
67 | |
68 | if (info == NULL) | |
69 | return -EINVAL; | |
70 | ||
71 | dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):" | |
72 | " %i\n", info->desc.name, info->is_enabled); | |
73 | ||
74 | return info->is_enabled; | |
75 | } | |
76 | ||
77 | /* db8500 regulator operations */ | |
1a18195a | 78 | static const struct regulator_ops db8500_regulator_ops = { |
1032fbfd BJ |
79 | .enable = db8500_regulator_enable, |
80 | .disable = db8500_regulator_disable, | |
81 | .is_enabled = db8500_regulator_is_enabled, | |
82 | }; | |
83 | ||
84 | /* | |
85 | * EPOD control | |
86 | */ | |
87 | static bool epod_on[NUM_EPOD_ID]; | |
88 | static bool epod_ramret[NUM_EPOD_ID]; | |
89 | ||
90 | static int enable_epod(u16 epod_id, bool ramret) | |
91 | { | |
92 | int ret; | |
93 | ||
94 | if (ramret) { | |
95 | if (!epod_on[epod_id]) { | |
96 | ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); | |
97 | if (ret < 0) | |
98 | return ret; | |
99 | } | |
100 | epod_ramret[epod_id] = true; | |
101 | } else { | |
102 | ret = prcmu_set_epod(epod_id, EPOD_STATE_ON); | |
103 | if (ret < 0) | |
104 | return ret; | |
105 | epod_on[epod_id] = true; | |
106 | } | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
111 | static int disable_epod(u16 epod_id, bool ramret) | |
112 | { | |
113 | int ret; | |
114 | ||
115 | if (ramret) { | |
116 | if (!epod_on[epod_id]) { | |
117 | ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF); | |
118 | if (ret < 0) | |
119 | return ret; | |
120 | } | |
121 | epod_ramret[epod_id] = false; | |
122 | } else { | |
123 | if (epod_ramret[epod_id]) { | |
124 | ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET); | |
125 | if (ret < 0) | |
126 | return ret; | |
127 | } else { | |
128 | ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF); | |
129 | if (ret < 0) | |
130 | return ret; | |
131 | } | |
132 | epod_on[epod_id] = false; | |
133 | } | |
134 | ||
135 | return 0; | |
136 | } | |
137 | ||
138 | /* | |
139 | * Regulator switch | |
140 | */ | |
141 | static int db8500_regulator_switch_enable(struct regulator_dev *rdev) | |
142 | { | |
38e96838 | 143 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
1032fbfd BJ |
144 | int ret; |
145 | ||
146 | if (info == NULL) | |
147 | return -EINVAL; | |
148 | ||
149 | dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n", | |
150 | info->desc.name); | |
151 | ||
152 | ret = enable_epod(info->epod_id, info->is_ramret); | |
153 | if (ret < 0) { | |
154 | dev_err(rdev_get_dev(rdev), | |
155 | "regulator-switch-%s-enable: prcmu call failed\n", | |
156 | info->desc.name); | |
157 | goto out; | |
158 | } | |
159 | ||
160 | info->is_enabled = true; | |
161 | out: | |
162 | return ret; | |
163 | } | |
164 | ||
165 | static int db8500_regulator_switch_disable(struct regulator_dev *rdev) | |
166 | { | |
38e96838 | 167 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
1032fbfd BJ |
168 | int ret; |
169 | ||
170 | if (info == NULL) | |
171 | return -EINVAL; | |
172 | ||
173 | dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n", | |
174 | info->desc.name); | |
175 | ||
176 | ret = disable_epod(info->epod_id, info->is_ramret); | |
177 | if (ret < 0) { | |
178 | dev_err(rdev_get_dev(rdev), | |
179 | "regulator_switch-%s-disable: prcmu call failed\n", | |
180 | info->desc.name); | |
181 | goto out; | |
182 | } | |
183 | ||
aab5fd7a | 184 | info->is_enabled = false; |
1032fbfd BJ |
185 | out: |
186 | return ret; | |
187 | } | |
188 | ||
189 | static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev) | |
190 | { | |
38e96838 | 191 | struct dbx500_regulator_info *info = rdev_get_drvdata(rdev); |
1032fbfd BJ |
192 | |
193 | if (info == NULL) | |
194 | return -EINVAL; | |
195 | ||
196 | dev_vdbg(rdev_get_dev(rdev), | |
197 | "regulator-switch-%s-is_enabled (is_enabled): %i\n", | |
198 | info->desc.name, info->is_enabled); | |
199 | ||
200 | return info->is_enabled; | |
201 | } | |
202 | ||
1a18195a | 203 | static const struct regulator_ops db8500_regulator_switch_ops = { |
1032fbfd BJ |
204 | .enable = db8500_regulator_switch_enable, |
205 | .disable = db8500_regulator_switch_disable, | |
206 | .is_enabled = db8500_regulator_switch_is_enabled, | |
207 | }; | |
208 | ||
209 | /* | |
210 | * Regulator information | |
211 | */ | |
38e96838 BJ |
212 | static struct dbx500_regulator_info |
213 | dbx500_regulator_info[DB8500_NUM_REGULATORS] = { | |
1032fbfd BJ |
214 | [DB8500_REGULATOR_VAPE] = { |
215 | .desc = { | |
216 | .name = "db8500-vape", | |
92722a8f | 217 | .of_match = of_match_ptr("db8500_vape"), |
1032fbfd BJ |
218 | .id = DB8500_REGULATOR_VAPE, |
219 | .ops = &db8500_regulator_ops, | |
220 | .type = REGULATOR_VOLTAGE, | |
221 | .owner = THIS_MODULE, | |
222 | }, | |
223 | }, | |
224 | [DB8500_REGULATOR_VARM] = { | |
225 | .desc = { | |
226 | .name = "db8500-varm", | |
92722a8f | 227 | .of_match = of_match_ptr("db8500_varm"), |
1032fbfd BJ |
228 | .id = DB8500_REGULATOR_VARM, |
229 | .ops = &db8500_regulator_ops, | |
230 | .type = REGULATOR_VOLTAGE, | |
231 | .owner = THIS_MODULE, | |
232 | }, | |
233 | }, | |
234 | [DB8500_REGULATOR_VMODEM] = { | |
235 | .desc = { | |
236 | .name = "db8500-vmodem", | |
92722a8f | 237 | .of_match = of_match_ptr("db8500_vmodem"), |
1032fbfd BJ |
238 | .id = DB8500_REGULATOR_VMODEM, |
239 | .ops = &db8500_regulator_ops, | |
240 | .type = REGULATOR_VOLTAGE, | |
241 | .owner = THIS_MODULE, | |
242 | }, | |
243 | }, | |
244 | [DB8500_REGULATOR_VPLL] = { | |
245 | .desc = { | |
246 | .name = "db8500-vpll", | |
92722a8f | 247 | .of_match = of_match_ptr("db8500_vpll"), |
1032fbfd BJ |
248 | .id = DB8500_REGULATOR_VPLL, |
249 | .ops = &db8500_regulator_ops, | |
250 | .type = REGULATOR_VOLTAGE, | |
251 | .owner = THIS_MODULE, | |
252 | }, | |
253 | }, | |
254 | [DB8500_REGULATOR_VSMPS1] = { | |
255 | .desc = { | |
256 | .name = "db8500-vsmps1", | |
92722a8f | 257 | .of_match = of_match_ptr("db8500_vsmps1"), |
1032fbfd BJ |
258 | .id = DB8500_REGULATOR_VSMPS1, |
259 | .ops = &db8500_regulator_ops, | |
260 | .type = REGULATOR_VOLTAGE, | |
261 | .owner = THIS_MODULE, | |
262 | }, | |
263 | }, | |
264 | [DB8500_REGULATOR_VSMPS2] = { | |
265 | .desc = { | |
266 | .name = "db8500-vsmps2", | |
92722a8f | 267 | .of_match = of_match_ptr("db8500_vsmps2"), |
1032fbfd BJ |
268 | .id = DB8500_REGULATOR_VSMPS2, |
269 | .ops = &db8500_regulator_ops, | |
270 | .type = REGULATOR_VOLTAGE, | |
271 | .owner = THIS_MODULE, | |
eced9d5e UH |
272 | .fixed_uV = 1800000, |
273 | .n_voltages = 1, | |
1032fbfd BJ |
274 | }, |
275 | .exclude_from_power_state = true, | |
276 | }, | |
277 | [DB8500_REGULATOR_VSMPS3] = { | |
278 | .desc = { | |
279 | .name = "db8500-vsmps3", | |
92722a8f | 280 | .of_match = of_match_ptr("db8500_vsmps3"), |
1032fbfd BJ |
281 | .id = DB8500_REGULATOR_VSMPS3, |
282 | .ops = &db8500_regulator_ops, | |
283 | .type = REGULATOR_VOLTAGE, | |
284 | .owner = THIS_MODULE, | |
285 | }, | |
286 | }, | |
287 | [DB8500_REGULATOR_VRF1] = { | |
288 | .desc = { | |
289 | .name = "db8500-vrf1", | |
92722a8f | 290 | .of_match = of_match_ptr("db8500_vrf1"), |
1032fbfd BJ |
291 | .id = DB8500_REGULATOR_VRF1, |
292 | .ops = &db8500_regulator_ops, | |
293 | .type = REGULATOR_VOLTAGE, | |
294 | .owner = THIS_MODULE, | |
295 | }, | |
296 | }, | |
297 | [DB8500_REGULATOR_SWITCH_SVAMMDSP] = { | |
298 | .desc = { | |
299 | .name = "db8500-sva-mmdsp", | |
92722a8f | 300 | .of_match = of_match_ptr("db8500_sva_mmdsp"), |
1032fbfd BJ |
301 | .id = DB8500_REGULATOR_SWITCH_SVAMMDSP, |
302 | .ops = &db8500_regulator_switch_ops, | |
303 | .type = REGULATOR_VOLTAGE, | |
304 | .owner = THIS_MODULE, | |
305 | }, | |
306 | .epod_id = EPOD_ID_SVAMMDSP, | |
307 | }, | |
308 | [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = { | |
309 | .desc = { | |
310 | .name = "db8500-sva-mmdsp-ret", | |
92722a8f | 311 | .of_match = of_match_ptr("db8500_sva_mmdsp_ret"), |
1032fbfd BJ |
312 | .id = DB8500_REGULATOR_SWITCH_SVAMMDSPRET, |
313 | .ops = &db8500_regulator_switch_ops, | |
314 | .type = REGULATOR_VOLTAGE, | |
315 | .owner = THIS_MODULE, | |
316 | }, | |
317 | .epod_id = EPOD_ID_SVAMMDSP, | |
318 | .is_ramret = true, | |
319 | }, | |
320 | [DB8500_REGULATOR_SWITCH_SVAPIPE] = { | |
321 | .desc = { | |
322 | .name = "db8500-sva-pipe", | |
92722a8f | 323 | .of_match = of_match_ptr("db8500_sva_pipe"), |
1032fbfd BJ |
324 | .id = DB8500_REGULATOR_SWITCH_SVAPIPE, |
325 | .ops = &db8500_regulator_switch_ops, | |
326 | .type = REGULATOR_VOLTAGE, | |
327 | .owner = THIS_MODULE, | |
328 | }, | |
329 | .epod_id = EPOD_ID_SVAPIPE, | |
330 | }, | |
331 | [DB8500_REGULATOR_SWITCH_SIAMMDSP] = { | |
332 | .desc = { | |
333 | .name = "db8500-sia-mmdsp", | |
92722a8f | 334 | .of_match = of_match_ptr("db8500_sia_mmdsp"), |
1032fbfd BJ |
335 | .id = DB8500_REGULATOR_SWITCH_SIAMMDSP, |
336 | .ops = &db8500_regulator_switch_ops, | |
337 | .type = REGULATOR_VOLTAGE, | |
338 | .owner = THIS_MODULE, | |
339 | }, | |
340 | .epod_id = EPOD_ID_SIAMMDSP, | |
341 | }, | |
342 | [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = { | |
343 | .desc = { | |
344 | .name = "db8500-sia-mmdsp-ret", | |
92722a8f | 345 | .of_match = of_match_ptr("db8500_sia_mmdsp_ret"), |
1032fbfd BJ |
346 | .id = DB8500_REGULATOR_SWITCH_SIAMMDSPRET, |
347 | .ops = &db8500_regulator_switch_ops, | |
348 | .type = REGULATOR_VOLTAGE, | |
349 | .owner = THIS_MODULE, | |
350 | }, | |
351 | .epod_id = EPOD_ID_SIAMMDSP, | |
352 | .is_ramret = true, | |
353 | }, | |
354 | [DB8500_REGULATOR_SWITCH_SIAPIPE] = { | |
355 | .desc = { | |
356 | .name = "db8500-sia-pipe", | |
92722a8f | 357 | .of_match = of_match_ptr("db8500_sia_pipe"), |
1032fbfd BJ |
358 | .id = DB8500_REGULATOR_SWITCH_SIAPIPE, |
359 | .ops = &db8500_regulator_switch_ops, | |
360 | .type = REGULATOR_VOLTAGE, | |
361 | .owner = THIS_MODULE, | |
362 | }, | |
363 | .epod_id = EPOD_ID_SIAPIPE, | |
364 | }, | |
365 | [DB8500_REGULATOR_SWITCH_SGA] = { | |
366 | .desc = { | |
367 | .name = "db8500-sga", | |
92722a8f | 368 | .of_match = of_match_ptr("db8500_sga"), |
1032fbfd BJ |
369 | .id = DB8500_REGULATOR_SWITCH_SGA, |
370 | .ops = &db8500_regulator_switch_ops, | |
371 | .type = REGULATOR_VOLTAGE, | |
372 | .owner = THIS_MODULE, | |
373 | }, | |
374 | .epod_id = EPOD_ID_SGA, | |
375 | }, | |
376 | [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = { | |
377 | .desc = { | |
378 | .name = "db8500-b2r2-mcde", | |
92722a8f | 379 | .of_match = of_match_ptr("db8500_b2r2_mcde"), |
1032fbfd BJ |
380 | .id = DB8500_REGULATOR_SWITCH_B2R2_MCDE, |
381 | .ops = &db8500_regulator_switch_ops, | |
382 | .type = REGULATOR_VOLTAGE, | |
383 | .owner = THIS_MODULE, | |
384 | }, | |
385 | .epod_id = EPOD_ID_B2R2_MCDE, | |
386 | }, | |
387 | [DB8500_REGULATOR_SWITCH_ESRAM12] = { | |
388 | .desc = { | |
389 | .name = "db8500-esram12", | |
92722a8f | 390 | .of_match = of_match_ptr("db8500_esram12"), |
1032fbfd BJ |
391 | .id = DB8500_REGULATOR_SWITCH_ESRAM12, |
392 | .ops = &db8500_regulator_switch_ops, | |
393 | .type = REGULATOR_VOLTAGE, | |
394 | .owner = THIS_MODULE, | |
395 | }, | |
396 | .epod_id = EPOD_ID_ESRAM12, | |
397 | .is_enabled = true, | |
398 | }, | |
399 | [DB8500_REGULATOR_SWITCH_ESRAM12RET] = { | |
400 | .desc = { | |
401 | .name = "db8500-esram12-ret", | |
92722a8f | 402 | .of_match = of_match_ptr("db8500_esram12_ret"), |
1032fbfd BJ |
403 | .id = DB8500_REGULATOR_SWITCH_ESRAM12RET, |
404 | .ops = &db8500_regulator_switch_ops, | |
405 | .type = REGULATOR_VOLTAGE, | |
406 | .owner = THIS_MODULE, | |
407 | }, | |
408 | .epod_id = EPOD_ID_ESRAM12, | |
409 | .is_ramret = true, | |
410 | }, | |
411 | [DB8500_REGULATOR_SWITCH_ESRAM34] = { | |
412 | .desc = { | |
413 | .name = "db8500-esram34", | |
92722a8f | 414 | .of_match = of_match_ptr("db8500_esram34"), |
1032fbfd BJ |
415 | .id = DB8500_REGULATOR_SWITCH_ESRAM34, |
416 | .ops = &db8500_regulator_switch_ops, | |
417 | .type = REGULATOR_VOLTAGE, | |
418 | .owner = THIS_MODULE, | |
419 | }, | |
420 | .epod_id = EPOD_ID_ESRAM34, | |
421 | .is_enabled = true, | |
422 | }, | |
423 | [DB8500_REGULATOR_SWITCH_ESRAM34RET] = { | |
424 | .desc = { | |
425 | .name = "db8500-esram34-ret", | |
92722a8f | 426 | .of_match = of_match_ptr("db8500_esram34_ret"), |
1032fbfd BJ |
427 | .id = DB8500_REGULATOR_SWITCH_ESRAM34RET, |
428 | .ops = &db8500_regulator_switch_ops, | |
429 | .type = REGULATOR_VOLTAGE, | |
430 | .owner = THIS_MODULE, | |
431 | }, | |
432 | .epod_id = EPOD_ID_ESRAM34, | |
433 | .is_ramret = true, | |
434 | }, | |
435 | }; | |
436 | ||
92722a8f | 437 | static int db8500_regulator_probe(struct platform_device *pdev) |
8986cf88 | 438 | { |
92722a8f | 439 | struct regulator_init_data *db8500_init_data; |
8986cf88 LJ |
440 | struct dbx500_regulator_info *info; |
441 | struct regulator_config config = { }; | |
2564002a | 442 | struct regulator_dev *rdev; |
92722a8f | 443 | int err, i; |
8986cf88 | 444 | |
92722a8f | 445 | db8500_init_data = dev_get_platdata(&pdev->dev); |
1bdd670a LJ |
446 | |
447 | for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) { | |
92722a8f AL |
448 | /* assign per-regulator data */ |
449 | info = &dbx500_regulator_info[i]; | |
92722a8f AL |
450 | |
451 | config.driver_data = info; | |
452 | config.dev = &pdev->dev; | |
453 | if (db8500_init_data) | |
454 | config.init_data = &db8500_init_data[i]; | |
455 | ||
2564002a AL |
456 | rdev = devm_regulator_register(&pdev->dev, &info->desc, |
457 | &config); | |
458 | if (IS_ERR(rdev)) { | |
459 | err = PTR_ERR(rdev); | |
92722a8f AL |
460 | dev_err(&pdev->dev, "failed to register %s: err %i\n", |
461 | info->desc.name, err); | |
1bdd670a | 462 | return err; |
1bdd670a | 463 | } |
92722a8f | 464 | dev_dbg(&pdev->dev, "regulator-%s-probed\n", info->desc.name); |
1032fbfd | 465 | } |
1bdd670a | 466 | |
92722a8f AL |
467 | ux500_regulator_debug_init(pdev, dbx500_regulator_info, |
468 | ARRAY_SIZE(dbx500_regulator_info)); | |
8986cf88 | 469 | return 0; |
1032fbfd BJ |
470 | } |
471 | ||
4ceb73ae | 472 | static int db8500_regulator_remove(struct platform_device *pdev) |
1032fbfd | 473 | { |
38e96838 BJ |
474 | ux500_regulator_debug_exit(); |
475 | ||
1032fbfd BJ |
476 | return 0; |
477 | } | |
478 | ||
479 | static struct platform_driver db8500_regulator_driver = { | |
480 | .driver = { | |
481 | .name = "db8500-prcmu-regulators", | |
259b93b2 | 482 | .probe_type = PROBE_PREFER_ASYNCHRONOUS, |
1032fbfd BJ |
483 | }, |
484 | .probe = db8500_regulator_probe, | |
4ceb73ae | 485 | .remove = db8500_regulator_remove, |
1032fbfd BJ |
486 | }; |
487 | ||
488 | static int __init db8500_regulator_init(void) | |
489 | { | |
90609503 | 490 | return platform_driver_register(&db8500_regulator_driver); |
1032fbfd BJ |
491 | } |
492 | ||
493 | static void __exit db8500_regulator_exit(void) | |
494 | { | |
495 | platform_driver_unregister(&db8500_regulator_driver); | |
496 | } | |
497 | ||
498 | arch_initcall(db8500_regulator_init); | |
499 | module_exit(db8500_regulator_exit); | |
500 | ||
501 | MODULE_AUTHOR("STMicroelectronics/ST-Ericsson"); | |
502 | MODULE_DESCRIPTION("DB8500 regulator driver"); | |
503 | MODULE_LICENSE("GPL v2"); |