soc: stm23u5: Provide power implementation
Provide power modes implementation for u5 socs. For now STOP3 mode is not implemented as this mode is not compatible with LPTIM activation and hence cannot be used as a workable suspend to idle state using LPTIM as kernel tick source. Signed-off-by: Erwan Gouriou <erwan.gouriou@linaro.org>
This commit is contained in:
parent
1ec41ce922
commit
997e4584ce
3 changed files with 160 additions and 0 deletions
|
@ -4,3 +4,7 @@ zephyr_include_directories(${ZEPHYR_BASE}/drivers)
|
|||
zephyr_sources(
|
||||
soc.c
|
||||
)
|
||||
|
||||
zephyr_sources_ifdef(CONFIG_PM
|
||||
power.c
|
||||
)
|
||||
|
|
|
@ -10,4 +10,7 @@ source "soc/arm/st_stm32/stm32u5/Kconfig.defconfig.stm32u5*"
|
|||
config SOC_SERIES
|
||||
default "stm32u5"
|
||||
|
||||
config STM32_LPTIM_TIMER
|
||||
default y if PM
|
||||
|
||||
endif # SOC_SERIES_STM32U5X
|
||||
|
|
153
soc/arm/st_stm32/stm32u5/power.c
Normal file
153
soc/arm/st_stm32/stm32u5/power.c
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Linaro Limited
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr.h>
|
||||
#include <pm/pm.h>
|
||||
#include <soc.h>
|
||||
#include <init.h>
|
||||
|
||||
#include <stm32u5xx_ll_utils.h>
|
||||
#include <stm32u5xx_ll_bus.h>
|
||||
#include <stm32u5xx_ll_cortex.h>
|
||||
#include <stm32u5xx_ll_pwr.h>
|
||||
#include <stm32u5xx_ll_rcc.h>
|
||||
#include <stm32u5xx_ll_system.h>
|
||||
#include <clock_control/clock_stm32_ll_common.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
|
||||
|
||||
/* select MSI as wake-up system clock if configured, HSI otherwise */
|
||||
#if STM32_SYSCLK_SRC_MSI
|
||||
#define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_MSI
|
||||
#else
|
||||
#define RCC_STOP_WAKEUPCLOCK_SELECTED LL_RCC_STOP_WAKEUPCLOCK_HSI
|
||||
#endif
|
||||
|
||||
void set_mode_stop(uint8_t substate_id)
|
||||
{
|
||||
/* ensure the proper wake-up system clock */
|
||||
LL_RCC_SetClkAfterWakeFromStop(RCC_STOP_WAKEUPCLOCK_SELECTED);
|
||||
|
||||
switch (substate_id) {
|
||||
case 1: /* enter STOP0 mode */
|
||||
LL_PWR_SetPowerMode(LL_PWR_STOP0_MODE);
|
||||
break;
|
||||
case 2: /* enter STOP1 mode */
|
||||
LL_PWR_SetPowerMode(LL_PWR_STOP1_MODE);
|
||||
break;
|
||||
case 3: /* enter STOP2 mode */
|
||||
LL_PWR_SetPowerMode(LL_PWR_STOP2_MODE);
|
||||
break;
|
||||
default:
|
||||
LOG_DBG("Unsupported power state substate-id %u", substate_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void set_mode_standby(uint8_t substate_id)
|
||||
{
|
||||
ARG_UNUSED(substate_id);
|
||||
/* Select standby mode */
|
||||
LL_PWR_SetPowerMode(LL_PWR_STANDBY_MODE);
|
||||
}
|
||||
|
||||
void set_mode_shutdown(uint8_t substate_id)
|
||||
{
|
||||
ARG_UNUSED(substate_id);
|
||||
/* Select shutdown mode */
|
||||
LL_PWR_SetPowerMode(LL_PWR_SHUTDOWN_MODE);
|
||||
}
|
||||
|
||||
/* Invoke Low Power/System Off specific Tasks */
|
||||
__weak void pm_power_state_set(struct pm_state_info info)
|
||||
{
|
||||
|
||||
switch (info.state) {
|
||||
case PM_STATE_SUSPEND_TO_IDLE:
|
||||
set_mode_stop(info.substate_id);
|
||||
break;
|
||||
case PM_STATE_STANDBY:
|
||||
/* To be tested */
|
||||
set_mode_standby(info.substate_id);
|
||||
break;
|
||||
case PM_STATE_SOFT_OFF:
|
||||
set_mode_shutdown(info.substate_id);
|
||||
break;
|
||||
/* Following states are not supported */
|
||||
case PM_STATE_RUNTIME_IDLE:
|
||||
__fallthrough;
|
||||
case PM_STATE_ACTIVE:
|
||||
__fallthrough;
|
||||
case PM_STATE_SUSPEND_TO_RAM:
|
||||
__fallthrough;
|
||||
case PM_STATE_SUSPEND_TO_DISK:
|
||||
LOG_DBG("Unsupported power state %u", info.state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set SLEEPDEEP bit of Cortex System Control Register */
|
||||
LL_LPM_EnableDeepSleep();
|
||||
|
||||
/* Select mode entry : WFE or WFI and enter the CPU selected mode */
|
||||
k_cpu_idle();
|
||||
}
|
||||
|
||||
/* Handle SOC specific activity after Low Power Mode Exit */
|
||||
__weak void pm_power_state_exit_post_ops(struct pm_state_info info)
|
||||
{
|
||||
switch (info.state) {
|
||||
case PM_STATE_SUSPEND_TO_IDLE:
|
||||
if (info.substate_id <= 3) {
|
||||
LL_LPM_DisableSleepOnExit();
|
||||
LL_LPM_EnableSleep();
|
||||
} else {
|
||||
LOG_DBG("Unsupported power substate-id %u",
|
||||
info.substate_id);
|
||||
}
|
||||
case PM_STATE_STANDBY:
|
||||
/* To be tested */
|
||||
LL_LPM_EnableSleep();
|
||||
case PM_STATE_SOFT_OFF:
|
||||
/* We should not get there */
|
||||
__fallthrough;
|
||||
case PM_STATE_ACTIVE:
|
||||
__fallthrough;
|
||||
case PM_STATE_SUSPEND_TO_RAM:
|
||||
__fallthrough;
|
||||
case PM_STATE_SUSPEND_TO_DISK:
|
||||
__fallthrough;
|
||||
default:
|
||||
LOG_DBG("Unsupported power state %u", info.state);
|
||||
break;
|
||||
}
|
||||
/* need to restore the clock */
|
||||
stm32_clock_control_init(NULL);
|
||||
|
||||
/*
|
||||
* System is now in active mode.
|
||||
* Reenable interrupts which were disabled
|
||||
* when OS started idling code.
|
||||
*/
|
||||
irq_unlock(0);
|
||||
}
|
||||
|
||||
/* Initialize STM32 Power */
|
||||
static int stm32_power_init(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
/* enable Power clock */
|
||||
LL_AHB3_GRP1_EnableClock(LL_AHB3_GRP1_PERIPH_PWR);
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
/* Enable the Debug Module during all and any Low power mode */
|
||||
LL_DBGMCU_EnableDBGStopMode();
|
||||
#endif /* CONFIG_DEBUG */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYS_INIT(stm32_power_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|
Loading…
Add table
Add a link
Reference in a new issue