mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
of: Add new helper of_parse_phandles_with_args()
The helper is factored out of of_get_gpio(). Will be used by the QE pin multiplexing functions (they need to parse the gpios = <> too). Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
parent
302905a347
commit
64b60e096f
3 changed files with 131 additions and 62 deletions
|
@ -458,3 +458,112 @@ int of_modalias_node(struct device_node *node, char *modalias, int len)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(of_modalias_node);
|
EXPORT_SYMBOL_GPL(of_modalias_node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* of_parse_phandles_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: pointer to device_node struct pointer (will be filled)
|
||||||
|
* @out_args: pointer to arguments pointer (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.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* phandle1: node1 {
|
||||||
|
* #list-cells = <2>;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* phandle2: node2 {
|
||||||
|
* #list-cells = <1>;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* node3 {
|
||||||
|
* list = <&phandle1 1 2 &phandle2 3>;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* 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);
|
||||||
|
*/
|
||||||
|
int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
|
||||||
|
const char *cells_name, int index,
|
||||||
|
struct device_node **out_node,
|
||||||
|
const void **out_args)
|
||||||
|
{
|
||||||
|
int ret = -EINVAL;
|
||||||
|
const u32 *list;
|
||||||
|
const u32 *list_end;
|
||||||
|
int size;
|
||||||
|
int cur_index = 0;
|
||||||
|
struct device_node *node = NULL;
|
||||||
|
const void *args;
|
||||||
|
|
||||||
|
list = of_get_property(np, list_name, &size);
|
||||||
|
if (!list) {
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
list_end = list + size / sizeof(*list);
|
||||||
|
|
||||||
|
while (list < list_end) {
|
||||||
|
const u32 *cells;
|
||||||
|
const phandle *phandle;
|
||||||
|
|
||||||
|
phandle = list;
|
||||||
|
args = list + 1;
|
||||||
|
|
||||||
|
/* one cell hole in the list = <>; */
|
||||||
|
if (!*phandle) {
|
||||||
|
list++;
|
||||||
|
goto next;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = of_find_node_by_phandle(*phandle);
|
||||||
|
if (!node) {
|
||||||
|
pr_debug("%s: could not find phandle\n",
|
||||||
|
np->full_name);
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next phandle is at offset of one phandle cell + #cells */
|
||||||
|
list += 1 + *cells;
|
||||||
|
if (list > list_end) {
|
||||||
|
pr_debug("%s: insufficient arguments length\n",
|
||||||
|
np->full_name);
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
next:
|
||||||
|
if (cur_index == index)
|
||||||
|
break;
|
||||||
|
|
||||||
|
of_node_put(node);
|
||||||
|
node = NULL;
|
||||||
|
cur_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node) {
|
||||||
|
ret = -ENOENT;
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_node = node;
|
||||||
|
*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);
|
||||||
|
|
|
@ -28,78 +28,35 @@
|
||||||
*/
|
*/
|
||||||
int of_get_gpio(struct device_node *np, int index)
|
int of_get_gpio(struct device_node *np, int index)
|
||||||
{
|
{
|
||||||
int ret = -EINVAL;
|
int ret;
|
||||||
struct device_node *gc;
|
struct device_node *gc;
|
||||||
struct of_gpio_chip *of_gc = NULL;
|
struct of_gpio_chip *of_gc = NULL;
|
||||||
int size;
|
int size;
|
||||||
const u32 *gpios;
|
|
||||||
u32 nr_cells;
|
|
||||||
int i;
|
|
||||||
const void *gpio_spec;
|
const void *gpio_spec;
|
||||||
const u32 *gpio_cells;
|
const u32 *gpio_cells;
|
||||||
int gpio_index = 0;
|
|
||||||
|
|
||||||
gpios = of_get_property(np, "gpios", &size);
|
ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
|
||||||
if (!gpios) {
|
&gc, &gpio_spec);
|
||||||
ret = -ENOENT;
|
if (ret) {
|
||||||
|
pr_debug("%s: can't parse gpios property\n", __func__);
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
nr_cells = size / sizeof(u32);
|
|
||||||
|
|
||||||
for (i = 0; i < nr_cells; gpio_index++) {
|
|
||||||
const phandle *gpio_phandle;
|
|
||||||
|
|
||||||
gpio_phandle = gpios + i;
|
|
||||||
gpio_spec = gpio_phandle + 1;
|
|
||||||
|
|
||||||
/* one cell hole in the gpios = <>; */
|
|
||||||
if (!*gpio_phandle) {
|
|
||||||
if (gpio_index == index)
|
|
||||||
return -ENOENT;
|
|
||||||
i++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
gc = of_find_node_by_phandle(*gpio_phandle);
|
|
||||||
if (!gc) {
|
|
||||||
pr_debug("%s: could not find phandle for gpios\n",
|
|
||||||
np->full_name);
|
|
||||||
goto err0;
|
|
||||||
}
|
|
||||||
|
|
||||||
of_gc = gc->data;
|
|
||||||
if (!of_gc) {
|
|
||||||
pr_debug("%s: gpio controller %s isn't registered\n",
|
|
||||||
np->full_name, gc->full_name);
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpio_cells = of_get_property(gc, "#gpio-cells", &size);
|
|
||||||
if (!gpio_cells || size != sizeof(*gpio_cells) ||
|
|
||||||
*gpio_cells != of_gc->gpio_cells) {
|
|
||||||
pr_debug("%s: wrong #gpio-cells for %s\n",
|
|
||||||
np->full_name, gc->full_name);
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Next phandle is at phandle cells + #gpio-cells */
|
|
||||||
i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells;
|
|
||||||
if (i >= nr_cells + 1) {
|
|
||||||
pr_debug("%s: insufficient gpio-spec length\n",
|
|
||||||
np->full_name);
|
|
||||||
goto err1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gpio_index == index)
|
|
||||||
break;
|
|
||||||
|
|
||||||
of_gc = NULL;
|
|
||||||
of_node_put(gc);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
of_gc = gc->data;
|
||||||
if (!of_gc) {
|
if (!of_gc) {
|
||||||
ret = -ENOENT;
|
pr_debug("%s: gpio controller %s isn't registered\n",
|
||||||
goto err0;
|
np->full_name, gc->full_name);
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
gpio_cells = of_get_property(gc, "#gpio-cells", &size);
|
||||||
|
if (!gpio_cells || size != sizeof(*gpio_cells) ||
|
||||||
|
*gpio_cells != of_gc->gpio_cells) {
|
||||||
|
pr_debug("%s: wrong #gpio-cells for %s\n",
|
||||||
|
np->full_name, gc->full_name);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = of_gc->xlate(of_gc, np, gpio_spec);
|
ret = of_gc->xlate(of_gc, np, gpio_spec);
|
||||||
|
|
|
@ -71,5 +71,8 @@ extern int of_n_size_cells(struct device_node *np);
|
||||||
extern const struct of_device_id *of_match_node(
|
extern const struct of_device_id *of_match_node(
|
||||||
const struct of_device_id *matches, const struct device_node *node);
|
const struct of_device_id *matches, const struct device_node *node);
|
||||||
extern int of_modalias_node(struct device_node *node, char *modalias, int len);
|
extern int of_modalias_node(struct device_node *node, char *modalias, int len);
|
||||||
|
extern 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);
|
||||||
|
|
||||||
#endif /* _LINUX_OF_H */
|
#endif /* _LINUX_OF_H */
|
||||||
|
|
Loading…
Reference in a new issue