Commit a3fae2f1 authored by Martí Bolívar's avatar Martí Bolívar Committed by Kumar Gala
Browse files

devicetree: add DT_COMPAT_ON_BUS()



And implement DT_ANY_INST_ON_BUS() in terms of it.

This makes some error messages quite a bit shorter by avoiding
UTIL_LISTIFY(), which has a nasty temper and tends to explode if not
treated gently.

Signed-off-by: default avatarMartí Bolívar <marti.bolivar@nordicsemi.no>
parent a5375ead
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -127,6 +127,12 @@ other-macro = %s"DT_N_" alternate-id
other-macro =/ %s"DT_N_INST_" dt-name %s"_NUM"
; E.g.: #define DT_CHOSEN_zephyr_flash
other-macro =/ %s"DT_CHOSEN_" dt-name
; Declares that a compatible has at least one node on a bus.
;
; Example:
;
;   #define DT_COMPAT_vnd_dev_BUS_spi 1
other-macro =/ %s"DT_COMPAT_" dt-name %s"_BUS_" dt-name

; --------------------------------------------------------------------
; alternate-id: another way to specify a node besides a path-id
+8 −0
Original line number Diff line number Diff line
# Copyright (c) 2020 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

description: GPIO expander via I2C

compatible: "vnd,gpio-expander"

include: i2c-device.yaml
+8 −0
Original line number Diff line number Diff line
# Copyright (c) 2020 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

description: GPIO expander via SPI

compatible: "vnd,gpio-expander"

include: spi-device.yaml
+27 −11
Original line number Diff line number Diff line
@@ -1036,6 +1036,31 @@
 */
#define DT_ON_BUS(node_id, bus) IS_ENABLED(DT_CAT(node_id, _BUS_##bus))

/**
 * @brief Test if any node of a compatible is on a bus of a given type
 *
 * Example devicetree overlay:
 *
 *     &i2c0 {
 *            temp: temperature-sensor@76 {
 *                     compatible = "vnd,some-sensor";
 *                     reg = <0x76>;
 *            };
 *     };
 *
 * Example usage, assuming "i2c0" is an I2C bus controller node, and
 * therefore "temp" is on an I2C bus:
 *
 *     DT_COMPAT_ON_BUS(vnd_some_sensor, i2c) // 1
 *
 * @param compat lowercase-and-underscores version of a compatible
 * @param bus a binding's bus type as a C token, lowercased and without quotes
 * @return 1 if any enabled node with that compatible is on that bus type,
 *         0 otherwise
 */
#define DT_COMPAT_ON_BUS(compat, bus) \
	IS_ENABLED(UTIL_CAT(DT_CAT(DT_COMPAT_, compat), _BUS_##bus))

/**
 * @}
 */
@@ -1319,17 +1344,10 @@
/**
 * @brief Test if any node with compatible DT_DRV_COMPAT is on a bus
 *
 * This is the same as logically ORing together DT_ON_BUS(node, bus)
 * for every enabled node which matches compatible DT_DRV_COMPAT.
 *
 * It can be useful, for instance, when writing device drivers for
 * hardware that supports multiple possible bus connections to the
 * SoC.
 *
 * This is equivalent to DT_COMPAT_ON_BUS(DT_DRV_COMPAT, bus).
 * @param bus a binding's bus type as a C token, lowercased and without quotes
 */
#define DT_ANY_INST_ON_BUS(bus) \
	(UTIL_LISTIFY(DT_NUM_INST(DT_DRV_COMPAT), DT_INST_ON_BUS_OR, bus) 0)
#define DT_ANY_INST_ON_BUS(bus) DT_COMPAT_ON_BUS(DT_DRV_COMPAT, bus)

/**
 * @def DT_INST_FOREACH
@@ -1445,8 +1463,6 @@
#define DT_DASH(...) MACRO_MAP_CAT(DT_DASH_PREFIX, __VA_ARGS__)
/** @internal helper for DT_DASH(): prepends _ to a name */
#define DT_DASH_PREFIX(name) _##name
/** @internal DT_ANY_INST_ON_BUS helper */
#define DT_INST_ON_BUS_OR(inst, bus) DT_ON_BUS(DT_DRV_INST(inst), bus) ||
/** @internal DT_INST_FOREACH helper */
#define DT_CALL_WITH_ARG(arg, expr) expr(arg);

+21 −17
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
# edtlib. This will keep this script simple.

import argparse
from collections import defaultdict
import os
import pathlib
import re
@@ -64,7 +65,7 @@ def main():
            write_vanilla_props(node)

        write_chosen(edt)
        write_inst_num(edt)
        write_global_compat_info(edt)


def parse_args():
@@ -510,26 +511,29 @@ def write_chosen(edt):
        out_define(macro, value, width=max_len)


def write_inst_num(edt):
    # Tree-wide information such as number of instances is printed here.
def write_global_compat_info(edt):
    # Tree-wide information related to each compatible, such as number
    # of instances, is printed here.

    out_comment("Number of instances\n")
    compat_list = []
    compat2numinst = {}
    compat2buses = defaultdict(list)
    for compat, enabled in edt.compat2enabled.items():
        compat2numinst[compat] = len(enabled)

    # Walk the nodes to build which compats we need to generate for
    for node in sorted(edt.nodes, key=lambda node: node.dep_ordinal):
        if not node.enabled:
            continue
        if not node.matching_compat:
            continue
        for compat in node.compats:
            if compat not in compat_list:
                compat_list.append(compat)
        for node in enabled:
            bus = node.on_bus
            if bus is not None and bus not in compat2buses[compat]:
                compat2buses[compat].append(bus)

    for compat in compat_list:
        num_inst = len(edt.compat2enabled[compat])
        out_define(f"DT_N_INST_{str2ident(compat)}_NUM", num_inst)
    out_comment("Number of enabled instances of each compatible\n")
    for compat, numinst in compat2numinst.items():
        out_define(f"DT_N_INST_{str2ident(compat)}_NUM", numinst)

    out_comment("Bus information for enabled nodes of each compatible\n")
    for compat, buses in compat2buses.items():
        for bus in buses:
            out_define(
                f"DT_COMPAT_{str2ident(compat)}_BUS_{str2ident(bus)}", 1)

def str2ident(s):
    # Converts 's' to a form suitable for (part of) an identifier
Loading