summaryrefslogtreecommitdiff
path: root/drivers/regulator/of_regulator.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/regulator/of_regulator.c')
-rw-r--r--drivers/regulator/of_regulator.c110
1 files changed, 109 insertions, 1 deletions
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index cec8c3647a00..d5dd7a9e577b 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -552,7 +552,75 @@ error:
return NULL;
}
-struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
+/**
+ * of_get_child_regulator - get a child regulator device node
+ * based on supply name
+ * @parent: Parent device node
+ * @prop_name: Combination regulator supply name and "-supply"
+ *
+ * Traverse all child nodes.
+ * Extract the child regulator device node corresponding to the supply name.
+ *
+ * Return: Pointer to the &struct device_node corresponding to the regulator
+ * if found, or %NULL if not found.
+ */
+static struct device_node *of_get_child_regulator(struct device_node *parent,
+ const char *prop_name)
+{
+ struct device_node *regnode = NULL;
+ struct device_node *child = NULL;
+
+ for_each_child_of_node(parent, child) {
+ regnode = of_parse_phandle(child, prop_name, 0);
+
+ if (!regnode) {
+ regnode = of_get_child_regulator(child, prop_name);
+ if (regnode)
+ goto err_node_put;
+ } else {
+ goto err_node_put;
+ }
+ }
+ return NULL;
+
+err_node_put:
+ of_node_put(child);
+ return regnode;
+}
+
+/**
+ * of_get_regulator - get a regulator device node based on supply name
+ * @dev: Device pointer for the consumer (of regulator) device
+ * @supply: regulator supply name
+ *
+ * Extract the regulator device node corresponding to the supply name.
+ *
+ * Return: Pointer to the &struct device_node corresponding to the regulator
+ * if found, or %NULL if not found.
+ */
+static struct device_node *of_get_regulator(struct device *dev, const char *supply)
+{
+ struct device_node *regnode = NULL;
+ char prop_name[64]; /* 64 is max size of property name */
+
+ dev_dbg(dev, "Looking up %s-supply from device tree\n", supply);
+
+ snprintf(prop_name, 64, "%s-supply", supply);
+ regnode = of_parse_phandle(dev->of_node, prop_name, 0);
+
+ if (!regnode) {
+ regnode = of_get_child_regulator(dev->of_node, prop_name);
+ if (regnode)
+ return regnode;
+
+ dev_dbg(dev, "Looking up %s property in node %pOF failed\n",
+ prop_name, dev->of_node);
+ return NULL;
+ }
+ return regnode;
+}
+
+static struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
{
struct device *dev;
@@ -561,6 +629,46 @@ struct regulator_dev *of_find_regulator_by_node(struct device_node *np)
return dev ? dev_to_rdev(dev) : NULL;
}
+/**
+ * of_regulator_dev_lookup - lookup a regulator device with device tree only
+ * @dev: Device pointer for regulator supply lookup.
+ * @supply: Supply name or regulator ID.
+ *
+ * Return: Pointer to the &struct regulator_dev on success, or ERR_PTR()
+ * encoded value on error.
+ *
+ * If successful, returns a pointer to the &struct regulator_dev that
+ * corresponds to the name @supply and with the embedded &struct device
+ * refcount incremented by one. The refcount must be dropped by calling
+ * put_device().
+ *
+ * On failure one of the following ERR_PTR() encoded values is returned:
+ * * -%ENODEV if lookup fails permanently.
+ * * -%EPROBE_DEFER if lookup could succeed in the future.
+ */
+struct regulator_dev *of_regulator_dev_lookup(struct device *dev,
+ const char *supply)
+{
+ struct regulator_dev *r;
+ struct device_node *node;
+
+ node = of_get_regulator(dev, supply);
+ if (node) {
+ r = of_find_regulator_by_node(node);
+ of_node_put(node);
+ if (r)
+ return r;
+
+ /*
+ * We have a node, but there is no device.
+ * assume it has not registered yet.
+ */
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ return ERR_PTR(-ENODEV);
+}
+
/*
* Returns number of regulators coupled with rdev.
*/