Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Anton Vorontsov and committed by
Benjamin Herrenschmidt
64b60e09 302905a3

+131 -62
+109
drivers/of/base.c
··· 458 458 } 459 459 EXPORT_SYMBOL_GPL(of_modalias_node); 460 460 461 + /** 462 + * of_parse_phandles_with_args - Find a node pointed by phandle in a list 463 + * @np: pointer to a device tree node containing a list 464 + * @list_name: property name that contains a list 465 + * @cells_name: property name that specifies phandles' arguments count 466 + * @index: index of a phandle to parse out 467 + * @out_node: pointer to device_node struct pointer (will be filled) 468 + * @out_args: pointer to arguments pointer (will be filled) 469 + * 470 + * This function is useful to parse lists of phandles and their arguments. 471 + * Returns 0 on success and fills out_node and out_args, on error returns 472 + * appropriate errno value. 473 + * 474 + * Example: 475 + * 476 + * phandle1: node1 { 477 + * #list-cells = <2>; 478 + * } 479 + * 480 + * phandle2: node2 { 481 + * #list-cells = <1>; 482 + * } 483 + * 484 + * node3 { 485 + * list = <&phandle1 1 2 &phandle2 3>; 486 + * } 487 + * 488 + * To get a device_node of the `node2' node you may call this: 489 + * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args); 490 + */ 491 + int of_parse_phandles_with_args(struct device_node *np, const char *list_name, 492 + const char *cells_name, int index, 493 + struct device_node **out_node, 494 + const void **out_args) 495 + { 496 + int ret = -EINVAL; 497 + const u32 *list; 498 + const u32 *list_end; 499 + int size; 500 + int cur_index = 0; 501 + struct device_node *node = NULL; 502 + const void *args; 503 + 504 + list = of_get_property(np, list_name, &size); 505 + if (!list) { 506 + ret = -ENOENT; 507 + goto err0; 508 + } 509 + list_end = list + size / sizeof(*list); 510 + 511 + while (list < list_end) { 512 + const u32 *cells; 513 + const phandle *phandle; 514 + 515 + phandle = list; 516 + args = list + 1; 517 + 518 + /* one cell hole in the list = <>; */ 519 + if (!*phandle) { 520 + list++; 521 + goto next; 522 + } 523 + 524 + node = of_find_node_by_phandle(*phandle); 525 + if (!node) { 526 + pr_debug("%s: could not find phandle\n", 527 + np->full_name); 528 + goto err0; 529 + } 530 + 531 + cells = of_get_property(node, cells_name, &size); 532 + if (!cells || size != sizeof(*cells)) { 533 + pr_debug("%s: could not get %s for %s\n", 534 + np->full_name, cells_name, node->full_name); 535 + goto err1; 536 + } 537 + 538 + /* Next phandle is at offset of one phandle cell + #cells */ 539 + list += 1 + *cells; 540 + if (list > list_end) { 541 + pr_debug("%s: insufficient arguments length\n", 542 + np->full_name); 543 + goto err1; 544 + } 545 + next: 546 + if (cur_index == index) 547 + break; 548 + 549 + of_node_put(node); 550 + node = NULL; 551 + cur_index++; 552 + } 553 + 554 + if (!node) { 555 + ret = -ENOENT; 556 + goto err0; 557 + } 558 + 559 + *out_node = node; 560 + *out_args = args; 561 + 562 + return 0; 563 + err1: 564 + of_node_put(node); 565 + err0: 566 + pr_debug("%s failed with status %d\n", __func__, ret); 567 + return ret; 568 + } 569 + EXPORT_SYMBOL(of_parse_phandles_with_args);
+19 -62
drivers/of/gpio.c
··· 28 28 */ 29 29 int of_get_gpio(struct device_node *np, int index) 30 30 { 31 - int ret = -EINVAL; 31 + int ret; 32 32 struct device_node *gc; 33 33 struct of_gpio_chip *of_gc = NULL; 34 34 int size; 35 - const u32 *gpios; 36 - u32 nr_cells; 37 - int i; 38 35 const void *gpio_spec; 39 36 const u32 *gpio_cells; 40 - int gpio_index = 0; 41 37 42 - gpios = of_get_property(np, "gpios", &size); 43 - if (!gpios) { 44 - ret = -ENOENT; 38 + ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index, 39 + &gc, &gpio_spec); 40 + if (ret) { 41 + pr_debug("%s: can't parse gpios property\n", __func__); 45 42 goto err0; 46 43 } 47 - nr_cells = size / sizeof(u32); 48 44 49 - for (i = 0; i < nr_cells; gpio_index++) { 50 - const phandle *gpio_phandle; 51 - 52 - gpio_phandle = gpios + i; 53 - gpio_spec = gpio_phandle + 1; 54 - 55 - /* one cell hole in the gpios = <>; */ 56 - if (!*gpio_phandle) { 57 - if (gpio_index == index) 58 - return -ENOENT; 59 - i++; 60 - continue; 61 - } 62 - 63 - gc = of_find_node_by_phandle(*gpio_phandle); 64 - if (!gc) { 65 - pr_debug("%s: could not find phandle for gpios\n", 66 - np->full_name); 67 - goto err0; 68 - } 69 - 70 - of_gc = gc->data; 71 - if (!of_gc) { 72 - pr_debug("%s: gpio controller %s isn't registered\n", 73 - np->full_name, gc->full_name); 74 - goto err1; 75 - } 76 - 77 - gpio_cells = of_get_property(gc, "#gpio-cells", &size); 78 - if (!gpio_cells || size != sizeof(*gpio_cells) || 79 - *gpio_cells != of_gc->gpio_cells) { 80 - pr_debug("%s: wrong #gpio-cells for %s\n", 81 - np->full_name, gc->full_name); 82 - goto err1; 83 - } 84 - 85 - /* Next phandle is at phandle cells + #gpio-cells */ 86 - i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells; 87 - if (i >= nr_cells + 1) { 88 - pr_debug("%s: insufficient gpio-spec length\n", 89 - np->full_name); 90 - goto err1; 91 - } 92 - 93 - if (gpio_index == index) 94 - break; 95 - 96 - of_gc = NULL; 97 - of_node_put(gc); 98 - } 99 - 45 + of_gc = gc->data; 100 46 if (!of_gc) { 101 - ret = -ENOENT; 102 - goto err0; 47 + pr_debug("%s: gpio controller %s isn't registered\n", 48 + np->full_name, gc->full_name); 49 + ret = -ENODEV; 50 + goto err1; 51 + } 52 + 53 + gpio_cells = of_get_property(gc, "#gpio-cells", &size); 54 + if (!gpio_cells || size != sizeof(*gpio_cells) || 55 + *gpio_cells != of_gc->gpio_cells) { 56 + pr_debug("%s: wrong #gpio-cells for %s\n", 57 + np->full_name, gc->full_name); 58 + ret = -EINVAL; 59 + goto err1; 103 60 } 104 61 105 62 ret = of_gc->xlate(of_gc, np, gpio_spec);
+3
include/linux/of.h
··· 71 71 extern const struct of_device_id *of_match_node( 72 72 const struct of_device_id *matches, const struct device_node *node); 73 73 extern int of_modalias_node(struct device_node *node, char *modalias, int len); 74 + extern int of_parse_phandles_with_args(struct device_node *np, 75 + const char *list_name, const char *cells_name, int index, 76 + struct device_node **out_node, const void **out_args); 74 77 75 78 #endif /* _LINUX_OF_H */