/*************************************************************************
*qspi.h
*This is head file for ssi0 module
*CopyRight by BWAVE
*Author:ZengYu
*Rev:Rev1.00
*data:2023.06.13
--------------------------------------------------------------------------
modify:

*************************************************************************/
#ifndef _QSPI_H_
#define _QSPI_H_

/* QSPI system clock frequency */
#define QSPI_SYSTEM_CLK                     LISOC_ARM_SYS_CLK   /* QSPI works on AHB sys clock */

#ifdef CFG_FPGA
#define SPI_DEF_BAUDR_DIV                   2u        /* 20MHz / 2 = 10MHz */
#define SPI_FAST_BAUDR_DIV                  2u        /* Minimum possible div setting = 2 */
#else
#define SPI_DEF_BAUDR_DIV                   6u        /* 27MHz / 2 = 13.5MHz */
#define SPI_FAST_BAUDR_DIV                  6u        /* Minimum possible div setting = 2  27M/2=13.5M */
#endif

/*********************************************************************************
* CTRL_R0 register bits macro
*********************************************************************************/
#define SPI_DFS_BITOFS                      0u
#define SPI_DFS_BITMASK                     (0x1Fu << SPI_DFS_BITOFS)
#define SPI_DAT_FRM_SIZ_4bit                0x03u
#define SPI_DAT_FRM_SIZ_8bit                0x07u
#define SPI_DAT_FRM_SIZ_16bit               0x0Fu
#define SPI_DAT_FRM_SIZ_32bit               0x1Fu

#define SPI_FRF_BITOFS                      6u
#define SPI_FRF_BITMASK                     (0x03u << SPI_FRF_BITOFS)
#define SPI_FRM_FMT_SPI                     0x00u
#define SPI_FRM_FMT_SSI                     0x01u
#define SPI_FRM_FMT_MICW                    0x02u

#define SPI_SCPH_BITOFS                     8u
#define SPI_SCLK_PHAS_BITMASK               (0x01u << SPI_SCPH_BITOFS)

typedef enum {
  SPI_CLOCK_PHASE_MIDDLE = 0u,
  SPI_CLOCK_PHASE_START = 1u,
} SPI_PHASE;


#define SPI_SCPOL_BITOFS                    9u
#define SPI_SCLK_POL_BITMASK                (0x01u << SPI_SCPOL_BITOFS)
typedef enum {
  SPI_CLOCK_POLARITY_LOW = 0u,
  SPI_CLOCK_POLARITY_HIGH = 1u,
} SPI_POLARITY;

#define SPI_TMOD_BITOFS                     10u
#define SPI_TMOD_BITMASK                    (0x03u << SPI_TMOD_BITOFS)
#define SPI_TMOD_TX_RX                      0x00u
#define SPI_TMOD_TX                         0x01u
#define SPI_TMOD_RX                         0x02u
#define SPI_TMOD_E2PROM                     0x03u

#define SPI_SSTE_BITOFS                     14u
#define SPI_SLVSEL_TOGG_EN_BITMASK          (0x01u << SPI_SSTE_BITOFS)
typedef enum {
  SPI_TOGGLE_DISABLE = 0u,
  SPI_TOGGLE_ENABLE,
} SPI_TOGGLE;

#define SPI_SPI_FRF_BITOFS                  22u
#define SPI_SPI_FRF_BITMASK                 (0x03u << SPI_SPI_FRF_BITOFS)
#define SPI_SPI_FRF_STD                     0x00u
#define SPI_SPI_FRF_DUAL                    0x01u
#define SPI_SPI_FRF_QUAD                    0x02u
#define SPI_SPI_FRF_OCTAL                   0x03u

#define SPI_SSI_IS_MST_BITOFS               31u
#define SPI_SSI_IS_MST_BITMASK              (0x01u << SPI_SSI_IS_MST_BITOFS)

