aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator/ab8500-ext.c
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2013-03-28 12:11:01 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-03-29 13:49:07 -0400
commitd1a820011b2fbc11d5af80d1a961fe66c613fa4b (patch)
treea651cd0d73b9a2b94385c83463a57964a4a7ca62 /drivers/regulator/ab8500-ext.c
parentcc40dc2981396748ebcdde4a313d65ba26b0159d (diff)
regulator: ab8500-ext: New driver to control external regulators
The ABx500 is capable of controlling three external regulator supplies. Most commonly on and off are supported, but if an external regulator chipset or power supply supports high-power and low-power mode settings, we can control those too. Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/regulator/ab8500-ext.c')
-rw-r--r--drivers/regulator/ab8500-ext.c394
1 files changed, 394 insertions, 0 deletions
diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c
new file mode 100644
index 000000000000..95008dec5190
--- /dev/null
+++ b/drivers/regulator/ab8500-ext.c
@@ -0,0 +1,394 @@
1/*
2 * Copyright (C) ST-Ericsson SA 2010
3 *
4 * License Terms: GNU General Public License v2
5 *
6 * Authors: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
7 *
8 * This file is based on drivers/regulator/ab8500.c
9 *
10 * AB8500 external regulators
11 *
12 * ab8500-ext supports the following regulators:
13 * - VextSupply3
14 */
15#include <linux/init.h>
16#include <linux/kernel.h>
17#include <linux/err.h>
18#include <linux/module.h>
19#include <linux/platform_device.h>
20#include <linux/regulator/driver.h>
21#include <linux/regulator/machine.h>
22#include <linux/mfd/abx500.h>
23#include <linux/mfd/abx500/ab8500.h>
24#include <linux/regulator/ab8500.h>
25
26/**
27 * struct ab8500_ext_regulator_info - ab8500 regulator information
28 * @dev: device pointer
29 * @desc: regulator description
30 * @rdev: regulator device
31 * @is_enabled: status of regulator (on/off)
32 * @update_bank: bank to control on/off
33 * @update_reg: register to control on/off
34 * @update_mask: mask to enable/disable and set mode of regulator
35 * @update_val: bits holding the regulator current mode
36 * @update_val_en: bits to set EN pin active (LPn pin deactive)
37 * normally this means high power mode
38 * @update_val_en_lp: bits to set EN pin active and LPn pin active
39 * normally this means low power mode
40 * @delay: startup delay in ms
41 */
42struct ab8500_ext_regulator_info {
43 struct device *dev;
44 struct regulator_desc desc;
45 struct regulator_dev *rdev;
46 bool is_enabled;
47 u8 update_bank;
48 u8 update_reg;
49 u8 update_mask;
50 u8 update_val;
51 u8 update_val_en;
52 u8 update_val_en_lp;
53};
54
55static int ab8500_ext_regulator_enable(struct regulator_dev *rdev)
56{
57 int ret;
58 struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
59
60 if (info == NULL) {
61 dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
62 return -EINVAL;
63 }
64
65 ret = abx500_mask_and_set_register_interruptible(info->dev,
66 info->update_bank, info->update_reg,
67 info->update_mask, info->update_val);
68 if (ret < 0)
69 dev_err(rdev_get_dev(info->rdev),
70 "couldn't set enable bits for regulator\n");
71
72 info->is_enabled = true;
73
74 dev_dbg(rdev_get_dev(rdev), "%s-enable (bank, reg, mask, value):"
75 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
76 info->desc.name, info->update_bank, info->update_reg,
77 info->update_mask, info->update_val);
78
79 return ret;
80}
81
82static int ab8500_ext_regulator_disable(struct regulator_dev *rdev)
83{
84 int ret;
85 struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
86
87 if (info == NULL) {
88 dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
89 return -EINVAL;
90 }
91
92 ret = abx500_mask_and_set_register_interruptible(info->dev,
93 info->update_bank, info->update_reg,
94 info->update_mask, 0x0);
95 if (ret < 0)
96 dev_err(rdev_get_dev(info->rdev),
97 "couldn't set disable bits for regulator\n");
98
99 info->is_enabled = false;
100
101 dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):"
102 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
103 info->desc.name, info->update_bank, info->update_reg,
104 info->update_mask, 0x0);
105
106 return ret;
107}
108
109static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev)
110{
111 int ret;
112 struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
113 u8 regval;
114
115 if (info == NULL) {
116 dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
117 return -EINVAL;
118 }
119
120 ret = abx500_get_register_interruptible(info->dev,
121 info->update_bank, info->update_reg, &regval);
122 if (ret < 0) {
123 dev_err(rdev_get_dev(rdev),
124 "couldn't read 0x%x register\n", info->update_reg);
125 return ret;
126 }
127
128 dev_dbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value):"
129 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
130 info->desc.name, info->update_bank, info->update_reg,
131 info->update_mask, regval);
132
133 if (regval & info->update_mask)
134 info->is_enabled = true;
135 else
136 info->is_enabled = false;
137
138 return info->is_enabled;
139}
140
141static int ab8500_ext_regulator_set_mode(struct regulator_dev *rdev,
142 unsigned int mode)
143{
144 int ret = 0;
145 struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
146
147 if (info == NULL) {
148 dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
149 return -EINVAL;
150 }
151
152 switch (mode) {
153 case REGULATOR_MODE_NORMAL:
154 info->update_val = info->update_val_hp;
155 break;
156 case REGULATOR_MODE_IDLE:
157 info->update_val = info->update_val_lp;
158 break;
159
160 default:
161 return -EINVAL;
162 }
163
164 if (info->is_enabled) {
165 u8 regval;
166
167 ret = enable(info, &regval);
168 if (ret < 0)
169 dev_err(rdev_get_dev(rdev),
170 "Could not set regulator mode.\n");
171
172 dev_dbg(rdev_get_dev(rdev),
173 "%s-set_mode (bank, reg, mask, value): "
174 "0x%x, 0x%x, 0x%x, 0x%x\n",
175 info->desc.name, info->update_bank, info->update_reg,
176 info->update_mask, regval);
177 }
178
179 return ret;
180}
181
182static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev)
183{
184 struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
185 int ret;
186
187 if (info == NULL) {
188 dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
189 return -EINVAL;
190 }
191
192 if (info->update_val == info->update_val_hp)
193 ret = REGULATOR_MODE_NORMAL;
194 else if (info->update_val == info->update_val_lp)
195 ret = REGULATOR_MODE_IDLE;
196 else
197 ret = -EINVAL;
198
199 return ret;
200}
201
202static int ab8500_ext_fixed_get_voltage(struct regulator_dev *rdev)
203{
204 struct regulation_constraints *regu_constraints = rdev->constraints;
205
206 if (regu_constraints == NULL) {
207 dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n");
208 return -EINVAL;
209 }
210 if (regu_constraints->min_uV && regu_constraints->max_uV) {
211 if (regu_constraints->min_uV == regu_constraints->max_uV)
212 return regu_constraints->min_uV;
213 }
214 return -EINVAL;
215}
216
217static int ab8500_ext_list_voltage(struct regulator_dev *rdev,
218 unsigned selector)
219{
220 struct regulation_constraints *regu_constraints = rdev->constraints;
221
222 if (regu_constraints == NULL) {
223 dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n");
224 return -EINVAL;
225 }
226 /* return the uV for the fixed regulators */
227 if (regu_constraints->min_uV && regu_constraints->max_uV) {
228 if (regu_constraints->min_uV == regu_constraints->max_uV)
229 return regu_constraints->min_uV;
230 }
231 return -EINVAL;
232}
233
234static struct regulator_ops ab8500_ext_regulator_ops = {
235 .enable = ab8500_ext_regulator_enable,
236 .disable = ab8500_ext_regulator_disable,
237 .is_enabled = ab8500_ext_regulator_is_enabled,
238 .set_mode = ab8500_ext_regulator_set_mode,
239 .get_mode = ab8500_ext_regulator_get_mode,
240 .get_voltage = ab8500_ext_fixed_get_voltage,
241 .list_voltage = ab8500_ext_list_voltage,
242};
243
244
245static struct ab8500_ext_regulator_info
246 ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = {
247 [AB8500_EXT_SUPPLY1] = {
248 .desc = {
249 .name = "VEXTSUPPLY1",
250 .ops = &ab8500_ext_regulator_ops,
251 .type = REGULATOR_VOLTAGE,
252 .id = AB8500_EXT_SUPPLY1,
253 .owner = THIS_MODULE,
254 .n_voltages = 1,
255 },
256 .update_bank = 0x04,
257 .update_reg = 0x08,
258 .update_mask = 0x03,
259 .update_val = 0x01,
260 .update_val_hp = 0x01,
261 .update_val_lp = 0x03,
262 .update_val_hw = 0x02,
263 },
264 [AB8500_EXT_SUPPLY2] = {
265 .desc = {
266 .name = "VEXTSUPPLY2",
267 .ops = &ab8500_ext_regulator_ops,
268 .type = REGULATOR_VOLTAGE,
269 .id = AB8500_EXT_SUPPLY2,
270 .owner = THIS_MODULE,
271 .n_voltages = 1,
272 },
273 .update_bank = 0x04,
274 .update_reg = 0x08,
275 .update_mask = 0x0c,
276 .update_val = 0x04,
277 .update_val_hp = 0x04,
278 .update_val_lp = 0x0c,
279 .update_val_hw = 0x08,
280 },
281 [AB8500_EXT_SUPPLY3] = {
282 .desc = {
283 .name = "VEXTSUPPLY3",
284 .ops = &ab8500_ext_regulator_ops,
285 .type = REGULATOR_VOLTAGE,
286 .id = AB8500_EXT_SUPPLY3,
287 .owner = THIS_MODULE,
288 .n_voltages = 1,
289 },
290 .update_bank = 0x04,
291 .update_reg = 0x08,
292 .update_mask = 0x30,
293 .update_val = 0x10,
294 .update_val_en = 0x10,
295 .update_val_en_lp = 0x30,
296 },
297};
298
299int ab8500_ext_regulator_init(struct platform_device *pdev)
300{
301 struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
302 struct ab8500_platform_data *ppdata;
303 struct ab8500_regulator_platform_data *pdata;
304 struct regulator_config config = { };
305 int i, err;
306
307 if (!ab8500) {
308 dev_err(&pdev->dev, "null mfd parent\n");
309 return -EINVAL;
310 }
311 ppdata = dev_get_platdata(ab8500->dev);
312 if (!ppdata) {
313 dev_err(&pdev->dev, "null parent pdata\n");
314 return -EINVAL;
315 }
316
317 pdata = ppdata->regulator;
318 if (!pdata) {
319 dev_err(&pdev->dev, "null pdata\n");
320 return -EINVAL;
321 }
322
323 /* make sure the platform data has the correct size */
324 if (pdata->num_ext_regulator != ARRAY_SIZE(ab8500_ext_regulator_info)) {
325 dev_err(&pdev->dev, "Configuration error: size mismatch.\n");
326 return -EINVAL;
327 }
328
329 /* check for AB8500 2.x */
330 if (abx500_get_chip_id(&pdev->dev) < 0x30) {
331 struct ab8500_ext_regulator_info *info;
332
333 /* VextSupply3LPn is inverted on AB8500 2.x */
334 info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3];
335 info->update_val = 0x30;
336 info->update_val_en = 0x30;
337 info->update_val_en_lp = 0x10;
338 }
339
340 /* register all regulators */
341 for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) {
342 struct ab8500_ext_regulator_info *info = NULL;
343
344 /* assign per-regulator data */
345 info = &ab8500_ext_regulator_info[i];
346 info->dev = &pdev->dev;
347
348 config.dev = &pdev->dev;
349 config.init_data = &pdata->ext_regulator[i];
350 config.driver_data = info;
351
352 /* register regulator with framework */
353 info->rdev = regulator_register(&info->desc, &config);
354
355 if (IS_ERR(info->rdev)) {
356 err = PTR_ERR(info->rdev);
357 dev_err(&pdev->dev, "failed to register regulator %s\n",
358 info->desc.name);
359 /* when we fail, un-register all earlier regulators */
360 while (--i >= 0) {
361 info = &ab8500_ext_regulator_info[i];
362 regulator_unregister(info->rdev);
363 }
364 return err;
365 }
366
367 dev_dbg(rdev_get_dev(info->rdev),
368 "%s-probed\n", info->desc.name);
369 }
370
371 return 0;
372}
373
374int ab8500_ext_regulator_exit(struct platform_device *pdev)
375{
376 int i;
377
378 for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) {
379 struct ab8500_ext_regulator_info *info = NULL;
380 info = &ab8500_ext_regulator_info[i];
381
382 dev_vdbg(rdev_get_dev(info->rdev),
383 "%s-remove\n", info->desc.name);
384
385 regulator_unregister(info->rdev);
386 }
387
388 return 0;
389}
390
391MODULE_LICENSE("GPL v2");
392MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>");
393MODULE_DESCRIPTION("AB8500 external regulator driver");
394MODULE_ALIAS("platform:ab8500-ext-regulator");