diff options
Diffstat (limited to 'drivers/regulator/ab8500-ext.c')
-rw-r--r-- | drivers/regulator/ab8500-ext.c | 98 |
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 | */ |
42 | struct ab8500_ext_regulator_info { | 44 | struct 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 | ||
55 | static int ab8500_ext_regulator_enable(struct regulator_dev *rdev) | 59 | static 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 | ||
82 | static int ab8500_ext_regulator_disable(struct regulator_dev *rdev) | 84 | static 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, ®val); | ||
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 | |||
105 | static 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 | |||
129 | static 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, ®val); | ||
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 | |||
245 | static struct ab8500_ext_regulator_info | 286 | static 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]; |