blob: 76152aaa330bd143fb733b7fcdf3b400190f35a6 [file] [log] [blame]
Thomas Gleixnerd2912cb2019-06-04 10:11:33 +02001// SPDX-License-Identifier: GPL-2.0-only
Gyungoh Yooffee1902012-08-09 14:24:34 -06002/*
3 * max8907-regulator.c -- support regulators in max8907
4 *
5 * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
6 * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
7 *
8 * Portions based on drivers/regulator/tps65910-regulator.c,
9 * Copyright 2010 Texas Instruments Inc.
10 * Author: Graeme Gregory <gg@slimlogic.co.uk>
11 * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
Gyungoh Yooffee1902012-08-09 14:24:34 -060012 */
13
14#include <linux/err.h>
15#include <linux/init.h>
16#include <linux/mfd/core.h>
17#include <linux/mfd/max8907.h>
18#include <linux/module.h>
19#include <linux/of.h>
20#include <linux/platform_device.h>
21#include <linux/regulator/driver.h>
22#include <linux/regulator/machine.h>
23#include <linux/regulator/of_regulator.h>
24#include <linux/regmap.h>
25#include <linux/slab.h>
26
27#define MAX8907_II2RR_VERSION_MASK 0xF0
28#define MAX8907_II2RR_VERSION_REV_A 0x00
29#define MAX8907_II2RR_VERSION_REV_B 0x10
30#define MAX8907_II2RR_VERSION_REV_C 0x30
31
32struct max8907_regulator {
33 struct regulator_desc desc[MAX8907_NUM_REGULATORS];
Gyungoh Yooffee1902012-08-09 14:24:34 -060034};
35
36#define REG_MBATT() \
37 [MAX8907_MBATT] = { \
38 .name = "MBATT", \
39 .supply_name = "mbatt", \
40 .id = MAX8907_MBATT, \
41 .ops = &max8907_mbatt_ops, \
42 .type = REGULATOR_VOLTAGE, \
43 .owner = THIS_MODULE, \
44 }
45
46#define REG_LDO(ids, supply, base, min, max, step) \
47 [MAX8907_##ids] = { \
48 .name = #ids, \
49 .supply_name = supply, \
50 .id = MAX8907_##ids, \
51 .n_voltages = ((max) - (min)) / (step) + 1, \
52 .ops = &max8907_ldo_ops, \
53 .type = REGULATOR_VOLTAGE, \
54 .owner = THIS_MODULE, \
55 .min_uV = (min), \
56 .uV_step = (step), \
57 .vsel_reg = (base) + MAX8907_VOUT, \
58 .vsel_mask = 0x3f, \
59 .enable_reg = (base) + MAX8907_CTL, \
60 .enable_mask = MAX8907_MASK_LDO_EN, \
61 }
62
63#define REG_FIXED(ids, supply, voltage) \
64 [MAX8907_##ids] = { \
65 .name = #ids, \
66 .supply_name = supply, \
67 .id = MAX8907_##ids, \
68 .n_voltages = 1, \
69 .ops = &max8907_fixed_ops, \
70 .type = REGULATOR_VOLTAGE, \
71 .owner = THIS_MODULE, \
72 .min_uV = (voltage), \
73 }
74
75#define REG_OUT5V(ids, supply, base, voltage) \
76 [MAX8907_##ids] = { \
77 .name = #ids, \
78 .supply_name = supply, \
79 .id = MAX8907_##ids, \
80 .n_voltages = 1, \
81 .ops = &max8907_out5v_ops, \
82 .type = REGULATOR_VOLTAGE, \
83 .owner = THIS_MODULE, \
84 .min_uV = (voltage), \
85 .enable_reg = (base), \
86 .enable_mask = MAX8907_MASK_OUT5V_EN, \
87 }
88
89#define REG_BBAT(ids, supply, base, min, max, step) \
90 [MAX8907_##ids] = { \
91 .name = #ids, \
92 .supply_name = supply, \
93 .id = MAX8907_##ids, \
94 .n_voltages = ((max) - (min)) / (step) + 1, \
95 .ops = &max8907_bbat_ops, \
96 .type = REGULATOR_VOLTAGE, \
97 .owner = THIS_MODULE, \
98 .min_uV = (min), \
99 .uV_step = (step), \
100 .vsel_reg = (base), \
101 .vsel_mask = MAX8907_MASK_VBBATTCV, \
102 }
103
104#define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), \
105 750000, 3900000, 50000)
106#define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \
107 650000, 2225000, 25000)
108
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530109static const struct regulator_ops max8907_mbatt_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600110};
111
112static struct regulator_ops max8907_ldo_ops = {
113 .list_voltage = regulator_list_voltage_linear,
114 .set_voltage_sel = regulator_set_voltage_sel_regmap,
115 .get_voltage_sel = regulator_get_voltage_sel_regmap,
116 .enable = regulator_enable_regmap,
117 .disable = regulator_disable_regmap,
118 .is_enabled = regulator_is_enabled_regmap,
119};
120
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530121static const struct regulator_ops max8907_ldo_hwctl_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600122 .list_voltage = regulator_list_voltage_linear,
123 .set_voltage_sel = regulator_set_voltage_sel_regmap,
124 .get_voltage_sel = regulator_get_voltage_sel_regmap,
125};
126
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530127static const struct regulator_ops max8907_fixed_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600128 .list_voltage = regulator_list_voltage_linear,
129};
130
131static struct regulator_ops max8907_out5v_ops = {
132 .list_voltage = regulator_list_voltage_linear,
133 .enable = regulator_enable_regmap,
134 .disable = regulator_disable_regmap,
135 .is_enabled = regulator_is_enabled_regmap,
136};
137
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530138static const struct regulator_ops max8907_out5v_hwctl_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600139 .list_voltage = regulator_list_voltage_linear,
140};
141
Bhumika Goyal88c9d472017-01-28 20:02:32 +0530142static const struct regulator_ops max8907_bbat_ops = {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600143 .list_voltage = regulator_list_voltage_linear,
144 .set_voltage_sel = regulator_set_voltage_sel_regmap,
145 .get_voltage_sel = regulator_get_voltage_sel_regmap,
146};
147
148static struct regulator_desc max8907_regulators[] = {
149 REG_MBATT(),
150 REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000),
151 REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500),
152 REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000),
153 LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1),
154 LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2),
155 LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3),
156 LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4),
157 LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5),
158 LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6),
159 LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7),
160 LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8),
161 LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9),
162 LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10),
163 LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11),
164 LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12),
165 LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13),
166 LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14),
167 LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15),
168 LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16),
169 LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17),
170 LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18),
171 LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19),
172 LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20),
173 REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000),
174 REG_OUT5V(OUT33V, "mbatt", MAX8907_REG_OUT33VEN, 3300000),
175 REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG,
176 2400000, 3000000, 200000),
177 REG_FIXED(SDBY, "MBATT", 1200000),
178 REG_FIXED(VRTC, "MBATT", 3300000),
179};
180
181#ifdef CONFIG_OF
182
183#define MATCH(_name, _id) \
184 [MAX8907_##_id] = { \
185 .name = #_name, \
186 .driver_data = (void *)&max8907_regulators[MAX8907_##_id], \
187 }
188
189static struct of_regulator_match max8907_matches[] = {
190 MATCH(mbatt, MBATT),
191 MATCH(sd1, SD1),
192 MATCH(sd2, SD2),
193 MATCH(sd3, SD3),
194 MATCH(ldo1, LDO1),
195 MATCH(ldo2, LDO2),
196 MATCH(ldo3, LDO3),
197 MATCH(ldo4, LDO4),
198 MATCH(ldo5, LDO5),
199 MATCH(ldo6, LDO6),
200 MATCH(ldo7, LDO7),
201 MATCH(ldo8, LDO8),
202 MATCH(ldo9, LDO9),
203 MATCH(ldo10, LDO10),
204 MATCH(ldo11, LDO11),
205 MATCH(ldo12, LDO12),
206 MATCH(ldo13, LDO13),
207 MATCH(ldo14, LDO14),
208 MATCH(ldo15, LDO15),
209 MATCH(ldo16, LDO16),
210 MATCH(ldo17, LDO17),
211 MATCH(ldo18, LDO18),
212 MATCH(ldo19, LDO19),
213 MATCH(ldo20, LDO20),
214 MATCH(out5v, OUT5V),
215 MATCH(out33v, OUT33V),
216 MATCH(bbat, BBAT),
217 MATCH(sdby, SDBY),
218 MATCH(vrtc, VRTC),
219};
220
221static int max8907_regulator_parse_dt(struct platform_device *pdev)
222{
Axel Linc92f5dd2013-01-27 21:16:56 +0800223 struct device_node *np, *regulators;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600224 int ret;
225
Guodong Xub8b27a42014-09-10 11:50:39 +0800226 np = pdev->dev.parent->of_node;
Axel Linc92f5dd2013-01-27 21:16:56 +0800227 if (!np)
Gyungoh Yooffee1902012-08-09 14:24:34 -0600228 return 0;
229
Sachin Kamatc61f1402014-02-14 17:19:50 +0530230 regulators = of_get_child_by_name(np, "regulators");
Gyungoh Yooffee1902012-08-09 14:24:34 -0600231 if (!regulators) {
232 dev_err(&pdev->dev, "regulators node not found\n");
233 return -EINVAL;
234 }
235
Axel Linf40cbcb2013-01-25 10:20:29 +0800236 ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
Gyungoh Yooffee1902012-08-09 14:24:34 -0600237 ARRAY_SIZE(max8907_matches));
Axel Linc92f5dd2013-01-27 21:16:56 +0800238 of_node_put(regulators);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600239 if (ret < 0) {
240 dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
241 ret);
242 return ret;
243 }
244
245 return 0;
246}
Stephen Warrendb551682012-08-20 09:39:10 -0600247
248static inline struct regulator_init_data *match_init_data(int index)
249{
250 return max8907_matches[index].init_data;
251}
252
253static inline struct device_node *match_of_node(int index)
254{
255 return max8907_matches[index].of_node;
256}
Gyungoh Yooffee1902012-08-09 14:24:34 -0600257#else
258static int max8907_regulator_parse_dt(struct platform_device *pdev)
259{
260 return 0;
261}
Stephen Warrendb551682012-08-20 09:39:10 -0600262
263static inline struct regulator_init_data *match_init_data(int index)
264{
265 return NULL;
266}
267
268static inline struct device_node *match_of_node(int index)
269{
270 return NULL;
271}
Gyungoh Yooffee1902012-08-09 14:24:34 -0600272#endif
273
Bill Pembertona5023572012-11-19 13:22:22 -0500274static int max8907_regulator_probe(struct platform_device *pdev)
Gyungoh Yooffee1902012-08-09 14:24:34 -0600275{
276 struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
277 struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
278 int ret;
279 struct max8907_regulator *pmic;
280 unsigned int val;
281 int i;
282 struct regulator_config config = {};
283 struct regulator_init_data *idata;
284 const char *mbatt_rail_name = NULL;
285
286 ret = max8907_regulator_parse_dt(pdev);
287 if (ret)
288 return ret;
289
290 pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
Sachin Kamatd016bdc2014-02-20 14:23:07 +0530291 if (!pmic)
Gyungoh Yooffee1902012-08-09 14:24:34 -0600292 return -ENOMEM;
Sachin Kamatd016bdc2014-02-20 14:23:07 +0530293
Gyungoh Yooffee1902012-08-09 14:24:34 -0600294 platform_set_drvdata(pdev, pmic);
295
296 memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
297
298 /* Backwards compatibility with MAX8907B; SD1 uses different voltages */
299 regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
300 if ((val & MAX8907_II2RR_VERSION_MASK) ==
301 MAX8907_II2RR_VERSION_REV_B) {
302 pmic->desc[MAX8907_SD1].min_uV = 637500;
303 pmic->desc[MAX8907_SD1].uV_step = 12500;
Axel Lin73056082012-08-16 12:26:02 +0800304 pmic->desc[MAX8907_SD1].n_voltages =
305 (1425000 - 637500) / 12500 + 1;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600306 }
307
308 for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
Krzysztof Kozlowskif9915252014-03-10 09:32:48 +0100309 struct regulator_dev *rdev;
310
Gyungoh Yooffee1902012-08-09 14:24:34 -0600311 config.dev = pdev->dev.parent;
312 if (pdata)
313 idata = pdata->init_data[i];
314 else
Stephen Warrendb551682012-08-20 09:39:10 -0600315 idata = match_init_data(i);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600316 config.init_data = idata;
317 config.driver_data = pmic;
318 config.regmap = max8907->regmap_gen;
Stephen Warrendb551682012-08-20 09:39:10 -0600319 config.of_node = match_of_node(i);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600320
321 switch (pmic->desc[i].id) {
322 case MAX8907_MBATT:
Stephen Warren5fc72f52012-08-23 12:19:18 -0600323 if (idata && idata->constraints.name)
324 mbatt_rail_name = idata->constraints.name;
325 else
326 mbatt_rail_name = pmic->desc[i].name;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600327 break;
328 case MAX8907_BBAT:
329 case MAX8907_SDBY:
330 case MAX8907_VRTC:
331 idata->supply_regulator = mbatt_rail_name;
332 break;
333 }
334
335 if (pmic->desc[i].ops == &max8907_ldo_ops) {
336 regmap_read(config.regmap, pmic->desc[i].enable_reg,
337 &val);
338 if ((val & MAX8907_MASK_LDO_SEQ) !=
339 MAX8907_MASK_LDO_SEQ)
340 pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
341 } else if (pmic->desc[i].ops == &max8907_out5v_ops) {
342 regmap_read(config.regmap, pmic->desc[i].enable_reg,
343 &val);
344 if ((val & (MAX8907_MASK_OUT5V_VINEN |
345 MAX8907_MASK_OUT5V_ENSRC)) !=
346 MAX8907_MASK_OUT5V_ENSRC)
347 pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
348 }
349
Krzysztof Kozlowskif9915252014-03-10 09:32:48 +0100350 rdev = devm_regulator_register(&pdev->dev,
Sachin Kamat5ecdf142013-09-04 11:07:59 +0530351 &pmic->desc[i], &config);
Krzysztof Kozlowskif9915252014-03-10 09:32:48 +0100352 if (IS_ERR(rdev)) {
Gyungoh Yooffee1902012-08-09 14:24:34 -0600353 dev_err(&pdev->dev,
354 "failed to register %s regulator\n",
355 pmic->desc[i].name);
Krzysztof Kozlowskif9915252014-03-10 09:32:48 +0100356 return PTR_ERR(rdev);
Gyungoh Yooffee1902012-08-09 14:24:34 -0600357 }
358 }
359
360 return 0;
Gyungoh Yooffee1902012-08-09 14:24:34 -0600361}
362
363static struct platform_driver max8907_regulator_driver = {
364 .driver = {
365 .name = "max8907-regulator",
Gyungoh Yooffee1902012-08-09 14:24:34 -0600366 },
367 .probe = max8907_regulator_probe,
Gyungoh Yooffee1902012-08-09 14:24:34 -0600368};
369
370static int __init max8907_regulator_init(void)
371{
372 return platform_driver_register(&max8907_regulator_driver);
373}
374
375subsys_initcall(max8907_regulator_init);
376
377static void __exit max8907_reg_exit(void)
378{
379 platform_driver_unregister(&max8907_regulator_driver);
380}
381
382module_exit(max8907_reg_exit);
383
384MODULE_DESCRIPTION("MAX8907 regulator driver");
385MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
386MODULE_LICENSE("GPL v2");
Axel Lind154f0a2012-08-25 14:56:48 +0800387MODULE_ALIAS("platform:max8907-regulator");