i2c: Document the message size limit
[safe/jmp/linux-2.6] / drivers / regulator / 88pm8607.c
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 = -ENOENT;
174         int ret;
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");