Merge remote-tracking branch 'regulator/topic/core' into regulator-next

This commit is contained in:
Mark Brown 2017-02-19 16:40:23 +00:00
commit 401c42429c
3 changed files with 109 additions and 110 deletions

View File

@ -1455,12 +1455,14 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name)
* lookup could succeed in the future. * lookup could succeed in the future.
* *
* If successful, returns a struct regulator_dev that corresponds to the name * If successful, returns a struct regulator_dev that corresponds to the name
* @supply and with the embedded struct device refcount incremented by one, * @supply and with the embedded struct device refcount incremented by one.
* or NULL on failure. The refcount must be dropped by calling put_device(). * 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, static struct regulator_dev *regulator_dev_lookup(struct device *dev,
const char *supply, const char *supply)
int *ret)
{ {
struct regulator_dev *r; struct regulator_dev *r;
struct device_node *node; 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); r = of_find_regulator_by_node(node);
if (r) if (r)
return r; return r;
*ret = -EPROBE_DEFER;
return NULL;
} else {
/* /*
* If we couldn't even get the node then it's * We have a node, but there is no device.
* not just that the device didn't register * assume it has not registered yet.
* yet, there's no node and we'll never
* succeed.
*/ */
*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 && if (strcmp(map->supply, supply) == 0 &&
get_device(&map->regulator->dev)) { get_device(&map->regulator->dev)) {
mutex_unlock(&regulator_list_mutex); r = map->regulator;
return map->regulator; break;
} }
} }
mutex_unlock(&regulator_list_mutex); mutex_unlock(&regulator_list_mutex);
return NULL; if (r)
return r;
return ERR_PTR(-ENODEV);
} }
static int regulator_resolve_supply(struct regulator_dev *rdev) 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) if (rdev->supply)
return 0; return 0;
r = regulator_dev_lookup(dev, rdev->supply_name, &ret); r = regulator_dev_lookup(dev, rdev->supply_name);
if (!r) { if (IS_ERR(r)) {
ret = PTR_ERR(r);
if (ret == -ENODEV) { if (ret == -ENODEV) {
/* /*
* No supply was specified for this regulator and * 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 */ /* Internal regulator request function */
static struct regulator *_regulator_get(struct device *dev, const char *id, struct regulator *_regulator_get(struct device *dev, const char *id,
bool exclusive, bool allow_dummy) enum regulator_get_type get_type)
{ {
struct regulator_dev *rdev; struct regulator_dev *rdev;
struct regulator *regulator = ERR_PTR(-EPROBE_DEFER); struct regulator *regulator;
const char *devname = NULL; const char *devname = dev ? dev_name(dev) : "deviceless";
int ret; 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) { if (id == NULL) {
pr_err("get() with no identifier\n"); pr_err("get() with no identifier\n");
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
if (dev) rdev = regulator_dev_lookup(dev, id);
devname = dev_name(dev); if (IS_ERR(rdev)) {
ret = PTR_ERR(rdev);
if (have_full_constraints()) /*
ret = -ENODEV; * If regulator_dev_lookup() fails with error other
else * than -ENODEV our job here is done, we simply return it.
ret = -EPROBE_DEFER; */
if (ret != -ENODEV)
return ERR_PTR(ret);
rdev = regulator_dev_lookup(dev, id, &ret); if (!have_full_constraints()) {
if (rdev) dev_warn(dev,
goto found; "incomplete constraints, dummy supplies not allowed\n");
return ERR_PTR(-ENODEV);
}
regulator = ERR_PTR(ret); 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;
/* case EXCLUSIVE_GET:
* If we have return value from dev_lookup fail, we do not expect to dev_warn(dev,
* succeed, so, quit with appropriate error value "dummy supplies not allowed for exclusive requests\n");
*/ /* fall through */
if (ret && ret != -ENODEV)
return regulator;
if (!devname) default:
devname = "deviceless"; return ERR_PTR(-ENODEV);
}
/*
* 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);
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");
} }
return regulator;
found:
if (rdev->exclusive) { if (rdev->exclusive) {
regulator = ERR_PTR(-EPERM); regulator = ERR_PTR(-EPERM);
put_device(&rdev->dev); put_device(&rdev->dev);
return regulator; return regulator;
} }
if (exclusive && rdev->open_count) { if (get_type == EXCLUSIVE_GET && rdev->open_count) {
regulator = ERR_PTR(-EBUSY); regulator = ERR_PTR(-EBUSY);
put_device(&rdev->dev); put_device(&rdev->dev);
return regulator; return regulator;
@ -1656,6 +1662,7 @@ found:
} }
if (!try_module_get(rdev->owner)) { if (!try_module_get(rdev->owner)) {
regulator = ERR_PTR(-EPROBE_DEFER);
put_device(&rdev->dev); put_device(&rdev->dev);
return regulator; return regulator;
} }
@ -1669,7 +1676,7 @@ found:
} }
rdev->open_count++; rdev->open_count++;
if (exclusive) { if (get_type == EXCLUSIVE_GET) {
rdev->exclusive = 1; rdev->exclusive = 1;
ret = _regulator_is_enabled(rdev); ret = _regulator_is_enabled(rdev);
@ -1697,7 +1704,7 @@ found:
*/ */
struct regulator *regulator_get(struct device *dev, const char *id) 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); 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) 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); 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) 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); EXPORT_SYMBOL_GPL(regulator_get_optional);
@ -3660,7 +3667,7 @@ err:
for (++i; i < num_consumers; ++i) { for (++i; i < num_consumers; ++i) {
r = regulator_enable(consumers[i].consumer); r = regulator_enable(consumers[i].consumer);
if (r != 0) if (r != 0)
pr_err("Failed to reename %s: %d\n", pr_err("Failed to re-enable %s: %d\n",
consumers[i].supply, r); consumers[i].supply, r);
} }
@ -3686,21 +3693,17 @@ int regulator_bulk_force_disable(int num_consumers,
struct regulator_bulk_data *consumers) struct regulator_bulk_data *consumers)
{ {
int i; int i;
int ret; int ret = 0;
for (i = 0; i < num_consumers; i++) for (i = 0; i < num_consumers; i++) {
consumers[i].ret = consumers[i].ret =
regulator_force_disable(consumers[i].consumer); regulator_force_disable(consumers[i].consumer);
for (i = 0; i < num_consumers; i++) { /* Store first error for reporting */
if (consumers[i].ret != 0) { if (consumers[i].ret && !ret)
ret = consumers[i].ret; ret = consumers[i].ret;
goto out;
}
} }
return 0;
out:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(regulator_bulk_force_disable); EXPORT_SYMBOL_GPL(regulator_bulk_force_disable);

View File

@ -19,12 +19,6 @@
#include "internal.h" #include "internal.h"
enum {
NORMAL_GET,
EXCLUSIVE_GET,
OPTIONAL_GET,
};
static void devm_regulator_release(struct device *dev, void *res) static void devm_regulator_release(struct device *dev, void *res)
{ {
regulator_put(*(struct regulator **)res); regulator_put(*(struct regulator **)res);
@ -39,20 +33,7 @@ static struct regulator *_devm_regulator_get(struct device *dev, const char *id,
if (!ptr) if (!ptr)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
switch (get_type) { regulator = _regulator_get(dev, id, 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);
}
if (!IS_ERR(regulator)) { if (!IS_ERR(regulator)) {
*ptr = regulator; *ptr = regulator;
devres_add(dev, ptr); devres_add(dev, ptr);
@ -139,6 +120,18 @@ void devm_regulator_put(struct regulator *regulator)
} }
EXPORT_SYMBOL_GPL(devm_regulator_put); 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 * devm_regulator_bulk_get - managed get multiple regulator consumers
* *
@ -157,30 +150,23 @@ EXPORT_SYMBOL_GPL(devm_regulator_put);
int devm_regulator_bulk_get(struct device *dev, int num_consumers, int devm_regulator_bulk_get(struct device *dev, int num_consumers,
struct regulator_bulk_data *consumers) struct regulator_bulk_data *consumers)
{ {
int i; struct regulator_bulk_devres *devres;
int ret; int ret;
for (i = 0; i < num_consumers; i++) devres = devres_alloc(devm_regulator_bulk_release,
consumers[i].consumer = NULL; sizeof(*devres), GFP_KERNEL);
if (!devres)
return -ENOMEM;
for (i = 0; i < num_consumers; i++) { ret = regulator_bulk_get(dev, num_consumers, consumers);
consumers[i].consumer = devm_regulator_get(dev, if (!ret) {
consumers[i].supply); devres->consumers = consumers;
if (IS_ERR(consumers[i].consumer)) { devres->num_consumers = num_consumers;
ret = PTR_ERR(consumers[i].consumer); devres_add(dev, devres);
dev_err(dev, "Failed to get supply '%s': %d\n", } else {
consumers[i].supply, ret); devres_free(devres);
consumers[i].consumer = NULL;
goto err;
}
} }
return 0;
err:
for (i = 0; i < num_consumers && consumers[i].consumer; i++)
devm_regulator_put(consumers[i].consumer);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(devm_regulator_bulk_get); EXPORT_SYMBOL_GPL(devm_regulator_bulk_get);

View File

@ -51,4 +51,14 @@ regulator_of_get_init_data(struct device *dev,
} }
#endif #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 #endif