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 <rruuaanng@outlook.com>
This commit is contained in:
parent
a782ec14bc
commit
4553a21fe5
3
doc/build/dts/api/api.rst
vendored
3
doc/build/dts/api/api.rst
vendored
@ -104,6 +104,9 @@ does not apply to macros which take cell names as arguments.
|
||||
For-each macros
|
||||
===============
|
||||
|
||||
The :c:macro:`DT_FOREACH_CHILD` macro allows iterating over the ancestor node
|
||||
of a devicetree node.
|
||||
|
||||
There is currently only one "generic" for-each macro,
|
||||
:c:macro:`DT_FOREACH_CHILD`, which allows iterating over the children of a
|
||||
devicetree node.
|
||||
|
||||
@ -2975,6 +2975,55 @@
|
||||
*/
|
||||
#define DT_FOREACH_STATUS_OKAY_NODE_VARGS(fn, ...) DT_FOREACH_OKAY_VARGS_HELPER(fn, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Invokes @p fn for each ancestor of @p node_id
|
||||
*
|
||||
* The macro @p fn must take one parameter, which will be the identifier
|
||||
* of a child node of @p node_id to enable traversal of all ancestor nodes.
|
||||
*
|
||||
* The ancestor will be iterated over in the same order as they
|
||||
* appear in the final devicetree.
|
||||
*
|
||||
* Example devicetree fragment:
|
||||
*
|
||||
* @code{.dts}
|
||||
* n: node1 {
|
||||
* foobar = "foo1";
|
||||
*
|
||||
* n_2: node2 {
|
||||
* foobar = "foo2";
|
||||
*
|
||||
* n_3: node3 {
|
||||
* foobar = "foo3";
|
||||
* };
|
||||
* };
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* @code{.c}
|
||||
* #define GET_PROP(n) DT_PROP(n, foobar),
|
||||
*
|
||||
* const char *ancestor_names[] = {
|
||||
* DT_FOREACH_ANCESTOR(DT_NODELABEL(n_3), GET_PROP)
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* This expands to:
|
||||
*
|
||||
* @code{.c}
|
||||
* const char *ancestor_names[] = {
|
||||
* "foo2", "foo1",
|
||||
* };
|
||||
* @endcode
|
||||
*
|
||||
* @param node_id node identifier
|
||||
* @param fn macro to invoke
|
||||
*/
|
||||
#define DT_FOREACH_ANCESTOR(node_id, fn) \
|
||||
DT_CAT(node_id, _FOREACH_ANCESTOR)(fn)
|
||||
|
||||
/**
|
||||
* @brief Invokes @p fn for each child of @p node_id
|
||||
*
|
||||
|
||||
@ -97,6 +97,7 @@ def main():
|
||||
out_dt_define(f"{node.z_path_id}_FOREACH_NODELABEL_VARGS(fn, ...)",
|
||||
" ".join(f"fn({nodelabel}, __VA_ARGS__)" for nodelabel in node.labels))
|
||||
|
||||
write_parent(node)
|
||||
write_children(node)
|
||||
write_dep_info(node)
|
||||
write_idents_and_existence(node)
|
||||
@ -457,6 +458,17 @@ def write_compatibles(node: edtlib.Node) -> None:
|
||||
out_dt_define(f"{node.z_path_id}_COMPAT_MODEL_IDX_{i}",
|
||||
quote_str(node.edt.compat2model[compat]))
|
||||
|
||||
def write_parent(node: edtlib.Node) -> None:
|
||||
# Visit all parent nodes.
|
||||
def _visit_parent_node(node: edtlib.Node):
|
||||
while node is not None:
|
||||
yield node.parent
|
||||
node = node.parent
|
||||
|
||||
# Writes helper macros for dealing with node's parent.
|
||||
out_dt_define(f"{node.z_path_id}_FOREACH_ANCESTOR(fn)",
|
||||
" ".join(f"fn(DT_{parent.z_path_id})" for parent in
|
||||
_visit_parent_node(node) if parent is not None))
|
||||
|
||||
def write_children(node: edtlib.Node) -> None:
|
||||
# Writes helper macros for dealing with node's children.
|
||||
|
||||
@ -635,6 +635,18 @@
|
||||
phys = <&test_transceiver1>;
|
||||
};
|
||||
|
||||
test_parent: test-parent {
|
||||
compatible = "vnd,parent-bindings";
|
||||
|
||||
test_parent_a: parent-a {
|
||||
val = <0>;
|
||||
|
||||
test_parent_b: parent-b {
|
||||
val = <0>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/* there should only be one of these */
|
||||
test_children: test-children {
|
||||
compatible = "vnd,child-bindings";
|
||||
|
||||
@ -2344,6 +2344,31 @@ ZTEST(devicetree_api, test_parent)
|
||||
TEST_SPI_BUS_0), "");
|
||||
}
|
||||
|
||||
#undef DT_DRV_COMPAT
|
||||
#define DT_DRV_COMPAT vnd_parent_bindings
|
||||
ZTEST(devicetree_api, test_parent_nodes_list)
|
||||
{
|
||||
/* When traversing upwards, there are no fixed attributes and labels */
|
||||
#define TEST_FUNC(parent) { /* No operation */ }
|
||||
#define TEST_FUNC_AND_COMMA(parent) TEST_FUNC(parent),
|
||||
|
||||
struct vnd_parent_binding {
|
||||
int val;
|
||||
};
|
||||
|
||||
struct vnd_parent_binding vals_a[] = {
|
||||
DT_FOREACH_ANCESTOR(DT_NODELABEL(test_parent_a), TEST_FUNC_AND_COMMA)};
|
||||
|
||||
struct vnd_parent_binding vals_b[] = {
|
||||
DT_FOREACH_ANCESTOR(DT_NODELABEL(test_parent_b), TEST_FUNC_AND_COMMA)};
|
||||
|
||||
zassert_equal(ARRAY_SIZE(vals_a), 3, "");
|
||||
zassert_equal(ARRAY_SIZE(vals_b), 4, "");
|
||||
|
||||
#undef TEST_FUNC_AND_COMMA
|
||||
#undef TEST_FUNC
|
||||
}
|
||||
|
||||
#undef DT_DRV_COMPAT
|
||||
#define DT_DRV_COMPAT vnd_i2c_mux_controller
|
||||
ZTEST(devicetree_api, test_gparent)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user