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/core.h>
19 #include <linux/mfd/88pm860x.h>
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;
27 unsigned int *vol_table;
28 unsigned int *vol_suspend;
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,
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,
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,
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,
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,
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,
106 static const unsigned int LDO1_table[] = {
107 1800000, 1200000, 2800000, 0,
110 static const unsigned int LDO1_suspend_table[] = {
111 1800000, 1200000, 0, 0,
114 static const unsigned int LDO2_table[] = {
115 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
118 static const unsigned int LDO2_suspend_table[] = {
119 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
122 static const unsigned int LDO3_table[] = {
123 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
126 static const unsigned int LDO3_suspend_table[] = {
127 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
130 static const unsigned int LDO4_table[] = {
131 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
134 static const unsigned int LDO4_suspend_table[] = {
135 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
138 static const unsigned int LDO5_table[] = {
139 2900000, 3000000, 3100000, 3300000,
142 static const unsigned int LDO5_suspend_table[] = {
146 static const unsigned int LDO6_table[] = {
147 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
150 static const unsigned int LDO6_suspend_table[] = {
151 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
154 static const unsigned int LDO7_table[] = {
155 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
158 static const unsigned int LDO7_suspend_table[] = {
159 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
162 static const unsigned int LDO8_table[] = {
163 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
166 static const unsigned int LDO8_suspend_table[] = {
167 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
170 static const unsigned int LDO9_table[] = {
171 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
174 static const unsigned int LDO9_suspend_table[] = {
175 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
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,
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,
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,
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,
198 static const unsigned int LDO13_table[] = {
199 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0, 0,
202 static const unsigned int LDO13_suspend_table[] = {
206 static const unsigned int LDO14_table[] = {
207 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
210 static const unsigned int LDO14_suspend_table[] = {
211 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
214 static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index)
216 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
219 if (info->vol_table && (index < (1 << info->vol_nbits))) {
220 ret = info->vol_table[index];
221 if (info->slope_double)
227 static int choose_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
229 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
230 int i, ret = -ENOENT;
232 if (info->slope_double) {
233 min_uV = min_uV >> 1;
234 max_uV = max_uV >> 1;
236 if (info->vol_table) {
237 for (i = 0; i < (1 << info->vol_nbits); i++) {
238 if (!info->vol_table[i])
240 if ((min_uV <= info->vol_table[i])
241 && (max_uV >= info->vol_table[i])) {
248 pr_err("invalid voltage range (%d %d) uV\n", min_uV, max_uV);
252 static int pm8607_set_voltage(struct regulator_dev *rdev,
253 int min_uV, int max_uV, unsigned *selector)
255 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
259 if (min_uV > max_uV) {
260 pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV);
264 ret = choose_voltage(rdev, min_uV, max_uV);
268 val = (uint8_t)(ret << info->vol_shift);
269 mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
271 ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, val);
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);
285 static int pm8607_get_voltage(struct regulator_dev *rdev)
287 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
291 ret = pm860x_reg_read(info->i2c, info->vol_reg);
295 mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
296 val = ((unsigned char)ret & mask) >> info->vol_shift;
298 return pm8607_list_voltage(rdev, val);
301 static int pm8607_enable(struct regulator_dev *rdev)
303 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
305 return pm860x_set_bits(info->i2c, info->enable_reg,
306 1 << info->enable_bit,
307 1 << info->enable_bit);
310 static int pm8607_disable(struct regulator_dev *rdev)
312 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
314 return pm860x_set_bits(info->i2c, info->enable_reg,
315 1 << info->enable_bit, 0);
318 static int pm8607_is_enabled(struct regulator_dev *rdev)
320 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
323 ret = pm860x_reg_read(info->i2c, info->enable_reg);
327 return !!((unsigned char)ret & (1 << info->enable_bit));
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,
338 #define PM8607_DVC(vreg, nbits, ureg, ubit, ereg, ebit) \
342 .ops = &pm8607_regulator_ops, \
343 .type = REGULATOR_VOLTAGE, \
344 .id = PM8607_ID_##vreg, \
345 .owner = THIS_MODULE, \
347 .vol_reg = PM8607_##vreg, \
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, \
359 #define PM8607_LDO(_id, vreg, shift, nbits, ereg, ebit) \
362 .name = "LDO" #_id, \
363 .ops = &pm8607_regulator_ops, \
364 .type = REGULATOR_VOLTAGE, \
365 .id = PM8607_ID_LDO##_id, \
366 .owner = THIS_MODULE, \
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, \
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),
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, 3, 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, 4, SUPPLIES_EN12, 6),
398 static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
400 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
401 struct pm8607_regulator_info *info = NULL;
402 struct regulator_init_data *pdata;
403 struct mfd_cell *cell;
406 cell = pdev->dev.platform_data;
409 pdata = cell->mfd_data;
413 for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
414 info = &pm8607_regulator_info[i];
415 if (!strcmp(info->desc.name, pdata->constraints.name))
418 if (i > ARRAY_SIZE(pm8607_regulator_info)) {
419 dev_err(&pdev->dev, "Failed to find regulator %s\n",
420 pdata->constraints.name);
424 info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
427 /* check DVC ramp slope double */
428 if (!strcmp(info->desc.name, "BUCK3"))
429 if (info->chip->buck3_double)
430 info->slope_double = 1;
432 info->regulator = regulator_register(&info->desc, &pdev->dev,
434 if (IS_ERR(info->regulator)) {
435 dev_err(&pdev->dev, "failed to register regulator %s\n",
437 return PTR_ERR(info->regulator);
440 platform_set_drvdata(pdev, info);
444 static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
446 struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
448 platform_set_drvdata(pdev, NULL);
449 regulator_unregister(info->regulator);
453 static struct platform_driver pm8607_regulator_driver = {
455 .name = "88pm860x-regulator",
456 .owner = THIS_MODULE,
458 .probe = pm8607_regulator_probe,
459 .remove = __devexit_p(pm8607_regulator_remove),
462 static int __init pm8607_regulator_init(void)
464 return platform_driver_register(&pm8607_regulator_driver);
466 subsys_initcall(pm8607_regulator_init);
468 static void __exit pm8607_regulator_exit(void)
470 platform_driver_unregister(&pm8607_regulator_driver);
472 module_exit(pm8607_regulator_exit);
474 MODULE_LICENSE("GPL");
475 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
476 MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
477 MODULE_ALIAS("platform:88pm8607-regulator");