of: update of_parse_phandle_with_args to latest linux code
Subsystems (4)
PATCH 1/3 of: update of_parse_phandle_with_args to latest linux code
Signed-off-by Lucas Stach <[email protected]>
--- drivers/of/base.c | 168 +++++++++++++++++++++++++++++++----------------------- drivers/of/gpio.c | 9 ++- include/of.h | 14 +++-- 3 files changed, 111 insertions(+), 80 deletions(-)
drivers/of/base.c +97 -71
@@ -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
drivers/of/gpio.c +4 -5
@@ -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;
include/of.h +10 -4
@@ -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);
Signature · 7 lines
1.8.2.1 _______________________________________________ barebox mailing list [email protected] http://lists.infradead.org/mailman/listinfo/barebox
PATCH 2/3 of: import of_property_match_string from Linux
Signed-off-by Lucas Stach <[email protected]>
--- drivers/of/base.c | 37 +++++++++++++++++++++++++++++++++++++ include/of.h | 2 ++ 2 files changed, 39 insertions(+)
drivers/of/base.c +37 -0
@@ -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
include/of.h +2 -0
@@ -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);
Signature · 7 lines
1.8.2.1 _______________________________________________ barebox mailing list [email protected] http://lists.infradead.org/mailman/listinfo/barebox
PATCH 3/3 clk: add clock lookup from devicetree
In reply to Lucas StachTaken from the Linuxkernel with some small adjustments for barebox.
Signed-off-by Lucas Stach <[email protected]>
--- drivers/clk/clk.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/clkdev.c | 74 +++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 33 ++++++++++++++++++ 3 files changed, 204 insertions(+)
drivers/clk/clk.c +97 -0
@@ -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;
drivers/clk/clkdev.c +74 -0
90 lines not on this page · raw message
include/linux/clk.h +33 -0
@@ -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
Signature · 7 lines
1.8.2.1 _______________________________________________ barebox mailing list [email protected] http://lists.infradead.org/mailman/listinfo/barebox
Re: [PATCH 3/3] clk: add clock lookup from devicetree
Quoted 246 lines · Lucas Stach
Taken from the Linuxkernel with some small adjustments for barebox.
Signed-off-by Lucas Stach <[email protected]>--- drivers/clk/clk.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/clk/clkdev.c | 74 +++++++++++++++++++++++++++++++++++++++ include/linux/clk.h | 33 ++++++++++++++++++ 3 files changed, 204 insertions(+)drivers/clk/clk.c +97
-0@@ -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;drivers/clk/clkdev.c +74
-0@@ -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);include/linux/clk.h +11
-0@@ -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);
include/linux/clk.h void clk_dump(int verbose); · line 233
Quoted 10 lines
include/linux/clk.h +10
-0+ +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
Signature · 9 lines
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 [email protected] http://lists.infradead.org/mailman/listinfo/barebox