text: /**
    ******************************************************************************
    * @file    bl702_i2s.c
    * @version V1.0
    * @date
    * @brief   This file is the standard driver c file
    ******************************************************************************
    * @attention
    *
    * <h2><center>&copy; COPYRIGHT(c) 2020 Bouffalo Lab</center></h2>
    *
    * Redistribution and use in source and binary forms, with or without modification,
    * are permitted provided that the following conditions are met:
    *   1. Redistributions of source code must retain the above copyright notice,
    *      this list of conditions and the following disclaimer.
    *   2. Redistributions in binary form must reproduce the above copyright notice,
    *      this list of conditions and the following disclaimer in the documentation
    *      and/or other materials provided with the distribution.
    *   3. Neither the name of Bouffalo Lab nor the names of its contributors
    *      may be used to endorse or promote products derived from this software
    *      without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    ******************************************************************************
    */
  
  #include "bl702_i2s.h"
  #include "bl702_glb.h"
  
  /** @addtogroup  BL702_Peripheral_Driver
   *  @{
   */
  
  /** @addtogroup  I2S
   *  @{
   */
  
  /** @defgroup  I2S_Private_Macros
   *  @{
   */
  
  /*@} end of group I2S_Private_Macros */
  
  /** @defgroup  I2S_Private_Types
   *  @{
   */
  
  /*@} end of group I2S_Private_Types */
  
  /** @defgroup  I2S_Private_Variables
   *  @{
   */
  
  /*@} end of group I2S_Private_Variables */
  
  /** @defgroup  I2S_Global_Variables
   *  @{
   */
  
  /*@} end of group I2S_Global_Variables */
  
  /** @defgroup  I2S_Private_Fun_Declaration
   *  @{
   */
  
  /*@} end of group I2S_Private_Fun_Declaration */
  
  /** @defgroup  I2S_Private_Functions
   *  @{
   */
  
  /*@} end of group I2S_Private_Functions */
  
  /** @defgroup  I2S_Public_Functions
   *  @{
   */
  
  /****************************************************************************/ /**
   * @brief  I2S BCLK config
   *
   * @param  i2sCfg: I2S configuration pointer
   *
   * @return NONE
   *
  *******************************************************************************/
  void I2S_SetBclkPeriod(I2S_CFG_Type *i2sCfg)
  {
      uint32_t overSampleRate;
      uint32_t bclkDivCnt;
      uint32_t tmpVal;
  
      CHECK_PARAM(IS_I2S_FRAME_SIZE_TYPE(i2sCfg->frameSize));
  
      overSampleRate = i2sCfg->audioFreqHz / i2sCfg->sampleFreqHz;
  
      switch (i2sCfg->frameSize) {
          case I2S_SIZE_FRAME_8:
              bclkDivCnt = overSampleRate / 16;
              break;
  
          case I2S_SIZE_FRAME_16:
              bclkDivCnt = overSampleRate / 32;
              break;
  
          case I2S_SIZE_FRAME_24:
              bclkDivCnt = overSampleRate / 48;
              break;
  
          case I2S_SIZE_FRAME_32:
              bclkDivCnt = overSampleRate / 64;
              break;
  
          default:
              bclkDivCnt = overSampleRate / 16;
              break;
      }
  
      bclkDivCnt = (bclkDivCnt / 2) - 1;
  
      tmpVal = (bclkDivCnt << 16) | bclkDivCnt;
      BL_WR_REG(I2S_BASE, I2S_BCLK_CONFIG, tmpVal);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S configuration
   *
   * @param  i2sCfg: I2S configuration pointer
   *
   * @return NONE
   *
  *******************************************************************************/
  void I2S_Init(I2S_CFG_Type *i2sCfg)
  {
      uint32_t tmpVal;
  
      /* Check the parameters */
      CHECK_PARAM(IS_I2S_ENDIAN_TYPE(i2sCfg->endianType));
      CHECK_PARAM(IS_I2S_MODE_TYPE(i2sCfg->modeType));
      CHECK_PARAM(IS_I2S_FRAME_SIZE_TYPE(i2sCfg->frameSize));
      CHECK_PARAM(IS_I2S_FS_MODE_TYPE(i2sCfg->fsMode));
      CHECK_PARAM(IS_I2S_FS_CHANNEL_TYPE(i2sCfg->fsChannel));
      CHECK_PARAM(IS_I2S_DATA_SIZE_TYPE(i2sCfg->dataSize));
      CHECK_PARAM(IS_I2S_MONO_MODE_CHANNEL(i2sCfg->monoModeChannel));
  
      /* Disable clock gate */
      GLB_AHB_Slave1_Clock_Gate(DISABLE, BL_AHB_SLAVE1_I2S);
  
      tmpVal = BL_RD_REG(I2S_BASE, I2S_CONFIG);
  
      /* Set data endian*/
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_ENDIAN, i2sCfg->endianType);
  
      /* Set I2S mode */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_I2S_MODE, i2sCfg->modeType);
  
      /* Set BCLK invert */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_I2S_BCLK_INV, i2sCfg->bclkInvert);
  
      /* Set FS size */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_FRAME_SIZE, i2sCfg->frameSize);
  
      /* Set FS invert */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_I2S_FS_INV, i2sCfg->fsInvert);
  
      /* Set FS mode */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_FS_1T_MODE, i2sCfg->fsMode);
  
      /* Set FS channel mode */
  
      switch (i2sCfg->fsChannel) {
          case I2S_FS_CHANNELS_2:
              tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_FS_3CH_MODE);
              tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_FS_4CH_MODE);
              break;
  
          case I2S_FS_CHANNELS_3:
              tmpVal = BL_SET_REG_BIT(tmpVal, I2S_CR_FS_3CH_MODE);
              tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_FS_4CH_MODE);
              break;
  
          case I2S_FS_CHANNELS_4:
              tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_FS_3CH_MODE);
              tmpVal = BL_SET_REG_BIT(tmpVal, I2S_CR_FS_4CH_MODE);
              break;
  
          default:
              break;
      }
  
      /* Set Data size */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_DATA_SIZE, i2sCfg->dataSize);
  
      /* Set Data offset */
      if (i2sCfg->dataOffset != 0) {
          tmpVal = BL_SET_REG_BIT(tmpVal, I2S_CR_OFS_EN);
          tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_OFS_CNT, i2sCfg->dataOffset - 1);
      } else {
          tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_OFS_EN);
      }
  
      /* Set mono mode */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_MONO_MODE, i2sCfg->monoMode);
  
      /* Set rx mono mode channel left or right */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_MONO_RX_CH, i2sCfg->monoModeChannel);
  
      /* Clear mute mode */
      tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_MUTE_MODE);
  
      BL_WR_REG(I2S_BASE, I2S_CONFIG, tmpVal);
  
      I2S_SetBclkPeriod(i2sCfg);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S configure FIFO function
   *
   * @param  fifoCfg: FIFO configuration structure pointer
   *
   * @return None
   *
  *******************************************************************************/
  void I2S_FifoConfig(I2S_FifoCfg_Type *fifoCfg)
  {
      uint32_t tmpVal;
  
      tmpVal = BL_RD_REG(I2S_BASE, I2S_FIFO_CONFIG_0);
      /* Set packed mode */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_FIFO_LR_MERGE, fifoCfg->lRMerge);
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_FIFO_LR_EXCHG, fifoCfg->frameDataExchange);
      /* Clear tx and rx FIFO signal */
      tmpVal = BL_SET_REG_BIT(tmpVal, I2S_TX_FIFO_CLR);
      tmpVal = BL_SET_REG_BIT(tmpVal, I2S_RX_FIFO_CLR);
  
      /* Set DMA config */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_DMA_TX_EN, fifoCfg->txfifoDmaEnable);
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_DMA_RX_EN, fifoCfg->rxfifoDmaEnable);
  
      BL_WR_REG(I2S_BASE, I2S_FIFO_CONFIG_0, tmpVal);
  
      /* Set CLR signal to 0*/
      tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_TX_FIFO_CLR);
      tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_RX_FIFO_CLR);
      BL_WR_REG(I2S_BASE, I2S_FIFO_CONFIG_0, tmpVal);
  
      tmpVal = BL_RD_REG(I2S_BASE, I2S_FIFO_CONFIG_1);
      /* Set TX and RX FIFO threshold */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_TX_FIFO_TH, fifoCfg->txFifoLevel);
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_RX_FIFO_TH, fifoCfg->rxFifoLevel);
  
      BL_WR_REG(I2S_BASE, I2S_FIFO_CONFIG_1, tmpVal);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S configure IO function
   *
   * @param  ioCfg: IO configuration structure pointer
   *
   * @return None
   *
  *******************************************************************************/
  void I2S_IOConfig(I2S_IOCfg_Type *ioCfg)
  {
      uint32_t tmpVal;
  
      tmpVal = BL_RD_REG(I2S_BASE, I2S_IO_CONFIG);
      /* Enable or disable deglitch */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_DEG_EN, ioCfg->deglitchEn);
  
      /* Set deglitch cycle count */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_DEG_CNT, ioCfg->deglitchCnt);
  
      /* Enable or disable inverse BCLK signal */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_I2S_BCLK_INV, ioCfg->inverseBCLK);
  
      /* Enable or disable inverse FS signal */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_I2S_FS_INV, ioCfg->inverseFS);
  
      /* Enable or disable inverse RX signal */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_I2S_RXD_INV, ioCfg->inverseRX);
  
      /* Enable or disable inverse TX signal */
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_I2S_TXD_INV, ioCfg->inverseTX);
  
      BL_WR_REG(I2S_BASE, I2S_IO_CONFIG, tmpVal);
  }
  
  /****************************************************************************/ /**
   * @brief  Enable I2S
   *
   * @param  roleType: I2S master or slave
   *
   * @return None
   *
  *******************************************************************************/
  void I2S_Enable(I2S_Role_Type roleType)
  {
      uint32_t tmpVal;
  
      /* Check the parameters */
      CHECK_PARAM(IS_I2S_ROLE_TYPE(roleType));
  
      tmpVal = BL_RD_REG(I2S_BASE, I2S_CONFIG);
      tmpVal = BL_SET_REG_BIT(tmpVal, I2S_CR_I2S_TXD_EN);
      tmpVal = BL_SET_REG_BIT(tmpVal, I2S_CR_I2S_RXD_EN);
  
      /* Set role type */
      if (I2S_ROLE_MASTER == roleType) {
          tmpVal = BL_SET_REG_BIT(tmpVal, I2S_CR_I2S_M_EN);
          tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_I2S_S_EN);
      } else if (I2S_ROLE_SLAVE == roleType) {
          tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_I2S_M_EN);
          tmpVal = BL_SET_REG_BIT(tmpVal, I2S_CR_I2S_S_EN);
      }
  
      BL_WR_REG(I2S_BASE, I2S_CONFIG, tmpVal);
  }
  
  /****************************************************************************/ /**
   * @brief  Disable I2S
   *
   * @param  None
   *
   * @return None
   *
  *******************************************************************************/
  void I2S_Disable(void)
  {
      uint32_t tmpVal;
  
      tmpVal = BL_RD_REG(I2S_BASE, I2S_CONFIG);
      tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_I2S_TXD_EN);
      tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_I2S_RXD_EN);
  
      tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_I2S_M_EN);
      tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_I2S_S_EN);
      BL_WR_REG(I2S_BASE, I2S_CONFIG, tmpVal);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S read data
   *
   * @param  None
   *
   * @return Data read
   *
  *******************************************************************************/
  uint32_t I2S_Read(void)
  {
      while (0 == BL_GET_REG_BITS_VAL(BL_RD_REG(I2S_BASE, I2S_FIFO_CONFIG_1), I2S_RX_FIFO_CNT)) {
      };
  
      return BL_RD_REG(I2S_BASE, I2S_FIFO_RDATA);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S write data
   *
   * @param  data: write data
   *
   * @return None
   *
  *******************************************************************************/
  void I2S_Write(uint32_t data)
  {
      while (0 == BL_GET_REG_BITS_VAL(BL_RD_REG(I2S_BASE, I2S_FIFO_CONFIG_1), I2S_TX_FIFO_CNT)) {
      };
  
      BL_WR_REG(I2S_BASE, I2S_FIFO_WDATA, data);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S set mute
   *
   * @param  enabled: mute enabled or not
   *
   * @return None
   *
  *******************************************************************************/
  void I2S_Mute(BL_Fun_Type enabled)
  {
      uint32_t tmpVal;
  
      tmpVal = BL_RD_REG(I2S_BASE, I2S_CONFIG);
  
      if (enabled ? 1 : 0) {
          tmpVal = BL_SET_REG_BIT(tmpVal, I2S_CR_MUTE_MODE);
      } else {
          tmpVal = BL_CLR_REG_BIT(tmpVal, I2S_CR_MUTE_MODE);
      }
  
      BL_WR_REG(I2S_BASE, I2S_CONFIG, tmpVal);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S set 24-bit data align mode in fifo
   *
   * @param  justType: Align mode
   *
   * @return None
   *
  *******************************************************************************/
  void I2S_SetFifoJustified(I2S_FIFO_24_Justified_Type justType)
  {
      uint32_t tmpVal;
  
      /* Check the parameters */
      CHECK_PARAM(IS_I2S_FIFO_24_JUSTIFIED_TYPE(justType));
  
      tmpVal = BL_RD_REG(I2S_BASE, I2S_FIFO_CONFIG_0);
      tmpVal = BL_SET_REG_BITS_VAL(tmpVal, I2S_CR_FIFO_24B_LJ, justType);
      BL_WR_REG(I2S_BASE, I2S_FIFO_CONFIG_0, tmpVal);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S flush
   *
   * @param  None
   *
   * @return data count in TX FIFO
   *
  *******************************************************************************/
  uint32_t I2S_GetTxFIFO_AvlCnt(void)
  {
      return BL_GET_REG_BITS_VAL(BL_RD_REG(I2S_BASE, I2S_FIFO_CONFIG_1), I2S_TX_FIFO_CNT);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S flush
   *
   * @param  None
   *
   * @return data count in RX FIFO
   *
  *******************************************************************************/
  uint32_t I2S_GetRxFIFO_AvlCnt(void)
  {
      return BL_GET_REG_BITS_VAL(BL_RD_REG(I2S_BASE, I2S_FIFO_CONFIG_1), I2S_RX_FIFO_CNT);
  }
  
  /****************************************************************************/ /**
   * @brief  I2S flush
   *
   * @param  None
   *
   * @return None
   *
  *******************************************************************************/
  void I2S_Flush(void)
  {
      while (I2S_TX_FIFO_SIZE != I2S_GetTxFIFO_AvlCnt())
          ;
  }
  
  /*@} end of group I2S_Public_Functions */
  
  /*@} end of group I2S */
  
  /*@} end of group BL702_Peripheral_Driver */
  