
/******************************************************************************
* @file      : HAL_PMU.c
* @version   : 1.0
* @date      : 2022.10.25
* @brief     : PMU HAL module driver
*   
* @history   :	
*   2022.10.25    lwq    create
*   2022.12.15    lwq    Modify     
*                        1. Interrupt mask processing will not be added to HAL libraryŁ¬The application layer controls by itself 
*                        2. Clear the PMU status, resolve the Stop2 exception after reset, and the MCO cannot be closed  
*                        3. In STOP2 mode, the HAK library no longer switches the system clock to RC32K, and the application layer switches itself                        
******************************************************************************/
#include "hal.h" 


#ifdef HAL_PMU_MODULE_ENABLED

/******************************************************************************
* @brief : Initialize the PMU peripheral.
* @param : none.
* @return: none
******************************************************************************/
void HAL_PMU_Init(void)
{
    //PMU CLK Enable
    __HAL_RCC_PMU_CLK_ENABLE();   
}

/******************************************************************************
* @brief : try to enter sleep mode.
* @param : sleepEntry: Event wake-up or interrupt wake-up
* @return: none
******************************************************************************/
void HAL_PMU_EnterSleepMode(uint32_t sleepEntry)
{
    /* clear SLEEPDEEP bit of Cortex System Control Register */
    CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));         

    if(sleepEntry == WAIT_FOR_INT)       
    {
        /* Wait For Interrupt */
        __WFI();
    }
    else
    {
        
        __SEV();      
        __WFE();
        __WFE(); /*Wait For Event */     
    }  
}

/******************************************************************************
* @brief : try to enter stop mode.
* @param : stopEntry: Event wake-up or interrupt wake-up
* @param : stopMode: STOP0/1/2.
* @return: none
******************************************************************************/
void HAL_PMU_EnterStopMode(uint32_t stopEntry, uint32_t stopMode)
{  
    PMU->STCLR = 0xFFFFFFFF;//Clear all wake-up flags  
    
    MODIFY_REG(PMU->CTRL0, PMU_CTL0_LPMS_Msk, stopMode);//Stop0/1/2 Mode
    
    SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));   // Set SLEEPDEEP bit of Cortex System Control Register 

    if(stopEntry == WAIT_FOR_INT)
    {
        /* Wait For Interrupt */   
        __WFI();
    }
    else
    {
        /* Wait For Event */  
        __SEV();   
        __WFE();
        __WFE();    
    }
    /* clear SLEEPDEEP bit of Cortex System Control Register */
    CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk)); 
}


/******************************************************************************
* @brief : try to enter standby mode.
* @param : none
* @return: none
******************************************************************************/
void HAL_PMU_EnterStandbyMode(void)
{  
    PMU->STCLR = 0xFFFFFFFF;//Clear all wake-up flags
    
    MODIFY_REG(PMU->CTRL0, PMU_CTL0_LPMS_Msk, PMU_CTL0_LPMS_STANDBY);//Standby Mode

    SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));   // Set SLEEPDEEP bit of Cortex System Control Register 

    /* Wait For Interrupt */   
    __WFI();


    CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk)); 
}

/******************************************************************************
* @brief : try to enter powerdown mode.
* @param : none
* @return: none
******************************************************************************/
void HAL_PMU_EnterPowerdownMode(void)
{  
    PMU->STCLR = 0xFFFFFFFF;//Clear all wake-up flags
    
    MODIFY_REG(PMU->CTRL0, PMU_CTL0_LPMS_Msk, PMU_CTL0_LPMS_POWER_DOWN);//powerdown Mode

    SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));   // Set SLEEPDEEP bit of Cortex System Control Register 

    /* Wait For Interrupt */   
    __WFI();


    CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk)); 
}


