[WATCHDOG] Winbond SMsC37B787 - remove trailing whitespace
[pandora-kernel.git] / drivers / char / watchdog / smsc37b787_wdt.c
1 /*
2  *      SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x
3  *
4  *      Based on acquirewdt.c by Alan Cox <alan@redhat.com>
5  *       and some other existing drivers
6  *
7  *      This program is free software; you can redistribute it and/or
8  *      modify it under the terms of the GNU General Public License
9  *      as published by the Free Software Foundation; either version
10  *      2 of the License, or (at your option) any later version.
11  *
12  *      The authors do NOT admit liability nor provide warranty for
13  *      any of this software. This material is provided "AS-IS" in
14  *      the hope that it may be useful for others.
15  *
16  *      (C) Copyright 2003-2006  Sven Anders <anders@anduras.de>
17  *
18  *  History:
19  *      2003 - Created version 1.0 for Linux 2.4.x.
20  *      2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE
21  *             features. Released version 1.1
22  *
23  *  Theory of operation:
24  *
25  *      A Watchdog Timer (WDT) is a hardware circuit that can
26  *      reset the computer system in case of a software fault.
27  *      You probably knew that already.
28  *
29  *      Usually a userspace daemon will notify the kernel WDT driver
30  *      via the /dev/watchdog special device file that userspace is
31  *      still alive, at regular intervals.  When such a notification
32  *      occurs, the driver will usually tell the hardware watchdog
33  *      that everything is in order, and that the watchdog should wait
34  *      for yet another little while to reset the system.
35  *      If userspace fails (RAM error, kernel bug, whatever), the
36  *      notifications cease to occur, and the hardware watchdog will
37  *      reset the system (causing a reboot) after the timeout occurs.
38  *
39  * Create device with:
40  *  mknod /dev/watchdog c 10 130
41  *
42  * For an example userspace keep-alive daemon, see:
43  *   Documentation/watchdog/watchdog.txt
44  */
45
46 #include <linux/module.h>
47 #include <linux/moduleparam.h>
48 #include <linux/types.h>
49 #include <linux/miscdevice.h>
50 #include <linux/watchdog.h>
51 #include <linux/delay.h>
52 #include <linux/fs.h>
53 #include <linux/ioport.h>
54 #include <linux/notifier.h>
55 #include <linux/reboot.h>
56 #include <linux/init.h>
57
58 #include <asm/io.h>
59 #include <asm/uaccess.h>
60 #include <asm/system.h>
61
62 /* enable support for minutes as units? */
63 /* (does not always work correctly, so disabled by default!) */
64 #define SMSC_SUPPORT_MINUTES
65 #undef SMSC_SUPPORT_MINUTES
66
67 #define MAX_TIMEOUT     255
68
69 #define UNIT_SECOND     0
70 #define UNIT_MINUTE     1
71
72 #define MODNAME         "smsc37b787_wdt: "
73 #define VERSION         "1.1"
74
75 #define WATCHDOG_MINOR  130
76
77 #define IOPORT          0x3F0
78 #define IOPORT_SIZE     2
79 #define IODEV_NO        8
80
81 static int unit = UNIT_SECOND;  /* timer's unit */
82 static int timeout = 60;        /* timeout value: default is 60 "units" */
83 static int timer_enabled = 0;   /* is the timer enabled? */
84
85 static char expect_close;       /* is the close expected? */
86
87 static int nowayout = WATCHDOG_NOWAYOUT;
88
89 /* -- Low level function ----------------------------------------*/
90
91 /* unlock the IO chip */
92
93 static inline void open_io_config(void)
94 {
95         outb(0x55, IOPORT);
96         mdelay(1);
97         outb(0x55, IOPORT);
98 }
99
100 /* lock the IO chip */
101 static inline void close_io_config(void)
102 {
103         outb(0xAA, IOPORT);
104 }
105
106 /* select the IO device */
107 static inline void select_io_device(unsigned char devno)
108 {
109         outb(0x07, IOPORT);
110         outb(devno, IOPORT+1);
111 }
112
113 /* write to the control register */
114 static inline void write_io_cr(unsigned char reg, unsigned char data)
115 {
116         outb(reg, IOPORT);
117         outb(data, IOPORT+1);
118 }
119
120 /* read from the control register */
121 static inline char read_io_cr(unsigned char reg)
122 {
123         outb(reg, IOPORT);
124         return inb(IOPORT+1);
125 }
126
127 /* -- Medium level functions ------------------------------------*/
128
129 static inline void gpio_bit12(unsigned char reg)
130 {
131         // -- General Purpose I/O Bit 1.2 --
132         // Bit 0,   In/Out: 0 = Output, 1 = Input
133         // Bit 1,   Polarity: 0 = No Invert, 1 = Invert
134         // Bit 2,   Group Enable Intr.: 0 = Disable, 1 = Enable
135         // Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17,
136         //                           11 = Either Edge Triggered Intr. 2
137         // Bit 5/6  (Reserved)
138         // Bit 7,   Output Type: 0 = Push Pull Bit, 1 = Open Drain
139         write_io_cr(0xE2, reg);
140 }
141
142 static inline void gpio_bit13(unsigned char reg)
143 {
144         // -- General Purpose I/O Bit 1.3 --
145         // Bit 0,  In/Out: 0 = Output, 1 = Input
146         // Bit 1,  Polarity: 0 = No Invert, 1 = Invert
147         // Bit 2,  Group Enable Intr.: 0 = Disable, 1 = Enable
148         // Bit 3,  Function select: 0 = GPI/O, 1 = LED
149         // Bit 4-6 (Reserved)
150         // Bit 7,  Output Type: 0 = Push Pull Bit, 1 = Open Drain
151         write_io_cr(0xE3, reg);
152 }
153
154 static inline void wdt_timer_units(unsigned char new_units)
155 {
156         // -- Watchdog timer units --
157         // Bit 0-6 (Reserved)
158         // Bit 7,  WDT Time-out Value Units Select
159         //         (0 = Minutes, 1 = Seconds)
160         write_io_cr(0xF1, new_units);
161 }
162
163 static inline void wdt_timeout_value(unsigned char new_timeout)
164 {
165         // -- Watchdog Timer Time-out Value --
166         // Bit 0-7 Binary coded units (0=Disabled, 1..255)
167         write_io_cr(0xF2, new_timeout);
168 }
169
170 static inline void wdt_timer_conf(unsigned char conf)
171 {
172         // -- Watchdog timer configuration --
173         // Bit 0   Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O
174         // Bit 1   Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr.
175         // Bit 2   Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr.
176         // Bit 3   Reset the timer
177         //         (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled)
178         // Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled,
179         //            0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15)
180         write_io_cr(0xF3, conf);
181 }
182
183 static inline void wdt_timer_ctrl(unsigned char reg)
184 {
185         // -- Watchdog timer control --
186         // Bit 0   Status Bit: 0 = Timer counting, 1 = Timeout occured
187         // Bit 1   Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz
188         // Bit 2   Force Timeout: 1 = Forces WD timeout event (self-cleaning)
189         // Bit 3   P20 Force Timeout enabled:
190         //          0 = P20 activity does not generate the WD timeout event
191         //          1 = P20 Allows rising edge of P20, from the keyboard
192         //              controller, to force the WD timeout event.
193         // Bit 4   (Reserved)
194         // -- Soft power management --
195         // Bit 5   Stop Counter: 1 = Stop software power down counter
196         //            set via register 0xB8, (self-cleaning)
197         //            (Upon read: 0 = Counter running, 1 = Counter stopped)
198         // Bit 6   Restart Counter: 1 = Restart software power down counter
199         //            set via register 0xB8, (self-cleaning)
200         // Bit 7   SPOFF: 1 = Force software power down (self-cleaning)
201
202         write_io_cr(0xF4, reg);
203 }
204
205 /* -- Higher level functions ------------------------------------*/
206
207 /* initialize watchdog */
208
209 static void wb_smsc_wdt_initialize(void)
210 {
211         unsigned char old;
212
213         open_io_config();
214         select_io_device(IODEV_NO);
215
216         // enable the watchdog
217         gpio_bit13(0x08);  // Select pin 80 = LED not GPIO
218         gpio_bit12(0x0A);  // Set pin 79 = WDT not GPIO/Output/Polarity=Invert
219
220         // disable the timeout
221         wdt_timeout_value(0);
222
223         // reset control register
224         wdt_timer_ctrl(0x00);
225
226         // reset configuration register
227         wdt_timer_conf(0x00);
228
229         // read old (timer units) register
230         old = read_io_cr(0xF1) & 0x7F;
231         if (unit == UNIT_SECOND) old |= 0x80; // set to seconds
232
233         // set the watchdog timer units
234         wdt_timer_units(old);
235
236         close_io_config();
237 }
238
239 /* shutdown the watchdog */
240
241 static void wb_smsc_wdt_shutdown(void)
242 {
243         open_io_config();
244         select_io_device(IODEV_NO);
245
246         // disable the watchdog
247         gpio_bit13(0x09);
248         gpio_bit12(0x09);
249
250         // reset watchdog config register
251         wdt_timer_conf(0x00);
252
253         // reset watchdog control register
254         wdt_timer_ctrl(0x00);
255
256         // disable timeout
257         wdt_timeout_value(0x00);
258
259         close_io_config();
260 }
261
262 /* set timeout => enable watchdog */
263
264 static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
265 {
266         open_io_config();
267         select_io_device(IODEV_NO);
268
269         // set Power LED to blink, if we enable the timeout
270         wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
271
272         // set timeout value
273         wdt_timeout_value(new_timeout);
274
275         close_io_config();
276 }
277
278 /* get timeout */
279
280 static unsigned char wb_smsc_wdt_get_timeout(void)
281 {
282         unsigned char set_timeout;
283
284         open_io_config();
285         select_io_device(IODEV_NO);
286         set_timeout = read_io_cr(0xF2);
287         close_io_config();
288
289         return set_timeout;
290 }
291
292 /* disable watchdog */
293
294 static void wb_smsc_wdt_disable(void)
295 {
296         // set the timeout to 0 to disable the watchdog
297         wb_smsc_wdt_set_timeout(0);
298 }
299
300 /* enable watchdog by setting the current timeout */
301
302 static void wb_smsc_wdt_enable(void)
303 {
304         // set the current timeout...
305         wb_smsc_wdt_set_timeout(timeout);
306 }
307
308 /* reset the timer */
309
310 static void wb_smsc_wdt_reset_timer(void)
311 {
312         open_io_config();
313         select_io_device(IODEV_NO);
314
315         // reset the timer
316         wdt_timeout_value(timeout);
317         wdt_timer_conf(0x08);
318
319         close_io_config();
320 }
321
322 /* return, if the watchdog is enabled (timeout is set...) */
323
324 static int wb_smsc_wdt_status(void)
325 {
326         return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING;
327 }
328
329
330 /* -- File operations -------------------------------------------*/
331
332 /* open => enable watchdog and set initial timeout */
333
334 static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
335 {
336         /* /dev/watchdog can only be opened once */
337
338         if (timer_enabled)
339                 return -EBUSY;
340
341         if (nowayout)
342                 __module_get(THIS_MODULE);
343
344         /* Reload and activate timer */
345         timer_enabled = 1;
346         wb_smsc_wdt_enable();
347
348         printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
349
350         return nonseekable_open(inode, file);
351 }
352
353 /* close => shut off the timer */
354
355 static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
356 {
357         /* Shut off the timer. */
358
359         if (expect_close == 42) {
360                 wb_smsc_wdt_disable();
361                 printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n");
362         } else {
363                 printk(KERN_CRIT MODNAME "Unexpected close, not stopping watchdog!\n");
364                 wb_smsc_wdt_reset_timer();
365         }
366
367         timer_enabled = 0;
368         expect_close = 0;
369         return 0;
370 }
371
372 /* write => update the timer to keep the machine alive */
373
374 static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
375                                  size_t len, loff_t *ppos)
376 {
377         /* See if we got the magic character 'V' and reload the timer */
378         if (len) {
379                 if (!nowayout) {
380                         size_t i;
381
382                         /* reset expect flag */
383                         expect_close = 0;
384
385                         /* scan to see whether or not we got the magic character */
386                         for (i = 0; i != len; i++) {
387                                 char c;
388                                 if (get_user(c, data+i))
389                                         return -EFAULT;
390                                 if (c == 'V')
391                                         expect_close = 42;
392                         }
393                 }
394
395                 /* someone wrote to us, we should reload the timer */
396                 wb_smsc_wdt_reset_timer();
397         }
398         return len;
399 }
400
401 /* ioctl => control interface */
402
403 static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file,
404                              unsigned int cmd, unsigned long arg)
405 {
406         int new_timeout;
407
408         union {
409                 struct watchdog_info __user *ident;
410                 int __user *i;
411         } uarg;
412
413         static struct watchdog_info ident = {
414                 .options =              WDIOF_KEEPALIVEPING |
415                                         WDIOF_SETTIMEOUT |
416                                         WDIOF_MAGICCLOSE,
417                 .firmware_version =     0,
418                 .identity =             "SMsC 37B787 Watchdog"
419         };
420
421         uarg.i = (int __user *)arg;
422
423         switch (cmd) {
424                 default:
425                         return -ENOTTY;
426
427                 case WDIOC_GETSUPPORT:
428                         return copy_to_user(uarg.ident, &ident, sizeof(ident));
429
430                 case WDIOC_GETSTATUS:
431                         return put_user(wb_smsc_wdt_status(), uarg.i);
432
433                 case WDIOC_GETBOOTSTATUS:
434                         return put_user(0, uarg.i);
435
436                 case WDIOC_KEEPALIVE:
437                         wb_smsc_wdt_reset_timer();
438                         return 0;
439
440                 case WDIOC_SETTIMEOUT:
441                         if (get_user(new_timeout, uarg.i))
442                                 return -EFAULT;
443
444                         // the API states this is given in secs
445                         if (unit == UNIT_MINUTE)
446                           new_timeout /= 60;
447
448                         if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
449                                 return -EINVAL;
450
451                         timeout = new_timeout;
452                         wb_smsc_wdt_set_timeout(timeout);
453
454                         // fall through and return the new timeout...
455
456                 case WDIOC_GETTIMEOUT:
457
458                         new_timeout = timeout;
459
460                         if (unit == UNIT_MINUTE)
461                           new_timeout *= 60;
462
463                         return put_user(new_timeout, uarg.i);
464
465                 case WDIOC_SETOPTIONS:
466                 {
467                         int options, retval = -EINVAL;
468
469                         if (get_user(options, uarg.i))
470                                 return -EFAULT;
471
472                         if (options & WDIOS_DISABLECARD) {
473                                 wb_smsc_wdt_disable();
474                                 retval = 0;
475                         }
476
477                         if (options & WDIOS_ENABLECARD) {
478                                 wb_smsc_wdt_enable();
479                                 retval = 0;
480                         }
481
482                         return retval;
483                 }
484         }
485 }
486
487 /* -- Notifier funtions -----------------------------------------*/
488
489 static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
490 {
491         if (code == SYS_DOWN || code == SYS_HALT)
492         {
493                 // set timeout to 0, to avoid possible race-condition
494                 timeout = 0;
495                 wb_smsc_wdt_disable();
496         }
497         return NOTIFY_DONE;
498 }
499
500 /* -- Module's structures ---------------------------------------*/
501
502 static struct file_operations wb_smsc_wdt_fops =
503 {
504         .owner          = THIS_MODULE,
505         .llseek         = no_llseek,
506         .write          = wb_smsc_wdt_write,
507         .ioctl          = wb_smsc_wdt_ioctl,
508         .open           = wb_smsc_wdt_open,
509         .release        = wb_smsc_wdt_release
510 };
511
512 static struct notifier_block wb_smsc_wdt_notifier =
513 {
514         .notifier_call  = wb_smsc_wdt_notify_sys
515 };
516
517 static struct miscdevice wb_smsc_wdt_miscdev =
518 {
519         .minor          = WATCHDOG_MINOR,
520         .name           = "watchdog",
521         .fops           = &wb_smsc_wdt_fops,
522 };
523
524 /* -- Module init functions -------------------------------------*/
525
526 /* module's "constructor" */
527
528 static int __init wb_smsc_wdt_init(void)
529 {
530         int ret;
531
532         printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n");
533
534         if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
535                 printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", IOPORT);
536                 ret = -EBUSY;
537                 goto out_pnp;
538         }
539
540         ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
541         if (ret) {
542                 printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret);
543                 goto out_io;
544         }
545
546         ret = misc_register(&wb_smsc_wdt_miscdev);
547         if (ret) {
548                 printk(KERN_ERR MODNAME "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
549                 goto out_rbt;
550         }
551
552         // init the watchdog timer
553         wb_smsc_wdt_initialize();
554
555         // set new maximum, if it's too big
556         if (timeout > MAX_TIMEOUT)
557                timeout = MAX_TIMEOUT;
558
559         // output info
560         printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
561         printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout);
562
563         // ret = 0
564
565 out_clean:
566         return ret;
567
568 out_rbt:
569         unregister_reboot_notifier(&wb_smsc_wdt_notifier);
570
571 out_io:
572         release_region(IOPORT, IOPORT_SIZE);
573
574 out_pnp:
575         goto out_clean;
576 }
577
578 /* module's "destructor" */
579
580 static void __exit wb_smsc_wdt_exit(void)
581 {
582         /* Stop the timer before we leave */
583         if (!nowayout)
584         {
585                 wb_smsc_wdt_shutdown();
586                 printk(KERN_INFO MODNAME "Watchdog disabled.\n");
587         }
588
589         misc_deregister(&wb_smsc_wdt_miscdev);
590         unregister_reboot_notifier(&wb_smsc_wdt_notifier);
591         release_region(IOPORT, IOPORT_SIZE);
592
593         printk("SMsC 37B787 watchdog component driver removed.\n");
594 }
595
596 module_init(wb_smsc_wdt_init);
597 module_exit(wb_smsc_wdt_exit);
598
599 MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
600 MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " VERSION ")");
601 MODULE_LICENSE("GPL");
602
603 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
604
605 #ifdef SMSC_SUPPORT_MINUTES
606 module_param(unit, int, 0);
607 MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0");
608 #endif
609
610 module_param(timeout, int, 60);
611 MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
612
613 module_param(nowayout, int, 0);
614 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");