blob: a8f2f07239fb9dddf05503556af4de06ca4ec708 [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];
Gyungoh Yooffee1902012-08-09 14:24:34 -060037};
38
39#define REG_MBATT() \
40 [MAX8907_MBATT] = { \
41 .name = "MBATT", \
42 .supply_name = "mbatt", \
43 .id = MAX8907_MBATT, \
44 .ops = &max8907_mbatt_ops, \
45 .type = REGULATOR_VOLTAGE, \
46 .owner = THIS_MODULE, \
47 }
48
49#define REG_LDO(ids, supply, base, min, max, step) \
50 [MAX8907_##ids] = { \
51 .name = #ids, \
52 .supply_name = supply, \
53 .id = MAX8907_##ids, \
54 .n_voltages = ((max) - (min)) / (step) + 1, \
55 .ops = &max8907_ldo_ops, \
56 .type = REGULATOR_VOLTAGE, \
57 .owner = THIS_MODULE, \
58 .min_uV = (min), \
59 .uV_step = (step), \
60 .vsel_reg = (base) + MAX8907_VOUT, \
61 .vsel_mask = 0x3f, \
62 .enable_reg = (base) + MAX8907_CTL, \
63 .enable_mask = MAX8907_MASK_LDO_EN, \
64 }
65
66#define REG_FIXED(ids, supply, voltage) \
67 [MAX8907_##ids] = { \
68 .name = #ids, \
69 .supply_name = supply, \
70 .id = MAX8907_##ids, \
71 .n_voltages = 1, \
72 .ops = &max8907_fixed_ops, \
73 .type = REGULATOR_VOLTAGE, \
74 .owner = THIS_MODULE, \
75 .min_uV = (voltage), \
76 }
77
78#define REG_OUT5V(ids, supply, base, voltage) \
79 [MAX8907_##ids] = { \
80 .name = #ids, \
81 .supply_name = supply, \
82 .id = MAX8907_##ids, \
83 .n_voltages = 1, \
84 .ops = &max8907_out5v_ops, \
85 .type = REGULATOR_VOLTAGE, \
86 .owner = THIS_MODULE, \
87 .min_uV = (voltage), \
88 .enable_reg = (base), \
89 .enable_mask = MAX8907_MASK_OUT5V_EN, \
90 }
91
92#define REG_BBAT(ids, supply, base, min, max, step) \
93 [MAX8907_##ids] = { \
94 .name = #ids, \
95 .supply_name = supply, \
96 .id = MAX8907_##ids, \
97 .n_voltages = ((max) - (min)) / (step) + 1, \
98 .ops = &max8907_bbat_ops, \
99 .type = REGULATOR_VOLTAGE, \
100 .owner = THIS_MODULE, \
101 .min_uV = (min), \
102 .uV_step = (step), \
103 .vsel_reg = (base), \
104 .vsel_mask = MAX8907_MASK_VBBATTCV, \
105 }
106
107#define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), \
108 750000, 3900000, 50000)
109#define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \
110 650000, 2225000, 25000)
111
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530112static const struct regulator_ops max8907_mbatt_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600113};
114
115static struct regulator_ops max8907_ldo_ops = {
116 .list_voltage = regulator_list_voltage_linear,
117 .set_voltage_sel = regulator_set_voltage_sel_regmap,
118 .get_voltage_sel = regulator_get_voltage_sel_regmap,
119 .enable = regulator_enable_regmap,
120 .disable = regulator_disable_regmap,
121 .is_enabled = regulator_is_enabled_regmap,
122};
123
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530124static const struct regulator_ops max8907_ldo_hwctl_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600125 .list_voltage = regulator_list_voltage_linear,
126 .set_voltage_sel = regulator_set_voltage_sel_regmap,
127 .get_voltage_sel = regulator_get_voltage_sel_regmap,
128};
129
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530130static const struct regulator_ops max8907_fixed_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600131 .list_voltage = regulator_list_voltage_linear,
132};
133
134static struct regulator_ops max8907_out5v_ops = {
135 .list_voltage = regulator_list_voltage_linear,
136 .enable = regulator_enable_regmap,
137 .disable = regulator_disable_regmap,
138 .is_enabled = regulator_is_enabled_regmap,
139};
140
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530141static const struct regulator_ops max8907_out5v_hwctl_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600142 .list_voltage = regulator_list_voltage_linear,
143};
144
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530145static const struct regulator_ops max8907_bbat_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600146 .list_voltage = regulator_list_voltage_linear,
147 .set_voltage_sel = regulator_set_voltage_sel_regmap,
148 .get_voltage_sel = regulator_get_voltage_sel_regmap,
149};
150
151static struct regulator_desc max8907_regulators[] = {
152 REG_MBATT(),
153 REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000),
154 REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500),
155 REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000),
156 LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1),
157 LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2),
158 LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3),
159 LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4),
160 LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5),
161 LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6),
162 LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7),
163 LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8),
164 LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9),
165 LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10),
166 LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11),
167 LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12),
168 LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13),
169 LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14),
170 LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15),
171 LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16),
172 LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17),
173 LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18),
174 LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19),
175 LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20),
176 REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000),
177 REG_OUT5V(OUT33V, "mbatt", MAX8907_REG_OUT33VEN, 3300000),
178 REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG,
179 2400000, 3000000, 200000),
180 REG_FIXED(SDBY, "MBATT", 1200000),
181 REG_FIXED(VRTC, "MBATT", 3300000),
182};
183
184#ifdef CONFIG_OF
185
186#define MATCH(_name, _id) \
187 [MAX8907_##_id] = { \
188 .name = #_name, \
189 .driver_data = (void *)&max8907_regulators[MAX8907_##_id], \
190 }
191
192static struct of_regulator_match max8907_matches[] = {
193 MATCH(mbatt, MBATT),
194 MATCH(sd1, SD1),
195 MATCH(sd2, SD2),
196 MATCH(sd3, SD3),
197 MATCH(ldo1, LDO1),
198 MATCH(ldo2, LDO2),
199 MATCH(ldo3, LDO3),
200 MATCH(ldo4, LDO4),
201 MATCH(ldo5, LDO5),
202 MATCH(ldo6, LDO6),
203 MATCH(ldo7, LDO7),
204 MATCH(ldo8, LDO8),
205 MATCH(ldo9, LDO9),
206 MATCH(ldo10, LDO10),
207 MATCH(ldo11, LDO11),
208 MATCH(ldo12, LDO12),
209 MATCH(ldo13, LDO13),
210 MATCH(ldo14, LDO14),
211 MATCH(ldo15, LDO15),
212 MATCH(ldo16, LDO16),
213 MATCH(ldo17, LDO17),
214 MATCH(ldo18, LDO18),
215 MATCH(ldo19, LDO19),
216 MATCH(ldo20, LDO20),
217 MATCH(out5v, OUT5V),
218 MATCH(out33v, OUT33V),
219 MATCH(bbat, BBAT),
220 MATCH(sdby, SDBY),
221 MATCH(vrtc, VRTC),
222};
223
224static int max8907_regulator_parse_dt(struct platform_device *pdev)
225{
Axel Linc92f5dd2013-01-27 21:16:56 +0800226 struct device_node *np, *regulators;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600227 int ret;
228
Guodong Xub8b27a42014-09-10 11:50:39 +0800229 np = pdev->dev.parent->of_node;
Axel Linc92f5dd2013-01-27 21:16:56 +0800230 if (!np)
Gyungoh Yooffee1902012-08-09 14:24:34 -0600231 return 0;
232
Sachin Kamatc61f1402014-02-14 17:19:50 +0530233 regulators = of_get_child_by_name(np, "regulators");
Gyungoh Yooffee1902012-08-09 14:24:34 -0600234 if (!regulators) {
235 dev_err(&pdev->dev, "regulators node not found\n");
236 return -EINVAL;
237 }
238
Axel Linf40cbcb2013-01-25 10:20:29 +0800239 ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
Gyungoh Yooffee1902012-08-09 14:24:34 -0600240 ARRAY_SIZE(max8907_matches));
Axel Linc92f5dd2013-01-27 21:16:56 +0800241 of_node_put(regulators);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600242 if (ret < 0) {
243 dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
244 ret);
245 return ret;
246 }
247
248 return 0;
249}
Stephen Warrendb551682012-08-20 09:39:10 -0600250
251static inline struct regulator_init_data *match_init_data(int index)
252{
253 return max8907_matches[index].init_data;
254}
255
256static inline struct device_node *match_of_node(int index)
257{
258 return max8907_matches[index].of_node;
259}
Gyungoh Yooffee1902012-08-09 14:24:34 -0600260#else
261static int max8907_regulator_parse_dt(struct platform_device *pdev)
262{
263 return 0;
264}
Stephen Warrendb551682012-08-20 09:39:10 -0600265
266static inline struct regulator_init_data *match_init_data(int index)
267{
268 return NULL;
269}
270
271static inline struct device_node *match_of_node(int index)
272{
273 return NULL;
274}
Gyungoh Yooffee1902012-08-09 14:24:34 -0600275#endif
276
Bill Pembertona5023572012-11-19 13:22:22 -0500277static int max8907_regulator_probe(struct platform_device *pdev)
Gyungoh Yooffee1902012-08-09 14:24:34 -0600278{
279 struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
280 struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
281 int ret;
282 struct max8907_regulator *pmic;
283 unsigned int val;
284 int i;
285 struct regulator_config config = {};
286 struct regulator_init_data *idata;
287 const char *mbatt_rail_name = NULL;
288
289 ret = max8907_regulator_parse_dt(pdev);
290 if (ret)
291 return ret;
292
293 pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
Sachin Kamatd016bdc2014-02-20 14:23:07 +0530294 if (!pmic)
Gyungoh Yooffee1902012-08-09 14:24:34 -0600295 return -ENOMEM;
Sachin Kamatd016bdc2014-02-20 14:23:07 +0530296
Gyungoh Yooffee1902012-08-09 14:24:34 -0600297 platform_set_drvdata(pdev, pmic);
298
299 memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
300
301 /* Backwards compatibility with MAX8907B; SD1 uses different voltages */
Yizhuo5a23b8f2019-10-03 10:58:13 -0700302 ret = regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
303 if (ret)
304 return ret;
305
Gyungoh Yooffee1902012-08-09 14:24:34 -0600306 if ((val & MAX8907_II2RR_VERSION_MASK) ==
307 MAX8907_II2RR_VERSION_REV_B) {
308 pmic->desc[MAX8907_SD1].min_uV = 637500;
309 pmic->desc[MAX8907_SD1].uV_step = 12500;
Axel Lin73056082012-08-16 12:26:02 +0800310 pmic->desc[MAX8907_SD1].n_voltages =
311 (1425000 - 637500) / 12500 + 1;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600312 }
313
314 for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
Krzysztof Kozlowskif9915252014-03-10 09:32:48 +0100315 struct regulator_dev *rdev;
316
Gyungoh Yooffee1902012-08-09 14:24:34 -0600317 config.dev = pdev->dev.parent;
318 if (pdata)
319 idata = pdata->init_data[i];
320 else
Stephen Warrendb551682012-08-20 09:39:10 -0600321 idata = match_init_data(i);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600322 config.init_data = idata;
323 config.driver_data = pmic;
324 config.regmap = max8907->regmap_gen;
Stephen Warrendb551682012-08-20 09:39:10 -0600325 config.of_node = match_of_node(i);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600326
327 switch (pmic->desc[i].id) {
328 case MAX8907_MBATT:
Stephen Warren5fc72f52012-08-23 12:19:18 -0600329 if (idata && idata->constraints.name)
330 mbatt_rail_name = idata->constraints.name;
331 else
332 mbatt_rail_name = pmic->desc[i].name;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600333 break;
334 case MAX8907_BBAT:
335 case MAX8907_SDBY:
336 case MAX8907_VRTC:
337 idata->supply_regulator = mbatt_rail_name;
338 break;
339 }
340
341 if (pmic->desc[i].ops == &max8907_ldo_ops) {
Yizhuo5a23b8f2019-10-03 10:58:13 -0700342 ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
Gyungoh Yooffee1902012-08-09 14:24:34 -0600343 &val);
Yizhuo5a23b8f2019-10-03 10:58:13 -0700344 if (ret)
345 return ret;
346
Gyungoh Yooffee1902012-08-09 14:24:34 -0600347 if ((val & MAX8907_MASK_LDO_SEQ) !=
348 MAX8907_MASK_LDO_SEQ)
349 pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
350 } else if (pmic->desc[i].ops == &max8907_out5v_ops) {
Yizhuo5a23b8f2019-10-03 10:58:13 -0700351 ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
Gyungoh Yooffee1902012-08-09 14:24:34 -0600352 &val);
Yizhuo5a23b8f2019-10-03 10:58:13 -0700353 if (ret)
354 return ret;
355
Gyungoh Yooffee1902012-08-09 14:24:34 -0600356 if ((val & (MAX8907_MASK_OUT5V_VINEN |
357 MAX8907_MASK_OUT5V_ENSRC)) !=
358 MAX8907_MASK_OUT5V_ENSRC)
359 pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
360 }
361
Krzysztof Kozlowskif9915252014-03-10 09:32:48 +0100362 rdev = devm_regulator_register(&pdev->dev,
Sachin Kamat5ecdf142013-09-04 11:07:59 +0530363 &pmic->desc[i], &config);
Krzysztof Kozlowskif9915252014-03-10 09:32:48 +0100364 if (IS_ERR(rdev)) {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600365 dev_err(&pdev->dev,
366 "failed to register %s regulator\n",
367 pmic->desc[i].name);
Krzysztof Kozlowskif9915252014-03-10 09:32:48 +0100368 return PTR_ERR(rdev);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600369 }
370 }
371
372 return 0;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600373}
374
375static struct platform_driver max8907_regulator_driver = {
376 .driver = {
377 .name = "max8907-regulator",
Gyungoh Yooffee1902012-08-09 14:24:34 -0600378 },
379 .probe = max8907_regulator_probe,
Gyungoh Yooffee1902012-08-09 14:24:34 -0600380};
381
382static int __init max8907_regulator_init(void)
383{
384 return platform_driver_register(&max8907_regulator_driver);
385}
386
387subsys_initcall(max8907_regulator_init);
388
389static void __exit max8907_reg_exit(void)
390{
391 platform_driver_unregister(&max8907_regulator_driver);
392}
393
394module_exit(max8907_reg_exit);
395
396MODULE_DESCRIPTION("MAX8907 regulator driver");
397MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
398MODULE_LICENSE("GPL v2");
Axel Lind154f0a2012-08-25 14:56:48 +0800399MODULE_ALIAS("platform:max8907-regulator");