提交 a0c7b164 编写于 作者: M Mark Brown

regulator: of: Provide simplified DT parsing method

Currently regulator drivers which support DT all repeat very similar code
to supply a list of known regulator identifiers to be matched with DT,
convert that to platform data which is then matched up with the regulators
as they are registered. This is both fiddly to get right and for devices
which can use the standard helpers to provide their operations is the main
source of code in the driver.

Since this code is essentially identical for most drivers we can factor it
out into the core, moving the identifiers in the match table into the
regulator descriptors and also allowing drivers to pass in the name of the
subnode to search. When a driver provides an of_match string for the
regulator the core will attempt to use that to obtain init_data, allowing
the driver to remove all explicit code for DT parsing and simply provide
data instead.

The current code leaks the phandles for the child nodes, this will be
addressed incrementally and makes no practical difference for FDT anyway
as the DT data structures are never freed.
Signed-off-by: NMark Brown <broonie@linaro.org>
上级 7d1311b9
...@@ -3516,12 +3516,17 @@ regulator_register(const struct regulator_desc *regulator_desc, ...@@ -3516,12 +3516,17 @@ regulator_register(const struct regulator_desc *regulator_desc,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
init_data = config->init_data;
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL); rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
if (rdev == NULL) if (rdev == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
init_data = regulator_of_get_init_data(dev, regulator_desc,
&rdev->dev.of_node);
if (!init_data) {
init_data = config->init_data;
rdev->dev.of_node = of_node_get(config->of_node);
}
mutex_lock(&regulator_list_mutex); mutex_lock(&regulator_list_mutex);
mutex_init(&rdev->mutex); mutex_init(&rdev->mutex);
...@@ -3548,7 +3553,6 @@ regulator_register(const struct regulator_desc *regulator_desc, ...@@ -3548,7 +3553,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
/* register with sysfs */ /* register with sysfs */
rdev->dev.class = &regulator_class; rdev->dev.class = &regulator_class;
rdev->dev.of_node = of_node_get(config->of_node);
rdev->dev.parent = dev; rdev->dev.parent = dev;
dev_set_name(&rdev->dev, "regulator.%d", dev_set_name(&rdev->dev, "regulator.%d",
atomic_inc_return(&regulator_no) - 1); atomic_inc_return(&regulator_no) - 1);
......
...@@ -35,4 +35,8 @@ struct regulator { ...@@ -35,4 +35,8 @@ struct regulator {
struct dentry *debugfs; struct dentry *debugfs;
}; };
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
const struct regulator_desc *desc,
struct device_node **node);
#endif #endif
...@@ -14,8 +14,11 @@ ...@@ -14,8 +14,11 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h> #include <linux/regulator/of_regulator.h>
#include "internal.h"
static void of_get_regulation_constraints(struct device_node *np, static void of_get_regulation_constraints(struct device_node *np,
struct regulator_init_data **init_data) struct regulator_init_data **init_data)
{ {
...@@ -189,3 +192,51 @@ int of_regulator_match(struct device *dev, struct device_node *node, ...@@ -189,3 +192,51 @@ int of_regulator_match(struct device *dev, struct device_node *node,
return count; return count;
} }
EXPORT_SYMBOL_GPL(of_regulator_match); EXPORT_SYMBOL_GPL(of_regulator_match);
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
const struct regulator_desc *desc,
struct device_node **node)
{
struct device_node *search, *child;
struct regulator_init_data *init_data = NULL;
const char *name;
if (!dev->of_node || !desc->of_match)
return NULL;
if (desc->regulators_node)
search = of_get_child_by_name(dev->of_node,
desc->regulators_node);
else
search = dev->of_node;
if (!search) {
dev_err(dev, "Failed to find regulator container node\n");
return NULL;
}
for_each_child_of_node(search, child) {
name = of_get_property(child, "regulator-compatible", NULL);
if (!name)
name = child->name;
if (strcmp(desc->of_match, name))
continue;
init_data = of_get_regulator_init_data(dev, child);
if (!init_data) {
dev_err(dev,
"failed to parse DT for regulator %s\n",
child->name);
break;
}
of_node_get(child);
*node = child;
break;
}
of_node_put(search);
return init_data;
}
...@@ -203,6 +203,8 @@ enum regulator_type { ...@@ -203,6 +203,8 @@ enum regulator_type {
* *
* @name: Identifying name for the regulator. * @name: Identifying name for the regulator.
* @supply_name: Identifying the regulator supply * @supply_name: Identifying the regulator supply
* @of_match: Name used to identify regulator in DT.
* @regulators_node: Name of node containing regulator definitions in DT.
* @id: Numerical identifier for the regulator. * @id: Numerical identifier for the regulator.
* @ops: Regulator operations table. * @ops: Regulator operations table.
* @irq: Interrupt number for the regulator. * @irq: Interrupt number for the regulator.
...@@ -242,6 +244,8 @@ enum regulator_type { ...@@ -242,6 +244,8 @@ enum regulator_type {
struct regulator_desc { struct regulator_desc {
const char *name; const char *name;
const char *supply_name; const char *supply_name;
const char *of_match;
const char *regulators_node;
int id; int id;
bool continuous_voltage_range; bool continuous_voltage_range;
unsigned n_voltages; unsigned n_voltages;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册