/**
 *******************************************************************************
 * @file    dpm32m0xx_pga.c
 *
 * @brief   Source file for PGA firmware driver.
 *          This file provides firmware functions to manage the following :
 *          functionalities of the Programmable Gain Amplifier(PGA) peripheral:
 *           + Initialization functions.
 *           + Configuration functions.
 *
 * @author  DPM
 *
 * @version V1.0.0
 *
 * @date    2023-11-01
 *
 * @verbatim
 ===============================================================================
                       ##### How to use this driver #####
 ===============================================================================
    [..]
      (#) Enable The PGA controller clock using
          RCC_APBPeriphClockCmd(RCC_APB_PERIPH_PGA, ENABLE).

      (#) PGA pin configuration.
        (+) Enable the clock for the PGA GPIO using the following function:
              RCC_AHBPeriphClockCmd(RCC_AHB_PERIPH_GPIO, ENABLE).
        (+) Configure these PGA pins in analog mode using GPIO_Init() function.
        (+) Set these PGA pins analog alternate functionin using
            GPIO_AnaAFConfig() function.

      (#) Configure PGA module: Initialize the PGA module to the required
          working mode and parameters using PGA_Init() function :
        (+) Set PGA gain: Select the appropriate PGA gain value using
            PGA_SetAmpGain() function.
        (+) Configure PGA reference voltage using PGA_SetVref() function.
        (+) Configuration input: It can be single ended input or differential
            input using PGA_SetInputMode() function.
        (+) Configuration output: whether to enable bias using
            PGA_SetBiasOutput() function.

      (#) Enable the PGA using PGA_Cmd() function.

 * @endverbatim
 *******************************************************************************/

#include "dpm32m0xx_pga.h"


/**
 *******************************************************************************
 * @brief   Deinitializes the PGA common registers to their default reset values.
 * @retval  None.
 ******************************************************************************/
void PGA_COMDeInit(void)
{
  uint32_t tmpReg = 0UL;

  /* Read the value of the PGA analog configuration register. */
  tmpReg = PGA->CR;

#if defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015) || \
    defined (DPM32M026) || defined (DPM32T55x)
  /* Clear PGA_OFFSET_EN,FLT_SEL,FLT_EN bit. */
  tmpReg &= ~(PGA_CR_OFFSET_SEL_Msk | PGA_CR_OUT_FLT_SEL_Msk | PGA_CR_OUT_FLT_EN_Msk);
#else /* DPM32M08x || DPM32M05x || DPM32M03x */
  /* Clear PGA_OFFSET_EN bit. */
  tmpReg &= ~PGA_CR_OFFSET_SEL_Msk;
#endif /* DPM32M036 || DPM32M030 || DPM32M015 || DPM32M026 || DPM32T55x */
  
#if defined (DPM32M08x) || defined (DPM32M05x) || defined (DPM32M03x)
  /* Set PGA_SPEED[1:0] bits . */
  tmpReg |= (uint32_t)(PGA_CR_PGA_SPEED_Msk);
#endif /* DPM32M08x || DPM32M05x || DPM32M03x */

  /* Store the new value. */
  PGA->CR = tmpReg;
}


/**
 *******************************************************************************
 * @brief   Deinitializes the PGA peripheral registers to their default reset values.
 * @param   [in]  PGA_Channel: Specifies the PGA channel.
 *                This parameter can be a value of @ref PGA_ChannelEnum.
 *                  @arg PGA_CH0: PGA channel 0.
 *                  @arg PGA_CH1: PGA channel 1.
 *                  @arg PGA_CH2: PGA channel 2.
 *                  @arg PGA_CH3: PGA channel 3.
 * @retval  None.
 ******************************************************************************/
