Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1161538AbbBDXUF (ORCPT ); Wed, 4 Feb 2015 18:20:05 -0500 Received: from seldrel01.sonyericsson.com ([212.209.106.2]:3397 "EHLO seldrel01.sonyericsson.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1161381AbbBDXUD (ORCPT ); Wed, 4 Feb 2015 18:20:03 -0500 Message-ID: <54D2A91D.5090700@sonymobile.com> Date: Wed, 4 Feb 2015 15:19:57 -0800 From: Tim Bird User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: , CC: "linux-kernel@vger.kernel.org" , Bjorn Andersson Subject: [PATCH] regulator: Support different config and dev of_nodes in regulator_register Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4569 Lines: 132 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 --- 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, ®ulator_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(®ulator_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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/