blob: 1ec379a9a95c88807c9987b23568e892b14bdc1a [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);
Axel Lin363506c2012-07-31 21:28:26 +0800208 if (ret < 0)
209 return ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100210 if (ret & mask)
211 return REGULATOR_STATUS_ERROR;
212
213 ret = wm831x_gp_ldo_get_mode(rdev);
214 if (ret < 0)
215 return ret;
216 else
217 return regulator_mode_to_status(ret);
218}
219
220static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
221 int input_uV,
222 int output_uV, int load_uA)
223{
224 if (load_uA < 20000)
225 return REGULATOR_MODE_STANDBY;
226 if (load_uA < 50000)
227 return REGULATOR_MODE_IDLE;
228 return REGULATOR_MODE_NORMAL;
229}
230
231
232static struct regulator_ops wm831x_gp_ldo_ops = {
233 .list_voltage = wm831x_gp_ldo_list_voltage,
Axel Lin0a479682012-06-12 10:46:43 +0800234 .map_voltage = wm831x_gp_ldo_map_voltage,
Mark Brownac663b42012-04-15 11:55:55 +0100235 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Axel Lin0a479682012-06-12 10:46:43 +0800236 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100237 .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
238 .get_mode = wm831x_gp_ldo_get_mode,
239 .set_mode = wm831x_gp_ldo_set_mode,
240 .get_status = wm831x_gp_ldo_get_status,
241 .get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
Mark Brown22c5fb62012-08-27 21:52:29 -0700242 .get_bypass = regulator_get_bypass_regmap,
243 .set_bypass = regulator_set_bypass_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100244
Mark Brownca8c3612012-04-15 12:38:52 +0100245 .is_enabled = regulator_is_enabled_regmap,
246 .enable = regulator_enable_regmap,
247 .disable = regulator_disable_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100248};
249
Bill Pembertona5023572012-11-19 13:22:22 -0500250static int wm831x_gp_ldo_probe(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100251{
252 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
253 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
Mark Brownc1727082012-04-04 00:50:22 +0100254 struct regulator_config config = { };
Mark Brown137a6352011-07-25 22:20:29 +0100255 int id;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100256 struct wm831x_ldo *ldo;
257 struct resource *res;
258 int ret, irq;
259
Mark Brown137a6352011-07-25 22:20:29 +0100260 if (pdata && pdata->wm831x_num)
261 id = (pdata->wm831x_num * 10) + 1;
262 else
263 id = 0;
264 id = pdev->id - id;
265
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100266 dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
267
Mark Brownfded2f42011-12-15 02:11:14 +0800268 ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100269 if (ldo == NULL) {
270 dev_err(&pdev->dev, "Unable to allocate private data\n");
271 return -ENOMEM;
272 }
273
274 ldo->wm831x = wm831x;
275
Mark Brown56560982012-08-07 19:42:47 +0100276 res = platform_get_resource(pdev, IORESOURCE_REG, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100277 if (res == NULL) {
Mark Brown56560982012-08-07 19:42:47 +0100278 dev_err(&pdev->dev, "No REG resource\n");
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100279 ret = -EINVAL;
280 goto err;
281 }
282 ldo->base = res->start;
283
284 snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
285 ldo->desc.name = ldo->name;
Mark Brownf1aba132012-03-28 21:40:20 +0100286
287 snprintf(ldo->supply_name, sizeof(ldo->supply_name),
288 "LDO%dVDD", id + 1);
289 ldo->desc.supply_name = ldo->supply_name;
290
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100291 ldo->desc.id = id;
292 ldo->desc.type = REGULATOR_VOLTAGE;
293 ldo->desc.n_voltages = WM831X_GP_LDO_MAX_SELECTOR + 1;
294 ldo->desc.ops = &wm831x_gp_ldo_ops;
295 ldo->desc.owner = THIS_MODULE;
Mark Brownac663b42012-04-15 11:55:55 +0100296 ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
297 ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
Mark Brownca8c3612012-04-15 12:38:52 +0100298 ldo->desc.enable_reg = WM831X_LDO_ENABLE;
299 ldo->desc.enable_mask = 1 << id;
Mark Brown22c5fb62012-08-27 21:52:29 -0700300 ldo->desc.bypass_reg = ldo->base;
301 ldo->desc.bypass_mask = WM831X_LDO1_SWI;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100302
Mark Brownc1727082012-04-04 00:50:22 +0100303 config.dev = pdev->dev.parent;
Mark Brownb7ca8782012-05-10 00:41:02 +0100304 if (pdata)
305 config.init_data = pdata->ldo[id];
Mark Brownc1727082012-04-04 00:50:22 +0100306 config.driver_data = ldo;
Mark Brownac663b42012-04-15 11:55:55 +0100307 config.regmap = wm831x->regmap;
Mark Brownc1727082012-04-04 00:50:22 +0100308
309 ldo->regulator = regulator_register(&ldo->desc, &config);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100310 if (IS_ERR(ldo->regulator)) {
311 ret = PTR_ERR(ldo->regulator);
312 dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
313 id + 1, ret);
314 goto err;
315 }
316
Mark Browncd997582012-05-14 23:14:24 +0200317 irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
Mark Browndfda9c22011-03-01 16:50:43 +0000318 ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
319 IRQF_TRIGGER_RISING, ldo->name,
320 ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100321 if (ret != 0) {
322 dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
323 irq, ret);
324 goto err_regulator;
325 }
326
327 platform_set_drvdata(pdev, ldo);
328
329 return 0;
330
331err_regulator:
332 regulator_unregister(ldo->regulator);
333err:
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100334 return ret;
335}
336
Bill Pemberton8dc995f2012-11-19 13:26:10 -0500337static int wm831x_gp_ldo_remove(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100338{
339 struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100340
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800341 platform_set_drvdata(pdev, NULL);
342
Mark Browncd997582012-05-14 23:14:24 +0200343 free_irq(wm831x_irq(ldo->wm831x,
344 platform_get_irq_byname(pdev, "UV")), ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100345 regulator_unregister(ldo->regulator);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100346
347 return 0;
348}
349
350static struct platform_driver wm831x_gp_ldo_driver = {
351 .probe = wm831x_gp_ldo_probe,
Bill Pemberton5eb9f2b2012-11-19 13:20:42 -0500352 .remove = wm831x_gp_ldo_remove,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100353 .driver = {
354 .name = "wm831x-ldo",
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800355 .owner = THIS_MODULE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100356 },
357};
358
359/*
360 * Analogue LDOs
361 */
362
363
364#define WM831X_ALDO_SELECTOR_LOW 0xc
365#define WM831X_ALDO_MAX_SELECTOR 0x1f
366
367static int wm831x_aldo_list_voltage(struct regulator_dev *rdev,
368 unsigned int selector)
369{
370 /* 1-1.6V in 50mV steps */
371 if (selector <= WM831X_ALDO_SELECTOR_LOW)
372 return 1000000 + (selector * 50000);
Axel Lin6085d4d2012-03-29 15:04:22 +0800373 /* 1.7-3.5V in 100mV steps */
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100374 if (selector <= WM831X_ALDO_MAX_SELECTOR)
375 return 1600000 + ((selector - WM831X_ALDO_SELECTOR_LOW)
376 * 100000);
377 return -EINVAL;
378}
379
Axel Lin0a479682012-06-12 10:46:43 +0800380static int wm831x_aldo_map_voltage(struct regulator_dev *rdev,
381 int min_uV, int max_uV)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100382{
Axel Lin0a479682012-06-12 10:46:43 +0800383 int volt, vsel;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100384
385 if (min_uV < 1000000)
386 vsel = 0;
387 else if (min_uV < 1700000)
388 vsel = ((min_uV - 1000000) / 50000);
389 else
390 vsel = ((min_uV - 1700000) / 100000)
391 + WM831X_ALDO_SELECTOR_LOW + 1;
392
Axel Lin0a479682012-06-12 10:46:43 +0800393 volt = wm831x_aldo_list_voltage(rdev, vsel);
394 if (volt < min_uV || volt > max_uV)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100395 return -EINVAL;
396
Axel Lin0a479682012-06-12 10:46:43 +0800397 return vsel;
Mark Brown3a93f2a2010-11-10 14:38:29 +0000398
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100399}
400
401static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
402 int uV)
403{
404 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
Axel Lin0a479682012-06-12 10:46:43 +0800405 struct wm831x *wm831x = ldo->wm831x;
406 int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100407
Axel Lin0a479682012-06-12 10:46:43 +0800408 sel = wm831x_aldo_map_voltage(rdev, uV, uV);
409 if (sel < 0)
410 return sel;
411
412 return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, sel);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100413}
414
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100415static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
416{
417 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
418 struct wm831x *wm831x = ldo->wm831x;
419 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
Roel Kluin6f17c652009-12-15 20:07:31 +0100420 int ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100421
422 ret = wm831x_reg_read(wm831x, on_reg);
423 if (ret < 0)
424 return 0;
425
426 if (ret & WM831X_LDO7_ON_MODE)
427 return REGULATOR_MODE_IDLE;
428 else
429 return REGULATOR_MODE_NORMAL;
430}
431
432static int wm831x_aldo_set_mode(struct regulator_dev *rdev,
433 unsigned int mode)
434{
435 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
436 struct wm831x *wm831x = ldo->wm831x;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100437 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
438 int ret;
439
440
441 switch (mode) {
442 case REGULATOR_MODE_NORMAL:
Axel Line841a362012-03-29 15:02:55 +0800443 ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100444 if (ret < 0)
445 return ret;
446 break;
447
448 case REGULATOR_MODE_IDLE:
Axel Line841a362012-03-29 15:02:55 +0800449 ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100450 WM831X_LDO7_ON_MODE);
451 if (ret < 0)
452 return ret;
453 break;
454
455 default:
456 return -EINVAL;
457 }
458
459 return 0;
460}
461
462static int wm831x_aldo_get_status(struct regulator_dev *rdev)
463{
464 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
465 struct wm831x *wm831x = ldo->wm831x;
466 int mask = 1 << rdev_get_id(rdev);
467 int ret;
468
469 /* Is the regulator on? */
470 ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
471 if (ret < 0)
472 return ret;
473 if (!(ret & mask))
474 return REGULATOR_STATUS_OFF;
475
476 /* Is it reporting under voltage? */
477 ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
Axel Lin363506c2012-07-31 21:28:26 +0800478 if (ret < 0)
479 return ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100480 if (ret & mask)
481 return REGULATOR_STATUS_ERROR;
482
483 ret = wm831x_aldo_get_mode(rdev);
484 if (ret < 0)
485 return ret;
486 else
487 return regulator_mode_to_status(ret);
488}
489
490static struct regulator_ops wm831x_aldo_ops = {
491 .list_voltage = wm831x_aldo_list_voltage,
Axel Lin0a479682012-06-12 10:46:43 +0800492 .map_voltage = wm831x_aldo_map_voltage,
Mark Brownac663b42012-04-15 11:55:55 +0100493 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Axel Lin0a479682012-06-12 10:46:43 +0800494 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100495 .set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
496 .get_mode = wm831x_aldo_get_mode,
497 .set_mode = wm831x_aldo_set_mode,
498 .get_status = wm831x_aldo_get_status,
Mark Brown22c5fb62012-08-27 21:52:29 -0700499 .set_bypass = regulator_set_bypass_regmap,
500 .get_bypass = regulator_get_bypass_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100501
Mark Brownca8c3612012-04-15 12:38:52 +0100502 .is_enabled = regulator_is_enabled_regmap,
503 .enable = regulator_enable_regmap,
504 .disable = regulator_disable_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100505};
506
Bill Pembertona5023572012-11-19 13:22:22 -0500507static int wm831x_aldo_probe(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100508{
509 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
510 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
Mark Brownc1727082012-04-04 00:50:22 +0100511 struct regulator_config config = { };
Mark Brown137a6352011-07-25 22:20:29 +0100512 int id;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100513 struct wm831x_ldo *ldo;
514 struct resource *res;
515 int ret, irq;
516
Mark Brown137a6352011-07-25 22:20:29 +0100517 if (pdata && pdata->wm831x_num)
518 id = (pdata->wm831x_num * 10) + 1;
519 else
520 id = 0;
521 id = pdev->id - id;
522
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100523 dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
524
Mark Brownfded2f42011-12-15 02:11:14 +0800525 ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100526 if (ldo == NULL) {
527 dev_err(&pdev->dev, "Unable to allocate private data\n");
528 return -ENOMEM;
529 }
530
531 ldo->wm831x = wm831x;
532
Mark Brown56560982012-08-07 19:42:47 +0100533 res = platform_get_resource(pdev, IORESOURCE_REG, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100534 if (res == NULL) {
Mark Brown56560982012-08-07 19:42:47 +0100535 dev_err(&pdev->dev, "No REG resource\n");
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100536 ret = -EINVAL;
537 goto err;
538 }
539 ldo->base = res->start;
540
541 snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
542 ldo->desc.name = ldo->name;
Mark Brownf1aba132012-03-28 21:40:20 +0100543
544 snprintf(ldo->supply_name, sizeof(ldo->supply_name),
545 "LDO%dVDD", id + 1);
546 ldo->desc.supply_name = ldo->supply_name;
547
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100548 ldo->desc.id = id;
549 ldo->desc.type = REGULATOR_VOLTAGE;
550 ldo->desc.n_voltages = WM831X_ALDO_MAX_SELECTOR + 1;
551 ldo->desc.ops = &wm831x_aldo_ops;
552 ldo->desc.owner = THIS_MODULE;
Mark Brownac663b42012-04-15 11:55:55 +0100553 ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
554 ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
Mark Brownca8c3612012-04-15 12:38:52 +0100555 ldo->desc.enable_reg = WM831X_LDO_ENABLE;
556 ldo->desc.enable_mask = 1 << id;
Mark Brown22c5fb62012-08-27 21:52:29 -0700557 ldo->desc.bypass_reg = ldo->base;
558 ldo->desc.bypass_mask = WM831X_LDO7_SWI;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100559
Mark Brownc1727082012-04-04 00:50:22 +0100560 config.dev = pdev->dev.parent;
Mark Brownb7ca8782012-05-10 00:41:02 +0100561 if (pdata)
562 config.init_data = pdata->ldo[id];
Mark Brownc1727082012-04-04 00:50:22 +0100563 config.driver_data = ldo;
Mark Brownac663b42012-04-15 11:55:55 +0100564 config.regmap = wm831x->regmap;
Mark Brownc1727082012-04-04 00:50:22 +0100565
566 ldo->regulator = regulator_register(&ldo->desc, &config);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100567 if (IS_ERR(ldo->regulator)) {
568 ret = PTR_ERR(ldo->regulator);
569 dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
570 id + 1, ret);
571 goto err;
572 }
573
Mark Browncd997582012-05-14 23:14:24 +0200574 irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
Mark Browndfda9c22011-03-01 16:50:43 +0000575 ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
576 IRQF_TRIGGER_RISING, ldo->name, ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100577 if (ret != 0) {
578 dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
579 irq, ret);
580 goto err_regulator;
581 }
582
583 platform_set_drvdata(pdev, ldo);
584
585 return 0;
586
587err_regulator:
588 regulator_unregister(ldo->regulator);
589err:
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100590 return ret;
591}
592
Bill Pemberton8dc995f2012-11-19 13:26:10 -0500593static int wm831x_aldo_remove(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100594{
595 struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100596
Mark Browncd997582012-05-14 23:14:24 +0200597 free_irq(wm831x_irq(ldo->wm831x, platform_get_irq_byname(pdev, "UV")),
598 ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100599 regulator_unregister(ldo->regulator);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100600
601 return 0;
602}
603
604static struct platform_driver wm831x_aldo_driver = {
605 .probe = wm831x_aldo_probe,
Bill Pemberton5eb9f2b2012-11-19 13:20:42 -0500606 .remove = wm831x_aldo_remove,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100607 .driver = {
608 .name = "wm831x-aldo",
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800609 .owner = THIS_MODULE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100610 },
611};
612
613/*
614 * Alive LDO
615 */
616
617#define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
618
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100619static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
620 int uV)
621{
622 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
Axel Lin0a479682012-06-12 10:46:43 +0800623 struct wm831x *wm831x = ldo->wm831x;
624 int sel, reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100625
Axel Lin0a479682012-06-12 10:46:43 +0800626 sel = regulator_map_voltage_linear(rdev, uV, uV);
627 if (sel < 0)
628 return sel;
629
630 return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, sel);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100631}
632
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100633static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
634{
635 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
636 struct wm831x *wm831x = ldo->wm831x;
637 int mask = 1 << rdev_get_id(rdev);
638 int ret;
639
640 /* Is the regulator on? */
641 ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
642 if (ret < 0)
643 return ret;
644 if (ret & mask)
645 return REGULATOR_STATUS_ON;
646 else
647 return REGULATOR_STATUS_OFF;
648}
649
650static struct regulator_ops wm831x_alive_ldo_ops = {
Mark Brownd31e9542012-05-09 21:53:32 +0100651 .list_voltage = regulator_list_voltage_linear,
Axel Linc2543b52012-05-31 17:39:00 +0800652 .map_voltage = regulator_map_voltage_linear,
Mark Brownac663b42012-04-15 11:55:55 +0100653 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Axel Lin0a479682012-06-12 10:46:43 +0800654 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100655 .set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
656 .get_status = wm831x_alive_ldo_get_status,
657
Mark Brownca8c3612012-04-15 12:38:52 +0100658 .is_enabled = regulator_is_enabled_regmap,
659 .enable = regulator_enable_regmap,
660 .disable = regulator_disable_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100661};
662
Bill Pembertona5023572012-11-19 13:22:22 -0500663static int wm831x_alive_ldo_probe(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100664{
665 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
666 struct wm831x_pdata *pdata = wm831x->dev->platform_data;
Mark Brownc1727082012-04-04 00:50:22 +0100667 struct regulator_config config = { };
Mark Brown137a6352011-07-25 22:20:29 +0100668 int id;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100669 struct wm831x_ldo *ldo;
670 struct resource *res;
671 int ret;
672
Mark Brown137a6352011-07-25 22:20:29 +0100673 if (pdata && pdata->wm831x_num)
674 id = (pdata->wm831x_num * 10) + 1;
675 else
676 id = 0;
677 id = pdev->id - id;
678
679
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100680 dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
681
Mark Brownfded2f42011-12-15 02:11:14 +0800682 ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100683 if (ldo == NULL) {
684 dev_err(&pdev->dev, "Unable to allocate private data\n");
685 return -ENOMEM;
686 }
687
688 ldo->wm831x = wm831x;
689
Mark Brown56560982012-08-07 19:42:47 +0100690 res = platform_get_resource(pdev, IORESOURCE_REG, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100691 if (res == NULL) {
Mark Brown56560982012-08-07 19:42:47 +0100692 dev_err(&pdev->dev, "No REG resource\n");
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100693 ret = -EINVAL;
694 goto err;
695 }
696 ldo->base = res->start;
697
698 snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
699 ldo->desc.name = ldo->name;
Mark Brownf1aba132012-03-28 21:40:20 +0100700
701 snprintf(ldo->supply_name, sizeof(ldo->supply_name),
702 "LDO%dVDD", id + 1);
703 ldo->desc.supply_name = ldo->supply_name;
704
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100705 ldo->desc.id = id;
706 ldo->desc.type = REGULATOR_VOLTAGE;
707 ldo->desc.n_voltages = WM831X_ALIVE_LDO_MAX_SELECTOR + 1;
708 ldo->desc.ops = &wm831x_alive_ldo_ops;
709 ldo->desc.owner = THIS_MODULE;
Mark Brownac663b42012-04-15 11:55:55 +0100710 ldo->desc.vsel_reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
711 ldo->desc.vsel_mask = WM831X_LDO11_ON_VSEL_MASK;
Mark Brownca8c3612012-04-15 12:38:52 +0100712 ldo->desc.enable_reg = WM831X_LDO_ENABLE;
713 ldo->desc.enable_mask = 1 << id;
Mark Brownd31e9542012-05-09 21:53:32 +0100714 ldo->desc.min_uV = 800000;
715 ldo->desc.uV_step = 50000;
Mark Browneefaa3c2012-06-27 15:00:02 +0100716 ldo->desc.enable_time = 1000;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100717
Mark Brownc1727082012-04-04 00:50:22 +0100718 config.dev = pdev->dev.parent;
Mark Brownb7ca8782012-05-10 00:41:02 +0100719 if (pdata)
720 config.init_data = pdata->ldo[id];
Mark Brownc1727082012-04-04 00:50:22 +0100721 config.driver_data = ldo;
Mark Brownac663b42012-04-15 11:55:55 +0100722 config.regmap = wm831x->regmap;
Mark Brownc1727082012-04-04 00:50:22 +0100723
724 ldo->regulator = regulator_register(&ldo->desc, &config);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100725 if (IS_ERR(ldo->regulator)) {
726 ret = PTR_ERR(ldo->regulator);
727 dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
728 id + 1, ret);
729 goto err;
730 }
731
732 platform_set_drvdata(pdev, ldo);
733
734 return 0;
735
736err:
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100737 return ret;
738}
739
Bill Pemberton8dc995f2012-11-19 13:26:10 -0500740static int wm831x_alive_ldo_remove(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100741{
742 struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
743
744 regulator_unregister(ldo->regulator);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100745
746 return 0;
747}
748
749static struct platform_driver wm831x_alive_ldo_driver = {
750 .probe = wm831x_alive_ldo_probe,
Bill Pemberton5eb9f2b2012-11-19 13:20:42 -0500751 .remove = wm831x_alive_ldo_remove,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100752 .driver = {
753 .name = "wm831x-alive-ldo",
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800754 .owner = THIS_MODULE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100755 },
756};
757
758static int __init wm831x_ldo_init(void)
759{
760 int ret;
761
762 ret = platform_driver_register(&wm831x_gp_ldo_driver);
763 if (ret != 0)
764 pr_err("Failed to register WM831x GP LDO driver: %d\n", ret);
765
766 ret = platform_driver_register(&wm831x_aldo_driver);
767 if (ret != 0)
768 pr_err("Failed to register WM831x ALDO driver: %d\n", ret);
769
770 ret = platform_driver_register(&wm831x_alive_ldo_driver);
771 if (ret != 0)
772 pr_err("Failed to register WM831x alive LDO driver: %d\n",
773 ret);
774
775 return 0;
776}
777subsys_initcall(wm831x_ldo_init);
778
779static void __exit wm831x_ldo_exit(void)
780{
781 platform_driver_unregister(&wm831x_alive_ldo_driver);
782 platform_driver_unregister(&wm831x_aldo_driver);
783 platform_driver_unregister(&wm831x_gp_ldo_driver);
784}
785module_exit(wm831x_ldo_exit);
786
787/* Module information */
788MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
789MODULE_DESCRIPTION("WM831x LDO driver");
790MODULE_LICENSE("GPL");
791MODULE_ALIAS("platform:wm831x-ldo");
792MODULE_ALIAS("platform:wm831x-aldo");
793MODULE_ALIAS("platform:wm831x-aliveldo");