* [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