MCUXpresso_MCXA153/components/i3c_bus/fsl_component_i3c.c
Yilin Sun 35e678394a
Initial commit v2.14.2
Signed-off-by: Yilin Sun <imi415@imi.moe>
2024-02-11 19:33:06 +08:00

1171 lines
35 KiB
C

/*
* Copyright 2020, 2022-2023 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "fsl_component_i3c.h"
/*******************************************************************************
* Definitions
******************************************************************************/
/*******************************************************************************
* Prototypes
******************************************************************************/
/*******************************************************************************
* Variables
******************************************************************************/
/*******************************************************************************
* Code
******************************************************************************/
void I3C_BusSetAddrSlot(i3c_bus_t *bus, uint8_t addr, i3c_addr_slot_status_t status)
{
uint16_t bitPos = (uint16_t)addr * I3C_BUS_ADDR_SLOTWIDTH;
uint32_t *slotPtr;
if (addr > I3C_BUS_MAX_ADDR)
{
return;
}
slotPtr = &bus->addrSlots[bitPos / I3C_BUS_ADDR_SLOTDEPTH];
*slotPtr &= ~((uint32_t)I3C_BUS_ADDR_SLOTMASK << (bitPos % I3C_BUS_ADDR_SLOTDEPTH));
*slotPtr |= (uint32_t)status << (bitPos % I3C_BUS_ADDR_SLOTDEPTH);
}
static void I3C_BusInitAddrSlots(i3c_bus_t *bus)
{
uint8_t i;
/* Reserve address 0x0 to 0x7. */
for (i = 0; i < 8U; i++)
{
I3C_BusSetAddrSlot(bus, i, kI3C_Bus_AddrSlot_Reserved);
}
/* Reserve the conditional restriction I3C address. */
I3C_BusSetAddrSlot(bus, 0x78U, kI3C_Bus_AddrSlot_Reserved);
I3C_BusSetAddrSlot(bus, 0x79U, kI3C_Bus_AddrSlot_Reserved);
I3C_BusSetAddrSlot(bus, 0x7BU, kI3C_Bus_AddrSlot_Reserved);
I3C_BusSetAddrSlot(bus, 0x7DU, kI3C_Bus_AddrSlot_Reserved);
/* All are prohibited since I3C targets will interpret an I3C address header with any of these addresses as a
* broadcast address with a single-bit error. */
I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR1, kI3C_Bus_AddrSlot_Reserved);
I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR2, kI3C_Bus_AddrSlot_Reserved);
I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR3, kI3C_Bus_AddrSlot_Reserved);
I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR4, kI3C_Bus_AddrSlot_Reserved);
I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR5, kI3C_Bus_AddrSlot_Reserved);
I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR6, kI3C_Bus_AddrSlot_Reserved);
I3C_BusSetAddrSlot(bus, I3C_BOARDCAST_SINGLE_BIT_ERR_DETECT_ADDR7, kI3C_Bus_AddrSlot_Reserved);
/* Reserve I3C broadcast address. */
I3C_BusSetAddrSlot(bus, I3C_BUS_BROADCAST_ADDR, kI3C_Bus_AddrSlot_Reserved);
}
static uint8_t I3C_BusGetAddrSlotStatus(i3c_bus_t *bus, uint8_t checkAddr)
{
uint16_t bitPos = (uint16_t)checkAddr * 2U;
uint32_t useStatus = 0;
if (checkAddr > I3C_BUS_MAX_ADDR)
{
return (uint8_t)kI3C_Bus_AddrSlot_Reserved;
}
useStatus = bus->addrSlots[bitPos / I3C_BUS_ADDR_SLOTDEPTH];
useStatus >>= bitPos % I3C_BUS_ADDR_SLOTDEPTH;
return (uint8_t)(useStatus & (uint8_t)I3C_BUS_ADDR_SLOTMASK);
}
static status_t I3C_CheckBusMasterOps(i3c_device_hw_ops_t *ops)
{
if ((ops == NULL) || (ops->Init == NULL) || (ops->DoI3CTransfer == NULL) || (ops->DoI2CTransfer == NULL) ||
(ops->TransmitCCC == NULL) || (ops->ProceedDAA == NULL))
{
return kStatus_I3CBus_MasterOpsMissing;
}
return kStatus_Success;
}
static status_t I3C_BusMasterGetMaxReadLength(i3c_device_t *master, i3c_device_information_t *info)
{
i3c_ccc_cmd_t getMRLCmd = {0};
status_t result = kStatus_Success;
getMRLCmd.isRead = true;
getMRLCmd.cmdId = I3C_BUS_CCC_GETMRL;
getMRLCmd.destAddr = info->dynamicAddr;
getMRLCmd.data = malloc(3U);
getMRLCmd.dataSize = 3U;
/*
* When the device does not have IBI payload GETMRL only returns 2
* bytes of data.
*/
if ((info->bcr & I3C_BUS_DEV_BCR_IBI_PAYLOAD_MASK) == 0U)
{
getMRLCmd.dataSize -= 1U;
}
result = I3C_BusMasterSendCCC(master, &getMRLCmd);
uint8_t *pData = getMRLCmd.data;
if ((info->bcr & I3C_BUS_DEV_BCR_IBI_PAYLOAD_MASK) != 0U)
{
info->maxIBILength = pData[2];
}
info->maxReadLength = (uint16_t)pData[0] << 8UL | (uint16_t)pData[1];
free(getMRLCmd.data);
return result;
}
static status_t I3C_BusMasterGetMaxWriteLength(i3c_device_t *master, i3c_device_information_t *info)
{
i3c_ccc_cmd_t getMWLCmd = {0};
status_t result = kStatus_Success;
uint16_t writelen;
getMWLCmd.isRead = true;
getMWLCmd.cmdId = I3C_BUS_CCC_GETMWL;
getMWLCmd.destAddr = info->dynamicAddr;
getMWLCmd.data = &writelen;
getMWLCmd.dataSize = 2U;
result = I3C_BusMasterSendCCC(master, &getMWLCmd);
info->maxWriteLength = writelen;
return result;
}
static status_t I3C_BusMasterGetHDRCapability(i3c_device_t *master, i3c_device_information_t *info)
{
i3c_ccc_cmd_t getHDRCapCmd = {0};
status_t result = kStatus_Success;
uint8_t hdrMode;
getHDRCapCmd.isRead = true;
getHDRCapCmd.cmdId = I3C_BUS_CCC_GETHDRCAP;
getHDRCapCmd.destAddr = info->dynamicAddr;
getHDRCapCmd.data = &hdrMode;
getHDRCapCmd.dataSize = 1U;
result = I3C_BusMasterSendCCC(master, &getHDRCapCmd);
info->hdrMode = hdrMode;
return result;
}
static status_t I3C_BusMasterGetPID(i3c_device_t *master, i3c_device_information_t *info)
{
uint8_t pid[6];
i3c_ccc_cmd_t getPidCmd = {0};
status_t result = kStatus_Success;
getPidCmd.isRead = true;
getPidCmd.cmdId = I3C_BUS_CCC_GETPID;
getPidCmd.destAddr = info->dynamicAddr;
getPidCmd.data = pid;
getPidCmd.dataSize = 6U;
result = I3C_BusMasterSendCCC(master, &getPidCmd);
info->vendorID = (((uint16_t)pid[0] << 8U | (uint16_t)pid[1]) & 0xFFFEU) >> 1U;
info->partNumber = ((uint32_t)pid[2] << 24U | (uint32_t)pid[3] << 16U | (uint32_t)pid[4] << 8U | (uint32_t)pid[5]);
return result;
}
static status_t I3C_BusMasterGetBCR(i3c_device_t *master, i3c_device_information_t *info)
{
uint8_t bcr;
i3c_ccc_cmd_t getBCRCmd = {0};
status_t result = kStatus_Success;
getBCRCmd.isRead = true;
getBCRCmd.cmdId = I3C_BUS_CCC_GETBCR;
getBCRCmd.destAddr = info->dynamicAddr;
getBCRCmd.data = &bcr;
getBCRCmd.dataSize = 1U;
result = I3C_BusMasterSendCCC(master, &getBCRCmd);
info->bcr = bcr;
return result;
}
static status_t I3C_BusMasterGetDCR(i3c_device_t *master, i3c_device_information_t *info)
{
uint8_t dcr;
i3c_ccc_cmd_t getDCRCmd = {0};
status_t result = kStatus_Success;
getDCRCmd.isRead = true;
getDCRCmd.cmdId = I3C_BUS_CCC_GETDCR;
getDCRCmd.destAddr = info->dynamicAddr;
getDCRCmd.data = &dcr;
getDCRCmd.dataSize = 1U;
result = I3C_BusMasterSendCCC(master, &getDCRCmd);
info->dcr = dcr;
return result;
}
static status_t I3C_BusMasterAssignDevDynamicAddr(i3c_device_t *masterDev)
{
i3c_bus_t *i3cBus = masterDev->bus;
status_t result = kStatus_Success;
list_handle_t i3cDevList = &(i3cBus->i3cDevList);
for (list_element_handle_t listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
{
i3c_device_t *tmpDev = (i3c_device_t *)(void *)listItem;
if (tmpDev == masterDev)
{
continue;
}
else if ((tmpDev->initDynamicAddr != 0U) && (tmpDev->info.staticAddr != 0U) && (tmpDev->info.dynamicAddr == 0U))
{
result =
I3C_BusMasterSetDynamicAddrFromStaticAddr(masterDev, tmpDev->info.staticAddr, tmpDev->initDynamicAddr);
if (result != kStatus_Success)
{
return result;
}
tmpDev->info.dynamicAddr = tmpDev->initDynamicAddr;
I3C_BusSetAddrSlot(i3cBus, tmpDev->info.dynamicAddr, kI3C_Bus_AddrSlot_I3CDev);
/* Retrieve device information. */
result = I3C_BusMasterGetDeviceInfo(masterDev, tmpDev->info.dynamicAddr, &tmpDev->info);
if (result != kStatus_Success)
{
return result;
}
}
else
{
/*Empty else to eliminate MISRA 15.7*/
}
}
return result;
}
static status_t I3C_BusMasterAddExistingI3CDevs(i3c_device_t *masterDev)
{
i3c_bus_t *i3cBus = masterDev->bus;
status_t result = kStatus_Success;
list_handle_t i3cDevList = &(i3cBus->i3cDevList);
for (list_element_handle_t listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
{
i3c_device_t *tmpDev = (i3c_device_t *)(void *)listItem;
if (tmpDev == masterDev)
{
continue;
}
else if (tmpDev->ibiInfo != NULL)
{
result = I3C_BusMasterRegisterDevIBI(masterDev, tmpDev, tmpDev->ibiInfo);
if (result != kStatus_Success)
{
return result;
}
}
else
{
/*Fix MISRA violation 15.7*/
}
}
return result;
}
/*!
* brief Add exist I3C device in bus to the bus device list.
*
* This function will simply add the device to the bus device list and set the related address slot.
*
* param bus Pointer to bus structure.
* param dev Pointer to I3C device.
*/
void I3C_BusAddI3CDev(i3c_bus_t *bus, i3c_device_t *dev)
{
/* Chain device into i3c_device_list */
list_handle_t i3cDevList = &bus->i3cDevList;
(void)LIST_AddTail(i3cDevList, &dev->listNode);
if (dev->info.dynamicAddr != 0U)
{
/* Set slot status I3C device */
I3C_BusSetAddrSlot(bus, dev->info.dynamicAddr, kI3C_Bus_AddrSlot_I3CDev);
}
if (dev->info.staticAddr != 0U)
{
/* Set slot status I2C device */
I3C_BusSetAddrSlot(bus, dev->info.staticAddr, kI3C_Bus_AddrSlot_I2CDev);
}
dev->bus = bus;
}
/*!
* brief Add exist I2C device in bus to the bus device list.
*
* This function will simply add the device to the bus device list and set the related address slot.
*
* param bus Pointer to bus structure.
* param dev Pointer to I2C device.
*/
void I3C_BusAddI2CDev(i3c_bus_t *bus, i2c_device_t *dev)
{
/* Chain device into i2c_device_list */
dev->bus = bus;
list_handle_t i2cDevList = &bus->i2cDevList;
(void)LIST_AddTail(i2cDevList, &dev->listNode);
/* Set slot status I2C device */
I3C_BusSetAddrSlot(bus, dev->staticAddr, kI3C_Bus_AddrSlot_I2CDev);
dev->bus = bus;
}
/*!
* brief Get valid address slot in the I3C bus.
*
* This function will search for available address lot in the I3C bus address pool, the search starts from
* the startAddr specified by user input, to end address defined in @ref I3C_BUS_MAX_ADDR. Will return the
* available address if the related address slot is valid.
*
* param bus Pointer to bus structure.
* param startAddr Start address for address slot searching, end address is defined in @ref I3C_BUS_MAX_ADDR.
* return Available address in the bus address pool.
*/
uint8_t I3C_BusGetValidAddrSlot(i3c_bus_t *bus, uint8_t startAddr)
{
uint8_t validAddr = 0xFF;
for (validAddr = startAddr; validAddr < I3C_BUS_MAX_ADDR; validAddr++)
{
if (I3C_BusGetAddrSlotStatus(bus, validAddr) == (uint8_t)kI3C_Bus_AddrSlot_Free)
{
return validAddr;
}
}
return validAddr;
}
/*!
* brief Gets the default configuration structure.
*
* This function initializes the bus configuration structure to a default value. The default
* values are:
* busConfig->busMode = kI3C_Bus_PureMode;
* busConfig->i2cBaudRate = 400000U;
* busConfig->i3cOpenDrainBaudRate = 1500000U;
* busConfig->i3cPushPullBaudRate = 4000000U;
*
* param config Pointer to a configuration structure.
*/
void I3C_BusGetDefaultBusConfig(i3c_bus_config_t *busConfig)
{
busConfig->busMode = kI3C_Bus_PureMode;
busConfig->i2cBaudRate = 400000U;
busConfig->i3cOpenDrainBaudRate = 1500000U;
busConfig->i3cPushPullBaudRate = 4000000U;
}
/*!
* brief Creates I3C bus structure.
*
* This function creates the bus structure with input bus configuration. Address pool set up and device
* list initialize process will be also done in this function call.
*
* param bus Pointer to bus structure.
* param busConfig Pointer to the bus configuration structure.
*/
void I3C_BusCreate(i3c_bus_t *bus, const i3c_bus_config_t *busConfig)
{
assert(bus != NULL);
(void)memset(bus, 0, sizeof(*bus));
LIST_Init(&bus->i2cDevList, 0);
LIST_Init(&bus->i3cDevList, 0);
I3C_BusInitAddrSlots(bus);
bus->busMode = busConfig->busMode;
bus->i2cBaudRate = busConfig->i2cBaudRate;
bus->i3cOpenDrainBaudRate = busConfig->i3cOpenDrainBaudRate;
bus->i3cPushPullBaudRate = busConfig->i3cPushPullBaudRate;
}
/*!
* brief Create I3C master structure on bus.
*
* This function will create I3C master bus structure, initialize the master according to bus characteristics, install
* device information and device control information.
*
* param masterDev Pointer to device structure creating as master.
* param bus Pointer to bus structure.
* param devInfo Pointer to device information structure.
* param masterControlInfo Pointer to master control information structure.
*/
status_t I3C_BusMasterCreate(i3c_device_t *masterDev,
i3c_bus_t *bus,
i3c_device_information_t *devInfo,
i3c_device_control_info_t *masterControlInfo)
{
status_t result = kStatus_Success;
(void)memset(masterDev, 0, sizeof(*masterDev));
masterDev->info = *devInfo;
result = I3C_CheckBusMasterOps(masterControlInfo->funcs);
if (result != kStatus_Success)
{
return result;
}
masterDev->devControlInfo = masterControlInfo;
masterDev->bus = bus;
/* call master init to initialize master */
result = masterControlInfo->funcs->Init(masterDev);
if (result != kStatus_Success)
{
return result;
}
if (!masterControlInfo->isSecondary)
{
bus->currentMaster = masterDev;
/*Add masterDev to bus i3c device list */
I3C_BusAddI3CDev(bus, masterDev);
/* Execute reset DAA CCC command to reset all i3c device dynamic address */
result = I3C_BusMasterResetDAA(masterDev, I3C_BUS_BROADCAST_ADDR);
if (result != kStatus_Success)
{
return result;
}
/* Master assign slave with init dynamic address. */
result = I3C_BusMasterAssignDevDynamicAddr(masterDev);
if (result != kStatus_Success)
{
return result;
}
result = I3C_BusMasterAddExistingI3CDevs(masterDev);
if (result != kStatus_Success)
{
return result;
}
/* Disable all events before start doing DAA. */
result = I3C_BusMasterDisableEvents(masterDev, I3C_BUS_BROADCAST_ADDR,
((uint8_t)kI3C_EventMR | (uint8_t)kI3C_EventHJ | (uint8_t)kI3C_EventIBI));
if (result != kStatus_Success)
{
return result;
}
/* Start to do DAA */
result = I3C_BusMasterDoDAA(masterDev);
if (result != kStatus_Success)
{
return result;
}
/* Enable all events before start doing DAA. */
result = I3C_BusMasterEnableEvents(masterDev, I3C_BUS_BROADCAST_ADDR,
((uint8_t)kI3C_EventMR | (uint8_t)kI3C_EventHJ | (uint8_t)kI3C_EventIBI));
if (result != kStatus_Success)
{
return result;
}
}
return result;
}
/*!
* brief Bus master transfer CCC frame.
*
* Bus master call this function to transfer CCC frame, CCC frame command and data is prepared in @ref i3c_ccc_cmd_t
* structure.
*
* param masterDev Pointer to I3C master device.
* param command Pointer to ccc frame.
*/
status_t I3C_BusMasterSendCCC(i3c_device_t *masterDev, i3c_ccc_cmd_t *command)
{
i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
if (masterDev != masterDev->bus->currentMaster)
{
return kStatus_I3CBus_NotCurrentMaster;
}
if (masterControlInfo->isSecondary)
{
return kStatus_I3CBus_Success;
}
if (NULL == masterControlInfo->funcs->TransmitCCC)
{
return kStatus_I3CBus_MasterOpsUnsupport;
}
return masterControlInfo->funcs->TransmitCCC(masterDev, command);
}
/*!
* brief Bus master reset dynamic assigned address.
*
* Bus master call this function to reset dynamic assigned address, the operation could be done to all connected I3C
* devices by using slave address I3C_BUS_BROADCAST_ADDR or to a specific connected device by using the device's dynamic
* address.
*
* param masterDev Pointer to I3C master device.
* param slaveAddr Slave address, use I3C_BUS_BROADCAST_ADDR as broadcast address.
*/
status_t I3C_BusMasterResetDAA(i3c_device_t *masterDev, uint8_t slaveAddr)
{
i3c_bus_t *i3cBus = masterDev->bus;
uint8_t addrStat;
status_t result;
if (masterDev != masterDev->bus->currentMaster)
{
return kStatus_I3CBus_NotCurrentMaster;
}
addrStat = I3C_BusGetAddrSlotStatus(i3cBus, slaveAddr);
if ((slaveAddr != I3C_BUS_BROADCAST_ADDR) && (addrStat != (uint8_t)kI3C_Bus_AddrSlot_I3CDev))
{
return kStatus_I3CBus_MasterOpsFailure;
}
i3c_ccc_cmd_t rstDaaCmd = {0};
rstDaaCmd.isRead = false;
rstDaaCmd.destAddr = slaveAddr;
rstDaaCmd.cmdId = I3C_BUS_CCC_RSTDAA((slaveAddr != I3C_BUS_BROADCAST_ADDR));
result = I3C_BusMasterSendCCC(masterDev, &rstDaaCmd);
if (result == kStatus_Success)
{
if (slaveAddr != I3C_BUS_BROADCAST_ADDR)
{
/* Do not free current Controller's dynamic address. */
if (masterDev->info.dynamicAddr != slaveAddr)
{
I3C_BusSetAddrSlot(i3cBus, slaveAddr, kI3C_Bus_AddrSlot_Free);
}
}
else
{
for (uint8_t i = 0; i <= I3C_BUS_MAX_ADDR; i++)
{
addrStat = I3C_BusGetAddrSlotStatus(i3cBus, i);
if ((addrStat == (uint8_t)kI3C_Bus_AddrSlot_I3CDev) && (masterDev->info.dynamicAddr != i))
{
I3C_BusSetAddrSlot(i3cBus, i, kI3C_Bus_AddrSlot_Free);
}
}
}
}
return result;
}
/*!
* brief Bus master do dynamic address assignment.
*
* Bus master call this function to do dynamic address assignment to the I3C devices connected on bus.
*
* param masterDev Pointer to I3C master device.
*/
status_t I3C_BusMasterDoDAA(i3c_device_t *masterDev)
{
i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
i3c_bus_t *i3cBus = masterDev->bus;
status_t result = kStatus_Success;
if (masterDev != i3cBus->currentMaster)
{
return kStatus_I3CBus_NotCurrentMaster;
}
result = masterControlInfo->funcs->ProceedDAA(masterDev);
if (result != kStatus_Success)
{
return result;
}
/* Send defslvs command on bus if there's secondary master */
bool isSend = false;
list_handle_t i3cDevList = &(i3cBus->i3cDevList);
for (list_element_handle_t listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
{
i3c_device_t *tmpDev = (i3c_device_t *)(void *)listItem;
if (tmpDev == masterDev)
{
continue;
}
else if ((tmpDev->info.bcr & I3C_BUS_DEV_BCR_DEV_ROLE_MASK) ==
I3C_BUS_DEV_BCR_DEV_ROLE(I3C_BUS_DEV_BCR_DEV_MASTER))
{
isSend = true;
break;
}
else
{
/*Empty else to eliminate MISRA 15.7*/
}
}
if (isSend)
{
result = I3C_BusMasterSendSlavesList(masterDev);
}
return result;
}
/*!
* brief Bus master set device dynamic address from static address.
*
* Bus master call this function to execute SETDASA CCC command to set device dynamic address from static address.
*
* param masterDev Pointer to I3C master device.
* param staticAddr Device static address.
* param initDynamicAddr Device initialized dynamic address.
*/
status_t I3C_BusMasterSetDynamicAddrFromStaticAddr(i3c_device_t *master, uint8_t staticAddr, uint8_t initDynamicAddr)
{
i3c_ccc_cmd_t setdasaCCC = {0};
status_t result = kStatus_Success;
uint8_t dynamicAddr = initDynamicAddr << 1;
setdasaCCC.cmdId = I3C_BUS_CCC_SETDASA;
setdasaCCC.destAddr = staticAddr;
setdasaCCC.data = &dynamicAddr;
setdasaCCC.dataSize = 1U;
setdasaCCC.isRead = false;
result = I3C_BusMasterSendCCC(master, &setdasaCCC);
return result;
}
/*!
* brief Bus master send slave list on bus.
*
* Bus master call this function to send slave list on bus to notify the secondary master.
*
* param masterDev Pointer to I3C master device.
*/
status_t I3C_BusMasterSendSlavesList(i3c_device_t *masterDev)
{
i3c_bus_t *i3cBus = masterDev->bus;
if (masterDev != i3cBus->currentMaster)
{
return kStatus_I3CBus_NotCurrentMaster;
}
list_element_handle_t listItem;
list_handle_t i2cDevList = &(i3cBus->i2cDevList);
list_handle_t i3cDevList = &(i3cBus->i3cDevList);
i3c_ccc_cmd_t defSlavesCmd = {0};
defSlavesCmd.isRead = false;
defSlavesCmd.destAddr = I3C_BUS_BROADCAST_ADDR;
defSlavesCmd.cmdId = I3C_BUS_CCC_DEFSLVS;
uint8_t devCount = 1;
status_t result = kStatus_Success;
for (listItem = i2cDevList->head; listItem != NULL; listItem = listItem->next)
{
devCount++;
}
for (listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
{
i3c_device_t *i3cDev = (i3c_device_t *)(void *)listItem;
if (i3cDev == masterDev)
{
continue;
}
else
{
devCount++;
}
}
defSlavesCmd.dataSize = (uint16_t)sizeof(i3c_ccc_dev_t) * (uint16_t)devCount + 1U;
defSlavesCmd.data = malloc(defSlavesCmd.dataSize);
uint8_t *pData = defSlavesCmd.data;
*pData = devCount;
i3c_ccc_dev_t *masterInfo = (i3c_ccc_dev_t *)(void *)&pData[1];
masterInfo->bcr = masterDev->info.bcr;
masterInfo->dcr = masterDev->info.dcr;
masterInfo->dynamicAddr = masterDev->info.dynamicAddr << 1U;
masterInfo->staticAddr = (I3C_BUS_BROADCAST_ADDR << 1U);
i3c_ccc_dev_t *slaveInfo = (i3c_ccc_dev_t *)((uint32_t)&pData[1] + sizeof(i3c_ccc_dev_t));
for (listItem = i2cDevList->head; listItem != NULL; listItem = listItem->next)
{
slaveInfo->lvr = ((i2c_device_t *)(void *)listItem)->lvr;
slaveInfo->staticAddr = (((i2c_device_t *)(void *)listItem)->staticAddr << 1U);
slaveInfo++;
}
for (listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
{
i3c_device_t *i3cDev = (i3c_device_t *)(void *)listItem;
if (i3cDev == masterDev)
{
continue;
}
slaveInfo->dcr = i3cDev->info.dcr;
slaveInfo->dynamicAddr = i3cDev->info.dynamicAddr << 1U;
slaveInfo->bcr = i3cDev->info.bcr;
slaveInfo->staticAddr = i3cDev->info.staticAddr << 1U;
slaveInfo++;
}
result = I3C_BusMasterSendCCC(masterDev, &defSlavesCmd);
free(defSlavesCmd.data);
return result;
}
/*!
* brief Bus master enable events.
*
* Bus master call this function to enable events on bus.
*
* param masterDev Pointer to I3C master device.
* param slaveAddr Slave address, use I3C_BUS_BROADCAST_ADDR as broadcast address.
* param busEvents Logic OR or member in @ref _i3c_bus_events.
*/
status_t I3C_BusMasterEnableEvents(i3c_device_t *masterDev, uint8_t slaveAddr, uint8_t busEvents)
{
i3c_ccc_cmd_t enEventsCmd = {0};
status_t result = kStatus_Success;
enEventsCmd.isRead = false;
enEventsCmd.cmdId = I3C_BUS_CCC_ENEC((slaveAddr != I3C_BUS_BROADCAST_ADDR));
enEventsCmd.destAddr = slaveAddr;
enEventsCmd.data = &busEvents;
enEventsCmd.dataSize = 1U;
result = I3C_BusMasterSendCCC(masterDev, &enEventsCmd);
return result;
}
/*!
* brief Bus master disable events.
*
* Bus master call this function to disable events on bus.
*
* param masterDev Pointer to I3C master device.
* param slaveAddr Slave address, use I3C_BUS_BROADCAST_ADDR as broadcast address.
* param busEvents Logic OR or member in @ref _i3c_bus_events.
*/
status_t I3C_BusMasterDisableEvents(i3c_device_t *masterDev, uint8_t slaveAddr, uint8_t busEvents)
{
i3c_ccc_cmd_t disEventsCmd = {0};
status_t result = kStatus_Success;
disEventsCmd.isRead = false;
disEventsCmd.cmdId = I3C_BUS_CCC_DISEC((slaveAddr != I3C_BUS_BROADCAST_ADDR));
disEventsCmd.destAddr = slaveAddr;
disEventsCmd.data = &busEvents;
disEventsCmd.dataSize = 1U;
result = I3C_BusMasterSendCCC(masterDev, &disEventsCmd);
return result;
}
/*!
* brief Bus master get device information for a specific I3C device.
*
* Bus master call this function to get device information for a specific I3C device.
*
* param masterDev Pointer to I3C master device.
* param slaveAddr Slave address, dynamic assigned address for a device.
* param devInfo Input pointer to structure i3c_device_information_t to store the read out device information.
*/
status_t I3C_BusMasterGetDeviceInfo(i3c_device_t *masterDev, uint8_t slaveAddr, i3c_device_information_t *devInfo)
{
status_t result = kStatus_Success;
devInfo->dynamicAddr = slaveAddr;
result = I3C_BusMasterGetPID(masterDev, devInfo);
if (result != kStatus_Success)
{
return result;
}
result = I3C_BusMasterGetBCR(masterDev, devInfo);
if (result != kStatus_Success)
{
return result;
}
result = I3C_BusMasterGetDCR(masterDev, devInfo);
if (result != kStatus_Success)
{
return result;
}
result = I3C_BusMasterGetMaxReadLength(masterDev, devInfo);
if (result != kStatus_Success)
{
return result;
}
result = I3C_BusMasterGetMaxWriteLength(masterDev, devInfo);
if (result != kStatus_Success)
{
return result;
}
if ((devInfo->bcr & I3C_BUS_DEV_BCR_MODE_MASK) != 0U)
{
result = I3C_BusMasterGetHDRCapability(masterDev, devInfo);
if (result != kStatus_Success)
{
return result;
}
}
return result;
}
status_t I3C_BusMasterRegisterDevIBI(i3c_device_t *masterDev, i3c_device_t *i3cDev, i3c_device_ibi_info_t *devIbiInfo)
{
i3c_bus_t *i3cBus = masterDev->bus;
if (masterDev != i3cBus->currentMaster)
{
return kStatus_I3CBus_NotCurrentMaster;
}
i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
i3cDev->ibiInfo = devIbiInfo;
if (I3C_BusGetAddrSlotStatus(i3cBus, i3cDev->info.dynamicAddr) == (uint8_t)kI3C_Bus_AddrSlot_I3CDev)
{
masterControlInfo->funcs->RegisterIBI(masterDev, i3cDev->info.dynamicAddr);
}
else
{
return kStatus_I3CBus_InvalidOps;
}
return kStatus_Success;
}
/*!
* brief Bus master handle in-band-interrupt event.
*
* Bus master call this function to handle in-band-interrupt event.
*
* param masterDev Pointer to I3C master device.
* param ibiAddress slave address which requests the IBI.
* param ibiData Pointer to the ibi data buffer.
* param payloadSize ibi data buffer size.
*/
status_t I3C_BusMasterHandleIBI(i3c_device_t *masterDev, uint8_t ibiAddress, void *ibiData, uint32_t payloadSize)
{
i3c_bus_t *i3cBus = masterDev->bus;
if (masterDev != i3cBus->currentMaster)
{
return kStatus_I3CBus_NotCurrentMaster;
}
list_element_handle_t listItem;
list_handle_t i3cDevList = &(i3cBus->i3cDevList);
i3c_device_t *i3cDev = NULL;
for (listItem = i3cDevList->head; listItem != NULL; listItem = listItem->next)
{
i3cDev = (i3c_device_t *)(void *)listItem;
if (i3cDev == masterDev)
{
continue;
}
if (i3cDev->info.dynamicAddr == ibiAddress)
{
break;
}
}
if (i3cDev != NULL)
{
assert(i3cDev->ibiInfo != NULL);
assert(i3cDev->ibiInfo->maxPayloadLength >= payloadSize);
assert(i3cDev->ibiInfo->ibiHandler != NULL);
i3cDev->ibiInfo->ibiHandler(i3cDev, ibiData, payloadSize);
}
return kStatus_Success;
}
/*!
* brief Bus master do data transfer to I2C device.
*
* Bus master call this function to transfer data to connected I2C device.
*
* param masterDev Pointer to I3C master device.
* param i2cDev Pointer to the I2C device master do transfer.
* param xfer Pointer to bus transfer.
*/
status_t I3C_BusMasterDoTransferToI2CDev(i3c_device_t *masterDev, i2c_device_t *i2cDev, i3c_bus_transfer_t *xfer)
{
i3c_bus_t *i3cBus = masterDev->bus;
if (masterDev != i3cBus->currentMaster)
{
return kStatus_I3CBus_NotCurrentMaster;
}
status_t result = kStatus_Success;
i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
if (I3C_BusGetAddrSlotStatus(i3cBus, i2cDev->staticAddr) == (uint8_t)kI3C_Bus_AddrSlot_I2CDev)
{
result = masterControlInfo->funcs->DoI2CTransfer(i2cDev, xfer);
}
else
{
result = kStatus_I3CBus_InvalidOps;
}
return result;
}
/*!
* brief Bus master do data transfer to I3C device.
*
* Bus master call this function to transfer data to connected I3C device.
*
* param masterDev Pointer to I3C master device.
* param i3cDev Pointer to the I3C device master do transfer.
* param xfer Pointer to bus transfer.
*/
status_t I3C_BusMasterDoTransferToI3CDev(i3c_device_t *masterDev, i3c_device_t *i3cDev, i3c_bus_transfer_t *xfer)
{
i3c_bus_t *i3cBus = masterDev->bus;
if (masterDev != i3cBus->currentMaster)
{
return kStatus_I3CBus_NotCurrentMaster;
}
status_t result = kStatus_Success;
i3c_device_control_info_t *masterControlInfo = masterDev->devControlInfo;
if (I3C_BusGetAddrSlotStatus(i3cBus, i3cDev->info.dynamicAddr) == (uint8_t)kI3C_Bus_AddrSlot_I3CDev)
{
result = masterControlInfo->funcs->DoI3CTransfer(i3cDev, xfer);
}
else
{
result = kStatus_I3CBus_InvalidOps;
}
return result;
}
/*!
* brief Create I2C slave structure on bus.
*
* This function will create I2C device bus structure, initialize the slave according to bus characteristics, install
* device information including static address, lvr and device control information.
*
* param i2cDev Pointer to device structure creating as I2C device.
* param bus Pointer to bus structure.
* param staticAddr Static address of the I2C device
* param lvr legacy virtual register value of the device.
* param devControlInfo Pointer to device control information structure.
*/
status_t I3C_BusI2CSlaveCreate(
i2c_device_t *i2cDev, i3c_bus_t *bus, uint8_t staticAddr, uint8_t lvr, i2c_device_control_info_t *devControlInfo)
{
(void)memset(i2cDev, 0, sizeof(*i2cDev));
i2cDev->bus = bus;
i2cDev->staticAddr = staticAddr;
i2cDev->lvr = lvr;
i2cDev->devControlInfo = devControlInfo;
i3c_device_t *masterDev = NULL;
status_t result = kStatus_Success;
if (bus != NULL)
{
masterDev = (i3c_device_t *)bus->currentMaster;
}
if (masterDev != NULL)
{
/*Add device to bus i2c device list */
I3C_BusAddI2CDev(bus, i2cDev);
}
if ((devControlInfo != NULL) && (devControlInfo->funcs != NULL) && (devControlInfo->funcs->Init != NULL))
{
result = devControlInfo->funcs->Init(i2cDev);
}
return result;
}
/*!
* brief Create I3C slave structure on bus.
*
* This function will create I3C device bus structure, initialize the slave according to bus characteristics, install
* device information and device control information.
*
* param i3cDev Pointer to device structure creating as I3C device.
* param bus Pointer to bus structure.
* param devInfo Pointer to device information structure
* param devControlInfo Pointer to device control information structure.
*/
status_t I3C_BusI3CSlaveCreate(i3c_device_t *i3cDev,
i3c_bus_t *bus,
i3c_device_information_t *devInfo,
i3c_device_ibi_info_t *ibiInfo,
i3c_device_control_info_t *devControlInfo)
{
(void)memset(i3cDev, 0, sizeof(*i3cDev));
i3cDev->bus = bus;
i3cDev->ibiInfo = ibiInfo;
i3cDev->info = *devInfo;
i3cDev->devControlInfo = devControlInfo;
status_t result = kStatus_Success;
i3c_device_t *masterDev = NULL;
if (bus != NULL)
{
masterDev = (i3c_device_t *)bus->currentMaster;
}
if (masterDev != NULL)
{
/*Add device to bus i3c device list */
I3C_BusAddI3CDev(bus, i3cDev);
}
if ((devControlInfo != NULL) && (devControlInfo->funcs != NULL) && (devControlInfo->funcs->Init != NULL))
{
result = devControlInfo->funcs->Init(i3cDev);
}
return result;
}
/*!
* brief I3C slave device request Hot Join on bus.
*
* param i3cDev Pointer to device structure creating as I3C device.
*/
status_t I3C_BusSlaveRequestHotJoin(i3c_device_t *i3cDev)
{
status_t result = kStatus_Success;
if ((i3cDev->devControlInfo != NULL) && (i3cDev->devControlInfo->funcs != NULL) &&
(i3cDev->devControlInfo->funcs->HotJoin != NULL))
{
i3cDev->devControlInfo->funcs->HotJoin(i3cDev);
}
else
{
result = kStatus_I3CBus_SlaveOpsNotSupported;
}
return result;
}
/*!
* brief I3C slave device request mastership on bus.
*
* param i3cDev Pointer to device structure creating as I3C device.
*/
status_t I3C_BusSlaveRequestMasterShip(i3c_device_t *i3cDev)
{
status_t result = kStatus_Success;
if ((i3cDev->devControlInfo != NULL) && (i3cDev->devControlInfo->funcs != NULL) &&
(i3cDev->devControlInfo->funcs->RequestMastership != NULL))
{
i3cDev->devControlInfo->funcs->RequestMastership(i3cDev);
}
else
{
result = kStatus_I3CBus_SlaveOpsNotSupported;
}
return result;
}
/*!
* brief I3C slave request IBI events.
*
* param i3cDev Pointer to device structure creating as I3C device.
* param data Pointer to data buffer to be sent in IBI event.
* param dataSize data size of IBI data.
*/
status_t I3C_BusSlaveRequestIBI(i3c_device_t *i3cDev, void *data, size_t dataSize)
{
status_t result = kStatus_Success;
if ((i3cDev->devControlInfo != NULL) && (i3cDev->devControlInfo->funcs != NULL) &&
(i3cDev->devControlInfo->funcs->RequestMastership != NULL))
{
i3cDev->devControlInfo->funcs->RequestIBI(i3cDev, data, dataSize);
}
else
{
result = kStatus_I3CBus_SlaveOpsNotSupported;
}
return result;
}