Skip to content

Commit a828012

Browse files
committed
devicetree: Add DT_CHILD_BY_UNIT_ADDR and DT_CHILD_BY_REG_ADDR
Allow fetching child node identifiers by unit/reg address. Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
1 parent 474d068 commit a828012

File tree

2 files changed

+127
-0
lines changed

2 files changed

+127
-0
lines changed

include/zephyr/devicetree.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,77 @@
435435
*/
436436
#define DT_CHILD(node_id, child) UTIL_CAT(node_id, DT_S_PREFIX(child))
437437

438+
/**
439+
* @brief Get a node identifier for a child node by a reg address
440+
*
441+
* Example devicetree fragment:
442+
*
443+
* @code{.dts}
444+
* / {
445+
* soc-label: soc {
446+
* serial1: serial@40001000 {
447+
* status = "okay";
448+
* current-speed = <115200>;
449+
* reg = <0x40001000 0x1000>;
450+
* ...
451+
* };
452+
* };
453+
* };
454+
* @endcode
455+
*
456+
* Example usage with DT_PROP() to get the status of the
457+
* `serial@40001000` node:
458+
*
459+
* @code{.c}
460+
* #define SOC_NODE DT_NODELABEL(soc_label)
461+
* DT_PROP(DT_CHILD_BY_REG_ADDR(SOC_NODE, 0, 0x40001000), status) // "okay"
462+
* @endcode
463+
*
464+
*
465+
* @param node_id node identifier
466+
* @param idx Register address index for the child node.
467+
* @param addr Register address for the child node. Can be hexadecimal (prefix with 0x) or decimal
468+
*
469+
* @return node identifier for the child node with the reg address at a specified index
470+
*/
471+
#define DT_CHILD_BY_REG_ADDR(node_id, idx, addr) \
472+
DT_CAT5(node_id, _CHILD_REG_IDX_, idx, _ADDR_, addr)
473+
474+
/**
475+
* @brief Get a node identifier for a child node by a unit address
476+
*
477+
* Example devicetree fragment:
478+
*
479+
* @code{.dts}
480+
* / {
481+
* soc-label: soc {
482+
* serial1: serial@40001000 {
483+
* status = "okay";
484+
* current-speed = <115200>;
485+
* reg = <0x40001000 0x1000>;
486+
* ...
487+
* };
488+
* };
489+
* };
490+
* @endcode
491+
*
492+
* Example usage with DT_PROP() to get the status of the
493+
* `serial@40001000` node:
494+
*
495+
* @code{.c}
496+
* #define SOC_NODE DT_NODELABEL(soc_label)
497+
* DT_PROP(DT_CHILD_BY_UNIT_ADDR(SOC_NODE, 0x40001000), status) // "okay"
498+
* @endcode
499+
*
500+
*
501+
* @param node_id node identifier
502+
* @param addr Unit address for the child node. Can be hexadecimal (prefix with 0x) or decimal
503+
*
504+
* @return node identifier for the child node with the reg address at a specified index
505+
*/
506+
#define DT_CHILD_BY_UNIT_ADDR(node_id, addr) \
507+
DT_CAT3(node_id, _CHILD_UNIT_ADDR_, addr)
508+
438509
/**
439510
* @brief Get a node identifier for a status `okay` node with a compatible
440511
*
@@ -4066,6 +4137,33 @@
40664137
#define DT_INST_CHILD(inst, child) \
40674138
DT_CHILD(DT_DRV_INST(inst), child)
40684139

4140+
/**
4141+
* @brief Get a node identifier for a child node by a reg address of DT_DRV_INST(inst)
4142+
*
4143+
* @param inst instance number
4144+
* @param idx Register address index for the child node.
4145+
* @param addr Register address for the child node. Can be hexadecimal (prefix with 0x) or decimal
4146+
*
4147+
* @return node identifier for the child node with the reg address at a specified index
4148+
*
4149+
* @see DT_CHILD_BY_REG_ADDR
4150+
*/
4151+
#define DT_INST_CHILD_BY_REG_ADDR(inst, idx, addr) \
4152+
DT_CHILD_BY_REG_ADDR(DT_DRV_INST(inst), idx, addr)
4153+
4154+
/**
4155+
* @brief Get a node identifier for a child node by a unit address of DT_DRV_INST(inst)
4156+
*
4157+
* @param inst instance number
4158+
* @param addr Unit address for the child node. Can be hexadecimal (prefix with 0x) or decimal
4159+
*
4160+
* @return node identifier for the child node with the reg address at a specified index
4161+
*
4162+
* @see DT_CHILD_BY_UNIT_ADDR
4163+
*/
4164+
#define DT_INST_CHILD_BY_UNIT_ADDR(inst, addr) \
4165+
DT_CHILD_BY_UNIT_ADDR(DT_DRV_INST(inst), addr)
4166+
40694167
/**
40704168
* @brief Get the number of child nodes of a given node
40714169
*

scripts/dts/gen_defines.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,35 @@ def write_children(node: edtlib.Node) -> None:
484484

485485
out_dt_define(f"{node.z_path_id}_CHILD_NUM_STATUS_OKAY", ok_nodes_num)
486486

487+
child_reg_addrs = {}
488+
for child in node.children.values():
489+
if child.unit_addr is not None:
490+
child_reg_addrs.setdefault((-1, child.unit_addr), []).append(child)
491+
# Provide a way to query child nodes
492+
for idx, reg in enumerate(child.regs):
493+
if reg.addr is not None:
494+
child_reg_addrs.setdefault((idx, reg.addr), []).append(child)
495+
496+
for (idx, addr), children in child_reg_addrs.items():
497+
if len(children) != 1:
498+
# Duplicate addresses for different children, skip
499+
continue
500+
501+
# Decimal and hexadecimal variants
502+
if idx == -1:
503+
out_dt_define(f"{node.z_path_id}_CHILD_UNIT_ADDR_{addr}", f"DT_{children[0].z_path_id}")
504+
out_dt_define(
505+
f"{node.z_path_id}_CHILD_UNIT_ADDR_{hex(addr)}", f"DT_{children[0].z_path_id}"
506+
)
507+
else:
508+
out_dt_define(
509+
f"{node.z_path_id}_CHILD_REG_IDX_{idx}_ADDR_{addr}", f"DT_{children[0].z_path_id}"
510+
)
511+
out_dt_define(
512+
f"{node.z_path_id}_CHILD_REG_IDX_{idx}_ADDR_{hex(addr)}",
513+
f"DT_{children[0].z_path_id}"
514+
)
515+
487516
out_dt_define(f"{node.z_path_id}_FOREACH_CHILD(fn)",
488517
" ".join(f"fn(DT_{child.z_path_id})" for child in
489518
node.children.values()))

0 commit comments

Comments
 (0)