[PATCH v2 7/8] watchdog: w83627hf_wdt: Add minute mode counting
Paul Louvel <[email protected]> Sun, 26 Jul 2026 20:44:34 +0200
| Newsgroups | org.kernel.vger.linux-watchdog,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
All of the chips supported by the driver can be set to minute mode, allowing timeout value up to 255 minutes. Add it to the driver. Signed-off-by: Paul Louvel <[email protected]> --- drivers/watchdog/w83627hf_wdt.c | 70 +++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 064a99db80ef..2957364485eb 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -40,6 +40,7 @@ #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ +#define WATCHDOG_MAX_TIMEOUT (255 * 60) enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, @@ -49,7 +50,8 @@ enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, static int timeout; /* in seconds */ module_param(timeout, int, 0); MODULE_PARM_DESC(timeout, - "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" + "Watchdog timeout in seconds. 1 <= timeout <= " + __MODULE_STRING(WATCHDOG_MAX_TIMEOUT) ", default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); static bool nowayout = WATCHDOG_NOWAYOUT; @@ -134,6 +136,9 @@ struct w83627hf_data { int sioaddr; int siocfg_enter; int siocfg_leave; + bool minute_mode; + u8 early_timer_val; + u8 timer_val; }; static void superio_outb(int base, int reg, int val) @@ -253,22 +258,11 @@ static int w83627hf_init(struct watchdog_device *wdog, enum chips chip) break; } - t = superio_inb(data->sioaddr, data->reg.timeout); - if (t != 0) { - if (early_disable) { - pr_warn("Stopping previously enabled watchdog until userland kicks in\n"); - superio_outb(data->sioaddr, data->reg.timeout, 0); - } else { - pr_info("Watchdog already running. Resetting timeout to %d sec\n", - wdog->timeout); - superio_outb(data->sioaddr, data->reg.timeout, wdog->timeout); - set_bit(WDOG_HW_RUNNING, &wdog->status); - } - } + data->early_timer_val = superio_inb(data->sioaddr, data->reg.timeout); - /* set second mode & disable keyboard reset turning off watchdog */ + /* disable keyboard reset turning off watchdog */ t = superio_inb(data->sioaddr, data->reg.control) & - ~(WDT_CTRL_MINUTE_MODE | WDT_CTRL_RISING_EDGE_KBD_RESET); + ~WDT_CTRL_RISING_EDGE_KBD_RESET; superio_outb(data->sioaddr, data->reg.control, t); t = superio_inb(data->sioaddr, data->reg.csr); @@ -287,6 +281,7 @@ static int w83627hf_init(struct watchdog_device *wdog, enum chips chip) static int wdt_set_time(struct watchdog_device *wdog, unsigned int timeout) { struct w83627hf_data *data = watchdog_get_drvdata(wdog); + unsigned char ctrl; int ret; ret = superio_enter(data->sioaddr, data->siocfg_enter); @@ -294,6 +289,15 @@ static int wdt_set_time(struct watchdog_device *wdog, unsigned int timeout) return ret; superio_select(data->sioaddr, W83627HF_LD_WDT); + + ctrl = superio_inb(data->sioaddr, data->reg.control); + + if (data->minute_mode) + ctrl |= WDT_CTRL_MINUTE_MODE; + else + ctrl &= ~WDT_CTRL_MINUTE_MODE; + + superio_outb(data->sioaddr, data->reg.control, ctrl); superio_outb(data->sioaddr, data->reg.timeout, timeout); superio_exit(data->sioaddr, data->siocfg_leave); @@ -302,7 +306,9 @@ static int wdt_set_time(struct watchdog_device *wdog, unsigned int timeout) static int wdt_start(struct watchdog_device *wdog) { - return wdt_set_time(wdog, wdog->timeout); + struct w83627hf_data *data = watchdog_get_drvdata(wdog); + + return wdt_set_time(wdog, data->timer_val); } static int wdt_stop(struct watchdog_device *wdog) @@ -312,6 +318,17 @@ static int wdt_stop(struct watchdog_device *wdog) static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout) { + struct w83627hf_data *data = watchdog_get_drvdata(wdog); + + if (timeout > 255) { + data->minute_mode = true; + data->timer_val = DIV_ROUND_UP(timeout, 60); + timeout = data->timer_val * 60; + } else { + data->minute_mode = false; + data->timer_val = timeout; + } + wdog->timeout = timeout; return 0; @@ -329,6 +346,8 @@ static unsigned int wdt_get_time(struct watchdog_device *wdog) superio_select(data->sioaddr, W83627HF_LD_WDT); timeleft = superio_inb(data->sioaddr, data->reg.timeout); + if (data->minute_mode) + timeleft *= 60; superio_exit(data->sioaddr, data->siocfg_leave); return timeleft; @@ -478,7 +497,7 @@ static int wdt_probe(struct platform_device *pdev) wdd->ops = &wdt_ops; wdd->timeout = WATCHDOG_TIMEOUT; wdd->min_timeout = 1; - wdd->max_timeout = 255; + wdd->max_timeout = WATCHDOG_MAX_TIMEOUT; data->sioaddr = res->start; data->siocfg_enter = pdata->siocfg_enter; @@ -503,10 +522,27 @@ static int wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(wdd, nowayout); watchdog_stop_on_reboot(wdd); + wdt_set_timeout(wdd, wdd->timeout); + ret = w83627hf_init(wdd, chip); if (ret) return dev_err_probe(dev, ret, "failed to initialize watchdog\n"); + if (data->early_timer_val) { + if (early_disable) { + dev_warn(dev, "Stopping previously enabled watchdog until userland kicks in\n"); + ret = wdt_stop(wdd); + } else { + dev_info(dev, "Watchdog already running. Resetting timeout to %d sec\n", + wdd->timeout); + ret = wdt_start(wdd); + set_bit(WDOG_HW_RUNNING, &wdd->status); + } + + if (ret) + return ret; + } + ret = devm_watchdog_register_device(&pdev->dev, wdd); if (ret) return ret; -- 2.55.0