|
10 | 10 | #define DT_DRV_COMPAT st_stm32_watchdog
|
11 | 11 |
|
12 | 12 | #include <zephyr/drivers/watchdog.h>
|
| 13 | +#include <zephyr/drivers/clock_control/stm32_clock_control.h> |
13 | 14 | #include <zephyr/kernel.h>
|
14 | 15 | #include <zephyr/sys_clock.h>
|
15 | 16 | #include <soc.h>
|
16 | 17 | #include <stm32_ll_bus.h>
|
| 18 | +#include <stm32_ll_rcc.h> |
17 | 19 | #include <stm32_ll_iwdg.h>
|
18 | 20 | #include <stm32_ll_system.h>
|
19 | 21 | #include <errno.h>
|
@@ -90,14 +92,16 @@ static int iwdg_stm32_setup(const struct device *dev, uint8_t options)
|
90 | 92 |
|
91 | 93 | /* Deactivate running when debugger is attached. */
|
92 | 94 | if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) {
|
93 |
| -#if defined(CONFIG_SOC_SERIES_STM32F0X) |
| 95 | +#if defined(CONFIG_SOC_SERIES_STM32WB0X) |
| 96 | + /* STM32WB0 watchdog does not support halt by debugger */ |
| 97 | + return -ENOTSUP; |
| 98 | +#elif defined(CONFIG_SOC_SERIES_STM32F0X) |
94 | 99 | LL_APB1_GRP2_EnableClock(LL_APB1_GRP2_PERIPH_DBGMCU);
|
95 | 100 | #elif defined(CONFIG_SOC_SERIES_STM32C0X) || defined(CONFIG_SOC_SERIES_STM32G0X)
|
96 | 101 | LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_DBGMCU);
|
97 | 102 | #elif defined(CONFIG_SOC_SERIES_STM32L0X)
|
98 | 103 | LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_DBGMCU);
|
99 |
| -#endif |
100 |
| -#if defined(CONFIG_SOC_SERIES_STM32H7X) |
| 104 | +#elif defined(CONFIG_SOC_SERIES_STM32H7X) |
101 | 105 | LL_DBGMCU_APB4_GRP1_FreezePeriph(LL_DBGMCU_APB4_GRP1_IWDG1_STOP);
|
102 | 106 | #elif defined(CONFIG_SOC_SERIES_STM32H7RSX)
|
103 | 107 | LL_DBGMCU_APB4_GRP1_FreezePeriph(LL_DBGMCU_APB4_GRP1_IWDG_STOP);
|
@@ -192,6 +196,43 @@ static DEVICE_API(wdt, iwdg_stm32_api) = {
|
192 | 196 |
|
193 | 197 | static int iwdg_stm32_init(const struct device *dev)
|
194 | 198 | {
|
| 199 | +/* Enable watchdog clock if needed */ |
| 200 | +#if DT_INST_NODE_HAS_PROP(0, clocks) |
| 201 | + const struct device *const clk = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); |
| 202 | + const struct stm32_pclken clk_cfg = STM32_CLOCK_INFO(0, DT_DRV_INST(0)); |
| 203 | + int err = clock_control_on(clk, (clock_control_subsys_t)&clk_cfg); |
| 204 | + |
| 205 | + if (err < 0) { |
| 206 | + return err; |
| 207 | + } |
| 208 | +#if defined(CONFIG_SOC_SERIES_STM32WB0X) |
| 209 | + /** |
| 210 | + * On STM32WB0, application must wait two slow clock cycles |
| 211 | + * before accessing the IWDG IP after turning on the WDGEN |
| 212 | + * bit in RCC registers. However, there is no register that |
| 213 | + * can be polled for this event. |
| 214 | + * To work around this limitation, force the IWDG to go |
| 215 | + * through a reset cycle, which also takes two slow clock |
| 216 | + * cycles, but can polled on (bit WDGRSTF of RCC_CIFR). |
| 217 | + */ |
| 218 | + |
| 219 | + /* Clear bit beforehand to avoid early exit of polling loop */ |
| 220 | + LL_RCC_ClearFlag_WDGRSTREL(); |
| 221 | + |
| 222 | + /* Place IWDG under reset, then release the reset */ |
| 223 | + LL_APB0_GRP1_ForceReset(LL_APB0_GRP1_PERIPH_WDG); |
| 224 | + LL_APB0_GRP1_ReleaseReset(LL_APB0_GRP1_PERIPH_WDG); |
| 225 | + while (!LL_RCC_IsActiveFlag_WDGRSTREL()) { |
| 226 | + /* Wait for IWDG reset release event, |
| 227 | + * which takes two slow clock cycles |
| 228 | + */ |
| 229 | + } |
| 230 | + |
| 231 | + /* Clear WDRSTF bit after polling completes */ |
| 232 | + LL_RCC_ClearFlag_WDGRSTREL(); |
| 233 | +#endif /* defined(CONFIG_SOC_SERIES_STM32WB0X) */ |
| 234 | +#endif /* DT_INST_NODE_HAS_PROP(0, clocks) */ |
| 235 | + |
195 | 236 | #ifndef CONFIG_WDT_DISABLE_AT_BOOT
|
196 | 237 | struct wdt_timeout_cfg config = {
|
197 | 238 | .window.max = CONFIG_IWDG_STM32_INITIAL_TIMEOUT
|
|
0 commit comments