Merge branch 'sched/urgent'
[linux-2.6/x86.git] / drivers / regulator / 88pm8607.c
blobd63fddb0fbb0d5ead8cadb323bfbff49b2a3e00f
1 /*
2 * Regulators driver for Marvell 88PM8607
4 * Copyright (C) 2009 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
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.
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>
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;
26 unsigned int *vol_table;
27 unsigned int *vol_suspend;
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;
39 static const unsigned int BUCK1_table[] = {
40 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000,
41 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000,
42 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
43 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
44 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
45 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
46 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
47 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
50 static const unsigned int BUCK1_suspend_table[] = {
51 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
52 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
53 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
54 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
55 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000,
56 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
57 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
58 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
61 static const unsigned int BUCK2_table[] = {
62 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000,
63 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000,
64 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000,
65 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
66 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
67 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
68 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
69 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
72 static const unsigned int BUCK2_suspend_table[] = {
73 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000,
74 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000,
75 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000,
76 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
77 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
78 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
79 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
80 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
83 static const unsigned int BUCK3_table[] = {
84 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
85 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
86 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
87 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
88 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000,
89 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
90 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
91 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
94 static const unsigned int BUCK3_suspend_table[] = {
95 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
96 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
97 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
98 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
99 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000,
100 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
101 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
102 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
105 static const unsigned int LDO1_table[] = {
106 1800000, 1200000, 2800000, 0,
109 static const unsigned int LDO1_suspend_table[] = {
110 1800000, 1200000, 0, 0,
113 static const unsigned int LDO2_table[] = {
114 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
117 static const unsigned int LDO2_suspend_table[] = {
118 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
121 static const unsigned int LDO3_table[] = {
122 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
125 static const unsigned int LDO3_suspend_table[] = {
126 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
129 static const unsigned int LDO4_table[] = {
130 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
133 static const unsigned int LDO4_suspend_table[] = {
134 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
137 static const unsigned int LDO5_table[] = {
138 2900000, 3000000, 3100000, 3300000,
141 static const unsigned int LDO5_suspend_table[] = {
142 2900000, 0, 0, 0,
145 static const unsigned int LDO6_table[] = {
146 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
149 static const unsigned int LDO6_suspend_table[] = {
150 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
153 static const unsigned int LDO7_table[] = {
154 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
157 static const unsigned int LDO7_suspend_table[] = {
158 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
161 static const unsigned int LDO8_table[] = {
162 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
165 static const unsigned int LDO8_suspend_table[] = {
166 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
169 static const unsigned int LDO9_table[] = {
170 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
173 static const unsigned int LDO9_suspend_table[] = {
174 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
177 static const unsigned int LDO10_table[] = {
178 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
179 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
182 static const unsigned int LDO10_suspend_table[] = {
183 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
184 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
187 static const unsigned int LDO12_table[] = {
188 1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
189 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
192 static const unsigned int LDO12_suspend_table[] = {
193 1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
194 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
197 static const unsigned int LDO13_table[] = {
198 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0, 0,
201 static const unsigned int LDO13_suspend_table[] = {
205 static const unsigned int LDO14_table[] = {
206 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
209 static const unsigned int LDO14_suspend_table[] = {
210 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
213 static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
215 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
216 int ret = -EINVAL;
218 if (info->vol_table && (index < (1 << info->vol_nbits))) {
219 ret = info->vol_table[index];
220 if (info->slope_double)
221 ret <<= 1;
223 return ret;
226 static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
228 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
229 int i, ret = -ENOENT;
231 if (info->slope_double) {
232 min_uV = min_uV >> 1;
233 max_uV = max_uV >> 1;
235 if (info->vol_table) {
236 for (i = 0; i < (1 << info->vol_nbits); i++) {
237 if (!info->vol_table[i])
238 break;
239 if ((min_uV <= info->vol_table[i])
240 && (max_uV >= info->vol_table[i])) {
241 ret = i;
242 break;
246 if (ret < 0)
247 pr_err("invalid voltage range (%d %d) uV\n", min_uV, max_uV);
248 return ret;
251 static int pm8607_set_voltage(struct regulator_dev *rdev,
252 int min_uV, int max_uV, unsigned *selector)
254 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
255 uint8_t val, mask;
256 int ret;
258 if (min_uV > max_uV) {
259 pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
260 return -EINVAL;
263 ret = choose_voltage(rdev, min_uV, max_uV);
264 if (ret < 0)
265 return -EINVAL;
266 *selector = ret;
267 val = (uint8_t)(ret << info->vol_shift);
268 mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
270 ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val);
271 if (ret)
272 return ret;
273 switch (info->desc.id) {
274 case PM8607_ID_BUCK1:
275 case PM8607_ID_BUCK3:
276 ret = pm860x_set_bits(info->i2c, info->update_reg,
277 1 << info->update_bit,
278 1 << info->update_bit);
279 break;
281 return ret;
284 static int pm8607_get_voltage(struct regulator_dev *rdev)
286 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
287 uint8_t val, mask;
288 int ret;
290 ret = pm860x_reg_read(info->i2c, info->vol_reg);
291 if (ret < 0)
292 return ret;
294 mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
295 val = ((unsigned char)ret & mask) >> info->vol_shift;
297 return pm8607_list_voltage(rdev, val);
300 static int pm8607_enable(struct regulator_dev *rdev)
302 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
304 return pm860x_set_bits(info->i2c, info->enable_reg,
305 1 << info->enable_bit,
306 1 << info->enable_bit);
309 static int pm8607_disable(struct regulator_dev *rdev)
311 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
313 return pm860x_set_bits(info->i2c, info->enable_reg,
314 1 << info->enable_bit, 0);
317 static int pm8607_is_enabled(struct regulator_dev *rdev)
319 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
320 int ret;
322 ret = pm860x_reg_read(info->i2c, info->enable_reg);
323 if (ret < 0)
324 return ret;
326 return !!((unsigned char)ret & (1 << info->enable_bit));
329 static struct regulator_ops pm8607_regulator_ops = {
330 .set_voltage = pm8607_set_voltage,
331 .get_voltage = pm8607_get_voltage,
332 .enable = pm8607_enable,
333 .disable = pm8607_disable,
334 .is_enabled = pm8607_is_enabled,
337 #define PM8607_DVC(vreg, nbits, ureg, ubit, ereg, ebit) \
339 .desc = { \
340 .name = #vreg, \
341 .ops = &pm8607_regulator_ops, \
342 .type = REGULATOR_VOLTAGE, \
343 .id = PM8607_ID_##vreg, \
344 .owner = THIS_MODULE, \
345 }, \
346 .vol_reg = PM8607_##vreg, \
347 .vol_shift = (0), \
348 .vol_nbits = (nbits), \
349 .update_reg = PM8607_##ureg, \
350 .update_bit = (ubit), \
351 .enable_reg = PM8607_##ereg, \
352 .enable_bit = (ebit), \
353 .slope_double = (0), \
354 .vol_table = (unsigned int *)&vreg##_table, \
355 .vol_suspend = (unsigned int *)&vreg##_suspend_table, \
358 #define PM8607_LDO(_id, vreg, shift, nbits, ereg, ebit) \
360 .desc = { \
361 .name = "LDO" #_id, \
362 .ops = &pm8607_regulator_ops, \
363 .type = REGULATOR_VOLTAGE, \
364 .id = PM8607_ID_LDO##_id, \
365 .owner = THIS_MODULE, \
366 }, \
367 .vol_reg = PM8607_##vreg, \
368 .vol_shift = (shift), \
369 .vol_nbits = (nbits), \
370 .enable_reg = PM8607_##ereg, \
371 .enable_bit = (ebit), \
372 .slope_double = (0), \
373 .vol_table = (unsigned int *)&LDO##_id##_table, \
374 .vol_suspend = (unsigned int *)&LDO##_id##_suspend_table, \
377 static struct pm8607_regulator_info pm8607_regulator_info[] = {
378 PM8607_DVC(BUCK1, 6, GO, 0, SUPPLIES_EN11, 0),
379 PM8607_DVC(BUCK2, 6, GO, 1, SUPPLIES_EN11, 1),
380 PM8607_DVC(BUCK3, 6, GO, 2, SUPPLIES_EN11, 2),
382 PM8607_LDO( 1, LDO1, 0, 2, SUPPLIES_EN11, 3),
383 PM8607_LDO( 2, LDO2, 0, 3, SUPPLIES_EN11, 4),
384 PM8607_LDO( 3, LDO3, 0, 3, SUPPLIES_EN11, 5),
385 PM8607_LDO( 4, LDO4, 0, 3, SUPPLIES_EN11, 6),
386 PM8607_LDO( 5, LDO5, 0, 2, SUPPLIES_EN11, 7),
387 PM8607_LDO( 6, LDO6, 0, 3, SUPPLIES_EN12, 0),
388 PM8607_LDO( 7, LDO7, 0, 3, SUPPLIES_EN12, 1),
389 PM8607_LDO( 8, LDO8, 0, 3, SUPPLIES_EN12, 2),
390 PM8607_LDO( 9, LDO9, 0, 3, SUPPLIES_EN12, 3),
391 PM8607_LDO(10, LDO10, 0, 3, SUPPLIES_EN12, 4),
392 PM8607_LDO(12, LDO12, 0, 4, SUPPLIES_EN12, 5),
393 PM8607_LDO(13, VIBRATOR_SET, 1, 3, VIBRATOR_SET, 0),
394 PM8607_LDO(14, LDO14, 0, 4, SUPPLIES_EN12, 6),
397 static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
399 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
400 struct pm8607_regulator_info *info = NULL;
401 struct regulator_init_data *pdata = pdev->dev.platform_data;
402 struct resource *res;
403 int i;
405 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
406 if (res == NULL) {
407 dev_err(&pdev->dev, "No I/O resource!\n");
408 return -EINVAL;
410 for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
411 info = &pm8607_regulator_info[i];
412 if (info->desc.id == res->start)
413 break;
415 if ((i < 0) || (i > PM8607_ID_RG_MAX)) {
416 dev_err(&pdev->dev, "Failed to find regulator %llu\n",
417 (unsigned long long)res->start);
418 return -EINVAL;
420 info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
421 info->chip = chip;
423 /* check DVC ramp slope double */
424 if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
425 info->slope_double = 1;
427 /* replace driver_data with info */
428 info->regulator = regulator_register(&info->desc, &pdev->dev,
429 pdata, info);
430 if (IS_ERR(info->regulator)) {
431 dev_err(&pdev->dev, "failed to register regulator %s\n",
432 info->desc.name);
433 return PTR_ERR(info->regulator);
436 platform_set_drvdata(pdev, info);
437 return 0;
440 static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
442 struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
444 platform_set_drvdata(pdev, NULL);
445 regulator_unregister(info->regulator);
446 return 0;
449 static struct platform_driver pm8607_regulator_driver = {
450 .driver = {
451 .name = "88pm860x-regulator",
452 .owner = THIS_MODULE,
454 .probe = pm8607_regulator_probe,
455 .remove = __devexit_p(pm8607_regulator_remove),
458 static int __init pm8607_regulator_init(void)
460 return platform_driver_register(&pm8607_regulator_driver);
462 subsys_initcall(pm8607_regulator_init);
464 static void __exit pm8607_regulator_exit(void)
466 platform_driver_unregister(&pm8607_regulator_driver);
468 module_exit(pm8607_regulator_exit);
470 MODULE_LICENSE("GPL");
471 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
472 MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
473 MODULE_ALIAS("platform:88pm8607-regulator");