If the watchdog hardware is already enabled during the boot process, when the Linux watchdog driver loads, it should reset the watchdog and tell the watchdog framework. As a result, ping can be generated from the watchdog framework (if CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED is set), until the userspace watchdog daemon takes over control Fixes:4332d113c66a ("watchdog: Add STM32 IWDG driver") Signed-off-by: Christophe Roullier <christophe.roullier@xxxxxx> --- drivers/watchdog/stm32_iwdg.c | 57 ++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c index a3a329011a06..2b3be3b1c15b 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -87,8 +87,23 @@ static inline void reg_write(void __iomem *base, u32 reg, u32 val) static int stm32_iwdg_start(struct watchdog_device *wdd) { struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd); - u32 tout, presc, iwdg_rlr, iwdg_pr, iwdg_sr; - int ret; + + dev_dbg(wdd->parent, "%s\n", __func__); + + /* Start the watchdog */ + reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE); + + /* reload watchdog */ + reg_write(wdt->regs, IWDG_KR, KR_KEY_RELOAD); + + set_bit(WDOG_HW_RUNNING, &wdd->status); + return 0; +} + +static int stm32_iwdg_setprescaler(struct watchdog_device *wdd) +{ + struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd); + u32 tout, presc, iwdg_rlr, iwdg_pr; dev_dbg(wdd->parent, "%s\n", __func__); @@ -108,19 +123,6 @@ static int stm32_iwdg_start(struct watchdog_device *wdd) /* set prescaler & reload registers */ reg_write(wdt->regs, IWDG_PR, iwdg_pr); reg_write(wdt->regs, IWDG_RLR, iwdg_rlr); - reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE); - - /* wait for the registers to be updated (max 100ms) */ - ret = readl_relaxed_poll_timeout(wdt->regs + IWDG_SR, iwdg_sr, - !(iwdg_sr & (SR_PVU | SR_RVU)), - SLEEP_US, TIMEOUT_US); - if (ret) { - dev_err(wdd->parent, "Fail to set prescaler, reload regs\n"); - return ret; - } - - /* reload watchdog */ - reg_write(wdt->regs, IWDG_KR, KR_KEY_RELOAD); return 0; } @@ -131,6 +133,9 @@ static int stm32_iwdg_ping(struct watchdog_device *wdd) dev_dbg(wdd->parent, "%s\n", __func__); + /* Start the watchdog */ + reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE); + /* reload watchdog */ reg_write(wdt->regs, IWDG_KR, KR_KEY_RELOAD); @@ -140,12 +145,21 @@ static int stm32_iwdg_ping(struct watchdog_device *wdd) static int stm32_iwdg_set_timeout(struct watchdog_device *wdd, unsigned int timeout) { + int ret; + dev_dbg(wdd->parent, "%s timeout: %d sec\n", __func__, timeout); wdd->timeout = timeout; - if (watchdog_active(wdd)) - return stm32_iwdg_start(wdd); + if (watchdog_active(wdd)) { + ret = stm32_iwdg_setprescaler(wdd); + if (ret) { + dev_err(wdd->parent, "failed to set prescaler\n"); + return ret; + } else { + return stm32_iwdg_start(wdd); + } + } return 0; } @@ -262,12 +276,21 @@ static int stm32_iwdg_probe(struct platform_device *pdev) watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT); watchdog_init_timeout(wdd, 0, dev); + /* Make sure the watchdog is serviced */ + set_bit(WDOG_HW_RUNNING, &wdd->status); + ret = devm_watchdog_register_device(dev, wdd); if (ret) return ret; platform_set_drvdata(pdev, wdt); + ret = stm32_iwdg_setprescaler(wdd); + if (ret) { + dev_err(dev, "failed to set prescaler\n"); + return ret; + } + return 0; } -- 2.17.1