of: create of_phandle_args to simplify return of phandle parsing data
of_parse_phandle_with_args() needs to return quite a bit of data. Rather than making each datum a separate **out_ argument, this patch creates struct of_phandle_args to contain all the returned data and reworks the user of the function. This patch also enables of_parse_phandle_with_args() to return the device node pointer for the phandle node. This patch also ends up being fairly major surgery to of_parse_handle_with_args(). The existing structure didn't work well when extending to use of_phandle_args, and I discovered bugs during testing. I also took the opportunity to rename the function to be like the existing of_parse_phandle(). v2: - moved declaration of of_phandle_args to fix compile on non-DT builds - fixed incorrect index in example usage - fixed incorrect return code handling for empty entries Reviewed-by: Shawn Guo <shawn.guo@freescale.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
This commit is contained in:
parent
1a2d397a6e
commit
15c9a0acc3
|
@ -824,17 +824,19 @@ of_parse_phandle(struct device_node *np, const char *phandle_name, int index)
|
||||||
EXPORT_SYMBOL(of_parse_phandle);
|
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
|
* @np: pointer to a device tree node containing a list
|
||||||
* @list_name: property name that contains a list
|
* @list_name: property name that contains a list
|
||||||
* @cells_name: property name that specifies phandles' arguments count
|
* @cells_name: property name that specifies phandles' arguments count
|
||||||
* @index: index of a phandle to parse out
|
* @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 output arguments structure (will be filled)
|
||||||
* @out_args: optional pointer to arguments pointer (will be filled)
|
|
||||||
*
|
*
|
||||||
* This function is useful to parse lists of phandles and their arguments.
|
* 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
|
* Returns 0 on success and fills out_args, on error returns appropriate
|
||||||
* appropriate errno value.
|
* errno value.
|
||||||
|
*
|
||||||
|
* Caller is responsible to call of_node_put() on the returned out_args->node
|
||||||
|
* pointer.
|
||||||
*
|
*
|
||||||
* Example:
|
* Example:
|
||||||
*
|
*
|
||||||
|
@ -851,94 +853,96 @@ EXPORT_SYMBOL(of_parse_phandle);
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* To get a device_node of the `node2' node you may call this:
|
* 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,
|
int of_parse_phandle_with_args(struct device_node *np, const char *list_name,
|
||||||
const char *cells_name, int index,
|
const char *cells_name, int index,
|
||||||
struct device_node **out_node,
|
struct of_phandle_args *out_args)
|
||||||
const void **out_args)
|
|
||||||
{
|
{
|
||||||
int ret = -EINVAL;
|
const __be32 *list, *list_end;
|
||||||
const __be32 *list;
|
int size, cur_index = 0;
|
||||||
const __be32 *list_end;
|
uint32_t count = 0;
|
||||||
int size;
|
|
||||||
int cur_index = 0;
|
|
||||||
struct device_node *node = NULL;
|
struct device_node *node = NULL;
|
||||||
const void *args = NULL;
|
phandle phandle;
|
||||||
|
|
||||||
|
/* Retrieve the phandle list property */
|
||||||
list = of_get_property(np, list_name, &size);
|
list = of_get_property(np, list_name, &size);
|
||||||
if (!list) {
|
if (!list)
|
||||||
ret = -ENOENT;
|
return -EINVAL;
|
||||||
goto err0;
|
|
||||||
}
|
|
||||||
list_end = list + size / sizeof(*list);
|
list_end = list + size / sizeof(*list);
|
||||||
|
|
||||||
|
/* Loop over the phandles until all the requested entry is found */
|
||||||
while (list < list_end) {
|
while (list < list_end) {
|
||||||
const __be32 *cells;
|
count = 0;
|
||||||
phandle phandle;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If phandle is 0, then it is an empty entry with no
|
||||||
|
* arguments. Skip forward to the next entry.
|
||||||
|
*/
|
||||||
phandle = be32_to_cpup(list++);
|
phandle = be32_to_cpup(list++);
|
||||||
args = list;
|
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);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* one cell hole in the list = <>; */
|
/*
|
||||||
if (!phandle)
|
* Make sure that the arguments actually fit in the
|
||||||
goto next;
|
* remaining property data length
|
||||||
|
*/
|
||||||
node = of_find_node_by_phandle(phandle);
|
if (list + count > list_end) {
|
||||||
if (!node) {
|
pr_err("%s: arguments longer than property\n",
|
||||||
pr_debug("%s: could not find phandle\n",
|
np->full_name);
|
||||||
np->full_name);
|
break;
|
||||||
goto err0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cells = of_get_property(node, cells_name, &size);
|
/*
|
||||||
if (!cells || size != sizeof(*cells)) {
|
* All of the error cases above bail out of the loop, so at
|
||||||
pr_debug("%s: could not get %s for %s\n",
|
* this point, the parsing is successful. If the requested
|
||||||
np->full_name, cells_name, node->full_name);
|
* index matches, then fill the out_args structure and return,
|
||||||
goto err1;
|
* or return -ENOENT for an empty entry.
|
||||||
}
|
*/
|
||||||
|
if (cur_index == index) {
|
||||||
|
if (!phandle)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
list += be32_to_cpup(cells);
|
if (out_args) {
|
||||||
if (list > list_end) {
|
int i;
|
||||||
pr_debug("%s: insufficient arguments length\n",
|
if (WARN_ON(count > MAX_PHANDLE_ARGS))
|
||||||
np->full_name);
|
count = MAX_PHANDLE_ARGS;
|
||||||
goto err1;
|
out_args->np = node;
|
||||||
|
out_args->args_count = count;
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
out_args->args[i] = be32_to_cpup(list++);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
next:
|
|
||||||
if (cur_index == index)
|
|
||||||
break;
|
|
||||||
|
|
||||||
of_node_put(node);
|
of_node_put(node);
|
||||||
node = NULL;
|
node = NULL;
|
||||||
args = NULL;
|
list += count;
|
||||||
cur_index++;
|
cur_index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node) {
|
/* Loop exited without finding a valid entry; return an error */
|
||||||
/*
|
if (node)
|
||||||
* args w/o node indicates that the loop above has stopped at
|
of_node_put(node);
|
||||||
* the 'hole' cell. Report this differently.
|
return -EINVAL;
|
||||||
*/
|
|
||||||
if (args)
|
|
||||||
ret = -EEXIST;
|
|
||||||
else
|
|
||||||
ret = -ENOENT;
|
|
||||||
goto err0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_node)
|
|
||||||
*out_node = node;
|
|
||||||
if (out_args)
|
|
||||||
*out_args = args;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
err1:
|
|
||||||
of_node_put(node);
|
|
||||||
err0:
|
|
||||||
pr_debug("%s failed with status %d\n", __func__, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(of_parse_phandles_with_args);
|
EXPORT_SYMBOL(of_parse_phandle_with_args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* prom_add_property - Add a property to a node
|
* prom_add_property - Add a property to a node
|
||||||
|
|
|
@ -35,32 +35,27 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
|
||||||
int index, enum of_gpio_flags *flags)
|
int index, enum of_gpio_flags *flags)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct device_node *gpio_np;
|
|
||||||
struct gpio_chip *gc;
|
struct gpio_chip *gc;
|
||||||
int size;
|
struct of_phandle_args gpiospec;
|
||||||
const void *gpio_spec;
|
|
||||||
const __be32 *gpio_cells;
|
|
||||||
|
|
||||||
ret = of_parse_phandles_with_args(np, propname, "#gpio-cells", index,
|
ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
|
||||||
&gpio_np, &gpio_spec);
|
&gpiospec);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
pr_debug("%s: can't parse gpios property\n", __func__);
|
pr_debug("%s: can't parse gpios property\n", __func__);
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gc = of_node_to_gpiochip(gpio_np);
|
gc = of_node_to_gpiochip(gpiospec.np);
|
||||||
if (!gc) {
|
if (!gc) {
|
||||||
pr_debug("%s: gpio controller %s isn't registered\n",
|
pr_debug("%s: gpio controller %s isn't registered\n",
|
||||||
np->full_name, gpio_np->full_name);
|
np->full_name, gpiospec.np->full_name);
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
gpio_cells = of_get_property(gpio_np, "#gpio-cells", &size);
|
if (gpiospec.args_count != gc->of_gpio_n_cells) {
|
||||||
if (!gpio_cells || size != sizeof(*gpio_cells) ||
|
|
||||||
be32_to_cpup(gpio_cells) != gc->of_gpio_n_cells) {
|
|
||||||
pr_debug("%s: wrong #gpio-cells for %s\n",
|
pr_debug("%s: wrong #gpio-cells for %s\n",
|
||||||
np->full_name, gpio_np->full_name);
|
np->full_name, gpiospec.np->full_name);
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
@ -69,13 +64,13 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
|
||||||
if (flags)
|
if (flags)
|
||||||
*flags = 0;
|
*flags = 0;
|
||||||
|
|
||||||
ret = gc->of_xlate(gc, np, gpio_spec, flags);
|
ret = gc->of_xlate(gc, &gpiospec, flags);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err1;
|
goto err1;
|
||||||
|
|
||||||
ret += gc->base;
|
ret += gc->base;
|
||||||
err1:
|
err1:
|
||||||
of_node_put(gpio_np);
|
of_node_put(gpiospec.np);
|
||||||
err0:
|
err0:
|
||||||
pr_debug("%s exited with status %d\n", __func__, ret);
|
pr_debug("%s exited with status %d\n", __func__, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -105,8 +100,8 @@ unsigned int of_gpio_count(struct device_node *np)
|
||||||
do {
|
do {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells",
|
ret = of_parse_phandle_with_args(np, "gpios", "#gpio-cells",
|
||||||
cnt, NULL, NULL);
|
cnt, NULL);
|
||||||
/* A hole in the gpios = <> counts anyway. */
|
/* A hole in the gpios = <> counts anyway. */
|
||||||
if (ret < 0 && ret != -EEXIST)
|
if (ret < 0 && ret != -EEXIST)
|
||||||
break;
|
break;
|
||||||
|
@ -127,12 +122,9 @@ EXPORT_SYMBOL(of_gpio_count);
|
||||||
* gpio chips. This function performs only one sanity check: whether gpio
|
* gpio chips. This function performs only one sanity check: whether gpio
|
||||||
* is less than ngpios (that is specified in the gpio_chip).
|
* is less than ngpios (that is specified in the gpio_chip).
|
||||||
*/
|
*/
|
||||||
int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
|
int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||||
const void *gpio_spec, u32 *flags)
|
const struct of_phandle_args *gpiospec, u32 *flags)
|
||||||
{
|
{
|
||||||
const __be32 *gpio = gpio_spec;
|
|
||||||
const u32 n = be32_to_cpup(gpio);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We're discouraging gpio_cells < 2, since that way you'll have to
|
* We're discouraging gpio_cells < 2, since that way you'll have to
|
||||||
* write your own xlate function (that will have to retrive the GPIO
|
* write your own xlate function (that will have to retrive the GPIO
|
||||||
|
@ -144,13 +136,16 @@ int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n > gc->ngpio)
|
if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (gpiospec->args[0] > gc->ngpio)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (flags)
|
if (flags)
|
||||||
*flags = be32_to_cpu(gpio[1]);
|
*flags = gpiospec->args[1];
|
||||||
|
|
||||||
return n;
|
return gpiospec->args[0];
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(of_gpio_simple_xlate);
|
EXPORT_SYMBOL(of_gpio_simple_xlate);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
#ifdef CONFIG_GPIOLIB
|
#ifdef CONFIG_GPIOLIB
|
||||||
|
|
||||||
|
@ -128,8 +129,8 @@ struct gpio_chip {
|
||||||
*/
|
*/
|
||||||
struct device_node *of_node;
|
struct device_node *of_node;
|
||||||
int of_gpio_n_cells;
|
int of_gpio_n_cells;
|
||||||
int (*of_xlate)(struct gpio_chip *gc, struct device_node *np,
|
int (*of_xlate)(struct gpio_chip *gc,
|
||||||
const void *gpio_spec, u32 *flags);
|
const struct of_phandle_args *gpiospec, u32 *flags);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,13 @@ struct device_node {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define MAX_PHANDLE_ARGS 8
|
||||||
|
struct of_phandle_args {
|
||||||
|
struct device_node *np;
|
||||||
|
int args_count;
|
||||||
|
uint32_t args[MAX_PHANDLE_ARGS];
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
#ifdef CONFIG_OF
|
||||||
|
|
||||||
/* Pointer for first entry in chain of all nodes. */
|
/* Pointer for first entry in chain of all nodes. */
|
||||||
|
@ -230,9 +237,9 @@ extern int of_modalias_node(struct device_node *node, char *modalias, int len);
|
||||||
extern struct device_node *of_parse_phandle(struct device_node *np,
|
extern struct device_node *of_parse_phandle(struct device_node *np,
|
||||||
const char *phandle_name,
|
const char *phandle_name,
|
||||||
int index);
|
int index);
|
||||||
extern int of_parse_phandles_with_args(struct device_node *np,
|
extern int of_parse_phandle_with_args(struct device_node *np,
|
||||||
const char *list_name, const char *cells_name, int index,
|
const char *list_name, const char *cells_name, int index,
|
||||||
struct device_node **out_node, const void **out_args);
|
struct of_phandle_args *out_args);
|
||||||
|
|
||||||
extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
|
extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align));
|
||||||
extern int of_alias_get_id(struct device_node *np, const char *stem);
|
extern int of_alias_get_id(struct device_node *np, const char *stem);
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
struct device_node;
|
struct device_node;
|
||||||
|
|
||||||
|
@ -57,8 +58,9 @@ extern int of_mm_gpiochip_add(struct device_node *np,
|
||||||
extern void of_gpiochip_add(struct gpio_chip *gc);
|
extern void of_gpiochip_add(struct gpio_chip *gc);
|
||||||
extern void of_gpiochip_remove(struct gpio_chip *gc);
|
extern void of_gpiochip_remove(struct gpio_chip *gc);
|
||||||
extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np);
|
extern struct gpio_chip *of_node_to_gpiochip(struct device_node *np);
|
||||||
extern int of_gpio_simple_xlate(struct gpio_chip *gc, struct device_node *np,
|
extern int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||||
const void *gpio_spec, u32 *flags);
|
const struct of_phandle_args *gpiospec,
|
||||||
|
u32 *flags);
|
||||||
|
|
||||||
#else /* CONFIG_OF_GPIO */
|
#else /* CONFIG_OF_GPIO */
|
||||||
|
|
||||||
|
@ -75,8 +77,8 @@ static inline unsigned int of_gpio_count(struct device_node *np)
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
|
static inline int of_gpio_simple_xlate(struct gpio_chip *gc,
|
||||||
struct device_node *np,
|
const struct of_phandle_args *gpiospec,
|
||||||
const void *gpio_spec, u32 *flags)
|
u32 *flags)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue