/*
 * @file hv_drv_Spi.h
 * @brief Header file of SPI module.
 *
 * @verbatim
 * ==============================================================================
 *                        ##### How to use #####
 * ==============================================================================
 * (+) Use ()
 *
 * @endverbatim
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2023-06-19
 */

#ifndef _HV_DRV_SPI_H
#define _HV_DRV_SPI_H
#include "Common/hv_comm_DataType.h"
#include "hv_cal_Dma.h"

/** @defgroup DRV_SPI DRV_SPI
 *  drv spi functions
 *  @{
 */

typedef enum _SpiPort
{
    SPI_PORT_0 = 0,
    SPI_PORT_1,
    SPI_PORT_MAX
} SpiPort;

typedef enum _SpiMode
{
    SPI_MODE_MASTER = 0,
    SPI_MODE_SLAVE,
    SPI_MODE_MAX
} SpiMode;

typedef enum _SpiBandWidth
{
    SPI_BITWIDTH_8      = 0x07, /* The DataSize for transmition is 8bits  */
    SPI_BITWIDTH_16     = 0x0F, /* The DataSize for transmition is 16bits */
    SPI_BITWIDTH_32     = 0x1F, /* The DataSize for transmition is 32bits */
    SPI_BITWIDTH_MAX,
} SpiBandWidth;

typedef enum _SpiDirection
{
    SPI_DIRECTION_TXRX = 0,   //SPI_DIRECTION_2LINES
    SPI_DIRECTION_TX,         //SPI_DIRECTION_1LINE
    SPI_DIRECTION_RX,         //SPI_DIRECTION_2LINES_RXONLY
    SPI_DIRECTION_MAX
} SpiDirection;

typedef enum _SpiClkPolarity
{
    SPI_CLKPOLARITY_LOW = 0,
    SPI_CLKPOLARITY_HIGH,
    SPI_CLKPOLARITY_MAX
} SpiClkPolarity;

typedef enum _SpiClkPhase
{
    SPI_CLKPHASE_1EDGE = 0,
    SPI_CLKPHASE_2EDGE,
    SPI_CLKPHASE_MAX
} SpiClkPhase;

typedef enum _SPiDivRatio
{
    SPI_DIVRATIO_2       = 2,
    SPI_DIVRATIO_4       = 4,
    SPI_DIVRATIO_8       = 8,
    SPI_DIVRATIO_16      = 16,
    SPI_DIVRATIO_32      = 32,
    SPI_DIVRATIO_64      = 64,
    SPI_DIVRATIO_128     = 128,
    SPI_DIVRATIO_256     = 256,
    SPI_DIVRATIO_512     = 512,
    SPI_DIVRATIO_MAX,
} SPiDivRatio;

typedef enum _SpiEnableState
{
    SPI_ENABLESTATE_RESET = 0,
    SPI_ENABLESTATE_SET,
    SPI_ENABLESTATE_MAX
} SpiEnableState;

typedef enum _SpiCsMode
{
    SPI_CSMODE_HARDWARE = 0,
    SPI_CSMODE_SOFTWARE,
    SPI_CSMODE_ALWAYS_LOW,
    SPI_CSMODE_MAX
} SpiCsMode;

typedef enum _SpiState
{
    SPI_STATE_RESET = 0,          /*!< SPI not yet initialized or disabled*/
    SPI_STATE_READY,              /*!< SPI initialized and ready for use*/
    SPI_STATE_BUSY,               /*!< SPI process is ongoing*/
    SPI_STATE_BUSY_TX,            /*!< Data Transmission process is ongoing */
    SPI_STATE_BUSY_RX,            /*!< Data Reception process is ongoing*/
    SPI_STATE_BUSY_TXRX,          /*!< Data Transmission and Reception process is ongoing */
    SPI_STATE_ERROR               /*!< SPI error state */
} SpiState;


typedef enum _SpiError
{
    SPI_ERROR_NONE = 0,          /*!< No error*/
    SPI_ERROR_MODF,              /*!< MODF error*/
    SPI_ERROR_TFEMPTY,           /*!< Tx fifo empty when transmit start as slave*/
    SPI_ERROR_OVR,               /*!< OVR error*/
    SPI_ERROR_DMA,               /*!< DMA transfer error */
    SPI_ERROR_FLAG,              /*!< Flag: RXNE,TXE, BSY */
    SPI_ERROR_TIMEOUT,           /*!< SPI Timeout erro */
} SpiError;


