aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog/wdt977.c
diff options
context:
space:
mode:
authorWoody Suwalski <woodys@xandros.com>2006-01-08 04:00:31 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 23:12:39 -0500
commit4dab06fa7b6d07ee95c8bba5ddd0840633069159 (patch)
tree18c54a1af00ec4effc062d67f45dfc3d8bc096ee /drivers/char/watchdog/wdt977.c
parent70c00ba0bbfb583e39b964ebd88620c18aa02c62 (diff)
[PATCH] ARM Netwinder watchdog wdt977 update
Cleanup for the ARM-only watchdog driver wdt977. This is probably the last update, since we want to merge with w83977f_wdt. Jose Goncalves has ported this driver to i386, so probably we can iron out configuration differences. Signed-off-by: Woody Suwalski <woodys@xandros.com> Cc: Russell King <rmk@arm.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/watchdog/wdt977.c')
-rw-r--r--drivers/char/watchdog/wdt977.c216
1 files changed, 141 insertions, 75 deletions
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
index 44d49dfacbb3..3843900e94c4 100644
--- a/drivers/char/watchdog/wdt977.c
+++ b/drivers/char/watchdog/wdt977.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Wdt977 0.03: A Watchdog Device for Netwinder W83977AF chip 2 * Wdt977 0.04: A Watchdog Device for Netwinder W83977AF chip
3 * 3 *
4 * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>) 4 * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
5 * 5 *
@@ -18,6 +18,8 @@
18 * from minutes to seconds. 18 * from minutes to seconds.
19 * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in 19 * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
20 * nwwatchdog_init. 20 * nwwatchdog_init.
21 * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks
22 * remove limitiation to be used on Netwinders only
21 */ 23 */
22 24
23#include <linux/module.h> 25#include <linux/module.h>
@@ -28,6 +30,7 @@
28#include <linux/fs.h> 30#include <linux/fs.h>
29#include <linux/miscdevice.h> 31#include <linux/miscdevice.h>
30#include <linux/init.h> 32#include <linux/init.h>
33#include <linux/ioport.h>
31#include <linux/watchdog.h> 34#include <linux/watchdog.h>
32#include <linux/notifier.h> 35#include <linux/notifier.h>
33#include <linux/reboot.h> 36#include <linux/reboot.h>
@@ -37,8 +40,18 @@
37#include <asm/mach-types.h> 40#include <asm/mach-types.h>
38#include <asm/uaccess.h> 41#include <asm/uaccess.h>
39 42
40#define PFX "Wdt977: " 43#define WATCHDOG_VERSION "0.04"
41#define WATCHDOG_MINOR 130 44#define WATCHDOG_NAME "Wdt977"
45#define PFX WATCHDOG_NAME ": "
46#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
47
48#define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */
49#define IO_DATA_PORT (IO_INDEX_PORT+1)
50
51#define UNLOCK_DATA 0x87
52#define LOCK_DATA 0xAA
53#define DEVICE_REGISTER 0x07
54
42 55
43#define DEFAULT_TIMEOUT 60 /* default timeout in seconds */ 56#define DEFAULT_TIMEOUT 60 /* default timeout in seconds */
44 57
@@ -47,6 +60,7 @@ static int timeoutM; /* timeout in minutes */
47static unsigned long timer_alive; 60static unsigned long timer_alive;
48static int testmode; 61static int testmode;
49static char expect_close; 62static char expect_close;
63static spinlock_t spinlock;
50 64
51module_param(timeout, int, 0); 65module_param(timeout, int, 0);
52MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); 66MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
@@ -63,9 +77,13 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CON
63 77
64static int wdt977_start(void) 78static int wdt977_start(void)
65{ 79{
80 unsigned long flags;
81
82 spin_lock_irqsave(&spinlock, flags);
83
66 /* unlock the SuperIO chip */ 84 /* unlock the SuperIO chip */
67 outb(0x87,0x370); 85 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
68 outb(0x87,0x370); 86 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
69 87
70 /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4 88 /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
71 * F2 has the timeout in minutes 89 * F2 has the timeout in minutes
@@ -73,28 +91,29 @@ static int wdt977_start(void)
73 * at timeout, and to reset timer on kbd/mouse activity (not impl.) 91 * at timeout, and to reset timer on kbd/mouse activity (not impl.)
74 * F4 is used to just clear the TIMEOUT'ed state (bit 0) 92 * F4 is used to just clear the TIMEOUT'ed state (bit 0)
75 */ 93 */
76 outb(0x07,0x370); 94 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
77 outb(0x08,0x371); 95 outb_p(0x08, IO_DATA_PORT);
78 outb(0xF2,0x370); 96 outb_p(0xF2, IO_INDEX_PORT);
79 outb(timeoutM,0x371); 97 outb_p(timeoutM, IO_DATA_PORT);
80 outb(0xF3,0x370); 98 outb_p(0xF3, IO_INDEX_PORT);
81 outb(0x00,0x371); /* another setting is 0E for kbd/mouse/LED */ 99 outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for kbd/mouse/LED */
82 outb(0xF4,0x370); 100 outb_p(0xF4, IO_INDEX_PORT);
83 outb(0x00,0x371); 101 outb_p(0x00, IO_DATA_PORT);
84 102
85 /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ 103 /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
86 /* in test mode watch the bit 1 on F4 to indicate "triggered" */ 104 /* in test mode watch the bit 1 on F4 to indicate "triggered" */
87 if (!testmode) 105 if (!testmode)
88 { 106 {
89 outb(0x07,0x370); 107 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
90 outb(0x07,0x371); 108 outb_p(0x07, IO_DATA_PORT);
91 outb(0xE6,0x370); 109 outb_p(0xE6, IO_INDEX_PORT);
92 outb(0x08,0x371); 110 outb_p(0x08, IO_DATA_PORT);
93 } 111 }
94 112
95 /* lock the SuperIO chip */ 113 /* lock the SuperIO chip */
96 outb(0xAA,0x370); 114 outb_p(LOCK_DATA, IO_INDEX_PORT);
97 115
116 spin_unlock_irqrestore(&spinlock, flags);
98 printk(KERN_INFO PFX "activated.\n"); 117 printk(KERN_INFO PFX "activated.\n");
99 118
100 return 0; 119 return 0;
@@ -106,35 +125,39 @@ static int wdt977_start(void)
106 125
107static int wdt977_stop(void) 126static int wdt977_stop(void)
108{ 127{
128 unsigned long flags;
129 spin_lock_irqsave(&spinlock, flags);
130
109 /* unlock the SuperIO chip */ 131 /* unlock the SuperIO chip */
110 outb(0x87,0x370); 132 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
111 outb(0x87,0x370); 133 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
112 134
113 /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4 135 /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
114 * F3 is reset to its default state 136 * F3 is reset to its default state
115 * F4 can clear the TIMEOUT'ed state (bit 0) - back to default 137 * F4 can clear the TIMEOUT'ed state (bit 0) - back to default
116 * We can not use GP17 as a PowerLed, as we use its usage as a RedLed 138 * We can not use GP17 as a PowerLed, as we use its usage as a RedLed
117 */ 139 */
118 outb(0x07,0x370); 140 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
119 outb(0x08,0x371); 141 outb_p(0x08, IO_DATA_PORT);
120 outb(0xF2,0x370); 142 outb_p(0xF2, IO_INDEX_PORT);
121 outb(0xFF,0x371); 143 outb_p(0xFF, IO_DATA_PORT);
122 outb(0xF3,0x370); 144 outb_p(0xF3, IO_INDEX_PORT);
123 outb(0x00,0x371); 145 outb_p(0x00, IO_DATA_PORT);
124 outb(0xF4,0x370); 146 outb_p(0xF4, IO_INDEX_PORT);
125 outb(0x00,0x371); 147 outb_p(0x00, IO_DATA_PORT);
126 outb(0xF2,0x370); 148 outb_p(0xF2, IO_INDEX_PORT);
127 outb(0x00,0x371); 149 outb_p(0x00, IO_DATA_PORT);
128 150
129 /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */ 151 /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
130 outb(0x07,0x370); 152 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
131 outb(0x07,0x371); 153 outb_p(0x07, IO_DATA_PORT);
132 outb(0xE6,0x370); 154 outb_p(0xE6, IO_INDEX_PORT);
133 outb(0x08,0x371); 155 outb_p(0x08, IO_DATA_PORT);
134 156
135 /* lock the SuperIO chip */ 157 /* lock the SuperIO chip */
136 outb(0xAA,0x370); 158 outb_p(LOCK_DATA, IO_INDEX_PORT);
137 159
160 spin_unlock_irqrestore(&spinlock, flags);
138 printk(KERN_INFO PFX "shutdown.\n"); 161 printk(KERN_INFO PFX "shutdown.\n");
139 162
140 return 0; 163 return 0;
@@ -147,19 +170,23 @@ static int wdt977_stop(void)
147 170
148static int wdt977_keepalive(void) 171static int wdt977_keepalive(void)
149{ 172{
173 unsigned long flags;
174 spin_lock_irqsave(&spinlock, flags);
175
150 /* unlock the SuperIO chip */ 176 /* unlock the SuperIO chip */
151 outb(0x87,0x370); 177 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
152 outb(0x87,0x370); 178 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
153 179
154 /* select device Aux2 (device=8) and kicks watchdog reg F2 */ 180 /* select device Aux2 (device=8) and kicks watchdog reg F2 */
155 /* F2 has the timeout in minutes */ 181 /* F2 has the timeout in minutes */
156 outb(0x07,0x370); 182 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
157 outb(0x08,0x371); 183 outb_p(0x08, IO_DATA_PORT);
158 outb(0xF2,0x370); 184 outb_p(0xF2, IO_INDEX_PORT);
159 outb(timeoutM,0x371); 185 outb_p(timeoutM, IO_DATA_PORT);
160 186
161 /* lock the SuperIO chip */ 187 /* lock the SuperIO chip */
162 outb(0xAA,0x370); 188 outb_p(LOCK_DATA, IO_INDEX_PORT);
189 spin_unlock_irqrestore(&spinlock, flags);
163 190
164 return 0; 191 return 0;
165} 192}
@@ -198,22 +225,26 @@ static int wdt977_set_timeout(int t)
198static int wdt977_get_status(int *status) 225static int wdt977_get_status(int *status)
199{ 226{
200 int new_status; 227 int new_status;
228 unsigned long flags;
201 229
202 *status=0; 230 spin_lock_irqsave(&spinlock, flags);
203 231
204 /* unlock the SuperIO chip */ 232 /* unlock the SuperIO chip */
205 outb(0x87,0x370); 233 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
206 outb(0x87,0x370); 234 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
207 235
208 /* select device Aux2 (device=8) and read watchdog reg F4 */ 236 /* select device Aux2 (device=8) and read watchdog reg F4 */
209 outb(0x07,0x370); 237 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
210 outb(0x08,0x371); 238 outb_p(0x08, IO_DATA_PORT);
211 outb(0xF4,0x370); 239 outb_p(0xF4, IO_INDEX_PORT);
212 new_status = inb(0x371); 240 new_status = inb_p(IO_DATA_PORT);
213 241
214 /* lock the SuperIO chip */ 242 /* lock the SuperIO chip */
215 outb(0xAA,0x370); 243 outb_p(LOCK_DATA, IO_INDEX_PORT);
216 244
245 spin_unlock_irqrestore(&spinlock, flags);
246
247 *status=0;
217 if (new_status & 1) 248 if (new_status & 1)
218 *status |= WDIOF_CARDRESET; 249 *status |= WDIOF_CARDRESET;
219 250
@@ -249,8 +280,8 @@ static int wdt977_release(struct inode *inode, struct file *file)
249 wdt977_stop(); 280 wdt977_stop();
250 clear_bit(0,&timer_alive); 281 clear_bit(0,&timer_alive);
251 } else { 282 } else {
252 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
253 wdt977_keepalive(); 283 wdt977_keepalive();
284 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
254 } 285 }
255 expect_close = 0; 286 expect_close = 0;
256 return 0; 287 return 0;
@@ -271,14 +302,17 @@ static int wdt977_release(struct inode *inode, struct file *file)
271static ssize_t wdt977_write(struct file *file, const char __user *buf, 302static ssize_t wdt977_write(struct file *file, const char __user *buf,
272 size_t count, loff_t *ppos) 303 size_t count, loff_t *ppos)
273{ 304{
274 if (count) { 305 if (count)
275 if (!nowayout) { 306 {
307 if (!nowayout)
308 {
276 size_t i; 309 size_t i;
277 310
278 /* In case it was set long ago */ 311 /* In case it was set long ago */
279 expect_close = 0; 312 expect_close = 0;
280 313
281 for (i = 0; i != count; i++) { 314 for (i = 0; i != count; i++)
315 {
282 char c; 316 char c;
283 if (get_user(c, buf + i)) 317 if (get_user(c, buf + i))
284 return -EFAULT; 318 return -EFAULT;
@@ -287,6 +321,7 @@ static ssize_t wdt977_write(struct file *file, const char __user *buf,
287 } 321 }
288 } 322 }
289 323
324 /* someone wrote to us, we should restart timer */
290 wdt977_keepalive(); 325 wdt977_keepalive();
291 } 326 }
292 return count; 327 return count;
@@ -308,7 +343,7 @@ static struct watchdog_info ident = {
308 WDIOF_MAGICCLOSE | 343 WDIOF_MAGICCLOSE |
309 WDIOF_KEEPALIVEPING, 344 WDIOF_KEEPALIVEPING,
310 .firmware_version = 1, 345 .firmware_version = 1,
311 .identity = "Winbond 83977", 346 .identity = WATCHDOG_NAME,
312}; 347};
313 348
314static int wdt977_ioctl(struct inode *inode, struct file *file, 349static int wdt977_ioctl(struct inode *inode, struct file *file,
@@ -405,50 +440,81 @@ static struct notifier_block wdt977_notifier = {
405 .notifier_call = wdt977_notify_sys, 440 .notifier_call = wdt977_notify_sys,
406}; 441};
407 442
408static int __init nwwatchdog_init(void) 443static int __init wd977_init(void)
409{ 444{
410 int retval; 445 int rc;
411 if (!machine_is_netwinder()) 446
412 return -ENODEV; 447 //if (!machine_is_netwinder())
448 // return -ENODEV;
449
450 printk(KERN_INFO PFX DRIVER_VERSION);
451
452 spin_lock_init(&spinlock);
413 453
414 /* Check that the timeout value is within it's range ; if not reset to the default */ 454 /* Check that the timeout value is within it's range ; if not reset to the default */
415 if (wdt977_set_timeout(timeout)) { 455 if (wdt977_set_timeout(timeout))
456 {
416 wdt977_set_timeout(DEFAULT_TIMEOUT); 457 wdt977_set_timeout(DEFAULT_TIMEOUT);
417 printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n", 458 printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n",
418 DEFAULT_TIMEOUT); 459 DEFAULT_TIMEOUT);
419 } 460 }
420 461
421 retval = register_reboot_notifier(&wdt977_notifier); 462 /* on Netwinder the IOports are already reserved by
422 if (retval) { 463 * arch/arm/mach-footbridge/netwinder-hw.c
423 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", 464 */
424 retval); 465 if (!machine_is_netwinder())
425 return retval; 466 {
467 if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
468 {
469 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
470 IO_INDEX_PORT);
471 rc = -EIO;
472 goto err_out;
473 }
426 } 474 }
427 475
428 retval = misc_register(&wdt977_miscdev); 476 rc = misc_register(&wdt977_miscdev);
429 if (retval) { 477 if (rc)
478 {
430 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", 479 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
431 WATCHDOG_MINOR, retval); 480 wdt977_miscdev.minor, rc);
432 unregister_reboot_notifier(&wdt977_notifier); 481 goto err_out_region;
433 return retval; 482 }
483
484 rc = register_reboot_notifier(&wdt977_notifier);
485 if (rc)
486 {
487 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
488 rc);
489 goto err_out_miscdev;
434 } 490 }
435 491
436 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode = %i)\n", 492 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
437 timeout, nowayout, testmode); 493 timeout, nowayout, testmode);
438 494
439 return 0; 495 return 0;
496
497err_out_miscdev:
498 misc_deregister(&wdt977_miscdev);
499err_out_region:
500 if (!machine_is_netwinder())
501 release_region(IO_INDEX_PORT,2);
502err_out:
503 return rc;
440} 504}
441 505
442static void __exit nwwatchdog_exit(void) 506static void __exit wd977_exit(void)
443{ 507{
508 wdt977_stop();
444 misc_deregister(&wdt977_miscdev); 509 misc_deregister(&wdt977_miscdev);
445 unregister_reboot_notifier(&wdt977_notifier); 510 unregister_reboot_notifier(&wdt977_notifier);
511 release_region(IO_INDEX_PORT,2);
446} 512}
447 513
448module_init(nwwatchdog_init); 514module_init(wd977_init);
449module_exit(nwwatchdog_exit); 515module_exit(wd977_exit);
450 516
451MODULE_AUTHOR("Woody Suwalski <woody@netwinder.org>"); 517MODULE_AUTHOR("Woody Suwalski <woodys@xandros.com>");
452MODULE_DESCRIPTION("W83977AF Watchdog driver"); 518MODULE_DESCRIPTION("W83977AF Watchdog driver");
453MODULE_LICENSE("GPL"); 519MODULE_LICENSE("GPL");
454MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 520MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);