MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / char / watchdog / m5272_wdt.c
blob3df8924617751d548cfb66e611f119e6d9340b70
1 /*
2 * Watchdog driver for the MCF5272
4 * (c) Copyright 2005 Javier Herrero <jherrero@hvsistemas.es>
5 * Based on SoftDog driver by Alan Cox <alan@redhat.com>
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.
12 * Neither Oleg Drokin nor iXcelerator.com admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
16 * (c) Copyright 2005 Javier Herrero <jherrero@hvsistemas.es>
18 * 03/05/2005 Initial release
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/types.h>
23 #include <linux/kernel.h>
24 #include <linux/fs.h>
25 #include <linux/miscdevice.h>
26 #include <linux/watchdog.h>
27 #include <linux/init.h>
29 #include <asm/bitops.h>
30 #include <asm/uaccess.h>
32 #include <asm/coldfire.h>
33 #include <asm/m5272sim.h>
35 #define M5272_CLOSE_MAGIC (0x5afc4453)
37 static unsigned long m5272wdt_users;
38 static int expect_close;
39 static unsigned short wdt_reset_ref;
40 static int boot_status;
41 #ifdef CONFIG_WATCHDOG_NOWAYOUT
42 static int nowayout = 1;
43 #else
44 static int nowayout = 0;
45 #endif
48 * Allow only one person to hold it open
50 static int m5272dog_open(struct inode *inode, struct file *file)
52 unsigned short* w;
54 nonseekable_open(inode, file);
55 if (test_and_set_bit(1,&m5272wdt_users))
56 return -EBUSY;
58 /* Activate M5272 Watchdog timer */
60 w = (unsigned short*)(MCF_MBAR + MCFSIM_WRRR);
61 *w = wdt_reset_ref | 0x0001;
62 w = (unsigned short*)(MCF_MBAR + MCFSIM_WCR);
63 *w = 0;
64 return 0;
68 * Shut off the timer.
69 * Lock it in if it's a module and we defined ...NOWAYOUT
70 * Oddly, the watchdog can only be enabled, but we can turn off
71 * the interrupt, which appears to prevent the watchdog timing out.
73 static int m5272dog_release(struct inode *inode, struct file *file)
75 unsigned short* w;
77 w = (unsigned short*)(MCF_MBAR + MCFSIM_WRRR);
79 if (expect_close == M5272_CLOSE_MAGIC) {
80 *w = 0;
81 } else {
82 printk(KERN_CRIT "WATCHDOG: WDT device closed unexpectedly. WDT will not stop!\n");
84 clear_bit(1, &m5272wdt_users);
85 expect_close = 0;
86 return 0;
89 static ssize_t m5272dog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
91 unsigned short* w;
93 if (len) {
94 if (!nowayout) {
95 size_t i;
97 expect_close = 0;
99 for (i = 0; i != len; i++) {
100 char c;
102 if (get_user(c, data + i))
103 return -EFAULT;
104 if (c == 'V')
105 expect_close = M5272_CLOSE_MAGIC;
108 /* Refresh watchdog timer. */
109 w = (unsigned short*)(MCF_MBAR + MCFSIM_WCR);
110 *w = 0;
113 return len;
116 static struct watchdog_info ident = {
117 .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
118 WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
119 .identity = "MCF5272 Watchdog",
122 static int m5272dog_ioctl(struct inode *inode, struct file *file,
123 unsigned int cmd, unsigned long arg)
125 int ret = -ENOIOCTLCMD;
126 int time;
127 unsigned short* w;
129 switch (cmd) {
130 case WDIOC_GETSUPPORT:
131 ret = copy_to_user((struct watchdog_info *)arg, &ident,
132 sizeof(ident)) ? -EFAULT : 0;
133 break;
135 case WDIOC_GETSTATUS:
136 ret = put_user(0, (int *)arg);
137 break;
139 case WDIOC_GETBOOTSTATUS:
140 ret = put_user(boot_status, (int *)arg);
141 break;
143 case WDIOC_SETTIMEOUT:
144 ret = get_user(time, (int *)arg);
145 if (ret)
146 break;
148 if (time <= 0 || time > (32768*16384/MCF_CLK)) {
149 ret = -EINVAL;
150 break;
153 wdt_reset_ref = (MCF_CLK / 16384) * time;
154 w = (unsigned short*)(MCF_MBAR + MCFSIM_WRRR);
155 *w = wdt_reset_ref | 0x0001;
156 /*fall through*/
158 case WDIOC_GETTIMEOUT:
159 ret = put_user(wdt_reset_ref * 16384 / MCF_CLK, (int *)arg);
160 break;
162 case WDIOC_KEEPALIVE:
163 w = (unsigned short*)(MCF_MBAR + MCFSIM_WCR);
164 *w = 0;
165 ret = 0;
166 break;
168 return ret;
171 static struct file_operations m5272dog_fops =
173 .owner = THIS_MODULE,
174 .llseek = no_llseek,
175 .write = m5272dog_write,
176 .ioctl = m5272dog_ioctl,
177 .open = m5272dog_open,
178 .release = m5272dog_release,
181 static struct miscdevice m5272dog_miscdev =
183 .minor = WATCHDOG_MINOR,
184 .name = "MCF5272 watchdog",
185 .fops = &m5272dog_fops,
188 static int margin __initdata = 16; /* (secs) Default is 1 minute */
190 static int __init m5272dog_init(void)
192 int ret;
195 * Read the reset status, and save it for later. If
196 * we suspend, RCSR will be cleared, and the watchdog
197 * reset reason will be lost.
199 // boot_status = (RCSR & RCSR_WDR) ? WDIOF_CARDRESET : 0;
200 wdt_reset_ref = (MCF_CLK / 16384) * margin;
202 ret = misc_register(&m5272dog_miscdev);
203 if (ret == 0)
204 printk("MCF5272 Watchdog Timer: timer margin %d sec\n",
205 margin);
207 return ret;
210 static void __exit m5272dog_exit(void)
212 misc_deregister(&m5272dog_miscdev);
215 module_init(m5272dog_init);
216 module_exit(m5272dog_exit);
218 MODULE_AUTHOR("Javier Herrero <jherrero@hvsistemas.es>");
219 MODULE_DESCRIPTION("MCF5272 Watchdog");
221 module_param(margin, int, 0);
222 MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 16s)");
224 module_param(nowayout, int, 0);
225 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
227 MODULE_LICENSE("GPL");
228 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);