2 * WDT driver for the Nios2
4 * (c) Copyright 2005 Walter Goossens <walter.goossens@emdes.nl>
5 * Neither Walter Goossens nor Emdes Embedded Systems admit liability
6 * nor provide warranty for any of this software. This material is
7 * provided "AS-IS" and at no charge.
10 * Original copyright messages:
12 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
13 * http://www.redhat.com
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version.
20 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
21 * warranty for any of this software. This material is provided
22 * "AS-IS" and at no charge.
24 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
27 #include <linux/module.h>
28 #include <linux/miscdevice.h>
29 #include <linux/watchdog.h>
31 #include <linux/ioport.h>
32 #include <linux/init.h>
35 #include <asm/uaccess.h>
36 #include <asm/system.h>
38 // Change this line if you used another name in your PTF file.
40 #define AVALON_WDT_BASE na_watchdog
41 #define AVALON_WDT_STATUS AVALON_WDT_BASE
42 #define AVALON_WDT_CONTROL (AVALON_WDT_BASE + 0x04)
43 #define AVALON_WDT_PERIODL (AVALON_WDT_BASE + 0x08)
44 #define AVALON_WDT_PERIODH (AVALON_WDT_BASE + 0x0C)
45 #define AVALON_WDT_SIZE 0x18
47 #define AVALON_WDT_RUN_BIT 0x04
49 static unsigned long wdt_is_open
;
54 * Start the watchdog driver.
56 static int avalon_wdt_start(void) {
57 outw_p(inw_p(AVALON_WDT_CONTROL
) | AVALON_WDT_RUN_BIT
, AVALON_WDT_CONTROL
);
58 printk(KERN_INFO
"avalonwdt: Starting watchdog timer\n");
65 * Reload counter one with the watchdog heartbeat.
67 static int avalon_wdt_ping(void) {
68 //It doesn't matter what value we write
69 outw_p(1,AVALON_WDT_PERIODL
);
75 * @file: file handle to the watchdog
76 * @buf: buffer to write (unused as data does not matter here
77 * @count: count of bytes
78 * @ppos: pointer to the position to write. No seeks allowed
80 * A write to a watchdog device is defined as a keepalive signal. Any
81 * write of data will do, as we we don't define content meaning.
84 static ssize_t
avalon_wdt_write(struct file
*file
, const char __user
*buf
, size_t count
, loff_t
*ppos
) {
93 * @inode: inode of the device
94 * @file: file handle to the device
95 * @cmd: watchdog command
96 * @arg: argument pointer
98 * The watchdog API defines a common set of functions for all watchdogs
99 * according to their available features. We only actually usefully support
100 * querying capabilities and current status.
103 static int avalon_wdt_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
) {
104 void __user
*argp
= (void __user
*)arg
;
106 static struct watchdog_info ident
= {
107 .options
= WDIOF_KEEPALIVEPING
,
108 .firmware_version
= 1,
109 .identity
= "Nios2_avalon_wdt",
113 case WDIOC_GETSUPPORT
:
114 return copy_to_user(argp
, &ident
, sizeof(ident
))?-EFAULT
:0;
115 case WDIOC_KEEPALIVE
:
125 * @inode: inode of device
126 * @file: file handle to device
128 * The watchdog device has been opened. The watchdog device is single
129 * open and on opening we load the counters.
130 * The timeout depends on the value you selected in SOPC-builder.
132 static int avalon_wdt_open(struct inode
*inode
, struct file
*file
) {
133 if(test_and_set_bit(0, &wdt_is_open
))
136 return nonseekable_open(inode
, file
);
140 * avalon_wdt_release:
141 * @inode: inode to board
142 * @file: file handle to board
145 static int avalon_wdt_release(struct inode
*inode
, struct file
*file
) {
146 clear_bit(0, &wdt_is_open
);
147 printk(KERN_CRIT
"avalonwdt: WDT device closed unexpectedly. WDT will (can) not stop!\n");
156 static struct file_operations avalon_wdt_fops
= {
157 .owner
= THIS_MODULE
,
159 .write
= avalon_wdt_write
,
160 .ioctl
= avalon_wdt_ioctl
,
161 .open
= avalon_wdt_open
,
162 .release
= avalon_wdt_release
,
165 static struct miscdevice avalon_wdt_miscdev
= {
166 .minor
= WATCHDOG_MINOR
,
168 .fops
= &avalon_wdt_fops
,
174 * Unload the watchdog. You cannot do this with any file handles open.
175 * If your watchdog is set to continue ticking on close and you unload
176 * it, well it keeps ticking. We won't get the interrupt but the board
177 * will not touch PC memory so all is fine. You just have to load a new
178 * module in 30 seconds or reboot.
181 static void __exit
avalon_wdt_exit(void)
183 misc_deregister(&avalon_wdt_miscdev
);
184 release_region(AVALON_WDT_BASE
,AVALON_WDT_SIZE
);
190 * Set up the WDT watchdog board. All we have to do is grab the
191 * resources we require and bitch if anyone beat us to them.
192 * The open() function will actually kick the board off.
195 static int __init
avalon_wdt_init(void)
199 if (!request_region(AVALON_WDT_BASE
, AVALON_WDT_SIZE
, "Nios2_avalon_wdt")) {
200 printk(KERN_ERR
"wdt: I/O address 0x%08x already in use\n", AVALON_WDT_BASE
);
203 ret
= misc_register(&avalon_wdt_miscdev
);
205 printk(KERN_ERR
"wdt: cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR
, ret
);
206 release_region(AVALON_WDT_BASE
,AVALON_WDT_SIZE
);
210 printk(KERN_INFO
"Nios2 Avalon Watchdog driver 0.01 at 0x%08x\n", AVALON_WDT_BASE
);
214 module_init(avalon_wdt_init
);
215 module_exit(avalon_wdt_exit
);
217 MODULE_AUTHOR("Walter Goossens");
218 MODULE_DESCRIPTION("Driver for Nios2 Watchdog");
219 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR
);
220 MODULE_LICENSE("GPL");