/*********************************************************************************
* SSIENR register bits macro
*********************************************************************************/
#define SPI_ENABLE                          0x01u
#define SPI_DISABLE                         0x00u

/*********************************************************************************
* SER (Slave Select Enable) register bits macro
*********************************************************************************/
typedef enum {
    SPI_CS_NONE = 0u,
    SPI_CS0 = 1u,
    SPI_CS1 = 2u,
} SPI_SLAVE;

/*********************************************************************************
* TXFLR, RXFLR register bits macro
*********************************************************************************/
#define SSI0_TXFIFO_DEPTH                   32u       /* max # of 1-byte entries in Tx fifo */
#define SSI0_RXFIFO_DEPTH                   32u       /* max # of 1-byte entries in Rx fifo */

#define SSI0_TX_PREFILL_THRES               28u       /* Prefill Tx fifo by this # of data entries */
#define SSI0_TXFIFO_THRES                   16u       /* when Tx fifo drops below this #, fill it up */

/*********************************************************************************
* SR (Status) register bits macro
*********************************************************************************/
#define SSI0_SR_BUSY                        0x1u
#define SSI0_SR_TF_NF                       0x2u
#define SSI0_SR_TF_E                        0x4u
#define SSI0_SR_RF_NE                       0x8u
#define SSI0_SR_RF_F                        0x10u
#define SSI0_SR_TX_ERR                      0x20u
#define SSI0_SR_DCOL                        0x40u

/*********************************************************************************
* IMR register bits macro
*********************************************************************************/
#define SPI_INT_DISABLE                     0x00

/*********************************************************************************
* SPI_CTRLR0 register bits macro
*********************************************************************************/
#define SPIR0_TRANS_TYP_BITOFS              0u
#define SPIR0_TRANS_TYP_MASK                (0x03u << SPIR0_TRANS_TYP_BITOFS)
#define SPIR0_INS_STD_ADR_STD               0u
#define SPIR0_INS_STD_ADR_FRF               1u
#define SPIR0_INS_FRF_ADR_FRF               2u

#define SPIR0_ADDR_L_BITOFS                 2u
#define SPIR0_ADDR_L_MASK                   (0x0Fu << SPIR0_ADDR_L_BITOFS)
#define SPIR0_ADDR_L_0bit                   0x00u
#define SPIR0_ADDR_L_8bit                   0x02u
#define SPIR0_ADDR_L_16bit                  0x04u
#define SPIR0_ADDR_L_20bit                  0x05u
#define SPIR0_ADDR_L_24bit                  0x06u
#define SPIR0_ADDR_L_28bit                  0x07u
#define SPIR0_ADDR_L_32bit                  0x08u

#define SPIR0_XIP_MODBIT_EN_BITOFS          7u
#define SPIR0_XIP_MODBIT_EN_MASK            (0x01u << SPIR0_XIP_MODBIT_EN_BITOFS)

#define SPIR0_INST_L_BITOFS                 8u
#define SPIR0_INST_L_MASK                   (0x03u << SPIR0_INST_L_BITOFS)
#define SPIR0_INST_L_0bit                   0x00u
#define SPIR0_INST_L_4bit                   0x01u
#define SPIR0_INST_L_8bit                   0x02u
#define SPIR0_INST_L_16bit                  0x03u

#define SPIR0_WAIT_CYC_BITOFS               11u
#define SPIR0_WAIT_CYC_MASK                 (0x1Fu << SPIR0_WAIT_CYC_BITOFS)
#define SPIR0_WAIT_CYC_0_CYC                0u
#define SPIR0_WAIT_CYC_4_CYC                4u
#define SPIR0_WAIT_CYC_6_CYC                6u
#define SPIR0_WAIT_CYC_8_CYC                8u
#define SPIR0_WAIT_CYC_10_CYC               10u
#define SPIR0_WAIT_CYC_31_CYC               31u

#define SPIR0_XIP_DFS_HC_BITOFS             19u
#define SPIR0_XIP_DFS_HC_MASK               (0x01u << SPIR0_XIP_DFS_HC_BITOFS)

#define SPIR0_XIP_INST_EN_BITOFS            20u
#define SPIR0_XIP_INST_EN_MASK              (0x01u << SPIR0_XIP_INST_EN_BITOFS)

#define SPIR0_XIP_CONT_XFER_EN_BITOFS       21u
#define SPIR0_XIP_CONT_XFER_EN_MASK         (0x01u << SPIR0_XIP_CONT_XFER_EN_BITOFS)

#define SPIR0_DM_EN_BITOFS                  24u
#define SPIR0_DAT_MSK_EN_MASK               (0x01u << SPIR0_DM_EN_BITOFS)

#define SPIR0_RXDS_SIG_EN_BITOFS            25u
#define SPIR0_RXDS_SIG_EN_MASK              (0x01u << SPIR0_RXDS_SIG_EN_BITOFS)

#define SPIR0_XIP_MBL_BITOFS                26u
#define SPIR0_XIP_MBL_MASK                  (0x03u << SPIR0_XIP_MBL_BITOFS)
#define SPIR0_XIP_MBL_2bit                  0x00u
#define SPIR0_XIP_MBL_4bit                  0x01u
#define SPIR0_XIP_MBL_8bit                  0x02u
#define SPIR0_XIP_MBL_16bit                 0x03u

#define SPIR0_XIP_PREFETCH_EN_BITOFS        29u
#define SPIR0_XIP_PREFETCH_EN_MASK          (0x01u << SPIR0_XIP_PREFETCH_EN_BITOFS)

#define SPIR0_CLK_STRETCH_EN_BITOFS         30u
#define SPIR0_CLK_STRETCH_EN_MASK           (0x01u << SPIR0_CLK_STRETCH_EN_BITOFS)

/*********************************************************************************
* XIP SYSC CCON0 register bits macro
*********************************************************************************/
#define SOC_CCON0_XIP_EN_BITOFS             0u
#define SOC_CCON0_QSPI_SS_IN_N_BITOFS       1u
#define SOC_CCON0_SPIMST_SS_IN_N_BITOFS     2u
#define SOC_CCON0_CACHE_BRIDGE_EN_BITOFS    3u

#define SPIF_XIP_MODE_BITS                  0xFCu
#define SPIF_XIP_CNT_TIME_OUT               0x10u

#define BOOT_XIP_NO_CACHE_MOD               0u
#define BOOT_XIP_CACHE_MOD                  1u

/*********************************************************************************
* ISR (Interrupt Status) register bits macro
*********************************************************************************/
#define SSI0_ISR_XRXOIS_BITOFS                  6u
#define SSI0_ISR_XRXOIS                         (1u << SSI0_ISR_XRXOIS_BITOFS)
#define SSI0_ISR_MSTIS_BITOFS                   5u
#define SSI0_ISR_MSTIS                          (1u << SSI0_ISR_MSTIS_BITOFS)
#define SSI0_ISR_RXFIS_BITOFS                   4u
#define SSI0_ISR_RXFIS                          (1u << SSI0_ISR_RXFIS_BITOFS)
#define SSI0_ISR_RXOIS_BITOFS                   3u
#define SSI0_ISR_RXOIS                          (1u << SSI0_ISR_RXOIS_BITOFS)
#define SSI0_ISR_RXUIS_BITOFS                   2u
#define SSI0_ISR_RXUIS                          (1u << SSI0_ISR_RXUIS_BITOFS)
#define SSI0_ISR_TXOIS_BITOFS                   1u
#define SSI0_ISR_TXOIS                          (1u << SSI0_ISR_TXOIS_BITOFS)
#define SSI0_ISR_TXEIS_BITOFS                   0u
#define SSI0_ISR_TXEIS                          (1u << SSI0_ISR_TXEIS_BITOFS)

/*function declaration*/

/*******************************************************************************
* Set CTRLR0.FRF: SPI_FRM_FMT_SPI, SPI_FRM_FMT_SSI, or SPI_FRM_FMT_MICW
********************************************************************************/
__INLINE void SPIM_SetFrmFormat(uint32_t fmt)
{
  SSI0_CTRLR0 = SSI0_CTRLR0 & (~SPI_FRF_BITMASK) | (fmt << SPI_FRF_BITOFS);
}

/*******************************************************************************
* Set CTRLR0.SPI_FRF: SPI_SPI_FRF_STD, SPI_SPI_FRF_DUAL, or SPI_SPI_FRF_QUAD
********************************************************************************/
__INLINE void SPIM_SetSpiFrmFormat(uint32_t spi_format)
{
  SSI0_CTRLR0 = SSI0_CTRLR0 & (~SPI_SPI_FRF_BITMASK) | (spi_format << SPI_SPI_FRF_BITOFS);
}

/*******************************************************************************
* Set CTRLR0.TMOD (spi Tx Rx trans mode):    SPI_TXRX_MOD_TX or SPI_TXRX_MOD_RX
********************************************************************************/
__INLINE void SPIM_SetMode(uint32_t mode)
{
  SSI0_CTRLR0 = SSI0_CTRLR0 & (~SPI_TMOD_BITMASK) | (mode << SPI_TMOD_BITOFS);
}

/*******************************************************************************
*set spi polarity
********************************************************************************/
__INLINE void SPIM_SetPolarity(SPI_POLARITY polarity)
{
  switch(polarity)
  {
    case SPI_CLOCK_POLARITY_LOW:
      SSI0_CTRLR0 &= (~SPI_SCLK_POL_BITMASK);
      break;

    case SPI_CLOCK_POLARITY_HIGH:
      SSI0_CTRLR0 |= SPI_SCLK_POL_BITMASK;
      break;

    default:
      break;
  }
}

/*******************************************************************************
*set spi phase
********************************************************************************/
__INLINE void SPIM_SetPhase(SPI_PHASE phase)
{
  switch(phase)
  {
    case SPI_CLOCK_PHASE_MIDDLE:
      SSI0_CTRLR0 &= (~SPI_SCLK_PHAS_BITMASK);
      break;

    case SPI_CLOCK_PHASE_START:
      SSI0_CTRLR0 |= SPI_SCLK_PHAS_BITMASK;
      break;

    default:
      break;
  }
}

/*******************************************************************************
*set spi data width
********************************************************************************/
__INLINE void SPIM_SetDataWidth(uint32_t datawidth)
{
  SSI0_CTRLR0 = SSI0_CTRLR0 & (~SPI_DFS_BITMASK) | (datawidth << SPI_DFS_BITOFS);
}

/*******************************************************************************
*set spi behavior of the slave select line (ss_*_n) between data frames.
********************************************************************************/
__INLINE void SPIM_SetSlaveSlectToggleEn(SPI_TOGGLE toggle)
{
  switch(toggle)
  {
    case SPI_TOGGLE_DISABLE:
      SSI0_CTRLR0 &= (~SPI_SLVSEL_TOGG_EN_BITMASK);
      break;

    case SPI_TOGGLE_ENABLE:
      SSI0_CTRLR0 |= SPI_SLVSEL_TOGG_EN_BITMASK;
      break;

    default:
      break;
  }
}


__INLINE void SPIM_Disable(void)
{
  SSI0_SSIENR = SPI_DISABLE;
}

__INLINE void SPIM_Enable(void)
{
  SSI0_SSIENR = SPI_ENABLE;
}

/*******************************************************************************
*select slave,spi master1 has 2 cs,suport two  slaves.spi mater0 only one cs.
********************************************************************************/
__INLINE void SPIM_SelectSlave(SPI_SLAVE slave)
{
  SSI0_SER = slave;
}

/*******************************************************************************
*set bitrate
********************************************************************************/
__INLINE void SPIM_SetBaudrate(uint32_t baudrate)
{
  SSI0_BAUDR = baudrate;
}

/*******************************************************************************
*mask the spi master interrupt
********************************************************************************/
__INLINE void SPIM_MaskInt(uint32_t mask)
{
  SSI0_IMR = mask;
}

/*******************************************************************************
* Set Wait cycles in Dual/Quad/Octal mode between ADDR tx and DATA rx
********************************************************************************/
__INLINE void SPIM_SetWaitCycle(uint32_t cycle)
{
  SSI0_SPI_CTRLR0 = SSI0_SPI_CTRLR0 & (~SPIR0_WAIT_CYC_MASK) | (cycle << SPIR0_WAIT_CYC_BITOFS);
}

/*******************************************************************************
* Set Dual/Quad/Octal mode instruction length in bits.(SPI_CTRLR0.INST_L)
********************************************************************************/
__INLINE void SPIM_SetInsLen(uint32_t inst_len)
{
  SSI0_SPI_CTRLR0 = SSI0_SPI_CTRLR0 & (~SPIR0_INST_L_MASK) | (inst_len << SPIR0_INST_L_BITOFS);
}

/*******************************************************************************
* Set Length of Address to be transmitted.(SPI_CTRLR0.ADDR_L)
* Only after this much bits are programmed in to the FIFO the transfer can begin.
********************************************************************************/
__INLINE void SPIM_SetAddrLen(uint32_t addr_len)
{
  SSI0_SPI_CTRLR0 = SSI0_SPI_CTRLR0 & (~SPIR0_ADDR_L_MASK) | (addr_len << SPIR0_ADDR_L_BITOFS);
}

/*******************************************************************************
* Set spi instruction / address transmission type
********************************************************************************/
__INLINE void SPIM_SetTransType(uint32_t spi_trans_type)
{
  SSI0_SPI_CTRLR0 = SSI0_SPI_CTRLR0 & (~SPIR0_TRANS_TYP_MASK) | (spi_trans_type << SPIR0_TRANS_TYP_BITOFS);
}

__INLINE void SPIM_SetClkStretEnable(void)
{
  SSI0_SPI_CTRLR0 |= SPIR0_CLK_STRETCH_EN_MASK;
}

__INLINE void SPIM_SetClkStretDisable(void)
{
  SSI0_SPI_CTRLR0 &= ~SPIR0_CLK_STRETCH_EN_MASK;
}

/*******************************************************************************
* XIP utility inline functions
********************************************************************************/
__INLINE void SPIM_SetSpiIsMaster(void)
{
  SSI0_CTRLR0 |= SPI_SSI_IS_MST_BITMASK;
}

__INLINE void SPIM_SetSpiIsSlave(void)
{
  SSI0_CTRLR0 &= ~SPI_SSI_IS_MST_BITMASK;
}

__INLINE void SPIM_SysXIPEnable(void)
{
  SYSC_SOC_CCON0 |= 0x01u << SOC_CCON0_XIP_EN_BITOFS;
}

__INLINE void SPIM_SysXIPDisable(void)
{
  SYSC_SOC_CCON0 &= ~(0x01u << SOC_CCON0_XIP_EN_BITOFS);
}

__INLINE void SPIM_XIPInsEnable(void)
{
  SSI0_SPI_CTRLR0 |= SPIR0_XIP_INST_EN_MASK;
}

__INLINE void SPIM_XIPInsDiable(void)
{
  SSI0_SPI_CTRLR0 &= ~SPIR0_XIP_INST_EN_MASK;
}

__INLINE void SPIM_XIPContTransEnable(void)
{
  SSI0_SPI_CTRLR0 |= SPIR0_XIP_CONT_XFER_EN_MASK;
}

__INLINE void SPIM_XIPContTransDisable(void)
{
  SSI0_SPI_CTRLR0 &= ~SPIR0_XIP_CONT_XFER_EN_MASK;
}

__INLINE void SPIM_SetXIPIncrIns(uint32_t ins)
{
  SSI0_XIP_INCR_INST = ins;
}

__INLINE void SPIM_SetXIPWrapIns(uint32_t ins)
{
  SSI0_XIP_WRAP_INST = ins;
}

__INLINE void SPIM_SetXIPCntTimeOut(uint8_t count)
{
  SSI0_XIP_CNT_TIME_OUT = count;
}

__INLINE void SPIM_SetXIPModeBitEn(void)
{
  SSI0_SPI_CTRLR0 |= SPIR0_XIP_MODBIT_EN_MASK;
}

__INLINE void SPIM_SetXIPModeBitDis(void)
{
  SSI0_SPI_CTRLR0 &= ~SPIR0_XIP_MODBIT_EN_MASK;
}

__INLINE void SPIM_SetXIPModeBitsLen(uint32_t len)
{
  SSI0_SPI_CTRLR0 &= ~SPIR0_XIP_MBL_MASK;
  SSI0_SPI_CTRLR0 |= len << SPIR0_XIP_MBL_BITOFS;
}

__INLINE void SPIM_SetXIPPreFetchEn(void)
{
  SSI0_SPI_CTRLR0 |= SPIR0_XIP_PREFETCH_EN_MASK;
}

__INLINE void SPIM_SetXIPFixedDFSTrans(void)
{
  SSI0_SPI_CTRLR0 |= SPIR0_XIP_DFS_HC_MASK;
}

__INLINE void SPIM_SetXIPModeBits(uint32_t mode_bits)
{
  SSI0_SPI_XIP_MODE_BITS = mode_bits;
}

__INLINE void SPIM_XIPSelectSlave(SPI_SLAVE slave)
{
  SSI0_XIP_SER = slave;
}

__INLINE void SPIM_SysCacheEnable(void)
{
  CACHE_CR |= 0x01u;
  SYSC_SOC_CCON0 |= 0x01u << SOC_CCON0_CACHE_BRIDGE_EN_BITOFS;
}

__INLINE void SPIM_SysCacheDisable(void)
{
  CACHE_CR &= ~0x01u;
  SYSC_SOC_CCON0 &= ~(0x01u << SOC_CCON0_CACHE_BRIDGE_EN_BITOFS);
}

__INLINE uint32_t SPIM_GetIntSts(void)
{
  return SSI0_ISR;
}

__INLINE uint32_t SPIM_GetRawIntSts(void)
{
  return SSI0_RISR;
}

__INLINE uint32_t SPIM_ClerTxOverflowIntSts(void)
{
  uint32_t reg;
  /* read register clear interrupt status. */
  reg = SSI0_TXOICR;
  return reg;
}

__INLINE uint32_t SPIM_ClerRxOverflowIntSts(void)
{
  uint32_t reg;
  /* read register clear interrupt status. */
  reg = SSI0_RXOICR;
  return reg;
}

__INLINE uint32_t SPIM_ClerRxUnderflowIntSts(void)
{
  uint32_t reg;
  /* read register clear interrupt status. */
  reg = SSI0_RXUICR;
  return reg;
}

__INLINE uint32_t SPIM_ClerMstContentionIntSts(void)
{
  uint32_t reg;
  /* read register clear interrupt status. */
  reg = SSI0_MSTICR;
  return reg;
}

__INLINE uint32_t SPIM_ClerIntSts(void)
{
  uint32_t reg;
  /* read register clear interrupt status. */
  reg = SSI0_ICR;
  return reg;
}

__INLINE void SPIM_SetRXSampleDelayClk(uint8_t delay_clk)
{
  SSI0_RX_SMPL_DLY = delay_clk;
}

#endif  /* QSPI_H */
