/* * 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; }