/******************************************************************************
*@file  : fxx_pmu.c
*@brief : PMU SPL module driver.
******************************************************************************/
#include  "fxx_pmu.h" 



/******************************************************************************
* @brief:  Deinitializes the PMU peripheral registers to their default reset values.     
* @param:  None
* @return: None
******************************************************************************/
void PMU_DeInit(void)
{
    /* Enable RTC PCLK */
    SCU->IPCKENR1 |= (1 << 13);     
    System_Delay(5);            
    /* Enable RTC RTC domain access */
    SCU->STOPCFG |= (1 << 0); 
    /* RTC domain soft reset */
    PMU->CR1 |= PMU_CR_BDRST_EN;
    /* Clear PMU status */
    PMU_ClearFlag(PMU_FLAG_ALL);
}

/******************************************************************************
* @brief:  Initialize the PMU peripheral.     
* @param:  None
* @return: None
******************************************************************************/
void PMU_Init(void)
{
    /* Enable RTC PCLK */
    SCU->IPCKENR1 |= (1 << 13);     
    System_Delay(5);            
    /* Enable RTC RTC domain access */
    SCU->STOPCFG |= (1 << 0); 
}

/******************************************************************************
* @brief:  Configures the voltage threshold detected by the LBOR.
* @param:  PMU_BORVoltage: specifies the BOR detection voltage
* @return: None
******************************************************************************/
void PMU_BORVoltageConfig(uint32_t PMU_BORVoltage)
{
    /* Check the parameters */
    assert_param(IS_PMU_BOR_VOLTAGE(PMU_BORVoltage));
    
    PMU->ANACR = (PMU->ANACR & (~(PMU_ANACR_BOR_CFG_Msk))) | PMU_BORVoltage;
}

/******************************************************************************
* @brief:  Enables or disables the BOR.
* @param:  NewState: new state of the BOR.
* @return: None
******************************************************************************/
void PMU_BORCmd(uint32_t NewState)
{
    /* Check the parameters */
    assert_param(IS_PMU_STATE(NewState));
    
    /* enable BOR */
    if (NewState != PMU_STATE_DISABLE)
    {
        PMU->ANACR |= PMU_ANACR_BOR_EN;   
    }
    else
    { 
        /* disable BOR */
        PMU->ANACR &= ~(PMU_ANACR_BOR_EN);
    }
}

/******************************************************************************
* @brief:  Enables or disables the BOR Reset function.
* @param:  NewState: new state of the BOR.
* @return: None
******************************************************************************/
void PMU_BORResetCmd(uint32_t NewState)
{
    /* Check the parameters */
    assert_param(IS_PMU_STATE(NewState));
    
    /* enable BOR reset */
    if (NewState != PMU_STATE_DISABLE)
    {
        PMU->CR1 |= PMU_CR_BORRST_EN;   
    }
    else
    { 
        /* disable BOR reset */
        PMU->CR1 &= ~(PMU_CR_BORRST_EN);
    }
}

/******************************************************************************
* @brief:  Enables or disables the WakeUp Pin .
* @param:  PMU_WakeUpPinx: specifies the WakeUp Pin.
* @param:  NewState: new state of the WakeUp Pin .
* @return: None
******************************************************************************/
void PMU_WakeupPinCmd(uint32_t PMU_WakeupPinx, uint32_t NewState)
{
    /* Check the parameters */  
    assert_param(IS_PMU_STATE(NewState));
    assert_param(IS_PMU_WAKEUP_PIN(PMU_WakeupPinx));
    
    /* WKUPx (x=6~1) pin wake-up function enable */
    if (NewState != PMU_STATE_DISABLE)
    {
        PMU->CR1 |= PMU_WakeupPinx << PMU_CR_EWUP1_Pos;   
    }
    else
    { 
        /* WKUPx (x=6~1) pin wake-up function disable */
        PMU->CR1 &= ~(PMU_WakeupPinx << PMU_CR_EWUP1_Pos);
    }
}

/******************************************************************************
* @brief:  Enables or disables the WKUPx (x=6~1) pin filter.
* @param:  PMU_WakeUpPinx: specifies the WakeUp Pin.
* @param:  NewState: new state of the WakeUp Pin Filter.
* @return: None
******************************************************************************/
void PMU_WakeupPinFilterCmd(uint32_t PMU_WakeupPinx, uint32_t NewState)
{
    /* Check the parameters */
    assert_param(IS_PMU_STATE(NewState));
    assert_param(IS_PMU_WAKEUP_PIN(PMU_WakeupPinx));
    
    /* enable wakeup pin Filter */
    if (NewState != PMU_STATE_DISABLE)
    {
        PMU->CR1 |= (PMU_WakeupPinx << PMU_CR_WUFILEN1_Pos);   
    }
    else
    { 
        /* disable wakeup pin Filter */
        PMU->CR1 &= (~(PMU_WakeupPinx << PMU_CR_WUFILEN1_Pos));
    }
}

/******************************************************************************
* @brief:  Configure WKUPx (x=6~1) pin wake-up polarity.
* @param:  PMU_WakeUpPinx: specifies the WakeUp Pin.
* @param:  PMU_WakeUpPolarity: Wakeup pin polarity.
* @return: None
******************************************************************************/
void PMU_WakeupPinPolarityConfig(uint32_t PMU_WakeupPinx, uint32_t PMU_WakeupPolarity)
{
    /* Check the parameters */
    assert_param(IS_PMU_WAKEUP_POLARITY(PMU_WakeupPolarity));
    assert_param(IS_PMU_WAKEUP_PIN(PMU_WakeupPinx));
    
    /* WKUPx pin low level wake-up */
    if (PMU_WakeupPolarity == PMU_WAKEUP_POLARITY_FALLING)
    {
        PMU->CR2 |= PMU_WakeupPinx;   
    }
    else
    { 
        /* WKUPx pin high level wake-up */
        PMU->CR2 &= ~(PMU_WakeupPinx);
    }
}

/******************************************************************************
* @brief : Enters SLEEP mode.
* @param : PMU_SleepEntry: specifies if SLEEP mode in entered with WFI 
           or WFE instruction
* @return: None
******************************************************************************/
void PMU_EnterSleepMode(uint8_t PMU_SleepEntry)
{
    /* Check the parameters */
    assert_param(IS_PMU_LOWPOWR_ENTRY(PMU_SleepEntry));
    
    /* Reset SLEEPDEEP bit of Cortex System Control Register */
    SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);     

    /* Select STOP mode entry */
    if(PMU_SleepEntry == PMU_LOWPOWRENTRY_WFI)       
    {
        /* Request Wait For Interrupt */
        __WFI();
    }
    else
    {
        /* Request Wait For Event */
        __SEV();      
        __WFE();
        __WFE();   
    }  
}

/******************************************************************************
* @brief:  Enters STOP mode.
* @param:  mode: specifies if STOP mode in entered with WFI 
           or WFE instruction.
* @return: None
******************************************************************************/
void PMU_EnterStopMode(uint8_t PMU_StopEntry)
{
    /* Check the parameters */
    assert_param(IS_PMU_LOWPOWR_ENTRY(PMU_StopEntry));
    
    /* Set SLEEPDEEP bit of Cortex System Control Register */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    
    SCU->STOPCFG &= ~(BIT11);  // PDDS=0 

    /* Select STOP mode entry */
    if(PMU_StopEntry == PMU_LOWPOWRENTRY_WFI)
    {   
        /* Request Wait For Interrupt */
        __WFI();
    }
    else
    {
        /* Request Wait For Event */
        __SEV();   
        __WFE();
        __WFE(); 
    }
    /* Reset SLEEPDEEP bit of Cortex System Control Register */
    SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);  
}

/******************************************************************************
* @brief:  Enters STANDBY mode.
* @param:  PMU_STANDBYEntry: specifies if STANDBY mode in entered with WFI 
           or WFE instruction.
* @return: None
******************************************************************************/
void PMU_EnterStandbyMode(uint8_t PMU_StandbyEntry)
{
    /* Check the parameters */
    assert_param(IS_PMU_LOWPOWR_ENTRY(PMU_StandbyEntry));
    
    /* Clear all wake-up flags */ 
    PMU_ClearFlag(PMU_FLAG_ALL);
    
    PMU->CR1 |= PMU_CR_STB_EN | PMU_CR_CWUF | PMU_CR_CSBF;
    
    SCU->STOPCFG |= BIT11;  // set PDDS=1 
    
    /* Set SLEEPDEEP bit of Cortex System Control Register */
    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    
    /* Select STOP mode entry */
    if(PMU_StandbyEntry == PMU_LOWPOWRENTRY_WFI)
    {   
        /* Request Wait For Interrupt */
        __WFI();
    }
    else
    {
        /* Request Wait For Event */
        __SEV();   
        __WFE();
        __WFE(); 
    }
    /* Reset SLEEPDEEP bit of Cortex System Control Register */
    SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk);  
}

/******************************************************************************
* @brief:  Set the wake-up waiting time of STANDBY mode.
* @param:  PMU_StandbyWaitTime: sSpecified standby mode wake-up waiting time.
* @return: None
******************************************************************************/
void PMU_SetStandbyWakeWaitTime(uint32_t PMU_StandbyWaitTime)
{
    /* Check the parameters */
    assert_param(IS_PMU_STANDBY_WAIT(PMU_StandbyWaitTime));

    PMU->CR1 = (PMU->CR1 & (~PMU_CR_WK_TIME_Msk)) | PMU_StandbyWaitTime ;
}

/******************************************************************************
* @brief:  Checks whether the specified PMU flag is set or not.
* @param:  PMU_FLAG: specifies the flag to check.
* @return: The new state of PMU_FLAG (SET or RESET).
******************************************************************************/
FlagStatus PMU_GetFlagStatus(uint32_t PMU_FLAG)
{
    FlagStatus bitstatus = RESET;

    /* Check the parameters */
    assert_param(IS_PMU_FLAG(PMU_FLAG));

    if ((PMU->SR & PMU_FLAG) != (uint32_t)RESET)
    {
        bitstatus = SET;
    }
    else
    {
        bitstatus = RESET;
    }

    /* Return the flag status */
    return bitstatus;
}

/******************************************************************************
* @brief:  Clears the PMU's pending flags.
* @param:  PMU_FLAG: specifies the flag to clear.
* @return: None
******************************************************************************/
void PMU_ClearFlag(uint32_t PMU_FLAG)
{
    /* Check the parameters */
    assert_param(IS_PMU_FLAG(PMU_FLAG));
    
    PMU->SR |= PMU_FLAG;
}

/******************************************************************************
* @brief:  PMU domain IO function selection.
* @param:  PMU_Pin: specifies the pmu domain IO Pin.
* @param:  PMU_Func: Specify the IO pin function of pmu domain.
* @return: None
******************************************************************************/
void PMU_PMUDomainPinFunction(uint32_t PMU_Pin, uint32_t PMU_Func)
{
    /* Check the parameters */
    assert_param(IS_PMU_PIN(PMU_Pin));
    assert_param(IS_PMU_PIN_FUNCTION(PMU_Func));
    
    /* PC13 pin function selection */
    if(PMU_Pin == PMU_PIN_PC13)
    {
        PMU->IOSEL = (PMU->IOSEL & (~PMU_IOSEL_PC13_SEL_Msk)) | (PMU_Func << PMU_IOSEL_PC13_SEL_Pos);
    }
    /* PC14 pin function selection */
    else if(PMU_Pin == PMU_PIN_PC14)
    {
        PMU->IOSEL = (PMU->IOSEL & (~PMU_IOSEL_PC14_SEL_Msk)) | (PMU_Func << PMU_IOSEL_PC14_SEL_Pos);
    }
    /* PC15 pin function selection */
    else
    {
        PMU->IOSEL = (PMU->IOSEL & (~PMU_IOSEL_PC15_SEL_Msk)) | (PMU_Func << PMU_IOSEL_PC15_SEL_Pos);
    }
}

/******************************************************************************
* @brief:  Set pmu domain IO value.
* @param:  PMU_Pin: specifies the pmu domain IO Pin.
* @param:  PMU_PinValue: specifies the pmu domain Pin Value.
* @return: None
******************************************************************************/
void PMU_SetPMUDomainPinValue(uint32_t PMU_Pin, uint32_t PMU_PinValue)
{
    /* Check the parameters */
    assert_param(IS_PMU_PIN(PMU_Pin));
    assert_param(IS_PMU_PIN_VALUE(PMU_PinValue));
    
    /* PC13 pin function selection */
    if(PMU_Pin == PMU_PIN_PC13)
    {
        PMU->IOSEL = (PMU->IOSEL & (~PMU_IOSEL_PC13_VALUE_Msk)) | (PMU_PinValue << PMU_IOSEL_PC13_VALUE_Pos);
    }
    /* PC14 pin function selection */
    else if(PMU_Pin == PMU_PIN_PC14)
    {
        PMU->IOSEL = (PMU->IOSEL & (~PMU_IOSEL_PC14_VALUE_Msk)) | (PMU_PinValue << PMU_IOSEL_PC14_VALUE_Pos);
    }
    /* PC15 pin function selection */
    else
    {
        PMU->IOSEL = (PMU->IOSEL & (~PMU_IOSEL_PC15_VALUE_Msk)) | (PMU_PinValue << PMU_IOSEL_PC15_VALUE_Pos);
    }
}

/******************************************************************************
* @brief:  Get pmu domain IO value.
* @param:  PMU_Pin: specifies the pmu domain IO Pin.
* @return: Pin Value
******************************************************************************/
uint32_t PMU_GetPMUDomainPinValue(uint32_t PMU_Pin)
{
    uint32_t tmp_value = 0;
    /* Check the parameters */
    assert_param(IS_PMU_PIN(PMU_Pin));
    
    /* get PC13 pin value */
    if(PMU_Pin == PMU_PIN_PC13)
    {
        tmp_value = ((PMU->IOSEL & PMU_IOSEL_PC13_VALUE_Msk) >> PMU_IOSEL_PC13_VALUE_Pos);
    }
    /* get PC14 pin value */
    else if(PMU_Pin == PMU_PIN_PC14)
    {
        tmp_value = ((PMU->IOSEL & PMU_IOSEL_PC14_VALUE_Msk) >> PMU_IOSEL_PC14_VALUE_Pos);
    }
    /* get PC15 pin value */
    else
    {
        tmp_value = ((PMU->IOSEL & PMU_IOSEL_PC15_VALUE_Msk) >> PMU_IOSEL_PC15_VALUE_Pos);
    }
    return tmp_value;
}

