1ffee1909SGyungoh Yoo /*
2ffee1909SGyungoh Yoo  * max8907-regulator.c -- support regulators in max8907
3ffee1909SGyungoh Yoo  *
4ffee1909SGyungoh Yoo  * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
5ffee1909SGyungoh Yoo  * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
6ffee1909SGyungoh Yoo  *
7ffee1909SGyungoh Yoo  * Portions based on drivers/regulator/tps65910-regulator.c,
8ffee1909SGyungoh Yoo  *     Copyright 2010 Texas Instruments Inc.
9ffee1909SGyungoh Yoo  *     Author: Graeme Gregory <gg@slimlogic.co.uk>
10ffee1909SGyungoh Yoo  *     Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
11ffee1909SGyungoh Yoo  *
12ffee1909SGyungoh Yoo  * This program is free software; you can redistribute it and/or modify
13ffee1909SGyungoh Yoo  * it under the terms of the GNU General Public License version 2 as
14ffee1909SGyungoh Yoo  * published by the Free Software Foundation.
15ffee1909SGyungoh Yoo  */
16ffee1909SGyungoh Yoo 
17ffee1909SGyungoh Yoo #include <linux/err.h>
18ffee1909SGyungoh Yoo #include <linux/init.h>
19ffee1909SGyungoh Yoo #include <linux/mfd/core.h>
20ffee1909SGyungoh Yoo #include <linux/mfd/max8907.h>
21ffee1909SGyungoh Yoo #include <linux/module.h>
22ffee1909SGyungoh Yoo #include <linux/of.h>
23ffee1909SGyungoh Yoo #include <linux/platform_device.h>
24ffee1909SGyungoh Yoo #include <linux/regulator/driver.h>
25ffee1909SGyungoh Yoo #include <linux/regulator/machine.h>
26ffee1909SGyungoh Yoo #include <linux/regulator/of_regulator.h>
27ffee1909SGyungoh Yoo #include <linux/regmap.h>
28ffee1909SGyungoh Yoo #include <linux/slab.h>
29ffee1909SGyungoh Yoo 
30ffee1909SGyungoh Yoo #define MAX8907_II2RR_VERSION_MASK	0xF0
31ffee1909SGyungoh Yoo #define MAX8907_II2RR_VERSION_REV_A	0x00
32ffee1909SGyungoh Yoo #define MAX8907_II2RR_VERSION_REV_B	0x10
33ffee1909SGyungoh Yoo #define MAX8907_II2RR_VERSION_REV_C	0x30
34ffee1909SGyungoh Yoo 
35ffee1909SGyungoh Yoo struct max8907_regulator {
36ffee1909SGyungoh Yoo 	struct regulator_desc desc[MAX8907_NUM_REGULATORS];
37ffee1909SGyungoh Yoo 	struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];
38ffee1909SGyungoh Yoo };
39ffee1909SGyungoh Yoo 
40ffee1909SGyungoh Yoo #define REG_MBATT() \
41ffee1909SGyungoh Yoo 	[MAX8907_MBATT] = { \
42ffee1909SGyungoh Yoo 		.name = "MBATT", \
43ffee1909SGyungoh Yoo 		.supply_name = "mbatt", \
44ffee1909SGyungoh Yoo 		.id = MAX8907_MBATT, \
45ffee1909SGyungoh Yoo 		.ops = &max8907_mbatt_ops, \
46ffee1909SGyungoh Yoo 		.type = REGULATOR_VOLTAGE, \
47ffee1909SGyungoh Yoo 		.owner = THIS_MODULE, \
48ffee1909SGyungoh Yoo 	}
49ffee1909SGyungoh Yoo 
50ffee1909SGyungoh Yoo #define REG_LDO(ids, supply, base, min, max, step) \
51ffee1909SGyungoh Yoo 	[MAX8907_##ids] = { \
52ffee1909SGyungoh Yoo 		.name = #ids, \
53ffee1909SGyungoh Yoo 		.supply_name = supply, \
54ffee1909SGyungoh Yoo 		.id = MAX8907_##ids, \
55ffee1909SGyungoh Yoo 		.n_voltages = ((max) - (min)) / (step) + 1, \
56ffee1909SGyungoh Yoo 		.ops = &max8907_ldo_ops, \
57ffee1909SGyungoh Yoo 		.type = REGULATOR_VOLTAGE, \
58ffee1909SGyungoh Yoo 		.owner = THIS_MODULE, \
59ffee1909SGyungoh Yoo 		.min_uV = (min), \
60ffee1909SGyungoh Yoo 		.uV_step = (step), \
61ffee1909SGyungoh Yoo 		.vsel_reg = (base) + MAX8907_VOUT, \
62ffee1909SGyungoh Yoo 		.vsel_mask = 0x3f, \
63ffee1909SGyungoh Yoo 		.enable_reg = (base) + MAX8907_CTL, \
64ffee1909SGyungoh Yoo 		.enable_mask = MAX8907_MASK_LDO_EN, \
65ffee1909SGyungoh Yoo 	}
66ffee1909SGyungoh Yoo 
67ffee1909SGyungoh Yoo #define REG_FIXED(ids, supply, voltage) \
68ffee1909SGyungoh Yoo 	[MAX8907_##ids] = { \
69ffee1909SGyungoh Yoo 		.name = #ids, \
70ffee1909SGyungoh Yoo 		.supply_name = supply, \
71ffee1909SGyungoh Yoo 		.id = MAX8907_##ids, \
72ffee1909SGyungoh Yoo 		.n_voltages = 1, \
73ffee1909SGyungoh Yoo 		.ops = &max8907_fixed_ops, \
74ffee1909SGyungoh Yoo 		.type = REGULATOR_VOLTAGE, \
75ffee1909SGyungoh Yoo 		.owner = THIS_MODULE, \
76ffee1909SGyungoh Yoo 		.min_uV = (voltage), \
77ffee1909SGyungoh Yoo 	}
78ffee1909SGyungoh Yoo 
79ffee1909SGyungoh Yoo #define REG_OUT5V(ids, supply, base, voltage) \
80ffee1909SGyungoh Yoo 	[MAX8907_##ids] = { \
81ffee1909SGyungoh Yoo 		.name = #ids, \
82ffee1909SGyungoh Yoo 		.supply_name = supply, \
83ffee1909SGyungoh Yoo 		.id = MAX8907_##ids, \
84ffee1909SGyungoh Yoo 		.n_voltages = 1, \
85ffee1909SGyungoh Yoo 		.ops = &max8907_out5v_ops, \
86ffee1909SGyungoh Yoo 		.type = REGULATOR_VOLTAGE, \
87ffee1909SGyungoh Yoo 		.owner = THIS_MODULE, \
88ffee1909SGyungoh Yoo 		.min_uV = (voltage), \
89ffee1909SGyungoh Yoo 		.enable_reg = (base), \
90ffee1909SGyungoh Yoo 		.enable_mask = MAX8907_MASK_OUT5V_EN, \
91ffee1909SGyungoh Yoo 	}
92ffee1909SGyungoh Yoo 
93ffee1909SGyungoh Yoo #define REG_BBAT(ids, supply, base, min, max, step) \
94ffee1909SGyungoh Yoo 	[MAX8907_##ids] = { \
95ffee1909SGyungoh Yoo 		.name = #ids, \
96ffee1909SGyungoh Yoo 		.supply_name = supply, \
97ffee1909SGyungoh Yoo 		.id = MAX8907_##ids, \
98ffee1909SGyungoh Yoo 		.n_voltages = ((max) - (min)) / (step) + 1, \
99ffee1909SGyungoh Yoo 		.ops = &max8907_bbat_ops, \
100ffee1909SGyungoh Yoo 		.type = REGULATOR_VOLTAGE, \
101ffee1909SGyungoh Yoo 		.owner = THIS_MODULE, \
102ffee1909SGyungoh Yoo 		.min_uV = (min), \
103ffee1909SGyungoh Yoo 		.uV_step = (step), \
104ffee1909SGyungoh Yoo 		.vsel_reg = (base), \
105ffee1909SGyungoh Yoo 		.vsel_mask = MAX8907_MASK_VBBATTCV, \
106ffee1909SGyungoh Yoo 	}
107ffee1909SGyungoh Yoo 
108ffee1909SGyungoh Yoo #define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), \
109ffee1909SGyungoh Yoo 			750000, 3900000, 50000)
110ffee1909SGyungoh Yoo #define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \
111ffee1909SGyungoh Yoo 			650000, 2225000, 25000)
112ffee1909SGyungoh Yoo 
113ffee1909SGyungoh Yoo static struct regulator_ops max8907_mbatt_ops = {
114ffee1909SGyungoh Yoo };
115ffee1909SGyungoh Yoo 
116ffee1909SGyungoh Yoo static struct regulator_ops max8907_ldo_ops = {
117ffee1909SGyungoh Yoo 	.list_voltage = regulator_list_voltage_linear,
118ffee1909SGyungoh Yoo 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
119ffee1909SGyungoh Yoo 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
120ffee1909SGyungoh Yoo 	.enable = regulator_enable_regmap,
121ffee1909SGyungoh Yoo 	.disable = regulator_disable_regmap,
122ffee1909SGyungoh Yoo 	.is_enabled = regulator_is_enabled_regmap,
123ffee1909SGyungoh Yoo };
124ffee1909SGyungoh Yoo 
125ffee1909SGyungoh Yoo static struct regulator_ops max8907_ldo_hwctl_ops = {
126ffee1909SGyungoh Yoo 	.list_voltage = regulator_list_voltage_linear,
127ffee1909SGyungoh Yoo 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
128ffee1909SGyungoh Yoo 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
129ffee1909SGyungoh Yoo };
130ffee1909SGyungoh Yoo 
131ffee1909SGyungoh Yoo static struct regulator_ops max8907_fixed_ops = {
132ffee1909SGyungoh Yoo 	.list_voltage = regulator_list_voltage_linear,
133ffee1909SGyungoh Yoo };
134ffee1909SGyungoh Yoo 
135ffee1909SGyungoh Yoo static struct regulator_ops max8907_out5v_ops = {
136ffee1909SGyungoh Yoo 	.list_voltage = regulator_list_voltage_linear,
137ffee1909SGyungoh Yoo 	.enable = regulator_enable_regmap,
138ffee1909SGyungoh Yoo 	.disable = regulator_disable_regmap,
139ffee1909SGyungoh Yoo 	.is_enabled = regulator_is_enabled_regmap,
140ffee1909SGyungoh Yoo };
141ffee1909SGyungoh Yoo 
142ffee1909SGyungoh Yoo static struct regulator_ops max8907_out5v_hwctl_ops = {
143ffee1909SGyungoh Yoo 	.list_voltage = regulator_list_voltage_linear,
144ffee1909SGyungoh Yoo };
145ffee1909SGyungoh Yoo 
146ffee1909SGyungoh Yoo static struct regulator_ops max8907_bbat_ops = {
147ffee1909SGyungoh Yoo 	.list_voltage = regulator_list_voltage_linear,
148ffee1909SGyungoh Yoo 	.set_voltage_sel = regulator_set_voltage_sel_regmap,
149ffee1909SGyungoh Yoo 	.get_voltage_sel = regulator_get_voltage_sel_regmap,
150ffee1909SGyungoh Yoo };
151ffee1909SGyungoh Yoo 
152ffee1909SGyungoh Yoo static struct regulator_desc max8907_regulators[] = {
153ffee1909SGyungoh Yoo 	REG_MBATT(),
154ffee1909SGyungoh Yoo 	REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000),
155ffee1909SGyungoh Yoo 	REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500),
156ffee1909SGyungoh Yoo 	REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000),
157ffee1909SGyungoh Yoo 	LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1),
158ffee1909SGyungoh Yoo 	LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2),
159ffee1909SGyungoh Yoo 	LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3),
160ffee1909SGyungoh Yoo 	LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4),
161ffee1909SGyungoh Yoo 	LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5),
162ffee1909SGyungoh Yoo 	LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6),
163ffee1909SGyungoh Yoo 	LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7),
164ffee1909SGyungoh Yoo 	LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8),
165ffee1909SGyungoh Yoo 	LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9),
166ffee1909SGyungoh Yoo 	LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10),
167ffee1909SGyungoh Yoo 	LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11),
168ffee1909SGyungoh Yoo 	LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12),
169ffee1909SGyungoh Yoo 	LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13),
170ffee1909SGyungoh Yoo 	LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14),
171ffee1909SGyungoh Yoo 	LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15),
172ffee1909SGyungoh Yoo 	LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16),
173ffee1909SGyungoh Yoo 	LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17),
174ffee1909SGyungoh Yoo 	LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18),
175ffee1909SGyungoh Yoo 	LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19),
176ffee1909SGyungoh Yoo 	LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20),
177ffee1909SGyungoh Yoo 	REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000),
178ffee1909SGyungoh Yoo 	REG_OUT5V(OUT33V, "mbatt",  MAX8907_REG_OUT33VEN, 3300000),
179ffee1909SGyungoh Yoo 	REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG,
180ffee1909SGyungoh Yoo 						2400000, 3000000, 200000),
181ffee1909SGyungoh Yoo 	REG_FIXED(SDBY, "MBATT", 1200000),
182ffee1909SGyungoh Yoo 	REG_FIXED(VRTC, "MBATT", 3300000),
183ffee1909SGyungoh Yoo };
184ffee1909SGyungoh Yoo 
185ffee1909SGyungoh Yoo #ifdef CONFIG_OF
186ffee1909SGyungoh Yoo 
187ffee1909SGyungoh Yoo #define MATCH(_name, _id) \
188ffee1909SGyungoh Yoo 	[MAX8907_##_id] = { \
189ffee1909SGyungoh Yoo 		.name = #_name, \
190ffee1909SGyungoh Yoo 		.driver_data = (void *)&max8907_regulators[MAX8907_##_id], \
191ffee1909SGyungoh Yoo 	}
192ffee1909SGyungoh Yoo 
193ffee1909SGyungoh Yoo static struct of_regulator_match max8907_matches[] = {
194ffee1909SGyungoh Yoo 	MATCH(mbatt, MBATT),
195ffee1909SGyungoh Yoo 	MATCH(sd1, SD1),
196ffee1909SGyungoh Yoo 	MATCH(sd2, SD2),
197ffee1909SGyungoh Yoo 	MATCH(sd3, SD3),
198ffee1909SGyungoh Yoo 	MATCH(ldo1, LDO1),
199ffee1909SGyungoh Yoo 	MATCH(ldo2, LDO2),
200ffee1909SGyungoh Yoo 	MATCH(ldo3, LDO3),
201ffee1909SGyungoh Yoo 	MATCH(ldo4, LDO4),
202ffee1909SGyungoh Yoo 	MATCH(ldo5, LDO5),
203ffee1909SGyungoh Yoo 	MATCH(ldo6, LDO6),
204ffee1909SGyungoh Yoo 	MATCH(ldo7, LDO7),
205ffee1909SGyungoh Yoo 	MATCH(ldo8, LDO8),
206ffee1909SGyungoh Yoo 	MATCH(ldo9, LDO9),
207ffee1909SGyungoh Yoo 	MATCH(ldo10, LDO10),
208ffee1909SGyungoh Yoo 	MATCH(ldo11, LDO11),
209ffee1909SGyungoh Yoo 	MATCH(ldo12, LDO12),
210ffee1909SGyungoh Yoo 	MATCH(ldo13, LDO13),
211ffee1909SGyungoh Yoo 	MATCH(ldo14, LDO14),
212ffee1909SGyungoh Yoo 	MATCH(ldo15, LDO15),
213ffee1909SGyungoh Yoo 	MATCH(ldo16, LDO16),
214ffee1909SGyungoh Yoo 	MATCH(ldo17, LDO17),
215ffee1909SGyungoh Yoo 	MATCH(ldo18, LDO18),
216ffee1909SGyungoh Yoo 	MATCH(ldo19, LDO19),
217ffee1909SGyungoh Yoo 	MATCH(ldo20, LDO20),
218ffee1909SGyungoh Yoo 	MATCH(out5v, OUT5V),
219ffee1909SGyungoh Yoo 	MATCH(out33v, OUT33V),
220ffee1909SGyungoh Yoo 	MATCH(bbat, BBAT),
221ffee1909SGyungoh Yoo 	MATCH(sdby, SDBY),
222ffee1909SGyungoh Yoo 	MATCH(vrtc, VRTC),
223ffee1909SGyungoh Yoo };
224ffee1909SGyungoh Yoo 
225ffee1909SGyungoh Yoo static int max8907_regulator_parse_dt(struct platform_device *pdev)
226ffee1909SGyungoh Yoo {
227ffee1909SGyungoh Yoo 	struct device_node *np = pdev->dev.parent->of_node;
228ffee1909SGyungoh Yoo 	struct device_node *regulators;
229ffee1909SGyungoh Yoo 	int ret;
230ffee1909SGyungoh Yoo 
231ffee1909SGyungoh Yoo 	if (!pdev->dev.parent->of_node)
232ffee1909SGyungoh Yoo 		return 0;
233ffee1909SGyungoh Yoo 
234ffee1909SGyungoh Yoo 	regulators = of_find_node_by_name(np, "regulators");
235ffee1909SGyungoh Yoo 	if (!regulators) {
236ffee1909SGyungoh Yoo 		dev_err(&pdev->dev, "regulators node not found\n");
237ffee1909SGyungoh Yoo 		return -EINVAL;
238ffee1909SGyungoh Yoo 	}
239ffee1909SGyungoh Yoo 
240f40cbcb9SAxel Lin 	ret = of_regulator_match(&pdev->dev, regulators, max8907_matches,
241ffee1909SGyungoh Yoo 				 ARRAY_SIZE(max8907_matches));
242ffee1909SGyungoh Yoo 	if (ret < 0) {
243ffee1909SGyungoh Yoo 		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
244ffee1909SGyungoh Yoo 			ret);
245ffee1909SGyungoh Yoo 		return ret;
246ffee1909SGyungoh Yoo 	}
247ffee1909SGyungoh Yoo 
248ffee1909SGyungoh Yoo 	return 0;
249ffee1909SGyungoh Yoo }
250db551682SStephen Warren 
251db551682SStephen Warren static inline struct regulator_init_data *match_init_data(int index)
252db551682SStephen Warren {
253db551682SStephen Warren 	return max8907_matches[index].init_data;
254db551682SStephen Warren }
255db551682SStephen Warren 
256db551682SStephen Warren static inline struct device_node *match_of_node(int index)
257db551682SStephen Warren {
258db551682SStephen Warren 	return max8907_matches[index].of_node;
259db551682SStephen Warren }
260ffee1909SGyungoh Yoo #else
261ffee1909SGyungoh Yoo static int max8907_regulator_parse_dt(struct platform_device *pdev)
262ffee1909SGyungoh Yoo {
263ffee1909SGyungoh Yoo 	return 0;
264ffee1909SGyungoh Yoo }
265db551682SStephen Warren 
266db551682SStephen Warren static inline struct regulator_init_data *match_init_data(int index)
267db551682SStephen Warren {
268db551682SStephen Warren 	return NULL;
269db551682SStephen Warren }
270db551682SStephen Warren 
271db551682SStephen Warren static inline struct device_node *match_of_node(int index)
272db551682SStephen Warren {
273db551682SStephen Warren 	return NULL;
274db551682SStephen Warren }
275ffee1909SGyungoh Yoo #endif
276ffee1909SGyungoh Yoo 
277a5023574SBill Pemberton static int max8907_regulator_probe(struct platform_device *pdev)
278ffee1909SGyungoh Yoo {
279ffee1909SGyungoh Yoo 	struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
280ffee1909SGyungoh Yoo 	struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
281ffee1909SGyungoh Yoo 	int ret;
282ffee1909SGyungoh Yoo 	struct max8907_regulator *pmic;
283ffee1909SGyungoh Yoo 	unsigned int val;
284ffee1909SGyungoh Yoo 	int i;
285ffee1909SGyungoh Yoo 	struct regulator_config config = {};
286ffee1909SGyungoh Yoo 	struct regulator_init_data *idata;
287ffee1909SGyungoh Yoo 	const char *mbatt_rail_name = NULL;
288ffee1909SGyungoh Yoo 
289ffee1909SGyungoh Yoo 	ret = max8907_regulator_parse_dt(pdev);
290ffee1909SGyungoh Yoo 	if (ret)
291ffee1909SGyungoh Yoo 		return ret;
292ffee1909SGyungoh Yoo 
293ffee1909SGyungoh Yoo 	pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
294ffee1909SGyungoh Yoo 	if (!pmic) {
295ffee1909SGyungoh Yoo 		dev_err(&pdev->dev, "Failed to alloc pmic\n");
296ffee1909SGyungoh Yoo 		return -ENOMEM;
297ffee1909SGyungoh Yoo 	}
298ffee1909SGyungoh Yoo 	platform_set_drvdata(pdev, pmic);
299ffee1909SGyungoh Yoo 
300ffee1909SGyungoh Yoo 	memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
301ffee1909SGyungoh Yoo 
302ffee1909SGyungoh Yoo 	/* Backwards compatibility with MAX8907B; SD1 uses different voltages */
303ffee1909SGyungoh Yoo 	regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
304ffee1909SGyungoh Yoo 	if ((val & MAX8907_II2RR_VERSION_MASK) ==
305ffee1909SGyungoh Yoo 	    MAX8907_II2RR_VERSION_REV_B) {
306ffee1909SGyungoh Yoo 		pmic->desc[MAX8907_SD1].min_uV = 637500;
307ffee1909SGyungoh Yoo 		pmic->desc[MAX8907_SD1].uV_step = 12500;
3087305608bSAxel Lin 		pmic->desc[MAX8907_SD1].n_voltages =
3097305608bSAxel Lin 						(1425000 - 637500) / 12500 + 1;
310ffee1909SGyungoh Yoo 	}
311ffee1909SGyungoh Yoo 
312ffee1909SGyungoh Yoo 	for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
313ffee1909SGyungoh Yoo 		config.dev = pdev->dev.parent;
314ffee1909SGyungoh Yoo 		if (pdata)
315ffee1909SGyungoh Yoo 			idata = pdata->init_data[i];
316ffee1909SGyungoh Yoo 		else
317db551682SStephen Warren 			idata = match_init_data(i);
318ffee1909SGyungoh Yoo 		config.init_data = idata;
319ffee1909SGyungoh Yoo 		config.driver_data = pmic;
320ffee1909SGyungoh Yoo 		config.regmap = max8907->regmap_gen;
321db551682SStephen Warren 		config.of_node = match_of_node(i);
322ffee1909SGyungoh Yoo 
323ffee1909SGyungoh Yoo 		switch (pmic->desc[i].id) {
324ffee1909SGyungoh Yoo 		case MAX8907_MBATT:
3255fc72f57SStephen Warren 			if (idata && idata->constraints.name)
326ffee1909SGyungoh Yoo 				mbatt_rail_name = idata->constraints.name;
3275fc72f57SStephen Warren 			else
3285fc72f57SStephen Warren 				mbatt_rail_name = pmic->desc[i].name;
329ffee1909SGyungoh Yoo 			break;
330ffee1909SGyungoh Yoo 		case MAX8907_BBAT:
331ffee1909SGyungoh Yoo 		case MAX8907_SDBY:
332ffee1909SGyungoh Yoo 		case MAX8907_VRTC:
333ffee1909SGyungoh Yoo 			idata->supply_regulator = mbatt_rail_name;
334ffee1909SGyungoh Yoo 			break;
335ffee1909SGyungoh Yoo 		}
336ffee1909SGyungoh Yoo 
337ffee1909SGyungoh Yoo 		if (pmic->desc[i].ops == &max8907_ldo_ops) {
338ffee1909SGyungoh Yoo 			regmap_read(config.regmap, pmic->desc[i].enable_reg,
339ffee1909SGyungoh Yoo 				    &val);
340ffee1909SGyungoh Yoo 			if ((val & MAX8907_MASK_LDO_SEQ) !=
341ffee1909SGyungoh Yoo 			    MAX8907_MASK_LDO_SEQ)
342ffee1909SGyungoh Yoo 				pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
343ffee1909SGyungoh Yoo 		} else if (pmic->desc[i].ops == &max8907_out5v_ops) {
344ffee1909SGyungoh Yoo 			regmap_read(config.regmap, pmic->desc[i].enable_reg,
345ffee1909SGyungoh Yoo 				    &val);
346ffee1909SGyungoh Yoo 			if ((val & (MAX8907_MASK_OUT5V_VINEN |
347ffee1909SGyungoh Yoo 						MAX8907_MASK_OUT5V_ENSRC)) !=
348ffee1909SGyungoh Yoo 			    MAX8907_MASK_OUT5V_ENSRC)
349ffee1909SGyungoh Yoo 				pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
350ffee1909SGyungoh Yoo 		}
351ffee1909SGyungoh Yoo 
352ffee1909SGyungoh Yoo 		pmic->rdev[i] = regulator_register(&pmic->desc[i], &config);
353ffee1909SGyungoh Yoo 		if (IS_ERR(pmic->rdev[i])) {
354ffee1909SGyungoh Yoo 			dev_err(&pdev->dev,
355ffee1909SGyungoh Yoo 				"failed to register %s regulator\n",
356ffee1909SGyungoh Yoo 				pmic->desc[i].name);
357ffee1909SGyungoh Yoo 			ret = PTR_ERR(pmic->rdev[i]);
358ffee1909SGyungoh Yoo 			goto err_unregister_regulator;
359ffee1909SGyungoh Yoo 		}
360ffee1909SGyungoh Yoo 	}
361ffee1909SGyungoh Yoo 
362ffee1909SGyungoh Yoo 	return 0;
363ffee1909SGyungoh Yoo 
364ffee1909SGyungoh Yoo err_unregister_regulator:
365ffee1909SGyungoh Yoo 	while (--i >= 0)
366ffee1909SGyungoh Yoo 		regulator_unregister(pmic->rdev[i]);
367ffee1909SGyungoh Yoo 	return ret;
368ffee1909SGyungoh Yoo }
369ffee1909SGyungoh Yoo 
3708dc995f5SBill Pemberton static int max8907_regulator_remove(struct platform_device *pdev)
371ffee1909SGyungoh Yoo {
3720764ef59SAxel Lin 	struct max8907_regulator *pmic = platform_get_drvdata(pdev);
373ffee1909SGyungoh Yoo 	int i;
374ffee1909SGyungoh Yoo 
375ffee1909SGyungoh Yoo 	for (i = 0; i < MAX8907_NUM_REGULATORS; i++)
376ffee1909SGyungoh Yoo 		regulator_unregister(pmic->rdev[i]);
377ffee1909SGyungoh Yoo 
378ffee1909SGyungoh Yoo 	return 0;
379ffee1909SGyungoh Yoo }
380ffee1909SGyungoh Yoo 
381ffee1909SGyungoh Yoo static struct platform_driver max8907_regulator_driver = {
382ffee1909SGyungoh Yoo 	.driver = {
383ffee1909SGyungoh Yoo 		   .name = "max8907-regulator",
384ffee1909SGyungoh Yoo 		   .owner = THIS_MODULE,
385ffee1909SGyungoh Yoo 		   },
386ffee1909SGyungoh Yoo 	.probe = max8907_regulator_probe,
3875eb9f2b9SBill Pemberton 	.remove = max8907_regulator_remove,
388ffee1909SGyungoh Yoo };
389ffee1909SGyungoh Yoo 
390ffee1909SGyungoh Yoo static int __init max8907_regulator_init(void)
391ffee1909SGyungoh Yoo {
392ffee1909SGyungoh Yoo 	return platform_driver_register(&max8907_regulator_driver);
393ffee1909SGyungoh Yoo }
394ffee1909SGyungoh Yoo 
395ffee1909SGyungoh Yoo subsys_initcall(max8907_regulator_init);
396ffee1909SGyungoh Yoo 
397ffee1909SGyungoh Yoo static void __exit max8907_reg_exit(void)
398ffee1909SGyungoh Yoo {
399ffee1909SGyungoh Yoo 	platform_driver_unregister(&max8907_regulator_driver);
400ffee1909SGyungoh Yoo }
401ffee1909SGyungoh Yoo 
402ffee1909SGyungoh Yoo module_exit(max8907_reg_exit);
403ffee1909SGyungoh Yoo 
404ffee1909SGyungoh Yoo MODULE_DESCRIPTION("MAX8907 regulator driver");
405ffee1909SGyungoh Yoo MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
406ffee1909SGyungoh Yoo MODULE_LICENSE("GPL v2");
407d154f0a6SAxel Lin MODULE_ALIAS("platform:max8907-regulator");
408