Zephyr Cadence SPI Driver Implementation

This page provides details on the implementation of the Cadence SPI Zephyr driver.

Driver Implementation

For a full list of features supported by this IP, refer Chapter 67: SPI Controller in Versal TRM.

SPI Layer

SPI uses framework zephyr-amd/include/zephyr/drivers/spi.h at master · Xilinx/zephyr-amd · GitHub to call the driver API.

Zephyr SPI software stack with and without the SPI-NOR subsystem: in the 'without NOR subsystem' path the application calls the SPI framework directly, while the 'with NOR subsystem' path adds the SPI- NOR subsystem between the application and the SPI framework / driver.

Zephyr SPI driver stack with and without the NOR subsystem.

Probe Data From Node

In driver “DT_DRV_COMPAT” need to be assign with driver compatible string so that when ever the compatible string matches with one of the DT nodes along with status property okay then driver registers the driver API to the SPI framework using a framework structure.

Probe SPIPS NODE

SPIPS Probe Node

#define CDNS_SPI_INIT(n)                                            \
        static void cdns_spi_config_func_##n(const struct device *dev);     \
         \
        static const struct cdns_spi_config cdns_spi_config_##n = { \
                .base = DT_INST_REG_ADDR(n),                            \
                .irq_config_func = cdns_spi_config_func_##n,        \
                .input_clk = DT_INST_PROP_BY_PHANDLE(n, clocks, clock_frequency), \
                .num_ss_bits = DT_INST_PROP(n, cdns_num_ss_bits),       \
                .tx_fifo_depth = 128,   \
                .is_decoded_cs = DT_INST_PROP(n, is_decoded_cs),        \
        };                                                              \
        \
        static struct cdns_spi_data cdns_spi_data_##n = {       \
                SPI_CONTEXT_INIT_LOCK(cdns_spi_data_##n, ctx),      \
                SPI_CONTEXT_INIT_SYNC(cdns_spi_data_##n, ctx),      \
                SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx)    \
        };                                                              \
        \
        DEVICE_DT_INST_DEFINE(n, &cdns_spi_init,                    \
                        NULL,                                       \
                        &cdns_spi_data_##n,                     \
                        &cdns_spi_config_##n, POST_KERNEL,      \
                        CONFIG_SPI_INIT_PRIORITY,                   \
                        &cdns_spi_driver_api);                  \
                        \
                        static void cdns_spi_config_func_##n(const struct device *dev)      \
{                                                               \
        IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),  \
                        cdns_spi_isr,                           \
                        DEVICE_DT_INST_GET(n), 0);                  \
        irq_enable(DT_INST_IRQN(n));                            \
}

DT_INST_FOREACH_STATUS_OKAY(CDNS_SPI_INIT)
DT_DRV_COMPAT
  • This macro holds the compatible string of the driver cdns_spi_r1p6.

DT_INST_FOREACH_STATUS_OKAY
  • This macro calls CDNS_SPI_INIT(n) on all node with compatible DT_DRV_COMPAT and status okay.

DEVICE_DT_INST_DEFINE
  • This macro defines a device structure that is automatically configured by kernel during system init.

  • cdns_spi_init API will be run by the kernel during system initialization.
    
  • device→name is set by “DEVICE_DT_NAME(n)” macro.

  • device→data is set with data##n variable address.

  • device→config is set with cdns_spi_config_##n variable address.

  • POST_KERNEL defines the device initialization level.

  • CONFIG_KERNEL_INIT_PRIORITY_DEVICE device priority within the device initialization level.

  • cdns_spi_driver_api is a structure where we add all the api that need to be registered to subsystem
    
DEVICE_DT_NAME(n)
  • This macro returns a string name for a device tree node.

DT_INST_REG_ADDR(n)
  • This macro returns instances register block address.

DT_INST_PROP(n, Property)
  • This macro returns node property value.

DT_INST_PROP_OR(n, Property, Default)
  • This macro returns node property value or default value.

SPI Subsystem

SPI subsystem has the following structure where any SPI driver needs to expose

Subsystem Structure

__subsystem struct spi_driver_api {
        spi_api_io transceive;
#ifdef CONFIG_SPI_ASYNC
        spi_api_io_async transceive_async;
#endif /* CONFIG_SPI_ASYNC */
#ifdef CONFIG_SPI_RTIO
        spi_api_iodev_submit iodev_submit;
#endif /* CONFIG_SPI_RTIO */
        spi_api_release release;
};

Functional Implementation

transceive

  • SPI callback for I/O operations.

transceive_async

  • SPI callback for asynchronous I/O operations.

iodev_submit

  • Callback API for submitting work to a SPI device with RTIO.

release

  • Callback API for unlocking SPI device.