blob: 2205fbc2c37b4cf9b917bafa5d1f583f7e767b49 [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
Mark Brown5ff26a12013-07-02 23:35:22 +010065static const struct regulator_linear_range wm831x_gp_ldo_ranges[] = {
Axel Linf3ef11b2013-09-23 15:54:20 +080066 { .min_uV = 900000, .max_uV = 1600000, .min_sel = 0, .max_sel = 14,
Mark Brown5ff26a12013-07-02 23:35:22 +010067 .uV_step = 50000 },
68 { .min_uV = 1700000, .max_uV = 3300000, .min_sel = 15, .max_sel = 31,
69 .uV_step = 100000 },
70};
Mark Brownd1c6b4f2009-07-28 15:22:02 +010071
72static int wm831x_gp_ldo_set_suspend_voltage(struct regulator_dev *rdev,
73 int uV)
74{
75 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
Axel Lin0a479682012-06-12 10:46:43 +080076 struct wm831x *wm831x = ldo->wm831x;
77 int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
Mark Brownd1c6b4f2009-07-28 15:22:02 +010078
Mark Brown5ff26a12013-07-02 23:35:22 +010079 sel = regulator_map_voltage_linear_range(rdev, uV, uV);
Axel Lin0a479682012-06-12 10:46:43 +080080 if (sel < 0)
81 return sel;
82
83 return wm831x_set_bits(wm831x, reg, WM831X_LDO1_ON_VSEL_MASK, sel);
Mark Brownd1c6b4f2009-07-28 15:22:02 +010084}
85
Mark Brownd1c6b4f2009-07-28 15:22:02 +010086static unsigned int wm831x_gp_ldo_get_mode(struct regulator_dev *rdev)
87{
88 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
89 struct wm831x *wm831x = ldo->wm831x;
90 int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
91 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
Roel Kluin9a767d42009-10-16 14:16:15 +020092 int ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +010093
94 ret = wm831x_reg_read(wm831x, on_reg);
95 if (ret < 0)
Roel Kluin9a767d42009-10-16 14:16:15 +020096 return ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +010097
98 if (!(ret & WM831X_LDO1_ON_MODE))
99 return REGULATOR_MODE_NORMAL;
100
101 ret = wm831x_reg_read(wm831x, ctrl_reg);
102 if (ret < 0)
Roel Kluin9a767d42009-10-16 14:16:15 +0200103 return ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100104
105 if (ret & WM831X_LDO1_LP_MODE)
106 return REGULATOR_MODE_STANDBY;
107 else
108 return REGULATOR_MODE_IDLE;
109}
110
111static int wm831x_gp_ldo_set_mode(struct regulator_dev *rdev,
112 unsigned int mode)
113{
114 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
115 struct wm831x *wm831x = ldo->wm831x;
116 int ctrl_reg = ldo->base + WM831X_LDO_CONTROL;
117 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
118 int ret;
119
120
121 switch (mode) {
122 case REGULATOR_MODE_NORMAL:
123 ret = wm831x_set_bits(wm831x, on_reg,
124 WM831X_LDO1_ON_MODE, 0);
125 if (ret < 0)
126 return ret;
127 break;
128
129 case REGULATOR_MODE_IDLE:
130 ret = wm831x_set_bits(wm831x, ctrl_reg,
Axel Line2609992010-09-06 16:48:13 +0800131 WM831X_LDO1_LP_MODE, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100132 if (ret < 0)
133 return ret;
134
135 ret = wm831x_set_bits(wm831x, on_reg,
136 WM831X_LDO1_ON_MODE,
137 WM831X_LDO1_ON_MODE);
138 if (ret < 0)
139 return ret;
Axel Line2609992010-09-06 16:48:13 +0800140 break;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100141
142 case REGULATOR_MODE_STANDBY:
143 ret = wm831x_set_bits(wm831x, ctrl_reg,
Axel Line2609992010-09-06 16:48:13 +0800144 WM831X_LDO1_LP_MODE,
145 WM831X_LDO1_LP_MODE);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100146 if (ret < 0)
147 return ret;
148
149 ret = wm831x_set_bits(wm831x, on_reg,
150 WM831X_LDO1_ON_MODE,
151 WM831X_LDO1_ON_MODE);
152 if (ret < 0)
153 return ret;
154 break;
155
156 default:
157 return -EINVAL;
158 }
159
160 return 0;
161}
162
163static int wm831x_gp_ldo_get_status(struct regulator_dev *rdev)
164{
165 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
166 struct wm831x *wm831x = ldo->wm831x;
167 int mask = 1 << rdev_get_id(rdev);
168 int ret;
169
170 /* Is the regulator on? */
171 ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
172 if (ret < 0)
173 return ret;
174 if (!(ret & mask))
175 return REGULATOR_STATUS_OFF;
176
177 /* Is it reporting under voltage? */
178 ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
Axel Lin363506c2012-07-31 21:28:26 +0800179 if (ret < 0)
180 return ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100181 if (ret & mask)
182 return REGULATOR_STATUS_ERROR;
183
184 ret = wm831x_gp_ldo_get_mode(rdev);
185 if (ret < 0)
186 return ret;
187 else
188 return regulator_mode_to_status(ret);
189}
190
191static unsigned int wm831x_gp_ldo_get_optimum_mode(struct regulator_dev *rdev,
192 int input_uV,
193 int output_uV, int load_uA)
194{
195 if (load_uA < 20000)
196 return REGULATOR_MODE_STANDBY;
197 if (load_uA < 50000)
198 return REGULATOR_MODE_IDLE;
199 return REGULATOR_MODE_NORMAL;
200}
201
202
203static struct regulator_ops wm831x_gp_ldo_ops = {
Mark Brown5ff26a12013-07-02 23:35:22 +0100204 .list_voltage = regulator_list_voltage_linear_range,
205 .map_voltage = regulator_map_voltage_linear_range,
Mark Brownac663b42012-04-15 11:55:55 +0100206 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Axel Lin0a479682012-06-12 10:46:43 +0800207 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100208 .set_suspend_voltage = wm831x_gp_ldo_set_suspend_voltage,
209 .get_mode = wm831x_gp_ldo_get_mode,
210 .set_mode = wm831x_gp_ldo_set_mode,
211 .get_status = wm831x_gp_ldo_get_status,
212 .get_optimum_mode = wm831x_gp_ldo_get_optimum_mode,
Mark Brown22c5fb62012-08-27 21:52:29 -0700213 .get_bypass = regulator_get_bypass_regmap,
214 .set_bypass = regulator_set_bypass_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100215
Mark Brownca8c3612012-04-15 12:38:52 +0100216 .is_enabled = regulator_is_enabled_regmap,
217 .enable = regulator_enable_regmap,
218 .disable = regulator_disable_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100219};
220
Bill Pembertona5023572012-11-19 13:22:22 -0500221static int wm831x_gp_ldo_probe(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100222{
223 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
Jingoo Handff91d02013-07-30 17:20:47 +0900224 struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
Mark Brownc1727082012-04-04 00:50:22 +0100225 struct regulator_config config = { };
Mark Brown137a6352011-07-25 22:20:29 +0100226 int id;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100227 struct wm831x_ldo *ldo;
228 struct resource *res;
229 int ret, irq;
230
Mark Brown137a6352011-07-25 22:20:29 +0100231 if (pdata && pdata->wm831x_num)
232 id = (pdata->wm831x_num * 10) + 1;
233 else
234 id = 0;
235 id = pdev->id - id;
236
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100237 dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
238
Mark Brownfded2f42011-12-15 02:11:14 +0800239 ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100240 if (ldo == NULL) {
241 dev_err(&pdev->dev, "Unable to allocate private data\n");
242 return -ENOMEM;
243 }
244
245 ldo->wm831x = wm831x;
246
Mark Brown56560982012-08-07 19:42:47 +0100247 res = platform_get_resource(pdev, IORESOURCE_REG, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100248 if (res == NULL) {
Mark Brown56560982012-08-07 19:42:47 +0100249 dev_err(&pdev->dev, "No REG resource\n");
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100250 ret = -EINVAL;
251 goto err;
252 }
253 ldo->base = res->start;
254
255 snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
256 ldo->desc.name = ldo->name;
Mark Brownf1aba132012-03-28 21:40:20 +0100257
258 snprintf(ldo->supply_name, sizeof(ldo->supply_name),
259 "LDO%dVDD", id + 1);
260 ldo->desc.supply_name = ldo->supply_name;
261
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100262 ldo->desc.id = id;
263 ldo->desc.type = REGULATOR_VOLTAGE;
Mark Brown5ff26a12013-07-02 23:35:22 +0100264 ldo->desc.n_voltages = 32;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100265 ldo->desc.ops = &wm831x_gp_ldo_ops;
266 ldo->desc.owner = THIS_MODULE;
Mark Brownac663b42012-04-15 11:55:55 +0100267 ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
268 ldo->desc.vsel_mask = WM831X_LDO1_ON_VSEL_MASK;
Mark Brownca8c3612012-04-15 12:38:52 +0100269 ldo->desc.enable_reg = WM831X_LDO_ENABLE;
270 ldo->desc.enable_mask = 1 << id;
Mark Brown22c5fb62012-08-27 21:52:29 -0700271 ldo->desc.bypass_reg = ldo->base;
272 ldo->desc.bypass_mask = WM831X_LDO1_SWI;
Mark Brown5ff26a12013-07-02 23:35:22 +0100273 ldo->desc.linear_ranges = wm831x_gp_ldo_ranges;
274 ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_gp_ldo_ranges);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100275
Mark Brownc1727082012-04-04 00:50:22 +0100276 config.dev = pdev->dev.parent;
Mark Brownb7ca8782012-05-10 00:41:02 +0100277 if (pdata)
278 config.init_data = pdata->ldo[id];
Mark Brownc1727082012-04-04 00:50:22 +0100279 config.driver_data = ldo;
Mark Brownac663b42012-04-15 11:55:55 +0100280 config.regmap = wm831x->regmap;
Mark Brownc1727082012-04-04 00:50:22 +0100281
282 ldo->regulator = regulator_register(&ldo->desc, &config);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100283 if (IS_ERR(ldo->regulator)) {
284 ret = PTR_ERR(ldo->regulator);
285 dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
286 id + 1, ret);
287 goto err;
288 }
289
Mark Browncd997582012-05-14 23:14:24 +0200290 irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
Mark Browndfda9c22011-03-01 16:50:43 +0000291 ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
292 IRQF_TRIGGER_RISING, ldo->name,
293 ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100294 if (ret != 0) {
295 dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
296 irq, ret);
297 goto err_regulator;
298 }
299
300 platform_set_drvdata(pdev, ldo);
301
302 return 0;
303
304err_regulator:
305 regulator_unregister(ldo->regulator);
306err:
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100307 return ret;
308}
309
Bill Pemberton8dc995f2012-11-19 13:26:10 -0500310static int wm831x_gp_ldo_remove(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100311{
312 struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100313
Mark Browncd997582012-05-14 23:14:24 +0200314 free_irq(wm831x_irq(ldo->wm831x,
315 platform_get_irq_byname(pdev, "UV")), ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100316 regulator_unregister(ldo->regulator);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100317
318 return 0;
319}
320
321static struct platform_driver wm831x_gp_ldo_driver = {
322 .probe = wm831x_gp_ldo_probe,
Bill Pemberton5eb9f2b2012-11-19 13:20:42 -0500323 .remove = wm831x_gp_ldo_remove,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100324 .driver = {
325 .name = "wm831x-ldo",
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800326 .owner = THIS_MODULE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100327 },
328};
329
330/*
331 * Analogue LDOs
332 */
333
Mark Brown5ff26a12013-07-02 23:35:22 +0100334static const struct regulator_linear_range wm831x_aldo_ranges[] = {
Axel Linf3ef11b2013-09-23 15:54:20 +0800335 { .min_uV = 1000000, .max_uV = 1600000, .min_sel = 0, .max_sel = 12,
Mark Brown5ff26a12013-07-02 23:35:22 +0100336 .uV_step = 50000 },
337 { .min_uV = 1700000, .max_uV = 3500000, .min_sel = 13, .max_sel = 31,
338 .uV_step = 100000 },
339};
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100340
341static int wm831x_aldo_set_suspend_voltage(struct regulator_dev *rdev,
342 int uV)
343{
344 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
Axel Lin0a479682012-06-12 10:46:43 +0800345 struct wm831x *wm831x = ldo->wm831x;
346 int sel, reg = ldo->base + WM831X_LDO_SLEEP_CONTROL;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100347
Mark Brown5ff26a12013-07-02 23:35:22 +0100348 sel = regulator_map_voltage_linear_range(rdev, uV, uV);
Axel Lin0a479682012-06-12 10:46:43 +0800349 if (sel < 0)
350 return sel;
351
352 return wm831x_set_bits(wm831x, reg, WM831X_LDO7_ON_VSEL_MASK, sel);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100353}
354
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100355static unsigned int wm831x_aldo_get_mode(struct regulator_dev *rdev)
356{
357 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
358 struct wm831x *wm831x = ldo->wm831x;
359 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
Roel Kluin6f17c652009-12-15 20:07:31 +0100360 int ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100361
362 ret = wm831x_reg_read(wm831x, on_reg);
363 if (ret < 0)
364 return 0;
365
366 if (ret & WM831X_LDO7_ON_MODE)
367 return REGULATOR_MODE_IDLE;
368 else
369 return REGULATOR_MODE_NORMAL;
370}
371
372static int wm831x_aldo_set_mode(struct regulator_dev *rdev,
373 unsigned int mode)
374{
375 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
376 struct wm831x *wm831x = ldo->wm831x;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100377 int on_reg = ldo->base + WM831X_LDO_ON_CONTROL;
378 int ret;
379
380
381 switch (mode) {
382 case REGULATOR_MODE_NORMAL:
Axel Line841a362012-03-29 15:02:55 +0800383 ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100384 if (ret < 0)
385 return ret;
386 break;
387
388 case REGULATOR_MODE_IDLE:
Axel Line841a362012-03-29 15:02:55 +0800389 ret = wm831x_set_bits(wm831x, on_reg, WM831X_LDO7_ON_MODE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100390 WM831X_LDO7_ON_MODE);
391 if (ret < 0)
392 return ret;
393 break;
394
395 default:
396 return -EINVAL;
397 }
398
399 return 0;
400}
401
402static int wm831x_aldo_get_status(struct regulator_dev *rdev)
403{
404 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
405 struct wm831x *wm831x = ldo->wm831x;
406 int mask = 1 << rdev_get_id(rdev);
407 int ret;
408
409 /* Is the regulator on? */
410 ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
411 if (ret < 0)
412 return ret;
413 if (!(ret & mask))
414 return REGULATOR_STATUS_OFF;
415
416 /* Is it reporting under voltage? */
417 ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
Axel Lin363506c2012-07-31 21:28:26 +0800418 if (ret < 0)
419 return ret;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100420 if (ret & mask)
421 return REGULATOR_STATUS_ERROR;
422
423 ret = wm831x_aldo_get_mode(rdev);
424 if (ret < 0)
425 return ret;
426 else
427 return regulator_mode_to_status(ret);
428}
429
430static struct regulator_ops wm831x_aldo_ops = {
Mark Brown5ff26a12013-07-02 23:35:22 +0100431 .list_voltage = regulator_list_voltage_linear_range,
432 .map_voltage = regulator_map_voltage_linear_range,
Mark Brownac663b42012-04-15 11:55:55 +0100433 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Axel Lin0a479682012-06-12 10:46:43 +0800434 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100435 .set_suspend_voltage = wm831x_aldo_set_suspend_voltage,
436 .get_mode = wm831x_aldo_get_mode,
437 .set_mode = wm831x_aldo_set_mode,
438 .get_status = wm831x_aldo_get_status,
Mark Brown22c5fb62012-08-27 21:52:29 -0700439 .set_bypass = regulator_set_bypass_regmap,
440 .get_bypass = regulator_get_bypass_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100441
Mark Brownca8c3612012-04-15 12:38:52 +0100442 .is_enabled = regulator_is_enabled_regmap,
443 .enable = regulator_enable_regmap,
444 .disable = regulator_disable_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100445};
446
Bill Pembertona5023572012-11-19 13:22:22 -0500447static int wm831x_aldo_probe(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100448{
449 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
Jingoo Handff91d02013-07-30 17:20:47 +0900450 struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
Mark Brownc1727082012-04-04 00:50:22 +0100451 struct regulator_config config = { };
Mark Brown137a6352011-07-25 22:20:29 +0100452 int id;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100453 struct wm831x_ldo *ldo;
454 struct resource *res;
455 int ret, irq;
456
Mark Brown137a6352011-07-25 22:20:29 +0100457 if (pdata && pdata->wm831x_num)
458 id = (pdata->wm831x_num * 10) + 1;
459 else
460 id = 0;
461 id = pdev->id - id;
462
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100463 dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
464
Mark Brownfded2f42011-12-15 02:11:14 +0800465 ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100466 if (ldo == NULL) {
467 dev_err(&pdev->dev, "Unable to allocate private data\n");
468 return -ENOMEM;
469 }
470
471 ldo->wm831x = wm831x;
472
Mark Brown56560982012-08-07 19:42:47 +0100473 res = platform_get_resource(pdev, IORESOURCE_REG, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100474 if (res == NULL) {
Mark Brown56560982012-08-07 19:42:47 +0100475 dev_err(&pdev->dev, "No REG resource\n");
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100476 ret = -EINVAL;
477 goto err;
478 }
479 ldo->base = res->start;
480
481 snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
482 ldo->desc.name = ldo->name;
Mark Brownf1aba132012-03-28 21:40:20 +0100483
484 snprintf(ldo->supply_name, sizeof(ldo->supply_name),
485 "LDO%dVDD", id + 1);
486 ldo->desc.supply_name = ldo->supply_name;
487
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100488 ldo->desc.id = id;
489 ldo->desc.type = REGULATOR_VOLTAGE;
Mark Brown5ff26a12013-07-02 23:35:22 +0100490 ldo->desc.n_voltages = 32;
491 ldo->desc.linear_ranges = wm831x_aldo_ranges;
492 ldo->desc.n_linear_ranges = ARRAY_SIZE(wm831x_aldo_ranges);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100493 ldo->desc.ops = &wm831x_aldo_ops;
494 ldo->desc.owner = THIS_MODULE;
Mark Brownac663b42012-04-15 11:55:55 +0100495 ldo->desc.vsel_reg = ldo->base + WM831X_LDO_ON_CONTROL;
496 ldo->desc.vsel_mask = WM831X_LDO7_ON_VSEL_MASK;
Mark Brownca8c3612012-04-15 12:38:52 +0100497 ldo->desc.enable_reg = WM831X_LDO_ENABLE;
498 ldo->desc.enable_mask = 1 << id;
Mark Brown22c5fb62012-08-27 21:52:29 -0700499 ldo->desc.bypass_reg = ldo->base;
500 ldo->desc.bypass_mask = WM831X_LDO7_SWI;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100501
Mark Brownc1727082012-04-04 00:50:22 +0100502 config.dev = pdev->dev.parent;
Mark Brownb7ca8782012-05-10 00:41:02 +0100503 if (pdata)
504 config.init_data = pdata->ldo[id];
Mark Brownc1727082012-04-04 00:50:22 +0100505 config.driver_data = ldo;
Mark Brownac663b42012-04-15 11:55:55 +0100506 config.regmap = wm831x->regmap;
Mark Brownc1727082012-04-04 00:50:22 +0100507
508 ldo->regulator = regulator_register(&ldo->desc, &config);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100509 if (IS_ERR(ldo->regulator)) {
510 ret = PTR_ERR(ldo->regulator);
511 dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
512 id + 1, ret);
513 goto err;
514 }
515
Mark Browncd997582012-05-14 23:14:24 +0200516 irq = wm831x_irq(wm831x, platform_get_irq_byname(pdev, "UV"));
Mark Browndfda9c22011-03-01 16:50:43 +0000517 ret = request_threaded_irq(irq, NULL, wm831x_ldo_uv_irq,
518 IRQF_TRIGGER_RISING, ldo->name, ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100519 if (ret != 0) {
520 dev_err(&pdev->dev, "Failed to request UV IRQ %d: %d\n",
521 irq, ret);
522 goto err_regulator;
523 }
524
525 platform_set_drvdata(pdev, ldo);
526
527 return 0;
528
529err_regulator:
530 regulator_unregister(ldo->regulator);
531err:
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100532 return ret;
533}
534
Bill Pemberton8dc995f2012-11-19 13:26:10 -0500535static int wm831x_aldo_remove(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100536{
537 struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100538
Mark Browncd997582012-05-14 23:14:24 +0200539 free_irq(wm831x_irq(ldo->wm831x, platform_get_irq_byname(pdev, "UV")),
540 ldo);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100541 regulator_unregister(ldo->regulator);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100542
543 return 0;
544}
545
546static struct platform_driver wm831x_aldo_driver = {
547 .probe = wm831x_aldo_probe,
Bill Pemberton5eb9f2b2012-11-19 13:20:42 -0500548 .remove = wm831x_aldo_remove,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100549 .driver = {
550 .name = "wm831x-aldo",
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800551 .owner = THIS_MODULE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100552 },
553};
554
555/*
556 * Alive LDO
557 */
558
559#define WM831X_ALIVE_LDO_MAX_SELECTOR 0xf
560
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100561static int wm831x_alive_ldo_set_suspend_voltage(struct regulator_dev *rdev,
562 int uV)
563{
564 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
Axel Lin0a479682012-06-12 10:46:43 +0800565 struct wm831x *wm831x = ldo->wm831x;
566 int sel, reg = ldo->base + WM831X_ALIVE_LDO_SLEEP_CONTROL;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100567
Axel Lin0a479682012-06-12 10:46:43 +0800568 sel = regulator_map_voltage_linear(rdev, uV, uV);
569 if (sel < 0)
570 return sel;
571
572 return wm831x_set_bits(wm831x, reg, WM831X_LDO11_ON_VSEL_MASK, sel);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100573}
574
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100575static int wm831x_alive_ldo_get_status(struct regulator_dev *rdev)
576{
577 struct wm831x_ldo *ldo = rdev_get_drvdata(rdev);
578 struct wm831x *wm831x = ldo->wm831x;
579 int mask = 1 << rdev_get_id(rdev);
580 int ret;
581
582 /* Is the regulator on? */
583 ret = wm831x_reg_read(wm831x, WM831X_LDO_STATUS);
584 if (ret < 0)
585 return ret;
586 if (ret & mask)
587 return REGULATOR_STATUS_ON;
588 else
589 return REGULATOR_STATUS_OFF;
590}
591
592static struct regulator_ops wm831x_alive_ldo_ops = {
Mark Brownd31e9542012-05-09 21:53:32 +0100593 .list_voltage = regulator_list_voltage_linear,
Axel Linc2543b52012-05-31 17:39:00 +0800594 .map_voltage = regulator_map_voltage_linear,
Mark Brownac663b42012-04-15 11:55:55 +0100595 .get_voltage_sel = regulator_get_voltage_sel_regmap,
Axel Lin0a479682012-06-12 10:46:43 +0800596 .set_voltage_sel = regulator_set_voltage_sel_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100597 .set_suspend_voltage = wm831x_alive_ldo_set_suspend_voltage,
598 .get_status = wm831x_alive_ldo_get_status,
599
Mark Brownca8c3612012-04-15 12:38:52 +0100600 .is_enabled = regulator_is_enabled_regmap,
601 .enable = regulator_enable_regmap,
602 .disable = regulator_disable_regmap,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100603};
604
Bill Pembertona5023572012-11-19 13:22:22 -0500605static int wm831x_alive_ldo_probe(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100606{
607 struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent);
Jingoo Handff91d02013-07-30 17:20:47 +0900608 struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
Mark Brownc1727082012-04-04 00:50:22 +0100609 struct regulator_config config = { };
Mark Brown137a6352011-07-25 22:20:29 +0100610 int id;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100611 struct wm831x_ldo *ldo;
612 struct resource *res;
613 int ret;
614
Mark Brown137a6352011-07-25 22:20:29 +0100615 if (pdata && pdata->wm831x_num)
616 id = (pdata->wm831x_num * 10) + 1;
617 else
618 id = 0;
619 id = pdev->id - id;
620
621
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100622 dev_dbg(&pdev->dev, "Probing LDO%d\n", id + 1);
623
Mark Brownfded2f42011-12-15 02:11:14 +0800624 ldo = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ldo), GFP_KERNEL);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100625 if (ldo == NULL) {
626 dev_err(&pdev->dev, "Unable to allocate private data\n");
627 return -ENOMEM;
628 }
629
630 ldo->wm831x = wm831x;
631
Mark Brown56560982012-08-07 19:42:47 +0100632 res = platform_get_resource(pdev, IORESOURCE_REG, 0);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100633 if (res == NULL) {
Mark Brown56560982012-08-07 19:42:47 +0100634 dev_err(&pdev->dev, "No REG resource\n");
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100635 ret = -EINVAL;
636 goto err;
637 }
638 ldo->base = res->start;
639
640 snprintf(ldo->name, sizeof(ldo->name), "LDO%d", id + 1);
641 ldo->desc.name = ldo->name;
Mark Brownf1aba132012-03-28 21:40:20 +0100642
643 snprintf(ldo->supply_name, sizeof(ldo->supply_name),
644 "LDO%dVDD", id + 1);
645 ldo->desc.supply_name = ldo->supply_name;
646
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100647 ldo->desc.id = id;
648 ldo->desc.type = REGULATOR_VOLTAGE;
649 ldo->desc.n_voltages = WM831X_ALIVE_LDO_MAX_SELECTOR + 1;
650 ldo->desc.ops = &wm831x_alive_ldo_ops;
651 ldo->desc.owner = THIS_MODULE;
Mark Brownac663b42012-04-15 11:55:55 +0100652 ldo->desc.vsel_reg = ldo->base + WM831X_ALIVE_LDO_ON_CONTROL;
653 ldo->desc.vsel_mask = WM831X_LDO11_ON_VSEL_MASK;
Mark Brownca8c3612012-04-15 12:38:52 +0100654 ldo->desc.enable_reg = WM831X_LDO_ENABLE;
655 ldo->desc.enable_mask = 1 << id;
Mark Brownd31e9542012-05-09 21:53:32 +0100656 ldo->desc.min_uV = 800000;
657 ldo->desc.uV_step = 50000;
Mark Browneefaa3c2012-06-27 15:00:02 +0100658 ldo->desc.enable_time = 1000;
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100659
Mark Brownc1727082012-04-04 00:50:22 +0100660 config.dev = pdev->dev.parent;
Mark Brownb7ca8782012-05-10 00:41:02 +0100661 if (pdata)
662 config.init_data = pdata->ldo[id];
Mark Brownc1727082012-04-04 00:50:22 +0100663 config.driver_data = ldo;
Mark Brownac663b42012-04-15 11:55:55 +0100664 config.regmap = wm831x->regmap;
Mark Brownc1727082012-04-04 00:50:22 +0100665
666 ldo->regulator = regulator_register(&ldo->desc, &config);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100667 if (IS_ERR(ldo->regulator)) {
668 ret = PTR_ERR(ldo->regulator);
669 dev_err(wm831x->dev, "Failed to register LDO%d: %d\n",
670 id + 1, ret);
671 goto err;
672 }
673
674 platform_set_drvdata(pdev, ldo);
675
676 return 0;
677
678err:
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100679 return ret;
680}
681
Bill Pemberton8dc995f2012-11-19 13:26:10 -0500682static int wm831x_alive_ldo_remove(struct platform_device *pdev)
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100683{
684 struct wm831x_ldo *ldo = platform_get_drvdata(pdev);
685
686 regulator_unregister(ldo->regulator);
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100687
688 return 0;
689}
690
691static struct platform_driver wm831x_alive_ldo_driver = {
692 .probe = wm831x_alive_ldo_probe,
Bill Pemberton5eb9f2b2012-11-19 13:20:42 -0500693 .remove = wm831x_alive_ldo_remove,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100694 .driver = {
695 .name = "wm831x-alive-ldo",
Dmitry Torokhoveb66d562010-02-23 23:38:39 -0800696 .owner = THIS_MODULE,
Mark Brownd1c6b4f2009-07-28 15:22:02 +0100697 },
698};
699
700static int __init wm831x_ldo_init(void)
701{
702 int ret;
703
704 ret = platform_driver_register(&wm831x_gp_ldo_driver);
705 if (ret != 0)
706 pr_err("Failed to register WM831x GP LDO driver: %d\n", ret);
707
708 ret = platform_driver_register(&wm831x_aldo_driver);
709 if (ret != 0)
710 pr_err("Failed to register WM831x ALDO driver: %d\n", ret);
711
712 ret = platform_driver_register(&wm831x_alive_ldo_driver);
713 if (ret != 0)
714 pr_err("Failed to register WM831x alive LDO driver: %d\n",
715 ret);
716
717 return 0;
718}
719subsys_initcall(wm831x_ldo_init);
720
721static void __exit wm831x_ldo_exit(void)
722{
723 platform_driver_unregister(&wm831x_alive_ldo_driver);
724 platform_driver_unregister(&wm831x_aldo_driver);
725 platform_driver_unregister(&wm831x_gp_ldo_driver);
726}
727module_exit(wm831x_ldo_exit);
728
729/* Module information */
730MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
731MODULE_DESCRIPTION("WM831x LDO driver");
732MODULE_LICENSE("GPL");
733MODULE_ALIAS("platform:wm831x-ldo");
734MODULE_ALIAS("platform:wm831x-aldo");
735MODULE_ALIAS("platform:wm831x-aliveldo");