diff options
author | Haojian Zhuang <haojian.zhuang@gmail.com> | 2009-10-08 02:03:57 -0400 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2009-12-17 05:27:23 -0500 |
commit | be0e2d3e802908e2a3ca620ba8f49ecab87982b2 (patch) | |
tree | 6d2303274e79bc660fc0cfd05c6247e2a0413164 /drivers | |
parent | e24a04c44cf312e88b50006a91ad7ffc1c0d97a5 (diff) |
regulator: add 88PM8607 PMIC driver
Hi Liam,
Since Samuel merged a new version of mfd 88pm8607 driver, I format a
new patch on regulator 88pm8607. I paste the new patch in mail. Please
help to review again. And I also attach the mfd driver in mail.
From: Haojian Zhuang <haojian.zhuang@marvell.com>
Date: Thu, 8 Oct 2009 09:36:53 -0400
Subject: [PATCH] regulator: Add 88PM8607 PMIC driver
This patch adds regulator drivers for Marvell 88PM8607 PMIC.
This controller contains 3 DVC and 14 LDO regulators. This controller
uses I2C interface.
Signed-off-by: Haojian Zhuang <haojian.zhuang@marvell.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/regulator/88pm8607.c | 684 | ||||
-rw-r--r-- | drivers/regulator/Kconfig | 6 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 1 |
3 files changed, 691 insertions, 0 deletions
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c new file mode 100644 index 000000000000..e1aabdaabf23 --- /dev/null +++ b/drivers/regulator/88pm8607.c | |||
@@ -0,0 +1,684 @@ | |||
1 | /* | ||
2 | * Regulators driver for Marvell 88PM8607 | ||
3 | * | ||
4 | * Copyright (C) 2009 Marvell International Ltd. | ||
5 | * Haojian Zhuang <haojian.zhuang@marvell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/regulator/driver.h> | ||
16 | #include <linux/regulator/machine.h> | ||
17 | #include <linux/mfd/88pm8607.h> | ||
18 | |||
19 | struct pm8607_regulator_info { | ||
20 | struct regulator_desc desc; | ||
21 | struct pm8607_chip *chip; | ||
22 | struct regulator_dev *regulator; | ||
23 | |||
24 | int min_uV; | ||
25 | int max_uV; | ||
26 | int step_uV; | ||
27 | int vol_reg; | ||
28 | int vol_shift; | ||
29 | int vol_nbits; | ||
30 | int update_reg; | ||
31 | int update_bit; | ||
32 | int enable_reg; | ||
33 | int enable_bit; | ||
34 | int slope_double; | ||
35 | }; | ||
36 | |||
37 | static inline int check_range(struct pm8607_regulator_info *info, | ||
38 | int min_uV, int max_uV) | ||
39 | { | ||
40 | if (max_uV < info->min_uV || min_uV > info->max_uV || min_uV > max_uV) | ||
41 | return -EINVAL; | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) | ||
47 | { | ||
48 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
49 | uint8_t chip_id = info->chip->chip_id; | ||
50 | int ret = -EINVAL; | ||
51 | |||
52 | switch (info->desc.id) { | ||
53 | case PM8607_ID_BUCK1: | ||
54 | ret = (index < 0x1d) ? (index * 25000 + 800000) : | ||
55 | ((index < 0x20) ? 1500000 : | ||
56 | ((index < 0x40) ? ((index - 0x20) * 25000) : | ||
57 | -EINVAL)); | ||
58 | break; | ||
59 | case PM8607_ID_BUCK3: | ||
60 | ret = (index < 0x3d) ? (index * 25000) : | ||
61 | ((index < 0x40) ? 1500000 : -EINVAL); | ||
62 | if (ret < 0) | ||
63 | break; | ||
64 | if (info->slope_double) | ||
65 | ret <<= 1; | ||
66 | break; | ||
67 | case PM8607_ID_LDO1: | ||
68 | ret = (index == 0) ? 1800000 : | ||
69 | ((index == 1) ? 1200000 : | ||
70 | ((index == 2) ? 2800000 : -EINVAL)); | ||
71 | break; | ||
72 | case PM8607_ID_LDO5: | ||
73 | ret = (index == 0) ? 2900000 : | ||
74 | ((index == 1) ? 3000000 : | ||
75 | ((index == 2) ? 3100000 : 3300000)); | ||
76 | break; | ||
77 | case PM8607_ID_LDO7: | ||
78 | case PM8607_ID_LDO8: | ||
79 | ret = (index < 3) ? (index * 50000 + 1800000) : | ||
80 | ((index < 8) ? (index * 50000 + 2550000) : | ||
81 | -EINVAL); | ||
82 | break; | ||
83 | case PM8607_ID_LDO12: | ||
84 | ret = (index < 2) ? (index * 100000 + 1800000) : | ||
85 | ((index < 7) ? (index * 100000 + 2500000) : | ||
86 | ((index == 7) ? 3300000 : 1200000)); | ||
87 | break; | ||
88 | case PM8607_ID_LDO2: | ||
89 | case PM8607_ID_LDO3: | ||
90 | case PM8607_ID_LDO9: | ||
91 | switch (chip_id) { | ||
92 | case PM8607_CHIP_A0: | ||
93 | case PM8607_CHIP_A1: | ||
94 | ret = (index < 3) ? (index * 50000 + 1800000) : | ||
95 | ((index < 8) ? (index * 50000 + 2550000) : | ||
96 | -EINVAL); | ||
97 | break; | ||
98 | case PM8607_CHIP_B0: | ||
99 | ret = (index < 3) ? (index * 50000 + 1800000) : | ||
100 | ((index < 7) ? (index * 50000 + 2550000) : | ||
101 | 3300000); | ||
102 | break; | ||
103 | } | ||
104 | break; | ||
105 | case PM8607_ID_LDO4: | ||
106 | switch (chip_id) { | ||
107 | case PM8607_CHIP_A0: | ||
108 | case PM8607_CHIP_A1: | ||
109 | ret = (index < 3) ? (index * 50000 + 1800000) : | ||
110 | ((index < 8) ? (index * 50000 + 2550000) : | ||
111 | -EINVAL); | ||
112 | break; | ||
113 | case PM8607_CHIP_B0: | ||
114 | ret = (index < 3) ? (index * 50000 + 1800000) : | ||
115 | ((index < 6) ? (index * 50000 + 2550000) : | ||
116 | ((index == 6) ? 2900000 : 3300000)); | ||
117 | break; | ||
118 | } | ||
119 | break; | ||
120 | case PM8607_ID_LDO6: | ||
121 | switch (chip_id) { | ||
122 | case PM8607_CHIP_A0: | ||
123 | case PM8607_CHIP_A1: | ||
124 | ret = (index < 3) ? (index * 50000 + 1800000) : | ||
125 | ((index < 8) ? (index * 50000 + 2450000) : | ||
126 | -EINVAL); | ||
127 | break; | ||
128 | case PM8607_CHIP_B0: | ||
129 | ret = (index < 2) ? (index * 50000 + 1800000) : | ||
130 | ((index < 7) ? (index * 50000 + 2500000) : | ||
131 | 3300000); | ||
132 | break; | ||
133 | } | ||
134 | break; | ||
135 | case PM8607_ID_LDO10: | ||
136 | switch (chip_id) { | ||
137 | case PM8607_CHIP_A0: | ||
138 | case PM8607_CHIP_A1: | ||
139 | ret = (index < 3) ? (index * 50000 + 1800000) : | ||
140 | ((index < 8) ? (index * 50000 + 2550000) : | ||
141 | 1200000); | ||
142 | break; | ||
143 | case PM8607_CHIP_B0: | ||
144 | ret = (index < 3) ? (index * 50000 + 1800000) : | ||
145 | ((index < 7) ? (index * 50000 + 2550000) : | ||
146 | ((index == 7) ? 3300000 : 1200000)); | ||
147 | break; | ||
148 | } | ||
149 | break; | ||
150 | case PM8607_ID_LDO14: | ||
151 | switch (chip_id) { | ||
152 | case PM8607_CHIP_A0: | ||
153 | case PM8607_CHIP_A1: | ||
154 | ret = (index < 3) ? (index * 50000 + 1800000) : | ||
155 | ((index < 8) ? (index * 50000 + 2550000) : | ||
156 | -EINVAL); | ||
157 | break; | ||
158 | case PM8607_CHIP_B0: | ||
159 | ret = (index < 2) ? (index * 50000 + 1800000) : | ||
160 | ((index < 7) ? (index * 50000 + 2600000) : | ||
161 | 3300000); | ||
162 | break; | ||
163 | } | ||
164 | break; | ||
165 | } | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV) | ||
170 | { | ||
171 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
172 | uint8_t chip_id = info->chip->chip_id; | ||
173 | int val, ret; | ||
174 | |||
175 | switch (info->desc.id) { | ||
176 | case PM8607_ID_BUCK1: | ||
177 | if (min_uV >= 800000) /* 800mV ~ 1500mV / 25mV */ | ||
178 | val = (min_uV - 775001) / 25000; | ||
179 | else { /* 25mV ~ 775mV / 25mV */ | ||
180 | val = (min_uV + 249999) / 25000; | ||
181 | val += 32; | ||
182 | } | ||
183 | break; | ||
184 | case PM8607_ID_BUCK3: | ||
185 | if (info->slope_double) | ||
186 | min_uV = min_uV >> 1; | ||
187 | val = (min_uV + 249999) / 25000; /* 0mV ~ 1500mV / 25mV */ | ||
188 | |||
189 | break; | ||
190 | case PM8607_ID_LDO1: | ||
191 | if (min_uV > 1800000) | ||
192 | val = 2; | ||
193 | else if (min_uV > 1200000) | ||
194 | val = 0; | ||
195 | else | ||
196 | val = 1; | ||
197 | break; | ||
198 | case PM8607_ID_LDO5: | ||
199 | if (min_uV > 3100000) | ||
200 | val = 3; | ||
201 | else /* 2900mV ~ 3100mV / 100mV */ | ||
202 | val = (min_uV - 2800001) / 100000; | ||
203 | break; | ||
204 | case PM8607_ID_LDO7: | ||
205 | case PM8607_ID_LDO8: | ||
206 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ | ||
207 | if (min_uV <= 1800000) | ||
208 | val = 0; /* 1800mv */ | ||
209 | else if (min_uV <= 1900000) | ||
210 | val = (min_uV - 1750001) / 50000; | ||
211 | else | ||
212 | val = 3; /* 2700mV */ | ||
213 | } else { /* 2700mV ~ 2900mV / 50mV */ | ||
214 | if (min_uV <= 2900000) { | ||
215 | val = (min_uV - 2650001) / 50000; | ||
216 | val += 3; | ||
217 | } else | ||
218 | val = -EINVAL; | ||
219 | } | ||
220 | break; | ||
221 | case PM8607_ID_LDO10: | ||
222 | if (min_uV > 2850000) | ||
223 | val = 7; | ||
224 | else if (min_uV <= 1200000) | ||
225 | val = 8; | ||
226 | else if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ | ||
227 | val = (min_uV - 1750001) / 50000; | ||
228 | else { /* 2700mV ~ 2850mV / 50mV */ | ||
229 | val = (min_uV - 2650001) / 50000; | ||
230 | val += 3; | ||
231 | } | ||
232 | break; | ||
233 | case PM8607_ID_LDO12: | ||
234 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 100mV */ | ||
235 | if (min_uV <= 1200000) | ||
236 | val = 8; /* 1200mV */ | ||
237 | else if (min_uV <= 1800000) | ||
238 | val = 0; /* 1800mV */ | ||
239 | else if (min_uV <= 1900000) | ||
240 | val = (min_uV - 1700001) / 100000; | ||
241 | else | ||
242 | val = 2; /* 2700mV */ | ||
243 | } else { /* 2700mV ~ 3100mV / 100mV */ | ||
244 | if (min_uV <= 3100000) { | ||
245 | val = (min_uV - 2600001) / 100000; | ||
246 | val += 2; | ||
247 | } else if (min_uV <= 3300000) | ||
248 | val = 7; | ||
249 | else | ||
250 | val = -EINVAL; | ||
251 | } | ||
252 | break; | ||
253 | case PM8607_ID_LDO2: | ||
254 | case PM8607_ID_LDO3: | ||
255 | case PM8607_ID_LDO9: | ||
256 | switch (chip_id) { | ||
257 | case PM8607_CHIP_A0: | ||
258 | case PM8607_CHIP_A1: | ||
259 | if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ | ||
260 | if (min_uV <= 1800000) | ||
261 | val = 0; | ||
262 | else if (min_uV <= 1900000) | ||
263 | val = (min_uV - 1750001) / 50000; | ||
264 | else | ||
265 | val = 3; /* 2700mV */ | ||
266 | else { /* 2700mV ~ 2900mV / 50mV */ | ||
267 | if (min_uV <= 2900000) { | ||
268 | val = (min_uV - 2650001) / 50000; | ||
269 | val += 3; | ||
270 | } else | ||
271 | val = -EINVAL; | ||
272 | } | ||
273 | break; | ||
274 | case PM8607_CHIP_B0: | ||
275 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ | ||
276 | if (min_uV <= 1800000) | ||
277 | val = 0; | ||
278 | else if (min_uV <= 1900000) | ||
279 | val = (min_uV - 1750001) / 50000; | ||
280 | else | ||
281 | val = 3; /* 2700mV */ | ||
282 | } else { /* 2700mV ~ 2850mV / 50mV */ | ||
283 | if (min_uV <= 2850000) { | ||
284 | val = (min_uV - 2650001) / 50000; | ||
285 | val += 3; | ||
286 | } else if (min_uV <= 3300000) | ||
287 | val = 7; | ||
288 | else | ||
289 | val = -EINVAL; | ||
290 | } | ||
291 | break; | ||
292 | } | ||
293 | break; | ||
294 | case PM8607_ID_LDO4: | ||
295 | switch (chip_id) { | ||
296 | case PM8607_CHIP_A0: | ||
297 | case PM8607_CHIP_A1: | ||
298 | if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ | ||
299 | if (min_uV <= 1800000) | ||
300 | val = 0; | ||
301 | else if (min_uV <= 1900000) | ||
302 | val = (min_uV - 1750001) / 50000; | ||
303 | else | ||
304 | val = 3; /* 2700mV */ | ||
305 | else { /* 2700mV ~ 2900mV / 50mV */ | ||
306 | if (min_uV <= 2900000) { | ||
307 | val = (min_uV - 2650001) / 50000; | ||
308 | val += 3; | ||
309 | } else | ||
310 | val = -EINVAL; | ||
311 | } | ||
312 | break; | ||
313 | case PM8607_CHIP_B0: | ||
314 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ | ||
315 | if (min_uV <= 1800000) | ||
316 | val = 0; | ||
317 | else if (min_uV <= 1900000) | ||
318 | val = (min_uV - 1750001) / 50000; | ||
319 | else | ||
320 | val = 3; /* 2700mV */ | ||
321 | } else { /* 2700mV ~ 2800mV / 50mV */ | ||
322 | if (min_uV <= 2850000) { | ||
323 | val = (min_uV - 2650001) / 50000; | ||
324 | val += 3; | ||
325 | } else if (min_uV <= 2900000) | ||
326 | val = 6; | ||
327 | else if (min_uV <= 3300000) | ||
328 | val = 7; | ||
329 | else | ||
330 | val = -EINVAL; | ||
331 | } | ||
332 | break; | ||
333 | } | ||
334 | break; | ||
335 | case PM8607_ID_LDO6: | ||
336 | switch (chip_id) { | ||
337 | case PM8607_CHIP_A0: | ||
338 | case PM8607_CHIP_A1: | ||
339 | if (min_uV < 2600000) { /* 1800mV ~ 1900mV / 50mV */ | ||
340 | if (min_uV <= 1800000) | ||
341 | val = 0; | ||
342 | else if (min_uV <= 1900000) | ||
343 | val = (min_uV - 1750001) / 50000; | ||
344 | else | ||
345 | val = 3; /* 2600mV */ | ||
346 | } else { /* 2600mV ~ 2800mV / 50mV */ | ||
347 | if (min_uV <= 2800000) { | ||
348 | val = (min_uV - 2550001) / 50000; | ||
349 | val += 3; | ||
350 | } else | ||
351 | val = -EINVAL; | ||
352 | } | ||
353 | break; | ||
354 | case PM8607_CHIP_B0: | ||
355 | if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */ | ||
356 | if (min_uV <= 1800000) | ||
357 | val = 0; | ||
358 | else if (min_uV <= 1850000) | ||
359 | val = (min_uV - 1750001) / 50000; | ||
360 | else | ||
361 | val = 2; /* 2600mV */ | ||
362 | } else { /* 2600mV ~ 2800mV / 50mV */ | ||
363 | if (min_uV <= 2800000) { | ||
364 | val = (min_uV - 2550001) / 50000; | ||
365 | val += 2; | ||
366 | } else if (min_uV <= 3300000) | ||
367 | val = 7; | ||
368 | else | ||
369 | val = -EINVAL; | ||
370 | } | ||
371 | break; | ||
372 | } | ||
373 | break; | ||
374 | case PM8607_ID_LDO14: | ||
375 | switch (chip_id) { | ||
376 | case PM8607_CHIP_A0: | ||
377 | case PM8607_CHIP_A1: | ||
378 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ | ||
379 | if (min_uV <= 1800000) | ||
380 | val = 0; | ||
381 | else if (min_uV <= 1900000) | ||
382 | val = (min_uV - 1750001) / 50000; | ||
383 | else | ||
384 | val = 3; /* 2700mV */ | ||
385 | } else { /* 2700mV ~ 2900mV / 50mV */ | ||
386 | if (min_uV <= 2900000) { | ||
387 | val = (min_uV - 2650001) / 50000; | ||
388 | val += 3; | ||
389 | } else | ||
390 | val = -EINVAL; | ||
391 | } | ||
392 | break; | ||
393 | case PM8607_CHIP_B0: | ||
394 | if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */ | ||
395 | if (min_uV <= 1800000) | ||
396 | val = 0; | ||
397 | else if (min_uV <= 1850000) | ||
398 | val = (min_uV - 1750001) / 50000; | ||
399 | else | ||
400 | val = 2; /* 2700mV */ | ||
401 | } else { /* 2700mV ~ 2900mV / 50mV */ | ||
402 | if (min_uV <= 2900000) { | ||
403 | val = (min_uV - 2650001) / 50000; | ||
404 | val += 2; | ||
405 | } else if (min_uV <= 3300000) | ||
406 | val = 7; | ||
407 | else | ||
408 | val = -EINVAL; | ||
409 | } | ||
410 | break; | ||
411 | } | ||
412 | break; | ||
413 | } | ||
414 | if (val >= 0) { | ||
415 | ret = pm8607_list_voltage(rdev, val); | ||
416 | if (ret > max_uV) { | ||
417 | pr_err("exceed voltage range (%d %d) uV", | ||
418 | min_uV, max_uV); | ||
419 | return -EINVAL; | ||
420 | } | ||
421 | } else | ||
422 | pr_err("invalid voltage range (%d %d) uV", min_uV, max_uV); | ||
423 | return val; | ||
424 | } | ||
425 | |||
426 | static int pm8607_set_voltage(struct regulator_dev *rdev, | ||
427 | int min_uV, int max_uV) | ||
428 | { | ||
429 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
430 | struct pm8607_chip *chip = info->chip; | ||
431 | uint8_t val, mask; | ||
432 | int ret; | ||
433 | |||
434 | if (check_range(info, min_uV, max_uV)) { | ||
435 | pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); | ||
436 | return -EINVAL; | ||
437 | } | ||
438 | |||
439 | ret = choose_voltage(rdev, min_uV, max_uV); | ||
440 | if (ret < 0) | ||
441 | return -EINVAL; | ||
442 | val = (uint8_t)(ret << info->vol_shift); | ||
443 | mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; | ||
444 | |||
445 | ret = pm8607_set_bits(chip, info->vol_reg, mask, val); | ||
446 | if (ret) | ||
447 | return ret; | ||
448 | switch (info->desc.id) { | ||
449 | case PM8607_ID_BUCK1: | ||
450 | case PM8607_ID_BUCK3: | ||
451 | ret = pm8607_set_bits(chip, info->update_reg, | ||
452 | 1 << info->update_bit, | ||
453 | 1 << info->update_bit); | ||
454 | break; | ||
455 | } | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | static int pm8607_get_voltage(struct regulator_dev *rdev) | ||
460 | { | ||
461 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
462 | struct pm8607_chip *chip = info->chip; | ||
463 | uint8_t val, mask; | ||
464 | int ret; | ||
465 | |||
466 | ret = pm8607_reg_read(chip, info->vol_reg); | ||
467 | if (ret < 0) | ||
468 | return ret; | ||
469 | |||
470 | mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; | ||
471 | val = ((unsigned char)ret & mask) >> info->vol_shift; | ||
472 | |||
473 | return pm8607_list_voltage(rdev, val); | ||
474 | } | ||
475 | |||
476 | static int pm8607_enable(struct regulator_dev *rdev) | ||
477 | { | ||
478 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
479 | struct pm8607_chip *chip = info->chip; | ||
480 | |||
481 | return pm8607_set_bits(chip, info->enable_reg, | ||
482 | 1 << info->enable_bit, | ||
483 | 1 << info->enable_bit); | ||
484 | } | ||
485 | |||
486 | static int pm8607_disable(struct regulator_dev *rdev) | ||
487 | { | ||
488 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
489 | struct pm8607_chip *chip = info->chip; | ||
490 | |||
491 | return pm8607_set_bits(chip, info->enable_reg, | ||
492 | 1 << info->enable_bit, 0); | ||
493 | } | ||
494 | |||
495 | static int pm8607_is_enabled(struct regulator_dev *rdev) | ||
496 | { | ||
497 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | ||
498 | struct pm8607_chip *chip = info->chip; | ||
499 | int ret; | ||
500 | |||
501 | ret = pm8607_reg_read(chip, info->enable_reg); | ||
502 | if (ret < 0) | ||
503 | return ret; | ||
504 | |||
505 | return !!((unsigned char)ret & (1 << info->enable_bit)); | ||
506 | } | ||
507 | |||
508 | static struct regulator_ops pm8607_regulator_ops = { | ||
509 | .set_voltage = pm8607_set_voltage, | ||
510 | .get_voltage = pm8607_get_voltage, | ||
511 | .enable = pm8607_enable, | ||
512 | .disable = pm8607_disable, | ||
513 | .is_enabled = pm8607_is_enabled, | ||
514 | }; | ||
515 | |||
516 | #define PM8607_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ | ||
517 | { \ | ||
518 | .desc = { \ | ||
519 | .name = "BUCK" #_id, \ | ||
520 | .ops = &pm8607_regulator_ops, \ | ||
521 | .type = REGULATOR_VOLTAGE, \ | ||
522 | .id = PM8607_ID_BUCK##_id, \ | ||
523 | .owner = THIS_MODULE, \ | ||
524 | }, \ | ||
525 | .min_uV = (min) * 1000, \ | ||
526 | .max_uV = (max) * 1000, \ | ||
527 | .step_uV = (step) * 1000, \ | ||
528 | .vol_reg = PM8607_##vreg, \ | ||
529 | .vol_shift = (0), \ | ||
530 | .vol_nbits = (nbits), \ | ||
531 | .update_reg = PM8607_##ureg, \ | ||
532 | .update_bit = (ubit), \ | ||
533 | .enable_reg = PM8607_##ereg, \ | ||
534 | .enable_bit = (ebit), \ | ||
535 | .slope_double = (0), \ | ||
536 | } | ||
537 | |||
538 | #define PM8607_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \ | ||
539 | { \ | ||
540 | .desc = { \ | ||
541 | .name = "LDO" #_id, \ | ||
542 | .ops = &pm8607_regulator_ops, \ | ||
543 | .type = REGULATOR_VOLTAGE, \ | ||
544 | .id = PM8607_ID_LDO##_id, \ | ||
545 | .owner = THIS_MODULE, \ | ||
546 | }, \ | ||
547 | .min_uV = (min) * 1000, \ | ||
548 | .max_uV = (max) * 1000, \ | ||
549 | .step_uV = (step) * 1000, \ | ||
550 | .vol_reg = PM8607_##vreg, \ | ||
551 | .vol_shift = (shift), \ | ||
552 | .vol_nbits = (nbits), \ | ||
553 | .enable_reg = PM8607_##ereg, \ | ||
554 | .enable_bit = (ebit), \ | ||
555 | .slope_double = (0), \ | ||
556 | } | ||
557 | |||
558 | static struct pm8607_regulator_info pm8607_regulator_info[] = { | ||
559 | PM8607_DVC(1, 0, 1500, 25, BUCK1, 6, GO, 0, SUPPLIES_EN11, 0), | ||
560 | PM8607_DVC(3, 0, 1500, 25, BUCK3, 6, GO, 2, SUPPLIES_EN11, 2), | ||
561 | |||
562 | PM8607_LDO(1 , 1200, 2800, 0, LDO1 , 0, 2, SUPPLIES_EN11, 3), | ||
563 | PM8607_LDO(2 , 1800, 3300, 0, LDO2 , 0, 3, SUPPLIES_EN11, 4), | ||
564 | PM8607_LDO(3 , 1800, 3300, 0, LDO3 , 0, 3, SUPPLIES_EN11, 5), | ||
565 | PM8607_LDO(4 , 1800, 3300, 0, LDO4 , 0, 3, SUPPLIES_EN11, 6), | ||
566 | PM8607_LDO(5 , 2900, 3300, 0, LDO5 , 0, 2, SUPPLIES_EN11, 7), | ||
567 | PM8607_LDO(6 , 1800, 3300, 0, LDO6 , 0, 3, SUPPLIES_EN12, 0), | ||
568 | PM8607_LDO(7 , 1800, 2900, 0, LDO7 , 0, 3, SUPPLIES_EN12, 1), | ||
569 | PM8607_LDO(8 , 1800, 2900, 0, LDO8 , 0, 3, SUPPLIES_EN12, 2), | ||
570 | PM8607_LDO(9 , 1800, 3300, 0, LDO9 , 0, 3, SUPPLIES_EN12, 3), | ||
571 | PM8607_LDO(10, 1200, 3300, 0, LDO10, 0, 4, SUPPLIES_EN11, 4), | ||
572 | PM8607_LDO(12, 1200, 3300, 0, LDO12, 0, 4, SUPPLIES_EN11, 5), | ||
573 | PM8607_LDO(14, 1800, 3300, 0, LDO14, 0, 3, SUPPLIES_EN11, 6), | ||
574 | }; | ||
575 | |||
576 | static inline struct pm8607_regulator_info *find_regulator_info(int id) | ||
577 | { | ||
578 | struct pm8607_regulator_info *info; | ||
579 | int i; | ||
580 | |||
581 | for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { | ||
582 | info = &pm8607_regulator_info[i]; | ||
583 | if (info->desc.id == id) | ||
584 | return info; | ||
585 | } | ||
586 | return NULL; | ||
587 | } | ||
588 | |||
589 | static int __devinit pm8607_regulator_probe(struct platform_device *pdev) | ||
590 | { | ||
591 | struct pm8607_chip *chip = dev_get_drvdata(pdev->dev.parent); | ||
592 | struct pm8607_platform_data *pdata = chip->dev->platform_data; | ||
593 | struct pm8607_regulator_info *info = NULL; | ||
594 | |||
595 | info = find_regulator_info(pdev->id); | ||
596 | if (info == NULL) { | ||
597 | dev_err(&pdev->dev, "invalid regulator ID specified\n"); | ||
598 | return -EINVAL; | ||
599 | } | ||
600 | |||
601 | info->chip = chip; | ||
602 | |||
603 | info->regulator = regulator_register(&info->desc, &pdev->dev, | ||
604 | pdata->regulator[pdev->id], info); | ||
605 | if (IS_ERR(info->regulator)) { | ||
606 | dev_err(&pdev->dev, "failed to register regulator %s\n", | ||
607 | info->desc.name); | ||
608 | return PTR_ERR(info->regulator); | ||
609 | } | ||
610 | |||
611 | /* check DVC ramp slope double */ | ||
612 | if (info->desc.id == PM8607_ID_BUCK3) | ||
613 | if (info->chip->buck3_double) | ||
614 | info->slope_double = 1; | ||
615 | |||
616 | platform_set_drvdata(pdev, info); | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static int __devexit pm8607_regulator_remove(struct platform_device *pdev) | ||
621 | { | ||
622 | struct pm8607_regulator_info *info = platform_get_drvdata(pdev); | ||
623 | |||
624 | regulator_unregister(info->regulator); | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | #define PM8607_REGULATOR_DRIVER(_name) \ | ||
629 | { \ | ||
630 | .driver = { \ | ||
631 | .name = "88pm8607-" #_name, \ | ||
632 | .owner = THIS_MODULE, \ | ||
633 | }, \ | ||
634 | .probe = pm8607_regulator_probe, \ | ||
635 | .remove = __devexit_p(pm8607_regulator_remove), \ | ||
636 | } | ||
637 | |||
638 | static struct platform_driver pm8607_regulator_driver[] = { | ||
639 | PM8607_REGULATOR_DRIVER(buck1), | ||
640 | PM8607_REGULATOR_DRIVER(buck2), | ||
641 | PM8607_REGULATOR_DRIVER(buck3), | ||
642 | PM8607_REGULATOR_DRIVER(ldo1), | ||
643 | PM8607_REGULATOR_DRIVER(ldo2), | ||
644 | PM8607_REGULATOR_DRIVER(ldo3), | ||
645 | PM8607_REGULATOR_DRIVER(ldo4), | ||
646 | PM8607_REGULATOR_DRIVER(ldo5), | ||
647 | PM8607_REGULATOR_DRIVER(ldo6), | ||
648 | PM8607_REGULATOR_DRIVER(ldo7), | ||
649 | PM8607_REGULATOR_DRIVER(ldo8), | ||
650 | PM8607_REGULATOR_DRIVER(ldo9), | ||
651 | PM8607_REGULATOR_DRIVER(ldo10), | ||
652 | PM8607_REGULATOR_DRIVER(ldo12), | ||
653 | PM8607_REGULATOR_DRIVER(ldo14), | ||
654 | }; | ||
655 | |||
656 | static int __init pm8607_regulator_init(void) | ||
657 | { | ||
658 | int i, count, ret; | ||
659 | |||
660 | count = ARRAY_SIZE(pm8607_regulator_driver); | ||
661 | for (i = 0; i < count; i++) { | ||
662 | ret = platform_driver_register(&pm8607_regulator_driver[i]); | ||
663 | if (ret != 0) | ||
664 | pr_err("Failed to register regulator driver: %d\n", | ||
665 | ret); | ||
666 | } | ||
667 | return 0; | ||
668 | } | ||
669 | subsys_initcall(pm8607_regulator_init); | ||
670 | |||
671 | static void __exit pm8607_regulator_exit(void) | ||
672 | { | ||
673 | int i, count; | ||
674 | |||
675 | count = ARRAY_SIZE(pm8607_regulator_driver); | ||
676 | for (i = 0; i < count; i++) | ||
677 | platform_driver_unregister(&pm8607_regulator_driver[i]); | ||
678 | } | ||
679 | module_exit(pm8607_regulator_exit); | ||
680 | |||
681 | MODULE_LICENSE("GPL"); | ||
682 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | ||
683 | MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC"); | ||
684 | MODULE_ALIAS("platform:88pm8607-regulator"); | ||
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 9e0aa14dc6af..262f62eec837 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig | |||
@@ -164,5 +164,11 @@ config REGULATOR_TPS6507X | |||
164 | three step-down converters and two general-purpose LDO voltage regulators. | 164 | three step-down converters and two general-purpose LDO voltage regulators. |
165 | It supports TI's software based Class-2 SmartReflex implementation. | 165 | It supports TI's software based Class-2 SmartReflex implementation. |
166 | 166 | ||
167 | config REGULATOR_88PM8607 | ||
168 | bool "Marvell 88PM8607 Power regulators" | ||
169 | depends on MFD_88PM8607=y | ||
170 | help | ||
171 | This driver supports 88PM8607 voltage regulator chips. | ||
172 | |||
167 | endif | 173 | endif |
168 | 174 | ||
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 12285e41beec..499ed079811f 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
@@ -26,5 +26,6 @@ obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o | |||
26 | 26 | ||
27 | obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o | 27 | obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o |
28 | obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o | 28 | obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o |
29 | obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o | ||
29 | 30 | ||
30 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG | 31 | ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG |