Commit | Line | Data |
---|---|---|
be0e2d3e HZ |
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; | |
ddec6810 MB |
173 | int val = -ENOENT; |
174 | int ret; | |
be0e2d3e HZ |
175 | |
176 | switch (info->desc.id) { | |
177 | case PM8607_ID_BUCK1: | |
178 | if (min_uV >= 800000) /* 800mV ~ 1500mV / 25mV */ | |
179 | val = (min_uV - 775001) / 25000; | |
180 | else { /* 25mV ~ 775mV / 25mV */ | |
181 | val = (min_uV + 249999) / 25000; | |
182 | val += 32; | |
183 | } | |
184 | break; | |
185 | case PM8607_ID_BUCK3: | |
186 | if (info->slope_double) | |
187 | min_uV = min_uV >> 1; | |
188 | val = (min_uV + 249999) / 25000; /* 0mV ~ 1500mV / 25mV */ | |
189 | ||
190 | break; | |
191 | case PM8607_ID_LDO1: | |
192 | if (min_uV > 1800000) | |
193 | val = 2; | |
194 | else if (min_uV > 1200000) | |
195 | val = 0; | |
196 | else | |
197 | val = 1; | |
198 | break; | |
199 | case PM8607_ID_LDO5: | |
200 | if (min_uV > 3100000) | |
201 | val = 3; | |
202 | else /* 2900mV ~ 3100mV / 100mV */ | |
203 | val = (min_uV - 2800001) / 100000; | |
204 | break; | |
205 | case PM8607_ID_LDO7: | |
206 | case PM8607_ID_LDO8: | |
207 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ | |
208 | if (min_uV <= 1800000) | |
209 | val = 0; /* 1800mv */ | |
210 | else if (min_uV <= 1900000) | |
211 | val = (min_uV - 1750001) / 50000; | |
212 | else | |
213 | val = 3; /* 2700mV */ | |
214 | } else { /* 2700mV ~ 2900mV / 50mV */ | |
215 | if (min_uV <= 2900000) { | |
216 | val = (min_uV - 2650001) / 50000; | |
217 | val += 3; | |
218 | } else | |
219 | val = -EINVAL; | |
220 | } | |
221 | break; | |
222 | case PM8607_ID_LDO10: | |
223 | if (min_uV > 2850000) | |
224 | val = 7; | |
225 | else if (min_uV <= 1200000) | |
226 | val = 8; | |
227 | else if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ | |
228 | val = (min_uV - 1750001) / 50000; | |
229 | else { /* 2700mV ~ 2850mV / 50mV */ | |
230 | val = (min_uV - 2650001) / 50000; | |
231 | val += 3; | |
232 | } | |
233 | break; | |
234 | case PM8607_ID_LDO12: | |
235 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 100mV */ | |
236 | if (min_uV <= 1200000) | |
237 | val = 8; /* 1200mV */ | |
238 | else if (min_uV <= 1800000) | |
239 | val = 0; /* 1800mV */ | |
240 | else if (min_uV <= 1900000) | |
241 | val = (min_uV - 1700001) / 100000; | |
242 | else | |
243 | val = 2; /* 2700mV */ | |
244 | } else { /* 2700mV ~ 3100mV / 100mV */ | |
245 | if (min_uV <= 3100000) { | |
246 | val = (min_uV - 2600001) / 100000; | |
247 | val += 2; | |
248 | } else if (min_uV <= 3300000) | |
249 | val = 7; | |
250 | else | |
251 | val = -EINVAL; | |
252 | } | |
253 | break; | |
254 | case PM8607_ID_LDO2: | |
255 | case PM8607_ID_LDO3: | |
256 | case PM8607_ID_LDO9: | |
257 | switch (chip_id) { | |
258 | case PM8607_CHIP_A0: | |
259 | case PM8607_CHIP_A1: | |
260 | if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ | |
261 | if (min_uV <= 1800000) | |
262 | val = 0; | |
263 | else if (min_uV <= 1900000) | |
264 | val = (min_uV - 1750001) / 50000; | |
265 | else | |
266 | val = 3; /* 2700mV */ | |
267 | else { /* 2700mV ~ 2900mV / 50mV */ | |
268 | if (min_uV <= 2900000) { | |
269 | val = (min_uV - 2650001) / 50000; | |
270 | val += 3; | |
271 | } else | |
272 | val = -EINVAL; | |
273 | } | |
274 | break; | |
275 | case PM8607_CHIP_B0: | |
276 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ | |
277 | if (min_uV <= 1800000) | |
278 | val = 0; | |
279 | else if (min_uV <= 1900000) | |
280 | val = (min_uV - 1750001) / 50000; | |
281 | else | |
282 | val = 3; /* 2700mV */ | |
283 | } else { /* 2700mV ~ 2850mV / 50mV */ | |
284 | if (min_uV <= 2850000) { | |
285 | val = (min_uV - 2650001) / 50000; | |
286 | val += 3; | |
287 | } else if (min_uV <= 3300000) | |
288 | val = 7; | |
289 | else | |
290 | val = -EINVAL; | |
291 | } | |
292 | break; | |
293 | } | |
294 | break; | |
295 | case PM8607_ID_LDO4: | |
296 | switch (chip_id) { | |
297 | case PM8607_CHIP_A0: | |
298 | case PM8607_CHIP_A1: | |
299 | if (min_uV < 2700000) /* 1800mV ~ 1900mV / 50mV */ | |
300 | if (min_uV <= 1800000) | |
301 | val = 0; | |
302 | else if (min_uV <= 1900000) | |
303 | val = (min_uV - 1750001) / 50000; | |
304 | else | |
305 | val = 3; /* 2700mV */ | |
306 | else { /* 2700mV ~ 2900mV / 50mV */ | |
307 | if (min_uV <= 2900000) { | |
308 | val = (min_uV - 2650001) / 50000; | |
309 | val += 3; | |
310 | } else | |
311 | val = -EINVAL; | |
312 | } | |
313 | break; | |
314 | case PM8607_CHIP_B0: | |
315 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ | |
316 | if (min_uV <= 1800000) | |
317 | val = 0; | |
318 | else if (min_uV <= 1900000) | |
319 | val = (min_uV - 1750001) / 50000; | |
320 | else | |
321 | val = 3; /* 2700mV */ | |
322 | } else { /* 2700mV ~ 2800mV / 50mV */ | |
323 | if (min_uV <= 2850000) { | |
324 | val = (min_uV - 2650001) / 50000; | |
325 | val += 3; | |
326 | } else if (min_uV <= 2900000) | |
327 | val = 6; | |
328 | else if (min_uV <= 3300000) | |
329 | val = 7; | |
330 | else | |
331 | val = -EINVAL; | |
332 | } | |
333 | break; | |
334 | } | |
335 | break; | |
336 | case PM8607_ID_LDO6: | |
337 | switch (chip_id) { | |
338 | case PM8607_CHIP_A0: | |
339 | case PM8607_CHIP_A1: | |
340 | if (min_uV < 2600000) { /* 1800mV ~ 1900mV / 50mV */ | |
341 | if (min_uV <= 1800000) | |
342 | val = 0; | |
343 | else if (min_uV <= 1900000) | |
344 | val = (min_uV - 1750001) / 50000; | |
345 | else | |
346 | val = 3; /* 2600mV */ | |
347 | } else { /* 2600mV ~ 2800mV / 50mV */ | |
348 | if (min_uV <= 2800000) { | |
349 | val = (min_uV - 2550001) / 50000; | |
350 | val += 3; | |
351 | } else | |
352 | val = -EINVAL; | |
353 | } | |
354 | break; | |
355 | case PM8607_CHIP_B0: | |
356 | if (min_uV < 2600000) { /* 1800mV ~ 1850mV / 50mV */ | |
357 | if (min_uV <= 1800000) | |
358 | val = 0; | |
359 | else if (min_uV <= 1850000) | |
360 | val = (min_uV - 1750001) / 50000; | |
361 | else | |
362 | val = 2; /* 2600mV */ | |
363 | } else { /* 2600mV ~ 2800mV / 50mV */ | |
364 | if (min_uV <= 2800000) { | |
365 | val = (min_uV - 2550001) / 50000; | |
366 | val += 2; | |
367 | } else if (min_uV <= 3300000) | |
368 | val = 7; | |
369 | else | |
370 | val = -EINVAL; | |
371 | } | |
372 | break; | |
373 | } | |
374 | break; | |
375 | case PM8607_ID_LDO14: | |
376 | switch (chip_id) { | |
377 | case PM8607_CHIP_A0: | |
378 | case PM8607_CHIP_A1: | |
379 | if (min_uV < 2700000) { /* 1800mV ~ 1900mV / 50mV */ | |
380 | if (min_uV <= 1800000) | |
381 | val = 0; | |
382 | else if (min_uV <= 1900000) | |
383 | val = (min_uV - 1750001) / 50000; | |
384 | else | |
385 | val = 3; /* 2700mV */ | |
386 | } else { /* 2700mV ~ 2900mV / 50mV */ | |
387 | if (min_uV <= 2900000) { | |
388 | val = (min_uV - 2650001) / 50000; | |
389 | val += 3; | |
390 | } else | |
391 | val = -EINVAL; | |
392 | } | |
393 | break; | |
394 | case PM8607_CHIP_B0: | |
395 | if (min_uV < 2700000) { /* 1800mV ~ 1850mV / 50mV */ | |
396 | if (min_uV <= 1800000) | |
397 | val = 0; | |
398 | else if (min_uV <= 1850000) | |
399 | val = (min_uV - 1750001) / 50000; | |
400 | else | |
401 | val = 2; /* 2700mV */ | |
402 | } else { /* 2700mV ~ 2900mV / 50mV */ | |
403 | if (min_uV <= 2900000) { | |
404 | val = (min_uV - 2650001) / 50000; | |
405 | val += 2; | |
406 | } else if (min_uV <= 3300000) | |
407 | val = 7; | |
408 | else | |
409 | val = -EINVAL; | |
410 | } | |
411 | break; | |
412 | } | |
413 | break; | |
414 | } | |
415 | if (val >= 0) { | |
416 | ret = pm8607_list_voltage(rdev, val); | |
417 | if (ret > max_uV) { | |
418 | pr_err("exceed voltage range (%d %d) uV", | |
419 | min_uV, max_uV); | |
420 | return -EINVAL; | |
421 | } | |
422 | } else | |
423 | pr_err("invalid voltage range (%d %d) uV", min_uV, max_uV); | |
424 | return val; | |
425 | } | |
426 | ||
427 | static int pm8607_set_voltage(struct regulator_dev *rdev, | |
428 | int min_uV, int max_uV) | |
429 | { | |
430 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | |
431 | struct pm8607_chip *chip = info->chip; | |
432 | uint8_t val, mask; | |
433 | int ret; | |
434 | ||
435 | if (check_range(info, min_uV, max_uV)) { | |
436 | pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); | |
437 | return -EINVAL; | |
438 | } | |
439 | ||
440 | ret = choose_voltage(rdev, min_uV, max_uV); | |
441 | if (ret < 0) | |
442 | return -EINVAL; | |
443 | val = (uint8_t)(ret << info->vol_shift); | |
444 | mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; | |
445 | ||
446 | ret = pm8607_set_bits(chip, info->vol_reg, mask, val); | |
447 | if (ret) | |
448 | return ret; | |
449 | switch (info->desc.id) { | |
450 | case PM8607_ID_BUCK1: | |
451 | case PM8607_ID_BUCK3: | |
452 | ret = pm8607_set_bits(chip, info->update_reg, | |
453 | 1 << info->update_bit, | |
454 | 1 << info->update_bit); | |
455 | break; | |
456 | } | |
457 | return ret; | |
458 | } | |
459 | ||
460 | static int pm8607_get_voltage(struct regulator_dev *rdev) | |
461 | { | |
462 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | |
463 | struct pm8607_chip *chip = info->chip; | |
464 | uint8_t val, mask; | |
465 | int ret; | |
466 | ||
467 | ret = pm8607_reg_read(chip, info->vol_reg); | |
468 | if (ret < 0) | |
469 | return ret; | |
470 | ||
471 | mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; | |
472 | val = ((unsigned char)ret & mask) >> info->vol_shift; | |
473 | ||
474 | return pm8607_list_voltage(rdev, val); | |
475 | } | |
476 | ||
477 | static int pm8607_enable(struct regulator_dev *rdev) | |
478 | { | |
479 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | |
480 | struct pm8607_chip *chip = info->chip; | |
481 | ||
482 | return pm8607_set_bits(chip, info->enable_reg, | |
483 | 1 << info->enable_bit, | |
484 | 1 << info->enable_bit); | |
485 | } | |
486 | ||
487 | static int pm8607_disable(struct regulator_dev *rdev) | |
488 | { | |
489 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | |
490 | struct pm8607_chip *chip = info->chip; | |
491 | ||
492 | return pm8607_set_bits(chip, info->enable_reg, | |
493 | 1 << info->enable_bit, 0); | |
494 | } | |
495 | ||
496 | static int pm8607_is_enabled(struct regulator_dev *rdev) | |
497 | { | |
498 | struct pm8607_regulator_info *info = rdev_get_drvdata(rdev); | |
499 | struct pm8607_chip *chip = info->chip; | |
500 | int ret; | |
501 | ||
502 | ret = pm8607_reg_read(chip, info->enable_reg); | |
503 | if (ret < 0) | |
504 | return ret; | |
505 | ||
506 | return !!((unsigned char)ret & (1 << info->enable_bit)); | |
507 | } | |
508 | ||
509 | static struct regulator_ops pm8607_regulator_ops = { | |
510 | .set_voltage = pm8607_set_voltage, | |
511 | .get_voltage = pm8607_get_voltage, | |
512 | .enable = pm8607_enable, | |
513 | .disable = pm8607_disable, | |
514 | .is_enabled = pm8607_is_enabled, | |
515 | }; | |
516 | ||
517 | #define PM8607_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ | |
518 | { \ | |
519 | .desc = { \ | |
520 | .name = "BUCK" #_id, \ | |
521 | .ops = &pm8607_regulator_ops, \ | |
522 | .type = REGULATOR_VOLTAGE, \ | |
523 | .id = PM8607_ID_BUCK##_id, \ | |
524 | .owner = THIS_MODULE, \ | |
525 | }, \ | |
526 | .min_uV = (min) * 1000, \ | |
527 | .max_uV = (max) * 1000, \ | |
528 | .step_uV = (step) * 1000, \ | |
529 | .vol_reg = PM8607_##vreg, \ | |
530 | .vol_shift = (0), \ | |
531 | .vol_nbits = (nbits), \ | |
532 | .update_reg = PM8607_##ureg, \ | |
533 | .update_bit = (ubit), \ | |
534 | .enable_reg = PM8607_##ereg, \ | |
535 | .enable_bit = (ebit), \ | |
536 | .slope_double = (0), \ | |
537 | } | |
538 | ||
539 | #define PM8607_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \ | |
540 | { \ | |
541 | .desc = { \ | |
542 | .name = "LDO" #_id, \ | |
543 | .ops = &pm8607_regulator_ops, \ | |
544 | .type = REGULATOR_VOLTAGE, \ | |
545 | .id = PM8607_ID_LDO##_id, \ | |
546 | .owner = THIS_MODULE, \ | |
547 | }, \ | |
548 | .min_uV = (min) * 1000, \ | |
549 | .max_uV = (max) * 1000, \ | |
550 | .step_uV = (step) * 1000, \ | |
551 | .vol_reg = PM8607_##vreg, \ | |
552 | .vol_shift = (shift), \ | |
553 | .vol_nbits = (nbits), \ | |
554 | .enable_reg = PM8607_##ereg, \ | |
555 | .enable_bit = (ebit), \ | |
556 | .slope_double = (0), \ | |
557 | } | |
558 | ||
559 | static struct pm8607_regulator_info pm8607_regulator_info[] = { | |
560 | PM8607_DVC(1, 0, 1500, 25, BUCK1, 6, GO, 0, SUPPLIES_EN11, 0), | |
561 | PM8607_DVC(3, 0, 1500, 25, BUCK3, 6, GO, 2, SUPPLIES_EN11, 2), | |
562 | ||
563 | PM8607_LDO(1 , 1200, 2800, 0, LDO1 , 0, 2, SUPPLIES_EN11, 3), | |
564 | PM8607_LDO(2 , 1800, 3300, 0, LDO2 , 0, 3, SUPPLIES_EN11, 4), | |
565 | PM8607_LDO(3 , 1800, 3300, 0, LDO3 , 0, 3, SUPPLIES_EN11, 5), | |
566 | PM8607_LDO(4 , 1800, 3300, 0, LDO4 , 0, 3, SUPPLIES_EN11, 6), | |
567 | PM8607_LDO(5 , 2900, 3300, 0, LDO5 , 0, 2, SUPPLIES_EN11, 7), | |
568 | PM8607_LDO(6 , 1800, 3300, 0, LDO6 , 0, 3, SUPPLIES_EN12, 0), | |
569 | PM8607_LDO(7 , 1800, 2900, 0, LDO7 , 0, 3, SUPPLIES_EN12, 1), | |
570 | PM8607_LDO(8 , 1800, 2900, 0, LDO8 , 0, 3, SUPPLIES_EN12, 2), | |
571 | PM8607_LDO(9 , 1800, 3300, 0, LDO9 , 0, 3, SUPPLIES_EN12, 3), | |
572 | PM8607_LDO(10, 1200, 3300, 0, LDO10, 0, 4, SUPPLIES_EN11, 4), | |
573 | PM8607_LDO(12, 1200, 3300, 0, LDO12, 0, 4, SUPPLIES_EN11, 5), | |
574 | PM8607_LDO(14, 1800, 3300, 0, LDO14, 0, 3, SUPPLIES_EN11, 6), | |
575 | }; | |
576 | ||
577 | static inline struct pm8607_regulator_info *find_regulator_info(int id) | |
578 | { | |
579 | struct pm8607_regulator_info *info; | |
580 | int i; | |
581 | ||
582 | for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) { | |
583 | info = &pm8607_regulator_info[i]; | |
584 | if (info->desc.id == id) | |
585 | return info; | |
586 | } | |
587 | return NULL; | |
588 | } | |
589 | ||
590 | static int __devinit pm8607_regulator_probe(struct platform_device *pdev) | |
591 | { | |
592 | struct pm8607_chip *chip = dev_get_drvdata(pdev->dev.parent); | |
593 | struct pm8607_platform_data *pdata = chip->dev->platform_data; | |
594 | struct pm8607_regulator_info *info = NULL; | |
595 | ||
596 | info = find_regulator_info(pdev->id); | |
597 | if (info == NULL) { | |
598 | dev_err(&pdev->dev, "invalid regulator ID specified\n"); | |
599 | return -EINVAL; | |
600 | } | |
601 | ||
602 | info->chip = chip; | |
603 | ||
604 | info->regulator = regulator_register(&info->desc, &pdev->dev, | |
605 | pdata->regulator[pdev->id], info); | |
606 | if (IS_ERR(info->regulator)) { | |
607 | dev_err(&pdev->dev, "failed to register regulator %s\n", | |
608 | info->desc.name); | |
609 | return PTR_ERR(info->regulator); | |
610 | } | |
611 | ||
612 | /* check DVC ramp slope double */ | |
613 | if (info->desc.id == PM8607_ID_BUCK3) | |
614 | if (info->chip->buck3_double) | |
615 | info->slope_double = 1; | |
616 | ||
617 | platform_set_drvdata(pdev, info); | |
618 | return 0; | |
619 | } | |
620 | ||
621 | static int __devexit pm8607_regulator_remove(struct platform_device *pdev) | |
622 | { | |
623 | struct pm8607_regulator_info *info = platform_get_drvdata(pdev); | |
624 | ||
625 | regulator_unregister(info->regulator); | |
626 | return 0; | |
627 | } | |
628 | ||
629 | #define PM8607_REGULATOR_DRIVER(_name) \ | |
630 | { \ | |
631 | .driver = { \ | |
632 | .name = "88pm8607-" #_name, \ | |
633 | .owner = THIS_MODULE, \ | |
634 | }, \ | |
635 | .probe = pm8607_regulator_probe, \ | |
636 | .remove = __devexit_p(pm8607_regulator_remove), \ | |
637 | } | |
638 | ||
639 | static struct platform_driver pm8607_regulator_driver[] = { | |
640 | PM8607_REGULATOR_DRIVER(buck1), | |
641 | PM8607_REGULATOR_DRIVER(buck2), | |
642 | PM8607_REGULATOR_DRIVER(buck3), | |
643 | PM8607_REGULATOR_DRIVER(ldo1), | |
644 | PM8607_REGULATOR_DRIVER(ldo2), | |
645 | PM8607_REGULATOR_DRIVER(ldo3), | |
646 | PM8607_REGULATOR_DRIVER(ldo4), | |
647 | PM8607_REGULATOR_DRIVER(ldo5), | |
648 | PM8607_REGULATOR_DRIVER(ldo6), | |
649 | PM8607_REGULATOR_DRIVER(ldo7), | |
650 | PM8607_REGULATOR_DRIVER(ldo8), | |
651 | PM8607_REGULATOR_DRIVER(ldo9), | |
652 | PM8607_REGULATOR_DRIVER(ldo10), | |
653 | PM8607_REGULATOR_DRIVER(ldo12), | |
654 | PM8607_REGULATOR_DRIVER(ldo14), | |
655 | }; | |
656 | ||
657 | static int __init pm8607_regulator_init(void) | |
658 | { | |
659 | int i, count, ret; | |
660 | ||
661 | count = ARRAY_SIZE(pm8607_regulator_driver); | |
662 | for (i = 0; i < count; i++) { | |
663 | ret = platform_driver_register(&pm8607_regulator_driver[i]); | |
664 | if (ret != 0) | |
665 | pr_err("Failed to register regulator driver: %d\n", | |
666 | ret); | |
667 | } | |
668 | return 0; | |
669 | } | |
670 | subsys_initcall(pm8607_regulator_init); | |
671 | ||
672 | static void __exit pm8607_regulator_exit(void) | |
673 | { | |
674 | int i, count; | |
675 | ||
676 | count = ARRAY_SIZE(pm8607_regulator_driver); | |
677 | for (i = 0; i < count; i++) | |
678 | platform_driver_unregister(&pm8607_regulator_driver[i]); | |
679 | } | |
680 | module_exit(pm8607_regulator_exit); | |
681 | ||
682 | MODULE_LICENSE("GPL"); | |
683 | MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>"); | |
684 | MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC"); | |
685 | MODULE_ALIAS("platform:88pm8607-regulator"); |