mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 1/3] of: update of_parse_phandle_with_args to latest linux code
@ 2013-06-04  7:29 Lucas Stach
  2013-06-04  7:29 ` [PATCH 2/3] of: import of_property_match_string from Linux Lucas Stach
  2013-06-04  7:29 ` [PATCH 3/3] clk: add clock lookup from devicetree Lucas Stach
  0 siblings, 2 replies; 4+ messages in thread
From: Lucas Stach @ 2013-06-04  7:29 UTC (permalink / raw)
  To: barebox

Signed-off-by: Lucas Stach <dev@lynxeye.de>
---
 drivers/of/base.c | 168 +++++++++++++++++++++++++++++++-----------------------
 drivers/of/gpio.c |   9 ++-
 include/of.h      |  14 +++--
 3 files changed, 111 insertions(+), 80 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 4241e65..b3d012c 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -406,17 +406,19 @@ int of_property_write_u32_array(struct device_node *np,
 }
 
 /**
- * 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.
+ *
+ * Caller is responsible to call of_node_put() on the returned out_args->node
+ * pointer.
  *
  * Example:
  *
@@ -433,92 +435,116 @@ int of_property_write_u32_array(struct device_node *np,
  * }
  *
  * 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)
+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)
 {
-	int ret = -EINVAL;
-	const __be32 *list;
-	const __be32 *list_end;
-	int size;
-	int cur_index = 0;
+	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;
+		/*
+		 * 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;
 		}
 
-		list += be32_to_cpup(cells);
-		if (list > list_end) {
-			pr_debug("%s: insufficient arguments length\n",
-				 np->full_name);
-			goto err1;
-		}
-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;
-	}
-
-	if (out_node)
-		*out_node = node;
-	if (out_args)
-		*out_args = args;
+	/*
+	 * 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;
+}
 
-	return 0;
-err1:
-err0:
-	pr_debug("%s failed with status %d\n", __func__, ret);
-	return ret;
+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_phandles_with_args);
+EXPORT_SYMBOL(of_parse_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..cd3e1b7 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 gpio_spec;
 
-	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,
+					 &gpio_spec);
 	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(gpio_spec.np->device, gpio_spec.args[0]);
 	if (ret < 0)
 		return ret;
 
diff --git a/include/of.h b/include/of.h
index 300b706..f00d1b4 100644
--- a/include/of.h
+++ b/include/of.h
@@ -32,6 +32,13 @@ struct device_node {
 	phandle phandle;
 };
 
+#define MAX_PHANDLE_ARGS 8
+struct of_phandle_args {
+	struct device_node *np;
+	int args_count;
+	uint32_t args[MAX_PHANDLE_ARGS];
+};
+
 struct of_device_id {
 	char *compatible;
 	unsigned long data;
@@ -130,10 +137,9 @@ 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_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);
 
 int of_get_named_gpio(struct device_node *np,
                                    const char *propname, int index);
-- 
1.8.2.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 2/3] of: import of_property_match_string from Linux
  2013-06-04  7:29 [PATCH 1/3] of: update of_parse_phandle_with_args to latest linux code Lucas Stach
@ 2013-06-04  7:29 ` Lucas Stach
  2013-06-04  7:29 ` [PATCH 3/3] clk: add clock lookup from devicetree Lucas Stach
  1 sibling, 0 replies; 4+ messages in thread
From: Lucas Stach @ 2013-06-04  7:29 UTC (permalink / raw)
  To: barebox

Signed-off-by: Lucas Stach <dev@lynxeye.de>
---
 drivers/of/base.c | 37 +++++++++++++++++++++++++++++++++++++
 include/of.h      |  2 ++
 2 files changed, 39 insertions(+)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index b3d012c..912e793 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -683,6 +683,43 @@ int of_property_read_string_index(struct device_node *np, const char *propname,
 EXPORT_SYMBOL_GPL(of_property_read_string_index);
 
 /**
+ * of_property_match_string() - Find string in a list and return index
+ * @np: pointer to node containing string list property
+ * @propname: string list property name
+ * @string: pointer to string to search for in string list
+ *
+ * This function searches a string list property and returns the index
+ * of a specific string value.
+ */
+int of_property_match_string(struct device_node *np, const char *propname,
+			     const char *string)
+{
+	struct property *prop = of_find_property(np, propname);
+	size_t l;
+	int i;
+	const char *p, *end;
+
+	if (!prop)
+		return -EINVAL;
+	if (!prop->value)
+		return -ENODATA;
+
+	p = prop->value;
+	end = p + prop->length;
+
+	for (i = 0; p < end; i++, p += l) {
+		l = strlen(p) + 1;
+		if (p + l > end)
+			return -EILSEQ;
+		pr_debug("comparing %s with %s\n", string, p);
+		if (strcmp(string, p) == 0)
+			return i; /* Found it; return index */
+	}
+	return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(of_property_match_string);
+
+/**
  * of_modalias_node - Lookup appropriate modalias for a device node
  * @node:	pointer to a device tree node
  * @modalias:	Pointer to buffer that modalias value will be copied into
diff --git a/include/of.h b/include/of.h
index f00d1b4..27fd8da 100644
--- a/include/of.h
+++ b/include/of.h
@@ -172,6 +172,8 @@ int of_property_read_string(struct device_node *np, const char *propname,
 				const char **out_string);
 int of_property_read_string_index(struct device_node *np, const char *propname,
 				  int index, const char **output);
+int of_property_match_string(struct device_node *np, const char *propname,
+			     const char *string);
 int of_set_property(struct device_node *node, const char *p, const void *val, int len,
 		int create);
 struct device_node *of_create_node(struct device_node *root, const char *path);
-- 
1.8.2.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 3/3] clk: add clock lookup from devicetree
  2013-06-04  7:29 [PATCH 1/3] of: update of_parse_phandle_with_args to latest linux code Lucas Stach
  2013-06-04  7:29 ` [PATCH 2/3] of: import of_property_match_string from Linux Lucas Stach
@ 2013-06-04  7:29 ` Lucas Stach
  2013-06-05  6:47   ` Sascha Hauer
  1 sibling, 1 reply; 4+ messages in thread
From: Lucas Stach @ 2013-06-04  7:29 UTC (permalink / raw)
  To: barebox

Taken from the Linuxkernel with some small adjustments for barebox.

Signed-off-by: Lucas Stach <dev@lynxeye.de>
---
 drivers/clk/clk.c    | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/clk/clkdev.c | 74 +++++++++++++++++++++++++++++++++++++++
 include/linux/clk.h  | 33 ++++++++++++++++++
 3 files changed, 204 insertions(+)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 690a0c6..bad3386 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -16,6 +16,7 @@
  */
 #include <common.h>
 #include <errno.h>
+#include <malloc.h>
 #include <linux/clk.h>
 #include <linux/err.h>
 
@@ -253,6 +254,102 @@ int clk_is_enabled_always(struct clk *clk)
 	return 1;
 }
 
