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
;
35 static const unsigned int BUCK1_table
[] = {
36 725000, 750000, 775000, 800000, 825000, 850000, 875000, 900000,
37 925000, 950000, 975000, 1000000, 1025000, 1050000, 1075000, 1100000,
38 1125000, 1150000, 1175000, 1200000, 1225000, 1250000, 1275000, 1300000,
39 1325000, 1350000, 1375000, 1400000, 1425000, 1450000, 1475000, 1500000,
40 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
41 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
42 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
43 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
46 static const unsigned int BUCK1_suspend_table
[] = {
47 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
48 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
49 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
50 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
51 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000,
52 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
53 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
54 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
57 static const unsigned int BUCK2_table
[] = {
58 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000,
59 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000,
60 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000,
61 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
62 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
63 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
64 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
65 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
68 static const unsigned int BUCK2_suspend_table
[] = {
69 0, 50000, 100000, 150000, 200000, 250000, 300000, 350000,
70 400000, 450000, 500000, 550000, 600000, 650000, 700000, 750000,
71 800000, 850000, 900000, 950000, 1000000, 1050000, 1100000, 1150000,
72 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000,
73 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000,
74 2000000, 2050000, 2100000, 2150000, 2200000, 2250000, 2300000, 2350000,
75 2400000, 2450000, 2500000, 2550000, 2600000, 2650000, 2700000, 2750000,
76 2800000, 2850000, 2900000, 2950000, 3000000, 3000000, 3000000, 3000000,
79 static const unsigned int BUCK3_table
[] = {
80 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
81 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
82 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
83 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
84 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000,
85 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
86 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
87 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
90 static const unsigned int BUCK3_suspend_table
[] = {
91 0, 25000, 50000, 75000, 100000, 125000, 150000, 175000,
92 200000, 225000, 250000, 275000, 300000, 325000, 350000, 375000,
93 400000, 425000, 450000, 475000, 500000, 525000, 550000, 575000,
94 600000, 625000, 650000, 675000, 700000, 725000, 750000, 775000,
95 800000, 825000, 850000, 875000, 900000, 925000, 950000, 975000,
96 1000000, 1025000, 1050000, 1075000, 1100000, 1125000, 1150000, 1175000,
97 1200000, 1225000, 1250000, 1275000, 1300000, 1325000, 1350000, 1375000,
98 1400000, 1425000, 1450000, 1475000, 1500000, 1500000, 1500000, 1500000,
101 static const unsigned int LDO1_table
[] = {
102 1800000, 1200000, 2800000, 0,
105 static const unsigned int LDO1_suspend_table
[] = {
106 1800000, 1200000, 0, 0,
109 static const unsigned int LDO2_table
[] = {
110 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
113 static const unsigned int LDO2_suspend_table
[] = {
114 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
117 static const unsigned int LDO3_table
[] = {
118 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
121 static const unsigned int LDO3_suspend_table
[] = {
122 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
125 static const unsigned int LDO4_table
[] = {
126 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 3300000,
129 static const unsigned int LDO4_suspend_table
[] = {
130 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2900000, 2900000,
133 static const unsigned int LDO5_table
[] = {
134 2900000, 3000000, 3100000, 3300000,
137 static const unsigned int LDO5_suspend_table
[] = {
141 static const unsigned int LDO6_table
[] = {
142 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 3300000,
145 static const unsigned int LDO6_suspend_table
[] = {
146 1800000, 1850000, 2600000, 2650000, 2700000, 2750000, 2800000, 2900000,
149 static const unsigned int LDO7_table
[] = {
150 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
153 static const unsigned int LDO7_suspend_table
[] = {
154 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
157 static const unsigned int LDO8_table
[] = {
158 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
161 static const unsigned int LDO8_suspend_table
[] = {
162 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
165 static const unsigned int LDO9_table
[] = {
166 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
169 static const unsigned int LDO9_suspend_table
[] = {
170 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
173 static const unsigned int LDO10_table
[] = {
174 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 3300000,
175 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
178 static const unsigned int LDO10_suspend_table
[] = {
179 1800000, 1850000, 1900000, 2700000, 2750000, 2800000, 2850000, 2900000,
180 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
183 static const unsigned int LDO12_table
[] = {
184 1800000, 1900000, 2700000, 2800000, 2900000, 3000000, 3100000, 3300000,
185 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
188 static const unsigned int LDO12_suspend_table
[] = {
189 1800000, 1900000, 2700000, 2800000, 2900000, 2900000, 2900000, 2900000,
190 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000, 1200000,
193 static const unsigned int LDO13_table
[] = {
194 1200000, 1300000, 1800000, 2000000, 2500000, 2800000, 3000000, 0,
197 static const unsigned int LDO13_suspend_table
[] = {
201 static const unsigned int LDO14_table
[] = {
202 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 3300000,
205 static const unsigned int LDO14_suspend_table
[] = {
206 1800000, 1850000, 2700000, 2750000, 2800000, 2850000, 2900000, 2900000,
209 static int pm8607_list_voltage(struct regulator_dev
*rdev
, unsigned index
)
211 struct pm8607_regulator_info
*info
= rdev_get_drvdata(rdev
);
214 if (info
->vol_table
&& (index
< rdev
->desc
->n_voltages
)) {
215 ret
= info
->vol_table
[index
];
216 if (info
->slope_double
)
222 static int pm8607_set_voltage_sel(struct regulator_dev
*rdev
, unsigned selector
)
224 struct pm8607_regulator_info
*info
= rdev_get_drvdata(rdev
);
228 val
= (uint8_t)(selector
<< (ffs(rdev
->desc
->vsel_mask
) - 1));
230 ret
= pm860x_set_bits(info
->i2c
, rdev
->desc
->vsel_reg
,
231 rdev
->desc
->vsel_mask
, val
);
234 switch (info
->desc
.id
) {
235 case PM8607_ID_BUCK1
:
236 case PM8607_ID_BUCK3
:
237 ret
= pm860x_set_bits(info
->i2c
, info
->update_reg
,
238 1 << info
->update_bit
,
239 1 << info
->update_bit
);
245 static struct regulator_ops pm8607_regulator_ops
= {
246 .list_voltage
= pm8607_list_voltage
,
247 .set_voltage_sel
= pm8607_set_voltage_sel
,
248 .get_voltage_sel
= regulator_get_voltage_sel_regmap
,
249 .enable
= regulator_enable_regmap
,
250 .disable
= regulator_disable_regmap
,
251 .is_enabled
= regulator_is_enabled_regmap
,
254 #define PM8607_DVC(vreg, ureg, ubit, ereg, ebit) \
258 .ops = &pm8607_regulator_ops, \
259 .type = REGULATOR_VOLTAGE, \
260 .id = PM8607_ID_##vreg, \
261 .owner = THIS_MODULE, \
262 .n_voltages = ARRAY_SIZE(vreg##_table), \
263 .vsel_reg = PM8607_##vreg, \
264 .vsel_mask = ARRAY_SIZE(vreg##_table) - 1, \
265 .enable_reg = PM8607_##ereg, \
266 .enable_mask = 1 << (ebit), \
268 .update_reg = PM8607_##ureg, \
269 .update_bit = (ubit), \
270 .slope_double = (0), \
271 .vol_table = (unsigned int *)&vreg##_table, \
272 .vol_suspend = (unsigned int *)&vreg##_suspend_table, \
275 #define PM8607_LDO(_id, vreg, shift, ereg, ebit) \
278 .name = "LDO" #_id, \
279 .ops = &pm8607_regulator_ops, \
280 .type = REGULATOR_VOLTAGE, \
281 .id = PM8607_ID_LDO##_id, \
282 .owner = THIS_MODULE, \
283 .n_voltages = ARRAY_SIZE(LDO##_id##_table), \
284 .vsel_reg = PM8607_##vreg, \
285 .vsel_mask = (ARRAY_SIZE(LDO##_id##_table) - 1) << (shift), \
286 .enable_reg = PM8607_##ereg, \
287 .enable_mask = 1 << (ebit), \
289 .slope_double = (0), \
290 .vol_table = (unsigned int *)&LDO##_id##_table, \
291 .vol_suspend = (unsigned int *)&LDO##_id##_suspend_table, \
294 static struct pm8607_regulator_info pm8607_regulator_info
[] = {
295 PM8607_DVC(BUCK1
, GO
, 0, SUPPLIES_EN11
, 0),
296 PM8607_DVC(BUCK2
, GO
, 1, SUPPLIES_EN11
, 1),
297 PM8607_DVC(BUCK3
, GO
, 2, SUPPLIES_EN11
, 2),
299 PM8607_LDO(1, LDO1
, 0, SUPPLIES_EN11
, 3),
300 PM8607_LDO(2, LDO2
, 0, SUPPLIES_EN11
, 4),
301 PM8607_LDO(3, LDO3
, 0, SUPPLIES_EN11
, 5),
302 PM8607_LDO(4, LDO4
, 0, SUPPLIES_EN11
, 6),
303 PM8607_LDO(5, LDO5
, 0, SUPPLIES_EN11
, 7),
304 PM8607_LDO(6, LDO6
, 0, SUPPLIES_EN12
, 0),
305 PM8607_LDO(7, LDO7
, 0, SUPPLIES_EN12
, 1),
306 PM8607_LDO(8, LDO8
, 0, SUPPLIES_EN12
, 2),
307 PM8607_LDO(9, LDO9
, 0, SUPPLIES_EN12
, 3),
308 PM8607_LDO(10, LDO10
, 0, SUPPLIES_EN12
, 4),
309 PM8607_LDO(12, LDO12
, 0, SUPPLIES_EN12
, 5),
310 PM8607_LDO(13, VIBRATOR_SET
, 1, VIBRATOR_SET
, 0),
311 PM8607_LDO(14, LDO14
, 0, SUPPLIES_EN12
, 6),
314 static int __devinit
pm8607_regulator_probe(struct platform_device
*pdev
)
316 struct pm860x_chip
*chip
= dev_get_drvdata(pdev
->dev
.parent
);
317 struct pm8607_regulator_info
*info
= NULL
;
318 struct regulator_init_data
*pdata
= pdev
->dev
.platform_data
;
319 struct regulator_config config
= { };
320 struct resource
*res
;
323 res
= platform_get_resource(pdev
, IORESOURCE_IO
, 0);
325 dev_err(&pdev
->dev
, "No I/O resource!\n");
328 for (i
= 0; i
< ARRAY_SIZE(pm8607_regulator_info
); i
++) {
329 info
= &pm8607_regulator_info
[i
];
330 if (info
->desc
.id
== res
->start
)
333 if (i
== ARRAY_SIZE(pm8607_regulator_info
)) {
334 dev_err(&pdev
->dev
, "Failed to find regulator %llu\n",
335 (unsigned long long)res
->start
);
338 info
->i2c
= (chip
->id
== CHIP_PM8607
) ? chip
->client
: chip
->companion
;
341 /* check DVC ramp slope double */
342 if ((i
== PM8607_ID_BUCK3
) && info
->chip
->buck3_double
)
343 info
->slope_double
= 1;
345 config
.dev
= &pdev
->dev
;
346 config
.init_data
= pdata
;
347 config
.driver_data
= info
;
349 if (chip
->id
== CHIP_PM8607
)
350 config
.regmap
= chip
->regmap
;
352 config
.regmap
= chip
->regmap_companion
;
354 /* replace driver_data with info */
355 info
->regulator
= regulator_register(&info
->desc
, &config
);
356 if (IS_ERR(info
->regulator
)) {
357 dev_err(&pdev
->dev
, "failed to register regulator %s\n",
359 return PTR_ERR(info
->regulator
);
362 platform_set_drvdata(pdev
, info
);
366 static int __devexit
pm8607_regulator_remove(struct platform_device
*pdev
)
368 struct pm8607_regulator_info
*info
= platform_get_drvdata(pdev
);
370 platform_set_drvdata(pdev
, NULL
);
371 regulator_unregister(info
->regulator
);
375 static struct platform_driver pm8607_regulator_driver
= {
377 .name
= "88pm860x-regulator",
378 .owner
= THIS_MODULE
,
380 .probe
= pm8607_regulator_probe
,
381 .remove
= __devexit_p(pm8607_regulator_remove
),
384 static int __init
pm8607_regulator_init(void)
386 return platform_driver_register(&pm8607_regulator_driver
);
388 subsys_initcall(pm8607_regulator_init
);
390 static void __exit
pm8607_regulator_exit(void)
392 platform_driver_unregister(&pm8607_regulator_driver
);
394 module_exit(pm8607_regulator_exit
);
396 MODULE_LICENSE("GPL");
397 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
398 MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM8607 PMIC");
399 MODULE_ALIAS("platform:88pm8607-regulator");