diff options
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/Kconfig | 33 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 3 | ||||
-rw-r--r-- | drivers/watchdog/alim1535_wdt.c | 20 | ||||
-rw-r--r-- | drivers/watchdog/alim7101_wdt.c | 18 | ||||
-rw-r--r-- | drivers/watchdog/ar7_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/at32ap700x_wdt.c | 69 | ||||
-rw-r--r-- | drivers/watchdog/bfin_wdt.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/it8712f_wdt.c | 400 | ||||
-rw-r--r-- | drivers/watchdog/mpc5200_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/mtx-1_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/sbc60xxwdt.c | 18 | ||||
-rw-r--r-- | drivers/watchdog/sbc7240_wdt.c | 324 | ||||
-rw-r--r-- | drivers/watchdog/scx200_wdt.c | 10 | ||||
-rw-r--r-- | drivers/watchdog/shwdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/txx9wdt.c | 276 | ||||
-rw-r--r-- | drivers/watchdog/w83877f_wdt.c | 18 | ||||
-rw-r--r-- | drivers/watchdog/w83977f_wdt.c | 18 | ||||
-rw-r--r-- | drivers/watchdog/wdt.c | 30 | ||||
-rw-r--r-- | drivers/watchdog/wdt977.c | 18 |
19 files changed, 1192 insertions, 75 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 2792bc1a7269..afcdc69e37d6 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -223,7 +223,7 @@ config DAVINCI_WATCHDOG | |||
223 | 223 | ||
224 | config AT32AP700X_WDT | 224 | config AT32AP700X_WDT |
225 | tristate "AT32AP700x watchdog" | 225 | tristate "AT32AP700x watchdog" |
226 | depends on CPU_AT32AP7000 | 226 | depends on CPU_AT32AP700X |
227 | help | 227 | help |
228 | Watchdog timer embedded into AT32AP700x devices. This will reboot | 228 | Watchdog timer embedded into AT32AP700x devices. This will reboot |
229 | your system when the timeout is reached. | 229 | your system when the timeout is reached. |
@@ -392,6 +392,16 @@ config ITCO_VENDOR_SUPPORT | |||
392 | devices. At this moment we only have additional support for some | 392 | devices. At this moment we only have additional support for some |
393 | SuperMicro Inc. motherboards. | 393 | SuperMicro Inc. motherboards. |
394 | 394 | ||
395 | config IT8712F_WDT | ||
396 | tristate "IT8712F (Smart Guardian) Watchdog Timer" | ||
397 | depends on X86 | ||
398 | ---help--- | ||
399 | This is the driver for the built-in watchdog timer on the IT8712F | ||
400 | Super I/0 chipset used on many motherboards. | ||
401 | |||
402 | To compile this driver as a module, choose M here: the | ||
403 | module will be called it8712f_wdt. | ||
404 | |||
395 | config SC1200_WDT | 405 | config SC1200_WDT |
396 | tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" | 406 | tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" |
397 | depends on X86 | 407 | depends on X86 |
@@ -456,6 +466,19 @@ config SBC8360_WDT | |||
456 | 466 | ||
457 | Most people will say N. | 467 | Most people will say N. |
458 | 468 | ||
469 | config SBC7240_WDT | ||
470 | tristate "SBC Nano 7240 Watchdog Timer" | ||
471 | depends on X86_32 | ||
472 | ---help--- | ||
473 | This is the driver for the hardware watchdog found on the IEI | ||
474 | single board computers EPIC Nano 7240 (and likely others). This | ||
475 | watchdog simply watches your kernel to make sure it doesn't freeze, | ||
476 | and if it does, it reboots your computer after a certain amount of | ||
477 | time. | ||
478 | |||
479 | To compile this driver as a module, choose M here: the | ||
480 | module will be called sbc7240_wdt. | ||
481 | |||
459 | config CPU5_WDT | 482 | config CPU5_WDT |
460 | tristate "SMA CPU5 Watchdog" | 483 | tristate "SMA CPU5 Watchdog" |
461 | depends on X86 | 484 | depends on X86 |
@@ -586,7 +609,7 @@ config SBC_EPX_C3_WATCHDOG | |||
586 | 609 | ||
587 | config INDYDOG | 610 | config INDYDOG |
588 | tristate "Indy/I2 Hardware Watchdog" | 611 | tristate "Indy/I2 Hardware Watchdog" |
589 | depends on SGI_IP22 | 612 | depends on SGI_HAS_INDYDOG |
590 | help | 613 | help |
591 | Hardware driver for the Indy's/I2's watchdog. This is a | 614 | Hardware driver for the Indy's/I2's watchdog. This is a |
592 | watchdog timer that will reboot the machine after a 60 second | 615 | watchdog timer that will reboot the machine after a 60 second |
@@ -616,6 +639,12 @@ config AR7_WDT | |||
616 | help | 639 | help |
617 | Hardware driver for the TI AR7 Watchdog Timer. | 640 | Hardware driver for the TI AR7 Watchdog Timer. |
618 | 641 | ||
642 | config TXX9_WDT | ||
643 | tristate "Toshiba TXx9 Watchdog Timer" | ||
644 | depends on CPU_TX39XX || CPU_TX49XX | ||
645 | help | ||
646 | Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs. | ||
647 | |||
619 | # PARISC Architecture | 648 | # PARISC Architecture |
620 | 649 | ||
621 | # POWERPC Architecture | 650 | # POWERPC Architecture |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 7d9e5734f8bb..ebc21146d40c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
@@ -66,11 +66,13 @@ obj-$(CONFIG_IBMASR) += ibmasr.o | |||
66 | obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o | 66 | obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o |
67 | obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o | 67 | obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o |
68 | obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o | 68 | obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o |
69 | obj-$(CONFIG_IT8712F_WDT) += it8712f_wdt.o | ||
69 | obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o | 70 | obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o |
70 | obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o | 71 | obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o |
71 | obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o | 72 | obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o |
72 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o | 73 | obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o |
73 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o | 74 | obj-$(CONFIG_SBC8360_WDT) += sbc8360.o |
75 | obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o | ||
74 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o | 76 | obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o |
75 | obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o | 77 | obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o |
76 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o | 78 | obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o |
@@ -91,6 +93,7 @@ obj-$(CONFIG_INDYDOG) += indydog.o | |||
91 | obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o | 93 | obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o |
92 | obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o | 94 | obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o |
93 | obj-$(CONFIG_AR7_WDT) += ar7_wdt.o | 95 | obj-$(CONFIG_AR7_WDT) += ar7_wdt.o |
96 | obj-$(CONFIG_TXX9_WDT) += txx9wdt.o | ||
94 | 97 | ||
95 | # PARISC Architecture | 98 | # PARISC Architecture |
96 | 99 | ||
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c index b481cc0e32e4..2b1fbdb2fcf7 100644 --- a/drivers/watchdog/alim1535_wdt.c +++ b/drivers/watchdog/alim1535_wdt.c | |||
@@ -413,18 +413,18 @@ static int __init watchdog_init(void) | |||
413 | /* Calculate the watchdog's timeout */ | 413 | /* Calculate the watchdog's timeout */ |
414 | ali_settimer(timeout); | 414 | ali_settimer(timeout); |
415 | 415 | ||
416 | ret = misc_register(&ali_miscdev); | 416 | ret = register_reboot_notifier(&ali_notifier); |
417 | if (ret != 0) { | 417 | if (ret != 0) { |
418 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 418 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", |
419 | WATCHDOG_MINOR, ret); | 419 | ret); |
420 | goto out; | 420 | goto out; |
421 | } | 421 | } |
422 | 422 | ||
423 | ret = register_reboot_notifier(&ali_notifier); | 423 | ret = misc_register(&ali_miscdev); |
424 | if (ret != 0) { | 424 | if (ret != 0) { |
425 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 425 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", |
426 | ret); | 426 | WATCHDOG_MINOR, ret); |
427 | goto unreg_miscdev; | 427 | goto unreg_reboot; |
428 | } | 428 | } |
429 | 429 | ||
430 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", | 430 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n", |
@@ -432,8 +432,8 @@ static int __init watchdog_init(void) | |||
432 | 432 | ||
433 | out: | 433 | out: |
434 | return ret; | 434 | return ret; |
435 | unreg_miscdev: | 435 | unreg_reboot: |
436 | misc_deregister(&ali_miscdev); | 436 | unregister_reboot_notifier(&ali_notifier); |
437 | goto out; | 437 | goto out; |
438 | } | 438 | } |
439 | 439 | ||
@@ -449,8 +449,8 @@ static void __exit watchdog_exit(void) | |||
449 | ali_stop(); | 449 | ali_stop(); |
450 | 450 | ||
451 | /* Deregister */ | 451 | /* Deregister */ |
452 | unregister_reboot_notifier(&ali_notifier); | ||
453 | misc_deregister(&ali_miscdev); | 452 | misc_deregister(&ali_miscdev); |
453 | unregister_reboot_notifier(&ali_notifier); | ||
454 | pci_dev_put(ali_pci); | 454 | pci_dev_put(ali_pci); |
455 | } | 455 | } |
456 | 456 | ||
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c index 67aed9f8c362..238273c98656 100644 --- a/drivers/watchdog/alim7101_wdt.c +++ b/drivers/watchdog/alim7101_wdt.c | |||
@@ -377,18 +377,18 @@ static int __init alim7101_wdt_init(void) | |||
377 | timeout); | 377 | timeout); |
378 | } | 378 | } |
379 | 379 | ||
380 | rc = misc_register(&wdt_miscdev); | 380 | rc = register_reboot_notifier(&wdt_notifier); |
381 | if (rc) { | 381 | if (rc) { |
382 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 382 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", |
383 | wdt_miscdev.minor, rc); | 383 | rc); |
384 | goto err_out; | 384 | goto err_out; |
385 | } | 385 | } |
386 | 386 | ||
387 | rc = register_reboot_notifier(&wdt_notifier); | 387 | rc = misc_register(&wdt_miscdev); |
388 | if (rc) { | 388 | if (rc) { |
389 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 389 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", |
390 | rc); | 390 | wdt_miscdev.minor, rc); |
391 | goto err_out_miscdev; | 391 | goto err_out_reboot; |
392 | } | 392 | } |
393 | 393 | ||
394 | if (nowayout) { | 394 | if (nowayout) { |
@@ -399,8 +399,8 @@ static int __init alim7101_wdt_init(void) | |||
399 | timeout, nowayout); | 399 | timeout, nowayout); |
400 | return 0; | 400 | return 0; |
401 | 401 | ||
402 | err_out_miscdev: | 402 | err_out_reboot: |
403 | misc_deregister(&wdt_miscdev); | 403 | unregister_reboot_notifier(&wdt_notifier); |
404 | err_out: | 404 | err_out: |
405 | pci_dev_put(alim7101_pmu); | 405 | pci_dev_put(alim7101_pmu); |
406 | return rc; | 406 | return rc; |
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c index cdaab8c3d3d0..2eb48c0df32c 100644 --- a/drivers/watchdog/ar7_wdt.c +++ b/drivers/watchdog/ar7_wdt.c | |||
@@ -279,7 +279,7 @@ static int ar7_wdt_ioctl(struct inode *inode, struct file *file, | |||
279 | } | 279 | } |
280 | } | 280 | } |
281 | 281 | ||
282 | static struct file_operations ar7_wdt_fops = { | 282 | static const struct file_operations ar7_wdt_fops = { |
283 | .owner = THIS_MODULE, | 283 | .owner = THIS_MODULE, |
284 | .write = ar7_wdt_write, | 284 | .write = ar7_wdt_write, |
285 | .ioctl = ar7_wdt_ioctl, | 285 | .ioctl = ar7_wdt_ioctl, |
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c index 54a516169d07..fb5ed6478f78 100644 --- a/drivers/watchdog/at32ap700x_wdt.c +++ b/drivers/watchdog/at32ap700x_wdt.c | |||
@@ -6,6 +6,19 @@ | |||
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | * | ||
10 | * | ||
11 | * Errata: WDT Clear is blocked after WDT Reset | ||
12 | * | ||
13 | * A watchdog timer event will, after reset, block writes to the WDT_CLEAR | ||
14 | * register, preventing the program to clear the next Watchdog Timer Reset. | ||
15 | * | ||
16 | * If you still want to use the WDT after a WDT reset a small code can be | ||
17 | * insterted at the startup checking the AVR32_PM.rcause register for WDT reset | ||
18 | * and use a GPIO pin to reset the system. This method requires that one of the | ||
19 | * GPIO pins are available and connected externally to the RESET_N pin. After | ||
20 | * the GPIO pin has pulled down the reset line the GPIO will be reset and leave | ||
21 | * the pin tristated with pullup. | ||
9 | */ | 22 | */ |
10 | 23 | ||
11 | #include <linux/init.h> | 24 | #include <linux/init.h> |
@@ -44,6 +57,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | |||
44 | 57 | ||
45 | #define WDT_CLR 0x04 | 58 | #define WDT_CLR 0x04 |
46 | 59 | ||
60 | #define WDT_RCAUSE 0x10 | ||
61 | #define WDT_RCAUSE_POR 0 | ||
62 | #define WDT_RCAUSE_EXT 2 | ||
63 | #define WDT_RCAUSE_WDT 3 | ||
64 | #define WDT_RCAUSE_JTAG 4 | ||
65 | #define WDT_RCAUSE_SERP 5 | ||
66 | |||
47 | #define WDT_BIT(name) (1 << WDT_##name) | 67 | #define WDT_BIT(name) (1 << WDT_##name) |
48 | #define WDT_BF(name, value) ((value) << WDT_##name) | 68 | #define WDT_BF(name, value) ((value) << WDT_##name) |
49 | 69 | ||
@@ -56,6 +76,7 @@ struct wdt_at32ap700x { | |||
56 | void __iomem *regs; | 76 | void __iomem *regs; |
57 | spinlock_t io_lock; | 77 | spinlock_t io_lock; |
58 | int timeout; | 78 | int timeout; |
79 | int boot_status; | ||
59 | unsigned long users; | 80 | unsigned long users; |
60 | struct miscdevice miscdev; | 81 | struct miscdevice miscdev; |
61 | }; | 82 | }; |
@@ -126,7 +147,7 @@ static int at32_wdt_close(struct inode *inode, struct file *file) | |||
126 | at32_wdt_stop(); | 147 | at32_wdt_stop(); |
127 | } else { | 148 | } else { |
128 | dev_dbg(wdt->miscdev.parent, | 149 | dev_dbg(wdt->miscdev.parent, |
129 | "Unexpected close, not stopping watchdog!\n"); | 150 | "unexpected close, not stopping watchdog!\n"); |
130 | at32_wdt_pat(); | 151 | at32_wdt_pat(); |
131 | } | 152 | } |
132 | clear_bit(1, &wdt->users); | 153 | clear_bit(1, &wdt->users); |
@@ -154,6 +175,33 @@ static int at32_wdt_settimeout(int time) | |||
154 | return 0; | 175 | return 0; |
155 | } | 176 | } |
156 | 177 | ||
178 | /* | ||
179 | * Get the watchdog status. | ||
180 | */ | ||
181 | static int at32_wdt_get_status(void) | ||
182 | { | ||
183 | int rcause; | ||
184 | int status = 0; | ||
185 | |||
186 | rcause = wdt_readl(wdt, RCAUSE); | ||
187 | |||
188 | switch (rcause) { | ||
189 | case WDT_BIT(RCAUSE_EXT): | ||
190 | status = WDIOF_EXTERN1; | ||
191 | break; | ||
192 | case WDT_BIT(RCAUSE_WDT): | ||
193 | status = WDIOF_CARDRESET; | ||
194 | break; | ||
195 | case WDT_BIT(RCAUSE_POR): /* fall through */ | ||
196 | case WDT_BIT(RCAUSE_JTAG): /* fall through */ | ||
197 | case WDT_BIT(RCAUSE_SERP): /* fall through */ | ||
198 | default: | ||
199 | break; | ||
200 | } | ||
201 | |||
202 | return status; | ||
203 | } | ||
204 | |||
157 | static struct watchdog_info at32_wdt_info = { | 205 | static struct watchdog_info at32_wdt_info = { |
158 | .identity = "at32ap700x watchdog", | 206 | .identity = "at32ap700x watchdog", |
159 | .options = WDIOF_SETTIMEOUT | | 207 | .options = WDIOF_SETTIMEOUT | |
@@ -194,10 +242,12 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, | |||
194 | case WDIOC_GETTIMEOUT: | 242 | case WDIOC_GETTIMEOUT: |
195 | ret = put_user(wdt->timeout, p); | 243 | ret = put_user(wdt->timeout, p); |
196 | break; | 244 | break; |
197 | case WDIOC_GETSTATUS: /* fall through */ | 245 | case WDIOC_GETSTATUS: |
198 | case WDIOC_GETBOOTSTATUS: | ||
199 | ret = put_user(0, p); | 246 | ret = put_user(0, p); |
200 | break; | 247 | break; |
248 | case WDIOC_GETBOOTSTATUS: | ||
249 | ret = put_user(wdt->boot_status, p); | ||
250 | break; | ||
201 | case WDIOC_SETOPTIONS: | 251 | case WDIOC_SETOPTIONS: |
202 | ret = get_user(time, p); | 252 | ret = get_user(time, p); |
203 | if (ret) | 253 | if (ret) |
@@ -282,8 +332,19 @@ static int __init at32_wdt_probe(struct platform_device *pdev) | |||
282 | dev_dbg(&pdev->dev, "could not map I/O memory\n"); | 332 | dev_dbg(&pdev->dev, "could not map I/O memory\n"); |
283 | goto err_free; | 333 | goto err_free; |
284 | } | 334 | } |
335 | |||
285 | spin_lock_init(&wdt->io_lock); | 336 | spin_lock_init(&wdt->io_lock); |
286 | wdt->users = 0; | 337 | wdt->boot_status = at32_wdt_get_status(); |
338 | |||
339 | /* Work-around for watchdog silicon errata. */ | ||
340 | if (wdt->boot_status & WDIOF_CARDRESET) { | ||
341 | dev_info(&pdev->dev, "CPU must be reset with external " | ||
342 | "reset or POR due to silicon errata.\n"); | ||
343 | ret = -EIO; | ||
344 | goto err_iounmap; | ||
345 | } else { | ||
346 | wdt->users = 0; | ||
347 | } | ||
287 | wdt->miscdev.minor = WATCHDOG_MINOR; | 348 | wdt->miscdev.minor = WATCHDOG_MINOR; |
288 | wdt->miscdev.name = "watchdog"; | 349 | wdt->miscdev.name = "watchdog"; |
289 | wdt->miscdev.fops = &at32_wdt_fops; | 350 | wdt->miscdev.fops = &at32_wdt_fops; |
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c index 309d27913fc1..472be10f0686 100644 --- a/drivers/watchdog/bfin_wdt.c +++ b/drivers/watchdog/bfin_wdt.c | |||
@@ -71,7 +71,7 @@ static int nowayout = WATCHDOG_NOWAYOUT; | |||
71 | static struct watchdog_info bfin_wdt_info; | 71 | static struct watchdog_info bfin_wdt_info; |
72 | static unsigned long open_check; | 72 | static unsigned long open_check; |
73 | static char expect_close; | 73 | static char expect_close; |
74 | static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED; | 74 | static DEFINE_SPINLOCK(bfin_wdt_spinlock); |
75 | 75 | ||
76 | /** | 76 | /** |
77 | * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive | 77 | * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive |
@@ -390,7 +390,7 @@ static struct platform_driver bfin_wdt_driver = { | |||
390 | .resume = bfin_wdt_resume, | 390 | .resume = bfin_wdt_resume, |
391 | }; | 391 | }; |
392 | 392 | ||
393 | static struct file_operations bfin_wdt_fops = { | 393 | static const struct file_operations bfin_wdt_fops = { |
394 | .owner = THIS_MODULE, | 394 | .owner = THIS_MODULE, |
395 | .llseek = no_llseek, | 395 | .llseek = no_llseek, |
396 | .write = bfin_wdt_write, | 396 | .write = bfin_wdt_write, |
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c new file mode 100644 index 000000000000..1b6d7d1b715d --- /dev/null +++ b/drivers/watchdog/it8712f_wdt.c | |||
@@ -0,0 +1,400 @@ | |||
1 | /* | ||
2 | * IT8712F "Smart Guardian" Watchdog support | ||
3 | * | ||
4 | * Copyright (c) 2006-2007 Jorge Boncompte - DTI2 <jorge@dti2.net> | ||
5 | * | ||
6 | * Based on info and code taken from: | ||
7 | * | ||
8 | * drivers/char/watchdog/scx200_wdt.c | ||
9 | * drivers/hwmon/it87.c | ||
10 | * IT8712F EC-LPC I/O Preliminary Specification 0.9.2.pdf | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License as | ||
14 | * published by the Free Software Foundation; either version 2 of the | ||
15 | * License, or (at your option) any later version. | ||
16 | * | ||
17 | * The author(s) of this software shall not be held liable for damages | ||
18 | * of any nature resulting due to the use of this software. This | ||
19 | * software is provided AS-IS with no warranties. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/miscdevice.h> | ||
26 | #include <linux/watchdog.h> | ||
27 | #include <linux/notifier.h> | ||
28 | #include <linux/reboot.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/pci.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | |||
33 | #include <asm/uaccess.h> | ||
34 | #include <asm/io.h> | ||
35 | |||
36 | #define NAME "it8712f_wdt" | ||
37 | |||
38 | MODULE_AUTHOR("Jorge Boncompte - DTI2 <jorge@dti2.net>"); | ||
39 | MODULE_DESCRIPTION("IT8712F Watchdog Driver"); | ||
40 | MODULE_LICENSE("GPL"); | ||
41 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
42 | |||
43 | static int margin = 60; /* in seconds */ | ||
44 | module_param(margin, int, 0); | ||
45 | MODULE_PARM_DESC(margin, "Watchdog margin in seconds"); | ||
46 | |||
47 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
48 | module_param(nowayout, int, 0); | ||
49 | MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); | ||
50 | |||
51 | static struct semaphore it8712f_wdt_sem; | ||
52 | static unsigned expect_close; | ||
53 | static spinlock_t io_lock; | ||
54 | |||
55 | /* Dog Food address - We use the game port address */ | ||
56 | static unsigned short address; | ||
57 | |||
58 | #define REG 0x2e /* The register to read/write */ | ||
59 | #define VAL 0x2f /* The value to read/write */ | ||
60 | |||
61 | #define LDN 0x07 /* Register: Logical device select */ | ||
62 | #define DEVID 0x20 /* Register: Device ID */ | ||
63 | #define DEVREV 0x22 /* Register: Device Revision */ | ||
64 | #define ACT_REG 0x30 /* LDN Register: Activation */ | ||
65 | #define BASE_REG 0x60 /* LDN Register: Base address */ | ||
66 | |||
67 | #define IT8712F_DEVID 0x8712 | ||
68 | |||
69 | #define LDN_GPIO 0x07 /* GPIO and Watch Dog Timer */ | ||
70 | #define LDN_GAME 0x09 /* Game Port */ | ||
71 | |||
72 | #define WDT_CONTROL 0x71 /* WDT Register: Control */ | ||
73 | #define WDT_CONFIG 0x72 /* WDT Register: Configuration */ | ||
74 | #define WDT_TIMEOUT 0x73 /* WDT Register: Timeout Value */ | ||
75 | |||
76 | #define WDT_RESET_GAME 0x10 | ||
77 | #define WDT_RESET_KBD 0x20 | ||
78 | #define WDT_RESET_MOUSE 0x40 | ||
79 | #define WDT_RESET_CIR 0x80 | ||
80 | |||
81 | #define WDT_UNIT_SEC 0x80 /* If 0 in MINUTES */ | ||
82 | |||
83 | #define WDT_OUT_PWROK 0x10 | ||
84 | #define WDT_OUT_KRST 0x40 | ||
85 | |||
86 | static int | ||
87 | superio_inb(int reg) | ||
88 | { | ||
89 | outb(reg, REG); | ||
90 | return inb(VAL); | ||
91 | } | ||
92 | |||
93 | static void | ||
94 | superio_outb(int val, int reg) | ||
95 | { | ||
96 | outb(reg, REG); | ||
97 | outb(val, VAL); | ||
98 | } | ||
99 | |||
100 | static int | ||
101 | superio_inw(int reg) | ||
102 | { | ||
103 | int val; | ||
104 | outb(reg++, REG); | ||
105 | val = inb(VAL) << 8; | ||
106 | outb(reg, REG); | ||
107 | val |= inb(VAL); | ||
108 | return val; | ||
109 | } | ||
110 | |||
111 | static inline void | ||
112 | superio_select(int ldn) | ||
113 | { | ||
114 | outb(LDN, REG); | ||
115 | outb(ldn, VAL); | ||
116 | } | ||
117 | |||
118 | static inline void | ||
119 | superio_enter(void) | ||
120 | { | ||
121 | spin_lock(&io_lock); | ||
122 | outb(0x87, REG); | ||
123 | outb(0x01, REG); | ||
124 | outb(0x55, REG); | ||
125 | outb(0x55, REG); | ||
126 | } | ||
127 | |||
128 | static inline void | ||
129 | superio_exit(void) | ||
130 | { | ||
131 | outb(0x02, REG); | ||
132 | outb(0x02, VAL); | ||
133 | spin_unlock(&io_lock); | ||
134 | } | ||
135 | |||
136 | static inline void | ||
137 | it8712f_wdt_ping(void) | ||
138 | { | ||
139 | inb(address); | ||
140 | } | ||
141 | |||
142 | static void | ||
143 | it8712f_wdt_update_margin(void) | ||
144 | { | ||
145 | int config = WDT_OUT_KRST | WDT_OUT_PWROK; | ||
146 | |||
147 | printk(KERN_INFO NAME ": timer margin %d seconds\n", margin); | ||
148 | |||
149 | /* The timeout register only has 8bits wide */ | ||
150 | if (margin < 256) | ||
151 | config |= WDT_UNIT_SEC; /* else UNIT are MINUTES */ | ||
152 | superio_outb(config, WDT_CONFIG); | ||
153 | |||
154 | superio_outb((margin > 255) ? (margin / 60) : margin, WDT_TIMEOUT); | ||
155 | } | ||
156 | |||
157 | static void | ||
158 | it8712f_wdt_enable(void) | ||
159 | { | ||
160 | printk(KERN_DEBUG NAME ": enabling watchdog timer\n"); | ||
161 | superio_enter(); | ||
162 | superio_select(LDN_GPIO); | ||
163 | |||
164 | superio_outb(WDT_RESET_GAME, WDT_CONTROL); | ||
165 | |||
166 | it8712f_wdt_update_margin(); | ||
167 | |||
168 | superio_exit(); | ||
169 | |||
170 | it8712f_wdt_ping(); | ||
171 | } | ||
172 | |||
173 | static void | ||
174 | it8712f_wdt_disable(void) | ||
175 | { | ||
176 | printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); | ||
177 | |||
178 | superio_enter(); | ||
179 | superio_select(LDN_GPIO); | ||
180 | |||
181 | superio_outb(0, WDT_CONFIG); | ||
182 | superio_outb(0, WDT_CONTROL); | ||
183 | superio_outb(0, WDT_TIMEOUT); | ||
184 | |||
185 | superio_exit(); | ||
186 | } | ||
187 | |||
188 | static int | ||
189 | it8712f_wdt_notify(struct notifier_block *this, | ||
190 | unsigned long code, void *unused) | ||
191 | { | ||
192 | if (code == SYS_HALT || code == SYS_POWER_OFF) | ||
193 | if (!nowayout) | ||
194 | it8712f_wdt_disable(); | ||
195 | |||
196 | return NOTIFY_DONE; | ||
197 | } | ||
198 | |||
199 | static struct notifier_block it8712f_wdt_notifier = { | ||
200 | .notifier_call = it8712f_wdt_notify, | ||
201 | }; | ||
202 | |||
203 | static ssize_t | ||
204 | it8712f_wdt_write(struct file *file, const char __user *data, | ||
205 | size_t len, loff_t *ppos) | ||
206 | { | ||
207 | /* check for a magic close character */ | ||
208 | if (len) { | ||
209 | size_t i; | ||
210 | |||
211 | it8712f_wdt_ping(); | ||
212 | |||
213 | expect_close = 0; | ||
214 | for (i = 0; i < len; ++i) { | ||
215 | char c; | ||
216 | if (get_user(c, data+i)) | ||
217 | return -EFAULT; | ||
218 | if (c == 'V') | ||
219 | expect_close = 42; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | return len; | ||
224 | } | ||
225 | |||
226 | static int | ||
227 | it8712f_wdt_ioctl(struct inode *inode, struct file *file, | ||
228 | unsigned int cmd, unsigned long arg) | ||
229 | { | ||
230 | void __user *argp = (void __user *)arg; | ||
231 | int __user *p = argp; | ||
232 | static struct watchdog_info ident = { | ||
233 | .identity = "IT8712F Watchdog", | ||
234 | .firmware_version = 1, | ||
235 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | ||
236 | }; | ||
237 | int new_margin; | ||
238 | |||
239 | switch (cmd) { | ||
240 | default: | ||
241 | return -ENOTTY; | ||
242 | case WDIOC_GETSUPPORT: | ||
243 | if (copy_to_user(argp, &ident, sizeof(ident))) | ||
244 | return -EFAULT; | ||
245 | return 0; | ||
246 | case WDIOC_GETSTATUS: | ||
247 | case WDIOC_GETBOOTSTATUS: | ||
248 | return put_user(0, p); | ||
249 | case WDIOC_KEEPALIVE: | ||
250 | it8712f_wdt_ping(); | ||
251 | return 0; | ||
252 | case WDIOC_SETTIMEOUT: | ||
253 | if (get_user(new_margin, p)) | ||
254 | return -EFAULT; | ||
255 | if (new_margin < 1) | ||
256 | return -EINVAL; | ||
257 | margin = new_margin; | ||
258 | superio_enter(); | ||
259 | superio_select(LDN_GPIO); | ||
260 | |||
261 | it8712f_wdt_update_margin(); | ||
262 | |||
263 | superio_exit(); | ||
264 | it8712f_wdt_ping(); | ||
265 | case WDIOC_GETTIMEOUT: | ||
266 | if (put_user(margin, p)) | ||
267 | return -EFAULT; | ||
268 | return 0; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | static int | ||
273 | it8712f_wdt_open(struct inode *inode, struct file *file) | ||
274 | { | ||
275 | /* only allow one at a time */ | ||
276 | if (down_trylock(&it8712f_wdt_sem)) | ||
277 | return -EBUSY; | ||
278 | it8712f_wdt_enable(); | ||
279 | |||
280 | return nonseekable_open(inode, file); | ||
281 | } | ||
282 | |||
283 | static int | ||
284 | it8712f_wdt_release(struct inode *inode, struct file *file) | ||
285 | { | ||
286 | if (expect_close != 42) { | ||
287 | printk(KERN_WARNING NAME | ||
288 | ": watchdog device closed unexpectedly, will not" | ||
289 | " disable the watchdog timer\n"); | ||
290 | } else if (!nowayout) { | ||
291 | it8712f_wdt_disable(); | ||
292 | } | ||
293 | expect_close = 0; | ||
294 | up(&it8712f_wdt_sem); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static const struct file_operations it8712f_wdt_fops = { | ||
300 | .owner = THIS_MODULE, | ||
301 | .llseek = no_llseek, | ||
302 | .write = it8712f_wdt_write, | ||
303 | .ioctl = it8712f_wdt_ioctl, | ||
304 | .open = it8712f_wdt_open, | ||
305 | .release = it8712f_wdt_release, | ||
306 | }; | ||
307 | |||
308 | static struct miscdevice it8712f_wdt_miscdev = { | ||
309 | .minor = WATCHDOG_MINOR, | ||
310 | .name = "watchdog", | ||
311 | .fops = &it8712f_wdt_fops, | ||
312 | }; | ||
313 | |||
314 | static int __init | ||
315 | it8712f_wdt_find(unsigned short *address) | ||
316 | { | ||
317 | int err = -ENODEV; | ||
318 | int chip_type; | ||
319 | |||
320 | superio_enter(); | ||
321 | chip_type = superio_inw(DEVID); | ||
322 | if (chip_type != IT8712F_DEVID) | ||
323 | goto exit; | ||
324 | |||
325 | superio_select(LDN_GAME); | ||
326 | superio_outb(1, ACT_REG); | ||
327 | if (!(superio_inb(ACT_REG) & 0x01)) { | ||
328 | printk(KERN_ERR NAME ": Device not activated, skipping\n"); | ||
329 | goto exit; | ||
330 | } | ||
331 | |||
332 | *address = superio_inw(BASE_REG); | ||
333 | if (*address == 0) { | ||
334 | printk(KERN_ERR NAME ": Base address not set, skipping\n"); | ||
335 | goto exit; | ||
336 | } | ||
337 | |||
338 | err = 0; | ||
339 | printk(KERN_DEBUG NAME ": Found IT%04xF chip revision %d - " | ||
340 | "using DogFood address 0x%x\n", | ||
341 | chip_type, superio_inb(DEVREV) & 0x0f, *address); | ||
342 | |||
343 | exit: | ||
344 | superio_exit(); | ||
345 | return err; | ||
346 | } | ||
347 | |||
348 | static int __init | ||
349 | it8712f_wdt_init(void) | ||
350 | { | ||
351 | int err = 0; | ||
352 | |||
353 | spin_lock_init(&io_lock); | ||
354 | |||
355 | if (it8712f_wdt_find(&address)) | ||
356 | return -ENODEV; | ||
357 | |||
358 | if (!request_region(address, 1, "IT8712F Watchdog")) { | ||
359 | printk(KERN_WARNING NAME ": watchdog I/O region busy\n"); | ||
360 | return -EBUSY; | ||
361 | } | ||
362 | |||
363 | it8712f_wdt_disable(); | ||
364 | |||
365 | sema_init(&it8712f_wdt_sem, 1); | ||
366 | |||
367 | err = register_reboot_notifier(&it8712f_wdt_notifier); | ||
368 | if (err) { | ||
369 | printk(KERN_ERR NAME ": unable to register reboot notifier\n"); | ||
370 | goto out; | ||
371 | } | ||
372 | |||
373 | err = misc_register(&it8712f_wdt_miscdev); | ||
374 | if (err) { | ||
375 | printk(KERN_ERR NAME | ||
376 | ": cannot register miscdev on minor=%d (err=%d)\n", | ||
377 | WATCHDOG_MINOR, err); | ||
378 | goto reboot_out; | ||
379 | } | ||
380 | |||
381 | return 0; | ||
382 | |||
383 | |||
384 | reboot_out: | ||
385 | unregister_reboot_notifier(&it8712f_wdt_notifier); | ||
386 | out: | ||
387 | release_region(address, 1); | ||
388 | return err; | ||
389 | } | ||
390 | |||
391 | static void __exit | ||
392 | it8712f_wdt_exit(void) | ||
393 | { | ||
394 | misc_deregister(&it8712f_wdt_miscdev); | ||
395 | unregister_reboot_notifier(&it8712f_wdt_notifier); | ||
396 | release_region(address, 1); | ||
397 | } | ||
398 | |||
399 | module_init(it8712f_wdt_init); | ||
400 | module_exit(it8712f_wdt_exit); | ||
diff --git a/drivers/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c index 11f6a111e75b..80a91d4cea11 100644 --- a/drivers/watchdog/mpc5200_wdt.c +++ b/drivers/watchdog/mpc5200_wdt.c | |||
@@ -158,7 +158,7 @@ static int mpc5200_wdt_release(struct inode *inode, struct file *file) | |||
158 | return 0; | 158 | return 0; |
159 | } | 159 | } |
160 | 160 | ||
161 | static struct file_operations mpc5200_wdt_fops = { | 161 | static const struct file_operations mpc5200_wdt_fops = { |
162 | .owner = THIS_MODULE, | 162 | .owner = THIS_MODULE, |
163 | .write = mpc5200_wdt_write, | 163 | .write = mpc5200_wdt_write, |
164 | .ioctl = mpc5200_wdt_ioctl, | 164 | .ioctl = mpc5200_wdt_ioctl, |
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index dcfd401a7ad7..98451747d3cd 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c | |||
@@ -180,7 +180,7 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, | |||
180 | return count; | 180 | return count; |
181 | } | 181 | } |
182 | 182 | ||
183 | static struct file_operations mtx1_wdt_fops = { | 183 | static const struct file_operations mtx1_wdt_fops = { |
184 | .owner = THIS_MODULE, | 184 | .owner = THIS_MODULE, |
185 | .llseek = no_llseek, | 185 | .llseek = no_llseek, |
186 | .ioctl = mtx1_wdt_ioctl, | 186 | .ioctl = mtx1_wdt_ioctl, |
diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c index e4f3cb6090bc..ef76f01625e7 100644 --- a/drivers/watchdog/sbc60xxwdt.c +++ b/drivers/watchdog/sbc60xxwdt.c | |||
@@ -359,20 +359,20 @@ static int __init sbc60xxwdt_init(void) | |||
359 | } | 359 | } |
360 | } | 360 | } |
361 | 361 | ||
362 | rc = misc_register(&wdt_miscdev); | 362 | rc = register_reboot_notifier(&wdt_notifier); |
363 | if (rc) | 363 | if (rc) |
364 | { | 364 | { |
365 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 365 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", |
366 | wdt_miscdev.minor, rc); | 366 | rc); |
367 | goto err_out_region2; | 367 | goto err_out_region2; |
368 | } | 368 | } |
369 | 369 | ||
370 | rc = register_reboot_notifier(&wdt_notifier); | 370 | rc = misc_register(&wdt_miscdev); |
371 | if (rc) | 371 | if (rc) |
372 | { | 372 | { |
373 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 373 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", |
374 | rc); | 374 | wdt_miscdev.minor, rc); |
375 | goto err_out_miscdev; | 375 | goto err_out_reboot; |
376 | } | 376 | } |
377 | 377 | ||
378 | printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n", | 378 | printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n", |
@@ -380,8 +380,8 @@ static int __init sbc60xxwdt_init(void) | |||
380 | 380 | ||
381 | return 0; | 381 | return 0; |
382 | 382 | ||
383 | err_out_miscdev: | 383 | err_out_reboot: |
384 | misc_deregister(&wdt_miscdev); | 384 | unregister_reboot_notifier(&wdt_notifier); |
385 | err_out_region2: | 385 | err_out_region2: |
386 | if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) | 386 | if ((wdt_stop != 0x45) && (wdt_stop != wdt_start)) |
387 | release_region(wdt_stop,1); | 387 | release_region(wdt_stop,1); |
diff --git a/drivers/watchdog/sbc7240_wdt.c b/drivers/watchdog/sbc7240_wdt.c new file mode 100644 index 000000000000..4c8cefbd8627 --- /dev/null +++ b/drivers/watchdog/sbc7240_wdt.c | |||
@@ -0,0 +1,324 @@ | |||
1 | /* | ||
2 | * NANO7240 SBC Watchdog device driver | ||
3 | * | ||
4 | * Based on w83877f.c by Scott Jennings, | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation; | ||
9 | * | ||
10 | * Software distributed under the License is distributed on an "AS IS" | ||
11 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or | ||
12 | * implied. See the License for the specific language governing | ||
13 | * rights and limitations under the License. | ||
14 | * | ||
15 | * (c) Copyright 2007 Gilles GIGAN <gilles.gigan@jcu.edu.au> | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/fs.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/jiffies.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/miscdevice.h> | ||
26 | #include <linux/notifier.h> | ||
27 | #include <linux/reboot.h> | ||
28 | #include <linux/types.h> | ||
29 | #include <linux/watchdog.h> | ||
30 | #include <asm/atomic.h> | ||
31 | #include <asm/io.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/uaccess.h> | ||
34 | |||
35 | #define SBC7240_PREFIX "sbc7240_wdt: " | ||
36 | |||
37 | #define SBC7240_ENABLE_PORT 0x443 | ||
38 | #define SBC7240_DISABLE_PORT 0x043 | ||
39 | #define SBC7240_SET_TIMEOUT_PORT SBC7240_ENABLE_PORT | ||
40 | #define SBC7240_MAGIC_CHAR 'V' | ||
41 | |||
42 | #define SBC7240_TIMEOUT 30 | ||
43 | #define SBC7240_MAX_TIMEOUT 255 | ||
44 | static int timeout = SBC7240_TIMEOUT; /* in seconds */ | ||
45 | module_param(timeout, int, 0); | ||
46 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=" | ||
47 | __MODULE_STRING(SBC7240_MAX_TIMEOUT) ", default=" | ||
48 | __MODULE_STRING(SBC7240_TIMEOUT) ")"); | ||
49 | |||
50 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
51 | module_param(nowayout, int, 0); | ||
52 | MODULE_PARM_DESC(nowayout, "Disable watchdog when closing device file"); | ||
53 | |||
54 | #define SBC7240_OPEN_STATUS_BIT 0 | ||
55 | #define SBC7240_ENABLED_STATUS_BIT 1 | ||
56 | #define SBC7240_EXPECT_CLOSE_STATUS_BIT 2 | ||
57 | static unsigned long wdt_status; | ||
58 | |||
59 | /* | ||
60 | * Utility routines | ||
61 | */ | ||
62 | |||
63 | static void wdt_disable(void) | ||
64 | { | ||
65 | /* disable the watchdog */ | ||
66 | if (test_and_clear_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) { | ||
67 | inb_p(SBC7240_DISABLE_PORT); | ||
68 | printk(KERN_INFO SBC7240_PREFIX | ||
69 | "Watchdog timer is now disabled.\n"); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | static void wdt_enable(void) | ||
74 | { | ||
75 | /* enable the watchdog */ | ||
76 | if (!test_and_set_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) { | ||
77 | inb_p(SBC7240_ENABLE_PORT); | ||
78 | printk(KERN_INFO SBC7240_PREFIX | ||
79 | "Watchdog timer is now enabled.\n"); | ||
80 | } | ||
81 | } | ||
82 | |||
83 | static int wdt_set_timeout(int t) | ||
84 | { | ||
85 | if (t < 1 || t > SBC7240_MAX_TIMEOUT) { | ||
86 | printk(KERN_ERR SBC7240_PREFIX | ||
87 | "timeout value must be 1<=x<=%d\n", | ||
88 | SBC7240_MAX_TIMEOUT); | ||
89 | return -1; | ||
90 | } | ||
91 | /* set the timeout */ | ||
92 | outb_p((unsigned)t, SBC7240_SET_TIMEOUT_PORT); | ||
93 | timeout = t; | ||
94 | printk(KERN_INFO SBC7240_PREFIX "timeout set to %d seconds\n", t); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | /* Whack the dog */ | ||
99 | static inline void wdt_keepalive(void) | ||
100 | { | ||
101 | if (test_bit(SBC7240_ENABLED_STATUS_BIT, &wdt_status)) | ||
102 | inb_p(SBC7240_ENABLE_PORT); | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | * /dev/watchdog handling | ||
107 | */ | ||
108 | static ssize_t fop_write(struct file *file, const char __user *buf, | ||
109 | size_t count, loff_t *ppos) | ||
110 | { | ||
111 | size_t i; | ||
112 | char c; | ||
113 | |||
114 | if (count) { | ||
115 | if (!nowayout) { | ||
116 | clear_bit(SBC7240_EXPECT_CLOSE_STATUS_BIT, | ||
117 | &wdt_status); | ||
118 | |||
119 | /* is there a magic char ? */ | ||
120 | for (i = 0; i != count; i++) { | ||
121 | if (get_user(c, buf + i)) | ||
122 | return -EFAULT; | ||
123 | if (c == SBC7240_MAGIC_CHAR) { | ||
124 | set_bit(SBC7240_EXPECT_CLOSE_STATUS_BIT, | ||
125 | &wdt_status); | ||
126 | break; | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | wdt_keepalive(); | ||
132 | } | ||
133 | |||
134 | return count; | ||
135 | } | ||
136 | |||
137 | static int fop_open(struct inode *inode, struct file *file) | ||
138 | { | ||
139 | if (test_and_set_bit(SBC7240_OPEN_STATUS_BIT, &wdt_status)) | ||
140 | return -EBUSY; | ||
141 | |||
142 | wdt_enable(); | ||
143 | |||
144 | return nonseekable_open(inode, file); | ||
145 | } | ||
146 | |||
147 | static int fop_close(struct inode *inode, struct file *file) | ||
148 | { | ||
149 | if (test_and_clear_bit(SBC7240_EXPECT_CLOSE_STATUS_BIT, &wdt_status) | ||
150 | || !nowayout) { | ||
151 | wdt_disable(); | ||
152 | } else { | ||
153 | printk(KERN_CRIT SBC7240_PREFIX | ||
154 | "Unexpected close, not stopping watchdog!\n"); | ||
155 | wdt_keepalive(); | ||
156 | } | ||
157 | |||
158 | clear_bit(SBC7240_OPEN_STATUS_BIT, &wdt_status); | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static struct watchdog_info ident = { | ||
163 | .options = WDIOF_KEEPALIVEPING| | ||
164 | WDIOF_SETTIMEOUT| | ||
165 | WDIOF_MAGICCLOSE, | ||
166 | .firmware_version = 1, | ||
167 | .identity = "SBC7240", | ||
168 | }; | ||
169 | |||
170 | |||
171 | static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
172 | unsigned long arg) | ||
173 | { | ||
174 | switch (cmd) { | ||
175 | case WDIOC_GETSUPPORT: | ||
176 | return copy_to_user | ||
177 | ((void __user *)arg, &ident, sizeof(ident)) | ||
178 | ? -EFAULT : 0; | ||
179 | case WDIOC_GETSTATUS: | ||
180 | case WDIOC_GETBOOTSTATUS: | ||
181 | return put_user(0, (int __user *)arg); | ||
182 | case WDIOC_KEEPALIVE: | ||
183 | wdt_keepalive(); | ||
184 | return 0; | ||
185 | case WDIOC_SETOPTIONS:{ | ||
186 | int options; | ||
187 | int retval = -EINVAL; | ||
188 | |||
189 | if (get_user(options, (int __user *)arg)) | ||
190 | return -EFAULT; | ||
191 | |||
192 | if (options & WDIOS_DISABLECARD) { | ||
193 | wdt_disable(); | ||
194 | retval = 0; | ||
195 | } | ||
196 | |||
197 | if (options & WDIOS_ENABLECARD) { | ||
198 | wdt_enable(); | ||
199 | retval = 0; | ||
200 | } | ||
201 | |||
202 | return retval; | ||
203 | } | ||
204 | case WDIOC_SETTIMEOUT:{ | ||
205 | int new_timeout; | ||
206 | |||
207 | if (get_user(new_timeout, (int __user *)arg)) | ||
208 | return -EFAULT; | ||
209 | |||
210 | if (wdt_set_timeout(new_timeout)) | ||
211 | return -EINVAL; | ||
212 | |||
213 | /* Fall through */ | ||
214 | } | ||
215 | case WDIOC_GETTIMEOUT: | ||
216 | return put_user(timeout, (int __user *)arg); | ||
217 | default: | ||
218 | return -ENOTTY; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static const struct file_operations wdt_fops = { | ||
223 | .owner = THIS_MODULE, | ||
224 | .llseek = no_llseek, | ||
225 | .write = fop_write, | ||
226 | .open = fop_open, | ||
227 | .release = fop_close, | ||
228 | .ioctl = fop_ioctl, | ||
229 | }; | ||
230 | |||
231 | static struct miscdevice wdt_miscdev = { | ||
232 | .minor = WATCHDOG_MINOR, | ||
233 | .name = "watchdog", | ||
234 | .fops = &wdt_fops, | ||
235 | }; | ||
236 | |||
237 | /* | ||
238 | * Notifier for system down | ||
239 | */ | ||
240 | |||
241 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
242 | void *unused) | ||
243 | { | ||
244 | if (code == SYS_DOWN || code == SYS_HALT) | ||
245 | wdt_disable(); | ||
246 | return NOTIFY_DONE; | ||
247 | } | ||
248 | |||
249 | static struct notifier_block wdt_notifier = { | ||
250 | .notifier_call = wdt_notify_sys, | ||
251 | }; | ||
252 | |||
253 | static void __exit sbc7240_wdt_unload(void) | ||
254 | { | ||
255 | printk(KERN_INFO SBC7240_PREFIX "Removing watchdog\n"); | ||
256 | misc_deregister(&wdt_miscdev); | ||
257 | |||
258 | unregister_reboot_notifier(&wdt_notifier); | ||
259 | release_region(SBC7240_ENABLE_PORT, 1); | ||
260 | } | ||
261 | |||
262 | static int __init sbc7240_wdt_init(void) | ||
263 | { | ||
264 | int rc = -EBUSY; | ||
265 | |||
266 | if (!request_region(SBC7240_ENABLE_PORT, 1, "SBC7240 WDT")) { | ||
267 | printk(KERN_ERR SBC7240_PREFIX | ||
268 | "I/O address 0x%04x already in use\n", | ||
269 | SBC7240_ENABLE_PORT); | ||
270 | rc = -EIO; | ||
271 | goto err_out; | ||
272 | } | ||
273 | |||
274 | /* The IO port 0x043 used to disable the watchdog | ||
275 | * is already claimed by the system timer, so we | ||
276 | * cant request_region() it ...*/ | ||
277 | |||
278 | if (timeout < 1 || timeout > SBC7240_MAX_TIMEOUT) { | ||
279 | timeout = SBC7240_TIMEOUT; | ||
280 | printk(KERN_INFO SBC7240_PREFIX | ||
281 | "timeout value must be 1<=x<=%d, using %d\n", | ||
282 | SBC7240_MAX_TIMEOUT, timeout); | ||
283 | } | ||
284 | wdt_set_timeout(timeout); | ||
285 | wdt_disable(); | ||
286 | |||
287 | rc = register_reboot_notifier(&wdt_notifier); | ||
288 | if (rc) { | ||
289 | printk(KERN_ERR SBC7240_PREFIX | ||
290 | "cannot register reboot notifier (err=%d)\n", rc); | ||
291 | goto err_out_region; | ||
292 | } | ||
293 | |||
294 | rc = misc_register(&wdt_miscdev); | ||
295 | if (rc) { | ||
296 | printk(KERN_ERR SBC7240_PREFIX | ||
297 | "cannot register miscdev on minor=%d (err=%d)\n", | ||
298 | wdt_miscdev.minor, rc); | ||
299 | goto err_out_reboot_notifier; | ||
300 | } | ||
301 | |||
302 | printk(KERN_INFO SBC7240_PREFIX | ||
303 | "Watchdog driver for SBC7240 initialised (nowayout=%d)\n", | ||
304 | nowayout); | ||
305 | |||
306 | return 0; | ||
307 | |||
308 | err_out_reboot_notifier: | ||
309 | unregister_reboot_notifier(&wdt_notifier); | ||
310 | err_out_region: | ||
311 | release_region(SBC7240_ENABLE_PORT, 1); | ||
312 | err_out: | ||
313 | return rc; | ||
314 | } | ||
315 | |||
316 | module_init(sbc7240_wdt_init); | ||
317 | module_exit(sbc7240_wdt_unload); | ||
318 | |||
319 | MODULE_AUTHOR("Gilles Gigan"); | ||
320 | MODULE_DESCRIPTION("Watchdog device driver for single board" | ||
321 | " computers EPIC Nano 7240 from iEi"); | ||
322 | MODULE_LICENSE("GPL"); | ||
323 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
324 | |||
diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c index d4fd0fa2f176..d55882bca319 100644 --- a/drivers/watchdog/scx200_wdt.c +++ b/drivers/watchdog/scx200_wdt.c | |||
@@ -231,17 +231,17 @@ static int __init scx200_wdt_init(void) | |||
231 | 231 | ||
232 | sema_init(&open_semaphore, 1); | 232 | sema_init(&open_semaphore, 1); |
233 | 233 | ||
234 | r = misc_register(&scx200_wdt_miscdev); | 234 | r = register_reboot_notifier(&scx200_wdt_notifier); |
235 | if (r) { | 235 | if (r) { |
236 | printk(KERN_ERR NAME ": unable to register reboot notifier"); | ||
236 | release_region(scx200_cb_base + SCx200_WDT_OFFSET, | 237 | release_region(scx200_cb_base + SCx200_WDT_OFFSET, |
237 | SCx200_WDT_SIZE); | 238 | SCx200_WDT_SIZE); |
238 | return r; | 239 | return r; |
239 | } | 240 | } |
240 | 241 | ||
241 | r = register_reboot_notifier(&scx200_wdt_notifier); | 242 | r = misc_register(&scx200_wdt_miscdev); |
242 | if (r) { | 243 | if (r) { |
243 | printk(KERN_ERR NAME ": unable to register reboot notifier"); | 244 | unregister_reboot_notifier(&scx200_wdt_notifier); |
244 | misc_deregister(&scx200_wdt_miscdev); | ||
245 | release_region(scx200_cb_base + SCx200_WDT_OFFSET, | 245 | release_region(scx200_cb_base + SCx200_WDT_OFFSET, |
246 | SCx200_WDT_SIZE); | 246 | SCx200_WDT_SIZE); |
247 | return r; | 247 | return r; |
@@ -252,8 +252,8 @@ static int __init scx200_wdt_init(void) | |||
252 | 252 | ||
253 | static void __exit scx200_wdt_cleanup(void) | 253 | static void __exit scx200_wdt_cleanup(void) |
254 | { | 254 | { |
255 | unregister_reboot_notifier(&scx200_wdt_notifier); | ||
256 | misc_deregister(&scx200_wdt_miscdev); | 255 | misc_deregister(&scx200_wdt_miscdev); |
256 | unregister_reboot_notifier(&scx200_wdt_notifier); | ||
257 | release_region(scx200_cb_base + SCx200_WDT_OFFSET, | 257 | release_region(scx200_cb_base + SCx200_WDT_OFFSET, |
258 | SCx200_WDT_SIZE); | 258 | SCx200_WDT_SIZE); |
259 | } | 259 | } |
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index cecbedd473a4..61dde863bd40 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c | |||
@@ -52,7 +52,7 @@ | |||
52 | * overflow periods respectively. | 52 | * overflow periods respectively. |
53 | * | 53 | * |
54 | * Also, since we can't really expect userspace to be responsive enough | 54 | * Also, since we can't really expect userspace to be responsive enough |
55 | * before the overflow happens, we maintain two seperate timers .. One in | 55 | * before the overflow happens, we maintain two separate timers .. One in |
56 | * the kernel for clearing out WOVF every 2ms or so (again, this depends on | 56 | * the kernel for clearing out WOVF every 2ms or so (again, this depends on |
57 | * HZ == 1000), and another for monitoring userspace writes to the WDT device. | 57 | * HZ == 1000), and another for monitoring userspace writes to the WDT device. |
58 | * | 58 | * |
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c new file mode 100644 index 000000000000..328b3c7211ef --- /dev/null +++ b/drivers/watchdog/txx9wdt.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | * txx9wdt: A Hardware Watchdog Driver for TXx9 SoCs | ||
3 | * | ||
4 | * Copyright (C) 2007 Atsushi Nemoto <anemo@mba.ocn.ne.jp> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/moduleparam.h> | ||
12 | #include <linux/types.h> | ||
13 | #include <linux/miscdevice.h> | ||
14 | #include <linux/watchdog.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/reboot.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/uaccess.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <asm/txx9tmr.h> | ||
24 | |||
25 | #define TIMER_MARGIN 60 /* Default is 60 seconds */ | ||
26 | |||
27 | static int timeout = TIMER_MARGIN; /* in seconds */ | ||
28 | module_param(timeout, int, 0); | ||
29 | MODULE_PARM_DESC(timeout, | ||
30 | "Watchdog timeout in seconds. " | ||
31 | "(0<timeout<((2^" __MODULE_STRING(TXX9_TIMER_BITS) ")/(IMCLK/256)), " | ||
32 | "default=" __MODULE_STRING(TIMER_MARGIN) ")"); | ||
33 | |||
34 | static int nowayout = WATCHDOG_NOWAYOUT; | ||
35 | module_param(nowayout, int, 0); | ||
36 | MODULE_PARM_DESC(nowayout, | ||
37 | "Watchdog cannot be stopped once started " | ||
38 | "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
39 | |||
40 | #define WD_TIMER_CCD 7 /* 1/256 */ | ||
41 | #define WD_TIMER_CLK (clk_get_rate(txx9_imclk) / (2 << WD_TIMER_CCD)) | ||
42 | #define WD_MAX_TIMEOUT ((0xffffffff >> (32 - TXX9_TIMER_BITS)) / WD_TIMER_CLK) | ||
43 | |||
44 | static unsigned long txx9wdt_alive; | ||
45 | static int expect_close; | ||
46 | static struct txx9_tmr_reg __iomem *txx9wdt_reg; | ||
47 | static struct clk *txx9_imclk; | ||
48 | |||
49 | static void txx9wdt_ping(void) | ||
50 | { | ||
51 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); | ||
52 | } | ||
53 | |||
54 | static void txx9wdt_start(void) | ||
55 | { | ||
56 | __raw_writel(WD_TIMER_CLK * timeout, &txx9wdt_reg->cpra); | ||
57 | __raw_writel(WD_TIMER_CCD, &txx9wdt_reg->ccdr); | ||
58 | __raw_writel(0, &txx9wdt_reg->tisr); /* clear pending interrupt */ | ||
59 | __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG, | ||
60 | &txx9wdt_reg->tcr); | ||
61 | __raw_writel(TXx9_TMWTMR_TWIE | TXx9_TMWTMR_TWC, &txx9wdt_reg->wtmr); | ||
62 | } | ||
63 | |||
64 | static void txx9wdt_stop(void) | ||
65 | { | ||
66 | __raw_writel(TXx9_TMWTMR_WDIS, &txx9wdt_reg->wtmr); | ||
67 | __raw_writel(__raw_readl(&txx9wdt_reg->tcr) & ~TXx9_TMTCR_TCE, | ||
68 | &txx9wdt_reg->tcr); | ||
69 | } | ||
70 | |||
71 | static int txx9wdt_open(struct inode *inode, struct file *file) | ||
72 | { | ||
73 | if (test_and_set_bit(0, &txx9wdt_alive)) | ||
74 | return -EBUSY; | ||
75 | |||
76 | if (__raw_readl(&txx9wdt_reg->tcr) & TXx9_TMTCR_TCE) { | ||
77 | clear_bit(0, &txx9wdt_alive); | ||
78 | return -EBUSY; | ||
79 | } | ||
80 | |||
81 | if (nowayout) | ||
82 | __module_get(THIS_MODULE); | ||
83 | |||
84 | txx9wdt_start(); | ||
85 | return nonseekable_open(inode, file); | ||
86 | } | ||
87 | |||
88 | static int txx9wdt_release(struct inode *inode, struct file *file) | ||
89 | { | ||
90 | if (expect_close) | ||
91 | txx9wdt_stop(); | ||
92 | else { | ||
93 | printk(KERN_CRIT "txx9wdt: " | ||
94 | "Unexpected close, not stopping watchdog!\n"); | ||
95 | txx9wdt_ping(); | ||
96 | } | ||
97 | clear_bit(0, &txx9wdt_alive); | ||
98 | expect_close = 0; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static ssize_t txx9wdt_write(struct file *file, const char __user *data, | ||
103 | size_t len, loff_t *ppos) | ||
104 | { | ||
105 | if (len) { | ||
106 | if (!nowayout) { | ||
107 | size_t i; | ||
108 | |||
109 | expect_close = 0; | ||
110 | for (i = 0; i != len; i++) { | ||
111 | char c; | ||
112 | if (get_user(c, data + i)) | ||
113 | return -EFAULT; | ||
114 | if (c == 'V') | ||
115 | expect_close = 1; | ||
116 | } | ||
117 | } | ||
118 | txx9wdt_ping(); | ||
119 | } | ||
120 | return len; | ||
121 | } | ||
122 | |||
123 | static int txx9wdt_ioctl(struct inode *inode, struct file *file, | ||
124 | unsigned int cmd, unsigned long arg) | ||
125 | { | ||
126 | void __user *argp = (void __user *)arg; | ||
127 | int __user *p = argp; | ||
128 | int new_timeout; | ||
129 | static struct watchdog_info ident = { | ||
130 | .options = WDIOF_SETTIMEOUT | | ||
131 | WDIOF_KEEPALIVEPING | | ||
132 | WDIOF_MAGICCLOSE, | ||
133 | .firmware_version = 0, | ||
134 | .identity = "Hardware Watchdog for TXx9", | ||
135 | }; | ||
136 | |||
137 | switch (cmd) { | ||
138 | default: | ||
139 | return -ENOTTY; | ||
140 | case WDIOC_GETSUPPORT: | ||
141 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
142 | case WDIOC_GETSTATUS: | ||
143 | case WDIOC_GETBOOTSTATUS: | ||
144 | return put_user(0, p); | ||
145 | case WDIOC_KEEPALIVE: | ||
146 | txx9wdt_ping(); | ||
147 | return 0; | ||
148 | case WDIOC_SETTIMEOUT: | ||
149 | if (get_user(new_timeout, p)) | ||
150 | return -EFAULT; | ||
151 | if (new_timeout < 1 || new_timeout > WD_MAX_TIMEOUT) | ||
152 | return -EINVAL; | ||
153 | timeout = new_timeout; | ||
154 | txx9wdt_stop(); | ||
155 | txx9wdt_start(); | ||
156 | /* Fall */ | ||
157 | case WDIOC_GETTIMEOUT: | ||
158 | return put_user(timeout, p); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | static int txx9wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
163 | void *unused) | ||
164 | { | ||
165 | if (code == SYS_DOWN || code == SYS_HALT) | ||
166 | txx9wdt_stop(); | ||
167 | return NOTIFY_DONE; | ||
168 | } | ||
169 | |||
170 | static const struct file_operations txx9wdt_fops = { | ||
171 | .owner = THIS_MODULE, | ||
172 | .llseek = no_llseek, | ||
173 | .write = txx9wdt_write, | ||
174 | .ioctl = txx9wdt_ioctl, | ||
175 | .open = txx9wdt_open, | ||
176 | .release = txx9wdt_release, | ||
177 | }; | ||
178 | |||
179 | static struct miscdevice txx9wdt_miscdev = { | ||
180 | .minor = WATCHDOG_MINOR, | ||
181 | .name = "watchdog", | ||
182 | .fops = &txx9wdt_fops, | ||
183 | }; | ||
184 | |||
185 | static struct notifier_block txx9wdt_notifier = { | ||
186 | .notifier_call = txx9wdt_notify_sys | ||
187 | }; | ||
188 | |||
189 | static int __init txx9wdt_probe(struct platform_device *dev) | ||
190 | { | ||
191 | struct resource *res; | ||
192 | int ret; | ||
193 | |||
194 | txx9_imclk = clk_get(NULL, "imbus_clk"); | ||
195 | if (IS_ERR(txx9_imclk)) { | ||
196 | ret = PTR_ERR(txx9_imclk); | ||
197 | txx9_imclk = NULL; | ||
198 | goto exit; | ||
199 | } | ||
200 | ret = clk_enable(txx9_imclk); | ||
201 | if (ret) { | ||
202 | clk_put(txx9_imclk); | ||
203 | txx9_imclk = NULL; | ||
204 | goto exit; | ||
205 | } | ||
206 | |||
207 | res = platform_get_resource(dev, IORESOURCE_MEM, 0); | ||
208 | if (!res) | ||
209 | goto exit_busy; | ||
210 | if (!devm_request_mem_region(&dev->dev, | ||
211 | res->start, res->end - res->start + 1, | ||
212 | "txx9wdt")) | ||
213 | goto exit_busy; | ||
214 | txx9wdt_reg = devm_ioremap(&dev->dev, | ||
215 | res->start, res->end - res->start + 1); | ||
216 | if (!txx9wdt_reg) | ||
217 | goto exit_busy; | ||
218 | |||
219 | ret = register_reboot_notifier(&txx9wdt_notifier); | ||
220 | if (ret) | ||
221 | goto exit; | ||
222 | |||
223 | ret = misc_register(&txx9wdt_miscdev); | ||
224 | if (ret) { | ||
225 | unregister_reboot_notifier(&txx9wdt_notifier); | ||
226 | goto exit; | ||
227 | } | ||
228 | |||
229 | printk(KERN_INFO "Hardware Watchdog Timer for TXx9: " | ||
230 | "timeout=%d sec (max %ld) (nowayout= %d)\n", | ||
231 | timeout, WD_MAX_TIMEOUT, nowayout); | ||
232 | |||
233 | return 0; | ||
234 | exit_busy: | ||
235 | ret = -EBUSY; | ||
236 | exit: | ||
237 | if (txx9_imclk) { | ||
238 | clk_disable(txx9_imclk); | ||
239 | clk_put(txx9_imclk); | ||
240 | } | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | static int __exit txx9wdt_remove(struct platform_device *dev) | ||
245 | { | ||
246 | misc_deregister(&txx9wdt_miscdev); | ||
247 | unregister_reboot_notifier(&txx9wdt_notifier); | ||
248 | clk_disable(txx9_imclk); | ||
249 | clk_put(txx9_imclk); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static struct platform_driver txx9wdt_driver = { | ||
254 | .remove = __exit_p(txx9wdt_remove), | ||
255 | .driver = { | ||
256 | .name = "txx9wdt", | ||
257 | .owner = THIS_MODULE, | ||
258 | }, | ||
259 | }; | ||
260 | |||
261 | static int __init watchdog_init(void) | ||
262 | { | ||
263 | return platform_driver_probe(&txx9wdt_driver, txx9wdt_probe); | ||
264 | } | ||
265 | |||
266 | static void __exit watchdog_exit(void) | ||
267 | { | ||
268 | platform_driver_unregister(&txx9wdt_driver); | ||
269 | } | ||
270 | |||
271 | module_init(watchdog_init); | ||
272 | module_exit(watchdog_exit); | ||
273 | |||
274 | MODULE_DESCRIPTION("TXx9 Watchdog Driver"); | ||
275 | MODULE_LICENSE("GPL"); | ||
276 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c index bcc9d48955de..f510a3a595e6 100644 --- a/drivers/watchdog/w83877f_wdt.c +++ b/drivers/watchdog/w83877f_wdt.c | |||
@@ -373,20 +373,20 @@ static int __init w83877f_wdt_init(void) | |||
373 | goto err_out_region1; | 373 | goto err_out_region1; |
374 | } | 374 | } |
375 | 375 | ||
376 | rc = misc_register(&wdt_miscdev); | 376 | rc = register_reboot_notifier(&wdt_notifier); |
377 | if (rc) | 377 | if (rc) |
378 | { | 378 | { |
379 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 379 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", |
380 | wdt_miscdev.minor, rc); | 380 | rc); |
381 | goto err_out_region2; | 381 | goto err_out_region2; |
382 | } | 382 | } |
383 | 383 | ||
384 | rc = register_reboot_notifier(&wdt_notifier); | 384 | rc = misc_register(&wdt_miscdev); |
385 | if (rc) | 385 | if (rc) |
386 | { | 386 | { |
387 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 387 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", |
388 | rc); | 388 | wdt_miscdev.minor, rc); |
389 | goto err_out_miscdev; | 389 | goto err_out_reboot; |
390 | } | 390 | } |
391 | 391 | ||
392 | printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n", | 392 | printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n", |
@@ -394,8 +394,8 @@ static int __init w83877f_wdt_init(void) | |||
394 | 394 | ||
395 | return 0; | 395 | return 0; |
396 | 396 | ||
397 | err_out_miscdev: | 397 | err_out_reboot: |
398 | misc_deregister(&wdt_miscdev); | 398 | unregister_reboot_notifier(&wdt_notifier); |
399 | err_out_region2: | 399 | err_out_region2: |
400 | release_region(WDT_PING,1); | 400 | release_region(WDT_PING,1); |
401 | err_out_region1: | 401 | err_out_region1: |
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c index b475529d2475..b209bcd7f789 100644 --- a/drivers/watchdog/w83977f_wdt.c +++ b/drivers/watchdog/w83977f_wdt.c | |||
@@ -494,20 +494,20 @@ static int __init w83977f_wdt_init(void) | |||
494 | goto err_out; | 494 | goto err_out; |
495 | } | 495 | } |
496 | 496 | ||
497 | rc = misc_register(&wdt_miscdev); | 497 | rc = register_reboot_notifier(&wdt_notifier); |
498 | if (rc) | 498 | if (rc) |
499 | { | 499 | { |
500 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 500 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", |
501 | wdt_miscdev.minor, rc); | 501 | rc); |
502 | goto err_out_region; | 502 | goto err_out_region; |
503 | } | 503 | } |
504 | 504 | ||
505 | rc = register_reboot_notifier(&wdt_notifier); | 505 | rc = misc_register(&wdt_miscdev); |
506 | if (rc) | 506 | if (rc) |
507 | { | 507 | { |
508 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 508 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", |
509 | rc); | 509 | wdt_miscdev.minor, rc); |
510 | goto err_out_miscdev; | 510 | goto err_out_reboot; |
511 | } | 511 | } |
512 | 512 | ||
513 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", | 513 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", |
@@ -515,8 +515,8 @@ static int __init w83977f_wdt_init(void) | |||
515 | 515 | ||
516 | return 0; | 516 | return 0; |
517 | 517 | ||
518 | err_out_miscdev: | 518 | err_out_reboot: |
519 | misc_deregister(&wdt_miscdev); | 519 | unregister_reboot_notifier(&wdt_notifier); |
520 | err_out_region: | 520 | err_out_region: |
521 | release_region(IO_INDEX_PORT,2); | 521 | release_region(IO_INDEX_PORT,2); |
522 | err_out: | 522 | err_out: |
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c index 53d0bb410df8..756fb15fdce7 100644 --- a/drivers/watchdog/wdt.c +++ b/drivers/watchdog/wdt.c | |||
@@ -70,6 +70,8 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _ | |||
70 | static int io=0x240; | 70 | static int io=0x240; |
71 | static int irq=11; | 71 | static int irq=11; |
72 | 72 | ||
73 | static DEFINE_SPINLOCK(wdt_lock); | ||
74 | |||
73 | module_param(io, int, 0); | 75 | module_param(io, int, 0); |
74 | MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); | 76 | MODULE_PARM_DESC(io, "WDT io port (default=0x240)"); |
75 | module_param(irq, int, 0); | 77 | module_param(irq, int, 0); |
@@ -109,6 +111,8 @@ static void wdt_ctr_load(int ctr, int val) | |||
109 | 111 | ||
110 | static int wdt_start(void) | 112 | static int wdt_start(void) |
111 | { | 113 | { |
114 | unsigned long flags; | ||
115 | spin_lock_irqsave(&wdt_lock, flags); | ||
112 | inb_p(WDT_DC); /* Disable watchdog */ | 116 | inb_p(WDT_DC); /* Disable watchdog */ |
113 | wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ | 117 | wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */ |
114 | wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ | 118 | wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */ |
@@ -117,6 +121,7 @@ static int wdt_start(void) | |||
117 | wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ | 121 | wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ |
118 | wdt_ctr_load(2,65535); /* Length of reset pulse */ | 122 | wdt_ctr_load(2,65535); /* Length of reset pulse */ |
119 | outb_p(0, WDT_DC); /* Enable watchdog */ | 123 | outb_p(0, WDT_DC); /* Enable watchdog */ |
124 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
120 | return 0; | 125 | return 0; |
121 | } | 126 | } |
122 | 127 | ||
@@ -128,9 +133,12 @@ static int wdt_start(void) | |||
128 | 133 | ||
129 | static int wdt_stop (void) | 134 | static int wdt_stop (void) |
130 | { | 135 | { |
136 | unsigned long flags; | ||
137 | spin_lock_irqsave(&wdt_lock, flags); | ||
131 | /* Turn the card off */ | 138 | /* Turn the card off */ |
132 | inb_p(WDT_DC); /* Disable watchdog */ | 139 | inb_p(WDT_DC); /* Disable watchdog */ |
133 | wdt_ctr_load(2,0); /* 0 length reset pulses now */ | 140 | wdt_ctr_load(2,0); /* 0 length reset pulses now */ |
141 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
134 | return 0; | 142 | return 0; |
135 | } | 143 | } |
136 | 144 | ||
@@ -143,11 +151,14 @@ static int wdt_stop (void) | |||
143 | 151 | ||
144 | static int wdt_ping(void) | 152 | static int wdt_ping(void) |
145 | { | 153 | { |
154 | unsigned long flags; | ||
155 | spin_lock_irqsave(&wdt_lock, flags); | ||
146 | /* Write a watchdog value */ | 156 | /* Write a watchdog value */ |
147 | inb_p(WDT_DC); /* Disable watchdog */ | 157 | inb_p(WDT_DC); /* Disable watchdog */ |
148 | wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ | 158 | wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */ |
149 | wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ | 159 | wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */ |
150 | outb_p(0, WDT_DC); /* Enable watchdog */ | 160 | outb_p(0, WDT_DC); /* Enable watchdog */ |
161 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
151 | return 0; | 162 | return 0; |
152 | } | 163 | } |
153 | 164 | ||
@@ -182,7 +193,12 @@ static int wdt_set_heartbeat(int t) | |||
182 | 193 | ||
183 | static int wdt_get_status(int *status) | 194 | static int wdt_get_status(int *status) |
184 | { | 195 | { |
185 | unsigned char new_status=inb_p(WDT_SR); | 196 | unsigned char new_status; |
197 | unsigned long flags; | ||
198 | |||
199 | spin_lock_irqsave(&wdt_lock, flags); | ||
200 | new_status = inb_p(WDT_SR); | ||
201 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
186 | 202 | ||
187 | *status=0; | 203 | *status=0; |
188 | if (new_status & WDC_SR_ISOI0) | 204 | if (new_status & WDC_SR_ISOI0) |
@@ -214,8 +230,12 @@ static int wdt_get_status(int *status) | |||
214 | 230 | ||
215 | static int wdt_get_temperature(int *temperature) | 231 | static int wdt_get_temperature(int *temperature) |
216 | { | 232 | { |
217 | unsigned short c=inb_p(WDT_RT); | 233 | unsigned short c; |
234 | unsigned long flags; | ||
218 | 235 | ||
236 | spin_lock_irqsave(&wdt_lock, flags); | ||
237 | c = inb_p(WDT_RT); | ||
238 | spin_unlock_irqrestore(&wdt_lock, flags); | ||
219 | *temperature = (c * 11 / 15) + 7; | 239 | *temperature = (c * 11 / 15) + 7; |
220 | return 0; | 240 | return 0; |
221 | } | 241 | } |
@@ -237,7 +257,10 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id) | |||
237 | * Read the status register see what is up and | 257 | * Read the status register see what is up and |
238 | * then printk it. | 258 | * then printk it. |
239 | */ | 259 | */ |
240 | unsigned char status=inb_p(WDT_SR); | 260 | unsigned char status; |
261 | |||
262 | spin_lock(&wdt_lock); | ||
263 | status = inb_p(WDT_SR); | ||
241 | 264 | ||
242 | printk(KERN_CRIT "WDT status %d\n", status); | 265 | printk(KERN_CRIT "WDT status %d\n", status); |
243 | 266 | ||
@@ -265,6 +288,7 @@ static irqreturn_t wdt_interrupt(int irq, void *dev_id) | |||
265 | printk(KERN_CRIT "Reset in 5ms.\n"); | 288 | printk(KERN_CRIT "Reset in 5ms.\n"); |
266 | #endif | 289 | #endif |
267 | } | 290 | } |
291 | spin_unlock(&wdt_lock); | ||
268 | return IRQ_HANDLED; | 292 | return IRQ_HANDLED; |
269 | } | 293 | } |
270 | 294 | ||
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c index 9b7f6b6edef6..fb4b876c9fda 100644 --- a/drivers/watchdog/wdt977.c +++ b/drivers/watchdog/wdt977.c | |||
@@ -470,20 +470,20 @@ static int __init wd977_init(void) | |||
470 | } | 470 | } |
471 | } | 471 | } |
472 | 472 | ||
473 | rc = misc_register(&wdt977_miscdev); | 473 | rc = register_reboot_notifier(&wdt977_notifier); |
474 | if (rc) | 474 | if (rc) |
475 | { | 475 | { |
476 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 476 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", |
477 | wdt977_miscdev.minor, rc); | 477 | rc); |
478 | goto err_out_region; | 478 | goto err_out_region; |
479 | } | 479 | } |
480 | 480 | ||
481 | rc = register_reboot_notifier(&wdt977_notifier); | 481 | rc = misc_register(&wdt977_miscdev); |
482 | if (rc) | 482 | if (rc) |
483 | { | 483 | { |
484 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 484 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", |
485 | rc); | 485 | wdt977_miscdev.minor, rc); |
486 | goto err_out_miscdev; | 486 | goto err_out_reboot; |
487 | } | 487 | } |
488 | 488 | ||
489 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", | 489 | printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n", |
@@ -491,8 +491,8 @@ static int __init wd977_init(void) | |||
491 | 491 | ||
492 | return 0; | 492 | return 0; |
493 | 493 | ||
494 | err_out_miscdev: | 494 | err_out_reboot: |
495 | misc_deregister(&wdt977_miscdev); | 495 | unregister_reboot_notifier(&wdt977_notifier); |
496 | err_out_region: | 496 | err_out_region: |
497 | if (!machine_is_netwinder()) | 497 | if (!machine_is_netwinder()) |
498 | release_region(IO_INDEX_PORT,2); | 498 | release_region(IO_INDEX_PORT,2); |