Blame view
drivers/watchdog/mtx-1_wdt.c
6.33 KB
04bf3b4f5 [WATCHDOG] MTX-1 ... |
1 2 3 |
/* * Driver for the MTX-1 Watchdog. * |
ed78c2da1 [WATCHDOG 28/57] ... |
4 5 |
* (C) Copyright 2005 4G Systems <info@4g-systems.biz>, * All Rights Reserved. |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
6 7 |
* http://www.4g-systems.biz * |
143a2e54b [WATCHDOG] More c... |
8 |
* (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org> |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Neither Michael Stickel nor 4G Systems admit liability nor provide * warranty for any of this software. This material is provided * "AS-IS" and at no charge. * * (c) Copyright 2005 4G Systems <info@4g-systems.biz> * * Release 0.01. * Author: Michael Stickel michael.stickel@4g-systems.biz * * Release 0.02. * Author: Florian Fainelli florian@openwrt.org * use the Linux watchdog/timer APIs * * The Watchdog is configured to reset the MTX-1 * if it is not triggered for 100 seconds. * It should not be triggered more often than 1.6 seconds. * * A timer triggers the watchdog every 5 seconds, until * it is opened for the first time. After the first open * it MUST be triggered every 2..95 seconds. */ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/ioport.h> #include <linux/timer.h> #include <linux/completion.h> #include <linux/jiffies.h> #include <linux/watchdog.h> |
6ea8115bb [WATCHDOG] Conver... |
49 |
#include <linux/platform_device.h> |
ed78c2da1 [WATCHDOG 28/57] ... |
50 51 52 |
#include <linux/io.h> #include <linux/uaccess.h> #include <linux/gpio.h> |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
53 54 55 56 57 58 59 60 61 |
#include <asm/mach-au1x00/au1000.h> #define MTX1_WDT_INTERVAL (5 * HZ) static int ticks = 100 * HZ; static struct { struct completion stop; |
ed78c2da1 [WATCHDOG 28/57] ... |
62 |
spinlock_t lock; |
996d62d44 [WATCHDOG] Remove... |
63 |
int running; |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
64 |
struct timer_list timer; |
996d62d44 [WATCHDOG] Remove... |
65 |
int queue; |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
66 67 |
int default_ticks; unsigned long inuse; |
6ea8115bb [WATCHDOG] Conver... |
68 |
unsigned gpio; |
2ea4e76e9 watchdog: mtx1-wd... |
69 |
unsigned int gstate; |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
70 71 72 73 |
} mtx1_wdt_device; static void mtx1_wdt_trigger(unsigned long unused) { |
ed78c2da1 [WATCHDOG 28/57] ... |
74 |
spin_lock(&mtx1_wdt_device.lock); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
75 76 |
if (mtx1_wdt_device.running) ticks--; |
b7f720d68 MIPS: Alchemy: Cl... |
77 78 |
/* toggle wdt gpio */ |
2ea4e76e9 watchdog: mtx1-wd... |
79 80 |
mtx1_wdt_device.gstate = !mtx1_wdt_device.gstate; gpio_set_value(mtx1_wdt_device.gpio, mtx1_wdt_device.gstate); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
81 82 83 |
if (mtx1_wdt_device.queue && ticks) mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); |
ed78c2da1 [WATCHDOG 28/57] ... |
84 |
else |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
85 |
complete(&mtx1_wdt_device.stop); |
ed78c2da1 [WATCHDOG 28/57] ... |
86 |
spin_unlock(&mtx1_wdt_device.lock); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
87 88 89 90 91 92 93 94 95 96 |
} static void mtx1_wdt_reset(void) { ticks = mtx1_wdt_device.default_ticks; } static void mtx1_wdt_start(void) { |
f80e919bb [WATCHDOG] fix mt... |
97 |
unsigned long flags; |
ed78c2da1 [WATCHDOG 28/57] ... |
98 |
spin_lock_irqsave(&mtx1_wdt_device.lock, flags); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
99 100 |
if (!mtx1_wdt_device.queue) { mtx1_wdt_device.queue = 1; |
b7f720d68 MIPS: Alchemy: Cl... |
101 |
mtx1_wdt_device.gstate = 1; |
2ea4e76e9 watchdog: mtx1-wd... |
102 |
gpio_set_value(mtx1_wdt_device.gpio, 1); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
103 104 105 |
mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); } mtx1_wdt_device.running++; |
ed78c2da1 [WATCHDOG 28/57] ... |
106 |
spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
107 108 109 110 |
} static int mtx1_wdt_stop(void) { |
f80e919bb [WATCHDOG] fix mt... |
111 |
unsigned long flags; |
ed78c2da1 [WATCHDOG 28/57] ... |
112 |
spin_lock_irqsave(&mtx1_wdt_device.lock, flags); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
113 114 |
if (mtx1_wdt_device.queue) { mtx1_wdt_device.queue = 0; |
b7f720d68 MIPS: Alchemy: Cl... |
115 |
mtx1_wdt_device.gstate = 0; |
2ea4e76e9 watchdog: mtx1-wd... |
116 |
gpio_set_value(mtx1_wdt_device.gpio, 0); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
117 |
} |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
118 |
ticks = mtx1_wdt_device.default_ticks; |
ed78c2da1 [WATCHDOG 28/57] ... |
119 |
spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
120 121 122 123 124 125 126 127 128 |
return 0; } /* Filesystem functions */ static int mtx1_wdt_open(struct inode *inode, struct file *file) { if (test_and_set_bit(0, &mtx1_wdt_device.inuse)) return -EBUSY; |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
129 130 131 132 133 134 135 136 137 |
return nonseekable_open(inode, file); } static int mtx1_wdt_release(struct inode *inode, struct file *file) { clear_bit(0, &mtx1_wdt_device.inuse); return 0; } |
ed78c2da1 [WATCHDOG 28/57] ... |
138 139 |
static long mtx1_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
140 141 |
{ void __user *argp = (void __user *)arg; |
ed78c2da1 [WATCHDOG 28/57] ... |
142 |
int __user *p = (int __user *)argp; |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
143 |
unsigned int value; |
ed78c2da1 [WATCHDOG 28/57] ... |
144 |
static const struct watchdog_info ident = { |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
145 146 147 |
.options = WDIOF_CARDRESET, .identity = "MTX-1 WDT", }; |
ed78c2da1 [WATCHDOG 28/57] ... |
148 |
switch (cmd) { |
0c06090c9 [WATCHDOG] Coding... |
149 150 151 |
case WDIOC_GETSUPPORT: if (copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; |
ed78c2da1 [WATCHDOG 28/57] ... |
152 153 154 155 156 |
break; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: put_user(0, p); break; |
ed78c2da1 [WATCHDOG 28/57] ... |
157 158 159 160 161 162 163 164 165 166 |
case WDIOC_SETOPTIONS: if (get_user(value, p)) return -EFAULT; if (value & WDIOS_ENABLECARD) mtx1_wdt_start(); else if (value & WDIOS_DISABLECARD) mtx1_wdt_stop(); else return -EINVAL; return 0; |
0c06090c9 [WATCHDOG] Coding... |
167 168 169 |
case WDIOC_KEEPALIVE: mtx1_wdt_reset(); break; |
ed78c2da1 [WATCHDOG 28/57] ... |
170 171 |
default: return -ENOTTY; |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
172 173 174 |
} return 0; } |
ed78c2da1 [WATCHDOG 28/57] ... |
175 176 |
static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
177 178 179 |
{ if (!count) return -EIO; |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
180 181 182 |
mtx1_wdt_reset(); return count; } |
b47a166ed [WATCHDOG] consti... |
183 |
static const struct file_operations mtx1_wdt_fops = { |
5f3b27569 watchdog: cleanup... |
184 |
.owner = THIS_MODULE, |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
185 |
.llseek = no_llseek, |
ed78c2da1 [WATCHDOG 28/57] ... |
186 |
.unlocked_ioctl = mtx1_wdt_ioctl, |
5f3b27569 watchdog: cleanup... |
187 188 189 |
.open = mtx1_wdt_open, .write = mtx1_wdt_write, .release = mtx1_wdt_release, |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
190 191 192 193 |
}; static struct miscdevice mtx1_wdt_misc = { |
5f3b27569 watchdog: cleanup... |
194 195 196 |
.minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &mtx1_wdt_fops, |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
197 |
}; |
b6bf291f1 [WATCHDOG] move p... |
198 |
static int __devinit mtx1_wdt_probe(struct platform_device *pdev) |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
199 200 |
{ int ret; |
6ea8115bb [WATCHDOG] Conver... |
201 |
mtx1_wdt_device.gpio = pdev->resource[0].start; |
9b19d40aa watchdog: mtx1-wd... |
202 203 204 205 206 207 |
ret = gpio_request_one(mtx1_wdt_device.gpio, GPIOF_OUT_INIT_HIGH, "mtx1-wdt"); if (ret < 0) { dev_err(&pdev->dev, "failed to request gpio"); return ret; } |
6ea8115bb [WATCHDOG] Conver... |
208 |
|
ed78c2da1 [WATCHDOG 28/57] ... |
209 |
spin_lock_init(&mtx1_wdt_device.lock); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
210 211 |
init_completion(&mtx1_wdt_device.stop); mtx1_wdt_device.queue = 0; |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
212 |
clear_bit(0, &mtx1_wdt_device.inuse); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
213 |
setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
214 |
mtx1_wdt_device.default_ticks = ticks; |
ed78c2da1 [WATCHDOG 28/57] ... |
215 216 |
ret = misc_register(&mtx1_wdt_misc); if (ret < 0) { |
fad0a9dd0 watchdog: mtx1-wd... |
217 218 |
dev_err(&pdev->dev, "failed to register "); |
ed78c2da1 [WATCHDOG 28/57] ... |
219 220 |
return ret; } |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
221 |
mtx1_wdt_start(); |
fad0a9dd0 watchdog: mtx1-wd... |
222 223 |
dev_info(&pdev->dev, "MTX-1 Watchdog driver "); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
224 225 |
return 0; } |
b6bf291f1 [WATCHDOG] move p... |
226 |
static int __devexit mtx1_wdt_remove(struct platform_device *pdev) |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
227 |
{ |
ed78c2da1 [WATCHDOG 28/57] ... |
228 |
/* FIXME: do we need to lock this test ? */ |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
229 230 231 232 |
if (mtx1_wdt_device.queue) { mtx1_wdt_device.queue = 0; wait_for_completion(&mtx1_wdt_device.stop); } |
9b19d40aa watchdog: mtx1-wd... |
233 234 |
gpio_free(mtx1_wdt_device.gpio); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
235 |
misc_deregister(&mtx1_wdt_misc); |
6ea8115bb [WATCHDOG] Conver... |
236 237 |
return 0; } |
db98f89a2 watchdog: mtx1-wd... |
238 |
static struct platform_driver mtx1_wdt_driver = { |
6ea8115bb [WATCHDOG] Conver... |
239 |
.probe = mtx1_wdt_probe, |
b6bf291f1 [WATCHDOG] move p... |
240 |
.remove = __devexit_p(mtx1_wdt_remove), |
6ea8115bb [WATCHDOG] Conver... |
241 |
.driver.name = "mtx1-wdt", |
f37d193c7 watchdog: fix pla... |
242 |
.driver.owner = THIS_MODULE, |
6ea8115bb [WATCHDOG] Conver... |
243 |
}; |
b8ec61189 watchdog: convert... |
244 |
module_platform_driver(mtx1_wdt_driver); |
04bf3b4f5 [WATCHDOG] MTX-1 ... |
245 246 247 248 |
MODULE_AUTHOR("Michael Stickel, Florian Fainelli"); MODULE_DESCRIPTION("Driver for the MTX-1 watchdog"); MODULE_LICENSE("GPL"); |
6ea8115bb [WATCHDOG] Conver... |
249 |
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
f37d193c7 watchdog: fix pla... |
250 |
MODULE_ALIAS("platform:mtx1-wdt"); |