/******************************************************************************
* @brief:  PMU domain IO digital or analog selection.
* @param:  PMU_Pin: specifies the pmu domain IO Pin.
* @param:  PMU_Mode: Specify the IO pin of the PMU domain as digital or analog.
* @return: None
******************************************************************************/
void PMU_PMUDomainPinMode(uint32_t PMU_Pin, uint32_t PMU_Mode)
{
    /* Check the parameters */
    assert_param(IS_PMU_PIN(PMU_Pin));
    assert_param(IS_PMU_PIN_MODE(PMU_Mode));
    
    /* PC13 pin function selection */
    if(PMU_Pin == PMU_PIN_PC13)
    {
        PMU->IOCR = (PMU->IOCR & (~PMU_IOCR_PC13_ADS_Msk)) | (PMU_Mode << PMU_IOCR_PC13_ADS_Pos);
    }
    /* PC14 pin function selection */
    else if(PMU_Pin == PMU_PIN_PC14)
    {
        PMU->IOCR = (PMU->IOCR & (~PMU_IOCR_PC14_ADS_Msk)) | (PMU_Mode << PMU_IOCR_PC14_ADS_Pos);
    }
    /* PC15 pin function selection */
    else
    {
        PMU->IOCR = (PMU->IOCR & (~PMU_IOCR_PC15_ADS_Msk)) | (PMU_Mode << PMU_IOCR_PC15_ADS_Pos);
    }    
}

/******************************************************************************
*@brief : PMU domain pin PC13 output type.
*@param : type: output type.
*@return: None
******************************************************************************/
void PMU_PMUDomainPinPC13OutputType(uint32_t type)
{
    /* Check the parameters */
    assert_param(IS_PMU_PIN_PC13_OUTPUT(type));

    /* Set PC13_Value bits according to type value */
    PMU->IOSEL = (PMU->IOSEL & (~PMU_IOSEL_PC13_VALUE_Msk)) | (type << PMU_IOSEL_PC13_VALUE_Pos);
}

/******************************************************************************
* @brief:  PMU domain IO pull-up or pull-down selection.
* @param:  PMU_Pin: specifies the pmu domain IO Pin.
* @param:  PMU_Mode: Specify the IO pin of the PMU domain as pull-up or pull-down.
* @return: None
******************************************************************************/
void PMU_PMUDomainPinPull(uint32_t PMU_Pin, uint32_t PMU_Pull)
{
    /* Check the parameters */
    assert_param(IS_PMU_PIN(PMU_Pin));
    assert_param(IS_PMU_PIN_PULL(PMU_Pull));
    
    /* PC13 pin function selection */
    if(PMU_Pin == PMU_PIN_PC13)
    {
        PMU->IOCR = (PMU->IOCR & (~(0x3 << PMU_IOCR_PC13_PU_Pos))) | (PMU_Pull << PMU_IOCR_PC13_PU_Pos);
    }
    /* PC14 pin function selection */
    else if(PMU_Pin == PMU_PIN_PC14)
    {
        PMU->IOCR = (PMU->IOCR & (~(0x3 << PMU_IOCR_PC14_PU_Pos))) | (PMU_Pull << PMU_IOCR_PC14_PU_Pos);
    }
    /* PC15 pin function selection */
    else
    {
        PMU->IOCR = (PMU->IOCR & (~(0x3 << PMU_IOCR_PC15_PU_Pos))) | (PMU_Pull << PMU_IOCR_PC15_PU_Pos);
    }    
}

/******************************************************************************
* @brief:  Enables or disables the RC32K.
* @param:  NewState: new state of the RC32K.
* @return: None
******************************************************************************/
uint8_t PMU_RC32KCmd(uint32_t NewState)
{
    uint32_t timeout;

    /* Check the parameters */
    assert_param(IS_PMU_STATE(NewState));

    if (NewState == PMU_STATE_DISABLE)
    {
        if (0x01 == (SCU->CCR1 & 0x07))
        {
            return 1;
        }

        if (PMU_CR_RTCEN == (PMU->CR1 & (PMU_CR_RTCEN | PMU_CR_RTCSEL)))
        {
            return 1;
        }
                
        /* disable RC32K */
        PMU->ANACR &= ~(PMU_ANACR_RC32KEN);
        timeout = PMU_RC32K_UNREADY_TIMEOUT;
        while (PMU->ANACR & PMU_ANACR_RC32KRDY)
        {
            if (0 == --timeout)
            {
                return 3;
            }
        }
    }
    else
    {
        /* enable RC32K */
        PMU->ANACR |= PMU_ANACR_RC32KEN;
        timeout = PMU_RC32K_READY_TIMEOUT;
        while (!(PMU->ANACR & PMU_ANACR_RC32KRDY))
        {
            if (0 == --timeout)
            {
                return 3;
            }
        }
    }

    return 0;
}


/******************************************************************************
* @brief:  Enables or disables the XTL.
* @param:  NewState: new state of the XTL.
* @return: None
******************************************************************************/
uint8_t PMU_XTLCmd(uint32_t NewState)
{
    uint32_t timeout;

    /* Check the parameters */
    assert_param(IS_PMU_STATE(NewState));

    if (NewState == PMU_STATE_DISABLE)
    {
        /* check whether the current configured clock is the system clock */
        if (0x03 == (SCU->CCR1 & 0x07))
        {
            return 1;
        }

        if ((PMU_CR_RTCEN | PMU_RTC_CLK_XTL) == (PMU->CR1 & (PMU_CR_RTCEN | PMU_RTC_CLK_XTL)))
        {
            return 1;
        }
        /* disable XTL */
        PMU->ANACR &= ~(PMU_ANACR_XTLEN);
        timeout = PMU_XTL_UNREADY_TIMEOUT;
        while (PMU->ANACR & PMU_ANACR_XTLRDY)
        {
            if (0 == --timeout)
            {
                return 3;
            }
        }
    }
    else
    {
        /* enable XTL */
        PMU->ANACR |= PMU_ANACR_XTLEN;
        timeout = PMU_XTL_READY_TIMEOUT;
        while (!(PMU->ANACR & PMU_ANACR_XTLRDY))
        {
            if (0 == --timeout)
            {
                return 3;
            }
        }
    }
    
    return 0;
}

/******************************************************************************
* @brief : Configure XTL driver capability and power consumption mode
* @param : mode: Power consumption selection
* @param : drive: drive capability
* @return: None
******************************************************************************/
void PMU_XTLDriveConfig(uint32_t mode, uint32_t drive)
{
    /* Check the parameters */
    assert_param(IS_PMU_XTL_MODE(mode));
    assert_param(IS_PMU_XTL_DRIVE(drive));
    
    PMU->ANACR = (PMU->ANACR & (~(PMU_ANACR_XTLDRV_Msk))) | mode | drive;
}

/******************************************************************************
* @brief:  Enables or disables the XTL bypass.
* @param:  NewState: new state of the XTL bypass.
* @return: None
******************************************************************************/
void PMU_XTLBypassCmd(uint32_t NewState)
{
    /* Check the parameters */
    assert_param(IS_PMU_STATE(NewState));
    
    if (NewState == PMU_STATE_DISABLE)
    {
        PMU->ANACR &= ~(PMU_ANACR_XTLBYP);        
    }
    else
    {
        PMU->ANACR |= PMU_ANACR_XTLBYP;        
    }
}


/******************************************************************************
* @brief:  Enables or disables the RTCCLK.
* @param:  NewState: new state of the RTCCLK.
* @return: None
******************************************************************************/
void PMU_RTCClkCmd(uint32_t NewState)
{
    /* Check the parameters */
    assert_param(IS_PMU_STATE(NewState));
    
    if (NewState == PMU_STATE_DISABLE)
    {
        PMU->CR1 &= ~(PMU_CR_RTCEN);        
    }
    else
    {
        PMU->CR1 |= PMU_CR_RTCEN;        
    }
}

/******************************************************************************
* @brief:  RTC clock selection.
* @param:  clock: RTC clock source.
* @return: None
******************************************************************************/
void PMU_RTCClkSelect(uint32_t clock)
{
    /* Check the parameters */
    assert_param(IS_PMU_RTC_CLK(clock));
    
    PMU->CR1 = (PMU->CR1 & (~(PMU_CR_RTCSEL_Msk))) | clock;        


}


/************************ (C) COPYRIGHT AISINOCHIP *****END OF FILE****/






