Skip to content

Commit 4553a21

Browse files
rruuaanngkartben
authored andcommitted
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 a782ec1 commit 4553a21

File tree

5 files changed

+101
-0
lines changed

5 files changed

+101
-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:macro:`DT_FOREACH_CHILD`, which allows iterating over the children of a
109112
devicetree node.

include/zephyr/devicetree.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2975,6 +2975,55 @@
29752975
*/
29762976
#define DT_FOREACH_STATUS_OKAY_NODE_VARGS(fn, ...) DT_FOREACH_OKAY_VARGS_HELPER(fn, __VA_ARGS__)
29772977

2978+
/**
2979+
* @brief Invokes @p fn for each ancestor of @p node_id
2980+
*
2981+
* The macro @p fn must take one parameter, which will be the identifier
2982+
* of a child node of @p node_id to enable traversal of all ancestor nodes.
2983+
*
2984+
* The ancestor will be iterated over in the same order as they
2985+
* appear in the final devicetree.
2986+
*
2987+
* Example devicetree fragment:
2988+
*
2989+
* @code{.dts}
2990+
* n: node1 {
2991+
* foobar = "foo1";
2992+
*
2993+
* n_2: node2 {
2994+
* foobar = "foo2";
2995+
*
2996+
* n_3: node3 {
2997+
* foobar = "foo3";
2998+
* };
2999+
* };
3000+
* };
3001+
* @endcode
3002+
*
3003+
* Example usage:
3004+
*
3005+
* @code{.c}
3006+
* #define GET_PROP(n) DT_PROP(n, foobar),
3007+
*
3008+
* const char *ancestor_names[] = {
3009+
* DT_FOREACH_ANCESTOR(DT_NODELABEL(n_3), GET_PROP)
3010+
* };
3011+
* @endcode
3012+
*
3013+
* This expands to:
3014+
*
3015+
* @code{.c}
3016+
* const char *ancestor_names[] = {
3017+
* "foo2", "foo1",
3018+
* };
3019+
* @endcode
3020+
*
3021+
* @param node_id node identifier
3022+
* @param fn macro to invoke
3023+
*/
3024+
#define DT_FOREACH_ANCESTOR(node_id, fn) \
3025+
DT_CAT(node_id, _FOREACH_ANCESTOR)(fn)
3026+
29783027
/**
29793028
* @brief Invokes @p fn for each child of @p node_id
29803029
*

scripts/dts/gen_defines.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ def main():
9797
out_dt_define(f"{node.z_path_id}_FOREACH_NODELABEL_VARGS(fn, ...)",
9898
" ".join(f"fn({nodelabel}, __VA_ARGS__)" for nodelabel in node.labels))
9999

100+
write_parent(node)
100101
write_children(node)
101102
write_dep_info(node)
102103
write_idents_and_existence(node)
@@ -457,6 +458,17 @@ def write_compatibles(node: edtlib.Node) -> None:
457458
out_dt_define(f"{node.z_path_id}_COMPAT_MODEL_IDX_{i}",
458459
quote_str(node.edt.compat2model[compat]))
459460

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

461473
def write_children(node: edtlib.Node) -> None:
462474
# 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
@@ -635,6 +635,18 @@
635635
phys = <&test_transceiver1>;
636636
};
637637

638+
test_parent: test-parent {
639+
compatible = "vnd,parent-bindings";
640+
641+
test_parent_a: parent-a {
642+
val = <0>;
643+
644+
test_parent_b: parent-b {
645+
val = <0>;
646+
};
647+
};
648+
};
649+
638650
/* there should only be one of these */
639651
test_children: test-children {
640652
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
@@ -2344,6 +2344,31 @@ ZTEST(devicetree_api, test_parent)
23442344
TEST_SPI_BUS_0), "");
23452345
}
23462346

2347+
#undef DT_DRV_COMPAT
2348+
#define DT_DRV_COMPAT vnd_parent_bindings
2349+
ZTEST(devicetree_api, test_parent_nodes_list)
2350+
{
2351+
/* When traversing upwards, there are no fixed attributes and labels */
2352+
#define TEST_FUNC(parent) { /* No operation */ }
2353+
#define TEST_FUNC_AND_COMMA(parent) TEST_FUNC(parent),
2354+
2355+
struct vnd_parent_binding {
2356+
int val;
2357+
};
2358+
2359+
struct vnd_parent_binding vals_a[] = {
2360+
DT_FOREACH_ANCESTOR(DT_NODELABEL(test_parent_a), TEST_FUNC_AND_COMMA)};
2361+
2362+
struct vnd_parent_binding vals_b[] = {
2363+
DT_FOREACH_ANCESTOR(DT_NODELABEL(test_parent_b), TEST_FUNC_AND_COMMA)};
2364+
2365+
zassert_equal(ARRAY_SIZE(vals_a), 3, "");
2366+
zassert_equal(ARRAY_SIZE(vals_b), 4, "");
2367+
2368+
#undef TEST_FUNC_AND_COMMA
2369+
#undef TEST_FUNC
2370+
}
2371+
23472372
#undef DT_DRV_COMPAT
23482373
#define DT_DRV_COMPAT vnd_i2c_mux_controller
23492374
ZTEST(devicetree_api, test_gparent)

0 commit comments

Comments
 (0)