Commit 2f63251e authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog

* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog: (28 commits)
  [WATCHDOG] Fix pcwd_init_module crash
  [WATCHDOG] ICH9 support for iTCO_wdt
  [WATCHDOG] 631xESB/632xESB support for iTCO_wdt - add all LPC bridges
  [WATCHDOG] 631xESB/632xESB support for iTCO_wdt
  [WATCHDOG] omap_wdt.c - default error for IOCTL is -ENOTTY
  [WATCHDOG] Return value of nonseekable_open
  [WATCHDOG] mv64x60_wdt: Rework the timeout register manipulation
  [WATCHDOG] mv64x60_wdt: disable watchdog timer when driver is probed
  [WATCHDOG] mv64x60_wdt: Support the WDIOF_MAGICCLOSE feature
  [WATCHDOG] mv64x60_wdt: Add a module parameter to change nowayout setting
  [WATCHDOG] mv64x60_wdt: Add WDIOC_SETOPTIONS ioctl support
  [WATCHDOG] mv64x60_wdt: Support for WDIOC_SETTIMEOUT ioctl
  [WATCHDOG] mv64x60_wdt: Fix WDIOC_GETTIMEOUT return value
  [WATCHDOG] mv64x60_wdt: Check return value of nonseekable_open
  [WATCHDOG] mv64x60_wdt: Add arch/powerpc platform support
  [WATCHDOG] mv64x60_wdt: Get register address from platform data
  [WATCHDOG] mv64x60_wdt: set up platform_device in platform code
  [WATCHDOG] ensure mouse and keyboard ignored in w83627hf_wdt
  [WATCHDOG] s3c2410_wdt: fixup after arch include moves
  [WATCHDOG] git-watchdog-typo
  ...