//SR
typedef enum _SpiFlag
{
    SPI_FLAG_BUSY    = (UINT32)(1 << 0),
    SPI_FLAG_TFNF    = (UINT32)(1 << 1),
    SPI_FLAG_TFE     = (UINT32)(1 << 2),
    SPI_FLAG_RFNE    = (UINT32)(1 << 3),
    SPI_FLAG_RFF     = (UINT32)(1 << 4),
    SPI_FLAG_TXE     = (UINT32)(1 << 5),
    SPI_FLAG_DCOL    = (UINT32)(1 << 6),
    SPI_FLAG_MAX,
} SpiFlag;

//ISR
typedef enum _SpiInterrupt
{
    SPI_INTERRUPT_TXEIR    = (UINT32)(1 << 0),
    SPI_INTERRUPT_TXOIR    = (UINT32)(1 << 1),
    SPI_INTERRUPT_RXUIR    = (UINT32)(1 << 2),
    SPI_INTERRUPT_RXOIR    = (UINT32)(1 << 3),
    SPI_INTERRUPT_RXFIR    = (UINT32)(1 << 4),
    SPI_INTERRUPT_MSTIR    = (UINT32)(1 << 5),
    SPI_INTERRUPT_MAX,
} SpiInterrupt;

typedef enum _SpiTransState
{
    SPI_TRANS_IN_PROCESS = 0,
    SPI_TRANS_END,
} SpiTransState;

typedef enum _SpiTransType
{
    SPI_TRANSMIT = 0,
    SPI_RECEIVE,
} SpiTransType;

typedef enum _SpiDmaTxEn
{
    SPI_DMATX_DISABLE = 0,
    SPI_DMATX_ENABLE,
} SpiDmaTxEn;

typedef enum _SpiDmaRxEn
{
    SPI_DMARX_DISABLE = 0,
    SPI_DMARX_ENABLE,
} SpiDmaRxEn;

typedef Status (*SpiCpltCallback)(SpiTransType enTransType, VOID *pArg);

typedef struct _SpiInitParam
{
    SpiMode                 enMode;                 /* Specifies the SPI operating mode: Master or Slave*/
    SpiDirection            enDirection;            /* Specifies the SPI Directional mode state.*/
    SpiBandWidth            enDataSize;             /* Specifies the SPI data size. */
    SpiClkPolarity          enClkPolarity;          /* Specifies the serial clock steady state. */
    SpiClkPhase             enClkPhase;             /* Specifies the clock active edge for the bit capture.*/
    SPiDivRatio             enBaudRatePrescaler;    /* Specifies the Baud Rate prescaler value.  */
    SpiCsMode               enCsCtlMode;            /* Specifies CS is controlled by controller or gpio */
    SpiCpltCallback         pfSpiCpltCallback;
} SpiInitParam;

typedef struct _SpiSelf SpiSelf;

#define HV_SPI_FIFO_DEPTH                   (16)
#define HV_SPI_TIMEOUT                      (5000)
#define HV_SPI_DR_ADDR_RANGE_TOTAL          (34 * 4)  /* Data Register Number */
#define HV_SPI_NO_DUMMY                     (0)

#if 1
#define HV_SPI_DMA_TX_THRESHOLD   1
#define HV_SPI_DMA_RX_THRESHOLD   0
#else
#define HV_SPI_DMA_TX_THRESHOLD   8
#define HV_SPI_DMA_RX_THRESHOLD   7
#endif

/**@brief Set the spi direction
 *  @param self pointer to spi structure.
 *  @param enDirection
 *  @retval none
 */
VOID Hv_Drv_Spi_SetDirection(SpiSelf *pstSelf, SpiDirection enDirection);

/**@brief Set data frame size
 *  @param self pointer to spi structure.
 *  @param FrameWidth Indicates how many bits of data are serially transmitted in a frame.
 *  @retval none
 */
VOID Hv_Drv_Spi_SetBitsWidth(SpiSelf *pstSelf, SpiBandWidth enFrameWidth);

/**@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);

/**@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);

/**@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);

/**@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);

/**@brief Get spi state
 *  @param self pointer to spi structure
 *  @retval spi state
 */
UCHAR8 Hv_Drv_Spi_GetState(const SpiSelf *self);

/**@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);

/**@brief De-initializes the SPI
 *  @param self pointer to spi structure
 *  @retval result
 */
Status Hv_Drv_Spi_Cleanup(SpiSelf *pstSelf);

/**@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);

 /**@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);

/**@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);

/**@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);

/**@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);

/**@brief Receive an amount of data in no-blocking mode with DMA
 *  @param self pointer to spi structure
 *  @param pCmd pointer to command buffer
 *  @param pData pointer to data buffer
 *  @param size amount of data to be sent
 *  @retval result
 */
Status Hv_Drv_Spi_DmaReceive(SpiSelf *pstSelf, UCHAR8 *pucCmd, UCHAR8 *pucRxData, USHORT16 usDataSize);

/**@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);

/** @} */
#endif//_HV_DRV_SPI_H
