aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/watchdog
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/watchdog')
-rw-r--r--drivers/char/watchdog/Kconfig32
-rw-r--r--drivers/char/watchdog/Makefile2
-rw-r--r--drivers/char/watchdog/acquirewdt.c2
-rw-r--r--drivers/char/watchdog/advantechwdt.c2
-rw-r--r--drivers/char/watchdog/alim1535_wdt.c12
-rw-r--r--drivers/char/watchdog/alim7101_wdt.c17
-rw-r--r--drivers/char/watchdog/at91_wdt.c2
-rw-r--r--drivers/char/watchdog/booke_wdt.c2
-rw-r--r--drivers/char/watchdog/cpu5wdt.c2
-rw-r--r--drivers/char/watchdog/ep93xx_wdt.c2
-rw-r--r--drivers/char/watchdog/eurotechwdt.c2
-rw-r--r--drivers/char/watchdog/i6300esb.c2
-rw-r--r--drivers/char/watchdog/i8xx_tco.c35
-rw-r--r--drivers/char/watchdog/iTCO_wdt.c735
-rw-r--r--drivers/char/watchdog/ib700wdt.c2
-rw-r--r--drivers/char/watchdog/ibmasr.c2
-rw-r--r--drivers/char/watchdog/indydog.c2
-rw-r--r--drivers/char/watchdog/ixp2000_wdt.c4
-rw-r--r--drivers/char/watchdog/ixp4xx_wdt.c4
-rw-r--r--drivers/char/watchdog/machzwd.c5
-rw-r--r--drivers/char/watchdog/mixcomwd.c2
-rw-r--r--drivers/char/watchdog/mpc83xx_wdt.c2
-rw-r--r--drivers/char/watchdog/mpc8xx_wdt.c2
-rw-r--r--drivers/char/watchdog/mpcore_wdt.c4
-rw-r--r--drivers/char/watchdog/mv64x60_wdt.c2
-rw-r--r--drivers/char/watchdog/pcwd.c2
-rw-r--r--drivers/char/watchdog/pcwd_pci.c2
-rw-r--r--drivers/char/watchdog/pcwd_usb.c2
-rw-r--r--drivers/char/watchdog/pnx4008_wdt.c362
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c12
-rw-r--r--drivers/char/watchdog/sa1100_wdt.c2
-rw-r--r--drivers/char/watchdog/sbc60xxwdt.c2
-rw-r--r--drivers/char/watchdog/sbc_epx_c3.c2
-rw-r--r--drivers/char/watchdog/sc1200wdt.c2
-rw-r--r--drivers/char/watchdog/sc520_wdt.c2
-rw-r--r--drivers/char/watchdog/scx200_wdt.c2
-rw-r--r--drivers/char/watchdog/shwdt.c2
-rw-r--r--drivers/char/watchdog/softdog.c2
-rw-r--r--drivers/char/watchdog/w83627hf_wdt.c2
-rw-r--r--drivers/char/watchdog/w83877f_wdt.c2
-rw-r--r--drivers/char/watchdog/w83977f_wdt.c2
-rw-r--r--drivers/char/watchdog/wafer5823wdt.c2
-rw-r--r--drivers/char/watchdog/wdrtas.c2
-rw-r--r--drivers/char/watchdog/wdt.c2
-rw-r--r--drivers/char/watchdog/wdt285.c2
-rw-r--r--drivers/char/watchdog/wdt977.c2
-rw-r--r--drivers/char/watchdog/wdt_pci.c2
47 files changed, 1219 insertions, 75 deletions
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index 77ab7e020da0a8..89e46d6dfc4ef7 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -172,6 +172,17 @@ config OMAP_WATCHDOG
Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to
enable the OMAP1610/OMAP1710 watchdog timer.
+config PNX4008_WATCHDOG
+ tristate "PNX4008 Watchdog"
+ depends on WATCHDOG && ARCH_PNX4008
+ help
+ Say Y here if to include support for the watchdog timer
+ in the PNX4008 processor.
+ This driver can be built as a module by choosing M. The module
+ will be called pnx4008_wdt.
+
+ Say N if you are unsure.
+
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
@@ -305,6 +316,27 @@ config I8XX_TCO
To compile this driver as a module, choose M here: the
module will be called i8xx_tco.
+config ITCO_WDT
+ tristate "Intel TCO Timer/Watchdog (EXPERIMENTAL)"
+ depends on WATCHDOG && (X86 || IA64) && PCI && EXPERIMENTAL
+ ---help---
+ Hardware driver for the intel TCO timer based watchdog devices.
+ These drivers are included in the Intel 82801 I/O Controller
+ Hub family 'from ICH0 up to ICH7) and in the Intel 6300ESB
+ controller hub.
+
+ The TCO (Total Cost of Ownership) timer is a watchdog timer
+ that will reboot the machine after its second expiration. The
+ expiration time can be configured with the "heartbeat" parameter.
+
+ On some motherboards the driver may fail to reset the chipset's
+ NO_REBOOT flag which prevents the watchdog from rebooting the
+ machine. If this is the case you will get a kernel message like
+ "failed to reset NO_REBOOT flag, reboot disabled by hardware".
+
+ To compile this driver as a module, choose M here: the
+ module will be called iTCO_wdt.
+
config SC1200_WDT
tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
depends on WATCHDOG && X86
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 5099f8be8cc51e..7f70abad465a3b 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
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
# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
@@ -46,6 +47,7 @@ obj-$(CONFIG_IBMASR) += ibmasr.o
obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o
+obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c
index c77fe3cf2852a1..154d67e591e5c9 100644
--- a/drivers/char/watchdog/acquirewdt.c
+++ b/drivers/char/watchdog/acquirewdt.c
@@ -183,7 +183,7 @@ static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
index 8069be445edc36..9d732769ba0144 100644
--- a/drivers/char/watchdog/advantechwdt.c
+++ b/drivers/char/watchdog/advantechwdt.c
@@ -176,7 +176,7 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
index c5c94e4c94950b..01b0d132ee41b3 100644
--- a/drivers/char/watchdog/alim1535_wdt.c
+++ b/drivers/char/watchdog/alim1535_wdt.c
@@ -236,7 +236,7 @@ static int ali_ioctl(struct inode *inode, struct file *file,
return put_user(timeout, p);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
@@ -330,17 +330,20 @@ static int __init ali_find_watchdog(void)
u32 wdog;
/* Check for a 1535 series bridge */
- pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
+ pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
if(pdev == NULL)
return -ENODEV;
+ pci_dev_put(pdev);
/* Check for the a 7101 PMU */
- pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
+ pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
if(pdev == NULL)
return -ENODEV;
- if(pci_enable_device(pdev))
+ if(pci_enable_device(pdev)) {
+ pci_dev_put(pdev);
return -EIO;
+ }
ali_pci = pdev;
@@ -447,6 +450,7 @@ static void __exit watchdog_exit(void)
/* Deregister */
unregister_reboot_notifier(&ali_notifier);
misc_deregister(&ali_miscdev);
+ pci_dev_put(ali_pci);
}
module_init(watchdog_init);
diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
index ffd7684f999b32..5948863b592b74 100644
--- a/drivers/char/watchdog/alim7101_wdt.c
+++ b/drivers/char/watchdog/alim7101_wdt.c
@@ -277,7 +277,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
@@ -333,6 +333,7 @@ static void __exit alim7101_wdt_unload(void)
/* Deregister */
misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier);
+ pci_dev_put(alim7101_pmu);
}
static int __init alim7101_wdt_init(void)
@@ -342,7 +343,8 @@ static int __init alim7101_wdt_init(void)
char tmp;
printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n");
- alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL);
+ alim7101_pmu = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
+ NULL);
if (!alim7101_pmu) {
printk(KERN_INFO PFX "ALi M7101 PMU not present - WDT not set\n");
return -EBUSY;
@@ -351,21 +353,23 @@ static int __init alim7101_wdt_init(void)
/* Set the WDT in the PMU to 1 second */
pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02);
- ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+ ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+ NULL);
if (!ali1543_south) {
printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n");
- return -EBUSY;
+ goto err_out;
}
pci_read_config_byte(ali1543_south, 0x5e, &tmp);
+ pci_dev_put(ali1543_south);
if ((tmp & 0x1e) == 0x00) {
if (!use_gpio) {
printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n");
- return -EBUSY;
+ goto err_out;
}
nowayout = 1;
} else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
- return -EBUSY;
+ goto err_out;
}
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
@@ -404,6 +408,7 @@ static int __init alim7101_wdt_init(void)
err_out_miscdev:
misc_deregister(&wdt_miscdev);
err_out:
+ pci_dev_put(alim7101_pmu);
return rc;
}
diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91_wdt.c
index cc266715ea320b..4e7a1145e78fd4 100644
--- a/drivers/char/watchdog/at91_wdt.c
+++ b/drivers/char/watchdog/at91_wdt.c
@@ -168,7 +168,7 @@ static int at91_wdt_ioctl(struct inode *inode, struct file *file,
return 0;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index e3cefc538b4047..488902231cc237 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -125,7 +125,7 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file,
return -EINVAL;
return 0;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
index 04c7e49918db0b..00bdabb90f27b9 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -183,7 +183,7 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm
}
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/char/watchdog/ep93xx_wdt.c
index 77c8a955ae9e1f..01cf123b1616db 100644
--- a/drivers/char/watchdog/ep93xx_wdt.c
+++ b/drivers/char/watchdog/ep93xx_wdt.c
@@ -144,7 +144,7 @@ static int
ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
index 62dbccb2f6df97..4f4269754c462f 100644
--- a/drivers/char/watchdog/eurotechwdt.c
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -240,7 +240,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
switch(cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c
index 870539eabbf3a9..fb64df4d7c8720 100644
--- a/drivers/char/watchdog/i6300esb.c
+++ b/drivers/char/watchdog/i6300esb.c
@@ -315,7 +315,7 @@ static int esb_ioctl (struct inode *inode, struct file *file,
return put_user(heartbeat, p);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
index 8385dd36eefe0f..e0627d79707b27 100644
--- a/drivers/char/watchdog/i8xx_tco.c
+++ b/drivers/char/watchdog/i8xx_tco.c
@@ -356,7 +356,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
@@ -406,18 +406,18 @@ static struct notifier_block i8xx_tco_notifier = {
* want to register another driver on the same PCI id.
*/
static struct pci_device_id i8xx_tco_pci_tbl[] = {
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, }, /* End of list */
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1) },
+ { }, /* End of list */
};
MODULE_DEVICE_TABLE (pci, i8xx_tco_pci_tbl);
@@ -434,12 +434,11 @@ static unsigned char __init i8xx_tco_getdevice (void)
* Find the PCI device
*/
- while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev)
if (pci_match_id(i8xx_tco_pci_tbl, dev)) {
i8xx_tco_pci = dev;
break;
}
- }
if (i8xx_tco_pci) {
/*
@@ -454,6 +453,7 @@ static unsigned char __init i8xx_tco_getdevice (void)
/* Something's wrong here, ACPIBASE has to be set */
if (badr == 0x0001 || badr == 0x0000) {
printk (KERN_ERR PFX "failed to get TCOBASE address\n");
+ pci_dev_put(i8xx_tco_pci);
return 0;
}
@@ -465,6 +465,7 @@ static unsigned char __init i8xx_tco_getdevice (void)
pci_read_config_byte (i8xx_tco_pci, 0xd4, &val1);
if (val1 & 0x02) {
printk (KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
+ pci_dev_put(i8xx_tco_pci);
return 0; /* Cannot reset NO_REBOOT bit */
}
}
@@ -476,6 +477,7 @@ static unsigned char __init i8xx_tco_getdevice (void)
if (!request_region (SMI_EN + 1, 1, "i8xx TCO")) {
printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
SMI_EN + 1);
+ pci_dev_put(i8xx_tco_pci);
return 0;
}
val1 = inb (SMI_EN + 1);
@@ -542,6 +544,7 @@ unreg_notifier:
unreg_region:
release_region (TCOBASE, 0x10);
out:
+ pci_dev_put(i8xx_tco_pci);
return ret;
}
@@ -555,6 +558,8 @@ static void __exit watchdog_cleanup (void)
misc_deregister (&i8xx_tco_miscdev);
unregister_reboot_notifier(&i8xx_tco_notifier);
release_region (TCOBASE, 0x10);
+
+ pci_dev_put(i8xx_tco_pci);
}
module_init(watchdog_init);
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c
new file mode 100644
index 00000000000000..8f89948832fc3e
--- /dev/null
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -0,0 +1,735 @@
+/*
+ * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
+ *
+ * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
+ * provide warranty for any of this software. This material is
+ * provided "AS-IS" and at no charge.
+ *
+ * The TCO watchdog is implemented in the following I/O controller hubs:
+ * (See the intel documentation on http://developer.intel.com.)
+ * 82801AA (ICH) : document number 290655-003, 290677-014,
+ * 82801AB (ICHO) : document number 290655-003, 290677-014,
+ * 82801BA (ICH2) : document number 290687-002, 298242-027,
+ * 82801BAM (ICH2-M) : document number 290687-002, 298242-027,
+ * 82801CA (ICH3-S) : document number 290733-003, 290739-013,
+ * 82801CAM (ICH3-M) : document number 290716-001, 290718-007,
+ * 82801DB (ICH4) : document number 290744-001, 290745-020,
+ * 82801DBM (ICH4-M) : document number 252337-001, 252663-005,
+ * 82801E (C-ICH) : document number 273599-001, 273645-002,
+ * 82801EB (ICH5) : document number 252516-001, 252517-003,
+ * 82801ER (ICH5R) : document number 252516-001, 252517-003,
+ * 82801FB (ICH6) : document number 301473-002, 301474-007,
+ * 82801FR (ICH6R) : document number 301473-002, 301474-007,
+ * 82801FBM (ICH6-M) : document number 301473-002, 301474-007,
+ * 82801FW (ICH6W) : document number 301473-001, 301474-007,
+ * 82801FRW (ICH6RW) : document number 301473-001, 301474-007,
+ * 82801GB (ICH7) : document number 307013-002, 307014-009,
+ * 82801GR (ICH7R) : document number 307013-002, 307014-009,
+ * 82801GDH (ICH7DH) : document number 307013-002, 307014-009,
+ * 82801GBM (ICH7-M) : document number 307013-002, 307014-009,
+ * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009,
+ * 6300ESB (6300ESB) : document number 300641-003
+ */
+
+/*
+ * Includes, defines, variables, module parameters, ...
+ */
+
+/* Module and version information */
+#define DRV_NAME "iTCO_wdt"
+#define DRV_VERSION "1.00"
+#define DRV_RELDATE "30-Jul-2006"
+#define PFX DRV_NAME ": "
+
+/* Includes */
+#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */
+#include <linux/module.h> /* For module specific items */
+#include <linux/moduleparam.h> /* For new moduleparam's */
+#include <linux/types.h> /* For standard types (like size_t) */
+#include <linux/errno.h> /* For the -ENODEV/... values */
+#include <linux/kernel.h> /* For printk/panic/... */
+#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
+#include <linux/watchdog.h> /* For the watchdog specific items */
+#include <linux/init.h> /* For __init/__exit/... */
+#include <linux/fs.h> /* For file operations */
+#include <linux/platform_device.h> /* For platform_driver framework */
+#include <linux/pci.h> /* For pci functions */
+#include <linux/ioport.h> /* For io-port access */
+#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
+
+#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
+#include <asm/io.h> /* For inb/outb/... */
+
+/* TCO related info */
+enum iTCO_chipsets {
+ TCO_ICH = 0, /* ICH */
+ TCO_ICH0, /* ICH0 */
+ TCO_ICH2, /* ICH2 */
+ TCO_ICH2M, /* ICH2-M */
+ TCO_ICH3, /* ICH3-S */
+ TCO_ICH3M, /* ICH3-M */
+ TCO_ICH4, /* ICH4 */
+ TCO_ICH4M, /* ICH4-M */
+ TCO_CICH, /* C-ICH */
+ TCO_ICH5, /* ICH5 & ICH5R */
+ TCO_6300ESB, /* 6300ESB */
+ TCO_ICH6, /* ICH6 & ICH6R */
+ TCO_ICH6M, /* ICH6-M */
+ TCO_ICH6W, /* ICH6W & ICH6RW */
+ TCO_ICH7, /* ICH7 & ICH7R */
+ TCO_ICH7M, /* ICH7-M */
+ TCO_ICH7MDH, /* ICH7-M DH */
+};
+
+static struct {
+ char *name;
+ unsigned int iTCO_version;
+} iTCO_chipset_info[] __devinitdata = {
+ {"ICH", 1},
+ {"ICH0", 1},
+ {"ICH2", 1},
+ {"ICH2-M", 1},
+ {"ICH3-S", 1},
+ {"ICH3-M", 1},
+ {"ICH4", 1},
+ {"ICH4-M", 1},
+ {"C-ICH", 1},
+ {"ICH5 or ICH5R", 1},
+ {"6300ESB", 1},
+ {"ICH6 or ICH6R", 2},
+ {"ICH6-M", 2},
+ {"ICH6W or ICH6RW", 2},
+ {"ICH7 or ICH7R", 2},
+ {"ICH7-M", 2},
+ {"ICH7-M DH", 2},
+ {NULL,0}
+};
+
+/*
+ * This data only exists for exporting the supported PCI ids
+ * via MODULE_DEVICE_TABLE. We do not actually register a
+ * pci_driver, because the I/O Controller Hub has also other
+ * functions that probably will be registered by other drivers.
+ */
+static struct pci_device_id iTCO_wdt_pci_tbl[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH0 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_CICH },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH5 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_6300ESB },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6W },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH },
+ { 0, }, /* End of list */
+};
+MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
+
+/* Address definitions for the TCO */
+#define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 /* TCO base address */
+#define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 /* SMI Control and Enable Register */
+
+#define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */
+#define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */
+#define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
+#define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */
+#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
+#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */
+#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */
+#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */
+#define TCOv2_TMR TCOBASE + 0x12 /* TCOv2 Timer Initial Value */
+
+/* internal variables */
+static unsigned long is_active;
+static char expect_release;
+static struct { /* this is private data for the iTCO_wdt device */
+ unsigned int iTCO_version; /* TCO version/generation */
+ unsigned long ACPIBASE; /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
+ unsigned long __iomem *gcs; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */
+ spinlock_t io_lock; /* the lock for io operations */
+ struct pci_dev *pdev; /* the PCI-device */
+} iTCO_wdt_private;
+
+static struct platform_device *iTCO_wdt_platform_device; /* the watchdog platform device */
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Some TCO specific functions
+ */
+
+static inline unsigned int seconds_to_ticks(int seconds)
+{
+ /* the internal timer is stored as ticks which decrement
+ * every 0.6 seconds */
+ return (seconds * 10) / 6;
+}
+
+static void iTCO_wdt_set_NO_REBOOT_bit(void)
+{
+ u32 val32;
+
+ /* Set the NO_REBOOT bit: this disables reboots */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ val32 = readl(iTCO_wdt_private.gcs);
+ val32 |= 0x00000020;
+ writel(val32, iTCO_wdt_private.gcs);
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+ val32 |= 0x00000002;
+ pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
+ }
+}
+
+static int iTCO_wdt_unset_NO_REBOOT_bit(void)
+{
+ int ret = 0;
+ u32 val32;
+
+ /* Unset the NO_REBOOT bit: this enables reboots */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ val32 = readl(iTCO_wdt_private.gcs);
+ val32 &= 0xffffffdf;
+ writel(val32, iTCO_wdt_private.gcs);
+
+ val32 = readl(iTCO_wdt_private.gcs);
+ if (val32 & 0x00000020)
+ ret = -EIO;
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+ val32 &= 0xfffffffd;
+ pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
+
+ pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+ if (val32 & 0x00000002)
+ ret = -EIO;
+ }
+
+ return ret; /* returns: 0 = OK, -EIO = Error */
+}
+
+static int iTCO_wdt_start(void)
+{
+ unsigned int val;
+
+ spin_lock(&iTCO_wdt_private.io_lock);
+
+ /* disable chipset's NO_REBOOT bit */
+ if (iTCO_wdt_unset_NO_REBOOT_bit()) {
+ printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
+ return -EIO;
+ }
+
+ /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
+ val = inw(TCO1_CNT);
+ val &= 0xf7ff;
+ outw(val, TCO1_CNT);
+ val = inw(TCO1_CNT);
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ if (val & 0x0800)
+ return -1;
+ return 0;
+}
+
+static int iTCO_wdt_stop(void)
+{
+ unsigned int val;
+
+ spin_lock(&iTCO_wdt_private.io_lock);
+
+ /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
+ val = inw(TCO1_CNT);
+ val |= 0x0800;
+ outw(val, TCO1_CNT);
+ val = inw(TCO1_CNT);
+
+ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+ iTCO_wdt_set_NO_REBOOT_bit();
+
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ if ((val & 0x0800) == 0)
+ return -1;
+ return 0;
+}
+
+static int iTCO_wdt_keepalive(void)
+{
+ spin_lock(&iTCO_wdt_private.io_lock);
+
+ /* Reload the timer by writing to the TCO Timer Counter register */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ outw(0x01, TCO_RLD);
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ outb(0x01, TCO_RLD);
+ }
+
+ spin_unlock(&iTCO_wdt_private.io_lock);
+ return 0;
+}
+
+static int iTCO_wdt_set_heartbeat(int t)
+{
+ unsigned int val16;
+ unsigned char val8;
+ unsigned int tmrval;
+
+ tmrval = seconds_to_ticks(t);
+ /* from the specs: */
+ /* "Values of 0h-3h are ignored and should not be attempted" */
+ if (tmrval < 0x04)
+ return -EINVAL;
+ if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
+ ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
+ return -EINVAL;
+
+ /* Write new heartbeat to watchdog */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ spin_lock(&iTCO_wdt_private.io_lock);
+ val16 = inw(TCOv2_TMR);
+ val16 &= 0xfc00;
+ val16 |= tmrval;
+ outw(val16, TCOv2_TMR);
+ val16 = inw(TCOv2_TMR);
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ if ((val16 & 0x3ff) != tmrval)
+ return -EINVAL;
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ spin_lock(&iTCO_wdt_private.io_lock);
+ val8 = inb(TCOv1_TMR);
+ val8 &= 0xc0;
+ val8 |= (tmrval & 0xff);
+ outb(val8, TCOv1_TMR);
+ val8 = inb(TCOv1_TMR);
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ if ((val8 & 0x3f) != tmrval)
+ return -EINVAL;
+ }
+
+ heartbeat = t;
+ return 0;
+}
+
+static int iTCO_wdt_get_timeleft (int *time_left)
+{
+ unsigned int val16;
+ unsigned char val8;
+
+ /* read the TCO Timer */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ spin_lock(&iTCO_wdt_private.io_lock);
+ val16 = inw(TCO_RLD);
+ val16 &= 0x3ff;
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ *time_left = (val16 * 6) / 10;
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ spin_lock(&iTCO_wdt_private.io_lock);
+ val8 = inb(TCO_RLD);
+ val8 &= 0x3f;
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ *time_left = (val8 * 6) / 10;
+ }
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int iTCO_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;
+
+ /*
+ * Reload and activate timer
+ */
+ iTCO_wdt_keepalive();
+ iTCO_wdt_start();
+ return nonseekable_open(inode, file);
+}
+
+static int iTCO_wdt_release (struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer.
+ */
+ if (expect_release == 42) {
+ iTCO_wdt_stop();
+ } else {
+ printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ iTCO_wdt_keepalive();
+ }
+ clear_bit(0, &is_active);
+ expect_release = 0;
+ return 0;
+}
+
+static ssize_t iTCO_wdt_write (struct file *file, const char __user *data,
+ size_t len, loff_t * ppos)
+{
+ /* See if we got the magic character 'V' and reload the timer */
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ /* note: just in case someone wrote the magic character
+ * five months ago... */
+ expect_release = 0;
+
+ /* scan to see whether or not we got the magic character */
+ for (i = 0; i != len; i++) {
+ char c;
+ if (get_user(c, data+i))
+ return -EFAULT;
+ if (c == 'V')
+ expect_release = 42;
+ }
+ }
+
+ /* someone wrote to us, we should reload the timer */
+ iTCO_wdt_keepalive();
+ }
+ return len;
+}
+
+static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int new_options, retval = -EINVAL;
+ int new_heartbeat;
+ int time_left;
+ void __user *argp = (void __user *)arg;
+ int __user *p = argp;
+ static struct watchdog_info ident = {
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+ .firmware_version = 0,
+ .identity = DRV_NAME,
+ };
+
+ 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:
+ iTCO_wdt_keepalive();
+ return 0;
+
+ case WDIOC_SETOPTIONS:
+ {
+ if (get_user(new_options, p))
+ return -EFAULT;
+
+ if (new_options & WDIOS_DISABLECARD) {
+ iTCO_wdt_stop();
+ retval = 0;
+ }
+
+ if (new_options & WDIOS_ENABLECARD) {
+ iTCO_wdt_keepalive();
+ iTCO_wdt_start();
+ retval = 0;
+ }
+
+ return retval;
+ }
+
+ case WDIOC_SETTIMEOUT:
+ {
+ if (get_user(new_heartbeat, p))
+ return -EFAULT;
+
+ if (iTCO_wdt_set_heartbeat(new_heartbeat))
+ return -EINVAL;
+
+ iTCO_wdt_keepalive();
+ /* Fall */
+ }
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+
+ case WDIOC_GETTIMELEFT:
+ {
+ if (iTCO_wdt_get_timeleft(&time_left))
+ return -EINVAL;
+
+ return put_user(time_left, p);
+ }
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static struct file_operations iTCO_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = iTCO_wdt_write,
+ .ioctl = iTCO_wdt_ioctl,
+ .open = iTCO_wdt_open,
+ .release = iTCO_wdt_release,
+};
+
+static struct miscdevice iTCO_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &iTCO_wdt_fops,
+};
+
+/*
+ * Init & exit routines
+ */
+
+static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev)
+{
+ int ret;
+ u32 base_address;
+ unsigned long RCBA;
+ unsigned long val32;
+
+ /*
+ * Find the ACPI/PM base I/O address which is the base
+ * for the TCO registers (TCOBASE=ACPIBASE + 0x60)
+ * ACPIBASE is bits [15:7] from 0x40-0x43
+ */
+ pci_read_config_dword(pdev, 0x40, &base_address);
+ base_address &= 0x00007f80;
+ if (base_address == 0x00000000) {
+ /* Something's wrong here, ACPIBASE has to be set */
+ printk(KERN_ERR PFX "failed to get TCOBASE address\n");
+ pci_dev_put(pdev);
+ return -ENODEV;
+ }
+ iTCO_wdt_private.iTCO_version = iTCO_chipset_info[ent->driver_data].iTCO_version;
+ iTCO_wdt_private.ACPIBASE = base_address;
+ iTCO_wdt_private.pdev = pdev;
+
+ /* Get the Memory-Mapped GCS register, we need it for the NO_REBOOT flag (TCO v2) */
+ /* To get access to it you have to read RCBA from PCI Config space 0xf0
+ and use it as base. GCS = RCBA + ICH6_GCS(0x3410). */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ pci_read_config_dword(pdev, 0xf0, &base_address);
+ RCBA = base_address & 0xffffc000;
+ iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410),4);
+ }
+
+ /* Check chipset's NO_REBOOT bit */
+ if (iTCO_wdt_unset_NO_REBOOT_bit()) {
+ printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
+ ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
+ goto out;
+ }
+
+ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+ iTCO_wdt_set_NO_REBOOT_bit();
+
+ /* Set the TCO_EN bit in SMI_EN register */
+ if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
+ printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
+ SMI_EN );
+ ret = -EIO;
+ goto out;
+ }
+ val32 = inl(SMI_EN);
+ val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
+ outl(val32, SMI_EN);
+ release_region(SMI_EN, 4);
+
+ /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */
+ if (!request_region (TCOBASE, 0x20, "iTCO_wdt")) {
+ printk (KERN_ERR PFX "I/O address 0x%04lx already in use\n",
+ TCOBASE);
+ ret = -EIO;
+ goto out;
+ }
+
+ printk(KERN_INFO PFX "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
+ iTCO_chipset_info[ent->driver_data].name,
+ iTCO_chipset_info[ent->driver_data].iTCO_version,
+ TCOBASE);
+
+ /* Clear out the (probably old) status */
+ outb(0, TCO1_STS);
+ outb(3, TCO2_STS);
+
+ /* Make sure the watchdog is not running */
+ iTCO_wdt_stop();
+
+ /* Check that the heartbeat value is within it's range ; if not reset to the default */
+ if (iTCO_wdt_set_heartbeat(heartbeat)) {
+ iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
+ printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39 (TCO v1) or 613 (TCO v2), using %d\n",
+ heartbeat);
+ }
+
+ ret = misc_register(&iTCO_wdt_miscdev);
+ if (ret != 0) {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto unreg_region;
+ }
+
+ printk (KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+ heartbeat, nowayout);
+
+ return 0;
+
+unreg_region:
+ release_region (TCOBASE, 0x20);
+out:
+ if (iTCO_wdt_private.iTCO_version == 2)
+ iounmap(iTCO_wdt_private.gcs);
+ pci_dev_put(iTCO_wdt_private.pdev);
+ iTCO_wdt_private.ACPIBASE = 0;
+ return ret;
+}
+
+static void iTCO_wdt_cleanup(void)
+{
+ /* Stop the timer before we leave */
+ if (!nowayout)
+ iTCO_wdt_stop();
+
+ /* Deregister */
+ misc_deregister(&iTCO_wdt_miscdev);
+ release_region(TCOBASE, 0x20);
+ if (iTCO_wdt_private.iTCO_version == 2)
+ iounmap(iTCO_wdt_private.gcs);
+ pci_dev_put(iTCO_wdt_private.pdev);
+ iTCO_wdt_private.ACPIBASE = 0;
+}
+
+static int iTCO_wdt_probe(struct platform_device *dev)
+{
+ int found = 0;
+ struct pci_dev *pdev = NULL;
+ const struct pci_device_id *ent;
+
+ spin_lock_init(&iTCO_wdt_private.io_lock);
+
+ for_each_pci_dev(pdev) {
+ ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
+ if (ent) {
+ if (!(iTCO_wdt_init(pdev, ent, dev))) {
+ found++;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ printk(KERN_INFO PFX "No card detected\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int iTCO_wdt_remove(struct platform_device *dev)
+{
+ if (iTCO_wdt_private.ACPIBASE)
+ iTCO_wdt_cleanup();
+
+ return 0;
+}
+
+static void iTCO_wdt_shutdown(struct platform_device *dev)
+{
+ iTCO_wdt_stop();
+}
+
+#define iTCO_wdt_suspend NULL
+#define iTCO_wdt_resume NULL
+
+static struct platform_driver iTCO_wdt_driver = {
+ .probe = iTCO_wdt_probe,
+ .remove = iTCO_wdt_remove,
+ .shutdown = iTCO_wdt_shutdown,
+ .suspend = iTCO_wdt_suspend,
+ .resume = iTCO_wdt_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init iTCO_wdt_init_module(void)
+{
+ int err;
+
+ printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s (%s)\n",
+ DRV_VERSION, DRV_RELDATE);
+
+ err = platform_driver_register(&iTCO_wdt_driver);
+ if (err)
+ return err;
+
+ iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
+ if (IS_ERR(iTCO_wdt_platform_device)) {
+ err = PTR_ERR(iTCO_wdt_platform_device);
+ goto unreg_platform_driver;
+ }
+
+ return 0;
+
+unreg_platform_driver:
+ platform_driver_unregister(&iTCO_wdt_driver);
+ return err;
+}
+
+static void __exit iTCO_wdt_cleanup_module(void)
+{
+ platform_device_unregister(iTCO_wdt_platform_device);
+ platform_driver_unregister(&iTCO_wdt_driver);
+ printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+}
+
+module_init(iTCO_wdt_init_module);
+module_exit(iTCO_wdt_cleanup_module);
+
+MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
+MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c
index fd95f732779869..c1ed209a138ca3 100644
--- a/drivers/char/watchdog/ib700wdt.c
+++ b/drivers/char/watchdog/ib700wdt.c
@@ -199,7 +199,7 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
index 26ceee7a4df092..dd6760f1a23ba4 100644
--- a/drivers/char/watchdog/ibmasr.c
+++ b/drivers/char/watchdog/ibmasr.c
@@ -295,7 +295,7 @@ static int asr_ioctl(struct inode *inode, struct file *file,
}
}
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
static int asr_open(struct inode *inode, struct file *file)
diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c
index dacc1c20a31074..0bc239308989d5 100644
--- a/drivers/char/watchdog/indydog.c
+++ b/drivers/char/watchdog/indydog.c
@@ -112,7 +112,7 @@ static int indydog_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info *)arg,
&ident, sizeof(ident)))
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
index 692908819e2665..fd955dbd588cb7 100644
--- a/drivers/char/watchdog/ixp2000_wdt.c
+++ b/drivers/char/watchdog/ixp2000_wdt.c
@@ -1,5 +1,5 @@
/*
- * drivers/watchdog/ixp2000_wdt.c
+ * drivers/char/watchdog/ixp2000_wdt.c
*
* Watchdog driver for Intel IXP2000 network processors
*
@@ -107,7 +107,7 @@ static int
ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
int time;
switch (cmd) {
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
index 9db5cf2c38c370..5864bb865cfe54 100644
--- a/drivers/char/watchdog/ixp4xx_wdt.c
+++ b/drivers/char/watchdog/ixp4xx_wdt.c
@@ -1,5 +1,5 @@
/*
- * drivers/watchdog/ixp4xx_wdt.c
+ * drivers/char/watchdog/ixp4xx_wdt.c
*
* Watchdog driver for Intel IXP4xx network processors
*
@@ -102,7 +102,7 @@ static int
ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
int time;
switch (cmd) {
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index 23734e07fb2250..276577d08fba2f 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -329,7 +329,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
@@ -426,8 +426,7 @@ static int __init zf_init(void)
printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n");
ret = zf_get_ZFL_version();
- printk("%#x\n", ret);
- if((!ret) || (ret != 0xffff)){
+ if ((!ret) || (ret == 0xffff)) {
printk(KERN_WARNING PFX ": no ZF-Logic found\n");
return -ENODEV;
}
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index ae943324d2511e..c2dac0aa1d6254 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -185,7 +185,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
mixcomwd_ping();
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c
index a480903ee1a59c..18ca752e2f904f 100644
--- a/drivers/char/watchdog/mpc83xx_wdt.c
+++ b/drivers/char/watchdog/mpc83xx_wdt.c
@@ -125,7 +125,7 @@ static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETTIMEOUT:
return put_user(timeout_sec, p);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
index 35dd9e6e114023..8aaed10dd4999e 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -126,7 +126,7 @@ static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index 54b3c56ead0df8..02d336ace50477 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -221,7 +221,7 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
} uarg;
if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
- return -ENOIOCTLCMD;
+ return -ENOTTY;
if (_IOC_DIR(cmd) & _IOC_WRITE) {
ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
@@ -271,7 +271,7 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
index 5c8fab345b4036..b887cdb0133428 100644
--- a/drivers/char/watchdog/mv64x60_wdt.c
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -160,7 +160,7 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
index cd7d1b6a5d9fb2..6f8515db5b0760 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/char/watchdog/pcwd.c
@@ -572,7 +572,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
switch(cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
if(copy_to_user(argp, &ident, sizeof(ident)))
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
index c7cfd6dbfe1b29..2de6e497c1402e 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -541,7 +541,7 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index b7ae73dcdd0823..77662cb0ac46e3 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -445,7 +445,7 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c
new file mode 100644
index 00000000000000..db2731ba88e303
--- /dev/null
+++ b/drivers/char/watchdog/pnx4008_wdt.c
@@ -0,0 +1,362 @@
+/*
+ * drivers/char/watchdog/pnx4008_wdt.c
+ *
+ * Watchdog driver for PNX4008 board
+ *
+ * Authors: Dmitry Chigirev <source@mvista.com>,
+ * Vitaly Wool <vitalywool@gmail.com>
+ * Based on sa1100 driver,
+ * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * 2005-2006 (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/config.h>
+#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/ioport.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define MODULE_NAME "PNX4008-WDT: "
+
+/* WatchDog Timer - Chapter 23 Page 207 */
+
+#define DEFAULT_HEARTBEAT 19
+#define MAX_HEARTBEAT 60
+
+/* Watchdog timer register set definition */
+#define WDTIM_INT(p) ((p) + 0x0)
+#define WDTIM_CTRL(p) ((p) + 0x4)
+#define WDTIM_COUNTER(p) ((p) + 0x8)
+#define WDTIM_MCTRL(p) ((p) + 0xC)
+#define WDTIM_MATCH0(p) ((p) + 0x10)
+#define WDTIM_EMR(p) ((p) + 0x14)
+#define WDTIM_PULSE(p) ((p) + 0x18)
+#define WDTIM_RES(p) ((p) + 0x1C)
+
+/* WDTIM_INT bit definitions */
+#define MATCH_INT 1
+
+/* WDTIM_CTRL bit definitions */
+#define COUNT_ENAB 1
+#define RESET_COUNT (1<<1)
+#define DEBUG_EN (1<<2)
+
+/* WDTIM_MCTRL bit definitions */
+#define MR0_INT 1
+#undef RESET_COUNT0
+#define RESET_COUNT0 (1<<2)
+#define STOP_COUNT0 (1<<2)
+#define M_RES1 (1<<3)
+#define M_RES2 (1<<4)
+#define RESFRC1 (1<<5)
+#define RESFRC2 (1<<6)
+
+/* WDTIM_EMR bit definitions */
+#define EXT_MATCH0 1
+#define MATCH_OUTPUT_HIGH (2<<4) /*a MATCH_CTRL setting */
+
+/* WDTIM_RES bit definitions */
+#define WDOG_RESET 1 /* read only */
+
+#define WDOG_COUNTER_RATE 13000000 /*the counter clock is 13 MHz fixed */
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+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 unsigned long boot_status;
+
+static struct resource *wdt_mem;
+static void __iomem *wdt_base;
+struct clk *wdt_clk;
+
+static void wdt_enable(void)
+{
+ spin_lock(&io_lock);
+
+ if (wdt_clk)
+ clk_set_rate(wdt_clk, 1);
+
+ /* stop counter, initiate counter reset */
+ __raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
+ /*wait for reset to complete. 100% guarantee event */
+ while (__raw_readl(WDTIM_COUNTER(wdt_base)))
+ cpu_relax();
+ /* internal and external reset, stop after that */
+ __raw_writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0,
+ WDTIM_MCTRL(wdt_base));
+ /* configure match output */
+ __raw_writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
+ /* clear interrupt, just in case */
+ __raw_writel(MATCH_INT, WDTIM_INT(wdt_base));
+ /* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */
+ __raw_writel(0xFFFF, WDTIM_PULSE(wdt_base));
+ __raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
+ /*enable counter, stop when debugger active */
+ __raw_writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
+
+ spin_unlock(&io_lock);
+}
+
+static void wdt_disable(void)
+{
+ spin_lock(&io_lock);
+
+ __raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */
+ if (wdt_clk)
+ clk_set_rate(wdt_clk, 0);
+
+ spin_unlock(&io_lock);
+}
+
+static int pnx4008_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();
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t
+pnx4008_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t * ppos)
+{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ 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_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "PNX4008 Watchdog",
+};
+
+static int
+pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = -ENOTTY;
+ int time;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 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_SETTIMEOUT:
+ ret = get_user(time, (int *)arg);
+ if (ret)
+ break;
+
+ if (time <= 0 || time > MAX_HEARTBEAT) {
+ ret = -EINVAL;
+ break;
+ }
+
+ heartbeat = time;
+ wdt_enable();
+ /* Fall through */
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_enable();
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int pnx4008_wdt_release(struct inode *inode, struct file *file)
+{
+ if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+ printk(KERN_WARNING "WATCHDOG: Device closed unexpectdly\n");
+
+ wdt_disable();
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return 0;
+}
+
+static struct file_operations pnx4008_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = pnx4008_wdt_write,
+ .ioctl = pnx4008_wdt_ioctl,
+ .open = pnx4008_wdt_open,
+ .release = pnx4008_wdt_release,
+};
+
+static struct miscdevice pnx4008_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &pnx4008_wdt_fops,
+};
+
+static int pnx4008_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
+ "PNX4008 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 resouce\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 *)IO_ADDRESS(res->start);
+
+ wdt_clk = clk_get(&pdev->dev, "wdt_ck");
+ if (!wdt_clk) {
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ goto out;
+ } else
+ clk_set_rate(wdt_clk, 1);
+
+ ret = misc_register(&pnx4008_wdt_miscdev);
+ if (ret < 0) {
+ printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ clk_set_rate(wdt_clk, 0);
+ } else {
+ boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
+ WDIOF_CARDRESET : 0;
+ wdt_disable(); /*disable for now */
+ set_bit(WDT_DEVICE_INITED, &wdt_status);
+ }
+
+out:
+ return ret;
+}
+
+static int pnx4008_wdt_remove(struct platform_device *pdev)
+{
+ misc_deregister(&pnx4008_wdt_miscdev);
+ if (wdt_clk) {
+ clk_set_rate(wdt_clk, 0);
+ clk_put(wdt_clk);
+ wdt_clk = NULL;
+ }
+ 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 = pnx4008_wdt_probe,
+ .remove = pnx4008_wdt_remove,
+};
+
+static int __init pnx4008_wdt_init(void)
+{
+ return platform_driver_register(&platform_wdt_driver);
+}
+
+static void __exit pnx4008_wdt_exit(void)
+{
+ return platform_driver_unregister(&platform_wdt_driver);
+}
+
+module_init(pnx4008_wdt_init);
+module_exit(pnx4008_wdt_exit);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("PNX4008 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_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+ "Set to 1 to keep watchdog running after device release");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index be978e8ed75494..b36a04ae9ab8e9 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -62,7 +62,7 @@
#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
-static int nowayout = WATCHDOG_NOWAYOUT;
+static int nowayout = WATCHDOG_NOWAYOUT;
static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
static int soft_noboot = 0;
@@ -213,11 +213,10 @@ static int s3c2410wdt_open(struct inode *inode, struct file *file)
if(down_trylock(&open_lock))
return -EBUSY;
- if (nowayout) {
+ if (nowayout)
__module_get(THIS_MODULE);
- } else {
- allow_close = CLOSE_STATE_ALLOW;
- }
+
+ allow_close = CLOSE_STATE_NOT;
/* start the timer */
s3c2410wdt_start();
@@ -230,6 +229,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file)
* Shut off the timer.
* Lock it in if it's a module and we set nowayout
*/
+
if (allow_close == CLOSE_STATE_ALLOW) {
s3c2410wdt_stop();
} else {
@@ -288,7 +288,7 @@ static int s3c2410wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &s3c2410_wdt_ident,
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
index 1fc16d99578879..33c1137f17d6d3 100644
--- a/drivers/char/watchdog/sa1100_wdt.c
+++ b/drivers/char/watchdog/sa1100_wdt.c
@@ -90,7 +90,7 @@ static struct watchdog_info ident = {
static int sa1100dog_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
int time;
void __user *argp = (void __user *)arg;
int __user *p = argp;
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
index 4663c2fd53cd6f..c7b2045bc76b51 100644
--- a/drivers/char/watchdog/sbc60xxwdt.c
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -235,7 +235,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
case WDIOC_GETSTATUS:
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
index bfc475dabe6d76..8882b427d24f44 100644
--- a/drivers/char/watchdog/sbc_epx_c3.c
+++ b/drivers/char/watchdog/sbc_epx_c3.c
@@ -141,7 +141,7 @@ static int epx_c3_ioctl(struct inode *inode, struct file *file,
return retval;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 7c3cf293a5afc3..d8d0f28e0acf9a 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -180,7 +180,7 @@ static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int
switch (cmd) {
default:
- return -ENOIOCTLCMD; /* Keep Pavel Machek amused ;) */
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof ident))
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
index 2c7c9db71be81e..caec37ba750a68 100644
--- a/drivers/char/watchdog/sc520_wdt.c
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -290,7 +290,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
case WDIOC_GETSTATUS:
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
index c561299a5537b4..fc0e0347f9d24b 100644
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -166,7 +166,7 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
if(copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
index e5b8c64f1d65ac..dc403629aeb3d7 100644
--- a/drivers/char/watchdog/shwdt.c
+++ b/drivers/char/watchdog/shwdt.c
@@ -360,7 +360,7 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file,
return retval;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
index ef8da517545add..4067e1f8a36878 100644
--- a/drivers/char/watchdog/softdog.c
+++ b/drivers/char/watchdog/softdog.c
@@ -203,7 +203,7 @@ static int softdog_ioctl(struct inode *inode, struct file *file,
};
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0;
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index 13f16d41c2fd33..b4adc527e687e8 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -223,7 +223,7 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c
index ccf6c0915945d8..b0e5f84d6bafdc 100644
--- a/drivers/char/watchdog/w83877f_wdt.c
+++ b/drivers/char/watchdog/w83877f_wdt.c
@@ -252,7 +252,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
case WDIOC_GETSTATUS:
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c
index 98f4e17db70a47..2c8d5d8bd4e853 100644
--- a/drivers/char/watchdog/w83977f_wdt.c
+++ b/drivers/char/watchdog/w83977f_wdt.c
@@ -393,7 +393,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0;
diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c
index 2bb6a9d6ad2805..163e028ef9ed6c 100644
--- a/drivers/char/watchdog/wafer5823wdt.c
+++ b/drivers/char/watchdog/wafer5823wdt.c
@@ -174,7 +174,7 @@ static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/wdrtas.c b/drivers/char/watchdog/wdrtas.c
index 5c38cdf4173120..1d64e277567dc4 100644
--- a/drivers/char/watchdog/wdrtas.c
+++ b/drivers/char/watchdog/wdrtas.c
@@ -385,7 +385,7 @@ wdrtas_ioctl(struct inode *inode, struct file *file,
return put_user(wdrtas_interval, argp);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c
index 70be81e39a61b3..13f23f4a223347 100644
--- a/drivers/char/watchdog/wdt.c
+++ b/drivers/char/watchdog/wdt.c
@@ -341,7 +341,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
diff --git a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c
index 6555fb844f2342..89a249e23fdee2 100644
--- a/drivers/char/watchdog/wdt285.c
+++ b/drivers/char/watchdog/wdt285.c
@@ -137,7 +137,7 @@ watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
unsigned int new_margin;
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
switch(cmd) {
case WDIOC_GETSUPPORT:
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
index a0935bc775f8eb..6253041b235bb2 100644
--- a/drivers/char/watchdog/wdt977.c
+++ b/drivers/char/watchdog/wdt977.c
@@ -361,7 +361,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident,
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
index 5918ca2c9c35b6..74d8cf836e13aa 100644
--- a/drivers/char/watchdog/wdt_pci.c
+++ b/drivers/char/watchdog/wdt_pci.c
@@ -386,7 +386,7 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;