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 <collinsd@codeaurora.org>
This commit is contained in:
committed by
Stephen Boyd
parent
3cecc29edd
commit
ff04efbf35
@@ -10,6 +10,11 @@ Optional properties:
|
||||
- regulator-always-on: boolean, regulator should never be disabled
|
||||
- regulator-boot-on: bootloader/firmware enabled regulator
|
||||
- <name>-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:
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user