/**
 * @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.
 * </table>
 */

#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;
}

