LCOV - code coverage report
Current view: top level - zephyr/drivers - emul.h Coverage Total Hit
Test: new.info Lines: 61.8 % 34 21
Test Date: 2025-09-05 20:47:19

            Line data    Source code
       1            0 : /*
       2              :  * Copyright (c) 2020 Nordic Semiconductor ASA
       3              :  * Copyright 2020 Google LLC
       4              :  *
       5              :  * SPDX-License-Identifier: Apache-2.0
       6              :  */
       7              : 
       8              : #ifndef ZEPHYR_INCLUDE_DRIVERS_EMUL_H_
       9              : #define ZEPHYR_INCLUDE_DRIVERS_EMUL_H_
      10              : 
      11              : /**
      12              :  * @brief Emulators used to test drivers and higher-level code that uses them
      13              :  * @defgroup io_emulators Emulator interfaces
      14              :  * @ingroup testing
      15              :  * @{
      16              :  */
      17              : 
      18              : #ifdef __cplusplus
      19              : extern "C" {
      20              : #endif /* __cplusplus */
      21              : 
      22              : struct emul;
      23              : 
      24              : /* #includes required after forward-declaration of struct emul later defined in this header. */
      25              : #include <zephyr/device.h>
      26              : #include <zephyr/devicetree.h>
      27              : #include <zephyr/drivers/espi_emul.h>
      28              : #include <zephyr/drivers/i2c_emul.h>
      29              : #include <zephyr/drivers/spi_emul.h>
      30              : #include <zephyr/drivers/mspi_emul.h>
      31              : #include <zephyr/drivers/uart_emul.h>
      32              : #include <zephyr/sys/iterable_sections.h>
      33              : 
      34              : /**
      35              :  * The types of supported buses.
      36              :  */
      37            0 : enum emul_bus_type {
      38              :         EMUL_BUS_TYPE_I2C,
      39              :         EMUL_BUS_TYPE_ESPI,
      40              :         EMUL_BUS_TYPE_SPI,
      41              :         EMUL_BUS_TYPE_MSPI,
      42              :         EMUL_BUS_TYPE_UART,
      43              :         EMUL_BUS_TYPE_NONE,
      44              : };
      45              : 
      46              : /**
      47              :  * Structure uniquely identifying a device to be emulated
      48              :  */
      49            1 : struct emul_link_for_bus {
      50            0 :         const struct device *dev;
      51              : };
      52              : 
      53              : /** List of emulators attached to a bus */
      54            1 : struct emul_list_for_bus {
      55              :         /** Identifiers for children of the node */
      56            1 :         const struct emul_link_for_bus *children;
      57              :         /** Number of children of the node */
      58            1 :         unsigned int num_children;
      59              : };
      60              : 
      61              : /**
      62              :  * Standard callback for emulator initialisation providing the initialiser
      63              :  * record and the device that calls the emulator functions.
      64              :  *
      65              :  * @param emul Emulator to init
      66              :  * @param parent Parent device that is using the emulator
      67              :  */
      68            1 : typedef int (*emul_init_t)(const struct emul *emul, const struct device *parent);
      69              : 
      70              : /**
      71              :  * Emulator API stub when an emulator is not actually placed on a bus.
      72              :  */
      73            1 : struct no_bus_emul {
      74            0 :         void *api;
      75            0 :         uint16_t addr;
      76              : };
      77              : 
      78              : /** An emulator instance - represents the *target* emulated device/peripheral that is
      79              :  * interacted with through an emulated bus. Instances of emulated bus nodes (e.g. i2c_emul)
      80              :  * and emulators (i.e. struct emul) are exactly 1..1
      81              :  */
      82            1 : struct emul {
      83              :         /** function used to initialise the emulator state */
      84            1 :         emul_init_t init;
      85              :         /** handle to the device for which this provides low-level emulation */
      86            1 :         const struct device *dev;
      87              :         /** Emulator-specific configuration data */
      88            1 :         const void *cfg;
      89              :         /** Emulator-specific data */
      90            1 :         void *data;
      91              :         /** The bus type that the emulator is attached to */
      92            1 :         enum emul_bus_type bus_type;
      93              :         /** Pointer to the emulated bus node */
      94            1 :         union bus {
      95            0 :                 struct i2c_emul *i2c;
      96            0 :                 struct espi_emul *espi;
      97            0 :                 struct spi_emul *spi;
      98            0 :                 struct mspi_emul *mspi;
      99            0 :                 struct uart_emul *uart;
     100            0 :                 struct no_bus_emul *none;
     101            0 :         } bus;
     102              :         /** Address of the API structure exposed by the emulator instance */
     103            1 :         const void *backend_api;
     104              : };
     105              : 
     106              : /**
     107              :  * @brief Use the devicetree node identifier as a unique name.
     108              :  *
     109              :  * @param node_id A devicetree node identifier
     110              :  */
     111            1 : #define EMUL_DT_NAME_GET(node_id) _CONCAT(__emulreg_, node_id)
     112              : 
     113              : /* Get a unique identifier based on the given _dev_node_id's reg property and
     114              :  * the bus its on. Intended for use in other internal macros when declaring {bus}_emul
     115              :  * structs in peripheral emulators.
     116              :  */
     117              : #define Z_EMUL_REG_BUS_IDENTIFIER(_dev_node_id) _CONCAT(_CONCAT(__emulreg_, _dev_node_id), _bus)
     118              : 
     119              : /* Conditionally places text based on what bus _dev_node_id is on. */
     120              : #define Z_EMUL_BUS(_dev_node_id, _i2c, _espi, _spi, _mspi, _uart, _none)                           \
     121              :         COND_CODE_1(DT_ON_BUS(_dev_node_id, i2c), (_i2c),                                          \
     122              :         (COND_CODE_1(DT_ON_BUS(_dev_node_id, espi), (_espi),                                       \
     123              :         (COND_CODE_1(DT_ON_BUS(_dev_node_id, spi), (_spi),                                         \
     124              :         (COND_CODE_1(DT_ON_BUS(_dev_node_id, mspi), (_mspi),                                       \
     125              :         (COND_CODE_1(DT_ON_BUS(_dev_node_id, uart), (_uart),                                       \
     126              :         (_none))))))))))
     127              : 
     128              : /**
     129              :  * @brief Define a new emulator
     130              :  *
     131              :  * This adds a new struct emul to the linker list of emulations. This is
     132              :  * typically used in your emulator's DT_INST_FOREACH_STATUS_OKAY() clause.
     133              :  *
     134              :  * @param node_id Node ID of the driver to emulate (e.g. DT_DRV_INST(n)); the node_id *MUST* have a
     135              :  *        corresponding DEVICE_DT_DEFINE().
     136              :  * @param init_fn function to call to initialise the emulator (see emul_init typedef)
     137              :  * @param data_ptr emulator-specific data
     138              :  * @param cfg_ptr emulator-specific configuration data
     139              :  * @param bus_api emulator-specific bus api
     140              :  * @param _backend_api emulator-specific backend api
     141              :  */
     142            1 : #define EMUL_DT_DEFINE(node_id, init_fn, data_ptr, cfg_ptr, bus_api, _backend_api)                 \
     143              :         static struct Z_EMUL_BUS(node_id, i2c_emul, espi_emul, spi_emul, mspi_emul, uart_emul,     \
     144              :                                  no_bus_emul) Z_EMUL_REG_BUS_IDENTIFIER(node_id) = {               \
     145              :                 .api = bus_api,                                                                    \
     146              :                 IF_ENABLED(DT_NODE_HAS_PROP(node_id, reg),                                         \
     147              :                            (.Z_EMUL_BUS(node_id, addr, chipsel, chipsel, dev_idx, dummy, addr) =   \
     148              :                                     DT_REG_ADDR(node_id),))};                                      \
     149              :         const STRUCT_SECTION_ITERABLE(emul, EMUL_DT_NAME_GET(node_id)) __used = {                  \
     150              :                 .init = (init_fn),                                                                 \
     151              :                 .dev = DEVICE_DT_GET(node_id),                                                     \
     152              :                 .cfg = (cfg_ptr),                                                                  \
     153              :                 .data = (data_ptr),                                                                \
     154              :                 .bus_type = Z_EMUL_BUS(node_id, EMUL_BUS_TYPE_I2C, EMUL_BUS_TYPE_ESPI,             \
     155              :                                        EMUL_BUS_TYPE_SPI, EMUL_BUS_TYPE_MSPI, EMUL_BUS_TYPE_UART,  \
     156              :                                        EMUL_BUS_TYPE_NONE),                                        \
     157              :                 .bus = {.Z_EMUL_BUS(node_id, i2c, espi, spi, mspi, uart, none) =                   \
     158              :                                 &(Z_EMUL_REG_BUS_IDENTIFIER(node_id))},                            \
     159              :                 .backend_api = (_backend_api),                                                     \
     160              :         };
     161              : 
     162              : /**
     163              :  * @brief Like EMUL_DT_DEFINE(), but uses an instance of a DT_DRV_COMPAT compatible instead of a
     164              :  *        node identifier.
     165              :  *
     166              :  * @param inst instance number. The @p node_id argument to EMUL_DT_DEFINE is set to
     167              :  *             <tt>DT_DRV_INST(inst)</tt>.
     168              :  * @param ... other parameters as expected by EMUL_DT_DEFINE.
     169              :  */
     170            1 : #define EMUL_DT_INST_DEFINE(inst, ...) EMUL_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__)
     171              : 
     172              : /**
     173              :  * @brief Get a <tt>const struct emul*</tt> from a devicetree node identifier
     174              :  *
     175              :  * @details Returns a pointer to an emulator object created from a devicetree
     176              :  * node, if any device was allocated by an emulator implementation.
     177              :  *
     178              :  * If no such device was allocated, this will fail at linker time. If you get an
     179              :  * error that looks like <tt>undefined reference to __device_dts_ord_<N></tt>,
     180              :  * that is what happened. Check to make sure your emulator implementation is
     181              :  * being compiled, usually by enabling the Kconfig options it requires.
     182              :  *
     183              :  * @param node_id A devicetree node identifier
     184              :  * @return A pointer to the emul object created for that node
     185              :  */
     186            1 : #define EMUL_DT_GET(node_id) (&EMUL_DT_NAME_GET(node_id))
     187              : 
     188              : /**
     189              :  * @brief Utility macro to obtain an optional reference to an emulator
     190              :  *
     191              :  * If the node identifier refers to a node with status `okay`, this returns `EMUL_DT_GET(node_id)`.
     192              :  * Otherwise, it returns `NULL`.
     193              :  *
     194              :  * @param node_id A devicetree node identifier
     195              :  * @return a @ref emul reference for the node identifier, which may be `NULL`.
     196              :  */
     197            1 : #define EMUL_DT_GET_OR_NULL(node_id)                                                               \
     198              :         COND_CODE_1(DT_NODE_HAS_STATUS_OKAY(node_id), (EMUL_DT_GET(node_id)), (NULL))
     199              : 
     200              : /**
     201              :  * @brief Set up a list of emulators
     202              :  *
     203              :  * @param dev Device the emulators are attached to (e.g. an I2C controller)
     204              :  * @return 0 if OK
     205              :  * @return negative value on error
     206              :  */
     207            1 : int emul_init_for_bus(const struct device *dev);
     208              : 
     209              : /**
     210              :  * @brief Retrieve the emul structure for an emulator by name
     211              :  *
     212              :  * @details Emulator objects are created via the EMUL_DT_DEFINE() macro and placed in memory by the
     213              :  * linker. If the emulator structure is needed for custom API calls, it can be retrieved by the name
     214              :  * that the emulator exposes to the system (this is the devicetree node's label by default).
     215              :  *
     216              :  * @param name Emulator name to search for.  A null pointer, or a pointer to an
     217              :  * empty string, will cause NULL to be returned.
     218              :  *
     219              :  * @return pointer to emulator structure; NULL if not found or cannot be used.
     220              :  */
     221            1 : const struct emul *emul_get_binding(const char *name);
     222              : 
     223              : /**
     224              :  * @}
     225              :  */
     226              : 
     227              : #define Z_MAYBE_EMUL_DECLARE_INTERNAL(node_id) extern const struct emul EMUL_DT_NAME_GET(node_id);
     228              : 
     229            0 : DT_FOREACH_STATUS_OKAY_NODE(Z_MAYBE_EMUL_DECLARE_INTERNAL);
     230              : 
     231              : #ifdef __cplusplus
     232              : }
     233              : #endif /* __cplusplus */
     234              : 
     235              : #endif /* ZEPHYR_INCLUDE_DRIVERS_EMUL_H_ */
        

Generated by: LCOV version 2.0-1