/******************************************************************************
* @brief : wakeup source select.
* @param : wakeup_io: wakeup source select
* @param : polarity: 0(high), 1(low).
* @return: none
******************************************************************************/
void HAL_PMU_StandbyWakeupIOConfig(PMU_WakeUpIo_t wakeup_io, uint32_t polarity)
{
    switch (wakeup_io)
    {
        case STANDBY_WAKEUP1: 
        case STANDBY_WAKEUP2: 
        case STANDBY_WAKEUP3: 
        case STANDBY_WAKEUP4: 
        case STANDBY_WAKEUP5: 
        {			        
             //Clear flags
            SET_BIT(PMU->STCLR, (PMU_SRCLR_CWUPFX_Msk | PMU_SRCLR_CSBF_Msk));

            /* Wakeup IO Filter Enable */
            PMU->CTRL2 |= wakeup_io << PMU_CTL2_WUXFILEN_Pos;

            /* Wakeup IO Enable */
            PMU->CTRL2  |= wakeup_io;
               
            if (polarity) 
            {
                PMU->CTRL3 |= wakeup_io;//low level
            }
            else 
            {
                PMU->CTRL3 &= (~wakeup_io);//high level   
            }
 
        }
        break;
        
        default: break;       
    }
}

/******************************************************************************
* @brief : Release the selected wakeup IO.
* @param : wakeup_io: wakeup source select 
* @return: none
******************************************************************************/
void HAL_PMU_StandbyWakeupIORelease(PMU_WakeUpIo_t wakeup_io)
{
    switch (wakeup_io)
    {
        case STANDBY_WAKEUP1: 
        case STANDBY_WAKEUP2: 
        case STANDBY_WAKEUP3: 
        case STANDBY_WAKEUP4: 
        case STANDBY_WAKEUP5: 
        {			        
            /* Wakeup IO Filter Disable */
            PMU->CTRL2 &= (~(wakeup_io << PMU_CTL2_WUXFILEN_Pos));

            /* Wakeup IO Disable */
            PMU->CTRL2 &= (~wakeup_io);
 
        }
        break;
        
        default: break;       
    }
}

/******************************************************************************
* @brief : wakeup source select.
* @param : Wakeup_rtc: wakeup source select
* @return: none
******************************************************************************/
void HAL_PMU_StandbyWakeupRTCConfig(PMU_WakeUpRtc_t wakeup_rtc)
{
    switch (wakeup_rtc)    
    {
        case STANDBY_WAKEUP_WUTIE:
        case STANDBY_WAKEUP_STAMP2:
        case STANDBY_WAKEUP_STAMP1:
        case STANDBY_WAKEUP_32S:
        case STANDBY_WAKEUP_ALARM:
        case STANDBY_WAKEUP_1KHZ:
        case STANDBY_WAKEUP_256HZ:
        case STANDBY_WAKEUP_64HZ:
        case STANDBY_WAKEUP_16HZ:
        case STANDBY_WAKEUP_8HZ:
        case STANDBY_WAKEUP_4HZ:
        case STANDBY_WAKEUP_2HZ:  
        case STANDBY_WAKEUP_SEC:
        case STANDBY_WAKEUP_MIN:
        case STANDBY_WAKEUP_HOUR:
        case STANDBY_WAKEUP_DATE:        
        {	
            //Enable RTC CLK
            __HAL_RCC_RTC_CLK_ENABLE();

            //Clear flags
            SET_BIT(PMU->STCLR, (PMU_SRCLR_CRTCWUF_Msk | PMU_SRCLR_CSBF_Msk));

            /* RTC domain write enable */
            SET_BIT(PMU->CTRL0,PMU_CTL0_RTC_WE);
            RTC->SR = wakeup_rtc;
            RTC->IE |= wakeup_rtc;

        }break;

        default: break; 
    }
}

/******************************************************************************
* @brief : Release the selected RTC wakeup source.
* @param : wakeup_rtc: wakeup source select 
* @return: none
******************************************************************************/
void HAL_PMU_StandbyWakeupRTCRelease(PMU_WakeUpRtc_t wakeup_rtc)
{
    switch (wakeup_rtc)    
    {
        case STANDBY_WAKEUP_WUTIE:
        case STANDBY_WAKEUP_STAMP2:
        case STANDBY_WAKEUP_STAMP1:
        case STANDBY_WAKEUP_32S:
        case STANDBY_WAKEUP_ALARM:
        case STANDBY_WAKEUP_1KHZ:
        case STANDBY_WAKEUP_256HZ:
        case STANDBY_WAKEUP_64HZ:
        case STANDBY_WAKEUP_16HZ:
        case STANDBY_WAKEUP_8HZ:
        case STANDBY_WAKEUP_4HZ:
        case STANDBY_WAKEUP_2HZ:  
        case STANDBY_WAKEUP_SEC:
        case STANDBY_WAKEUP_MIN:
        case STANDBY_WAKEUP_HOUR:
        case STANDBY_WAKEUP_DATE:        
        {	
            //Enable RTC CLK
            __HAL_RCC_RTC_CLK_ENABLE();
            /* RTC domain write enable */
            SET_BIT(PMU->CTRL0,PMU_CTL0_RTC_WE);
            
            RTC->SR = wakeup_rtc;
            RTC->IE &= (~wakeup_rtc);

        }break;

        default: break;
    }
}

/*********************************************************************************
* @brief : Check MCU have entered standby mode
* @param : none 
* @return: 0: Not Enter Standby Mode,1: Entered Standby Mode
**********************************************************************************/
bool HAL_PMU_ChecktStandbyStatus(void)
{
    if (PMU->SR & PMU_SR_SBF_Msk) 
    {
        return true;
    }
    else 
    {
        return false;
    }
}

/******************************************************************************
* @brief : Get MCU Standby Wakeup Source.
* @param : none 
* @return: Wakeup Source
******************************************************************************/
uint32_t HAL_PMU_GetStandbyWakeupSource(void)
{
    return PMU->SR;
}

/******************************************************************************
* @brief : Clear MCU Standby Wakeup status.
* @param : status: Wakeup status
* @return: none
******************************************************************************/
void HAL_PMU_ClearStandbyWakeupStatus(uint32_t status)
{
     PMU->STCLR |= status;
}


/******************************************************************************
* @brief : LVD Enable.
* @param : voltage: LVD threshold voltage selection 
* @param : filter:  LVD filter time 
* @param : filter_en: Digital filter enable
* @return: none
******************************************************************************/
void HAL_PMU_LvdResetEnable(uint32_t voltage, uint32_t filter, uint32_t filter_en)
{
    assert_param(IS_PMU_LVD_VOLTAGE(voltage));
    assert_param(IS_PMU_LVD_FILTER(filter));
    assert_param(IS_PMU_LVD_FILTER_STATE(filter_en));
    PMU->CTRL1 = ((voltage) | (PMU_CTL1_LVDEN) | (filter) | (filter_en));
    HAL_SimpleDelay(100);
    __HAL_RCC_LVDRSTTOSYSRST_ENABLE();
}

/******************************************************************************
* @brief : LVD disable.
* @param : none
* @return: none
******************************************************************************/
void HAL_PMU_LvdResetDisable(void)
{
    PMU->CTRL1 &= (~PMU_CTL1_LVDEN);
    HAL_SimpleDelay(100);
    __HAL_RCC_LVDRSTTOSYSRST_DISABLE();
}

/******************************************************************************
* @brief : BOR Enable.
* @param : voltage: BOR voltage selection 
* @return: none
******************************************************************************/
void HAL_PMU_BorResetEnable(uint32_t voltage)
{
    assert_param(IS_PMU_BOR_VOLTAGE(voltage));
    PMU->CTRL2 |= ((voltage) | (PMU_CTL2_BOR_EN) | (PMU_CTL2_BORRST_EN));
    HAL_SimpleDelay(100);
}

/******************************************************************************
* @brief : BOR Disable.
* @param : none
* @return: none
******************************************************************************/
void HAL_PMU_BorResetDisable(void)
{
    PMU->CTRL2 &= (~((PMU_CTL2_BOR_EN) | (PMU_CTL2_BORRST_EN)));
    HAL_SimpleDelay(100);
}

#endif






