[PATCH 16/22] OF: base: import parse phandle functions from Linux OF API

Sebastian Hesselbarth sebastian.hesselbarth at gmail.com
Tue Jun 18 13:30:01 EDT 2013


This imports of_parse_phandle_with_args and of_count_phandle_with_args
from Linux OF API. The slightly different of_parse_phandles_with_args
is removed and all users are converted to reflect the API change.

Signed-off-by: Sebastian Hesselbarth <sebastian.hesselbarth at gmail.com>
---
Cc: barebox at lists.infradead.org
---
 drivers/of/base.c              |  188 +++++++++++++++++++++++++---------------
 drivers/of/gpio.c              |    9 +-
 drivers/usb/imx/chipidea-imx.c |   11 +--
 include/of.h                   |   30 ++++++-
 4 files changed, 151 insertions(+), 87 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index e729a65..a3a9aac 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -862,17 +862,16 @@ struct device_node *of_parse_phandle(const struct device_node *np,
 EXPORT_SYMBOL(of_parse_phandle);
 
 /**
- * of_parse_phandles_with_args - Find a node pointed by phandle in a list
+ * of_parse_phandle_with_args() - Find a node pointed by phandle in a list
  * @np:		pointer to a device tree node containing a list
  * @list_name:	property name that contains a list
  * @cells_name:	property name that specifies phandles' arguments count
  * @index:	index of a phandle to parse out
- * @out_node:	optional pointer to device_node struct pointer (will be filled)
- * @out_args:	optional pointer to arguments pointer (will be filled)
+ * @out_args:	optional pointer to output arguments structure (will be filled)
  *
  * This function is useful to parse lists of phandles and their arguments.
- * Returns 0 on success and fills out_node and out_args, on error returns
- * appropriate errno value.
+ * Returns 0 on success and fills out_args, on error returns appropriate
+ * errno value.
  *
  * Example:
  *
@@ -889,92 +888,139 @@ EXPORT_SYMBOL(of_parse_phandle);
  * }
  *
  * To get a device_node of the `node2' node you may call this:
- * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args);
+ * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
  */
-int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
-				const char *cells_name, int index,
-				struct device_node **out_node,
-				const void **out_args)
-{
-	int ret = -EINVAL;
-	const __be32 *list;
-	const __be32 *list_end;
-	int size;
-	int cur_index = 0;
+static int __of_parse_phandle_with_args(const struct device_node *np,
+					const char *list_name,
+					const char *cells_name, int index,
+					struct of_phandle_args *out_args)
+{
+	const __be32 *list, *list_end;
+	int rc = 0, size, cur_index = 0;
+	uint32_t count = 0;
 	struct device_node *node = NULL;
-	const void *args = NULL;
+	phandle phandle;
 
+	/* Retrieve the phandle list property */
 	list = of_get_property(np, list_name, &size);
-	if (!list) {
-		ret = -ENOENT;
-		goto err0;
-	}
+	if (!list)
+		return -ENOENT;
 	list_end = list + size / sizeof(*list);
 
+	/* Loop over the phandles until all the requested entry is found */
 	while (list < list_end) {
-		const __be32 *cells;
-		phandle phandle;
+		rc = -EINVAL;
+		count = 0;
 
+		/*
+		 * If phandle is 0, then it is an empty entry with no
+		 * arguments.  Skip forward to the next entry.
+		 */
 		phandle = be32_to_cpup(list++);
-		args = list;
-
-		/* one cell hole in the list = <>; */
-		if (!phandle)
-			goto next;
-
-		node = of_find_node_by_phandle(phandle);
-		if (!node) {
-			pr_debug("%s: could not find phandle %d\n",
-				 np->full_name, phandle);
-			goto err0;
+		if (phandle) {
+			/*
+			 * Find the provider node and parse the #*-cells
+			 * property to determine the argument length
+			 */
+			node = of_find_node_by_phandle(phandle);
+			if (!node) {
+				pr_err("%s: could not find phandle\n",
+					 np->full_name);
+				goto err;
+			}
+			if (of_property_read_u32(node, cells_name, &count)) {
+				pr_err("%s: could not get %s for %s\n",
+					 np->full_name, cells_name,
+					 node->full_name);
+				goto err;
+			}
+
+			/*
+			 * Make sure that the arguments actually fit in the
+			 * remaining property data length
+			 */
+			if (list + count > list_end) {
+				pr_err("%s: arguments longer than property\n",
+					 np->full_name);
+				goto err;
+			}
 		}
 
-		cells = of_get_property(node, cells_name, &size);
-		if (!cells || size != sizeof(*cells)) {
-			pr_debug("%s: could not get %s for %s\n",
-				 np->full_name, cells_name, node->full_name);
-			goto err1;
-		}
-
-		list += be32_to_cpup(cells);
-		if (list > list_end) {
-			pr_debug("%s: insufficient arguments length\n",
-				 np->full_name);
-			goto err1;
+		/*
+		 * All of the error cases above bail out of the loop, so at
+		 * this point, the parsing is successful. If the requested
+		 * index matches, then fill the out_args structure and return,
+		 * or return -ENOENT for an empty entry.
+		 */
+		rc = -ENOENT;
+		if (cur_index == index) {
+			if (!phandle)
+				goto err;
+
+			if (out_args) {
+				int i;
+				if (WARN_ON(count > MAX_PHANDLE_ARGS))
+					count = MAX_PHANDLE_ARGS;
+				out_args->np = node;
+				out_args->args_count = count;
+				for (i = 0; i < count; i++)
+					out_args->args[i] =
+						be32_to_cpup(list++);
+			}
+
+			/* Found it! return success */
+			return 0;
 		}
-next:
-		if (cur_index == index)
-			break;
 
 		node = NULL;
-		args = NULL;
+		list += count;
 		cur_index++;
 	}
 
-	if (!node) {
-		/*
-		 * args w/o node indicates that the loop above has stopped at
-		 * the 'hole' cell. Report this differently.
-		 */
-		if (args)
-			ret = -EEXIST;
-		else
-			ret = -ENOENT;
-		goto err0;
-	}
+	/*
+	 * Unlock node before returning result; will be one of:
+	 * -ENOENT : index is for empty phandle
+	 * -EINVAL : parsing error on data
+	 * [1..n]  : Number of phandle (count mode; when index = -1)
+	 */
+	rc = index < 0 ? cur_index : -ENOENT;
+ err:
+	return rc;
+}
 
-	if (out_node)
-		*out_node = node;
-	if (out_args)
-		*out_args = args;
+int of_parse_phandle_with_args(const struct device_node *np,
+		const char *list_name, const char *cells_name, int index,
+		struct of_phandle_args *out_args)
+{
+	if (index < 0)
+		return -EINVAL;
+	return __of_parse_phandle_with_args(np, list_name, cells_name,
+					index, out_args);
+}
+EXPORT_SYMBOL(of_parse_phandle_with_args);
 
-	return 0;
-err1:
-err0:
-	pr_debug("%s failed with status %d\n", __func__, ret);
-	return ret;
+/**
+ * of_count_phandle_with_args() - Find the number of phandles references in a property
+ * @np:		pointer to a device tree node containing a list
+ * @list_name:	property name that contains a list
+ * @cells_name:	property name that specifies phandles' arguments count
+ *
+ * Returns the number of phandle + argument tuples within a property. It
+ * is a typical pattern to encode a list of phandle and variable
+ * arguments into a single property. The number of arguments is encoded
+ * by a property in the phandle-target node. For example, a gpios
+ * property would contain a list of GPIO specifies consisting of a
+ * phandle and 1 or more arguments. The number of arguments are
+ * determined by the #gpio-cells property in the node pointed to by the
+ * phandle.
+ */
+int of_count_phandle_with_args(const struct device_node *np,
+			const char *list_name, const char *cells_name)
+{
+	return __of_parse_phandle_with_args(np, list_name, cells_name,
+					-1, NULL);
 }
-EXPORT_SYMBOL(of_parse_phandles_with_args);
+EXPORT_SYMBOL(of_count_phandle_with_args);
 
 /**
  * of_machine_is_compatible - Test root of device tree for a given compatible value
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 83b72c0..87b9c0c 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -9,17 +9,16 @@ int of_get_named_gpio(struct device_node *np,
                                    const char *propname, int index)
 {
 	int ret;
-	struct device_node *gpio_np;
-	const void *gpio_spec;
+	struct of_phandle_args out_args;
 
-	ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index,
-					  &gpio_np, &gpio_spec);
+	ret = of_parse_phandle_with_args(np, propname, "#gpio-cells",
+					index, &out_args);
 	if (ret) {
 		pr_debug("%s: can't parse gpios property: %d\n", __func__, ret);
 		return -EINVAL;
 	}
 
-	ret = gpio_get_num(gpio_np->device, be32_to_cpup(gpio_spec));
+	ret = gpio_get_num(out_args.np->device, outargs.args[0]);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/usb/imx/chipidea-imx.c b/drivers/usb/imx/chipidea-imx.c
index 32b05aa..ee7c010 100644
--- a/drivers/usb/imx/chipidea-imx.c
+++ b/drivers/usb/imx/chipidea-imx.c
@@ -62,16 +62,15 @@ static int imx_chipidea_port_post_init(void *drvdata)
 
 static int imx_chipidea_probe_dt(struct imx_chipidea *ci)
 {
-	const void *out_args;
-	struct device_node *usbmisc_np;
+	struct of_phandle_args out_args;
 	enum usb_dr_mode mode;
 	enum usb_phy_interface phymode;
 
-	of_parse_phandles_with_args(ci->dev->device_node, "fsl,usbmisc",
-			"#index-cells", 0, &usbmisc_np, &out_args);
-
-	ci->portno = be32_to_cpup(out_args);
+	if (of_parse_phandle_with_args(ci->dev->device_node, "fsl,usbmisc",
+					"#index-cells", 0, &out_args))
+		return -ENODEV;
 
+	ci->portno = out_args.args[0];
 	ci->flags = MXC_EHCI_MODE_UTMI_8BIT;
 
 	mode = of_usb_get_dr_mode(ci->dev->device_node, NULL);
diff --git a/include/of.h b/include/of.h
index 81df5a6..51ecf4d 100644
--- a/include/of.h
+++ b/include/of.h
@@ -42,6 +42,13 @@ struct of_device_id {
 	unsigned long data;
 };
 
+#define MAX_PHANDLE_ARGS 8
+struct of_phandle_args {
+	struct device_node *np;
+	int args_count;
+	uint32_t args[MAX_PHANDLE_ARGS];
+};
+
 #define OF_MAX_RESERVE_MAP	16
 struct of_reserve_map {
 	uint64_t start[OF_MAX_RESERVE_MAP];
@@ -120,11 +127,6 @@ static inline int of_property_write_u32(struct device_node *np,
 const void *of_get_property(const struct device_node *np, const char *name,
 			 int *lenp);
 
-int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
-				const char *cells_name, int index,
-				struct device_node **out_node,
-				const void **out_args);
-
 int of_get_named_gpio(struct device_node *np,
                                    const char *propname, int index);
 
@@ -217,6 +219,11 @@ extern int of_property_count_strings(struct device_node *np,
 extern struct device_node *of_parse_phandle(const struct device_node *np,
 					    const char *phandle_name,
 					    int index);
+extern int of_parse_phandle_with_args(const struct device_node *np,
+	const char *list_name, const char *cells_name, int index,
+	struct of_phandle_args *out_args);
+extern int of_count_phandle_with_args(const struct device_node *np,
+	const char *list_name, const char *cells_name);
 
 extern void of_alias_scan(void);
 extern int of_alias_get_id(struct device_node *np, const char *stem);
@@ -352,6 +359,19 @@ static inline struct device_node *of_parse_phandle(const struct device_node *np,
 	return NULL;
 }
 
+static inline int of_parse_phandle_with_args(const struct device_node *np,
+		const char *list_name, const char *cells_name, int index,
+		struct of_phandle_args *out_args)
+{
+	return -ENOSYS;
+}
+
+static inline int of_count_phandle_with_args(const struct device_node *np,
+				const char *list_name, const char *cells_name)
+{
+	return -ENOSYS;
+}
+
 static inline struct device_node *of_find_node_by_path(const char *path)
 {
 	return NULL;
-- 
1.7.2.5




More information about the barebox mailing list