Zephyr Cadence IIC Driver Implementation

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

Zephyr - IIC Cadence Driver - File

Zephyr Cadence IIC driver source tree showing drivers/ -> i2c/ -> i2c_cdns.c.

Zephyr Cadence IIC driver file location.

Zephyr - IIC Cadence Device Tree

Iicps Node

ps_i2c1: i2c@ff030000 {
    compatible = "cdns,i2c-r1p14";
    status = "okay";
    #address-cells = <1>;
    #size-cells = <0>;
    reg = <0xff030000 0x1000>;
    interrupt-parent = <&gic>;
    interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>;
    clocks = <&i2c_ref_clk>;
};

cdns,i2c-r1p14.yaml

description: Cadence I2C controller version 1.4

compatible: "cdns,i2c-r1p14"

include: [i2c-controller.yaml, reset-device.yaml]

properties:
  reg:
    required: true

  clocks:
    required: true

  interrupts:
    required: true

  fifo-depth:
    type: int
    description: Size of the data FIFO in bytes.
    default: 16
    enum: [2, 4, 8, 16, 32, 64, 128, 256]
  • Node properties are similar to Linux device tree

Zephyr - IIC Cadence Kconfig

Kconfig.cdns

config I2C_CADENCE
    bool "Cadence I2C driver"
    default y
    depends on DT_HAS_CDNS_I2C_R1P10_ENABLED || DT_HAS_CDNS_I2C_R1P14_ENABLED
    select EVENTS
    help
      Enable Cadence I2C driver.

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 - IIC Cadence Driver - Supported APIs

Driver - API

/* IIC Cadence Driver - Supported Driver APIs */

static const struct i2c_driver_api cdns_i2c_driver_api = {
    /* configure the I2C controller speed */
    .configure = cdns_i2c_configure,

    /* Get configuration of I2C controller */
    .get_config = cdns_i2c_get_config,

    /* Data transfers on the I2C bus (Master Mode) */
    .transfer = cdns_i2c_master_transfer,

#if defined(CONFIG_I2C_TARGET)
    /* registers the device as an I2C target (Slave Mode) */
    .target_register = cdns_i2c_target_register,

    /* removes the device as an I2C target (Slave Mode) */
    .target_unregister = cdns_i2c_target_unregister,
#endif
};

Zephyr - IIC Cadence Driver - Data Structures

Driver - Structures

/**
 * struct cdns_i2c_data - Cadence I2C device private data structure
 * @membase: Base address of the I2C device.
 * @ctrl_reg: Cached value of the control register.
 * @input_clk: Input clock to I2C controller.
 * @i2c_clk: Maximum I2C clock speed.
 * @i2c_config: Configuration of I2C settings.
 * @fifo_depth: The depth of the transfer FIFO.
 * @transfer_size: The maximum number of bytes in one transfer.
 * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit.
 * @broken_hold_flag: Flag for broken hold bit usage in r1p10.
 * @xfer_done: Transfer complete event.
 * @err_status: Error status in Interrupt Status Register.
 * @p_msg: Message pointer for I2C communication.
 * @p_send_buf: Pointer to transmit buffer.
 * @p_recv_buf: Pointer to receive buffer.
 * @send_count: Number of bytes still expected to send.
 * @recv_count: Number of bytes still expected to receive.
 * @curr_recv_count: Number of bytes to be received in current transfer.
 * @bus_mutex: Mutex for bus access synchronization
 * @ctrl_reg_diva_divb: Value of fields DIV_A and DIV_B from CR register.
 * @slave: Registered slave instance.
 * @dev_mode: I2C operating role (master/slave).
 * @slave_state: I2C Slave state (idle/read/write).
 */
struct cdns_i2c_data {
    mem_addr_t membase;
    uint32_t ctrl_reg;
    uint32_t input_clk;
    uint32_t i2c_clk;
    uint32_t i2c_config;
    uint32_t fifo_depth;
    uint32_t transfer_size;
    uint32_t bus_hold_flag;
    uint32_t broken_hold_flag;

    struct k_event xfer_done;
    uint32_t err_status;
    struct i2c_msg *p_msg;
    uint8_t *p_send_buf;
    uint8_t *p_recv_buf;
    uint32_t send_count;
    uint32_t recv_count;
    uint32_t curr_recv_count;

    struct k_mutex bus_mutex;

#if defined(CONFIG_I2C_TARGET)
    uint16_t ctrl_reg_diva_divb;
    struct i2c_target_config *slave;
    enum cdns_i2c_mode dev_mode;
    enum cdns_i2c_slave_state slave_state;
#endif
};

Zephyr - IIC Cadence Driver - Master Mode Example Flow

Cadence IIC master-mode example flow: from Zephyr boot-up and post-kernel device tree init the cdns,i2c-r1p14 compatible invokes i2c_cdns_init (populates DT config, registers I2C driver APIs, sets the I2C bus speed, initializes the controller, and registers the :term:`ISR`); the application's i2c_configure / i2c_get_config / i2c_write / i2c_read calls then route through i2c_transfer into i2c_cdns_transfer for interrupt-driven I/O.

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

Zephyr - IIC Cadence Driver - Slave Mode Example Flow

Cadence IIC slave-mode example flow: Zephyr boot-up and post-kernel init calls i2c_cdns_init through the cdns,i2c-r1p14 compatible; the application's i2c_configure, i2c_get_config, i2c_target_register, and i2c_target_unregister calls map to i2c_cdns_configure / i2c_cdns_get_config / i2c_cdns_target_register / i2c_cdns_target_unregister, which perform the controller re-init, target callback wiring, target address setup, and disable.

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