aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-07-30 02:28:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-30 02:28:47 -0400
commit2313bcdcc9ff1e42f51b200dc65ddaae14c347f4 (patch)
treefdb0e3f953841cdd661e36c40a965c9e044d82f5 /drivers/watchdog
parent59ed2bb27492f74ab898ee1e26c69dfd78444640 (diff)
parent3f43f68e29f1dcb853d70280c7412fc0ef9a0da6 (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-watchdog
* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-watchdog: (25 commits) watchdog: WatchDog Timer Driver Core - Add minimum and max timeout watchdog: WatchDog Timer Driver Core - Add ioctl call watchdog: WatchDog Timer Driver Core - Add nowayout feature watchdog: WatchDog Timer Driver Core - Add Magic Close feature watchdog: WatchDog Timer Driver Core - Add WDIOC_SETTIMEOUT and WDIOC_GETTIMEOUT ioctl watchdog: WatchDog Timer Driver Core - Add WDIOC_SETOPTIONS ioctl watchdog: WatchDog Timer Driver Core - Add WDIOC_KEEPALIVE ioctl watchdog: WatchDog Timer Driver Core - Add basic ioctl functionality watchdog: WatchDog Timer Driver Core - Add basic framework watchdog: hpwdt: add next gen HP servers watchdog: it8712f_wdt.c: improve includes watchdog: at91sam9/wdt: move register header to drivers watchdog: Add Xilinx watchdog timer driver watchdog: remove empty pm-functions watchdog: sp805: Flush posted writes in enable/disable. watchdog: sp805: Don't write 0 to the load value register. watchdog: imx2_wdt: add device tree probe support watchdog: s3c2410: Add support for device tree based probe watchdog: mpcore_wdt: Add suspend/resume support. watchdog: mtx1-wdt: use dev_{err,info} instead of printk() ...
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig36
-rw-r--r--drivers/watchdog/Makefile8
-rw-r--r--drivers/watchdog/at91sam9_wdt.c21
-rw-r--r--drivers/watchdog/at91sam9_wdt.h37
-rw-r--r--drivers/watchdog/dw_wdt.c376
-rw-r--r--drivers/watchdog/hpwdt.c104
-rw-r--r--drivers/watchdog/iTCO_wdt.c412
-rw-r--r--drivers/watchdog/imx2_wdt.c6
-rw-r--r--drivers/watchdog/it8712f_wdt.c63
-rw-r--r--drivers/watchdog/it87_wdt.c168
-rw-r--r--drivers/watchdog/mpcore_wdt.c23
-rw-r--r--drivers/watchdog/mtx-1_wdt.c4
-rw-r--r--drivers/watchdog/of_xilinx_wdt.c433
-rw-r--r--drivers/watchdog/pc87413_wdt.c96
-rw-r--r--drivers/watchdog/s3c2410_wdt.c10
-rw-r--r--drivers/watchdog/sch311x_wdt.c5
-rw-r--r--drivers/watchdog/sp805_wdt.c5
-rw-r--r--drivers/watchdog/watchdog_core.c111
-rw-r--r--drivers/watchdog/watchdog_dev.c395
-rw-r--r--drivers/watchdog/watchdog_dev.h33
20 files changed, 1875 insertions, 471 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 21d816e9dfa5..f441726ddf2b 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -28,6 +28,17 @@ menuconfig WATCHDOG
28 28
29if WATCHDOG 29if WATCHDOG
30 30
31config WATCHDOG_CORE
32 bool "WatchDog Timer Driver Core"
33 ---help---
34 Say Y here if you want to use the new watchdog timer driver core.
35 This driver provides a framework for all watchdog timer drivers
36 and gives them the /dev/watchdog interface (and later also the
37 sysfs interface).
38
39 To compile this driver as a module, choose M here: the module will
40 be called watchdog.
41
31config WATCHDOG_NOWAYOUT 42config WATCHDOG_NOWAYOUT
32 bool "Disable watchdog shutdown on close" 43 bool "Disable watchdog shutdown on close"
33 help 44 help
@@ -186,6 +197,15 @@ config SA1100_WATCHDOG
186 To compile this driver as a module, choose M here: the 197 To compile this driver as a module, choose M here: the
187 module will be called sa1100_wdt. 198 module will be called sa1100_wdt.
188 199
200config DW_WATCHDOG
201 tristate "Synopsys DesignWare watchdog"
202 depends on ARM && HAVE_CLK
203 help
204 Say Y here if to include support for the Synopsys DesignWare
205 watchdog timer found in many ARM chips.
206 To compile this driver as a module, choose M here: the
207 module will be called dw_wdt.
208
189config MPCORE_WATCHDOG 209config MPCORE_WATCHDOG
190 tristate "MPcore watchdog" 210 tristate "MPcore watchdog"
191 depends on HAVE_ARM_TWD 211 depends on HAVE_ARM_TWD
@@ -321,7 +341,7 @@ config MAX63XX_WATCHDOG
321 341
322config IMX2_WDT 342config IMX2_WDT
323 tristate "IMX2+ Watchdog" 343 tristate "IMX2+ Watchdog"
324 depends on ARCH_MX2 || ARCH_MX25 || ARCH_MX3 || ARCH_MX5 344 depends on IMX_HAVE_PLATFORM_IMX2_WDT
325 help 345 help
326 This is the driver for the hardware watchdog 346 This is the driver for the hardware watchdog
327 on the Freescale IMX2 and later processors. 347 on the Freescale IMX2 and later processors.
@@ -879,6 +899,20 @@ config M54xx_WATCHDOG
879 To compile this driver as a module, choose M here: the 899 To compile this driver as a module, choose M here: the
880 module will be called m54xx_wdt. 900 module will be called m54xx_wdt.
881 901
902# MicroBlaze Architecture
903
904config XILINX_WATCHDOG
905 tristate "Xilinx Watchdog timer"
906 depends on MICROBLAZE
907 ---help---
908 Watchdog driver for the xps_timebase_wdt ip core.
909
910 IMPORTANT: The xps_timebase_wdt parent must have the property
911 "clock-frequency" at device tree.
912
913 To compile this driver as a module, choose M here: the
914 module will be called of_xilinx_wdt.
915
882# MIPS Architecture 916# MIPS Architecture
883 917
884config ATH79_WDT 918config ATH79_WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index ed26f7094e47..55bd5740e910 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -2,6 +2,10 @@
2# Makefile for the WatchDog device drivers. 2# Makefile for the WatchDog device drivers.
3# 3#
4 4
5# The WatchDog Timer Driver Core.
6watchdog-objs += watchdog_core.o watchdog_dev.o
7obj-$(CONFIG_WATCHDOG_CORE) += watchdog.o
8
5# Only one watchdog can succeed. We probe the ISA/PCI/USB based 9# Only one watchdog can succeed. We probe the ISA/PCI/USB based
6# watchdog-cards first, then the architecture specific watchdog 10# watchdog-cards first, then the architecture specific watchdog
7# drivers and then the architecture independent "softdog" driver. 11# drivers and then the architecture independent "softdog" driver.
@@ -37,6 +41,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
37obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o 41obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
38obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o 42obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
39obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o 43obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
44obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o
40obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o 45obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
41obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o 46obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
42obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o 47obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
@@ -109,6 +114,9 @@ obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
109# M68K Architecture 114# M68K Architecture
110obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o 115obj-$(CONFIG_M54xx_WATCHDOG) += m54xx_wdt.o
111 116
117# MicroBlaze Architecture
118obj-$(CONFIG_XILINX_WATCHDOG) += of_xilinx_wdt.o
119
112# MIPS Architecture 120# MIPS Architecture
113obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o 121obj-$(CONFIG_ATH79_WDT) += ath79_wdt.o
114obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o 122obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index eac26021e8da..87445b2d72a7 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -31,7 +31,7 @@
31#include <linux/bitops.h> 31#include <linux/bitops.h>
32#include <linux/uaccess.h> 32#include <linux/uaccess.h>
33 33
34#include <mach/at91_wdt.h> 34#include "at91sam9_wdt.h"
35 35
36#define DRV_NAME "AT91SAM9 Watchdog" 36#define DRV_NAME "AT91SAM9 Watchdog"
37 37
@@ -284,27 +284,8 @@ static int __exit at91wdt_remove(struct platform_device *pdev)
284 return res; 284 return res;
285} 285}
286 286
287#ifdef CONFIG_PM
288
289static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
290{
291 return 0;
292}
293
294static int at91wdt_resume(struct platform_device *pdev)
295{
296 return 0;
297}
298
299#else
300#define at91wdt_suspend NULL
301#define at91wdt_resume NULL
302#endif
303
304static struct platform_driver at91wdt_driver = { 287static struct platform_driver at91wdt_driver = {
305 .remove = __exit_p(at91wdt_remove), 288 .remove = __exit_p(at91wdt_remove),
306 .suspend = at91wdt_suspend,
307 .resume = at91wdt_resume,
308 .driver = { 289 .driver = {
309 .name = "at91_wdt", 290 .name = "at91_wdt",
310 .owner = THIS_MODULE, 291 .owner = THIS_MODULE,
diff --git a/drivers/watchdog/at91sam9_wdt.h b/drivers/watchdog/at91sam9_wdt.h
new file mode 100644
index 000000000000..757f9cab5c82
--- /dev/null
+++ b/drivers/watchdog/at91sam9_wdt.h
@@ -0,0 +1,37 @@
1/*
2 * drivers/watchdog/at91sam9_wdt.h
3 *
4 * Copyright (C) 2007 Andrew Victor
5 * Copyright (C) 2007 Atmel Corporation.
6 *
7 * Watchdog Timer (WDT) - System peripherals regsters.
8 * Based on AT91SAM9261 datasheet revision D.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 */
15
16#ifndef AT91_WDT_H
17#define AT91_WDT_H
18
19#define AT91_WDT_CR (AT91_WDT + 0x00) /* Watchdog Control Register */
20#define AT91_WDT_WDRSTT (1 << 0) /* Restart */
21#define AT91_WDT_KEY (0xa5 << 24) /* KEY Password */
22
23#define AT91_WDT_MR (AT91_WDT + 0x04) /* Watchdog Mode Register */
24#define AT91_WDT_WDV (0xfff << 0) /* Counter Value */
25#define AT91_WDT_WDFIEN (1 << 12) /* Fault Interrupt Enable */
26#define AT91_WDT_WDRSTEN (1 << 13) /* Reset Processor */
27#define AT91_WDT_WDRPROC (1 << 14) /* Timer Restart */
28#define AT91_WDT_WDDIS (1 << 15) /* Watchdog Disable */
29#define AT91_WDT_WDD (0xfff << 16) /* Delta Value */
30#define AT91_WDT_WDDBGHLT (1 << 28) /* Debug Halt */
31#define AT91_WDT_WDIDLEHLT (1 << 29) /* Idle Halt */
32
33#define AT91_WDT_SR (AT91_WDT + 0x08) /* Watchdog Status Register */
34#define AT91_WDT_WDUNF (1 << 0) /* Watchdog Underflow */
35#define AT91_WDT_WDERR (1 << 1) /* Watchdog Error */
36
37#endif
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
new file mode 100644
index 000000000000..f10f8c0abba4
--- /dev/null
+++ b/drivers/watchdog/dw_wdt.c
@@ -0,0 +1,376 @@
1/*
2 * Copyright 2010-2011 Picochip Ltd., Jamie Iles
3 * http://www.picochip.com
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * This file implements a driver for the Synopsys DesignWare watchdog device
11 * in the many ARM subsystems. The watchdog has 16 different timeout periods
12 * and these are a function of the input clock frequency.
13 *
14 * The DesignWare watchdog cannot be stopped once it has been started so we
15 * use a software timer to implement a ping that will keep the watchdog alive.
16 * If we receive an expected close for the watchdog then we keep the timer
17 * running, otherwise the timer is stopped and the watchdog will expire.
18 */
19#define pr_fmt(fmt) "dw_wdt: " fmt
20
21#include <linux/bitops.h>
22#include <linux/clk.h>
23#include <linux/device.h>
24#include <linux/err.h>
25#include <linux/fs.h>
26#include <linux/io.h>
27#include <linux/kernel.h>
28#include <linux/miscdevice.h>
29#include <linux/module.h>
30#include <linux/moduleparam.h>
31#include <linux/pm.h>
32#include <linux/platform_device.h>
33#include <linux/spinlock.h>
34#include <linux/timer.h>
35#include <linux/uaccess.h>
36#include <linux/watchdog.h>
37
38#define WDOG_CONTROL_REG_OFFSET 0x00
39#define WDOG_CONTROL_REG_WDT_EN_MASK 0x01
40#define WDOG_TIMEOUT_RANGE_REG_OFFSET 0x04
41#define WDOG_CURRENT_COUNT_REG_OFFSET 0x08
42#define WDOG_COUNTER_RESTART_REG_OFFSET 0x0c
43#define WDOG_COUNTER_RESTART_KICK_VALUE 0x76
44
45/* The maximum TOP (timeout period) value that can be set in the watchdog. */
46#define DW_WDT_MAX_TOP 15
47
48static int nowayout = WATCHDOG_NOWAYOUT;
49module_param(nowayout, int, 0);
50MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
51 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
52
53#define WDT_TIMEOUT (HZ / 2)
54
55static struct {
56 spinlock_t lock;
57 void __iomem *regs;
58 struct clk *clk;
59 unsigned long in_use;
60 unsigned long next_heartbeat;
61 struct timer_list timer;
62 int expect_close;
63} dw_wdt;
64
65static inline int dw_wdt_is_enabled(void)
66{
67 return readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET) &
68 WDOG_CONTROL_REG_WDT_EN_MASK;
69}
70
71static inline int dw_wdt_top_in_seconds(unsigned top)
72{
73 /*
74 * There are 16 possible timeout values in 0..15 where the number of
75 * cycles is 2 ^ (16 + i) and the watchdog counts down.
76 */
77 return (1 << (16 + top)) / clk_get_rate(dw_wdt.clk);
78}
79
80static int dw_wdt_get_top(void)
81{
82 int top = readl(dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET) & 0xF;
83
84 return dw_wdt_top_in_seconds(top);
85}
86
87static inline void dw_wdt_set_next_heartbeat(void)
88{
89 dw_wdt.next_heartbeat = jiffies + dw_wdt_get_top() * HZ;
90}
91
92static int dw_wdt_set_top(unsigned top_s)
93{
94 int i, top_val = DW_WDT_MAX_TOP;
95
96 /*
97 * Iterate over the timeout values until we find the closest match. We
98 * always look for >=.
99 */
100 for (i = 0; i <= DW_WDT_MAX_TOP; ++i)
101 if (dw_wdt_top_in_seconds(i) >= top_s) {
102 top_val = i;
103 break;
104 }
105
106 /* Set the new value in the watchdog. */
107 writel(top_val, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
108
109 dw_wdt_set_next_heartbeat();
110
111 return dw_wdt_top_in_seconds(top_val);
112}
113
114static void dw_wdt_keepalive(void)
115{
116 writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
117 WDOG_COUNTER_RESTART_REG_OFFSET);
118}
119
120static void dw_wdt_ping(unsigned long data)
121{
122 if (time_before(jiffies, dw_wdt.next_heartbeat) ||
123 (!nowayout && !dw_wdt.in_use)) {
124 dw_wdt_keepalive();
125 mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
126 } else
127 pr_crit("keepalive missed, machine will reset\n");
128}
129
130static int dw_wdt_open(struct inode *inode, struct file *filp)
131{
132 if (test_and_set_bit(0, &dw_wdt.in_use))
133 return -EBUSY;
134
135 /* Make sure we don't get unloaded. */
136 __module_get(THIS_MODULE);
137
138 spin_lock(&dw_wdt.lock);
139 if (!dw_wdt_is_enabled()) {
140 /*
141 * The watchdog is not currently enabled. Set the timeout to
142 * the maximum and then start it.
143 */
144 dw_wdt_set_top(DW_WDT_MAX_TOP);
145 writel(WDOG_CONTROL_REG_WDT_EN_MASK,
146 dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
147 }
148
149 dw_wdt_set_next_heartbeat();
150
151 spin_unlock(&dw_wdt.lock);
152
153 return nonseekable_open(inode, filp);
154}
155
156ssize_t dw_wdt_write(struct file *filp, const char __user *buf, size_t len,
157 loff_t *offset)
158{
159 if (!len)
160 return 0;
161
162 if (!nowayout) {
163 size_t i;
164
165 dw_wdt.expect_close = 0;
166
167 for (i = 0; i < len; ++i) {
168 char c;
169
170 if (get_user(c, buf + i))
171 return -EFAULT;
172
173 if (c == 'V') {
174 dw_wdt.expect_close = 1;
175 break;
176 }
177 }
178 }
179
180 dw_wdt_set_next_heartbeat();
181 mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
182
183 return len;
184}
185
186static u32 dw_wdt_time_left(void)
187{
188 return readl(dw_wdt.regs + WDOG_CURRENT_COUNT_REG_OFFSET) /
189 clk_get_rate(dw_wdt.clk);
190}
191
192static const struct watchdog_info dw_wdt_ident = {
193 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
194 WDIOF_MAGICCLOSE,
195 .identity = "Synopsys DesignWare Watchdog",
196};
197
198static long dw_wdt_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
199{
200 unsigned long val;
201 int timeout;
202
203 switch (cmd) {
204 case WDIOC_GETSUPPORT:
205 return copy_to_user((struct watchdog_info *)arg, &dw_wdt_ident,
206 sizeof(dw_wdt_ident)) ? -EFAULT : 0;
207
208 case WDIOC_GETSTATUS:
209 case WDIOC_GETBOOTSTATUS:
210 return put_user(0, (int *)arg);
211
212 case WDIOC_KEEPALIVE:
213 dw_wdt_set_next_heartbeat();
214 return 0;
215
216 case WDIOC_SETTIMEOUT:
217 if (get_user(val, (int __user *)arg))
218 return -EFAULT;
219 timeout = dw_wdt_set_top(val);
220 return put_user(timeout , (int __user *)arg);
221
222 case WDIOC_GETTIMEOUT:
223 return put_user(dw_wdt_get_top(), (int __user *)arg);
224
225 case WDIOC_GETTIMELEFT:
226 /* Get the time left until expiry. */
227 if (get_user(val, (int __user *)arg))
228 return -EFAULT;
229 return put_user(dw_wdt_time_left(), (int __user *)arg);
230
231 default:
232 return -ENOTTY;
233 }
234}
235
236static int dw_wdt_release(struct inode *inode, struct file *filp)
237{
238 clear_bit(0, &dw_wdt.in_use);
239
240 if (!dw_wdt.expect_close) {
241 del_timer(&dw_wdt.timer);
242
243 if (!nowayout)
244 pr_crit("unexpected close, system will reboot soon\n");
245 else
246 pr_crit("watchdog cannot be disabled, system will reboot soon\n");
247 }
248
249 dw_wdt.expect_close = 0;
250
251 return 0;
252}
253
254#ifdef CONFIG_PM
255static int dw_wdt_suspend(struct device *dev)
256{
257 clk_disable(dw_wdt.clk);
258
259 return 0;
260}
261
262static int dw_wdt_resume(struct device *dev)
263{
264 int err = clk_enable(dw_wdt.clk);
265
266 if (err)
267 return err;
268
269 dw_wdt_keepalive();
270
271 return 0;
272}
273
274static const struct dev_pm_ops dw_wdt_pm_ops = {
275 .suspend = dw_wdt_suspend,
276 .resume = dw_wdt_resume,
277};
278#endif /* CONFIG_PM */
279
280static const struct file_operations wdt_fops = {
281 .owner = THIS_MODULE,
282 .llseek = no_llseek,
283 .open = dw_wdt_open,
284 .write = dw_wdt_write,
285 .unlocked_ioctl = dw_wdt_ioctl,
286 .release = dw_wdt_release
287};
288
289static struct miscdevice dw_wdt_miscdev = {
290 .fops = &wdt_fops,
291 .name = "watchdog",
292 .minor = WATCHDOG_MINOR,
293};
294
295static int __devinit dw_wdt_drv_probe(struct platform_device *pdev)
296{
297 int ret;
298 struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
299
300 if (!mem)
301 return -EINVAL;
302
303 if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem),
304 "dw_wdt"))
305 return -ENOMEM;
306
307 dw_wdt.regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
308 if (!dw_wdt.regs)
309 return -ENOMEM;
310
311 dw_wdt.clk = clk_get(&pdev->dev, NULL);
312 if (IS_ERR(dw_wdt.clk))
313 return PTR_ERR(dw_wdt.clk);
314
315 ret = clk_enable(dw_wdt.clk);
316 if (ret)
317 goto out_put_clk;
318
319 spin_lock_init(&dw_wdt.lock);
320
321 ret = misc_register(&dw_wdt_miscdev);
322 if (ret)
323 goto out_disable_clk;
324
325 dw_wdt_set_next_heartbeat();
326 setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
327 mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
328
329 return 0;
330
331out_disable_clk:
332 clk_disable(dw_wdt.clk);
333out_put_clk:
334 clk_put(dw_wdt.clk);
335
336 return ret;
337}
338
339static int __devexit dw_wdt_drv_remove(struct platform_device *pdev)
340{
341 misc_deregister(&dw_wdt_miscdev);
342
343 clk_disable(dw_wdt.clk);
344 clk_put(dw_wdt.clk);
345
346 return 0;
347}
348
349static struct platform_driver dw_wdt_driver = {
350 .probe = dw_wdt_drv_probe,
351 .remove = __devexit_p(dw_wdt_drv_remove),
352 .driver = {
353 .name = "dw_wdt",
354 .owner = THIS_MODULE,
355#ifdef CONFIG_PM
356 .pm = &dw_wdt_pm_ops,
357#endif /* CONFIG_PM */
358 },
359};
360
361static int __init dw_wdt_watchdog_init(void)
362{
363 return platform_driver_register(&dw_wdt_driver);
364}
365module_init(dw_wdt_watchdog_init);
366
367static void __exit dw_wdt_watchdog_exit(void)
368{
369 platform_driver_unregister(&dw_wdt_driver);
370}
371module_exit(dw_wdt_watchdog_exit);
372
373MODULE_AUTHOR("Jamie Iles");
374MODULE_DESCRIPTION("Synopsys DesignWare Watchdog Driver");
375MODULE_LICENSE("GPL");
376MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 8cb26855bfed..410fba45378d 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -36,7 +36,7 @@
36#include <asm/cacheflush.h> 36#include <asm/cacheflush.h>
37#endif /* CONFIG_HPWDT_NMI_DECODING */ 37#endif /* CONFIG_HPWDT_NMI_DECODING */
38 38
39#define HPWDT_VERSION "1.2.0" 39#define HPWDT_VERSION "1.3.0"
40#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) 40#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
41#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) 41#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
42#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) 42#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
@@ -87,6 +87,19 @@ struct smbios_cru64_info {
87}; 87};
88#define SMBIOS_CRU64_INFORMATION 212 88#define SMBIOS_CRU64_INFORMATION 212
89 89
90/* type 219 */
91struct smbios_proliant_info {
92 u8 type;
93 u8 byte_length;
94 u16 handle;
95 u32 power_features;
96 u32 omega_features;
97 u32 reserved;
98 u32 misc_features;
99};
100#define SMBIOS_ICRU_INFORMATION 219
101
102
90struct cmn_registers { 103struct cmn_registers {
91 union { 104 union {
92 struct { 105 struct {
@@ -132,6 +145,7 @@ struct cmn_registers {
132static unsigned int hpwdt_nmi_decoding; 145static unsigned int hpwdt_nmi_decoding;
133static unsigned int allow_kdump; 146static unsigned int allow_kdump;
134static unsigned int priority; /* hpwdt at end of die_notify list */ 147static unsigned int priority; /* hpwdt at end of die_notify list */
148static unsigned int is_icru;
135static DEFINE_SPINLOCK(rom_lock); 149static DEFINE_SPINLOCK(rom_lock);
136static void *cru_rom_addr; 150static void *cru_rom_addr;
137static struct cmn_registers cmn_regs; 151static struct cmn_registers cmn_regs;
@@ -476,19 +490,22 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
476 goto out; 490 goto out;
477 491
478 spin_lock_irqsave(&rom_lock, rom_pl); 492 spin_lock_irqsave(&rom_lock, rom_pl);
479 if (!die_nmi_called) 493 if (!die_nmi_called && !is_icru)
480 asminline_call(&cmn_regs, cru_rom_addr); 494 asminline_call(&cmn_regs, cru_rom_addr);
481 die_nmi_called = 1; 495 die_nmi_called = 1;
482 spin_unlock_irqrestore(&rom_lock, rom_pl); 496 spin_unlock_irqrestore(&rom_lock, rom_pl);
483 if (cmn_regs.u1.ral == 0) { 497 if (!is_icru) {
484 printk(KERN_WARNING "hpwdt: An NMI occurred, " 498 if (cmn_regs.u1.ral == 0) {
485 "but unable to determine source.\n"); 499 printk(KERN_WARNING "hpwdt: An NMI occurred, "
486 } else { 500 "but unable to determine source.\n");
487 if (allow_kdump) 501 }
488 hpwdt_stop();
489 panic("An NMI occurred, please see the Integrated "
490 "Management Log for details.\n");
491 } 502 }
503
504 if (allow_kdump)
505 hpwdt_stop();
506 panic("An NMI occurred, please see the Integrated "
507 "Management Log for details.\n");
508
492out: 509out:
493 return NOTIFY_OK; 510 return NOTIFY_OK;
494} 511}
@@ -659,30 +676,63 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev)
659} 676}
660#endif /* CONFIG_X86_LOCAL_APIC */ 677#endif /* CONFIG_X86_LOCAL_APIC */
661 678
679/*
680 * dmi_find_icru
681 *
682 * Routine Description:
683 * This function checks whether or not we are on an iCRU-based server.
684 * This check is independent of architecture and needs to be made for
685 * any ProLiant system.
686 */
687static void __devinit dmi_find_icru(const struct dmi_header *dm, void *dummy)
688{
689 struct smbios_proliant_info *smbios_proliant_ptr;
690
691 if (dm->type == SMBIOS_ICRU_INFORMATION) {
692 smbios_proliant_ptr = (struct smbios_proliant_info *) dm;
693 if (smbios_proliant_ptr->misc_features & 0x01)
694 is_icru = 1;
695 }
696}
697
662static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) 698static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev)
663{ 699{
664 int retval; 700 int retval;
665 701
666 /* 702 /*
667 * We need to map the ROM to get the CRU service. 703 * On typical CRU-based systems we need to map that service in
668 * For 32 bit Operating Systems we need to go through the 32 Bit 704 * the BIOS. For 32 bit Operating Systems we need to go through
669 * BIOS Service Directory 705 * the 32 Bit BIOS Service Directory. For 64 bit Operating
670 * For 64 bit Operating Systems we get that service through SMBIOS. 706 * Systems we get that service through SMBIOS.
707 *
708 * On systems that support the new iCRU service all we need to
709 * do is call dmi_walk to get the supported flag value and skip
710 * the old cru detect code.
671 */ 711 */
672 retval = detect_cru_service(); 712 dmi_walk(dmi_find_icru, NULL);
673 if (retval < 0) { 713 if (!is_icru) {
674 dev_warn(&dev->dev, 714
675 "Unable to detect the %d Bit CRU Service.\n", 715 /*
676 HPWDT_ARCH); 716 * We need to map the ROM to get the CRU service.
677 return retval; 717 * For 32 bit Operating Systems we need to go through the 32 Bit
678 } 718 * BIOS Service Directory
719 * For 64 bit Operating Systems we get that service through SMBIOS.
720 */
721 retval = detect_cru_service();
722 if (retval < 0) {
723 dev_warn(&dev->dev,
724 "Unable to detect the %d Bit CRU Service.\n",
725 HPWDT_ARCH);
726 return retval;
727 }
679 728
680 /* 729 /*
681 * We know this is the only CRU call we need to make so lets keep as 730 * We know this is the only CRU call we need to make so lets keep as
682 * few instructions as possible once the NMI comes in. 731 * few instructions as possible once the NMI comes in.
683 */ 732 */
684 cmn_regs.u1.rah = 0x0D; 733 cmn_regs.u1.rah = 0x0D;
685 cmn_regs.u1.ral = 0x02; 734 cmn_regs.u1.ral = 0x02;
735 }
686 736
687 /* 737 /*
688 * If the priority is set to 1, then we will be put first on the 738 * If the priority is set to 1, then we will be put first on the
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
index 5fd020da7c55..751a591684da 100644
--- a/drivers/watchdog/iTCO_wdt.c
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -120,72 +120,12 @@ enum iTCO_chipsets {
120 TCO_3420, /* 3420 */ 120 TCO_3420, /* 3420 */
121 TCO_3450, /* 3450 */ 121 TCO_3450, /* 3450 */
122 TCO_EP80579, /* EP80579 */ 122 TCO_EP80579, /* EP80579 */
123 TCO_CPT1, /* Cougar Point */ 123 TCO_CPT, /* Cougar Point */
124 TCO_CPT2, /* Cougar Point Desktop */ 124 TCO_CPTD, /* Cougar Point Desktop */
125 TCO_CPT3, /* Cougar Point Mobile */ 125 TCO_CPTM, /* Cougar Point Mobile */
126 TCO_CPT4, /* Cougar Point */ 126 TCO_PBG, /* Patsburg */
127 TCO_CPT5, /* Cougar Point */
128 TCO_CPT6, /* Cougar Point */
129 TCO_CPT7, /* Cougar Point */
130 TCO_CPT8, /* Cougar Point */
131 TCO_CPT9, /* Cougar Point */
132 TCO_CPT10, /* Cougar Point */
133 TCO_CPT11, /* Cougar Point */
134 TCO_CPT12, /* Cougar Point */
135 TCO_CPT13, /* Cougar Point */
136 TCO_CPT14, /* Cougar Point */
137 TCO_CPT15, /* Cougar Point */
138 TCO_CPT16, /* Cougar Point */
139 TCO_CPT17, /* Cougar Point */
140 TCO_CPT18, /* Cougar Point */
141 TCO_CPT19, /* Cougar Point */
142 TCO_CPT20, /* Cougar Point */
143 TCO_CPT21, /* Cougar Point */
144 TCO_CPT22, /* Cougar Point */
145 TCO_CPT23, /* Cougar Point */
146 TCO_CPT24, /* Cougar Point */
147 TCO_CPT25, /* Cougar Point */
148 TCO_CPT26, /* Cougar Point */
149 TCO_CPT27, /* Cougar Point */
150 TCO_CPT28, /* Cougar Point */
151 TCO_CPT29, /* Cougar Point */
152 TCO_CPT30, /* Cougar Point */
153 TCO_CPT31, /* Cougar Point */
154 TCO_PBG1, /* Patsburg */
155 TCO_PBG2, /* Patsburg */
156 TCO_DH89XXCC, /* DH89xxCC */ 127 TCO_DH89XXCC, /* DH89xxCC */
157 TCO_PPT0, /* Panther Point */ 128 TCO_PPT, /* Panther Point */
158 TCO_PPT1, /* Panther Point */
159 TCO_PPT2, /* Panther Point */
160 TCO_PPT3, /* Panther Point */
161 TCO_PPT4, /* Panther Point */
162 TCO_PPT5, /* Panther Point */
163 TCO_PPT6, /* Panther Point */
164 TCO_PPT7, /* Panther Point */
165 TCO_PPT8, /* Panther Point */
166 TCO_PPT9, /* Panther Point */
167 TCO_PPT10, /* Panther Point */
168 TCO_PPT11, /* Panther Point */
169 TCO_PPT12, /* Panther Point */
170 TCO_PPT13, /* Panther Point */
171 TCO_PPT14, /* Panther Point */
172 TCO_PPT15, /* Panther Point */
173 TCO_PPT16, /* Panther Point */
174 TCO_PPT17, /* Panther Point */
175 TCO_PPT18, /* Panther Point */
176 TCO_PPT19, /* Panther Point */
177 TCO_PPT20, /* Panther Point */
178 TCO_PPT21, /* Panther Point */
179 TCO_PPT22, /* Panther Point */
180 TCO_PPT23, /* Panther Point */
181 TCO_PPT24, /* Panther Point */
182 TCO_PPT25, /* Panther Point */
183 TCO_PPT26, /* Panther Point */
184 TCO_PPT27, /* Panther Point */
185 TCO_PPT28, /* Panther Point */
186 TCO_PPT29, /* Panther Point */
187 TCO_PPT30, /* Panther Point */
188 TCO_PPT31, /* Panther Point */
189}; 129};
190 130
191static struct { 131static struct {
@@ -244,83 +184,14 @@ static struct {
244 {"3450", 2}, 184 {"3450", 2},
245 {"EP80579", 2}, 185 {"EP80579", 2},
246 {"Cougar Point", 2}, 186 {"Cougar Point", 2},
247 {"Cougar Point", 2}, 187 {"Cougar Point Desktop", 2},
248 {"Cougar Point", 2}, 188 {"Cougar Point Mobile", 2},
249 {"Cougar Point", 2},
250 {"Cougar Point", 2},
251 {"Cougar Point", 2},
252 {"Cougar Point", 2},
253 {"Cougar Point", 2},
254 {"Cougar Point", 2},
255 {"Cougar Point", 2},
256 {"Cougar Point", 2},
257 {"Cougar Point", 2},
258 {"Cougar Point", 2},
259 {"Cougar Point", 2},
260 {"Cougar Point", 2},
261 {"Cougar Point", 2},
262 {"Cougar Point", 2},
263 {"Cougar Point", 2},
264 {"Cougar Point", 2},
265 {"Cougar Point", 2},
266 {"Cougar Point", 2},
267 {"Cougar Point", 2},
268 {"Cougar Point", 2},
269 {"Cougar Point", 2},
270 {"Cougar Point", 2},
271 {"Cougar Point", 2},
272 {"Cougar Point", 2},
273 {"Cougar Point", 2},
274 {"Cougar Point", 2},
275 {"Cougar Point", 2},
276 {"Cougar Point", 2},
277 {"Patsburg", 2},
278 {"Patsburg", 2}, 189 {"Patsburg", 2},
279 {"DH89xxCC", 2}, 190 {"DH89xxCC", 2},
280 {"Panther Point", 2}, 191 {"Panther Point", 2},
281 {"Panther Point", 2},
282 {"Panther Point", 2},
283 {"Panther Point", 2},
284 {"Panther Point", 2},
285 {"Panther Point", 2},
286 {"Panther Point", 2},
287 {"Panther Point", 2},
288 {"Panther Point", 2},
289 {"Panther Point", 2},
290 {"Panther Point", 2},
291 {"Panther Point", 2},
292 {"Panther Point", 2},
293 {"Panther Point", 2},
294 {"Panther Point", 2},
295 {"Panther Point", 2},
296 {"Panther Point", 2},
297 {"Panther Point", 2},
298 {"Panther Point", 2},
299 {"Panther Point", 2},
300 {"Panther Point", 2},
301 {"Panther Point", 2},
302 {"Panther Point", 2},
303 {"Panther Point", 2},
304 {"Panther Point", 2},
305 {"Panther Point", 2},
306 {"Panther Point", 2},
307 {"Panther Point", 2},
308 {"Panther Point", 2},
309 {"Panther Point", 2},
310 {"Panther Point", 2},
311 {"Panther Point", 2},
312 {NULL, 0} 192 {NULL, 0}
313}; 193};
314 194
315#define ITCO_PCI_DEVICE(dev, data) \
316 .vendor = PCI_VENDOR_ID_INTEL, \
317 .device = dev, \
318 .subvendor = PCI_ANY_ID, \
319 .subdevice = PCI_ANY_ID, \
320 .class = 0, \
321 .class_mask = 0, \
322 .driver_data = data
323
324/* 195/*
325 * This data only exists for exporting the supported PCI ids 196 * This data only exists for exporting the supported PCI ids
326 * via MODULE_DEVICE_TABLE. We do not actually register a 197 * via MODULE_DEVICE_TABLE. We do not actually register a
@@ -328,138 +199,138 @@ static struct {
328 * functions that probably will be registered by other drivers. 199 * functions that probably will be registered by other drivers.
329 */ 200 */
330static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = { 201static DEFINE_PCI_DEVICE_TABLE(iTCO_wdt_pci_tbl) = {
331 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AA_0, TCO_ICH)}, 202 { PCI_VDEVICE(INTEL, 0x2410), TCO_ICH},
332 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801AB_0, TCO_ICH0)}, 203 { PCI_VDEVICE(INTEL, 0x2420), TCO_ICH0},
333 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_0, TCO_ICH2)}, 204 { PCI_VDEVICE(INTEL, 0x2440), TCO_ICH2},
334 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801BA_10, TCO_ICH2M)}, 205 { PCI_VDEVICE(INTEL, 0x244c), TCO_ICH2M},
335 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_0, TCO_ICH3)}, 206 { PCI_VDEVICE(INTEL, 0x2480), TCO_ICH3},
336 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801CA_12, TCO_ICH3M)}, 207 { PCI_VDEVICE(INTEL, 0x248c), TCO_ICH3M},
337 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_0, TCO_ICH4)}, 208 { PCI_VDEVICE(INTEL, 0x24c0), TCO_ICH4},
338 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801DB_12, TCO_ICH4M)}, 209 { PCI_VDEVICE(INTEL, 0x24cc), TCO_ICH4M},
339 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801E_0, TCO_CICH)}, 210 { PCI_VDEVICE(INTEL, 0x2450), TCO_CICH},
340 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_82801EB_0, TCO_ICH5)}, 211 { PCI_VDEVICE(INTEL, 0x24d0), TCO_ICH5},
341 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB_1, TCO_6300ESB)}, 212 { PCI_VDEVICE(INTEL, 0x25a1), TCO_6300ESB},
342 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_0, TCO_ICH6)}, 213 { PCI_VDEVICE(INTEL, 0x2640), TCO_ICH6},
343 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_1, TCO_ICH6M)}, 214 { PCI_VDEVICE(INTEL, 0x2641), TCO_ICH6M},
344 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH6_2, TCO_ICH6W)}, 215 { PCI_VDEVICE(INTEL, 0x2642), TCO_ICH6W},
345 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ESB2_0, TCO_631XESB)}, 216 { PCI_VDEVICE(INTEL, 0x2670), TCO_631XESB},
346 { ITCO_PCI_DEVICE(0x2671, TCO_631XESB)}, 217 { PCI_VDEVICE(INTEL, 0x2671), TCO_631XESB},
347 { ITCO_PCI_DEVICE(0x2672, TCO_631XESB)}, 218 { PCI_VDEVICE(INTEL, 0x2672), TCO_631XESB},
348 { ITCO_PCI_DEVICE(0x2673, TCO_631XESB)}, 219 { PCI_VDEVICE(INTEL, 0x2673), TCO_631XESB},
349 { ITCO_PCI_DEVICE(0x2674, TCO_631XESB)}, 220 { PCI_VDEVICE(INTEL, 0x2674), TCO_631XESB},
350 { ITCO_PCI_DEVICE(0x2675, TCO_631XESB)}, 221 { PCI_VDEVICE(INTEL, 0x2675), TCO_631XESB},
351 { ITCO_PCI_DEVICE(0x2676, TCO_631XESB)}, 222 { PCI_VDEVICE(INTEL, 0x2676), TCO_631XESB},
352 { ITCO_PCI_DEVICE(0x2677, TCO_631XESB)}, 223 { PCI_VDEVICE(INTEL, 0x2677), TCO_631XESB},
353 { ITCO_PCI_DEVICE(0x2678, TCO_631XESB)}, 224 { PCI_VDEVICE(INTEL, 0x2678), TCO_631XESB},
354 { ITCO_PCI_DEVICE(0x2679, TCO_631XESB)}, 225 { PCI_VDEVICE(INTEL, 0x2679), TCO_631XESB},
355 { ITCO_PCI_DEVICE(0x267a, TCO_631XESB)}, 226 { PCI_VDEVICE(INTEL, 0x267a), TCO_631XESB},
356 { ITCO_PCI_DEVICE(0x267b, TCO_631XESB)}, 227 { PCI_VDEVICE(INTEL, 0x267b), TCO_631XESB},
357 { ITCO_PCI_DEVICE(0x267c, TCO_631XESB)}, 228 { PCI_VDEVICE(INTEL, 0x267c), TCO_631XESB},
358 { ITCO_PCI_DEVICE(0x267d, TCO_631XESB)}, 229 { PCI_VDEVICE(INTEL, 0x267d), TCO_631XESB},
359 { ITCO_PCI_DEVICE(0x267e, TCO_631XESB)}, 230 { PCI_VDEVICE(INTEL, 0x267e), TCO_631XESB},
360 { ITCO_PCI_DEVICE(0x267f, TCO_631XESB)}, 231 { PCI_VDEVICE(INTEL, 0x267f), TCO_631XESB},
361 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_0, TCO_ICH7)}, 232 { PCI_VDEVICE(INTEL, 0x27b8), TCO_ICH7},
362 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_30, TCO_ICH7DH)}, 233 { PCI_VDEVICE(INTEL, 0x27b0), TCO_ICH7DH},
363 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_1, TCO_ICH7M)}, 234 { PCI_VDEVICE(INTEL, 0x27b9), TCO_ICH7M},
364 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH7_31, TCO_ICH7MDH)}, 235 { PCI_VDEVICE(INTEL, 0x27bd), TCO_ICH7MDH},
365 { ITCO_PCI_DEVICE(0x27bc, TCO_NM10)}, 236 { PCI_VDEVICE(INTEL, 0x27bc), TCO_NM10},
366 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_0, TCO_ICH8)}, 237 { PCI_VDEVICE(INTEL, 0x2810), TCO_ICH8},
367 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_2, TCO_ICH8DH)}, 238 { PCI_VDEVICE(INTEL, 0x2812), TCO_ICH8DH},
368 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_3, TCO_ICH8DO)}, 239 { PCI_VDEVICE(INTEL, 0x2814), TCO_ICH8DO},
369 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_4, TCO_ICH8M)}, 240 { PCI_VDEVICE(INTEL, 0x2815), TCO_ICH8M},
370 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH8_1, TCO_ICH8ME)}, 241 { PCI_VDEVICE(INTEL, 0x2811), TCO_ICH8ME},
371 { ITCO_PCI_DEVICE(0x2918, TCO_ICH9)}, 242 { PCI_VDEVICE(INTEL, 0x2918), TCO_ICH9},
372 { ITCO_PCI_DEVICE(0x2916, TCO_ICH9R)}, 243 { PCI_VDEVICE(INTEL, 0x2916), TCO_ICH9R},
373 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_2, TCO_ICH9DH)}, 244 { PCI_VDEVICE(INTEL, 0x2912), TCO_ICH9DH},
374 { ITCO_PCI_DEVICE(PCI_DEVICE_ID_INTEL_ICH9_4, TCO_ICH9DO)}, 245 { PCI_VDEVICE(INTEL, 0x2914), TCO_ICH9DO},
375 { ITCO_PCI_DEVICE(0x2919, TCO_ICH9M)}, 246 { PCI_VDEVICE(INTEL, 0x2919), TCO_ICH9M},
376 { ITCO_PCI_DEVICE(0x2917, TCO_ICH9ME)}, 247 { PCI_VDEVICE(INTEL, 0x2917), TCO_ICH9ME},
377 { ITCO_PCI_DEVICE(0x3a18, TCO_ICH10)}, 248 { PCI_VDEVICE(INTEL, 0x3a18), TCO_ICH10},
378 { ITCO_PCI_DEVICE(0x3a16, TCO_ICH10R)}, 249 { PCI_VDEVICE(INTEL, 0x3a16), TCO_ICH10R},
379 { ITCO_PCI_DEVICE(0x3a1a, TCO_ICH10D)}, 250 { PCI_VDEVICE(INTEL, 0x3a1a), TCO_ICH10D},
380 { ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)}, 251 { PCI_VDEVICE(INTEL, 0x3a14), TCO_ICH10DO},
381 { ITCO_PCI_DEVICE(0x3b00, TCO_PCH)}, 252 { PCI_VDEVICE(INTEL, 0x3b00), TCO_PCH},
382 { ITCO_PCI_DEVICE(0x3b01, TCO_PCHM)}, 253 { PCI_VDEVICE(INTEL, 0x3b01), TCO_PCHM},
383 { ITCO_PCI_DEVICE(0x3b02, TCO_P55)}, 254 { PCI_VDEVICE(INTEL, 0x3b02), TCO_P55},
384 { ITCO_PCI_DEVICE(0x3b03, TCO_PM55)}, 255 { PCI_VDEVICE(INTEL, 0x3b03), TCO_PM55},
385 { ITCO_PCI_DEVICE(0x3b06, TCO_H55)}, 256 { PCI_VDEVICE(INTEL, 0x3b06), TCO_H55},
386 { ITCO_PCI_DEVICE(0x3b07, TCO_QM57)}, 257 { PCI_VDEVICE(INTEL, 0x3b07), TCO_QM57},
387 { ITCO_PCI_DEVICE(0x3b08, TCO_H57)}, 258 { PCI_VDEVICE(INTEL, 0x3b08), TCO_H57},
388 { ITCO_PCI_DEVICE(0x3b09, TCO_HM55)}, 259 { PCI_VDEVICE(INTEL, 0x3b09), TCO_HM55},
389 { ITCO_PCI_DEVICE(0x3b0a, TCO_Q57)}, 260 { PCI_VDEVICE(INTEL, 0x3b0a), TCO_Q57},
390 { ITCO_PCI_DEVICE(0x3b0b, TCO_HM57)}, 261 { PCI_VDEVICE(INTEL, 0x3b0b), TCO_HM57},
391 { ITCO_PCI_DEVICE(0x3b0d, TCO_PCHMSFF)}, 262 { PCI_VDEVICE(INTEL, 0x3b0d), TCO_PCHMSFF},
392 { ITCO_PCI_DEVICE(0x3b0f, TCO_QS57)}, 263 { PCI_VDEVICE(INTEL, 0x3b0f), TCO_QS57},
393 { ITCO_PCI_DEVICE(0x3b12, TCO_3400)}, 264 { PCI_VDEVICE(INTEL, 0x3b12), TCO_3400},
394 { ITCO_PCI_DEVICE(0x3b14, TCO_3420)}, 265 { PCI_VDEVICE(INTEL, 0x3b14), TCO_3420},
395 { ITCO_PCI_DEVICE(0x3b16, TCO_3450)}, 266 { PCI_VDEVICE(INTEL, 0x3b16), TCO_3450},
396 { ITCO_PCI_DEVICE(0x5031, TCO_EP80579)}, 267 { PCI_VDEVICE(INTEL, 0x5031), TCO_EP80579},
397 { ITCO_PCI_DEVICE(0x1c41, TCO_CPT1)}, 268 { PCI_VDEVICE(INTEL, 0x1c41), TCO_CPT},
398 { ITCO_PCI_DEVICE(0x1c42, TCO_CPT2)}, 269 { PCI_VDEVICE(INTEL, 0x1c42), TCO_CPTD},
399 { ITCO_PCI_DEVICE(0x1c43, TCO_CPT3)}, 270 { PCI_VDEVICE(INTEL, 0x1c43), TCO_CPTM},
400 { ITCO_PCI_DEVICE(0x1c44, TCO_CPT4)}, 271 { PCI_VDEVICE(INTEL, 0x1c44), TCO_CPT},
401 { ITCO_PCI_DEVICE(0x1c45, TCO_CPT5)}, 272 { PCI_VDEVICE(INTEL, 0x1c45), TCO_CPT},
402 { ITCO_PCI_DEVICE(0x1c46, TCO_CPT6)}, 273 { PCI_VDEVICE(INTEL, 0x1c46), TCO_CPT},
403 { ITCO_PCI_DEVICE(0x1c47, TCO_CPT7)}, 274 { PCI_VDEVICE(INTEL, 0x1c47), TCO_CPT},
404 { ITCO_PCI_DEVICE(0x1c48, TCO_CPT8)}, 275 { PCI_VDEVICE(INTEL, 0x1c48), TCO_CPT},
405 { ITCO_PCI_DEVICE(0x1c49, TCO_CPT9)}, 276 { PCI_VDEVICE(INTEL, 0x1c49), TCO_CPT},
406 { ITCO_PCI_DEVICE(0x1c4a, TCO_CPT10)}, 277 { PCI_VDEVICE(INTEL, 0x1c4a), TCO_CPT},
407 { ITCO_PCI_DEVICE(0x1c4b, TCO_CPT11)}, 278 { PCI_VDEVICE(INTEL, 0x1c4b), TCO_CPT},
408 { ITCO_PCI_DEVICE(0x1c4c, TCO_CPT12)}, 279 { PCI_VDEVICE(INTEL, 0x1c4c), TCO_CPT},
409 { ITCO_PCI_DEVICE(0x1c4d, TCO_CPT13)}, 280 { PCI_VDEVICE(INTEL, 0x1c4d), TCO_CPT},
410 { ITCO_PCI_DEVICE(0x1c4e, TCO_CPT14)}, 281 { PCI_VDEVICE(INTEL, 0x1c4e), TCO_CPT},
411 { ITCO_PCI_DEVICE(0x1c4f, TCO_CPT15)}, 282 { PCI_VDEVICE(INTEL, 0x1c4f), TCO_CPT},
412 { ITCO_PCI_DEVICE(0x1c50, TCO_CPT16)}, 283 { PCI_VDEVICE(INTEL, 0x1c50), TCO_CPT},
413 { ITCO_PCI_DEVICE(0x1c51, TCO_CPT17)}, 284 { PCI_VDEVICE(INTEL, 0x1c51), TCO_CPT},
414 { ITCO_PCI_DEVICE(0x1c52, TCO_CPT18)}, 285 { PCI_VDEVICE(INTEL, 0x1c52), TCO_CPT},
415 { ITCO_PCI_DEVICE(0x1c53, TCO_CPT19)}, 286 { PCI_VDEVICE(INTEL, 0x1c53), TCO_CPT},
416 { ITCO_PCI_DEVICE(0x1c54, TCO_CPT20)}, 287 { PCI_VDEVICE(INTEL, 0x1c54), TCO_CPT},
417 { ITCO_PCI_DEVICE(0x1c55, TCO_CPT21)}, 288 { PCI_VDEVICE(INTEL, 0x1c55), TCO_CPT},
418 { ITCO_PCI_DEVICE(0x1c56, TCO_CPT22)}, 289 { PCI_VDEVICE(INTEL, 0x1c56), TCO_CPT},
419 { ITCO_PCI_DEVICE(0x1c57, TCO_CPT23)}, 290 { PCI_VDEVICE(INTEL, 0x1c57), TCO_CPT},
420 { ITCO_PCI_DEVICE(0x1c58, TCO_CPT24)}, 291 { PCI_VDEVICE(INTEL, 0x1c58), TCO_CPT},
421 { ITCO_PCI_DEVICE(0x1c59, TCO_CPT25)}, 292 { PCI_VDEVICE(INTEL, 0x1c59), TCO_CPT},
422 { ITCO_PCI_DEVICE(0x1c5a, TCO_CPT26)}, 293 { PCI_VDEVICE(INTEL, 0x1c5a), TCO_CPT},
423 { ITCO_PCI_DEVICE(0x1c5b, TCO_CPT27)}, 294 { PCI_VDEVICE(INTEL, 0x1c5b), TCO_CPT},
424 { ITCO_PCI_DEVICE(0x1c5c, TCO_CPT28)}, 295 { PCI_VDEVICE(INTEL, 0x1c5c), TCO_CPT},
425 { ITCO_PCI_DEVICE(0x1c5d, TCO_CPT29)}, 296 { PCI_VDEVICE(INTEL, 0x1c5d), TCO_CPT},
426 { ITCO_PCI_DEVICE(0x1c5e, TCO_CPT30)}, 297 { PCI_VDEVICE(INTEL, 0x1c5e), TCO_CPT},
427 { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)}, 298 { PCI_VDEVICE(INTEL, 0x1c5f), TCO_CPT},
428 { ITCO_PCI_DEVICE(0x1d40, TCO_PBG1)}, 299 { PCI_VDEVICE(INTEL, 0x1d40), TCO_PBG},
429 { ITCO_PCI_DEVICE(0x1d41, TCO_PBG2)}, 300 { PCI_VDEVICE(INTEL, 0x1d41), TCO_PBG},
430 { ITCO_PCI_DEVICE(0x2310, TCO_DH89XXCC)}, 301 { PCI_VDEVICE(INTEL, 0x2310), TCO_DH89XXCC},
431 { ITCO_PCI_DEVICE(0x1e40, TCO_PPT0)}, 302 { PCI_VDEVICE(INTEL, 0x1e40), TCO_PPT},
432 { ITCO_PCI_DEVICE(0x1e41, TCO_PPT1)}, 303 { PCI_VDEVICE(INTEL, 0x1e41), TCO_PPT},
433 { ITCO_PCI_DEVICE(0x1e42, TCO_PPT2)}, 304 { PCI_VDEVICE(INTEL, 0x1e42), TCO_PPT},
434 { ITCO_PCI_DEVICE(0x1e43, TCO_PPT3)}, 305 { PCI_VDEVICE(INTEL, 0x1e43), TCO_PPT},
435 { ITCO_PCI_DEVICE(0x1e44, TCO_PPT4)}, 306 { PCI_VDEVICE(INTEL, 0x1e44), TCO_PPT},
436 { ITCO_PCI_DEVICE(0x1e45, TCO_PPT5)}, 307 { PCI_VDEVICE(INTEL, 0x1e45), TCO_PPT},
437 { ITCO_PCI_DEVICE(0x1e46, TCO_PPT6)}, 308 { PCI_VDEVICE(INTEL, 0x1e46), TCO_PPT},
438 { ITCO_PCI_DEVICE(0x1e47, TCO_PPT7)}, 309 { PCI_VDEVICE(INTEL, 0x1e47), TCO_PPT},
439 { ITCO_PCI_DEVICE(0x1e48, TCO_PPT8)}, 310 { PCI_VDEVICE(INTEL, 0x1e48), TCO_PPT},
440 { ITCO_PCI_DEVICE(0x1e49, TCO_PPT9)}, 311 { PCI_VDEVICE(INTEL, 0x1e49), TCO_PPT},
441 { ITCO_PCI_DEVICE(0x1e4a, TCO_PPT10)}, 312 { PCI_VDEVICE(INTEL, 0x1e4a), TCO_PPT},
442 { ITCO_PCI_DEVICE(0x1e4b, TCO_PPT11)}, 313 { PCI_VDEVICE(INTEL, 0x1e4b), TCO_PPT},
443 { ITCO_PCI_DEVICE(0x1e4c, TCO_PPT12)}, 314 { PCI_VDEVICE(INTEL, 0x1e4c), TCO_PPT},
444 { ITCO_PCI_DEVICE(0x1e4d, TCO_PPT13)}, 315 { PCI_VDEVICE(INTEL, 0x1e4d), TCO_PPT},
445 { ITCO_PCI_DEVICE(0x1e4e, TCO_PPT14)}, 316 { PCI_VDEVICE(INTEL, 0x1e4e), TCO_PPT},
446 { ITCO_PCI_DEVICE(0x1e4f, TCO_PPT15)}, 317 { PCI_VDEVICE(INTEL, 0x1e4f), TCO_PPT},
447 { ITCO_PCI_DEVICE(0x1e50, TCO_PPT16)}, 318 { PCI_VDEVICE(INTEL, 0x1e50), TCO_PPT},
448 { ITCO_PCI_DEVICE(0x1e51, TCO_PPT17)}, 319 { PCI_VDEVICE(INTEL, 0x1e51), TCO_PPT},
449 { ITCO_PCI_DEVICE(0x1e52, TCO_PPT18)}, 320 { PCI_VDEVICE(INTEL, 0x1e52), TCO_PPT},
450 { ITCO_PCI_DEVICE(0x1e53, TCO_PPT19)}, 321 { PCI_VDEVICE(INTEL, 0x1e53), TCO_PPT},
451 { ITCO_PCI_DEVICE(0x1e54, TCO_PPT20)}, 322 { PCI_VDEVICE(INTEL, 0x1e54), TCO_PPT},
452 { ITCO_PCI_DEVICE(0x1e55, TCO_PPT21)}, 323 { PCI_VDEVICE(INTEL, 0x1e55), TCO_PPT},
453 { ITCO_PCI_DEVICE(0x1e56, TCO_PPT22)}, 324 { PCI_VDEVICE(INTEL, 0x1e56), TCO_PPT},
454 { ITCO_PCI_DEVICE(0x1e57, TCO_PPT23)}, 325 { PCI_VDEVICE(INTEL, 0x1e57), TCO_PPT},
455 { ITCO_PCI_DEVICE(0x1e58, TCO_PPT24)}, 326 { PCI_VDEVICE(INTEL, 0x1e58), TCO_PPT},
456 { ITCO_PCI_DEVICE(0x1e59, TCO_PPT25)}, 327 { PCI_VDEVICE(INTEL, 0x1e59), TCO_PPT},
457 { ITCO_PCI_DEVICE(0x1e5a, TCO_PPT26)}, 328 { PCI_VDEVICE(INTEL, 0x1e5a), TCO_PPT},
458 { ITCO_PCI_DEVICE(0x1e5b, TCO_PPT27)}, 329 { PCI_VDEVICE(INTEL, 0x1e5b), TCO_PPT},
459 { ITCO_PCI_DEVICE(0x1e5c, TCO_PPT28)}, 330 { PCI_VDEVICE(INTEL, 0x1e5c), TCO_PPT},
460 { ITCO_PCI_DEVICE(0x1e5d, TCO_PPT29)}, 331 { PCI_VDEVICE(INTEL, 0x1e5d), TCO_PPT},
461 { ITCO_PCI_DEVICE(0x1e5e, TCO_PPT30)}, 332 { PCI_VDEVICE(INTEL, 0x1e5e), TCO_PPT},
462 { ITCO_PCI_DEVICE(0x1e5f, TCO_PPT31)}, 333 { PCI_VDEVICE(INTEL, 0x1e5f), TCO_PPT},
463 { 0, }, /* End of list */ 334 { 0, }, /* End of list */
464}; 335};
465MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); 336MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
@@ -1052,15 +923,10 @@ static void iTCO_wdt_shutdown(struct platform_device *dev)
1052 iTCO_wdt_stop(); 923 iTCO_wdt_stop();
1053} 924}
1054 925
1055#define iTCO_wdt_suspend NULL
1056#define iTCO_wdt_resume NULL
1057
1058static struct platform_driver iTCO_wdt_driver = { 926static struct platform_driver iTCO_wdt_driver = {
1059 .probe = iTCO_wdt_probe, 927 .probe = iTCO_wdt_probe,
1060 .remove = __devexit_p(iTCO_wdt_remove), 928 .remove = __devexit_p(iTCO_wdt_remove),
1061 .shutdown = iTCO_wdt_shutdown, 929 .shutdown = iTCO_wdt_shutdown,
1062 .suspend = iTCO_wdt_suspend,
1063 .resume = iTCO_wdt_resume,
1064 .driver = { 930 .driver = {
1065 .owner = THIS_MODULE, 931 .owner = THIS_MODULE,
1066 .name = DRV_NAME, 932 .name = DRV_NAME,
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 86f7cac1026c..b8ef2c6dca7c 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -329,12 +329,18 @@ static void imx2_wdt_shutdown(struct platform_device *pdev)
329 } 329 }
330} 330}
331 331
332static const struct of_device_id imx2_wdt_dt_ids[] = {
333 { .compatible = "fsl,imx21-wdt", },
334 { /* sentinel */ }
335};
336
332static struct platform_driver imx2_wdt_driver = { 337static struct platform_driver imx2_wdt_driver = {
333 .remove = __exit_p(imx2_wdt_remove), 338 .remove = __exit_p(imx2_wdt_remove),
334 .shutdown = imx2_wdt_shutdown, 339 .shutdown = imx2_wdt_shutdown,
335 .driver = { 340 .driver = {
336 .name = DRIVER_NAME, 341 .name = DRIVER_NAME,
337 .owner = THIS_MODULE, 342 .owner = THIS_MODULE,
343 .of_match_table = imx2_wdt_dt_ids,
338 }, 344 },
339}; 345};
340 346
diff --git a/drivers/watchdog/it8712f_wdt.c b/drivers/watchdog/it8712f_wdt.c
index 6143f52ba6b8..8d2d8502d3e8 100644
--- a/drivers/watchdog/it8712f_wdt.c
+++ b/drivers/watchdog/it8712f_wdt.c
@@ -28,10 +28,10 @@
28#include <linux/notifier.h> 28#include <linux/notifier.h>
29#include <linux/reboot.h> 29#include <linux/reboot.h>
30#include <linux/fs.h> 30#include <linux/fs.h>
31#include <linux/pci.h>
32#include <linux/spinlock.h> 31#include <linux/spinlock.h>
33#include <linux/uaccess.h> 32#include <linux/uaccess.h>
34#include <linux/io.h> 33#include <linux/io.h>
34#include <linux/ioport.h>
35 35
36#define NAME "it8712f_wdt" 36#define NAME "it8712f_wdt"
37 37
@@ -51,7 +51,6 @@ MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
51 51
52static unsigned long wdt_open; 52static unsigned long wdt_open;
53static unsigned expect_close; 53static unsigned expect_close;
54static spinlock_t io_lock;
55static unsigned char revision; 54static unsigned char revision;
56 55
57/* Dog Food address - We use the game port address */ 56/* Dog Food address - We use the game port address */
@@ -121,20 +120,26 @@ static inline void superio_select(int ldn)
121 outb(ldn, VAL); 120 outb(ldn, VAL);
122} 121}
123 122
124static inline void superio_enter(void) 123static inline int superio_enter(void)
125{ 124{
126 spin_lock(&io_lock); 125 /*
126 * Try to reserve REG and REG + 1 for exclusive access.
127 */
128 if (!request_muxed_region(REG, 2, NAME))
129 return -EBUSY;
130
127 outb(0x87, REG); 131 outb(0x87, REG);
128 outb(0x01, REG); 132 outb(0x01, REG);
129 outb(0x55, REG); 133 outb(0x55, REG);
130 outb(0x55, REG); 134 outb(0x55, REG);
135 return 0;
131} 136}
132 137
133static inline void superio_exit(void) 138static inline void superio_exit(void)
134{ 139{
135 outb(0x02, REG); 140 outb(0x02, REG);
136 outb(0x02, VAL); 141 outb(0x02, VAL);
137 spin_unlock(&io_lock); 142 release_region(REG, 2);
138} 143}
139 144
140static inline void it8712f_wdt_ping(void) 145static inline void it8712f_wdt_ping(void)
@@ -173,10 +178,13 @@ static int it8712f_wdt_get_status(void)
173 return 0; 178 return 0;
174} 179}
175 180
176static void it8712f_wdt_enable(void) 181static int it8712f_wdt_enable(void)
177{ 182{
183 int ret = superio_enter();
184 if (ret)
185 return ret;
186
178 printk(KERN_DEBUG NAME ": enabling watchdog timer\n"); 187 printk(KERN_DEBUG NAME ": enabling watchdog timer\n");
179 superio_enter();
180 superio_select(LDN_GPIO); 188 superio_select(LDN_GPIO);
181 189
182 superio_outb(wdt_control_reg, WDT_CONTROL); 190 superio_outb(wdt_control_reg, WDT_CONTROL);
@@ -186,13 +194,17 @@ static void it8712f_wdt_enable(void)
186 superio_exit(); 194 superio_exit();
187 195
188 it8712f_wdt_ping(); 196 it8712f_wdt_ping();
197
198 return 0;
189} 199}
190 200
191static void it8712f_wdt_disable(void) 201static int it8712f_wdt_disable(void)
192{ 202{
193 printk(KERN_DEBUG NAME ": disabling watchdog timer\n"); 203 int ret = superio_enter();
204 if (ret)
205 return ret;
194 206
195 superio_enter(); 207 printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
196 superio_select(LDN_GPIO); 208 superio_select(LDN_GPIO);
197 209
198 superio_outb(0, WDT_CONFIG); 210 superio_outb(0, WDT_CONFIG);
@@ -202,6 +214,7 @@ static void it8712f_wdt_disable(void)
202 superio_outb(0, WDT_TIMEOUT); 214 superio_outb(0, WDT_TIMEOUT);
203 215
204 superio_exit(); 216 superio_exit();
217 return 0;
205} 218}
206 219
207static int it8712f_wdt_notify(struct notifier_block *this, 220static int it8712f_wdt_notify(struct notifier_block *this,
@@ -252,6 +265,7 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
252 WDIOF_MAGICCLOSE, 265 WDIOF_MAGICCLOSE,
253 }; 266 };
254 int value; 267 int value;
268 int ret;
255 269
256 switch (cmd) { 270 switch (cmd) {
257 case WDIOC_GETSUPPORT: 271 case WDIOC_GETSUPPORT:
@@ -259,7 +273,9 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
259 return -EFAULT; 273 return -EFAULT;
260 return 0; 274 return 0;
261 case WDIOC_GETSTATUS: 275 case WDIOC_GETSTATUS:
262 superio_enter(); 276 ret = superio_enter();
277 if (ret)
278 return ret;
263 superio_select(LDN_GPIO); 279 superio_select(LDN_GPIO);
264 280
265 value = it8712f_wdt_get_status(); 281 value = it8712f_wdt_get_status();
@@ -280,7 +296,9 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
280 if (value > (max_units * 60)) 296 if (value > (max_units * 60))
281 return -EINVAL; 297 return -EINVAL;
282 margin = value; 298 margin = value;
283 superio_enter(); 299 ret = superio_enter();
300 if (ret)
301 return ret;
284 superio_select(LDN_GPIO); 302 superio_select(LDN_GPIO);
285 303
286 it8712f_wdt_update_margin(); 304 it8712f_wdt_update_margin();
@@ -299,10 +317,14 @@ static long it8712f_wdt_ioctl(struct file *file, unsigned int cmd,
299 317
300static int it8712f_wdt_open(struct inode *inode, struct file *file) 318static int it8712f_wdt_open(struct inode *inode, struct file *file)
301{ 319{
320 int ret;
302 /* only allow one at a time */ 321 /* only allow one at a time */
303 if (test_and_set_bit(0, &wdt_open)) 322 if (test_and_set_bit(0, &wdt_open))
304 return -EBUSY; 323 return -EBUSY;
305 it8712f_wdt_enable(); 324
325 ret = it8712f_wdt_enable();
326 if (ret)
327 return ret;
306 return nonseekable_open(inode, file); 328 return nonseekable_open(inode, file);
307} 329}
308 330
@@ -313,7 +335,8 @@ static int it8712f_wdt_release(struct inode *inode, struct file *file)
313 ": watchdog device closed unexpectedly, will not" 335 ": watchdog device closed unexpectedly, will not"
314 " disable the watchdog timer\n"); 336 " disable the watchdog timer\n");
315 } else if (!nowayout) { 337 } else if (!nowayout) {
316 it8712f_wdt_disable(); 338 if (it8712f_wdt_disable())
339 printk(KERN_WARNING NAME "Watchdog disable failed\n");
317 } 340 }
318 expect_close = 0; 341 expect_close = 0;
319 clear_bit(0, &wdt_open); 342 clear_bit(0, &wdt_open);
@@ -340,8 +363,10 @@ static int __init it8712f_wdt_find(unsigned short *address)
340{ 363{
341 int err = -ENODEV; 364 int err = -ENODEV;
342 int chip_type; 365 int chip_type;
366 int ret = superio_enter();
367 if (ret)
368 return ret;
343 369
344 superio_enter();
345 chip_type = superio_inw(DEVID); 370 chip_type = superio_inw(DEVID);
346 if (chip_type != IT8712F_DEVID) 371 if (chip_type != IT8712F_DEVID)
347 goto exit; 372 goto exit;
@@ -382,8 +407,6 @@ static int __init it8712f_wdt_init(void)
382{ 407{
383 int err = 0; 408 int err = 0;
384 409
385 spin_lock_init(&io_lock);
386
387 if (it8712f_wdt_find(&address)) 410 if (it8712f_wdt_find(&address))
388 return -ENODEV; 411 return -ENODEV;
389 412
@@ -392,7 +415,11 @@ static int __init it8712f_wdt_init(void)
392 return -EBUSY; 415 return -EBUSY;
393 } 416 }
394 417
395 it8712f_wdt_disable(); 418 err = it8712f_wdt_disable();
419 if (err) {
420 printk(KERN_ERR NAME ": unable to disable watchdog timer.\n");
421 goto out;
422 }
396 423
397 err = register_reboot_notifier(&it8712f_wdt_notifier); 424 err = register_reboot_notifier(&it8712f_wdt_notifier);
398 if (err) { 425 if (err) {
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index b1bc72f9a209..a2d9a1266a23 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -137,7 +137,6 @@
137 137
138static unsigned int base, gpact, ciract, max_units, chip_type; 138static unsigned int base, gpact, ciract, max_units, chip_type;
139static unsigned long wdt_status; 139static unsigned long wdt_status;
140static DEFINE_SPINLOCK(spinlock);
141 140
142static int nogameport = DEFAULT_NOGAMEPORT; 141static int nogameport = DEFAULT_NOGAMEPORT;
143static int exclusive = DEFAULT_EXCLUSIVE; 142static int exclusive = DEFAULT_EXCLUSIVE;
@@ -163,18 +162,26 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="
163 162
164/* Superio Chip */ 163/* Superio Chip */
165 164
166static inline void superio_enter(void) 165static inline int superio_enter(void)
167{ 166{
167 /*
168 * Try to reserve REG and REG + 1 for exclusive access.
169 */
170 if (!request_muxed_region(REG, 2, WATCHDOG_NAME))
171 return -EBUSY;
172
168 outb(0x87, REG); 173 outb(0x87, REG);
169 outb(0x01, REG); 174 outb(0x01, REG);
170 outb(0x55, REG); 175 outb(0x55, REG);
171 outb(0x55, REG); 176 outb(0x55, REG);
177 return 0;
172} 178}
173 179
174static inline void superio_exit(void) 180static inline void superio_exit(void)
175{ 181{
176 outb(0x02, REG); 182 outb(0x02, REG);
177 outb(0x02, VAL); 183 outb(0x02, VAL);
184 release_region(REG, 2);
178} 185}
179 186
180static inline void superio_select(int ldn) 187static inline void superio_select(int ldn)
@@ -255,12 +262,11 @@ static void wdt_keepalive(void)
255 set_bit(WDTS_KEEPALIVE, &wdt_status); 262 set_bit(WDTS_KEEPALIVE, &wdt_status);
256} 263}
257 264
258static void wdt_start(void) 265static int wdt_start(void)
259{ 266{
260 unsigned long flags; 267 int ret = superio_enter();
261 268 if (ret)
262 spin_lock_irqsave(&spinlock, flags); 269 return ret;
263 superio_enter();
264 270
265 superio_select(GPIO); 271 superio_select(GPIO);
266 if (test_bit(WDTS_USE_GP, &wdt_status)) 272 if (test_bit(WDTS_USE_GP, &wdt_status))
@@ -270,15 +276,15 @@ static void wdt_start(void)
270 wdt_update_timeout(); 276 wdt_update_timeout();
271 277
272 superio_exit(); 278 superio_exit();
273 spin_unlock_irqrestore(&spinlock, flags); 279
280 return 0;
274} 281}
275 282
276static void wdt_stop(void) 283static int wdt_stop(void)
277{ 284{
278 unsigned long flags; 285 int ret = superio_enter();
279 286 if (ret)
280 spin_lock_irqsave(&spinlock, flags); 287 return ret;
281 superio_enter();
282 288
283 superio_select(GPIO); 289 superio_select(GPIO);
284 superio_outb(0x00, WDTCTRL); 290 superio_outb(0x00, WDTCTRL);
@@ -288,7 +294,7 @@ static void wdt_stop(void)
288 superio_outb(0x00, WDTVALMSB); 294 superio_outb(0x00, WDTVALMSB);
289 295
290 superio_exit(); 296 superio_exit();
291 spin_unlock_irqrestore(&spinlock, flags); 297 return 0;
292} 298}
293 299
294/** 300/**
@@ -303,8 +309,6 @@ static void wdt_stop(void)
303 309
304static int wdt_set_timeout(int t) 310static int wdt_set_timeout(int t)
305{ 311{
306 unsigned long flags;
307
308 if (t < 1 || t > max_units * 60) 312 if (t < 1 || t > max_units * 60)
309 return -EINVAL; 313 return -EINVAL;
310 314
@@ -313,14 +317,15 @@ static int wdt_set_timeout(int t)
313 else 317 else
314 timeout = t; 318 timeout = t;
315 319
316 spin_lock_irqsave(&spinlock, flags);
317 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 320 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
318 superio_enter(); 321 int ret = superio_enter();
322 if (ret)
323 return ret;
324
319 superio_select(GPIO); 325 superio_select(GPIO);
320 wdt_update_timeout(); 326 wdt_update_timeout();
321 superio_exit(); 327 superio_exit();
322 } 328 }
323 spin_unlock_irqrestore(&spinlock, flags);
324 return 0; 329 return 0;
325} 330}
326 331
@@ -339,12 +344,12 @@ static int wdt_set_timeout(int t)
339 344
340static int wdt_get_status(int *status) 345static int wdt_get_status(int *status)
341{ 346{
342 unsigned long flags;
343
344 *status = 0; 347 *status = 0;
345 if (testmode) { 348 if (testmode) {
346 spin_lock_irqsave(&spinlock, flags); 349 int ret = superio_enter();
347 superio_enter(); 350 if (ret)
351 return ret;
352
348 superio_select(GPIO); 353 superio_select(GPIO);
349 if (superio_inb(WDTCTRL) & WDT_ZERO) { 354 if (superio_inb(WDTCTRL) & WDT_ZERO) {
350 superio_outb(0x00, WDTCTRL); 355 superio_outb(0x00, WDTCTRL);
@@ -353,7 +358,6 @@ static int wdt_get_status(int *status)
353 } 358 }
354 359
355 superio_exit(); 360 superio_exit();
356 spin_unlock_irqrestore(&spinlock, flags);
357 } 361 }
358 if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status)) 362 if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status))
359 *status |= WDIOF_KEEPALIVEPING; 363 *status |= WDIOF_KEEPALIVEPING;
@@ -379,9 +383,17 @@ static int wdt_open(struct inode *inode, struct file *file)
379 if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status)) 383 if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status))
380 return -EBUSY; 384 return -EBUSY;
381 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) { 385 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
386 int ret;
382 if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status)) 387 if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status))
383 __module_get(THIS_MODULE); 388 __module_get(THIS_MODULE);
384 wdt_start(); 389
390 ret = wdt_start();
391 if (ret) {
392 clear_bit(WDTS_LOCKED, &wdt_status);
393 clear_bit(WDTS_TIMER_RUN, &wdt_status);
394 clear_bit(WDTS_DEV_OPEN, &wdt_status);
395 return ret;
396 }
385 } 397 }
386 return nonseekable_open(inode, file); 398 return nonseekable_open(inode, file);
387} 399}
@@ -403,7 +415,16 @@ static int wdt_release(struct inode *inode, struct file *file)
403{ 415{
404 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { 416 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
405 if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) { 417 if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) {
406 wdt_stop(); 418 int ret = wdt_stop();
419 if (ret) {
420 /*
421 * Stop failed. Just keep the watchdog alive
422 * and hope nothing bad happens.
423 */
424 set_bit(WDTS_EXPECTED, &wdt_status);
425 wdt_keepalive();
426 return ret;
427 }
407 clear_bit(WDTS_TIMER_RUN, &wdt_status); 428 clear_bit(WDTS_TIMER_RUN, &wdt_status);
408 } else { 429 } else {
409 wdt_keepalive(); 430 wdt_keepalive();
@@ -484,7 +505,9 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
484 &ident, sizeof(ident)) ? -EFAULT : 0; 505 &ident, sizeof(ident)) ? -EFAULT : 0;
485 506
486 case WDIOC_GETSTATUS: 507 case WDIOC_GETSTATUS:
487 wdt_get_status(&status); 508 rc = wdt_get_status(&status);
509 if (rc)
510 return rc;
488 return put_user(status, uarg.i); 511 return put_user(status, uarg.i);
489 512
490 case WDIOC_GETBOOTSTATUS: 513 case WDIOC_GETBOOTSTATUS:
@@ -500,14 +523,22 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
500 523
501 switch (new_options) { 524 switch (new_options) {
502 case WDIOS_DISABLECARD: 525 case WDIOS_DISABLECARD:
503 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) 526 if (test_bit(WDTS_TIMER_RUN, &wdt_status)) {
504 wdt_stop(); 527 rc = wdt_stop();
528 if (rc)
529 return rc;
530 }
505 clear_bit(WDTS_TIMER_RUN, &wdt_status); 531 clear_bit(WDTS_TIMER_RUN, &wdt_status);
506 return 0; 532 return 0;
507 533
508 case WDIOS_ENABLECARD: 534 case WDIOS_ENABLECARD:
509 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) 535 if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) {
510 wdt_start(); 536 rc = wdt_start();
537 if (rc) {
538 clear_bit(WDTS_TIMER_RUN, &wdt_status);
539 return rc;
540 }
541 }
511 return 0; 542 return 0;
512 543
513 default: 544 default:
@@ -560,16 +591,17 @@ static int __init it87_wdt_init(void)
560 int rc = 0; 591 int rc = 0;
561 int try_gameport = !nogameport; 592 int try_gameport = !nogameport;
562 u8 chip_rev; 593 u8 chip_rev;
563 unsigned long flags; 594 int gp_rreq_fail = 0;
564 595
565 wdt_status = 0; 596 wdt_status = 0;
566 597
567 spin_lock_irqsave(&spinlock, flags); 598 rc = superio_enter();
568 superio_enter(); 599 if (rc)
600 return rc;
601
569 chip_type = superio_inw(CHIPID); 602 chip_type = superio_inw(CHIPID);
570 chip_rev = superio_inb(CHIPREV) & 0x0f; 603 chip_rev = superio_inb(CHIPREV) & 0x0f;
571 superio_exit(); 604 superio_exit();
572 spin_unlock_irqrestore(&spinlock, flags);
573 605
574 switch (chip_type) { 606 switch (chip_type) {
575 case IT8702_ID: 607 case IT8702_ID:
@@ -603,8 +635,9 @@ static int __init it87_wdt_init(void)
603 return -ENODEV; 635 return -ENODEV;
604 } 636 }
605 637
606 spin_lock_irqsave(&spinlock, flags); 638 rc = superio_enter();
607 superio_enter(); 639 if (rc)
640 return rc;
608 641
609 superio_select(GPIO); 642 superio_select(GPIO);
610 superio_outb(WDT_TOV1, WDTCFG); 643 superio_outb(WDT_TOV1, WDTCFG);
@@ -620,21 +653,16 @@ static int __init it87_wdt_init(void)
620 } 653 }
621 gpact = superio_inb(ACTREG); 654 gpact = superio_inb(ACTREG);
622 superio_outb(0x01, ACTREG); 655 superio_outb(0x01, ACTREG);
623 superio_exit();
624 spin_unlock_irqrestore(&spinlock, flags);
625 if (request_region(base, 1, WATCHDOG_NAME)) 656 if (request_region(base, 1, WATCHDOG_NAME))
626 set_bit(WDTS_USE_GP, &wdt_status); 657 set_bit(WDTS_USE_GP, &wdt_status);
627 else 658 else
628 rc = -EIO; 659 gp_rreq_fail = 1;
629 } else {
630 superio_exit();
631 spin_unlock_irqrestore(&spinlock, flags);
632 } 660 }
633 661
634 /* If we haven't Gameport support, try to get CIR support */ 662 /* If we haven't Gameport support, try to get CIR support */
635 if (!test_bit(WDTS_USE_GP, &wdt_status)) { 663 if (!test_bit(WDTS_USE_GP, &wdt_status)) {
636 if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) { 664 if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) {
637 if (rc == -EIO) 665 if (gp_rreq_fail)
638 printk(KERN_ERR PFX 666 printk(KERN_ERR PFX
639 "I/O Address 0x%04x and 0x%04x" 667 "I/O Address 0x%04x and 0x%04x"
640 " already in use\n", base, CIR_BASE); 668 " already in use\n", base, CIR_BASE);
@@ -646,21 +674,16 @@ static int __init it87_wdt_init(void)
646 goto err_out; 674 goto err_out;
647 } 675 }
648 base = CIR_BASE; 676 base = CIR_BASE;
649 spin_lock_irqsave(&spinlock, flags);
650 superio_enter();
651 677
652 superio_select(CIR); 678 superio_select(CIR);
653 superio_outw(base, BASEREG); 679 superio_outw(base, BASEREG);
654 superio_outb(0x00, CIR_ILS); 680 superio_outb(0x00, CIR_ILS);
655 ciract = superio_inb(ACTREG); 681 ciract = superio_inb(ACTREG);
656 superio_outb(0x01, ACTREG); 682 superio_outb(0x01, ACTREG);
657 if (rc == -EIO) { 683 if (gp_rreq_fail) {
658 superio_select(GAMEPORT); 684 superio_select(GAMEPORT);
659 superio_outb(gpact, ACTREG); 685 superio_outb(gpact, ACTREG);
660 } 686 }
661
662 superio_exit();
663 spin_unlock_irqrestore(&spinlock, flags);
664 } 687 }
665 688
666 if (timeout < 1 || timeout > max_units * 60) { 689 if (timeout < 1 || timeout > max_units * 60) {
@@ -704,6 +727,7 @@ static int __init it87_wdt_init(void)
704 "nogameport=%d)\n", chip_type, chip_rev, timeout, 727 "nogameport=%d)\n", chip_type, chip_rev, timeout,
705 nowayout, testmode, exclusive, nogameport); 728 nowayout, testmode, exclusive, nogameport);
706 729
730 superio_exit();
707 return 0; 731 return 0;
708 732
709err_out_reboot: 733err_out_reboot:
@@ -711,49 +735,37 @@ err_out_reboot:
711err_out_region: 735err_out_region:
712 release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8); 736 release_region(base, test_bit(WDTS_USE_GP, &wdt_status) ? 1 : 8);
713 if (!test_bit(WDTS_USE_GP, &wdt_status)) { 737 if (!test_bit(WDTS_USE_GP, &wdt_status)) {
714 spin_lock_irqsave(&spinlock, flags);
715 superio_enter();
716 superio_select(CIR); 738 superio_select(CIR);
717 superio_outb(ciract, ACTREG); 739 superio_outb(ciract, ACTREG);
718 superio_exit();
719 spin_unlock_irqrestore(&spinlock, flags);
720 } 740 }
721err_out: 741err_out:
722 if (try_gameport) { 742 if (try_gameport) {
723 spin_lock_irqsave(&spinlock, flags);
724 superio_enter();
725 superio_select(GAMEPORT); 743 superio_select(GAMEPORT);
726 superio_outb(gpact, ACTREG); 744 superio_outb(gpact, ACTREG);
727 superio_exit();
728 spin_unlock_irqrestore(&spinlock, flags);
729 } 745 }
730 746
747 superio_exit();
731 return rc; 748 return rc;
732} 749}
733 750
734static void __exit it87_wdt_exit(void) 751static void __exit it87_wdt_exit(void)
735{ 752{
736 unsigned long flags; 753 if (superio_enter() == 0) {
737 int nolock; 754 superio_select(GPIO);
738 755 superio_outb(0x00, WDTCTRL);
739 nolock = !spin_trylock_irqsave(&spinlock, flags); 756 superio_outb(0x00, WDTCFG);
740 superio_enter(); 757 superio_outb(0x00, WDTVALLSB);
741 superio_select(GPIO); 758 if (max_units > 255)
742 superio_outb(0x00, WDTCTRL); 759 superio_outb(0x00, WDTVALMSB);
743 superio_outb(0x00, WDTCFG); 760 if (test_bit(WDTS_USE_GP, &wdt_status)) {
744 superio_outb(0x00, WDTVALLSB); 761 superio_select(GAMEPORT);
745 if (max_units > 255) 762 superio_outb(gpact, ACTREG);
746 superio_outb(0x00, WDTVALMSB); 763 } else {
747 if (test_bit(WDTS_USE_GP, &wdt_status)) { 764 superio_select(CIR);
748 superio_select(GAMEPORT); 765 superio_outb(ciract, ACTREG);
749 superio_outb(gpact, ACTREG); 766 }
750 } else { 767 superio_exit();
751 superio_select(CIR);
752 superio_outb(ciract, ACTREG);
753 } 768 }
754 superio_exit();
755 if (!nolock)
756 spin_unlock_irqrestore(&spinlock, flags);
757 769
758 misc_deregister(&wdt_miscdev); 770 misc_deregister(&wdt_miscdev);
759 unregister_reboot_notifier(&wdt_notifier); 771 unregister_reboot_notifier(&wdt_notifier);
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index 2b4af222b5f2..4dc31024d26c 100644
--- a/drivers/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -407,12 +407,35 @@ static int __devexit mpcore_wdt_remove(struct platform_device *dev)
407 return 0; 407 return 0;
408} 408}
409 409
410#ifdef CONFIG_PM
411static int mpcore_wdt_suspend(struct platform_device *dev, pm_message_t msg)
412{
413 struct mpcore_wdt *wdt = platform_get_drvdata(dev);
414 mpcore_wdt_stop(wdt); /* Turn the WDT off */
415 return 0;
416}
417
418static int mpcore_wdt_resume(struct platform_device *dev)
419{
420 struct mpcore_wdt *wdt = platform_get_drvdata(dev);
421 /* re-activate timer */
422 if (test_bit(0, &wdt->timer_alive))
423 mpcore_wdt_start(wdt);
424 return 0;
425}
426#else
427#define mpcore_wdt_suspend NULL
428#define mpcore_wdt_resume NULL
429#endif
430
410/* work with hotplug and coldplug */ 431/* work with hotplug and coldplug */
411MODULE_ALIAS("platform:mpcore_wdt"); 432MODULE_ALIAS("platform:mpcore_wdt");
412 433
413static struct platform_driver mpcore_wdt_driver = { 434static struct platform_driver mpcore_wdt_driver = {
414 .probe = mpcore_wdt_probe, 435 .probe = mpcore_wdt_probe,
415 .remove = __devexit_p(mpcore_wdt_remove), 436 .remove = __devexit_p(mpcore_wdt_remove),
437 .suspend = mpcore_wdt_suspend,
438 .resume = mpcore_wdt_resume,
416 .shutdown = mpcore_wdt_shutdown, 439 .shutdown = mpcore_wdt_shutdown,
417 .driver = { 440 .driver = {
418 .owner = THIS_MODULE, 441 .owner = THIS_MODULE,
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
index 0430e093b1a0..ac37bb82392c 100644
--- a/drivers/watchdog/mtx-1_wdt.c
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -225,11 +225,11 @@ static int __devinit mtx1_wdt_probe(struct platform_device *pdev)
225 225
226 ret = misc_register(&mtx1_wdt_misc); 226 ret = misc_register(&mtx1_wdt_misc);
227 if (ret < 0) { 227 if (ret < 0) {
228 printk(KERN_ERR " mtx-1_wdt : failed to register\n"); 228 dev_err(&pdev->dev, "failed to register\n");
229 return ret; 229 return ret;
230 } 230 }
231 mtx1_wdt_start(); 231 mtx1_wdt_start();
232 printk(KERN_INFO "MTX-1 Watchdog driver\n"); 232 dev_info(&pdev->dev, "MTX-1 Watchdog driver\n");
233 return 0; 233 return 0;
234} 234}
235 235
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
new file mode 100644
index 000000000000..4ec741ac952c
--- /dev/null
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -0,0 +1,433 @@
1/*
2* of_xilinx_wdt.c 1.01 A Watchdog Device Driver for Xilinx xps_timebase_wdt
3*
4* (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>)
5*
6* -----------------------
7*
8* This program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public License
10* as published by the Free Software Foundation; either version
11* 2 of the License, or (at your option) any later version.
12*
13* -----------------------
14* 30-May-2011 Alejandro Cabrera <aldaya@gmail.com>
15* - If "xlnx,wdt-enable-once" wasn't found on device tree the
16* module will use CONFIG_WATCHDOG_NOWAYOUT
17* - If the device tree parameters ("clock-frequency" and
18* "xlnx,wdt-interval") wasn't found the driver won't
19* know the wdt reset interval
20*/
21
22#include <linux/module.h>
23#include <linux/types.h>
24#include <linux/kernel.h>
25#include <linux/fs.h>
26#include <linux/miscdevice.h>
27#include <linux/init.h>
28#include <linux/ioport.h>
29#include <linux/watchdog.h>
30#include <linux/io.h>
31#include <linux/uaccess.h>
32#include <linux/of.h>
33#include <linux/of_device.h>
34#include <linux/of_address.h>
35
36/* Register offsets for the Wdt device */
37#define XWT_TWCSR0_OFFSET 0x0 /* Control/Status Register0 */
38#define XWT_TWCSR1_OFFSET 0x4 /* Control/Status Register1 */
39#define XWT_TBR_OFFSET 0x8 /* Timebase Register Offset */
40
41/* Control/Status Register Masks */
42#define XWT_CSR0_WRS_MASK 0x00000008 /* Reset status */
43#define XWT_CSR0_WDS_MASK 0x00000004 /* Timer state */
44#define XWT_CSR0_EWDT1_MASK 0x00000002 /* Enable bit 1 */
45
46/* Control/Status Register 0/1 bits */
47#define XWT_CSRX_EWDT2_MASK 0x00000001 /* Enable bit 2 */
48
49/* SelfTest constants */
50#define XWT_MAX_SELFTEST_LOOP_COUNT 0x00010000
51#define XWT_TIMER_FAILED 0xFFFFFFFF
52
53#define WATCHDOG_NAME "Xilinx Watchdog"
54#define PFX WATCHDOG_NAME ": "
55
56struct xwdt_device {
57 struct resource res;
58 void __iomem *base;
59 u32 nowayout;
60 u32 wdt_interval;
61 u32 boot_status;
62};
63
64static struct xwdt_device xdev;
65
66static u32 timeout;
67static u32 control_status_reg;
68static u8 expect_close;
69static u8 no_timeout;
70static unsigned long driver_open;
71
72static DEFINE_SPINLOCK(spinlock);
73
74static void xwdt_start(void)
75{
76 spin_lock(&spinlock);
77
78 /* Clean previous status and enable the watchdog timer */
79 control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
80 control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
81
82 iowrite32((control_status_reg | XWT_CSR0_EWDT1_MASK),
83 xdev.base + XWT_TWCSR0_OFFSET);
84
85 iowrite32(XWT_CSRX_EWDT2_MASK, xdev.base + XWT_TWCSR1_OFFSET);
86
87 spin_unlock(&spinlock);
88}
89
90static void xwdt_stop(void)
91{
92 spin_lock(&spinlock);
93
94 control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
95
96 iowrite32((control_status_reg & ~XWT_CSR0_EWDT1_MASK),
97 xdev.base + XWT_TWCSR0_OFFSET);
98
99 iowrite32(0, xdev.base + XWT_TWCSR1_OFFSET);
100
101 spin_unlock(&spinlock);
102 printk(KERN_INFO PFX "Stopped!\n");
103}
104
105static void xwdt_keepalive(void)
106{
107 spin_lock(&spinlock);
108
109 control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
110 control_status_reg |= (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK);
111 iowrite32(control_status_reg, xdev.base + XWT_TWCSR0_OFFSET);
112
113 spin_unlock(&spinlock);
114}
115
116static void xwdt_get_status(int *status)
117{
118 int new_status;
119
120 spin_lock(&spinlock);
121
122 control_status_reg = ioread32(xdev.base + XWT_TWCSR0_OFFSET);
123 new_status = ((control_status_reg &
124 (XWT_CSR0_WRS_MASK | XWT_CSR0_WDS_MASK)) != 0);
125 spin_unlock(&spinlock);
126
127 *status = 0;
128 if (new_status & 1)
129 *status |= WDIOF_CARDRESET;
130}
131
132static u32 xwdt_selftest(void)
133{
134 int i;
135 u32 timer_value1;
136 u32 timer_value2;
137
138 spin_lock(&spinlock);
139
140 timer_value1 = ioread32(xdev.base + XWT_TBR_OFFSET);
141 timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
142
143 for (i = 0;
144 ((i <= XWT_MAX_SELFTEST_LOOP_COUNT) &&
145 (timer_value2 == timer_value1)); i++) {
146 timer_value2 = ioread32(xdev.base + XWT_TBR_OFFSET);
147 }
148
149 spin_unlock(&spinlock);
150
151 if (timer_value2 != timer_value1)
152 return ~XWT_TIMER_FAILED;
153 else
154 return XWT_TIMER_FAILED;
155}
156
157static int xwdt_open(struct inode *inode, struct file *file)
158{
159 /* Only one process can handle the wdt at a time */
160 if (test_and_set_bit(0, &driver_open))
161 return -EBUSY;
162
163 /* Make sure that the module are always loaded...*/
164 if (xdev.nowayout)
165 __module_get(THIS_MODULE);
166
167 xwdt_start();
168 printk(KERN_INFO PFX "Started...\n");
169
170 return nonseekable_open(inode, file);
171}
172
173static int xwdt_release(struct inode *inode, struct file *file)
174{
175 if (expect_close == 42) {
176 xwdt_stop();
177 } else {
178 printk(KERN_CRIT PFX
179 "Unexpected close, not stopping watchdog!\n");
180 xwdt_keepalive();
181 }
182
183 clear_bit(0, &driver_open);
184 expect_close = 0;
185 return 0;
186}
187
188/*
189 * xwdt_write:
190 * @file: file handle to the watchdog
191 * @buf: buffer to write (unused as data does not matter here
192 * @count: count of bytes
193 * @ppos: pointer to the position to write. No seeks allowed
194 *
195 * A write to a watchdog device is defined as a keepalive signal. Any
196 * write of data will do, as we don't define content meaning.
197 */
198static ssize_t xwdt_write(struct file *file, const char __user *buf,
199 size_t len, loff_t *ppos)
200{
201 if (len) {
202 if (!xdev.nowayout) {
203 size_t i;
204
205 /* In case it was set long ago */
206 expect_close = 0;
207
208 for (i = 0; i != len; i++) {
209 char c;
210
211 if (get_user(c, buf + i))
212 return -EFAULT;
213 if (c == 'V')
214 expect_close = 42;
215 }
216 }
217 xwdt_keepalive();
218 }
219 return len;
220}
221
222static const struct watchdog_info ident = {
223 .options = WDIOF_MAGICCLOSE |
224 WDIOF_KEEPALIVEPING,
225 .firmware_version = 1,
226 .identity = WATCHDOG_NAME,
227};
228
229/*
230 * xwdt_ioctl:
231 * @file: file handle to the device
232 * @cmd: watchdog command
233 * @arg: argument pointer
234 *
235 * The watchdog API defines a common set of functions for all watchdogs
236 * according to their available features.
237 */
238static long xwdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
239{
240 int status;
241
242 union {
243 struct watchdog_info __user *ident;
244 int __user *i;
245 } uarg;
246
247 uarg.i = (int __user *)arg;
248
249 switch (cmd) {
250 case WDIOC_GETSUPPORT:
251 return copy_to_user(uarg.ident, &ident,
252 sizeof(ident)) ? -EFAULT : 0;
253
254 case WDIOC_GETBOOTSTATUS:
255 return put_user(xdev.boot_status, uarg.i);
256
257 case WDIOC_GETSTATUS:
258 xwdt_get_status(&status);
259 return put_user(status, uarg.i);
260
261 case WDIOC_KEEPALIVE:
262 xwdt_keepalive();
263 return 0;
264
265 case WDIOC_GETTIMEOUT:
266 if (no_timeout)
267 return -ENOTTY;
268 else
269 return put_user(timeout, uarg.i);
270
271 default:
272 return -ENOTTY;
273 }
274}
275
276static const struct file_operations xwdt_fops = {
277 .owner = THIS_MODULE,
278 .llseek = no_llseek,
279 .write = xwdt_write,
280 .open = xwdt_open,
281 .release = xwdt_release,
282 .unlocked_ioctl = xwdt_ioctl,
283};
284
285static struct miscdevice xwdt_miscdev = {
286 .minor = WATCHDOG_MINOR,
287 .name = "watchdog",
288 .fops = &xwdt_fops,
289};
290
291static int __devinit xwdt_probe(struct platform_device *pdev)
292{
293 int rc;
294 u32 *tmptr;
295 u32 *pfreq;
296
297 no_timeout = 0;
298
299 pfreq = (u32 *)of_get_property(pdev->dev.of_node->parent,
300 "clock-frequency", NULL);
301
302 if (pfreq == NULL) {
303 printk(KERN_WARNING PFX
304 "The watchdog clock frequency cannot be obtained!\n");
305 no_timeout = 1;
306 }
307
308 rc = of_address_to_resource(pdev->dev.of_node, 0, &xdev.res);
309 if (rc) {
310 printk(KERN_WARNING PFX "invalid address!\n");
311 return rc;
312 }
313
314 tmptr = (u32 *)of_get_property(pdev->dev.of_node,
315 "xlnx,wdt-interval", NULL);
316 if (tmptr == NULL) {
317 printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-interval\""
318 " not found in device tree!\n");
319 no_timeout = 1;
320 } else {
321 xdev.wdt_interval = *tmptr;
322 }
323
324 tmptr = (u32 *)of_get_property(pdev->dev.of_node,
325 "xlnx,wdt-enable-once", NULL);
326 if (tmptr == NULL) {
327 printk(KERN_WARNING PFX "Parameter \"xlnx,wdt-enable-once\""
328 " not found in device tree!\n");
329 xdev.nowayout = WATCHDOG_NOWAYOUT;
330 }
331
332/*
333 * Twice of the 2^wdt_interval / freq because the first wdt overflow is
334 * ignored (interrupt), reset is only generated at second wdt overflow
335 */
336 if (!no_timeout)
337 timeout = 2 * ((1<<xdev.wdt_interval) / *pfreq);
338
339 if (!request_mem_region(xdev.res.start,
340 xdev.res.end - xdev.res.start + 1, WATCHDOG_NAME)) {
341 rc = -ENXIO;
342 printk(KERN_ERR PFX "memory request failure!\n");
343 goto err_out;
344 }
345
346 xdev.base = ioremap(xdev.res.start, xdev.res.end - xdev.res.start + 1);
347 if (xdev.base == NULL) {
348 rc = -ENOMEM;
349 printk(KERN_ERR PFX "ioremap failure!\n");
350 goto release_mem;
351 }
352
353 rc = xwdt_selftest();
354 if (rc == XWT_TIMER_FAILED) {
355 printk(KERN_ERR PFX "SelfTest routine error!\n");
356 goto unmap_io;
357 }
358
359 xwdt_get_status(&xdev.boot_status);
360
361 rc = misc_register(&xwdt_miscdev);
362 if (rc) {
363 printk(KERN_ERR PFX
364 "cannot register miscdev on minor=%d (err=%d)\n",
365 xwdt_miscdev.minor, rc);
366 goto unmap_io;
367 }
368
369 if (no_timeout)
370 printk(KERN_INFO PFX
371 "driver loaded (timeout=? sec, nowayout=%d)\n",
372 xdev.nowayout);
373 else
374 printk(KERN_INFO PFX
375 "driver loaded (timeout=%d sec, nowayout=%d)\n",
376 timeout, xdev.nowayout);
377
378 expect_close = 0;
379 clear_bit(0, &driver_open);
380
381 return 0;
382
383unmap_io:
384 iounmap(xdev.base);
385release_mem:
386 release_mem_region(xdev.res.start, resource_size(&xdev.res));
387err_out:
388 return rc;
389}
390
391static int __devexit xwdt_remove(struct platform_device *dev)
392{
393 misc_deregister(&xwdt_miscdev);
394 iounmap(xdev.base);
395 release_mem_region(xdev.res.start, resource_size(&xdev.res));
396
397 return 0;
398}
399
400/* Match table for of_platform binding */
401static struct of_device_id __devinitdata xwdt_of_match[] = {
402 { .compatible = "xlnx,xps-timebase-wdt-1.01.a", },
403 {},
404};
405MODULE_DEVICE_TABLE(of, xwdt_of_match);
406
407static struct platform_driver xwdt_driver = {
408 .probe = xwdt_probe,
409 .remove = __devexit_p(xwdt_remove),
410 .driver = {
411 .owner = THIS_MODULE,
412 .name = WATCHDOG_NAME,
413 .of_match_table = xwdt_of_match,
414 },
415};
416
417static int __init xwdt_init(void)
418{
419 return platform_driver_register(&xwdt_driver);
420}
421
422static void __exit xwdt_exit(void)
423{
424 platform_driver_unregister(&xwdt_driver);
425}
426
427module_init(xwdt_init);
428module_exit(xwdt_exit);
429
430MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>");
431MODULE_DESCRIPTION("Xilinx Watchdog driver");
432MODULE_LICENSE("GPL");
433MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
index b7c139051575..e78d89986768 100644
--- a/drivers/watchdog/pc87413_wdt.c
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -56,6 +56,7 @@
56#define IO_DEFAULT 0x2E /* Address used on Portwell Boards */ 56#define IO_DEFAULT 0x2E /* Address used on Portwell Boards */
57 57
58static int io = IO_DEFAULT; 58static int io = IO_DEFAULT;
59static int swc_base_addr = -1;
59 60
60static int timeout = DEFAULT_TIMEOUT; /* timeout value */ 61static int timeout = DEFAULT_TIMEOUT; /* timeout value */
61static unsigned long timer_enabled; /* is the timer enabled? */ 62static unsigned long timer_enabled; /* is the timer enabled? */
@@ -116,9 +117,8 @@ static inline void pc87413_enable_swc(void)
116 117
117/* Read SWC I/O base address */ 118/* Read SWC I/O base address */
118 119
119static inline unsigned int pc87413_get_swc_base(void) 120static void pc87413_get_swc_base_addr(void)
120{ 121{
121 unsigned int swc_base_addr = 0;
122 unsigned char addr_l, addr_h = 0; 122 unsigned char addr_l, addr_h = 0;
123 123
124 /* Step 3: Read SWC I/O Base Address */ 124 /* Step 3: Read SWC I/O Base Address */
@@ -136,12 +136,11 @@ static inline unsigned int pc87413_get_swc_base(void)
136 "Read SWC I/O Base Address: low %d, high %d, res %d\n", 136 "Read SWC I/O Base Address: low %d, high %d, res %d\n",
137 addr_l, addr_h, swc_base_addr); 137 addr_l, addr_h, swc_base_addr);
138#endif 138#endif
139 return swc_base_addr;
140} 139}
141 140
142/* Select Bank 3 of SWC */ 141/* Select Bank 3 of SWC */
143 142
144static inline void pc87413_swc_bank3(unsigned int swc_base_addr) 143static inline void pc87413_swc_bank3(void)
145{ 144{
146 /* Step 4: Select Bank3 of SWC */ 145 /* Step 4: Select Bank3 of SWC */
147 outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f); 146 outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
@@ -152,8 +151,7 @@ static inline void pc87413_swc_bank3(unsigned int swc_base_addr)
152 151
153/* Set watchdog timeout to x minutes */ 152/* Set watchdog timeout to x minutes */
154 153
155static inline void pc87413_programm_wdto(unsigned int swc_base_addr, 154static inline void pc87413_programm_wdto(char pc87413_time)
156 char pc87413_time)
157{ 155{
158 /* Step 5: Programm WDTO, Twd. */ 156 /* Step 5: Programm WDTO, Twd. */
159 outb_p(pc87413_time, swc_base_addr + WDTO); 157 outb_p(pc87413_time, swc_base_addr + WDTO);
@@ -164,7 +162,7 @@ static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
164 162
165/* Enable WDEN */ 163/* Enable WDEN */
166 164
167static inline void pc87413_enable_wden(unsigned int swc_base_addr) 165static inline void pc87413_enable_wden(void)
168{ 166{
169 /* Step 6: Enable WDEN */ 167 /* Step 6: Enable WDEN */
170 outb_p(inb(swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL); 168 outb_p(inb(swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
@@ -174,7 +172,7 @@ static inline void pc87413_enable_wden(unsigned int swc_base_addr)
174} 172}
175 173
176/* Enable SW_WD_TREN */ 174/* Enable SW_WD_TREN */
177static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr) 175static inline void pc87413_enable_sw_wd_tren(void)
178{ 176{
179 /* Enable SW_WD_TREN */ 177 /* Enable SW_WD_TREN */
180 outb_p(inb(swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG); 178 outb_p(inb(swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
@@ -185,7 +183,7 @@ static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr)
185 183
186/* Disable SW_WD_TREN */ 184/* Disable SW_WD_TREN */
187 185
188static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr) 186static inline void pc87413_disable_sw_wd_tren(void)
189{ 187{
190 /* Disable SW_WD_TREN */ 188 /* Disable SW_WD_TREN */
191 outb_p(inb(swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG); 189 outb_p(inb(swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
@@ -196,7 +194,7 @@ static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr)
196 194
197/* Enable SW_WD_TRG */ 195/* Enable SW_WD_TRG */
198 196
199static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr) 197static inline void pc87413_enable_sw_wd_trg(void)
200{ 198{
201 /* Enable SW_WD_TRG */ 199 /* Enable SW_WD_TRG */
202 outb_p(inb(swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL); 200 outb_p(inb(swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
@@ -207,7 +205,7 @@ static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr)
207 205
208/* Disable SW_WD_TRG */ 206/* Disable SW_WD_TRG */
209 207
210static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr) 208static inline void pc87413_disable_sw_wd_trg(void)
211{ 209{
212 /* Disable SW_WD_TRG */ 210 /* Disable SW_WD_TRG */
213 outb_p(inb(swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL); 211 outb_p(inb(swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
@@ -222,18 +220,13 @@ static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr)
222 220
223static void pc87413_enable(void) 221static void pc87413_enable(void)
224{ 222{
225 unsigned int swc_base_addr;
226
227 spin_lock(&io_lock); 223 spin_lock(&io_lock);
228 224
229 pc87413_select_wdt_out(); 225 pc87413_swc_bank3();
230 pc87413_enable_swc(); 226 pc87413_programm_wdto(timeout);
231 swc_base_addr = pc87413_get_swc_base(); 227 pc87413_enable_wden();
232 pc87413_swc_bank3(swc_base_addr); 228 pc87413_enable_sw_wd_tren();
233 pc87413_programm_wdto(swc_base_addr, timeout); 229 pc87413_enable_sw_wd_trg();
234 pc87413_enable_wden(swc_base_addr);
235 pc87413_enable_sw_wd_tren(swc_base_addr);
236 pc87413_enable_sw_wd_trg(swc_base_addr);
237 230
238 spin_unlock(&io_lock); 231 spin_unlock(&io_lock);
239} 232}
@@ -242,17 +235,12 @@ static void pc87413_enable(void)
242 235
243static void pc87413_disable(void) 236static void pc87413_disable(void)
244{ 237{
245 unsigned int swc_base_addr;
246
247 spin_lock(&io_lock); 238 spin_lock(&io_lock);
248 239
249 pc87413_select_wdt_out(); 240 pc87413_swc_bank3();
250 pc87413_enable_swc(); 241 pc87413_disable_sw_wd_tren();
251 swc_base_addr = pc87413_get_swc_base(); 242 pc87413_disable_sw_wd_trg();
252 pc87413_swc_bank3(swc_base_addr); 243 pc87413_programm_wdto(0);
253 pc87413_disable_sw_wd_tren(swc_base_addr);
254 pc87413_disable_sw_wd_trg(swc_base_addr);
255 pc87413_programm_wdto(swc_base_addr, 0);
256 244
257 spin_unlock(&io_lock); 245 spin_unlock(&io_lock);
258} 246}
@@ -261,20 +249,15 @@ static void pc87413_disable(void)
261 249
262static void pc87413_refresh(void) 250static void pc87413_refresh(void)
263{ 251{
264 unsigned int swc_base_addr;
265
266 spin_lock(&io_lock); 252 spin_lock(&io_lock);
267 253
268 pc87413_select_wdt_out(); 254 pc87413_swc_bank3();
269 pc87413_enable_swc(); 255 pc87413_disable_sw_wd_tren();
270 swc_base_addr = pc87413_get_swc_base(); 256 pc87413_disable_sw_wd_trg();
271 pc87413_swc_bank3(swc_base_addr); 257 pc87413_programm_wdto(timeout);
272 pc87413_disable_sw_wd_tren(swc_base_addr); 258 pc87413_enable_wden();
273 pc87413_disable_sw_wd_trg(swc_base_addr); 259 pc87413_enable_sw_wd_tren();
274 pc87413_programm_wdto(swc_base_addr, timeout); 260 pc87413_enable_sw_wd_trg();
275 pc87413_enable_wden(swc_base_addr);
276 pc87413_enable_sw_wd_tren(swc_base_addr);
277 pc87413_enable_sw_wd_trg(swc_base_addr);
278 261
279 spin_unlock(&io_lock); 262 spin_unlock(&io_lock);
280} 263}
@@ -528,7 +511,8 @@ static int __init pc87413_init(void)
528 printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", 511 printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n",
529 WDT_INDEX_IO_PORT); 512 WDT_INDEX_IO_PORT);
530 513
531 /* request_region(io, 2, "pc87413"); */ 514 if (!request_muxed_region(io, 2, MODNAME))
515 return -EBUSY;
532 516
533 ret = register_reboot_notifier(&pc87413_notifier); 517 ret = register_reboot_notifier(&pc87413_notifier);
534 if (ret != 0) { 518 if (ret != 0) {
@@ -541,12 +525,32 @@ static int __init pc87413_init(void)
541 printk(KERN_ERR PFX 525 printk(KERN_ERR PFX
542 "cannot register miscdev on minor=%d (err=%d)\n", 526 "cannot register miscdev on minor=%d (err=%d)\n",
543 WATCHDOG_MINOR, ret); 527 WATCHDOG_MINOR, ret);
544 unregister_reboot_notifier(&pc87413_notifier); 528 goto reboot_unreg;
545 return ret;
546 } 529 }
547 printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout); 530 printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
531
532 pc87413_select_wdt_out();
533 pc87413_enable_swc();
534 pc87413_get_swc_base_addr();
535
536 if (!request_region(swc_base_addr, 0x20, MODNAME)) {
537 printk(KERN_ERR PFX
538 "cannot request SWC region at 0x%x\n", swc_base_addr);
539 ret = -EBUSY;
540 goto misc_unreg;
541 }
542
548 pc87413_enable(); 543 pc87413_enable();
544
545 release_region(io, 2);
549 return 0; 546 return 0;
547
548misc_unreg:
549 misc_deregister(&pc87413_miscdev);
550reboot_unreg:
551 unregister_reboot_notifier(&pc87413_notifier);
552 release_region(io, 2);
553 return ret;
550} 554}
551 555
552/** 556/**
@@ -569,7 +573,7 @@ static void __exit pc87413_exit(void)
569 573
570 misc_deregister(&pc87413_miscdev); 574 misc_deregister(&pc87413_miscdev);
571 unregister_reboot_notifier(&pc87413_notifier); 575 unregister_reboot_notifier(&pc87413_notifier);
572 /* release_region(io, 2); */ 576 release_region(swc_base_addr, 0x20);
573 577
574 printk(KERN_INFO MODNAME " watchdog component driver removed.\n"); 578 printk(KERN_INFO MODNAME " watchdog component driver removed.\n");
575} 579}
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index f7f5aa00df60..30da88f47cd3 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -589,6 +589,15 @@ static int s3c2410wdt_resume(struct platform_device *dev)
589#define s3c2410wdt_resume NULL 589#define s3c2410wdt_resume NULL
590#endif /* CONFIG_PM */ 590#endif /* CONFIG_PM */
591 591
592#ifdef CONFIG_OF
593static const struct of_device_id s3c2410_wdt_match[] = {
594 { .compatible = "samsung,s3c2410-wdt" },
595 {},
596};
597MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
598#else
599#define s3c2410_wdt_match NULL
600#endif
592 601
593static struct platform_driver s3c2410wdt_driver = { 602static struct platform_driver s3c2410wdt_driver = {
594 .probe = s3c2410wdt_probe, 603 .probe = s3c2410wdt_probe,
@@ -599,6 +608,7 @@ static struct platform_driver s3c2410wdt_driver = {
599 .driver = { 608 .driver = {
600 .owner = THIS_MODULE, 609 .owner = THIS_MODULE,
601 .name = "s3c2410-wdt", 610 .name = "s3c2410-wdt",
611 .of_match_table = s3c2410_wdt_match,
602 }, 612 },
603}; 613};
604 614
diff --git a/drivers/watchdog/sch311x_wdt.c b/drivers/watchdog/sch311x_wdt.c
index c7cf4b01f58d..029467e34636 100644
--- a/drivers/watchdog/sch311x_wdt.c
+++ b/drivers/watchdog/sch311x_wdt.c
@@ -472,15 +472,10 @@ static void sch311x_wdt_shutdown(struct platform_device *dev)
472 sch311x_wdt_stop(); 472 sch311x_wdt_stop();
473} 473}
474 474
475#define sch311x_wdt_suspend NULL
476#define sch311x_wdt_resume NULL
477
478static struct platform_driver sch311x_wdt_driver = { 475static struct platform_driver sch311x_wdt_driver = {
479 .probe = sch311x_wdt_probe, 476 .probe = sch311x_wdt_probe,
480 .remove = __devexit_p(sch311x_wdt_remove), 477 .remove = __devexit_p(sch311x_wdt_remove),
481 .shutdown = sch311x_wdt_shutdown, 478 .shutdown = sch311x_wdt_shutdown,
482 .suspend = sch311x_wdt_suspend,
483 .resume = sch311x_wdt_resume,
484 .driver = { 479 .driver = {
485 .owner = THIS_MODULE, 480 .owner = THIS_MODULE,
486 .name = DRV_NAME, 481 .name = DRV_NAME,
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 0d80e08b6439..cc2cfbe33b30 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -134,6 +134,8 @@ static void wdt_enable(void)
134 writel(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL); 134 writel(INT_ENABLE | RESET_ENABLE, wdt->base + WDTCONTROL);
135 writel(LOCK, wdt->base + WDTLOCK); 135 writel(LOCK, wdt->base + WDTLOCK);
136 136
137 /* Flush posted writes. */
138 readl(wdt->base + WDTLOCK);
137 spin_unlock(&wdt->lock); 139 spin_unlock(&wdt->lock);
138} 140}
139 141
@@ -144,9 +146,10 @@ static void wdt_disable(void)
144 146
145 writel(UNLOCK, wdt->base + WDTLOCK); 147 writel(UNLOCK, wdt->base + WDTLOCK);
146 writel(0, wdt->base + WDTCONTROL); 148 writel(0, wdt->base + WDTCONTROL);
147 writel(0, wdt->base + WDTLOAD);
148 writel(LOCK, wdt->base + WDTLOCK); 149 writel(LOCK, wdt->base + WDTLOCK);
149 150
151 /* Flush posted writes. */
152 readl(wdt->base + WDTLOCK);
150 spin_unlock(&wdt->lock); 153 spin_unlock(&wdt->lock);
151} 154}
152 155
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
new file mode 100644
index 000000000000..cfa1a1518aad
--- /dev/null
+++ b/drivers/watchdog/watchdog_core.c
@@ -0,0 +1,111 @@
1/*
2 * watchdog_core.c
3 *
4 * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>,
5 * All Rights Reserved.
6 *
7 * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
8 *
9 * This source code is part of the generic code that can be used
10 * by all the watchdog timer drivers.
11 *
12 * Based on source code of the following authors:
13 * Matt Domsch <Matt_Domsch@dell.com>,
14 * Rob Radez <rob@osinvestor.com>,
15 * Rusty Lynch <rusty@linux.co.intel.com>
16 * Satyam Sharma <satyam@infradead.org>
17 * Randy Dunlap <randy.dunlap@oracle.com>
18 *
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version
22 * 2 of the License, or (at your option) any later version.
23 *
24 * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
25 * admit liability nor provide warranty for any of this software.
26 * This material is provided "AS-IS" and at no charge.
27 */
28
29#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
31#include <linux/module.h> /* For EXPORT_SYMBOL/module stuff/... */
32#include <linux/types.h> /* For standard types */
33#include <linux/errno.h> /* For the -ENODEV/... values */
34#include <linux/kernel.h> /* For printk/panic/... */
35#include <linux/watchdog.h> /* For watchdog specific items */
36#include <linux/init.h> /* For __init/__exit/... */
37
38#include "watchdog_dev.h" /* For watchdog_dev_register/... */
39
40/**
41 * watchdog_register_device() - register a watchdog device
42 * @wdd: watchdog device
43 *
44 * Register a watchdog device with the kernel so that the
45 * watchdog timer can be accessed from userspace.
46 *
47 * A zero is returned on success and a negative errno code for
48 * failure.
49 */
50int watchdog_register_device(struct watchdog_device *wdd)
51{
52 int ret;
53
54 if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
55 return -EINVAL;
56
57 /* Mandatory operations need to be supported */
58 if (wdd->ops->start == NULL || wdd->ops->stop == NULL)
59 return -EINVAL;
60
61 /*
62 * Check that we have valid min and max timeout values, if
63 * not reset them both to 0 (=not used or unknown)
64 */
65 if (wdd->min_timeout > wdd->max_timeout) {
66 pr_info("Invalid min and max timeout values, resetting to 0!\n");
67 wdd->min_timeout = 0;
68 wdd->max_timeout = 0;
69 }
70
71 /*
72 * Note: now that all watchdog_device data has been verified, we
73 * will not check this anymore in other functions. If data gets
74 * corrupted in a later stage then we expect a kernel panic!
75 */
76
77 /* We only support 1 watchdog device via the /dev/watchdog interface */
78 ret = watchdog_dev_register(wdd);
79 if (ret) {
80 pr_err("error registering /dev/watchdog (err=%d).\n", ret);
81 return ret;
82 }
83
84 return 0;
85}
86EXPORT_SYMBOL_GPL(watchdog_register_device);
87
88/**
89 * watchdog_unregister_device() - unregister a watchdog device
90 * @wdd: watchdog device to unregister
91 *
92 * Unregister a watchdog device that was previously successfully
93 * registered with watchdog_register_device().
94 */
95void watchdog_unregister_device(struct watchdog_device *wdd)
96{
97 int ret;
98
99 if (wdd == NULL)
100 return;
101
102 ret = watchdog_dev_unregister(wdd);
103 if (ret)
104 pr_err("error unregistering /dev/watchdog (err=%d).\n", ret);
105}
106EXPORT_SYMBOL_GPL(watchdog_unregister_device);
107
108MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
109MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
110MODULE_DESCRIPTION("WatchDog Timer Driver Core");
111MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
new file mode 100644
index 000000000000..d33520d0b4c9
--- /dev/null
+++ b/drivers/watchdog/watchdog_dev.c
@@ -0,0 +1,395 @@
1/*
2 * watchdog_dev.c
3 *
4 * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>,
5 * All Rights Reserved.
6 *
7 * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
8 *
9 *
10 * This source code is part of the generic code that can be used
11 * by all the watchdog timer drivers.
12 *
13 * This part of the generic code takes care of the following
14 * misc device: /dev/watchdog.
15 *
16 * Based on source code of the following authors:
17 * Matt Domsch <Matt_Domsch@dell.com>,
18 * Rob Radez <rob@osinvestor.com>,
19 * Rusty Lynch <rusty@linux.co.intel.com>
20 * Satyam Sharma <satyam@infradead.org>
21 * Randy Dunlap <randy.dunlap@oracle.com>
22 *
23 * This program is free software; you can redistribute it and/or
24 * modify it under the terms of the GNU General Public License
25 * as published by the Free Software Foundation; either version
26 * 2 of the License, or (at your option) any later version.
27 *
28 * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
29 * admit liability nor provide warranty for any of this software.
30 * This material is provided "AS-IS" and at no charge.
31 */
32
33#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34
35#include <linux/module.h> /* For module stuff/... */
36#include <linux/types.h> /* For standard types (like size_t) */
37#include <linux/errno.h> /* For the -ENODEV/... values */
38#include <linux/kernel.h> /* For printk/panic/... */
39#include <linux/fs.h> /* For file operations */
40#include <linux/watchdog.h> /* For watchdog specific items */
41#include <linux/miscdevice.h> /* For handling misc devices */
42#include <linux/init.h> /* For __init/__exit/... */
43#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
44
45/* make sure we only register one /dev/watchdog device */
46static unsigned long watchdog_dev_busy;
47/* the watchdog device behind /dev/watchdog */
48static struct watchdog_device *wdd;
49
50/*
51 * watchdog_ping: ping the watchdog.
52 * @wddev: the watchdog device to ping
53 *
54 * If the watchdog has no own ping operation then it needs to be
55 * restarted via the start operation. This wrapper function does
56 * exactly that.
57 * We only ping when the watchdog device is running.
58 */
59
60static int watchdog_ping(struct watchdog_device *wddev)
61{
62 if (test_bit(WDOG_ACTIVE, &wdd->status)) {
63 if (wddev->ops->ping)
64 return wddev->ops->ping(wddev); /* ping the watchdog */
65 else
66 return wddev->ops->start(wddev); /* restart watchdog */
67 }
68 return 0;
69}
70
71/*
72 * watchdog_start: wrapper to start the watchdog.
73 * @wddev: the watchdog device to start
74 *
75 * Start the watchdog if it is not active and mark it active.
76 * This function returns zero on success or a negative errno code for
77 * failure.
78 */
79
80static int watchdog_start(struct watchdog_device *wddev)
81{
82 int err;
83
84 if (!test_bit(WDOG_ACTIVE, &wdd->status)) {
85 err = wddev->ops->start(wddev);
86 if (err < 0)
87 return err;
88
89 set_bit(WDOG_ACTIVE, &wdd->status);
90 }
91 return 0;
92}
93
94/*
95 * watchdog_stop: wrapper to stop the watchdog.
96 * @wddev: the watchdog device to stop
97 *
98 * Stop the watchdog if it is still active and unmark it active.
99 * This function returns zero on success or a negative errno code for
100 * failure.
101 * If the 'nowayout' feature was set, the watchdog cannot be stopped.
102 */
103
104static int watchdog_stop(struct watchdog_device *wddev)
105{
106 int err = -EBUSY;
107
108 if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) {
109 pr_info("%s: nowayout prevents watchdog to be stopped!\n",
110 wdd->info->identity);
111 return err;
112 }
113
114 if (test_bit(WDOG_ACTIVE, &wdd->status)) {
115 err = wddev->ops->stop(wddev);
116 if (err < 0)
117 return err;
118
119 clear_bit(WDOG_ACTIVE, &wdd->status);
120 }
121 return 0;
122}
123
124/*
125 * watchdog_write: writes to the watchdog.
126 * @file: file from VFS
127 * @data: user address of data
128 * @len: length of data
129 * @ppos: pointer to the file offset
130 *
131 * A write to a watchdog device is defined as a keepalive ping.
132 * Writing the magic 'V' sequence allows the next close to turn
133 * off the watchdog (if 'nowayout' is not set).
134 */
135
136static ssize_t watchdog_write(struct file *file, const char __user *data,
137 size_t len, loff_t *ppos)
138{
139 size_t i;
140 char c;
141
142 if (len == 0)
143 return 0;
144
145 /*
146 * Note: just in case someone wrote the magic character
147 * five months ago...
148 */
149 clear_bit(WDOG_ALLOW_RELEASE, &wdd->status);
150
151 /* scan to see whether or not we got the magic character */
152 for (i = 0; i != len; i++) {
153 if (get_user(c, data + i))
154 return -EFAULT;
155 if (c == 'V')
156 set_bit(WDOG_ALLOW_RELEASE, &wdd->status);
157 }
158
159 /* someone wrote to us, so we send the watchdog a keepalive ping */
160 watchdog_ping(wdd);
161
162 return len;
163}
164
165/*
166 * watchdog_ioctl: handle the different ioctl's for the watchdog device.
167 * @file: file handle to the device
168 * @cmd: watchdog command
169 * @arg: argument pointer
170 *
171 * The watchdog API defines a common set of functions for all watchdogs
172 * according to their available features.
173 */
174
175static long watchdog_ioctl(struct file *file, unsigned int cmd,
176 unsigned long arg)
177{
178 void __user *argp = (void __user *)arg;
179 int __user *p = argp;
180 unsigned int val;
181 int err;
182
183 if (wdd->ops->ioctl) {
184 err = wdd->ops->ioctl(wdd, cmd, arg);
185 if (err != -ENOIOCTLCMD)
186 return err;
187 }
188
189 switch (cmd) {
190 case WDIOC_GETSUPPORT:
191 return copy_to_user(argp, wdd->info,
192 sizeof(struct watchdog_info)) ? -EFAULT : 0;
193 case WDIOC_GETSTATUS:
194 val = wdd->ops->status ? wdd->ops->status(wdd) : 0;
195 return put_user(val, p);
196 case WDIOC_GETBOOTSTATUS:
197 return put_user(wdd->bootstatus, p);
198 case WDIOC_SETOPTIONS:
199 if (get_user(val, p))
200 return -EFAULT;
201 if (val & WDIOS_DISABLECARD) {
202 err = watchdog_stop(wdd);
203 if (err < 0)
204 return err;
205 }
206 if (val & WDIOS_ENABLECARD) {
207 err = watchdog_start(wdd);
208 if (err < 0)
209 return err;
210 }
211 return 0;
212 case WDIOC_KEEPALIVE:
213 if (!(wdd->info->options & WDIOF_KEEPALIVEPING))
214 return -EOPNOTSUPP;
215 watchdog_ping(wdd);
216 return 0;
217 case WDIOC_SETTIMEOUT:
218 if ((wdd->ops->set_timeout == NULL) ||
219 !(wdd->info->options & WDIOF_SETTIMEOUT))
220 return -EOPNOTSUPP;
221 if (get_user(val, p))
222 return -EFAULT;
223 if ((wdd->max_timeout != 0) &&
224 (val < wdd->min_timeout || val > wdd->max_timeout))
225 return -EINVAL;
226 err = wdd->ops->set_timeout(wdd, val);
227 if (err < 0)
228 return err;
229 wdd->timeout = val;
230 /* If the watchdog is active then we send a keepalive ping
231 * to make sure that the watchdog keep's running (and if
232 * possible that it takes the new timeout) */
233 watchdog_ping(wdd);
234 /* Fall */
235 case WDIOC_GETTIMEOUT:
236 /* timeout == 0 means that we don't know the timeout */
237 if (wdd->timeout == 0)
238 return -EOPNOTSUPP;
239 return put_user(wdd->timeout, p);
240 default:
241 return -ENOTTY;
242 }
243}
244
245/*
246 * watchdog_open: open the /dev/watchdog device.
247 * @inode: inode of device
248 * @file: file handle to device
249 *
250 * When the /dev/watchdog device gets opened, we start the watchdog.
251 * Watch out: the /dev/watchdog device is single open, so we make sure
252 * it can only be opened once.
253 */
254
255static int watchdog_open(struct inode *inode, struct file *file)
256{
257 int err = -EBUSY;
258
259 /* the watchdog is single open! */
260 if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status))
261 return -EBUSY;
262
263 /*
264 * If the /dev/watchdog device is open, we don't want the module
265 * to be unloaded.
266 */
267 if (!try_module_get(wdd->ops->owner))
268 goto out;
269
270 err = watchdog_start(wdd);
271 if (err < 0)
272 goto out_mod;
273
274 /* dev/watchdog is a virtual (and thus non-seekable) filesystem */
275 return nonseekable_open(inode, file);
276
277out_mod:
278 module_put(wdd->ops->owner);
279out:
280 clear_bit(WDOG_DEV_OPEN, &wdd->status);
281 return err;
282}
283
284/*
285 * watchdog_release: release the /dev/watchdog device.
286 * @inode: inode of device
287 * @file: file handle to device
288 *
289 * This is the code for when /dev/watchdog gets closed. We will only
290 * stop the watchdog when we have received the magic char (and nowayout
291 * was not set), else the watchdog will keep running.
292 */
293
294static int watchdog_release(struct inode *inode, struct file *file)
295{
296 int err = -EBUSY;
297
298 /*
299 * We only stop the watchdog if we received the magic character
300 * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then
301 * watchdog_stop will fail.
302 */
303 if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) ||
304 !(wdd->info->options & WDIOF_MAGICCLOSE))
305 err = watchdog_stop(wdd);
306
307 /* If the watchdog was not stopped, send a keepalive ping */
308 if (err < 0) {
309 pr_crit("%s: watchdog did not stop!\n", wdd->info->identity);
310 watchdog_ping(wdd);
311 }
312
313 /* Allow the owner module to be unloaded again */
314 module_put(wdd->ops->owner);
315
316 /* make sure that /dev/watchdog can be re-opened */
317 clear_bit(WDOG_DEV_OPEN, &wdd->status);
318
319 return 0;
320}
321
322static const struct file_operations watchdog_fops = {
323 .owner = THIS_MODULE,
324 .write = watchdog_write,
325 .unlocked_ioctl = watchdog_ioctl,
326 .open = watchdog_open,
327 .release = watchdog_release,
328};
329
330static struct miscdevice watchdog_miscdev = {
331 .minor = WATCHDOG_MINOR,
332 .name = "watchdog",
333 .fops = &watchdog_fops,
334};
335
336/*
337 * watchdog_dev_register:
338 * @watchdog: watchdog device
339 *
340 * Register a watchdog device as /dev/watchdog. /dev/watchdog
341 * is actually a miscdevice and thus we set it up like that.
342 */
343
344int watchdog_dev_register(struct watchdog_device *watchdog)
345{
346 int err;
347
348 /* Only one device can register for /dev/watchdog */
349 if (test_and_set_bit(0, &watchdog_dev_busy)) {
350 pr_err("only one watchdog can use /dev/watchdog.\n");
351 return -EBUSY;
352 }
353
354 wdd = watchdog;
355
356 err = misc_register(&watchdog_miscdev);
357 if (err != 0) {
358 pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
359 watchdog->info->identity, WATCHDOG_MINOR, err);
360 goto out;
361 }
362
363 return 0;
364
365out:
366 wdd = NULL;
367 clear_bit(0, &watchdog_dev_busy);
368 return err;
369}
370
371/*
372 * watchdog_dev_unregister:
373 * @watchdog: watchdog device
374 *
375 * Deregister the /dev/watchdog device.
376 */
377
378int watchdog_dev_unregister(struct watchdog_device *watchdog)
379{
380 /* Check that a watchdog device was registered in the past */
381 if (!test_bit(0, &watchdog_dev_busy) || !wdd)
382 return -ENODEV;
383
384 /* We can only unregister the watchdog device that was registered */
385 if (watchdog != wdd) {
386 pr_err("%s: watchdog was not registered as /dev/watchdog.\n",
387 watchdog->info->identity);
388 return -ENODEV;
389 }
390
391 misc_deregister(&watchdog_miscdev);
392 wdd = NULL;
393 clear_bit(0, &watchdog_dev_busy);
394 return 0;
395}
diff --git a/drivers/watchdog/watchdog_dev.h b/drivers/watchdog/watchdog_dev.h
new file mode 100644
index 000000000000..bc7612be25ce
--- /dev/null
+++ b/drivers/watchdog/watchdog_dev.h
@@ -0,0 +1,33 @@
1/*
2 * watchdog_core.h
3 *
4 * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>,
5 * All Rights Reserved.
6 *
7 * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>.
8 *
9 * This source code is part of the generic code that can be used
10 * by all the watchdog timer drivers.
11 *
12 * Based on source code of the following authors:
13 * Matt Domsch <Matt_Domsch@dell.com>,
14 * Rob Radez <rob@osinvestor.com>,
15 * Rusty Lynch <rusty@linux.co.intel.com>
16 * Satyam Sharma <satyam@infradead.org>
17 * Randy Dunlap <randy.dunlap@oracle.com>
18 *
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version
22 * 2 of the License, or (at your option) any later version.
23 *
24 * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw.
25 * admit liability nor provide warranty for any of this software.
26 * This material is provided "AS-IS" and at no charge.
27 */
28
29/*
30 * Functions/procedures to be called by the core
31 */
32int watchdog_dev_register(struct watchdog_device *);
33int watchdog_dev_unregister(struct watchdog_device *);