void PGA_DeInit(PGA_ChannelEnum PGA_Channel)
{
  uint32_t tmpReg = 0UL;

  /* Parameters check. */
  PARAM_ASSERT(IS_PGA_CHANNEL(PGA_Channel));

  /* Read the value of the PGA analog configuration register. */
  tmpReg = PGA->CR;

  /* Clear PGA_MODE,PGA0_AMP[2:0] bit. */
  tmpReg &= ~((PGA_CR_PGA0_MODE_Msk << PGA_Channel) \
              | (PGA_CR_PGA0_OFFSET_EN_Msk << PGA_Channel) \
              | (PGA_CR_PGA0_AMP_Msk << 0x04u * PGA_Channel) \
              | (PGA_CR_PGA0_EN_Msk << PGA_Channel));
              
  /* Store the new value. */
  PGA->CR = tmpReg;
}


/**
 *******************************************************************************
 * @brief   Initializes the EPWM peripheral channelx output function
 *          according to the specified parameters in the EPWM_CHInitTypeStruct.
 * @param   [in]  PGA_Channel: Specifies the PGA channel.
 *                This parameter can be a value of @ref PGA_ChannelEnum.
 *                  @arg PGA_CH0: PGA channel 0.
 *                  @arg PGA_CH1: PGA channel 1.
 *                  @arg PGA_CH2: PGA channel 2.
 *                  @arg PGA_CH3: PGA channel 3.
 * @param   [in]  PGA_InitType: Structure pointer of PGA channelx configuration.
 * @retval  None.
 ******************************************************************************/
void PGA_Init(PGA_ChannelEnum PGA_Channel, PGA_InitTypeStruct* PGA_InitType)
{
  uint32_t tmpReg = 0UL;

  /* Parameters check. */
  PARAM_ASSERT(IS_PGA_CHANNEL(PGA_Channel));
  PARAM_ASSERT(IS_PGA_INOUT_MODE(PGA_InitType->PGA_Mode));
  PARAM_ASSERT(IS_PGA_OFFSET_SEL(PGA_InitType->PGA_OffsetSel));
  PARAM_ASSERT(IS_PGA_AMP_GAIN(PGA_InitType->PGA_Gain));
  
#if defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015) || \
    defined (DPM32M026) || defined (DPM32T55x)
  PARAM_ASSERT(IS_PGA_FILT_SEL(PGA_InitType->PGA_FiltSel));
#endif /* DPM32M036 || DPM32M030 || DPM32M015 || DPM32M026 || DPM32T55x */

  /* Read the value of the PGA analog configuration register. */
  tmpReg = PGA->CR;

#if defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015) || \
    defined (DPM32M026) || defined (DPM32T55x)
  /* Clear PGA_MODE,PGA_OFFSET_EN,PGA0_AMP[2:0],FLT_SEL,FLT_EN bit. */
  tmpReg &= ~((PGA_CR_PGA0_MODE_Msk << PGA_Channel) \
              | (PGA_CR_PGA0_OFFSET_EN_Msk << PGA_Channel) \
              | (PGA_CR_PGA0_AMP_Msk << 0x04u * PGA_Channel) \
              | PGA_CR_OFFSET_SEL_Msk | PGA_CR_OUT_FLT_SEL_Msk \
              | PGA_CR_OUT_FLT_EN_Msk);
#else /* DPM32M08x || DPM32M05x || DPM32M03x */
  /* Clear PGA_MODE,PGA_OFFSET_EN,PGA0_AMP[2:0] bit. */
  tmpReg &= ~((PGA_CR_PGA0_MODE_Msk << PGA_Channel) \
              | (PGA_CR_PGA0_OFFSET_EN_Msk << PGA_Channel) \
              | (PGA_CR_PGA0_AMP_Msk << 0x04u * PGA_Channel) \
              | PGA_CR_OFFSET_SEL_Msk);
#endif /* DPM32M036 || DPM32M030 || DPM32M015 || DPM32M026 || DPM32T55x */

  /* Set PGA_MODE bit with PGA_Mode. */
  tmpReg |= (uint32_t)(PGA_InitType->PGA_Mode << (PGA_CR_PGA0_MODE_Pos + PGA_Channel));

  /* Set PGA0_AMP[2:0] bits according to PGA_InitType. */
  tmpReg |= (uint32_t)(PGA_InitType->PGA_Gain << (PGA_CR_PGA0_AMP_Pos + 0x04u * PGA_Channel));

  /* Set PGA_OFFSET_EN bit according to PGA_InitType. */
  tmpReg |= (uint32_t)(PGA_InitType->PGA_OffsetState << (PGA_CR_PGA0_OFFSET_EN_Pos + PGA_Channel));
  /* Set OFFSET_SEL bits according to PGA_InitType. */
  tmpReg |= (uint32_t)(PGA_InitType->PGA_OffsetSel << PGA_CR_OFFSET_SEL_Pos);
  
#if defined (DPM32M08x) || defined (DPM32M05x) || defined (DPM32M03x)
  /* Set PGA_SPEED[1:0] bits . */
  tmpReg |= (uint32_t)(PGA_CR_PGA_SPEED_Msk);
#endif /* DPM32M08x || DPM32M05x || DPM32M03x */

#if defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015) || \
    defined (DPM32M026) || defined (DPM32T55x)
  /* Set FILT_SEL bits according to PGA_InitType. */
  tmpReg |= (uint32_t)(PGA_InitType->PGA_FiltSel << PGA_CR_OUT_FLT_SEL_Pos);
  
  /* Set PGA_FILT_EN bit according to PGA_InitType. */
  tmpReg |= (uint32_t)(PGA_InitType->PGA_FiltState << PGA_CR_OUT_FLT_EN_Pos);
#endif /* DPM32M036 || DPM32M030 || DPM32M015 || DPM32M026 || DPM32T55x */

  /* Store the new value. */
  PGA->CR = tmpReg;
}


