/**
 *******************************************************************************
 * @file    tmpm311_dsad.c
 * @brief   This file provides API functions for DSADC driver.
 * @version V2.0.2.1
 * @date    2014/09/02
 * 
 * DO NOT USE THIS SOFTWARE WITHOUT THE SOFTWARE LICENSE AGREEMENT.
 * 
 * (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2017 All rights reserved
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "tmpm311_dsad.h"

/** @addtogroup TX03_Periph_Driver
  * @{
  */

/** @defgroup DSADC_Private_Defines
  * @{
  */
#define DSAD_SWRST_CMD1                 ((uint32_t)0x00000002)
#define DSAD_SWRST_CMD2                 ((uint32_t)0x00000001)

#define DSAD_CR3_DSADHTG_SET            ((uint32_t)0x00001000)
#define DSAD_CR3_DSADHTG_CLEAR          ((uint32_t)0xFFFFEFFF)
#define DSAD_CR3_DSADHS_SET             ((uint32_t)0x00002000)
#define DSAD_CR3_DSADHS_CLEAR           ((uint32_t)0xFFFFDFFF)
#define DSAD_CR3_ADSYNC_REPEAT_CLEAR    ((uint32_t)0xFFFFFEFE)

/** @} */
/* End of group DSADC_Private_Defines */


/**
  * @brief  Set AD conversion clock.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD.  
  * @param  Clk: AD conversion clock selection.
  *   This parameter can be one of the following values:
  *   DSADC_FC_DIVIDE_LEVEL_1, DSADC_FC_DIVIDE_LEVEL_2,
  *   DSADC_FC_DIVIDE_LEVEL_4, DSADC_FC_DIVIDE_LEVEL_8.
  * @retval None.
  * @note1 The DSADCLK<ADCLK[2:0]> register is modified under the circumstances 
  *        where DSADCR1<BIASEN> and <MODEN> are "0" and the AD conversion stops.
  * @note2 When the synchronous start function is used, select the same conversion clock for all units.
  * @register The used register:
  *   DSADCLK<ADCLK[2:0]>
  */
void DSADC_SetClk(TSB_DSAD_TypeDef * DSADCx, uint32_t Clk)
{
    /* Check the parameters */
    assert_param(IS_DSADC_PERIPH(DSADCx));
    assert_param(IS_DSADC_CLOCK_SEL(Clk));
    /* Set DSADCLK */
    DSADCx->CLK = Clk;
}

/**
  * @brief  Software reset ADC function.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD. 
  * @retval None.
  * @register The used registers:
  *   DSADCR0<ADRST[1:0]>, DSADCR1<BIASEN>.
  */
void DSADC_SWReset(TSB_DSAD_TypeDef * DSADCx)
{
    assert_param(IS_DSADC_PERIPH(DSADCx));
    DSADCx->CR1 |= 0x02U;       /* Valid only when DSADCR1<BIASEN>="1". */
    DSADCx->CR0 = DSAD_SWRST_CMD1;
    DSADCx->CR0 = DSAD_SWRST_CMD2;
}

/**
  * @brief  Start DSADC function.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD. 
  * @retval None
  * @register The used register:
  *   DSADCR2<ADS>
  */
void DSADC_Start(TSB_DSAD_TypeDef * DSADCx)
{
    assert_param(IS_DSADC_PERIPH(DSADCx));
    /* Set ADMOD0<ADS> = 1 to start DSADC */
    DSADCx->CR2 = 0x01U;
}

/**
  * @brief  Change DSADC Synchronous mode and Conversion mode.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD.
  * @param  SyncMode: Select the DSADC Synchronous mode.
  *   This parameter can be one of the following values:
  *   DSADC_A_SYNC_MODE,DSADC_SYNC_MODE.
  * @param  ConvMode: Select the ConvMode mode.
  *   This parameter can be one of the following values:
  *   DSADC_SINGLE_MODE,DSADC_REPEAT_MODE.
  * @retval None
  * @register The used register:
  *   DSADCR3<REPEAT><ADSYNC>
  */
