提交 0b87da68 编写于 作者: L Linus Torvalds

Merge git://www.linux-watchdog.org/linux-watchdog

Pull first set of watchdog updates from Wim Van Sebroeck:
 "This pull contains:

   - The removal of ixp2000_wdt
   - The addition of ie6xx_wdt
   - Some documentation fixes
   - Small fixes and improvements

  (Note: Part 2 will contain generic watchdog core changes + conversion
  of some more drivers)"

* git://www.linux-watchdog.org/linux-watchdog:
  Documentation/watchdog: Fix the file descriptor leak when no cmdline arg given
  Documentation/watchdog: close the fd when cmdline arg given
  Documentation/watchdog: Fix a small typo
  watchdog: s3c2410_wdt: Set timeout to actually achieved timeout
  watchdog: wm831x: Convert to gpio_request_one()
  watchdog: via_wdt: depends on PCI
  watchdog: ie6xx_wdt needs io.h
  watchdog: ie6xx_wdt.c: fix printk format warning
  watchdog: Add watchdog driver for Intel Atom E6XX
  watchdog: it87_wdt: Add support for IT8728F watchdog.
  watchdog: i6300esb: don't depend on X86
  watchdog: Use module_pci_driver
  watchdog: sch311x_wdt.c: Remove RESGEN
  watchdog: s3c2410-wdt: Use of_match_ptr().
  watchdog: Device tree support for pnx4008-wdt
  watchdog: ar7_wdt.c: use devm_request_and_ioremap
  watchdog: remove ixp2000 driver
  watchdog: sp5100_tco.c: quiet sparse noise about using plain integer was NULL pointer