/**
 *******************************************************************************
 * @brief   Initialize the PGA_InitType with default parameters.
 * @param   [in]  PGA_InitType: Pointer to a PGA_InitTypeStruct structure which will be initialized.
 * @retval  None.
 ******************************************************************************/
void PGA_StructInit(PGA_InitTypeStruct* PGA_InitType)
{
  PGA_InitType->PGA_Mode = PGA_INPUT_MODE_DIFFERENTIAL;
#if defined (DPM32M026) || defined (DPM32T55x)
  PGA_InitType->PGA_Gain = PGA_AMP_GAIN4;
#else
  PGA_InitType->PGA_Gain = PGA_AMP_GAIN1;
#endif /* DPM32M026 || DPM32T55x */
  PGA_InitType->PGA_OffsetState = DISABLE;
  PGA_InitType->PGA_OffsetSel = PGA_OFFSET_SEL_AVDD;
#if defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015) || \
    defined (DPM32M026) || defined (DPM32T55x)
  PGA_InitType->PGA_FiltSel = PGA_FILT_SEL_PGA0;
  PGA_InitType->PGA_FiltState = DISABLE;
#endif /* DPM32M036 || DPM32M030 || DPM32M015 || DPM32M026 || DPM32T55x */
}


/**
 *******************************************************************************
 * @brief   Enable or disable specifies PGA.
 * @param   [in]  PGA_Channel: Specifies the PGA channel.
 *                This parameter can be a value of @ref PGA_ChannelEnum.
 *                  @arg PGA_CH0: PGA channel 0.
 *                  @arg PGA_CH1: PGA channel 1.
 *                  @arg PGA_CH2: PGA channel 2.
 *                  @arg PGA_CH3: PGA channel 3.
 * @param   [in]  NewState: New state of PGA.
 *                This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void PGA_Cmd(PGA_ChannelEnum PGA_Channel, FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable PGAx. */
    PGA->CR |= (PGA_CR_PGA0_EN_Msk << PGA_Channel);
  }
  else
  {
    /* Disable PGAx. */
    PGA->CR &= ~(PGA_CR_PGA0_EN_Msk << PGA_Channel);
  }
}