void DSADC_ChangeMode(TSB_DSAD_TypeDef * DSADCx, uint32_t SyncMode, uint32_t ConvMode)
{
    uint32_t reg = SyncMode << 8U;

    assert_param(IS_DSADC_PERIPH(DSADCx));
    assert_param(IS_DSADC_1BIT_CHECK(SyncMode));
    assert_param(IS_DSADC_1BIT_CHECK(ConvMode));

    reg |= ConvMode;
    DSADCx->CR3 &= DSAD_CR3_ADSYNC_REPEAT_CLEAR;
    DSADCx->CR3 |= reg;
}

/**
  * @brief  Enable or disable hardware startup.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD.
  * @param  NewState: Hardware startup is enabled or disabled.
  *   This parameter can be one of the following values:
  *   DISABLE or ENABLE.
  * @retval None
  * @register The used register:
  *   DSADCR3<DSADHTG>
  */
void DSADC_SetHWStartup(TSB_DSAD_TypeDef * DSADCx, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_DSADC_PERIPH(DSADCx));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState == ENABLE) {
        DSADCx->CR3 |= DSAD_CR3_DSADHTG_SET;
    } else {
        DSADCx->CR3 &= DSAD_CR3_DSADHTG_CLEAR;
    }
}

/**
  * @brief  Specify the hardware startup factor.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD.
  * @param  StartupFactor: Hardware startup factor.
  *   This parameter can be one of the following values:
  *   DSADC_HARDWARE_TRIGGER_EXT or DSADC_HARDWARE_TRIGGER_INT.
  * @retval None
  * @register The used register:
  *   DSADCR3<DSADHS>
  */
void DSADC_SetHWStartupFactor(TSB_DSAD_TypeDef * DSADCx, uint32_t StartupFactor)
{
    /* Check the parameters */
    assert_param(IS_DSADC_PERIPH(DSADCx));
    assert_param(IS_DSADC_HARDWARE_TRIGGER(StartupFactor));

    if (StartupFactor == DSADC_HARDWARE_TRIGGER_INT) {
        DSADCx->CR3 |= DSAD_CR3_DSADHS_SET;
    } else {
        DSADCx->CR3 &= DSAD_CR3_DSADHS_CLEAR;
    }
}

/**
  * @brief  Set DSADC Amplifier.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD.
  * @param  Amplifier: DSADC Amplifier setting.
  *   This parameter can be one of the following values:
  *   DSADC_GAIN_1x,DSADC_GAIN_2x,DSADC_GAIN_4x,DSADC_GAIN_8x,DSADC_GAIN_16x.
  * @retval None
  * @register The used register:
  *   DSADCR4<DSGAIN[2:0]>
  */
void DSADC_SetAmplifier(TSB_DSAD_TypeDef * DSADCx, uint32_t Amplifier)
{
    assert_param(IS_DSADC_PERIPH(DSADCx));
    assert_param(IS_DSADC_GAIN(Amplifier));
    DSADCx->CR4 = Amplifier;
}

/**
  * @brief  Set the analog inputs.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD.
  * @param  AnalogInput: The analog inputs.
  *   This parameter can be one of the following values:
  *   For unit A, unit B and unit C:
  *   DSADC_ANALOG_INPUT_DAIN.
  *   For unit D:
  *   DSADC_ANALOG_INPUT_DAIN or DSADC_ANALOG_INPUT_INT.
  * @retval None
  * @register The used register:
  *   DSADCR5<DSADCH>
  */
void DSADC_SetAnalogInput(TSB_DSAD_TypeDef * DSADCx, uint32_t AnalogInput)
{
    /* Check the parameters */
    assert_param(IS_DSADC_PERIPH(DSADCx));
    assert_param(IS_DSADC_ANALOG_INPUT(DSADCx, AnalogInput));

    DSADCx->CR5 = AnalogInput;
}

/**
  * @brief  Get DSADC convert result.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD. 
  * @retval Convert result.
  * @register The used register:
  *   DSADRES<ADR[23:0]>
  */
