devicetree: Add DT_FOREACH_CHILD_STATUS_OKAY macro

The macro only iterates the enabled child nodes and invokes
provided macro for each node.

Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
diff --git a/doc/guides/dts/macros.bnf b/doc/guides/dts/macros.bnf
index 6211198..838cba0 100644
--- a/doc/guides/dts/macros.bnf
+++ b/doc/guides/dts/macros.bnf
@@ -51,6 +51,9 @@
 ; These are used internally by DT_FOREACH_CHILD, which iterates over
 ; each child node.
 node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD"
+; These are used internally by DT_FOREACH_CHILD_STATUS_OKAY, which iterates
+; over each child node with status "okay".
+node-macro =/ %s"DT_N" path-id %s"_FOREACH_CHILD_STATUS_OKAY"
 ; The node's status macro; dt-name in this case is something like "okay"
 ; or "disabled".
 node-macro =/ %s"DT_N" path-id %s"_STATUS_" dt-name
diff --git a/include/devicetree.h b/include/devicetree.h
index c65546b..ba94826 100644
--- a/include/devicetree.h
+++ b/include/devicetree.h
@@ -1486,6 +1486,21 @@
 	DT_CAT(node_id, _FOREACH_CHILD)(fn)
 
 /**
+ * @brief Call "fn" on the child nodes with status "okay"
+ *
+ * The macro "fn" should take one argument, which is the node
+ * identifier for the child node.
+ *
+ * As usual, both a missing status and an "ok" status are
+ * treated as "okay".
+ *
+ * @param node_id node identifier
+ * @param fn macro to invoke
+ */
+#define DT_FOREACH_CHILD_STATUS_OKAY(node_id, fn) \
+	DT_CAT(node_id, _FOREACH_CHILD_STATUS_OKAY)(fn)
+
+/**
  * @brief Invokes "fn" for each element in the value of property "prop".
  *
  * The macro "fn" must take three parameters: fn(node_id, prop, idx).
diff --git a/scripts/dts/gen_defines.py b/scripts/dts/gen_defines.py
index 6ddde90..5ce8417 100755
--- a/scripts/dts/gen_defines.py
+++ b/scripts/dts/gen_defines.py
@@ -119,6 +119,7 @@
                               f"DT_{node.parent.z_path_id}")
 
             write_child_functions(node)
+            write_child_functions_status_okay(node)
             write_dep_info(node)
             write_idents_and_existence(node)
             write_bus(node)
@@ -479,6 +480,18 @@
                 node.children.values()))
 
 
+def write_child_functions_status_okay(node):
+    # Writes macro that are helpers that will call a macro/function
+    # for each child node with status "okay".
+
+    functions = ''
+    for child in node.children.values():
+        if child.status == "okay":
+            functions = functions + f"fn(DT_{child.z_path_id}) "
+
+    out_dt_define(f"{node.z_path_id}_FOREACH_CHILD_STATUS_OKAY(fn)", functions)
+
+
 def write_status(node):
     out_dt_define(f"{node.z_path_id}_STATUS_{str2ident(node.status)}", 1)
 
diff --git a/tests/lib/devicetree/api/app.overlay b/tests/lib/devicetree/api/app.overlay
index f5ad07d..61560df 100644
--- a/tests/lib/devicetree/api/app.overlay
+++ b/tests/lib/devicetree/api/app.overlay
@@ -386,12 +386,15 @@
 
 			test_child_a: child-a {
 				val = <0>;
+				status = "okay";
 			};
 			test_child_b: child-b {
 				val = <1>;
+				status = "okay";
 			};
 			test_child_c: child-c {
 				val = <2>;
+				status = "disabled";
 			};
 		};
 
diff --git a/tests/lib/devicetree/api/src/main.c b/tests/lib/devicetree/api/src/main.c
index 22ed662..db61051 100644
--- a/tests/lib/devicetree/api/src/main.c
+++ b/tests/lib/devicetree/api/src/main.c
@@ -1568,8 +1568,13 @@
 		DT_INST_FOREACH_CHILD(0, TEST_FUNC)
 	};
 
+	struct vnd_child_binding vals_status_okay[] = {
+		DT_FOREACH_CHILD_STATUS_OKAY(TEST_PARENT, TEST_FUNC)
+	};
+
 	zassert_equal(ARRAY_SIZE(vals), 3, "");
 	zassert_equal(ARRAY_SIZE(vals_inst), 3, "");
+	zassert_equal(ARRAY_SIZE(vals_status_okay), 2, "");
 
 	zassert_false(strlen(STRINGIFY(TEST_PARENT)) == 0, "");
 
@@ -1579,6 +1584,8 @@
 	zassert_equal(vals_inst[0].val, 0, "");
 	zassert_equal(vals_inst[1].val, 1, "");
 	zassert_equal(vals_inst[2].val, 2, "");
+	zassert_equal(vals_status_okay[0].val, 0, "");
+	zassert_equal(vals_status_okay[1].val, 1, "");
 
 	#undef TEST_PARENT
 	#undef TEST_FUNC