diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-31 20:43:52 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-31 20:43:52 -0700 |
commit | 2f63251ed0a803ddbe7bf2577b69d467aa872f68 (patch) | |
tree | 960ba4e27bb2cffdda0841ee701515c4bd75143a | |
parent | d6dd9e93c7531fa31370e27d053a3940d8d662fb (diff) | |
parent | 647e50f38345525d8261c295a0d0629dcea23a9b (diff) |
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
...
29 files changed, 1509 insertions, 156 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index c2928976074..1e15a0edc31 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -756,6 +756,14 @@ L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) W: http://blackfin.uclinux.org 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 P: Thomas Sailer M: t.sailer@alumni.ethz.ch diff --git a/arch/powerpc/boot/dts/prpmc2800.dts b/arch/powerpc/boot/dts/prpmc2800.dts index 699d0df574d..5300b50cdc2 100644 --- a/arch/powerpc/boot/dts/prpmc2800.dts +++ b/arch/powerpc/boot/dts/prpmc2800.dts @@ -207,6 +207,12 @@ interrupt-parent = <&/mv64x60/pic>; }; + wdt@b410 { /* watchdog timer */ + compatible = "marvell,mv64x60-wdt"; + reg = <b410 8>; + timeout = <a>; /* wdt timeout in seconds */ + }; + i2c@c000 { device_type = "i2c"; compatible = "marvell,mv64x60-i2c"; diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c index b618fa60aef..548a32082e4 100644 --- a/arch/powerpc/sysdev/mv64x60_dev.c +++ b/arch/powerpc/sysdev/mv64x60_dev.c @@ -390,6 +390,61 @@ error: 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) { struct device_node *np = NULL; @@ -414,6 +469,15 @@ static int __init mv64x60_device_setup(void) if ((err = mv64x60_i2c_device_setup(np, id))) 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; error: diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c index d212b1c418a..2744b8a6f66 100644 --- a/arch/ppc/syslib/mv64x60.c +++ b/arch/ppc/syslib/mv64x60.c @@ -441,6 +441,32 @@ static struct platform_device i2c_device = { }; #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) static struct mv64xxx_pdata mv64xxx_pdata = { .hs_reg_valid = 0, @@ -476,6 +502,9 @@ static struct platform_device *mv64x60_pd_devs[] __initdata = { #ifdef CONFIG_I2C_MV64XXX &i2c_device, #endif +#ifdef CONFIG_MV64X60_WDT + &wdt_device, +#endif #if defined(CONFIG_SYSFS) && !defined(CONFIG_GT64260) &mv64xxx_device, #endif diff --git a/drivers/Makefile b/drivers/Makefile index a9e4c5f922a..f0878b2ec55 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -66,6 +66,7 @@ obj-y += i2c/ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_POWER_SUPPLY) += power/ obj-$(CONFIG_HWMON) += hwmon/ +obj-$(CONFIG_WATCHDOG) += char/watchdog/ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 23b26b87cc3..d68ddbe70f7 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -97,7 +97,6 @@ obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_GPIO_TB0219) += tb0219.o obj-$(CONFIG_TELCLOCK) += tlclk.o -obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_MWAVE) += mwave/ obj-$(CONFIG_AGP) += agp/ obj-$(CONFIG_DRM) += drm/ diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 16fb23125e9..37bddc1802d 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -55,6 +55,8 @@ config SOFT_WATCHDOG To compile this driver as a module, choose M here: the module will be called softdog. +# ALPHA Architecture + # ARM Architecture config AT91RM9200_WATCHDOG @@ -189,7 +191,7 @@ config PNX4008_WATCHDOG config IOP_WATCHDOG tristate "IOP Watchdog" - depends on WATCHDOG && PLAT_IOP + depends on PLAT_IOP select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X) help Say Y here if to include support for the watchdog timer @@ -203,15 +205,48 @@ config IOP_WATCHDOG operating as an Root Complex and/or Central Resource, the PCI-X and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER. +config DAVINCI_WATCHDOG + tristate "DaVinci watchdog" + depends on ARCH_DAVINCI + help + Say Y here if to include support for the watchdog timer + in the DaVinci DM644x/DM646x processors. + To compile this driver as a module, choose M here: the + module will be called davinci_wdt. + + NOTE: once enabled, this timer cannot be disabled. + Say N if you are unsure. + +# ARM26 Architecture + # AVR32 Architecture config AT32AP700X_WDT tristate "AT32AP700x watchdog" - depends on WATCHDOG && CPU_AT32AP7000 + depends on CPU_AT32AP7000 help Watchdog timer embedded into AT32AP700x devices. This will reboot your system when the timeout is reached. +# BLACKFIN Architecture + +config BFIN_WDT + tristate "Blackfin On-Chip Watchdog Timer" + depends on BLACKFIN + ---help--- + If you say yes here you will get support for the Blackfin On-Chip + Watchdog Timer. If you have one of these processors and wish to + have watchdog support enabled, say Y, otherwise say N. + + To compile this driver as a module, choose M here: the + module will be called bfin_wdt. + +# CRIS Architecture + +# FRV Architecture + +# H8300 Architecture + # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT @@ -540,37 +575,11 @@ config SBC_EPX_C3_WATCHDOG To compile this driver as a module, choose M here: the module will be called sbc_epx_c3. -# PowerPC Architecture +# M32R Architecture -config 8xx_WDT - tristate "MPC8xx Watchdog Timer" - depends on 8xx +# M68K Architecture -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. +# M68KNOMMU Architecture # MIPS Architecture @@ -600,6 +609,44 @@ config WDT_RM9K_GPI To compile this driver as a module, choose M here: the module will be called rm9k_wdt. +# PARISC Architecture + +# POWERPC Architecture + +config MPC5200_WDT + tristate "MPC5200 Watchdog Timer" + depends on PPC_MPC52xx + +config 8xx_WDT + tristate "MPC8xx Watchdog Timer" + depends on 8xx + +config 83xx_WDT + tristate "MPC83xx Watchdog Timer" + depends on PPC_83xx + +config MV64X60_WDT + tristate "MV64X60 (Marvell Discovery) Watchdog Timer" + depends on MV64X60 + +config BOOKE_WDT + bool "PowerPC Book-E Watchdog Timer" + depends on BOOKE || 4xx + ---help--- + Please see Documentation/watchdog/watchdog-api.txt for + more information. + +# PPC64 Architecture + +config WATCHDOG_RTAS + tristate "RTAS watchdog" + depends on PPC_RTAS + help + This driver adds watchdog support for the RTAS watchdog. + + To compile this driver as a module, choose M here. The module + will be called wdrtas. + # S390 Architecture config ZVM_WATCHDOG @@ -614,7 +661,7 @@ config ZVM_WATCHDOG To compile this driver as a module, choose M here. The module will be called vmwatchdog. -# SUPERH Architecture +# SUPERH (sh + sh64) Architecture config SH_WDT tristate "SuperH Watchdog" @@ -641,6 +688,8 @@ config SH_WDT_MMAP If you say Y here, user applications will be able to mmap the WDT/CPG registers. +# SPARC Architecture + # SPARC64 Architecture config WATCHDOG_CP1XXX @@ -665,6 +714,10 @@ config WATCHDOG_RIO machines. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. +# V850 Architecture + +# XTENSA Architecture + # # ISA-based Watchdog Cards # diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index bdb9d5e3bb4..389f8b14ccc 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -22,6 +22,8 @@ obj-$(CONFIG_WDTPCI) += wdt_pci.o # USB-based Watchdog Cards obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o +# ALPHA Architecture + # ARM Architecture obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o @@ -36,10 +38,22 @@ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o +obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o + +# ARM26 Architecture # AVR32 Architecture obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o +# BLACKFIN Architecture +obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o + +# CRIS Architecture + +# FRV Architecture + +# H8300 Architecture + # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o @@ -66,8 +80,22 @@ obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o obj-$(CONFIG_MACHZ_WDT) += machzwd.o obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o -# PowerPC Architecture +# M32R Architecture + +# M68K Architecture + +# M68KNOMMU Architecture + +# MIPS Architecture +obj-$(CONFIG_INDYDOG) += indydog.o +obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o +obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o + +# PARISC Architecture + +# POWERPC Architecture obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o +obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o @@ -75,17 +103,18 @@ obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o # PPC64 Architecture obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o -# MIPS Architecture -obj-$(CONFIG_INDYDOG) += indydog.o -obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o -obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o - # S390 Architecture -# SUPERH Architecture +# SUPERH (sh + sh64) Architecture obj-$(CONFIG_SH_WDT) += shwdt.o +# SPARC Architecture + # SPARC64 Architecture +# V850 Architecture + +# XTENSA Architecture + # Architecture Independant obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o diff --git a/drivers/char/watchdog/bfin_wdt.c b/drivers/char/watchdog/bfin_wdt.c new file mode 100644 index 00000000000..309d27913fc --- /dev/null +++ b/drivers/char/watchdog/bfin_wdt.c @@ -0,0 +1,490 @@ +/* + * Blackfin On-Chip Watchdog Driver + * Supports BF53[123]/BF53[467]/BF54[2489]/BF561 + * + * Originally based on softdog.c + * Copyright 2006-2007 Analog Devices Inc. + * Copyright 2006-2007 Michele d'Amico + * Copyright 1996 Alan Cox <alan@redhat.com> + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/timer.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/fs.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <asm/blackfin.h> +#include <asm/uaccess.h> + +#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) +#define stampit() stamp("here i am") + +#define WATCHDOG_NAME "bfin-wdt" +#define PFX WATCHDOG_NAME ": " + +/* The BF561 has two watchdogs (one per core), but since Linux + * only runs on core A, we'll just work with that one. + */ +#ifdef BF561_FAMILY +# define bfin_read_WDOG_CTL() bfin_read_WDOGA_CTL() +# define bfin_read_WDOG_CNT() bfin_read_WDOGA_CNT() +# define bfin_read_WDOG_STAT() bfin_read_WDOGA_STAT() +# define bfin_write_WDOG_CTL(x) bfin_write_WDOGA_CTL(x) +# define bfin_write_WDOG_CNT(x) bfin_write_WDOGA_CNT(x) +# define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x) +#endif + +/* Bit in SWRST that indicates boot caused by watchdog */ +#define SWRST_RESET_WDOG 0x4000 + +/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */ +#define WDOG_EXPIRED 0x8000 + +/* Masks for WDEV field in WDOG_CTL register */ +#define ICTL_RESET 0x0 +#define ICTL_NMI 0x2 +#define ICTL_GPI 0x4 +#define ICTL_NONE 0x6 +#define ICTL_MASK 0x6 + +/* Masks for WDEN field in WDOG_CTL register */ +#define WDEN_MASK 0x0FF0 +#define WDEN_ENABLE 0x0000 +#define WDEN_DISABLE 0x0AD0 + +/* some defaults */ +#define WATCHDOG_TIMEOUT 20 + +static unsigned int timeout = WATCHDOG_TIMEOUT; +static int nowayout = WATCHDOG_NOWAYOUT; +static struct watchdog_info bfin_wdt_info; +static unsigned long open_check; +static char expect_close; +static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED; + +/** + * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive + * + * The Userspace watchdog got a KeepAlive: schedule the next timeout. + */ +static int bfin_wdt_keepalive(void) +{ + stampit(); + bfin_write_WDOG_STAT(0); + return 0; +} + +/** + * bfin_wdt_stop - Stop the Watchdog + * + * Stops the on-chip watchdog. + */ +static int bfin_wdt_stop(void) +{ + stampit(); + bfin_write_WDOG_CTL(WDEN_DISABLE); + return 0; +} + +/** + * bfin_wdt_start - Start the Watchdog + * + * Starts the on-chip watchdog. Automatically loads WDOG_CNT + * into WDOG_STAT for us. + */ +static int bfin_wdt_start(void) +{ + stampit(); + bfin_write_WDOG_CTL(WDEN_ENABLE | ICTL_RESET); + return 0; +} + +/** + * bfin_wdt_running - Check Watchdog status + * + * See if the watchdog is running. + */ +static int bfin_wdt_running(void) +{ + stampit(); + return ((bfin_read_WDOG_CTL() & WDEN_MASK) != WDEN_DISABLE); +} + +/** + * bfin_wdt_set_timeout - Set the Userspace Watchdog timeout + * @t: new timeout value (in seconds) + * + * Translate the specified timeout in seconds into System Clock + * terms which is what the on-chip Watchdog requires. + */ +static int bfin_wdt_set_timeout(unsigned long t) +{ + u32 cnt; + unsigned long flags; + + stampit(); + + cnt = t * get_sclk(); + if (cnt < get_sclk()) { + printk(KERN_WARNING PFX "timeout value is too large\n"); + return -EINVAL; + } + + spin_lock_irqsave(&bfin_wdt_spinlock, flags); + { + int run = bfin_wdt_running(); + bfin_wdt_stop(); + bfin_write_WDOG_CNT(cnt); + if (run) bfin_wdt_start(); + } + spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); + + timeout = t; + + return 0; +} + +/** + * bfin_wdt_open - Open the Device + * @inode: inode of device + * @file: file handle of device + * + * Watchdog device is opened and started. + */ +static int bfin_wdt_open(struct inode *inode, struct file *file) +{ + stampit(); + + if (test_and_set_bit(0, &open_check)) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + bfin_wdt_keepalive(); + bfin_wdt_start(); + + return nonseekable_open(inode, file); +} + +/** + * bfin_wdt_close - Close the Device + * @inode: inode of device + * @file: file handle of device + * + * Watchdog device is closed and stopped. + */ +static int bfin_wdt_release(struct inode *inode, struct file *file) +{ + stampit(); + + if (expect_close == 42) { + bfin_wdt_stop(); + } else { + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + bfin_wdt_keepalive(); + } + + expect_close = 0; + clear_bit(0, &open_check); + + return 0; +} + +/** + * bfin_wdt_write - Write to Device + * @file: file handle of device + * @buf: buffer to write + * @count: length of buffer + * @ppos: offset + * + * Pings the watchdog on write. + */ +static ssize_t bfin_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + stampit(); + + if (len) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + expect_close = 0; + + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } + bfin_wdt_keepalive(); + } + + return len; +} + +/** + * bfin_wdt_ioctl - Query Device + * @inode: inode of device + * @file: file handle of device + * @cmd: watchdog command + * @arg: argument + * + * Query basic information from the device or ping it, as outlined by the + * watchdog API. + */ +static int bfin_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + + stampit(); + + switch (cmd) { + default: + return -ENOTTY; + + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info))) + return -EFAULT; + else + return 0; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p); + + case WDIOC_KEEPALIVE: + bfin_wdt_keepalive(); + return 0; + + case WDIOC_SETTIMEOUT: { + int new_timeout; + + if (get_user(new_timeout, p)) + return -EFAULT; + + if (bfin_wdt_set_timeout(new_timeout)) + return -EINVAL; + } + /* Fall */ + case WDIOC_GETTIMEOUT: + return put_user(timeout, p); + + case WDIOC_SETOPTIONS: { + unsigned long flags; + int options, ret = -EINVAL; + + if (get_user(options, p)) + return -EFAULT; + + spin_lock_irqsave(&bfin_wdt_spinlock, flags); + + if (options & WDIOS_DISABLECARD) { + bfin_wdt_stop(); + ret = 0; + } + + if (options & WDIOS_ENABLECARD) { + bfin_wdt_start(); + ret = 0; + } + + spin_unlock_irqrestore(&bfin_wdt_spinlock, flags); + + return ret; + } + } +} + +/** + * bfin_wdt_notify_sys - Notifier Handler + * @this: notifier block + * @code: notifier event + * @unused: unused + * + * Handles specific events, such as turning off the watchdog during a + * shutdown event. + */ +static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + stampit(); + + if (code == SYS_DOWN || code == SYS_HALT) + bfin_wdt_stop(); + + return NOTIFY_DONE; +} + +#ifdef CONFIG_PM +static int state_before_suspend; + +/** + * bfin_wdt_suspend - suspend the watchdog + * @pdev: device being suspended + * @state: requested suspend state + * + * Remember if the watchdog was running and stop it. + * TODO: is this even right? Doesn't seem to be any + * standard in the watchdog world ... + */ +static int bfin_wdt_suspend(struct platform_device *pdev, pm_message_t state) +{ + stampit(); + + state_before_suspend = bfin_wdt_running(); + bfin_wdt_stop(); + + return 0; +} + +/** + * bfin_wdt_resume - resume the watchdog + * @pdev: device being resumed + * + * If the watchdog was running, turn it back on. + */ +static int bfin_wdt_resume(struct platform_device *pdev) +{ + stampit(); + + if (state_before_suspend) { + bfin_wdt_set_timeout(timeout); + bfin_wdt_start(); + } + + return 0; +} +#else +# define bfin_wdt_suspend NULL +# define bfin_wdt_resume NULL +#endif + +static struct platform_device bfin_wdt_device = { + .name = WATCHDOG_NAME, + .id = -1, +}; + +static struct platform_driver bfin_wdt_driver = { + .driver = { + .name = WATCHDOG_NAME, + .owner = THIS_MODULE, + }, + .suspend = bfin_wdt_suspend, + .resume = bfin_wdt_resume, +}; + +static struct file_operations bfin_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = bfin_wdt_write, + .ioctl = bfin_wdt_ioctl, + .open = bfin_wdt_open, + .release = bfin_wdt_release, +}; + +static struct miscdevice bfin_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &bfin_wdt_fops, +}; + +static struct watchdog_info bfin_wdt_info = { + .identity = "Blackfin Watchdog", + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +static struct notifier_block bfin_wdt_notifier = { + .notifier_call = bfin_wdt_notify_sys, +}; + +/** + * bfin_wdt_init - Initialize module + * + * Registers the device and notifier handler. Actual device + * initialization is handled by bfin_wdt_open(). + */ +static int __init bfin_wdt_init(void) +{ + int ret; + + stampit(); + + /* Check that the timeout value is within range */ + if (bfin_wdt_set_timeout(timeout)) + return -EINVAL; + + /* Since this is an on-chip device and needs no board-specific + * resources, we'll handle all the platform device stuff here. + */ + ret = platform_device_register(&bfin_wdt_device); + if (ret) + return ret; + + ret = platform_driver_probe(&bfin_wdt_driver, NULL); + if (ret) + return ret; + + ret = register_reboot_notifier(&bfin_wdt_notifier); + if (ret) { + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret); + return ret; + } + + ret = misc_register(&bfin_wdt_miscdev); + if (ret) { + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + unregister_reboot_notifier(&bfin_wdt_notifier); + return ret; + } + + printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n", + timeout, nowayout); + + return 0; +} + +/** + * bfin_wdt_exit - Deinitialize module + * + * Unregisters the device and notifier handler. Actual device + * deinitialization is handled by bfin_wdt_close(). + */ +static void __exit bfin_wdt_exit(void) +{ + misc_deregister(&bfin_wdt_miscdev); + unregister_reboot_notifier(&bfin_wdt_notifier); +} + +module_init(bfin_wdt_init); +module_exit(bfin_wdt_exit); + +MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>"); +MODULE_DESCRIPTION("Blackfin Watchdog Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, "W |