blob: 4568c15fa78dea0eafda170f64f9fc86db251faa [file] [log] [blame]
Gyungoh Yooffee1902012-08-09 14:24:34 -06001/*
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{
Axel Linc92f5dd2013-01-27 21:16:56 +0800227 struct device_node *np, *regulators;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600228 int ret;
229
Axel Linc92f5dd2013-01-27 21:16:56 +0800230 np = of_node_get(pdev->dev.parent->of_node);
231 if (!np)
Gyungoh Yooffee1902012-08-09 14:24:34 -0600232 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
Axel Linf40cbcb2013-01-25 10:20:29 +0800240 ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
Gyungoh Yooffee1902012-08-09 14:24:34 -0600241 ARRAY_SIZE(max8907_matches));
Axel Linc92f5dd2013-01-27 21:16:56 +0800242 of_node_put(regulators);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600243 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}
Stephen Warrendb551682012-08-20 09:39:10 -0600251
252static inline struct regulator_init_data *match_init_data(int index)
253{
254 return max8907_matches[index].init_data;
255}
256
257static inline struct device_node *match_of_node(int index)
258{
259 return max8907_matches[index].of_node;
260}
Gyungoh Yooffee1902012-08-09 14:24:34 -0600261#else
262static int max8907_regulator_parse_dt(struct platform_device *pdev)
263{
264 return 0;
265}
Stephen Warrendb551682012-08-20 09:39:10 -0600266
267static inline struct regulator_init_data *match_init_data(int index)
268{
269 return NULL;
270}
271
272static inline struct device_node *match_of_node(int index)
273{
274 return NULL;
275}
Gyungoh Yooffee1902012-08-09 14:24:34 -0600276#endif
277
Bill Pembertona5023572012-11-19 13:22:22 -0500278static int max8907_regulator_probe(struct platform_device *pdev)
Gyungoh Yooffee1902012-08-09 14:24:34 -0600279{
280 struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
281 struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
282 int ret;
283 struct max8907_regulator *pmic;
284 unsigned int val;
285 int i;
286 struct regulator_config config = {};
287 struct regulator_init_data *idata;
288 const char *mbatt_rail_name = NULL;
289
290 ret = max8907_regulator_parse_dt(pdev);
291 if (ret)
292 return ret;
293
294 pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
295 if (!pmic) {
296 dev_err(&pdev->dev, "Failed to alloc pmic\n");
297 return -ENOMEM;
298 }
299 platform_set_drvdata(pdev, pmic);
300
301 memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
302
303 /* Backwards compatibility with MAX8907B; SD1 uses different voltages */
304 regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
305 if ((val & MAX8907_II2RR_VERSION_MASK) ==
306 MAX8907_II2RR_VERSION_REV_B) {
307 pmic->desc[MAX8907_SD1].min_uV = 637500;
308 pmic->desc[MAX8907_SD1].uV_step = 12500;
Axel Lin73056082012-08-16 12:26:02 +0800309 pmic->desc[MAX8907_SD1].n_voltages =
310 (1425000 - 637500) / 12500 + 1;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600311 }
312
313 for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
314 config.dev = pdev->dev.parent;
315 if (pdata)
316 idata = pdata->init_data[i];
317 else
Stephen Warrendb551682012-08-20 09:39:10 -0600318 idata = match_init_data(i);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600319 config.init_data = idata;
320 config.driver_data = pmic;
321 config.regmap = max8907->regmap_gen;
Stephen Warrendb551682012-08-20 09:39:10 -0600322 config.of_node = match_of_node(i);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600323
324 switch (pmic->desc[i].id) {
325 case MAX8907_MBATT:
Stephen Warren5fc72f52012-08-23 12:19:18 -0600326 if (idata && idata->constraints.name)
327 mbatt_rail_name = idata->constraints.name;
328 else
329 mbatt_rail_name = pmic->desc[i].name;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600330 break;
331 case MAX8907_BBAT:
332 case MAX8907_SDBY:
333 case MAX8907_VRTC:
334 idata->supply_regulator = mbatt_rail_name;
335 break;
336 }
337
338 if (pmic->desc[i].ops == &max8907_ldo_ops) {
339 regmap_read(config.regmap, pmic->desc[i].enable_reg,
340 &val);
341 if ((val & MAX8907_MASK_LDO_SEQ) !=
342 MAX8907_MASK_LDO_SEQ)
343 pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
344 } else if (pmic->desc[i].ops == &max8907_out5v_ops) {
345 regmap_read(config.regmap, pmic->desc[i].enable_reg,
346 &val);
347 if ((val & (MAX8907_MASK_OUT5V_VINEN |
348 MAX8907_MASK_OUT5V_ENSRC)) !=
349 MAX8907_MASK_OUT5V_ENSRC)
350 pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
351 }
352
353 pmic->rdev[i] = regulator_register(&pmic->desc[i], &config);
354 if (IS_ERR(pmic->rdev[i])) {
355 dev_err(&pdev->dev,
356 "failed to register %s regulator\n",
357 pmic->desc[i].name);
358 ret = PTR_ERR(pmic->rdev[i]);
359 goto err_unregister_regulator;
360 }
361 }
362
363 return 0;
364
365err_unregister_regulator:
366 while (--i >= 0)
367 regulator_unregister(pmic->rdev[i]);
368 return ret;
369}
370
Bill Pemberton8dc995f2012-11-19 13:26:10 -0500371static int max8907_regulator_remove(struct platform_device *pdev)
Gyungoh Yooffee1902012-08-09 14:24:34 -0600372{
Axel Lin0764ef52012-08-18 14:33:05 +0800373 struct max8907_regulator *pmic = platform_get_drvdata(pdev);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600374 int i;
375
376 for (i = 0; i < MAX8907_NUM_REGULATORS; i++)
377 regulator_unregister(pmic->rdev[i]);
378
379 return 0;
380}
381
382static struct platform_driver max8907_regulator_driver = {
383 .driver = {
384 .name = "max8907-regulator",
385 .owner = THIS_MODULE,
386 },
387 .probe = max8907_regulator_probe,
Bill Pemberton5eb9f2b2012-11-19 13:20:42 -0500388 .remove = max8907_regulator_remove,
Gyungoh Yooffee1902012-08-09 14:24:34 -0600389};
390
391static int __init max8907_regulator_init(void)
392{
393 return platform_driver_register(&max8907_regulator_driver);
394}
395
396subsys_initcall(max8907_regulator_init);
397
398static void __exit max8907_reg_exit(void)
399{
400 platform_driver_unregister(&max8907_regulator_driver);
401}
402
403module_exit(max8907_reg_exit);
404
405MODULE_DESCRIPTION("MAX8907 regulator driver");
406MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
407MODULE_LICENSE("GPL v2");
Axel Lind154f0a2012-08-25 14:56:48 +0800408MODULE_ALIAS("platform:max8907-regulator");