regulator: tps80031: adjust tolerance if req minuV > dev minuV
[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 #include <linux/module.h>
20
21 struct pm8607_regulator_info {
22         struct regulator_desc   desc;
23         struct pm860x_chip      *chip;
24         struct regulator_dev    *regulator;
25         struct i2c_client       *i2c;
26
27         unsigned int    *vol_table;
28         unsigned int    *vol_suspend;
29
30         int     vol_reg;
31         int     vol_shift;
32         int     vol_nbits;
33         int     update_reg;
34         int     update_bit;
35         int     enable_reg;
36         int     enable_bit;
37         int     slope_double;
38 };
39
40 static const unsigned int BUCK1_table[] = {
41          725000,  750000,  775000,  800000,  825000,  850000,  875000,  900000,
42          925000,  950000,  975000, 1000000, 1025000, 1050000, 1075000, 1100000,
43         1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
44         1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
45               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
46          200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
47          400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
48          600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
49 };
50
51 static const unsigned int BUCK1_suspend_table[] = {
52               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
53          200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
54          400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
55          600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
56          800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
57         1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
58         1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
59         1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
60 };
61
62 static const unsigned int BUCK2_table[] = {
63               0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
64          400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
65          800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
66         1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
67         1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
68         2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
69         2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
70         2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
71 };
72
73 static const unsigned int BUCK2_suspend_table[] = {
74               0,   50000,  100000,  150000,  200000,  250000,  300000,  350000,
75          400000,  450000,  500000,  550000,  600000,  650000,  700000,  750000,
76          800000,  850000,  900000,  950000, 1000000, 1050000, 1100000, 1150000,
77         1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
78         1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
79         2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
80         2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
81         2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
82 };
83
84 static const unsigned int BUCK3_table[] = {
85               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
86          200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
87          400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
88          600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
89          800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
90         1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
91         1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
92         1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
93 };
94
95 static const unsigned int BUCK3_suspend_table[] = {
96               0,   25000,   50000,   75000,  100000,  125000,  150000,  175000,
97          200000,  225000,  250000,  275000,  300000,  325000,  350000,  375000,
98          400000,  425000,  450000,  475000,  500000,  525000,  550000,  575000,
99          600000,  625000,  650000,  675000,  700000,  725000,  750000,  775000,
100          800000,  825000,  850000,  875000,  900000,  925000,  950000,  975000,
101         1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
102         1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
103         1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
104 };
105
106 static const unsigned int LDO1_table[] = {
107         1800000, 1200000, 2800000, 0,
108 };
109
110 static const unsigned int LDO1_suspend_table[] = {
111         1800000, 1200000, 0, 0,
112 };
113
114 static const unsigned int LDO2_table[] = {
115         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
116 };
117
118 static const unsigned int LDO2_suspend_table[] = {
119         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
120 };
121
122 static const unsigned int LDO3_table[] = {
123         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
124 };
125
126 static const unsigned int LDO3_suspend_table[] = {
127         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
128 };
129
130 static const unsigned int LDO4_table[] = {
131         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
132 };
133
134 static const unsigned int LDO4_suspend_table[] = {
135         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
136 };
137
138 static const unsigned int LDO5_table[] = {
139         2900000, 3000000, 3100000, 3300000,
140 };
141
142 static const unsigned int LDO5_suspend_table[] = {
143         2900000, 0, 0, 0,
144 };
145
146 static const unsigned int LDO6_table[] = {
147         1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
148 };
149
150 static const unsigned int LDO6_suspend_table[] = {
151         1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
152 };
153
154 static const unsigned int LDO7_table[] = {
155         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
156 };
157
158 static const unsigned int LDO7_suspend_table[] = {
159         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
160 };
161
162 static const unsigned int LDO8_table[] = {
163         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
164 };
165
166 static const unsigned int LDO8_suspend_table[] = {
167         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
168 };
169
170 static const unsigned int LDO9_table[] = {
171         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
172 };
173
174 static const unsigned int LDO9_suspend_table[] = {
175         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
176 };
177
178 static const unsigned int LDO10_table[] = {
179         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
180         1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
181 };
182
183 static const unsigned int LDO10_suspend_table[] = {
184         1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
185         1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
186 };
187
188 static const unsigned int LDO12_table[] = {
189         1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
190         1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
191 };
192
193 static const unsigned int LDO12_suspend_table[] = {
194         1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
195         1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
196 };
197
198 static const unsigned int LDO13_table[] = {
199         1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0,
200 };
201
202 static const unsigned int LDO13_suspend_table[] = {
203         0,
204 };
205
206 static const unsigned int LDO14_table[] = {
207         1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
208 };
209
210 static const unsigned int LDO14_suspend_table[] = {
211         1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
212 };
213
214 static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
215 {
216         struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
217         int ret = -EINVAL;
218
219         if (info->vol_table && (index < (1 << info->vol_nbits))) {
220                 ret = info->vol_table[index];
221                 if (info->slope_double)
222                         ret <<= 1;
223         }
224         return ret;
225 }
226
227 static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
228 {
229         struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
230         int i, ret = -ENOENT;
231
232         if (info->slope_double) {
233                 min_uV = min_uV >> 1;
234                 max_uV = max_uV >> 1;
235         }
236         if (info->vol_table) {
237                 for (i = 0; i < (1 << info->vol_nbits); i++) {
238                         if (!info->vol_table[i])
239                                 break;
240                         if ((min_uV <= info->vol_table[i])
241                                 && (max_uV >= info->vol_table[i])) {
242                                 ret = i;
243                                 break;
244                         }
245                 }
246         }
247         if (ret < 0)
248                 pr_err("invalid voltage range (%d %d) uV\n", min_uV, max_uV);
249         return ret;
250 }
251
252 static int pm8607_set_voltage(struct regulator_dev *rdev,
253                               int min_uV, int max_uV, unsigned *selector)
254 {
255         struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
256         uint8_t val, mask;
257         int ret;
258
259         if (min_uV > max_uV) {
260                 pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
261                 return -EINVAL;
262         }
263
264         ret = choose_voltage(rdev, min_uV, max_uV);
265         if (ret < 0)
266                 return -EINVAL;
267         *selector = ret;
268         val = (uint8_t)(ret << info->vol_shift);
269         mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
270
271         ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val);
272         if (ret)
273                 return ret;
274         switch (info->desc.id) {
275         case PM8607_ID_BUCK1:
276         case PM8607_ID_BUCK3:
277                 ret = pm860x_set_bits(info->i2c, info->update_reg,
278                                       1 << info->update_bit,
279                                       1 << info->update_bit);
280                 break;
281         }
282         return ret;
283 }
284
285 static int pm8607_get_voltage(struct regulator_dev *rdev)
286 {
287         struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
288         uint8_t val, mask;
289         int ret;
290
291         ret = pm860x_reg_read(info->i2c, info->vol_reg);
292         if (ret < 0)
293                 return ret;
294
295         mask = ((1 << info->vol_nbits) - 1)  << info->vol_shift;
296         val = ((unsigned char)ret & mask) >> info->vol_shift;
297
298         return pm8607_list_voltage(rdev, val);
299 }
300
301 static int pm8607_enable(struct regulator_dev *rdev)
302 {
303         struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
304
305         return pm860x_set_bits(info->i2c, info->enable_reg,
306                                1 << info->enable_bit,
307                                1 << info->enable_bit);
308 }
309
310 static int pm8607_disable(struct regulator_dev *rdev)
311 {
312         struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
313
314         return pm860x_set_bits(info->i2c, info->enable_reg,
315                                1 << info->enable_bit, 0);
316 }
317
318 static int pm8607_is_enabled(struct regulator_dev *rdev)
319 {
320         struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
321         int ret;
322
323         ret = pm860x_reg_read(info->i2c, info->enable_reg);
324         if (ret < 0)
325                 return ret;
326
327         return !!((unsigned char)ret & (1 << info->enable_bit));
328 }
329
330 static struct regulator_ops pm8607_regulator_ops = {
331         .set_voltage    = pm8607_set_voltage,
332         .get_voltage    = pm8607_get_voltage,
333         .enable         = pm8607_enable,
334         .disable        = pm8607_disable,
335         .is_enabled     = pm8607_is_enabled,
336 };
337
338 #define PM8607_DVC(vreg, nbits, ureg, ubit, ereg, ebit)                 \
339 {                                                                       \
340         .desc   = {                                                     \
341                 .name   = #vreg,                                        \
342                 .ops    = &pm8607_regulator_ops,                        \
343                 .type   = REGULATOR_VOLTAGE,                            \
344                 .id     = PM8607_ID_##vreg,                             \
345                 .owner  = THIS_MODULE,                                  \
346         },                                                              \
347         .vol_reg        = PM8607_##vreg,                                \
348         .vol_shift      = (0),                                          \
349         .vol_nbits      = (nbits),                                      \
350         .update_reg     = PM8607_##ureg,                                \
351         .update_bit     = (ubit),                                       \
352         .enable_reg     = PM8607_##ereg,                                \
353         .enable_bit     = (ebit),                                       \
354         .slope_double   = (0),                                          \
355         .vol_table      = (unsigned int *)&vreg##_table,                \
356         .vol_suspend    = (unsigned int *)&vreg##_suspend_table,        \
357 }
358
359 #define PM8607_LDO(_id, vreg, shift, nbits, ereg, ebit)                 \
360 {                                                                       \
361         .desc   = {                                                     \
362                 .name   = "LDO" #_id,                                   \
363                 .ops    = &pm8607_regulator_ops,                        \
364                 .type   = REGULATOR_VOLTAGE,                            \
365                 .id     = PM8607_ID_LDO##_id,                           \
366                 .owner  = THIS_MODULE,                                  \
367         },                                                              \
368         .vol_reg        = PM8607_##vreg,                                \
369         .vol_shift      = (shift),                                      \
370         .vol_nbits      = (nbits),                                      \
371         .enable_reg     = PM8607_##ereg,                                \
372         .enable_bit     = (ebit),                                       \
373         .slope_double   = (0),                                          \
374         .vol_table      = (unsigned int *)&LDO##_id##_table,            \
375         .vol_suspend    = (unsigned int *)&LDO##_id##_suspend_table,    \
376 }
377
378 static struct pm8607_regulator_info pm8607_regulator_info[] = {
379         PM8607_DVC(BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
380         PM8607_DVC(BUCK2, 6, GO, 1, SUPPLIES_EN11, 1),
381         PM8607_DVC(BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
382
383         PM8607_LDO( 1,         LDO1, 0, 2, SUPPLIES_EN11, 3),
384         PM8607_LDO( 2,         LDO2, 0, 3, SUPPLIES_EN11, 4),
385         PM8607_LDO( 3,         LDO3, 0, 3, SUPPLIES_EN11, 5),
386         PM8607_LDO( 4,         LDO4, 0, 3, SUPPLIES_EN11, 6),
387         PM8607_LDO( 5,         LDO5, 0, 2, SUPPLIES_EN11, 7),
388         PM8607_LDO( 6,         LDO6, 0, 3, SUPPLIES_EN12, 0),
389         PM8607_LDO( 7,         LDO7, 0, 3, SUPPLIES_EN12, 1),
390         PM8607_LDO( 8,         LDO8, 0, 3, SUPPLIES_EN12, 2),
391         PM8607_LDO( 9,         LDO9, 0, 3, SUPPLIES_EN12, 3),
392         PM8607_LDO(10,        LDO10, 0, 4, SUPPLIES_EN12, 4),
393         PM8607_LDO(12,        LDO12, 0, 4, SUPPLIES_EN12, 5),
394         PM8607_LDO(13, VIBRATOR_SET, 1, 3,  VIBRATOR_SET, 0),
395         PM8607_LDO(14,        LDO14, 0, 3, SUPPLIES_EN12, 6),
396 };
397
398 static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
399 {
400         struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
401         struct pm8607_regulator_info *info = NULL;
402         struct regulator_init_data *pdata = pdev->dev.platform_data;
403         struct resource *res;
404         int i;
405
406         res = platform_get_resource(pdev, IORESOURCE_IO, 0);
407         if (res == NULL) {
408                 dev_err(&pdev->dev, "No I/O resource!\n");
409                 return -EINVAL;
410         }
411         for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
412                 info = &pm8607_regulator_info[i];
413                 if (info->desc.id == res->start)
414                         break;
415         }
416         if (i == ARRAY_SIZE(pm8607_regulator_info)) {
417                 dev_err(&pdev->dev, "Failed to find regulator %llu\n",
418                         (unsigned long long)res->start);
419                 return -EINVAL;
420         }
421         info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
422         info->chip = chip;
423
424         /* check DVC ramp slope double */
425         if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
426                 info->slope_double = 1;
427
428         /* replace driver_data with info */
429         info->regulator = regulator_register(&info->desc, &pdev->dev,
430                                              pdata, info, NULL);
431         if (IS_ERR(info->regulator)) {
432                 dev_err(&pdev->dev, "failed to register regulator %s\n",
433                         info->desc.name);
434                 return PTR_ERR(info->regulator);
435         }
436
437         platform_set_drvdata(pdev, info);
438         return 0;
439 }
440
441 static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
442 {
443         struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
444
445         platform_set_drvdata(pdev, NULL);
446         regulator_unregister(info->regulator);
447         return 0;
448 }
449
450 static struct platform_driver pm8607_regulator_driver = {
451         .driver         = {
452                 .name   = "88pm860x-regulator",
453                 .owner  = THIS_MODULE,
454         },
455         .probe          = pm8607_regulator_probe,
456         .remove         = __devexit_p(pm8607_regulator_remove),
457 };
458
459 static int __init pm8607_regulator_init(void)
460 {
461         return platform_driver_register(&pm8607_regulator_driver);
462 }
463 subsys_initcall(pm8607_regulator_init);
464
465 static void __exit pm8607_regulator_exit(void)
466 {
467         platform_driver_unregister(&pm8607_regulator_driver);
468 }
469 module_exit(pm8607_regulator_exit);
470
471 MODULE_LICENSE("GPL");
472 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
473 MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
474 MODULE_ALIAS("platform:88pm8607-regulator");