From mboxrd@z Thu Jan 1 00:00:00 1970 From: Krzysztof Kozlowski Subject: [RFC v4 01/14] regulator: of: Add helper for getting all supplies Date: Thu, 09 Jun 2016 11:44:18 +0200 Message-ID: <1465465471-28740-2-git-send-email-k.kozlowski@samsung.com> References: <1465465471-28740-1-git-send-email-k.kozlowski@samsung.com> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Return-path: In-reply-to: <1465465471-28740-1-git-send-email-k.kozlowski@samsung.com> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: Ulf Hansson , Rob Herring , Pawel Moll , Mark Rutland , Ian Campbell , Kumar Gala , Krzysztof Kozlowski , Sebastian Reichel , Dmitry Eremin-Solenikov , David Woodhouse , Liam Girdwood , Mark Brown , Greg Kroah-Hartman , Hans de Goede , Jean-Christophe Plagniol-Villard , Tomi Valkeinen , Heiko Stuebner , linux-mmc@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-pm@vger.kernel.org, linux-usb@vger. Cc: Bartlomiej Zolnierkiewicz List-Id: devicetree@vger.kernel.org Few drivers have a need of getting regulator supplies without knowing their names: 1. The Simple Framebuffer driver works on setup provided by bootloader (outside of scope of kernel); 2. Generic power sequence driver may be attached to any device node. Add a Device Tree helper for parsing "-supply" properties and returning allocated bulk regulator consumers. Signed-off-by: Krzysztof Kozlowski --- drivers/regulator/of_regulator.c | 86 ++++++++++++++++++++++++++++++++++ include/linux/regulator/of_regulator.h | 13 +++++ 2 files changed, 99 insertions(+) diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index cd828dbf9d52..0d2c8dd0ebc0 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -350,3 +350,89 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev, return init_data; } + +/** + * devm_of_regulator_all_get - get all regulator consumers + * + * @dev: Device to supply + * @num_consumers Number of consumers registered (only on success) + * @consumers: Configuration of consumers; names of supplies and clients + * are stored here; allocated only on success (NULL otherwise); + * + * @return 0 on success, an errno on failure. + * + * This helper function allows drivers to get all regulator consumers + * for given device in one operation. The names of regulator supplies + * do not have to be provided. If any of the regulators cannot be + * acquired then any regulators that were allocated will be freed + * before returning to the caller. + */ +int devm_of_regulator_all_get(struct device *dev, unsigned int *num_consumers, + struct regulator_bulk_data **consumers) +{ + struct device_node *np = dev->of_node; + struct regulator_bulk_data *bulk; + unsigned int count = 0, i = 0; + struct property *prop; + const char *p; + int ret; + + if (!np) { + ret = 0; + goto err; /* Not really an error */ + } + + /* Count the number of regulator supplies */ + for_each_property_of_node(np, prop) { + p = strstr(prop->name, "-supply"); + if (p && p != prop->name) + count++; + } + + if (!count) { + ret = 0; + goto err; /* Not really an error */ + } + + bulk = devm_kcalloc(dev, count, sizeof(**consumers), GFP_KERNEL); + if (!bulk) { + ret = -ENOMEM; + goto err; + } + + /* Get all the names for supplies */ + for_each_property_of_node(np, prop) { + char *name; + int len; + + p = strstr(prop->name, "-supply"); + if (!p || p == prop->name) + continue; + + len = strlen(prop->name) - strlen("-supply") + 1; + name = devm_kzalloc(dev, len, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto err; + } + + strlcpy(name, prop->name, len); + bulk[i++].supply = name; + } + + ret = devm_regulator_bulk_get(dev, i, bulk); + if (ret) + goto err; + + *consumers = bulk; + *num_consumers = i; + + return 0; + +err: + *num_consumers = 0; + *consumers = NULL; + + return ret; +} +EXPORT_SYMBOL_GPL(devm_of_regulator_all_get); diff --git a/include/linux/regulator/of_regulator.h b/include/linux/regulator/of_regulator.h index 763953f7e3b8..93a3b7fe92e8 100644 --- a/include/linux/regulator/of_regulator.h +++ b/include/linux/regulator/of_regulator.h @@ -7,6 +7,7 @@ #define __LINUX_OF_REG_H struct regulator_desc; +struct regulator_bulk_data; struct of_regulator_match { const char *name; @@ -24,6 +25,9 @@ extern struct regulator_init_data extern int of_regulator_match(struct device *dev, struct device_node *node, struct of_regulator_match *matches, unsigned int num_matches); +extern int devm_of_regulator_all_get(struct device *dev, + unsigned int *num_consumers, + struct regulator_bulk_data **consumers); #else static inline struct regulator_init_data *of_get_regulator_init_data(struct device *dev, @@ -40,6 +44,15 @@ static inline int of_regulator_match(struct device *dev, { return 0; } +static inline int devm_of_regulator_all_get(struct device *dev, + unsigned int *num_consumers, + struct regulator_bulk_data **consumers) +{ + *num_consumers = 0; + *consumers = NULL; + + return 0; +} #endif /* CONFIG_OF */ #endif /* __LINUX_OF_REG_H */ -- 1.9.1