blob: fc52c95feb6757b55a7a33d5b9137b2cac0341e0 [file] [log] [blame]
/****************************************************************************
* arch/arm/src/gd32f4/gd32f4xx_pmu.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include "nvic.h"
#include "gd32f4xx_pmu.h"
#include "gd32f4xx.h"
#if defined(CONFIG_GD32F4_PMU)
/****************************************************************************
* Private Data
****************************************************************************/
static uint32_t gd32_pmu_reg_snap[4];
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: gd32_pmu_lvd_select
*
* Description:
* Select low voltage detector threshold.
*
* Input Parameters:
* lvdt_n - PMU_CTL_LVDT(n), LVD threshold level
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_lvd_select(uint32_t lvdt_n)
{
uint32_t regval;
/* Disable LVD */
modifyreg32(GD32_PMU_CTL, PMU_CTL_LVDEN, 0);
regval = getreg32(GD32_PMU_CTL);
/* Clear LVDT bits */
regval &= ~PMU_CTL_LVDT_MASK;
/* Set LVDT bits according to pmu_lvdt_n */
regval |= lvdt_n;
putreg32(regval, GD32_PMU_CTL);
/* Enable LVD */
modifyreg32(GD32_PMU_CTL, 0, PMU_CTL_LVDEN);
}
/****************************************************************************
* Name: gd32_pmu_lvd_enable
*
* Description:
* Enable LVD
*
****************************************************************************/
void gd32_pmu_lvd_enable(void)
{
/* Enable LVD */
modifyreg32(GD32_PMU_CTL, 0, PMU_CTL_LVDEN);
}
/****************************************************************************
* Name: gd32_pmu_lvd_disable
*
* Description:
* Disable LVD
*
****************************************************************************/
void gd32_pmu_lvd_disable(void)
{
/* Disable LVD */
modifyreg32(GD32_PMU_CTL, PMU_CTL_LVDEN, 0);
}
/****************************************************************************
* Name: gd32_pmu_ldo_output_select
*
* Description:
* Select the LDO output voltage. Set LDO output when the main PLL closed,
* and it takes effect when the main PLL enabled.
*
* Input Parameters:
* ldo_output - PMU_CTL_LDOVS(n), PMU LDO output voltage select
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_ldo_output_select(uint32_t ldo_output)
{
uint32_t regval;
regval = getreg32(GD32_PMU_CTL);
regval &= ~PMU_CTL_LDOVS_MASK;
regval |= ldo_output;
putreg32(regval, GD32_PMU_CTL);
}
/****************************************************************************
* Name: gd32_pmu_highdriver_mode_enable
*
* Description:
* Disable high-driver mode
*
****************************************************************************/
void gd32_pmu_highdriver_mode_enable(void)
{
modifyreg32(GD32_PMU_CTL, 0, PMU_CTL_HDEN);
}
/****************************************************************************
* Name: gd32_pmu_highdriver_mode_disable
*
* Description:
* Disable high-driver mode
*
****************************************************************************/
void gd32_pmu_highdriver_mode_disable(void)
{
modifyreg32(GD32_PMU_CTL, PMU_CTL_HDEN, 0);
}
/****************************************************************************
* Name: gd32_pmu_highdriver_switch_select
*
* Description:
* Switch high-driver mode.
*
* Input Parameters:
* highdr_switch - PMU high-driver mode
* - PMU_HIGHDR_SWITCH_NONE
* - PMU_HIGHDR_SWITCH_EN
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_highdriver_switch_select(uint32_t highdr_switch)
{
uint32_t regval;
while (getreg32(GD32_PMU_CS) & PMU_CS_HDRF);
regval = getreg32(GD32_PMU_CTL);
regval &= ~PMU_CTL_HDS;
regval |= highdr_switch;
putreg32(regval, GD32_PMU_CTL);
}
/****************************************************************************
* Name: gd32_pmu_lowdriver_mode_enable
*
* Description:
* Enable low-driver mode in deep-sleep
*
****************************************************************************/
void gd32_pmu_lowdriver_mode_enable(void)
{
modifyreg32(GD32_PMU_CTL, 0, PMU_LOWDRIVER_ENABLE);
}
/****************************************************************************
* Name: gd32_pmu_lowdriver_mode_disable
*
* Description:
* Disable low-driver mode in deep-sleep
*
****************************************************************************/
void gd32_pmu_lowdriver_mode_disable(void)
{
modifyreg32(GD32_PMU_CTL, PMU_LOWDRIVER_ENABLE, PMU_LOWDRIVER_DISABLE);
}
/****************************************************************************
* Name: gd32_pmu_lowpower_driver_config
*
* Description:
* In deep-sleep mode, driver mode when use low power LDO.
*
* Input Parameters:
* mode - PMU low-driver mode
* - PMU_NORMALDR_LOWPWR: normal driver when use low power LDO
* - PMU_LOWDR_LOWPWR: low-driver mode enabled when LDEN is 11 and
* use low power LDO
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_lowpower_driver_config(uint32_t mode)
{
uint32_t regval;
regval = getreg32(GD32_PMU_CTL);
regval &= ~PMU_CTL_LDLP;
regval |= mode;
putreg32(regval, GD32_PMU_CTL);
}
/****************************************************************************
* Name: gd32_pmu_normalpower_driver_config
*
* Description:
* In deep-sleep mode, driver mode when use normal power LDO.
*
* Input Parameters:
* mode - PMU low-driver mode
* - PMU_NORMALDR_NORMALPWR: normal driver when use normal power LDO
* - PMU_LOWDR_NORMALPWR: low-driver mode enabled when LDEN is 11 and
* use normal power LDO
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_normalpower_driver_config(uint32_t mode)
{
uint32_t regval;
regval = getreg32(GD32_PMU_CTL);
regval &= ~PMU_CTL_LDNP;
regval |= mode;
putreg32(regval, GD32_PMU_CTL);
}
/****************************************************************************
* Name: gd32_pmu_to_sleepmode
*
* Description:
* PMU work in sleep mode.
*
* Input Parameters:
* sleepmodecmd - PMU command constants
* - WFI_CMD: use WFI command
* - WFE_CMD: use WFE command
* sleeponexit
* - true: SLEEPONEXIT bit is set when the WFI instruction is
* executed, the MCU enters Sleep mode as soon as it
* exits the lowest priority ISR.
* - false: SLEEPONEXIT bit is cleared, the MCU enters Sleep
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_to_sleepmode(uint8_t sleepmodecmd, bool sleeponexit)
{
uint32_t regval;
/* Clear SLEEPDEEP bit of Cortex-M4 System Control Register */
regval = getreg32(NVIC_SYSCON);
regval &= ~NVIC_SYSCON_SLEEPDEEP;
if (sleeponexit)
{
regval |= NVIC_SYSCON_SLEEPONEXIT;
}
else
{
regval &= ~NVIC_SYSCON_SLEEPONEXIT;
}
putreg32(regval, NVIC_SYSCON);
/* Select WFI or WFE command to enter sleep mode */
if (sleepmodecmd == WFI_CMD)
{
asm("wfi");
}
else
{
asm("wfe");
}
}
/****************************************************************************
* Name: gd32_pmu_to_deepsleepmode
*
* Description:
* PMU work in deep-sleep mode
*
* Input Parameters:
* ldo
* - PMU_LDO_NORMAL: LDO normal work when pmu enter deep-sleep mode
* - PMU_LDO_LOWPOWER: LDO work at low power mode when pmu enter
* deep-sleep mode
* lowdrive
* - PMU_LOWDRIVER_DISABLE: Low-driver mode disable in deep-sleep mode
* - PMU_LOWDRIVER_ENABLE: Low-driver mode enable in deep-sleep mode
*
* deepsleepmodecmdd - PMU command constants
* - WFI_CMD: use WFI command
* - WFE_CMD: use WFE command
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_to_deepsleepmode(uint32_t ldo, uint32_t lowdrive,
uint8_t deepsleepmodecmd)
{
uint32_t regval;
regval = getreg32(GD32_PMU_CTL);
/* Clear stbmod and ldolp bits */
regval &= ~(PMU_CTL_STBMOD | PMU_CTL_LDOLP | PMU_CTL_LDEN_MASK |
PMU_CTL_LDNP | PMU_CTL_LDLP);
/* Set ldolp bit according to pmu_ldo */
regval |= ldo;
/* Configure low drive mode in deep-sleep mode */
if (lowdrive == PMU_LOWDRIVER_ENABLE)
{
if (ldo == PMU_LDO_NORMAL)
{
regval |= (PMU_LOWDRIVER_ENABLE | PMU_CTL_LDNP);
}
else
{
regval |= (PMU_LOWDRIVER_ENABLE | PMU_CTL_LDLP);
}
}
putreg32(regval, GD32_PMU_CTL);
/* Set SLEEPDEEP bit of Cortex-M4 System Control Register */
regval = getreg32(NVIC_SYSCON);
regval |= NVIC_SYSCON_SLEEPDEEP;
putreg32(regval, NVIC_SYSCON);
gd32_pmu_reg_snap[0] = getreg32(NVIC_SYSTICK_CTRL);
gd32_pmu_reg_snap[1] = getreg32(NVIC_IRQ0_31_ENABLE);
gd32_pmu_reg_snap[2] = getreg32(NVIC_IRQ32_63_ENABLE);
gd32_pmu_reg_snap[3] = getreg32(NVIC_IRQ64_95_ENABLE);
putreg32((0x00010004u & gd32_pmu_reg_snap[0]), NVIC_SYSTICK_CTRL);
putreg32(0xff7ff831u, NVIC_IRQ0_31_CLEAR);
putreg32(0xff7ff831u, NVIC_IRQ32_63_CLEAR);
putreg32(0xff7ff831u, NVIC_IRQ64_95_CLEAR);
/* Select WFI or WFE command to enter sleep mode */
if (deepsleepmodecmd == WFI_CMD)
{
asm("wfi");
}
else
{
asm("sev");
asm("wfe");
asm("wfe");
}
putreg32(gd32_pmu_reg_snap[0], NVIC_SYSTICK_CTRL);
putreg32(gd32_pmu_reg_snap[1], NVIC_IRQ0_31_ENABLE);
putreg32(gd32_pmu_reg_snap[2], NVIC_IRQ32_63_ENABLE);
putreg32(gd32_pmu_reg_snap[3], NVIC_IRQ64_95_ENABLE);
/* Reset SLEEPDEEP bit of Cortex-M4 System Control Register */
regval = getreg32(NVIC_SYSCON);
regval &= ~NVIC_SYSCON_SLEEPDEEP;
putreg32(regval, NVIC_SYSCON);
}
/****************************************************************************
* Name: gd32_pmu_to_standbymode
*
* Description:
* PMU work in standby mode
*
* Input Parameters:
* standbymodecmd - PMU command constants
* WFI_CMD: use WFI command
* WFE_CMD: use WFE command
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_to_standbymode(uint8_t standbymodecmd)
{
uint32_t regval;
/* Set SLEEPDEEP bit of Cortex-M4 System Control Register */
regval = getreg32(NVIC_SYSCON);
regval |= NVIC_SYSCON_SLEEPDEEP;
putreg32(regval, NVIC_SYSCON);
regval = getreg32(GD32_PMU_CTL);
/* Set stbmod bit */
regval |= PMU_CTL_STBMOD;
/* Reset wakeup flag */
regval |= PMU_CTL_WURST;
putreg32(regval, GD32_PMU_CTL);
/* Select WFI or WFE command to enter sleep mode */
if (standbymodecmd == WFI_CMD)
{
asm("wfi");
}
else
{
asm("wfe");
asm("wfe");
}
}
/****************************************************************************
* Name: gd32_pmu_wakeup_pin_enable
*
* Description:
* Enables PMU wakeup pin.
*
****************************************************************************/
void gd32_pmu_wakeup_pin_enable(void)
{
modifyreg32(GD32_PMU_CS, 0, PMU_CS_WUPEN);
}
/****************************************************************************
* Name: gd32_pmu_wakeup_pin_disable
*
* Description:
* Disables PMU wakeup pin.
*
****************************************************************************/
void gd32_pmu_wakeup_pin_disable(void)
{
modifyreg32(GD32_PMU_CS, PMU_CS_WUPEN, 0);
}
/****************************************************************************
* Name: gd32_pmu_backup_ldo_config
*
* Description:
* Enables the backup ldo, to open Backup SRAM LDO for data protection of
* backup SRAM when VDD shut down. When VDD shut down and this bit is
* cleared, the data in Backup SRAM will be lost.
* Once set, the application should wait that the Backup SRAM LDO flag
* (BLDORF) is set to indicate that the data written into the RAM will be
* maintained when VDD shut down.
*
* Input Parameters:
* bkp_ldo - state to set it to
* - PMU_BLDOON_OFF: backup SRAM LDO closed
* - PMU_BLDOON_ON: backup SRAM LDO closed
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_backup_ldo_config(bool bkp_ldo)
{
uint32_t regval;
regval = getreg32(GD32_PMU_CS);
regval &= ~ PMU_CS_BLDOON;
regval |= bkp_ldo;
putreg32(regval, GD32_PMU_CS);
}
/****************************************************************************
* Name: gd32_pmu_backup_init
*
* Description:
* Insures the referenced count access to the backup domain
* (RTC registers, RTC backup data registers and backup SRAM is consistent
* with the hardware state without relying on a variable.
*
* NOTE: This function should only be called by SoC Start up code.
*
* Input Parameters:
* writable - set the initial state of the enable or disable
*
* Returned Value:
* None
*
****************************************************************************/
void gd32_pmu_backup_init(bool writable)
{
uint32_t regval;
/* Make the hardware not writable */
regval = getreg32(GD32_PMU_CTL);
regval &= ~PMU_CS_WUPEN;
putreg32(regval, GD32_PMU_CTL);
if (writable)
{
gd32_pmu_backup_write_enable();
}
else
{
gd32_pmu_backup_write_disable();
}
}
/****************************************************************************
* Name: gd32_pmu_backup_write_enable
*
* Description:
* Enableswrite access to the registers in backup domain
*
****************************************************************************/
void gd32_pmu_backup_write_enable(void)
{
modifyreg32(GD32_PMU_CTL, 0, PMU_CTL_BKPWEN);
}
/****************************************************************************
* Name: gd32_pmu_backup_write_disable
*
* Description:
* DIsables write access to the registers in backup domain
*
****************************************************************************/
void gd32_pmu_backup_write_disable(void)
{
modifyreg32(GD32_PMU_CTL, PMU_CTL_BKPWEN, 0);
}
/****************************************************************************
* Name: gd32_pmu_flag_get
*
* Description:
* Get flag state
*
* Input Parameters:
* flag - PMU_CS_WUF: wakeup flag
* - PMU_CS_STBF: standby flag
* - PMU_CS_LVDF: lvd flag
* - PMU_CS_BLDORF: backup SRAM LDO ready flag
* - PMU_CS_LDOVSRF: LDO voltage select ready flag
* - PMU_CS_HDRF: high-driver ready flag
* - PMU_CS_HDSRF: high-driver switch ready flag
* - PMU_CS_LDRF: low-driver mode ready flag
*
****************************************************************************/
bool gd32_pmu_flag_get(uint32_t flag)
{
if (getreg32(GD32_PMU_CS) & flag)
{
return 1;
}
else
{
return 0;
}
}
/****************************************************************************
* Name: gd32_pmu_backup_write_disable
*
* Description:
* Clear the flag
*
* Input Parameters:
* flag - PMU_FLAG_RESET_WAKEUP: reset wakeup flag
* - PMU_FLAG_RESET_STANDBY: reset standby flag
*
****************************************************************************/
void gd32_pmu_flag_clear(uint32_t flag)
{
uint32_t regval;
regval = getreg32(GD32_PMU_CTL);
switch (flag)
{
case PMU_FLAG_RESET_WAKEUP:
/* Reset wakeup flag */
regval |= PMU_CTL_WURST;
putreg32(regval, GD32_PMU_CTL);
break;
case PMU_FLAG_RESET_STANDBY:
/* Reset standby flag */
regval |= PMU_CTL_STBRST;
putreg32(regval, GD32_PMU_CTL);
break;
default:
break;
}
}
#endif /* CONFIG_GD32F4_PMU */