Zephyr AXI IIC Driver Implementation

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

Zephyr - AXI IIC Driver - File

Zephyr AXI IIC driver source tree showing drivers/ -> i2c/ -> i2c_xilinx_axi.c.

Zephyr AXI IIC driver file location.

Zephyr - AXI IIC Device Tree

axi-i2c Node

axi_i2c0: i2c@a0000000 {
    compatible = "xlnx,xps-iic-2.00.a";
    #address-cells = <1>;
    #size-cells = <0>;
    status = "okay";
    interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL
                  IRQ_DEFAULT_PRIORITY>;
    reg = <0xa0000000 0x1000>;
    interrupt-parent = <&gic>;
};

xlnx,xps-iic-2.00.a.yaml

description: Xilinx AXI IIC Bus Interface

compatible: "xlnx,xps-iic-2.00.a"

include: [i2c-controller.yaml]

properties:
  reg:
    required: true

  interrupts:
    required: true
  • Changes with respect to Linux device tree

    • clocks property is not added

Zephyr - AXI IIC Kconfig

Kconfig.xilinx_axi

config I2C_XILINX_AXI
    bool "Xilinx AXI I2C driver"
    default y
    depends on DT_HAS_XLNX_XPS_IIC_2_00_A_ENABLED || DT_HAS_XLNX_XPS_IIC_2_1_ENABLED
    select EVENTS
    help
      Enable the Xilinx AXI IIC Bus Interface driver.
      This is an FPGA logic core as described by Xilinx document PG090.

Zephyr - I2C Driver - Common Framework Hooks

i2c.h

/* Driver APIs supported by Zephyr I2C Framework */

__subsystem struct i2c_driver_api {
     /* configuring the I2C bus settings */
    i2c_api_configure_t configure;

    /* get the current I2C bus configuration */
    i2c_api_get_config_t get_config;

    /* transferring data over the I2C bus */
    i2c_api_full_io_t transfer;

    /* registering a target device */
    i2c_api_target_register_t target_register;

    /* unregistering a target device */
    i2c_api_target_unregister_t target_unregister;

    /* callback for I2C transfer completion */
    i2c_api_transfer_cb_t transfer_cb;

    /* I/O device submission in real-time I/O */
    i2c_api_iodev_submit iodev_submit;

    /* Recover I2C bus from error state */
    i2c_api_recover_bus_t recover_bus;
};

Zephyr - AXI I2C Driver - Supported APIs

Driver - API

/* AXI I2C Driver - Supported Driver APIs */

static const struct i2c_driver_api i2c_xilinx_axi_driver_api = {
    /* initialize the I2C controller */
    .configure = i2c_xilinx_axi_configure,

    /* Data transfers on the I2C bus */
    .transfer = i2c_xilinx_axi_transfer,

#if defined(CONFIG_I2C_TARGET)

    /* registers the device as an I2C target */
    .target_register = i2c_xilinx_axi_target_register,

    /* removes the device as an I2C target */
    .target_unregister = i2c_xilinx_axi_target_unregister,
#endif
};

Zephyr - AXI I2C Driver - Data Structures

Driver - Structures

/*
 * Structure to hold configuration data for the Xilinx AXI I2C device.
 */
struct i2c_xilinx_axi_config {
    /* Memory-mapped base address of the AXI I2C device */
    mem_addr_t base;

    /* set up interrupt handling for the I2C device */
    void (*irq_config_func)(const struct device *dev);

    /* flag indicating dynamic read functionality */
    bool dyn_read_working;
};


/*
 * Structure to store runtime data for the Xilinx AXI I2C device.
 * This includes synchronization primitives and, if enabled, target-specific settings.
 */
struct i2c_xilinx_axi_data {
    /* signal the completion of interrupt-driven operations */
    struct k_event irq_event;

    /* synchronize access between the interrupt service routine (ISR) */
    struct k_spinlock lock;

    /* mutual exclusion for concurrent I2C requests */
    struct k_mutex mutex;

#if defined(CONFIG_I2C_TARGET)
    /* set up I2C target-specific settings. */
    struct i2c_target_config *target_cfg;

    /* flag indicating  whether the device is currently in target reading mode. */
    bool target_reading;

    /* flag indicating whether the current read operation has been aborted. */
    bool target_read_aborted;

    /* flag indicating whether the device is currently in target writing mode. */
    bool target_writing;
#endif
};

Zephyr - AXI I2C Driver - Master Mode Example Flow

AXI I2C master-mode example flow: from Zephyr boot-up and post-kernel device tree init the xlnx,xps-iic-2.00.a compatible invokes i2c_xilinx_axi_init (populates DT config, registers I2C driver APIs, initializes the controller, and registers the ISR); the application's i2c_configure call then maps to i2c_xilinx_axi_configure (controller re-init), and i2c_write / i2c_read flow through i2c_transfer into i2c_xilinx_axi_transfer for interrupt-driven I/O.

Zephyr AXI IIC driver - master mode end-to-end flow.

Zephyr - AXI I2C Driver - Slave Mode Example Flow

AXI I2C slave-mode example flow: Zephyr boot-up and post-kernel init calls i2c_xilinx_axi_init through the xlnx,xps-iic-2.00.a compatible; the application's i2c_configure, i2c_target_register, and i2c_target_unregister calls map to i2c_xilinx_axi_configure (controller re-init), i2c_xilinx_axi_target_register, and i2c_xilinx_axi_target_unregister, performing controller re-init, target callback wiring, target address setup, and disable.

Zephyr AXI IIC driver - slave mode end-to-end flow.