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 
240ffee1909SGyungoh Yoo 	ret = of_regulator_match(pdev->dev.parent, regulators,
241ffee1909SGyungoh Yoo 				 max8907_matches,
242ffee1909SGyungoh Yoo 				 ARRAY_SIZE(max8907_matches));
243ffee1909SGyungoh Yoo 	if (ret < 0) {
244ffee1909SGyungoh Yoo 		dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
245ffee1909SGyungoh Yoo 			ret);
246ffee1909SGyungoh Yoo 		return ret;
247ffee1909SGyungoh Yoo 	}
248ffee1909SGyungoh Yoo 
249ffee1909SGyungoh Yoo 	return 0;
250ffee1909SGyungoh Yoo }
251ffee1909SGyungoh Yoo #else
252ffee1909SGyungoh Yoo static int max8907_regulator_parse_dt(struct platform_device *pdev)
253ffee1909SGyungoh Yoo {
254ffee1909SGyungoh Yoo 	return 0;
255ffee1909SGyungoh Yoo }
256ffee1909SGyungoh Yoo #endif
257ffee1909SGyungoh Yoo 
258ffee1909SGyungoh Yoo static __devinit int max8907_regulator_probe(struct platform_device *pdev)
259ffee1909SGyungoh Yoo {
260ffee1909SGyungoh Yoo 	struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
261ffee1909SGyungoh Yoo 	struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
262ffee1909SGyungoh Yoo 	int ret;
263ffee1909SGyungoh Yoo 	struct max8907_regulator *pmic;
264ffee1909SGyungoh Yoo 	unsigned int val;
265ffee1909SGyungoh Yoo 	int i;
266ffee1909SGyungoh Yoo 	struct regulator_config config = {};
267ffee1909SGyungoh Yoo 	struct regulator_init_data *idata;
268ffee1909SGyungoh Yoo 	const char *mbatt_rail_name = NULL;
269ffee1909SGyungoh Yoo 
270ffee1909SGyungoh Yoo 	ret = max8907_regulator_parse_dt(pdev);
271ffee1909SGyungoh Yoo 	if (ret)
272ffee1909SGyungoh Yoo 		return ret;
273ffee1909SGyungoh Yoo 
274ffee1909SGyungoh Yoo 	pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
275ffee1909SGyungoh Yoo 	if (!pmic) {
276ffee1909SGyungoh Yoo 		dev_err(&pdev->dev, "Failed to alloc pmic\n");
277ffee1909SGyungoh Yoo 		return -ENOMEM;
278ffee1909SGyungoh Yoo 	}
279ffee1909SGyungoh Yoo 	platform_set_drvdata(pdev, pmic);
280ffee1909SGyungoh Yoo 
281ffee1909SGyungoh Yoo 	memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
282ffee1909SGyungoh Yoo 
283ffee1909SGyungoh Yoo 	/* Backwards compatibility with MAX8907B; SD1 uses different voltages */
284ffee1909SGyungoh Yoo 	regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
285ffee1909SGyungoh Yoo 	if ((val & MAX8907_II2RR_VERSION_MASK) ==
286ffee1909SGyungoh Yoo 	    MAX8907_II2RR_VERSION_REV_B) {
287ffee1909SGyungoh Yoo 		pmic->desc[MAX8907_SD1].min_uV = 637500;
288ffee1909SGyungoh Yoo 		pmic->desc[MAX8907_SD1].uV_step = 12500;
289ffee1909SGyungoh Yoo 		pmic->desc[MAX8907_SD1].n_voltages = (1425000 - 637500) / 12500;
290ffee1909SGyungoh Yoo 	}
291ffee1909SGyungoh Yoo 
292ffee1909SGyungoh Yoo 	for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
293ffee1909SGyungoh Yoo 		config.dev = pdev->dev.parent;
294ffee1909SGyungoh Yoo 		if (pdata)
295ffee1909SGyungoh Yoo 			idata = pdata->init_data[i];
296ffee1909SGyungoh Yoo 		else
297ffee1909SGyungoh Yoo 			idata = max8907_matches[i].init_data;
298ffee1909SGyungoh Yoo 		config.init_data = idata;
299ffee1909SGyungoh Yoo 		config.driver_data = pmic;
300ffee1909SGyungoh Yoo 		config.regmap = max8907->regmap_gen;
301ffee1909SGyungoh Yoo 		config.of_node = max8907_matches[i].of_node;
302ffee1909SGyungoh Yoo 
303ffee1909SGyungoh Yoo 		switch (pmic->desc[i].id) {
304ffee1909SGyungoh Yoo 		case MAX8907_MBATT:
305ffee1909SGyungoh Yoo 			mbatt_rail_name = idata->constraints.name;
306ffee1909SGyungoh Yoo 			break;
307ffee1909SGyungoh Yoo 		case MAX8907_BBAT:
308ffee1909SGyungoh Yoo 		case MAX8907_SDBY:
309ffee1909SGyungoh Yoo 		case MAX8907_VRTC:
310ffee1909SGyungoh Yoo 			idata->supply_regulator = mbatt_rail_name;
311ffee1909SGyungoh Yoo 			break;
312ffee1909SGyungoh Yoo 		}
313ffee1909SGyungoh Yoo 
314ffee1909SGyungoh Yoo 		if (pmic->desc[i].ops == &max8907_ldo_ops) {
315ffee1909SGyungoh Yoo 			regmap_read(config.regmap, pmic->desc[i].enable_reg,
316ffee1909SGyungoh Yoo 				    &val);
317ffee1909SGyungoh Yoo 			if ((val & MAX8907_MASK_LDO_SEQ) !=
318ffee1909SGyungoh Yoo 			    MAX8907_MASK_LDO_SEQ)
319ffee1909SGyungoh Yoo 				pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
320ffee1909SGyungoh Yoo 		} else if (pmic->desc[i].ops == &max8907_out5v_ops) {
321ffee1909SGyungoh Yoo 			regmap_read(config.regmap, pmic->desc[i].enable_reg,
322ffee1909SGyungoh Yoo 				    &val);
323ffee1909SGyungoh Yoo 			if ((val & (MAX8907_MASK_OUT5V_VINEN |
324ffee1909SGyungoh Yoo 						MAX8907_MASK_OUT5V_ENSRC)) !=
325ffee1909SGyungoh Yoo 			    MAX8907_MASK_OUT5V_ENSRC)
326ffee1909SGyungoh Yoo 				pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
327ffee1909SGyungoh Yoo 		}
328ffee1909SGyungoh Yoo 
329ffee1909SGyungoh Yoo 		pmic->rdev[i] = regulator_register(&pmic->desc[i], &config);
330ffee1909SGyungoh Yoo 		if (IS_ERR(pmic->rdev[i])) {
331ffee1909SGyungoh Yoo 			dev_err(&pdev->dev,
332ffee1909SGyungoh Yoo 				"failed to register %s regulator\n",
333ffee1909SGyungoh Yoo 				pmic->desc[i].name);
334ffee1909SGyungoh Yoo 			ret = PTR_ERR(pmic->rdev[i]);
335ffee1909SGyungoh Yoo 			goto err_unregister_regulator;
336ffee1909SGyungoh Yoo 		}
337ffee1909SGyungoh Yoo 	}
338ffee1909SGyungoh Yoo 
339ffee1909SGyungoh Yoo 	return 0;
340ffee1909SGyungoh Yoo 
341ffee1909SGyungoh Yoo err_unregister_regulator:
342ffee1909SGyungoh Yoo 	while (--i >= 0)
343ffee1909SGyungoh Yoo 		regulator_unregister(pmic->rdev[i]);
344ffee1909SGyungoh Yoo 	return ret;
345ffee1909SGyungoh Yoo }
346ffee1909SGyungoh Yoo 
347ffee1909SGyungoh Yoo static __devexit int max8907_regulator_remove(struct platform_device *pdev)
348ffee1909SGyungoh Yoo {
349ffee1909SGyungoh Yoo 	struct max8907_regulator *pmic;
350ffee1909SGyungoh Yoo 	int i;
351ffee1909SGyungoh Yoo 
352ffee1909SGyungoh Yoo 	for (i = 0; i < MAX8907_NUM_REGULATORS; i++)
353ffee1909SGyungoh Yoo 		regulator_unregister(pmic->rdev[i]);
354ffee1909SGyungoh Yoo 
355ffee1909SGyungoh Yoo 	return 0;
356ffee1909SGyungoh Yoo }
357ffee1909SGyungoh Yoo 
358ffee1909SGyungoh Yoo static struct platform_driver max8907_regulator_driver = {
359ffee1909SGyungoh Yoo 	.driver = {
360ffee1909SGyungoh Yoo 		   .name = "max8907-regulator",
361ffee1909SGyungoh Yoo 		   .owner = THIS_MODULE,
362ffee1909SGyungoh Yoo 		   },
363ffee1909SGyungoh Yoo 	.probe = max8907_regulator_probe,
364ffee1909SGyungoh Yoo 	.remove = __devexit_p(max8907_regulator_remove),
365ffee1909SGyungoh Yoo };
366ffee1909SGyungoh Yoo 
367ffee1909SGyungoh Yoo static int __init max8907_regulator_init(void)
368ffee1909SGyungoh Yoo {
369ffee1909SGyungoh Yoo 	return platform_driver_register(&max8907_regulator_driver);
370ffee1909SGyungoh Yoo }
371ffee1909SGyungoh Yoo 
372ffee1909SGyungoh Yoo subsys_initcall(max8907_regulator_init);
373ffee1909SGyungoh Yoo 
374ffee1909SGyungoh Yoo static void __exit max8907_reg_exit(void)
375ffee1909SGyungoh Yoo {
376ffee1909SGyungoh Yoo 	platform_driver_unregister(&max8907_regulator_driver);
377ffee1909SGyungoh Yoo }
378ffee1909SGyungoh Yoo 
379ffee1909SGyungoh Yoo module_exit(max8907_reg_exit);
380ffee1909SGyungoh Yoo 
381ffee1909SGyungoh Yoo MODULE_DESCRIPTION("MAX8907 regulator driver");
382ffee1909SGyungoh Yoo MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
383ffee1909SGyungoh Yoo MODULE_LICENSE("GPL v2");
384