diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2009-03-11 20:43:34 -0400 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2009-03-31 04:56:28 -0400 |
commit | cd94b5053081963614f6ad77b9b66a7968056c84 (patch) | |
tree | 42e2ae16a14457a4e755f63fd5ff95511220f9c8 /drivers/regulator | |
parent | 1dc60343f874ce4bfbbc2c3d2f7865fc897df479 (diff) |
regulator: refcount fixes
Fix some refcounting issues in the regulator framework, supporting
regulator_disable() for regulators that were enabled at boot time
via machine constraints:
- Update those regulators' usecounts after enabling, so they
can cleanly be disabled at that level.
- Remove the problematic per-consumer usecount, so there's
only one level of enable/disable.
Buggy consumers could notice different bug symptoms. The main
example would be refcounting bugs; also, any (out-of-tree) users
of the experimental regulator_set_optimum_mode() stuff which
don't call it when they're done using a regulator.
This is a net minor codeshrink.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Acked-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 | 30 |
1 files changed, 8 insertions, 22 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 019a8a42ac18..944887578d66 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c | |||
@@ -52,7 +52,6 @@ struct regulator { | |||
52 | int uA_load; | 52 | int uA_load; |
53 | int min_uV; | 53 | int min_uV; |
54 | int max_uV; | 54 | int max_uV; |
55 | int enabled; /* count of client enables */ | ||
56 | char *supply_name; | 55 | char *supply_name; |
57 | struct device_attribute dev_attr; | 56 | struct device_attribute dev_attr; |
58 | struct regulator_dev *rdev; | 57 | struct regulator_dev *rdev; |
@@ -815,6 +814,7 @@ static int set_machine_constraints(struct regulator_dev *rdev, | |||
815 | rdev->constraints = NULL; | 814 | rdev->constraints = NULL; |
816 | goto out; | 815 | goto out; |
817 | } | 816 | } |
817 | rdev->use_count = 1; | ||
818 | } | 818 | } |
819 | 819 | ||
820 | print_constraints(rdev); | 820 | print_constraints(rdev); |
@@ -1068,10 +1068,6 @@ void regulator_put(struct regulator *regulator) | |||
1068 | mutex_lock(®ulator_list_mutex); | 1068 | mutex_lock(®ulator_list_mutex); |
1069 | rdev = regulator->rdev; | 1069 | rdev = regulator->rdev; |
1070 | 1070 | ||
1071 | if (WARN(regulator->enabled, "Releasing supply %s while enabled\n", | ||
1072 | regulator->supply_name)) | ||
1073 | _regulator_disable(rdev); | ||
1074 | |||
1075 | /* remove any sysfs entries */ | 1071 | /* remove any sysfs entries */ |
1076 | if (regulator->dev) { | 1072 | if (regulator->dev) { |
1077 | sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); | 1073 | sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); |
@@ -1146,12 +1142,7 @@ int regulator_enable(struct regulator *regulator) | |||
1146 | int ret = 0; | 1142 | int ret = 0; |
1147 | 1143 | ||
1148 | mutex_lock(&rdev->mutex); | 1144 | mutex_lock(&rdev->mutex); |
1149 | if (regulator->enabled == 0) | 1145 | ret = _regulator_enable(rdev); |
1150 | ret = _regulator_enable(rdev); | ||
1151 | else if (regulator->enabled < 0) | ||
1152 | ret = -EIO; | ||
1153 | if (ret == 0) | ||
1154 | regulator->enabled++; | ||
1155 | mutex_unlock(&rdev->mutex); | 1146 | mutex_unlock(&rdev->mutex); |
1156 | return ret; | 1147 | return ret; |
1157 | } | 1148 | } |
@@ -1162,6 +1153,11 @@ static int _regulator_disable(struct regulator_dev *rdev) | |||
1162 | { | 1153 | { |
1163 | int ret = 0; | 1154 | int ret = 0; |
1164 | 1155 | ||
1156 | if (WARN(rdev->use_count <= 0, | ||
1157 | "unbalanced disables for %s\n", | ||
1158 | rdev->desc->name)) | ||
1159 | return -EIO; | ||
1160 | |||
1165 | /* are we the last user and permitted to disable ? */ | 1161 | /* are we the last user and permitted to disable ? */ |
1166 | if (rdev->use_count == 1 && !rdev->constraints->always_on) { | 1162 | if (rdev->use_count == 1 && !rdev->constraints->always_on) { |
1167 | 1163 | ||
@@ -1210,16 +1206,7 @@ int regulator_disable(struct regulator *regulator) | |||
1210 | int ret = 0; | 1206 | int ret = 0; |
1211 | 1207 | ||
1212 | mutex_lock(&rdev->mutex); | 1208 | mutex_lock(&rdev->mutex); |
1213 | if (regulator->enabled == 1) { | 1209 | ret = _regulator_disable(rdev); |
1214 | ret = _regulator_disable(rdev); | ||
1215 | if (ret == 0) | ||
1216 | regulator->uA_load = 0; | ||
1217 | } else if (WARN(regulator->enabled <= 0, | ||
1218 | "unbalanced disables for supply %s\n", | ||
1219 | regulator->supply_name)) | ||
1220 | ret = -EIO; | ||
1221 | if (ret == 0) | ||
1222 | regulator->enabled--; | ||
1223 | mutex_unlock(&rdev->mutex); | 1210 | mutex_unlock(&rdev->mutex); |
1224 | return ret; | 1211 | return ret; |
1225 | } | 1212 | } |
@@ -1266,7 +1253,6 @@ int regulator_force_disable(struct regulator *regulator) | |||
1266 | int ret; | 1253 | int ret; |
1267 | 1254 | ||
1268 | mutex_lock(®ulator->rdev->mutex); | 1255 | mutex_lock(®ulator->rdev->mutex); |
1269 | regulator->enabled = 0; | ||
1270 | regulator->uA_load = 0; | 1256 | regulator->uA_load = 0; |
1271 | ret = _regulator_force_disable(regulator->rdev); | 1257 | ret = _regulator_force_disable(regulator->rdev); |
1272 | mutex_unlock(®ulator->rdev->mutex); | 1258 | mutex_unlock(®ulator->rdev->mutex); |