Zephyr AXI QSPI Driver Implementation

This page provides details on the implementation of the AXI QSPI Zephyr driver.

SPI Layer

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

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 XLNX_QUADSPI_INIT(n)                                            \
        static void xlnx_quadspi_config_func_##n(const struct device *dev);     \
                                                                        \
        static const struct xlnx_quadspi_config xlnx_quadspi_config_##n = { \
                .base = DT_INST_REG_ADDR(n),                            \
                .irq_config_func = xlnx_quadspi_config_func_##n,        \
                .num_ss_bits = DT_INST_PROP(n, xlnx_num_ss_bits),       \
                .num_xfer_bytes =                                       \
                        DT_INST_PROP(n, xlnx_num_transfer_bits) / 8,    \
                .fifo_size = DT_INST_PROP_OR(n, fifo_size, 0),          \
                STARTUP_BLOCK_INIT(n)                                   \
        };                                                              \
                                                                        \
        static struct xlnx_quadspi_data xlnx_quadspi_data_##n = {       \
                SPI_CONTEXT_INIT_LOCK(xlnx_quadspi_data_##n, ctx),      \
                SPI_CONTEXT_INIT_SYNC(xlnx_quadspi_data_##n, ctx),      \
                SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(n), ctx)    \
        };                                                              \
                                                                        \
        DEVICE_DT_INST_DEFINE(n, &xlnx_quadspi_init,                    \
                            NULL,                                       \
                            &xlnx_quadspi_data_##n,                     \
                            &xlnx_quadspi_config_##n, POST_KERNEL,      \
                            CONFIG_SPI_INIT_PRIORITY,                   \
                            &xlnx_quadspi_driver_api);                  \
                                                                        \
        static void xlnx_quadspi_config_func_##n(const struct device *dev)      \
        {                                                               \
                IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority),  \
                            xlnx_quadspi_isr,                           \
                            DEVICE_DT_INST_GET(n), 0);                  \
                irq_enable(DT_INST_IRQN(n));                            \
        }

DT_INST_FOREACH_STATUS_OKAY(XLNX_QUADSPI_INIT)
DT_DRV_COMPAT
  • This macro holds the compatible string of the driver “xlnx_xps_spi_2_00_a

DT_INST_FOREACH_STATUS_OKAY
  • This macro calls “XLNX_QUADSPI_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.

  • xlnx_quadspi_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 xlnx_quadspi_config_##n variable address.

  • POST_KERNEL defines the device initialization level.

  • CONFIG_KERNEL_INIT_PRIORITY_DEVICE device priority within the device initialization level.

  • xlnx_quadspi_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

Release

  • Callback API for unlocking SPI device