diff options
author | David Brownell <dbrownell@users.sourceforge.net> | 2008-11-16 11:44:46 -0800 |
---|---|---|
committer | Liam Girdwood <lrg@slimlogic.co.uk> | 2009-01-08 20:10:29 +0000 |
commit | 412aec610559bdb602a0a21ce149ba8ffbb6f983 (patch) | |
tree | ddc1e45080b94fdd791c244ab6f9cada712a52e5 | |
parent | 812460a927c1d0dc1fbdbec9aa07de1b04043d83 (diff) |
regulator: enable/disable refcounting
Make the <linux/regulator.h> framework treat enable/disable call
pairs like the <linux/clk.h> and <linux/interrupt.h> frameworks do:
they're refcounted, so that different parts of a driver don't need
to put work into coordination that frameworks normally handle.
It's a minor object code shrink.
It also makes the regulator_is_disabled() kerneldoc say what it's
actually returning: return value is not a refcount, and may report
an error (e.g. I/O error from I2C).
It also fixes some minor regulator_put() goofage: removing unlocked
access to the enable state. (But still not making regulator put/get
match the refcounting pattern they invoke.)
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
-rw-r--r-- | drivers/regulator/core.c | 71 |
1 files changed, 36 insertions, 35 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 9a644d41b81..c2b7ec90103 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -79,7 +79,7 @@ struct regulator { int uA_load; int min_uV; int max_uV; - int enabled; /* client has called enabled */ + int enabled; /* count of client enables */ char *supply_name; struct device_attribute dev_attr; struct regulator_dev *rdev; @@ -963,16 +963,13 @@ void regulator_put(struct regulator *regulator) if (regulator == NULL || IS_ERR(regulator)) return; - if (regulator->enabled) { - printk(KERN_WARNING "Releasing supply %s while enabled\n", - regulator->supply_name); - WARN_ON(regulator->enabled); - regulator_disable(regulator); - } - mutex_lock(®ulator_list_mutex); rdev = regulator->rdev; + if (WARN(regulator->enabled, "Releasing supply %s while enabled\n", + regulator->supply_name)) + _regulator_disable(rdev); + /* remove any sysfs entries */ if (regulator->dev) { sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); @@ -1042,21 +1039,17 @@ static int _regulator_enable(struct regulator_dev *rdev) */ int regulator_enable(struct regulator *regulator) { - int ret; - - if (regulator->enabled) { - printk(KERN_CRIT "Regulator %s already enabled\n", - regulator->supply_name); - WARN_ON(regulator->enabled); - return 0; - } + struct regulator_dev *rdev = regulator->rdev; + int ret = 0; - mutex_lock(®ulator->rdev->mutex); - regulator->enabled = 1; - ret = _regulator_enable(regulator->rdev); - if (ret != 0) - regulator->enabled = 0; - mutex_unlock(®ulator->rdev->mutex); + mutex_lock(&rdev->mutex); + if (regulator->enabled == 0) + ret = _regulator_enable(rdev); + else if (regulator->enabled < 0) + ret = -EIO; + if (ret == 0) + regulator->enabled++; + mutex_unlock(&rdev->mutex); return ret; } EXPORT_SYMBOL_GPL(regulator_enable); @@ -1108,19 +1101,21 @@ static int _regulator_disable(struct regulator_dev *rdev) */ int regulator_disable(struct regulator *regulator) { - int ret; - - if (!regulator->enabled) { - printk(KERN_ERR "%s: not in use by this consumer\n", - __func__); - return 0; - } + struct regulator_dev *rdev = regulator->rdev; + int ret = 0; - mutex_lock(®ulator->rdev->mutex); - regulator->enabled = 0; - regulator->uA_load = 0; - ret = _regulator_disable(regulator->rdev); - mutex_unlock(®ulator->rdev->mutex); + mutex_lock(&rdev->mutex); + if (regulator->enabled == 1) { + ret = _regulator_disable(rdev); + if (ret == 0) + regulator->uA_load = 0; + } else if (WARN(regulator->enabled <= 0, + "unbalanced disables for supply %s\n", + regulator->supply_name)) + ret = -EIO; + if (ret == 0) + regulator->enabled--; + mutex_unlock(&rdev->mutex); return ret; } EXPORT_SYMBOL_GPL(regulator_disable); @@ -1196,7 +1191,13 @@ out: * regulator_is_enabled - is the regulator output enabled * @regulator: regulator source * - * Returns zero for disabled otherwise return number of enable requests. + * Returns positive if the regulator driver backing the source/client + * has requested that the device be enabled, zero if it hasn't, else a + * negative errno code. + * + * Note that the device backing this regulator handle can have multiple + * users, so it might be enabled even if regulator_enable() was never + * called for this particular source. */ int regulator_is_enabled(struct regulator *regulator) { |