aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/ab8500-ext.c394
-rw-r--r--drivers/regulator/ab8500.c12
-rw-r--r--include/linux/regulator/ab8500.h28
4 files changed, 434 insertions, 2 deletions
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 6e8250382def..47a34ff88f98 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
12obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o 12obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
13obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o 13obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
14obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o 14obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o
15obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o 15obj-$(CONFIG_REGULATOR_AB8500) += ab8500.o ab8500-ext.o
16obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o 16obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
17obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o 17obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o
18obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o 18obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
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");
diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c
index 3a1896655557..49746884923d 100644
--- a/drivers/regulator/ab8500.c
+++ b/drivers/regulator/ab8500.c
@@ -947,6 +947,11 @@ static int ab8500_regulator_probe(struct platform_device *pdev)
947 return err; 947 return err;
948 } 948 }
949 949
950 /* register external regulators (before Vaux1, 2 and 3) */
951 err = ab8500_ext_regulator_init(pdev);
952 if (err)
953 return err;
954
950 /* register all regulators */ 955 /* register all regulators */
951 for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { 956 for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
952 err = ab8500_regulator_register(pdev, &pdata->regulator[i], i, NULL); 957 err = ab8500_regulator_register(pdev, &pdata->regulator[i], i, NULL);
@@ -959,7 +964,7 @@ static int ab8500_regulator_probe(struct platform_device *pdev)
959 964
960static int ab8500_regulator_remove(struct platform_device *pdev) 965static int ab8500_regulator_remove(struct platform_device *pdev)
961{ 966{
962 int i; 967 int i, err;
963 968
964 for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) { 969 for (i = 0; i < ARRAY_SIZE(ab8500_regulator_info); i++) {
965 struct ab8500_regulator_info *info = NULL; 970 struct ab8500_regulator_info *info = NULL;
@@ -971,6 +976,11 @@ static int ab8500_regulator_remove(struct platform_device *pdev)
971 regulator_unregister(info->regulator); 976 regulator_unregister(info->regulator);
972 } 977 }
973 978
979 /* remove external regulators (after Vaux1, 2 and 3) */
980 err = ab8500_ext_regulator_exit(pdev);
981 if (err)
982 return err;
983
974 return 0; 984 return 0;
975} 985}
976 986
diff --git a/include/linux/regulator/ab8500.h b/include/linux/regulator/ab8500.h
index 26792ff360be..4e92e5b879a5 100644
--- a/include/linux/regulator/ab8500.h
+++ b/include/linux/regulator/ab8500.h
@@ -10,6 +10,8 @@
10#ifndef __LINUX_MFD_AB8500_REGULATOR_H 10#ifndef __LINUX_MFD_AB8500_REGULATOR_H
11#define __LINUX_MFD_AB8500_REGULATOR_H 11#define __LINUX_MFD_AB8500_REGULATOR_H
12 12
13#include <linux/platform_device.h>
14
13/* AB8500 regulators */ 15/* AB8500 regulators */
14enum ab8500_regulator_id { 16enum ab8500_regulator_id {
15 AB8500_LDO_AUX1, 17 AB8500_LDO_AUX1,
@@ -140,11 +142,37 @@ enum ab9540_regulator_reg {
140 AB9540_NUM_REGULATOR_REGISTERS, 142 AB9540_NUM_REGULATOR_REGISTERS,
141}; 143};
142 144
145/* AB8500 external regulators */
146enum ab8500_ext_regulator_id {
147 AB8500_EXT_SUPPLY1,
148 AB8500_EXT_SUPPLY2,
149 AB8500_EXT_SUPPLY3,
150 AB8500_NUM_EXT_REGULATORS,
151};
152
153/* AB8500 regulator platform data */
143struct ab8500_regulator_platform_data { 154struct ab8500_regulator_platform_data {
144 int num_reg_init; 155 int num_reg_init;
145 struct ab8500_regulator_reg_init *reg_init; 156 struct ab8500_regulator_reg_init *reg_init;
146 int num_regulator; 157 int num_regulator;
147 struct regulator_init_data *regulator; 158 struct regulator_init_data *regulator;
159 int num_ext_regulator;
160 struct regulator_init_data *ext_regulator;
148}; 161};
149 162
163/* AB8500 external regulator functions (internal) */
164#ifdef CONFIG_REGULATOR_AB8500_EXT
165int ab8500_ext_regulator_init(struct platform_device *pdev);
166int ab8500_ext_regulator_exit(struct platform_device *pdev);
167#else
168inline int ab8500_ext_regulator_init(struct platform_device *pdev)
169{
170 return 0;
171}
172inline int ab8500_ext_regulator_exit(struct platform_device *pdev)
173{
174 return 0;
175}
176#endif
177
150#endif 178#endif