Skip to content

Commit 73e41ed

Browse files
committed
devicetree: Add DT_FOREACH_ANCESTOR macro
Add 'DT_FOREACH_ANCESTOR' macro to get a list of ancestor node of a given node_id. Signed-off-by: James Roy <[email protected]>
1 parent 2f23313 commit 73e41ed

File tree

5 files changed

+97
-0
lines changed

5 files changed

+97
-0
lines changed

doc/build/dts/api/api.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ does not apply to macros which take cell names as arguments.
104104
For-each macros
105105
===============
106106

107+
The :c:macro:`DT_FOREACH_CHILD` macro allows iterating over the ancestor node
108+
of a devicetree node.
109+
107110
There is currently only one "generic" for-each macro,
108111
:c:func:`DT_FOREACH_CHILD`, which allows iterating over the children of a
109112
devicetree node.

include/zephyr/devicetree.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2961,6 +2961,52 @@
29612961
*/
29622962
#define DT_FOREACH_STATUS_OKAY_NODE_VARGS(fn, ...) DT_FOREACH_OKAY_VARGS_HELPER(fn, __VA_ARGS__)
29632963

2964+
/**
2965+
* @brief Invokes @p fn for each ancestor of @p node_id
2966+
*
2967+
* The macro @p fn must take one argument which will be the identifier
2968+
* of an ancestor node to traverse from @p node_id towards the root node.
2969+
*
2970+
* Example devicetree fragment:
2971+
*
2972+
* @code{.dts}
2973+
* n: node1 {
2974+
* foobar = "foo1";
2975+
*
2976+
* n_2: node2 {
2977+
* foobar = "foo2";
2978+
*
2979+
* n_3: node3 {
2980+
* foobar = "foo3";
2981+
* };
2982+
* };
2983+
* };
2984+
* @endcode
2985+
*
2986+
* Example usage:
2987+
*
2988+
* @code{.c}
2989+
* #define GET_PROP(n) DT_PROP(n, foobar),
2990+
*
2991+
* const char *ancestor_names[] = {
2992+
* DT_FOREACH_ANCESTOR(DT_NODELABEL(n_3), GET_PROP)
2993+
* };
2994+
* @endcode
2995+
*
2996+
* This expands to:
2997+
*
2998+
* @code{.c}
2999+
* const char *ancestor_names[] = {
3000+
* "foo2", "foo1",
3001+
* };
3002+
* @endcode
3003+
*
3004+
* @param node_id node identifier
3005+
* @param fn macro to invoke
3006+
*/
3007+
#define DT_FOREACH_ANCESTOR(node_id, fn) \
3008+
DT_CAT(node_id, _FOREACH_ANCESTOR)(fn)
3009+
29643010
/**
29653011
* @brief Invokes @p fn for each child of @p node_id
29663012
*

scripts/dts/gen_defines.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,17 @@ def write_compatibles(node: edtlib.Node) -> None:
457457
out_dt_define(f"{node.z_path_id}_COMPAT_MODEL_IDX_{i}",
458458
quote_str(node.edt.compat2model[compat]))
459459

460+
def write_parent(node: edtlib.Node) -> None:
461+
# Visit all parent nodes.
462+
def _visit_parent_node(node: edtlib.Node):
463+
while node is not None:
464+
yield node.parent
465+
node = node.parent
466+
467+
# Writes helper macros for dealing with node's parent.
468+
out_dt_define(f"{node.z_path_id}_FOREACH_ANCESTOR(fn)",
469+
" ".join(f"fn(DT_{parent.z_path_id})" for parent in
470+
_visit_parent_node(node) if parent is not None))
460471

461472
def write_children(node: edtlib.Node) -> None:
462473
# Writes helper macros for dealing with node's children.

tests/lib/devicetree/api/app.overlay

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,18 @@
570570
phys = <&test_transceiver1>;
571571
};
572572

573+
test_parent: test-parent {
574+
compatible = "vnd,parent-bindings";
575+
576+
test_parent_a: parent-a {
577+
val = <0>;
578+
579+
test_parent_b: parent-b {
580+
val = <0>;
581+
};
582+
};
583+
};
584+
573585
/* there should only be one of these */
574586
test_children: test-children {
575587
compatible = "vnd,child-bindings";

tests/lib/devicetree/api/src/main.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,6 +2225,31 @@ ZTEST(devicetree_api, test_parent)
22252225
TEST_SPI_BUS_0), "");
22262226
}
22272227

2228+
#undef DT_DRV_COMPAT
2229+
#define DT_DRV_COMPAT vnd_parent_bindings
2230+
ZTEST(devicetree_api, test_parent_nodes_list)
2231+
{
2232+
/* When traversing upwards, there are no fixed attributes and labels */
2233+
#define TEST_FUNC(parent) { /* No operation */ }
2234+
#define TEST_FUNC_AND_COMMA(parent) TEST_FUNC(parent),
2235+
2236+
struct vnd_parent_binding {
2237+
int val;
2238+
};
2239+
2240+
struct vnd_parent_binding vals_a[] = {
2241+
DT_FOREACH_ANCESTOR(DT_NODELABEL(test_parent_a), TEST_FUNC_AND_COMMA)};
2242+
2243+
struct vnd_parent_binding vals_b[] = {
2244+
DT_FOREACH_ANCESTOR(DT_NODELABEL(test_parent_b), TEST_FUNC_AND_COMMA)};
2245+
2246+
zassert_equal(ARRAY_SIZE(vals_a), 3, "");
2247+
zassert_equal(ARRAY_SIZE(vals_b), 4, "");
2248+
2249+
#undef TEST_FUNC_AND_COMMA
2250+
#undef TEST_FUNC
2251+
}
2252+
22282253
#undef DT_DRV_COMPAT
22292254
#define DT_DRV_COMPAT vnd_i2c_mux_controller
22302255
ZTEST(devicetree_api, test_gparent)

0 commit comments

Comments
 (0)