aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChao Xie <chao.xie@marvell.com>2013-07-17 23:07:03 -0400
committerMark Brown <broonie@linaro.org>2013-07-19 14:08:36 -0400
commit95f1dc08c6f98a62b5dae6ed86fa04f40fb6b34f (patch)
treec365a36eac72cccef1c022954b5e86c97f72c561
parente54e6aa245c8a3d349b133bea4f5ad3d491465c9 (diff)
regulator: 88pm800: add regulator driver for 88pm800
Add the regulator driver for PMIC 88pm800 including device tree support. 88pm800 is an I2C-based power-management IC containing voltage regulators, a real-time clock, and some general purpose ADC devices, Signed-off-by: Yi Zhang <yizhang@marvell.com> Signed-off-by: Chao Xie <chao.xie@marvell.com> Signed-off-by: Mark Brown <broonie@linaro.org>
-rw-r--r--Documentation/devicetree/bindings/regulator/88pm800.txt38
-rw-r--r--drivers/regulator/88pm800.c377
-rw-r--r--drivers/regulator/Kconfig10
-rw-r--r--drivers/regulator/Makefile1
4 files changed, 426 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/regulator/88pm800.txt b/Documentation/devicetree/bindings/regulator/88pm800.txt
new file mode 100644
index 000000000000..e8a54c2a5821
--- /dev/null
+++ b/Documentation/devicetree/bindings/regulator/88pm800.txt
@@ -0,0 +1,38 @@
1Marvell 88PM800 regulator
2
3Required properties:
4- compatible: "marvell,88pm800"
5- reg: I2C slave address
6- regulators: A node that houses a sub-node for each regulator within the
7 device. Each sub-node is identified using the node's name (or the deprecated
8 regulator-compatible property if present), with valid values listed below.
9 The content of each sub-node is defined by the standard binding for
10 regulators; see regulator.txt.
11
12The valid names for regulators are:
13
14 buck1, buck2, buck3, buck4, buck5, ldo1, ldo2, ldo3, ldo4, ldo5, ldo6, ldo7,
15 ldo8, ldo9, ldo10, ldo11, ldo12, ldo13, ldo14, ldo15, ldo16, ldo17, ldo18, ldo19
16
17Example:
18
19 pmic: 88pm800@31 {
20 compatible = "marvell,88pm800";
21 reg = <0x31>;
22
23 regulators {
24 buck1 {
25 regulator-min-microvolt = <600000>;
26 regulator-max-microvolt = <3950000>;
27 regulator-boot-on;
28 regulator-always-on;
29 };
30 ldo1 {
31 regulator-min-microvolt = <600000>;
32 regulator-max-microvolt = <15000000>;
33 regulator-boot-on;
34 regulator-always-on;
35 };
36...
37 };
38 };
diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c
new file mode 100644
index 000000000000..a7d962f7a9b4
--- /dev/null
+++ b/drivers/regulator/88pm800.c
@@ -0,0 +1,377 @@
1/*
2 * Regulators driver for Marvell 88PM800
3 *
4 * Copyright (C) 2012 Marvell International Ltd.
5 * Joseph(Yossi) Hanin <yhanin@marvell.com>
6 * Yi Zhang <yizhang@marvell.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#include <linux/module.h>
13#include <linux/moduleparam.h>
14#include <linux/init.h>
15#include <linux/err.h>
16#include <linux/regmap.h>
17#include <linux/regulator/driver.h>
18#include <linux/regulator/machine.h>
19#include <linux/mfd/88pm80x.h>
20#include <linux/delay.h>
21#include <linux/io.h>
22#include <linux/of.h>
23#include <linux/regulator/of_regulator.h>
24
25/* LDO1 with DVC[0..3] */
26#define PM800_LDO1_VOUT (0x08) /* VOUT1 */
27#define PM800_LDO1_VOUT_2 (0x09)
28#define PM800_LDO1_VOUT_3 (0x0A)
29#define PM800_LDO2_VOUT (0x0B)
30#define PM800_LDO3_VOUT (0x0C)
31#define PM800_LDO4_VOUT (0x0D)
32#define PM800_LDO5_VOUT (0x0E)
33#define PM800_LDO6_VOUT (0x0F)
34#define PM800_LDO7_VOUT (0x10)
35#define PM800_LDO8_VOUT (0x11)
36#define PM800_LDO9_VOUT (0x12)
37#define PM800_LDO10_VOUT (0x13)
38#define PM800_LDO11_VOUT (0x14)
39#define PM800_LDO12_VOUT (0x15)
40#define PM800_LDO13_VOUT (0x16)
41#define PM800_LDO14_VOUT (0x17)
42#define PM800_LDO15_VOUT (0x18)
43#define PM800_LDO16_VOUT (0x19)
44#define PM800_LDO17_VOUT (0x1A)
45#define PM800_LDO18_VOUT (0x1B)
46#define PM800_LDO19_VOUT (0x1C)
47
48/* BUCK1 with DVC[0..3] */
49#define PM800_BUCK1 (0x3C)
50#define PM800_BUCK1_1 (0x3D)
51#define PM800_BUCK1_2 (0x3E)
52#define PM800_BUCK1_3 (0x3F)
53#define PM800_BUCK2 (0x40)
54#define PM800_BUCK3 (0x41)
55#define PM800_BUCK3 (0x41)
56#define PM800_BUCK4 (0x42)
57#define PM800_BUCK4_1 (0x43)
58#define PM800_BUCK4_2 (0x44)
59#define PM800_BUCK4_3 (0x45)
60#define PM800_BUCK5 (0x46)
61
62#define PM800_BUCK_ENA (0x50)
63#define PM800_LDO_ENA1_1 (0x51)
64#define PM800_LDO_ENA1_2 (0x52)
65#define PM800_LDO_ENA1_3 (0x53)
66
67#define PM800_LDO_ENA2_1 (0x56)
68#define PM800_LDO_ENA2_2 (0x57)
69#define PM800_LDO_ENA2_3 (0x58)
70
71#define PM800_BUCK1_MISC1 (0x78)
72#define PM800_BUCK3_MISC1 (0x7E)
73#define PM800_BUCK4_MISC1 (0x81)
74#define PM800_BUCK5_MISC1 (0x84)
75
76struct pm800_regulator_info {
77 struct regulator_desc desc;
78 int max_ua;
79};
80
81struct pm800_regulators {
82 struct regulator_dev *regulators[PM800_ID_RG_MAX];
83 struct pm80x_chip *chip;
84 struct regmap *map;
85};
86
87/*
88 * vreg - the buck regs string.
89 * ereg - the string for the enable register.
90 * ebit - the bit number in the enable register.
91 * amax - the current
92 * Buck has 2 kinds of voltage steps. It is easy to find voltage by ranges,
93 * not the constant voltage table.
94 */
95#define PM800_BUCK(vreg, ereg, ebit, amax, volt_ranges) \
96{ \
97 .desc = { \
98 .name = #vreg, \
99 .ops = &pm800_volt_range_ops, \
100 .type = REGULATOR_VOLTAGE, \
101 .id = PM800_ID_##vreg, \
102 .owner = THIS_MODULE, \
103 .linear_ranges = volt_ranges, \
104 .n_linear_ranges = ARRAY_SIZE(volt_ranges), \
105 .vsel_reg = PM800_##vreg, \
106 .vsel_mask = 0x7f, \
107 .enable_reg = PM800_##ereg, \
108 .enable_mask = 1 << (ebit), \
109 }, \
110 .max_ua = (amax), \
111}
112
113/*
114 * vreg - the LDO regs string
115 * ereg - the string for the enable register.
116 * ebit - the bit number in the enable register.
117 * amax - the current
118 * volt_table - the LDO voltage table
119 * For all the LDOes, there are too many ranges. Using volt_table will be
120 * simpler and faster.
121 */
122#define PM800_LDO(vreg, ereg, ebit, amax, ldo_volt_table) \
123{ \
124 .desc = { \
125 .name = #vreg, \
126 .ops = &pm800_volt_table_ops, \
127 .type = REGULATOR_VOLTAGE, \
128 .id = PM800_ID_##vreg, \
129 .owner = THIS_MODULE, \
130 .n_voltages = ARRAY_SIZE(ldo_volt_table), \
131 .vsel_reg = PM800_##vreg##_VOUT, \
132 .vsel_mask = 0x1f, \
133 .enable_reg = PM800_##ereg, \
134 .enable_mask = 1 << (ebit), \
135 .volt_table = ldo_volt_table, \
136 }, \
137 .max_ua = (amax), \
138}
139
140/* Ranges are sorted in ascending order. */
141static const struct regulator_linear_range buck1_volt_range[] = {
142 { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f,
143 .uV_step = 12500 },
144 { .min_uV = 1600000, .max_uV = 1800000, .min_sel = 0x50,
145 .max_sel = 0x54, .uV_step = 50000 },
146};
147
148/* BUCK 2~5 have same ranges. */
149static const struct regulator_linear_range buck2_5_volt_range[] = {
150 { .min_uV = 600000, .max_uV = 1587500, .min_sel = 0, .max_sel = 0x4f,
151 .uV_step = 12500 },
152 { .min_uV = 1600000, .max_uV = 3300000, .min_sel = 0x50,
153 .max_sel = 0x72, .uV_step = 50000 },
154};
155
156static const unsigned int ldo1_volt_table[] = {
157 600000, 650000, 700000, 750000, 800000, 850000, 900000, 950000,
158 1000000, 1050000, 1100000, 1150000, 1200000, 1300000, 1400000, 1500000,
159};
160
161static const unsigned int ldo2_volt_table[] = {
162 1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2700000, 2800000,
163};
164
165/* LDO 3~17 have same voltage table. */
166static const unsigned int ldo3_17_volt_table[] = {
167 1200000, 1250000, 1700000, 1800000, 1850000, 1900000, 2500000, 2600000,
168 2700000, 2750000, 2800000, 2850000, 2900000, 3000000, 3100000, 3300000,
169};
170
171/* LDO 18~19 have same voltage table. */
172static const unsigned int ldo18_19_volt_table[] = {
173 1700000, 1800000, 1900000, 2500000, 2800000, 2900000, 3100000, 3300000,
174};
175
176static int pm800_get_current_limit(struct regulator_dev *rdev)
177{
178 struct pm800_regulator_info *info = rdev_get_drvdata(rdev);
179
180 return info->max_ua;
181}
182
183static struct regulator_ops pm800_volt_range_ops = {
184 .list_voltage = regulator_list_voltage_linear_range,
185 .map_voltage = regulator_map_voltage_linear_range,
186 .set_voltage_sel = regulator_set_voltage_sel_regmap,
187 .get_voltage_sel = regulator_get_voltage_sel_regmap,
188 .enable = regulator_enable_regmap,
189 .disable = regulator_disable_regmap,
190 .is_enabled = regulator_is_enabled_regmap,
191 .get_current_limit = pm800_get_current_limit,
192};
193
194static struct regulator_ops pm800_volt_table_ops = {
195 .list_voltage = regulator_list_voltage_table,
196 .map_voltage = regulator_map_voltage_iterate,
197 .set_voltage_sel = regulator_set_voltage_sel_regmap,
198 .get_voltage_sel = regulator_get_voltage_sel_regmap,
199 .enable = regulator_enable_regmap,
200 .disable = regulator_disable_regmap,
201 .is_enabled = regulator_is_enabled_regmap,
202 .get_current_limit = pm800_get_current_limit,
203};
204
205/* The array is indexed by id(PM800_ID_XXX) */
206static struct pm800_regulator_info pm800_regulator_info[] = {
207 PM800_BUCK(BUCK1, BUCK_ENA, 0, 3000000, buck1_volt_range),
208 PM800_BUCK(BUCK2, BUCK_ENA, 1, 1200000, buck2_5_volt_range),
209 PM800_BUCK(BUCK3, BUCK_ENA, 2, 1200000, buck2_5_volt_range),
210 PM800_BUCK(BUCK4, BUCK_ENA, 3, 1200000, buck2_5_volt_range),
211 PM800_BUCK(BUCK5, BUCK_ENA, 4, 1200000, buck2_5_volt_range),
212
213 PM800_LDO(LDO1, LDO_ENA1_1, 0, 200000, ldo1_volt_table),
214 PM800_LDO(LDO2, LDO_ENA1_1, 1, 10000, ldo2_volt_table),
215 PM800_LDO(LDO3, LDO_ENA1_1, 2, 300000, ldo3_17_volt_table),
216 PM800_LDO(LDO4, LDO_ENA1_1, 3, 300000, ldo3_17_volt_table),
217 PM800_LDO(LDO5, LDO_ENA1_1, 4, 300000, ldo3_17_volt_table),
218 PM800_LDO(LDO6, LDO_ENA1_1, 5, 300000, ldo3_17_volt_table),
219 PM800_LDO(LDO7, LDO_ENA1_1, 6, 300000, ldo3_17_volt_table),
220 PM800_LDO(LDO8, LDO_ENA1_1, 7, 300000, ldo3_17_volt_table),
221 PM800_LDO(LDO9, LDO_ENA1_2, 0, 300000, ldo3_17_volt_table),
222 PM800_LDO(LDO10, LDO_ENA1_2, 1, 300000, ldo3_17_volt_table),
223 PM800_LDO(LDO11, LDO_ENA1_2, 2, 300000, ldo3_17_volt_table),
224 PM800_LDO(LDO12, LDO_ENA1_2, 3, 300000, ldo3_17_volt_table),
225 PM800_LDO(LDO13, LDO_ENA1_2, 4, 300000, ldo3_17_volt_table),
226 PM800_LDO(LDO14, LDO_ENA1_2, 5, 300000, ldo3_17_volt_table),
227 PM800_LDO(LDO15, LDO_ENA1_2, 6, 300000, ldo3_17_volt_table),
228 PM800_LDO(LDO16, LDO_ENA1_2, 7, 300000, ldo3_17_volt_table),
229 PM800_LDO(LDO17, LDO_ENA1_3, 0, 300000, ldo3_17_volt_table),
230 PM800_LDO(LDO18, LDO_ENA1_3, 1, 200000, ldo18_19_volt_table),
231 PM800_LDO(LDO19, LDO_ENA1_3, 2, 200000, ldo18_19_volt_table),
232};
233
234#define PM800_REGULATOR_OF_MATCH(_name, _id) \
235 [PM800_ID_##_id] = { \
236 .name = #_name, \
237 .driver_data = &pm800_regulator_info[PM800_ID_##_id], \
238 }
239
240static struct of_regulator_match pm800_regulator_matches[] = {
241 PM800_REGULATOR_OF_MATCH(buck1, BUCK1),
242 PM800_REGULATOR_OF_MATCH(buck2, BUCK2),
243 PM800_REGULATOR_OF_MATCH(buck3, BUCK3),
244 PM800_REGULATOR_OF_MATCH(buck4, BUCK4),
245 PM800_REGULATOR_OF_MATCH(buck5, BUCK5),
246 PM800_REGULATOR_OF_MATCH(ldo1, LDO1),
247 PM800_REGULATOR_OF_MATCH(ldo2, LDO2),
248 PM800_REGULATOR_OF_MATCH(ldo3, LDO3),
249 PM800_REGULATOR_OF_MATCH(ldo4, LDO4),
250 PM800_REGULATOR_OF_MATCH(ldo5, LDO5),
251 PM800_REGULATOR_OF_MATCH(ldo6, LDO6),
252 PM800_REGULATOR_OF_MATCH(ldo7, LDO7),
253 PM800_REGULATOR_OF_MATCH(ldo8, LDO8),
254 PM800_REGULATOR_OF_MATCH(ldo9, LDO9),
255 PM800_REGULATOR_OF_MATCH(ldo10, LDO10),
256 PM800_REGULATOR_OF_MATCH(ldo11, LDO11),
257 PM800_REGULATOR_OF_MATCH(ldo12, LDO12),
258 PM800_REGULATOR_OF_MATCH(ldo13, LDO13),
259 PM800_REGULATOR_OF_MATCH(ldo14, LDO14),
260 PM800_REGULATOR_OF_MATCH(ldo15, LDO15),
261 PM800_REGULATOR_OF_MATCH(ldo16, LDO16),
262 PM800_REGULATOR_OF_MATCH(ldo17, LDO17),
263 PM800_REGULATOR_OF_MATCH(ldo18, LDO18),
264 PM800_REGULATOR_OF_MATCH(ldo19, LDO19),
265};
266
267static int pm800_regulator_dt_init(struct platform_device *pdev)
268{
269 struct device_node *np = pdev->dev.of_node;
270 int ret;
271
272 ret = of_regulator_match(&pdev->dev, np,
273 pm800_regulator_matches,
274 ARRAY_SIZE(pm800_regulator_matches));
275 if (ret < 0)
276 return ret;
277
278 return 0;
279}
280
281static int pm800_regulator_probe(struct platform_device *pdev)
282{
283 struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
284 struct pm80x_platform_data *pdata = pdev->dev.parent->platform_data;
285 struct pm800_regulators *pm800_data;
286 struct pm800_regulator_info *info;
287 struct regulator_config config = { };
288 struct regulator_init_data *init_data;
289 int i, ret;
290
291 if (!pdata || pdata->num_regulators == 0) {
292 if (IS_ENABLED(CONFIG_OF)) {
293 ret = pm800_regulator_dt_init(pdev);
294 if (ret)
295 return ret;
296 } else {
297 return -ENODEV;
298 }
299 } else if (pdata->num_regulators) {
300 /* Check whether num_regulator is valid. */
301 unsigned int count = 0;
302 for (i = 0; pdata->regulators[i]; i++)
303 count++;
304 if (count != pdata->num_regulators)
305 return -EINVAL;
306 } else {
307 return -EINVAL;
308 }
309
310 pm800_data = devm_kzalloc(&pdev->dev, sizeof(*pm800_data),
311 GFP_KERNEL);
312 if (!pm800_data) {
313 dev_err(&pdev->dev, "Failed to allocate pm800_regualtors");
314 return -ENOMEM;
315 }
316
317 pm800_data->map = chip->subchip->regmap_power;
318 pm800_data->chip = chip;
319
320 platform_set_drvdata(pdev, pm800_data);
321
322 for (i = 0; i < PM800_ID_RG_MAX; i++) {
323 if (!pdata || pdata->num_regulators == 0)
324 init_data = pm800_regulator_matches[i].init_data;
325 else
326 init_data = pdata->regulators[i];
327 if (!init_data)
328 continue;
329 info = pm800_regulator_matches[i].driver_data;
330 config.dev = &pdev->dev;
331 config.init_data = init_data;
332 config.driver_data = info;
333 config.regmap = pm800_data->map;
334
335 pm800_data->regulators[i] =
336 regulator_register(&info->desc, &config);
337 if (IS_ERR(pm800_data->regulators[i])) {
338 ret = PTR_ERR(pm800_data->regulators[i]);
339 dev_err(&pdev->dev, "Failed to register %s\n",
340 info->desc.name);
341
342 while (--i >= 0)
343 regulator_unregister(pm800_data->regulators[i]);
344
345 return ret;
346 }
347 }
348
349 return 0;
350}
351
352static int pm800_regulator_remove(struct platform_device *pdev)
353{
354 struct pm800_regulators *pm800_data = platform_get_drvdata(pdev);
355 int i;
356
357 for (i = 0; i < PM800_ID_RG_MAX; i++)
358 regulator_unregister(pm800_data->regulators[i]);
359
360 return 0;
361}
362
363static struct platform_driver pm800_regulator_driver = {
364 .driver = {
365 .name = "88pm80x-regulator",
366 .owner = THIS_MODULE,
367 },
368 .probe = pm800_regulator_probe,
369 .remove = pm800_regulator_remove,
370};
371
372module_platform_driver(pm800_regulator_driver);
373
374MODULE_LICENSE("GPL");
375MODULE_AUTHOR("Joseph(Yossi) Hanin <yhanin@marvell.com>");
376MODULE_DESCRIPTION("Regulator Driver for Marvell 88PM800 PMIC");
377MODULE_ALIAS("platform:88pm800-regulator");
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 759b601b54ef..65b7d5b1bb39 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -64,6 +64,16 @@ config REGULATOR_USERSPACE_CONSUMER
64 64
65 If unsure, say no. 65 If unsure, say no.
66 66
67config REGULATOR_88PM800
68 tristate "Marvell 88PM800 Power regulators"
69 depends on MFD_88PM800=y
70 help
71 This driver supports Marvell 88PM800 voltage regulator chips.
72 It delivers digitally programmable output,
73 the voltage is programmed via I2C interface.
74 It's suitable to support PXA988 chips to control VCC_MAIN and
75 various voltages.
76
67config REGULATOR_88PM8607 77config REGULATOR_88PM8607
68 bool "Marvell 88PM8607 Power regulators" 78 bool "Marvell 88PM8607 Power regulators"
69 depends on MFD_88PM860X=y 79 depends on MFD_88PM860X=y
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index d240772d90ee..e292f26a1fbd 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
9obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o 9obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
10obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o 10obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o
11 11
12obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o
12obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o 13obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o
13obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o 14obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o
14obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o 15obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o