From d0639fedcfa4a2db7973132be16178c5abc9ee23 Mon Sep 17 00:00:00 2001 From: Mathieu Choplain Date: Wed, 8 Jan 2025 11:24:06 +0100 Subject: [PATCH] drivers: watchdog: iwdg_stm32: add support for STM32WB0 Add support for the STM32WB0 series to the existing STM32 driver for Independent Watchdog peripheral. NOTE: this commit only includes basic support for the watchdog. STM32WB0 specificities such as the different possible clock sources, LSI frequency measurement or window support are left for future implementation. Signed-off-by: Mathieu Choplain --- drivers/watchdog/wdt_iwdg_stm32.c | 47 +++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/wdt_iwdg_stm32.c b/drivers/watchdog/wdt_iwdg_stm32.c index f472d03eb48..682963b1070 100644 --- a/drivers/watchdog/wdt_iwdg_stm32.c +++ b/drivers/watchdog/wdt_iwdg_stm32.c @@ -10,10 +10,12 @@ #define DT_DRV_COMPAT st_stm32_watchdog #include +#include #include #include #include #include +#include #include #include #include @@ -90,14 +92,16 @@ static int iwdg_stm32_setup(const struct device *dev, uint8_t options) /* Deactivate running when debugger is attached. */ if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { -#if defined(CONFIG_SOC_SERIES_STM32F0X) +#if defined(CONFIG_SOC_SERIES_STM32WB0X) + /* STM32WB0 watchdog does not support halt by debugger */ + return -ENOTSUP; +#elif defined(CONFIG_SOC_SERIES_STM32F0X) LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_DBGMCU); #elif defined(CONFIG_SOC_SERIES_STM32C0X) || defined(CONFIG_SOC_SERIES_STM32G0X) LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_DBGMCU); #elif defined(CONFIG_SOC_SERIES_STM32L0X) LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_DBGMCU); -#endif -#if defined(CONFIG_SOC_SERIES_STM32H7X) +#elif defined(CONFIG_SOC_SERIES_STM32H7X) LL_DBGMCU_APB4_GRP1_FreezePeriph(LL_DBGMCU_APB4_GRP1_IWDG1_STOP); #elif defined(CONFIG_SOC_SERIES_STM32H7RSX) LL_DBGMCU_APB4_GRP1_FreezePeriph(LL_DBGMCU_APB4_GRP1_IWDG_STOP); @@ -192,6 +196,43 @@ static DEVICE_API(wdt, iwdg_stm32_api) = { static int iwdg_stm32_init(const struct device *dev) { +/* Enable watchdog clock if needed */ +#if DT_INST_NODE_HAS_PROP(0, clocks) + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); + const struct stm32_pclken clk_cfg = STM32_CLOCK_INFO(0, DT_DRV_INST(0)); + int err = clock_control_on(clk, (clock_control_subsys_t)&clk_cfg); + + if (err < 0) { + return err; + } +#if defined(CONFIG_SOC_SERIES_STM32WB0X) + /** + * On STM32WB0, application must wait two slow clock cycles + * before accessing the IWDG IP after turning on the WDGEN + * bit in RCC registers. However, there is no register that + * can be polled for this event. + * To work around this limitation, force the IWDG to go + * through a reset cycle, which also takes two slow clock + * cycles, but can polled on (bit WDGRSTF of RCC_CIFR). + */ + + /* Clear bit beforehand to avoid early exit of polling loop */ + LL_RCC_ClearFlag_WDGRSTREL(); + + /* Place IWDG under reset, then release the reset */ + LL_APB0_GRP1_ForceReset(LL_APB0_GRP1_PERIPH_WDG); + LL_APB0_GRP1_ReleaseReset(LL_APB0_GRP1_PERIPH_WDG); + while (!LL_RCC_IsActiveFlag_WDGRSTREL()) { + /* Wait for IWDG reset release event, + * which takes two slow clock cycles + */ + } + + /* Clear WDRSTF bit after polling completes */ + LL_RCC_ClearFlag_WDGRSTREL(); +#endif /* defined(CONFIG_SOC_SERIES_STM32WB0X) */ +#endif /* DT_INST_NODE_HAS_PROP(0, clocks) */ + #ifndef CONFIG_WDT_DISABLE_AT_BOOT struct wdt_timeout_cfg config = { .window.max = CONFIG_IWDG_STM32_INITIAL_TIMEOUT