aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig2
-rw-r--r--drivers/watchdog/at91rm9200_wdt.c4
-rw-r--r--drivers/watchdog/at91sam9_wdt.c1
-rw-r--r--drivers/watchdog/gef_wdt.c2
-rw-r--r--drivers/watchdog/iTCO_vendor_support.c32
-rw-r--r--drivers/watchdog/iTCO_wdt.c35
-rw-r--r--drivers/watchdog/ks8695_wdt.c1
-rw-r--r--drivers/watchdog/orion5x_wdt.c1
-rw-r--r--drivers/watchdog/rc32434_wdt.c168
9 files changed, 118 insertions, 128 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 09a3d5522b43..325c10ff6a2c 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -406,7 +406,7 @@ config ITCO_WDT
406 ---help--- 406 ---help---
407 Hardware driver for the intel TCO timer based watchdog devices. 407 Hardware driver for the intel TCO timer based watchdog devices.
408 These drivers are included in the Intel 82801 I/O Controller 408 These drivers are included in the Intel 82801 I/O Controller
409 Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB 409 Hub family (from ICH0 up to ICH10) and in the Intel 63xxESB
410 controller hub. 410 controller hub.
411 411
412 The TCO (Total Cost of Ownership) timer is a watchdog timer 412 The TCO (Total Cost of Ownership) timer is a watchdog timer
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c
index 5531691f46ea..e35d54589232 100644
--- a/drivers/watchdog/at91rm9200_wdt.c
+++ b/drivers/watchdog/at91rm9200_wdt.c
@@ -107,10 +107,10 @@ static int at91_wdt_close(struct inode *inode, struct file *file)
107static int at91_wdt_settimeout(int new_time) 107static int at91_wdt_settimeout(int new_time)
108{ 108{
109 /* 109 /*
110 * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz 110 * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
111 * 111 *
112 * Since WDV is a 16-bit counter, the maximum period is 112 * Since WDV is a 16-bit counter, the maximum period is
113 * 65536 / 0.256 = 256 seconds. 113 * 65536 / 256 = 256 seconds.
114 */ 114 */
115 if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) 115 if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
116 return -EINVAL; 116 return -EINVAL;
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index b1da287f90ec..a56ac84381b1 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -18,6 +18,7 @@
18#include <linux/errno.h> 18#include <linux/errno.h>
19#include <linux/fs.h> 19#include <linux/fs.h>
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/io.h>
21#include <linux/kernel.h> 22#include <linux/kernel.h>
22#include <linux/miscdevice.h> 23#include <linux/miscdevice.h>
23#include <linux/module.h> 24#include <linux/module.h>
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
index f0c2b7a1a175..734d9806a872 100644
--- a/drivers/watchdog/gef_wdt.c
+++ b/drivers/watchdog/gef_wdt.c
@@ -269,7 +269,7 @@ static int __devinit gef_wdt_probe(struct of_device *dev,
269 bus_clk = 133; /* in MHz */ 269 bus_clk = 133; /* in MHz */
270 270
271 freq = fsl_get_sys_freq(); 271 freq = fsl_get_sys_freq();
272 if (freq > 0) 272 if (freq != -1)
273 bus_clk = freq; 273 bus_clk = freq;
274 274
275 /* Map devices registers into memory */ 275 /* Map devices registers into memory */
diff --git a/drivers/watchdog/iTCO_vendor_support.c b/drivers/watchdog/iTCO_vendor_support.c
index 2474ebca88f6..d8264ad0be41 100644
--- a/drivers/watchdog/iTCO_vendor_support.c
+++ b/drivers/watchdog/iTCO_vendor_support.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * intel TCO vendor specific watchdog driver support 2 * intel TCO vendor specific watchdog driver support
3 * 3 *
4 * (c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>. 4 * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
@@ -19,7 +19,7 @@
19 19
20/* Module and version information */ 20/* Module and version information */
21#define DRV_NAME "iTCO_vendor_support" 21#define DRV_NAME "iTCO_vendor_support"
22#define DRV_VERSION "1.02" 22#define DRV_VERSION "1.03"
23#define PFX DRV_NAME ": " 23#define PFX DRV_NAME ": "
24 24
25/* Includes */ 25/* Includes */
@@ -77,6 +77,26 @@ MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (n
77 * 20.6 seconds. 77 * 20.6 seconds.
78 */ 78 */
79 79
80static void supermicro_old_pre_start(unsigned long acpibase)
81{
82 unsigned long val32;
83
84 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
85 val32 = inl(SMI_EN);
86 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
87 outl(val32, SMI_EN); /* Needed to activate watchdog */
88}
89
90static void supermicro_old_pre_stop(unsigned long acpibase)
91{
92 unsigned long val32;
93
94 /* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
95 val32 = inl(SMI_EN);
96 val32 |= 0x00002000; /* Turn on SMI clearing watchdog */
97 outl(val32, SMI_EN); /* Needed to deactivate watchdog */
98}
99
80static void supermicro_old_pre_keepalive(unsigned long acpibase) 100static void supermicro_old_pre_keepalive(unsigned long acpibase)
81{ 101{
82 /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */ 102 /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
@@ -228,14 +248,18 @@ static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
228void iTCO_vendor_pre_start(unsigned long acpibase, 248void iTCO_vendor_pre_start(unsigned long acpibase,
229 unsigned int heartbeat) 249 unsigned int heartbeat)
230{ 250{
231 if (vendorsupport == SUPERMICRO_NEW_BOARD) 251 if (vendorsupport == SUPERMICRO_OLD_BOARD)
252 supermicro_old_pre_start(acpibase);
253 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
232 supermicro_new_pre_start(heartbeat); 254 supermicro_new_pre_start(heartbeat);
233} 255}
234EXPORT_SYMBOL(iTCO_vendor_pre_start); 256EXPORT_SYMBOL(iTCO_vendor_pre_start);
235 257
236void iTCO_vendor_pre_stop(unsigned long acpibase) 258void iTCO_vendor_pre_stop(unsigned long acpibase)
237{ 259{
238 if (vendorsupport == SUPERMICRO_NEW_BOARD) 260 if (vendorsupport == SUPERMICRO_OLD_BOARD)
261 supermicro_old_pre_stop(acpibase);
262 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
239 supermicro_new_pre_stop(); 263 supermicro_new_pre_stop();
240} 264}
241EXPORT_SYMBOL(iTCO_vendor_pre_stop); 265EXPORT_SYMBOL(iTCO_vendor_pre_stop);
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 5b395a4ddfdf..352334947ea3 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets) 2 * intel TCO Watchdog Driver (Used in i82801 and i63xxESB chipsets)
3 * 3 *
4 * (c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>. 4 * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License 7 * modify it under the terms of the GNU General Public License
@@ -63,7 +63,7 @@
63 63
64/* Module and version information */ 64/* Module and version information */
65#define DRV_NAME "iTCO_wdt" 65#define DRV_NAME "iTCO_wdt"
66#define DRV_VERSION "1.04" 66#define DRV_VERSION "1.05"
67#define PFX DRV_NAME ": " 67#define PFX DRV_NAME ": "
68 68
69/* Includes */ 69/* Includes */
@@ -236,16 +236,16 @@ MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
236 236
237/* Address definitions for the TCO */ 237/* Address definitions for the TCO */
238/* TCO base address */ 238/* TCO base address */
239#define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 239#define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60
240/* SMI Control and Enable Register */ 240/* SMI Control and Enable Register */
241#define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 241#define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30
242 242
243#define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Curr. Value */ 243#define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Curr. Value */
244#define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */ 244#define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */
245#define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */ 245#define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
246#define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */ 246#define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */
247#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */ 247#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
248#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */ 248#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */
249#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */ 249#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */
250#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */ 250#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */
251#define TCOv2_TMR TCOBASE + 0x12 /* TCOv2 Timer Initial Value */ 251#define TCOv2_TMR TCOBASE + 0x12 /* TCOv2 Timer Initial Value */
@@ -338,7 +338,6 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void)
338static int iTCO_wdt_start(void) 338static int iTCO_wdt_start(void)
339{ 339{
340 unsigned int val; 340 unsigned int val;
341 unsigned long val32;
342 341
343 spin_lock(&iTCO_wdt_private.io_lock); 342 spin_lock(&iTCO_wdt_private.io_lock);
344 343
@@ -351,11 +350,6 @@ static int iTCO_wdt_start(void)
351 return -EIO; 350 return -EIO;
352 } 351 }
353 352
354 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
355 val32 = inl(SMI_EN);
356 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
357 outl(val32, SMI_EN);
358
359 /* Force the timer to its reload value by writing to the TCO_RLD 353 /* Force the timer to its reload value by writing to the TCO_RLD
360 register */ 354 register */
361 if (iTCO_wdt_private.iTCO_version == 2) 355 if (iTCO_wdt_private.iTCO_version == 2)
@@ -378,7 +372,6 @@ static int iTCO_wdt_start(void)
378static int iTCO_wdt_stop(void) 372static int iTCO_wdt_stop(void)
379{ 373{
380 unsigned int val; 374 unsigned int val;
381 unsigned long val32;
382 375
383 spin_lock(&iTCO_wdt_private.io_lock); 376 spin_lock(&iTCO_wdt_private.io_lock);
384 377
@@ -390,11 +383,6 @@ static int iTCO_wdt_stop(void)
390 outw(val, TCO1_CNT); 383 outw(val, TCO1_CNT);
391 val = inw(TCO1_CNT); 384 val = inw(TCO1_CNT);
392 385
393 /* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
394 val32 = inl(SMI_EN);
395 val32 |= 0x00002000;
396 outl(val32, SMI_EN);
397
398 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ 386 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
399 iTCO_wdt_set_NO_REBOOT_bit(); 387 iTCO_wdt_set_NO_REBOOT_bit();
400 388
@@ -649,6 +637,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
649 int ret; 637 int ret;
650 u32 base_address; 638 u32 base_address;
651 unsigned long RCBA; 639 unsigned long RCBA;
640 unsigned long val32;
652 641
653 /* 642 /*
654 * Find the ACPI/PM base I/O address which is the base 643 * Find the ACPI/PM base I/O address which is the base
@@ -695,6 +684,10 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
695 ret = -EIO; 684 ret = -EIO;
696 goto out; 685 goto out;
697 } 686 }
687 /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
688 val32 = inl(SMI_EN);
689 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
690 outl(val32, SMI_EN);
698 691
699 /* The TCO I/O registers reside in a 32-byte range pointed to 692 /* The TCO I/O registers reside in a 32-byte range pointed to
700 by the TCOBASE value */ 693 by the TCOBASE value */
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
index 0b798fdaa378..74c92d384112 100644
--- a/drivers/watchdog/ks8695_wdt.c
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -21,6 +21,7 @@
21#include <linux/watchdog.h> 21#include <linux/watchdog.h>
22#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/uaccess.h> 23#include <linux/uaccess.h>
24#include <mach/timex.h>
24#include <mach/regs-timer.h> 25#include <mach/regs-timer.h>
25 26
26#define WDT_DEFAULT_TIME 5 /* seconds */ 27#define WDT_DEFAULT_TIME 5 /* seconds */
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c
index 14a339f58b6a..b64ae1a17832 100644
--- a/drivers/watchdog/orion5x_wdt.c
+++ b/drivers/watchdog/orion5x_wdt.c
@@ -29,6 +29,7 @@
29#define WDT_EN 0x0010 29#define WDT_EN 0x0010
30#define WDT_VAL (TIMER_VIRT_BASE + 0x0024) 30#define WDT_VAL (TIMER_VIRT_BASE + 0x0024)
31 31
32#define ORION5X_TCLK 166666667
32#define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK) 33#define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK)
33#define WDT_IN_USE 0 34#define WDT_IN_USE 0
34#define WDT_OK_TO_CLOSE 1 35#define WDT_OK_TO_CLOSE 1
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c
index 57027f4653ce..f3553fa40b17 100644
--- a/drivers/watchdog/rc32434_wdt.c
+++ b/drivers/watchdog/rc32434_wdt.c
@@ -34,104 +34,89 @@
34#include <asm/time.h> 34#include <asm/time.h>
35#include <asm/mach-rc32434/integ.h> 35#include <asm/mach-rc32434/integ.h>
36 36
37#define MAX_TIMEOUT 20 37#define VERSION "0.4"
38#define RC32434_WDT_INTERVAL (15 * HZ)
39
40#define VERSION "0.2"
41 38
42static struct { 39static struct {
43 struct completion stop;
44 int running;
45 struct timer_list timer;
46 int queue;
47 int default_ticks;
48 unsigned long inuse; 40 unsigned long inuse;
49} rc32434_wdt_device; 41} rc32434_wdt_device;
50 42
51static struct integ __iomem *wdt_reg; 43static struct integ __iomem *wdt_reg;
52static int ticks = 100 * HZ;
53 44
54static int expect_close; 45static int expect_close;
55static int timeout; 46
47/* Board internal clock speed in Hz,
48 * the watchdog timer ticks at. */
49extern unsigned int idt_cpu_freq;
50
51/* translate wtcompare value to seconds and vice versa */
52#define WTCOMP2SEC(x) (x / idt_cpu_freq)
53#define SEC2WTCOMP(x) (x * idt_cpu_freq)
54
55/* Use a default timeout of 20s. This should be
56 * safe for CPU clock speeds up to 400MHz, as
57 * ((2 ^ 32) - 1) / (400MHz / 2) = 21s. */
58#define WATCHDOG_TIMEOUT 20
59
60static int timeout = WATCHDOG_TIMEOUT;
56 61
57static int nowayout = WATCHDOG_NOWAYOUT; 62static int nowayout = WATCHDOG_NOWAYOUT;
58module_param(nowayout, int, 0); 63module_param(nowayout, int, 0);
59MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 64MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
60 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 65 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
61 66
67/* apply or and nand masks to data read from addr and write back */
68#define SET_BITS(addr, or, nand) \
69 writel((readl(&addr) | or) & ~nand, &addr)
62 70
63static void rc32434_wdt_start(void) 71static void rc32434_wdt_start(void)
64{ 72{
65 u32 val; 73 u32 or, nand;
66
67 if (!rc32434_wdt_device.inuse) {
68 writel(0, &wdt_reg->wtcount);
69 74
70 val = RC32434_ERR_WRE; 75 /* zero the counter before enabling */
71 writel(readl(&wdt_reg->errcs) | val, &wdt_reg->errcs); 76 writel(0, &wdt_reg->wtcount);
72 77
73 val = RC32434_WTC_EN; 78 /* don't generate a non-maskable interrupt,
74 writel(readl(&wdt_reg->wtc) | val, &wdt_reg->wtc); 79 * do a warm reset instead */
75 } 80 nand = 1 << RC32434_ERR_WNE;
76 rc32434_wdt_device.running++; 81 or = 1 << RC32434_ERR_WRE;
77}
78 82
79static void rc32434_wdt_stop(void) 83 /* reset the ERRCS timeout bit in case it's set */
80{ 84 nand |= 1 << RC32434_ERR_WTO;
81 u32 val;
82 85
83 if (rc32434_wdt_device.running) { 86 SET_BITS(wdt_reg->errcs, or, nand);
84 87
85 val = ~RC32434_WTC_EN; 88 /* reset WTC timeout bit and enable WDT */
86 writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc); 89 nand = 1 << RC32434_WTC_TO;
90 or = 1 << RC32434_WTC_EN;
87 91
88 val = ~RC32434_ERR_WRE; 92 SET_BITS(wdt_reg->wtc, or, nand);
89 writel(readl(&wdt_reg->errcs) & val, &wdt_reg->errcs); 93}
90 94
91 rc32434_wdt_device.running = 0; 95static void rc32434_wdt_stop(void)
92 } 96{
97 /* Disable WDT */
98 SET_BITS(wdt_reg->wtc, 0, 1 << RC32434_WTC_EN);
93} 99}
94 100
95static void rc32434_wdt_set(int new_timeout) 101static int rc32434_wdt_set(int new_timeout)
96{ 102{
97 u32 cmp = new_timeout * HZ; 103 int max_to = WTCOMP2SEC((u32)-1);
98 u32 state, val;
99 104
105 if (new_timeout < 0 || new_timeout > max_to) {
106 printk(KERN_ERR KBUILD_MODNAME
107 ": timeout value must be between 0 and %d",
108 max_to);
109 return -EINVAL;
110 }
100 timeout = new_timeout; 111 timeout = new_timeout;
101 /* 112 writel(SEC2WTCOMP(timeout), &wdt_reg->wtcompare);
102 * store and disable WTC
103 */
104 state = (u32)(readl(&wdt_reg->wtc) & RC32434_WTC_EN);
105 val = ~RC32434_WTC_EN;
106 writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc);
107
108 writel(0, &wdt_reg->wtcount);
109 writel(cmp, &wdt_reg->wtcompare);
110
111 /*
112 * restore WTC
113 */
114
115 writel(readl(&wdt_reg->wtc) | state, &wdt_reg);
116}
117 113
118static void rc32434_wdt_reset(void) 114 return 0;
119{
120 ticks = rc32434_wdt_device.default_ticks;
121} 115}
122 116
123static void rc32434_wdt_update(unsigned long unused) 117static void rc32434_wdt_ping(void)
124{ 118{
125 if (rc32434_wdt_device.running)
126 ticks--;
127
128 writel(0, &wdt_reg->wtcount); 119 writel(0, &wdt_reg->wtcount);
129
130 if (rc32434_wdt_device.queue && ticks)
131 mod_timer(&rc32434_wdt_device.timer,
132 jiffies + RC32434_WDT_INTERVAL);
133 else
134 complete(&rc32434_wdt_device.stop);
135} 120}
136 121
137static int rc32434_wdt_open(struct inode *inode, struct file *file) 122static int rc32434_wdt_open(struct inode *inode, struct file *file)
@@ -142,19 +127,23 @@ static int rc32434_wdt_open(struct inode *inode, struct file *file)
142 if (nowayout) 127 if (nowayout)
143 __module_get(THIS_MODULE); 128 __module_get(THIS_MODULE);
144 129
130 rc32434_wdt_start();
131 rc32434_wdt_ping();
132
145 return nonseekable_open(inode, file); 133 return nonseekable_open(inode, file);
146} 134}
147 135
148static int rc32434_wdt_release(struct inode *inode, struct file *file) 136static int rc32434_wdt_release(struct inode *inode, struct file *file)
149{ 137{
150 if (expect_close && nowayout == 0) { 138 if (expect_close == 42) {
151 rc32434_wdt_stop(); 139 rc32434_wdt_stop();
152 printk(KERN_INFO KBUILD_MODNAME ": disabling watchdog timer\n"); 140 printk(KERN_INFO KBUILD_MODNAME ": disabling watchdog timer\n");
153 module_put(THIS_MODULE); 141 module_put(THIS_MODULE);
154 } else 142 } else {
155 printk(KERN_CRIT KBUILD_MODNAME 143 printk(KERN_CRIT KBUILD_MODNAME
156 ": device closed unexpectedly. WDT will not stop !\n"); 144 ": device closed unexpectedly. WDT will not stop !\n");
157 145 rc32434_wdt_ping();
146 }
158 clear_bit(0, &rc32434_wdt_device.inuse); 147 clear_bit(0, &rc32434_wdt_device.inuse);
159 return 0; 148 return 0;
160} 149}
@@ -174,10 +163,10 @@ static ssize_t rc32434_wdt_write(struct file *file, const char *data,
174 if (get_user(c, data + i)) 163 if (get_user(c, data + i))
175 return -EFAULT; 164 return -EFAULT;
176 if (c == 'V') 165 if (c == 'V')
177 expect_close = 1; 166 expect_close = 42;
178 } 167 }
179 } 168 }
180 rc32434_wdt_update(0); 169 rc32434_wdt_ping();
181 return len; 170 return len;
182 } 171 }
183 return 0; 172 return 0;
@@ -197,11 +186,11 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
197 }; 186 };
198 switch (cmd) { 187 switch (cmd) {
199 case WDIOC_KEEPALIVE: 188 case WDIOC_KEEPALIVE:
200 rc32434_wdt_reset(); 189 rc32434_wdt_ping();
201 break; 190 break;
202 case WDIOC_GETSTATUS: 191 case WDIOC_GETSTATUS:
203 case WDIOC_GETBOOTSTATUS: 192 case WDIOC_GETBOOTSTATUS:
204 value = readl(&wdt_reg->wtcount); 193 value = 0;
205 if (copy_to_user(argp, &value, sizeof(int))) 194 if (copy_to_user(argp, &value, sizeof(int)))
206 return -EFAULT; 195 return -EFAULT;
207 break; 196 break;
@@ -218,6 +207,7 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
218 break; 207 break;
219 case WDIOS_DISABLECARD: 208 case WDIOS_DISABLECARD:
220 rc32434_wdt_stop(); 209 rc32434_wdt_stop();
210 break;
221 default: 211 default:
222 return -EINVAL; 212 return -EINVAL;
223 } 213 }
@@ -225,11 +215,9 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd,
225 case WDIOC_SETTIMEOUT: 215 case WDIOC_SETTIMEOUT:
226 if (copy_from_user(&new_timeout, argp, sizeof(int))) 216 if (copy_from_user(&new_timeout, argp, sizeof(int)))
227 return -EFAULT; 217 return -EFAULT;
228 if (new_timeout < 1) 218 if (rc32434_wdt_set(new_timeout))
229 return -EINVAL; 219 return -EINVAL;
230 if (new_timeout > MAX_TIMEOUT) 220 /* Fall through */
231 return -EINVAL;
232 rc32434_wdt_set(new_timeout);
233 case WDIOC_GETTIMEOUT: 221 case WDIOC_GETTIMEOUT:
234 return copy_to_user(argp, &timeout, sizeof(int)); 222 return copy_to_user(argp, &timeout, sizeof(int));
235 default: 223 default:
@@ -254,15 +242,15 @@ static struct miscdevice rc32434_wdt_miscdev = {
254 .fops = &rc32434_wdt_fops, 242 .fops = &rc32434_wdt_fops,
255}; 243};
256 244
257static char banner[] = KERN_INFO KBUILD_MODNAME 245static char banner[] __devinitdata = KERN_INFO KBUILD_MODNAME
258 ": Watchdog Timer version " VERSION ", timer margin: %d sec\n"; 246 ": Watchdog Timer version " VERSION ", timer margin: %d sec\n";
259 247
260static int rc32434_wdt_probe(struct platform_device *pdev) 248static int __devinit rc32434_wdt_probe(struct platform_device *pdev)
261{ 249{
262 int ret; 250 int ret;
263 struct resource *r; 251 struct resource *r;
264 252
265 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb500_wdt_res"); 253 r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb532_wdt_res");
266 if (!r) { 254 if (!r) {
267 printk(KERN_ERR KBUILD_MODNAME 255 printk(KERN_ERR KBUILD_MODNAME
268 "failed to retrieve resources\n"); 256 "failed to retrieve resources\n");
@@ -277,24 +265,12 @@ static int rc32434_wdt_probe(struct platform_device *pdev)
277 } 265 }
278 266
279 ret = misc_register(&rc32434_wdt_miscdev); 267 ret = misc_register(&rc32434_wdt_miscdev);
280
281 if (ret < 0) { 268 if (ret < 0) {
282 printk(KERN_ERR KBUILD_MODNAME 269 printk(KERN_ERR KBUILD_MODNAME
283 "failed to register watchdog device\n"); 270 "failed to register watchdog device\n");
284 goto unmap; 271 goto unmap;
285 } 272 }
286 273
287 init_completion(&rc32434_wdt_device.stop);
288 rc32434_wdt_device.queue = 0;
289
290 clear_bit(0, &rc32434_wdt_device.inuse);
291
292 setup_timer(&rc32434_wdt_device.timer, rc32434_wdt_update, 0L);
293
294 rc32434_wdt_device.default_ticks = ticks;
295
296 rc32434_wdt_start();
297
298 printk(banner, timeout); 274 printk(banner, timeout);
299 275
300 return 0; 276 return 0;
@@ -304,23 +280,17 @@ unmap:
304 return ret; 280 return ret;
305} 281}
306 282
307static int rc32434_wdt_remove(struct platform_device *pdev) 283static int __devexit rc32434_wdt_remove(struct platform_device *pdev)
308{ 284{
309 if (rc32434_wdt_device.queue) {
310 rc32434_wdt_device.queue = 0;
311 wait_for_completion(&rc32434_wdt_device.stop);
312 }
313 misc_deregister(&rc32434_wdt_miscdev); 285 misc_deregister(&rc32434_wdt_miscdev);
314
315 iounmap(wdt_reg); 286 iounmap(wdt_reg);
316
317 return 0; 287 return 0;
318} 288}
319 289
320static struct platform_driver rc32434_wdt = { 290static struct platform_driver rc32434_wdt = {
321 .probe = rc32434_wdt_probe, 291 .probe = rc32434_wdt_probe,
322 .remove = rc32434_wdt_remove, 292 .remove = __devexit_p(rc32434_wdt_remove),
323 .driver = { 293 .driver = {
324 .name = "rc32434_wdt", 294 .name = "rc32434_wdt",
325 } 295 }
326}; 296};