summaryrefslogtreecommitdiff
path: root/drivers/regulator
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2017-02-19 19:40:23 +0300
committerMark Brown <broonie@kernel.org>2017-02-19 19:40:23 +0300
commit401c42429caa8e374d17abcbc92505dd6b2e2a18 (patch)
tree40786a3839b4f80ab99af02f438cdfc2b9824ff5 /drivers/regulator
parent0fe3f971fc83bfd709b70f8ac822ad6db4a05c9e (diff)
parenta4d7641fa797b523c0789d2fa55b0a3d53abc2fb (diff)
downloadlinux-401c42429caa8e374d17abcbc92505dd6b2e2a18.tar.xz
Merge remote-tracking branch 'regulator/topic/core' into regulator-next
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/core.c145
-rw-r--r--drivers/regulator/devres.c66
-rw-r--r--drivers/regulator/internal.h10
3 files changed, 110 insertions, 111 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index e9fd40ecaef5..6ea646466a07 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -1455,12 +1455,14 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name)
* lookup could succeed in the future.
*
* If successful, returns a struct regulator_dev that corresponds to the name
- * @supply and with the embedded struct device refcount incremented by one,
- * or NULL on failure. The refcount must be dropped by calling put_device().
+ * @supply and with the embedded struct device refcount incremented by one.
+ * The refcount must be dropped by calling put_device().
+ * On failure one of the following ERR-PTR-encoded values is returned:
+ * -ENODEV if lookup fails permanently, -EPROBE_DEFER if lookup could succeed
+ * in the future.
*/
static struct regulator_dev *regulator_dev_lookup(struct device *dev,
- const char *supply,
- int *ret)
+ const char *supply)
{
struct regulator_dev *r;
struct device_node *node;
@@ -1476,16 +1478,12 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
r = of_find_regulator_by_node(node);
if (r)
return r;
- *ret = -EPROBE_DEFER;
- return NULL;
- } else {
+
/*
- * If we couldn't even get the node then it's
- * not just that the device didn't register
- * yet, there's no node and we'll never
- * succeed.
+ * We have a node, but there is no device.
+ * assume it has not registered yet.
*/
- *ret = -ENODEV;
+ return ERR_PTR(-EPROBE_DEFER);
}
}
@@ -1506,13 +1504,16 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
if (strcmp(map->supply, supply) == 0 &&
get_device(&map->regulator->dev)) {
- mutex_unlock(&regulator_list_mutex);
- return map->regulator;
+ r = map->regulator;
+ break;
}
}
mutex_unlock(&regulator_list_mutex);
- return NULL;
+ if (r)
+ return r;
+
+ return ERR_PTR(-ENODEV);
}
static int regulator_resolve_supply(struct regulator_dev *rdev)
@@ -1529,8 +1530,10 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
if (rdev->supply)
return 0;
- r = regulator_dev_lookup(dev, rdev->supply_name, &ret);
- if (!r) {
+ r = regulator_dev_lookup(dev, rdev->supply_name);
+ if (IS_ERR(r)) {
+ ret = PTR_ERR(r);
+
if (ret == -ENODEV) {
/*
* No supply was specified for this regulator and
@@ -1580,69 +1583,72 @@ static int regulator_resolve_supply(struct regulator_dev *rdev)
}
/* Internal regulator request function */
-static struct regulator *_regulator_get(struct device *dev, const char *id,
- bool exclusive, bool allow_dummy)
+struct regulator *_regulator_get(struct device *dev, const char *id,
+ enum regulator_get_type get_type)
{
struct regulator_dev *rdev;
- struct regulator *regulator = ERR_PTR(-EPROBE_DEFER);
- const char *devname = NULL;
+ struct regulator *regulator;
+ const char *devname = dev ? dev_name(dev) : "deviceless";
int ret;
+ if (get_type >= MAX_GET_TYPE) {
+ dev_err(dev, "invalid type %d in %s\n", get_type, __func__);
+ return ERR_PTR(-EINVAL);
+ }
+
if (id == NULL) {
pr_err("get() with no identifier\n");
return ERR_PTR(-EINVAL);
}
- if (dev)
- devname = dev_name(dev);
-
- if (have_full_constraints())
- ret = -ENODEV;
- else
- ret = -EPROBE_DEFER;
-
- rdev = regulator_dev_lookup(dev, id, &ret);
- if (rdev)
- goto found;
+ rdev = regulator_dev_lookup(dev, id);
+ if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
- regulator = ERR_PTR(ret);
+ /*
+ * If regulator_dev_lookup() fails with error other
+ * than -ENODEV our job here is done, we simply return it.
+ */
+ if (ret != -ENODEV)
+ return ERR_PTR(ret);
- /*
- * If we have return value from dev_lookup fail, we do not expect to
- * succeed, so, quit with appropriate error value
- */
- if (ret && ret != -ENODEV)
- return regulator;
+ if (!have_full_constraints()) {
+ dev_warn(dev,
+ "incomplete constraints, dummy supplies not allowed\n");
+ return ERR_PTR(-ENODEV);
+ }
- if (!devname)
- devname = "deviceless";
+ switch (get_type) {
+ case NORMAL_GET:
+ /*
+ * Assume that a regulator is physically present and
+ * enabled, even if it isn't hooked up, and just
+ * provide a dummy.
+ */
+ dev_warn(dev,
+ "%s supply %s not found, using dummy regulator\n",
+ devname, id);
+ rdev = dummy_regulator_rdev;
+ get_device(&rdev->dev);
+ break;
- /*
- * Assume that a regulator is physically present and enabled
- * even if it isn't hooked up and just provide a dummy.
- */
- if (have_full_constraints() && allow_dummy) {
- pr_warn("%s supply %s not found, using dummy regulator\n",
- devname, id);
+ case EXCLUSIVE_GET:
+ dev_warn(dev,
+ "dummy supplies not allowed for exclusive requests\n");
+ /* fall through */
- rdev = dummy_regulator_rdev;
- get_device(&rdev->dev);
- goto found;
- /* Don't log an error when called from regulator_get_optional() */
- } else if (!have_full_constraints() || exclusive) {
- dev_warn(dev, "dummy supplies not allowed\n");
+ default:
+ return ERR_PTR(-ENODEV);
+ }
}
- return regulator;
-
-found:
if (rdev->exclusive) {
regulator = ERR_PTR(-EPERM);
put_device(&rdev->dev);
return regulator;
}
- if (exclusive && rdev->open_count) {
+ if (get_type == EXCLUSIVE_GET && rdev->open_count) {
regulator = ERR_PTR(-EBUSY);
put_device(&rdev->dev);
return regulator;
@@ -1656,6 +1662,7 @@ found:
}
if (!try_module_get(rdev->owner)) {
+ regulator = ERR_PTR(-EPROBE_DEFER);
put_device(&rdev->dev);
return regulator;
}
@@ -1669,7 +1676,7 @@ found:
}
rdev->open_count++;
- if (exclusive) {
+ if (get_type == EXCLUSIVE_GET) {
rdev->exclusive = 1;
ret = _regulator_is_enabled(rdev);
@@ -1697,7 +1704,7 @@ found:
*/
struct regulator *regulator_get(struct device *dev, const char *id)
{
- return _regulator_get(dev, id, false, true);
+ return _regulator_get(dev, id, NORMAL_GET);
}
EXPORT_SYMBOL_GPL(regulator_get);
@@ -1724,7 +1731,7 @@ EXPORT_SYMBOL_GPL(regulator_get);
*/
struct regulator *regulator_get_exclusive(struct device *dev, const char *id)
{
- return _regulator_get(dev, id, true, false);
+ return _regulator_get(dev, id, EXCLUSIVE_GET);
}
EXPORT_SYMBOL_GPL(regulator_get_exclusive);
@@ -1750,7 +1757,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive);
*/
struct regulator *regulator_get_optional(struct device *dev, const char *id)
{
- return _regulator_get(dev, id, false, false);
+ return _regulator_get(dev, id, OPTIONAL_GET);
}
EXPORT_SYMBOL_GPL(regulator_get_optional);
@@ -3660,7 +3667,7 @@ err:
for (++i; i < num_consumers; ++i) {
r = regulator_enable(consumers[i].consumer);
if (r != 0)
- pr_err("Failed to reename %s: %d\n",
+ pr_err("Failed to re-enable %s: %d\n",
consumers[i].supply, r);
}
@@ -3686,21 +3693,17 @@ int regulator_bulk_force_disable(int num_consumers,
struct regulator_bulk_data *consumers)
{
int i;
- int ret;
+ int ret = 0;
- for (i = 0; i < num_consumers; i++)
+ for (i = 0; i < num_consumers; i++) {
consumers[i].ret =
regulator_force_disable(consumers[i].consumer);
- for (i = 0; i < num_consumers; i++) {
- if (consumers[i].ret != 0) {
+ /* Store first error for reporting */
+ if (consumers[i].ret && !ret)
ret = consumers[i].ret;
- goto out;
- }
}
- return 0;
-out:
return ret;
}
EXPORT_SYMBOL_GPL(regulator_bulk_force_disable);
diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c
index 6ec1d400adae..784e3bf32210 100644
--- a/drivers/regulator/devres.c
+++ b/drivers/regulator/devres.c
@@ -19,12 +19,6 @@
#include "internal.h"
-enum {
- NORMAL_GET,
- EXCLUSIVE_GET,
- OPTIONAL_GET,
-};
-
static void devm_regulator_release(struct device *dev, void *res)
{
regulator_put(*(struct regulator **)res);
@@ -39,20 +33,7 @@ static struct regulator *_devm_regulator_get(struct device *dev, const char *id,
if (!ptr)
return ERR_PTR(-ENOMEM);
- switch (get_type) {
- case NORMAL_GET:
- regulator = regulator_get(dev, id);
- break;
- case EXCLUSIVE_GET:
- regulator = regulator_get_exclusive(dev, id);
- break;
- case OPTIONAL_GET:
- regulator = regulator_get_optional(dev, id);
- break;
- default:
- regulator = ERR_PTR(-EINVAL);
- }
-
+ regulator = _regulator_get(dev, id, get_type);
if (!IS_ERR(regulator)) {
*ptr = regulator;
devres_add(dev, ptr);
@@ -139,6 +120,18 @@ void devm_regulator_put(struct regulator *regulator)
}
EXPORT_SYMBOL_GPL(devm_regulator_put);
+struct regulator_bulk_devres {
+ struct regulator_bulk_data *consumers;
+ int num_consumers;
+};
+
+static void devm_regulator_bulk_release(struct device *dev, void *res)
+{
+ struct regulator_bulk_devres *devres = res;
+
+ regulator_bulk_free(devres->num_consumers, devres->consumers);
+}
+
/**
* devm_regulator_bulk_get - managed get multiple regulator consumers
*
@@ -157,29 +150,22 @@ EXPORT_SYMBOL_GPL(devm_regulator_put);
int devm_regulator_bulk_get(struct device *dev, int num_consumers,
struct regulator_bulk_data *consumers)
{
- int i;
+ struct regulator_bulk_devres *devres;
int ret;
- for (i = 0; i < num_consumers; i++)
- consumers[i].consumer = NULL;
-
- for (i = 0; i < num_consumers; i++) {
- consumers[i].consumer = devm_regulator_get(dev,
- consumers[i].supply);
- if (IS_ERR(consumers[i].consumer)) {
- ret = PTR_ERR(consumers[i].consumer);
- dev_err(dev, "Failed to get supply '%s': %d\n",
- consumers[i].supply, ret);
- consumers[i].consumer = NULL;
- goto err;
- }
- }
-
- return 0;
+ devres = devres_alloc(devm_regulator_bulk_release,
+ sizeof(*devres), GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
-err:
- for (i = 0; i < num_consumers && consumers[i].consumer; i++)
- devm_regulator_put(consumers[i].consumer);
+ ret = regulator_bulk_get(dev, num_consumers, consumers);
+ if (!ret) {
+ devres->consumers = consumers;
+ devres->num_consumers = num_consumers;
+ devres_add(dev, devres);
+ } else {
+ devres_free(devres);
+ }
return ret;
}
diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h
index c74ac8734023..1dd575b28564 100644
--- a/drivers/regulator/internal.h
+++ b/drivers/regulator/internal.h
@@ -51,4 +51,14 @@ regulator_of_get_init_data(struct device *dev,
}
#endif
+enum regulator_get_type {
+ NORMAL_GET,
+ EXCLUSIVE_GET,
+ OPTIONAL_GET,
+ MAX_GET_TYPE
+};
+
+struct regulator *_regulator_get(struct device *dev, const char *id,
+ enum regulator_get_type get_type);
+
#endif