/** * @file hv_drv_Spi.c * @brief SPI drviver layer file. * * @author HiView SoC Software Team * @version 1.0.0 * @date 2023-06-19 * @copyright Copyright(c),2023-6, Hiview Software. All rights reserved. * */ #include "hv_vos_Comm.h" #include "hv_comm_Assert.h" #include "hv_chip_Config.h" #include "hv_comm_Define.h" #include "hv_drv_Spi.h" struct _SpiSelf { SpiInitParam stInitParam; /* SPI communication parameters */ UINT32 uiBaseOffset; /* SPI addr offset*/ UCHAR8 *pucCmdAddr; /*!< Pointer to spi command and address buffer.*/ USHORT16 usCmdAddrSize; /*!< Spi command and address size. */ UCHAR8 *pucTxBuff; /* Pointer to SPI Tx transfer Buffer */ USHORT16 usTxXferSize; /* SPI Tx transfer size */ USHORT16 usTxXferCount; /* SPI Tx transfer counter */ UCHAR8 *pucRxBuff; /* Pointer to SPI Rx transfer Buffer */ USHORT16 usRxXferSize; /* SPI Rx transfer size */ USHORT16 usRxXferCount; /* SPI Rx transfer counter */ USHORT16 usDumSize; /*!< The Dummy size of receive. */ SpiState enState; /* SPI communication state */ SpiError enErrorCode; /* SPI Error code */ SpiTransState enTransCompleteFlag; /* SPI Transmit Complete flag */ DmaSelf *pstDmaTx; /* SPI Send Dma */ DmaSelf *pstDmaRx; /* SPI Receive Dma */ }; static SpiSelf s_Spi = {0}; static VOID Hv_Spi_ModeSelect(const SpiSelf* pstSelf) { if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { HV_W32_FIELD_EX(CPU_SYS_SPI0_MODE_CTL0, pstSelf->uiBaseOffset, reg_ssi_master, 1); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_W32_FIELD_EX(CPU_SYS_SPI0_MODE_CTL0, pstSelf->uiBaseOffset, reg_ssi_master, 0); } } static UCHAR8 Hv_Spi_GetFlag(const SpiSelf *pstSelf, SpiFlag enFlag) { UINT32 val = 0; if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { val = HV_R32(CPU_SYS_SPI0_M_SR + pstSelf->uiBaseOffset); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { val = HV_R32(CPU_SYS_SPI0_S_SR + pstSelf->uiBaseOffset); } return (((val & enFlag) == enFlag) ? 1 : 0); } static Status Hv_Spi_WaitOnFlagUntilTimeout(SpiSelf *pstSelf, SpiFlag enflag, UINT32 uiStatus, UINT32 uiTimeout) { UINT64 ullTickstart = 0; ullTickstart = Hv_Vos_GetTick(); if (uiStatus == HV_SET) { while (Hv_Spi_GetFlag(pstSelf, enflag) == 0)/* Wait the flag set*/ { if ((uiTimeout == 0) || ((Hv_Vos_GetTick() - ullTickstart ) > uiTimeout)) { pstSelf->enErrorCode = SPI_ERROR_TIMEOUT; pstSelf->enState = SPI_STATE_READY; return HV_TIMEOUT; } } } else { while (Hv_Spi_GetFlag(pstSelf, enflag) == 1)/* Wait the flag reset*/ { if ((uiTimeout == 0) || ((Hv_Vos_GetTick() - ullTickstart ) > uiTimeout)) { pstSelf->enErrorCode = SPI_ERROR_TIMEOUT; pstSelf->enState = SPI_STATE_READY; return HV_TIMEOUT; } } } return HV_SUCCESS; } static VOID Hv_Spi_Enable(const SpiSelf* pstSelf) { if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { HV_W32_FIELD_EX(CPU_SYS_SPI0_M_SSIENR, pstSelf->uiBaseOffset, SSI_EN, 1); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_W32_FIELD_EX(CPU_SYS_SPI0_S_SSIENR, pstSelf->uiBaseOffset, SSI_EN, 1); } } static VOID Hv_Spi_Disable(const SpiSelf *pstSelf) { if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { HV_W32_FIELD_EX(CPU_SYS_SPI0_M_SSIENR, pstSelf->uiBaseOffset, SSI_EN, 0); /* Enable spi0 master */ } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_W32_FIELD_EX(CPU_SYS_SPI0_S_SSIENR, pstSelf->uiBaseOffset, SSI_EN, 0); /* Enable spi0 slave */ } return; } static VOID Hv_Spi_MaskInt(const SpiSelf *pstSelf) { if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { HV_W32(CPU_SYS_SPI0_M_IMR + pstSelf->uiBaseOffset, 0x00); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_W32(CPU_SYS_SPI0_S_IMR + pstSelf->uiBaseOffset, 0x00); } return; } static VOID Hv_Spi_InterruptEnable(const SpiSelf *pstSelf, UINT32 uiIntType) { UINT32 uiVal = 0; if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { uiVal = HV_R32(CPU_SYS_SPI0_M_IMR + pstSelf->uiBaseOffset); uiVal |= uiIntType; HV_W32(CPU_SYS_SPI0_M_IMR + pstSelf->uiBaseOffset, uiVal); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { uiVal = HV_R32(CPU_SYS_SPI0_S_IMR + pstSelf->uiBaseOffset); uiVal |= uiIntType; HV_W32(CPU_SYS_SPI0_S_IMR + pstSelf->uiBaseOffset, uiVal); } else { //do nothing } } static VOID Hv_Spi_InterruptDisable(const SpiSelf *pstSelf, UINT32 uiIntType) { UINT32 uiVal = 0; if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { uiVal = HV_R32(CPU_SYS_SPI0_M_IMR + pstSelf->uiBaseOffset); uiVal &= ~uiIntType; HV_W32(CPU_SYS_SPI0_M_IMR + pstSelf->uiBaseOffset, uiVal); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { uiVal = HV_R32(CPU_SYS_SPI0_S_IMR + pstSelf->uiBaseOffset); uiVal &= ~uiIntType; HV_W32(CPU_SYS_SPI0_S_IMR + pstSelf->uiBaseOffset, uiVal); } else { //do nothing } } static UINT32 Hv_Spi_GetIntStateVal(const SpiSelf *pstSelf) { UINT32 uiVal = 0; if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { uiVal = HV_R32(CPU_SYS_SPI0_M_ISR + pstSelf->uiBaseOffset); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { uiVal = HV_R32(CPU_SYS_SPI0_S_ISR + pstSelf->uiBaseOffset); } return uiVal; } static UCHAR8 Hv_Spi_GetTxFifoLevel(const SpiSelf *pstSelf) { UCHAR8 uiVal = 0; HV_R32_DECL_VAR(); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { uiVal = HV_R32_FIELD_EX(CPU_SYS_SPI0_M_TXFLR, pstSelf->uiBaseOffset, TXTFL) & 0x1f; } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { uiVal = HV_R32_FIELD_EX(CPU_SYS_SPI0_S_TXFLR, pstSelf->uiBaseOffset, TXTFL) & 0x1f; } return uiVal; } static UCHAR8 Hv_Spi_GetRxFifoLevel(const SpiSelf *pstSelf) { UCHAR8 uiVal = 0; HV_R32_DECL_VAR(); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { uiVal = HV_R32_FIELD_EX(CPU_SYS_SPI0_M_RXFLR, pstSelf->uiBaseOffset, RXTFL) & 0x1f; } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { uiVal = HV_R32_FIELD_EX(CPU_SYS_SPI0_S_RXFLR, pstSelf->uiBaseOffset, RXTFL) & 0x1f; } return uiVal; } static VOID Hv_Spi_CsAlwaysLowSet(const SpiSelf *pstSelf) { UINT32 uiVal = 0; uiVal = HV_R32(CPU_SYS_SPI0_MODE_CTL0 + pstSelf->uiBaseOffset); cpu_sys_spi0_mode_ctl0(uiVal)->cs_oe_ctrl = 1; cpu_sys_spi0_mode_ctl0(uiVal)->reg_cs_oe = 1; cpu_sys_spi0_mode_ctl0(uiVal)->sck_oe_ctrl = 1; cpu_sys_spi0_mode_ctl0(uiVal)->reg_sck_oe = 1; cpu_sys_spi0_mode_ctl0(uiVal)->mosi_oe_ctrl = 1; cpu_sys_spi0_mode_ctl0(uiVal)->reg_mosi_oe = 1; HV_W32(CPU_SYS_SPI0_MODE_CTL0 + pstSelf->uiBaseOffset, uiVal); return; } static VOID Hv_Spi_CsAlwaysLowRelease(const SpiSelf *pstSelf) { UINT32 uiVal = 0; uiVal = HV_R32(CPU_SYS_SPI0_MODE_CTL0 + pstSelf->uiBaseOffset); cpu_sys_spi0_mode_ctl0(uiVal)->cs_oe_ctrl = 0; cpu_sys_spi0_mode_ctl0(uiVal)->reg_cs_oe = 0; cpu_sys_spi0_mode_ctl0(uiVal)->sck_oe_ctrl = 0; cpu_sys_spi0_mode_ctl0(uiVal)->reg_sck_oe = 0; cpu_sys_spi0_mode_ctl0(uiVal)->mosi_oe_ctrl = 0; cpu_sys_spi0_mode_ctl0(uiVal)->reg_mosi_oe = 0; HV_W32(CPU_SYS_SPI0_MODE_CTL0 + pstSelf->uiBaseOffset, uiVal); return; } static UCHAR8* Hv_Spi_TransmitOne(const SpiSelf *pstSelf, UINT32 uiCmdDataRegAddr, UCHAR8* pucData) { UCHAR8 ucToDR0Val = 0; UINT32 uiToDR0Val = 0; if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { ucToDR0Val = *pucData++; uiToDR0Val = (UINT32)ucToDR0Val; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32) { uiToDR0Val = CHANGE_TO_U32_BE(pucData); pucData = pucData + 4; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_16) { uiToDR0Val = CHANGE_TO_U16_BE(pucData); pucData = pucData + 2; } HV_W32(uiCmdDataRegAddr, uiToDR0Val); return pucData; } static UCHAR8* Hv_Spi_ReceiveOne(const SpiSelf *pstSelf, UINT32 uiCmdDataRegAddr, UCHAR8* pucData) { UINT32 uiFromDR0Val = HV_R32(uiCmdDataRegAddr); if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { *pucData++ = (UCHAR8)((uiFromDR0Val ) & 0xff); } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32) { *((UINT32*)(pucData)) = HV_SWAP32(uiFromDR0Val);//CHANGE_ENDIAN_U32(uiFromDR0Val); pucData = pucData + 4; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_16) { *((USHORT16*)(pucData)) = CHANGE_ENDIAN_U16((uiFromDR0Val) & 0xffff); pucData = pucData + 2; } return pucData; } static Status Hv_Spi_IntTransmitCpltCallback(SpiSelf *pstSelf) { if (Hv_Spi_WaitOnFlagUntilTimeout(pstSelf, SPI_FLAG_TFE, HV_SET, HV_SPI_TIMEOUT) != HV_SUCCESS) { return HV_TIMEOUT; } if (pstSelf->stInitParam.enCsCtlMode != SPI_CSMODE_ALWAYS_LOW) { if (Hv_Spi_WaitOnFlagUntilTimeout(pstSelf, SPI_FLAG_BUSY, HV_RESET, HV_SPI_TIMEOUT) != HV_SUCCESS) { return HV_TIMEOUT; } } pstSelf->enState = SPI_STATE_READY; pstSelf->enTransCompleteFlag = SPI_TRANS_END; if (pstSelf->stInitParam.pfSpiCpltCallback != NULL) { pstSelf->stInitParam.pfSpiCpltCallback(SPI_TRANSMIT, (VOID*)pstSelf); } return HV_SUCCESS; } static Status Hv_Spi_IntReceiveCpltCallback(SpiSelf *pstSelf) { if ((pstSelf->stInitParam.enMode == SPI_MODE_MASTER) && (pstSelf->stInitParam.enCsCtlMode != SPI_CSMODE_ALWAYS_LOW)) { if (Hv_Spi_WaitOnFlagUntilTimeout(pstSelf, SPI_FLAG_BUSY, HV_RESET, HV_SPI_TIMEOUT) != HV_SUCCESS) { return HV_TIMEOUT; } } pstSelf->enState = SPI_STATE_READY; pstSelf->enTransCompleteFlag = SPI_TRANS_END; if (pstSelf->stInitParam.pfSpiCpltCallback != NULL) { pstSelf->stInitParam.pfSpiCpltCallback(SPI_RECEIVE, (VOID*)pstSelf); } return HV_SUCCESS; } static Status Hv_Spi_IntTransmitHandler(SpiSelf *pstSelf) { UINT32 i = 0; UINT32 uiTxFifoSurplusLev = 0; UINT32 uiTxDataNumOnce = 0; UINT32 uiTxDataTotalNum = pstSelf->usCmdAddrSize + pstSelf->usTxXferSize; UCHAR8 *pucTxData = NULL; UINT32 uiCmdDataRegAddr = 0; if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { uiCmdDataRegAddr = CPU_SYS_SPI0_M_DR0 + pstSelf->uiBaseOffset; } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { uiCmdDataRegAddr = CPU_SYS_SPI0_S_DR0 + pstSelf->uiBaseOffset; } if (pstSelf->enState == SPI_STATE_BUSY_TX) { if (pstSelf->usTxXferSize != 0) { if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { pucTxData = &pstSelf->pucTxBuff[pstSelf->usTxXferCount]; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_16) { pucTxData = &pstSelf->pucTxBuff[2 * pstSelf->usTxXferCount]; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32) { pucTxData = &pstSelf->pucTxBuff[4 * pstSelf->usTxXferCount]; } else { //do nothing } } } uiTxFifoSurplusLev = HV_SPI_FIFO_DEPTH - Hv_Spi_GetTxFifoLevel(pstSelf); uiTxDataNumOnce = (uiTxDataTotalNum > uiTxFifoSurplusLev) ? uiTxFifoSurplusLev : uiTxDataTotalNum; for (i = 0; i < uiTxDataNumOnce; i++) { if (pstSelf->usCmdAddrSize == 0) { if (pstSelf->enState == SPI_STATE_BUSY_TX) { pucTxData = Hv_Spi_TransmitOne(pstSelf, uiCmdDataRegAddr, pucTxData); pstSelf->usTxXferCount++; } else if (pstSelf->enState == SPI_STATE_BUSY_RX) { UCHAR8 ucDummy[4] = {0}; Hv_Spi_TransmitOne(pstSelf, uiCmdDataRegAddr, ucDummy); } pstSelf->usTxXferSize--; uiCmdDataRegAddr = uiCmdDataRegAddr + 4; } else { pstSelf->pucCmdAddr = Hv_Spi_TransmitOne(pstSelf, uiCmdDataRegAddr, pstSelf->pucCmdAddr); pstSelf->usCmdAddrSize--; uiCmdDataRegAddr = uiCmdDataRegAddr + 4; } } if ((pstSelf->usCmdAddrSize + pstSelf->usTxXferSize) == 0) { UINT32 uiIntFlag = 0; uiIntFlag = SPI_INTERRUPT_TXEIR | SPI_INTERRUPT_TXOIR; Hv_Spi_InterruptDisable(pstSelf, uiIntFlag); if (pstSelf->enState == SPI_STATE_BUSY_TX) { Hv_Spi_IntTransmitCpltCallback(pstSelf); } } return HV_SUCCESS; } static Status Hv_Spi_IntReceiveHandler(SpiSelf *pstSelf) { UINT32 i = 0; UINT32 uiRxFifoDataLev = 0; UCHAR8 *pucRxData = NULL; UCHAR8 ucDumSize[4] = {0}; UINT32 uiCmdDataRegAddrBase = 0; if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { uiCmdDataRegAddrBase = CPU_SYS_SPI0_M_DR0 + pstSelf->uiBaseOffset; } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { uiCmdDataRegAddrBase = CPU_SYS_SPI0_S_DR0 + pstSelf->uiBaseOffset; } if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { pucRxData = &pstSelf->pucRxBuff[pstSelf->usRxXferCount]; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_16) { pucRxData = &pstSelf->pucRxBuff[2 * pstSelf->usRxXferCount]; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32) { pucRxData = &pstSelf->pucRxBuff[4 * pstSelf->usRxXferCount]; } uiRxFifoDataLev = Hv_Spi_GetRxFifoLevel(pstSelf); for (i = 0; i < uiRxFifoDataLev; i++) { if (pstSelf->usDumSize != 0) { Hv_Spi_ReceiveOne(pstSelf,uiCmdDataRegAddrBase, ucDumSize); pstSelf->usDumSize--; } else { pucRxData = Hv_Spi_ReceiveOne(pstSelf, uiCmdDataRegAddrBase, pucRxData); pstSelf->usRxXferCount++; } pstSelf->usRxXferSize--; } if (pstSelf->usRxXferSize == 0) { UINT32 uiIntFlag = 0; uiIntFlag = SPI_INTERRUPT_RXFIR|SPI_INTERRUPT_RXUIR|SPI_INTERRUPT_RXOIR; Hv_Spi_InterruptDisable(pstSelf, uiIntFlag); Hv_Spi_IntReceiveCpltCallback(pstSelf); } return HV_SUCCESS; } HV_VOS_ISR_RESULT_E Hv_Spi_IrqHandler(UINT32 uiIrqNum, VOID *pArg) { UINT32 uiIntStaVal = 0; SpiSelf *pstSelf; HV_UNUSED(uiIrqNum); pstSelf = (SpiSelf *)pArg; uiIntStaVal = Hv_Spi_GetIntStateVal(pstSelf); if (uiIntStaVal & SPI_INTERRUPT_TXEIR) { // HV_LOGI("Now enter tx int.\n"); Hv_Spi_IntTransmitHandler(pstSelf); } if (uiIntStaVal & SPI_INTERRUPT_RXFIR) { //HV_LOGI("Now enter rx int.\n"); Hv_Spi_IntReceiveHandler(pstSelf); } if (uiIntStaVal & SPI_INTERRUPT_TXOIR) { } if (uiIntStaVal & SPI_INTERRUPT_RXUIR) { } if (uiIntStaVal & SPI_INTERRUPT_RXOIR) { } if (uiIntStaVal & SPI_INTERRUPT_MSTIR) { } return HV_VOS_ISR_HANDLED; } static VOID Hv_Spi_ConfigDmaTxReg(SpiSelf *pstSelf, UINT32 uiEnFlag, UINT32 uiSpiTxDmaThres) { Hv_Spi_Disable(pstSelf); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { HV_W32_FIELD_EX(CPU_SYS_SPI0_M_DMACR, pstSelf->uiBaseOffset, TDMAE, uiEnFlag); HV_W32_FIELD_EX(CPU_SYS_SPI0_M_DMATDLR, pstSelf->uiBaseOffset, DMATDL, uiSpiTxDmaThres); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_W32_FIELD_EX(CPU_SYS_SPI0_S_DMACR, pstSelf->uiBaseOffset, TDMAE, uiEnFlag); HV_W32_FIELD_EX(CPU_SYS_SPI0_S_DMATDLR, pstSelf->uiBaseOffset, DMATDL, uiSpiTxDmaThres); } } static VOID Hv_Spi_ConfigDmaRxReg(SpiSelf *pstSelf, UINT32 uiEnFlag, UINT32 uiSpiRxDmaThres) { Hv_Spi_Disable(pstSelf); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { HV_W32_FIELD_EX(CPU_SYS_SPI0_M_DMACR, pstSelf->uiBaseOffset, RDMAE, uiEnFlag); HV_W32_FIELD_EX(CPU_SYS_SPI0_M_DMARDLR, pstSelf->uiBaseOffset, DMARDL, uiSpiRxDmaThres); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_W32_FIELD_EX(CPU_SYS_SPI0_S_DMACR, pstSelf->uiBaseOffset, RDMAE, uiEnFlag); HV_W32_FIELD_EX(CPU_SYS_SPI0_S_DMARDLR, pstSelf->uiBaseOffset, DMARDL, uiSpiRxDmaThres); } } static Status Hv_Spi_DmaTransmitCpltCallback(DmaSelf* pstArg) { SpiSelf* pstSelf = (SpiSelf *)Hv_Cal_Dma_GetParent(pstArg); Hv_Cal_Dma_XferCallbackUnBond(pstSelf->pstDmaTx); if (pstSelf->enState == SPI_STATE_BUSY_TX) { if (Hv_Spi_WaitOnFlagUntilTimeout(pstSelf, SPI_FLAG_TFE, HV_SET, HV_SPI_TIMEOUT) != HV_SUCCESS) { return HV_TIMEOUT; } if (pstSelf->stInitParam.enCsCtlMode != SPI_CSMODE_ALWAYS_LOW) { if (Hv_Spi_WaitOnFlagUntilTimeout(pstSelf, SPI_FLAG_BUSY, HV_RESET, HV_SPI_TIMEOUT) != HV_SUCCESS) { return HV_TIMEOUT; } } Hv_Spi_Disable(pstSelf); Hv_Spi_ConfigDmaTxReg(pstSelf, SPI_DMATX_DISABLE, HV_SPI_DMA_TX_THRESHOLD); Hv_Vos_InvalidAllDCache(); pstSelf->enState = SPI_STATE_READY; pstSelf->enTransCompleteFlag = SPI_TRANS_END; if (pstSelf->stInitParam.pfSpiCpltCallback != NULL) { pstSelf->stInitParam.pfSpiCpltCallback(SPI_TRANSMIT, (VOID*)pstSelf); } } return HV_SUCCESS; } static Status Hv_Spi_DmaReceiveCpltCallback(DmaSelf* pArg) { SpiSelf* pstSelf = (SpiSelf *)Hv_Cal_Dma_GetParent(pArg); if ((pstSelf->stInitParam.enMode == SPI_MODE_MASTER) && (pstSelf->stInitParam.enCsCtlMode != SPI_CSMODE_ALWAYS_LOW)) { if (Hv_Spi_WaitOnFlagUntilTimeout(pstSelf, SPI_FLAG_BUSY, HV_RESET, 1000) != HV_SUCCESS) { return HV_TIMEOUT; } } Hv_Spi_Disable(pstSelf); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { Hv_Spi_ConfigDmaTxReg(pstSelf, SPI_DMATX_DISABLE, HV_SPI_DMA_TX_THRESHOLD); } Hv_Spi_ConfigDmaRxReg(pstSelf, SPI_DMARX_DISABLE, HV_SPI_DMA_RX_THRESHOLD); Hv_Cal_Dma_XferCallbackUnBond(pstSelf->pstDmaRx); Hv_Vos_InvalidAllDCache(); pstSelf->enState = SPI_STATE_READY; pstSelf->enTransCompleteFlag = SPI_TRANS_END; if (pstSelf->stInitParam.pfSpiCpltCallback != NULL) { pstSelf->stInitParam.pfSpiCpltCallback(SPI_RECEIVE, (VOID*)pstSelf); } return HV_SUCCESS; } /**@brief Get spi state * @param self pointer to spi structure * @retval spi state */ UCHAR8 Hv_Drv_Spi_GetState(const SpiSelf* pstSelf) { return pstSelf->enState; } /**@brief Set spi transmit DMA * @param self pointer to spi structure. * @param transmit DMA structure * @retval none */ VOID Hv_Drv_Spi_SetDmaTx(SpiSelf *pstSelf, DmaSelf *pstDmaTx) { pstSelf->pstDmaTx = pstDmaTx; Hv_Cal_Dma_SetParent(pstDmaTx, (VOID*)pstSelf); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { Hv_Cal_Dma_SetDstAddr(pstDmaTx, CPU_SYS_SPI0_M_DR0 + pstSelf->uiBaseOffset); } else { Hv_Cal_Dma_SetDstAddr(pstDmaTx, CPU_SYS_SPI0_S_DR0 + pstSelf->uiBaseOffset); } if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { Hv_Cal_Dma_SetSrcFrameSize(pstDmaTx, DMA_DATA_SIZE_32Bits); Hv_Cal_Dma_SetDstFrameSize(pstDmaTx, DMA_DATA_SIZE_8Bits); } return; } /**@brief Set spi receive DMA * @param self pointer to spi structure. * @param receive DMA structure * @retval none */ VOID Hv_Drv_Spi_SetDmaRx(SpiSelf *pstSelf, DmaSelf *pstDmaRx) { pstSelf->pstDmaRx = pstDmaRx; Hv_Cal_Dma_SetParent(pstDmaRx,(VOID*)pstSelf); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { Hv_Cal_Dma_SetSrcAddr(pstDmaRx, CPU_SYS_SPI0_M_DR0 + pstSelf->uiBaseOffset); } else { Hv_Cal_Dma_SetSrcAddr(pstDmaRx, CPU_SYS_SPI0_S_DR0 + pstSelf->uiBaseOffset); } if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { Hv_Cal_Dma_SetSrcFrameSize(pstDmaRx, DMA_DATA_SIZE_8Bits); Hv_Cal_Dma_SetDstFrameSize(pstDmaRx, DMA_DATA_SIZE_32Bits); } return; } /**@brief Bond the complete callback * @param self pointer to spi structure. * @param CallbackFunc callback defined by user * @retval none */ VOID Hv_Drv_Spi_SetCpltCallBack(SpiSelf *pstSelf, SpiCpltCallback pfCallbackFunc) { pstSelf->stInitParam.pfSpiCpltCallback = pfCallbackFunc; } /**@brief Set the spi direction * @param self pointer to spi structure. * @param enDirection * @retval none */ VOID Hv_Drv_Spi_SetDirection(SpiSelf *pstSelf, SpiDirection enDirection) { Hv_Spi_Disable(pstSelf); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { HV_W32_FIELD_EX(CPU_SYS_SPI0_M_CTRLR0, pstSelf->uiBaseOffset, TMOD, enDirection); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_W32_FIELD_EX(CPU_SYS_SPI0_S_CTRLR0, pstSelf->uiBaseOffset, TMOD, enDirection); } pstSelf->stInitParam.enDirection = enDirection; return; } /**@brief Set spi data frame size * @param self pointer to spi structure. * @param enFrameWidth Indicates how many bits of data are serially transmitted in a frame. * @retval none */ VOID Hv_Drv_Spi_SetBitsWidth(SpiSelf *pstSelf, SpiBandWidth enFrameWidth) { Hv_Spi_Disable(pstSelf); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { HV_W32_FIELD_EX(CPU_SYS_SPI0_M_CTRLR0, pstSelf->uiBaseOffset, DFS_32, (UINT32)enFrameWidth); } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_W32_FIELD_EX(CPU_SYS_SPI0_S_CTRLR0, pstSelf->uiBaseOffset, DFS_32, (UINT32)enFrameWidth); } pstSelf->stInitParam.enDataSize = enFrameWidth; return; } /**@brief Set spi the baudrate * @param self pointer to spi structure. * @param BaudRate baudrate which will set as SCKDV. * @retval none */ VOID Hv_Drv_Spi_SetBaudRate(SpiSelf *pstSelf, SPiDivRatio enDivRatio) { Hv_Spi_Disable(pstSelf); HV_W32_FIELD_EX(CPU_SYS_SPI0_M_BAUDR, pstSelf->uiBaseOffset, SCKDV, (UINT32)enDivRatio); pstSelf->stInitParam.enBaudRatePrescaler = enDivRatio; return; } /**@brief Initializes the SPI according to the specified parameters and create the associated handle. * @param initParam pointer to the configuration information for SPI module. * @return spi handler */ SpiSelf* Hv_Drv_Spi_Init(SpiInitParam *pstInitParam) { SpiSelf *pstSelf = NULL; HV_ASSERT_VALID_PTR_RET(pstInitParam, NULL); HV_ASSERT_TRUE_RET((pstInitParam->enCsCtlMode < SPI_CSMODE_MAX), NULL); pstSelf = &s_Spi; HV_MEMCPY(&pstSelf->stInitParam, pstInitParam, sizeof(*pstInitParam)); pstSelf->uiBaseOffset = 0; Hv_Spi_ModeSelect(pstSelf); Hv_Spi_Disable(pstSelf); Hv_Spi_MaskInt(pstSelf); if (pstInitParam->enMode == SPI_MODE_MASTER) { rs_cpu_sys_spi0_m_ctrlr0 regCtrl0Val = {0}; /* Config spi0 master ctrl0 reg*/ regCtrl0Val.FRF = 0; regCtrl0Val.SCPH = pstInitParam->enClkPhase; regCtrl0Val.SCPOL = pstInitParam->enClkPolarity; regCtrl0Val.TMOD = pstInitParam->enDirection; regCtrl0Val.SRL = 0; regCtrl0Val.DFS_32 = pstInitParam->enDataSize; regCtrl0Val.SPI_FRF = 0; regCtrl0Val.SSTE = 0;/* No toggle*/ HV_W32_REG(CPU_SYS_SPI0_M_CTRLR0 + pstSelf->uiBaseOffset, regCtrl0Val); HV_W32(CPU_SYS_SPI0_M_BAUDR + pstSelf->uiBaseOffset, pstInitParam->enBaudRatePrescaler); HV_W32_FIELD_EX(CPU_SYS_SPI0_M_TXFTLR, pstSelf->uiBaseOffset, TFT, 8); HV_W32_FIELD_EX(CPU_SYS_SPI0_M_RXFTLR, pstSelf->uiBaseOffset, RFT, 0); HV_W32(CPU_SYS_SPI0_M_CTRLR1 + pstSelf->uiBaseOffset, 0x03); HV_W32_FIELD_EX(CPU_SYS_SPI0_M_SER, pstSelf->uiBaseOffset, SER, 1); } else if (pstInitParam->enMode == SPI_MODE_SLAVE) { rs_cpu_sys_spi0_s_ctrlr0 regCtrl0Val = {0};/* Config spi0 slave ctrl0 reg*/ regCtrl0Val.FRF = 0; regCtrl0Val.SCPH = pstInitParam->enClkPhase; /* if need to config */ regCtrl0Val.SCPOL = pstInitParam->enClkPolarity; regCtrl0Val.TMOD = pstInitParam->enDirection; regCtrl0Val.SLV_OE = 0; regCtrl0Val.SRL = 0; regCtrl0Val.DFS_32 = pstInitParam->enDataSize; regCtrl0Val.SPI_FRF = 0; regCtrl0Val.SSTE = 0; HV_W32_REG(CPU_SYS_SPI0_S_CTRLR0 + pstSelf->uiBaseOffset, regCtrl0Val); HV_W32_FIELD_EX(CPU_SYS_SPI0_S_TXFTLR, pstSelf->uiBaseOffset, TFT, 8); HV_W32_FIELD_EX(CPU_SYS_SPI0_S_RXFTLR, pstSelf->uiBaseOffset, RFT, 0); } HV_W32_FIELD_EX(CPU_SYS_SPI0_M_RX_SAMPLE_DLY, pstSelf->uiBaseOffset, RSD, 1); Hv_Vos_ConfigIrq(HV_CHIP_IRQ_SPI0, HV_TRUE, 0); Hv_Vos_AttachIsr(HV_CHIP_IRQ_SPI0, Hv_Spi_IrqHandler, pstSelf); Hv_Vos_UnmaskIrq(HV_CHIP_IRQ_SPI0); if (pstSelf->stInitParam.enCsCtlMode == SPI_CSMODE_ALWAYS_LOW) { Hv_Spi_CsAlwaysLowSet(pstSelf); } pstSelf->enState = SPI_STATE_READY; pstSelf->enErrorCode = SPI_ERROR_NONE; return pstSelf; } /**@brief De-initializes the SPI. * @param self pointer to spi structure. * @retval result */ Status Hv_Drv_Spi_Cleanup(SpiSelf *pstSelf) { Hv_Vos_MaskIrq(HV_CHIP_IRQ_SPI0); Hv_Vos_DetachIsr(HV_CHIP_IRQ_SPI0, Hv_Spi_IrqHandler); if (pstSelf->stInitParam.enCsCtlMode == SPI_CSMODE_ALWAYS_LOW) { Hv_Spi_CsAlwaysLowRelease(pstSelf); } Hv_Spi_Disable(pstSelf); pstSelf->enErrorCode = SPI_ERROR_NONE; pstSelf->enState = SPI_STATE_RESET; return HV_SUCCESS; } /**@brief Transmit an amount of data in blocking mode * @param self pointer to spi structure * @param pucCmdAddr pointer to command buffer * @param pucTxData pointer to data buffer * @param usDataSize amount of data to be sent * @param uiTimeout Timeout duration * @retval result */ Status Hv_Drv_Spi_PollingTransmit(SpiSelf *pstSelf, UCHAR8 *pucCmdAddr, USHORT16 usCmdAddrSize, UCHAR8 *pucTxData, USHORT16 usDataSize, UINT32 uiTimeout) { UINT32 i = 0; UINT32 uiTxFifoSurplusLev = 0; UINT32 uiTxDataNumOnce = 0; USHORT16 usCmdAddrSizeTemp = 0; USHORT16 usDataSizeTemp = 0; USHORT16 usTxTotalSize = 0; UINT32 uiCmdDataRegAddrBase = 0; UINT32 uiCmdDataRegAddr = 0; HV_UNUSED(uiTimeout); if (pstSelf->enState == SPI_STATE_READY) { if (((pucCmdAddr == NULL ) && (pucTxData == NULL)) || ((usCmdAddrSize == 0) && (usDataSize == 0))) { return HV_FAILURE; } if ((pstSelf->stInitParam.enDirection != SPI_DIRECTION_TXRX) && (pstSelf->stInitParam.enDirection != SPI_DIRECTION_TX)) { return HV_FAILURE; } if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { usCmdAddrSizeTemp = usCmdAddrSize; usDataSizeTemp = usDataSize; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_16) { usCmdAddrSizeTemp = usCmdAddrSize / 2; usDataSizeTemp = usDataSize / 2; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32) { usCmdAddrSizeTemp = usCmdAddrSize / 4; usDataSizeTemp = usDataSize / 4; } if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_ASSERT(pucCmdAddr == NULL); HV_ASSERT(usCmdAddrSizeTemp == 0); } usTxTotalSize = usCmdAddrSizeTemp + usDataSizeTemp; pstSelf->enState = SPI_STATE_BUSY_TX; pstSelf->enErrorCode = SPI_ERROR_NONE; Hv_Spi_Enable(pstSelf); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { uiCmdDataRegAddrBase = CPU_SYS_SPI0_M_DR0 + pstSelf->uiBaseOffset; uiCmdDataRegAddr = uiCmdDataRegAddrBase; } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE)/*Preventing from TXE Erro*/ { uiCmdDataRegAddrBase = CPU_SYS_SPI0_S_DR0 + pstSelf->uiBaseOffset; uiCmdDataRegAddr = uiCmdDataRegAddrBase; pucTxData = Hv_Spi_TransmitOne(pstSelf, uiCmdDataRegAddr, pucTxData); uiCmdDataRegAddr = uiCmdDataRegAddr + 4; pstSelf->usTxXferSize--; } while (usTxTotalSize > 0) { uiTxFifoSurplusLev = HV_SPI_FIFO_DEPTH - Hv_Spi_GetTxFifoLevel(pstSelf); uiTxDataNumOnce = (usTxTotalSize > uiTxFifoSurplusLev) ? uiTxFifoSurplusLev : usTxTotalSize; for (i = 0; i < uiTxDataNumOnce; i++) { if (usCmdAddrSizeTemp == 0) { pucTxData = Hv_Spi_TransmitOne(pstSelf, uiCmdDataRegAddr, pucTxData); } else { pucCmdAddr = Hv_Spi_TransmitOne(pstSelf, uiCmdDataRegAddr, pucCmdAddr); usCmdAddrSizeTemp--; } uiCmdDataRegAddr = uiCmdDataRegAddr + 4; if ((uiCmdDataRegAddr - uiCmdDataRegAddrBase) == HV_SPI_DR_ADDR_RANGE_TOTAL) { uiCmdDataRegAddr = uiCmdDataRegAddrBase; } usTxTotalSize--; } } if (Hv_Spi_WaitOnFlagUntilTimeout(pstSelf, SPI_FLAG_TFE, HV_SET, HV_SPI_TIMEOUT) != HV_SUCCESS) { return HV_TIMEOUT; } if (pstSelf->stInitParam.enCsCtlMode != SPI_CSMODE_ALWAYS_LOW) { if (Hv_Spi_WaitOnFlagUntilTimeout(pstSelf, SPI_FLAG_BUSY, HV_RESET, HV_SPI_TIMEOUT) != HV_SUCCESS) { return HV_TIMEOUT; } } pstSelf->enState = SPI_STATE_READY; Hv_Spi_Disable(pstSelf); return HV_SUCCESS; } else { return HV_BUSY; } } /**@brief Transmit an amount of data in no-blocking mode with interrupt * @param self pointer to spi structure * @param pucCmdAddr pointer to command buffer * @param pucTxData pointer to data buffer * @param usDataSize amount of data to be sent * @retval result */ Status Hv_Drv_Spi_IntTransmit(SpiSelf *pstSelf, UCHAR8 *pucCmdAddr, USHORT16 usCmdAddrSize, UCHAR8 *pucTxData, USHORT16 usDataSize) { UINT32 uiIntFlag = 0; USHORT16 usCmdAddrSizeTemp = 0; USHORT16 usDataSizeTemp = 0; if (pstSelf->enState == SPI_STATE_READY) { if (((pucCmdAddr == NULL ) && (pucTxData == NULL)) || ((usCmdAddrSize == 0) && (usDataSize == 0))) { return HV_FAILURE; } if ((pstSelf->stInitParam.enDirection != SPI_DIRECTION_TXRX) && (pstSelf->stInitParam.enDirection != SPI_DIRECTION_TX)) { return HV_FAILURE; } if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { usCmdAddrSizeTemp = usCmdAddrSize; usDataSizeTemp = usDataSize; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_16) { usCmdAddrSizeTemp = usCmdAddrSize / 2; usDataSizeTemp = usDataSize / 2; }else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32) { usCmdAddrSizeTemp = usCmdAddrSize / 4; usDataSizeTemp = usDataSize / 4; } if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { pstSelf->pucCmdAddr = pucCmdAddr; pstSelf->usCmdAddrSize = usCmdAddrSizeTemp; } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_ASSERT(pucCmdAddr == NULL); HV_ASSERT(usCmdAddrSizeTemp == 0); } pstSelf->pucTxBuff = pucTxData; pstSelf->usTxXferSize = usDataSizeTemp; pstSelf->usTxXferCount = 0; pstSelf->enState = SPI_STATE_BUSY_TX; pstSelf->enErrorCode = SPI_ERROR_NONE; pstSelf->enTransCompleteFlag = SPI_TRANS_IN_PROCESS; uiIntFlag = SPI_INTERRUPT_TXEIR | SPI_INTERRUPT_TXOIR; Hv_Spi_InterruptEnable(pstSelf, uiIntFlag); Hv_Spi_Enable(pstSelf); return HV_SUCCESS; } else { return HV_BUSY; } } /**@brief Transmit an amount of data in no-blocking mode with DMA * @param self pointer to spi structure * @param pucData pointer to data buffer * @param usDataSize amount of data to be sent * @retval result */ Status Hv_Drv_Spi_DmaTransmit(SpiSelf *pstSelf, UCHAR8* pucData, USHORT16 usDataSize) { USHORT16 usBlockSize = 0; if (pstSelf->enState == SPI_STATE_READY) { if ((pstSelf->stInitParam.enDirection != SPI_DIRECTION_TXRX) && (pstSelf->stInitParam.enDirection != SPI_DIRECTION_TX)) { return HV_FAILURE; } if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { HV_ASSERT((usDataSize % 4) == 0); usBlockSize = usDataSize / 4; }else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32){ HV_ASSERT((usDataSize % 4) == 0); usBlockSize = usDataSize / 4; } Hv_Spi_ConfigDmaTxReg(pstSelf, SPI_DMATX_ENABLE, HV_SPI_DMA_TX_THRESHOLD); Hv_Spi_Enable(pstSelf); Hv_Cal_Dma_XferCallbackBond(pstSelf->pstDmaTx, Hv_Spi_DmaTransmitCpltCallback); Hv_Cal_Dma_SetBlockSize(pstSelf->pstDmaTx, usBlockSize); Hv_Cal_Dma_SetSrcAddr(pstSelf->pstDmaTx, (UINT32)pucData); pstSelf->enState = SPI_STATE_BUSY_TX; pstSelf->enErrorCode = SPI_ERROR_NONE; pstSelf->enTransCompleteFlag = SPI_TRANS_IN_PROCESS; Hv_Cal_Dma_ChannelEn(pstSelf->pstDmaTx); return HV_SUCCESS; } else { return HV_BUSY; } } /**@brief Receive an amount of data in blocking mode * @param self pointer to spi structure * @param pucCmdAddr pointer to command buffer * @param pucRxData pointer to data buffer * @param usDataSize amount of data to be sent * @param uiTimeout Timeout duration * @retval result */ Status Hv_Drv_Spi_PollingReceive(SpiSelf *pstSelf, UCHAR8 *pucCmdAddr, USHORT16 usCmdAddrSize, UCHAR8 *pucRxData, USHORT16 usDataSize, UINT32 uiTimeout) { UINT32 uiLoop = 0; UINT32 uiTxFifoSurplusLev = 0; UINT32 uiTxDataNumOnce = 0; UINT32 uiRxFifoDataLev = 0; UCHAR8 ucDummy[4] = {0}; UINT32 uiDummySize = 0; UINT64 ullTickstart = Hv_Vos_GetTick(); USHORT16 usCmdAddrSizeTemp = 0; USHORT16 usDataSizeTemp = 0; USHORT16 usTxTotalSize = 0; UINT32 uiCmdDataRegAddrBase = 0; UINT32 uiCmdDataRegAddr = 0; if (pstSelf->enState == SPI_STATE_READY) { if ((pstSelf->stInitParam.enDirection != SPI_DIRECTION_TXRX) && (pstSelf->stInitParam.enDirection != SPI_DIRECTION_RX)) { return HV_FAILURE; } if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { usCmdAddrSizeTemp = usCmdAddrSize; usDataSizeTemp = usDataSize; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_16) { usCmdAddrSizeTemp = usCmdAddrSize / 2; usDataSizeTemp = usDataSize / 2; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32) { usCmdAddrSizeTemp = usCmdAddrSize / 4; usDataSizeTemp = usDataSize / 4; } if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { if (usDataSize != 0) { uiDummySize = usCmdAddrSizeTemp; } usTxTotalSize = usCmdAddrSizeTemp + usDataSizeTemp; pstSelf->usRxXferSize = usCmdAddrSizeTemp + usDataSizeTemp; uiCmdDataRegAddrBase = CPU_SYS_SPI0_M_DR0 + pstSelf->uiBaseOffset; uiCmdDataRegAddr = uiCmdDataRegAddrBase; } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_ASSERT(pucCmdAddr == NULL); HV_ASSERT(usCmdAddrSize == 0); pstSelf->usRxXferSize = usDataSizeTemp; uiCmdDataRegAddrBase = CPU_SYS_SPI0_S_DR0 + pstSelf->uiBaseOffset; uiCmdDataRegAddr = uiCmdDataRegAddrBase; } pstSelf->enState = SPI_STATE_BUSY_RX; pstSelf->enErrorCode = SPI_ERROR_NONE; Hv_Spi_Enable(pstSelf); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) /*read more need read at the moment*/ { while (usTxTotalSize > 0) { uiTxFifoSurplusLev = HV_SPI_FIFO_DEPTH - Hv_Spi_GetTxFifoLevel(pstSelf); uiTxDataNumOnce = (usTxTotalSize > uiTxFifoSurplusLev)? uiTxFifoSurplusLev : usTxTotalSize; for (uiLoop = 0; uiLoop < uiTxDataNumOnce; uiLoop++) { if (usCmdAddrSizeTemp == 0) { Hv_Spi_TransmitOne(pstSelf, uiCmdDataRegAddr, ucDummy); uiCmdDataRegAddr = uiCmdDataRegAddr + 4; } else { pucCmdAddr = Hv_Spi_TransmitOne(pstSelf, uiCmdDataRegAddr, pucCmdAddr); usCmdAddrSizeTemp--; uiCmdDataRegAddr = uiCmdDataRegAddr + 4; } if ((uiCmdDataRegAddr - uiCmdDataRegAddrBase) == HV_SPI_DR_ADDR_RANGE_TOTAL) { uiCmdDataRegAddr = uiCmdDataRegAddrBase; } usTxTotalSize--; } uiRxFifoDataLev = Hv_Spi_GetRxFifoLevel(pstSelf); if (uiRxFifoDataLev > pstSelf->usRxXferSize) { uiRxFifoDataLev = pstSelf->usRxXferSize; } for (uiLoop = 0; uiLoop < uiRxFifoDataLev; uiLoop++) { if (uiDummySize == 0) { pucRxData = Hv_Spi_ReceiveOne(pstSelf, uiCmdDataRegAddrBase, pucRxData); } else { Hv_Spi_ReceiveOne(pstSelf, uiCmdDataRegAddrBase, ucDummy); uiDummySize--; } pstSelf->usRxXferSize--; } } } while (pstSelf->usRxXferSize > 0) { uiRxFifoDataLev = Hv_Spi_GetRxFifoLevel(pstSelf); if (uiRxFifoDataLev > pstSelf->usRxXferSize) { uiRxFifoDataLev = pstSelf->usRxXferSize; } for (uiLoop = 0; uiLoop < uiRxFifoDataLev; uiLoop++) { if (uiDummySize == 0) { pucRxData = Hv_Spi_ReceiveOne(pstSelf, uiCmdDataRegAddrBase, pucRxData); } else { Hv_Spi_ReceiveOne(pstSelf, uiCmdDataRegAddrBase, ucDummy); uiDummySize--; } pstSelf->usRxXferSize--; } if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { if ((Hv_Vos_GetTick() - ullTickstart) > uiTimeout) { return HV_TIMEOUT; } } } if ((pstSelf->stInitParam.enMode == SPI_MODE_MASTER) && (pstSelf->stInitParam.enCsCtlMode != SPI_CSMODE_ALWAYS_LOW)) { if (Hv_Spi_WaitOnFlagUntilTimeout(pstSelf, SPI_FLAG_BUSY, HV_RESET, HV_SPI_TIMEOUT) != HV_SUCCESS) { return HV_TIMEOUT; } } pstSelf->enState = SPI_STATE_READY; Hv_Spi_Disable(pstSelf); return HV_SUCCESS; } else { return HV_BUSY; } } /**@brief Receive an amount of data in no-blocking mode with interrupt * @param self pointer to spi structure * @param pCmd pointer to command buffer * @param pRxData pointer to data buffer * @param size amount of data to be sent * @retval result */ Status Hv_Drv_Spi_IntReceive(SpiSelf *pstSelf, UCHAR8 *pucCmdAddr, USHORT16 usCmdAddrSize, UCHAR8 *pucRxData,USHORT16 usDataSize) { UINT32 uiIntFlag = 0; USHORT16 usCmdAddrSizeTemp = 0; USHORT16 usDataSizeTemp = 0; if (pstSelf->enState == SPI_STATE_READY) { if ((pstSelf->stInitParam.enDirection != SPI_DIRECTION_TXRX) && (pstSelf->stInitParam.enDirection != SPI_DIRECTION_RX)) { return HV_FAILURE; } if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { usCmdAddrSizeTemp = usCmdAddrSize; usDataSizeTemp = usDataSize; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_16) { usCmdAddrSizeTemp = usCmdAddrSize / 2; usDataSizeTemp = usDataSize / 2; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32) { usCmdAddrSizeTemp = usCmdAddrSize / 4; usDataSizeTemp = usDataSize / 4; } if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { pstSelf->usDumSize= usCmdAddrSizeTemp; pstSelf->usCmdAddrSize = usCmdAddrSizeTemp; pstSelf->pucCmdAddr = pucCmdAddr; pstSelf->pucTxBuff = NULL; pstSelf->usTxXferSize = usDataSizeTemp; pstSelf->usTxXferCount = 0; } else if (pstSelf->stInitParam.enMode == SPI_MODE_SLAVE) { HV_ASSERT(pucCmdAddr == NULL); HV_ASSERT(usCmdAddrSize == 0); } pstSelf->pucRxBuff = pucRxData; pstSelf->usRxXferSize = usDataSizeTemp + pstSelf->usDumSize; pstSelf->usRxXferCount = 0; pstSelf->enState = SPI_STATE_BUSY_RX; pstSelf->enErrorCode = SPI_ERROR_NONE; pstSelf->enTransCompleteFlag = SPI_TRANS_IN_PROCESS; if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { uiIntFlag = SPI_INTERRUPT_TXEIR | SPI_INTERRUPT_TXOIR | SPI_INTERRUPT_RXFIR | SPI_INTERRUPT_RXOIR | SPI_INTERRUPT_RXUIR; } else { uiIntFlag = SPI_INTERRUPT_RXFIR | SPI_INTERRUPT_RXOIR | SPI_INTERRUPT_RXUIR; } Hv_Spi_InterruptEnable(pstSelf, uiIntFlag); Hv_Spi_Enable(pstSelf); return HV_SUCCESS; } else { return HV_BUSY; } } /**@brief Receive an amount of data in no-blocking mode with DMA * @param self pointer to spi structure * @param pucCmd pointer to command buffer * @param pucRxData pointer to data buffer * @param usDataSize amount of data to be sent * @retval result */ Status Hv_Drv_Spi_DmaReceive(SpiSelf *pstSelf, UCHAR8 *pucCmd, UCHAR8* pucRxData, USHORT16 usDataSize) { UINT32 uiTxBlockSize = 0; UINT32 uiRxBlockSize = 0; if (pstSelf->enState == SPI_STATE_READY) { if ((pstSelf->stInitParam.enDirection != SPI_DIRECTION_TXRX) && (pstSelf->stInitParam.enDirection != SPI_DIRECTION_RX)) { return HV_FAILURE; } if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_8) { HV_ASSERT((usDataSize % 4) == 0); uiTxBlockSize = usDataSize / 4; uiRxBlockSize = usDataSize; } else if (pstSelf->stInitParam.enDataSize == SPI_BITWIDTH_32) { uiTxBlockSize = usDataSize / 4; uiRxBlockSize = usDataSize / 4; } Hv_Cal_Dma_XferCallbackBond(pstSelf->pstDmaRx, Hv_Spi_DmaReceiveCpltCallback); Hv_Cal_Dma_SetBlockSize(pstSelf->pstDmaRx, uiRxBlockSize); Hv_Cal_Dma_SetDstAddr(pstSelf->pstDmaRx, (UINT32)pucRxData); Hv_Cal_Dma_ChannelEn(pstSelf->pstDmaRx); if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { Hv_Spi_ConfigDmaTxReg(pstSelf, SPI_DMATX_ENABLE, HV_SPI_DMA_TX_THRESHOLD); } Hv_Spi_ConfigDmaRxReg(pstSelf, SPI_DMARX_ENABLE, HV_SPI_DMA_RX_THRESHOLD); Hv_Spi_Enable(pstSelf); pstSelf->enState = SPI_STATE_BUSY_RX; pstSelf->enErrorCode = SPI_ERROR_NONE; pstSelf->enTransCompleteFlag = SPI_TRANS_IN_PROCESS; if (pstSelf->stInitParam.enMode == SPI_MODE_MASTER) { Hv_Cal_Dma_XferCallbackBond(pstSelf->pstDmaTx, Hv_Spi_DmaTransmitCpltCallback); Hv_Cal_Dma_SetBlockSize(pstSelf->pstDmaTx, uiTxBlockSize); Hv_Cal_Dma_SetSrcAddr(pstSelf->pstDmaTx, (UINT32)pucCmd); Hv_Cal_Dma_ChannelEn(pstSelf->pstDmaTx); } return HV_SUCCESS; } else { return HV_BUSY; } } /**@brief check spi transfer complete yes or not * @param self pointer to spi structure * @retval HV_TRUE/HV_FALSE */ BOOL Hv_Drv_Spi_TransferIsComplete(SpiSelf *pstSelf) { if (pstSelf->enTransCompleteFlag == SPI_TRANS_IN_PROCESS) { return HV_FALSE; } else if (pstSelf->enTransCompleteFlag == SPI_TRANS_END) { return HV_TRUE; } return HV_FALSE; } /**@brief read spi rx fifo data * @param self pointer to spi structure * @retval none */ VOID Hv_Drv_Spi_SaveModeReadEmptyFifo(SpiSelf *pstSelf) { UINT32 i = 0; UINT32 uiRxFifoDataLev = 0; UCHAR8 ucDataTmp[128] = {0}; //UINT32 uiData = 0; UINT32 uiCmdDataRegAddrBase = 0; uiCmdDataRegAddrBase = CPU_SYS_SPI0_S_DR0 + pstSelf->uiBaseOffset; uiRxFifoDataLev = Hv_Spi_GetRxFifoLevel(pstSelf); if (uiRxFifoDataLev > pstSelf->usRxXferSize) { uiRxFifoDataLev = pstSelf->usRxXferSize; } for (i = 0; i < uiRxFifoDataLev; i++) { Hv_Spi_ReceiveOne(pstSelf, uiCmdDataRegAddrBase, ucDataTmp); //uiData = *((UINT32 *)cmdDataRegAddrBase); } return; }