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 <[email protected]>
---
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 [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to