[PATCH 7/9] watchdog: w83627hf_wdt: Add minute mode counting
From: Paul Louvel
Date: Sat Jul 25 2026 - 06:34:05 EST
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 <paul.louvel@xxxxxxxxxxx>
---
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 fed05fcf82bb..90d41f21aa5e 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;
@@ -477,7 +496,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;
@@ -502,12 +521,29 @@ 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) {
pr_err("failed to initialize watchdog (err=%d)\n", ret);
return ret;
}
+ if (data->early_timer_val) {
+ if (early_disable) {
+ pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
+ ret = wdt_stop(wdd);
+ } else {
+ pr_info("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