summaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-07-21 16:00:23 +0100
committerLiam Girdwood <lrg@slimlogic.co.uk>2009-09-22 13:32:38 +0100
commit5ffbd136e6c51c8d1eec7a4a0c5d2180c81aea30 (patch)
tree1281ca42478aea061ba5de5be045e2361cd282d5 /drivers/regulator
parentc1b60873ca2078bfca94b73bc88ef1c5adcc928b (diff)
downloadkernel-crypto-5ffbd136e6c51c8d1eec7a4a0c5d2180c81aea30.tar.gz
kernel-crypto-5ffbd136e6c51c8d1eec7a4a0c5d2180c81aea30.tar.xz
kernel-crypto-5ffbd136e6c51c8d1eec7a4a0c5d2180c81aea30.zip
regulator: Add regulator_get_exclusive() API
Some consumers require complete control of the regulator and can't tolerate sharing it with other consumers, most commonly because they need to have the regulator actually disabled so can't have other consumers forcing it on. This new regulator_get_exclusive() API call allows these consumers to explicitly request this, documenting the assumptions that they are making. In order to simplify coding of such consumers the use count for regulators they request is forced to match the enabled state of the regulator when it is requested. This is not possible for consumers which can share regulators due to the need to keep track of the ownership of use counts. A new API call is used rather than an additional argument to the existing regulator_get() in order to avoid merge headaches with driver code in other trees. 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.c88
1 files changed, 74 insertions, 14 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 24e05b7607b..68549008582 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1025,25 +1025,15 @@ overflow_err:
return NULL;
}
-/**
- * regulator_get - lookup and obtain a reference to a regulator.
- * @dev: device for regulator "consumer"
- * @id: Supply name or regulator ID.
- *
- * Returns a struct regulator corresponding to the regulator producer,
- * or IS_ERR() condition containing errno.
- *
- * Use of supply names configured via regulator_set_device_supply() is
- * strongly encouraged. It is recommended that the supply name used
- * should match the name used for the supply and/or the relevant
- * device pins in the datasheet.
- */
-struct regulator *regulator_get(struct device *dev, const char *id)
+/* Internal regulator request function */
+static struct regulator *_regulator_get(struct device *dev, const char *id,
+ int exclusive)
{
struct regulator_dev *rdev;
struct regulator_map *map;
struct regulator *regulator = ERR_PTR(-ENODEV);
const char *devname = NULL;
+ int ret;
if (id == NULL) {
printk(KERN_ERR "regulator: get() with no identifier\n");
@@ -1070,6 +1060,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)
return regulator;
found:
+ if (rdev->exclusive) {
+ regulator = ERR_PTR(-EPERM);
+ goto out;
+ }
+
+ if (exclusive && rdev->open_count) {
+ regulator = ERR_PTR(-EBUSY);
+ goto out;
+ }
+
if (!try_module_get(rdev->owner))
goto out;
@@ -1079,13 +1079,70 @@ found:
module_put(rdev->owner);
}
+ rdev->open_count++;
+ if (exclusive) {
+ rdev->exclusive = 1;
+
+ ret = _regulator_is_enabled(rdev);
+ if (ret > 0)
+ rdev->use_count = 1;
+ else
+ rdev->use_count = 0;
+ }
+
out:
mutex_unlock(&regulator_list_mutex);
+
return regulator;
}
+
+/**
+ * regulator_get - lookup and obtain a reference to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged. It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get(struct device *dev, const char *id)
+{
+ return _regulator_get(dev, id, 0);
+}
EXPORT_SYMBOL_GPL(regulator_get);
/**
+ * regulator_get_exclusive - obtain exclusive access to a regulator.
+ * @dev: device for regulator "consumer"
+ * @id: Supply name or regulator ID.
+ *
+ * Returns a struct regulator corresponding to the regulator producer,
+ * or IS_ERR() condition containing errno. Other consumers will be
+ * unable to obtain this reference is held and the use count for the
+ * regulator will be initialised to reflect the current state of the
+ * regulator.
+ *
+ * This is intended for use by consumers which cannot tolerate shared
+ * use of the regulator such as those which need to force the
+ * regulator off for correct operation of the hardware they are
+ * controlling.
+ *
+ * Use of supply names configured via regulator_set_device_supply() is
+ * strongly encouraged. It is recommended that the supply name used
+ * should match the name used for the supply and/or the relevant
+ * device pins in the datasheet.
+ */
+struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
+{
+ return _regulator_get(dev, id, 1);
+}
+EXPORT_SYMBOL_GPL(regulator_get_exclusive);
+
+/**
* regulator_put - "free" the regulator source
* @regulator: regulator source
*
@@ -1113,6 +1170,9 @@ void regulator_put(struct regulator *regulator)
list_del(&regulator->list);
kfree(regulator);
+ rdev->open_count--;
+ rdev->exclusive = 0;
+
module_put(rdev->owner);
mutex_unlock(&regulator_list_mutex);
}