+#ifdef CONFIG_OFTREE
+/**
+ * struct of_clk_provider - Clock provider registration structure
+ * @link: Entry in global list of clock providers
+ * @node: Pointer to device tree node of clock provider
+ * @get: Get clock callback.  Returns NULL or a struct clk for the
+ *       given clock specifier
+ * @data: context pointer to be passed into @get callback
+ */
+struct of_clk_provider {
+	struct list_head link;
+
+	struct device_node *node;
+	struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
+	void *data;
+};
+
+static LIST_HEAD(of_clk_providers);
+
+struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
+{
+	struct clk_onecell_data *clk_data = data;
+	unsigned int idx = clkspec->args[0];
+
+	if (idx >= clk_data->clk_num) {
+		pr_err("%s: invalid clock index %d\n", __func__, idx);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return clk_data->clks[idx];
+}
+EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
+
+/**
+ * of_clk_add_provider() - Register a clock provider for a node
+ * @np: Device node pointer associated with clock provider
+ * @clk_src_get: callback for decoding clock
+ * @data: context pointer for @clk_src_get callback.
+ */
+int of_clk_add_provider(struct device_node *np,
+			struct clk *(*clk_src_get)(struct of_phandle_args *clkspec,
+						   void *data),
+			void *data)
+{
+	struct of_clk_provider *cp;
+
+	cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL);
+	if (!cp)
+		return -ENOMEM;
+
+	cp->node = np;
+	cp->data = data;
+	cp->get = clk_src_get;
+
+	list_add(&cp->link, &of_clk_providers);
+	pr_debug("Added clock from %s\n", np->full_name);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_clk_add_provider);
+
+/**
+ * of_clk_del_provider() - Remove a previously registered clock provider
+ * @np: Device node pointer associated with clock provider
+ */
+void of_clk_del_provider(struct device_node *np)
+{
+	struct of_clk_provider *cp;
+
+	list_for_each_entry(cp, &of_clk_providers, link) {
+		if (cp->node == np) {
+			list_del(&cp->link);
+			kfree(cp);
+			break;
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(of_clk_del_provider);
+
+struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
+{
+	struct of_clk_provider *provider;
+	struct clk *clk = ERR_PTR(-ENOENT);
+
+	/* Check if we have such a provider in our array */
+	list_for_each_entry(provider, &of_clk_providers, link) {
+		if (provider->node == clkspec->np)
+			clk = provider->get(clkspec, provider->data);
+		if (!IS_ERR(clk))
+			break;
+	}
+
+	return clk;
+}
+#endif
+
 static void dump_one(struct clk *clk, int verbose, int indent)
 {
 	struct clk *c;
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 256927e..0b91af0 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -19,10 +19,80 @@
 #include <linux/clkdev.h>
 #include <init.h>
 #include <malloc.h>
+#include <of.h>
 #include <stdio.h>
 
 static LIST_HEAD(clocks);
 
+#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK)
+struct clk *of_clk_get(struct device_node *np, int index)
+{
+	struct of_phandle_args clkspec;
+	struct clk *clk;
+	int rc;
+
+	if (index < 0)
+		return ERR_PTR(-EINVAL);
+
+	rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
+					&clkspec);
+	if (rc)
+		return ERR_PTR(rc);
+
+	clk = of_clk_get_from_provider(&clkspec);
+	return clk;
+}
+EXPORT_SYMBOL(of_clk_get);
+
+/**
+ * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
+ * @np: pointer to clock consumer node
+ * @name: name of consumer's clock input, or NULL for the first clock reference
+ *
+ * This function parses the clocks and clock-names properties,
+ * and uses them to look up the struct clk from the registered list of clock
+ * providers.
+ */
+struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
+{
+	struct clk *clk = ERR_PTR(-ENOENT);
+
+	/* Walk up the tree of devices looking for a clock that matches */
+	while (np) {
+		int index = 0;
+
+		/*
+		 * For named clocks, first look up the name in the
+		 * "clock-names" property.  If it cannot be found, then
+		 * index will be an error code, and of_clk_get() will fail.
+		 */
+		if (name)
+			index = of_property_match_string(np, "clock-names",
+							 name);
+		clk = of_clk_get(np, index);
+		if (!IS_ERR(clk))
+			break;
+		else if (name && index >= 0) {
+			pr_err("ERROR: could not get clock %s:%s(%i)\n",
+				np->full_name, name ? name : "", index);
+			return clk;
+		}
+
+		/*
+		 * No matching clock found on this node.  If the parent node
+		 * has a "clock-ranges" property, then we can try one of its
+		 * clocks.
+		 */
+		np = np->parent;
+		if (np && !of_get_property(np, "clock-ranges", NULL))
+			break;
+	}
+
+	return clk;
+}
+EXPORT_SYMBOL(of_clk_get_by_name);
+#endif
+
 /*
  * Find the correct struct clk for the device and connection ID.
  * We do slightly fuzzy matching here:
@@ -109,6 +179,10 @@ struct clk *clk_get(struct device_d *dev, const char *con_id)
 	if (!IS_ERR(clk))
 		return clk;
 
+	clk = of_clk_get_by_name(dev->device_node, con_id);
+		if (!IS_ERR(clk))
+			return clk;
+
 	return clk_get_sys(dev_id, con_id);
 }
 EXPORT_SYMBOL(clk_get);
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 37a4813..0f7158a 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -11,6 +11,8 @@
 #ifndef __LINUX_CLK_H
 #define __LINUX_CLK_H
 
+#include <linux/err.h>
+
 struct device_d;
 
 /*
@@ -210,4 +212,35 @@ void clk_dump(int verbose);
 
 #endif
 
+struct device_node;
+struct of_phandle_args;
+
+#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK)
+int of_clk_add_provider(struct device_node *np,
+			struct clk *(*clk_src_get)(struct of_phandle_args *args,
+						   void *data),
+			void *data);
+void of_clk_del_provider(struct device_node *np);
+
+struct clk_onecell_data {
+	struct clk **clks;
+	unsigned int clk_num;
+};
+struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
+
+struct clk *of_clk_get(struct device_node *np, int index);
+struct clk *of_clk_get_by_name(struct device_node *np, const char *name);
+struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec);
+#else
+static inline struct clk *of_clk_get(struct device_node *np, int index)
+{
+	return ERR_PTR(-ENOENT);
+}
+static inline struct clk *of_clk_get_by_name(struct device_node *np,
+					     const char *name)
+{
+	return ERR_PTR(-ENOENT);
+}
+#endif
+
 #endif
-- 
1.8.2.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 3/3] clk: add clock lookup from devicetree
  2013-06-04  7:29 ` [PATCH 3/3] clk: add clock lookup from devicetree Lucas Stach
@ 2013-06-05  6:47   ` Sascha Hauer
  0 siblings, 0 replies; 4+ messages in thread
From: Sascha Hauer @ 2013-06-05  6:47 UTC (permalink / raw)
  To: Lucas Stach; +Cc: barebox

On Tue, Jun 04, 2013 at 09:29:11AM +0200, Lucas Stach wrote:
> Taken from the Linuxkernel with some small adjustments for barebox.
> 
> Signed-off-by: Lucas Stach <dev@lynxeye.de>
> ---
>  drivers/clk/clk.c    | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/clk/clkdev.c | 74 +++++++++++++++++++++++++++++++++++++++
>  include/linux/clk.h  | 33 ++++++++++++++++++
>  3 files changed, 204 insertions(+)
> 
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 690a0c6..bad3386 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -16,6 +16,7 @@
>   */
>  #include <common.h>
>  #include <errno.h>
> +#include <malloc.h>
>  #include <linux/clk.h>
>  #include <linux/err.h>
>  
> @@ -253,6 +254,102 @@ int clk_is_enabled_always(struct clk *clk)
>  	return 1;
>  }
>  
> +#ifdef CONFIG_OFTREE
> +/**
> + * struct of_clk_provider - Clock provider registration structure
> + * @link: Entry in global list of clock providers
> + * @node: Pointer to device tree node of clock provider
> + * @get: Get clock callback.  Returns NULL or a struct clk for the
> + *       given clock specifier
> + * @data: context pointer to be passed into @get callback
> + */
> +struct of_clk_provider {
> +	struct list_head link;
> +
> +	struct device_node *node;
> +	struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
> +	void *data;
> +};
> +
> +static LIST_HEAD(of_clk_providers);
> +
> +struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data)
> +{
> +	struct clk_onecell_data *clk_data = data;
> +	unsigned int idx = clkspec->args[0];
> +
> +	if (idx >= clk_data->clk_num) {
> +		pr_err("%s: invalid clock index %d\n", __func__, idx);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	return clk_data->clks[idx];
> +}
> +EXPORT_SYMBOL_GPL(of_clk_src_onecell_get);
> +
> +/**
> + * of_clk_add_provider() - Register a clock provider for a node
> + * @np: Device node pointer associated with clock provider
> + * @clk_src_get: callback for decoding clock
> + * @data: context pointer for @clk_src_get callback.
> + */
> +int of_clk_add_provider(struct device_node *np,
> +			struct clk *(*clk_src_get)(struct of_phandle_args *clkspec,
> +						   void *data),
> +			void *data)
> +{
> +	struct of_clk_provider *cp;
> +
> +	cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL);
> +	if (!cp)
> +		return -ENOMEM;
> +
> +	cp->node = np;
> +	cp->data = data;
> +	cp->get = clk_src_get;
> +
> +	list_add(&cp->link, &of_clk_providers);
> +	pr_debug("Added clock from %s\n", np->full_name);
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(of_clk_add_provider);
> +
> +/**
> + * of_clk_del_provider() - Remove a previously registered clock provider
> + * @np: Device node pointer associated with clock provider
> + */
> +void of_clk_del_provider(struct device_node *np)
> +{
> +	struct of_clk_provider *cp;
> +
> +	list_for_each_entry(cp, &of_clk_providers, link) {
> +		if (cp->node == np) {
> +			list_del(&cp->link);
> +			kfree(cp);
> +			break;
> +		}
> +	}
> +}
> +EXPORT_SYMBOL_GPL(of_clk_del_provider);
> +
> +struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
> +{
> +	struct of_clk_provider *provider;
> +	struct clk *clk = ERR_PTR(-ENOENT);
> +
> +	/* Check if we have such a provider in our array */
> +	list_for_each_entry(provider, &of_clk_providers, link) {
> +		if (provider->node == clkspec->np)
> +			clk = provider->get(clkspec, provider->data);
> +		if (!IS_ERR(clk))
> +			break;
> +	}
> +
> +	return clk;
> +}
> +#endif
> +
>  static void dump_one(struct clk *clk, int verbose, int indent)
>  {
>  	struct clk *c;
> diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
> index 256927e..0b91af0 100644
> --- a/drivers/clk/clkdev.c
> +++ b/drivers/clk/clkdev.c
> @@ -19,10 +19,80 @@
>  #include <linux/clkdev.h>
>  #include <init.h>
>  #include <malloc.h>
> +#include <of.h>
>  #include <stdio.h>
>  
>  static LIST_HEAD(clocks);
>  
> +#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK)
> +struct clk *of_clk_get(struct device_node *np, int index)
> +{
> +	struct of_phandle_args clkspec;
> +	struct clk *clk;
> +	int rc;
> +
> +	if (index < 0)
> +		return ERR_PTR(-EINVAL);
> +
> +	rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", index,
> +					&clkspec);
> +	if (rc)
> +		return ERR_PTR(rc);
> +
> +	clk = of_clk_get_from_provider(&clkspec);
> +	return clk;
> +}
> +EXPORT_SYMBOL(of_clk_get);
> +
> +/**
> + * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
> + * @np: pointer to clock consumer node
> + * @name: name of consumer's clock input, or NULL for the first clock reference
> + *
> + * This function parses the clocks and clock-names properties,
> + * and uses them to look up the struct clk from the registered list of clock
> + * providers.
> + */
> +struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
> +{
> +	struct clk *clk = ERR_PTR(-ENOENT);
> +
> +	/* Walk up the tree of devices looking for a clock that matches */
> +	while (np) {
> +		int index = 0;
> +
> +		/*
> +		 * For named clocks, first look up the name in the
> +		 * "clock-names" property.  If it cannot be found, then
> +		 * index will be an error code, and of_clk_get() will fail.
> +		 */
> +		if (name)
> +			index = of_property_match_string(np, "clock-names",
> +							 name);
> +		clk = of_clk_get(np, index);
> +		if (!IS_ERR(clk))
> +			break;
> +		else if (name && index >= 0) {
> +			pr_err("ERROR: could not get clock %s:%s(%i)\n",
> +				np->full_name, name ? name : "", index);
> +			return clk;
> +		}
> +
> +		/*
> +		 * No matching clock found on this node.  If the parent node
> +		 * has a "clock-ranges" property, then we can try one of its
> +		 * clocks.
> +		 */
> +		np = np->parent;
> +		if (np && !of_get_property(np, "clock-ranges", NULL))
> +			break;
> +	}
> +
> +	return clk;
> +}
> +EXPORT_SYMBOL(of_clk_get_by_name);
> +#endif
> +
>  /*
>   * Find the correct struct clk for the device and connection ID.
>   * We do slightly fuzzy matching here:
> @@ -109,6 +179,10 @@ struct clk *clk_get(struct device_d *dev, const char *con_id)
>  	if (!IS_ERR(clk))
>  		return clk;
>  
> +	clk = of_clk_get_by_name(dev->device_node, con_id);
> +		if (!IS_ERR(clk))
> +			return clk;
> +
>  	return clk_get_sys(dev_id, con_id);
>  }
>  EXPORT_SYMBOL(clk_get);
> diff --git a/include/linux/clk.h b/include/linux/clk.h
> index 37a4813..0f7158a 100644
> --- a/include/linux/clk.h
> +++ b/include/linux/clk.h
> @@ -11,6 +11,8 @@
>  #ifndef __LINUX_CLK_H
>  #define __LINUX_CLK_H
>  
> +#include <linux/err.h>
> +
>  struct device_d;
>  
>  /*
> @@ -210,4 +212,35 @@ void clk_dump(int verbose);
>  
>  #endif
>  
> +struct device_node;
> +struct of_phandle_args;
> +
> +#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK)
> +int of_clk_add_provider(struct device_node *np,
> +			struct clk *(*clk_src_get)(struct of_phandle_args *args,
> +						   void *data),
> +			void *data);
> +void of_clk_del_provider(struct device_node *np);
> +
> +struct clk_onecell_data {
> +	struct clk **clks;
> +	unsigned int clk_num;
> +};
> +struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
> +
> +struct clk *of_clk_get(struct device_node *np, int index);
> +struct clk *of_clk_get_by_name(struct device_node *np, const char *name);
> +struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec);

Can we have a CLK_HAVE_OF_PROVIDER Kconfig symbol and a static inline
version of of_clk_get_from_provider if this is not set? On architectures
which do not call of_clk_add_provider this only adds to the binary space
otherwise.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-06-05  6:47 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-04  7:29 [PATCH 1/3] of: update of_parse_phandle_with_args to latest linux code Lucas Stach
2013-06-04  7:29 ` [PATCH 2/3] of: import of_property_match_string from Linux Lucas Stach
2013-06-04  7:29 ` [PATCH 3/3] clk: add clock lookup from devicetree Lucas Stach
2013-06-05  6:47   ` Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox