aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator/ab8500-ext.c
diff options
context:
space:
mode:
authorBengt Jonsson <bengt.g.jonsson@stericsson.com>2013-03-28 12:11:06 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-03-29 13:49:09 -0400
commit18bc2b39307b45527efc6c84836953c7a8f2181e (patch)
tree29062ff9e05ed3a8afaff67fafbdfceda81d7fa3 /drivers/regulator/ab8500-ext.c
parente0c44686c3e22b2b7f0441a31db411b1c70b47c3 (diff)
regulator: ab8500-ext: Add HW request support
Support for HW request is added in the external regulator driver. A flag in the board configuration can be set to let HW control the regulator when there is no SW request. This means that the regulator will be put in high power mode when there is a SW request and in HW-request mode otherwise. Signed-off-by: Bengt Jonsson <bengt.g.jonsson@stericsson.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Reviewed-by: Mattias NILSSON <mattias.i.nilsson@stericsson.com> Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/regulator/ab8500-ext.c')
-rw-r--r--drivers/regulator/ab8500-ext.c98
1 files changed, 71 insertions, 27 deletions
diff --git a/drivers/regulator/ab8500-ext.c b/drivers/regulator/ab8500-ext.c
index 95008dec5190..21b9bfb0fc5e 100644
--- a/drivers/regulator/ab8500-ext.c
+++ b/drivers/regulator/ab8500-ext.c
@@ -28,80 +28,121 @@
28 * @dev: device pointer 28 * @dev: device pointer
29 * @desc: regulator description 29 * @desc: regulator description
30 * @rdev: regulator device 30 * @rdev: regulator device
31 * @cfg: regulator configuration (extension of regulator FW configuration)
31 * @is_enabled: status of regulator (on/off) 32 * @is_enabled: status of regulator (on/off)
32 * @update_bank: bank to control on/off 33 * @update_bank: bank to control on/off
33 * @update_reg: register to control on/off 34 * @update_reg: register to control on/off
34 * @update_mask: mask to enable/disable and set mode of regulator 35 * @update_mask: mask to enable/disable and set mode of regulator
35 * @update_val: bits holding the regulator current mode 36 * @update_val: bits holding the regulator current mode
36 * @update_val_en: bits to set EN pin active (LPn pin deactive) 37 * @update_val_hp: bits to set EN pin active (LPn pin deactive)
37 * normally this means high power mode 38 * normally this means high power mode
38 * @update_val_en_lp: bits to set EN pin active and LPn pin active 39 * @update_val_lp: bits to set EN pin active and LPn pin active
39 * normally this means low power mode 40 * normally this means low power mode
40 * @delay: startup delay in ms 41 * @update_val_hw: bits to set regulator pins in HW control
42 * SysClkReq pins and logic will choose mode
41 */ 43 */
42struct ab8500_ext_regulator_info { 44struct ab8500_ext_regulator_info {
43 struct device *dev; 45 struct device *dev;
44 struct regulator_desc desc; 46 struct regulator_desc desc;
45 struct regulator_dev *rdev; 47 struct regulator_dev *rdev;
48 struct ab8500_ext_regulator_cfg *cfg;
46 bool is_enabled; 49 bool is_enabled;
47 u8 update_bank; 50 u8 update_bank;
48 u8 update_reg; 51 u8 update_reg;
49 u8 update_mask; 52 u8 update_mask;
50 u8 update_val; 53 u8 update_val;
51 u8 update_val_en; 54 u8 update_val_hp;
52 u8 update_val_en_lp; 55 u8 update_val_lp;
56 u8 update_val_hw;
53}; 57};
54 58
55static int ab8500_ext_regulator_enable(struct regulator_dev *rdev) 59static int enable(struct ab8500_ext_regulator_info *info, u8 *regval)
56{ 60{
57 int ret; 61 int ret;
58 struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
59 62
60 if (info == NULL) { 63 *regval = info->update_val;
61 dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 64
62 return -EINVAL; 65 /*
63 } 66 * To satisfy both HW high power request and SW request, the regulator
67 * must be on in high power.
68 */
69 if (info->cfg && info->cfg->hwreq)
70 *regval = info->update_val_hp;
64 71
65 ret = abx500_mask_and_set_register_interruptible(info->dev, 72 ret = abx500_mask_and_set_register_interruptible(info->dev,
66 info->update_bank, info->update_reg, 73 info->update_bank, info->update_reg,
67 info->update_mask, info->update_val); 74 info->update_mask, *regval);
68 if (ret < 0) 75 if (ret < 0)
69 dev_err(rdev_get_dev(info->rdev), 76 dev_err(rdev_get_dev(info->rdev),
70 "couldn't set enable bits for regulator\n"); 77 "couldn't set enable bits for regulator\n");
71 78
72 info->is_enabled = true; 79 info->is_enabled = true;
73 80
74 dev_dbg(rdev_get_dev(rdev), "%s-enable (bank, reg, mask, value):"
75 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
76 info->desc.name, info->update_bank, info->update_reg,
77 info->update_mask, info->update_val);
78
79 return ret; 81 return ret;
80} 82}
81 83
82static int ab8500_ext_regulator_disable(struct regulator_dev *rdev) 84static int ab8500_ext_regulator_enable(struct regulator_dev *rdev)
83{ 85{
84 int ret; 86 int ret;
85 struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev); 87 struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
88 u8 regval;
86 89
87 if (info == NULL) { 90 if (info == NULL) {
88 dev_err(rdev_get_dev(rdev), "regulator info null pointer\n"); 91 dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
89 return -EINVAL; 92 return -EINVAL;
90 } 93 }
91 94
95 ret = enable(info, &regval);
96
97 dev_dbg(rdev_get_dev(rdev), "%s-enable (bank, reg, mask, value):"
98 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
99 info->desc.name, info->update_bank, info->update_reg,
100 info->update_mask, regval);
101
102 return ret;
103}
104
105static int disable(struct ab8500_ext_regulator_info *info, u8 *regval)
106{
107 int ret;
108
109 *regval = 0x0;
110
111 /*
112 * Set the regulator in HW request mode if configured
113 */
114 if (info->cfg && info->cfg->hwreq)
115 *regval = info->update_val_hw;
116
92 ret = abx500_mask_and_set_register_interruptible(info->dev, 117 ret = abx500_mask_and_set_register_interruptible(info->dev,
93 info->update_bank, info->update_reg, 118 info->update_bank, info->update_reg,
94 info->update_mask, 0x0); 119 info->update_mask, *regval);
95 if (ret < 0) 120 if (ret < 0)
96 dev_err(rdev_get_dev(info->rdev), 121 dev_err(rdev_get_dev(info->rdev),
97 "couldn't set disable bits for regulator\n"); 122 "couldn't set disable bits for regulator\n");
98 123
99 info->is_enabled = false; 124 info->is_enabled = false;
100 125
126 return ret;
127}
128
129static int ab8500_ext_regulator_disable(struct regulator_dev *rdev)
130{
131 int ret;
132 struct ab8500_ext_regulator_info *info = rdev_get_drvdata(rdev);
133 u8 regval;
134
135 if (info == NULL) {
136 dev_err(rdev_get_dev(rdev), "regulator info null pointer\n");
137 return -EINVAL;
138 }
139
140 ret = disable(info, &regval);
141
101 dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):" 142 dev_dbg(rdev_get_dev(rdev), "%s-disable (bank, reg, mask, value):"
102 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n", 143 " 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
103 info->desc.name, info->update_bank, info->update_reg, 144 info->desc.name, info->update_bank, info->update_reg,
104 info->update_mask, 0x0); 145 info->update_mask, regval);
105 146
106 return ret; 147 return ret;
107} 148}
@@ -130,7 +171,8 @@ static int ab8500_ext_regulator_is_enabled(struct regulator_dev *rdev)
130 info->desc.name, info->update_bank, info->update_reg, 171 info->desc.name, info->update_bank, info->update_reg,
131 info->update_mask, regval); 172 info->update_mask, regval);
132 173
133 if (regval & info->update_mask) 174 if (((regval & info->update_mask) == info->update_val_lp) ||
175 ((regval & info->update_mask) == info->update_val_hp))
134 info->is_enabled = true; 176 info->is_enabled = true;
135 else 177 else
136 info->is_enabled = false; 178 info->is_enabled = false;
@@ -241,7 +283,6 @@ static struct regulator_ops ab8500_ext_regulator_ops = {
241 .list_voltage = ab8500_ext_list_voltage, 283 .list_voltage = ab8500_ext_list_voltage,
242}; 284};
243 285
244
245static struct ab8500_ext_regulator_info 286static struct ab8500_ext_regulator_info
246 ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = { 287 ab8500_ext_regulator_info[AB8500_NUM_EXT_REGULATORS] = {
247 [AB8500_EXT_SUPPLY1] = { 288 [AB8500_EXT_SUPPLY1] = {
@@ -291,8 +332,9 @@ static struct ab8500_ext_regulator_info
291 .update_reg = 0x08, 332 .update_reg = 0x08,
292 .update_mask = 0x30, 333 .update_mask = 0x30,
293 .update_val = 0x10, 334 .update_val = 0x10,
294 .update_val_en = 0x10, 335 .update_val_hp = 0x10,
295 .update_val_en_lp = 0x30, 336 .update_val_lp = 0x30,
337 .update_val_hw = 0x20,
296 }, 338 },
297}; 339};
298 340
@@ -333,8 +375,8 @@ int ab8500_ext_regulator_init(struct platform_device *pdev)
333 /* VextSupply3LPn is inverted on AB8500 2.x */ 375 /* VextSupply3LPn is inverted on AB8500 2.x */
334 info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3]; 376 info = &ab8500_ext_regulator_info[AB8500_EXT_SUPPLY3];
335 info->update_val = 0x30; 377 info->update_val = 0x30;
336 info->update_val_en = 0x30; 378 info->update_val_hp = 0x30;
337 info->update_val_en_lp = 0x10; 379 info->update_val_lp = 0x10;
338 } 380 }
339 381
340 /* register all regulators */ 382 /* register all regulators */
@@ -344,6 +386,8 @@ int ab8500_ext_regulator_init(struct platform_device *pdev)
344 /* assign per-regulator data */ 386 /* assign per-regulator data */
345 info = &ab8500_ext_regulator_info[i]; 387 info = &ab8500_ext_regulator_info[i];
346 info->dev = &pdev->dev; 388 info->dev = &pdev->dev;
389 info->cfg = (struct ab8500_ext_regulator_cfg *)
390 pdata->ext_regulator[i].driver_data;
347 391
348 config.dev = &pdev->dev; 392 config.dev = &pdev->dev;
349 config.init_data = &pdata->ext_regulator[i]; 393 config.init_data = &pdata->ext_regulator[i];