aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorGyungoh Yoo <jack.yoo@maxim-ic.com>2012-08-09 16:24:34 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-08-28 14:00:28 -0400
commitffee19091a4e0c5dae0e83a6e0927c0f5c554537 (patch)
tree13093eb53df177798b2268cb3def839e28d1d4b2 /drivers/regulator
parent0ffff5a60fdd7455c83855ee788a8aae9a79aab4 (diff)
regulator: add MAX8907 driver
The MAX8907 is an I2C-based power-management IC containing voltage regulators, a reset controller, a real-time clock, and a touch-screen controller. The original driver was written by: * Gyungoh Yoo <jack.yoo@maxim-ic.com> Various fixes and enhancements by: * Jin Park <jinyoungp@nvidia.com> * Tom Cherry <tcherry@nvidia.com> * Prashant Gaikwad <pgaikwad@nvidia.com> * Dan Willemsen <dwillemsen@nvidia.com> * Laxman Dewangan <ldewangan@nvidia.com> During upstreaming, I (swarren): * Converted to regmap. * Allowed probing from device tree. * Reworked the regulator driver to be represented as a single device that provides multiple regulators, rather than as a device per regulator. * Replaced many regulator ops with standard functions. * Added ability to specify supplies for each regulator. * Removed the WLED regulator. If/when we expose this in the driver, it should be a backlight object not a regulator object. * Renamed from max8907c->max8907, since the driver covers at least the C and B revisions. * General cleanup. Signed-off-by: Gyungoh Yoo <jack.yoo@maxim-ic.com> Signed-off-by: Stephen Warren <swarren@nvidia.com> Acked-by: Laxman Dewangan <ldewangan@nvidia.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig8
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/max8907-regulator.c383
3 files changed, 392 insertions, 0 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 4e932cc695e9..1c6320c131f4 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -172,6 +172,14 @@ config REGULATOR_MAX8660
172 This driver controls a Maxim 8660/8661 voltage output 172 This driver controls a Maxim 8660/8661 voltage output
173 regulator via I2C bus. 173 regulator via I2C bus.
174 174
175config REGULATOR_MAX8907
176 tristate "Maxim 8907 voltage regulator"
177 depends on MFD_MAX8907
178 help
179 This driver controls a Maxim 8907 voltage output regulator
180 via I2C bus. The provided regulator is suitable for Tegra
181 chip to control Step-Down DC-DC and LDOs.
182
175config REGULATOR_MAX8925 183config REGULATOR_MAX8925
176 tristate "Maxim MAX8925 Power Management IC" 184 tristate "Maxim MAX8925 Power Management IC"
177 depends on MFD_MAX8925 185 depends on MFD_MAX8925
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 3342615cf25e..3a0dbc5de66e 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
30obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o 30obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
31obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o 31obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
32obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o 32obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
33obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o
33obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o 34obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
34obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o 35obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
35obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o 36obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
new file mode 100644
index 000000000000..bd3b28b55231
--- /dev/null
+++ b/drivers/regulator/max8907-regulator.c
@@ -0,0 +1,383 @@
1/*
2 * max8907-regulator.c -- support regulators in max8907
3 *
4 * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
5 * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
6 *
7 * Portions based on drivers/regulator/tps65910-regulator.c,
8 * Copyright 2010 Texas Instruments Inc.
9 * Author: Graeme Gregory <gg@slimlogic.co.uk>
10 * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 */
16
17#include <linux/err.h>
18#include <linux/init.h>
19#include <linux/mfd/core.h>
20#include <linux/mfd/max8907.h>
21#include <linux/module.h>
22#include <linux/of.h>
23#include <linux/platform_device.h>
24#include <linux/regulator/driver.h>
25#include <linux/regulator/machine.h>
26#include <linux/regulator/of_regulator.h>
27#include <linux/regmap.h>
28#include <linux/slab.h>
29
30#define MAX8907_II2RR_VERSION_MASK 0xF0
31#define MAX8907_II2RR_VERSION_REV_A 0x00
32#define MAX8907_II2RR_VERSION_REV_B 0x10
33#define MAX8907_II2RR_VERSION_REV_C 0x30
34
35struct max8907_regulator {
36 struct regulator_desc desc[MAX8907_NUM_REGULATORS];
37 struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];
38};
39
40#define REG_MBATT() \
41 [MAX8907_MBATT] = { \
42 .name = "MBATT", \
43 .supply_name = "mbatt", \
44 .id = MAX8907_MBATT, \
45 .ops = &max8907_mbatt_ops, \
46 .type = REGULATOR_VOLTAGE, \
47 .owner = THIS_MODULE, \
48 }
49
50#define REG_LDO(ids, supply, base, min, max, step) \
51 [MAX8907_##ids] = { \
52 .name = #ids, \
53 .supply_name = supply, \
54 .id = MAX8907_##ids, \
55 .n_voltages = ((max) - (min)) / (step) + 1, \
56 .ops = &max8907_ldo_ops, \
57 .type = REGULATOR_VOLTAGE, \
58 .owner = THIS_MODULE, \
59 .min_uV = (min), \
60 .uV_step = (step), \
61 .vsel_reg = (base) + MAX8907_VOUT, \
62 .vsel_mask = 0x3f, \
63 .enable_reg = (base) + MAX8907_CTL, \
64 .enable_mask = MAX8907_MASK_LDO_EN, \
65 }
66
67#define REG_FIXED(ids, supply, voltage) \
68 [MAX8907_##ids] = { \
69 .name = #ids, \
70 .supply_name = supply, \
71 .id = MAX8907_##ids, \
72 .n_voltages = 1, \
73 .ops = &max8907_fixed_ops, \
74 .type = REGULATOR_VOLTAGE, \
75 .owner = THIS_MODULE, \
76 .min_uV = (voltage), \
77 }
78
79#define REG_OUT5V(ids, supply, base, voltage) \
80 [MAX8907_##ids] = { \
81 .name = #ids, \
82 .supply_name = supply, \
83 .id = MAX8907_##ids, \
84 .n_voltages = 1, \
85 .ops = &max8907_out5v_ops, \
86 .type = REGULATOR_VOLTAGE, \
87 .owner = THIS_MODULE, \
88 .min_uV = (voltage), \
89 .enable_reg = (base), \
90 .enable_mask = MAX8907_MASK_OUT5V_EN, \
91 }
92
93#define REG_BBAT(ids, supply, base, min, max, step) \
94 [MAX8907_##ids] = { \
95 .name = #ids, \
96 .supply_name = supply, \
97 .id = MAX8907_##ids, \
98 .n_voltages = ((max) - (min)) / (step) + 1, \
99 .ops = &max8907_bbat_ops, \
100 .type = REGULATOR_VOLTAGE, \
101 .owner = THIS_MODULE, \
102 .min_uV = (min), \
103 .uV_step = (step), \
104 .vsel_reg = (base), \
105 .vsel_mask = MAX8907_MASK_VBBATTCV, \
106 }
107
108#define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), \
109 750000, 3900000, 50000)
110#define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \
111 650000, 2225000, 25000)
112
113static struct regulator_ops max8907_mbatt_ops = {
114};
115
116static struct regulator_ops max8907_ldo_ops = {
117 .list_voltage = regulator_list_voltage_linear,
118 .set_voltage_sel = regulator_set_voltage_sel_regmap,
119 .get_voltage_sel = regulator_get_voltage_sel_regmap,
120 .enable = regulator_enable_regmap,
121 .disable = regulator_disable_regmap,
122 .is_enabled = regulator_is_enabled_regmap,
123};
124
125static struct regulator_ops max8907_ldo_hwctl_ops = {
126 .list_voltage = regulator_list_voltage_linear,
127 .set_voltage_sel = regulator_set_voltage_sel_regmap,
128 .get_voltage_sel = regulator_get_voltage_sel_regmap,
129};
130
131static struct regulator_ops max8907_fixed_ops = {
132 .list_voltage = regulator_list_voltage_linear,
133};
134
135static struct regulator_ops max8907_out5v_ops = {
136 .list_voltage = regulator_list_voltage_linear,
137 .enable = regulator_enable_regmap,
138 .disable = regulator_disable_regmap,
139 .is_enabled = regulator_is_enabled_regmap,
140};
141
142static struct regulator_ops max8907_out5v_hwctl_ops = {
143 .list_voltage = regulator_list_voltage_linear,
144};
145
146static struct regulator_ops max8907_bbat_ops = {
147 .list_voltage = regulator_list_voltage_linear,
148 .set_voltage_sel = regulator_set_voltage_sel_regmap,
149 .get_voltage_sel = regulator_get_voltage_sel_regmap,
150};
151
152static struct regulator_desc max8907_regulators[] = {
153 REG_MBATT(),
154 REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000),
155 REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500),
156 REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000),
157 LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1),
158 LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2),
159 LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3),
160 LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4),
161 LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5),
162 LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6),
163 LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7),
164 LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8),
165 LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9),
166 LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10),
167 LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11),
168 LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12),
169 LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13),
170 LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14),
171 LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15),
172 LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16),
173 LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17),
174 LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18),
175 LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19),
176 LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20),
177 REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000),
178 REG_OUT5V(OUT33V, "mbatt", MAX8907_REG_OUT33VEN, 3300000),
179 REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG,
180 2400000, 3000000, 200000),
181 REG_FIXED(SDBY, "MBATT", 1200000),
182 REG_FIXED(VRTC, "MBATT", 3300000),
183};
184
185#ifdef CONFIG_OF
186
187#define MATCH(_name, _id) \
188 [MAX8907_##_id] = { \
189 .name = #_name, \
190 .driver_data = (void *)&max8907_regulators[MAX8907_##_id], \
191 }
192
193static struct of_regulator_match max8907_matches[] = {
194 MATCH(mbatt, MBATT),
195 MATCH(sd1, SD1),
196 MATCH(sd2, SD2),
197 MATCH(sd3, SD3),
198 MATCH(ldo1, LDO1),
199 MATCH(ldo2, LDO2),
200 MATCH(ldo3, LDO3),
201 MATCH(ldo4, LDO4),
202 MATCH(ldo5, LDO5),
203 MATCH(ldo6, LDO6),
204 MATCH(ldo7, LDO7),
205 MATCH(ldo8, LDO8),
206 MATCH(ldo9, LDO9),
207 MATCH(ldo10, LDO10),
208 MATCH(ldo11, LDO11),
209 MATCH(ldo12, LDO12),
210 MATCH(ldo13, LDO13),
211 MATCH(ldo14, LDO14),
212 MATCH(ldo15, LDO15),
213 MATCH(ldo16, LDO16),
214 MATCH(ldo17, LDO17),
215 MATCH(ldo18, LDO18),
216 MATCH(ldo19, LDO19),
217 MATCH(ldo20, LDO20),
218 MATCH(out5v, OUT5V),
219 MATCH(out33v, OUT33V),
220 MATCH(bbat, BBAT),
221 MATCH(sdby, SDBY),
222 MATCH(vrtc, VRTC),
223};
224
225static int max8907_regulator_parse_dt(struct platform_device *pdev)
226{
227 struct device_node *np = pdev->dev.parent->of_node;
228 struct device_node *regulators;
229 int ret;
230
231 if (!pdev->dev.parent->of_node)
232 return 0;
233
234 regulators = of_find_node_by_name(np, "regulators");
235 if (!regulators) {
236 dev_err(&pdev->dev, "regulators node not found\n");
237 return -EINVAL;
238 }
239
240 ret = of_regulator_match(pdev->dev.parent, regulators,
241 max8907_matches,
242 ARRAY_SIZE(max8907_matches));
243 if (ret < 0) {
244 dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
245 ret);
246 return ret;
247 }
248
249 return 0;
250}
251#else
252static int max8907_regulator_parse_dt(struct platform_device *pdev)
253{
254 return 0;
255}
256#endif
257
258static __devinit int max8907_regulator_probe(struct platform_device *pdev)
259{
260 struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
261 struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
262 int ret;
263 struct max8907_regulator *pmic;
264 unsigned int val;
265 int i;
266 struct regulator_config config = {};
267 struct regulator_init_data *idata;
268 const char *mbatt_rail_name = NULL;
269
270 ret = max8907_regulator_parse_dt(pdev);
271 if (ret)
272 return ret;
273
274 pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
275 if (!pmic) {
276 dev_err(&pdev->dev, "Failed to alloc pmic\n");
277 return -ENOMEM;
278 }
279 platform_set_drvdata(pdev, pmic);
280
281 memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
282
283 /* Backwards compatibility with MAX8907B; SD1 uses different voltages */
284 regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
285 if ((val & MAX8907_II2RR_VERSION_MASK) ==
286 MAX8907_II2RR_VERSION_REV_B) {
287 pmic->desc[MAX8907_SD1].min_uV = 637500;
288 pmic->desc[MAX8907_SD1].uV_step = 12500;
289 pmic->desc[MAX8907_SD1].n_voltages = (1425000 - 637500) / 12500;
290 }
291
292 for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
293 config.dev = pdev->dev.parent;
294 if (pdata)
295 idata = pdata->init_data[i];
296 else
297 idata = max8907_matches[i].init_data;
298 config.init_data = idata;
299 config.driver_data = pmic;
300 config.regmap = max8907->regmap_gen;
301 config.of_node = max8907_matches[i].of_node;
302
303 switch (pmic->desc[i].id) {
304 case MAX8907_MBATT:
305 mbatt_rail_name = idata->constraints.name;
306 break;
307 case MAX8907_BBAT:
308 case MAX8907_SDBY:
309 case MAX8907_VRTC:
310 idata->supply_regulator = mbatt_rail_name;
311 break;
312 }
313
314 if (pmic->desc[i].ops == &max8907_ldo_ops) {
315 regmap_read(config.regmap, pmic->desc[i].enable_reg,
316 &val);
317 if ((val & MAX8907_MASK_LDO_SEQ) !=
318 MAX8907_MASK_LDO_SEQ)
319 pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
320 } else if (pmic->desc[i].ops == &max8907_out5v_ops) {
321 regmap_read(config.regmap, pmic->desc[i].enable_reg,
322 &val);
323 if ((val & (MAX8907_MASK_OUT5V_VINEN |
324 MAX8907_MASK_OUT5V_ENSRC)) !=
325 MAX8907_MASK_OUT5V_ENSRC)
326 pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
327 }
328
329 pmic->rdev[i] = regulator_register(&pmic->desc[i], &config);
330 if (IS_ERR(pmic->rdev[i])) {
331 dev_err(&pdev->dev,
332 "failed to register %s regulator\n",
333 pmic->desc[i].name);
334 ret = PTR_ERR(pmic->rdev[i]);
335 goto err_unregister_regulator;
336 }
337 }
338
339 return 0;
340
341err_unregister_regulator:
342 while (--i >= 0)
343 regulator_unregister(pmic->rdev[i]);
344 return ret;
345}
346
347static __devexit int max8907_regulator_remove(struct platform_device *pdev)
348{
349 struct max8907_regulator *pmic;
350 int i;
351
352 for (i = 0; i < MAX8907_NUM_REGULATORS; i++)
353 regulator_unregister(pmic->rdev[i]);
354
355 return 0;
356}
357
358static struct platform_driver max8907_regulator_driver = {
359 .driver = {
360 .name = "max8907-regulator",
361 .owner = THIS_MODULE,
362 },
363 .probe = max8907_regulator_probe,
364 .remove = __devexit_p(max8907_regulator_remove),
365};
366
367static int __init max8907_regulator_init(void)
368{
369 return platform_driver_register(&max8907_regulator_driver);
370}
371
372subsys_initcall(max8907_regulator_init);
373
374static void __exit max8907_reg_exit(void)
375{
376 platform_driver_unregister(&max8907_regulator_driver);
377}
378
379module_exit(max8907_reg_exit);
380
381MODULE_DESCRIPTION("MAX8907 regulator driver");
382MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
383MODULE_LICENSE("GPL v2");