/**
 *******************************************************************************
 * @brief   Enable or disable PGA Output bias.
 * @param   [in]  PGA_Channel: Specifies the PGA channel.
 *                This parameter can be a value of @ref PGA_ChannelEnum.
 *                  @arg PGA_CH0: PGA channel 0.
 *                  @arg PGA_CH1: PGA channel 1.
 *                  @arg PGA_CH2: PGA channel 2.
 *                  @arg PGA_CH3: PGA channel 3.
 * @param   [in]  NewState: New state of PGA.
 *                This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void PGA_OffsetCmd(PGA_ChannelEnum PGA_Channel, FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable PGAx. */
    PGA->CR |= (PGA_CR_PGA0_OFFSET_EN_Msk << PGA_Channel);
  }
  else
  {
    /* Disable PGAx. */
    PGA->CR &= ~(PGA_CR_PGA0_OFFSET_EN_Msk << PGA_Channel);
  }
}


/**
 *******************************************************************************
 * @brief   Output bias select.
 * @param   [in]  PGA_OffsetSel: Specifies the output bias value.
 *                This parameter can be a value of @ref PGA_OffsetSelEnum.
 *                  @arg PGA_OFFSET_SEL_AVDD: Select 1/2 AVDD as bias value.
 *                  @arg PGA_OFFSET_SEL_BANDGAP: Select 1/2 Bandgap as bias value.
 * @retval  None.
 ******************************************************************************/
void PGA_OffsetSelect(PGA_OffsetSelEnum PGA_OffsetSel)
{
  uint32_t tmpReg = 0UL;

  /* Read the value of the PGA_CR register. */
  tmpReg = PGA->CR;

  /* Clear OFFSET_SEL bit. */
  tmpReg &= ~PGA_CR_OFFSET_SEL_Msk;

  /* Set OFFSET_SEL bit according to sel value. */
  tmpReg |= (uint32_t)(PGA_OffsetSel << PGA_CR_OFFSET_SEL_Pos);

  /* Store the new value. */
  PGA->CR = tmpReg;
}


/**
 *******************************************************************************
 * @brief   Set PGA channelx input mode.
 * @param   [in]  PGA_Channel: Specifies the PGA channel.
 *                This parameter can be a value of @ref PGA_ChannelEnum.
 *                  @arg PGA_CH0: PGA channel 0.
 *                  @arg PGA_CH1: PGA channel 1.
 *                  @arg PGA_CH2: PGA channel 2.
 *                  @arg PGA_CH3: PGA channel 3.
 * @param   [in]  PGA_Mode: New mode of PGA channelx.
 *                This parameter can be a value of @ref PGA_InputModeEnum.
 *                  @arg PGA_INPUT_MODE_SINGLE: differential input mode.(M036||M030||M015||M026)
 *                  @arg PGA_INPUT_MODE_DIFFERENTIAL: differential input mode.

 * @retval  None.
 ******************************************************************************/
void PGA_SetInputMode(PGA_ChannelEnum PGA_Channel, PGA_InputModeEnum PGA_Mode)
{
  uint32_t tmpReg = 0UL;

  /* Read the value of the PGA_CR register. */
  tmpReg = PGA->CR;

  /* Clear PGA_MODE bit. */
  tmpReg &= ~(uint32_t)(PGA_CR_PGA0_MODE_Msk << PGA_Channel);

  /* Set PGA_MODE bit according to mode value. */
  tmpReg |= (uint32_t)(PGA_Mode << (PGA_CR_PGA0_MODE_Pos + PGA_Channel));

  /* Store the new value. */
  PGA->CR = tmpReg;
}


