The I3C driver provides a complete software interface for operating the Synaptics I3C peripheral in both Controller and Target modes.
The driver supports standard I3C and mixed I3C/I2C bus environments, enabling dynamic device management, high-speed data transfers, interrupt-driven communication, and advanced bus arbitration features.
Features:
- SDR and HDR transfer modes
- Dynamic Address Assignment (ENTDAA / SETDASA)
- Direct and Broadcast CCC command support
- Mixed I3C + I2C device coexistence
- In-Band Interrupt (IBI) handling
- Hot-Join detection and processing
- Master Request arbitration support
- FIFO-based data buffering with programmable thresholds
- Blocking and non-blocking transfer models
- ISR-driven asynchronous operation
The driver is structured around:
- Controller APIs for device discovery, configuration, and transfers
- Target APIs for target-mode operation and event generation
- Unified configuration structures for controller and target modes
- Callback-based interrupt handling for asynchronous events
- Note
- I3C APIs are divided into two categories:
- High-level APIs: Provides structured configuration and transaction-oriented interfaces for operating the I3C peripheral in Controller or Target mode using well-defined configuration structures and transfer descriptors. These APIs abstract queue management, command formatting, and protocol sequencing, and are intended for most application-level use cases.
Low-level APIs: Provides direct control over hardware state and protocol behavior, including fine-grained interrupt management, FIFO handling, response queue inspection, and manual Hot-Join or IBI processing.
This model is intended for system-level software, performance-sensitive applications, protocol validation, or custom arbitration and timing control scenarios.
- Warning
- Once enabled, core configuration such as operating mode, timing parameters, and dynamic addressing must not be modified until the peripheral is disabled using i3c_disable.
Configuration Considerations
To initialize and operate the I3C driver:
- Call i3c_init to initialize the peripheral instance and reset the internal driver context.
- Populate either i3c_controller_config_t or i3c_target_config_t depending on the intended operating mode.
- Apply configuration using i3c_controller_set_config or i3c_target_set_config. This programs timing, thresholds, addressing behavior, and bus characteristics.
- Optionally register an application callback using i3c_register_callback to enable interrupt-driven event handling.
- Enable the peripheral using i3c_enable to allow bus participation.
Controller Mode Operation:
- Configure controller behavior policy and notifications using i3c_controller_set_policy_config and i3c_controller_set_interrupt_config.
- Perform Dynamic Address Assignment using i3c_controller_perform_daa.
- Optionally configure HDR behavior using i3c_controller_config_hdr_mode before HDR transfers.
- Use i3c_controller_send_ccc for broadcast/direct CCC operations (and response helpers for queued CCC responses).
- Build an i3c_transfer_t descriptor with target address, address mode, buffer, length, speed, direction, and flags.
- Execute data transfers using blocking or non-blocking APIs: (i3c_controller_write_blocking, i3c_controller_read_blocking, i3c_controller_write_non_blocking, i3c_controller_read_non_blocking).
- Optionally enable advanced features such as i3c_controller_enable_ibi or i3c_controller_process_hot_join_and_enumerate.
Using Dynamic Address Assignment (DAA)
DAA is typically used once after bus bring-up, and again when new target devices are introduced (for example after Hot-Join).
Recommended controller-side flow:
- Fill an array of i3c_device_config_t with known target capabilities.
- Call i3c_controller_perform_daa.
- Read discovered devices from the internal list using i3c_controller_get_device_count and i3c_controller_get_device, or from the optional output buffer passed to i3c_controller_perform_daa.
- Use the assigned dynamic address or DAT index in i3c_transfer_t for subsequent private transfers.
- Note
- Legacy I²C targets do not participate in ENTDAA. Configure them with static addressing and use matching transfer speed constraints.
Using Speed Modes (SDR/HDR)
Speed is selected per transfer through i3c_transfer_t.speed.
Practical guidance:
Controller timing can be selected using i3c_controller_config_t.sdr_timing_preset. Choose I3C_SDR_TIMING_PRESET_MANUAL when explicit nanosecond timing values are required in i3c_scl_timing_t.
Using Common Command Codes (CCC)
CCC transactions are initiated with i3c_controller_send_ccc.
Recommended flow:
- Select I3C_CCC_BROADCAST for bus-wide commands, or I3C_CCC_DIRECT with a valid DAT index for per-target commands.
- Provide request payload in req_buffer/req_length when required by CCC.
- Provide resp_buffer/resp_max_length for read/response CCCs.
- Read queued response metadata using i3c_controller_ccc_response_get_count and i3c_controller_ccc_response_read.
- Note
- When using direct CCC, DAT index must refer to a currently enumerated target in the controller internal device list.
Using Hot-Join
Hot-Join allows a new target to request participation after initial bus setup.
Recommended controller-side flow:
- Enable policy using i3c_controller_set_policy_config and/or i3c_controller_config_hot_join.
- Enable notification via i3c_controller_set_interrupt_config with I3C_EVENT_MASK_IBI_HJ_REQ_RECEIVED.
- On event notification, call i3c_controller_process_hot_join_req, or use i3c_controller_process_hot_join_and_enumerate for one-step handling.
- Re-run targeted enumeration/DAA as needed and refresh active device descriptors used by transfers.
Target Mode Operation:
- After configuration and enable, wait for Dynamic Address Assignment from the controller.
- Expect controller-driven CCCs and address changes as part of enumeration and capability negotiation.
- Prepare transfer buffers using i3c_target_prep_controller_read or i3c_target_prep_controller_write.
- Optionally generate events such as i3c_target_raise_ibi_sir or i3c_target_raise_master_request.
- Ensure non-blocking target buffers remain valid until transfer completion/abort is reported through status or callback.
- Disable the peripheral using i3c_disable before modifying core configuration parameters or switching operating mode.
i3c_init
Initializes the I3C peripheral and prepares the hardware for configuration.
i3c_controller_set_config
Configures controller timing, thresholds, and bus behavior.
memset(&ctrl_cfg, 0, sizeof(ctrl_cfg));
ctrl_cfg.core_clk = I3C_CORE_CLK_HZ;
ctrl_cfg.num_of_devices = 1;
i3c_target_set_config
Configures target mode parameters and identification fields.
memset(&tgt_cfg, 0, sizeof(tgt_cfg));
tgt_cfg.core_clk = I3C_CORE_CLK_HZ;
i3c_enable
Enables the I3C peripheral and allows bus participation.
i3c_controller_perform_daa
Performs Dynamic Address Assignment for connected devices.
.static_address = 0,
.dynamic_address = 0
};
i3c_controller_write_blocking
Executes a blocking write transfer.
blk_cfg.buf = tx_buf;
blk_cfg.size = sizeof(tx_buf);
blk_cfg.timeout = 100;
blk_cfg.send_stop = true;
blk_cfg.is_read = false;
i3c_controller_read_blocking
Executes a blocking read transfer.
blk_cfg.buf = rx_buf;
blk_cfg.size = sizeof(rx_buf);
blk_cfg.timeout = 100;
blk_cfg.send_stop = true;
blk_cfg.is_read = true;
i3c_controller_write_non_blocking
Starts an interrupt-driven write transfer.
nb_cfg.buf = tx_buf;
nb_cfg.size = sizeof(tx_buf);
nb_cfg.send_stop = true;
nb_cfg.is_read = false;
i3c_controller_read_non_blocking
Starts an interrupt-driven read transfer.
nb_cfg.buf = rx_buf;
nb_cfg.size = sizeof(rx_buf);
nb_cfg.send_stop = true;
nb_cfg.is_read = true;
i3c_disable
Disables the I3C peripheral.
i3c_deinit
Deinitializes the I3C instance and returns hardware to reset state.