devicetree: introduce DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY

Add a new macro, DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY
name, evaluates to 1 if any enabled instance of `compat` has the
property or to zero if it hasn't.

This macro can be useful in drivers for a family of devices.

Signed-off-by: Efrain Calderon <efrain.calderon.estrada@gmail.com>
This commit is contained in:
Efrain Calderon 2023-06-22 01:55:51 +02:00 committed by Carles Cufí
commit ce9bf1071e
2 changed files with 99 additions and 5 deletions

View file

@ -3201,7 +3201,7 @@
*/ */
#define DT_FOREACH_STATUS_OKAY(compat, fn) \ #define DT_FOREACH_STATUS_OKAY(compat, fn) \
COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat), \ COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat), \
(DT_CAT(DT_FOREACH_OKAY_, compat)(fn)), \ (UTIL_CAT(DT_FOREACH_OKAY_, compat)(fn)), \
()) ())
/** /**
@ -3254,6 +3254,25 @@
compat)(fn, __VA_ARGS__)), \ compat)(fn, __VA_ARGS__)), \
()) ())
/**
* @brief Call @p fn on all nodes with compatible `compat`
* and status `okay` with multiple arguments
*
*
* @param compat lowercase-and-underscores devicetree compatible
* @param fn Macro to call for each enabled node. Must accept a
* devicetree compatible and instance number.
* @param ... Additional arguments to pass to @p fn
*
* @see DT_INST_FOREACH_STATUS_OKAY_VARGS
*/
#define DT_COMPAT_FOREACH_STATUS_OKAY_VARGS(compat, fn, ...) \
COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat), \
(UTIL_CAT(DT_FOREACH_OKAY_INST_VARGS_, \
compat)(fn, compat, __VA_ARGS__)), \
())
/** /**
* @brief Invokes @p fn for each node label of a given node * @brief Invokes @p fn for each node label of a given node
* *
@ -4459,6 +4478,52 @@
#define DT_ANY_INST_HAS_PROP_STATUS_OKAY(prop) \ #define DT_ANY_INST_HAS_PROP_STATUS_OKAY(prop) \
COND_CODE_1(IS_EMPTY(DT_ANY_INST_HAS_PROP_STATUS_OKAY_(prop)), (0), (1)) COND_CODE_1(IS_EMPTY(DT_ANY_INST_HAS_PROP_STATUS_OKAY_(prop)), (0), (1))
/**
* @brief Check if any device node with status `okay` has a given
* property.
*
* @param prop lowercase-and-underscores property name
*
* Example devicetree overlay:
*
* @code{.dts}
* &i2c0 {
* sensor0: sensor@0 {
* compatible = "vnd,some-sensor";
* status = "okay";
* reg = <0>;
* foo = <1>;
* bar = <2>;
* };
*
* sensor1: sensor@1 {
* compatible = "vnd,some-sensor";
* status = "okay";
* reg = <1>;
* foo = <2>;
* };
*
* sensor2: sensor@2 {
* compatible = "vnd,some-sensor";
* status = "disabled";
* reg = <2>;
* baz = <1>;
* };
* };
* @endcode
*
* Example usage:
*
* @code{.c}
*
* DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(vnd_some_sensor, foo) // 1
* DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(vnd_some_sensor, bar) // 1
* DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(vnd_some_sensor, baz) // 0
* @endcode
*/
#define DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(compat, prop) \
(DT_COMPAT_FOREACH_STATUS_OKAY_VARGS(compat, DT_COMPAT_NODE_HAS_PROP_AND_OR, prop) 0)
/** /**
* @brief Call @p fn on all nodes with compatible `DT_DRV_COMPAT` * @brief Call @p fn on all nodes with compatible `DT_DRV_COMPAT`
* and status `okay` * and status `okay`
@ -4536,15 +4601,16 @@
* *
* *
* @param fn Macro to call for each enabled node. Must accept an * @param fn Macro to call for each enabled node. Must accept an
* instance number as its only parameter. * instance number.
* @param ... variable number of arguments to pass to @p fn * @param ... variable number of arguments to pass to @p fn
* *
* @see DT_INST_FOREACH_STATUS_OKAY * @see DT_INST_FOREACH_STATUS_OKAY
* @see DT_COMPAT_FOREACH_STATUS_OKAY_VARGS
*/ */
#define DT_INST_FOREACH_STATUS_OKAY_VARGS(fn, ...) \ #define DT_INST_FOREACH_STATUS_OKAY_VARGS(fn, ...) \
COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT), \ COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT), \
(UTIL_CAT(DT_FOREACH_OKAY_INST_VARGS_, \ (UTIL_CAT(DT_FOREACH_OKAY_INST_VARGS_, \
DT_DRV_COMPAT)(fn, __VA_ARGS__)), \ DT_DRV_COMPAT)(fn, __VA_ARGS__)), \
()) ())
/** /**
@ -4806,6 +4872,12 @@
#define DT_NODE_HAS_STATUS_INTERNAL(node_id, status) \ #define DT_NODE_HAS_STATUS_INTERNAL(node_id, status) \
IS_ENABLED(DT_CAT3(node_id, _STATUS_, status)) IS_ENABLED(DT_CAT3(node_id, _STATUS_, status))
/** @brief Helper macro to OR multiple has property checks in a loop macro
* (for the specified device)
*/
#define DT_COMPAT_NODE_HAS_PROP_AND_OR(inst, compat, prop) \
DT_NODE_HAS_PROP(DT_INST(inst, compat), prop) ||
/** /**
* @def DT_U64_C * @def DT_U64_C
* @brief Macro to add ULL postfix to the devicetree address constants * @brief Macro to add ULL postfix to the devicetree address constants

View file

@ -211,6 +211,16 @@ ZTEST(devicetree_api, test_any_inst_prop)
1, ""); 1, "");
} }
#undef DT_DRV_COMPAT
ZTEST(devicetree_api, test_any_compat_inst_prop)
{
zassert_equal(DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(vnd_device_with_props, foo), 1, "");
zassert_equal(DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(vnd_device_with_props, bar), 1, "");
zassert_equal(DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(vnd_device_with_props, baz), 0, "");
zassert_equal(DT_ANY_COMPAT_HAS_PROP_STATUS_OKAY(vnd_device_with_props, does_not_exist),
0, "");
}
ZTEST(devicetree_api, test_default_prop_access) ZTEST(devicetree_api, test_default_prop_access)
{ {
/* /*
@ -1595,6 +1605,18 @@ ZTEST(devicetree_api, test_foreach_status_okay)
val = DT_FOREACH_STATUS_OKAY_VARGS(vnd_enum_holder, MY_FN, +) 3; val = DT_FOREACH_STATUS_OKAY_VARGS(vnd_enum_holder, MY_FN, +) 3;
zassert_equal(val, 5, ""); zassert_equal(val, 5, "");
#undef MY_FN
#define MY_FN(inst, compat, operator) DT_ENUM_IDX(DT_INST(inst, compat), val) operator
/* This should expand to something like:
*
* 0 + 2 + 3
*
* and order of expansion doesn't matter, since we're adding
* the values all up.
*/
val = DT_COMPAT_FOREACH_STATUS_OKAY_VARGS(vnd_enum_holder, MY_FN, +) 3;
zassert_equal(val, 5, "");
/* /*
* Make sure DT_INST_FOREACH_STATUS_OKAY can be called from functions * Make sure DT_INST_FOREACH_STATUS_OKAY can be called from functions
* using macros with side effects in the current scope. * using macros with side effects in the current scope.