xref: /linux/drivers/regulator/max8907-regulator.c (revision 02680c23d7b3febe45ea3d4f9818c2b2dc89020a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
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>
12  */
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 
32 struct max8907_regulator {
33 	struct regulator_desc desc[MAX8907_NUM_REGULATORS];
34 };
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 
109 static const struct regulator_ops max8907_mbatt_ops = {
110 };
111 
112 static const 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 
121 static const struct regulator_ops max8907_ldo_hwctl_ops = {
122 	.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 
127 static const struct regulator_ops max8907_fixed_ops = {
128 	.list_voltage = regulator_list_voltage_linear,
129 };
130 
131 static const 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 
138 static const struct regulator_ops max8907_out5v_hwctl_ops = {
139 	.list_voltage = regulator_list_voltage_linear,
140 };
141 
142 static const struct regulator_ops max8907_bbat_ops = {
143 	.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 
148 static const 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 
189 static 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 
221 static int max8907_regulator_parse_dt(struct platform_device *pdev)
222 {
223 	struct device_node *np, *regulators;
224 	int ret;
225 
226 	np = pdev->dev.parent->of_node;
227 	if (!np)
228 		return 0;
229 
230 	regulators = of_get_child_by_name(np, "regulators");
231 	if (!regulators) {
232 		dev_err(&pdev->dev, "regulators node not found\n");
233 		return -EINVAL;
234 	}
235 
236 	ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
237 				 ARRAY_SIZE(max8907_matches));
238 	of_node_put(regulators);
239 	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 }
247 
248 static inline struct regulator_init_data *match_init_data(int index)
249 {
250 	return max8907_matches[index].init_data;
251 }
252 
253 static inline struct device_node *match_of_node(int index)
254 {
255 	return max8907_matches[index].of_node;
256 }
257 #else
258 static int max8907_regulator_parse_dt(struct platform_device *pdev)
259 {
260 	return 0;
261 }
262 
263 static inline struct regulator_init_data *match_init_data(int index)
264 {
265 	return NULL;
266 }
267 
268 static inline struct device_node *match_of_node(int index)
269 {
270 	return NULL;
271 }
272 #endif
273 
274 static int max8907_regulator_probe(struct platform_device *pdev)
275 {
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);
291 	if (!pmic)
292 		return -ENOMEM;
293 
294 	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 	ret = regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
300 	if (ret)
301 		return ret;
302 
303 	if ((val & MAX8907_II2RR_VERSION_MASK) ==
304 	    MAX8907_II2RR_VERSION_REV_B) {
305 		pmic->desc[MAX8907_SD1].min_uV = 637500;
306 		pmic->desc[MAX8907_SD1].uV_step = 12500;
307 		pmic->desc[MAX8907_SD1].n_voltages =
308 						(1425000 - 637500) / 12500 + 1;
309 	}
310 
311 	for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
312 		struct regulator_dev *rdev;
313 
314 		config.dev = pdev->dev.parent;
315 		if (pdata)
316 			idata = pdata->init_data[i];
317 		else
318 			idata = match_init_data(i);
319 		config.init_data = idata;
320 		config.driver_data = pmic;
321 		config.regmap = max8907->regmap_gen;
322 		config.of_node = match_of_node(i);
323 
324 		switch (pmic->desc[i].id) {
325 		case MAX8907_MBATT:
326 			if (idata && idata->constraints.name)
327 				mbatt_rail_name = idata->constraints.name;
328 			else
329 				mbatt_rail_name = pmic->desc[i].name;
330 			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 			ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
340 				    &val);
341 			if (ret)
342 				return ret;
343 
344 			if ((val & MAX8907_MASK_LDO_SEQ) !=
345 			    MAX8907_MASK_LDO_SEQ)
346 				pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
347 		} else if (pmic->desc[i].ops == &max8907_out5v_ops) {
348 			ret = regmap_read(config.regmap, pmic->desc[i].enable_reg,
349 				    &val);
350 			if (ret)
351 				return ret;
352 
353 			if ((val & (MAX8907_MASK_OUT5V_VINEN |
354 						MAX8907_MASK_OUT5V_ENSRC)) !=
355 			    MAX8907_MASK_OUT5V_ENSRC)
356 				pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
357 		}
358 
359 		rdev = devm_regulator_register(&pdev->dev,
360 						&pmic->desc[i], &config);
361 		if (IS_ERR(rdev)) {
362 			dev_err(&pdev->dev,
363 				"failed to register %s regulator\n",
364 				pmic->desc[i].name);
365 			return PTR_ERR(rdev);
366 		}
367 	}
368 
369 	return 0;
370 }
371 
372 static struct platform_driver max8907_regulator_driver = {
373 	.driver = {
374 		   .name = "max8907-regulator",
375 		   },
376 	.probe = max8907_regulator_probe,
377 };
378 
379 static int __init max8907_regulator_init(void)
380 {
381 	return platform_driver_register(&max8907_regulator_driver);
382 }
383 
384 subsys_initcall(max8907_regulator_init);
385 
386 static void __exit max8907_reg_exit(void)
387 {
388 	platform_driver_unregister(&max8907_regulator_driver);
389 }
390 
391 module_exit(max8907_reg_exit);
392 
393 MODULE_DESCRIPTION("MAX8907 regulator driver");
394 MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
395 MODULE_LICENSE("GPL v2");
396 MODULE_ALIAS("platform:max8907-regulator");
397