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>
19 #include <linux/module.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;
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[] = {
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 1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 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);
218 if (info->vol_table && (index < rdev->desc->n_voltages)) {
219 ret = info->vol_table[index];
220 if (info->slope_double)
226 static int pm8607_set_voltage_sel(struct regulator_dev *rdev, unsigned selector)
228 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
232 val = (uint8_t)(selector << info->vol_shift);
233 mask = (rdev->desc->n_voltages - 1) << info->vol_shift;
235 ret = pm860x_set_bits(info->i2c, info->vol_reg, mask, selector);
238 switch (info->desc.id) {
239 case PM8607_ID_BUCK1:
240 case PM8607_ID_BUCK3:
241 ret = pm860x_set_bits(info->i2c, info->update_reg,
242 1 << info->update_bit,
243 1 << info->update_bit);
249 static int pm8607_get_voltage_sel(struct regulator_dev *rdev)
251 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
255 ret = pm860x_reg_read(info->i2c, info->vol_reg);
259 mask = (rdev->desc->n_voltages - 1) << info->vol_shift;
260 val = ((unsigned char)ret & mask) >> info->vol_shift;
265 static int pm8607_enable(struct regulator_dev *rdev)
267 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
269 return pm860x_set_bits(info->i2c, info->enable_reg,
270 1 << info->enable_bit,
271 1 << info->enable_bit);
274 static int pm8607_disable(struct regulator_dev *rdev)
276 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
278 return pm860x_set_bits(info->i2c, info->enable_reg,
279 1 << info->enable_bit, 0);
282 static int pm8607_is_enabled(struct regulator_dev *rdev)
284 struct pm8607_regulator_info *info = rdev_get_drvdata(rdev);
287 ret = pm860x_reg_read(info->i2c, info->enable_reg);
291 return !!((unsigned char)ret & (1 << info->enable_bit));
294 static struct regulator_ops pm8607_regulator_ops = {
295 .list_voltage = pm8607_list_voltage,
296 .set_voltage_sel = pm8607_set_voltage_sel,
297 .get_voltage_sel = pm8607_get_voltage_sel,
298 .enable = pm8607_enable,
299 .disable = pm8607_disable,
300 .is_enabled = pm8607_is_enabled,
303 #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \
307 .ops = &pm8607_regulator_ops, \
308 .type = REGULATOR_VOLTAGE, \
309 .id = PM8607_ID_##vreg, \
310 .owner = THIS_MODULE, \
311 .n_voltages = ARRAY_SIZE(vreg##_table), \
313 .vol_reg = PM8607_##vreg, \
315 .update_reg = PM8607_##ureg, \
316 .update_bit = (ubit), \
317 .enable_reg = PM8607_##ereg, \
318 .enable_bit = (ebit), \
319 .slope_double = (0), \
320 .vol_table = (unsigned int *)&vreg##_table, \
321 .vol_suspend = (unsigned int *)&vreg##_suspend_table, \
324 #define PM8607_LDO(_id, vreg, shift, ereg, ebit) \
327 .name = "LDO" #_id, \
328 .ops = &pm8607_regulator_ops, \
329 .type = REGULATOR_VOLTAGE, \
330 .id = PM8607_ID_LDO##_id, \
331 .owner = THIS_MODULE, \
332 .n_voltages = ARRAY_SIZE(LDO##_id##_table), \
334 .vol_reg = PM8607_##vreg, \
335 .vol_shift = (shift), \
336 .enable_reg = PM8607_##ereg, \
337 .enable_bit = (ebit), \
338 .slope_double = (0), \
339 .vol_table = (unsigned int *)&LDO##_id##_table, \
340 .vol_suspend = (unsigned int *)&LDO##_id##_suspend_table, \
343 static struct pm8607_regulator_info pm8607_regulator_info[] = {
344 PM8607_DVC(BUCK1, GO, 0, SUPPLIES_EN11, 0),
345 PM8607_DVC(BUCK2, GO, 1, SUPPLIES_EN11, 1),
346 PM8607_DVC(BUCK3, GO, 2, SUPPLIES_EN11, 2),
348 PM8607_LDO(1, LDO1, 0, SUPPLIES_EN11, 3),
349 PM8607_LDO(2, LDO2, 0, SUPPLIES_EN11, 4),
350 PM8607_LDO(3, LDO3, 0, SUPPLIES_EN11, 5),
351 PM8607_LDO(4, LDO4, 0, SUPPLIES_EN11, 6),
352 PM8607_LDO(5, LDO5, 0, SUPPLIES_EN11, 7),
353 PM8607_LDO(6, LDO6, 0, SUPPLIES_EN12, 0),
354 PM8607_LDO(7, LDO7, 0, SUPPLIES_EN12, 1),
355 PM8607_LDO(8, LDO8, 0, SUPPLIES_EN12, 2),
356 PM8607_LDO(9, LDO9, 0, SUPPLIES_EN12, 3),
357 PM8607_LDO(10, LDO10, 0, SUPPLIES_EN12, 4),
358 PM8607_LDO(12, LDO12, 0, SUPPLIES_EN12, 5),
359 PM8607_LDO(13, VIBRATOR_SET, 1, VIBRATOR_SET, 0),
360 PM8607_LDO(14, LDO14, 0, SUPPLIES_EN12, 6),
363 static int __devinit pm8607_regulator_probe(struct platform_device *pdev)
365 struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
366 struct pm8607_regulator_info *info = NULL;
367 struct regulator_init_data *pdata = pdev->dev.platform_data;
368 struct resource *res;
371 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
373 dev_err(&pdev->dev, "No I/O resource!\n");
376 for (i = 0; i < ARRAY_SIZE(pm8607_regulator_info); i++) {
377 info = &pm8607_regulator_info[i];
378 if (info->desc.id == res->start)
381 if (i == ARRAY_SIZE(pm8607_regulator_info)) {
382 dev_err(&pdev->dev, "Failed to find regulator %llu\n",
383 (unsigned long long)res->start);
386 info->i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
389 /* check DVC ramp slope double */
390 if ((i == PM8607_ID_BUCK3) && info->chip->buck3_double)
391 info->slope_double = 1;
393 /* replace driver_data with info */
394 info->regulator = regulator_register(&info->desc, &pdev->dev,
396 if (IS_ERR(info->regulator)) {
397 dev_err(&pdev->dev, "failed to register regulator %s\n",
399 return PTR_ERR(info->regulator);
402 platform_set_drvdata(pdev, info);
406 static int __devexit pm8607_regulator_remove(struct platform_device *pdev)
408 struct pm8607_regulator_info *info = platform_get_drvdata(pdev);
410 platform_set_drvdata(pdev, NULL);
411 regulator_unregister(info->regulator);
415 static struct platform_driver pm8607_regulator_driver = {
417 .name = "88pm860x-regulator",
418 .owner = THIS_MODULE,
420 .probe = pm8607_regulator_probe,
421 .remove = __devexit_p(pm8607_regulator_remove),
424 static int __init pm8607_regulator_init(void)
426 return platform_driver_register(&pm8607_regulator_driver);
428 subsys_initcall(pm8607_regulator_init);
430 static void __exit pm8607_regulator_exit(void)
432 platform_driver_unregister(&pm8607_regulator_driver);
434 module_exit(pm8607_regulator_exit);
436 MODULE_LICENSE("GPL");
437 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
438 MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
439 MODULE_ALIAS("platform:88pm8607-regulator");