aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/ixp2000_wdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/ixp2000_wdt.c')
-rw-r--r--drivers/watchdog/ixp2000_wdt.c61
1 files changed, 28 insertions, 33 deletions
diff --git a/drivers/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c
index 4226dae7d260..4f4b35a20d84 100644
--- a/drivers/watchdog/ixp2000_wdt.c
+++ b/drivers/watchdog/ixp2000_wdt.c
@@ -25,42 +25,44 @@
25#include <linux/watchdog.h> 25#include <linux/watchdog.h>
26#include <linux/init.h> 26#include <linux/init.h>
27#include <linux/bitops.h> 27#include <linux/bitops.h>
28 28#include <linux/uaccess.h>
29#include <mach/hardware.h> 29#include <mach/hardware.h>
30#include <asm/uaccess.h>
31 30
32static int nowayout = WATCHDOG_NOWAYOUT; 31static int nowayout = WATCHDOG_NOWAYOUT;
33static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */ 32static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
34static unsigned long wdt_status; 33static unsigned long wdt_status;
34static spinlock_t wdt_lock;
35 35
36#define WDT_IN_USE 0 36#define WDT_IN_USE 0
37#define WDT_OK_TO_CLOSE 1 37#define WDT_OK_TO_CLOSE 1
38 38
39static unsigned long wdt_tick_rate; 39static unsigned long wdt_tick_rate;
40 40
41static void 41static void wdt_enable(void)
42wdt_enable(void)
43{ 42{
43 spin_lock(&wdt_lock);
44 ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE); 44 ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
45 ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE); 45 ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
46 ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); 46 ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
47 ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE); 47 ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
48 spin_unlock(&wdt_lock);
48} 49}
49 50
50static void 51static void wdt_disable(void)
51wdt_disable(void)
52{ 52{
53 spin_lock(&wdt_lock);
53 ixp2000_reg_write(IXP2000_T4_CTL, 0); 54 ixp2000_reg_write(IXP2000_T4_CTL, 0);
55 spin_unlock(&wdt_lock);
54} 56}
55 57
56static void 58static void wdt_keepalive(void)
57wdt_keepalive(void)
58{ 59{
60 spin_lock(&wdt_lock);
59 ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate); 61 ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
62 spin_unlock(&wdt_lock);
60} 63}
61 64
62static int 65static int ixp2000_wdt_open(struct inode *inode, struct file *file)
63ixp2000_wdt_open(struct inode *inode, struct file *file)
64{ 66{
65 if (test_and_set_bit(WDT_IN_USE, &wdt_status)) 67 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
66 return -EBUSY; 68 return -EBUSY;
@@ -72,8 +74,8 @@ ixp2000_wdt_open(struct inode *inode, struct file *file)
72 return nonseekable_open(inode, file); 74 return nonseekable_open(inode, file);
73} 75}
74 76
75static ssize_t 77static ssize_t ixp2000_wdt_write(struct file *file, const char *data,
76ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) 78 size_t len, loff_t *ppos)
77{ 79{
78 if (len) { 80 if (len) {
79 if (!nowayout) { 81 if (!nowayout) {
@@ -103,9 +105,8 @@ static struct watchdog_info ident = {
103 .identity = "IXP2000 Watchdog", 105 .identity = "IXP2000 Watchdog",
104}; 106};
105 107
106static int 108static long ixp2000_wdt_ioctl(struct file *file, unsigned int cmd,
107ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, 109 unsigned long arg)
108 unsigned long arg)
109{ 110{
110 int ret = -ENOTTY; 111 int ret = -ENOTTY;
111 int time; 112 int time;
@@ -124,6 +125,11 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
124 ret = put_user(0, (int *)arg); 125 ret = put_user(0, (int *)arg);
125 break; 126 break;
126 127
128 case WDIOC_KEEPALIVE:
129 wdt_enable();
130 ret = 0;
131 break;
132
127 case WDIOC_SETTIMEOUT: 133 case WDIOC_SETTIMEOUT:
128 ret = get_user(time, (int *)arg); 134 ret = get_user(time, (int *)arg);
129 if (ret) 135 if (ret)
@@ -141,26 +147,18 @@ ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
141 case WDIOC_GETTIMEOUT: 147 case WDIOC_GETTIMEOUT:
142 ret = put_user(heartbeat, (int *)arg); 148 ret = put_user(heartbeat, (int *)arg);
143 break; 149 break;
144
145 case WDIOC_KEEPALIVE:
146 wdt_enable();
147 ret = 0;
148 break;
149 } 150 }
150 151
151 return ret; 152 return ret;
152} 153}
153 154
154static int 155static int ixp2000_wdt_release(struct inode *inode, struct file *file)
155ixp2000_wdt_release(struct inode *inode, struct file *file)
156{ 156{
157 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) { 157 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
158 wdt_disable(); 158 wdt_disable();
159 } else { 159 else
160 printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - " 160 printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
161 "timer will not stop\n"); 161 "timer will not stop\n");
162 }
163
164 clear_bit(WDT_IN_USE, &wdt_status); 162 clear_bit(WDT_IN_USE, &wdt_status);
165 clear_bit(WDT_OK_TO_CLOSE, &wdt_status); 163 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
166 164
@@ -168,18 +166,16 @@ ixp2000_wdt_release(struct inode *inode, struct file *file)
168} 166}
169 167
170 168
171static const struct file_operations ixp2000_wdt_fops = 169static const struct file_operations ixp2000_wdt_fops = {
172{
173 .owner = THIS_MODULE, 170 .owner = THIS_MODULE,
174 .llseek = no_llseek, 171 .llseek = no_llseek,
175 .write = ixp2000_wdt_write, 172 .write = ixp2000_wdt_write,
176 .ioctl = ixp2000_wdt_ioctl, 173 .unlocked_ioctl = ixp2000_wdt_ioctl,
177 .open = ixp2000_wdt_open, 174 .open = ixp2000_wdt_open,
178 .release = ixp2000_wdt_release, 175 .release = ixp2000_wdt_release,
179}; 176};
180 177
181static struct miscdevice ixp2000_wdt_miscdev = 178static struct miscdevice ixp2000_wdt_miscdev = {
182{
183 .minor = WATCHDOG_MINOR, 179 .minor = WATCHDOG_MINOR,
184 .name = "watchdog", 180 .name = "watchdog",
185 .fops = &ixp2000_wdt_fops, 181 .fops = &ixp2000_wdt_fops,
@@ -191,9 +187,8 @@ static int __init ixp2000_wdt_init(void)
191 printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n"); 187 printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n");
192 return -EIO; 188 return -EIO;
193 } 189 }
194
195 wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256; 190 wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
196 191 spin_lock_init(&wdt_lock);
197 return misc_register(&ixp2000_wdt_miscdev); 192 return misc_register(&ixp2000_wdt_miscdev);
198} 193}
199 194