diff --git a/dts/arm/st/l1/stm32l1.dtsi b/dts/arm/st/l1/stm32l1.dtsi index 375d97d1c5e..0e29922611d 100644 --- a/dts/arm/st/l1/stm32l1.dtsi +++ b/dts/arm/st/l1/stm32l1.dtsi @@ -16,11 +16,13 @@ #include #include #include +#include #include / { chosen { zephyr,flash-controller = &flash; + zephyr,cortex-m-idle-timer = &rtc; }; cpus { @@ -30,10 +32,27 @@ cpu0: cpu@0 { device_type = "cpu"; compatible = "arm,cortex-m3"; + cpu-power-states = <&sleep &stop>; reg = <0>; }; }; + power-states { + sleep: sleep { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <1000000>; + exit-latency-us = <750>; + }; + + stop: stop { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + min-residency-us = <1000000>; + exit-latency-us = <750>; + }; + }; + sram0: memory@20000000 { compatible = "mmio-sram"; }; @@ -81,7 +100,6 @@ }; soc { - flash: flash-controller@40023c00 { compatible = "st,stm32-flash-controller", "st,stm32f1-flash-controller"; reg = <0x40023c00 0x400>; @@ -184,6 +202,32 @@ status = "disabled"; }; + pwr: power@40007000 { + compatible = "st,stm32-pwr"; + reg = <0x40007000 0x400>; /* PWR register bank */ + status = "disabled"; + + wkup-pins-nb = <3>; + + #address-cells = <1>; + #size-cells = <0>; + + wkup-pin@1 { + reg = <0x1>; + wkup-gpios = <&gpioa 0 STM32_PWR_WKUP_PIN_NOT_MUXED>; + }; + + wkup-pin@2 { + reg = <0x2>; + wkup-gpios = <&gpioc 13 STM32_PWR_WKUP_PIN_NOT_MUXED>; + }; + + wkup-pin@3 { + reg = <0x3>; + wkup-gpios = <&gpioe 6 STM32_PWR_WKUP_PIN_NOT_MUXED>; + }; + }; + spi1: spi@40013000 { compatible = "st,stm32-spi"; #address-cells = <1>; diff --git a/samples/boards/st/power_mgmt/wkup_pins/boards/nucleo_l152re.overlay b/samples/boards/st/power_mgmt/wkup_pins/boards/nucleo_l152re.overlay new file mode 100644 index 00000000000..008a6cc7aac --- /dev/null +++ b/samples/boards/st/power_mgmt/wkup_pins/boards/nucleo_l152re.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 Oleh Kravchenko + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + wkup-src = &user_button; + }; +}; + +&pwr { + status = "okay"; +}; diff --git a/samples/boards/st/power_mgmt/wkup_pins/boards/stm32l1_disco.overlay b/samples/boards/st/power_mgmt/wkup_pins/boards/stm32l1_disco.overlay new file mode 100644 index 00000000000..008a6cc7aac --- /dev/null +++ b/samples/boards/st/power_mgmt/wkup_pins/boards/stm32l1_disco.overlay @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2025 Oleh Kravchenko + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/ { + aliases { + wkup-src = &user_button; + }; +}; + +&pwr { + status = "okay"; +}; diff --git a/samples/boards/st/power_mgmt/wkup_pins/sample.yaml b/samples/boards/st/power_mgmt/wkup_pins/sample.yaml index d6d697ba15d..26259c3de31 100644 --- a/samples/boards/st/power_mgmt/wkup_pins/sample.yaml +++ b/samples/boards/st/power_mgmt/wkup_pins/sample.yaml @@ -12,5 +12,7 @@ tests: - nucleo_u5a5zj_q - nucleo_wl55jc - nucleo_f103rb + - stm32l1_disco + - nucleo_l152re integration_platforms: - nucleo_l4r5zi diff --git a/soc/st/stm32/common/soc_config.c b/soc/st/stm32/common/soc_config.c index ebfe2b2a008..e600c4d5538 100644 --- a/soc/st/stm32/common/soc_config.c +++ b/soc/st/stm32/common/soc_config.c @@ -69,7 +69,7 @@ static int st_stm32_common_config(void) #if defined(CONFIG_STM32_ENABLE_DEBUG_SLEEP_STOP) -#if defined(CONFIG_SOC_SERIES_STM32F1X) +#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32L1X) LL_DBGMCU_EnableDBGSleepMode(); LL_DBGMCU_EnableDBGStopMode(); LL_DBGMCU_EnableDBGStandbyMode(); @@ -89,7 +89,7 @@ static int st_stm32_common_config(void) #else /* keeping in mind that debugging draws a lot of power we explcitly disable when not needed */ -#if defined(CONFIG_SOC_SERIES_STM32F1X) +#if defined(CONFIG_SOC_SERIES_STM32F1X) || defined(CONFIG_SOC_SERIES_STM32L1X) LL_DBGMCU_DisableDBGSleepMode(); LL_DBGMCU_DisableDBGStopMode(); LL_DBGMCU_DisableDBGStandbyMode(); diff --git a/soc/st/stm32/stm32l1x/CMakeLists.txt b/soc/st/stm32/stm32l1x/CMakeLists.txt index 3e033529043..c254da84fb8 100644 --- a/soc/st/stm32/stm32l1x/CMakeLists.txt +++ b/soc/st/stm32/stm32l1x/CMakeLists.txt @@ -1,7 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + zephyr_include_directories(${ZEPHYR_BASE}/drivers) -zephyr_sources( - soc.c - ) +zephyr_sources(soc.c) + +zephyr_sources_ifdef(CONFIG_PM power.c) +zephyr_sources_ifdef(CONFIG_POWEROFF poweroff.c) zephyr_include_directories(.) diff --git a/soc/st/stm32/stm32l1x/Kconfig b/soc/st/stm32/stm32l1x/Kconfig index 656bfcb7329..976b273d689 100644 --- a/soc/st/stm32/stm32l1x/Kconfig +++ b/soc/st/stm32/stm32l1x/Kconfig @@ -7,7 +7,9 @@ config SOC_SERIES_STM32L1X select ARM select CPU_CORTEX_M3 select CPU_CORTEX_M_HAS_DWT + select CPU_HAS_ARM_MPU + select HAS_PM + select HAS_POWEROFF select HAS_STM32CUBE select HAS_SWO - select CPU_HAS_ARM_MPU select SOC_EARLY_INIT_HOOK diff --git a/soc/st/stm32/stm32l1x/Kconfig.defconfig b/soc/st/stm32/stm32l1x/Kconfig.defconfig index e04f33b22dd..1be84e6fba6 100644 --- a/soc/st/stm32/stm32l1x/Kconfig.defconfig +++ b/soc/st/stm32/stm32l1x/Kconfig.defconfig @@ -12,4 +12,11 @@ config TASK_WDT_HW_FALLBACK_DELAY depends on TASK_WDT_HW_FALLBACK default 200 +if PM + +config COUNTER + default y + +endif # PM + endif # SOC_SERIES_STM32L1X diff --git a/soc/st/stm32/stm32l1x/power.c b/soc/st/stm32/stm32l1x/power.c new file mode 100644 index 00000000000..f9aa5196460 --- /dev/null +++ b/soc/st/stm32/stm32l1x/power.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2025 Oleh Kravchenko + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +#include +#include +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +__weak void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + switch (state) { + case PM_STATE_RUNTIME_IDLE: + LL_LPM_DisableEventOnPend(); + LL_PWR_ClearFlag_WU(); + + LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_LOW_POWER); + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP); + LL_LPM_EnableSleep(); + + k_cpu_idle(); + break; + + case PM_STATE_SUSPEND_TO_IDLE: + LL_LPM_DisableEventOnPend(); + LL_PWR_ClearFlag_WU(); + + LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_LOW_POWER); + LL_PWR_SetPowerMode(LL_PWR_MODE_STOP); + LL_LPM_EnableDeepSleep(); + + k_cpu_idle(); + break; + + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +__weak void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_RUNTIME_IDLE: + LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_MAIN); + break; + + case PM_STATE_SUSPEND_TO_IDLE: + LL_LPM_DisableSleepOnExit(); + LL_LPM_EnableSleep(); + LL_PWR_SetRegulModeLP(LL_PWR_REGU_LPMODES_MAIN); + + /* Restore the clock setup. */ + stm32_clock_control_init(NULL); + break; + + default: + LOG_DBG("Unsupported power substate-id %u", state); + break; + } + + /* + * System is now in active mode. Reenable interrupts which were + * disabled when OS started idling code. + */ + irq_unlock(0); +} diff --git a/soc/st/stm32/stm32l1x/poweroff.c b/soc/st/stm32/stm32l1x/poweroff.c new file mode 100644 index 00000000000..be61a9d1252 --- /dev/null +++ b/soc/st/stm32/stm32l1x/poweroff.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Oleh Kravchenko + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include + +void z_sys_poweroff(void) +{ + LL_PWR_ClearFlag_SB(); + LL_PWR_ClearFlag_WU(); + + LL_LPM_DisableEventOnPend(); + LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY); + LL_LPM_EnableDeepSleep(); + + k_cpu_idle(); + + CODE_UNREACHABLE; +}