From 6df434068c1c14a1bcb2f185b8650dfaacb0a970 Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Wed, 6 May 2026 20:23:31 -0400 Subject: [PATCH] drivers: watchdog: stm32: add IWDG standby mode configuration Add Kconfig choice to control the IWDG_STDBY option byte, allowing users to configure whether the independent watchdog runs or is frozen during standby mode. Uses the public flash_ex_op API to read/write option bytes at APPLICATION init level (flash device must be ready). Three options: - No change (default): leave option byte as-is, no extra code - Freeze: clear IWDG_STDBY so IWDG is frozen in standby - Active: set IWDG_STDBY so IWDG continues running in standby The write triggers OBL_LAUNCH (system reset) only when the option byte differs from the desired value. On subsequent boots, no write occurs. Signed-off-by: Jon Ringle --- drivers/watchdog/Kconfig.stm32 | 33 +++++++++++++++++++++++++++ drivers/watchdog/wdt_iwdg_stm32.c | 37 +++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/drivers/watchdog/Kconfig.stm32 b/drivers/watchdog/Kconfig.stm32 index 35ad0e4b9c224..cba1b9263d914 100644 --- a/drivers/watchdog/Kconfig.stm32 +++ b/drivers/watchdog/Kconfig.stm32 @@ -14,6 +14,39 @@ menuconfig IWDG_STM32 help Enable IWDG driver for STM32 line of MCUs +choice IWDG_STM32_STANDBY + prompt "IWDG behavior in standby mode" + depends on IWDG_STM32 + default IWDG_STM32_STANDBY_NO_CHANGE + help + Configure whether the IWDG runs during standby mode. + This modifies the IWDG_STDBY option byte if needed. + Selecting "no change" leaves the option byte as-is. + +config IWDG_STM32_STANDBY_NO_CHANGE + bool "No change" + help + Do not modify the IWDG_STDBY option byte. + +config IWDG_STM32_STANDBY_FREEZE + bool "Freeze IWDG in standby" + select FLASH_STM32_OPTION_BYTES + select FLASH_EX_OP_ENABLED + help + Clear the IWDG_STDBY option byte so the IWDG is frozen + during standby mode. Prevents spurious watchdog resets + when the system enters low-power standby. + +config IWDG_STM32_STANDBY_ACTIVE + bool "IWDG active in standby" + select FLASH_STM32_OPTION_BYTES + select FLASH_EX_OP_ENABLED + help + Set the IWDG_STDBY option byte so the IWDG continues + running during standby mode. + +endchoice + config IWDG_STM32_INITIAL_TIMEOUT int "Value for IWDG timeout in ms" depends on IWDG_STM32 diff --git a/drivers/watchdog/wdt_iwdg_stm32.c b/drivers/watchdog/wdt_iwdg_stm32.c index 95dec9ad412c6..8caa69f280953 100644 --- a/drivers/watchdog/wdt_iwdg_stm32.c +++ b/drivers/watchdog/wdt_iwdg_stm32.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,11 @@ #include #include +#if defined(CONFIG_IWDG_STM32_STANDBY_FREEZE) || defined(CONFIG_IWDG_STM32_STANDBY_ACTIVE) +#include +#include +#endif + #include "wdt_iwdg_stm32.h" #define IWDG_PRESCALER_MIN (4U) @@ -266,3 +272,34 @@ DEVICE_DT_INST_DEFINE(0, iwdg_stm32_init, NULL, &iwdg_stm32_dev_data, &iwdg_stm32_dev_cfg, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &iwdg_stm32_api); + +#if defined(CONFIG_IWDG_STM32_STANDBY_FREEZE) || defined(CONFIG_IWDG_STM32_STANDBY_ACTIVE) +static int iwdg_stm32_configure_standby(void) +{ + const struct device *flash_dev = + DEVICE_DT_GET(DT_CHOSEN(zephyr_flash_controller)); + uint32_t optr; + int rc; + + rc = flash_ex_op(flash_dev, FLASH_STM32_EX_OP_OPTB_READ, 0, &optr); + if (rc < 0) { + return rc; + } + + if (IS_ENABLED(CONFIG_IWDG_STM32_STANDBY_FREEZE) && + (optr & FLASH_OPTR_IWDG_STDBY)) { + optr &= ~FLASH_OPTR_IWDG_STDBY; + rc = flash_ex_op(flash_dev, FLASH_STM32_EX_OP_OPTB_WRITE, + (uintptr_t)optr, NULL); + } else if (IS_ENABLED(CONFIG_IWDG_STM32_STANDBY_ACTIVE) && + !(optr & FLASH_OPTR_IWDG_STDBY)) { + optr |= FLASH_OPTR_IWDG_STDBY; + rc = flash_ex_op(flash_dev, FLASH_STM32_EX_OP_OPTB_WRITE, + (uintptr_t)optr, NULL); + } + + return rc; +} + +SYS_INIT(iwdg_stm32_configure_standby, APPLICATION, 0); +#endif /* CONFIG_IWDG_STM32_STANDBY_FREEZE || CONFIG_IWDG_STM32_STANDBY_ACTIVE */