xref: /linux/drivers/regulator/ab8500-ext.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
10376148fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2d1a82001SLee Jones /*
3d1a82001SLee Jones  * Copyright (C) ST-Ericsson SA 2010
4d1a82001SLee Jones  *
5d1a82001SLee Jones  * Authors: Bengt Jonsson <bengt.g.jonsson@stericsson.com>
6d1a82001SLee Jones  *
7d1a82001SLee Jones  * This file is based on drivers/regulator/ab8500.c
8d1a82001SLee Jones  *
9d1a82001SLee Jones  * AB8500 external regulators
10d1a82001SLee Jones  *
11d1a82001SLee Jones  * ab8500-ext supports the following regulators:
12d1a82001SLee Jones  * - VextSupply3
13d1a82001SLee Jones  */
14d1a82001SLee Jones #include <linux/init.h>
15d1a82001SLee Jones #include <linux/kernel.h>
16d1a82001SLee Jones #include <linux/err.h>
17d1a82001SLee Jones #include <linux/module.h>
1830aa4b26SLee Jones #include <linux/of.h>
19d1a82001SLee Jones #include <linux/platform_device.h>
20d1a82001SLee Jones #include <linux/regulator/driver.h>
21d1a82001SLee Jones #include <linux/regulator/machine.h>
2230aa4b26SLee Jones #include <linux/regulator/of_regulator.h>
23d1a82001SLee Jones #include <linux/mfd/abx500.h>
24d1a82001SLee Jones #include <linux/mfd/abx500/ab8500.h>
253acb64c0SLinus Walleij 
263acb64c0SLinus Walleij /* AB8500 external regulators */
273acb64c0SLinus Walleij enum ab8500_ext_regulator_id {
283acb64c0SLinus Walleij 	AB8500_EXT_SUPPLY1,
293acb64c0SLinus Walleij 	AB8500_EXT_SUPPLY2,
303acb64c0SLinus Walleij 	AB8500_EXT_SUPPLY3,
313acb64c0SLinus Walleij 	AB8500_NUM_EXT_REGULATORS,
323acb64c0SLinus Walleij };
333acb64c0SLinus Walleij 
343acb64c0SLinus Walleij struct ab8500_ext_regulator_cfg {
353acb64c0SLinus Walleij 	bool hwreq; /* requires hw mode or high power mode */
363acb64c0SLinus Walleij };
37d1a82001SLee Jones 
3879886be0SArnd Bergmann /* supply for VextSupply3 */
3979886be0SArnd Bergmann static struct regulator_consumer_supply ab8500_ext_supply3_consumers[] = {
4079886be0SArnd Bergmann 	/* SIM supply for 3 V SIM cards */
4179886be0SArnd Bergmann 	REGULATOR_SUPPLY("vinvsim", "sim-detect.0"),
4279886be0SArnd Bergmann };
4379886be0SArnd Bergmann 
4479886be0SArnd Bergmann /*
4579886be0SArnd Bergmann  * AB8500 external regulators
4679886be0SArnd Bergmann  */
4779886be0SArnd Bergmann static struct regulator_init_data ab8500_ext_regulators[] = {
4879886be0SArnd Bergmann 	/* fixed Vbat supplies VSMPS1_EXT_1V8 */
4979886be0SArnd Bergmann 	[AB8500_EXT_SUPPLY1] = {
5079886be0SArnd Bergmann 		.constraints = {
5179886be0SArnd Bergmann 			.name = "ab8500-ext-supply1",
5279886be0SArnd Bergmann 			.min_uV = 1800000,
5379886be0SArnd Bergmann 			.max_uV = 1800000,
5479886be0SArnd Bergmann 			.initial_mode = REGULATOR_MODE_IDLE,
5579886be0SArnd Bergmann 			.boot_on = 1,
5679886be0SArnd Bergmann 			.always_on = 1,
5779886be0SArnd Bergmann 		},
5879886be0SArnd Bergmann 	},
5979886be0SArnd Bergmann 	/* fixed Vbat supplies VSMPS2_EXT_1V36 and VSMPS5_EXT_1V15 */
6079886be0SArnd Bergmann 	[AB8500_EXT_SUPPLY2] = {
6179886be0SArnd Bergmann 		.constraints = {
6279886be0SArnd Bergmann 			.name = "ab8500-ext-supply2",
6379886be0SArnd Bergmann 			.min_uV = 1360000,
6479886be0SArnd Bergmann 			.max_uV = 1360000,
6579886be0SArnd Bergmann 		},
6679886be0SArnd Bergmann 	},
6779886be0SArnd Bergmann 	/* fixed Vbat supplies VSMPS3_EXT_3V4 and VSMPS4_EXT_3V4 */
6879886be0SArnd Bergmann 	[AB8500_EXT_SUPPLY3] = {
6979886be0SArnd Bergmann 		.constraints = {
7079886be0SArnd Bergmann 			.name = "ab8500-ext-supply3",
7179886be0SArnd Bergmann 			.min_uV = 3400000,
7279886be0SArnd Bergmann 			.max_uV = 3400000,
7379886be0SArnd Bergmann 			.valid_ops_mask = REGULATOR_CHANGE_STATUS,
7479886be0SArnd Bergmann 			.boot_on = 1,
7579886be0SArnd Bergmann 		},
7679886be0SArnd Bergmann 		.num_consumer_supplies =
7779886be0SArnd Bergmann 			ARRAY_SIZE(ab8500_ext_supply3_consumers),
7879886be0SArnd Bergmann 		.consumer_supplies = ab8500_ext_supply3_consumers,
7979886be0SArnd Bergmann 	},
8079886be0SArnd Bergmann };
8179886be0SArnd Bergmann 
82d1a82001SLee Jones /**
83d1a82001SLee Jones  * struct ab8500_ext_regulator_info - ab8500 regulator information
84d1a82001SLee Jones  * @dev: device pointer
85d1a82001SLee Jones  * @desc: regulator description
8618bc2b39SBengt Jonsson  * @cfg: regulator configuration (extension of regulator FW configuration)
87d1a82001SLee Jones  * @update_bank: bank to control on/off
88d1a82001SLee Jones  * @update_reg: register to control on/off
89d1a82001SLee Jones  * @update_mask: mask to enable/disable and set mode of regulator
90d1a82001SLee Jones  * @update_val: bits holding the regulator current mode
9118bc2b39SBengt Jonsson  * @update_val_hp: bits to set EN pin active (LPn pin deactive)
92d1a82001SLee Jones  *                 normally this means high power mode
9318bc2b39SBengt Jonsson  * @update_val_lp: bits to set EN pin active and LPn pin active
94d1a82001SLee Jones  *                 normally this means low power mode
9518bc2b39SBengt Jonsson  * @update_val_hw: bits to set regulator pins in HW control
9618bc2b39SBengt Jonsson  *                 SysClkReq pins and logic will choose mode
97d1a82001SLee Jones  */
98d1a82001SLee Jones struct ab8500_ext_regulator_info {
99d1a82001SLee Jones 	struct device *dev;
100d1a82001SLee Jones 	struct regulator_desc desc;
10118bc2b39SBengt Jonsson 	struct ab8500_ext_regulator_cfg *cfg;
102d1a82001SLee Jones 	u8 update_bank;
103d1a82001SLee Jones 	u8 update_reg;
104d1a82001SLee Jones 	u8 update_mask;
105d1a82001SLee Jones 	u8 update_val;
10618bc2b39SBengt Jonsson 	u8 update_val_hp;
10718bc2b39SBengt Jonsson 	u8 update_val_lp;
10818bc2b39SBengt Jonsson 	u8 update_val_hw;
109d1a82001SLee Jones };
110d1a82001SLee Jones 
ab8500_ext_regulator_enable(struct regulator_dev * rdev)11118bc2b39SBengt Jonsson static int ab8500_ext_regulator_enable(struct regulator_dev *rdev)
11218bc2b39SBengt Jonsson {
11318bc2b39SBengt Jonsson 	int ret;
11418bc2b39SBengt Jonsson 	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
11518bc2b39SBengt Jonsson 	u8 regval;
11618bc2b39SBengt Jonsson 
11718bc2b39SBengt Jonsson 	if (info == NULL) {
11818bc2b39SBengt Jonsson 		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
11918bc2b39SBengt Jonsson 		return -EINVAL;
12018bc2b39SBengt Jonsson 	}
12118bc2b39SBengt Jonsson 
12218bc2b39SBengt Jonsson 	/*
1237384744dSAxel Lin 	 * To satisfy both HW high power request and SW request, the regulator
1247384744dSAxel Lin 	 * must be on in high power.
12518bc2b39SBengt Jonsson 	 */
12618bc2b39SBengt Jonsson 	if (info->cfg && info->cfg->hwreq)
1277384744dSAxel Lin 		regval = info->update_val_hp;
1287384744dSAxel Lin 	else
1297384744dSAxel Lin 		regval = info->update_val;
13018bc2b39SBengt Jonsson 
13118bc2b39SBengt Jonsson 	ret = abx500_mask_and_set_register_interruptible(info->dev,
13218bc2b39SBengt Jonsson 		info->update_bank, info->update_reg,
1337384744dSAxel Lin 		info->update_mask, regval);
13437daa8aeSAxel Lin 	if (ret < 0) {
13580a9c22aSAxel Lin 		dev_err(rdev_get_dev(rdev),
1367384744dSAxel Lin 			"couldn't set enable bits for regulator\n");
13737daa8aeSAxel Lin 		return ret;
13837daa8aeSAxel Lin 	}
13918bc2b39SBengt Jonsson 
1407384744dSAxel Lin 	dev_dbg(rdev_get_dev(rdev),
1417384744dSAxel Lin 		"%s-enable (bank, reg, mask, value): 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
1427384744dSAxel Lin 		info->desc.name, info->update_bank, info->update_reg,
1437384744dSAxel Lin 		info->update_mask, regval);
1447384744dSAxel Lin 
1457384744dSAxel Lin 	return 0;
146d1a82001SLee Jones }
147d1a82001SLee Jones 
ab8500_ext_regulator_disable(struct regulator_dev * rdev)148d1a82001SLee Jones static int ab8500_ext_regulator_disable(struct regulator_dev *rdev)
149d1a82001SLee Jones {
150d1a82001SLee Jones 	int ret;
151d1a82001SLee Jones 	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
15218bc2b39SBengt Jonsson 	u8 regval;
153d1a82001SLee Jones 
154d1a82001SLee Jones 	if (info == NULL) {
155d1a82001SLee Jones 		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
156d1a82001SLee Jones 		return -EINVAL;
157d1a82001SLee Jones 	}
158d1a82001SLee Jones 
1597384744dSAxel Lin 	/*
1607384744dSAxel Lin 	 * Set the regulator in HW request mode if configured
1617384744dSAxel Lin 	 */
1627384744dSAxel Lin 	if (info->cfg && info->cfg->hwreq)
1637384744dSAxel Lin 		regval = info->update_val_hw;
1647384744dSAxel Lin 	else
1657384744dSAxel Lin 		regval = 0;
1667384744dSAxel Lin 
1677384744dSAxel Lin 	ret = abx500_mask_and_set_register_interruptible(info->dev,
1687384744dSAxel Lin 		info->update_bank, info->update_reg,
1697384744dSAxel Lin 		info->update_mask, regval);
1707384744dSAxel Lin 	if (ret < 0) {
17180a9c22aSAxel Lin 		dev_err(rdev_get_dev(rdev),
1727384744dSAxel Lin 			"couldn't set disable bits for regulator\n");
1737384744dSAxel Lin 		return ret;
1747384744dSAxel Lin 	}
175d1a82001SLee Jones 
176d1a82001SLee Jones 	dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):"
177d1a82001SLee Jones 		" 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
178d1a82001SLee Jones 		info->desc.name, info->update_bank, info->update_reg,
17918bc2b39SBengt Jonsson 		info->update_mask, regval);
180d1a82001SLee Jones 
1817384744dSAxel Lin 	return 0;
182d1a82001SLee Jones }
183d1a82001SLee Jones 
ab8500_ext_regulator_is_enabled(struct regulator_dev * rdev)184d1a82001SLee Jones static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev)
185d1a82001SLee Jones {
186d1a82001SLee Jones 	int ret;
187d1a82001SLee Jones 	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
188d1a82001SLee Jones 	u8 regval;
189d1a82001SLee Jones 
190d1a82001SLee Jones 	if (info == NULL) {
191d1a82001SLee Jones 		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
192d1a82001SLee Jones 		return -EINVAL;
193d1a82001SLee Jones 	}
194d1a82001SLee Jones 
195d1a82001SLee Jones 	ret = abx500_get_register_interruptible(info->dev,
196d1a82001SLee Jones 		info->update_bank, info->update_reg, &regval);
197d1a82001SLee Jones 	if (ret < 0) {
198d1a82001SLee Jones 		dev_err(rdev_get_dev(rdev),
199d1a82001SLee Jones 			"couldn't read 0x%x register\n", info->update_reg);
200d1a82001SLee Jones 		return ret;
201d1a82001SLee Jones 	}
202d1a82001SLee Jones 
203d1a82001SLee Jones 	dev_dbg(rdev_get_dev(rdev), "%s-is_enabled (bank, reg, mask, value):"
204d1a82001SLee Jones 		" 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
205d1a82001SLee Jones 		info->desc.name, info->update_bank, info->update_reg,
206d1a82001SLee Jones 		info->update_mask, regval);
207d1a82001SLee Jones 
20818bc2b39SBengt Jonsson 	if (((regval & info->update_mask) == info->update_val_lp) ||
20918bc2b39SBengt Jonsson 	    ((regval & info->update_mask) == info->update_val_hp))
2109ab51a0eSAxel Lin 		return 1;
211d1a82001SLee Jones 	else
2129ab51a0eSAxel Lin 		return 0;
213d1a82001SLee Jones }
214d1a82001SLee Jones 
ab8500_ext_regulator_set_mode(struct regulator_dev * rdev,unsigned int mode)215d1a82001SLee Jones static int ab8500_ext_regulator_set_mode(struct regulator_dev *rdev,
216d1a82001SLee Jones 					 unsigned int mode)
217d1a82001SLee Jones {
218d1a82001SLee Jones 	int ret = 0;
219d1a82001SLee Jones 	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
22066511fa4SAxel Lin 	u8 regval;
221d1a82001SLee Jones 
222d1a82001SLee Jones 	if (info == NULL) {
223d1a82001SLee Jones 		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
224d1a82001SLee Jones 		return -EINVAL;
225d1a82001SLee Jones 	}
226d1a82001SLee Jones 
227d1a82001SLee Jones 	switch (mode) {
228d1a82001SLee Jones 	case REGULATOR_MODE_NORMAL:
22966511fa4SAxel Lin 		regval = info->update_val_hp;
230d1a82001SLee Jones 		break;
231d1a82001SLee Jones 	case REGULATOR_MODE_IDLE:
23266511fa4SAxel Lin 		regval = info->update_val_lp;
233d1a82001SLee Jones 		break;
234d1a82001SLee Jones 
235d1a82001SLee Jones 	default:
236d1a82001SLee Jones 		return -EINVAL;
237d1a82001SLee Jones 	}
238d1a82001SLee Jones 
23966511fa4SAxel Lin 	/* If regulator is enabled and info->cfg->hwreq is set, the regulator
24066511fa4SAxel Lin 	   must be on in high power, so we don't need to write the register with
24166511fa4SAxel Lin 	   the same value.
24266511fa4SAxel Lin 	 */
24366511fa4SAxel Lin 	if (ab8500_ext_regulator_is_enabled(rdev) &&
24466511fa4SAxel Lin 	    !(info->cfg && info->cfg->hwreq)) {
24566511fa4SAxel Lin 		ret = abx500_mask_and_set_register_interruptible(info->dev,
24666511fa4SAxel Lin 					info->update_bank, info->update_reg,
24766511fa4SAxel Lin 					info->update_mask, regval);
24866511fa4SAxel Lin 		if (ret < 0) {
249d1a82001SLee Jones 			dev_err(rdev_get_dev(rdev),
250d1a82001SLee Jones 				"Could not set regulator mode.\n");
25166511fa4SAxel Lin 			return ret;
25266511fa4SAxel Lin 		}
253d1a82001SLee Jones 
254d1a82001SLee Jones 		dev_dbg(rdev_get_dev(rdev),
255d1a82001SLee Jones 			"%s-set_mode (bank, reg, mask, value): "
256d1a82001SLee Jones 			"0x%x, 0x%x, 0x%x, 0x%x\n",
257d1a82001SLee Jones 			info->desc.name, info->update_bank, info->update_reg,
258d1a82001SLee Jones 			info->update_mask, regval);
259d1a82001SLee Jones 	}
260d1a82001SLee Jones 
26166511fa4SAxel Lin 	info->update_val = regval;
26266511fa4SAxel Lin 
26366511fa4SAxel Lin 	return 0;
264d1a82001SLee Jones }
265d1a82001SLee Jones 
ab8500_ext_regulator_get_mode(struct regulator_dev * rdev)266d1a82001SLee Jones static unsigned int ab8500_ext_regulator_get_mode(struct regulator_dev *rdev)
267d1a82001SLee Jones {
268d1a82001SLee Jones 	struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
269d1a82001SLee Jones 	int ret;
270d1a82001SLee Jones 
271d1a82001SLee Jones 	if (info == NULL) {
272d1a82001SLee Jones 		dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
273d1a82001SLee Jones 		return -EINVAL;
274d1a82001SLee Jones 	}
275d1a82001SLee Jones 
276d1a82001SLee Jones 	if (info->update_val == info->update_val_hp)
277d1a82001SLee Jones 		ret = REGULATOR_MODE_NORMAL;
278d1a82001SLee Jones 	else if (info->update_val == info->update_val_lp)
279d1a82001SLee Jones 		ret = REGULATOR_MODE_IDLE;
280d1a82001SLee Jones 	else
281d1a82001SLee Jones 		ret = -EINVAL;
282d1a82001SLee Jones 
283d1a82001SLee Jones 	return ret;
284d1a82001SLee Jones }
285d1a82001SLee Jones 
ab8500_ext_set_voltage(struct regulator_dev * rdev,int min_uV,int max_uV,unsigned * selector)28633fb8802SLee Jones static int ab8500_ext_set_voltage(struct regulator_dev *rdev, int min_uV,
28733fb8802SLee Jones 				  int max_uV, unsigned *selector)
28833fb8802SLee Jones {
28933fb8802SLee Jones 	struct regulation_constraints *regu_constraints = rdev->constraints;
29033fb8802SLee Jones 
29133fb8802SLee Jones 	if (!regu_constraints) {
29233fb8802SLee Jones 		dev_err(rdev_get_dev(rdev), "No regulator constraints\n");
29333fb8802SLee Jones 		return -EINVAL;
29433fb8802SLee Jones 	}
29533fb8802SLee Jones 
29633fb8802SLee Jones 	if (regu_constraints->min_uV == min_uV &&
29733fb8802SLee Jones 	    regu_constraints->max_uV == max_uV)
29833fb8802SLee Jones 		return 0;
29933fb8802SLee Jones 
30033fb8802SLee Jones 	dev_err(rdev_get_dev(rdev),
30133fb8802SLee Jones 		"Requested min %duV max %duV != constrained min %duV max %duV\n",
30233fb8802SLee Jones 		min_uV, max_uV,
30333fb8802SLee Jones 		regu_constraints->min_uV, regu_constraints->max_uV);
30433fb8802SLee Jones 
30533fb8802SLee Jones 	return -EINVAL;
30633fb8802SLee Jones }
30733fb8802SLee Jones 
ab8500_ext_list_voltage(struct regulator_dev * rdev,unsigned selector)308d1a82001SLee Jones static int ab8500_ext_list_voltage(struct regulator_dev *rdev,
309d1a82001SLee Jones 				   unsigned selector)
310d1a82001SLee Jones {
311d1a82001SLee Jones 	struct regulation_constraints *regu_constraints = rdev->constraints;
312d1a82001SLee Jones 
313d1a82001SLee Jones 	if (regu_constraints == NULL) {
314d1a82001SLee Jones 		dev_err(rdev_get_dev(rdev), "regulator constraints null pointer\n");
315d1a82001SLee Jones 		return -EINVAL;
316d1a82001SLee Jones 	}
317d1a82001SLee Jones 	/* return the uV for the fixed regulators */
318d1a82001SLee Jones 	if (regu_constraints->min_uV && regu_constraints->max_uV) {
319d1a82001SLee Jones 		if (regu_constraints->min_uV == regu_constraints->max_uV)
320d1a82001SLee Jones 			return regu_constraints->min_uV;
321d1a82001SLee Jones 	}
322d1a82001SLee Jones 	return -EINVAL;
323d1a82001SLee Jones }
324d1a82001SLee Jones 
3258e5be4f7SAxel Lin static const struct regulator_ops ab8500_ext_regulator_ops = {
326d1a82001SLee Jones 	.enable			= ab8500_ext_regulator_enable,
327d1a82001SLee Jones 	.disable		= ab8500_ext_regulator_disable,
328d1a82001SLee Jones 	.is_enabled		= ab8500_ext_regulator_is_enabled,
329d1a82001SLee Jones 	.set_mode		= ab8500_ext_regulator_set_mode,
330d1a82001SLee Jones 	.get_mode		= ab8500_ext_regulator_get_mode,
33133fb8802SLee Jones 	.set_voltage		= ab8500_ext_set_voltage,
332d1a82001SLee Jones 	.list_voltage		= ab8500_ext_list_voltage,
333d1a82001SLee Jones };
334d1a82001SLee Jones 
335d1a82001SLee Jones static struct ab8500_ext_regulator_info
336d1a82001SLee Jones 		ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = {
337d1a82001SLee Jones 	[AB8500_EXT_SUPPLY1] = {
338d1a82001SLee Jones 		.desc = {
339d1a82001SLee Jones 			.name		= "VEXTSUPPLY1",
34048cb9737SAxel Lin 			.of_match	= of_match_ptr("ab8500_ext1"),
341d1a82001SLee Jones 			.ops		= &ab8500_ext_regulator_ops,
342d1a82001SLee Jones 			.type		= REGULATOR_VOLTAGE,
343d1a82001SLee Jones 			.id		= AB8500_EXT_SUPPLY1,
344d1a82001SLee Jones 			.owner		= THIS_MODULE,
345d1a82001SLee Jones 			.n_voltages	= 1,
346d1a82001SLee Jones 		},
347d1a82001SLee Jones 		.update_bank		= 0x04,
348d1a82001SLee Jones 		.update_reg		= 0x08,
349d1a82001SLee Jones 		.update_mask		= 0x03,
350d1a82001SLee Jones 		.update_val		= 0x01,
351d1a82001SLee Jones 		.update_val_hp		= 0x01,
352d1a82001SLee Jones 		.update_val_lp		= 0x03,
353d1a82001SLee Jones 		.update_val_hw		= 0x02,
354d1a82001SLee Jones 	},
355d1a82001SLee Jones 	[AB8500_EXT_SUPPLY2] = {
356d1a82001SLee Jones 		.desc = {
357d1a82001SLee Jones 			.name		= "VEXTSUPPLY2",
35848cb9737SAxel Lin 			.of_match	= of_match_ptr("ab8500_ext2"),
359d1a82001SLee Jones 			.ops		= &ab8500_ext_regulator_ops,
360d1a82001SLee Jones 			.type		= REGULATOR_VOLTAGE,
361d1a82001SLee Jones 			.id		= AB8500_EXT_SUPPLY2,
362d1a82001SLee Jones 			.owner		= THIS_MODULE,
363d1a82001SLee Jones 			.n_voltages	= 1,
364d1a82001SLee Jones 		},
365d1a82001SLee Jones 		.update_bank		= 0x04,
366d1a82001SLee Jones 		.update_reg		= 0x08,
367d1a82001SLee Jones 		.update_mask		= 0x0c,
368d1a82001SLee Jones 		.update_val		= 0x04,
369d1a82001SLee Jones 		.update_val_hp		= 0x04,
370d1a82001SLee Jones 		.update_val_lp		= 0x0c,
371d1a82001SLee Jones 		.update_val_hw		= 0x08,
372d1a82001SLee Jones 	},
373d1a82001SLee Jones 	[AB8500_EXT_SUPPLY3] = {
374d1a82001SLee Jones 		.desc = {
375d1a82001SLee Jones 			.name		= "VEXTSUPPLY3",
37648cb9737SAxel Lin 			.of_match	= of_match_ptr("ab8500_ext3"),
377d1a82001SLee Jones 			.ops		= &ab8500_ext_regulator_ops,
378d1a82001SLee Jones 			.type		= REGULATOR_VOLTAGE,
379d1a82001SLee Jones 			.id		= AB8500_EXT_SUPPLY3,
380d1a82001SLee Jones 			.owner		= THIS_MODULE,
381d1a82001SLee Jones 			.n_voltages	= 1,
382d1a82001SLee Jones 		},
383d1a82001SLee Jones 		.update_bank		= 0x04,
384d1a82001SLee Jones 		.update_reg		= 0x08,
385d1a82001SLee Jones 		.update_mask		= 0x30,
386d1a82001SLee Jones 		.update_val		= 0x10,
38718bc2b39SBengt Jonsson 		.update_val_hp		= 0x10,
38818bc2b39SBengt Jonsson 		.update_val_lp		= 0x30,
38918bc2b39SBengt Jonsson 		.update_val_hw		= 0x20,
390d1a82001SLee Jones 	},
391d1a82001SLee Jones };
392d1a82001SLee Jones 
ab8500_ext_regulator_probe(struct platform_device * pdev)39308d49f43SSachin Kamat static int ab8500_ext_regulator_probe(struct platform_device *pdev)
394d1a82001SLee Jones {
395d1a82001SLee Jones 	struct ab8500 *ab8500 = dev_get_drvdata(pdev->dev.parent);
396d1a82001SLee Jones 	struct regulator_config config = { };
39780a9c22aSAxel Lin 	struct regulator_dev *rdev;
39848cb9737SAxel Lin 	int i;
39930aa4b26SLee Jones 
400d1a82001SLee Jones 	if (!ab8500) {
401d1a82001SLee Jones 		dev_err(&pdev->dev, "null mfd parent\n");
402d1a82001SLee Jones 		return -EINVAL;
403d1a82001SLee Jones 	}
40430aa4b26SLee Jones 
405d1a82001SLee Jones 	/* check for AB8500 2.x */
406a6324709SBengt Jonsson 	if (is_ab8500_2p0_or_earlier(ab8500)) {
407d1a82001SLee Jones 		struct ab8500_ext_regulator_info *info;
408d1a82001SLee Jones 
409d1a82001SLee Jones 		/* VextSupply3LPn is inverted on AB8500 2.x */
410d1a82001SLee Jones 		info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3];
411d1a82001SLee Jones 		info->update_val = 0x30;
41218bc2b39SBengt Jonsson 		info->update_val_hp = 0x30;
41318bc2b39SBengt Jonsson 		info->update_val_lp = 0x10;
414d1a82001SLee Jones 	}
415d1a82001SLee Jones 
416d1a82001SLee Jones 	/* register all regulators */
417d1a82001SLee Jones 	for (i = 0; i < ARRAY_SIZE(ab8500_ext_regulator_info); i++) {
418d1a82001SLee Jones 		struct ab8500_ext_regulator_info *info = NULL;
419d1a82001SLee Jones 
420d1a82001SLee Jones 		/* assign per-regulator data */
421d1a82001SLee Jones 		info = &ab8500_ext_regulator_info[i];
422d1a82001SLee Jones 		info->dev = &pdev->dev;
42318bc2b39SBengt Jonsson 		info->cfg = (struct ab8500_ext_regulator_cfg *)
424c512150bSLinus Walleij 			ab8500_ext_regulators[i].driver_data;
425d1a82001SLee Jones 
426d1a82001SLee Jones 		config.dev = &pdev->dev;
427d1a82001SLee Jones 		config.driver_data = info;
428c512150bSLinus Walleij 		config.init_data = &ab8500_ext_regulators[i];
429d1a82001SLee Jones 
430d1a82001SLee Jones 		/* register regulator with framework */
43180a9c22aSAxel Lin 		rdev = devm_regulator_register(&pdev->dev, &info->desc,
432a4a6b9deSJingoo Han 					       &config);
43380a9c22aSAxel Lin 		if (IS_ERR(rdev)) {
434d1a82001SLee Jones 			dev_err(&pdev->dev, "failed to register regulator %s\n",
435d1a82001SLee Jones 					info->desc.name);
43680a9c22aSAxel Lin 			return PTR_ERR(rdev);
437d1a82001SLee Jones 		}
438d1a82001SLee Jones 
43980a9c22aSAxel Lin 		dev_dbg(&pdev->dev, "%s-probed\n", info->desc.name);
440d1a82001SLee Jones 	}
441d1a82001SLee Jones 
442d1a82001SLee Jones 	return 0;
443d1a82001SLee Jones }
444d1a82001SLee Jones 
4455a49b4a5SLee Jones static struct platform_driver ab8500_ext_regulator_driver = {
4465a49b4a5SLee Jones 	.probe = ab8500_ext_regulator_probe,
4475a49b4a5SLee Jones 	.driver         = {
4485a49b4a5SLee Jones 		.name   = "ab8500-ext-regulator",
449*259b93b2SDouglas Anderson 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
4505a49b4a5SLee Jones 	},
4515a49b4a5SLee Jones };
4525a49b4a5SLee Jones 
ab8500_ext_regulator_init(void)4535a49b4a5SLee Jones static int __init ab8500_ext_regulator_init(void)
4545a49b4a5SLee Jones {
4555a49b4a5SLee Jones 	int ret;
4565a49b4a5SLee Jones 
4575a49b4a5SLee Jones 	ret = platform_driver_register(&ab8500_ext_regulator_driver);
4585a49b4a5SLee Jones 	if (ret)
4595a49b4a5SLee Jones 		pr_err("Failed to register ab8500 ext regulator: %d\n", ret);
4605a49b4a5SLee Jones 
4615a49b4a5SLee Jones 	return ret;
4625a49b4a5SLee Jones }
4635a49b4a5SLee Jones subsys_initcall(ab8500_ext_regulator_init);
4645a49b4a5SLee Jones 
ab8500_ext_regulator_exit(void)4655a49b4a5SLee Jones static void __exit ab8500_ext_regulator_exit(void)
4665a49b4a5SLee Jones {
4675a49b4a5SLee Jones 	platform_driver_unregister(&ab8500_ext_regulator_driver);
4685a49b4a5SLee Jones }
4695a49b4a5SLee Jones module_exit(ab8500_ext_regulator_exit);
4705a49b4a5SLee Jones 
471d1a82001SLee Jones MODULE_LICENSE("GPL v2");
472d1a82001SLee Jones MODULE_AUTHOR("Bengt Jonsson <bengt.g.jonsson@stericsson.com>");
473d1a82001SLee Jones MODULE_DESCRIPTION("AB8500 external regulator driver");
474d1a82001SLee Jones MODULE_ALIAS("platform:ab8500-ext-regulator");
475