aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-17 18:28:18 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-17 18:28:18 -0400
commit99e1221d1a1edac316f7f8116c781f75733b1159 (patch)
tree43eb69bf65de33b2a4d6e506e6bc95c14906bed7
parentf3d9071667752e5d419e59f76912ed3fb4a6bb9c (diff)
parent7e2a1498a90aff0e57271bf838a29aaa4e1c6bf9 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog
* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog: (21 commits) [WATCHDOG] at32ap700x_wdt.c - Fix compilation warnings [WATCHDOG] at32ap700x_wdt.c - Add spinlock support [WATCHDOG] at32ap700x_wdt.c - Add nowayout + MAGICCLOSE features [WATCHDOG] at32ap700x_wdt.c - timeout module parameter patch [WATCHDOG] at32ap700x_wdt.c - checkpatch.pl-0.05 clean-up's [WATCHDOG] change s3c2410_wdt to using dev_() macros for output [WATCHDOG] s3c2410_wdt announce initialisation [WATCHDOG] at32ap700x-wdt: add iounmap if probe function fails [WATCHDOG] at32ap700x-wdt: add missing iounmap in _remove [WATCHDOG] watchdog-driver-for-at32ap700x-devices-fix-2 [WATCHDOG] watchdog-driver-for-at32ap700x-devices-fix [WATCHDOG] Watchdog driver for AT32AP700X devices [WATCHDOG] Mixcom Watchdog - CodingStyle clean-up [WATCHDOG] Mixcom Watchdog - clean-up printk's [WATCHDOG] Mixcom Watchdog - clean-up printk's [WATCHDOG] Mixcom Watchdog - checkcard part 2 [WATCHDOG] Mixcom Watchdog - checkcard [WATCHDOG] Mixcom Watchdog - get rid of port offset's [WATCHDOG] Mixcom Watchdog - update "Documentation" [WATCHDOG] Remove the redundant check for pwrite() in EP93XXX watchdog. ...
-rw-r--r--drivers/char/watchdog/Kconfig9
-rw-r--r--drivers/char/watchdog/Makefile3
-rw-r--r--drivers/char/watchdog/at32ap700x_wdt.c386
-rw-r--r--drivers/char/watchdog/ep93xx_wdt.c4
-rw-r--r--drivers/char/watchdog/mixcomwd.c127
-rw-r--r--drivers/char/watchdog/pnx4008_wdt.c4
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c41
7 files changed, 502 insertions, 72 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 53f5538c0c05..2f48ba329961 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -187,6 +187,15 @@ config PNX4008_WATCHDOG
187 187
188 Say N if you are unsure. 188 Say N if you are unsure.
189 189
190# AVR32 Architecture
191
192config AT32AP700X_WDT
193 tristate "AT32AP700x watchdog"
194 depends on WATCHDOG && CPU_AT32AP7000
195 help
196 Watchdog timer embedded into AT32AP700x devices. This will reboot
197 your system when the timeout is reached.
198
190# X86 (i386 + ia64 + x86_64) Architecture 199# X86 (i386 + ia64 + x86_64) Architecture
191 200
192config ACQUIRE_WDT 201config ACQUIRE_WDT
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index d90f649038c2..3907ec04a4e5 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -36,6 +36,9 @@ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
36obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o 36obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
37obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o 37obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
38 38
39# AVR32 Architecture
40obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
41
39# X86 (i386 + ia64 + x86_64) Architecture 42# X86 (i386 + ia64 + x86_64) Architecture
40obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o 43obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
41obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o 44obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c
new file mode 100644
index 000000000000..54a516169d07
--- /dev/null
+++ b/drivers/char/watchdog/at32ap700x_wdt.c
@@ -0,0 +1,386 @@
1/*
2 * Watchdog driver for Atmel AT32AP700X devices
3 *
4 * Copyright (C) 2005-2006 Atmel Corporation
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/miscdevice.h>
16#include <linux/fs.h>
17#include <linux/platform_device.h>
18#include <linux/watchdog.h>
19#include <linux/uaccess.h>
20#include <linux/io.h>
21#include <linux/spinlock.h>
22
23#define TIMEOUT_MIN 1
24#define TIMEOUT_MAX 2
25#define TIMEOUT_DEFAULT TIMEOUT_MAX
26
27/* module parameters */
28static int timeout = TIMEOUT_DEFAULT;
29module_param(timeout, int, 0);
30MODULE_PARM_DESC(timeout,
31 "Timeout value. Limited to be 1 or 2 seconds. (default="
32 __MODULE_STRING(TIMEOUT_DEFAULT) ")");
33
34static int nowayout = WATCHDOG_NOWAYOUT;
35module_param(nowayout, int, 0);
36MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
37 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
38
39/* Watchdog registers and write/read macro */
40#define WDT_CTRL 0x00
41#define WDT_CTRL_EN 0
42#define WDT_CTRL_PSEL 8
43#define WDT_CTRL_KEY 24
44
45#define WDT_CLR 0x04
46
47#define WDT_BIT(name) (1 << WDT_##name)
48#define WDT_BF(name, value) ((value) << WDT_##name)
49
50#define wdt_readl(dev, reg) \
51 __raw_readl((dev)->regs + WDT_##reg)
52#define wdt_writel(dev, reg, value) \
53 __raw_writel((value), (dev)->regs + WDT_##reg)
54
55struct wdt_at32ap700x {
56 void __iomem *regs;
57 spinlock_t io_lock;
58 int timeout;
59 unsigned long users;
60 struct miscdevice miscdev;
61};
62
63static struct wdt_at32ap700x *wdt;
64static char expect_release;
65
66/*
67 * Disable the watchdog.
68 */
69static inline void at32_wdt_stop(void)
70{
71 unsigned long psel;
72
73 spin_lock(&wdt->io_lock);
74 psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f);
75 wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0x55));
76 wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0xaa));
77 spin_unlock(&wdt->io_lock);
78}
79
80/*
81 * Enable and reset the watchdog.
82 */
83static inline void at32_wdt_start(void)
84{
85 /* 0xf is 2^16 divider = 2 sec, 0xe is 2^15 divider = 1 sec */
86 unsigned long psel = (wdt->timeout > 1) ? 0xf : 0xe;
87
88 spin_lock(&wdt->io_lock);
89 wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
90 | WDT_BF(CTRL_PSEL, psel)
91 | WDT_BF(CTRL_KEY, 0x55));
92 wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
93 | WDT_BF(CTRL_PSEL, psel)
94 | WDT_BF(CTRL_KEY, 0xaa));
95 spin_unlock(&wdt->io_lock);
96}
97
98/*
99 * Pat the watchdog timer.
100 */
101static inline void at32_wdt_pat(void)
102{
103 spin_lock(&wdt->io_lock);
104 wdt_writel(wdt, CLR, 0x42);
105 spin_unlock(&wdt->io_lock);
106}
107
108/*
109 * Watchdog device is opened, and watchdog starts running.
110 */
111static int at32_wdt_open(struct inode *inode, struct file *file)
112{
113 if (test_and_set_bit(1, &wdt->users))
114 return -EBUSY;
115
116 at32_wdt_start();
117 return nonseekable_open(inode, file);
118}
119
120/*
121 * Close the watchdog device.
122 */
123static int at32_wdt_close(struct inode *inode, struct file *file)
124{
125 if (expect_release == 42) {
126 at32_wdt_stop();
127 } else {
128 dev_dbg(wdt->miscdev.parent,
129 "Unexpected close, not stopping watchdog!\n");
130 at32_wdt_pat();
131 }
132 clear_bit(1, &wdt->users);
133 expect_release = 0;
134 return 0;
135}
136
137/*
138 * Change the watchdog time interval.
139 */
140static int at32_wdt_settimeout(int time)
141{
142 /*
143 * All counting occurs at 1 / SLOW_CLOCK (32 kHz) and max prescaler is
144 * 2 ^ 16 allowing up to 2 seconds timeout.
145 */
146 if ((time < TIMEOUT_MIN) || (time > TIMEOUT_MAX))
147 return -EINVAL;
148
149 /*
150 * Set new watchdog time. It will be used when at32_wdt_start() is
151 * called.
152 */
153 wdt->timeout = time;
154 return 0;
155}
156
157static struct watchdog_info at32_wdt_info = {
158 .identity = "at32ap700x watchdog",
159 .options = WDIOF_SETTIMEOUT |
160 WDIOF_KEEPALIVEPING |
161 WDIOF_MAGICCLOSE,
162};
163
164/*
165 * Handle commands from user-space.
166 */
167static int at32_wdt_ioctl(struct inode *inode, struct file *file,
168 unsigned int cmd, unsigned long arg)
169{
170 int ret = -ENOTTY;
171 int time;
172 void __user *argp = (void __user *)arg;
173 int __user *p = argp;
174
175 switch (cmd) {
176 case WDIOC_KEEPALIVE:
177 at32_wdt_pat();
178 ret = 0;
179 break;
180 case WDIOC_GETSUPPORT:
181 ret = copy_to_user(argp, &at32_wdt_info,
182 sizeof(at32_wdt_info)) ? -EFAULT : 0;
183 break;
184 case WDIOC_SETTIMEOUT:
185 ret = get_user(time, p);
186 if (ret)
187 break;
188 ret = at32_wdt_settimeout(time);
189 if (ret)
190 break;
191 /* Enable new time value */
192 at32_wdt_start();
193 /* fall through */
194 case WDIOC_GETTIMEOUT:
195 ret = put_user(wdt->timeout, p);
196 break;
197 case WDIOC_GETSTATUS: /* fall through */
198 case WDIOC_GETBOOTSTATUS:
199 ret = put_user(0, p);
200 break;
201 case WDIOC_SETOPTIONS:
202 ret = get_user(time, p);
203 if (ret)
204 break;
205 if (time & WDIOS_DISABLECARD)
206 at32_wdt_stop();
207 if (time & WDIOS_ENABLECARD)
208 at32_wdt_start();
209 ret = 0;
210 break;
211 }
212
213 return ret;
214}
215
216static ssize_t at32_wdt_write(struct file *file, const char __user *data,
217 size_t len, loff_t *ppos)
218{
219 /* See if we got the magic character 'V' and reload the timer */
220 if (len) {
221 if (!nowayout) {
222 size_t i;
223
224 /*
225 * note: just in case someone wrote the magic
226 * character five months ago...
227 */
228 expect_release = 0;
229
230 /*
231 * scan to see whether or not we got the magic
232 * character
233 */
234 for (i = 0; i != len; i++) {
235 char c;
236 if (get_user(c, data+i))
237 return -EFAULT;
238 if (c == 'V')
239 expect_release = 42;
240 }
241 }
242 /* someone wrote to us, we should pat the watchdog */
243 at32_wdt_pat();
244 }
245 return len;
246}
247
248static const struct file_operations at32_wdt_fops = {
249 .owner = THIS_MODULE,
250 .llseek = no_llseek,
251 .ioctl = at32_wdt_ioctl,
252 .open = at32_wdt_open,
253 .release = at32_wdt_close,
254 .write = at32_wdt_write,
255};
256
257static int __init at32_wdt_probe(struct platform_device *pdev)
258{
259 struct resource *regs;
260 int ret;
261
262 if (wdt) {
263 dev_dbg(&pdev->dev, "only 1 wdt instance supported.\n");
264 return -EBUSY;
265 }
266
267 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
268 if (!regs) {
269 dev_dbg(&pdev->dev, "missing mmio resource\n");
270 return -ENXIO;
271 }
272
273 wdt = kzalloc(sizeof(struct wdt_at32ap700x), GFP_KERNEL);
274 if (!wdt) {
275 dev_dbg(&pdev->dev, "no memory for wdt structure\n");
276 return -ENOMEM;
277 }
278
279 wdt->regs = ioremap(regs->start, regs->end - regs->start + 1);
280 if (!wdt->regs) {
281 ret = -ENOMEM;
282 dev_dbg(&pdev->dev, "could not map I/O memory\n");
283 goto err_free;
284 }
285 spin_lock_init(&wdt->io_lock);
286 wdt->users = 0;
287 wdt->miscdev.minor = WATCHDOG_MINOR;
288 wdt->miscdev.name = "watchdog";
289 wdt->miscdev.fops = &at32_wdt_fops;
290
291 if (at32_wdt_settimeout(timeout)) {
292 at32_wdt_settimeout(TIMEOUT_DEFAULT);
293 dev_dbg(&pdev->dev,
294 "default timeout invalid, set to %d sec.\n",
295 TIMEOUT_DEFAULT);
296 }
297
298 ret = misc_register(&wdt->miscdev);
299 if (ret) {
300 dev_dbg(&pdev->dev, "failed to register wdt miscdev\n");
301 goto err_iounmap;
302 }
303
304 platform_set_drvdata(pdev, wdt);
305 wdt->miscdev.parent = &pdev->dev;
306 dev_info(&pdev->dev,
307 "AT32AP700X WDT at 0x%p, timeout %d sec (nowayout=%d)\n",
308 wdt->regs, wdt->timeout, nowayout);
309
310 return 0;
311
312err_iounmap:
313 iounmap(wdt->regs);
314err_free:
315 kfree(wdt);
316 wdt = NULL;
317 return ret;
318}
319
320static int __exit at32_wdt_remove(struct platform_device *pdev)
321{
322 if (wdt && platform_get_drvdata(pdev) == wdt) {
323 /* Stop the timer before we leave */
324 if (!nowayout)
325 at32_wdt_stop();
326
327 misc_deregister(&wdt->miscdev);
328 iounmap(wdt->regs);
329 kfree(wdt);
330 wdt = NULL;
331 platform_set_drvdata(pdev, NULL);
332 }
333
334 return 0;
335}
336
337static void at32_wdt_shutdown(struct platform_device *pdev)
338{
339 at32_wdt_stop();
340}
341
342#ifdef CONFIG_PM
343static int at32_wdt_suspend(struct platform_device *pdev, pm_message_t message)
344{
345 at32_wdt_stop();
346 return 0;
347}
348
349static int at32_wdt_resume(struct platform_device *pdev)
350{
351 if (wdt->users)
352 at32_wdt_start();
353 return 0;
354}
355#else
356#define at32_wdt_suspend NULL
357#define at32_wdt_resume NULL
358#endif
359
360static struct platform_driver at32_wdt_driver = {
361 .remove = __exit_p(at32_wdt_remove),
362 .suspend = at32_wdt_suspend,
363 .resume = at32_wdt_resume,
364 .driver = {
365 .name = "at32_wdt",
366 .owner = THIS_MODULE,
367 },
368 .shutdown = at32_wdt_shutdown,
369};
370
371static int __init at32_wdt_init(void)
372{
373 return platform_driver_probe(&at32_wdt_driver, at32_wdt_probe);
374}
375module_init(at32_wdt_init);
376
377static void __exit at32_wdt_exit(void)
378{
379 platform_driver_unregister(&at32_wdt_driver);
380}
381module_exit(at32_wdt_exit);
382
383MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
384MODULE_DESCRIPTION("Watchdog driver for Atmel AT32AP700X");
385MODULE_LICENSE("GPL");
386MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/char/watchdog/ep93xx_wdt.c
index 01cf123b1616..0e4787a0bb87 100644
--- a/drivers/char/watchdog/ep93xx_wdt.c
+++ b/drivers/char/watchdog/ep93xx_wdt.c
@@ -107,10 +107,6 @@ static ssize_t
107ep93xx_wdt_write(struct file *file, const char __user *data, size_t len, 107ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
108 loff_t *ppos) 108 loff_t *ppos)
109{ 109{
110 /* Can't seek (pwrite) on this device */
111 if (*ppos != file->f_pos)
112 return -ESPIPE;
113
114 if (len) { 110 if (len) {
115 if (!nowayout) { 111 if (!nowayout) {
116 size_t i; 112 size_t i;
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index f35e2848aa3e..db2ccb864412 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -29,11 +29,18 @@
29 * - support for one more type board 29 * - support for one more type board
30 * 30 *
31 * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com> 31 * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
32 * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT 32 * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
33 *
34 * Version 0.6 (2002/04/12): Rob Radez <rob@osinvestor.com>
35 * - make mixcomwd_opened unsigned,
36 * removed lock_kernel/unlock_kernel from mixcomwd_release,
37 * modified ioctl a bit to conform to API
33 * 38 *
34 */ 39 */
35 40
36#define VERSION "0.5" 41#define VERSION "0.6"
42#define WATCHDOG_NAME "mixcomwd"
43#define PFX WATCHDOG_NAME ": "
37 44
38#include <linux/module.h> 45#include <linux/module.h>
39#include <linux/moduleparam.h> 46#include <linux/moduleparam.h>
@@ -49,12 +56,46 @@
49#include <asm/uaccess.h> 56#include <asm/uaccess.h>
50#include <asm/io.h> 57#include <asm/io.h>
51 58
52static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 }; 59/*
53 60 * We have two types of cards that can be probed:
54#define MIXCOM_WATCHDOG_OFFSET 0xc10 61 * 1) The Mixcom cards: these cards can be found at addresses
62 * 0x180, 0x280, 0x380 with an additional offset of 0xc10.
63 * (Or 0xd90, 0xe90, 0xf90).
64 * 2) The FlashCOM cards: these cards can be set up at
65 * 0x300 -> 0x378, in 0x8 jumps with an offset of 0x04.
66 * (Or 0x304 -> 0x37c in 0x8 jumps).
67 * Each card has it's own ID.
68 */
55#define MIXCOM_ID 0x11 69#define MIXCOM_ID 0x11
56#define FLASHCOM_WATCHDOG_OFFSET 0x4
57#define FLASHCOM_ID 0x18 70#define FLASHCOM_ID 0x18
71static struct {
72 int ioport;
73 int id;
74} mixcomwd_io_info[] __devinitdata = {
75 /* The Mixcom cards */
76 {0x0d90, MIXCOM_ID},
77 {0x0e90, MIXCOM_ID},
78 {0x0f90, MIXCOM_ID},
79 /* The FlashCOM cards */
80 {0x0304, FLASHCOM_ID},
81 {0x030c, FLASHCOM_ID},
82 {0x0314, FLASHCOM_ID},
83 {0x031c, FLASHCOM_ID},
84 {0x0324, FLASHCOM_ID},
85 {0x032c, FLASHCOM_ID},
86 {0x0334, FLASHCOM_ID},
87 {0x033c, FLASHCOM_ID},
88 {0x0344, FLASHCOM_ID},
89 {0x034c, FLASHCOM_ID},
90 {0x0354, FLASHCOM_ID},
91 {0x035c, FLASHCOM_ID},
92 {0x0364, FLASHCOM_ID},
93 {0x036c, FLASHCOM_ID},
94 {0x0374, FLASHCOM_ID},
95 {0x037c, FLASHCOM_ID},
96 /* The end of the list */
97 {0x0000, 0},
98};
58 99
59static void mixcomwd_timerfun(unsigned long d); 100static void mixcomwd_timerfun(unsigned long d);
60 101
@@ -113,13 +154,13 @@ static int mixcomwd_release(struct inode *inode, struct file *file)
113{ 154{
114 if (expect_close == 42) { 155 if (expect_close == 42) {
115 if(mixcomwd_timer_alive) { 156 if(mixcomwd_timer_alive) {
116 printk(KERN_ERR "mixcomwd: release called while internal timer alive"); 157 printk(KERN_ERR PFX "release called while internal timer alive");
117 return -EBUSY; 158 return -EBUSY;
118 } 159 }
119 mixcomwd_timer_alive=1; 160 mixcomwd_timer_alive=1;
120 mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); 161 mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
121 } else { 162 } else {
122 printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly. WDT will not stop!\n"); 163 printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
123 } 164 }
124 165
125 clear_bit(0,&mixcomwd_opened); 166 clear_bit(0,&mixcomwd_opened);
@@ -188,8 +229,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
188 return 0; 229 return 0;
189} 230}
190 231
191static const struct file_operations mixcomwd_fops= 232static const struct file_operations mixcomwd_fops = {
192{
193 .owner = THIS_MODULE, 233 .owner = THIS_MODULE,
194 .llseek = no_llseek, 234 .llseek = no_llseek,
195 .write = mixcomwd_write, 235 .write = mixcomwd_write,
@@ -198,46 +238,30 @@ static const struct file_operations mixcomwd_fops=
198 .release = mixcomwd_release, 238 .release = mixcomwd_release,
199}; 239};
200 240
201static struct miscdevice mixcomwd_miscdev= 241static struct miscdevice mixcomwd_miscdev = {
202{
203 .minor = WATCHDOG_MINOR, 242 .minor = WATCHDOG_MINOR,
204 .name = "watchdog", 243 .name = "watchdog",
205 .fops = &mixcomwd_fops, 244 .fops = &mixcomwd_fops,
206}; 245};
207 246
208static int __init mixcomwd_checkcard(int port) 247static int __init checkcard(int port, int card_id)
209{ 248{
210 int id; 249 int id;
211 250
212 port += MIXCOM_WATCHDOG_OFFSET;
213 if (!request_region(port, 1, "MixCOM watchdog")) {
214 return 0;
215 }
216
217 id=inb_p(port) & 0x3f;
218 if(id!=MIXCOM_ID) {
219 release_region(port, 1);
220 return 0;
221 }
222 return port;
223}
224
225static int __init flashcom_checkcard(int port)
226{
227 int id;
228
229 port += FLASHCOM_WATCHDOG_OFFSET;
230 if (!request_region(port, 1, "MixCOM watchdog")) { 251 if (!request_region(port, 1, "MixCOM watchdog")) {
231 return 0; 252 return 0;
232 } 253 }
233 254
234 id=inb_p(port); 255 id=inb_p(port);
235 if(id!=FLASHCOM_ID) { 256 if (card_id==MIXCOM_ID)
257 id &= 0x3f;
258
259 if (id!=card_id) {
236 release_region(port, 1); 260 release_region(port, 1);
237 return 0; 261 return 0;
238 } 262 }
239 return port; 263 return 1;
240 } 264}
241 265
242static int __init mixcomwd_init(void) 266static int __init mixcomwd_init(void)
243{ 267{
@@ -245,50 +269,50 @@ static int __init mixcomwd_init(void)
245 int ret; 269 int ret;
246 int found=0; 270 int found=0;
247 271
248 for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) { 272 for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) {
249 watchdog_port = mixcomwd_checkcard(mixcomwd_ioports[i]); 273 if (checkcard(mixcomwd_io_info[i].ioport,
250 if (watchdog_port) { 274 mixcomwd_io_info[i].id)) {
251 found = 1;
252 }
253 }
254
255 /* The FlashCOM card can be set up at 0x300 -> 0x378, in 0x8 jumps */
256 for (i = 0x300; !found && i < 0x380; i+=0x8) {
257 watchdog_port = flashcom_checkcard(i);
258 if (watchdog_port) {
259 found = 1; 275 found = 1;
276 watchdog_port = mixcomwd_io_info[i].ioport;
260 } 277 }
261 } 278 }
262 279
263 if (!found) { 280 if (!found) {
264 printk("mixcomwd: No card detected, or port not available.\n"); 281 printk(KERN_ERR PFX "No card detected, or port not available.\n");
265 return -ENODEV; 282 return -ENODEV;
266 } 283 }
267 284
268 ret = misc_register(&mixcomwd_miscdev); 285 ret = misc_register(&mixcomwd_miscdev);
269 if (ret) 286 if (ret)
270 { 287 {
271 release_region(watchdog_port, 1); 288 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
272 return ret; 289 WATCHDOG_MINOR, ret);
290 goto error_misc_register_watchdog;
273 } 291 }
274 292
275 printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port); 293 printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
294 VERSION, watchdog_port);
276 295
277 return 0; 296 return 0;
297
298error_misc_register_watchdog:
299 release_region(watchdog_port, 1);
300 watchdog_port = 0x0000;
301 return ret;
278} 302}
279 303
280static void __exit mixcomwd_exit(void) 304static void __exit mixcomwd_exit(void)
281{ 305{
282 if (!nowayout) { 306 if (!nowayout) {
283 if(mixcomwd_timer_alive) { 307 if(mixcomwd_timer_alive) {
284 printk(KERN_WARNING "mixcomwd: I quit now, hardware will" 308 printk(KERN_WARNING PFX "I quit now, hardware will"
285 " probably reboot!\n"); 309 " probably reboot!\n");
286 del_timer_sync(&mixcomwd_timer); 310 del_timer_sync(&mixcomwd_timer);
287 mixcomwd_timer_alive=0; 311 mixcomwd_timer_alive=0;
288 } 312 }
289 } 313 }
290 release_region(watchdog_port,1);
291 misc_deregister(&mixcomwd_miscdev); 314 misc_deregister(&mixcomwd_miscdev);
315 release_region(watchdog_port,1);
292} 316}
293 317
294module_init(mixcomwd_init); 318module_init(mixcomwd_init);
@@ -296,5 +320,6 @@ module_exit(mixcomwd_exit);
296 320
297MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>"); 321MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
298MODULE_DESCRIPTION("MixCom Watchdog driver"); 322MODULE_DESCRIPTION("MixCom Watchdog driver");
323MODULE_VERSION(VERSION);
299MODULE_LICENSE("GPL"); 324MODULE_LICENSE("GPL");
300MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 325MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c
index 5991add702b0..22f8873dd092 100644
--- a/drivers/char/watchdog/pnx4008_wdt.c
+++ b/drivers/char/watchdog/pnx4008_wdt.c
@@ -148,10 +148,6 @@ static ssize_t
148pnx4008_wdt_write(struct file *file, const char *data, size_t len, 148pnx4008_wdt_write(struct file *file, const char *data, size_t len,
149 loff_t * ppos) 149 loff_t * ppos)
150{ 150{
151 /* Can't seek (pwrite) on this device */
152 if (ppos != &file->f_pos)
153 return -ESPIPE;
154
155 if (len) { 151 if (len) {
156 if (!nowayout) { 152 if (!nowayout) {
157 size_t i; 153 size_t i;
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 20fa29ca7404..50430bced2f2 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -92,6 +92,7 @@ typedef enum close_state {
92 92
93static DECLARE_MUTEX(open_lock); 93static DECLARE_MUTEX(open_lock);
94 94
95static struct device *wdt_dev; /* platform device attached to */
95static struct resource *wdt_mem; 96static struct resource *wdt_mem;
96static struct resource *wdt_irq; 97static struct resource *wdt_irq;
97static struct clk *wdt_clock; 98static struct clk *wdt_clock;
@@ -180,7 +181,7 @@ static int s3c2410wdt_set_heartbeat(int timeout)
180 } 181 }
181 182
182 if ((count / divisor) >= 0x10000) { 183 if ((count / divisor) >= 0x10000) {
183 printk(KERN_ERR PFX "timeout %d too big\n", timeout); 184 dev_err(wdt_dev, "timeout %d too big\n", timeout);
184 return -EINVAL; 185 return -EINVAL;
185 } 186 }
186 } 187 }
@@ -233,7 +234,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file)
233 if (allow_close == CLOSE_STATE_ALLOW) { 234 if (allow_close == CLOSE_STATE_ALLOW) {
234 s3c2410wdt_stop(); 235 s3c2410wdt_stop();
235 } else { 236 } else {
236 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); 237 dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");
237 s3c2410wdt_keepalive(); 238 s3c2410wdt_keepalive();
238 } 239 }
239 240
@@ -338,7 +339,7 @@ static struct miscdevice s3c2410wdt_miscdev = {
338 339
339static irqreturn_t s3c2410wdt_irq(int irqno, void *param) 340static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
340{ 341{
341 printk(KERN_INFO PFX "Watchdog timer expired!\n"); 342 dev_info(wdt_dev, "watchdog timer expired (irq)\n");
342 343
343 s3c2410wdt_keepalive(); 344 s3c2410wdt_keepalive();
344 return IRQ_HANDLED; 345 return IRQ_HANDLED;
@@ -348,31 +349,36 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
348static int s3c2410wdt_probe(struct platform_device *pdev) 349static int s3c2410wdt_probe(struct platform_device *pdev)
349{ 350{
350 struct resource *res; 351 struct resource *res;
352 struct device *dev;
353 unsigned int wtcon;
351 int started = 0; 354 int started = 0;
352 int ret; 355 int ret;
353 int size; 356 int size;
354 357
355 DBG("%s: probe=%p\n", __FUNCTION__, pdev); 358 DBG("%s: probe=%p\n", __FUNCTION__, pdev);
356 359
360 dev = &pdev->dev;
361 wdt_dev = &pdev->dev;
362
357 /* get the memory region for the watchdog timer */ 363 /* get the memory region for the watchdog timer */
358 364
359 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 365 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
360 if (res == NULL) { 366 if (res == NULL) {
361 printk(KERN_INFO PFX "failed to get memory region resouce\n"); 367 dev_err(dev, "no memory resource specified\n");
362 return -ENOENT; 368 return -ENOENT;
363 } 369 }
364 370
365 size = (res->end-res->start)+1; 371 size = (res->end-res->start)+1;
366 wdt_mem = request_mem_region(res->start, size, pdev->name); 372 wdt_mem = request_mem_region(res->start, size, pdev->name);
367 if (wdt_mem == NULL) { 373 if (wdt_mem == NULL) {
368 printk(KERN_INFO PFX "failed to get memory region\n"); 374 dev_err(dev, "failed to get memory region\n");
369 ret = -ENOENT; 375 ret = -ENOENT;
370 goto err_req; 376 goto err_req;
371 } 377 }
372 378
373 wdt_base = ioremap(res->start, size); 379 wdt_base = ioremap(res->start, size);
374 if (wdt_base == 0) { 380 if (wdt_base == 0) {
375 printk(KERN_INFO PFX "failed to ioremap() region\n"); 381 dev_err(dev, "failed to ioremap() region\n");
376 ret = -EINVAL; 382 ret = -EINVAL;
377 goto err_req; 383 goto err_req;
378 } 384 }
@@ -381,20 +387,20 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
381 387
382 wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 388 wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
383 if (wdt_irq == NULL) { 389 if (wdt_irq == NULL) {
384 printk(KERN_INFO PFX "failed to get irq resource\n"); 390 dev_err(dev, "no irq resource specified\n");
385 ret = -ENOENT; 391 ret = -ENOENT;
386 goto err_map; 392 goto err_map;
387 } 393 }
388 394
389 ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev); 395 ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
390 if (ret != 0) { 396 if (ret != 0) {
391 printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); 397 dev_err(dev, "failed to install irq (%d)\n", ret);
392 goto err_map; 398 goto err_map;
393 } 399 }
394 400
395 wdt_clock = clk_get(&pdev->dev, "watchdog"); 401 wdt_clock = clk_get(&pdev->dev, "watchdog");
396 if (IS_ERR(wdt_clock)) { 402 if (IS_ERR(wdt_clock)) {
397 printk(KERN_INFO PFX "failed to find watchdog clock source\n"); 403 dev_err(dev, "failed to find watchdog clock source\n");
398 ret = PTR_ERR(wdt_clock); 404 ret = PTR_ERR(wdt_clock);
399 goto err_irq; 405 goto err_irq;
400 } 406 }
@@ -408,22 +414,22 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
408 started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); 414 started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
409 415
410 if (started == 0) { 416 if (started == 0) {
411 printk(KERN_INFO PFX "tmr_margin value out of range, default %d used\n", 417 dev_info(dev,"tmr_margin value out of range, default %d used\n",
412 CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); 418 CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
413 } else { 419 } else {
414 printk(KERN_INFO PFX "default timer value is out of range, cannot start\n"); 420 dev_info(dev, "default timer value is out of range, cannot start\n");
415 } 421 }
416 } 422 }
417 423
418 ret = misc_register(&s3c2410wdt_miscdev); 424 ret = misc_register(&s3c2410wdt_miscdev);
419 if (ret) { 425 if (ret) {
420 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", 426 dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
421 WATCHDOG_MINOR, ret); 427 WATCHDOG_MINOR, ret);
422 goto err_clk; 428 goto err_clk;
423 } 429 }
424 430
425 if (tmr_atboot && started == 0) { 431 if (tmr_atboot && started == 0) {
426 printk(KERN_INFO PFX "Starting Watchdog Timer\n"); 432 dev_info(dev, "starting watchdog timer\n");
427 s3c2410wdt_start(); 433 s3c2410wdt_start();
428 } else if (!tmr_atboot) { 434 } else if (!tmr_atboot) {
429 /* if we're not enabling the watchdog, then ensure it is 435 /* if we're not enabling the watchdog, then ensure it is
@@ -433,6 +439,15 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
433 s3c2410wdt_stop(); 439 s3c2410wdt_stop();
434 } 440 }
435 441
442 /* print out a statement of readiness */
443
444 wtcon = readl(wdt_base + S3C2410_WTCON);
445
446 dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
447 (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in",
448 (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis",
449 (wtcon & S3C2410_WTCON_INTEN) ? "" : "en");
450
436 return 0; 451 return 0;
437 452
438 err_clk: 453 err_clk: