diff options
author | Linus Walleij <linus.walleij@stericsson.com> | 2009-09-09 05:31:00 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2009-09-17 03:47:25 -0400 |
commit | d619bc143e311a738113dbbe7792bd032403939f (patch) | |
tree | f5a7bebf4058761a223dba7ffc7057d70d17245b /drivers/regulator | |
parent | bd207cfb0011389d55827b3f3181c60e8c3c7148 (diff) |
regulator: AB3100 support
This adds support for the regulators found in the AB3100
Mixed-Signal IC.
It further also defines platform data for the ST-Ericsson
U300 platform and extends the AB3100 MFD driver so that
platform/board data with regulation constraints and an init
function can be passed down all the way from the board to
the regulators.
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/Kconfig | 9 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 | ||||
-rw-r--r-- | drivers/regulator/ab3100.c | 694 |
3 files changed, 704 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index c505714b0a98..2dc42bbf6fe9 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
@@ -138,5 +138,14 @@ config REGULATOR_MC13783 | |||
138 | Say y here to support the regulators found on the Freescale MC13783 | 138 | Say y here to support the regulators found on the Freescale MC13783 |
139 | PMIC. | 139 | PMIC. |
140 | 140 | ||
141 | config REGULATOR_AB3100 | ||
142 | tristate "ST-Ericsson AB3100 Regulator functions" | ||
143 | depends on AB3100_CORE | ||
144 | default y if AB3100_CORE | ||
145 | help | ||
146 | These regulators correspond to functionality in the | ||
147 | AB3100 analog baseband dealing with power regulators | ||
148 | for the system. | ||
149 | |||
141 | endif | 150 | endif |
142 | 151 | ||
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 5034830a395e..768b3316d6eb 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
@@ -21,5 +21,6 @@ obj-$(CONFIG_REGULATOR_DA903X) += da903x.o | |||
21 | obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o | 21 | obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o |
22 | obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o | 22 | obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o |
23 | obj-$(CONFIG_REGULATOR_MC13783) += mc13783.o | 23 | obj-$(CONFIG_REGULATOR_MC13783) += mc13783.o |
24 | obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o | ||
24 | 25 | ||
25 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG | 26 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG |
diff --git a/drivers/regulator/ab3100.c b/drivers/regulator/ab3100.c new file mode 100644 index 000000000000..156979d1f41e --- /dev/null +++ b/drivers/regulator/ab3100.c | |||
@@ -0,0 +1,694 @@ | |||
1 | /* | ||
2 | * drivers/regulator/ab3100.c | ||
3 | * | ||
4 | * Copyright (C) 2008-2009 ST-Ericsson AB | ||
5 | * License terms: GNU General Public License (GPL) version 2 | ||
6 | * Low-level control of the AB3100 IC Low Dropout (LDO) | ||
7 | * regulators, external regulator and buck converter | ||
8 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> | ||
9 | * Author: Linus Walleij <linus.walleij@stericsson.com> | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/regulator/driver.h> | ||
19 | #include <linux/mfd/ab3100.h> | ||
20 | |||
21 | /* LDO registers and some handy masking definitions for AB3100 */ | ||
22 | #define AB3100_LDO_A 0x40 | ||
23 | #define AB3100_LDO_C 0x41 | ||
24 | #define AB3100_LDO_D 0x42 | ||
25 | #define AB3100_LDO_E 0x43 | ||
26 | #define AB3100_LDO_E_SLEEP 0x44 | ||
27 | #define AB3100_LDO_F 0x45 | ||
28 | #define AB3100_LDO_G 0x46 | ||
29 | #define AB3100_LDO_H 0x47 | ||
30 | #define AB3100_LDO_H_SLEEP_MODE 0 | ||
31 | #define AB3100_LDO_H_SLEEP_EN 2 | ||
32 | #define AB3100_LDO_ON 4 | ||
33 | #define AB3100_LDO_H_VSEL_AC 5 | ||
34 | #define AB3100_LDO_K 0x48 | ||
35 | #define AB3100_LDO_EXT 0x49 | ||
36 | #define AB3100_BUCK 0x4A | ||
37 | #define AB3100_BUCK_SLEEP 0x4B | ||
38 | #define AB3100_REG_ON_MASK 0x10 | ||
39 | |||
40 | /** | ||
41 | * struct ab3100_regulator | ||
42 | * A struct passed around the individual regulator functions | ||
43 | * @platform_device: platform device holding this regulator | ||
44 | * @ab3100: handle to the AB3100 parent chip | ||
45 | * @plfdata: AB3100 platform data passed in at probe time | ||
46 | * @regreg: regulator register number in the AB3100 | ||
47 | * @fixed_voltage: a fixed voltage for this regulator, if this | ||
48 | * 0 the voltages array is used instead. | ||
49 | * @typ_voltages: an array of available typical voltages for | ||
50 | * this regulator | ||
51 | * @voltages_len: length of the array of available voltages | ||
52 | */ | ||
53 | struct ab3100_regulator { | ||
54 | struct regulator_dev *rdev; | ||
55 | struct ab3100 *ab3100; | ||
56 | struct ab3100_platform_data *plfdata; | ||
57 | u8 regreg; | ||
58 | int fixed_voltage; | ||
59 | int const *typ_voltages; | ||
60 | u8 voltages_len; | ||
61 | }; | ||
62 | |||
63 | /* The order in which registers are initialized */ | ||
64 | static const u8 ab3100_reg_init_order[AB3100_NUM_REGULATORS+2] = { | ||
65 | AB3100_LDO_A, | ||
66 | AB3100_LDO_C, | ||
67 | AB3100_LDO_E, | ||
68 | AB3100_LDO_E_SLEEP, | ||
69 | AB3100_LDO_F, | ||
70 | AB3100_LDO_G, | ||
71 | AB3100_LDO_H, | ||
72 | AB3100_LDO_K, | ||
73 | AB3100_LDO_EXT, | ||
74 | AB3100_BUCK, | ||
75 | AB3100_BUCK_SLEEP, | ||
76 | AB3100_LDO_D, | ||
77 | }; | ||
78 | |||
79 | /* Preset (hardware defined) voltages for these regulators */ | ||
80 | #define LDO_A_VOLTAGE 2750000 | ||
81 | #define LDO_C_VOLTAGE 2650000 | ||
82 | #define LDO_D_VOLTAGE 2650000 | ||
83 | |||
84 | static const int const ldo_e_buck_typ_voltages[] = { | ||
85 | 1800000, | ||
86 | 1400000, | ||
87 | 1300000, | ||
88 | 1200000, | ||
89 | 1100000, | ||
90 | 1050000, | ||
91 | 900000, | ||
92 | }; | ||
93 | |||
94 | static const int const ldo_f_typ_voltages[] = { | ||
95 | 1800000, | ||
96 | 1400000, | ||
97 | 1300000, | ||
98 | 1200000, | ||
99 | 1100000, | ||
100 | 1050000, | ||
101 | 2500000, | ||
102 | 2650000, | ||
103 | }; | ||
104 | |||
105 | static const int const ldo_g_typ_voltages[] = { | ||
106 | 2850000, | ||
107 | 2750000, | ||
108 | 1800000, | ||
109 | 1500000, | ||
110 | }; | ||
111 | |||
112 | static const int const ldo_h_typ_voltages[] = { | ||
113 | 2750000, | ||
114 | 1800000, | ||
115 | 1500000, | ||
116 | 1200000, | ||
117 | }; | ||
118 | |||
119 | static const int const ldo_k_typ_voltages[] = { | ||
120 | 2750000, | ||
121 | 1800000, | ||
122 | }; | ||
123 | |||
124 | |||
125 | /* The regulator devices */ | ||
126 | static struct ab3100_regulator | ||
127 | ab3100_regulators[AB3100_NUM_REGULATORS] = { | ||
128 | { | ||
129 | .regreg = AB3100_LDO_A, | ||
130 | .fixed_voltage = LDO_A_VOLTAGE, | ||
131 | }, | ||
132 | { | ||
133 | .regreg = AB3100_LDO_C, | ||
134 | .fixed_voltage = LDO_C_VOLTAGE, | ||
135 | }, | ||
136 | { | ||
137 | .regreg = AB3100_LDO_D, | ||
138 | .fixed_voltage = LDO_D_VOLTAGE, | ||
139 | }, | ||
140 | { | ||
141 | .regreg = AB3100_LDO_E, | ||
142 | .typ_voltages = ldo_e_buck_typ_voltages, | ||
143 | .voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages), | ||
144 | }, | ||
145 | { | ||
146 | .regreg = AB3100_LDO_F, | ||
147 | .typ_voltages = ldo_f_typ_voltages, | ||
148 | .voltages_len = ARRAY_SIZE(ldo_f_typ_voltages), | ||
149 | }, | ||
150 | { | ||
151 | .regreg = AB3100_LDO_G, | ||
152 | .typ_voltages = ldo_g_typ_voltages, | ||
153 | .voltages_len = ARRAY_SIZE(ldo_g_typ_voltages), | ||
154 | }, | ||
155 | { | ||
156 | .regreg = AB3100_LDO_H, | ||
157 | .typ_voltages = ldo_h_typ_voltages, | ||
158 | .voltages_len = ARRAY_SIZE(ldo_h_typ_voltages), | ||
159 | }, | ||
160 | { | ||
161 | .regreg = AB3100_LDO_K, | ||
162 | .typ_voltages = ldo_k_typ_voltages, | ||
163 | .voltages_len = ARRAY_SIZE(ldo_k_typ_voltages), | ||
164 | }, | ||
165 | { | ||
166 | .regreg = AB3100_LDO_EXT, | ||
167 | /* No voltages for the external regulator */ | ||
168 | }, | ||
169 | { | ||
170 | .regreg = AB3100_BUCK, | ||
171 | .typ_voltages = ldo_e_buck_typ_voltages, | ||
172 | .voltages_len = ARRAY_SIZE(ldo_e_buck_typ_voltages), | ||
173 | }, | ||
174 | }; | ||
175 | |||
176 | /* | ||
177 | * General functions for enable, disable and is_enabled used for | ||
178 | * LDO: A,C,E,F,G,H,K,EXT and BUCK | ||
179 | */ | ||
180 | static int ab3100_enable_regulator(struct regulator_dev *reg) | ||
181 | { | ||
182 | struct ab3100_regulator *abreg = reg->reg_data; | ||
183 | int err; | ||
184 | u8 regval; | ||
185 | |||
186 | err = ab3100_get_register_interruptible(abreg->ab3100, abreg->regreg, | ||
187 | ®val); | ||
188 | if (err) { | ||
189 | dev_warn(®->dev, "failed to get regid %d value\n", | ||
190 | abreg->regreg); | ||
191 | return err; | ||
192 | } | ||
193 | |||
194 | /* The regulator is already on, no reason to go further */ | ||
195 | if (regval & AB3100_REG_ON_MASK) | ||
196 | return 0; | ||
197 | |||
198 | regval |= AB3100_REG_ON_MASK; | ||
199 | |||
200 | err = ab3100_set_register_interruptible(abreg->ab3100, abreg->regreg, | ||
201 | regval); | ||
202 | if (err) { | ||
203 | dev_warn(®->dev, "failed to set regid %d value\n", | ||
204 | abreg->regreg); | ||
205 | return err; | ||
206 | } | ||
207 | |||
208 | /* Per-regulator power on delay from spec */ | ||
209 | switch (abreg->regreg) { | ||
210 | case AB3100_LDO_A: /* Fallthrough */ | ||
211 | case AB3100_LDO_C: /* Fallthrough */ | ||
212 | case AB3100_LDO_D: /* Fallthrough */ | ||
213 | case AB3100_LDO_E: /* Fallthrough */ | ||
214 | case AB3100_LDO_H: /* Fallthrough */ | ||
215 | case AB3100_LDO_K: | ||
216 | udelay(200); | ||
217 | break; | ||
218 | case AB3100_LDO_F: | ||
219 | udelay(600); | ||
220 | break; | ||
221 | case AB3100_LDO_G: | ||
222 | udelay(400); | ||
223 | break; | ||
224 | case AB3100_BUCK: | ||
225 | mdelay(1); | ||
226 | break; | ||
227 | default: | ||
228 | break; | ||
229 | } | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int ab3100_disable_regulator(struct regulator_dev *reg) | ||
235 | { | ||
236 | struct ab3100_regulator *abreg = reg->reg_data; | ||
237 | int err; | ||
238 | u8 regval; | ||
239 | |||
240 | /* | ||
241 | * LDO D is a special regulator. When it is disabled, the entire | ||
242 | * system is shut down. So this is handled specially. | ||
243 | */ | ||
244 | if (abreg->regreg == AB3100_LDO_D) { | ||
245 | int i; | ||
246 | |||
247 | dev_info(®->dev, "disabling LDO D - shut down system\n"); | ||
248 | /* | ||
249 | * Set regulators to default values, ignore any errors, | ||
250 | * we're going DOWN | ||
251 | */ | ||
252 | for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) { | ||
253 | (void) ab3100_set_register_interruptible(abreg->ab3100, | ||
254 | ab3100_reg_init_order[i], | ||
255 | abreg->plfdata->reg_initvals[i]); | ||
256 | } | ||
257 | |||
258 | /* Setting LDO D to 0x00 cuts the power to the SoC */ | ||
259 | return ab3100_set_register_interruptible(abreg->ab3100, | ||
260 | AB3100_LDO_D, 0x00U); | ||
261 | |||
262 | } | ||
263 | |||
264 | /* | ||
265 | * All other regulators are handled here | ||
266 | */ | ||
267 | err = ab3100_get_register_interruptible(abreg->ab3100, abreg->regreg, | ||
268 | ®val); | ||
269 | if (err) { | ||
270 | dev_err(®->dev, "unable to get register 0x%x\n", | ||
271 | abreg->regreg); | ||
272 | return err; | ||
273 | } | ||
274 | regval &= ~AB3100_REG_ON_MASK; | ||
275 | return ab3100_set_register_interruptible(abreg->ab3100, abreg->regreg, | ||
276 | regval); | ||
277 | } | ||
278 | |||
279 | static int ab3100_is_enabled_regulator(struct regulator_dev *reg) | ||
280 | { | ||
281 | struct ab3100_regulator *abreg = reg->reg_data; | ||
282 | u8 regval; | ||
283 | int err; | ||
284 | |||
285 | err = ab3100_get_register_interruptible(abreg->ab3100, abreg->regreg, | ||
286 | ®val); | ||
287 | if (err) { | ||
288 | dev_err(®->dev, "unable to get register 0x%x\n", | ||
289 | abreg->regreg); | ||
290 | return err; | ||
291 | } | ||
292 | |||
293 | return regval & AB3100_REG_ON_MASK; | ||
294 | } | ||
295 | |||
296 | static int ab3100_list_voltage_regulator(struct regulator_dev *reg, | ||
297 | unsigned selector) | ||
298 | { | ||
299 | struct ab3100_regulator *abreg = reg->reg_data; | ||
300 | |||
301 | if (selector > abreg->voltages_len) | ||
302 | return -EINVAL; | ||
303 | return abreg->typ_voltages[selector]; | ||
304 | } | ||
305 | |||
306 | static int ab3100_get_voltage_regulator(struct regulator_dev *reg) | ||
307 | { | ||
308 | struct ab3100_regulator *abreg = reg->reg_data; | ||
309 | u8 regval; | ||
310 | int err; | ||
311 | |||
312 | /* Return the voltage for fixed regulators immediately */ | ||
313 | if (abreg->fixed_voltage) | ||
314 | return abreg->fixed_voltage; | ||
315 | |||
316 | /* | ||
317 | * For variable types, read out setting and index into | ||
318 | * supplied voltage list. | ||
319 | */ | ||
320 | err = ab3100_get_register_interruptible(abreg->ab3100, | ||
321 | abreg->regreg, ®val); | ||
322 | if (err) { | ||
323 | dev_warn(®->dev, | ||
324 | "failed to get regulator value in register %02x\n", | ||
325 | abreg->regreg); | ||
326 | return err; | ||
327 | } | ||
328 | |||
329 | /* The 3 highest bits index voltages */ | ||
330 | regval &= 0xE0; | ||
331 | regval >>= 5; | ||
332 | |||
333 | if (regval > abreg->voltages_len) { | ||
334 | dev_err(®->dev, | ||
335 | "regulator register %02x contains an illegal voltage setting\n", | ||
336 | abreg->regreg); | ||
337 | return -EINVAL; | ||
338 | } | ||
339 | |||
340 | return abreg->typ_voltages[regval]; | ||
341 | } | ||
342 | |||
343 | static int ab3100_get_best_voltage_index(struct regulator_dev *reg, | ||
344 | int min_uV, int max_uV) | ||
345 | { | ||
346 | struct ab3100_regulator *abreg = reg->reg_data; | ||
347 | int i; | ||
348 | int bestmatch; | ||
349 | int bestindex; | ||
350 | |||
351 | /* | ||
352 | * Locate the minimum voltage fitting the criteria on | ||
353 | * this regulator. The switchable voltages are not | ||
354 | * in strict falling order so we need to check them | ||
355 | * all for the best match. | ||
356 | */ | ||
357 | bestmatch = INT_MAX; | ||
358 | bestindex = -1; | ||
359 | for (i = 0; i < abreg->voltages_len; i++) { | ||
360 | if (abreg->typ_voltages[i] <= max_uV && | ||
361 | abreg->typ_voltages[i] >= min_uV && | ||
362 | abreg->typ_voltages[i] < bestmatch) { | ||
363 | bestmatch = abreg->typ_voltages[i]; | ||
364 | bestindex = i; | ||
365 | } | ||
366 | } | ||
367 | |||
368 | if (bestindex < 0) { | ||
369 | dev_warn(®->dev, "requested %d<=x<=%d uV, out of range!\n", | ||
370 | min_uV, max_uV); | ||
371 | return -EINVAL; | ||
372 | } | ||
373 | return bestindex; | ||
374 | } | ||
375 | |||
376 | static int ab3100_set_voltage_regulator(struct regulator_dev *reg, | ||
377 | int min_uV, int max_uV) | ||
378 | { | ||
379 | struct ab3100_regulator *abreg = reg->reg_data; | ||
380 | u8 regval; | ||
381 | int err; | ||
382 | int bestindex; | ||
383 | |||
384 | bestindex = ab3100_get_best_voltage_index(reg, min_uV, max_uV); | ||
385 | if (bestindex < 0) | ||
386 | return bestindex; | ||
387 | |||
388 | err = ab3100_get_register_interruptible(abreg->ab3100, | ||
389 | abreg->regreg, ®val); | ||
390 | if (err) { | ||
391 | dev_warn(®->dev, | ||
392 | "failed to get regulator register %02x\n", | ||
393 | abreg->regreg); | ||
394 | return err; | ||
395 | } | ||
396 | |||
397 | /* The highest three bits control the variable regulators */ | ||
398 | regval &= ~0xE0; | ||
399 | regval |= (bestindex << 5); | ||
400 | |||
401 | err = ab3100_set_register_interruptible(abreg->ab3100, | ||
402 | abreg->regreg, regval); | ||
403 | if (err) | ||
404 | dev_warn(®->dev, "failed to set regulator register %02x\n", | ||
405 | abreg->regreg); | ||
406 | |||
407 | return err; | ||
408 | } | ||
409 | |||
410 | static int ab3100_set_suspend_voltage_regulator(struct regulator_dev *reg, | ||
411 | int uV) | ||
412 | { | ||
413 | struct ab3100_regulator *abreg = reg->reg_data; | ||
414 | u8 regval; | ||
415 | int err; | ||
416 | int bestindex; | ||
417 | u8 targetreg; | ||
418 | |||
419 | if (abreg->regreg == AB3100_LDO_E) | ||
420 | targetreg = AB3100_LDO_E_SLEEP; | ||
421 | else if (abreg->regreg == AB3100_BUCK) | ||
422 | targetreg = AB3100_BUCK_SLEEP; | ||
423 | else | ||
424 | return -EINVAL; | ||
425 | |||
426 | /* LDO E and BUCK have special suspend voltages you can set */ | ||
427 | bestindex = ab3100_get_best_voltage_index(reg, uV, uV); | ||
428 | |||
429 | err = ab3100_get_register_interruptible(abreg->ab3100, | ||
430 | targetreg, ®val); | ||
431 | if (err) { | ||
432 | dev_warn(®->dev, | ||
433 | "failed to get regulator register %02x\n", | ||
434 | targetreg); | ||
435 | return err; | ||
436 | } | ||
437 | |||
438 | /* The highest three bits control the variable regulators */ | ||
439 | regval &= ~0xE0; | ||
440 | regval |= (bestindex << 5); | ||
441 | |||
442 | err = ab3100_set_register_interruptible(abreg->ab3100, | ||
443 | targetreg, regval); | ||
444 | if (err) | ||
445 | dev_warn(®->dev, "failed to set regulator register %02x\n", | ||
446 | abreg->regreg); | ||
447 | |||
448 | return err; | ||
449 | } | ||
450 | |||
451 | /* | ||
452 | * The external regulator can just define a fixed voltage. | ||
453 | */ | ||
454 | static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg) | ||
455 | { | ||
456 | struct ab3100_regulator *abreg = reg->reg_data; | ||
457 | |||
458 | return abreg->plfdata->external_voltage; | ||
459 | } | ||
460 | |||
461 | static struct regulator_ops regulator_ops_fixed = { | ||
462 | .enable = ab3100_enable_regulator, | ||
463 | .disable = ab3100_disable_regulator, | ||
464 | .is_enabled = ab3100_is_enabled_regulator, | ||
465 | .get_voltage = ab3100_get_voltage_regulator, | ||
466 | }; | ||
467 | |||
468 | static struct regulator_ops regulator_ops_variable = { | ||
469 | .enable = ab3100_enable_regulator, | ||
470 | .disable = ab3100_disable_regulator, | ||
471 | .is_enabled = ab3100_is_enabled_regulator, | ||
472 | .get_voltage = ab3100_get_voltage_regulator, | ||
473 | .set_voltage = ab3100_set_voltage_regulator, | ||
474 | .list_voltage = ab3100_list_voltage_regulator, | ||
475 | }; | ||
476 | |||
477 | static struct regulator_ops regulator_ops_variable_sleepable = { | ||
478 | .enable = ab3100_enable_regulator, | ||
479 | .disable = ab3100_disable_regulator, | ||
480 | .is_enabled = ab3100_is_enabled_regulator, | ||
481 | .get_voltage = ab3100_get_voltage_regulator, | ||
482 | .set_voltage = ab3100_set_voltage_regulator, | ||
483 | .set_suspend_voltage = ab3100_set_suspend_voltage_regulator, | ||
484 | .list_voltage = ab3100_list_voltage_regulator, | ||
485 | }; | ||
486 | |||
487 | /* | ||
488 | * LDO EXT is an external regulator so it is really | ||
489 | * not possible to set any voltage locally here, AB3100 | ||
490 | * is an on/off switch plain an simple. The external | ||
491 | * voltage is defined in the board set-up if any. | ||
492 | */ | ||
493 | static struct regulator_ops regulator_ops_external = { | ||
494 | .enable = ab3100_enable_regulator, | ||
495 | .disable = ab3100_disable_regulator, | ||
496 | .is_enabled = ab3100_is_enabled_regulator, | ||
497 | .get_voltage = ab3100_get_voltage_regulator_external, | ||
498 | }; | ||
499 | |||
500 | static struct regulator_desc | ||
501 | ab3100_regulator_desc[AB3100_NUM_REGULATORS] = { | ||
502 | { | ||
503 | .name = "LDO_A", | ||
504 | .id = AB3100_LDO_A, | ||
505 | .ops = ®ulator_ops_fixed, | ||
506 | .type = REGULATOR_VOLTAGE, | ||
507 | }, | ||
508 | { | ||
509 | .name = "LDO_C", | ||
510 | .id = AB3100_LDO_C, | ||
511 | .ops = ®ulator_ops_fixed, | ||
512 | .type = REGULATOR_VOLTAGE, | ||
513 | }, | ||
514 | { | ||
515 | .name = "LDO_D", | ||
516 | .id = AB3100_LDO_D, | ||
517 | .ops = ®ulator_ops_fixed, | ||
518 | .type = REGULATOR_VOLTAGE, | ||
519 | }, | ||
520 | { | ||
521 | .name = "LDO_E", | ||
522 | .id = AB3100_LDO_E, | ||
523 | .ops = ®ulator_ops_variable_sleepable, | ||
524 | .type = REGULATOR_VOLTAGE, | ||
525 | }, | ||
526 | { | ||
527 | .name = "LDO_F", | ||
528 | .id = AB3100_LDO_F, | ||
529 | .ops = ®ulator_ops_variable, | ||
530 | .type = REGULATOR_VOLTAGE, | ||
531 | }, | ||
532 | { | ||
533 | .name = "LDO_G", | ||
534 | .id = AB3100_LDO_G, | ||
535 | .ops = ®ulator_ops_variable, | ||
536 | .type = REGULATOR_VOLTAGE, | ||
537 | }, | ||
538 | { | ||
539 | .name = "LDO_H", | ||
540 | .id = AB3100_LDO_H, | ||
541 | .ops = ®ulator_ops_variable, | ||
542 | .type = REGULATOR_VOLTAGE, | ||
543 | }, | ||
544 | { | ||
545 | .name = "LDO_K", | ||
546 | .id = AB3100_LDO_K, | ||
547 | .ops = ®ulator_ops_variable, | ||
548 | .type = REGULATOR_VOLTAGE, | ||
549 | }, | ||
550 | { | ||
551 | .name = "LDO_EXT", | ||
552 | .id = AB3100_LDO_EXT, | ||
553 | .ops = ®ulator_ops_external, | ||
554 | .type = REGULATOR_VOLTAGE, | ||
555 | }, | ||
556 | { | ||
557 | .name = "BUCK", | ||
558 | .id = AB3100_BUCK, | ||
559 | .ops = ®ulator_ops_variable_sleepable, | ||
560 | .type = REGULATOR_VOLTAGE, | ||
561 | }, | ||
562 | }; | ||
563 | |||
564 | /* | ||
565 | * NOTE: the following functions are regulators pluralis - it is the | ||
566 | * binding to the AB3100 core driver and the parent platform device | ||
567 | * for all the different regulators. | ||
568 | */ | ||
569 | |||
570 | static int __init ab3100_regulators_probe(struct platform_device *pdev) | ||
571 | { | ||
572 | struct ab3100_platform_data *plfdata = pdev->dev.platform_data; | ||
573 | struct ab3100 *ab3100 = platform_get_drvdata(pdev); | ||
574 | int err = 0; | ||
575 | u8 data; | ||
576 | int i; | ||
577 | |||
578 | /* Check chip state */ | ||
579 | err = ab3100_get_register_interruptible(ab3100, | ||
580 | AB3100_LDO_D, &data); | ||
581 | if (err) { | ||
582 | dev_err(&pdev->dev, "could not read initial status of LDO_D\n"); | ||
583 | return err; | ||
584 | } | ||
585 | if (data & 0x10) | ||
586 | dev_notice(&pdev->dev, | ||
587 | "chip is already in active mode (Warm start)\n"); | ||
588 | else | ||
589 | dev_notice(&pdev->dev, | ||
590 | "chip is in inactive mode (Cold start)\n"); | ||
591 | |||
592 | /* Set up regulators */ | ||
593 | for (i = 0; i < ARRAY_SIZE(ab3100_reg_init_order); i++) { | ||
594 | err = ab3100_set_register_interruptible(ab3100, | ||
595 | ab3100_reg_init_order[i], | ||
596 | plfdata->reg_initvals[i]); | ||
597 | if (err) { | ||
598 | dev_err(&pdev->dev, "regulator initialization failed with error %d\n", | ||
599 | err); | ||
600 | return err; | ||
601 | } | ||
602 | } | ||
603 | |||
604 | if (err) { | ||
605 | dev_err(&pdev->dev, | ||
606 | "LDO D regulator initialization failed with error %d\n", | ||
607 | err); | ||
608 | return err; | ||
609 | } | ||
610 | |||
611 | /* Register the regulators */ | ||
612 | for (i = 0; i < AB3100_NUM_REGULATORS; i++) { | ||
613 | struct ab3100_regulator *reg = &ab3100_regulators[i]; | ||
614 | struct regulator_dev *rdev; | ||
615 | |||
616 | /* | ||
617 | * Initialize per-regulator struct. | ||
618 | * Inherit platform data, this comes down from the | ||
619 | * i2c boarddata, from the machine. So if you want to | ||
620 | * see what it looks like for a certain machine, go | ||
621 | * into the machine I2C setup. | ||
622 | */ | ||
623 | reg->ab3100 = ab3100; | ||
624 | reg->plfdata = plfdata; | ||
625 | |||
626 | /* | ||
627 | * Register the regulator, pass around | ||
628 | * the ab3100_regulator struct | ||
629 | */ | ||
630 | rdev = regulator_register(&ab3100_regulator_desc[i], | ||
631 | &pdev->dev, | ||
632 | &plfdata->reg_constraints[i], | ||
633 | reg); | ||
634 | |||
635 | if (IS_ERR(rdev)) { | ||
636 | err = PTR_ERR(rdev); | ||
637 | dev_err(&pdev->dev, | ||
638 | "%s: failed to register regulator %s err %d\n", | ||
639 | __func__, ab3100_regulator_desc[i].name, | ||
640 | err); | ||
641 | i--; | ||
642 | /* remove the already registered regulators */ | ||
643 | while (i > 0) { | ||
644 | regulator_unregister(ab3100_regulators[i].rdev); | ||
645 | i--; | ||
646 | } | ||
647 | return err; | ||
648 | } | ||
649 | |||
650 | /* Then set a pointer back to the registered regulator */ | ||
651 | reg->rdev = rdev; | ||
652 | } | ||
653 | |||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | static int __exit ab3100_regulators_remove(struct platform_device *pdev) | ||
658 | { | ||
659 | int i; | ||
660 | |||
661 | for (i = 0; i < AB3100_NUM_REGULATORS; i++) { | ||
662 | struct ab3100_regulator *reg = &ab3100_regulators[i]; | ||
663 | |||
664 | regulator_unregister(reg->rdev); | ||
665 | } | ||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | static struct platform_driver ab3100_regulators_driver = { | ||
670 | .driver = { | ||
671 | .name = "ab3100-regulators", | ||
672 | .owner = THIS_MODULE, | ||
673 | }, | ||
674 | .probe = ab3100_regulators_probe, | ||
675 | .remove = __exit_p(ab3100_regulators_remove), | ||
676 | }; | ||
677 | |||
678 | static __init int ab3100_regulators_init(void) | ||
679 | { | ||
680 | return platform_driver_register(&ab3100_regulators_driver); | ||
681 | } | ||
682 | |||
683 | static __exit void ab3100_regulators_exit(void) | ||
684 | { | ||
685 | platform_driver_register(&ab3100_regulators_driver); | ||
686 | } | ||
687 | |||
688 | subsys_initcall(ab3100_regulators_init); | ||
689 | module_exit(ab3100_regulators_exit); | ||
690 | |||
691 | MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>"); | ||
692 | MODULE_DESCRIPTION("AB3100 Regulator driver"); | ||
693 | MODULE_LICENSE("GPL"); | ||
694 | MODULE_ALIAS("platform:ab3100-regulators"); | ||