uint32_t DSADC_GetConvertResult(TSB_DSAD_TypeDef * DSADCx)
{
    uint32_t result = 0U;

    assert_param(IS_DSADC_PERIPH(DSADCx));

    while (!((DSADCx->ST & 0x02U))) {   /* wait conversion end */
    }
    result = DSADCx->RES;
    if (result & 0x01U) {
        result >>= 8U;
    } else {
        /* Do nothing */
    }
    return result;
}

/**
  * @brief  Initialize the specified DSADC channel.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD. 
  * @param  InitStruct: The structure containing basic DSADC configuration.
  * @retval None
  * @register The used registers:
  *   DSADCLK<ADCLK[2:0]>, DSADCR0<ADRST>, DSADCR1<BIASEN><MODEN>, 
  *   DSADCR3<DSADHS><DSADHTG><ADSYNC><REPEAT>, DSADCR4< DSGAIN[2:0]>,
  *   DSADCR5<DSADCH>, DSADADJ<OFFSET><ADJ>.
  */
void DSADC_Init(TSB_DSAD_TypeDef * DSADCx, DSADC_InitTypeDef * InitStruct)
{
    assert_param(IS_DSADC_PERIPH(DSADCx));
    assert_param(IS_POINTER_NOT_NULL(InitStruct));
    assert_param(IS_DSADC_CLOCK_SEL(InitStruct->Clk));
    assert_param(IS_DSADC_1BIT_CHECK(InitStruct->BiasEn));
    assert_param(IS_DSADC_1BIT_CHECK(InitStruct->ModulatorEn));
    assert_param(IS_DSADC_HARDWARE_TRIGGER(InitStruct->HardwareFactor));
    assert_param(IS_FUNCTIONAL_STATE(InitStruct->HardwareEn));
    assert_param(IS_DSADC_1BIT_CHECK(InitStruct->SyncMode));
    assert_param(IS_DSADC_1BIT_CHECK(InitStruct->Repeatmode));
    assert_param(IS_DSADC_ANALOG_INPUT(DSADCx, InitStruct->AnalogInput));

    assert_param(IS_DSADC_1BIT_CHECK(InitStruct->CorrectEn));
    assert_param(IS_DSADC_GAIN(InitStruct->Amplifier));

    /* Select the AD conversion clock. */
    DSADCx->CLK = InitStruct->Clk;

    /* SW Reset */
    DSADC_SWReset(DSADCx);

    /* DSADCR1 BIT1: BIASEN  BIT0: MODEN */
    DSADCx->CR1 = (InitStruct->BiasEn << 1U) | InitStruct->ModulatorEn;

    /* DSADCR3 BIT13: DSADHS  BIT12: DSADHTG  BIT8: ADSYNC  BIT0: REPEAT */
    DSADCx->CR3 = (InitStruct->HardwareFactor << 13) | ((uint32_t) InitStruct->HardwareEn << 12U) |
        (InitStruct->SyncMode << 8U) | InitStruct->Repeatmode;

    /* Sets the analog inputs. */
    DSADCx->CR5 = InitStruct->AnalogInput;

    /* DSADADJ */
    DSADCx->ADJ = ((uint32_t) InitStruct->Offset << 16U) | InitStruct->CorrectEn;

    /* Amplifier setting */
    DSADCx->CR4 = InitStruct->Amplifier;
}

/**
  * @brief  Indicate DSADC Convertor status and result.
  * @param  DSADCx: Select the DSADC channel.
  *   This parameter can be one of the following values:
  *   TSB_DSADA, TSB_DSADB, TSB_DSADC, TSB_DSADD. 
  * @retval The DSADC Convertor status and result.
  * @register The used registers:
  *   DSADST<EOCF><ADBF>, DSADRES<ADR[23:0]><ADOVR><ADRF>.
  */
DSAD_status DSADC_GetStatus(TSB_DSAD_TypeDef * DSADCx)
{
    DSAD_status retval = { 0U };

    assert_param(IS_DSADC_PERIPH(DSADCx));

    retval.All = DSADCx->ST & 0x03U;
    retval.All = retval.All << 2U;
    retval.All |= DSADCx->RES;
    return retval;
}

/** @} */
/* End of group DSADC_Exported_Functions */

/** @} */
/* End of group DSADC */

/** @} */
/* End of group TX03_Periph_Driver */
