From ff04efbf35aba8cbf7f0c3da477c5d22cfdd459e Mon Sep 17 00:00:00 2001 From: David Collins Date: Tue, 1 May 2012 15:43:13 -0700 Subject: [PATCH] regulator: Extend of_get_regulator_init_data to support non-DT consumers Extend the of_get_regulator_init_data function so that it can parse an additional property from regulator device tree nodes which is needed to support non-device tree consumers. The new property is named qcom,consumer-supplies. Its value is a list of strings of the form: qcom,consumer-supplies = "supply_name1", "device_name1", "supply_name2", "device_name2", ... Change-Id: Ia689d04e6de568e6889b807eed15df3116de01d2 Signed-off-by: David Collins --- .../bindings/regulator/regulator.txt | 6 ++ drivers/regulator/of_regulator.c | 73 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index 5b7a408acda..b2c4387a9c0 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -10,6 +10,11 @@ Optional properties: - regulator-always-on: boolean, regulator should never be disabled - regulator-boot-on: bootloader/firmware enabled regulator - -supply: phandle to the parent supply/regulator node +- qcom,consumer-supplies: flattened list of supply and dev_name pairs + This property is used to support regulator consumers that have no device + tree node. An empty string, "", can be used to specify a null device + name. A null device name is used to allow calls such as: + regulator_get(NULL, "pll_vdd"). Example: @@ -18,6 +23,7 @@ Example: regulator-max-microvolt = <2500000>; regulator-always-on; vin-supply = <&vin>; + qcom,consumer-supplies = "pll_vdd", "", "lcd_vcc", "foo.1"; }; Regulator Consumers: diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index 679734d26a1..fea22b6d11d 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -13,6 +13,7 @@ #include #include #include +#include #include static void of_get_regulation_constraints(struct device_node *np, @@ -61,6 +62,71 @@ static void of_get_regulation_constraints(struct device_node *np, constraints->valid_ops_mask |= REGULATOR_CHANGE_STATUS; } +static const char *consumer_supply_prop_name = "qcom,consumer-supplies"; +#define MAX_DEV_NAME_LEN 256 +/* + * Fill in regulator init_data based on qcom legacy requirements. + */ +static int of_get_qcom_regulator_init_data(struct device *dev, + struct regulator_init_data **init_data) +{ + struct device_node *node = dev->of_node; + struct regulator_consumer_supply *consumer_supplies; + int i, rc, num_consumer_supplies, array_len; + + array_len = of_property_count_strings(node, consumer_supply_prop_name); + if (array_len > 0) { + /* Array length must be divisible by 2. */ + if (array_len & 1) { + dev_err(dev, "error: %s device node property value " + "contains an odd number of elements: %d\n", + consumer_supply_prop_name, array_len); + return -EINVAL; + } + num_consumer_supplies = array_len / 2; + + consumer_supplies = devm_kzalloc(dev, + sizeof(struct regulator_consumer_supply) + * num_consumer_supplies, GFP_KERNEL); + if (consumer_supplies == NULL) { + dev_err(dev, "devm_kzalloc failed\n"); + return -ENOMEM; + } + + for (i = 0; i < num_consumer_supplies; i++) { + rc = of_property_read_string_index(node, + consumer_supply_prop_name, i * 2, + &consumer_supplies[i].supply); + if (rc) { + dev_err(dev, "of_property_read_string_index " + "failed, rc=%d\n", rc); + devm_kfree(dev, consumer_supplies); + return rc; + } + + rc = of_property_read_string_index(node, + consumer_supply_prop_name, (i * 2) + 1, + &consumer_supplies[i].dev_name); + if (rc) { + dev_err(dev, "of_property_read_string_index " + "failed, rc=%d\n", rc); + devm_kfree(dev, consumer_supplies); + return rc; + } + + /* Treat dev_name = "" as a wildcard. */ + if (strnlen(consumer_supplies[i].dev_name, + MAX_DEV_NAME_LEN) == 0) + consumer_supplies[i].dev_name = NULL; + } + + (*init_data)->consumer_supplies = consumer_supplies; + (*init_data)->num_consumer_supplies = num_consumer_supplies; + } + + return 0; +} + /** * of_get_regulator_init_data - extract regulator_init_data structure info * @dev: device requesting for regulator_init_data @@ -73,6 +139,7 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, struct device_node *node) { struct regulator_init_data *init_data; + int rc; if (!node) return NULL; @@ -82,6 +149,12 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev, return NULL; /* Out of memory? */ of_get_regulation_constraints(node, &init_data); + rc = of_get_qcom_regulator_init_data(dev, &init_data); + if (rc) { + devm_kfree(dev, init_data); + return NULL; + } + return init_data; } EXPORT_SYMBOL_GPL(of_get_regulator_init_data);