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>
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;
44 static int nowayout
= 0;
48 * Allow only one person to hold it open
50 static int m5272dog_open(struct inode
*inode
, struct file
*file
)
54 nonseekable_open(inode
, file
);
55 if (test_and_set_bit(1,&m5272wdt_users
))
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
);
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
)
77 w
= (unsigned short*)(MCF_MBAR
+ MCFSIM_WRRR
);
79 if (expect_close
== M5272_CLOSE_MAGIC
) {
82 printk(KERN_CRIT
"WATCHDOG: WDT device closed unexpectedly. WDT will not stop!\n");
84 clear_bit(1, &m5272wdt_users
);
89 static ssize_t
m5272dog_write(struct file
*file
, const char *data
, size_t len
, loff_t
*ppos
)
99 for (i
= 0; i
!= len
; i
++) {
102 if (get_user(c
, data
+ i
))
105 expect_close
= M5272_CLOSE_MAGIC
;
108 /* Refresh watchdog timer. */
109 w
= (unsigned short*)(MCF_MBAR
+ MCFSIM_WCR
);
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
;
130 case WDIOC_GETSUPPORT
:
131 ret
= copy_to_user((struct watchdog_info
*)arg
, &ident
,
132 sizeof(ident
)) ? -EFAULT
: 0;
135 case WDIOC_GETSTATUS
:
136 ret
= put_user(0, (int *)arg
);
139 case WDIOC_GETBOOTSTATUS
:
140 ret
= put_user(boot_status
, (int *)arg
);
143 case WDIOC_SETTIMEOUT
:
144 ret
= get_user(time
, (int *)arg
);
148 if (time
<= 0 || time
> (32768*16384/MCF_CLK
)) {
153 wdt_reset_ref
= (MCF_CLK
/ 16384) * time
;
154 w
= (unsigned short*)(MCF_MBAR
+ MCFSIM_WRRR
);
155 *w
= wdt_reset_ref
| 0x0001;
158 case WDIOC_GETTIMEOUT
:
159 ret
= put_user(wdt_reset_ref
* 16384 / MCF_CLK
, (int *)arg
);
162 case WDIOC_KEEPALIVE
:
163 w
= (unsigned short*)(MCF_MBAR
+ MCFSIM_WCR
);
171 static struct file_operations m5272dog_fops
=
173 .owner
= THIS_MODULE
,
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)
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
);
204 printk("MCF5272 Watchdog Timer: timer margin %d sec\n",
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
);