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, ®val);
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