openmv/lib/alif/Alif_CMSIS/Source/Driver_I3C.c
iabdalkader daf2bb30da misc: Restructure repo.
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
2025-04-13 08:28:34 +02:00

2421 lines
72 KiB
C

/* Copyright (C) 2023 Alif Semiconductor - All Rights Reserved.
* Use, distribution and modification of this code is permitted under the
* terms stated in the Alif Semiconductor Software License Agreement
*
* You should have received a copy of the Alif Semiconductor Software
* License Agreement with this file. If not, please write to:
* contact@alifsemi.com, or visit: https://alifsemi.com/license
*/
/* System Includes */
#include <string.h>
#include "RTE_Device.h"
#include "RTE_Components.h"
#include CMSIS_device_header
/* Project Includes */
#include "Driver_I3C_Private.h"
#include "i3c.h"
#include "sys_ctrl_i3c.h"
#if !(RTE_I3C)
#error "I3C is not enabled in the RTE_Device.h"
#endif
#if (defined(RTE_Drivers_I3C) && !RTE_I3C)
#error "I3C not configured in RTE_Device.h!"
#endif
#define ARM_I3C_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(7, 3) /* driver version */
/* Driver Version */
static const ARM_DRIVER_VERSION DriverVersion =
{
ARM_I3C_API_VERSION,
ARM_I3C_DRV_VERSION
};
/* Driver Capabilities */
static const ARM_I3C_CAPABILITIES DriverCapabilities =
{
1, /* Supports legacy i2c device */
1, /* Supports Slave I2C/I3C Adaptive mode support during boot up phase */
1, /* Supports In-Band Interrupts */
0, /* Doesn't support In-Band Interrupt with Payload */
1, /* Supports Secondary Master Configuration */
1, /* Supports HDR DDR0 mode */
0, /* Doesn't support HDR Ternary Symbol Pure-Bus mode */
0, /* Doesn't support HDR Ternary Symbol Legacy-Inclusive-Bus mode */
0 /* Reserved (must be zero) */
};
#if I3C_DMA_ENABLE
/**
\fn int32_t I3C_DMA_Initialize(DMA_PERIPHERAL_CONFIG *dma_periph)
\brief Initialize DMA for I3C
\param[in] dma_periph Pointer to DMA resources
\return \ref execution_status
*/
__STATIC_INLINE int32_t I3C_DMA_Initialize(DMA_PERIPHERAL_CONFIG *dma_periph)
{
int32_t status;
ARM_DRIVER_DMA *dma_drv = dma_periph->dma_drv;
/* Initializes DMA interface */
status = dma_drv->Initialize();
if(status)
{
return ARM_DRIVER_ERROR;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3C_DMA_PowerControl(ARM_POWER_STATE state,
DMA_PERIPHERAL_CONFIG *dma_periph)
\brief PowerControl DMA for I3C
\param[in] state Power state
\param[in] dma_periph Pointer to DMA resources
\return \ref execution_status
*/
__STATIC_INLINE int32_t I3C_DMA_PowerControl(ARM_POWER_STATE state,
DMA_PERIPHERAL_CONFIG *dma_periph)
{
int32_t status;
ARM_DRIVER_DMA *dma_drv = dma_periph->dma_drv;
/* Initializes DMA interface */
status = dma_drv->PowerControl(state);
if(status)
{
return ARM_DRIVER_ERROR;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3C_DMA_Allocate(DMA_PERIPHERAL_CONFIG *dma_periph)
\brief Allocate a channel for I3C
\param[in] dma_periph Pointer to DMA resources
\return \ref execution_status
*/
__STATIC_INLINE int32_t I3C_DMA_Allocate(DMA_PERIPHERAL_CONFIG *dma_periph)
{
int32_t status;
ARM_DRIVER_DMA *dma_drv = dma_periph->dma_drv;
/* Allocate handle for peripheral */
status = dma_drv->Allocate(&dma_periph->dma_handle);
if(status)
{
return ARM_DRIVER_ERROR;
}
/* Enable the channel in the Event Router */
if(dma_periph->evtrtr_cfg.instance == 0)
{
evtrtr0_enable_dma_channel(dma_periph->evtrtr_cfg.channel,
dma_periph->evtrtr_cfg.group,
DMA_ACK_COMPLETION_PERIPHERAL);
}
else
{
evtrtrlocal_enable_dma_channel(dma_periph->evtrtr_cfg.channel,
DMA_ACK_COMPLETION_PERIPHERAL);
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3C_DMA_DeAllocate(DMA_PERIPHERAL_CONFIG *dma_periph)
\brief De-allocate channel of I3C
\param[in] dma_periph Pointer to DMA resources
\return \ref execution_status
*/
__STATIC_INLINE int32_t I3C_DMA_DeAllocate(DMA_PERIPHERAL_CONFIG *dma_periph)
{
int32_t status;
ARM_DRIVER_DMA *dma_drv = dma_periph->dma_drv;
/* De-Allocate handle */
status = dma_drv->DeAllocate(&dma_periph->dma_handle);
if(status)
{
return ARM_DRIVER_ERROR;
}
/* Disable the channel in the Event Router */
if(dma_periph->evtrtr_cfg.instance == 0)
{
evtrtr0_disable_dma_channel(dma_periph->evtrtr_cfg.channel);
evtrtr0_disable_dma_handshake(dma_periph->evtrtr_cfg.channel,
dma_periph->evtrtr_cfg.group);
}
else
{
evtrtrlocal_disable_dma_channel(dma_periph->evtrtr_cfg.channel);
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3C_DMA_Start(DMA_PERIPHERAL_CONFIG *dma_periph,
ARM_DMA_PARAMS *dma_params)
\brief Start I3C DMA transfer
\param[in] dma_periph Pointer to DMA resources
\param[in] dma_params Pointer to DMA parameters
\return \ref execution_status
*/
__STATIC_INLINE int32_t I3C_DMA_Start(DMA_PERIPHERAL_CONFIG *dma_periph,
ARM_DMA_PARAMS *dma_params)
{
int32_t status;
ARM_DRIVER_DMA *dma_drv = dma_periph->dma_drv;
/* Start transfer */
status = dma_drv->Start(&dma_periph->dma_handle, dma_params);
if(status)
{
return ARM_DRIVER_ERROR;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3C_DMA_Stop(DMA_PERIPHERAL_CONFIG *dma_periph)
\brief Stop I3C DMA transfer
\param[in] dma_periph Pointer to DMA resources
\return \ref execution_status
*/
__STATIC_INLINE int32_t I3C_DMA_Stop(DMA_PERIPHERAL_CONFIG *dma_periph)
{
int32_t status;
ARM_DRIVER_DMA *dma_drv = dma_periph->dma_drv;
/* Stop transfer */
status = dma_drv->Stop(&dma_periph->dma_handle);
if(status)
{
return ARM_DRIVER_ERROR;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3C_DMA_Start_TX(I3C_RESOURCES *i3c,
const void *src_addr,
uint32_t len)
\brief Start sending data to I3C TX FIFO using DMA
\param[in] i3c : Pointer to i3c resources structure
\param[in] src_addr : Pointer to source address
\param[in] len : number of bytes
\return execution_status
*/
static int32_t I3C_DMA_Start_TX(I3C_RESOURCES *i3c,
const void *src_addr,
uint32_t len)
{
int32_t status;
ARM_DMA_PARAMS dma_params;
/* Start the DMA engine for sending the data to I3C */
dma_params.peri_reqno = (int8_t)i3c->dma_cfg->dma_tx.dma_periph_req;
dma_params.dir = ARM_DMA_MEM_TO_DEV;
dma_params.cb_event = i3c->dma_cb;
dma_params.src_addr = src_addr;
dma_params.dst_addr = i3c_get_dma_tx_addr(i3c->regs);
dma_params.num_bytes = len;
/* i3c TX/RX FIFO is 4-byte(word) aligned,
* if length is not 4-byte aligned(multiple of 4),
* make it aligned by adding extra length.
*/
if(len % 4)
{
dma_params.num_bytes += (4 - (len % 4));
}
dma_params.irq_priority = i3c->dma_irq_priority;
/* i3c TX/RX FIFO is 4-byte(word) aligned */
dma_params.burst_size = BS_BYTE_4;
dma_params.burst_len = i3c_get_tx_empty_buf_thld(i3c->regs);
if( dma_params.burst_len > 16)
{
dma_params.burst_len = 16;
}
/* Start DMA transfer */
status = I3C_DMA_Start(&i3c->dma_cfg->dma_tx, &dma_params);
if(status)
{
return ARM_DRIVER_ERROR;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3C_DMA_Start_RX(I3C_RESOURCES *i3c,
void *dst_addr
uint32_t len)
\brief Start receiving data from I3C RX FIFO using DMA
\param[in] i3c : Pointer to i3c resources structure
\param[in] dst_addr : Pointer to destination address
\param[in] len : number of bytes
\return execution_status
*/
static int32_t I3C_DMA_Start_RX(I3C_RESOURCES *i3c,
void *dst_addr,
uint32_t len)
{
ARM_DMA_PARAMS dma_params;
int32_t status;
/* Start the DMA engine for sending the data to i3c */
dma_params.peri_reqno = (int8_t)i3c->dma_cfg->dma_rx.dma_periph_req;
dma_params.dir = ARM_DMA_DEV_TO_MEM;
dma_params.cb_event = i3c->dma_cb;
dma_params.src_addr = i3c_get_dma_rx_addr(i3c->regs);
dma_params.dst_addr = dst_addr;
dma_params.num_bytes = len;
/* i3c TX/RX FIFO is 4-byte(word) aligned,
* if length is not 4-byte aligned(multiple of 4),
* make it aligned by adding extra length.
*/
if(len % 4)
{
dma_params.num_bytes += (4 - (len % 4));
}
dma_params.irq_priority = i3c->dma_irq_priority;
/* i3c TX/RX FIFO is 4-byte(word) aligned */
dma_params.burst_size = BS_BYTE_4;
dma_params.burst_len = i3c_get_rx_buf_thld(i3c->regs);
if( dma_params.burst_len > 16)
{
dma_params.burst_len = 16;
}
/* Start DMA transfer */
status = I3C_DMA_Start(&i3c->dma_cfg->dma_rx, &dma_params);
if(status)
{
return ARM_DRIVER_ERROR;
}
return ARM_DRIVER_OK;
}
#endif /* I3C_DMA_ENABLE */
/**
\fn int I3cMasterGetAddrPos(I3C_RESOURCES *i3c, uint8_t addr)
\brief Get already assigned slave address position from DAT(Device Address Table).
For i3c, dynamic address and for i2c, static address is used for communication.
\param[in] i3c : Pointer to i3c resources structure
\param[in] addr : Assigned Slave Address;
Dynamic Address for i3c, Static Address for i2c slave device
\return Assigned slave address position from DAT(Device Address Table) index OR
ARM_DRIVER_ERROR in case slave is not already assigned.
*/
static int I3cMasterGetAddrPos(I3C_RESOURCES *i3c, uint8_t addr)
{
uint32_t pos;
for (pos = 0; pos < i3c->slave_dat.maxdevs; pos++)
{
if (addr == (i3c->slave_dat.addrs[pos] &
(~I3C_TARGET_SLAVE_TYPE_I2C)))
return pos;
}
return ARM_DRIVER_ERROR;
}
/**
\fn int I3cMasterGetFreePos(I3C_RESOURCES *i3c)
\brief Get free position from DAT(Device Address Table)
\param[in] i3c : Pointer to i3c resources structure
\return Free position from DAT OR
ARM_DRIVER_ERROR in case DAT is Full.
Maximum 8 Slave Devices are supported
(\ref register DEVICE_ADDR_TABLE_POINTER)
*/
static int I3cMasterGetFreePos(I3C_RESOURCES *i3c)
{
uint32_t i;
if (!(i3c->slave_dat.freepos & GENMASK(i3c->slave_dat.maxdevs - 1, 0)))
return ARM_DRIVER_ERROR;
for (i = 0; i < i3c->slave_dat.maxdevs; i++)
{
if (i3c->slave_dat.freepos & (1 << i))
return i;
}
return ARM_DRIVER_ERROR;
}
/**
\fn int I3Cx_GetSlaveDynamicAddr(I3C_RESOURCES *i3c,
uint8_t* addr_list,
uint8_t count)
\brief Fetches the slave's dynamic address from DAT
\ given the static address
\param[in] i3c : Pointer to i3c resources structure
\param[in] static_addr : Slave's static address
\param[in] dynamic_addr : Slave's dynamic address
\return \ref execution_status
*/
static int I3Cx_GetSlaveDynamicAddr(I3C_RESOURCES *i3c,
uint8_t static_addr,
uint8_t *dynamic_addr)
{
if(!dynamic_addr)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
*dynamic_addr = i3c_get_slv_dyn_addr(i3c->regs, static_addr);
/* Returns error if the requested address not found */
if(!(*dynamic_addr))
{
return ARM_DRIVER_ERROR_PARAMETER;
}
return ARM_DRIVER_OK;
}
/**
\fn int I3Cx_GetSlvsInfo(I3C_RESOURCES *i3c,
ARM_I3C_DEV_CHAR* data,
const uint8_t value)
\ Note: It is valid only for secondary masters, not for
\ current bus master
\brief Fetches the slaves info from DCT
\param[in] i3c : Pointer to i3c resources structure
\param[in] data : Device characteristics data
\param[in] count : Slaves count
\return \ref execution_status
*/
static int I3Cx_GetSlvsInfo(I3C_RESOURCES *i3c,
void* data,
const uint8_t value)
{
uint8_t iter;
if(!data)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
if(i3c->state.is_master)
{
/* Performs the following if it's a master */
/* Considering value as the slave address.
* Returns error if the slave address is present in table */
if(I3cMasterGetAddrPos(i3c, value) < 0)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
ARM_I3C_DEV_PRIME_INFO *prime_info = (ARM_I3C_DEV_PRIME_INFO*)data;
i3c_dev_prime_info_t p_info;
/* Gets slave characteristics */
i3c_master_get_dct(i3c->regs, &p_info, value);
prime_info->dev_char.static_addr = p_info.dev_char.static_addr;
prime_info->dev_char.bcr = p_info.dev_char.bcr;
prime_info->dev_char.dcr = p_info.dev_char.dcr;
prime_info->dev_char.dynamic_addr = p_info.dev_char.dynamic_addr;
prime_info->pid.dcr = p_info.pid.dcr;
prime_info->pid.inst_id = p_info.pid.inst_id;
prime_info->pid.part_id = p_info.pid.part_id;
prime_info->pid.pid_sel = p_info.pid.pid_sel;
prime_info->pid.mipi_mfg_id = p_info.pid.mipi_mfg_id;
}
else
{
/* Performs the following if it's a master */
/* Considering value as the count of slaves.
* Returns error if the slave count is more than
* max supported slaves */
if(value > i3c->slave_dat.maxdevs)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
ARM_I3C_DEV_CHAR *char_info = (ARM_I3C_DEV_CHAR*)data;
/* Create device characteristics array of specified length */
i3c_dev_char_t dev_chr[I3C_MAX_DEVS];
/* Secondary master fetches slaves' characteristics */
i3c_sec_master_get_dct(i3c->regs, dev_chr, value);
/* Store the Device characteristics info */
for(iter = 0U; iter < value; iter++)
{
char_info->static_addr = dev_chr[iter].static_addr;
char_info->bcr = dev_chr[iter].bcr;
char_info->dcr = dev_chr[iter].dcr;
char_info->dynamic_addr = dev_chr[iter].dynamic_addr;
char_info++;
}
}
return ARM_DRIVER_OK;
}
/**
\fn int I3Cx_GetSlaveList(I3C_RESOURCES *i3c,
uint8_t* addr_list,
uint8_t count)
\brief Fetches the slaves list from address table
\param[in] i3c : Pointer to i3c resources structure
\param[in] addr_list : Slave address list
\param[in] count : Slaves count
\return \ref execution_status
*/
static int I3Cx_GetSlaveList(I3C_RESOURCES *i3c,
uint8_t* addr_list,
uint8_t* count)
{
uint8_t pos = 0U;
if((!addr_list) || (!count))
{
return ARM_DRIVER_ERROR_PARAMETER;
}
(*count) = 0U;
/* Fetches all valid slave addresses*/
for (pos = 0; pos < i3c->slave_dat.maxdevs; pos++)
{
if (!(i3c->slave_dat.freepos & (1 << pos)))
{
*addr_list = (i3c->slave_dat.addrs[pos] &
(~I3C_TARGET_SLAVE_TYPE_I2C));
addr_list++;
(*count)++;
}
}
return ARM_DRIVER_OK;
}
/**
\fn static void I3C_DetachSlaves(I3C_RESOURCES *i3c,
uint8_t slv_cnt)
\brief Detach already attached i3c devices from the i3c bus.
\param[in] i3c : Pointer to i3c resources structure
\param[in] slv_cnt : Slaves count
\param[in] ccc_cmd : CCC command
\return None
*/
static void I3C_DetachSlaves(I3C_RESOURCES *i3c,
uint8_t slv_cnt,
uint32_t ccc_cmd)
{
int8_t pos = 0;
if((ccc_cmd == I3C_CCC_ENTDAA) ||
(ccc_cmd == I3C_CCC_SETDASA))
{
/* Perform the following when ENTDAA or SETDASA failed */
for(pos = i3c->slave_dat.maxdevs; ((pos > 0) && (slv_cnt)); pos--)
{
if(i3c->slave_dat.last_asgd_addr_pos & (1U << (pos - 1U)))
{
/* free the index */
i3c->slave_dat.freepos |= (BIT(pos - 1U));
i3c->slave_dat.addrs[(pos - 1U)] = 0U;
/* clear the DAT index pos */
i3c_remove_slv_from_dat(i3c->regs, (pos - 1U));
slv_cnt--;
}
}
}
else if(ccc_cmd == I3C_CCC_RSTDAA(false))
{
/* Perform the following when Direct RSTDAA is successful */
pos = I3cMasterGetAddrPos(i3c,
(i3c->slave_dat.addrs[i3c->xfer.xfer_cmd.addr_index] &
(~I3C_TARGET_SLAVE_TYPE_I2C)));
if(pos >= 0)
{
i3c->slave_dat.freepos |= (BIT(pos));
i3c->slave_dat.addrs[pos] = 0U;
i3c_remove_slv_from_dat(i3c->regs, pos);
}
}
else if(ccc_cmd == I3C_CCC_RSTDAA(true))
{
/* Perform the following when broadcast RSTDAA is successful */
for(pos = 0; pos < ((int8_t)i3c->slave_dat.maxdevs); pos++)
{
/* Detaches only I3C slaves */
if((!(i3c->slave_dat.freepos & (1U << pos))) &&
(!(i3c->slave_dat.addrs[pos] & I3C_TARGET_SLAVE_TYPE_I2C)))
{
i3c_remove_slv_from_dat(i3c->regs, pos);
i3c->slave_dat.freepos |= (BIT(pos));
i3c->slave_dat.addrs[pos] = 0U;
}
}
}
else if(ccc_cmd == I3C_CCC_SETNEWDA)
{
/* Perform the following when Direct SETNEWDA is successful */
pos = I3cMasterGetAddrPos(i3c,
(i3c->slave_dat.addrs[i3c->xfer.xfer_cmd.addr_index] &
(~I3C_TARGET_SLAVE_TYPE_I2C)));
if(pos >= 0)
{
/* Update the slave address with new one */
i3c->slave_dat.addrs[pos] = (*((uint8_t*)i3c->xfer.tx_buf) >> 1U);
i3c_update_slv_addr_in_dat(i3c->regs,
pos,
(*((uint8_t*)i3c->xfer.tx_buf) >> 1U));
}
}
}
/**
\fn int I3C_AddDynamicAddrParity(uint8_t *dyn_addr)
\brief Generates and adds the parity to dynamic address
\param[in] dyn_addr : Dynamic address
\return None
*/
static void I3C_AddDynamicAddrParity(uint8_t *dyn_addr)
{
uint8_t bit_iter = 0U;
uint8_t xor_value = 0U;
/* XOR the 1st 7 bits of dynamic address*/
xor_value = ((*dyn_addr) & (1U << 0U));
for(bit_iter = 1U; bit_iter < 7U; bit_iter++)
{
xor_value ^= (((*dyn_addr) >> bit_iter) & 1U);
}
/* Assign the negated XOR value to 7th
* bit of dynamic address */
*dyn_addr |= ((~xor_value) << 7U);
}
/**
\fn ARM_DRIVER_VERSION I3C_GetVersion(void)
\brief Get i3c driver version
\return i3c driver version
*/
static ARM_DRIVER_VERSION I3C_GetVersion(void)
{
return DriverVersion;
}
/**
\fn ARM_I3C_CAPABILITIES I3C_GetCapabilities(void)
\brief Get i3c driver capabilities
\return i3c driver capabilities
*/
static ARM_I3C_CAPABILITIES I3C_GetCapabilities(void)
{
return DriverCapabilities;
}
/**
\fn ARM_I3C_STATUS I3Cx_GetStatus(I3C_RESOURCES *i3c)
\brief Get i3c driver status
\return i3c driver status
*/
static ARM_I3C_STATUS I3Cx_GetStatus(I3C_RESOURCES *i3c)
{
/* Returns Current I3C driver status */
i3c->status.mode = i3c->state.is_master;
i3c->status.ibi_slv_addr = i3c->xfer.addr;
/* Fetch the last error found */
switch(i3c->xfer.error)
{
case I3C_COMM_ERROR_CRC:
i3c->status.last_error_code = ARM_I3C_LEC_CRC_ERROR;
break;
case I3C_COMM_ERROR_PARITY:
i3c->status.last_error_code = ARM_I3C_LEC_PARITY_ERROR;
break;
case I3C_COMM_ERROR_FRAME:
i3c->status.last_error_code = ARM_I3C_LEC_FRAME_ERROR;
break;
case I3C_COMM_ERROR_IBA_NACK:
i3c->status.last_error_code = ARM_I3C_LEC_IBA_NACK_ERROR;
break;
case I3C_COMM_ERROR_ADDR_NACK:
i3c->status.last_error_code = ARM_I3C_LEC_ADDR_NACK_ERROR;
break;
case I3C_COMM_ERROR_BUF_UNDR_OVR_FLW:
i3c->status.last_error_code = ARM_I3C_LEC_BUF_UNDER_OVERFLOW_ERROR;
break;
case I3C_COMM_ERROR_XFER_ABORT:
i3c->status.last_error_code = ARM_I3C_LEC_TRANSFER_ABORT_ERROR;
break;
case I3C_COMM_ERROR_I2C_SLV_W_NACK:
i3c->status.last_error_code = ARM_I3C_LEC_I2C_SLAVE_NACK_ERROR;
break;
case I3C_COMM_ERROR_PEC_OR_EARLY_TERM:
if(i3c->state.is_master)
{
i3c->status.last_error_code = ARM_I3C_LEC_PEC_BYTE_ERROR;
}
else
{
i3c->status.last_error_code = ARM_I3C_LEC_EARLY_TERMINATION_ERROR;
}
break;
default:
i3c->status.last_error_code = ARM_I3C_LEC_NO_ERROR;
break;
}
return i3c->status;
}
/**
\fn ARM_I3C_DEVICE_INFO I3Cx_GetDeviceInfo(I3C_RESOURCES *i3c)
\brief Get i3c device information
\return i3c driver info
*/
static ARM_I3C_DEVICE_INFO I3Cx_GetDeviceInfo(I3C_RESOURCES *i3c)
{
ARM_I3C_DEVICE_INFO dev_info;
i3c_slave_pid_t slv_pid;
/* Fetch the device information from low level and return */
dev_info.prime_info.dev_char.static_addr = i3c_get_static_addr(i3c->regs);
dev_info.prime_info.dev_char.dynamic_addr = i3c_get_dynamic_addr(i3c->regs);
dev_info.prime_info.dev_char.dcr = i3c_get_dcr(i3c->regs);
dev_info.prime_info.dev_char.bcr = i3c_get_bcr(i3c->regs);
if(i3c->state.is_master)
{
/* Fetch master specific information */
dev_info.max_read_len = I3C_MAX_DATA_BUF_SIZE;
dev_info.max_write_len = I3C_MAX_DATA_BUF_SIZE;
dev_info.max_read_speed = 0U;
dev_info.max_write_speed = 0U;
dev_info.max_read_turnaround = 0U;
memset(&dev_info.prime_info.pid, 0, sizeof(ARM_I3C_SLV_PID));
}
else
{
/* Fetch slave specific information */
dev_info.max_read_len = i3c_slave_get_max_read_len(i3c->regs);
dev_info.max_write_len = i3c_slave_get_max_write_len(i3c->regs);
dev_info.max_read_speed = i3c_slave_get_max_read_speed(i3c->regs);
dev_info.max_write_speed = i3c_slave_get_max_write_speed(i3c->regs);
dev_info.max_read_turnaround = i3c_slave_get_max_read_turn(i3c->regs);
slv_pid = i3c_slave_get_pid(i3c->regs);
dev_info.prime_info.pid.dcr = slv_pid.dcr;
dev_info.prime_info.pid.inst_id = slv_pid.inst_id;
dev_info.prime_info.pid.part_id = slv_pid.part_id;
dev_info.prime_info.pid.pid_sel = slv_pid.pid_sel;
dev_info.prime_info.pid.mipi_mfg_id = slv_pid.mipi_mfg_id;
}
return dev_info;
}
/**
\fn int I3Cx_MasterSendCommand(I3C_RESOURCES *i3c, ARM_I3C_CMD *ccc)
\brief Send an I3C command to the slave
\param[in] i3c : Pointer to i3c resources structure
\param[in] ccc : Pointer to i3c command structure
\return \ref execution_status
*/
static int I3Cx_MasterSendCommand(I3C_RESOURCES *i3c, ARM_I3C_CMD *ccc)
{
int32_t index;
if (i3c->state.powered == 0U)
return ARM_DRIVER_ERROR;
if (i3c->status.busy)
return ARM_DRIVER_ERROR_BUSY;
if (!ccc)
return ARM_DRIVER_ERROR_PARAMETER;
if(ccc->len > I3C_MAX_DATA_BUF_SIZE)
return ARM_DRIVER_ERROR_PARAMETER;
index = I3cMasterGetAddrPos(i3c, ccc->addr);
if (index < 0)
{
/* Returns error if it is a Direct CCC
* and no such slave present.*/
if(ccc->cmd_id & I3C_CCC_DIRECT)
{
return ARM_DRIVER_ERROR;
}
}
i3c->status.busy = 1;
i3c->xfer.error = 0U;
if (ccc->rw) /* command read */
{
i3c->xfer.tx_buf = NULL;
i3c->xfer.tx_len = 0U;
i3c->xfer.rx_buf = ccc->data;
i3c->xfer.rx_len = ccc->len;
i3c->xfer.xfer_cmd.cmd_type = I3C_XFER_CCC_GET;
i3c->xfer.xfer_cmd.cmd_id = ccc->cmd_id;
i3c->xfer.xfer_cmd.addr_index = index;
i3c->xfer.xfer_cmd.addr_depth = 1U;
i3c->xfer.xfer_cmd.def_byte = ccc->def_byte;
i3c->xfer.xfer_cmd.data_len = ccc->len;
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
{
/* Invoke xfer cmd blocking api */
i3c_send_xfer_cmd_blocking(i3c->regs, &i3c->xfer);
i3c->status.busy = 0U;
if(!(i3c->xfer.status & I3C_XFER_STATUS_DONE))
{
/* Resume the device if error occurs */
i3c_resume(i3c->regs);
return ARM_DRIVER_ERROR;
}
}
else
#endif
{
/* Invoke xfer cmd api */
i3c_send_xfer_cmd(i3c->regs, &(i3c->xfer));
}
} /* command read */
else /* command write */
{
if(ccc->cmd_id == I3C_CCC_ENTHDR(0U))
{
/* Set speed to HDR-DDR speed */
i3c->xfer.xfer_cmd.speed = I3C_SPEED_HDR_DDR;
i3c->status.busy = 0;
}
else if((ccc->cmd_id > I3C_CCC_ENTHDR(0U)) &&
(ccc->cmd_id <= I3C_CCC_ENTHDR(7U)))
{
/* Return unsupported if other HDR-DDR speeds requested */
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
else
{
i3c->xfer.rx_buf = NULL;
i3c->xfer.rx_len = 0U;
i3c->xfer.tx_buf = ccc->data;
i3c->xfer.tx_len = ccc->len;
i3c->xfer.xfer_cmd.cmd_type = I3C_XFER_CCC_SET;
i3c->xfer.xfer_cmd.cmd_id = ccc->cmd_id;
i3c->xfer.xfer_cmd.addr_index = index;
i3c->xfer.xfer_cmd.addr_depth = 1U;
i3c->xfer.xfer_cmd.def_byte = ccc->def_byte;
i3c->xfer.xfer_cmd.data_len = ccc->len;
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
{
/* Invoke xfer cmd blocking api */
i3c_send_xfer_cmd_blocking(i3c->regs, &i3c->xfer);
i3c->status.busy = 0U;
if(i3c->xfer.status != I3C_XFER_STATUS_DONE)
{
/* Resume the device if error occurs */
i3c_resume(i3c->regs);
return ARM_DRIVER_ERROR;
}
else
{
/* If RSTDAA or SETNEWDA command is successful
* then invoke detach slave fuction to remove slaves' info */
if((i3c->xfer.xfer_cmd.cmd_id == I3C_CCC_RSTDAA(true)) ||
(i3c->xfer.xfer_cmd.cmd_id == I3C_CCC_RSTDAA(false)) ||
(i3c->xfer.xfer_cmd.cmd_id == I3C_CCC_SETNEWDA))
{
I3C_DetachSlaves(i3c,
i3c->xfer.tx_len,
i3c->xfer.xfer_cmd.cmd_id);
}
}
}
else
#endif
{
/* Invoke xfer cmd api */
i3c_send_xfer_cmd(i3c->regs, &i3c->xfer);
}
}
}
return ARM_DRIVER_OK;
}
/*
* Note for I3C DMA:
* For proper Master and Slave communication,
* There should be fix protocol between Master and Slave,
* in which both should be knowing well in advanced that
* how much data is going to transmit/receive from both the sides.
* (currently different-different transfer data length from
* Master and Slave is not supported.)
*/
/**
\fn int I3Cx_MasterTransmit(I3C_RESOURCES *i3c, uint8_t addr,
const uint8_t *data, uint16_t len)
\brief Write data to the slave
\param[in] i3c : Pointer to i3c resources structure
\param[in] addr : Assigned Slave Address;
Dynamic Address for i3c, Static Address for i2c slave device
\param[in] data : Pointer to buffer with data which needs to be transmit to slave
\param[in] len : Number of bytes needs to be transmit
\return \ref execution_status
*/
static int I3Cx_MasterTransmit(I3C_RESOURCES *i3c, uint8_t addr,
const uint8_t *data, uint16_t len)
{
int32_t index;
#if I3C_DMA_ENABLE
int32_t ret;
#endif
if (i3c->state.powered == 0U)
return ARM_DRIVER_ERROR;
/* Checking for Master initialization */
if ((!i3c->state.enabled) ||
(!i3c->state.is_master))
return ARM_DRIVER_ERROR;
if (!data || !len)
return ARM_DRIVER_ERROR_PARAMETER;
if(len > I3C_MAX_DATA_BUF_SIZE)
return ARM_DRIVER_ERROR_PARAMETER;
if (i3c->status.busy)
return ARM_DRIVER_ERROR_BUSY;
index = I3cMasterGetAddrPos(i3c, addr);
if (index < 0)
return ARM_DRIVER_ERROR_PARAMETER;
i3c->status.busy = 1;
i3c->xfer.error = 0U;
i3c->xfer.rx_buf = NULL;
i3c->xfer.rx_len = 0U;
i3c->xfer.xfer_cmd.addr_index = index;
i3c->xfer.xfer_cmd.data_len = len;
#if (!I3C_DMA_ENABLE) /* update only if DMA disable */
i3c->xfer.tx_buf = data;
i3c->xfer.tx_len = len;
#else
i3c->xfer.tx_buf = NULL;
i3c->xfer.tx_len = 0U;
#endif
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
{
/* Invoke master send blocking api */
i3c_master_tx_blocking(i3c->regs, &i3c->xfer);
i3c->status.busy = 0U;
/* Sets the speed to SDR Maximum */
i3c->xfer.xfer_cmd.speed = I3C_SPEED_SDR0;
if(!(i3c->xfer.status & I3C_XFER_STATUS_MST_TX_DONE))
{
/* Resume the device if error occurs */
i3c_resume(i3c->regs);
return ARM_DRIVER_ERROR;
}
}
else
#endif
{
/* Invoke master send api */
i3c_master_tx(i3c->regs, &i3c->xfer);
}
#if I3C_DMA_ENABLE
ret = I3C_DMA_Start_TX(i3c, data, len);
if(ret)
{
return ARM_DRIVER_ERROR;
}
#endif
return ARM_DRIVER_OK;
}
/**
\fn int I3Cx_MasterReceive(I3C_RESOURCES *i3c, uint8_t addr,
uint8_t *data, uint16_t len)
\brief Read data from the slave
\param[in] i3c : Pointer to i3c resources structure
\param[in] addr : Assigned Slave Address;
Dynamic Address for i3c, Static Address for i2c slave device
\param[in] data : Pointer to buffer for data to receive from slave
\param[in] len : Number of bytes needs to be receive
\return \ref execution_status
*/
static int I3Cx_MasterReceive(I3C_RESOURCES *i3c, uint8_t addr,
uint8_t *data, uint16_t len)
{
int32_t index;
#if I3C_DMA_ENABLE
int32_t ret;
#endif
if (i3c->state.powered == 0U)
return ARM_DRIVER_ERROR;
/* Checking for Master initialization */
if ((!i3c->state.enabled) ||
(!i3c->state.is_master))
return ARM_DRIVER_ERROR;
if (!data || !len)
return ARM_DRIVER_ERROR_PARAMETER;
if(len > I3C_MAX_DATA_BUF_SIZE)
return ARM_DRIVER_ERROR_PARAMETER;
if (i3c->status.busy)
return ARM_DRIVER_ERROR_BUSY;
index = I3cMasterGetAddrPos(i3c, addr);
if (index < 0)
return ARM_DRIVER_ERROR_PARAMETER;
i3c->status.busy = 1;
i3c->xfer.error = 0U;
i3c->xfer.tx_buf = NULL;
i3c->xfer.tx_len = 0U;
i3c->xfer.xfer_cmd.addr_index = index;
i3c->xfer.xfer_cmd.data_len = len;
i3c->xfer.rx_len = len;
#if (!I3C_DMA_ENABLE) /* update only if DMA disable */
i3c->xfer.rx_buf = data;
#else
i3c->xfer.rx_buf = NULL;
#endif
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
{
/* Invoke master receive blocking api */
i3c_master_rx_blocking(i3c->regs, &i3c->xfer);
i3c->status.busy = 0U;
/* Sets the speed to SDR Maximum */
i3c->xfer.xfer_cmd.speed = I3C_SPEED_SDR0;
if(!(i3c->xfer.status & I3C_XFER_STATUS_MST_RX_DONE))
{
/* Resume the device if error occurs */
i3c_resume(i3c->regs);
return ARM_DRIVER_ERROR;
}
}
else
#endif
{
/* Invoke master receive api */
i3c_master_rx(i3c->regs, &i3c->xfer);
}
#if I3C_DMA_ENABLE
ret = I3C_DMA_Start_RX(i3c, data, len);
if(ret)
{
return ARM_DRIVER_ERROR;
}
#endif
return ARM_DRIVER_OK;
}
/**
\fn int I3Cx_SlaveTransmit(I3C_RESOURCES *i3c,
const uint8_t *data,
uint16_t len)
\brief Write data to the master
\param[in] i3c : Pointer to i3c resources structure
\param[in] data : Pointer to buffer with data
which needs to be transmit to master
\param[in] len : Number of bytes needs to be transmit
\return \ref execution_status
*/
static int I3Cx_SlaveTransmit(I3C_RESOURCES *i3c,
const uint8_t *data,
uint16_t len)
{
#if I3C_DMA_ENABLE
int32_t ret;
#endif
/* Checking for power done initialization */
if (i3c->state.powered == 0U)
return ARM_DRIVER_ERROR;
/* Checking for slave initialization */
if ((!i3c->state.enabled) ||
(i3c->state.is_master))
return ARM_DRIVER_ERROR;
/* Parameter check */
if (!data || !len)
return ARM_DRIVER_ERROR_PARAMETER;
if((len > i3c_slave_get_max_write_len(i3c->regs)) ||
(len > I3C_MAX_DATA_BUF_SIZE))
{
/* Return error if required legth is greater than
* Master Set Max Write Length or I3C_MAX_DATA_BUF_SIZE */
return ARM_DRIVER_ERROR_PARAMETER;
}
if (i3c->status.busy)
return ARM_DRIVER_ERROR_BUSY;
i3c->status.busy = 1;
i3c->xfer.error = 0U;
i3c->xfer.rx_buf = NULL;
i3c->xfer.rx_len = 0U;
i3c->xfer.xfer_cmd.data_len = len;
i3c->xfer.tx_len = len;
#if (!I3C_DMA_ENABLE) /* update only if DMA disable */
i3c->xfer.tx_buf = data;
#else
i3c->xfer.tx_buf = NULL;
#endif
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
{
/* Invoke slave transmit blocking api */
i3c_slave_tx_blocking(i3c->regs, &i3c->xfer);
i3c->status.busy = 0U;
if(!(i3c->xfer.status & I3C_XFER_STATUS_SLV_TX_DONE))
{
/* Resume the device if error occurs */
i3c_resume(i3c->regs);
return ARM_DRIVER_ERROR;
}
}
else
#endif
{
/* Invoke slave transmit api */
i3c_slave_tx(i3c->regs, &i3c->xfer);
}
#if I3C_DMA_ENABLE
ret = I3C_DMA_Start_TX(i3c, data, len);
if(ret)
{
return ARM_DRIVER_ERROR;
}
#endif
return ARM_DRIVER_OK;
}
/**
\fn int I3Cx_SlaveReceive(I3C_RESOURCES *i3c,
uint8_t *data,
uint32_t len)
\brief Read data from the master
\param[in] i3c : Pointer to i3c resources structure
\param[in] data : Pointer to buffer for data
to receive from master
\param[in] len : Number of bytes needs to be receive
\return \ref execution_status
*/
static int I3Cx_SlaveReceive(I3C_RESOURCES *i3c,
uint8_t *data,
uint32_t len)
{
#if I3C_DMA_ENABLE
int32_t ret;
#endif
/* Checking for power done initialization */
if (i3c->state.powered == 0U)
return ARM_DRIVER_ERROR;
/* Checking for slave initialization */
if ((!i3c->state.enabled) ||
(i3c->state.is_master))
return ARM_DRIVER_ERROR;
/* Parameter check */
if (!data || !len)
return ARM_DRIVER_ERROR_PARAMETER;
if((len > i3c_slave_get_max_read_len(i3c->regs)) ||
(len > I3C_MAX_DATA_BUF_SIZE))
{
/* Return error if required legth is greater than
* Master Set Max Read Length or I3C_MAX_DATA_BUF_SIZE */
return ARM_DRIVER_ERROR_PARAMETER;
}
if (i3c->status.busy)
return ARM_DRIVER_ERROR_BUSY;
i3c->status.busy = 1;
i3c->xfer.error = 0U;
i3c->xfer.tx_buf = NULL;
i3c->xfer.tx_len = 0;
i3c->xfer.rx_len = len;
#if (!I3C_DMA_ENABLE) /* update only if DMA disable */
/* Buffer initialization for TX/RX */
i3c->xfer.rx_buf = data;
#else
i3c->xfer.rx_buf = NULL;
#endif
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
{
/* Invoke slave receive blocking api */
i3c_slave_rx_blocking(i3c->regs, &i3c->xfer);
i3c->status.busy = 0U;
if(!(i3c->xfer.status & I3C_XFER_STATUS_SLV_RX_DONE))
{
/* Resume the device if error occurs */
i3c_resume(i3c->regs);
return ARM_DRIVER_ERROR;
}
}
else
#endif
{
/* Invoke slave receive api */
i3c_slave_rx(i3c->regs, &i3c->xfer);
}
#if I3C_DMA_ENABLE
ret = I3C_DMA_Start_RX(i3c, data, len);
if(ret)
{
return ARM_DRIVER_ERROR;
}
#endif
return ARM_DRIVER_OK;
}
/**
\fn int I3Cx_MasterAssignDA(I3C_RESOURCES *i3c,
ARM_I3C_CMD *addr_cmd)
\brief Assign dynamic address to the i3c slave using
ENTDAA and SETDASA
Note: Only required for i3c slave devices;
i2c slave device uses static address
for communication \ref I3Cx_AttachSlvDev.
\param[in] i3c : Pointer to i3c resources structure
\param[in] addr_cmd : Address CCC
\return \ref execution_status
*/
static int I3Cx_MasterAssignDA(I3C_RESOURCES *i3c,
ARM_I3C_CMD *addr_cmd)
{
int32_t pos = 0U;
uint8_t init_pos = 0xFFU;
uint8_t iter = 0U;
uint8_t dyn_addr = 0U;
if (i3c->state.powered == 0U)
return ARM_DRIVER_ERROR;
if (i3c->status.busy)
return ARM_DRIVER_ERROR_BUSY;
/* Perform below if it is ENTDAA CCC */
if(addr_cmd->cmd_id == I3C_CCC_ENTDAA)
{
if(!addr_cmd->len)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
else if(addr_cmd->len > i3c->slave_dat.maxdevs)
{
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
for(iter = 0U; iter < addr_cmd->len; iter++)
{
pos = I3cMasterGetFreePos(i3c);
/* the dat is full */
if (pos < 0)
{
if(init_pos == 0xFFU)
return ARM_DRIVER_ERROR;
else
break;
}
else
{
/* reserve the index */
i3c->slave_dat.freepos &= ~(BIT(pos));
i3c->slave_dat.last_asgd_addr_pos |= (BIT(pos));
/* we start assigning addresses from 0x09 */
addr_cmd->addr = (pos + I3C_NEXT_SLAVE_ADDR_OFFSET);
while(true)
{
/* Checks if new address is not a self address and
* not already assigned to some slave. If true then,
* assign it otherwise increment it */
if((I3cMasterGetAddrPos(i3c, addr_cmd->addr) < 0) &&
(i3c_get_dynamic_addr(i3c->regs) != addr_cmd->addr))
{
break;
}
else
{
addr_cmd->addr++;
}
}
i3c->slave_dat.addrs[pos] = addr_cmd->addr;
i3c->slave_dat.addrs[pos] &= (~I3C_TARGET_SLAVE_TYPE_I2C);
I3C_AddDynamicAddrParity(&addr_cmd->addr);
/* We have space in the dat,
* program the dat in index pos */
i3c_add_slv_to_dat(i3c->regs, pos,
addr_cmd->addr,
0);
}
/* Stores first found free address position in
* init position*/
if(init_pos == 0xFFU)
{
init_pos = pos;
}
}
i3c->xfer.xfer_cmd.cmd_id = addr_cmd->cmd_id;
i3c->xfer.xfer_cmd.addr_index = init_pos;
i3c->xfer.xfer_cmd.addr_depth = addr_cmd->len;
}
else
{
/*Returns error if slave static address is invalid */
if (!addr_cmd->addr)
return ARM_DRIVER_ERROR_PARAMETER;
/* Find the first unused index in freepos, note that this also
* corresponds to the first unused location in the DAT
*/
pos = I3cMasterGetFreePos(i3c);
/* the dat is full */
if (pos < 0)
{
return ARM_DRIVER_ERROR;
}
/* reserve the index */
i3c->slave_dat.freepos &= ~(BIT(pos));
i3c->slave_dat.last_asgd_addr_pos |= (BIT(pos));
/* we start assigning addresses from 0x09 */
dyn_addr = pos + I3C_NEXT_SLAVE_ADDR_OFFSET;
while(true)
{
/* Checks if new address is not a self address and
* not already assigned to some slave. If true then,
* assign it otherwise increment it */
if((I3cMasterGetAddrPos(i3c, dyn_addr) < 0) &&
(i3c_get_dynamic_addr(i3c->regs) != dyn_addr))
{
break;
}
else
{
dyn_addr++;
}
}
i3c->slave_dat.addrs[pos] = dyn_addr;
i3c->slave_dat.addrs[pos] &= (~I3C_TARGET_SLAVE_TYPE_I2C);
/* We have space in the dat,
* program the dat in index pos */
i3c_add_slv_to_dat(i3c->regs, pos,
dyn_addr,
addr_cmd->addr);
i3c->xfer.xfer_cmd.cmd_id = addr_cmd->cmd_id;
i3c->xfer.xfer_cmd.addr_index = pos;
i3c->xfer.xfer_cmd.addr_depth = 1U;
}
i3c->status.busy = 1U;
i3c->xfer.error = 0U;
i3c->xfer.rx_len = 0U;
i3c->xfer.xfer_cmd.cmd_type = I3C_XFER_TYPE_ADDR_ASSIGN;
i3c->xfer.xfer_cmd.def_byte = addr_cmd->def_byte;
i3c->xfer.xfer_cmd.data_len = 0U;
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
{
i3c->xfer.rx_len = 0U;
i3c_send_xfer_cmd_blocking(i3c->regs, &i3c->xfer);
i3c->status.busy = 0U;
if(i3c->xfer.status != I3C_XFER_STATUS_DONE)
{
/* Error during address assignment,
* so remove slave from Device address table */
I3C_DetachSlaves(i3c, i3c->xfer.rx_len, i3c->xfer.xfer_cmd.cmd_id);
i3c->slave_dat.last_asgd_addr_pos = 0U;
i3c_resume(i3c->regs);
return ARM_DRIVER_ERROR;
}
}
else
#endif
{
i3c_send_xfer_cmd(i3c->regs, &i3c->xfer);
}
return ARM_DRIVER_OK;
}
/**
\fn int I3Cx_AttachSlvDev(I3C_RESOURCES *i3c,
const ARM_I3C_DEVICE_TYPE dev_type,
const uint8_t addr)
\brief Attach legacy i2c device to the i3c bus.
\param[in] i3c : Pointer to i3c resources structure
\param[in] dev_type : i2c/i3c device
\param[in] addr : Static/Dynamic address of slave device
\return \ref execution_status
*/
static int I3Cx_AttachSlvDev(I3C_RESOURCES *i3c,
const ARM_I3C_DEVICE_TYPE dev_type,
const uint8_t addr)
{
int32_t pos;
if (i3c->state.powered == 0U)
return ARM_DRIVER_ERROR;
if (!addr)
return ARM_DRIVER_ERROR_PARAMETER;
/* Return error if the slave is already attached to
* Device address table */
if(I3cMasterGetAddrPos(i3c, addr) >= 0)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
/* Return error if the slave address is same as
* self address */
if(addr == i3c_get_dynamic_addr(i3c->regs))
{
return ARM_DRIVER_ERROR_PARAMETER;
}
/* Find the first unused index in freepos, note that this also
* corresponds to the first unused location in the DAT(Device Address Table) */
pos = I3cMasterGetFreePos(i3c);
/* DAT(Device Address Table) is full? */
if (pos < 0)
{
/* error: DAT is full */
return ARM_DRIVER_ERROR;
}
/* reserve the index */
i3c->slave_dat.freepos &= ~(BIT(pos));
if(dev_type == ARM_I3C_DEVICE_TYPE_I2C)
{
/* ok, we have space in the DAT, store the static address and
* mark as i2c legacy device is present.
*/
i3c->slave_dat.addrs[pos] = (addr | I3C_TARGET_SLAVE_TYPE_I2C);
/* Program the DAT(device address table) in index pos. */
i3c_add_slv_to_dat(i3c->regs, pos, 0, addr);
}
else
{
/* ok, we have space in the DAT, store the i3c address */
i3c->slave_dat.addrs[pos] = addr;
/* Program the DAT(device address table) in index pos.
* Store it as a dynamic address */
i3c_add_slv_to_dat(i3c->regs, pos, addr, 0);
}
return ARM_DRIVER_OK;
}
/**
\fn int I3Cx_Detachdev(I3C_RESOURCES *i3c, uint8_t addr)
\brief Detach already attached i2c/i3c device from the i3c bus.
\param[in] i3c : Pointer to i3c resources structure
\param[in] addr : Static address of already attached i2c device
OR
Dynamic address of already attached i3c device
\return \ref execution_status
*/
static int I3Cx_Detachdev(I3C_RESOURCES *i3c, uint8_t addr)
{
int32_t pos;
if (!addr)
return ARM_DRIVER_ERROR_PARAMETER;
if (i3c->state.powered == 0U)
return ARM_DRIVER_ERROR;
/* Get already attached i2c device address index in
* DAT (device address table). */
pos = I3cMasterGetAddrPos(i3c, addr);
/* i2c i3c is not attached to DAT? */
if (pos < 0)
{
/* err: i2c slave device is not attached to DAT,
* first attach i2c device \ref I3Cx_AttachI2Cdev */
return ARM_DRIVER_ERROR;
}
/* free the index */
i3c->slave_dat.freepos |= (BIT(pos));
i3c->slave_dat.addrs[pos] = 0;
/* clear the DAT index pos */
i3c_remove_slv_from_dat(i3c->regs, pos);
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3Cx_Control(I3C_RESOURCES *i3c,
uint32_t control,
uint32_t arg)
\brief Control i3c master and slave.
\param[in] i3c : Pointer to i3c resources structure
\param[in] control : Operation
\param[in] arg : Argument of operation
\return \ref execution_status
*/
static int32_t I3Cx_Control(I3C_RESOURCES *i3c,
uint32_t control,
uint32_t arg)
{
I3C_I2C_SPEED_MODE i2c_speed_mode = 0;
uint8_t slv_addr = 0U;
int32_t pos = 0;
uint8_t retry_cnt = 0U;
ARM_I3C_SLV_PID *hal_pid;
i3c_slave_pid_t slv_pid;
if (i3c->state.powered == 0U)
return ARM_DRIVER_ERROR;
bool blocking_mode = false;
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
blocking_mode = true;
#endif
switch(control)
{
case I3C_MASTER_INIT:
if(!i3c->state.enabled)
{
/* Sets the dynamic address */
i3c_master_set_dynamic_addr(i3c->regs);
}
/* Initialise master */
i3c_master_init(i3c->regs);
if(!blocking_mode)
{
/* Enables interrupts */
i3c_master_enable_interrupts(i3c->regs);
}
/* set state as master enabled. */
i3c->state.enabled = 1U;
i3c->state.is_master = 1U;
break;
case I3C_MASTER_SET_BUS_MODE:
switch(arg)
{
case I3C_BUS_MODE_MIXED_FAST_I2C_FMP_SPEED_1_MBPS:
case I3C_BUS_MODE_MIXED_FAST_I2C_FM_SPEED_400_KBPS:
case I3C_BUS_MODE_MIXED_SLOW_I2C_SS_SPEED_100_KBPS:
case I3C_BUS_MODE_MIXED_LIMITED:
if(arg == I3C_BUS_MODE_MIXED_FAST_I2C_FMP_SPEED_1_MBPS)
i2c_speed_mode = I3C_I2C_SPEED_MODE_FMP_1_MBPS;
if(arg == I3C_BUS_MODE_MIXED_FAST_I2C_FM_SPEED_400_KBPS)
i2c_speed_mode = I3C_I2C_SPEED_MODE_FM_400_KBPS;
if(arg == I3C_BUS_MODE_MIXED_SLOW_I2C_SS_SPEED_100_KBPS)
i2c_speed_mode = I3C_I2C_SPEED_MODE_SS_100_KBPS;
if(arg == I3C_BUS_MODE_MIXED_LIMITED)
i2c_speed_mode = I3C_I2C_SPEED_MODE_LIMITED;
if (!(i3c->core_clk))
return ARM_DRIVER_ERROR;
/* i2c clock configuration for selected Speed mode. */
i2c_clk_cfg(i3c->regs, i3c->core_clk, i2c_speed_mode);
/* fall through */
case I3C_BUS_SLOW_MODE:
if (!(i3c->core_clk))
return ARM_DRIVER_ERROR;
/* i3c clock configuration */
i3c_slow_bus_clk_cfg(i3c->regs, i3c->core_clk);
break;
case I3C_BUS_NORMAL_MODE:
if (!(i3c->core_clk))
return ARM_DRIVER_ERROR;
/* i3c clock configuration */
i3c_normal_bus_clk_cfg(i3c->regs, i3c->core_clk);
break;
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
break;
case I3C_SLAVE_SET_ADDR:
/* Initialize and Enable i3c Slave */
slv_addr = arg;
i3c_slave_setup_adaptive_mode(i3c->regs, i3c->adaptive_mode);
i3c_slave_init(i3c->regs, slv_addr, i3c->core_clk);
if(!blocking_mode)
{
i3c_slave_enable_interrupts(i3c->regs);
}
/* set state as slave enabled. */
i3c->state.enabled = 1U;
i3c->state.is_master = 0U;
break;
case I3C_MASTER_SET_SLAVE_NACK_RETRY_COUNT:
pos = I3cMasterGetAddrPos(i3c, (uint8_t)arg);
if(pos < 0)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
retry_cnt = ((arg & I3C_SLAVE_NACK_RETRY_COUNT_Msk) >>
I3C_SLAVE_NACK_RETRY_COUNT_Pos);
if(retry_cnt > I3C_SLAVE_NACK_RETRY_COUNT_MAX)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
/* Invoke low level api to set slv nack retry cnt */
i3c_set_slave_nack_retry_cnt(i3c->regs, pos, retry_cnt);
break;
case I3C_SET_SDA_TX_HOLD_TIME:
if(arg > I3C_SDA_TX_HOLD_TIME_MAX)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
/* Sets sda tx hold time */
i3c_set_sda_tx_hold_time(i3c->regs, arg);
break;
case I3C_MASTER_ABORT_MESSAGE_TRANSFER:
i3c_abort_msg_transfer(i3c->regs);
break;
case I3C_MASTER_SETUP_HOT_JOIN_ACCEPTANCE:
/* Sets up HJ acceptability at master side */
i3c_master_setup_hot_join_ctrl(i3c->regs, arg);
break;
case I3C_MASTER_SETUP_MR_ACCEPTANCE:
/* Sets Master Request acceptability at master side */
i3c_master_setup_mst_req_ctrl(i3c->regs, arg);
break;
case I3C_MASTER_SETUP_SIR_ACCEPTANCE:
/* Sets Slave Interrupt Request acceptability at master side */
i3c_master_setup_slv_intr_req_ctrl(i3c->regs, arg);
break;
case I3C_SLAVE_REQUEST_IBI_BUS_MASTERSHIP:
if(i3c_slave_req_bus_mastership(i3c->regs) != 0)
{
return ARM_DRIVER_ERROR;
}
break;
case I3C_SLAVE_SET_IBI_SIR:
/* Sets Slave interrupt request to master */
if(i3c_slave_tx_slv_intr_req(i3c->regs) != 0)
{
return ARM_DRIVER_ERROR;
}
break;
case I3C_SET_DEVICE_CHARACTERISTICS:
/* Sets device's DCR */
i3c_set_dcr(i3c->regs, arg);
break;
case I3C_SLAVE_SET_PID:
if(!arg)
{
return ARM_DRIVER_ERROR_PARAMETER;
}
/* Copy the PID and invoke set pid fun
* to store it */
hal_pid = (ARM_I3C_SLV_PID*)arg;
slv_pid.dcr = hal_pid->dcr;
slv_pid.inst_id = hal_pid->inst_id;
slv_pid.part_id = hal_pid->part_id;
slv_pid.pid_sel = hal_pid->pid_sel;
slv_pid.mipi_mfg_id = hal_pid->mipi_mfg_id;
i3c_slave_set_pid(i3c->regs, slv_pid);
break;
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3Cx_Initialize(I3C_RESOURCES *i3c,
ARM_I3C_SignalEvent_t cb_event)
\brief Initialize the i3c device.
\param[in] i3c : Pointer to i3c resources structure
\param[in] cb_event : Pointer to I3C Event
\ref ARM_I3C_SignalEvent_t
\return \ref execution_status
*/
static int32_t I3Cx_Initialize(I3C_RESOURCES *i3c,
ARM_I3C_SignalEvent_t cb_event)
{
if (i3c->state.initialized == 1)
return ARM_DRIVER_OK;
bool blocking_mode = false;
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
{
blocking_mode = true;
}
#endif
/* If callback function is null in non-blocking mode,
* then sends Error parameter */
if((!blocking_mode) && (!cb_event))
return ARM_DRIVER_ERROR_PARAMETER;
/* set the user callback event. */
i3c->cb_event = cb_event;
#if I3C_DMA_ENABLE
i3c->dma_cfg->dma_rx.dma_handle = -1;
i3c->dma_cfg->dma_tx.dma_handle = -1;
/* Initialize DMA for I3C-Tx */
if(I3C_DMA_Initialize(&i3c->dma_cfg->dma_tx) != ARM_DRIVER_OK)
return ARM_DRIVER_ERROR;
/* Initialize DMA for I3C-Rx */
if(I3C_DMA_Initialize(&i3c->dma_cfg->dma_rx) != ARM_DRIVER_OK)
return ARM_DRIVER_ERROR;
#endif
i3c->core_clk = GetSystemAPBClock();
/* set the state as initialized. */
i3c->state.initialized = 1;
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3Cx_Uninitialize(I3C_RESOURCES *i3c)
\brief Uninitialize the i3c device
\param[in] i3c : Pointer to i3c resources structure
\return \ref execution_status
*/
static int32_t I3Cx_Uninitialize(I3C_RESOURCES *i3c)
{
#if I3C_DMA_ENABLE
i3c->dma_cfg->dma_rx.dma_handle = -1;
i3c->dma_cfg->dma_tx.dma_handle = -1;
#endif
i3c->state.initialized = 0;
return ARM_DRIVER_OK;
}
/**
\fn int32_t I3Cx_PowerControl(I3C_RESOURCES *i3c,
ARM_POWER_STATE state)
\brief i3c power control
\param[in] i3c : Pointer to i3c resources structure
\param[in] state : Power state
\return \ref execution_status
*/
static int32_t I3Cx_PowerControl(I3C_RESOURCES *i3c,
ARM_POWER_STATE state)
{
bool blocking_mode = false;
#if RTE_I3C_BLOCKING_MODE_ENABLE
if(i3c->blocking_mode)
{
blocking_mode = true;
}
#endif
switch (state)
{
case ARM_POWER_OFF:
/* Perform below steps if not blocking mode */
if(!blocking_mode)
{
/* Disable i3c IRQ */
NVIC_DisableIRQ(i3c->irq);
/* Clear Any Pending i3c IRQ */
NVIC_ClearPendingIRQ(i3c->irq);
}
#if I3C_DMA_ENABLE
/* Disable i3c DMA */
i3c_dma_disable(i3c->regs);
/* Deallocate DMA channel for Tx */
if(I3C_DMA_DeAllocate(&i3c->dma_cfg->dma_tx))
return ARM_DRIVER_ERROR;
/* Deallocate DMA channel for Rx */
if(I3C_DMA_DeAllocate(&i3c->dma_cfg->dma_rx))
return ARM_DRIVER_ERROR;
#endif /* I3C_DMA_ENABLE */
/* i3c EXPMST0 control configuration:
* Disable i3c clock. */
disable_i3c_clock();
/* Reset the power state. */
i3c->state.enabled = 0U;
i3c->state.is_master = 0U;
i3c->state.powered = 0;
break;
case ARM_POWER_FULL:
if (i3c->state.initialized == 0U)
return ARM_DRIVER_ERROR;
if (i3c->state.powered)
break;
/* i3c EXPMST0 control configuration:
* Enable i3c clock. */
enable_i3c_clock();
#if I3C_DMA_ENABLE
/* if DMA2 is selected? */
if(i3c->dma_cfg->dma_tx.evtrtr_cfg.instance == 2)
{
select_i3c_dma2();
}
/* else: default DMA0 is selected. */
/* Enable i3c DMA */
i3c_dma_enable(i3c->regs);
#endif /* I3C_DMA_ENABLE */
/* Perform below steps if not blocking mode */
if(!blocking_mode)
{
/* Enable i3c IRQ */
NVIC_ClearPendingIRQ(i3c->irq);
NVIC_SetPriority(i3c->irq, i3c->irq_priority);
NVIC_EnableIRQ(i3c->irq);
}
i3c->slave_dat.datp = i3c_get_dat_addr(i3c->regs);
i3c->slave_dat.maxdevs = i3c_get_dat_depth(i3c->regs);
i3c->slave_dat.freepos = GENMASK(i3c->slave_dat.maxdevs - 1, 0);
/* Set the state as powered */
i3c->state.enabled = 0U;
i3c->state.is_master = 0U;
i3c->state.powered = 1;
break;
default:
return ARM_DRIVER_ERROR_UNSUPPORTED;
}
#if I3C_DMA_ENABLE
/* Power Control DMA for I3C-Tx */
if(I3C_DMA_PowerControl(state, &i3c->dma_cfg->dma_tx) != ARM_DRIVER_OK)
{
i3c->state.powered = 0;
return ARM_DRIVER_ERROR;
}
/* Power Control DMA for I3C-Rx */
if(I3C_DMA_PowerControl(state, &i3c->dma_cfg->dma_rx) != ARM_DRIVER_OK)
{
i3c->state.powered = 0;
return ARM_DRIVER_ERROR;
}
if(state == ARM_POWER_FULL)
{
/* Try to allocate a DMA channel for TX */
if(I3C_DMA_Allocate(&i3c->dma_cfg->dma_tx))
{
i3c->state.powered = 0;
return ARM_DRIVER_ERROR;
}
/* Try to allocate a DMA channel for RX */
if(I3C_DMA_Allocate(&i3c->dma_cfg->dma_rx))
{
i3c->state.powered = 0;
return ARM_DRIVER_ERROR;
}
}
#endif /* I3C_DMA_ENABLE */
return ARM_DRIVER_OK;
}
#if I3C_DMA_ENABLE
/**
\fn static void I3Cx_DMACallback(uint32_t event, int8_t peri_num,
I3C_RESOURCES *i3c)
\brief Callback function from DMA for I3C
\param[in] event Event from DMA
\param[in] peri_num Peripheral number
\param[in] I3C Pointer to I3C resources
\return none
*/
static void I3Cx_DMACallback(uint32_t event, int8_t peri_num,
I3C_RESOURCES *i3c)
{
if(!i3c->cb_event)
return;
/* Transfer Completed */
if(event & ARM_DMA_EVENT_COMPLETE)
{
switch(peri_num)
{
case I3C_DMA_TX_PERIPH_REQ:
/* For DMA TX,
* Success/Error decision will be taken by
* Interrupt Handler based on status of Response-Queue.
* (as this callback will be always called
* irrespective of slave gives ACK/NACK.)
*/
break;
case I3C_DMA_RX_PERIPH_REQ:
/* For DMA RX,
* Success decision will be taken here(DMA RX Callback).
* Error decision will be taken by Interrupt Handler
* based on status of Response-Queue.
*/
/* clear transfer status. */
i3c->xfer.status = I3C_XFER_STATUS_NONE;
/* clear busy flag. */
i3c->status.busy = 0;
/* Mark event as success and call the user callback */
i3c->cb_event(ARM_I3C_EVENT_TRANSFER_DONE);
break;
default:
break;
}
}
/* Abort Occurred */
if(event & ARM_DMA_EVENT_ABORT)
{
}
}
#endif /* RTE_I3C_DMA_ENABLE */
/* I3C Driver Instance */
#if (RTE_I3C)
#if RTE_I3C_DMA_ENABLE
static void I3C_DMACallback(uint32_t event, int8_t peri_num);
static I3C_DMA_HW_CONFIG I3Cx_DMA_HW_CONFIG =
{
.dma_rx =
{
.dma_drv = &ARM_Driver_DMA_(I3C_DMA),
.dma_periph_req = I3C_DMA_RX_PERIPH_REQ,
.evtrtr_cfg =
{
.instance = I3C_DMA,
.group = I3C_DMA_GROUP,
.channel = I3C_DMA_RX_PERIPH_REQ,
.enable_handshake = I3C_DMA_HANDSHAKE_ENABLE,
},
},
.dma_tx =
{
.dma_drv = &ARM_Driver_DMA_(I3C_DMA),
.dma_periph_req = I3C_DMA_TX_PERIPH_REQ,
.evtrtr_cfg =
{
.instance = I3C_DMA,
.group = I3C_DMA_GROUP,
.channel = I3C_DMA_TX_PERIPH_REQ,
.enable_handshake = I3C_DMA_HANDSHAKE_ENABLE,
},
},
};
#endif /* RTE_I3C_DMA_ENABLE */
/* I3C Device Resources */
static I3C_RESOURCES i3c =
{
.regs = (I3C_Type *)I3C_BASE,
.cb_event = (void*)0,
.xfer = {
.xfer_cmd = {0},
.tx_len = 0,
.rx_len = 0,
.tx_buf = (void*)0,
.rx_buf = (void*)0,
.status = I3C_XFER_STATUS_NONE,
.error = 0,
.addr = 0
},
.status = {0},
.state = {0},
#if RTE_I3C_BLOCKING_MODE_ENABLE
.blocking_mode = true,
#endif
.adaptive_mode = RTE_I3C_SLAVE_ADAPTIVE_MODE_ENABLE,
.irq = (IRQn_Type) I3C_IRQ_IRQn,
.irq_priority = RTE_I3C_IRQ_PRI,
#if RTE_I3C_DMA_ENABLE
.dma_cb = I3C_DMACallback,
.dma_cfg = &I3Cx_DMA_HW_CONFIG,
.dma_irq_priority = RTE_I3C_DMA_IRQ_PRI,
#endif
};
#if RTE_I3C_DMA_ENABLE
/**
\fn static void I3C_DMACallback (uint32_t event, int8_t peri_num)
\param[in] event Event from DMA
\param[in] peri_num Peripheral number
\brief Callback function from DMA for I3C
*/
static void I3C_DMACallback(uint32_t event, int8_t peri_num)
{
I3Cx_DMACallback(event, peri_num, &i3c);
}
#endif /* RTE_I3C_DMA_ENABLE */
void I3C_IRQHandler(void)
{
i3c_xfer_t *xfer = &(i3c.xfer);
uint32_t event = 0;
/* Invokes master ISR if the mode is master, else invokes slave ISR */
if(i3c.state.is_master)
{
i3c_master_irq_handler(i3c.regs, xfer);
}
else
{
i3c_slave_irq_handler(i3c.regs, xfer);
}
/* check status: Transfer Error? */
if(xfer->status & I3C_XFER_STATUS_ERROR)
{
#if RTE_I3C_DMA_ENABLE
/* Stop DMA TX transfer */
if(xfer->status & I3C_XFER_STATUS_ERROR_TX)
{
I3C_DMA_Stop(&i3c.dma_cfg->dma_tx);
}
/* Stop DMA RX transfer */
if(xfer->status & I3C_XFER_STATUS_ERROR_RX)
{
I3C_DMA_Stop(&i3c.dma_cfg->dma_rx);
}
#endif /* RTE_I3C_DMA_ENABLE */
/* mark event as Transfer Error. */
event = ARM_I3C_EVENT_TRANSFER_ERROR;
if(xfer->status & I3C_XFER_STATUS_ERROR_ADDR_ASSIGN)
{
/* Error during address assignment,
* so remove slave from Device address table */
I3C_DetachSlaves(&i3c, i3c.xfer.tx_len, i3c.xfer.xfer_cmd.cmd_id);
i3c.slave_dat.last_asgd_addr_pos = 0U;
}
else if(xfer->status & I3C_XFER_STATUS_ERROR_XFER_ABORT)
{
/* mark event as Transfer Error. */
event = ARM_I3C_EVENT_MESSAGE_TRANSFER_ABORT;
}
/* error: Resume i3c controller and
* clear error status. */
i3c_resume(i3c.regs);
i3c_clear_xfer_error(i3c.regs);
} /* if I3C_XFER_STATUS_ERROR */
/* check status: Transfer Success? */
else if(xfer->status & I3C_XFER_STATUS_DONE)
{
/* mark event as Transfer done. */
event = ARM_I3C_EVENT_TRANSFER_DONE;
if(xfer->status & I3C_XFER_STATUS_SLV_HOT_JOIN_REQ)
{
/* mark event as Hot Join request */
event = ARM_I3C_EVENT_IBI_HOT_JOIN_REQ;
}
else if(xfer->status & I3C_XFER_STATUS_IBI_SLV_INTR_REQ)
{
/* mark event as SIR request */
event = ARM_I3C_EVENT_IBI_SLV_INTR_REQ;
}
else if(xfer->status & I3C_XFER_STATUS_DEFSLV_LIST)
{
i3c.status.defslv_cnt = xfer->rx_len;
/* mark event as slave list received */
event = ARM_I3C_EVENT_SLAVE_LIST;
}
else if(xfer->status & I3C_XFER_STATUS_IBI_MASTERSHIP_REQ)
{
if(I3cMasterGetAddrPos(&i3c, xfer->addr) != ARM_DRIVER_ERROR)
{
/* mark event as Mastership request */
event = ARM_I3C_EVENT_IBI_MASTERSHIP_REQ;
}
else
{
/* clear transfer status. */
xfer->status = I3C_XFER_STATUS_NONE;
/* clear busy flag. */
i3c.status.busy = 0;
/* Sets the speed to SDR Maximum */
i3c.xfer.xfer_cmd.speed = I3C_SPEED_SDR0;
return;
}
}
else if(xfer->status & I3C_XFER_STATUS_BUSOWNER_UPDATED)
{
if(i3c_is_master(i3c.regs))
{
i3c.state.is_master = 1U;
}
else
{
i3c.state.is_master = 0U;
memset(&i3c.slave_dat, 0, sizeof(I3C_SLAVE_DAT_TYPE));
}
/* Flushes all buffers and resumes */
i3c_flush_all_buffers(i3c.regs);
i3c_resume(i3c.regs);
/* mark event as Bus owner updated */
event = ARM_I3C_EVENT_BUSOWNER_UPDATED;
}
else if(xfer->status & I3C_XFER_STATUS_ADDR_ASSIGN_DONE)
{
i3c.slave_dat.last_asgd_addr_pos = 0U;
}
else if(xfer->status & I3C_XFER_STATUS_CCC_SET_DONE)
{
if((i3c.xfer.xfer_cmd.cmd_id == I3C_CCC_RSTDAA(true)) ||
(i3c.xfer.xfer_cmd.cmd_id == I3C_CCC_RSTDAA(false)) ||
(i3c.xfer.xfer_cmd.cmd_id == I3C_CCC_SETNEWDA))
{
I3C_DetachSlaves(&i3c,
i3c.xfer.tx_len,
i3c.xfer.xfer_cmd.cmd_id);
}
}
else if(xfer->status & I3C_XFER_STATUS_SLV_CCC_UPDATED)
{
/* mark event as Slave CCC updated */
event = ARM_I3C_EVENT_SLAVE_CCC_UPDATED;
}
/* check status: Slave dynamic address assign? (only for Slave mode) */
else if(xfer->status & I3C_XFER_STATUS_SLV_DYN_ADDR_ASSGN)
{
/* mark event as Slave dynamic address assignment done. */
event = ARM_I3C_EVENT_SLV_DYN_ADDR_ASSGN;
}
#if RTE_I3C_DMA_ENABLE
/* DMA TX,
* Success/Error decision will be taken by
* Interrupt Handler based on status of Response-Queue.
*
* DMA RX,
* Success decision will be taken in DMA_RX callback.
* Error decision will be taken by Interrupt Handler
* based on status of Response-Queue.
*/
if( (xfer->status & I3C_XFER_STATUS_MST_RX_DONE) ||
(xfer->status & I3C_XFER_STATUS_SLV_RX_DONE) )
{
/* for DMA RX Success, mark event as 0. */
event = 0;
/* clear transfer status. */
xfer->status = I3C_XFER_STATUS_NONE;
}
#endif /* RTE_I3C_DMA_ENABLE */
}/* else if I3C_XFER_STATUS_DONE*/
if(event)
{
/* clear transfer status. */
xfer->status = I3C_XFER_STATUS_NONE;
/* clear busy flag. */
i3c.status.busy = 0;
/* call the user callback */
if(i3c.cb_event)
i3c.cb_event(event);
}
/* Sets the speed to SDR Maximum */
i3c.xfer.xfer_cmd.speed = I3C_SPEED_SDR0;
}
/* wrapper functions for I3C */
static ARM_I3C_STATUS I3C_GetStatus(void)
{
return I3Cx_GetStatus(&i3c);
}
static ARM_I3C_DEVICE_INFO I3C_GetDeviceInfo(void)
{
return I3Cx_GetDeviceInfo(&i3c);
}
static int32_t I3C_Initialize(ARM_I3C_SignalEvent_t cb_event)
{
return (I3Cx_Initialize(&i3c, cb_event));
}
static int32_t I3C_Uninitialize(void)
{
return (I3Cx_Uninitialize(&i3c));
}
static int32_t I3C_PowerControl(ARM_POWER_STATE state)
{
return (I3Cx_PowerControl(&i3c, state));
}
static int32_t I3C_MasterTransmit(uint8_t addr, const uint8_t *data, uint16_t len)
{
return (I3Cx_MasterTransmit(&i3c, addr, data, len));
}
static int32_t I3C_MasterReceive(uint8_t addr, uint8_t *data, uint16_t len)
{
return (I3Cx_MasterReceive(&i3c, addr, data, len));
}
static int32_t I3C_SlaveTransmit(const uint8_t *data, uint16_t len)
{
return (I3Cx_SlaveTransmit(&i3c, data, len));
}
static int32_t I3C_SlaveReceive(uint8_t *data, uint16_t len)
{
return (I3Cx_SlaveReceive(&i3c, data, len));
}
static int32_t I3C_MasterSendCommand(ARM_I3C_CMD *ccc)
{
return (I3Cx_MasterSendCommand(&i3c, ccc));
}
static int32_t I3C_Control(uint32_t control, uint32_t arg)
{
return (I3Cx_Control(&i3c, control, arg));
}
static int32_t I3C_MasterAssignDA(ARM_I3C_CMD *addr_cmd)
{
return (I3Cx_MasterAssignDA(&i3c, addr_cmd));
}
static int32_t I3C_AttachSlvdev(const ARM_I3C_DEVICE_TYPE dev_type,
const uint8_t addr)
{
return (I3Cx_AttachSlvDev(&i3c, dev_type, addr));
}
static int32_t I3C_Detachdev(uint8_t addr)
{
return (I3Cx_Detachdev(&i3c, addr));
}
static int32_t I3C_GetSlaveList(uint8_t* addr_list,
uint8_t* count)
{
return I3Cx_GetSlaveList(&i3c, addr_list, count);
}
static int32_t I3C_GetSlaveDynamicAddr(const uint8_t static_addr,
uint8_t *dynamic_addr)
{
return I3Cx_GetSlaveDynamicAddr(&i3c, static_addr, dynamic_addr);
}
static int32_t I3C_GetSlvsInfo(void* data, const uint8_t value)
{
return I3Cx_GetSlvsInfo(&i3c, data, value);
}
/* I3C Driver Control Block */
extern ARM_DRIVER_I3C Driver_I3C;
ARM_DRIVER_I3C Driver_I3C =
{
I3C_GetVersion,
I3C_GetCapabilities,
I3C_GetStatus,
I3C_GetDeviceInfo,
I3C_Initialize,
I3C_Uninitialize,
I3C_PowerControl,
I3C_MasterTransmit,
I3C_MasterReceive,
I3C_SlaveTransmit,
I3C_SlaveReceive,
I3C_Control,
I3C_MasterSendCommand,
I3C_MasterAssignDA,
I3C_AttachSlvdev,
I3C_Detachdev,
I3C_GetSlaveList,
I3C_GetSlaveDynamicAddr,
I3C_GetSlvsInfo
};
#endif /* RTE_I3C */
/************************ (C) COPYRIGHT ALIF SEMICONDUCTOR *****END OF FILE****/