blob: f203a972dedf4a83a7ed66b43ed92b3aa7c873f2 [file] [log] [blame]
Mark Brownd1c6b4f2009-07-28 15:22:02 +01001/*
2 * wm831x-ldo.c -- LDO driver for the WM831x series
3 *
4 * Copyright 2009 Wolfson Microelectronics PLC.
5 *
6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
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
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/init.h>
17#include <linux/bitops.h>
18#include <linux/err.h>
19#include <linux/i2c.h>
20#include <linux/platform_device.h>
21#include <linux/regulator/driver.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090022#include <linux/slab.h>
Mark Brownd1c6b4f2009-07-28 15:22:02 +010023
24#include <linux/mfd/wm831x/core.h>
25#include <linux/mfd/wm831x/regulator.h>
26#include <linux/mfd/wm831x/pdata.h>
27
Mark Brownf1aba132012-03-28 21:40:20 +010028#define WM831X_LDO_MAX_NAME 9
Mark Brownd1c6b4f2009-07-28 15:22:02 +010029
30#define WM831X_LDO_CONTROL 0
31#define WM831X_LDO_ON_CONTROL 1
32#define WM831X_LDO_SLEEP_CONTROL 2
33
34#define WM831X_ALIVE_LDO_ON_CONTROL 0
35#define WM831X_ALIVE_LDO_SLEEP_CONTROL 1
36
37struct wm831x_ldo {
38 char name[WM831X_LDO_MAX_NAME];
Mark Brownf1aba132012-03-28 21:40:20 +010039 char supply_name[WM831X_LDO_MAX_NAME];
Mark Brownd1c6b4f2009-07-28 15:22:02 +010040 struct regulator_desc desc;
41 int base;
42 struct wm831x *wm831x;
43 struct regulator_dev *regulator;
44};
45
46/*
47 * Shared
48 */
49
Mark Brownd1c6b4f2009-07-28 15:22:02 +010050static irqreturn_t wm831x_ldo_uv_irq(int irq, void *data)
51{
52 struct wm831x_ldo *ldo = data;
53
54 regulator_notifier_call_chain(ldo->regulator,
55 REGULATOR_EVENT_UNDER_VOLTAGE,
56 NULL);
57
58 return IRQ_HANDLED;
59}
60
61/*
62 * General purpose LDOs
63 */
64
65#define WM831X_GP_LDO_SELECTOR_LOW 0xe
66#define WM831X_GP_LDO_MAX_SELECTOR 0x1f
67
68static int wm831x_gp_ldo_list_voltage(struct regulator_dev *rdev,
69 unsigned int selector)
70{
71 /* 0.9-1.6V in 50mV steps */
72 if (selector <= WM831X_GP_LDO_SELECTOR_LOW)
73 return 900000 + (selector * 50000);
Axel Lin6085d4d2012-03-29 15:04:22 +080074 /* 1.7-3.3V in 100mV steps */
Mark Brownd1c6b4f2009-07-28 15:22:02 +010075 if (selector <= WM831X_GP_LDO_MAX_SELECTOR)
76 return 1600000 + ((selector - WM831X_GP_LDO_SELECTOR_LOW)
77 * 100000);
78 return -EINVAL;
79}
80
Axel Lin0a479682012-06-12 10:46:43 +080081static int wm831x_gp_ldo_map_voltage(struct regulator_dev *rdev,
82 int min_uV, int max_uV)
Mark Brownd1c6b4f2009-07-28 15:22:02 +010083{
Axel Lin0a479682012-06-12 10:46:43 +080084 int volt, vsel;
Mark Brownd1c6b4f2009-07-28 15:22:02 +010085
86 if (min_uV < 900000)
87 vsel = 0;
88 else if (min_uV < 1700000)
89 vsel = ((min_uV - 900000) / 50000);
90 else
91 vsel = ((min_uV - 1700000) / 100000)
92 + WM831X_GP_LDO_SELECTOR_LOW + 1;
93
Axel Lin0a479682012-06-12 10:46:43 +080094 volt = wm831x_gp_ldo_list_voltage(rdev, vsel);
95 if (volt < min_uV || volt > max_uV)
Mark Brownd1c6b4f2009-07-28 15:22:02 +010096 return -EINVAL;
97
Axel Lin0a479682012-06-12 10:46:43 +080098 return vsel;
Mark Brownd1c6b4f2009-07-28 15:22:02 +010099}
100
101static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
102 int uV)
103{
104 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
Axel Lin0a479682012-06-12 10:46:43 +0800105 struct wm831x *wm831x = ldo->wm831x;
106 int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100107
Axel Lin0a479682012-06-12 10:46:43 +0800108 sel = wm831x_gp_ldo_map_voltage(rdev, uV, uV);
109 if (sel < 0)
110 return sel;
111
112 return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, sel);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100113}
114
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100115static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
116{
117 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
118 struct wm831x *wm831x = ldo->wm831x;
119 int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
120 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
Roel Kluin9a767d42009-10-16 14:16:15 +0200121 int ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100122
123 ret = wm831x_reg_read(wm831x, on_reg);
124 if (ret < 0)
Roel Kluin9a767d42009-10-16 14:16:15 +0200125 return ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100126
127 if (!(ret & WM831X_LDO1_ON_MODE))
128 return REGULATOR_MODE_NORMAL;
129
130 ret = wm831x_reg_read(wm831x, ctrl_reg);
131 if (ret < 0)
Roel Kluin9a767d42009-10-16 14:16:15 +0200132 return ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100133
134 if (ret & WM831X_LDO1_LP_MODE)
135 return REGULATOR_MODE_STANDBY;
136 else
137 return REGULATOR_MODE_IDLE;
138}
139
140static int wm831x_gp_ldo_set_mode(struct regulator_dev *rdev,
141 unsigned int mode)
142{
143 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
144 struct wm831x *wm831x = ldo->wm831x;
145 int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
146 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
147 int ret;
148
149
150 switch (mode) {
151 case REGULATOR_MODE_NORMAL:
152 ret = wm831x_set_bits(wm831x, on_reg,
153 WM831X_LDO1_ON_MODE, 0);
154 if (ret < 0)
155 return ret;
156 break;
157
158 case REGULATOR_MODE_IDLE:
159 ret = wm831x_set_bits(wm831x, ctrl_reg,
Axel Line2609992010-09-06 16:48:13 +0800160 WM831X_LDO1_LP_MODE, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100161 if (ret < 0)
162 return ret;
163
164 ret = wm831x_set_bits(wm831x, on_reg,
165 WM831X_LDO1_ON_MODE,
166 WM831X_LDO1_ON_MODE);
167 if (ret < 0)
168 return ret;
Axel Line2609992010-09-06 16:48:13 +0800169 break;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100170
171 case REGULATOR_MODE_STANDBY:
172 ret = wm831x_set_bits(wm831x, ctrl_reg,
Axel Line2609992010-09-06 16:48:13 +0800173 WM831X_LDO1_LP_MODE,
174 WM831X_LDO1_LP_MODE);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100175 if (ret < 0)
176 return ret;
177
178 ret = wm831x_set_bits(wm831x, on_reg,
179 WM831X_LDO1_ON_MODE,
180 WM831X_LDO1_ON_MODE);
181 if (ret < 0)
182 return ret;
183 break;
184
185 default:
186 return -EINVAL;
187 }
188
189 return 0;
190}
191
192static int wm831x_gp_ldo_get_status(struct regulator_dev *rdev)
193{
194 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
195 struct wm831x *wm831x = ldo->wm831x;
196 int mask = 1 << rdev_get_id(rdev);
197 int ret;
198
199 /* Is the regulator on? */
200 ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
201 if (ret < 0)
202 return ret;
203 if (!(ret & mask))
204 return REGULATOR_STATUS_OFF;
205
206 /* Is it reporting under voltage? */
207 ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
208 if (ret & mask)
209 return REGULATOR_STATUS_ERROR;
210
211 ret = wm831x_gp_ldo_get_mode(rdev);
212 if (ret < 0)
213 return ret;
214 else
215 return regulator_mode_to_status(ret);
216}
217
218static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
219 int input_uV,
220 int output_uV, int load_uA)
221{
222 if (load_uA < 20000)
223 return REGULATOR_MODE_STANDBY;
224 if (load_uA < 50000)
225 return REGULATOR_MODE_IDLE;
226 return REGULATOR_MODE_NORMAL;
227}
228
229
230static struct regulator_ops wm831x_gp_ldo_ops = {
231 .list_voltage = wm831x_gp_ldo_list_voltage,
Axel Lin0a479682012-06-12 10:46:43 +0800232 .map_voltage = wm831x_gp_ldo_map_voltage,
Mark Brownac663b42012-04-15 11:55:55 +0100233 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Axel Lin0a479682012-06-12 10:46:43 +0800234 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100235 .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
236 .get_mode = wm831x_gp_ldo_get_mode,
237 .set_mode = wm831x_gp_ldo_set_mode,
238 .get_status = wm831x_gp_ldo_get_status,
239 .get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
Mark Brown22c5fb62012-08-27 21:52:29 -0700240 .get_bypass = regulator_get_bypass_regmap,
241 .set_bypass = regulator_set_bypass_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100242
Mark Brownca8c3612012-04-15 12:38:52 +0100243 .is_enabled = regulator_is_enabled_regmap,
244 .enable = regulator_enable_regmap,
245 .disable = regulator_disable_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100246};
247
248static __devinit int wm831x_gp_ldo_probe(struct platform_device *pdev)
249{
250 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
251 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
Mark Brownc172708d2012-04-04 00:50:22 +0100252 struct regulator_config config = { };
Mark Brown137a6352011-07-25 22:20:29 +0100253 int id;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100254 struct wm831x_ldo *ldo;
255 struct resource *res;
256 int ret, irq;
257
Mark Brown137a6352011-07-25 22:20:29 +0100258 if (pdata && pdata->wm831x_num)
259 id = (pdata->wm831x_num * 10) + 1;
260 else
261 id = 0;
262 id = pdev->id - id;
263
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100264 dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
265
Mark Brownfded2f42011-12-15 02:11:14 +0800266 ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100267 if (ldo == NULL) {
268 dev_err(&pdev->dev, "Unable to allocate private data\n");
269 return -ENOMEM;
270 }
271
272 ldo->wm831x = wm831x;
273
274 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
275 if (res == NULL) {
276 dev_err(&pdev->dev, "No I/O resource\n");
277 ret = -EINVAL;
278 goto err;
279 }
280 ldo->base = res->start;
281
282 snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
283 ldo->desc.name = ldo->name;
Mark Brownf1aba132012-03-28 21:40:20 +0100284
285 snprintf(ldo->supply_name, sizeof(ldo->supply_name),
286 "LDO%dVDD", id + 1);
287 ldo->desc.supply_name = ldo->supply_name;
288
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100289 ldo->desc.id = id;
290 ldo->desc.type = REGULATOR_VOLTAGE;
291 ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1;
292 ldo->desc.ops = &wm831x_gp_ldo_ops;
293 ldo->desc.owner = THIS_MODULE;
Mark Brownac663b42012-04-15 11:55:55 +0100294 ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
295 ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
Mark Brownca8c3612012-04-15 12:38:52 +0100296 ldo->desc.enable_reg = WM831X_LDO_ENABLE;
297 ldo->desc.enable_mask = 1 << id;
Mark Brown22c5fb62012-08-27 21:52:29 -0700298 ldo->desc.bypass_reg = ldo->base;
299 ldo->desc.bypass_mask = WM831X_LDO1_SWI;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100300
Mark Brownc172708d2012-04-04 00:50:22 +0100301 config.dev = pdev->dev.parent;
Mark Brownb7ca8782012-05-10 00:41:02 +0100302 if (pdata)
303 config.init_data = pdata->ldo[id];
Mark Brownc172708d2012-04-04 00:50:22 +0100304 config.driver_data = ldo;
Mark Brownac663b42012-04-15 11:55:55 +0100305 config.regmap = wm831x->regmap;
Mark Brownc172708d2012-04-04 00:50:22 +0100306
307 ldo->regulator = regulator_register(&ldo->desc, &config);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100308 if (IS_ERR(ldo->regulator)) {
309 ret = PTR_ERR(ldo->regulator);
310 dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
311 id + 1, ret);
312 goto err;
313 }
314
Mark Browncd997582012-05-14 23:14:24 +0200315 irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
Mark Browndfda9c22011-03-01 16:50:43 +0000316 ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
317 IRQF_TRIGGER_RISING, ldo->name,
318 ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100319 if (ret != 0) {
320 dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
321 irq, ret);
322 goto err_regulator;
323 }
324
325 platform_set_drvdata(pdev, ldo);
326
327 return 0;
328
329err_regulator:
330 regulator_unregister(ldo->regulator);
331err:
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100332 return ret;
333}
334
335static __devexit int wm831x_gp_ldo_remove(struct platform_device *pdev)
336{
337 struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100338
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800339 platform_set_drvdata(pdev, NULL);
340
Mark Browncd997582012-05-14 23:14:24 +0200341 free_irq(wm831x_irq(ldo->wm831x,
342 platform_get_irq_byname(pdev, "UV")), ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100343 regulator_unregister(ldo->regulator);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100344
345 return 0;
346}
347
348static struct platform_driver wm831x_gp_ldo_driver = {
349 .probe = wm831x_gp_ldo_probe,
350 .remove = __devexit_p(wm831x_gp_ldo_remove),
351 .driver = {
352 .name = "wm831x-ldo",
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800353 .owner = THIS_MODULE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100354 },
355};
356
357/*
358 * Analogue LDOs
359 */
360
361
362#define WM831X_ALDO_SELECTOR_LOW 0xc
363#define WM831X_ALDO_MAX_SELECTOR 0x1f
364
365static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
366 unsigned int selector)
367{
368 /* 1-1.6V in 50mV steps */
369 if (selector <= WM831X_ALDO_SELECTOR_LOW)
370 return 1000000 + (selector * 50000);
Axel Lin6085d4d2012-03-29 15:04:22 +0800371 /* 1.7-3.5V in 100mV steps */
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100372 if (selector <= WM831X_ALDO_MAX_SELECTOR)
373 return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW)
374 * 100000);
375 return -EINVAL;
376}
377
Axel Lin0a479682012-06-12 10:46:43 +0800378static int wm831x_aldo_map_voltage(struct regulator_dev *rdev,
379 int min_uV, int max_uV)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100380{
Axel Lin0a479682012-06-12 10:46:43 +0800381 int volt, vsel;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100382
383 if (min_uV < 1000000)
384 vsel = 0;
385 else if (min_uV < 1700000)
386 vsel = ((min_uV - 1000000) / 50000);
387 else
388 vsel = ((min_uV - 1700000) / 100000)
389 + WM831X_ALDO_SELECTOR_LOW + 1;
390
Axel Lin0a479682012-06-12 10:46:43 +0800391 volt = wm831x_aldo_list_voltage(rdev, vsel);
392 if (volt < min_uV || volt > max_uV)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100393 return -EINVAL;
394
Axel Lin0a479682012-06-12 10:46:43 +0800395 return vsel;
Mark Brown3a93f2a2010-11-10 14:38:29 +0000396
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100397}
398
399static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
400 int uV)
401{
402 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
Axel Lin0a479682012-06-12 10:46:43 +0800403 struct wm831x *wm831x = ldo->wm831x;
404 int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100405
Axel Lin0a479682012-06-12 10:46:43 +0800406 sel = wm831x_aldo_map_voltage(rdev, uV, uV);
407 if (sel < 0)
408 return sel;
409
410 return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, sel);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100411}
412
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100413static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
414{
415 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
416 struct wm831x *wm831x = ldo->wm831x;
417 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
Roel Kluin6f17c652009-12-15 20:07:31 +0100418 int ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100419
420 ret = wm831x_reg_read(wm831x, on_reg);
421 if (ret < 0)
422 return 0;
423
424 if (ret & WM831X_LDO7_ON_MODE)
425 return REGULATOR_MODE_IDLE;
426 else
427 return REGULATOR_MODE_NORMAL;
428}
429
430static int wm831x_aldo_set_mode(struct regulator_dev *rdev,
431 unsigned int mode)
432{
433 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
434 struct wm831x *wm831x = ldo->wm831x;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100435 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
436 int ret;
437
438
439 switch (mode) {
440 case REGULATOR_MODE_NORMAL:
Axel Line841a362012-03-29 15:02:55 +0800441 ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100442 if (ret < 0)
443 return ret;
444 break;
445
446 case REGULATOR_MODE_IDLE:
Axel Line841a362012-03-29 15:02:55 +0800447 ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100448 WM831X_LDO7_ON_MODE);
449 if (ret < 0)
450 return ret;
451 break;
452
453 default:
454 return -EINVAL;
455 }
456
457 return 0;
458}
459
460static int wm831x_aldo_get_status(struct regulator_dev *rdev)
461{
462 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
463 struct wm831x *wm831x = ldo->wm831x;
464 int mask = 1 << rdev_get_id(rdev);
465 int ret;
466
467 /* Is the regulator on? */
468 ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
469 if (ret < 0)
470 return ret;
471 if (!(ret & mask))
472 return REGULATOR_STATUS_OFF;
473
474 /* Is it reporting under voltage? */
475 ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
476 if (ret & mask)
477 return REGULATOR_STATUS_ERROR;
478
479 ret = wm831x_aldo_get_mode(rdev);
480 if (ret < 0)
481 return ret;
482 else
483 return regulator_mode_to_status(ret);
484}
485
486static struct regulator_ops wm831x_aldo_ops = {
487 .list_voltage = wm831x_aldo_list_voltage,
Axel Lin0a479682012-06-12 10:46:43 +0800488 .map_voltage = wm831x_aldo_map_voltage,
Mark Brownac663b42012-04-15 11:55:55 +0100489 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Axel Lin0a479682012-06-12 10:46:43 +0800490 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100491 .set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
492 .get_mode = wm831x_aldo_get_mode,
493 .set_mode = wm831x_aldo_set_mode,
494 .get_status = wm831x_aldo_get_status,
Mark Brown22c5fb62012-08-27 21:52:29 -0700495 .set_bypass = regulator_set_bypass_regmap,
496 .get_bypass = regulator_get_bypass_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100497
Mark Brownca8c3612012-04-15 12:38:52 +0100498 .is_enabled = regulator_is_enabled_regmap,
499 .enable = regulator_enable_regmap,
500 .disable = regulator_disable_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100501};
502
503static __devinit int wm831x_aldo_probe(struct platform_device *pdev)
504{
505 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
506 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
Mark Brownc172708d2012-04-04 00:50:22 +0100507 struct regulator_config config = { };
Mark Brown137a6352011-07-25 22:20:29 +0100508 int id;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100509 struct wm831x_ldo *ldo;
510 struct resource *res;
511 int ret, irq;
512
Mark Brown137a6352011-07-25 22:20:29 +0100513 if (pdata && pdata->wm831x_num)
514 id = (pdata->wm831x_num * 10) + 1;
515 else
516 id = 0;
517 id = pdev->id - id;
518
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100519 dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
520
Mark Brownfded2f42011-12-15 02:11:14 +0800521 ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100522 if (ldo == NULL) {
523 dev_err(&pdev->dev, "Unable to allocate private data\n");
524 return -ENOMEM;
525 }
526
527 ldo->wm831x = wm831x;
528
529 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
530 if (res == NULL) {
531 dev_err(&pdev->dev, "No I/O resource\n");
532 ret = -EINVAL;
533 goto err;
534 }
535 ldo->base = res->start;
536
537 snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
538 ldo->desc.name = ldo->name;
Mark Brownf1aba132012-03-28 21:40:20 +0100539
540 snprintf(ldo->supply_name, sizeof(ldo->supply_name),
541 "LDO%dVDD", id + 1);
542 ldo->desc.supply_name = ldo->supply_name;
543
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100544 ldo->desc.id = id;
545 ldo->desc.type = REGULATOR_VOLTAGE;
546 ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1;
547 ldo->desc.ops = &wm831x_aldo_ops;
548 ldo->desc.owner = THIS_MODULE;
Mark Brownac663b42012-04-15 11:55:55 +0100549 ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
550 ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
Mark Brownca8c3612012-04-15 12:38:52 +0100551 ldo->desc.enable_reg = WM831X_LDO_ENABLE;
552 ldo->desc.enable_mask = 1 << id;
Mark Brown22c5fb62012-08-27 21:52:29 -0700553 ldo->desc.bypass_reg = ldo->base;
554 ldo->desc.bypass_mask = WM831X_LDO7_SWI;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100555
Mark Brownc172708d2012-04-04 00:50:22 +0100556 config.dev = pdev->dev.parent;
Mark Brownb7ca8782012-05-10 00:41:02 +0100557 if (pdata)
558 config.init_data = pdata->ldo[id];
Mark Brownc172708d2012-04-04 00:50:22 +0100559 config.driver_data = ldo;
Mark Brownac663b42012-04-15 11:55:55 +0100560 config.regmap = wm831x->regmap;
Mark Brownc172708d2012-04-04 00:50:22 +0100561
562 ldo->regulator = regulator_register(&ldo->desc, &config);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100563 if (IS_ERR(ldo->regulator)) {
564 ret = PTR_ERR(ldo->regulator);
565 dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
566 id + 1, ret);
567 goto err;
568 }
569
Mark Browncd997582012-05-14 23:14:24 +0200570 irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
Mark Browndfda9c22011-03-01 16:50:43 +0000571 ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
572 IRQF_TRIGGER_RISING, ldo->name, ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100573 if (ret != 0) {
574 dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
575 irq, ret);
576 goto err_regulator;
577 }
578
579 platform_set_drvdata(pdev, ldo);
580
581 return 0;
582
583err_regulator:
584 regulator_unregister(ldo->regulator);
585err:
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100586 return ret;
587}
588
589static __devexit int wm831x_aldo_remove(struct platform_device *pdev)
590{
591 struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100592
Mark Browncd997582012-05-14 23:14:24 +0200593 free_irq(wm831x_irq(ldo->wm831x, platform_get_irq_byname(pdev, "UV")),
594 ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100595 regulator_unregister(ldo->regulator);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100596
597 return 0;
598}
599
600static struct platform_driver wm831x_aldo_driver = {
601 .probe = wm831x_aldo_probe,
602 .remove = __devexit_p(wm831x_aldo_remove),
603 .driver = {
604 .name = "wm831x-aldo",
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800605 .owner = THIS_MODULE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100606 },
607};
608
609/*
610 * Alive LDO
611 */
612
613#define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
614
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100615static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
616 int uV)
617{
618 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
Axel Lin0a479682012-06-12 10:46:43 +0800619 struct wm831x *wm831x = ldo->wm831x;
620 int sel, reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100621
Axel Lin0a479682012-06-12 10:46:43 +0800622 sel = regulator_map_voltage_linear(rdev, uV, uV);
623 if (sel < 0)
624 return sel;
625
626 return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, sel);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100627}
628
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100629static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
630{
631 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
632 struct wm831x *wm831x = ldo->wm831x;
633 int mask = 1 << rdev_get_id(rdev);
634 int ret;
635
636 /* Is the regulator on? */
637 ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
638 if (ret < 0)
639 return ret;
640 if (ret & mask)
641 return REGULATOR_STATUS_ON;
642 else
643 return REGULATOR_STATUS_OFF;
644}
645
646static struct regulator_ops wm831x_alive_ldo_ops = {
Mark Brownd31e9542012-05-09 21:53:32 +0100647 .list_voltage = regulator_list_voltage_linear,
Axel Linc2543b52012-05-31 17:39:00 +0800648 .map_voltage = regulator_map_voltage_linear,
Mark Brownac663b42012-04-15 11:55:55 +0100649 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Axel Lin0a479682012-06-12 10:46:43 +0800650 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100651 .set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
652 .get_status = wm831x_alive_ldo_get_status,
653
Mark Brownca8c3612012-04-15 12:38:52 +0100654 .is_enabled = regulator_is_enabled_regmap,
655 .enable = regulator_enable_regmap,
656 .disable = regulator_disable_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100657};
658
659static __devinit int wm831x_alive_ldo_probe(struct platform_device *pdev)
660{
661 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
662 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
Mark Brownc172708d2012-04-04 00:50:22 +0100663 struct regulator_config config = { };
Mark Brown137a6352011-07-25 22:20:29 +0100664 int id;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100665 struct wm831x_ldo *ldo;
666 struct resource *res;
667 int ret;
668
Mark Brown137a6352011-07-25 22:20:29 +0100669 if (pdata && pdata->wm831x_num)
670 id = (pdata->wm831x_num * 10) + 1;
671 else
672 id = 0;
673 id = pdev->id - id;
674
675
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100676 dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
677
Mark Brownfded2f42011-12-15 02:11:14 +0800678 ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100679 if (ldo == NULL) {
680 dev_err(&pdev->dev, "Unable to allocate private data\n");
681 return -ENOMEM;
682 }
683
684 ldo->wm831x = wm831x;
685
686 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
687 if (res == NULL) {
688 dev_err(&pdev->dev, "No I/O resource\n");
689 ret = -EINVAL;
690 goto err;
691 }
692 ldo->base = res->start;
693
694 snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
695 ldo->desc.name = ldo->name;
Mark Brownf1aba132012-03-28 21:40:20 +0100696
697 snprintf(ldo->supply_name, sizeof(ldo->supply_name),
698 "LDO%dVDD", id + 1);
699 ldo->desc.supply_name = ldo->supply_name;
700
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100701 ldo->desc.id = id;
702 ldo->desc.type = REGULATOR_VOLTAGE;
703 ldo->desc.n_voltages = WM831X_ALIVE_LDO_MAX_SELECTOR + 1;
704 ldo->desc.ops = &wm831x_alive_ldo_ops;
705 ldo->desc.owner = THIS_MODULE;
Mark Brownac663b42012-04-15 11:55:55 +0100706 ldo->desc.vsel_reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
707 ldo->desc.vsel_mask = WM831X_LDO11_ON_VSEL_MASK;
Mark Brownca8c3612012-04-15 12:38:52 +0100708 ldo->desc.enable_reg = WM831X_LDO_ENABLE;
709 ldo->desc.enable_mask = 1 << id;
Mark Brownd31e9542012-05-09 21:53:32 +0100710 ldo->desc.min_uV = 800000;
711 ldo->desc.uV_step = 50000;
Mark Browneefaa3c2012-06-27 15:00:02 +0100712 ldo->desc.enable_time = 1000;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100713
Mark Brownc172708d2012-04-04 00:50:22 +0100714 config.dev = pdev->dev.parent;
Mark Brownb7ca8782012-05-10 00:41:02 +0100715 if (pdata)
716 config.init_data = pdata->ldo[id];
Mark Brownc172708d2012-04-04 00:50:22 +0100717 config.driver_data = ldo;
Mark Brownac663b42012-04-15 11:55:55 +0100718 config.regmap = wm831x->regmap;
Mark Brownc172708d2012-04-04 00:50:22 +0100719
720 ldo->regulator = regulator_register(&ldo->desc, &config);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100721 if (IS_ERR(ldo->regulator)) {
722 ret = PTR_ERR(ldo->regulator);
723 dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
724 id + 1, ret);
725 goto err;
726 }
727
728 platform_set_drvdata(pdev, ldo);
729
730 return 0;
731
732err:
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100733 return ret;
734}
735
736static __devexit int wm831x_alive_ldo_remove(struct platform_device *pdev)
737{
738 struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
739
740 regulator_unregister(ldo->regulator);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100741
742 return 0;
743}
744
745static struct platform_driver wm831x_alive_ldo_driver = {
746 .probe = wm831x_alive_ldo_probe,
747 .remove = __devexit_p(wm831x_alive_ldo_remove),
748 .driver = {
749 .name = "wm831x-alive-ldo",
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800750 .owner = THIS_MODULE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100751 },
752};
753
754static int __init wm831x_ldo_init(void)
755{
756 int ret;
757
758 ret = platform_driver_register(&wm831x_gp_ldo_driver);
759 if (ret != 0)
760 pr_err("Failed to register WM831x GP LDO driver: %d\n", ret);
761
762 ret = platform_driver_register(&wm831x_aldo_driver);
763 if (ret != 0)
764 pr_err("Failed to register WM831x ALDO driver: %d\n", ret);
765
766 ret = platform_driver_register(&wm831x_alive_ldo_driver);
767 if (ret != 0)
768 pr_err("Failed to register WM831x alive LDO driver: %d\n",
769 ret);
770
771 return 0;
772}
773subsys_initcall(wm831x_ldo_init);
774
775static void __exit wm831x_ldo_exit(void)
776{
777 platform_driver_unregister(&wm831x_alive_ldo_driver);
778 platform_driver_unregister(&wm831x_aldo_driver);
779 platform_driver_unregister(&wm831x_gp_ldo_driver);
780}
781module_exit(wm831x_ldo_exit);
782
783/* Module information */
784MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
785MODULE_DESCRIPTION("WM831x LDO driver");
786MODULE_LICENSE("GPL");
787MODULE_ALIAS("platform:wm831x-ldo");
788MODULE_ALIAS("platform:wm831x-aldo");
789MODULE_ALIAS("platform:wm831x-aliveldo");