[PATCH] regulator: Support different config and dev of_nodes in regulator_register

From: Tim Bird
Date: Wed Feb 04 2015 - 18:20:10 EST


Support calling regulator_register with a dev node and a config node
with different of_nodes. This is useful when a single driver
wishes to register multiple child regulators.

Without this you get silent failures allocating a supply
for a regulator which is registered using the device node of the
regulator's DT parent (but it's own DT node).

Signed-off-by: Tim Bird <tim.bird@xxxxxxxxxxxxxx>
---
I encountered a problem where I did a devm_regulator_register with
a dev (for a charger driver) and a config (for the regulator child
of the driver) that had different of_nodes. In this case, inside
regulator_dev_lookup the code did not find the supply that I had
specified in the child regulator's DT node. The DT setup looked
as follows:

charger@1000 {
compatible = "qcom,pm8941-charger";
reg = <0x1000 0x700>;
....
chg_otg {
regulator_name = "chg_otg";
otg-supply = <&pm8941_mvs1>;
...
}
}

This code checks the of_node of specified in the struct regulator_config
if the supply is not found in the dev.of_node. This code has no effect
if dev.of_node and config.of_node are the same, so it shouldn't affect
any existing (working) code.

drivers/regulator/core.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 128b432..36c5d78 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -128,13 +128,16 @@ static bool have_full_constraints(void)
/**
* of_get_regulator - get a regulator device node based on supply name
* @dev: Device pointer for the consumer (of regulator) device
+ * @config: pointer to config for regulator registration
* @supply: regulator supply name
*
* Extract the regulator device node corresponding to the supply name.
* returns the device node corresponding to the regulator if found, else
* returns NULL.
*/
-static struct device_node *of_get_regulator(struct device *dev, const char *supply)
+static struct device_node *of_get_regulator(struct device *dev,
+ const struct regulator_config *config,
+ const char *supply)
{
struct device_node *regnode = NULL;
char prop_name[32]; /* 32 is max size of property name */
@@ -147,7 +150,15 @@ static struct device_node *of_get_regulator(struct device *dev, const char *supp
if (!regnode) {
dev_dbg(dev, "Looking up %s property in node %s failed",
prop_name, dev->of_node->full_name);
- return NULL;
+ if (!config || !config->of_node ||
+ config->of_node == dev->of_node)
+ return NULL;
+ regnode = of_parse_phandle(config->of_node, prop_name, 0);
+ if (!regnode) {
+ dev_dbg(dev, "Looking up %s property in node %s failed",
+ prop_name, dev->of_node->full_name);
+ return NULL;
+ }
}
return regnode;
}
@@ -1284,9 +1295,10 @@ static void regulator_supply_alias(struct device **dev, const char **supply)
}
}

-static struct regulator_dev *regulator_dev_lookup(struct device *dev,
- const char *supply,
- int *ret)
+static struct regulator_dev *regulator_dev_config_lookup(struct device *dev,
+ const struct regulator_config *config,
+ const char *supply,
+ int *ret)
{
struct regulator_dev *r;
struct device_node *node;
@@ -1297,7 +1309,7 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,

/* first do a dt based lookup */
if (dev && dev->of_node) {
- node = of_get_regulator(dev, supply);
+ node = of_get_regulator(dev, config, supply);
if (node) {
list_for_each_entry(r, &regulator_list, list)
if (r->dev.parent &&
@@ -1334,7 +1346,6 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev,
return map->regulator;
}

-
return NULL;
}

@@ -1362,7 +1373,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id,

mutex_lock(&regulator_list_mutex);

- rdev = regulator_dev_lookup(dev, id, &ret);
+ rdev = regulator_dev_config_lookup(dev, NULL, id, &ret);
if (rdev)
goto found;

@@ -3642,7 +3653,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
if (supply) {
struct regulator_dev *r;

- r = regulator_dev_lookup(dev, supply, &ret);
+ r = regulator_dev_config_lookup(dev, config, supply, &ret);

if (ret == -ENODEV) {
/*
--
1.8.2.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/