/**
 *******************************************************************************
 * @brief   Set PGA channelx amplify gain.
 * @param   [in]  PGA_Channel: Specifies the PGA channel.
 *                This parameter can be a value of @ref PGA_ChannelEnum.
 *                  @arg PGA_CH0: PGA channel 0.
 *                  @arg PGA_CH1: PGA channel 1.
 *                  @arg PGA_CH2: PGA channel 2.
 *                  @arg PGA_CH3: PGA channel 3.
 * @param   [in]  PGA_Gain: New gain of PGA channelx.
 *                This parameter can be a value of @ref PGA_AmpGainEnum.
 *                  @arg PGA_AMP_GAIN2: 1x gain.
 *                  @arg PGA_AMP_GAIN2: 2x gain or (M036||M030||M015)PGA_AMP_GAIN3: 3x gain.
 *                  @arg PGA_AMP_GAIN4: 4x gain or (M036||M030||M015)PGA_AMP_GAIN5: 5x gain.
 *                  @arg PGA_AMP_GAIN8: 8x gain or (M036||M030||M015)PGA_AMP_GAIN9: 9x gain.
 *                  @arg PGA_AMP_GAIN16: 16x gain or (M036||M030||M015)PGA_AMP_GAIN17: 17x gain.
 *                  @arg PGA_AMP_GAIN32: 32x gain or (M036||M030||M015)PGA_AMP_GAIN33: 33x gain.
 * @retval  None.
 ******************************************************************************/
void PGA_SetAmpGain(PGA_ChannelEnum PGA_Channel, PGA_AmpGainEnum PGA_Gain)
{
  uint32_t tmpReg = 0UL;

  /* Read the value of the PGA_CR register. */
  tmpReg = PGA->CR;

  /* Clear PGA0_AMP[2:0] bits. */
  tmpReg &= ~(PGA_CR_PGA0_AMP_Msk << 0x04u * PGA_Channel);

  /* Set PGA0_AMP[2:0] bits according to PGA_InitType. */
  tmpReg |= (uint32_t)(PGA_Gain << (PGA_CR_PGA0_AMP_Pos + 0x04u * PGA_Channel));

  /* Store the new value. */
  PGA->CR = tmpReg;
}


#if defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015) || \
    defined (DPM32M026) || defined (DPM32T55x)
/**
 *******************************************************************************
 * @brief   Enable or disable PGA output filter enable.
 * @param   [in]  NewState: New state of PGA.
 *                This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void PGA_FiltCmd(FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable PGA output filter. */
    PGA->CR |= PGA_CR_OUT_FLT_EN_Msk;
  }
  else
  {
    /* Disable PGA output filter. */
    PGA->CR &= ~PGA_CR_OUT_FLT_EN_Msk ;
  }
}


/**
 *******************************************************************************
 * @brief   output filter circuit input source selection.
 * @param   [in]  PGA_Filt: Specifies the output filter circuit input source.
 *                This parameter can be a value of @ref PGA_FiltSelEnum.
 *                  @arg PGA_FILT_SEL_PGA0: Select PGA0 output as the input for the filter circuit.
 *                  @arg PGA_FILT_SEL_PGA1: Select PGA1 output as the input for the filter circuit.
 *                  @arg PGA_FILT_SEL_PGA2: Select PGA2 output as the input for the filter circuit.
 * @retval  None.
 ******************************************************************************/
void PGA_FiltSelect(PGA_FiltSelEnum PGA_Filt)
{
  uint32_t tmpReg = 0UL;

  /* Read the value of the PGA_CR register. */
  tmpReg = PGA->CR;

  /* Clear OUT_FLT_SEL bit. */
  tmpReg &= ~PGA_CR_OUT_FLT_SEL_Msk;

  /* Set OUT_FLT_SEL bit according to sel value. */
  tmpReg |= (uint32_t)(PGA_Filt << PGA_CR_OUT_FLT_SEL_Pos);

  /* Store the new value. */
  PGA->CR = tmpReg;
}
#endif /* DPM32M036 || DPM32M030 || DPM32M015 || DPM32M026 || DPM32T55x */
