23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
25 #include <linux/module.h>
29 #include <linux/watchdog.h>
31 #include <linux/reboot.h>
39 #define NAME "it8712f_wdt"
46 static int max_units = 255;
47 static int margin = 60;
55 static unsigned long wdt_open;
71 #define IT8712F_DEVID 0x8712
76 #define WDT_CONTROL 0x71
77 #define WDT_CONFIG 0x72
78 #define WDT_TIMEOUT 0x73
80 #define WDT_RESET_GAME 0x10
81 #define WDT_RESET_KBD 0x20
82 #define WDT_RESET_MOUSE 0x40
83 #define WDT_RESET_CIR 0x80
85 #define WDT_UNIT_SEC 0x80
87 #define WDT_OUT_PWROK 0x10
88 #define WDT_OUT_KRST 0x40
93 "register. The default WDT_RESET_GAME resets the timer on "
94 "game port reads that this driver generates. You can also "
95 "use KBD, MOUSE or CIR if you have some external way to "
96 "generate those interrupts.");
98 static int superio_inb(
int reg)
104 static void superio_outb(
int val,
int reg)
110 static int superio_inw(
int reg)
126 static inline int superio_enter(
void)
141 static inline void superio_exit(
void)
148 static inline void it8712f_wdt_ping(
void)
154 static void it8712f_wdt_update_margin(
void)
162 if (units <= max_units) {
164 pr_info(
"timer margin %d seconds\n", units);
167 pr_info(
"timer margin %d minutes\n", units);
176 static int it8712f_wdt_get_status(
void)
184 static int it8712f_wdt_enable(
void)
186 int ret = superio_enter();
190 pr_debug(
"enabling watchdog timer\n");
195 it8712f_wdt_update_margin();
204 static int it8712f_wdt_disable(
void)
206 int ret = superio_enter();
210 pr_debug(
"disabling watchdog timer\n");
228 it8712f_wdt_disable();
234 .notifier_call = it8712f_wdt_notify,
238 size_t len, loff_t *ppos)
247 for (i = 0; i < len; ++
i) {
259 static long it8712f_wdt_ioctl(
struct file *file,
unsigned int cmd,
265 .identity =
"IT8712F Watchdog",
266 .firmware_version = 1,
279 ret = superio_enter();
284 value = it8712f_wdt_get_status();
299 if (value > (max_units * 60))
302 ret = superio_enter();
307 it8712f_wdt_update_margin();
321 static int it8712f_wdt_open(
struct inode *
inode,
struct file *file)
328 ret = it8712f_wdt_enable();
334 static int it8712f_wdt_release(
struct inode *inode,
struct file *file)
336 if (expect_close != 42) {
337 pr_warn(
"watchdog device closed unexpectedly, will not disable the watchdog timer\n");
338 }
else if (!nowayout) {
339 if (it8712f_wdt_disable())
340 pr_warn(
"Watchdog disable failed\n");
351 .write = it8712f_wdt_write,
352 .unlocked_ioctl = it8712f_wdt_ioctl,
353 .open = it8712f_wdt_open,
354 .release = it8712f_wdt_release,
357 static struct miscdevice it8712f_wdt_miscdev = {
360 .fops = &it8712f_wdt_fops,
367 int ret = superio_enter();
371 chip_type = superio_inw(
DEVID);
377 if (!(superio_inb(
ACT_REG) & 0x01)) {
378 pr_err(
"Device not activated, skipping\n");
384 pr_err(
"Base address not set, skipping\n");
395 if (margin > (max_units * 60))
396 margin = (max_units * 60);
398 pr_info(
"Found IT%04xF chip revision %d - using DogFood address 0x%x\n",
406 static int __init it8712f_wdt_init(
void)
410 if (it8712f_wdt_find(&address))
414 pr_warn(
"watchdog I/O region busy\n");
418 err = it8712f_wdt_disable();
420 pr_err(
"unable to disable watchdog timer\n");
426 pr_err(
"unable to register reboot notifier\n");
432 pr_err(
"cannot register miscdev on minor=%d (err=%d)\n",
447 static void __exit it8712f_wdt_exit(
void)