* NXP PNX watchdog timer
Required properties:
- compatible: must be "nxp,pnx4008-wdt"
- reg: physical base address of the controller and length of memory mapped
region.
Example:
watchdog@4003C000 {
compatible = "nxp,pnx4008-wdt";
reg = <0x4003C000 0x1000>;
};
......@@ -7,6 +7,7 @@
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/watchdog.h>
......@@ -29,6 +30,14 @@ static void keep_alive(void)
* The main program. Run the program with "-d" to disable the card,
* or "-e" to enable the card.
*/
void term(int sig)
{
close(fd);
fprintf(stderr, "Stopping watchdog ticks...\n");
exit(0);
}
int main(int argc, char *argv[])
{
int flags;
......@@ -47,26 +56,31 @@ int main(int argc, char *argv[])
ioctl(fd, WDIOC_SETOPTIONS, &flags);
fprintf(stderr, "Watchdog card disabled.\n");
fflush(stderr);
exit(0);
goto end;
} else if (!strncasecmp(argv[1], "-e", 2)) {
flags = WDIOS_ENABLECARD;
ioctl(fd, WDIOC_SETOPTIONS, &flags);
fprintf(stderr, "Watchdog card enabled.\n");
fflush(stderr);
exit(0);
goto end;
} else {
fprintf(stderr, "-d to disable, -e to enable.\n");
fprintf(stderr, "run by itself to tick the card.\n");
fflush(stderr);
exit(0);
goto end;
}
} else {
fprintf(stderr, "Watchdog Ticking Away!\n");
fflush(stderr);
}
signal(SIGINT, term);
while(1) {
keep_alive();
sleep(1);
}
end:
close(fd);
return 0;
}
......@@ -59,7 +59,7 @@ It contains following fields:
* bootstatus: status of the device after booting (reported with watchdog
WDIOF_* status bits).
* driver_data: a pointer to the drivers private data of a watchdog device.
This data should only be accessed via the watchdog_set_drvadata and
This data should only be accessed via the watchdog_set_drvdata and
watchdog_get_drvdata routines.
* status: this field contains a number of status bits that give extra
information about the status of the device (Like: is the watchdog timer
......
......@@ -129,17 +129,6 @@ config 977_WATCHDOG
Not sure? It's safe to say N.
config IXP2000_WATCHDOG
tristate "IXP2000 Watchdog"
depends on ARCH_IXP2000
help
Say Y here if to include support for the watchdog timer
in the Intel IXP2000(2400, 2800, 2850) network processors.
This driver can be built as a module by choosing M. The module
will be called ixp2000_wdt.
Say N if you are unsure.
config IXP4XX_WATCHDOG
tristate "IXP4xx Watchdog"
depends on ARCH_IXP4XX
......@@ -543,7 +532,7 @@ config WAFER_WDT
config I6300ESB_WDT
tristate "Intel 6300ESB Timer/Watchdog"
depends on X86 && PCI
depends on PCI
---help---
Hardware driver for the watchdog timer built into the Intel
6300ESB controller hub.
......@@ -551,6 +540,19 @@ config I6300ESB_WDT
To compile this driver as a module, choose M here: the
module will be called i6300esb.
config IE6XX_WDT
tristate "Intel Atom E6xx Watchdog"
depends on X86 && PCI
select WATCHDOG_CORE
select MFD_CORE
select LPC_SCH
---help---
Hardware driver for the watchdog timer built into the Intel
Atom E6XX (TunnelCreek) processor.
To compile this driver as a module, choose M here: the
module will be called ie6xx_wdt.
config INTEL_SCU_WATCHDOG
bool "Intel SCU Watchdog for Mobile Platforms"
depends on X86_MRST
......@@ -607,7 +609,12 @@ config IT87_WDT
depends on X86 && EXPERIMENTAL
---help---
This is the driver for the hardware watchdog on the ITE IT8702,
IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 Super I/O chips.
IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728
Super I/O chips.
If the driver does not work, then make sure that the game port in
the BIOS is enabled.
This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain
amount of time.
......@@ -780,7 +787,7 @@ config SMSC37B787_WDT
config VIA_WDT
tristate "VIA Watchdog Timer"
depends on X86
depends on X86 && PCI
select WATCHDOG_CORE
---help---
This is the driver for the hardware watchdog timer on VIA
......
......@@ -36,7 +36,6 @@ obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
......@@ -81,6 +80,7 @@ obj-$(CONFIG_IB700_WDT) += ib700wdt.o
obj-$(CONFIG_IBMASR) += ibmasr.o
obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
obj-$(CONFIG_IE6XX_WDT) += ie6xx_wdt.o
obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o
ifeq ($(CONFIG_ITCO_VENDOR_SUPPORT),y)
obj-$(CONFIG_ITCO_WDT) += iTCO_vendor_support.o
......
......@@ -282,29 +282,19 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
if (!ar7_regs_wdt) {
pr_err("could not get registers resource\n");
rc = -ENODEV;
goto out;
}
if (!request_mem_region(ar7_regs_wdt->start,
resource_size(ar7_regs_wdt), LONGNAME)) {
pr_warn("watchdog I/O region busy\n");
rc = -EBUSY;
goto out;
return -ENODEV;
}
ar7_wdt = ioremap(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
ar7_wdt = devm_request_and_ioremap(&pdev->dev, ar7_regs_wdt);
if (!ar7_wdt) {
pr_err("could not ioremap registers\n");
rc = -ENXIO;
goto out_mem_region;
return -ENXIO;
}
vbus_clk = clk_get(NULL, "vbus");
if (IS_ERR(vbus_clk)) {
pr_err("could not get vbus clock\n");
rc = PTR_ERR(vbus_clk);
goto out_mem_region;
return PTR_ERR(vbus_clk);
}
ar7_wdt_disable_wdt();
......@@ -314,24 +304,21 @@ static int __devinit ar7_wdt_probe(struct platform_device *pdev)
rc = misc_register(&ar7_wdt_miscdev);
if (rc) {
pr_err("unable to register misc device\n");
goto out_alloc;
goto out;
}
goto out;
return 0;
out_alloc:
iounmap(ar7_wdt);
out_mem_region:
release_mem_region(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
out:
clk_put(vbus_clk);
vbus_clk = NULL;
return rc;
}
static int __devexit ar7_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&ar7_wdt_miscdev);
iounmap(ar7_wdt);
release_mem_region(ar7_regs_wdt->start, resource_size(ar7_regs_wdt));
clk_put(vbus_clk);
vbus_clk = NULL;
return 0;
}
......
......@@ -861,16 +861,6 @@ static struct pci_driver hpwdt_driver = {
.remove = __devexit_p(hpwdt_exit),
};
static void __exit hpwdt_cleanup(void)
{
pci_unregister_driver(&hpwdt_driver);
}
static int __init hpwdt_init(void)
{
return pci_register_driver(&hpwdt_driver);
}
MODULE_AUTHOR("Tom Mingarelli");
MODULE_DESCRIPTION("hp watchdog driver");
MODULE_LICENSE("GPL");
......@@ -889,5 +879,4 @@ module_param(allow_kdump, int, 0);
MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs");
#endif /* !CONFIG_HPWDT_NMI_DECODING */
module_init(hpwdt_init);
module_exit(hpwdt_cleanup);
module_pci_driver(hpwdt_driver);
......@@ -492,19 +492,7 @@ static struct pci_driver esb_driver = {
.shutdown = esb_shutdown,
};
static int __init watchdog_init(void)
{
return pci_register_driver(&esb_driver);
}
static void __exit watchdog_cleanup(void)
{
pci_unregister_driver(&esb_driver);
pr_info("Watchdog Module Unloaded\n");
}
module_init(watchdog_init);
module_exit(watchdog_cleanup);
module_pci_driver(esb_driver);
MODULE_AUTHOR("Ross Biro and David Härdeman");
MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
......
/*
* Intel Atom E6xx Watchdog driver
*
* Copyright (C) 2011 Alexander Stein
* <alexander.stein@systec-electronic.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General
* Public License as published by the Free Software Foundation.
*
* This program is distributed in the hope that 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.
* The full GNU General Public License is included in this
* distribution in the file called COPYING.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/miscdevice.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/spinlock.h>
#define DRIVER_NAME "ie6xx_wdt"
#define PV1 0x00
#define PV2 0x04
#define RR0 0x0c
#define RR1 0x0d
#define WDT_RELOAD 0x01
#define WDT_TOUT 0x02
#define WDTCR 0x10
#define WDT_PRE_SEL 0x04
#define WDT_RESET_SEL 0x08
#define WDT_RESET_EN 0x10
#define WDT_TOUT_EN 0x20
#define DCR 0x14
#define WDTLR 0x18
#define WDT_LOCK 0x01
#define WDT_ENABLE 0x02
#define WDT_TOUT_CNF 0x03
#define MIN_TIME 1
#define MAX_TIME (10 * 60) /* 10 minutes */
#define DEFAULT_TIME 60
static unsigned int timeout = DEFAULT_TIME;
module_param(timeout, uint, 0);
MODULE_PARM_DESC(timeout,
"Default Watchdog timer setting ("
__MODULE_STRING(DEFAULT_TIME) "s)."
"The range is from 1 to 600");
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static u8 resetmode = 0x10;
module_param(resetmode, byte, 0);
MODULE_PARM_DESC(resetmode,
"Resetmode bits: 0x08 warm reset (cold reset otherwise), "
"0x10 reset enable, 0x20 disable toggle GPIO[4] (default=0x10)");
static struct {
unsigned short sch_wdtba;
struct spinlock unlock_sequence;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
#endif
} ie6xx_wdt_data;
/*
* This is needed to write to preload and reload registers
* struct ie6xx_wdt_data.unlock_sequence must be used
* to prevent sequence interrupts
*/
static void ie6xx_wdt_unlock_registers(void)
{
outb(0x80, ie6xx_wdt_data.sch_wdtba + RR0);
outb(0x86, ie6xx_wdt_data.sch_wdtba + RR0);
}
static int ie6xx_wdt_ping(struct watchdog_device *wdd)
{
spin_lock(&ie6xx_wdt_data.unlock_sequence);
ie6xx_wdt_unlock_registers();
outb(WDT_RELOAD, ie6xx_wdt_data.sch_wdtba + RR1);
spin_unlock(&ie6xx_wdt_data.unlock_sequence);
return 0;
}
static int ie6xx_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
{
u32 preload;
u64 clock;
u8 wdtcr;
/* Watchdog clock is PCI Clock (33MHz) */
clock = 33000000;
/* and the preload value is loaded into [34:15] of the down counter */
preload = (t * clock) >> 15;
/*
* Manual states preload must be one less.
* Does not wrap as t is at least 1
*/
preload -= 1;
spin_lock(&ie6xx_wdt_data.unlock_sequence);
/* Set ResetMode & Enable prescaler for range 10ms to 10 min */
wdtcr = resetmode & 0x38;
outb(wdtcr, ie6xx_wdt_data.sch_wdtba + WDTCR);
ie6xx_wdt_unlock_registers();
outl(0, ie6xx_wdt_data.sch_wdtba + PV1);
ie6xx_wdt_unlock_registers();
outl(preload, ie6xx_wdt_data.sch_wdtba + PV2);
ie6xx_wdt_unlock_registers();
outb(WDT_RELOAD | WDT_TOUT, ie6xx_wdt_data.sch_wdtba + RR1);
spin_unlock(&ie6xx_wdt_data.unlock_sequence);
wdd->timeout = t;
return 0;
}
static int ie6xx_wdt_start(struct watchdog_device *wdd)
{
ie6xx_wdt_set_timeout(wdd, wdd->timeout);
/* Enable the watchdog timer */
spin_lock(&ie6xx_wdt_data.unlock_sequence);
outb(WDT_ENABLE, ie6xx_wdt_data.sch_wdtba + WDTLR);
spin_unlock(&ie6xx_wdt_data.unlock_sequence);
return 0;
}
static int ie6xx_wdt_stop(struct watchdog_device *wdd)
{
if (inb(ie6xx_wdt_data.sch_wdtba + WDTLR) & WDT_LOCK)
return -1;
/* Disable the watchdog timer */
spin_lock(&ie6xx_wdt_data.unlock_sequence);
outb(0, ie6xx_wdt_data.sch_wdtba + WDTLR);
spin_unlock(&ie6xx_wdt_data.unlock_sequence);
return 0;
}
static const struct watchdog_info ie6xx_wdt_info = {
.identity = "Intel Atom E6xx Watchdog",
.options = WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE |
WDIOF_KEEPALIVEPING,
};
static const struct watchdog_ops ie6xx_wdt_ops = {
.owner = THIS_MODULE,
.start = ie6xx_wdt_start,
.stop = ie6xx_wdt_stop,
.ping = ie6xx_wdt_ping,
.set_timeout = ie6xx_wdt_set_timeout,
};
static struct watchdog_device ie6xx_wdt_dev = {
.info = &ie6xx_wdt_info,
.ops = &ie6xx_wdt_ops,
.min_timeout = MIN_TIME,
.max_timeout = MAX_TIME,
};
#ifdef CONFIG_DEBUG_FS
static int ie6xx_wdt_dbg_show(struct seq_file *s, void *unused)
{
seq_printf(s, "PV1 = 0x%08x\n",
inl(ie6xx_wdt_data.sch_wdtba + PV1));
seq_printf(s, "PV2 = 0x%08x\n",
inl(ie6xx_wdt_data.sch_wdtba + PV2));
seq_printf(s, "RR = 0x%08x\n",
inw(ie6xx_wdt_data.sch_wdtba + RR0));
seq_printf(s, "WDTCR = 0x%08x\n",
inw(ie6xx_wdt_data.sch_wdtba + WDTCR));
seq_printf(s, "DCR = 0x%08x\n",
inl(ie6xx_wdt_data.sch_wdtba + DCR));
seq_printf(s, "WDTLR = 0x%08x\n",
inw(ie6xx_wdt_data.sch_wdtba + WDTLR));
seq_printf(s, "\n");
return 0;
}
static int ie6xx_wdt_dbg_open(struct inode *inode, struct file *file)
{
return single_open(file, ie6xx_wdt_dbg_show, NULL);
}
static const struct file_operations ie6xx_wdt_dbg_operations = {
.open = ie6xx_wdt_dbg_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static void __devinit ie6xx_wdt_debugfs_init(void)
{
/* /sys/kernel/debug/ie6xx_wdt */
ie6xx_wdt_data.debugfs = debugfs_create_file("ie6xx_wdt",
S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_dbg_operations);
}
static void __devexit ie6xx_wdt_debugfs_exit(void)
{
debugfs_remove(ie6xx_wdt_data.debugfs);
}
#else
static void __devinit ie6xx_wdt_debugfs_init(void)
{
}
static void __devexit ie6xx_wdt_debugfs_exit(void)
{
}
#endif
static int __devinit ie6xx_wdt_probe(struct platform_device *pdev)
{
struct resource *res;
u8 wdtlr;
int ret;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
return -ENODEV;
if (!request_region(res->start, resource_size(res), pdev->name)) {
dev_err(&pdev->dev, "Watchdog region 0x%llx already in use!\n",
(u64)res->start);
return -EBUSY;
}
ie6xx_wdt_data.sch_wdtba = res->start;
dev_dbg(&pdev->dev, "WDT = 0x%X\n", ie6xx_wdt_data.sch_wdtba);
ie6xx_wdt_dev.timeout = timeout;
watchdog_set_nowayout(&ie6xx_wdt_dev, nowayout);
spin_lock_init(&ie6xx_wdt_data.unlock_sequence);
wdtlr = inb(ie6xx_wdt_data.sch_wdtba + WDTLR);
if (wdtlr & WDT_LOCK)
dev_warn(&pdev->dev,
"Watchdog Timer is Locked (Reg=0x%x)\n", wdtlr);
ie6xx_wdt_debugfs_init();
ret = watchdog_register_device(&ie6xx_wdt_dev);
if (ret) {
dev_err(&pdev->dev,
"Watchdog timer: cannot register device (err =%d)\n",
ret);
goto misc_register_error;
}
return 0;
misc_register_error:
ie6xx_wdt_debugfs_exit();
release_region(res->start, resource_size(res));
ie6xx_wdt_data.sch_wdtba = 0;
return ret;
}
static int __devexit ie6xx_wdt_remove(struct platform_device *pdev)
{
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
ie6xx_wdt_stop(NULL);
watchdog_unregister_device(&ie6xx_wdt_dev);
ie6xx_wdt_debugfs_exit();
release_region(res->start, resource_size(res));
ie6xx_wdt_data.sch_wdtba = 0;
return 0;
}
static struct platform_driver ie6xx_wdt_driver = {
.probe = ie6xx_wdt_probe,
.remove = __devexit_p(ie6xx_wdt_remove),
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
static int __init ie6xx_wdt_init(void)
{
/* Check boot parameters to verify that their initial values */
/* are in range. */
if ((timeout < MIN_TIME) ||
(timeout > MAX_TIME)) {
pr_err("Watchdog timer: value of timeout %d (dec) "
"is out of range from %d to %d (dec)\n",
timeout, MIN_TIME, MAX_TIME);
return -EINVAL;
}
return platform_driver_register(&ie6xx_wdt_driver);
}
static void __exit ie6xx_wdt_exit(void)
{
platform_driver_unregister(&ie6xx_wdt_driver);
}
late_initcall(ie6xx_wdt_init);
module_exit(ie6xx_wdt_exit);
MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
MODULE_DESCRIPTION("Intel Atom E6xx Watchdog Device Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
MODULE_ALIAS("platform:" DRIVER_NAME);
......@@ -12,7 +12,8 @@
* http://www.ite.com.tw/
*
* Support of the watchdog timers, which are available on
* IT8702, IT8712, IT8716, IT8718, IT8720, IT8721 and IT8726.
* IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726
* and IT8728.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
......@@ -84,6 +85,7 @@
#define IT8720_ID 0x8720
#define IT8721_ID 0x8721
#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
#define IT8728_ID 0x8728
/* GPIO Configuration Registers LDN=0x07 */
#define WDTCTRL 0x71
......@@ -95,7 +97,7 @@
#define WDT_CIRINT 0x80
#define WDT_MOUSEINT 0x40
#define WDT_KYBINT 0x20
#define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721 */
#define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721, it8728 */
#define WDT_FORCE 0x02
#define WDT_ZERO 0x01
......@@ -616,6 +618,7 @@ static int __init it87_wdt_init(void)
case IT8718_ID:
case IT8720_ID:
case IT8721_ID:
case IT8728_ID:
max_units = 65535;
try_gameport = 0;
break;
......
/*
* drivers/char/watchdog/ixp2000_wdt.c
*
* Watchdog driver for Intel IXP2000 network processors
*
* Adapted from the IXP4xx watchdog driver by Lennert Buytenhek.
* The original version carries these notices:
*
* Author: Deepak Saxena <dsaxena@plexity.net>
*
* Copyright 2004 (c) MontaVista, Software, Inc.
* Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
*
* 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.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/timer.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/uaccess.h>
#include <mach/hardware.h>
static bool nowayout = WATCHDOG_NOWAYOUT;
static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
static unsigned long wdt_status;
static DEFINE_SPINLOCK(wdt_lock);
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
static unsigned long wdt_tick_rate;
static void wdt_enable(void)
{
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
spin_unlock(&wdt_lock);
}
static void wdt_disable(void)
{
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_T4_CTL, 0);
spin_unlock(&wdt_lock);
}
static void wdt_keepalive(void)
{
spin_lock(&wdt_lock);
ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
spin_unlock(&wdt_lock);
}
static int ixp2000_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 ixp2000_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_keepalive();
}
return len;
}
static const struct watchdog_info ident = {
.options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING,
.identity = "IXP2000 Watchdog",
};
static long ixp2000_wdt_ioctl(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(0, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_enable();
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg);
if (ret)
break;
if (time <= 0 || time > 60) {
ret = -EINVAL;
break;
}
heartbeat = time;
wdt_keepalive();
/* Fall through */
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
}
return ret;
}
static int ixp2000_wdt_release(struct inode *inode, struct file *file)
{
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
wdt_disable();
else
pr_crit("Device closed unexpectedly - timer will not stop\n");
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
return 0;
}
static const struct file_operations ixp2000_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = ixp2000_wdt_write,
.unlocked_ioctl = ixp2000_wdt_ioctl,
.open = ixp2000_wdt_open,
.release = ixp2000_wdt_release,
};
static struct miscdevice ixp2000_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &ixp2000_wdt_fops,
};
static int __init ixp2000_wdt_init(void)
{
if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
pr_info("Unable to use IXP2000 watchdog due to IXP2800 erratum #25\n");
return -EIO;
}
wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
return misc_register(&ixp2000_wdt_miscdev);
}
static void __exit ixp2000_wdt_exit(void)
{
misc_deregister(&ixp2000_wdt_miscdev);
}
module_init(ixp2000_wdt_init);
module_exit(ixp2000_wdt_exit);
MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
......@@ -707,6 +707,7 @@ static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
goto err_out_disable_device;
}
spin_lock_init(&pcipcwd_private.io_lock);
pcipcwd_private.pdev = pdev;
pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
......@@ -814,22 +815,7 @@ static struct pci_driver pcipcwd_driver = {
.remove = __devexit_p(pcipcwd_card_exit),
};
static int __init pcipcwd_init_module(void)
{
spin_lock_init(&pcipcwd_private.io_lock);
return pci_register_driver(&pcipcwd_driver);
}
static void __exit pcipcwd_cleanup_module(void)
{
pci_unregister_driver(&pcipcwd_driver);
pr_info("Watchdog Module Unloaded\n");
}
module_init(pcipcwd_init_module);
module_exit(pcipcwd_cleanup_module);
module_pci_driver(pcipcwd_driver);
MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");
......
......@@ -32,6 +32,7 @@
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/of.h>
#include <mach/hardware.h>
/* WatchDog Timer - Chapter 23 Page 207 */
......@@ -201,10 +202,19 @@ static int __devexit pnx4008_wdt_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id pnx4008_wdt_match[] = {
{ .compatible = "nxp,pnx4008-wdt" },
{ }
};
MODULE_DEVICE_TABLE(of, pnx4008_wdt_match);
#endif
static struct platform_driver platform_wdt_driver = {
.driver = {
.name = "pnx4008-watchdog",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(pnx4008_wdt_match),
},
.probe = pnx4008_wdt_probe,
.remove = __devexit_p(pnx4008_wdt_remove),
......
......@@ -40,6 +40,7 @@
#include <linux/cpufreq.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/of.h>
#include <mach/map.h>
......@@ -201,7 +202,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
writel(count, wdt_base + S3C2410_WTDAT);
writel(wtcon, wdt_base + S3C2410_WTCON);
wdd->timeout = timeout;
wdd->timeout = (count * divisor) / freq;
return 0;
}
......@@ -503,8 +504,6 @@ static const struct of_device_id s3c2410_wdt_match[] = {
{},
};
MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
#else
#define s3c2410_wdt_match NULL
#endif
static struct platform_driver s3c2410wdt_driver = {
......@@ -516,7 +515,7 @@ static struct platform_driver s3c2410wdt_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "s3c2410-wdt",
.of_match_table = s3c2410_wdt_match,
.of_match_table = of_match_ptr(s3c2410_wdt_match),
},
};
......
......@@ -41,7 +41,6 @@
#define DRV_NAME "sch311x_wdt"
/* Runtime registers */
#define RESGEN 0x1d
#define GP60 0x47
#define WDT_TIME_OUT 0x65
#define WDT_VAL 0x66
......@@ -69,10 +68,6 @@ static unsigned short force_id;
module_param(force_id, ushort, 0);
MODULE_PARM_DESC(force_id, "Override the detected device ID");
static unsigned short therm_trip;
module_param(therm_trip, ushort, 0);
MODULE_PARM_DESC(therm_trip, "Should a ThermTrip trigger the reset generator");
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0);
......@@ -358,26 +353,16 @@ static struct miscdevice sch311x_wdt_miscdev = {
static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
unsigned char val;
int err;
spin_lock_init(&sch311x_wdt_data.io_lock);
if (!request_region(sch311x_wdt_data.runtime_reg + RESGEN, 1,
DRV_NAME)) {
dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
sch311x_wdt_data.runtime_reg + RESGEN,
sch311x_wdt_data.runtime_reg + RESGEN);
err = -EBUSY;
goto exit;
}
if (!request_region(sch311x_wdt_data.runtime_reg + GP60, 1, DRV_NAME)) {
dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
sch311x_wdt_data.runtime_reg + GP60,
sch311x_wdt_data.runtime_reg + GP60);
err = -EBUSY;
goto exit_release_region;
goto exit;
}
if (!request_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4,
......@@ -386,7 +371,7 @@ static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
sch311x_wdt_data.runtime_reg + WDT_TIME_OUT,
sch311x_wdt_data.runtime_reg + WDT_CTRL);
err = -EBUSY;
goto exit_release_region2;
goto exit_release_region;
}
/* Make sure that the watchdog is not running */
......@@ -414,24 +399,13 @@ static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
/* Get status at boot */
sch311x_wdt_get_status(&sch311x_wdt_data.boot_status);
/* enable watchdog */
/* -- Reset Generator --
* Bit 0 Enable Watchdog Timer Generation: 0* = Enabled, 1 = Disabled
* Bit 1 Thermtrip Source Select: O* = No Source, 1 = Source
* Bit 2 WDT2_CTL: WDT input bit
* Bit 3-7 Reserved
*/
outb(0, sch311x_wdt_data.runtime_reg + RESGEN);
val = therm_trip ? 0x06 : 0x04;
outb(val, sch311x_wdt_data.runtime_reg + RESGEN);
sch311x_wdt_miscdev.parent = dev;
err = misc_register(&sch311x_wdt_miscdev);
if (err != 0) {
dev_err(dev, "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, err);
goto exit_release_region3;
goto exit_release_region2;
}
dev_info(dev,
......@@ -440,12 +414,10 @@ static int __devinit sch311x_wdt_probe(struct platform_device *pdev)
return 0;
exit_release_region3:
release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
exit_release_region2:
release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
exit_release_region:
release_region(sch311x_wdt_data.runtime_reg + RESGEN, 1);
release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
sch311x_wdt_data.runtime_reg = 0;
exit:
return err;
......@@ -461,7 +433,6 @@ static int __devexit sch311x_wdt_remove(struct platform_device *pdev)
misc_deregister(&sch311x_wdt_miscdev);
release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
release_region(sch311x_wdt_data.runtime_reg + RESGEN, 1);
sch311x_wdt_data.runtime_reg = 0;
return 0;
}
......
......@@ -313,7 +313,7 @@ static unsigned char __devinit sp5100_tco_setupdevice(void)
tcobase_phys = val;
tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
if (tcobase == 0) {
if (!tcobase) {
pr_err("failed to get tcobase address\n");
goto unreg_mem_region;
}
......
......@@ -202,6 +202,9 @@ static int __devinit wdt_probe(struct pci_dev *pdev,
goto err_out_release;
}
if (timeout < 1 || timeout > WDT_TIMEOUT_MAX)
timeout = WDT_TIMEOUT;
wdt_dev.timeout = timeout;
watchdog_set_nowayout(&wdt_dev, nowayout);
if (readl(wdt_mem) & VIA_WDT_FIRED)
......@@ -250,20 +253,7 @@ static struct pci_driver wdt_driver = {
.remove = __devexit_p(wdt_remove),
};
static int __init wdt_init(void)
{
if (timeout < 1 || timeout > WDT_TIMEOUT_MAX)
timeout = WDT_TIMEOUT;
return pci_register_driver(&wdt_driver);
}
static void __exit wdt_exit(void)
{
pci_unregister_driver(&wdt_driver);
}
module_init(wdt_init);
module_exit(wdt_exit);
module_pci_driver(wdt_driver);
MODULE_AUTHOR("Marc Vertes");
MODULE_DESCRIPTION("Driver for watchdog timer on VIA chipset");
......
......@@ -739,39 +739,7 @@ static struct pci_driver wdtpci_driver = {
.remove = __devexit_p(wdtpci_remove_one),
};
/**
* wdtpci_cleanup:
*
* Unload the watchdog. You cannot do this with any file handles open.
* If your watchdog is set to continue ticking on close and you unload
* it, well it keeps ticking. We won't get the interrupt but the board
* will not touch PC memory so all is fine. You just have to load a new
* module in xx seconds or reboot.
*/
static void __exit wdtpci_cleanup(void)
{
pci_unregister_driver(&wdtpci_driver);
}
/**
* wdtpci_init:
*
* Set up the WDT watchdog board. All we have to do is grab the
* resources we require and bitch if anyone beat us to them.
* The open() function will actually kick the board off.
*/
static int __init wdtpci_init(void)
{
return pci_register_driver(&wdtpci_driver);
}
module_init(wdtpci_init);
module_exit(wdtpci_cleanup);
module_pci_driver(wdtpci_driver);
MODULE_AUTHOR("JP Nollmann, Alan Cox");
MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
......
......@@ -247,8 +247,9 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT;
if (pdata->update_gpio) {
ret = gpio_request(pdata->update_gpio,
"Watchdog update");
ret = gpio_request_one(pdata->update_gpio,
GPIOF_DIR_OUT | GPIOF_INIT_LOW,
"Watchdog update");
if (ret < 0) {
dev_err(wm831x->dev,
"Failed to request update GPIO: %d\n",
......@@ -256,14 +257,6 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev)
goto err;
}
ret = gpio_direction_output(pdata->update_gpio, 0);
if (ret != 0) {
dev_err(wm831x->dev,
"gpio_direction_output returned: %d\n",
ret);
goto err_gpio;
}
driver_data->update_gpio = pdata->update_gpio;
/* Make sure the watchdog takes hardware updates */
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册