]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/regulator/s5m8767.c
9d5d9159040f2834e2a15e56856f373676a836f9
[mv-sheeva.git] / drivers / regulator / s5m8767.c
1 /*
2  * s5m8767.c
3  *
4  * Copyright (c) 2011 Samsung Electronics Co., Ltd
5  *              http://www.samsung.com
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  *
12  */
13
14 #include <linux/bug.h>
15 #include <linux/delay.h>
16 #include <linux/err.h>
17 #include <linux/gpio.h>
18 #include <linux/slab.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/regulator/driver.h>
22 #include <linux/regulator/machine.h>
23 #include <linux/mfd/s5m87xx/s5m-core.h>
24 #include <linux/mfd/s5m87xx/s5m-pmic.h>
25
26 struct s5m8767_info {
27         struct device *dev;
28         struct s5m87xx_dev *iodev;
29         int num_regulators;
30         struct regulator_dev **rdev;
31
32         int ramp_delay;
33         bool buck2_ramp;
34         bool buck3_ramp;
35         bool buck4_ramp;
36
37         bool buck2_gpiodvs;
38         bool buck3_gpiodvs;
39         bool buck4_gpiodvs;
40         u8 buck2_vol[8];
41         u8 buck3_vol[8];
42         u8 buck4_vol[8];
43         int buck_gpios[3];
44         int buck_gpioindex;
45 };
46
47 struct s5m_voltage_desc {
48         int max;
49         int min;
50         int step;
51 };
52
53 static const struct s5m_voltage_desc buck_voltage_val1 = {
54         .max = 2225000,
55         .min =  650000,
56         .step =   6250,
57 };
58
59 static const struct s5m_voltage_desc buck_voltage_val2 = {
60         .max = 1600000,
61         .min =  600000,
62         .step =   6250,
63 };
64
65 static const struct s5m_voltage_desc buck_voltage_val3 = {
66         .max = 3000000,
67         .min =  750000,
68         .step =  12500,
69 };
70
71 static const struct s5m_voltage_desc ldo_voltage_val1 = {
72         .max = 3950000,
73         .min =  800000,
74         .step =  50000,
75 };
76
77 static const struct s5m_voltage_desc ldo_voltage_val2 = {
78         .max = 2375000,
79         .min =  800000,
80         .step =  25000,
81 };
82
83 static const struct s5m_voltage_desc *reg_voltage_map[] = {
84         [S5M8767_LDO1] = &ldo_voltage_val2,
85         [S5M8767_LDO2] = &ldo_voltage_val2,
86         [S5M8767_LDO3] = &ldo_voltage_val1,
87         [S5M8767_LDO4] = &ldo_voltage_val1,
88         [S5M8767_LDO5] = &ldo_voltage_val1,
89         [S5M8767_LDO6] = &ldo_voltage_val2,
90         [S5M8767_LDO7] = &ldo_voltage_val2,
91         [S5M8767_LDO8] = &ldo_voltage_val2,
92         [S5M8767_LDO9] = &ldo_voltage_val1,
93         [S5M8767_LDO10] = &ldo_voltage_val1,
94         [S5M8767_LDO11] = &ldo_voltage_val1,
95         [S5M8767_LDO12] = &ldo_voltage_val1,
96         [S5M8767_LDO13] = &ldo_voltage_val1,
97         [S5M8767_LDO14] = &ldo_voltage_val1,
98         [S5M8767_LDO15] = &ldo_voltage_val2,
99         [S5M8767_LDO16] = &ldo_voltage_val1,
100         [S5M8767_LDO17] = &ldo_voltage_val1,
101         [S5M8767_LDO18] = &ldo_voltage_val1,
102         [S5M8767_LDO19] = &ldo_voltage_val1,
103         [S5M8767_LDO20] = &ldo_voltage_val1,
104         [S5M8767_LDO21] = &ldo_voltage_val1,
105         [S5M8767_LDO22] = &ldo_voltage_val1,
106         [S5M8767_LDO23] = &ldo_voltage_val1,
107         [S5M8767_LDO24] = &ldo_voltage_val1,
108         [S5M8767_LDO25] = &ldo_voltage_val1,
109         [S5M8767_LDO26] = &ldo_voltage_val1,
110         [S5M8767_LDO27] = &ldo_voltage_val1,
111         [S5M8767_LDO28] = &ldo_voltage_val1,
112         [S5M8767_BUCK1] = &buck_voltage_val1,
113         [S5M8767_BUCK2] = &buck_voltage_val2,
114         [S5M8767_BUCK3] = &buck_voltage_val2,
115         [S5M8767_BUCK4] = &buck_voltage_val2,
116         [S5M8767_BUCK5] = &buck_voltage_val1,
117         [S5M8767_BUCK6] = &buck_voltage_val1,
118         [S5M8767_BUCK7] = NULL,
119         [S5M8767_BUCK8] = NULL,
120         [S5M8767_BUCK9] = &buck_voltage_val3,
121 };
122
123 static int s5m8767_list_voltage(struct regulator_dev *rdev,
124                                 unsigned int selector)
125 {
126         const struct s5m_voltage_desc *desc;
127         int reg_id = rdev_get_id(rdev);
128         int val;
129
130         if (reg_id >= ARRAY_SIZE(reg_voltage_map) || reg_id < 0)
131                 return -EINVAL;
132
133         desc = reg_voltage_map[reg_id];
134         if (desc == NULL)
135                 return -EINVAL;
136
137         val = desc->min + desc->step * selector;
138         if (val > desc->max)
139                 return -EINVAL;
140
141         return val;
142 }
143
144 static int s5m8767_get_register(struct regulator_dev *rdev, int *reg)
145 {
146         int reg_id = rdev_get_id(rdev);
147
148         switch (reg_id) {
149         case S5M8767_LDO1 ... S5M8767_LDO2:
150                 *reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
151                 break;
152         case S5M8767_LDO3 ... S5M8767_LDO28:
153                 *reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
154                 break;
155         case S5M8767_BUCK1:
156                 *reg = S5M8767_REG_BUCK1CTRL1;
157                 break;
158         case S5M8767_BUCK2 ... S5M8767_BUCK4:
159                 *reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9;
160                 break;
161         case S5M8767_BUCK5:
162                 *reg = S5M8767_REG_BUCK5CTRL1;
163                 break;
164         case S5M8767_BUCK6 ... S5M8767_BUCK9:
165                 *reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2;
166                 break;
167         default:
168                 return -EINVAL;
169         }
170
171         return 0;
172 }
173
174 static int s5m8767_reg_is_enabled(struct regulator_dev *rdev)
175 {
176         struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
177         int ret, reg;
178         int mask = 0xc0, pattern = 0xc0;
179         u8 val;
180
181         ret = s5m8767_get_register(rdev, &reg);
182         if (ret == -EINVAL)
183                 return 1;
184         else if (ret)
185                 return ret;
186
187         ret = s5m_reg_read(s5m8767->iodev, reg, &val);
188         if (ret)
189                 return ret;
190
191         return (val & mask) == pattern;
192 }
193
194 static int s5m8767_reg_enable(struct regulator_dev *rdev)
195 {
196         struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
197         int ret, reg;
198         int mask = 0xc0, pattern = 0xc0;
199
200         ret = s5m8767_get_register(rdev, &reg);
201         if (ret)
202                 return ret;
203
204         return s5m_reg_update(s5m8767->iodev, reg, pattern, mask);
205 }
206
207 static int s5m8767_reg_disable(struct regulator_dev *rdev)
208 {
209         struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
210         int ret, reg;
211         int  mask = 0xc0, pattern = 0xc0;
212
213         ret = s5m8767_get_register(rdev, &reg);
214         if (ret)
215                 return ret;
216
217         return s5m_reg_update(s5m8767->iodev, reg, ~pattern, mask);
218 }
219
220 static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
221 {
222         int reg_id = rdev_get_id(rdev);
223         int reg;
224
225         switch (reg_id) {
226         case S5M8767_LDO1 ... S5M8767_LDO2:
227                 reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1);
228                 break;
229         case S5M8767_LDO3 ... S5M8767_LDO28:
230                 reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3);
231                 break;
232         case S5M8767_BUCK1:
233                 reg = S5M8767_REG_BUCK1CTRL2;
234                 break;
235         case S5M8767_BUCK2:
236                 reg = S5M8767_REG_BUCK2DVS1;
237                 break;
238         case S5M8767_BUCK3:
239                 reg = S5M8767_REG_BUCK3DVS1;
240                 break;
241         case S5M8767_BUCK4:
242                 reg = S5M8767_REG_BUCK4DVS1;
243                 break;
244         case S5M8767_BUCK5:
245                 reg = S5M8767_REG_BUCK5CTRL2;
246                 break;
247         case S5M8767_BUCK6 ... S5M8767_BUCK9:
248                 reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2;
249                 break;
250         default:
251                 return -EINVAL;
252         }
253
254         *_reg = reg;
255
256         return 0;
257 }
258
259 static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
260 {
261         struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
262         int reg, mask = 0xff, ret;
263         int reg_id = rdev_get_id(rdev);
264         u8 val;
265
266         ret = s5m8767_get_voltage_register(rdev, &reg);
267         if (ret)
268                 return ret;
269
270         switch (reg_id) {
271         case S5M8767_LDO1 ... S5M8767_LDO28:
272                 mask = 0x3f;
273                 break;
274         case S5M8767_BUCK2:
275                 if (s5m8767->buck2_gpiodvs)
276                         reg += s5m8767->buck_gpioindex;
277                 break;
278         case S5M8767_BUCK3:
279                 if (s5m8767->buck3_gpiodvs)
280                         reg += s5m8767->buck_gpioindex;
281                 break;
282         case S5M8767_BUCK4:
283                 if (s5m8767->buck4_gpiodvs)
284                         reg += s5m8767->buck_gpioindex;
285                 break;
286         }
287
288         ret = s5m_reg_read(s5m8767->iodev, reg, &val);
289         if (ret)
290                 return ret;
291
292         val &= mask;
293
294         return val;
295 }
296
297 static int s5m8767_convert_voltage_to_sel(
298                 const struct s5m_voltage_desc *desc,
299                 int min_vol, int max_vol)
300 {
301         int selector = 0;
302
303         if (desc == NULL)
304                 return -EINVAL;
305
306         if (max_vol < desc->min || min_vol > desc->max)
307                 return -EINVAL;
308
309         selector = (min_vol - desc->min) / desc->step;
310
311         if (desc->min + desc->step * selector > max_vol)
312                 return -EINVAL;
313
314         return selector;
315 }
316
317 static int s5m8767_set_voltage(struct regulator_dev *rdev,
318                                 int min_uV, int max_uV, unsigned *selector)
319 {
320         struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
321         const struct s5m_voltage_desc *desc;
322         int reg_id = rdev_get_id(rdev);
323         int reg, mask, ret;
324         int i;
325         u8 val;
326
327         switch (reg_id) {
328         case S5M8767_LDO1 ... S5M8767_LDO28:
329                 mask = 0x3f;
330                 break;
331         case S5M8767_BUCK1 ... S5M8767_BUCK6:
332                 mask = 0xff;
333                 break;
334         case S5M8767_BUCK7 ... S5M8767_BUCK8:
335                 return -EINVAL;
336         case S5M8767_BUCK9:
337                 mask = 0xff;
338                 break;
339         default:
340                 return -EINVAL;
341         }
342
343         desc = reg_voltage_map[reg_id];
344
345         i = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
346         if (i < 0)
347                 return i;
348
349         ret = s5m8767_get_voltage_register(rdev, &reg);
350         if (ret)
351                 return ret;
352
353         s5m_reg_read(s5m8767->iodev, reg, &val);
354         val = val & mask;
355
356         ret = s5m_reg_write(s5m8767->iodev, reg, val);
357         *selector = i;
358
359         return ret;
360 }
361
362 static inline void s5m8767_set_high(struct s5m8767_info *s5m8767)
363 {
364         int temp_index = s5m8767->buck_gpioindex;
365
366         gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
367         gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
368         gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
369 }
370
371 static inline void s5m8767_set_low(struct s5m8767_info *s5m8767)
372 {
373         int temp_index = s5m8767->buck_gpioindex;
374
375         gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1);
376         gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1);
377         gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1);
378 }
379
380 static int s5m8767_set_voltage_buck(struct regulator_dev *rdev,
381                                     int min_uV, int max_uV, unsigned *selector)
382 {
383         struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
384         int reg_id = rdev_get_id(rdev);
385         const struct s5m_voltage_desc *desc;
386         int new_val, old_val, i = 0;
387
388         if (reg_id < S5M8767_BUCK1 || reg_id > S5M8767_BUCK6)
389                 return -EINVAL;
390
391         switch (reg_id) {
392         case S5M8767_BUCK1:
393                 return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
394         case S5M8767_BUCK2 ... S5M8767_BUCK4:
395                 break;
396         case S5M8767_BUCK5 ... S5M8767_BUCK6:
397                 return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
398         case S5M8767_BUCK9:
399                 return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
400         }
401
402         desc = reg_voltage_map[reg_id];
403         new_val = s5m8767_convert_voltage_to_sel(desc, min_uV, max_uV);
404         if (new_val < 0)
405                 return new_val;
406
407         switch (reg_id) {
408         case S5M8767_BUCK2:
409                 if (s5m8767->buck2_gpiodvs) {
410                         while (s5m8767->buck2_vol[i] != new_val)
411                                 i++;
412                 } else
413                         return s5m8767_set_voltage(rdev, min_uV,
414                                                    max_uV, selector);
415                 break;
416         case S5M8767_BUCK3:
417                 if (s5m8767->buck3_gpiodvs) {
418                         while (s5m8767->buck3_vol[i] != new_val)
419                                 i++;
420                 } else
421                         return s5m8767_set_voltage(rdev, min_uV,
422                                                    max_uV, selector);
423                 break;
424         case S5M8767_BUCK4:
425                 if (s5m8767->buck3_gpiodvs) {
426                         while (s5m8767->buck4_vol[i] != new_val)
427                                 i++;
428                 } else
429                         return s5m8767_set_voltage(rdev, min_uV,
430                                                    max_uV, selector);
431                 break;
432         }
433
434         old_val = s5m8767->buck_gpioindex;
435         s5m8767->buck_gpioindex = i;
436
437         if (i > old_val)
438                 s5m8767_set_high(s5m8767);
439         else
440                 s5m8767_set_low(s5m8767);
441
442         *selector = new_val;
443         return 0;
444 }
445
446 static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev,
447                                              unsigned int old_sel,
448                                              unsigned int new_sel)
449 {
450         struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev);
451         const struct s5m_voltage_desc *desc;
452         int reg_id = rdev_get_id(rdev);
453
454         desc = reg_voltage_map[reg_id];
455
456         if (old_sel < new_sel)
457                 return DIV_ROUND_UP(desc->step * (new_sel - old_sel),
458                                         s5m8767->ramp_delay * 1000);
459         return 0;
460 }
461
462 static struct regulator_ops s5m8767_ldo_ops = {
463         .list_voltage           = s5m8767_list_voltage,
464         .is_enabled             = s5m8767_reg_is_enabled,
465         .enable                 = s5m8767_reg_enable,
466         .disable                = s5m8767_reg_disable,
467         .get_voltage_sel        = s5m8767_get_voltage_sel,
468         .set_voltage            = s5m8767_set_voltage,
469         .set_voltage_time_sel   = s5m8767_set_voltage_time_sel,
470 };
471
472 static struct regulator_ops s5m8767_buck_ops = {
473         .list_voltage           = s5m8767_list_voltage,
474         .is_enabled             = s5m8767_reg_is_enabled,
475         .enable                 = s5m8767_reg_enable,
476         .disable                = s5m8767_reg_disable,
477         .get_voltage_sel        = s5m8767_get_voltage_sel,
478         .set_voltage            = s5m8767_set_voltage_buck,
479         .set_voltage_time_sel   = s5m8767_set_voltage_time_sel,
480 };
481
482 #define regulator_desc_ldo(num)         {       \
483         .name           = "LDO"#num,            \
484         .id             = S5M8767_LDO##num,     \
485         .ops            = &s5m8767_ldo_ops,     \
486         .type           = REGULATOR_VOLTAGE,    \
487         .owner          = THIS_MODULE,          \
488 }
489 #define regulator_desc_buck(num)        {       \
490         .name           = "BUCK"#num,           \
491         .id             = S5M8767_BUCK##num,    \
492         .ops            = &s5m8767_buck_ops,    \
493         .type           = REGULATOR_VOLTAGE,    \
494         .owner          = THIS_MODULE,          \
495 }
496
497 static struct regulator_desc regulators[] = {
498         regulator_desc_ldo(1),
499         regulator_desc_ldo(2),
500         regulator_desc_ldo(3),
501         regulator_desc_ldo(4),
502         regulator_desc_ldo(5),
503         regulator_desc_ldo(6),
504         regulator_desc_ldo(7),
505         regulator_desc_ldo(8),
506         regulator_desc_ldo(9),
507         regulator_desc_ldo(10),
508         regulator_desc_ldo(11),
509         regulator_desc_ldo(12),
510         regulator_desc_ldo(13),
511         regulator_desc_ldo(14),
512         regulator_desc_ldo(15),
513         regulator_desc_ldo(16),
514         regulator_desc_ldo(17),
515         regulator_desc_ldo(18),
516         regulator_desc_ldo(19),
517         regulator_desc_ldo(20),
518         regulator_desc_ldo(21),
519         regulator_desc_ldo(22),
520         regulator_desc_ldo(23),
521         regulator_desc_ldo(24),
522         regulator_desc_ldo(25),
523         regulator_desc_ldo(26),
524         regulator_desc_ldo(27),
525         regulator_desc_ldo(28),
526         regulator_desc_buck(1),
527         regulator_desc_buck(2),
528         regulator_desc_buck(3),
529         regulator_desc_buck(4),
530         regulator_desc_buck(5),
531         regulator_desc_buck(6),
532         regulator_desc_buck(7),
533         regulator_desc_buck(8),
534         regulator_desc_buck(9),
535 };
536
537 static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
538 {
539         struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent);
540         struct s5m_platform_data *pdata = dev_get_platdata(iodev->dev);
541         struct regulator_dev **rdev;
542         struct s5m8767_info *s5m8767;
543         int i, ret, size;
544
545         if (!pdata) {
546                 dev_err(pdev->dev.parent, "Platform data not supplied\n");
547                 return -ENODEV;
548         }
549
550         s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info),
551                                 GFP_KERNEL);
552         if (!s5m8767)
553                 return -ENOMEM;
554
555         size = sizeof(struct regulator_dev *) * (S5M8767_REG_MAX - 2);
556         s5m8767->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
557         if (!s5m8767->rdev)
558                 return -ENOMEM;
559
560         rdev = s5m8767->rdev;
561         s5m8767->dev = &pdev->dev;
562         s5m8767->iodev = iodev;
563         s5m8767->num_regulators = S5M8767_REG_MAX - 2;
564         platform_set_drvdata(pdev, s5m8767);
565
566         s5m8767->buck_gpioindex = pdata->buck_default_idx;
567         s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs;
568         s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs;
569         s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs;
570         s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
571         s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
572         s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
573         s5m8767->ramp_delay = pdata->buck_ramp_delay;
574         s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
575         s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
576         s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
577
578         for (i = 0; i < 8; i++) {
579                 if (s5m8767->buck2_gpiodvs) {
580                         s5m8767->buck2_vol[i] =
581                                 s5m8767_convert_voltage_to_sel(
582                                                 &buck_voltage_val2,
583                                                 pdata->buck2_voltage[i],
584                                                 pdata->buck2_voltage[i] +
585                                                 buck_voltage_val2.step);
586                 }
587
588                 if (s5m8767->buck3_gpiodvs) {
589                         s5m8767->buck3_vol[i] =
590                                 s5m8767_convert_voltage_to_sel(
591                                                 &buck_voltage_val2,
592                                                 pdata->buck3_voltage[i],
593                                                 pdata->buck3_voltage[i] +
594                                                 buck_voltage_val2.step);
595                 }
596
597                 if (s5m8767->buck4_gpiodvs) {
598                         s5m8767->buck4_vol[i] =
599                                 s5m8767_convert_voltage_to_sel(
600                                                 &buck_voltage_val2,
601                                                 pdata->buck4_voltage[i],
602                                                 pdata->buck4_voltage[i] +
603                                                 buck_voltage_val2.step);
604                 }
605         }
606
607         if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
608                 pdata->buck4_gpiodvs) {
609                 if (gpio_is_valid(pdata->buck_gpios[0]) &&
610                         gpio_is_valid(pdata->buck_gpios[1]) &&
611                         gpio_is_valid(pdata->buck_gpios[2])) {
612                         ret = gpio_request(pdata->buck_gpios[0],
613                                                 "S5M8767 SET1");
614                         if (ret == -EBUSY)
615                                 dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n");
616
617                         ret = gpio_request(pdata->buck_gpios[1],
618                                            "S5M8767 SET2");
619                         if (ret == -EBUSY)
620                                 dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n");
621
622                         ret = gpio_request(pdata->buck_gpios[2],
623                                            "S5M8767 SET3");
624                         if (ret == -EBUSY)
625                                 dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n");
626                         /* SET1 GPIO */
627                         gpio_direction_output(pdata->buck_gpios[0],
628                                         (s5m8767->buck_gpioindex >> 2) & 0x1);
629                         /* SET2 GPIO */
630                         gpio_direction_output(pdata->buck_gpios[1],
631                                         (s5m8767->buck_gpioindex >> 1) & 0x1);
632                         /* SET3 GPIO */
633                         gpio_direction_output(pdata->buck_gpios[2],
634                                         (s5m8767->buck_gpioindex >> 0) & 0x1);
635                         ret = 0;
636                 } else {
637                         dev_err(&pdev->dev, "GPIO NOT VALID\n");
638                         ret = -EINVAL;
639                         return ret;
640                 }
641         }
642
643         if (pdata->buck2_gpiodvs) {
644                 if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
645                         dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
646                         ret = -EINVAL;
647                         return ret;
648                 }
649         }
650
651         if (pdata->buck3_gpiodvs) {
652                 if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) {
653                         dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
654                         ret = -EINVAL;
655                         return ret;
656                 }
657         }
658
659         if (pdata->buck4_gpiodvs) {
660                 if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) {
661                         dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n");
662                         ret = -EINVAL;
663                         return ret;
664                 }
665         }
666
667         s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
668                         (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
669         s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
670                         (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
671         s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
672                         (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
673
674         /* Initialize GPIO DVS registers */
675         for (i = 0; i < 8; i++) {
676                 if (s5m8767->buck2_gpiodvs) {
677                         s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS1 + i,
678                                            s5m8767->buck2_vol[i]);
679                 }
680
681                 if (s5m8767->buck3_gpiodvs) {
682                         s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS1 + i,
683                                            s5m8767->buck3_vol[i]);
684                 }
685
686                 if (s5m8767->buck4_gpiodvs) {
687                         s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS1 + i,
688                                            s5m8767->buck4_vol[i]);
689                 }
690         }
691         s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, 0x78, 0xff);
692         s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, 0x58, 0xff);
693         s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, 0x78, 0xff);
694
695         if (s5m8767->buck2_ramp)
696                 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x08, 0x08);
697
698         if (s5m8767->buck3_ramp)
699                 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x04, 0x04);
700
701         if (s5m8767->buck4_ramp)
702                 s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, 0x02, 0x02);
703
704         if (s5m8767->buck2_ramp || s5m8767->buck3_ramp
705                 || s5m8767->buck4_ramp) {
706                 switch (s5m8767->ramp_delay) {
707                 case 15:
708                         s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
709                                         0xc0, 0xf0);
710                         break;
711                 case 25:
712                         s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
713                                         0xd0, 0xf0);
714                         break;
715                 case 50:
716                         s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
717                                         0xe0, 0xf0);
718                         break;
719                 case 100:
720                         s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
721                                         0xf0, 0xf0);
722                         break;
723                 default:
724                         s5m_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP,
725                                         0x90, 0xf0);
726                 }
727         }
728
729         for (i = 0; i < pdata->num_regulators; i++) {
730                 const struct s5m_voltage_desc *desc;
731                 int id = pdata->regulators[i].id;
732
733                 desc = reg_voltage_map[id];
734                 if (desc)
735                         regulators[id].n_voltages =
736                                 (desc->max - desc->min) / desc->step + 1;
737
738                 rdev[i] = regulator_register(&regulators[id], s5m8767->dev,
739                                 pdata->regulators[i].initdata, s5m8767, NULL);
740                 if (IS_ERR(rdev[i])) {
741                         ret = PTR_ERR(rdev[i]);
742                         dev_err(s5m8767->dev, "regulator init failed for %d\n",
743                                         id);
744                         rdev[i] = NULL;
745                         goto err;
746                 }
747         }
748
749         return 0;
750 err:
751         for (i = 0; i < s5m8767->num_regulators; i++)
752                 if (rdev[i])
753                         regulator_unregister(rdev[i]);
754
755         return ret;
756 }
757
758 static int __devexit s5m8767_pmic_remove(struct platform_device *pdev)
759 {
760         struct s5m8767_info *s5m8767 = platform_get_drvdata(pdev);
761         struct regulator_dev **rdev = s5m8767->rdev;
762         int i;
763
764         for (i = 0; i < s5m8767->num_regulators; i++)
765                 if (rdev[i])
766                         regulator_unregister(rdev[i]);
767
768         return 0;
769 }
770
771 static const struct platform_device_id s5m8767_pmic_id[] = {
772         { "s5m8767-pmic", 0},
773         { },
774 };
775 MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id);
776
777 static struct platform_driver s5m8767_pmic_driver = {
778         .driver = {
779                 .name = "s5m8767-pmic",
780                 .owner = THIS_MODULE,
781         },
782         .probe = s5m8767_pmic_probe,
783         .remove = __devexit_p(s5m8767_pmic_remove),
784         .id_table = s5m8767_pmic_id,
785 };
786
787 static int __init s5m8767_pmic_init(void)
788 {
789         return platform_driver_register(&s5m8767_pmic_driver);
790 }
791 subsys_initcall(s5m8767_pmic_init);
792
793 static void __exit s5m8767_pmic_exit(void)
794 {
795         platform_driver_unregister(&s5m8767_pmic_driver);
796 }
797 module_exit(s5m8767_pmic_exit);
798
799 /* Module information */
800 MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
801 MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver");
802 MODULE_LICENSE("GPL");