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