parents d6dd9e93 647e50f3
...@@ -756,6 +756,14 @@ L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) ...@@ -756,6 +756,14 @@ L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
W: http://blackfin.uclinux.org W: http://blackfin.uclinux.org
S: Supported S: Supported
BLACKFIN WATCHDOG DRIVER
P: Mike Frysinger
M: michael.frysinger@analog.com
M: vapier.adi@gmail.com
L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only)
W: http://blackfin.uclinux.org
S: Supported
BAYCOM/HDLCDRV DRIVERS FOR AX.25 BAYCOM/HDLCDRV DRIVERS FOR AX.25
P: Thomas Sailer P: Thomas Sailer
M: t.sailer@alumni.ethz.ch M: t.sailer@alumni.ethz.ch
......
...@@ -207,6 +207,12 @@ mpsc@9000 { ...@@ -207,6 +207,12 @@ mpsc@9000 {
interrupt-parent = <&/mv64x60/pic>; interrupt-parent = <&/mv64x60/pic>;
}; };
wdt@b410 { /* watchdog timer */
compatible = "marvell,mv64x60-wdt";
reg = <b410 8>;
timeout = <a>; /* wdt timeout in seconds */
};
i2c@c000 { i2c@c000 {
device_type = "i2c"; device_type = "i2c";
compatible = "marvell,mv64x60-i2c"; compatible = "marvell,mv64x60-i2c";
......
...@@ -390,6 +390,61 @@ static int __init mv64x60_i2c_device_setup(struct device_node *np, int id) ...@@ -390,6 +390,61 @@ static int __init mv64x60_i2c_device_setup(struct device_node *np, int id)
return err; return err;
} }
/*
* Create mv64x60_wdt platform devices
*/
static int __init mv64x60_wdt_device_setup(struct device_node *np, int id)
{
struct resource r;
struct platform_device *pdev;
struct mv64x60_wdt_pdata pdata;
const unsigned int *prop;
int err;
err = of_address_to_resource(np, 0, &r);
if (err)
return err;
memset(&pdata, 0, sizeof(pdata));
prop = of_get_property(np, "timeout", NULL);
if (!prop)
return -ENODEV;
pdata.timeout = *prop;
np = of_get_parent(np);
if (!np)
return -ENODEV;
prop = of_get_property(np, "clock-frequency", NULL);
of_node_put(np);
if (!prop)
return -ENODEV;
pdata.bus_clk = *prop / 1000000; /* wdt driver wants freq in MHz */
pdev = platform_device_alloc(MV64x60_WDT_NAME, id);
if (!pdev)
return -ENOMEM;
err = platform_device_add_resources(pdev, &r, 1);
if (err)
goto error;
err = platform_device_add_data(pdev, &pdata, sizeof(pdata));
if (err)
goto error;
err = platform_device_add(pdev);
if (err)
goto error;
return 0;
error:
platform_device_put(pdev);
return err;
}
static int __init mv64x60_device_setup(void) static int __init mv64x60_device_setup(void)
{ {
struct device_node *np = NULL; struct device_node *np = NULL;
...@@ -414,6 +469,15 @@ static int __init mv64x60_device_setup(void) ...@@ -414,6 +469,15 @@ static int __init mv64x60_device_setup(void)
if ((err = mv64x60_i2c_device_setup(np, id))) if ((err = mv64x60_i2c_device_setup(np, id)))
goto error; goto error;
/* support up to one watchdog timer */
np = of_find_compatible_node(np, NULL, "marvell,mv64x60-wdt");
if (np) {
if ((err = mv64x60_wdt_device_setup(np, id)))
goto error;
of_node_put(np);
}
return 0; return 0;
error: error:
......
...@@ -441,6 +441,32 @@ static struct platform_device i2c_device = { ...@@ -441,6 +441,32 @@ static struct platform_device i2c_device = {
}; };
#endif #endif
#ifdef CONFIG_WATCHDOG
static struct mv64x60_wdt_pdata mv64x60_wdt_pdata = {
.timeout = 10, /* default watchdog expiry in seconds */
.bus_clk = 133, /* default bus clock in MHz */
};
static struct resource mv64x60_wdt_resources[] = {
[0] = {
.name = "mv64x60 wdt base",
.start = MV64x60_WDT_WDC,
.end = MV64x60_WDT_WDC + 8 - 1, /* two 32-bit registers */
.flags = IORESOURCE_MEM,
},
};
static struct platform_device wdt_device = {
.name = MV64x60_WDT_NAME,
.id = 0,
.num_resources = ARRAY_SIZE(mv64x60_wdt_resources),
.resource = mv64x60_wdt_resources,
.dev = {
.platform_data = &mv64x60_wdt_pdata,
},
};
#endif
#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260) #if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
static struct mv64xxx_pdata mv64xxx_pdata = { static struct mv64xxx_pdata mv64xxx_pdata = {
.hs_reg_valid = 0, .hs_reg_valid = 0,
...@@ -476,6 +502,9 @@ static struct platform_device *mv64x60_pd_devs[] __initdata = { ...@@ -476,6 +502,9 @@ static struct platform_device *mv64x60_pd_devs[] __initdata = {
#ifdef CONFIG_I2C_MV64XXX #ifdef CONFIG_I2C_MV64XXX
&i2c_device, &i2c_device,
#endif #endif
#ifdef CONFIG_MV64X60_WDT
&wdt_device,
#endif
#if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260) #if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260)
&mv64xxx_device, &mv64xxx_device,
#endif #endif
......
...@@ -66,6 +66,7 @@ obj-y += i2c/ ...@@ -66,6 +66,7 @@ obj-y += i2c/
obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/ obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/ obj-$(CONFIG_HWMON) += hwmon/
obj-$(CONFIG_WATCHDOG) += char/watchdog/
obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/ obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/ obj-$(CONFIG_BT) += bluetooth/
......
...@@ -97,7 +97,6 @@ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o ...@@ -97,7 +97,6 @@ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o obj-$(CONFIG_TELCLOCK) += tlclk.o
obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_MWAVE) += mwave/
obj-$(CONFIG_AGP) += agp/ obj-$(CONFIG_AGP) += agp/
obj-$(CONFIG_DRM) += drm/ obj-$(CONFIG_DRM) += drm/
......
...@@ -55,6 +55,8 @@ config SOFT_WATCHDOG ...@@ -55,6 +55,8 @@ config SOFT_WATCHDOG
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called softdog. module will be called softdog.
# ALPHA Architecture
# ARM Architecture # ARM Architecture
config AT91RM9200_WATCHDOG config AT91RM9200_WATCHDOG
...@@ -189,7 +191,7 @@ config PNX4008_WATCHDOG ...@@ -189,7 +191,7 @@ config PNX4008_WATCHDOG
config IOP_WATCHDOG config IOP_WATCHDOG
tristate "IOP Watchdog" tristate "IOP Watchdog"
depends on WATCHDOG && PLAT_IOP depends on PLAT_IOP
select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X) select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
help help
Say Y here if to include support for the watchdog timer Say Y here if to include support for the watchdog timer
...@@ -203,15 +205,48 @@ config IOP_WATCHDOG ...@@ -203,15 +205,48 @@ config IOP_WATCHDOG
operating as an Root Complex and/or Central Resource, the PCI-X operating as an Root Complex and/or Central Resource, the PCI-X
and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER. and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER.
config DAVINCI_WATCHDOG
tristate "DaVinci watchdog"
depends on ARCH_DAVINCI
help
Say Y here if to include support for the watchdog timer
in the DaVinci DM644x/DM646x processors.
To compile this driver as a module, choose M here: the
module will be called davinci_wdt.
NOTE: once enabled, this timer cannot be disabled.
Say N if you are unsure.
# ARM26 Architecture
# AVR32 Architecture # AVR32 Architecture
config AT32AP700X_WDT config AT32AP700X_WDT
tristate "AT32AP700x watchdog" tristate "AT32AP700x watchdog"
depends on WATCHDOG && CPU_AT32AP7000 depends on CPU_AT32AP7000
help help
Watchdog timer embedded into AT32AP700x devices. This will reboot Watchdog timer embedded into AT32AP700x devices. This will reboot
your system when the timeout is reached. your system when the timeout is reached.
# BLACKFIN Architecture
config BFIN_WDT
tristate "Blackfin On-Chip Watchdog Timer"
depends on BLACKFIN
---help---
If you say yes here you will get support for the Blackfin On-Chip
Watchdog Timer. If you have one of these processors and wish to
have watchdog support enabled, say Y, otherwise say N.
To compile this driver as a module, choose M here: the
module will be called bfin_wdt.
# CRIS Architecture
# FRV Architecture
# H8300 Architecture
# X86 (i386 + ia64 + x86_64) Architecture # X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT config ACQUIRE_WDT
...@@ -540,37 +575,11 @@ config SBC_EPX_C3_WATCHDOG ...@@ -540,37 +575,11 @@ config SBC_EPX_C3_WATCHDOG
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called sbc_epx_c3. module will be called sbc_epx_c3.
# PowerPC Architecture # M32R Architecture
config 8xx_WDT # M68K Architecture
tristate "MPC8xx Watchdog Timer"
depends on 8xx
config 83xx_WDT # M68KNOMMU Architecture
tristate "MPC83xx Watchdog Timer"
depends on PPC_83xx
config MV64X60_WDT
tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
depends on MV64X60
config BOOKE_WDT
bool "PowerPC Book-E Watchdog Timer"
depends on BOOKE || 4xx
---help---
Please see Documentation/watchdog/watchdog-api.txt for
more information.
# PPC64 Architecture
config WATCHDOG_RTAS
tristate "RTAS watchdog"
depends on PPC_RTAS
help
This driver adds watchdog support for the RTAS watchdog.
To compile this driver as a module, choose M here. The module
will be called wdrtas.
# MIPS Architecture # MIPS Architecture
...@@ -600,6 +609,44 @@ config WDT_RM9K_GPI ...@@ -600,6 +609,44 @@ config WDT_RM9K_GPI
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called rm9k_wdt. module will be called rm9k_wdt.
# PARISC Architecture
# POWERPC Architecture
config MPC5200_WDT
tristate "MPC5200 Watchdog Timer"
depends on PPC_MPC52xx
config 8xx_WDT
tristate "MPC8xx Watchdog Timer"
depends on 8xx
config 83xx_WDT
tristate "MPC83xx Watchdog Timer"
depends on PPC_83xx
config MV64X60_WDT
tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
depends on MV64X60
config BOOKE_WDT
bool "PowerPC Book-E Watchdog Timer"
depends on BOOKE || 4xx
---help---
Please see Documentation/watchdog/watchdog-api.txt for
more information.
# PPC64 Architecture
config WATCHDOG_RTAS
tristate "RTAS watchdog"
depends on PPC_RTAS
help
This driver adds watchdog support for the RTAS watchdog.
To compile this driver as a module, choose M here. The module
will be called wdrtas.
# S390 Architecture # S390 Architecture
config ZVM_WATCHDOG config ZVM_WATCHDOG
...@@ -614,7 +661,7 @@ config ZVM_WATCHDOG ...@@ -614,7 +661,7 @@ config ZVM_WATCHDOG
To compile this driver as a module, choose M here. The module To compile this driver as a module, choose M here. The module
will be called vmwatchdog. will be called vmwatchdog.
# SUPERH Architecture # SUPERH (sh + sh64) Architecture
config SH_WDT config SH_WDT
tristate "SuperH Watchdog" tristate "SuperH Watchdog"
...@@ -641,6 +688,8 @@ config SH_WDT_MMAP ...@@ -641,6 +688,8 @@ config SH_WDT_MMAP
If you say Y here, user applications will be able to mmap the If you say Y here, user applications will be able to mmap the
WDT/CPG registers. WDT/CPG registers.
# SPARC Architecture
# SPARC64 Architecture # SPARC64 Architecture
config WATCHDOG_CP1XXX config WATCHDOG_CP1XXX
...@@ -665,6 +714,10 @@ config WATCHDOG_RIO ...@@ -665,6 +714,10 @@ config WATCHDOG_RIO
machines. The watchdog timeout period is normally one minute but machines. The watchdog timeout period is normally one minute but
can be changed with a boot-time parameter. can be changed with a boot-time parameter.
# V850 Architecture
# XTENSA Architecture
# #
# ISA-based Watchdog Cards # ISA-based Watchdog Cards
# #
......
...@@ -22,6 +22,8 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o ...@@ -22,6 +22,8 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o
# USB-based Watchdog Cards # USB-based Watchdog Cards
obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
# ALPHA Architecture
# ARM Architecture # ARM Architecture
obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
...@@ -36,10 +38,22 @@ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o ...@@ -36,10 +38,22 @@ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
# ARM26 Architecture
# AVR32 Architecture # AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
# BLACKFIN Architecture
obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o
# CRIS Architecture
# FRV Architecture
# H8300 Architecture
# X86 (i386 + ia64 + x86_64) Architecture # X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
...@@ -66,8 +80,22 @@ obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o ...@@ -66,8 +80,22 @@ obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_MACHZ_WDT) += machzwd.o
obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
# PowerPC Architecture # M32R Architecture
# M68K Architecture
# M68KNOMMU Architecture
# MIPS Architecture
obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
# PARISC Architecture
# POWERPC Architecture
obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o
obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
...@@ -75,17 +103,18 @@ obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o ...@@ -75,17 +103,18 @@ obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
# PPC64 Architecture # PPC64 Architecture
obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
# MIPS Architecture
obj-$(CONFIG_INDYDOG) += indydog.o
obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
# S390 Architecture # S390 Architecture
# SUPERH Architecture # SUPERH (sh + sh64) Architecture
obj-$(CONFIG_SH_WDT) += shwdt.o obj-$(CONFIG_SH_WDT) += shwdt.o
# SPARC Architecture
# SPARC64 Architecture # SPARC64 Architecture
# V850 Architecture
# XTENSA Architecture
# Architecture Independant # Architecture Independant
obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
/*
* Blackfin On-Chip Watchdog Driver
* Supports BF53[123]/BF53[467]/BF54[2489]/BF561
*
* Originally based on softdog.c
* Copyright 2006-2007 Analog Devices Inc.
* Copyright 2006-2007 Michele d'Amico
* Copyright 1996 Alan Cox <alan@redhat.com>
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/fs.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <asm/blackfin.h>
#include <asm/uaccess.h>
#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
#define stampit() stamp("here i am")
#define WATCHDOG_NAME "bfin-wdt"
#define PFX WATCHDOG_NAME ": "
/* The BF561 has two watchdogs (one per core), but since Linux
* only runs on core A, we'll just work with that one.
*/
#ifdef BF561_FAMILY
# define bfin_read_WDOG_CTL() bfin_read_WDOGA_CTL()
# define bfin_read_WDOG_CNT() bfin_read_WDOGA_CNT()
# define bfin_read_WDOG_STAT() bfin_read_WDOGA_STAT()
# define bfin_write_WDOG_CTL(x) bfin_write_WDOGA_CTL(x)
# define bfin_write_WDOG_CNT(x) bfin_write_WDOGA_CNT(x)
# define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x)
#endif
/* Bit in SWRST that indicates boot caused by watchdog */
#define SWRST_RESET_WDOG 0x4000
/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */
#define WDOG_EXPIRED 0x8000
/* Masks for WDEV field in WDOG_CTL register */
#define ICTL_RESET 0x0
#define ICTL_NMI 0x2
#define ICTL_GPI 0x4
#define ICTL_NONE 0x6
#define ICTL_MASK 0x6
/* Masks for WDEN field in WDOG_CTL register */
#define WDEN_MASK 0x0FF0
#define WDEN_ENABLE 0x0000
#define WDEN_DISABLE 0x0AD0
/* some defaults */
#define WATCHDOG_TIMEOUT 20
static unsigned int timeout = WATCHDOG_TIMEOUT;
static int nowayout = WATCHDOG_NOWAYOUT;
static struct watchdog_info bfin_wdt_info;
static unsigned long open_check;
static char expect_close;
static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED;
/**
* bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
*
* The Userspace watchdog got a KeepAlive: schedule the next timeout.
*/
static int bfin_wdt_keepalive(void)
{
stampit();
bfin_write_WDOG_STAT(0);
return 0;
}
/**
* bfin_wdt_stop - Stop the Watchdog
*
* Stops the on-chip watchdog.
*/
static int bfin_wdt_stop(void)
{
stampit();
bfin_write_WDOG_CTL(WDEN_DISABLE);
return 0;
}
/**
* bfin_wdt_start - Start the Watchdog
*
* Starts the on-chip watchdog. Automatically loads WDOG_CNT
* into WDOG_STAT for us.
*/
static int bfin_wdt_start(void)
{
stampit();
bfin_write_WDOG_CTL(WDEN_ENABLE | ICTL_RESET);
return 0;
}
/**
* bfin_wdt_running - Check Watchdog status
*
* See if the watchdog is running.
*/
static int bfin_wdt_running(void)
{
stampit();
return ((bfin_read_WDOG_CTL() & WDEN_MASK) != WDEN_DISABLE);
}
/**
* bfin_wdt_set_timeout - Set the Userspace Watchdog timeout
* @t: new timeout value (in seconds)
*
* Translate the specified timeout in seconds into System Clock
* terms which is what the on-chip Watchdog requires.
*/
static int bfin_wdt_set_timeout(unsigned long t)
{
u32 cnt;
unsigned long flags;
stampit();
cnt = t * get_sclk();
if (cnt < get_sclk()) {
printk(KERN_WARNING PFX "timeout value is too large\n");
return -EINVAL;
}
spin_lock_irqsave(&bfin_wdt_spinlock, flags);
{
int run = bfin_wdt_running();
bfin_wdt_stop();
bfin_write_WDOG_CNT(cnt);
if (run) bfin_wdt_start();
}
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
timeout = t;
return 0;
}
/**
* bfin_wdt_open - Open the Device
* @inode: inode of device
* @file: file handle of device
*
* Watchdog device is opened and started.
*/
static int bfin_wdt_open(struct inode *inode, struct file *file)
{
stampit();
if (test_and_set_bit(0, &open_check))
return -EBUSY;
if (nowayout)
__module_get(THIS_MODULE);
bfin_wdt_keepalive();
bfin_wdt_start();
return nonseekable_open(inode, file);
}
/**
* bfin_wdt_close - Close the Device
* @inode: inode of device
* @file: file handle of device
*
* Watchdog device is closed and stopped.
*/
static int bfin_wdt_release(struct inode *inode, struct file *file)
{
stampit();
if (expect_close == 42) {
bfin_wdt_stop();
} else {
printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
bfin_wdt_keepalive();
}
expect_close = 0;
clear_bit(0, &open_check);
return 0;
}
/**
* bfin_wdt_write - Write to Device
* @file: file handle of device
* @buf: buffer to write
* @count: length of buffer
* @ppos: offset
*
* Pings the watchdog on write.
*/
static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
stampit();
if (len) {
if (!nowayout) {
size_t i;
/* In case it was set long ago */
expect_close = 0;
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
}
}
bfin_wdt_keepalive();
}
return len;
}
/**
* bfin_wdt_ioctl - Query Device
* @inode: inode of device
* @file: file handle of device
* @cmd: watchdog command
* @arg: argument
*
* Query basic information from the device or ping it, as outlined by the
* watchdog API.
*/
static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
int __user *p = argp;
stampit();
switch (cmd) {
default:
return -ENOTTY;
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
return -EFAULT;
else
return 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
case WDIOC_KEEPALIVE:
bfin_wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT: {
int new_timeout;
if (get_user(new_timeout, p))
return -EFAULT;
if (bfin_wdt_set_timeout(new_timeout))
return -EINVAL;
}
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
case WDIOC_SETOPTIONS: {
unsigned long flags;
int options, ret = -EINVAL;
if (get_user(options, p))
return -EFAULT;
spin_lock_irqsave(&bfin_wdt_spinlock, flags);
if (options & WDIOS_DISABLECARD) {
bfin_wdt_stop();
ret = 0;
}
if (options & WDIOS_ENABLECARD) {
bfin_wdt_start();
ret = 0;
}
spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
return ret;
}
}
}
/**
* bfin_wdt_notify_sys - Notifier Handler
* @this: notifier block
* @code: notifier event
* @unused: unused
*
* Handles specific events, such as turning off the watchdog during a
* shutdown event.
*/
static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code,
void *unused)
{
stampit();
if (code == SYS_DOWN || code == SYS_HALT)
bfin_wdt_stop();
return NOTIFY_DONE;
}
#ifdef CONFIG_PM
static int state_before_suspend;
/**
* bfin_wdt_suspend - suspend the watchdog
* @pdev: device being suspended
* @state: requested suspend state
*
* Remember if the watchdog was running and stop it.
* TODO: is this even right? Doesn't seem to be any
* standard in the watchdog world ...
*/
static int bfin_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
stampit();
state_before_suspend = bfin_wdt_running();
bfin_wdt_stop();
return 0;
}
/**
* bfin_wdt_resume - resume the watchdog
* @pdev: device being resumed
*
* If the watchdog was running, turn it back on.
*/
static int bfin_wdt_resume(struct platform_device *pdev)
{
stampit();
if (state_before_suspend) {
bfin_wdt_set_timeout(timeout);
bfin_wdt_start();
}
return 0;
}
#else
# define bfin_wdt_suspend NULL
# define bfin_wdt_resume NULL
#endif
static struct platform_device bfin_wdt_device = {
.name = WATCHDOG_NAME,
.id = -1,
};
static struct platform_driver bfin_wdt_driver = {
.driver = {
.name = WATCHDOG_NAME,
.owner = THIS_MODULE,
},
.suspend = bfin_wdt_suspend,
.resume = bfin_wdt_resume,
};
static struct file_operations bfin_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = bfin_wdt_write,
.ioctl = bfin_wdt_ioctl,
.open = bfin_wdt_open,
.release = bfin_wdt_release,
};
static struct miscdevice bfin_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &bfin_wdt_fops,
};
static struct watchdog_info bfin_wdt_info = {
.identity = "Blackfin Watchdog",
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
};
static struct notifier_block bfin_wdt_notifier = {
.notifier_call = bfin_wdt_notify_sys,
};
/**
* bfin_wdt_init - Initialize module
*
* Registers the device and notifier handler. Actual device
* initialization is handled by bfin_wdt_open().
*/
static int __init bfin_wdt_init(void)
{
int ret;
stampit();
/* Check that the timeout value is within range */
if (bfin_wdt_set_timeout(timeout))
return -EINVAL;
/* Since this is an on-chip device and needs no board-specific
* resources, we'll handle all the platform device stuff here.
*/
ret = platform_device_register(&bfin_wdt_device);
if (ret)
return ret;
ret = platform_driver_probe(&bfin_wdt_driver, NULL);
if (ret)
return ret;
ret = register_reboot_notifier(&bfin_wdt_notifier);
if (ret) {
printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
return ret;
}
ret = misc_register(&bfin_wdt_miscdev);
if (ret) {
printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&bfin_wdt_notifier);
return ret;
}
printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return 0;
}
/**
* bfin_wdt_exit - Deinitialize module
*
* Unregisters the device and notifier handler. Actual device
* deinitialization is handled by bfin_wdt_close().
*/
static void __exit bfin_wdt_exit(void)
{
misc_deregister(&bfin_wdt_miscdev);
unregister_reboot_notifier(&bfin_wdt_notifier);
}
module_init(bfin_wdt_init);
module_exit(bfin_wdt_exit);
MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>");
MODULE_DESCRIPTION("Blackfin Watchdog Device Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
module_param(timeout, uint, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
...@@ -144,7 +144,7 @@ static int booke_wdt_open (struct inode *inode, struct file *file) ...@@ -144,7 +144,7 @@ static int booke_wdt_open (struct inode *inode, struct file *file)
booke_wdt_period); booke_wdt_period);
} }
return 0; return nonseekable_open(inode, file);
} }
static const struct file_operations booke_wdt_fops = { static const struct file_operations booke_wdt_fops = {
......
...@@ -162,6 +162,10 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm ...@@ -162,6 +162,10 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm
if ( copy_to_user(argp, &value, sizeof(int)) ) if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT; return -EFAULT;
break; break;
case WDIOC_GETBOOTSTATUS:
if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT;
break;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if ( copy_to_user(argp, &ident, sizeof(ident)) ) if ( copy_to_user(argp, &ident, sizeof(ident)) )
return -EFAULT; return -EFAULT;
......
/*
* drivers/char/watchdog/davinci_wdt.c
*
* Watchdog driver for DaVinci DM644x/DM646x processors
*
* Copyright (C) 2006 Texas Instruments.
*
* 2007 (c) MontaVista Software, Inc. This file is licensed under
* the terms of the GNU General Public License version 2. This program
* is licensed "as is" without any warranty of any kind, whether express
* or implied.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#define MODULE_NAME "DAVINCI-WDT: "
#define DEFAULT_HEARTBEAT 60
#define MAX_HEARTBEAT 600 /* really the max margin is 264/27MHz*/
/* Timer register set definition */
#define PID12 (0x0)
#define EMUMGT (0x4)
#define TIM12 (0x10)
#define TIM34 (0x14)
#define PRD12 (0x18)
#define PRD34 (0x1C)
#define TCR (0x20)
#define TGCR (0x24)
#define WDTCR (0x28)
/* TCR bit definitions */
#define ENAMODE12_DISABLED (0 << 6)
#define ENAMODE12_ONESHOT (1 << 6)
#define ENAMODE12_PERIODIC (2 << 6)
/* TGCR bit definitions */
#define TIM12RS_UNRESET (1 << 0)
#define TIM34RS_UNRESET (1 << 1)
#define TIMMODE_64BIT_WDOG (2 << 2)
/* WDTCR bit definitions */
#define WDEN (1 << 14)
#define WDFLAG (1 << 15)
#define WDKEY_SEQ0 (0xa5c6 << 16)
#define WDKEY_SEQ1 (0xda7e << 16)
static int heartbeat = DEFAULT_HEARTBEAT;
static spinlock_t io_lock;
static unsigned long wdt_status;
#define WDT_IN_USE 0
#define WDT_OK_TO_CLOSE 1
#define WDT_REGION_INITED 2
#define WDT_DEVICE_INITED 3
static struct resource *wdt_mem;
static void __iomem *wdt_base;
static void wdt_service(void)
{
spin_lock(&io_lock);
/* put watchdog in service state */
davinci_writel(WDKEY_SEQ0, wdt_base + WDTCR);
/* put watchdog in active state */
davinci_writel(WDKEY_SEQ1, wdt_base + WDTCR);
spin_unlock(&io_lock);
}
static void wdt_enable(void)
{
u32 tgcr;
u32 timer_margin;
spin_lock(&io_lock);
/* disable, internal clock source */
davinci_writel(0, wdt_base + TCR);
/* reset timer, set mode to 64-bit watchdog, and unreset */
davinci_writel(0, wdt_base + TGCR);
tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
davinci_writel(tgcr, wdt_base + TGCR);
/* clear counter regs */
davinci_writel(0, wdt_base + TIM12);
davinci_writel(0, wdt_base + TIM34);
/* set timeout period */
timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) & 0xffffffff);
davinci_writel(timer_margin, wdt_base + PRD12);
timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) >> 32);
davinci_writel(timer_margin, wdt_base + PRD34);
/* enable run continuously */
davinci_writel(ENAMODE12_PERIODIC, wdt_base + TCR);
/* Once the WDT is in pre-active state write to
* TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
* write protected (except for the WDKEY field)
*/
/* put watchdog in pre-active state */
davinci_writel(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR);
/* put watchdog in active state */
davinci_writel(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR);
spin_unlock(&io_lock);
}
static int davinci_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;
wdt_enable();
return nonseekable_open(inode, file);
}
static ssize_t
davinci_wdt_write(struct file *file, const char *data, size_t len,
loff_t *ppos)
{
if (len)
wdt_service();
return len;
}
static struct watchdog_info ident = {
.options = WDIOF_KEEPALIVEPING,
.identity = "DaVinci Watchdog",
};
static int
davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
int ret = -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
ret = copy_to_user((struct watchdog_info *)arg, &ident,
sizeof(ident)) ? -EFAULT : 0;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
ret = put_user(0, (int *)arg);
break;
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
case WDIOC_KEEPALIVE:
wdt_service();
ret = 0;
break;
}
return ret;
}
static int davinci_wdt_release(struct inode *inode, struct file *file)
{
wdt_service();
clear_bit(WDT_IN_USE, &wdt_status);
return 0;
}
static const struct file_operations davinci_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = davinci_wdt_write,
.ioctl = davinci_wdt_ioctl,
.open = davinci_wdt_open,
.release = davinci_wdt_release,
};
static struct miscdevice davinci_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &davinci_wdt_fops,
};
static int davinci_wdt_probe(struct platform_device *pdev)
{
int ret = 0, size;
struct resource *res;
spin_lock_init(&io_lock);
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT;
printk(KERN_INFO MODULE_NAME
"DaVinci Watchdog Timer: heartbeat %d sec\n", heartbeat);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
printk(KERN_INFO MODULE_NAME
"failed to get memory region resource\n");
return -ENOENT;
}
size = res->end - res->start + 1;
wdt_mem = request_mem_region(res->start, size, pdev->name);
if (wdt_mem == NULL) {
printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
return -ENOENT;
}
wdt_base = (void __iomem *)(res->start);
ret = misc_register(&davinci_wdt_miscdev);
if (ret < 0) {
printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
release_resource(wdt_mem);
kfree(wdt_mem);
} else {
set_bit(WDT_DEVICE_INITED, &wdt_status);
}
return ret;
}
static int davinci_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&davinci_wdt_miscdev);
if (wdt_mem) {
release_resource(wdt_mem);
kfree(wdt_mem);
wdt_mem = NULL;
}
return 0;
}
static struct platform_driver platform_wdt_driver = {
.driver = {
.name = "watchdog",
},
.probe = davinci_wdt_probe,
.remove = davinci_wdt_remove,
};
static int __init davinci_wdt_init(void)
{
return platform_driver_register(&platform_wdt_driver);
}
static void __exit davinci_wdt_exit(void)
{
return platform_driver_unregister(&platform_wdt_driver);
}
module_init(davinci_wdt_init);
module_exit(davinci_wdt_exit);
MODULE_AUTHOR("Texas Instruments");
MODULE_DESCRIPTION("DaVinci Watchdog Driver");
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat,
"Watchdog heartbeat period in seconds from 1 to "
__MODULE_STRING(MAX_HEARTBEAT) ", default "
__MODULE_STRING(DEFAULT_HEARTBEAT));
MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
...@@ -39,7 +39,12 @@ ...@@ -39,7 +39,12 @@
* 82801HR (ICH8R) : document number 313056-002, 313057-004, * 82801HR (ICH8R) : document number 313056-002, 313057-004,
* 82801HH (ICH8DH) : document number 313056-002, 313057-004, * 82801HH (ICH8DH) : document number 313056-002, 313057-004,
* 82801HO (ICH8DO) : document number 313056-002, 313057-004, * 82801HO (ICH8DO) : document number 313056-002, 313057-004,
* 6300ESB (6300ESB) : document number 300641-003 * 82801IB (ICH9) : document number 316972-001, 316973-001,
* 82801IR (ICH9R) : document number 316972-001, 316973-001,
* 82801IH (ICH9DH) : document number 316972-001, 316973-001,
* 6300ESB (6300ESB) : document number 300641-003, 300884-010,
* 631xESB (631xESB) : document number 313082-001, 313075-005,
* 632xESB (632xESB) : document number 313082-001, 313075-005
*/ */
/* /*
...@@ -48,8 +53,8 @@ ...@@ -48,8 +53,8 @@
/* Module and version information */ /* Module and version information */
#define DRV_NAME "iTCO_wdt" #define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.01" #define DRV_VERSION "1.02"
#define DRV_RELDATE "21-Jan-2007" #define DRV_RELDATE "26-Jul-2007"
#define PFX DRV_NAME ": " #define PFX DRV_NAME ": "
/* Includes */ /* Includes */
...@@ -92,6 +97,10 @@ enum iTCO_chipsets { ...@@ -92,6 +97,10 @@ enum iTCO_chipsets {
TCO_ICH8, /* ICH8 & ICH8R */ TCO_ICH8, /* ICH8 & ICH8R */
TCO_ICH8DH, /* ICH8DH */ TCO_ICH8DH, /* ICH8DH */
TCO_ICH8DO, /* ICH8DO */ TCO_ICH8DO, /* ICH8DO */
TCO_ICH9, /* ICH9 */
TCO_ICH9R, /* ICH9R */
TCO_ICH9DH, /* ICH9DH */
TCO_631XESB, /* 631xESB/632xESB */
}; };
static struct { static struct {
...@@ -118,6 +127,10 @@ static struct { ...@@ -118,6 +127,10 @@ static struct {
{"ICH8 or ICH8R", 2}, {"ICH8 or ICH8R", 2},
{"ICH8DH", 2}, {"ICH8DH", 2},
{"ICH8DO", 2}, {"ICH8DO", 2},
{"ICH9", 2},
{"ICH9R", 2},
{"ICH9DH", 2},
{"631xESB/632xESB", 2},
{NULL,0} {NULL,0}
}; };
...@@ -148,6 +161,25 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { ...@@ -148,6 +161,25 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO },
{ PCI_VENDOR_ID_INTEL, 0x2918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9 },
{ PCI_VENDOR_ID_INTEL, 0x2916, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9R },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9DH },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ PCI_VENDOR_ID_INTEL, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
{ 0, }, /* End of list */ { 0, }, /* End of list */
}; };
MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl); MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
......
...@@ -321,6 +321,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd, ...@@ -321,6 +321,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p); return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
......
...@@ -215,6 +215,11 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file, ...@@ -215,6 +215,11 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
return -EFAULT; return -EFAULT;
} }
break; break;
case WDIOC_GETBOOTSTATUS:
if (copy_to_user(p, &status, sizeof(int))) {
return -EFAULT;
}
break;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof(ident))) { if (copy_to_user(argp, &ident, sizeof(ident))) {
return -EFAULT; return -EFAULT;
......
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <asm/of_platform.h>
#include <asm/uaccess.h>
#include <asm/mpc52xx.h>
#define GPT_MODE_WDT (1<<15)
#define GPT_MODE_CE (1<<12)
#define GPT_MODE_MS_TIMER (0x4)
struct mpc5200_wdt {
unsigned count; /* timer ticks before watchdog kicks in */
long ipb_freq;
struct miscdevice miscdev;
struct resource mem;
struct mpc52xx_gpt __iomem *regs;
spinlock_t io_lock;
};
/* is_active stores wether or not the /dev/watchdog device is opened */
static unsigned long is_active;
/* misc devices don't provide a way, to get back to 'dev' or 'miscdev' from
* file operations, which sucks. But there can be max 1 watchdog anyway, so...
*/
static struct mpc5200_wdt *wdt_global;
/* helper to calculate timeout in timer counts */
static void mpc5200_wdt_set_timeout(struct mpc5200_wdt *wdt, int timeout)
{
/* use biggest prescaler of 64k */
wdt->count = (wdt->ipb_freq + 0xffff) / 0x10000 * timeout;
if (wdt->count > 0xffff)
wdt->count = 0xffff;
}
/* return timeout in seconds (calculated from timer count) */
static int mpc5200_wdt_get_timeout(struct mpc5200_wdt *wdt)
{
return wdt->count * 0x10000 / wdt->ipb_freq;
}
/* watchdog operations */
static int mpc5200_wdt_start(struct mpc5200_wdt *wdt)
{
spin_lock(&wdt->io_lock);
/* disable */
out_be32(&wdt->regs->mode, 0);
/* set timeout, with maximum prescaler */
out_be32(&wdt->regs->count, 0x0 | wdt->count);
/* enable watchdog */
out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER);
spin_unlock(&wdt->io_lock);
return 0;
}
static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt)
{
spin_lock(&wdt->io_lock);
/* writing A5 to OCPW resets the watchdog */
out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode)));
spin_unlock(&wdt->io_lock);
return 0;
}
static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt)
{
spin_lock(&wdt->io_lock);
/* disable */
out_be32(&wdt->regs->mode, 0);
spin_unlock(&wdt->io_lock);
return 0;
}
/* file operations */
static ssize_t mpc5200_wdt_write(struct file *file, const char *data,
size_t len, loff_t *ppos)
{
struct mpc5200_wdt *wdt = file->private_data;
mpc5200_wdt_ping(wdt);
return 0;
}
static struct watchdog_info mpc5200_wdt_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "mpc5200 watchdog on GPT0",
};
static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct mpc5200_wdt *wdt = file->private_data;
int __user *data = (int __user *)arg;
int timeout;
int ret = 0;
switch (cmd) {
case WDIOC_GETSUPPORT:
ret = copy_to_user(data, &mpc5200_wdt_info,
sizeof(mpc5200_wdt_info));
if (ret)
ret = -EFAULT;
break;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
ret = put_user(0, data);
break;
case WDIOC_KEEPALIVE:
mpc5200_wdt_ping(wdt);
break;
case WDIOC_SETTIMEOUT:
ret = get_user(timeout, data);
if (ret)
break;
mpc5200_wdt_set_timeout(wdt, timeout);
mpc5200_wdt_start(wdt);
/* fall through and return the timeout */
case WDIOC_GETTIMEOUT:
timeout = mpc5200_wdt_get_timeout(wdt);
ret = put_user(timeout, data);
break;
default:
ret = -ENOTTY;
}
return ret;
}
static int mpc5200_wdt_open(struct inode *inode, struct file *file)
{
/* /dev/watchdog can only be opened once */
if (test_and_set_bit(0, &is_active))
return -EBUSY;
/* Set and activate the watchdog */
mpc5200_wdt_set_timeout(wdt_global, 30);
mpc5200_wdt_start(wdt_global);
file->private_data = wdt_global;
return nonseekable_open(inode, file);
}
static int mpc5200_wdt_release(struct inode *inode, struct file *file)
{
#if WATCHDOG_NOWAYOUT == 0
struct mpc5200_wdt *wdt = file->private_data;
mpc5200_wdt_stop(wdt);
wdt->count = 0; /* == disabled */
#endif
clear_bit(0, &is_active);
return 0;
}
static struct file_operations mpc5200_wdt_fops = {
.owner = THIS_MODULE,
.write = mpc5200_wdt_write,
.ioctl = mpc5200_wdt_ioctl,
.open = mpc5200_wdt_open,
.release = mpc5200_wdt_release,
};
/* module operations */
static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match)
{
struct mpc5200_wdt *wdt;
int err;
const void *has_wdt;
int size;
has_wdt = of_get_property(op->node, "has-wdt", NULL);
if (!has_wdt)
return -ENODEV;
wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
if (!wdt)
return -ENOMEM;
wdt->ipb_freq = mpc52xx_find_ipb_freq(op->node);
err = of_address_to_resource(op->node, 0, &wdt->mem);
if (err)
goto out_free;
size = wdt->mem.end - wdt->mem.start + 1;
if (!request_mem_region(wdt->mem.start, size, "mpc5200_wdt")) {
err = -ENODEV;
goto out_free;
}
wdt->regs = ioremap(wdt->mem.start, size);
if (!wdt->regs) {
err = -ENODEV;
goto out_release;
}
dev_set_drvdata(&op->dev, wdt);
spin_lock_init(&wdt->io_lock);
wdt->miscdev = (struct miscdevice) {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &mpc5200_wdt_fops,
.parent = &op->dev,
};
wdt_global = wdt;
err = misc_register(&wdt->miscdev);
if (!err)
return 0;
iounmap(wdt->regs);
out_release:
release_mem_region(wdt->mem.start, size);
out_free:
kfree(wdt);
return err;
}
static int mpc5200_wdt_remove(struct of_device *op)
{
struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
mpc5200_wdt_stop(wdt);
misc_deregister(&wdt->miscdev);
iounmap(wdt->regs);
release_mem_region(wdt->mem.start, wdt->mem.end - wdt->mem.start + 1);
kfree(wdt);
return 0;
}
static int mpc5200_wdt_suspend(struct of_device *op, pm_message_t state)
{
struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
mpc5200_wdt_stop(wdt);
return 0;
}
static int mpc5200_wdt_resume(struct of_device *op)
{
struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
if (wdt->count)
mpc5200_wdt_start(wdt);
return 0;
}
static int mpc5200_wdt_shutdown(struct of_device *op)
{
struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
mpc5200_wdt_stop(wdt);
return 0;
}
static struct of_device_id mpc5200_wdt_match[] = {
{ .compatible = "mpc5200-gpt", },
{},
};
static struct of_platform_driver mpc5200_wdt_driver = {
.owner = THIS_MODULE,
.name = "mpc5200-gpt-wdt",
.match_table = mpc5200_wdt_match,
.probe = mpc5200_wdt_probe,
.remove = mpc5200_wdt_remove,
.suspend = mpc5200_wdt_suspend,
.resume = mpc5200_wdt_resume,
.shutdown = mpc5200_wdt_shutdown,
};
static int __init mpc5200_wdt_init(void)
{
return of_register_platform_driver(&mpc5200_wdt_driver);
}
static void __exit mpc5200_wdt_exit(void)
{
of_unregister_platform_driver(&mpc5200_wdt_driver);
}
module_init(mpc5200_wdt_init);
module_exit(mpc5200_wdt_exit);
MODULE_AUTHOR("Domen Puncer <domen.puncer@telargo.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
...@@ -119,6 +119,9 @@ static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -119,6 +119,9 @@ static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) { switch (cmd) {
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
mpc83xx_wdt_keepalive(); mpc83xx_wdt_keepalive();
return 0; return 0;
......
...@@ -57,7 +57,7 @@ static int mpc8xx_wdt_open(struct inode *inode, struct file *file) ...@@ -57,7 +57,7 @@ static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
m8xx_wdt_reset(); m8xx_wdt_reset();
mpc8xx_wdt_handler_disable(); mpc8xx_wdt_handler_disable();
return 0; return nonseekable_open(inode, file);
} }
static int mpc8xx_wdt_release(struct inode *inode, struct file *file) static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
......
...@@ -143,6 +143,7 @@ static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int c ...@@ -143,6 +143,7 @@ static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int c
mtx1_wdt_reset(); mtx1_wdt_reset();
break; break;
case WDIOC_GETSTATUS: case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
if ( copy_to_user(argp, &value, sizeof(int)) ) if ( copy_to_user(argp, &value, sizeof(int)) )
return -EFAULT; return -EFAULT;
break; break;
......
...@@ -23,61 +23,101 @@ ...@@ -23,61 +23,101 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <asm/mv64x60.h> #include <linux/mv643xx.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
/* MV64x60 WDC (config) register access definitions */ #define MV64x60_WDT_WDC_OFFSET 0
#define MV64x60_WDC_CTL1_MASK (3 << 24)
#define MV64x60_WDC_CTL1(val) ((val & 3) << 24) /*
#define MV64x60_WDC_CTL2_MASK (3 << 26) * The watchdog configuration register contains a pair of 2-bit fields,
#define MV64x60_WDC_CTL2(val) ((val & 3) << 26) * 1. a reload field, bits 27-26, which triggers a reload of
* the countdown register, and
* 2. an enable field, bits 25-24, which toggles between
* enabling and disabling the watchdog timer.
* Bit 31 is a read-only field which indicates whether the
* watchdog timer is currently enabled.
*
* The low 24 bits contain the timer reload value.
*/
#define MV64x60_WDC_ENABLE_SHIFT 24
#define MV64x60_WDC_SERVICE_SHIFT 26
#define MV64x60_WDC_ENABLED_SHIFT 31
#define MV64x60_WDC_ENABLED_TRUE 1
#define MV64x60_WDC_ENABLED_FALSE 0
/* Flags bits */ /* Flags bits */
#define MV64x60_WDOG_FLAG_OPENED 0 #define MV64x60_WDOG_FLAG_OPENED 0
#define MV64x60_WDOG_FLAG_ENABLED 1
static unsigned long wdt_flags; static unsigned long wdt_flags;
static int wdt_status; static int wdt_status;
static void __iomem *mv64x60_regs; static void __iomem *mv64x60_wdt_regs;
static int mv64x60_wdt_timeout; static int mv64x60_wdt_timeout;
static int mv64x60_wdt_count;
static unsigned int bus_clk;
static char expect_close;
static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static void mv64x60_wdt_reg_write(u32 val) static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift)
{ {
/* Allow write only to CTL1 / CTL2 fields, retaining values in u32 data;
* other fields. u32 enabled;
*/ int ret = 0;
u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC);
data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK); spin_lock(&mv64x60_wdt_spinlock);
data |= val; data = readl(mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
writel(data, mv64x60_regs + MV64x60_WDT_WDC); enabled = (data >> MV64x60_WDC_ENABLED_SHIFT) & 1;
/* only toggle the requested field if enabled state matches predicate */
if ((enabled ^ enabled_predicate) == 0) {
/* We write a 1, then a 2 -- to the appropriate field */
data = (1 << field_shift) | mv64x60_wdt_count;
writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
data = (2 << field_shift) | mv64x60_wdt_count;
writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
ret = 1;
}
spin_unlock(&mv64x60_wdt_spinlock);
return ret;
} }
static void mv64x60_wdt_service(void) static void mv64x60_wdt_service(void)
{ {
/* Write 01 followed by 10 to CTL2 */ mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01)); MV64x60_WDC_SERVICE_SHIFT);
mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02)); }
static void mv64x60_wdt_handler_enable(void)
{
if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE,
MV64x60_WDC_ENABLE_SHIFT)) {
mv64x60_wdt_service();
printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
}
} }
static void mv64x60_wdt_handler_disable(void) static void mv64x60_wdt_handler_disable(void)
{ {
if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) { if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
/* Write 01 followed by 10 to CTL1 */ MV64x60_WDC_ENABLE_SHIFT))
mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01));
mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n"); printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
}
} }
static void mv64x60_wdt_handler_enable(void) static void mv64x60_wdt_set_timeout(unsigned int timeout)
{ {
if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) { /* maximum bus cycle count is 0xFFFFFFFF */
/* Write 01 followed by 10 to CTL1 */ if (timeout > 0xFFFFFFFF / bus_clk)
mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01)); timeout = 0xFFFFFFFF / bus_clk;
mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02));
printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n"); mv64x60_wdt_count = timeout * bus_clk >> 8;
} mv64x60_wdt_timeout = timeout;
} }
static int mv64x60_wdt_open(struct inode *inode, struct file *file) static int mv64x60_wdt_open(struct inode *inode, struct file *file)
...@@ -85,21 +125,24 @@ static int mv64x60_wdt_open(struct inode *inode, struct file *file) ...@@ -85,21 +125,24 @@ static int mv64x60_wdt_open(struct inode *inode, struct file *file)
if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags)) if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
return -EBUSY; return -EBUSY;
mv64x60_wdt_service(); if (nowayout)
mv64x60_wdt_handler_enable(); __module_get(THIS_MODULE);
nonseekable_open(inode, file); mv64x60_wdt_handler_enable();
return 0; return nonseekable_open(inode, file);
} }
static int mv64x60_wdt_release(struct inode *inode, struct file *file) static int mv64x60_wdt_release(struct inode *inode, struct file *file)
{ {
mv64x60_wdt_service(); if (expect_close == 42)
#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
mv64x60_wdt_handler_disable(); mv64x60_wdt_handler_disable();
#endif else {
printk(KERN_CRIT
"mv64x60_wdt: unexpected close, not stopping timer!\n");
mv64x60_wdt_service();
}
expect_close = 0;
clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags); clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
...@@ -109,8 +152,22 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file) ...@@ -109,8 +152,22 @@ static int mv64x60_wdt_release(struct inode *inode, struct file *file)
static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data, static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t * ppos) size_t len, loff_t * ppos)
{ {
if (len) if (len) {
if (!nowayout) {
size_t i;
expect_close = 0;
for (i = 0; i != len; i++) {
char c;
if(get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_close = 42;
}
}
mv64x60_wdt_service(); mv64x60_wdt_service();
}
return len; return len;
} }
...@@ -119,9 +176,12 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -119,9 +176,12 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int timeout; int timeout;
int options;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
static struct watchdog_info info = { static struct watchdog_info info = {
.options = WDIOF_KEEPALIVEPING, .options = WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE |
WDIOF_KEEPALIVEPING,
.firmware_version = 0, .firmware_version = 0,
.identity = "MV64x60 watchdog", .identity = "MV64x60 watchdog",
}; };
...@@ -143,7 +203,15 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -143,7 +203,15 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
return -EOPNOTSUPP; return -EOPNOTSUPP;
case WDIOC_SETOPTIONS: case WDIOC_SETOPTIONS:
return -EOPNOTSUPP; if (get_user(options, (int __user *)argp))
return -EFAULT;
if (options & WDIOS_DISABLECARD)
mv64x60_wdt_handler_disable();
if (options & WDIOS_ENABLECARD)
mv64x60_wdt_handler_enable();
break;
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
mv64x60_wdt_service(); mv64x60_wdt_service();
...@@ -151,11 +219,13 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -151,11 +219,13 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
break; break;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
return -EOPNOTSUPP; if (get_user(timeout, (int __user *)argp))
return -EFAULT;
mv64x60_wdt_set_timeout(timeout);
/* Fall through */
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
timeout = mv64x60_wdt_timeout * HZ; if (put_user(mv64x60_wdt_timeout, (int __user *)argp))
if (put_user(timeout, (int __user *)argp))
return -EFAULT; return -EFAULT;
break; break;
...@@ -184,18 +254,33 @@ static struct miscdevice mv64x60_wdt_miscdev = { ...@@ -184,18 +254,33 @@ static struct miscdevice mv64x60_wdt_miscdev = {
static int __devinit mv64x60_wdt_probe(struct platform_device *dev) static int __devinit mv64x60_wdt_probe(struct platform_device *dev)
{ {
struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data; struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data;
int bus_clk = 133; struct resource *r;
int timeout = 10;
mv64x60_wdt_timeout = 10; bus_clk = 133; /* in MHz */
if (pdata) { if (pdata) {
mv64x60_wdt_timeout = pdata->timeout; timeout = pdata->timeout;
bus_clk = pdata->bus_clk; bus_clk = pdata->bus_clk;
} }
mv64x60_regs = mv64x60_get_bridge_vbase(); /* Since bus_clk is truncated MHz, actual frequency could be
* up to 1MHz higher. Round up, since it's better to time out
* too late than too soon.
*/
bus_clk++;
bus_clk *= 1000000; /* convert to Hz */
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!r)
return -ENODEV;
mv64x60_wdt_regs = ioremap(r->start, r->end - r->start + 1);
if (mv64x60_wdt_regs == NULL)
return -ENOMEM;
mv64x60_wdt_set_timeout(timeout);
writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8, mv64x60_wdt_handler_disable(); /* in case timer was already running */
mv64x60_regs + MV64x60_WDT_WDC);
return misc_register(&mv64x60_wdt_miscdev); return misc_register(&mv64x60_wdt_miscdev);
} }
...@@ -204,9 +289,10 @@ static int __devexit mv64x60_wdt_remove(struct platform_device *dev) ...@@ -204,9 +289,10 @@ static int __devexit mv64x60_wdt_remove(struct platform_device *dev)
{ {
misc_deregister(&mv64x60_wdt_miscdev); misc_deregister(&mv64x60_wdt_miscdev);
mv64x60_wdt_service();
mv64x60_wdt_handler_disable(); mv64x60_wdt_handler_disable();
iounmap(mv64x60_wdt_regs);
return 0; return 0;
} }
...@@ -219,40 +305,16 @@ static struct platform_driver mv64x60_wdt_driver = { ...@@ -219,40 +305,16 @@ static struct platform_driver mv64x60_wdt_driver = {
}, },
}; };
static struct platform_device *mv64x60_wdt_dev;
static int __init mv64x60_wdt_init(void) static int __init mv64x60_wdt_init(void)
{ {
int ret;
printk(KERN_INFO "MV64x60 watchdog driver\n"); printk(KERN_INFO "MV64x60 watchdog driver\n");
mv64x60_wdt_dev = platform_device_alloc(MV64x60_WDT_NAME, -1); return platform_driver_register(&mv64x60_wdt_driver);
if (!mv64x60_wdt_dev) {
ret = -ENOMEM;
goto out;
}
ret = platform_device_add(mv64x60_wdt_dev);
if (ret) {
platform_device_put(mv64x60_wdt_dev);
goto out;
}
ret = platform_driver_register(&mv64x60_wdt_driver);
if (ret) {
platform_device_unregister(mv64x60_wdt_dev);
goto out;
}
out:
return ret;
} }
static void __exit mv64x60_wdt_exit(void) static void __exit mv64x60_wdt_exit(void)
{ {
platform_driver_unregister(&mv64x60_wdt_driver); platform_driver_unregister(&mv64x60_wdt_driver);
platform_device_unregister(mv64x60_wdt_dev);
} }
module_init(mv64x60_wdt_init); module_init(mv64x60_wdt_init);
......
...@@ -142,7 +142,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file) ...@@ -142,7 +142,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
omap_wdt_set_timeout(); omap_wdt_set_timeout();
omap_wdt_enable(); omap_wdt_enable();
return 0; return nonseekable_open(inode, file);
} }
static int omap_wdt_release(struct inode *inode, struct file *file) static int omap_wdt_release(struct inode *inode, struct file *file)
...@@ -197,7 +197,7 @@ omap_wdt_ioctl(struct inode *inode, struct file *file, ...@@ -197,7 +197,7 @@ omap_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) { switch (cmd) {
default: default:
return -ENOIOCTLCMD; return -ENOTTY;
case WDIOC_GETSUPPORT: case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info __user *)arg, &ident, return copy_to_user((struct watchdog_info __user *)arg, &ident,
sizeof(ident)); sizeof(ident));
......
...@@ -52,10 +52,10 @@ ...@@ -52,10 +52,10 @@
#include <asm/arch/map.h> #include <asm/arch/map.h>
#undef S3C24XX_VA_WATCHDOG #undef S3C_VA_WATCHDOG
#define S3C24XX_VA_WATCHDOG (0) #define S3C_VA_WATCHDOG (0)
#include <asm/arch/regs-watchdog.h> #include <asm/plat-s3c/regs-watchdog.h>
#define PFX "s3c2410-wdt: " #define PFX "s3c2410-wdt: "
......
...@@ -45,7 +45,6 @@ static int boot_status; ...@@ -45,7 +45,6 @@ static int boot_status;
*/ */
static int sa1100dog_open(struct inode *inode, struct file *file) static int sa1100dog_open(struct inode *inode, struct file *file)
{ {
nonseekable_open(inode, file);
if (test_and_set_bit(1,&sa1100wdt_users)) if (test_and_set_bit(1,&sa1100wdt_users))
return -EBUSY; return -EBUSY;
...@@ -54,7 +53,7 @@ static int sa1100dog_open(struct inode *inode, struct file *file) ...@@ -54,7 +53,7 @@ static int sa1100dog_open(struct inode *inode, struct file *file)
OSSR = OSSR_M3; OSSR = OSSR_M3;
OWER = OWER_WME; OWER = OWER_WME;
OIER |= OIER_E3; OIER |= OIER_E3;
return 0; return nonseekable_open(inode, file);
} }
/* /*
......
...@@ -191,8 +191,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou ...@@ -191,8 +191,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
static int fop_open(struct inode * inode, struct file * file) static int fop_open(struct inode * inode, struct file * file)
{ {
nonseekable_open(inode, file);
/* Just in case we're already talking to someone... */ /* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open)) if(test_and_set_bit(0, &wdt_is_open))
return -EBUSY; return -EBUSY;
...@@ -202,7 +200,7 @@ static int fop_open(struct inode * inode, struct file * file) ...@@ -202,7 +200,7 @@ static int fop_open(struct inode * inode, struct file * file)
/* Good, fire up the show */ /* Good, fire up the show */
wdt_startup(); wdt_startup();
return 0; return nonseekable_open(inode, file);
} }
static int fop_close(struct inode * inode, struct file * file) static int fop_close(struct inode * inode, struct file * file)
......
...@@ -150,8 +150,6 @@ static inline int sc1200wdt_status(void) ...@@ -150,8 +150,6 @@ static inline int sc1200wdt_status(void)
static int sc1200wdt_open(struct inode *inode, struct file *file) static int sc1200wdt_open(struct inode *inode, struct file *file)
{ {
nonseekable_open(inode, file);
/* allow one at a time */ /* allow one at a time */
if (down_trylock(&open_sem)) if (down_trylock(&open_sem))
return -EBUSY; return -EBUSY;
...@@ -162,7 +160,7 @@ static int sc1200wdt_open(struct inode *inode, struct file *file) ...@@ -162,7 +160,7 @@ static int sc1200wdt_open(struct inode *inode, struct file *file)
sc1200wdt_start(); sc1200wdt_start();
printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout); printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
return 0; return nonseekable_open(inode, file);
} }
......
...@@ -248,8 +248,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou ...@@ -248,8 +248,6 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou
static int fop_open(struct inode * inode, struct file * file) static int fop_open(struct inode * inode, struct file * file)
{ {
nonseekable_open(inode, file);
/* Just in case we're already talking to someone... */ /* Just in case we're already talking to someone... */
if(test_and_set_bit(0, &wdt_is_open)) if(test_and_set_bit(0, &wdt_is_open))
return -EBUSY; return -EBUSY;
...@@ -258,7 +256,7 @@ static int fop_open(struct inode * inode, struct file * file) ...@@ -258,7 +256,7 @@ static int fop_open(struct inode * inode, struct file * file)
/* Good, fire up the show */ /* Good, fire up the show */
wdt_startup(); wdt_startup();
return 0; return nonseekable_open(inode, file);
} }
static int fop_close(struct inode * inode, struct file * file) static int fop_close(struct inode * inode, struct file * file)
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com> * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
* added support for W83627THF. * added support for W83627THF.
* *
* (c) Copyright 2003 Pdraig Brady <P@draigBrady.com> * (c) Copyright 2003,2007 Pdraig Brady <P@draigBrady.com>
* *
* Based on advantechwdt.c which is based on wdt.c. * Based on advantechwdt.c which is based on wdt.c.
* Original copyright messages: * Original copyright messages:
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/system.h> #include <asm/system.h>
#define WATCHDOG_NAME "w83627hf/thf WDT" #define WATCHDOG_NAME "w83627hf/thf/hg WDT"
#define PFX WATCHDOG_NAME ": " #define PFX WATCHDOG_NAME ": "
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
...@@ -57,7 +57,7 @@ MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); ...@@ -57,7 +57,7 @@ MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
module_param(timeout, int, 0); module_param(timeout, int, 0);
MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) "."); MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
static int nowayout = WATCHDOG_NOWAYOUT; static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0); module_param(nowayout, int, 0);
...@@ -114,11 +114,17 @@ w83627hf_init(void) ...@@ -114,11 +114,17 @@ w83627hf_init(void)
printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout); printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout);
outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
} }
outb_p(0xF5, WDT_EFER); /* Select CRF5 */ outb_p(0xF5, WDT_EFER); /* Select CRF5 */
t=inb_p(WDT_EFDR); /* read CRF5 */ t=inb_p(WDT_EFDR); /* read CRF5 */
t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */ t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */
outb_p(t, WDT_EFDR); /* Write back to CRF5 */ outb_p(t, WDT_EFDR); /* Write back to CRF5 */
outb_p(0xF7, WDT_EFER); /* Select CRF7 */
t=inb_p(WDT_EFDR); /* read CRF7 */
t&=~0xC0; /* disable keyboard & mouse turning off watchdog */
outb_p(t, WDT_EFDR); /* Write back to CRF7 */
w83627hf_unselect_wd_register(); w83627hf_unselect_wd_register();
} }
...@@ -154,7 +160,7 @@ wdt_disable(void) ...@@ -154,7 +160,7 @@ wdt_disable(void)
static int static int
wdt_set_heartbeat(int t) wdt_set_heartbeat(int t)
{ {
if ((t < 1) || (t > 63)) if ((t < 1) || (t > 255))
return -EINVAL; return -EINVAL;
timeout = t; timeout = t;
...@@ -324,11 +330,11 @@ wdt_init(void) ...@@ -324,11 +330,11 @@ wdt_init(void)
spin_lock_init(&io_lock); spin_lock_init(&io_lock);
printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF Super I/O chip initialising.\n"); printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n");
if (wdt_set_heartbeat(timeout)) { if (wdt_set_heartbeat(timeout)) {
wdt_set_heartbeat(WATCHDOG_TIMEOUT); wdt_set_heartbeat(WATCHDOG_TIMEOUT);
printk (KERN_INFO PFX "timeout value must be 1<=timeout<=63, using %d\n", printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
WATCHDOG_TIMEOUT); WATCHDOG_TIMEOUT);
} }
......
...@@ -120,14 +120,6 @@ extern spinlock_t mv64x60_lock; ...@@ -120,14 +120,6 @@ extern spinlock_t mv64x60_lock;
#define MV64x60_64BIT_WIN_COUNT 24 #define MV64x60_64BIT_WIN_COUNT 24
/* Watchdog Platform Device, Driver Data */
#define MV64x60_WDT_NAME "wdt"
struct mv64x60_wdt_pdata {
int timeout; /* watchdog expiry in seconds, default 10 */
int bus_clk; /* bus clock in MHz, default 133 */
};
/* /*
* Define a structure that's used to pass in config information to the * Define a structure that's used to pass in config information to the
* core routines. * core routines.
......
...@@ -1302,4 +1302,12 @@ struct mv643xx_eth_platform_data { ...@@ -1302,4 +1302,12 @@ struct mv643xx_eth_platform_data {
u8 mac_addr[6]; /* mac address if non-zero*/ u8 mac_addr[6]; /* mac address if non-zero*/
}; };
/* Watchdog Platform Device, Driver Data */
#define MV64x60_WDT_NAME "mv64x60_wdt"
struct mv64x60_wdt_pdata {
int timeout; /* watchdog expiry in seconds, default 10 */
int bus_clk; /* bus clock in MHz, default 133 */
};
#endif /* __ASM_MV643XX_H */ #endif /* __ASM_MV643XX_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment