/*!
 * @file        qpm32f10x_qspi.c
 *
 * @brief       This file contains all the functions for the QSPI peripheral
 *
 * @version     V1.0.1
 *
 * @date        2021-03-23
 *
 */

#if defined (APM32F10X_MD) || defined (APM32F10X_LD)

#include "apm32f10x_qspi.h"

/** @addtogroup Peripherals_Library Standard Peripheral Library
  @{
*/

/** @addtogroup QSPI_Driver  QSPI Driver
  @{
*/

/** @addtogroup QSPI_Fuctions Fuctions
  @{
*/

/*!
 * @brief       Reset QSPI peripheral registers to their default values
 *
 * @param       None
 *
 * @retval      None
 */
void QSPI_Reset(void)
{
    volatile uint32_t dummy = 0;

    QSPI->IOSW = QSPI_IOSW_RESET_VALUE;
    QSPI->SSIEN = QSPI_SSIEN_RESET_VALUE;
    QSPI->INTEN = QSPI_INTEN_RESET_VALUE;
    dummy = QSPI->ICF;
    QSPI->CTRL1 = QSPI_CTRL1_RESET_VALUE;
    QSPI->CTRL2 = QSPI_CTRL2_RESET_VALUE;
    QSPI->CTRL3 = QSPI_CTRL3_RESET_VALUE;
    QSPI->SLAEN = QSPI_SLAEN_RESET_VALUE;
    QSPI->BR = QSPI_BR_RESET_VALUE;
    QSPI->TFL = QSPI_TFL_RESET_VALUE;
    QSPI->RFL = QSPI_RFL_RESET_VALUE;
    QSPI->TFTL = QSPI_TFTL_RESET_VALUE;
    QSPI->RFTL = QSPI_RFTL_RESET_VALUE;
    QSPI->STS = QSPI_STS_RESET_VALUE;
    QSPI->RSD = QSPI_RSD_RESET_VALUE;
}

/*!
 * @brief       Config the QSPI peripheral according to the specified parameters in the qspiConfig
 *
 * @param       qspiConfig: Pointer to a QSPI_Config_T structure that contains the configuration information
 *
 * @retval      None
 */
void QSPI_Config(QSPI_Config_T * qspiConfig)
{
    QSPI->CTRL1_B.CPHA = qspiConfig->clockPhase;
    QSPI->CTRL1_B.CPOL = qspiConfig->clockPolarity;
    QSPI->CTRL1_B.FRF = qspiConfig->frameFormat;
    QSPI->CTRL1_B.DFS = qspiConfig->dataFrameSize;;
    QSPI->CTRL1_B.SSTEN = qspiConfig->selectSlaveToggle;

    QSPI->BR = qspiConfig->clockDiv;

}

/*!
 * @brief       Fills each qspiConfig member with its default value
 *
 * @param       qspiConfig: Pointer to a QSPI_Config_T structure which will be initialized
 *
 * @retval      None
 */
void QSPI_ConfigStructInit(QSPI_Config_T *qspiConfig)
{
    qspiConfig->clockPhase = QSPI_CLKPHA_2EDGE;
    qspiConfig->clockPolarity = QSPI_CLKPOL_LOW;
    qspiConfig->clockDiv = 0;

    qspiConfig->frameFormat = QSPI_FRF_STANDARD;
    qspiConfig->dataFrameSize = QSPI_DFS_8BIT;
    qspiConfig->selectSlaveToggle = QSPI_SST_DISABLE;
}

/*!
 * @brief       Configs frame number
 *
 * @param       num: Configs a 16bit frame number
 *
 * @retval      None
 */
void QSPI_ConfigFrameNum(uint16_t num)
{
    QSPI->CTRL2_B.NDF = num;
}

/*!
 * @brief       Configs data frame size
 *
 * @param       dfs: Specifies the data frame size
 *                   The parameter can be one of following values:
 *                   @arg QSPI_DFS_4BIT  : Specifies data frame size to 4bit
 *                   @arg QSPI_DFS_5BIT  : Specifies data frame size to 5bit
 *                   @arg QSPI_DFS_6BIT  : Specifies data frame size to 6bit
 *                   @arg QSPI_DFS_7BIT  : Specifies data frame size to 7bit
 *                   @arg QSPI_DFS_8BIT  : Specifies data frame size to 8bit
 *                   @arg QSPI_DFS_9BIT  : Specifies data frame size to 9bit
 *                   @arg QSPI_DFS_10BIT : Specifies data frame size to 10bit
 *                   @arg QSPI_DFS_11BIT : Specifies data frame size to 11bit
 *                   @arg QSPI_DFS_12BIT : Specifies data frame size to 12bit
 *                   @arg QSPI_DFS_13BIT : Specifies data frame size to 13bit
 *                   @arg QSPI_DFS_14BIT : Specifies data frame size to 14bit
 *                   @arg QSPI_DFS_15BIT : Specifies data frame size to 15bit
 *                   @arg QSPI_DFS_16BIT : Specifies data frame size to 16bit
 *                   @arg QSPI_DFS_17BIT : Specifies data frame size to 17bit
 *                   @arg QSPI_DFS_18BIT : Specifies data frame size to 18bit
 *                   @arg QSPI_DFS_19BIT : Specifies data frame size to 19bit
 *                   @arg QSPI_DFS_20BIT : Specifies data frame size to 20bit
 *                   @arg QSPI_DFS_21BIT : Specifies data frame size to 21bit
 *                   @arg QSPI_DFS_22BIT : Specifies data frame size to 22bit
 *                   @arg QSPI_DFS_23BIT : Specifies data frame size to 23bit
 *                   @arg QSPI_DFS_24BIT : Specifies data frame size to 24bit
 *                   @arg QSPI_DFS_25BIT : Specifies data frame size to 25bit
 *                   @arg QSPI_DFS_26BIT : Specifies data frame size to 26bit
 *                   @arg QSPI_DFS_27BIT : Specifies data frame size to 27bit
 *                   @arg QSPI_DFS_28BIT : Specifies data frame size to 28bit
 *                   @arg QSPI_DFS_29BIT : Specifies data frame size to 29bit
 *                   @arg QSPI_DFS_30BIT : Specifies data frame size to 30bit
 *                   @arg QSPI_DFS_31BIT : Specifies data frame size to 31bit
 *                   @arg QSPI_DFS_32BIT : Specifies data frame size to 32bit
 *
 * @retval      None
 */
void QSPI_ConfigDataFrameSize(QSPI_DFS_T dfs)
{
    QSPI->CTRL1_B.DFS = dfs;
}

/*!
 * @brief       Configs frame format
 *
 * @param       frameFormat
 *
 * @retval      None
 */
void QSPI_ConfigFrameFormat(QSPI_FRF_T frameFormat)
{
    QSPI->CTRL1_B.FRF = frameFormat;
}

/*!
 * @brief       Enable QSPI
 *
 * @param       None
 *
 * @retval      None
 */
void QSPI_Enable(void)
{
    QSPI->SSIEN_B.EN = BIT_SET;
}

/*!
 * @brief       Disable QSPI
 *
 * @param       None
 *
 * @retval      None
 */
void QSPI_Disable(void)
{
    QSPI->SSIEN_B.EN = BIT_RESET;
}

/*!
 * @brief       Read Tx FIFO number of data
 *
 * @param       None
 *
 * @retval      None
 */
uint8_t QSPI_ReadTxFifoDataNum(void)
{
    return (uint8_t)QSPI->TFL_B.TFL;
}

/*!
 * @brief       Read Rx FIFO number of data
 *
 * @param       None
 *
 * @retval      Returns Rx FIFO number of data
 */
uint8_t QSPI_ReadRxFifoDataNum(void)
{
    return (uint8_t)QSPI->RFL_B.RFL;
}

/*!
 * @brief       Configs rx FIFO threshold
 *
 * @param       threshold: Speicifes rx FIFO threshold with a 3bit value
 *
 * @retval      None
 */
void QSPI_ConfigRxFifoThreshold(uint8_t threshold)
{
    QSPI->RFTL_B.RFT = threshold;
}

/*!
 * @brief       Congfigs Tx FIFO threshold
 *
 * @param       threshold: Speicifes Tx FIFO threshold with a 3bit value
 *
 * @retval      None
 */
void QSPI_ConfigTxFifoThreshold(uint8_t threshold)
{
    QSPI->TFTL_B.TFTH = threshold;
}

/*!
 * @brief       Congfigs Tx FIFO empty threshold
 *
 * @param       threshold: Speicifes Tx FIFO empty threshold with a 3bit value
 *
 * @retval      None
 */
void QSPI_ConfigTxFifoEmptyThreshold(uint8_t threshold)
{
    QSPI->TFTL_B.TFT = threshold;
}

/*!
 * @brief       Configs RX sample edge
 *
 * @param       rse: Specifies the sample edge
 *                   The parameter can be one of following values:
 *                   @arg QSPI_RSE_RISING : rising edge sample
 *                   @arg QSPI_RSE_FALLING: falling edge sample
 *
 * @retval      None
 */
void QSPI_ConfigRxSampleEdge(QSPI_RSE_T rse)
{
    QSPI->RSD_B.RSE = rse;
}

/*!
 * @brief       Set RX sample delay
 *
 * @param       delay: Specifies the sample delay with a 8-bit value
 *
 * @retval      None
 */
void QSPI_ConfigRxSampleDelay(uint8_t delay)
{
    QSPI->RSD_B.RSD = delay;
}

/*!
 * @brief       Clock stretch enable
 *
 * @param       None
 *
 * @retval      None
 */
void QSPI_EnableClockStretch(void)
{
    QSPI->CTRL3_B.CSEN = BIT_SET;
}

/*!
 * @brief       Clock stretch disable
 *
 * @param       None
 *
 * @retval      None
 */
void QSPI_DisableClockStretch(void)
{
    QSPI->CTRL3_B.CSEN = BIT_RESET;
}

/*!
 * @brief       Configs instruction length
 *
 * @param       len: Specifies the length of instruction
 *                   The parameter can be one of following values:
 *                   @arg QSPI_INST_LEN_0     : no instruction
 *                   @arg QSPI_INST_LEN_4BIT  : 4-bit instruction
 *                   @arg QSPI_INST_LEN_8BIT  : 8-bit instruction
 *                   @arg QSPI_INST_LEN_16BIT : 16-bit instruction
 *
 * @retval      None
 */
void QSPI_ConfigInstLen(QSPI_INST_LEN_T len)
{
    QSPI->CTRL3_B.INSLEN = len;
}

/*!
 * @brief       Configs address length
 *
 * @param       len: Specifies the address length
 *                   The parameter can be one of following values:
 *                   @arg QSPI_ADDR_LEN_0     : no address
 *                   @arg QSPI_ADDR_LEN_4BIT  : 4-bit address length
 *                   @arg QSPI_ADDR_LEN_8BIT, : 8-bit address length
 *                   @arg QSPI_ADDR_LEN_12BIT : 12-bit address length
 *                   @arg QSPI_ADDR_LEN_16BIT : 16-bit address length
 *                   @arg QSPI_ADDR_LEN_20BIT : 20-bit address length
 *                   @arg QSPI_ADDR_LEN_24BIT : 24-bit address length
 *                   @arg QSPI_ADDR_LEN_28BIT : 28-bit address length
 *                   @arg QSPI_ADDR_LEN_32BIT : 32-bit address length
 *                   @arg QSPI_ADDR_LEN_36BIT : 36-bit address length
 *                   @arg QSPI_ADDR_LEN_40BIT : 40-bit address length
 *                   @arg QSPI_ADDR_LEN_44BIT : 44-bit address length
 *                   @arg QSPI_ADDR_LEN_48BIT : 48-bit address length
 *                   @arg QSPI_ADDR_LEN_52BIT : 52-bit address length
 *                   @arg QSPI_ADDR_LEN_56BIT : 56-bit address length
 *                   @arg QSPI_ADDR_LEN_60BIT : 60-bit address length
 *
 * @retval      None
 */
void QSPI_ConfigAddrLen(QSPI_ADDR_LEN_T len)
{
    QSPI->CTRL3_B.ADDRLEN = len;
}

/*!
 * @brief       Configs instruction and address type
 *
 * @param       type: Specifies the instruction and address type
 *                    The parameter can be one of following values:
 *                    @arg QSPI_INST_ADDR_TYPE_STANDARD : Tx instruction in standard SPI mode,
 *                                                         Tx address in standard SPI mode
 *                    @arg QSPI_INST_TYPE_STANDARD      : Tx instruction in standard SPI mode,
 *                                                         Tx address in mode of SPI_FRF
 *                    @arg QSPI_INST_ADDR_TYPE_FRF      : Tx instruction in mode of SPI_FRF,
 *                                                         Tx address in mode of SPI_FRF
 *
 * @retval      None
 */
void QSPI_ConfigInstAddrType(QSPI_INST_ADDR_TYPE_T type)
{
    QSPI->CTRL3_B.IAT = type;
}

/*!
 * @brief       Configs wait cycle number
 *
 * @param       cycle: Specifies the wait cycle number with a 5-bit value
 *
 * @retval      None
 */
void QSPI_ConfigWaitCycle(uint8_t cycle)
{
    QSPI->CTRL3_B.WAITCYC = cycle;
}

/*!
 * @brief       Open QSPI GPIO
 *
 * @param       None
 *
 * @retval      None
 */
void QSPI_OpenIO(void)
{
    QSPI->IOSW_B.IOSW = BIT_SET;
}

/*!
 * @brief       Close QSPI GPIO
 *
 * @param       None
 *
 * @retval      None
 */
void QSPI_CloseIO(void)
{
    QSPI->IOSW_B.IOSW = BIT_RESET;
}

/*!
 * @brief       Set transmission mode
 *
 * @param       mode: Specifies the transmission mode
 *                    The parameter can be one of following values:
 *                    @arg QSPI_TRANS_MODE_TX_RX       : TX and RX mode
 *                    @arg QSPI_TRANS_MODE_TX          : TX mode only
 *                    @arg QSPI_TRANS_MODE_RX          : RX mode only
 *                    @arg QSPI_TRANS_MODE_EEPROM_READ : EEPROM read mode
 *
 * @retval      None
 */
void QSPI_ConfigTansMode(QSPI_TRANS_MODE_T mode)
{
    QSPI->CTRL1_B.TXMODE = mode;
}

/*!
 * @brief       Transmit data
 *
 * @param       data: Data to be transmited
 *
 * @retval      None
 */
void QSPI_TxData(uint32_t data)
{
    QSPI->DATA = data;
}

/*!
 * @brief       Returns the most recent received data
 *
 * @param       None
 *
 * @retval      The received data
 */
uint32_t QSPI_RxData(void)
{
    return (uint32_t)QSPI->DATA;
}

/*!
 * @brief       Enable Slave
 *
 * @param       None
 *
 * @retval      None
 */
void QSPI_EnableSlave(void)
{
    QSPI->SLAEN_B.SLAEN = BIT_SET;
}

/*!
 * @brief       Disable slave
 *
 * @param       None
 *
 * @retval      None
 */
void QSPI_DisableSlave(void)
{
    QSPI->SLAEN_B.SLAEN = BIT_RESET;
}

/*!
 * @brief       Enable the specified QSPI interrupts
 *
 * @param       interrupt:  Specifies the QSPI interrupt sources
 *                          The parameter can be combination of following values:
 *                          @arg QSPI_INT_TFE:      TX FIFO empty interrupt
 *                          @arg QSPI_INT_TFO:      TX FIFO overflow interrupt
 *                          @arg QSPI_INT_RFU:      RX FIFO underflow interrupt
 *                          @arg QSPI_INT_RFO:      RX FIFO overflow interrupt
 *                          @arg QSPI_INT_RFF:      RX FIFO full interrupt
 *                          @arg QSPI_INT_MST:      Master interrupt
 *
 * @retval      None
 */
void QSPI_EnableInterrupt(uint32_t interrupt)
{
    QSPI->INTEN |= interrupt;
}

/*!
 * @brief       Disable the specified QSPI interrupts
 *
 * @param       interrupt:  Specifies the QSPI interrupt sources
 *                          The parameter can be combination of following values:
 *                          @arg QSPI_INT_TFE:      TX FIFO empty interrupt
 *                          @arg QSPI_INT_TFO:      TX FIFO overflow interrupt
 *                          @arg QSPI_INT_RFU:      RX FIFO underflow interrupt
 *                          @arg QSPI_INT_RFO:      RX FIFO overflow interrupt
 *                          @arg QSPI_INT_RFF:      RX FIFO full interrupt
 *                          @arg QSPI_INT_MST:      Master interrupt
 *
 * @retval      None
 */
void QSPI_DisableInterrupt(uint32_t interrupt)
{
    QSPI->INTEN &= (uint32_t)~interrupt;
}

/*!
 * @brief       Read specified QSPI flag
 *
 * @param       flag:   Specifies the flag to be checked
 *                      The parameter can be one of following values:
 *                      @arg QSPI_FLAG_BUSY:    Busy flag
 *                      @arg QSPI_FLAG_TFNF:    TX FIFO not full flag
 *                      @arg QSPI_FLAG_TFE:     TX FIFO empty flag
 *                      @arg QSPI_FLAG_RFNE:    RX FIFO not empty flag
 *                      @arg QSPI_FLAG_RFF:     RX FIFO full flag
 *                      @arg QSPI_FLAG_DCE:     Data collision error
 *
 * @retval      The new state of flag (SET or RESET)
 */
uint8_t QSPI_ReadStatusFlag(QSPI_FLAG_T flag)
{
    uint8_t ret = RESET;

    ret = QSPI->STS & flag ? SET : RESET;

    return ret;
}

/*!
 * @brief       Clear specified QSPI flag
 *
 * @param       None
 *
 * @retval      None
 *
 * @note        This funtion only clear Data collision error flag(QSPI_FLAG_DCE)
 */
void QSPI_ClearStatusFlag(void)
{
    volatile uint32_t dummy = 0;

    dummy = QSPI->STS;
}

/*!
 * @brief       Read specified QSPI interrupt flag
 *
 * @param       flag:   Specifies the interrupt flag to be checked
 *                      The parameter can be one of following values:
 *                      @arg QSPI_INT_FLAG_TFE:     TX FIFO empty interrupt flag
 *                      @arg QSPI_INT_FLAG_TFO:     TX FIFO overflow interrupt flag
 *                      @arg QSPI_INT_FLAG_RFU:     RX FIFO underflow interrupt flag
 *                      @arg QSPI_INT_FLAG_RFO:     RX FIFO overflow interrupt flag
 *                      @arg QSPI_INT_FLAG_RFF:     RX FIFO full interrupt flag
 *                      @arg QSPI_INT_FLAG_MST:     Master interrupt flag
 *
 * @retval      The new state of flag (SET or RESET)
 */
uint8_t QSPI_ReadIntFlag(QSPI_INT_FLAG_T flag)
{
    uint8_t ret = RESET;

    ret = QSPI->ISTS & flag ? SET : RESET;

    return ret;
}

/*!
 * @brief       Clear specified QSPI interrupt flag
 *
 * @param       flag:   Specifies the interrupt flag to be checked
 *                      The parameter can be one of following values:
 *                      @arg QSPI_INT_FLAG_TFO:     TX FIFO overflow interrupt flag
 *                      @arg QSPI_INT_FLAG_RFU:     RX FIFO underflow interrupt flag
 *                      @arg QSPI_INT_FLAG_RFO:     RX FIFO overflow interrupt flag
 *                      @arg QSPI_INT_FLAG_MST:     Master interrupt flag
 *
 * @retval      None
 */
void QSPI_ClearIntFlag(uint32_t flag)
{
    volatile uint32_t dummy = 0;

    if(flag & QSPI_INT_FLAG_TFO)
    {
        dummy = QSPI->TFOIC;
    }
    else if(flag & QSPI_INT_FLAG_RFO)
    {
        dummy = QSPI->RFOIC;
    }
    else if(flag & QSPI_INT_FLAG_RFU)
    {
        dummy = QSPI->RFUIC;
    }
    else if(flag & QSPI_INT_FLAG_MST)
    {
        dummy = QSPI->MIC;
    }
}

/**@} end of group QSPI_Fuctions*/
/**@} end of group QSPI_Driver */
/**@} end of group Peripherals_Library*/

#endif
