diff options
Diffstat (limited to 'drivers/watchdog/it87_wdt.c')
-rw-r--r-- | drivers/watchdog/it87_wdt.c | 96 |
1 files changed, 68 insertions, 28 deletions
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index b709b3b2d1ef..dad29245a6a7 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c | |||
@@ -12,7 +12,7 @@ | |||
12 | * http://www.ite.com.tw/ | 12 | * http://www.ite.com.tw/ |
13 | * | 13 | * |
14 | * Support of the watchdog timers, which are available on | 14 | * Support of the watchdog timers, which are available on |
15 | * IT8716, IT8718, IT8726 and IT8712 (J,K version). | 15 | * IT8702, IT8712, IT8716, IT8718, IT8720 and IT8726. |
16 | * | 16 | * |
17 | * This program is free software; you can redistribute it and/or | 17 | * This program is free software; you can redistribute it and/or |
18 | * modify it under the terms of the GNU General Public License | 18 | * modify it under the terms of the GNU General Public License |
@@ -45,7 +45,7 @@ | |||
45 | 45 | ||
46 | #include <asm/system.h> | 46 | #include <asm/system.h> |
47 | 47 | ||
48 | #define WATCHDOG_VERSION "1.12" | 48 | #define WATCHDOG_VERSION "1.13" |
49 | #define WATCHDOG_NAME "IT87 WDT" | 49 | #define WATCHDOG_NAME "IT87 WDT" |
50 | #define PFX WATCHDOG_NAME ": " | 50 | #define PFX WATCHDOG_NAME ": " |
51 | #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" | 51 | #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" |
@@ -76,10 +76,12 @@ | |||
76 | 76 | ||
77 | /* Chip Id numbers */ | 77 | /* Chip Id numbers */ |
78 | #define NO_DEV_ID 0xffff | 78 | #define NO_DEV_ID 0xffff |
79 | #define IT8702_ID 0x8702 | ||
79 | #define IT8705_ID 0x8705 | 80 | #define IT8705_ID 0x8705 |
80 | #define IT8712_ID 0x8712 | 81 | #define IT8712_ID 0x8712 |
81 | #define IT8716_ID 0x8716 | 82 | #define IT8716_ID 0x8716 |
82 | #define IT8718_ID 0x8718 | 83 | #define IT8718_ID 0x8718 |
84 | #define IT8720_ID 0x8720 | ||
83 | #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ | 85 | #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ |
84 | 86 | ||
85 | /* GPIO Configuration Registers LDN=0x07 */ | 87 | /* GPIO Configuration Registers LDN=0x07 */ |
@@ -92,7 +94,7 @@ | |||
92 | #define WDT_CIRINT 0x80 | 94 | #define WDT_CIRINT 0x80 |
93 | #define WDT_MOUSEINT 0x40 | 95 | #define WDT_MOUSEINT 0x40 |
94 | #define WDT_KYBINT 0x20 | 96 | #define WDT_KYBINT 0x20 |
95 | #define WDT_GAMEPORT 0x10 /* not it8718 */ | 97 | #define WDT_GAMEPORT 0x10 /* not in it8718, it8720 */ |
96 | #define WDT_FORCE 0x02 | 98 | #define WDT_FORCE 0x02 |
97 | #define WDT_ZERO 0x01 | 99 | #define WDT_ZERO 0x01 |
98 | 100 | ||
@@ -132,7 +134,7 @@ | |||
132 | #define WDTS_USE_GP 4 | 134 | #define WDTS_USE_GP 4 |
133 | #define WDTS_EXPECTED 5 | 135 | #define WDTS_EXPECTED 5 |
134 | 136 | ||
135 | static unsigned int base, gpact, ciract; | 137 | static unsigned int base, gpact, ciract, max_units; |
136 | static unsigned long wdt_status; | 138 | static unsigned long wdt_status; |
137 | static DEFINE_SPINLOCK(spinlock); | 139 | static DEFINE_SPINLOCK(spinlock); |
138 | 140 | ||
@@ -210,6 +212,33 @@ static inline void superio_outw(int val, int reg) | |||
210 | outb(val, VAL); | 212 | outb(val, VAL); |
211 | } | 213 | } |
212 | 214 | ||
215 | /* Internal function, should be called after superio_select(GPIO) */ | ||
216 | static void wdt_update_timeout(void) | ||
217 | { | ||
218 | unsigned char cfg = WDT_KRST | WDT_PWROK; | ||
219 | int tm = timeout; | ||
220 | |||
221 | if (testmode) | ||
222 | cfg = 0; | ||
223 | |||
224 | if (tm <= max_units) | ||
225 | cfg |= WDT_TOV1; | ||
226 | else | ||
227 | tm /= 60; | ||
228 | |||
229 | superio_outb(cfg, WDTCFG); | ||
230 | superio_outb(tm, WDTVALLSB); | ||
231 | if (max_units > 255) | ||
232 | superio_outb(tm>>8, WDTVALMSB); | ||
233 | } | ||
234 | |||
235 | static int wdt_round_time(int t) | ||
236 | { | ||
237 | t += 59; | ||
238 | t -= t % 60; | ||
239 | return t; | ||
240 | } | ||
241 | |||
213 | /* watchdog timer handling */ | 242 | /* watchdog timer handling */ |
214 | 243 | ||
215 | static void wdt_keepalive(void) | 244 | static void wdt_keepalive(void) |
@@ -234,12 +263,7 @@ static void wdt_start(void) | |||
234 | superio_outb(WDT_GAMEPORT, WDTCTRL); | 263 | superio_outb(WDT_GAMEPORT, WDTCTRL); |
235 | else | 264 | else |
236 | superio_outb(WDT_CIRINT, WDTCTRL); | 265 | superio_outb(WDT_CIRINT, WDTCTRL); |
237 | if (!testmode) | 266 | wdt_update_timeout(); |
238 | superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG); | ||
239 | else | ||
240 | superio_outb(WDT_TOV1, WDTCFG); | ||
241 | superio_outb(timeout>>8, WDTVALMSB); | ||
242 | superio_outb(timeout, WDTVALLSB); | ||
243 | 267 | ||
244 | superio_exit(); | 268 | superio_exit(); |
245 | spin_unlock_irqrestore(&spinlock, flags); | 269 | spin_unlock_irqrestore(&spinlock, flags); |
@@ -255,8 +279,9 @@ static void wdt_stop(void) | |||
255 | superio_select(GPIO); | 279 | superio_select(GPIO); |
256 | superio_outb(0x00, WDTCTRL); | 280 | superio_outb(0x00, WDTCTRL); |
257 | superio_outb(WDT_TOV1, WDTCFG); | 281 | superio_outb(WDT_TOV1, WDTCFG); |
258 | superio_outb(0x00, WDTVALMSB); | ||
259 | superio_outb(0x00, WDTVALLSB); | 282 | superio_outb(0x00, WDTVALLSB); |
283 | if (max_units > 255) | ||
284 | superio_outb(0x00, WDTVALMSB); | ||
260 | 285 | ||
261 | superio_exit(); | 286 | superio_exit(); |
262 | spin_unlock_irqrestore(&spinlock, flags); | 287 | spin_unlock_irqrestore(&spinlock, flags); |
@@ -266,8 +291,8 @@ static void wdt_stop(void) | |||
266 | * wdt_set_timeout - set a new timeout value with watchdog ioctl | 291 | * wdt_set_timeout - set a new timeout value with watchdog ioctl |
267 | * @t: timeout value in seconds | 292 | * @t: timeout value in seconds |
268 | * | 293 | * |
269 | * The hardware device has a 16 bit watchdog timer, thus the | 294 | * The hardware device has a 8 or 16 bit watchdog timer (depends on |
270 | * timeout time ranges between 1 and 65535 seconds. | 295 | * chip version) that can be configured to count seconds or minutes. |
271 | * | 296 | * |
272 | * Used within WDIOC_SETTIMEOUT watchdog device ioctl. | 297 | * Used within WDIOC_SETTIMEOUT watchdog device ioctl. |
273 | */ | 298 | */ |
@@ -276,19 +301,19 @@ static int wdt_set_timeout(int t) | |||
276 | { | 301 | { |
277 | unsigned long flags; | 302 | unsigned long flags; |
278 | 303 | ||
279 | if (t < 1 || t > 65535) | 304 | if (t < 1 || t > max_units * 60) |
280 | return -EINVAL; | 305 | return -EINVAL; |
281 | 306 | ||
282 | timeout = t; | 307 | if (t > max_units) |
308 | timeout = wdt_round_time(t); | ||
309 | else | ||
310 | timeout = t; | ||
283 | 311 | ||
284 | spin_lock_irqsave(&spinlock, flags); | 312 | spin_lock_irqsave(&spinlock, flags); |
285 | if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { | 313 | if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { |
286 | superio_enter(); | 314 | superio_enter(); |
287 | |||
288 | superio_select(GPIO); | 315 | superio_select(GPIO); |
289 | superio_outb(t>>8, WDTVALMSB); | 316 | wdt_update_timeout(); |
290 | superio_outb(t, WDTVALLSB); | ||
291 | |||
292 | superio_exit(); | 317 | superio_exit(); |
293 | } | 318 | } |
294 | spin_unlock_irqrestore(&spinlock, flags); | 319 | spin_unlock_irqrestore(&spinlock, flags); |
@@ -529,10 +554,13 @@ static struct notifier_block wdt_notifier = { | |||
529 | static int __init it87_wdt_init(void) | 554 | static int __init it87_wdt_init(void) |
530 | { | 555 | { |
531 | int rc = 0; | 556 | int rc = 0; |
557 | int try_gameport = !nogameport; | ||
532 | u16 chip_type; | 558 | u16 chip_type; |
533 | u8 chip_rev; | 559 | u8 chip_rev; |
534 | unsigned long flags; | 560 | unsigned long flags; |
535 | 561 | ||
562 | wdt_status = 0; | ||
563 | |||
536 | spin_lock_irqsave(&spinlock, flags); | 564 | spin_lock_irqsave(&spinlock, flags); |
537 | superio_enter(); | 565 | superio_enter(); |
538 | chip_type = superio_inw(CHIPID); | 566 | chip_type = superio_inw(CHIPID); |
@@ -541,13 +569,21 @@ static int __init it87_wdt_init(void) | |||
541 | spin_unlock_irqrestore(&spinlock, flags); | 569 | spin_unlock_irqrestore(&spinlock, flags); |
542 | 570 | ||
543 | switch (chip_type) { | 571 | switch (chip_type) { |
572 | case IT8702_ID: | ||
573 | max_units = 255; | ||
574 | break; | ||
575 | case IT8712_ID: | ||
576 | max_units = (chip_rev < 8) ? 255 : 65535; | ||
577 | break; | ||
544 | case IT8716_ID: | 578 | case IT8716_ID: |
545 | case IT8718_ID: | ||
546 | case IT8726_ID: | 579 | case IT8726_ID: |
580 | max_units = 65535; | ||
581 | break; | ||
582 | case IT8718_ID: | ||
583 | case IT8720_ID: | ||
584 | max_units = 65535; | ||
585 | try_gameport = 0; | ||
547 | break; | 586 | break; |
548 | case IT8712_ID: | ||
549 | if (chip_rev > 7) | ||
550 | break; | ||
551 | case IT8705_ID: | 587 | case IT8705_ID: |
552 | printk(KERN_ERR PFX | 588 | printk(KERN_ERR PFX |
553 | "Unsupported Chip found, Chip %04x Revision %02x\n", | 589 | "Unsupported Chip found, Chip %04x Revision %02x\n", |
@@ -571,7 +607,7 @@ static int __init it87_wdt_init(void) | |||
571 | superio_outb(0x00, WDTCTRL); | 607 | superio_outb(0x00, WDTCTRL); |
572 | 608 | ||
573 | /* First try to get Gameport support */ | 609 | /* First try to get Gameport support */ |
574 | if (chip_type != IT8718_ID && !nogameport) { | 610 | if (try_gameport) { |
575 | superio_select(GAMEPORT); | 611 | superio_select(GAMEPORT); |
576 | base = superio_inw(BASEREG); | 612 | base = superio_inw(BASEREG); |
577 | if (!base) { | 613 | if (!base) { |
@@ -623,13 +659,16 @@ static int __init it87_wdt_init(void) | |||
623 | spin_unlock_irqrestore(&spinlock, flags); | 659 | spin_unlock_irqrestore(&spinlock, flags); |
624 | } | 660 | } |
625 | 661 | ||
626 | if (timeout < 1 || timeout > 65535) { | 662 | if (timeout < 1 || timeout > max_units * 60) { |
627 | timeout = DEFAULT_TIMEOUT; | 663 | timeout = DEFAULT_TIMEOUT; |
628 | printk(KERN_WARNING PFX | 664 | printk(KERN_WARNING PFX |
629 | "Timeout value out of range, use default %d sec\n", | 665 | "Timeout value out of range, use default %d sec\n", |
630 | DEFAULT_TIMEOUT); | 666 | DEFAULT_TIMEOUT); |
631 | } | 667 | } |
632 | 668 | ||
669 | if (timeout > max_units) | ||
670 | timeout = wdt_round_time(timeout); | ||
671 | |||
633 | rc = register_reboot_notifier(&wdt_notifier); | 672 | rc = register_reboot_notifier(&wdt_notifier); |
634 | if (rc) { | 673 | if (rc) { |
635 | printk(KERN_ERR PFX | 674 | printk(KERN_ERR PFX |
@@ -656,7 +695,7 @@ static int __init it87_wdt_init(void) | |||
656 | outb(0x09, CIR_IER(base)); | 695 | outb(0x09, CIR_IER(base)); |
657 | } | 696 | } |
658 | 697 | ||
659 | printk(KERN_INFO PFX "Chip it%04x revision %d initialized. " | 698 | printk(KERN_INFO PFX "Chip IT%04x revision %d initialized. " |
660 | "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d " | 699 | "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d " |
661 | "nogameport=%d)\n", chip_type, chip_rev, timeout, | 700 | "nogameport=%d)\n", chip_type, chip_rev, timeout, |
662 | nowayout, testmode, exclusive, nogameport); | 701 | nowayout, testmode, exclusive, nogameport); |
@@ -676,7 +715,7 @@ err_out_region: | |||
676 | spin_unlock_irqrestore(&spinlock, flags); | 715 | spin_unlock_irqrestore(&spinlock, flags); |
677 | } | 716 | } |
678 | err_out: | 717 | err_out: |
679 | if (chip_type != IT8718_ID && !nogameport) { | 718 | if (try_gameport) { |
680 | spin_lock_irqsave(&spinlock, flags); | 719 | spin_lock_irqsave(&spinlock, flags); |
681 | superio_enter(); | 720 | superio_enter(); |
682 | superio_select(GAMEPORT); | 721 | superio_select(GAMEPORT); |
@@ -698,8 +737,9 @@ static void __exit it87_wdt_exit(void) | |||
698 | superio_select(GPIO); | 737 | superio_select(GPIO); |
699 | superio_outb(0x00, WDTCTRL); | 738 | superio_outb(0x00, WDTCTRL); |
700 | superio_outb(0x00, WDTCFG); | 739 | superio_outb(0x00, WDTCFG); |
701 | superio_outb(0x00, WDTVALMSB); | ||
702 | superio_outb(0x00, WDTVALLSB); | 740 | superio_outb(0x00, WDTVALLSB); |
741 | if (max_units > 255) | ||
742 | superio_outb(0x00, WDTVALMSB); | ||
703 | if (test_bit(WDTS_USE_GP, &wdt_status)) { | 743 | if (test_bit(WDTS_USE_GP, &wdt_status)) { |
704 | superio_select(GAMEPORT); | 744 | superio_select(GAMEPORT); |
705 | superio_outb(gpact, ACTREG); | 745 | superio_outb(gpact, ACTREG); |