summaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/watchdog')
-rw-r--r--drivers/char/watchdog/Kconfig133
-rw-r--r--drivers/char/watchdog/Makefile44
-rw-r--r--drivers/char/watchdog/alim1535_wdt.c7
-rw-r--r--drivers/char/watchdog/bfin_wdt.c490
-rw-r--r--drivers/char/watchdog/booke_wdt.c2
-rw-r--r--drivers/char/watchdog/cpu5wdt.c4
-rw-r--r--drivers/char/watchdog/davinci_wdt.c281
-rw-r--r--drivers/char/watchdog/eurotechwdt.c13
-rw-r--r--drivers/char/watchdog/iTCO_wdt.c38
-rw-r--r--drivers/char/watchdog/iop_wdt.c262
-rw-r--r--drivers/char/watchdog/machzwd.c1
-rw-r--r--drivers/char/watchdog/mixcomwd.c5
-rw-r--r--drivers/char/watchdog/mpc5200_wdt.c286
-rw-r--r--drivers/char/watchdog/mpc83xx_wdt.c3
-rw-r--r--drivers/char/watchdog/mpc8xx_wdt.c2
-rw-r--r--drivers/char/watchdog/mpcore_wdt.c3
-rw-r--r--drivers/char/watchdog/mtx-1_wdt.c1
-rw-r--r--drivers/char/watchdog/mv64x60_wdt.c218
-rw-r--r--drivers/char/watchdog/omap_wdt.c4
-rw-r--r--drivers/char/watchdog/pcwd_usb.c3
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c6
-rw-r--r--drivers/char/watchdog/sa1100_wdt.c3
-rw-r--r--drivers/char/watchdog/sbc60xxwdt.c4
-rw-r--r--drivers/char/watchdog/sc1200wdt.c4
-rw-r--r--drivers/char/watchdog/sc520_wdt.c4
-rw-r--r--drivers/char/watchdog/w83627hf_wdt.c24
26 files changed, 1688 insertions, 157 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 2f48ba32996..37bddc1802d 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -55,6 +55,8 @@ config SOFT_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called softdog.
+# ALPHA Architecture
+
# ARM Architecture
config AT91RM9200_WATCHDOG
@@ -187,15 +189,64 @@ config PNX4008_WATCHDOG
Say N if you are unsure.
+config IOP_WATCHDOG
+ tristate "IOP Watchdog"
+ depends on PLAT_IOP
+ select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
+ help
+ Say Y here if to include support for the watchdog timer
+ in the Intel IOP3XX & IOP13XX I/O Processors. This driver can
+ be built as a module by choosing M. The module will
+ be called iop_wdt.
+
+ Note: The IOP13XX watchdog does an Internal Bus Reset which will
+ affect both cores and the peripherals of the IOP. The ATU-X
+ and/or ATUe configuration registers will remain intact, but if
+ operating as an Root Complex and/or Central Resource, the PCI-X
+ and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER.
+
+config DAVINCI_WATCHDOG
+ tristate "DaVinci watchdog"
+ depends on ARCH_DAVINCI
+ help
+ Say Y here if to include support for the watchdog timer
+ in the DaVinci DM644x/DM646x processors.
+ To compile this driver as a module, choose M here: the
+ module will be called davinci_wdt.
+
+ NOTE: once enabled, this timer cannot be disabled.
+ Say N if you are unsure.
+
+# ARM26 Architecture
+
# AVR32 Architecture
config AT32AP700X_WDT
tristate "AT32AP700x watchdog"
- depends on WATCHDOG && CPU_AT32AP7000
+ depends on CPU_AT32AP7000
help
Watchdog timer embedded into AT32AP700x devices. This will reboot
your system when the timeout is reached.
+# BLACKFIN Architecture
+
+config BFIN_WDT
+ tristate "Blackfin On-Chip Watchdog Timer"
+ depends on BLACKFIN
+ ---help---
+ If you say yes here you will get support for the Blackfin On-Chip
+ Watchdog Timer. If you have one of these processors and wish to
+ have watchdog support enabled, say Y, otherwise say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bfin_wdt.
+
+# CRIS Architecture
+
+# FRV Architecture
+
+# H8300 Architecture
+
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
@@ -524,37 +575,11 @@ config SBC_EPX_C3_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called sbc_epx_c3.
-# PowerPC Architecture
-
-config 8xx_WDT
- tristate "MPC8xx Watchdog Timer"
- depends on 8xx
-
-config 83xx_WDT
- tristate "MPC83xx Watchdog Timer"
- depends on PPC_83xx
-
-config MV64X60_WDT
- tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
- depends on MV64X60
-
-config BOOKE_WDT
- bool "PowerPC Book-E Watchdog Timer"
- depends on BOOKE || 4xx
- ---help---
- Please see Documentation/watchdog/watchdog-api.txt for
- more information.
-
-# PPC64 Architecture
+# M32R Architecture
-config WATCHDOG_RTAS
- tristate "RTAS watchdog"
- depends on PPC_RTAS
- help
- This driver adds watchdog support for the RTAS watchdog.
+# M68K Architecture
- To compile this driver as a module, choose M here. The module
- will be called wdrtas.
+# M68KNOMMU Architecture
# MIPS Architecture
@@ -584,6 +609,44 @@ config WDT_RM9K_GPI
To compile this driver as a module, choose M here: the
module will be called rm9k_wdt.
+# PARISC Architecture
+
+# POWERPC Architecture
+
+config MPC5200_WDT
+ tristate "MPC5200 Watchdog Timer"
+ depends on PPC_MPC52xx
+
+config 8xx_WDT
+ tristate "MPC8xx Watchdog Timer"
+ depends on 8xx
+
+config 83xx_WDT
+ tristate "MPC83xx Watchdog Timer"
+ depends on PPC_83xx
+
+config MV64X60_WDT
+ tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
+ depends on MV64X60
+
+config BOOKE_WDT
+ bool "PowerPC Book-E Watchdog Timer"
+ depends on BOOKE || 4xx
+ ---help---
+ Please see Documentation/watchdog/watchdog-api.txt for
+ more information.
+
+# PPC64 Architecture
+
+config WATCHDOG_RTAS
+ tristate "RTAS watchdog"
+ depends on PPC_RTAS
+ help
+ This driver adds watchdog support for the RTAS watchdog.
+
+ To compile this driver as a module, choose M here. The module
+ will be called wdrtas.
+
# S390 Architecture
config ZVM_WATCHDOG
@@ -598,11 +661,11 @@ config ZVM_WATCHDOG
To compile this driver as a module, choose M here. The module
will be called vmwatchdog.
-# SUPERH Architecture
+# SUPERH (sh + sh64) Architecture
config SH_WDT
tristate "SuperH Watchdog"
- depends on SUPERH
+ depends on SUPERH && (CPU_SH3 || CPU_SH4)
help
This driver adds watchdog support for the integrated watchdog in the
SuperH processors. If you have one of these processors and wish
@@ -625,6 +688,8 @@ config SH_WDT_MMAP
If you say Y here, user applications will be able to mmap the
WDT/CPG registers.
+# SPARC Architecture
+
# SPARC64 Architecture
config WATCHDOG_CP1XXX
@@ -649,6 +714,10 @@ config WATCHDOG_RIO
machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter.
+# V850 Architecture
+
+# XTENSA Architecture
+
#
# ISA-based Watchdog Cards
#
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 3907ec04a4e..389f8b14ccc 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -22,6 +22,8 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o
# USB-based Watchdog Cards
obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
+# ALPHA Architecture
+
# ARM Architecture
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
@@ -35,10 +37,23 @@ obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
+obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
+obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
+
+# ARM26 Architecture
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
+# BLACKFIN Architecture
+obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o
+
+# CRIS Architecture
+
+# FRV Architecture
+
+# H8300 Architecture
+
# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
@@ -65,8 +80,22 @@ obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
-# PowerPC Architecture
+# M32R Architecture
+
+# M68K Architecture
+
+# M68KNOMMU Architecture
+
+# MIPS Architecture
+obj-$(CONFIG_INDYDOG) += indydog.o
+obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
+obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
+
+# PARISC Architecture
+
+# POWERPC Architecture
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
+obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
@@ -74,17 +103,18 @@ obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
# PPC64 Architecture
obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
-# MIPS Architecture
-obj-$(CONFIG_INDYDOG) += indydog.o
-obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
-obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
-
# S390 Architecture
-# SUPERH Architecture
+# SUPERH (sh + sh64) Architecture
obj-$(CONFIG_SH_WDT) += shwdt.o
+# SPARC Architecture
+
# SPARC64 Architecture
+# V850 Architecture
+
+# XTENSA Architecture
+
# Architecture Independant
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
index e3f6a7d0c83..c404fc69e7e 100644
--- a/drivers/char/watchdog/alim1535_wdt.c
+++ b/drivers/char/watchdog/alim1535_wdt.c
@@ -312,6 +312,7 @@ static int ali_notify_sys(struct notifier_block *this, unsigned long code, void
*/
static struct pci_device_id ali_pci_tbl[] = {
+ { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
{ PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
{ 0, },
};
@@ -329,9 +330,11 @@ static int __init ali_find_watchdog(void)
struct pci_dev *pdev;
u32 wdog;
- /* Check for a 1535 series bridge */
+ /* Check for a 1533/1535 series bridge */
pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
- if(pdev == NULL)
+ if (pdev == NULL)
+ pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1533, NULL);
+ if (pdev == NULL)
return -ENODEV;
pci_dev_put(pdev);
diff --git a/drivers/char/watchdog/bfin_wdt.c b/drivers/char/watchdog/bfin_wdt.c
new file mode 100644
index 00000000000..309d27913fc
--- /dev/null
+++ b/drivers/char/watchdog/bfin_wdt.c
@@ -0,0 +1,490 @@
+/*
+ * Blackfin On-Chip Watchdog Driver
+ * Supports BF53[123]/BF53[467]/BF54[2489]/BF561
+ *
+ * Originally based on softdog.c
+ * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2007 Michele d'Amico
+ * Copyright 1996 Alan Cox <alan@redhat.com>
+ *
+ * Enter bugs at http://blackfin.uclinux.org/
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/timer.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/blackfin.h>
+#include <asm/uaccess.h>
+
+#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
+#define stampit() stamp("here i am")
+
+#define WATCHDOG_NAME "bfin-wdt"
+#define PFX WATCHDOG_NAME ": "
+
+/* The BF561 has two watchdogs (one per core), but since Linux
+ * only runs on core A, we'll just work with that one.
+ */
+#ifdef BF561_FAMILY
+# define bfin_read_WDOG_CTL() bfin_read_WDOGA_CTL()
+# define bfin_read_WDOG_CNT() bfin_read_WDOGA_CNT()
+# define bfin_read_WDOG_STAT() bfin_read_WDOGA_STAT()
+# define bfin_write_WDOG_CTL(x) bfin_write_WDOGA_CTL(x)
+# define bfin_write_WDOG_CNT(x) bfin_write_WDOGA_CNT(x)
+# define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x)
+#endif
+
+/* Bit in SWRST that indicates boot caused by watchdog */
+#define SWRST_RESET_WDOG 0x4000
+
+/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */
+#define WDOG_EXPIRED 0x8000
+
+/* Masks for WDEV field in WDOG_CTL register */
+#define ICTL_RESET 0x0
+#define ICTL_NMI 0x2
+#define ICTL_GPI 0x4
+#define ICTL_NONE 0x6
+#define ICTL_MASK 0x6
+
+/* Masks for WDEN field in WDOG_CTL register */
+#define WDEN_MASK 0x0FF0
+#define WDEN_ENABLE 0x0000
+#define WDEN_DISABLE 0x0AD0
+
+/* some defaults */
+#define WATCHDOG_TIMEOUT 20
+
+static unsigned int timeout = WATCHDOG_TIMEOUT;
+static int nowayout = WATCHDOG_NOWAYOUT;
+static struct watchdog_info bfin_wdt_info;
+static unsigned long open_check;
+static char expect_close;
+static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED;
+
+/**
+ * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
+ *
+ * The Userspace watchdog got a KeepAlive: schedule the next timeout.
+ */
+static int bfin_wdt_keepalive(void)
+{
+ stampit();
+ bfin_write_WDOG_STAT(0);
+ return 0;
+}
+
+/**
+ * bfin_wdt_stop - Stop the Watchdog
+ *
+ * Stops the on-chip watchdog.
+ */
+static int bfin_wdt_stop(void)
+{
+ stampit();
+ bfin_write_WDOG_CTL(WDEN_DISABLE);
+ return 0;
+}
+
+/**
+ * bfin_wdt_start - Start the Watchdog
+ *
+ * Starts the on-chip watchdog. Automatically loads WDOG_CNT
+ * into WDOG_STAT for us.
+ */
+static int bfin_wdt_start(void)
+{
+ stampit();
+ bfin_write_WDOG_CTL(WDEN_ENABLE | ICTL_RESET);
+ return 0;
+}
+
+/**
+ * bfin_wdt_running - Check Watchdog status
+ *
+ * See if the watchdog is running.
+ */
+static int bfin_wdt_running(void)
+{
+ stampit();
+ return ((bfin_read_WDOG_CTL() & WDEN_MASK) != WDEN_DISABLE);
+}
+
+/**
+ * bfin_wdt_set_timeout - Set the Userspace Watchdog timeout
+ * @t: new timeout value (in seconds)
+ *
+ * Translate the specified timeout in seconds into System Clock
+ * terms which is what the on-chip Watchdog requires.
+ */
+static int bfin_wdt_set_timeout(unsigned long t)
+{
+ u32 cnt;
+ unsigned long flags;
+
+ stampit();
+
+ cnt = t * get_sclk();
+ if (cnt < get_sclk()) {
+ printk(KERN_WARNING PFX "timeout value is too large\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&bfin_wdt_spinlock, flags);
+ {
+ int run = bfin_wdt_running();
+ bfin_wdt_stop();
+ bfin_write_WDOG_CNT(cnt);
+ if (run) bfin_wdt_start();
+ }
+ spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
+
+ timeout = t;
+
+ return 0;
+}
+
+/**
+ * bfin_wdt_open - Open the Device
+ * @inode: inode of device
+ * @file: file handle of device
+ *
+ * Watchdog device is opened and started.
+ */
+static int bfin_wdt_open(struct inode *inode, struct file *file)
+{
+ stampit();
+
+ if (test_and_set_bit(0, &open_check))
+ return -EBUSY;
+
+ if (nowayout)
+ __module_get(THIS_MODULE);
+
+ bfin_wdt_keepalive();
+ bfin_wdt_start();
+
+ return nonseekable_open(inode, file);
+}
+
+/**
+ * bfin_wdt_close - Close the Device
+ * @inode: inode of device
+ * @file: file handle of device
+ *
+ * Watchdog device is closed and stopped.
+ */
+static int bfin_wdt_release(struct inode *inode, struct file *file)
+{
+ stampit();
+
+ if (expect_close == 42) {
+ bfin_wdt_stop();
+ } else {
+ printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ bfin_wdt_keepalive();
+ }
+
+ expect_close = 0;
+ clear_bit(0, &open_check);
+
+ return 0;
+}
+
+/**
+ * bfin_wdt_write - Write to Device
+ * @file: file handle of device
+ * @buf: buffer to write
+ * @count: length of buffer
+ * @ppos: offset
+ *
+ * Pings the watchdog on write.
+ */
+static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ stampit();
+
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* In case it was set long ago */
+ expect_close = 0;
+
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
+ bfin_wdt_keepalive();
+ }
+
+ return len;
+}
+
+/**
+ * bfin_wdt_ioctl - Query Device
+ * @inode: inode of device
+ * @file: file handle of device
+ * @cmd: watchdog command
+ * @arg: argument
+ *
+ * Query basic information from the device or ping it, as outlined by the
+ * watchdog API.
+ */
+static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+
+ stampit();
+
+ switch (cmd) {
+ default:
+ return -ENOTTY;
+
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
+ return -EFAULT;
+ else
+ return 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
+
+ case WDIOC_KEEPALIVE:
+ bfin_wdt_keepalive();
+ return 0;
+
+ case WDIOC_SETTIMEOUT: {
+ int new_timeout;
+
+ if (get_user(new_timeout, p))
+ return -EFAULT;
+
+ if (bfin_wdt_set_timeout(new_timeout))
+ return -EINVAL;
+ }
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timeout, p);
+
+ case WDIOC_SETOPTIONS: {
+ unsigned long flags;
+ int options, ret = -EINVAL;
+
+ if (get_user(options, p))
+ return -EFAULT;
+
+ spin_lock_irqsave(&bfin_wdt_spinlock, flags);
+
+ if (options & WDIOS_DISABLECARD) {
+ bfin_wdt_stop();
+ ret = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ bfin_wdt_start();
+ ret = 0;
+ }
+
+ spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
+
+ return ret;
+ }
+ }
+}
+
+/**
+ * bfin_wdt_notify_sys - Notifier Handler
+ * @this: notifier block
+ * @code: notifier event
+ * @unused: unused
+ *
+ * Handles specific events, such as turning off the watchdog during a
+ * shutdown event.
+ */
+static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code,
+ void *unused)
+{
+ stampit();
+
+ if (code == SYS_DOWN || code == SYS_HALT)
+ bfin_wdt_stop();
+
+ return NOTIFY_DONE;
+}
+
+#ifdef CONFIG_PM
+static int state_before_suspend;
+
+/**
+ * bfin_wdt_suspend - suspend the watchdog
+ * @pdev: device being suspended
+ * @state: requested suspend state
+ *
+ * Remember if the watchdog was running and stop it.
+ * TODO: is this even right? Doesn't seem to be any
+ * standard in the watchdog world ...
+ */
+static int bfin_wdt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ stampit();
+
+ state_before_suspend = bfin_wdt_running();
+ bfin_wdt_stop();
+
+ return 0;
+}
+
+/**
+ * bfin_wdt_resume - resume the watchdog
+ * @pdev: device being resumed
+ *
+ * If the watchdog was running, turn it back on.
+ */
+static int bfin_wdt_resume(struct platform_device *pdev)
+{
+ stampit();
+
+ if (state_before_suspend) {
+ bfin_wdt_set_timeout(timeout);
+ bfin_wdt_start();
+ }
+
+ return 0;
+}
+#else
+# define bfin_wdt_suspend NULL
+# define bfin_wdt_resume NULL
+#endif
+
+static struct platform_device bfin_wdt_device = {
+ .name = WATCHDOG_NAME,
+ .id = -1,
+};
+
+static struct platform_driver bfin_wdt_driver = {
+ .driver = {
+ .name = WATCHDOG_NAME,
+ .owner = THIS_MODULE,
+ },
+ .suspend = bfin_wdt_suspend,
+ .resume = bfin_wdt_resume,
+};
+
+static struct file_operations bfin_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = bfin_wdt_write,
+ .ioctl = bfin_wdt_ioctl,
+ .open = bfin_wdt_open,
+ .release = bfin_wdt_release,
+};
+
+static struct miscdevice bfin_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &bfin_wdt_fops,
+};
+
+static struct watchdog_info bfin_wdt_info = {
+ .identity = "Blackfin Watchdog",
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
+static struct notifier_block bfin_wdt_notifier = {
+ .notifier_call = bfin_wdt_notify_sys,
+};
+
+/**
+ * bfin_wdt_init - Initialize module
+ *
+ * Registers the device and notifier handler. Actual device
+ * initialization is handled by bfin_wdt_open().
+ */
+static int __init bfin_wdt_init(void)
+{
+ int ret;
+
+ stampit();
+
+ /* Check that the timeout value is within range */
+ if (bfin_wdt_set_timeout(timeout))
+ return -EINVAL;
+
+ /* Since this is an on-chip device and needs no board-specific
+ * resources, we'll handle all the platform device stuff here.
+ */
+ ret = platform_device_register(&bfin_wdt_device);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_probe(&bfin_wdt_driver, NULL);
+ if (ret)
+ return ret;
+
+ ret = register_reboot_notifier(&bfin_wdt_notifier);
+ if (ret) {
+ printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
+ return ret;
+ }
+
+ ret = misc_register(&bfin_wdt_miscdev);
+ if (ret) {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ unregister_reboot_notifier(&bfin_wdt_notifier);
+ return ret;
+ }
+
+ printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
+ timeout, nowayout);
+
+ return 0;
+}
+
+/**
+ * bfin_wdt_exit - Deinitialize module
+ *
+ * Unregisters the device and notifier handler. Actual device
+ * deinitialization is handled by bfin_wdt_close().
+ */
+static void __exit bfin_wdt_exit(void)
+{
+ misc_deregister(&bfin_wdt_miscdev);
+ unregister_reboot_notifier(&bfin_wdt_notifier);
+}
+
+module_init(bfin_wdt_init);
+module_exit(bfin_wdt_exit);
+
+MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>");
+MODULE_DESCRIPTION("Blackfin Watchdog Device Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index 0f5c77ddd39..d362f5bf658 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -144,7 +144,7 @@ static int booke_wdt_open (struct inode *inode, struct file *file)
booke_wdt_period);
}
- return 0;
+ return nonseekable_open(inode, file);
}
static const struct file_operations booke_wdt_fops = {
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
index d0d45a8b09f..5941ca601a3 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -162,6 +162,10 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm
if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT;
break;
+ case WDIOC_GETBOOTSTATUS:
+ if ( copy_to_user(argp, &value, sizeof(int)) )
+ return -EFAULT;
+ break;
case WDIOC_GETSUPPORT:
if ( copy_to_user(argp, &ident, sizeof(ident)) )
return -EFAULT;
diff --git a/drivers/char/watchdog/davinci_wdt.c b/drivers/char/watchdog/davinci_wdt.c
new file mode 100644
index 00000000000..19db5302ba6
--- /dev/null
+++ b/drivers/char/watchdog/davinci_wdt.c
@@ -0,0 +1,281 @@
+/*
+ * drivers/char/watchdog/davinci_wdt.c
+ *
+ * Watchdog driver for DaVinci DM644x/DM646x processors
+ *
+ * Copyright (C) 2006 Texas Instruments.
+ *
+ * 2007 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define MODULE_NAME "DAVINCI-WDT: "
+
+#define DEFAULT_HEARTBEAT 60
+#define MAX_HEARTBEAT 600 /* really the max margin is 264/27MHz*/
+
+/* Timer register set definition */
+#define PID12 (0x0)
+#define EMUMGT (0x4)
+#define TIM12 (0x10)
+#define TIM34 (0x14)
+#define PRD12 (0x18)
+#define PRD34 (0x1C)
+#define TCR (0x20)
+#define TGCR (0x24)
+#define WDTCR (0x28)
+
+/* TCR bit definitions */
+#define ENAMODE12_DISABLED (0 << 6)
+#define ENAMODE12_ONESHOT (1 << 6)
+#define ENAMODE12_PERIODIC (2 << 6)
+
+/* TGCR bit definitions */
+#define TIM12RS_UNRESET (1 << 0)
+#define TIM34RS_UNRESET (1 << 1)
+#define TIMMODE_64BIT_WDOG (2 << 2)
+
+/* WDTCR bit definitions */
+#define WDEN (1 << 14)
+#define WDFLAG (1 << 15)
+#define WDKEY_SEQ0 (0xa5c6 << 16)
+#define WDKEY_SEQ1 (0xda7e << 16)
+
+static int heartbeat = DEFAULT_HEARTBEAT;
+
+static spinlock_t io_lock;
+static unsigned long wdt_status;
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+#define WDT_REGION_INITED 2
+#define WDT_DEVICE_INITED 3
+
+static struct resource *wdt_mem;
+static void __iomem *wdt_base;
+
+static void wdt_service(void)
+{
+ spin_lock(&io_lock);
+
+ /* put watchdog in service state */
+ davinci_writel(WDKEY_SEQ0, wdt_base + WDTCR);
+ /* put watchdog in active state */
+ davinci_writel(WDKEY_SEQ1, wdt_base + WDTCR);
+
+ spin_unlock(&io_lock);
+}
+
+static void wdt_enable(void)
+{
+ u32 tgcr;
+ u32 timer_margin;
+
+ spin_lock(&io_lock);
+
+ /* disable, internal clock source */
+ davinci_writel(0, wdt_base + TCR);
+ /* reset timer, set mode to 64-bit watchdog, and unreset */
+ davinci_writel(0, wdt_base + TGCR);
+ tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
+ davinci_writel(tgcr, wdt_base + TGCR);
+ /* clear counter regs */
+ davinci_writel(0, wdt_base + TIM12);
+ davinci_writel(0, wdt_base + TIM34);
+ /* set timeout period */
+ timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) & 0xffffffff);
+ davinci_writel(timer_margin, wdt_base + PRD12);
+ timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) >> 32);
+ davinci_writel(timer_margin, wdt_base + PRD34);
+ /* enable run continuously */
+ davinci_writel(ENAMODE12_PERIODIC, wdt_base + TCR);
+ /* Once the WDT is in pre-active state write to
+ * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
+ * write protected (except for the WDKEY field)
+ */
+ /* put watchdog in pre-active state */
+ davinci_writel(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR);
+ /* put watchdog in active state */
+ davinci_writel(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR);
+
+ spin_unlock(&io_lock);
+}
+
+static int davinci_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+
+ wdt_enable();
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t
+davinci_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t *ppos)
+{
+ if (len)
+ wdt_service();
+
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_KEEPALIVEPING,
+ .identity = "DaVinci Watchdog",
+};
+
+static int
+davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_service();
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int davinci_wdt_release(struct inode *inode, struct file *file)
+{
+ wdt_service();
+ clear_bit(WDT_IN_USE, &wdt_status);
+
+ return 0;
+}
+
+static const struct file_operations davinci_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = davinci_wdt_write,
+ .ioctl = davinci_wdt_ioctl,
+ .open = davinci_wdt_open,
+ .release = davinci_wdt_release,
+};
+
+static struct miscdevice davinci_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &davinci_wdt_fops,
+};
+
+static int davinci_wdt_probe(struct platform_device *pdev)
+{
+ int ret = 0, size;
+ struct resource *res;
+
+ spin_lock_init(&io_lock);
+
+ if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+ heartbeat = DEFAULT_HEARTBEAT;
+
+ printk(KERN_INFO MODULE_NAME
+ "DaVinci Watchdog Timer: heartbeat %d sec\n", heartbeat);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ printk(KERN_INFO MODULE_NAME
+ "failed to get memory region resource\n");
+ return -ENOENT;
+ }
+
+ size = res->end - res->start + 1;
+ wdt_mem = request_mem_region(res->start, size, pdev->name);
+
+ if (wdt_mem == NULL) {
+ printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
+ return -ENOENT;
+ }
+ wdt_base = (void __iomem *)(res->start);
+
+ ret = misc_register(&davinci_wdt_miscdev);
+ if (ret < 0) {
+ printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ } else {
+ set_bit(WDT_DEVICE_INITED, &wdt_status);
+ }
+
+ return ret;
+}
+
+static int davinci_wdt_remove(struct platform_device *pdev)
+{
+ misc_deregister(&davinci_wdt_miscdev);
+ if (wdt_mem) {
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ wdt_mem = NULL;
+ }
+ return 0;
+}
+
+static struct platform_driver platform_wdt_driver = {
+ .driver = {
+ .name = "watchdog",
+ },
+ .probe = davinci_wdt_probe,
+ .remove = davinci_wdt_remove,
+};
+
+static int __init davinci_wdt_init(void)
+{
+ return platform_driver_register(&platform_wdt_driver);
+}
+
+static void __exit davinci_wdt_exit(void)
+{
+ return platform_driver_unregister(&platform_wdt_driver);
+}
+
+module_init(davinci_wdt_init);
+module_exit(davinci_wdt_exit);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("DaVinci Watchdog Driver");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog heartbeat period in seconds from 1 to "
+ __MODULE_STRING(MAX_HEARTBEAT) ", default "
+ __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
index b070324e27a..b14e9d1f164 100644
--- a/drivers/char/watchdog/eurotechwdt.c
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -1,5 +1,5 @@
/*
- * Eurotech CPU-1220/1410 on board WDT driver
+ * Eurotech CPU-1220/1410/1420 on board WDT driver
*
* (c) Copyright 2001 Ascensit <support@ascensit.com>
* (c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com>
@@ -25,6 +25,9 @@
/* Changelog:
*
+ * 2001 - Rodolfo Giometti
+ * Initial release
+ *
* 2002/04/25 - Rob Radez
* clean up #includes
* clean up locking
@@ -33,13 +36,15 @@
* add WDIOC_GETSTATUS and WDIOC_SETOPTIONS ioctls
* add expect_close support
*
- * 2001 - Rodolfo Giometti
- * Initial release
- *
* 2002.05.30 - Joel Becker <joel.becker@oracle.com>
* Added Matt Domsch's nowayout module option.
*/
+/*
+ * The eurotech CPU-1220/1410/1420's watchdog is a part
+ * of the on-board SUPER I/O device SMSC FDC 37B782.
+ */
+
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c
index eac4f9b9f00..cd5a565bc3a 100644
--- a/drivers/char/watchdog/iTCO_wdt.c
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -39,7 +39,12 @@
* 82801HR (ICH8R) : document number 313056-002, 313057-004,
* 82801HH (ICH8DH) : document number 313056-002, 313057-004,
* 82801HO (ICH8DO) : document number 313056-002, 313057-004,
- * 6300ESB (6300ESB) : document number 300641-003
+ * 82801IB (ICH9) : document number 316972-001, 316973-001,
+ * 82801IR (ICH9R) : document number 316972-001, 316973-001,
+ * 82801IH (ICH9DH) : document number 316972-001, 316973-001,
+ * 6300ESB (6300ESB) : document number 300641-003, 300884-010,
+ * 631xESB (631xESB) : document number 313082-001, 313075-005,
+ * 632xESB (632xESB) : document number 313082-001, 313075-005
*/
/*
@@ -48,8 +53,8 @@
/* Module and version information */
#define DRV_NAME "iTCO_wdt"
-#define DRV_VERSION "1.01"
-#define DRV_RELDATE "21-Jan-2007"
+#define DRV_VERSION "1.02"
+#define DRV_RELDATE "26-Jul-2007"
#define PFX DRV_NAME ": "
/* Includes */
@@ -92,6 +97,10 @@ enum iTCO_chipsets {
TCO_ICH8, /* ICH8 & ICH8R */
TCO_ICH8DH, /* ICH8DH */
TCO_ICH8DO, /* ICH8DO */
+ TCO_ICH9, /* ICH9 */
+ TCO_ICH9R, /* ICH9R */
+ TCO_ICH9DH, /* ICH9DH */
+ TCO_631XESB, /* 631xESB/632xESB */
};
static struct {
@@ -118,6 +127,10 @@ static struct {
{"ICH8 or ICH8R", 2},
{"ICH8DH", 2},
{"ICH8DO", 2},
+ {"ICH9", 2},
+ {"ICH9R", 2},
+ {"ICH9DH", 2},
+ {"631xESB/632xESB", 2},
{NULL,0}
};
@@ -148,6 +161,25 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO },
+ { PCI_VENDOR_ID_INTEL, 0x2918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9 },
+ { PCI_VENDOR_ID_INTEL, 0x2916, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9R },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9DH },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
+ { PCI_VENDOR_ID_INTEL, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ 0, }, /* End of list */
};
MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
diff --git a/drivers/char/watchdog/iop_wdt.c b/drivers/char/watchdog/iop_wdt.c
new file mode 100644
index 00000000000..bbbd91af754
--- /dev/null
+++ b/drivers/char/watchdog/iop_wdt.c
@@ -0,0 +1,262 @@
+/*
+ * drivers/char/watchdog/iop_wdt.c
+ *
+ * WDT driver for Intel I/O Processors
+ * Copyright (C) 2005, Intel Corporation.
+ *
+ * Based on ixp4xx driver, Copyright 2004 (c) MontaVista, Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * Curt E Bruns <curt.e.bruns@intel.com>
+ * Peter Milne <peter.milne@d-tacq.com>
+ * Dan Williams <dan.j.williams@intel.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/uaccess.h>
+#include <asm/hardware.h>
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static unsigned long wdt_status;
+static unsigned long boot_status;
+
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+#define WDT_ENABLED 2
+
+static unsigned long iop_watchdog_timeout(void)
+{
+ return (0xffffffffUL / get_iop_tick_rate());
+}
+
+/**
+ * wdt_supports_disable - determine if we are accessing a iop13xx watchdog
+ * or iop3xx by whether it has a disable command
+ */
+static int wdt_supports_disable(void)
+{
+ int can_disable;
+
+ if (IOP_WDTCR_EN_ARM != IOP_WDTCR_DIS_ARM)
+ can_disable = 1;
+ else
+ can_disable = 0;
+
+ return can_disable;
+}
+
+static void wdt_enable(void)
+{
+ /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
+ * Takes approx. 10.7s to timeout
+ */
+ write_wdtcr(IOP_WDTCR_EN_ARM);
+ write_wdtcr(IOP_WDTCR_EN);
+}
+
+/* returns 0 if the timer was successfully disabled */
+static int wdt_disable(void)
+{
+ /* Stop Counting */
+ if (wdt_supports_disable()) {
+ write_wdtcr(IOP_WDTCR_DIS_ARM);
+ write_wdtcr(IOP_WDTCR_DIS);
+ clear_bit(WDT_ENABLED, &wdt_status);
+ printk(KERN_INFO "WATCHDOG: Disabled\n");
+ return 0;
+ } else
+ return 1;
+}
+
+static int iop_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ wdt_enable();
+
+ set_bit(WDT_ENABLED, &wdt_status);
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t
+iop_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t *ppos)
+{
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ }
+ }
+ wdt_enable();
+ }
+
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
+ .identity = "iop watchdog",
+};
+
+static int
+iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int options;
+ int ret = -ENOTTY;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ if (copy_to_user
+ ((struct watchdog_info *)arg, &ident, sizeof ident))
+ ret = -EFAULT;
+ else
+ ret = 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(boot_status, (int *)arg);
+ break;
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(iop_watchdog_timeout(), (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_enable();
+ ret = 0;
+ break;
+
+ case WDIOC_SETOPTIONS:
+ if (get_user(options, (int *)arg))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD) {
+ if (!nowayout) {
+ if (wdt_disable() == 0) {
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ ret = 0;
+ } else
+ ret = -ENXIO;
+ } else
+ ret = 0;
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ wdt_enable();
+ ret = 0;
+ }
+ break;
+ }
+
+ return ret;
+}
+
+static int iop_wdt_release(struct inode *inode, struct file *file)
+{
+ int state = 1;
+ if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+ if (test_bit(WDT_ENABLED, &wdt_status))
+ state = wdt_disable();
+
+ /* if the timer is not disbaled reload and notify that we are still
+ * going down
+ */
+ if (state != 0) {
+ wdt_enable();
+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
+ "reset in %lu seconds\n", iop_watchdog_timeout());
+ }
+
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return 0;
+}
+
+static const struct file_operations iop_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = iop_wdt_write,
+ .ioctl = iop_wdt_ioctl,
+ .open = iop_wdt_open,
+ .release = iop_wdt_release,
+};
+
+static struct miscdevice iop_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &iop_wdt_fops,
+};
+
+static int __init iop_wdt_init(void)
+{
+ int ret;
+
+ ret = misc_register(&iop_wdt_miscdev);
+ if (ret == 0)
+ printk("iop watchdog timer: timeout %lu sec\n",
+ iop_watchdog_timeout());
+
+ /* check if the reset was caused by the watchdog timer */
+ boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
+
+ /* Configure Watchdog Timeout to cause an Internal Bus (IB) Reset
+ * NOTE: An IB Reset will Reset both cores in the IOP342
+ */
+ write_wdtsr(IOP13XX_WDTCR_IB_RESET);
+
+ return ret;
+}
+
+static void __exit iop_wdt_exit(void)
+{
+ misc_deregister(&iop_wdt_miscdev);
+}
+
+module_init(iop_wdt_init);
+module_exit(iop_wdt_exit);
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+
+MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
+MODULE_DESCRIPTION("iop watchdog timer driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index a0d27160c80..6d35bb112a5 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -321,6 +321,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE:
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index db2ccb86441..1adf1d56027 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -215,6 +215,11 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
}
break;
+ case WDIOC_GETBOOTSTATUS:
+ if (copy_to_user(p, &status, sizeof(int))) {
+ return -EFAULT;
+ }
+ break;
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident))) {
return -EFAULT;
diff --git a/drivers/char/watchdog/mpc5200_wdt.c b/drivers/char/watchdog/mpc5200_wdt.c
new file mode 100644
index 00000000000..564143d4061
--- /dev/null
+++ b/drivers/char/watchdog/mpc5200_wdt.c
@@ -0,0 +1,286 @@
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <asm/of_platform.h>
+#include <asm/uaccess.h>
+#include <asm/mpc52xx.h>
+
+
+#define GPT_MODE_WDT (1<<15)
+#define GPT_MODE_CE (1<<12)
+#define GPT_MODE_MS_TIMER (0x4)
+
+
+struct mpc5200_wdt {
+ unsigned count; /* timer ticks before watchdog kicks in */
+ long ipb_freq;
+ struct miscdevice miscdev;
+ struct resource mem;
+ struct mpc52xx_gpt __iomem *regs;
+ spinlock_t io_lock;
+};
+
+/* is_active stores wether or not the /dev/watchdog device is opened */
+static unsigned long is_active;
+
+/* misc devices don't provide a way, to get back to 'dev' or 'miscdev' from
+ * file operations, which sucks. But there can be max 1 watchdog anyway, so...
+ */
+static struct mpc5200_wdt *wdt_global;
+
+
+/* helper to calculate timeout in timer counts */
+static void mpc5200_wdt_set_timeout(struct mpc5200_wdt *wdt, int timeout)
+{
+ /* use biggest prescaler of 64k */
+ wdt->count = (wdt->ipb_freq + 0xffff) / 0x10000 * timeout;
+
+ if (wdt->count > 0xffff)
+ wdt->count = 0xffff;
+}
+/* return timeout in seconds (calculated from timer count) */
+static int mpc5200_wdt_get_timeout(struct mpc5200_wdt *wdt)
+{
+ return wdt->count * 0x10000 / wdt->ipb_freq;
+}
+
+
+/* watchdog operations */
+static int mpc5200_wdt_start(struct mpc5200_wdt *wdt)
+{
+ spin_lock(&wdt->io_lock);
+ /* disable */
+ out_be32(&wdt->regs->mode, 0);
+ /* set timeout, with maximum prescaler */
+ out_be32(&wdt->regs->count, 0x0 | wdt->count);
+ /* enable watchdog */
+ out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER);
+ spin_unlock(&wdt->io_lock);
+
+ return 0;
+}
+static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt)
+{
+ spin_lock(&wdt->io_lock);
+ /* writing A5 to OCPW resets the watchdog */
+ out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode)));
+ spin_unlock(&wdt->io_lock);
+ return 0;
+}
+static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt)
+{
+ spin_lock(&wdt->io_lock);
+ /* disable */
+ out_be32(&wdt->regs->mode, 0);
+ spin_unlock(&wdt->io_lock);
+ return 0;
+}
+
+
+/* file operations */
+static ssize_t mpc5200_wdt_write(struct file *file, const char *data,
+ size_t len, loff_t *ppos)
+{
+ struct mpc5200_wdt *wdt = file->private_data;
+ mpc5200_wdt_ping(wdt);
+ return 0;
+}
+static struct watchdog_info mpc5200_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "mpc5200 watchdog on GPT0",
+};
+static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mpc5200_wdt *wdt = file->private_data;
+ int __user *data = (int __user *)arg;
+ int timeout;
+ int ret = 0;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user(data, &mpc5200_wdt_info,
+ sizeof(mpc5200_wdt_info));
+ if (ret)
+ ret = -EFAULT;
+ break;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(0, data);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ mpc5200_wdt_ping(wdt);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(timeout, data);
+ if (ret)
+ break;
+ mpc5200_wdt_set_timeout(wdt, timeout);
+ mpc5200_wdt_start(wdt);
+ /* fall through and return the timeout */
+
+ case WDIOC_GETTIMEOUT:
+ timeout = mpc5200_wdt_get_timeout(wdt);
+ ret = put_user(timeout, data);
+ break;
+
+ default:
+ ret = -ENOTTY;
+ }
+ return ret;
+}
+static int mpc5200_wdt_open(struct inode *inode, struct file *file)
+{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &is_active))
+ return -EBUSY;
+
+ /* Set and activate the watchdog */
+ mpc5200_wdt_set_timeout(wdt_global, 30);
+ mpc5200_wdt_start(wdt_global);
+ file->private_data = wdt_global;
+ return nonseekable_open(inode, file);
+}
+static int mpc5200_wdt_release(struct inode *inode, struct file *file)
+{
+#if WATCHDOG_NOWAYOUT == 0
+ struct mpc5200_wdt *wdt = file->private_data;
+ mpc5200_wdt_stop(wdt);
+ wdt->count = 0; /* == disabled */
+#endif
+ clear_bit(0, &is_active);
+ return 0;
+}
+
+static struct file_operations mpc5200_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = mpc5200_wdt_write,
+ .ioctl = mpc5200_wdt_ioctl,
+ .open = mpc5200_wdt_open,
+ .release = mpc5200_wdt_release,
+};
+
+/* module operations */
+static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match)
+{
+ struct mpc5200_wdt *wdt;
+ int err;
+ const void *has_wdt;
+ int size;
+
+ has_wdt = of_get_property(op->node, "has-wdt", NULL);
+ if (!has_wdt)
+ return -ENODEV;
+
+ wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+
+ wdt->ipb_freq = mpc52xx_find_ipb_freq(op->node);
+
+ err = of_address_to_resource(op->node, 0, &wdt->mem);
+ if (err)
+ goto out_free;
+ size = wdt->mem.end - wdt->mem.start + 1;
+ if (!request_mem_region(wdt->mem.start, size, "mpc5200_wdt")) {
+ err = -ENODEV;
+ goto out_free;
+ }
+ wdt->regs = ioremap(wdt->mem.start, size);
+ if (!wdt->regs) {
+ err = -ENODEV;
+ goto out_release;
+ }
+
+ dev_set_drvdata(&op->dev, wdt);
+ spin_lock_init(&wdt->io_lock);
+
+ wdt->miscdev = (struct miscdevice) {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &mpc5200_wdt_fops,
+ .parent = &op->dev,
+ };
+ wdt_global = wdt;
+ err = misc_register(&wdt->miscdev);
+ if (!err)
+ return 0;
+
+ iounmap(wdt->regs);
+ out_release:
+ release_mem_region(wdt->mem.start, size);
+ out_free:
+ kfree(wdt);
+ return err;
+}
+
+static int mpc5200_wdt_remove(struct of_device *op)
+{
+ struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+
+ mpc5200_wdt_stop(wdt);
+ misc_deregister(&wdt->miscdev);
+ iounmap(wdt->regs);
+ release_mem_region(wdt->mem.start, wdt->mem.end - wdt->mem.start + 1);
+ kfree(wdt);
+
+ return 0;
+}
+static int mpc5200_wdt_suspend(struct of_device *op, pm_message_t state)
+{
+ struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+ mpc5200_wdt_stop(wdt);
+ return 0;
+}
+static int mpc5200_wdt_resume(struct of_device *op)
+{
+ struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+ if (wdt->count)
+ mpc5200_wdt_start(wdt);
+ return 0;
+}
+static int mpc5200_wdt_shutdown(struct of_device *op)
+{
+ struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
+ mpc5200_wdt_stop(wdt);
+ return 0;
+}
+
+static struct of_device_id mpc5200_wdt_match[] = {
+ { .compatible = "mpc5200-gpt", },
+ {},
+};
+static struct of_platform_driver mpc5200_wdt_driver = {
+ .owner = THIS_MODULE,
+ .name = "mpc5200-gpt-wdt",
+ .match_table = mpc5200_wdt_match,
+ .probe = mpc5200_wdt_probe,
+ .remove = mpc5200_wdt_remove,
+ .suspend = mpc5200_wdt_suspend,
+ .resume = mpc5200_wdt_resume,
+ .shutdown = mpc5200_wdt_shutdown,
+};
+
+
+static int __init mpc5200_wdt_init(void)
+{
+ return of_register_platform_driver(&mpc5200_wdt_driver);
+}
+
+static void __exit mpc5200_wdt_exit(void)
+{
+ of_unregister_platform_driver(&mpc5200_wdt_driver);
+}
+
+module_init(mpc5200_wdt_init);
+module_exit(mpc5200_wdt_exit);
+
+MODULE_AUTHOR("Domen Puncer <domen.puncer@telargo.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c
index 18ca752e2f9..a0bf95fb976 100644
--- a/drivers/char/watchdog/mpc83xx_wdt.c
+++ b/drivers/char/watchdog/mpc83xx_wdt.c
@@ -119,6 +119,9 @@ static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, p);
case WDIOC_KEEPALIVE:
mpc83xx_wdt_keepalive();
return 0;
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
index 8aaed10dd49..85b5734403a 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -57,7 +57,7 @@ static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
m8xx_wdt_reset();
mpc8xx_wdt_handler_disable();
- return 0;
+ return nonseekable_open(inode, file);
}
static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index e88947f8fe5..0d2b2773541 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -328,12 +328,11 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev)
goto err_out;
}
- wdt = kmalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
+ wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
if (!wdt) {
ret = -ENOMEM;
goto err_out;
}
- memset(wdt, 0, sizeof(struct mpcore_wdt));
wdt->dev = &dev->dev;
wdt->irq = platform_get_irq(dev, 0);
diff --git a/drivers/char/watchdog/mtx-1_wdt.c b/drivers/char/watchdog/mtx-1_wdt.c
index 419ab445c94..dcfd401a7ad 100644
--- a/drivers/char/watchdog/mtx-1_wdt.c
+++ b/drivers/char/watchdog/mtx-1_wdt.c
@@ -143,6 +143,7 @@ static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int c
mtx1_wdt_reset();
break;
case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT;
break;
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
index b887cdb0133..0365c317f7e 100644
--- a/drivers/char/watchdog/mv64x60_wdt.c
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -23,61 +23,101 @@
#include <linux/watchdog.h>
#include <linux/platform_device.h>
-#include <asm/mv64x60.h>
+#include <linux/mv643xx.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-/* MV64x60 WDC (config) register access definitions */
-#define MV64x60_WDC_CTL1_MASK (3 << 24)
-#define MV64x60_WDC_CTL1(val) ((val & 3) << 24)
-#define MV64x60_WDC_CTL2_MASK (3 << 26)
-#define MV64x60_WDC_CTL2(val) ((val & 3) << 26)
+#define MV64x60_WDT_WDC_OFFSET 0
+
+/*
+ * The watchdog configuration register contains a pair of 2-bit fields,
+ * 1. a reload field, bits 27-26, which triggers a reload of
+ * the countdown register, and
+ * 2. an enable field, bits 25-24, which toggles between
+ * enabling and disabling the watchdog timer.
+ * Bit 31 is a read-only field which indicates whether the
+ * watchdog timer is currently enabled.
+ *
+ * The low 24 bits contain the timer reload value.
+ */
+#define MV64x60_WDC_ENABLE_SHIFT 24
+#define MV64x60_WDC_SERVICE_SHIFT 26
+#define MV64x60_WDC_ENABLED_SHIFT 31
+
+#define MV64x60_WDC_ENABLED_TRUE 1
+#define MV64x60_WDC_ENABLED_FALSE 0
/* Flags bits */
#define MV64x60_WDOG_FLAG_OPENED 0
-#define MV64x60_WDOG_FLAG_ENABLED 1
static unsigned long wdt_flags;
static int wdt_status;
-static void __iomem *mv64x60_regs;
+static void __iomem *mv64x60_wdt_regs;
static int mv64x60_wdt_timeout;
+static int mv64x60_wdt_count;
+static unsigned int bus_clk;
+static char expect_close;
+static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-static void mv64x60_wdt_reg_write(u32 val)
+static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift)
{
- /* Allow write only to CTL1 / CTL2 fields, retaining values in
- * other fields.
- */
- u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);
- data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK);
- data |= val;
- writel(data, mv64x60_regs + MV64x60_WDT_WDC);
+ u32 data;
+ u32 enabled;
+ int ret = 0;
+
+ spin_lock(&mv64x60_wdt_spinlock);
+ data = readl(mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
+ enabled = (data >> MV64x60_WDC_ENABLED_SHIFT) & 1;
+
+ /* only toggle the requested field if enabled state matches predicate */
+ if ((enabled ^ enabled_predicate) == 0) {
+ /* We write a 1, then a 2 -- to the appropriate field */
+ data = (1 << field_shift) | mv64x60_wdt_count;
+ writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
+
+ data = (2 << field_shift) | mv64x60_wdt_count;
+ writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
+ ret = 1;
+ }
+ spin_unlock(&mv64x60_wdt_spinlock);
+
+ return ret;
}
static void mv64x60_wdt_service(void)
{
- /* Write 01 followed by 10 to CTL2 */
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01));
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02));
+ mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
+ MV64x60_WDC_SERVICE_SHIFT);
+}
+
+static void mv64x60_wdt_handler_enable(void)
+{
+ if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE,
+ MV64x60_WDC_ENABLE_SHIFT)) {
+ mv64x60_wdt_service();
+ printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
+ }
}
static void mv64x60_wdt_handler_disable(void)
{
- if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
- /* Write 01 followed by 10 to CTL1 */
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
+ if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
+ MV64x60_WDC_ENABLE_SHIFT))
printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
- }
}
-static void mv64x60_wdt_handler_enable(void)
+static void mv64x60_wdt_set_timeout(unsigned int timeout)
{
- if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) {
- /* Write 01 followed by 10 to CTL1 */
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
- mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
- printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
- }
+ /* maximum bus cycle count is 0xFFFFFFFF */
+ if (timeout > 0xFFFFFFFF / bus_clk)
+ timeout = 0xFFFFFFFF / bus_clk;
+
+ mv64x60_wdt_count = timeout * bus_clk >> 8;
+ mv64x60_wdt_timeout = timeout;
}
static int mv64x60_wdt_open(struct inode *inode, struct file *file)
@@ -85,21 +125,24 @@ static int mv64x60_wdt_open(struct inode *inode, struct file *file)
if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
return -EBUSY;
- mv64x60_wdt_service();
- mv64x60_wdt_handler_enable();
+ if (nowayout)
+ __module_get(THIS_MODULE);
- nonseekable_open(inode, file);
+ mv64x60_wdt_handler_enable();
- return 0;
+ return nonseekable_open(inode, file);
}
static int mv64x60_wdt_release(struct inode *inode, struct file *file)
{
- mv64x60_wdt_service();
-
-#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
- mv64x60_wdt_handler_disable();
-#endif
+ if (expect_close == 42)
+ mv64x60_wdt_handler_disable();
+ else {
+ printk(KERN_CRIT
+ "mv64x60_wdt: unexpected close, not stopping timer!\n");
+ mv64x60_wdt_service();
+ }
+ expect_close = 0;
clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
@@ -109,8 +152,22 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file)
static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t * ppos)
{
- if (len)
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ expect_close = 0;
+
+ for (i = 0; i != len; i++) {
+ char c;
+ if(get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_close = 42;
+ }
+ }
mv64x60_wdt_service();
+ }
return len;
}
@@ -119,9 +176,12 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int timeout;
+ int options;
void __user *argp = (void __user *)arg;
static struct watchdog_info info = {
- .options = WDIOF_KEEPALIVEPING,
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE |
+ WDIOF_KEEPALIVEPING,
.firmware_version = 0,
.identity = "MV64x60 watchdog",
};
@@ -143,7 +203,15 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
return -EOPNOTSUPP;
case WDIOC_SETOPTIONS:
- return -EOPNOTSUPP;
+ if (get_user(options, (int __user *)argp))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD)
+ mv64x60_wdt_handler_disable();
+
+ if (options & WDIOS_ENABLECARD)
+ mv64x60_wdt_handler_enable();
+ break;
case WDIOC_KEEPALIVE:
mv64x60_wdt_service();
@@ -151,11 +219,13 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
break;
case WDIOC_SETTIMEOUT:
- return -EOPNOTSUPP;
+ if (get_user(timeout, (int __user *)argp))
+ return -EFAULT;
+ mv64x60_wdt_set_timeout(timeout);
+ /* Fall through */
case WDIOC_GETTIMEOUT:
- timeout = mv64x60_wdt_timeout * HZ;
- if (put_user(timeout, (int __user *)argp))
+ if (put_user(mv64x60_wdt_timeout, (int __user *)argp))
return -EFAULT;
break;
@@ -184,18 +254,33 @@ static struct miscdevice mv64x60_wdt_miscdev = {
static int __devinit mv64x60_wdt_probe(struct platform_device *dev)
{
struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data;
- int bus_clk = 133;
+ struct resource *r;
+ int timeout = 10;
- mv64x60_wdt_timeout = 10;
+ bus_clk = 133; /* in MHz */
if (pdata) {
- mv64x60_wdt_timeout = pdata->timeout;
+ timeout = pdata->timeout;
bus_clk = pdata->bus_clk;
}
- mv64x60_regs = mv64x60_get_bridge_vbase();
+ /* Since bus_clk is truncated MHz, actual frequency could be
+ * up to 1MHz higher. Round up, since it's better to time out
+ * too late than too soon.
+ */
+ bus_clk++;
+ bus_clk *= 1000000; /* convert to Hz */
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -ENODEV;
- writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8,
- mv64x60_regs + MV64x60_WDT_WDC);
+ mv64x60_wdt_regs = ioremap(r->start, r->end - r->start + 1);
+ if (mv64x60_wdt_regs == NULL)
+ return -ENOMEM;
+
+ mv64x60_wdt_set_timeout(timeout);
+
+ mv64x60_wdt_handler_disable(); /* in case timer was already running */
return misc_register(&mv64x60_wdt_miscdev);
}
@@ -204,9 +289,10 @@ static int __devexit mv64x60_wdt_remove(struct platform_device *dev)
{
misc_deregister(&mv64x60_wdt_miscdev);
- mv64x60_wdt_service();
mv64x60_wdt_handler_disable();
+ iounmap(mv64x60_wdt_regs);
+
return 0;
}
@@ -219,40 +305,16 @@ static struct platform_driver mv64x60_wdt_driver = {
},
};
-static struct platform_device *mv64x60_wdt_dev;
-
static int __init mv64x60_wdt_init(void)
{
- int ret;
-
printk(KERN_INFO "MV64x60 watchdog driver\n");
- mv64x60_wdt_dev = platform_device_alloc(MV64x60_WDT_NAME, -1);
- if (!mv64x60_wdt_dev) {
- ret = -ENOMEM;
- goto out;
- }
-
- ret = platform_device_add(mv64x60_wdt_dev);
- if (ret) {
- platform_device_put(mv64x60_wdt_dev);
- goto out;
- }
-
- ret = platform_driver_register(&mv64x60_wdt_driver);
- if (ret) {
- platform_device_unregister(mv64x60_wdt_dev);
- goto out;
- }
-
- out:
- return ret;
+ return platform_driver_register(&mv64x60_wdt_driver);
}
static void __exit mv64x60_wdt_exit(void)
{
platform_driver_unregister(&mv64x60_wdt_driver);
- platform_device_unregister(mv64x60_wdt_dev);
}
module_init(mv64x60_wdt_init);
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
index b36fa8de213..719b066f73c 100644
--- a/drivers/char/watchdog/omap_wdt.c
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -142,7 +142,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
omap_wdt_set_timeout();
omap_wdt_enable();
- return 0;
+ return nonseekable_open(inode, file);
}
static int omap_wdt_release(struct inode *inode, struct file *file)
@@ -197,7 +197,7 @@ omap_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(ident));
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index 1e7a6719d5b..0f3fd6c9c35 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -626,12 +626,11 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
/* allocate memory for our device and initialize it */
- usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
+ usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
if (usb_pcwd == NULL) {
printk(KERN_ERR PFX "Out of memory\n");
goto error;
}
- memset (usb_pcwd, 0x00, sizeof (*usb_pcwd));
usb_pcwd_device = usb_pcwd;
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index 50430bced2f..5d1c15f83d2 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -52,10 +52,10 @@
#include <asm/arch/map.h>
-#undef S3C24XX_VA_WATCHDOG
-#define S3C24XX_VA_WATCHDOG (0)
+#undef S3C_VA_WATCHDOG
+#define S3C_VA_WATCHDOG (0)
-#include <asm/arch/regs-watchdog.h>
+#include <asm/plat-s3c/regs-watchdog.h>
#define PFX "s3c2410-wdt: "
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
index 33c1137f17d..3475f47aaa4 100644
--- a/drivers/char/watchdog/sa1100_wdt.c
+++ b/drivers/char/watchdog/sa1100_wdt.c
@@ -45,7 +45,6 @@ static int boot_status;
*/
static int sa1100dog_open(struct inode *inode, struct file *file)
{
- nonseekable_open(inode, file);
if (test_and_set_bit(1,&sa1100wdt_users))
return -EBUSY;
@@ -54,7 +53,7 @@ static int sa1100dog_open(struct inode *inode, struct file *file)
OSSR = OSSR_M3;
OWER = OWER_WME;
OIER |= OIER_E3;
- return 0;
+ return nonseekable_open(inode, file);
}
/*
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
index b6282039198..e4f3cb6090b 100644
--- a/drivers/char/watchdog/sbc60xxwdt.c
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -191,8 +191,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
static int fop_open(struct inode * inode, struct file * file)
{
- nonseekable_open(inode, file);
-
/* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
@@ -202,7 +200,7 @@ static int fop_open(struct inode * inode, struct file * file)
/* Good, fire up the show */
wdt_startup();
- return 0;
+ return nonseekable_open(inode, file);
}
static int fop_close(struct inode * inode, struct file * file)
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 2f7ba7a514f..9670d47190d 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -150,8 +150,6 @@ static inline int sc1200wdt_status(void)
static int sc1200wdt_open(struct inode *inode, struct file *file)
{
- nonseekable_open(inode, file);
-
/* allow one at a time */
if (down_trylock(&open_sem))
return -EBUSY;
@@ -162,7 +160,7 @@ static int sc1200wdt_open(struct inode *inode, struct file *file)
sc1200wdt_start();
printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
- return 0;
+ return nonseekable_open(inode, file);
}
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
index 2676a43895a..e8594c64d1e 100644
--- a/drivers/char/watchdog/sc520_wdt.c
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -248,8 +248,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
static int fop_open(struct inode * inode, struct file * file)
{
- nonseekable_open(inode, file);
-
/* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open))
return -EBUSY;
@@ -258,7 +256,7 @@ static int fop_open(struct inode * inode, struct file * file)
/* Good, fire up the show */
wdt_startup();
- return 0;
+ return nonseekable_open(inode, file);
}
static int fop_close(struct inode * inode, struct file * file)
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index b46e7f47d70..df33b3b5a53 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -4,7 +4,7 @@
* (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
* added support for W83627THF.
*
- * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
+ * (c) Copyright 2003,2007 Pádraig Brady <P@draigBrady.com>
*
* Based on advantechwdt.c which is based on wdt.c.
* Original copyright messages:
@@ -42,7 +42,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
-#define WATCHDOG_NAME "w83627hf/thf WDT"
+#define WATCHDOG_NAME "w83627hf/thf/hg WDT"
#define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
@@ -57,7 +57,7 @@ MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
@@ -78,9 +78,9 @@ w83627hf_select_wd_register(void)
outb_p(0x87, WDT_EFER); /* Enter extended function mode */
outb_p(0x87, WDT_EFER); /* Again according to manual */
- outb(0x20, WDT_EFER); /* check chip version */
+ outb(0x20, WDT_EFER); /* check chip version */
c = inb(WDT_EFDR);
- if (c == 0x82) { /* W83627THF */
+ if (c == 0x82) { /* W83627THF */
outb_p(0x2b, WDT_EFER); /* select GPIO3 */
c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
outb_p(0x2b, WDT_EFER);
@@ -114,11 +114,17 @@ w83627hf_init(void)
printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout);
outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
}
+
outb_p(0xF5, WDT_EFER); /* Select CRF5 */
t=inb_p(WDT_EFDR); /* read CRF5 */
t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */
outb_p(t, WDT_EFDR); /* Write back to CRF5 */
+ outb_p(0xF7, WDT_EFER); /* Select CRF7 */
+ t=inb_p(WDT_EFDR); /* read CRF7 */
+ t&=~0xC0; /* disable keyboard & mouse turning off watchdog */
+ outb_p(t, WDT_EFDR); /* Write back to CRF7 */
+
w83627hf_unselect_wd_register();
}
@@ -126,7 +132,7 @@ static void
wdt_ctrl(int timeout)
{
spin_lock(&io_lock);
-
+
w83627hf_select_wd_register();
outb_p(0xF6, WDT_EFER); /* Select CRF6 */
@@ -154,7 +160,7 @@ wdt_disable(void)
static int
wdt_set_heartbeat(int t)
{
- if ((t < 1) || (t > 63))
+ if ((t < 1) || (t > 255))
return -EINVAL;
timeout = t;
@@ -324,11 +330,11 @@ wdt_init(void)
spin_lock_init(&io_lock);
- printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF Super I/O chip initialising.\n");
+ printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n");
if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT);
- printk (KERN_INFO PFX "timeout value must be 1<=timeout<=63, using %d\n",
+ printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
WATCHDOG_TIMEOUT);
}