diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-08-03 13:49:57 -0400 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2009-09-22 08:32:41 -0400 |
commit | 9a2372fa7a403ba327873d0208a619d781a8a150 (patch) | |
tree | a9b3b932420563fdebc9be6f7451aefb1df7fb6f /drivers/regulator | |
parent | 9332546fe88fa88bf6a7d9b1dce53ff5d314934e (diff) |
regulator: regulator_enable() permission checking
The regulator_enable() code wasn't actually checking that the
machine constraints had given permission to enable the regulator.
Add code to do that, but only if the regulator is not already on
due to something like always_on or being left on at startup since
in those cases there's no physical change being introduced and the
constraint wouldn't make any sense.
Also add matching code for disable(). We need to do less there since
either regulator_enable() should have succeeded first or the board
setup makes no sense.
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/core.c | 56 |
1 files changed, 36 insertions, 20 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 60fcd986ff3f..dbf27bf028c4 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -1191,16 +1191,21 @@ void regulator_put(struct regulator *regulator) | |||
1191 | } | 1191 | } |
1192 | EXPORT_SYMBOL_GPL(regulator_put); | 1192 | EXPORT_SYMBOL_GPL(regulator_put); |
1193 | 1193 | ||
1194 | static int _regulator_can_change_status(struct regulator_dev *rdev) | ||
1195 | { | ||
1196 | if (!rdev->constraints) | ||
1197 | return 0; | ||
1198 | |||
1199 | if (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_STATUS) | ||
1200 | return 1; | ||
1201 | else | ||
1202 | return 0; | ||
1203 | } | ||
1204 | |||
1194 | /* locks held by regulator_enable() */ | 1205 | /* locks held by regulator_enable() */ |
1195 | static int _regulator_enable(struct regulator_dev *rdev) | 1206 | static int _regulator_enable(struct regulator_dev *rdev) |
1196 | { | 1207 | { |
1197 | int ret = -EINVAL; | 1208 | int ret; |
1198 | |||
1199 | if (!rdev->constraints) { | ||
1200 | printk(KERN_ERR "%s: %s has no constraints\n", | ||
1201 | __func__, rdev->desc->name); | ||
1202 | return ret; | ||
1203 | } | ||
1204 | 1209 | ||
1205 | /* do we need to enable the supply regulator first */ | 1210 | /* do we need to enable the supply regulator first */ |
1206 | if (rdev->supply) { | 1211 | if (rdev->supply) { |
@@ -1213,24 +1218,34 @@ static int _regulator_enable(struct regulator_dev *rdev) | |||
1213 | } | 1218 | } |
1214 | 1219 | ||
1215 | /* check voltage and requested load before enabling */ | 1220 | /* check voltage and requested load before enabling */ |
1216 | if (rdev->desc->ops->enable) { | 1221 | if (rdev->constraints && |
1222 | (rdev->constraints->valid_ops_mask & REGULATOR_CHANGE_DRMS)) | ||
1223 | drms_uA_update(rdev); | ||
1217 | 1224 | ||
1218 | if (rdev->constraints && | 1225 | if (rdev->use_count == 0) { |
1219 | (rdev->constraints->valid_ops_mask & | 1226 | /* The regulator may on if it's not switchable or left on */ |
1220 | REGULATOR_CHANGE_DRMS)) | 1227 | ret = _regulator_is_enabled(rdev); |
1221 | drms_uA_update(rdev); | 1228 | if (ret == -EINVAL || ret == 0) { |
1222 | 1229 | if (!_regulator_can_change_status(rdev)) | |
1223 | ret = rdev->desc->ops->enable(rdev); | 1230 | return -EPERM; |
1224 | if (ret < 0) { | 1231 | |
1225 | printk(KERN_ERR "%s: failed to enable %s: %d\n", | 1232 | if (rdev->desc->ops->enable) { |
1233 | ret = rdev->desc->ops->enable(rdev); | ||
1234 | if (ret < 0) | ||
1235 | return ret; | ||
1236 | } else { | ||
1237 | return -EINVAL; | ||
1238 | } | ||
1239 | } else { | ||
1240 | printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", | ||
1226 | __func__, rdev->desc->name, ret); | 1241 | __func__, rdev->desc->name, ret); |
1227 | return ret; | 1242 | return ret; |
1228 | } | 1243 | } |
1229 | rdev->use_count++; | ||
1230 | return ret; | ||
1231 | } | 1244 | } |
1232 | 1245 | ||
1233 | return ret; | 1246 | rdev->use_count++; |
1247 | |||
1248 | return 0; | ||
1234 | } | 1249 | } |
1235 | 1250 | ||
1236 | /** | 1251 | /** |
@@ -1270,7 +1285,8 @@ static int _regulator_disable(struct regulator_dev *rdev) | |||
1270 | if (rdev->use_count == 1 && !rdev->constraints->always_on) { | 1285 | if (rdev->use_count == 1 && !rdev->constraints->always_on) { |
1271 | 1286 | ||
1272 | /* we are last user */ | 1287 | /* we are last user */ |
1273 | if (rdev->desc->ops->disable) { | 1288 | if (_regulator_can_change_status(rdev) && |
1289 | rdev->desc->ops->disable) { | ||
1274 | ret = rdev->desc->ops->disable(rdev); | 1290 | ret = rdev->desc->ops->disable(rdev); |
1275 | if (ret < 0) { | 1291 | if (ret < 0) { |
1276 | printk(KERN_ERR "%s: failed to disable %s\n", | 1292 | printk(KERN_ERR "%s: failed to disable %s\n", |