From 4cf85459e0db0b2ffd6c4112594b695bdbcff10f Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 28 May 2007 14:55:06 -0400 Subject: [WATCHDOG] Remove the redundant check for pwrite() in pnx4008 watchdog. Given that the open routine already calls nonseekable_open(), remove the redundant check for pwrite(). Signed-off-by: Robert P. J. Day Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/pnx4008_wdt.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c index 5991add..22f8873 100644 --- a/drivers/char/watchdog/pnx4008_wdt.c +++ b/drivers/char/watchdog/pnx4008_wdt.c @@ -148,10 +148,6 @@ static ssize_t pnx4008_wdt_write(struct file *file, const char *data, size_t len, loff_t * ppos) { - /* Can't seek (pwrite) on this device */ - if (ppos != &file->f_pos) - return -ESPIPE; - if (len) { if (!nowayout) { size_t i; -- cgit v1.1 From a9e8bb5b60a9f5c10d38aebc13f8a3d2e1ffc0e7 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 28 May 2007 14:51:29 -0400 Subject: [WATCHDOG] Remove the redundant check for pwrite() in EP93XXX watchdog. Remove the redundant check for pwrite(), given that the open() routine already invokes nonseekable_open(). Signed-off-by: Robert P. J. Day Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/ep93xx_wdt.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/char/watchdog/ep93xx_wdt.c index 01cf123..0e4787a 100644 --- a/drivers/char/watchdog/ep93xx_wdt.c +++ b/drivers/char/watchdog/ep93xx_wdt.c @@ -107,10 +107,6 @@ static ssize_t ep93xx_wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { - /* Can't seek (pwrite) on this device */ - if (*ppos != file->f_pos) - return -ESPIPE; - if (len) { if (!nowayout) { size_t i; -- cgit v1.1 From b10958d338d62a4157005b335799d1466567d59d Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sun, 3 Jun 2007 15:22:32 +0000 Subject: [WATCHDOG] Mixcom Watchdog - update "Documentation" Robert Radez started cleaning up the mixcomwd driver in 2002. All his changes have been incorporated. Since he owns that credit -> document it correctly. Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/mixcomwd.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index f35e284..df5fc76 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -29,11 +29,16 @@ * - support for one more type board * * Version 0.5 (2001/12/14) Matt Domsch - * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * + * Version 0.6 (2002/04/12): Rob Radez + * - make mixcomwd_opened unsigned, + * removed lock_kernel/unlock_kernel from mixcomwd_release, + * modified ioctl a bit to conform to API * */ -#define VERSION "0.5" +#define VERSION "0.6" #include #include -- cgit v1.1 From 63e6e17ead8f918889c63cc361de58a3f71f6115 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sun, 3 Jun 2007 15:39:25 +0000 Subject: [WATCHDOG] Mixcom Watchdog - get rid of port offset's Get rid of the port offset's used for the mixcom and flashcom watchdog devices. Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/mixcomwd.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index df5fc76..b614a5f 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -54,12 +54,19 @@ #include #include -static int mixcomwd_ioports[] = { 0x180, 0x280, 0x380, 0x000 }; - -#define MIXCOM_WATCHDOG_OFFSET 0xc10 +/* + * We have two types of cards that can be probed: + * 1) The Mixcom cards: these cards can be found at addresses + * 0x180, 0x280, 0x380 with an additional offset of 0xc10. + * (Or 0xd90, 0xe90, 0xf90). + * 2) The FlashCOM cards: these cards can be set up at + * 0x300 -> 0x378, in 0x8 jumps with an offset of 0x04. + * (Or 0x304 -> 0x37c in 0x8 jumps). + * Each card has it's own ID. + */ #define MIXCOM_ID 0x11 -#define FLASHCOM_WATCHDOG_OFFSET 0x4 #define FLASHCOM_ID 0x18 +static int mixcomwd_ioports[] = { 0xd90, 0xe90, 0xf90, 0x000 }; static void mixcomwd_timerfun(unsigned long d); @@ -214,7 +221,6 @@ static int __init mixcomwd_checkcard(int port) { int id; - port += MIXCOM_WATCHDOG_OFFSET; if (!request_region(port, 1, "MixCOM watchdog")) { return 0; } @@ -231,7 +237,6 @@ static int __init flashcom_checkcard(int port) { int id; - port += FLASHCOM_WATCHDOG_OFFSET; if (!request_region(port, 1, "MixCOM watchdog")) { return 0; } @@ -257,8 +262,8 @@ static int __init mixcomwd_init(void) } } - /* The FlashCOM card can be set up at 0x300 -> 0x378, in 0x8 jumps */ - for (i = 0x300; !found && i < 0x380; i+=0x8) { + /* The FlashCOM card can be set up at 0x304 -> 0x37c, in 0x8 jumps */ + for (i = 0x304; !found && i < 0x380; i+=0x8) { watchdog_port = flashcom_checkcard(i); if (watchdog_port) { found = 1; -- cgit v1.1 From 4194db10fab1c9595f12b2846b6799417a8db4dd Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sun, 3 Jun 2007 19:01:38 +0000 Subject: [WATCHDOG] Mixcom Watchdog - checkcard Simplify the mixcomwd_checkcard and flashcom_checkcard functions to one checkcard function as part of the port to an isa watchdog device driver. Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/mixcomwd.c | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index b614a5f..17c29cb 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -217,23 +217,7 @@ static struct miscdevice mixcomwd_miscdev= .fops = &mixcomwd_fops, }; -static int __init mixcomwd_checkcard(int port) -{ - int id; - - if (!request_region(port, 1, "MixCOM watchdog")) { - return 0; - } - - id=inb_p(port) & 0x3f; - if(id!=MIXCOM_ID) { - release_region(port, 1); - return 0; - } - return port; -} - -static int __init flashcom_checkcard(int port) +static int __init checkcard(int port, int card_id) { int id; @@ -242,12 +226,15 @@ static int __init flashcom_checkcard(int port) } id=inb_p(port); - if(id!=FLASHCOM_ID) { + if (card_id==MIXCOM_ID) + id &= 0x3f; + + if (id!=card_id) { release_region(port, 1); return 0; } - return port; - } + return 1; +} static int __init mixcomwd_init(void) { @@ -256,17 +243,17 @@ static int __init mixcomwd_init(void) int found=0; for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) { - watchdog_port = mixcomwd_checkcard(mixcomwd_ioports[i]); - if (watchdog_port) { + if (checkcard(mixcomwd_ioports[i], MIXCOM_ID)) { found = 1; + watchdog_port = mixcomwd_ioports[i]; } } /* The FlashCOM card can be set up at 0x304 -> 0x37c, in 0x8 jumps */ for (i = 0x304; !found && i < 0x380; i+=0x8) { - watchdog_port = flashcom_checkcard(i); - if (watchdog_port) { + if (checkcard(i, FLASHCOM_ID)) { found = 1; + watchdog_port = i; } } -- cgit v1.1 From 21baf3c7c7fcef5004671f697789aea84854ca45 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sun, 3 Jun 2007 20:46:05 +0000 Subject: [WATCHDOG] Mixcom Watchdog - checkcard part 2 Convert the mixcom and flashcom card checks to a single checkcard call by creating a new structure that contains all io-ports and their id's. This is part of the port to the isa watchdog device driver. Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/mixcomwd.c | 44 +++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index 17c29cb..0836b9a 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -66,7 +66,34 @@ */ #define MIXCOM_ID 0x11 #define FLASHCOM_ID 0x18 -static int mixcomwd_ioports[] = { 0xd90, 0xe90, 0xf90, 0x000 }; +static struct { + int ioport; + int id; +} mixcomwd_io_info[] __devinitdata = { + /* The Mixcom cards */ + {0x0d90, MIXCOM_ID}, + {0x0e90, MIXCOM_ID}, + {0x0f90, MIXCOM_ID}, + /* The FlashCOM cards */ + {0x0304, FLASHCOM_ID}, + {0x030c, FLASHCOM_ID}, + {0x0314, FLASHCOM_ID}, + {0x031c, FLASHCOM_ID}, + {0x0324, FLASHCOM_ID}, + {0x032c, FLASHCOM_ID}, + {0x0334, FLASHCOM_ID}, + {0x033c, FLASHCOM_ID}, + {0x0344, FLASHCOM_ID}, + {0x034c, FLASHCOM_ID}, + {0x0354, FLASHCOM_ID}, + {0x035c, FLASHCOM_ID}, + {0x0364, FLASHCOM_ID}, + {0x036c, FLASHCOM_ID}, + {0x0374, FLASHCOM_ID}, + {0x037c, FLASHCOM_ID}, + /* The end of the list */ + {0x0000, 0}, +}; static void mixcomwd_timerfun(unsigned long d); @@ -242,18 +269,11 @@ static int __init mixcomwd_init(void) int ret; int found=0; - for (i = 0; !found && mixcomwd_ioports[i] != 0; i++) { - if (checkcard(mixcomwd_ioports[i], MIXCOM_ID)) { - found = 1; - watchdog_port = mixcomwd_ioports[i]; - } - } - - /* The FlashCOM card can be set up at 0x304 -> 0x37c, in 0x8 jumps */ - for (i = 0x304; !found && i < 0x380; i+=0x8) { - if (checkcard(i, FLASHCOM_ID)) { + for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) { + if (checkcard(mixcomwd_io_info[i].ioport, + mixcomwd_io_info[i].id)) { found = 1; - watchdog_port = i; + watchdog_port = mixcomwd_io_info[i].ioport; } } -- cgit v1.1 From 1c067318a2357fffc04e082429f276a8f4075561 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Mon, 4 Jun 2007 18:35:41 +0000 Subject: [WATCHDOG] Mixcom Watchdog - clean-up printk's Clean-up printk's. Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/mixcomwd.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index 0836b9a..e36c59c 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -39,6 +39,8 @@ */ #define VERSION "0.6" +#define WATCHDOG_NAME "mixcomwd" +#define PFX WATCHDOG_NAME ": " #include #include @@ -152,13 +154,13 @@ static int mixcomwd_release(struct inode *inode, struct file *file) { if (expect_close == 42) { if(mixcomwd_timer_alive) { - printk(KERN_ERR "mixcomwd: release called while internal timer alive"); + printk(KERN_ERR PFX "release called while internal timer alive"); return -EBUSY; } mixcomwd_timer_alive=1; mod_timer(&mixcomwd_timer, jiffies + 5 * HZ); } else { - printk(KERN_CRIT "mixcomwd: WDT device closed unexpectedly. WDT will not stop!\n"); + printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n"); } clear_bit(0,&mixcomwd_opened); @@ -278,7 +280,7 @@ static int __init mixcomwd_init(void) } if (!found) { - printk("mixcomwd: No card detected, or port not available.\n"); + printk(KERN_ERR PFX "No card detected, or port not available.\n"); return -ENODEV; } @@ -298,7 +300,7 @@ static void __exit mixcomwd_exit(void) { if (!nowayout) { if(mixcomwd_timer_alive) { - printk(KERN_WARNING "mixcomwd: I quit now, hardware will" + printk(KERN_WARNING PFX "I quit now, hardware will" " probably reboot!\n"); del_timer_sync(&mixcomwd_timer); mixcomwd_timer_alive=0; @@ -313,5 +315,6 @@ module_exit(mixcomwd_exit); MODULE_AUTHOR("Gergely Madarasz "); MODULE_DESCRIPTION("MixCom Watchdog driver"); +MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- cgit v1.1 From 27c7742e7ae089377f984cde608ba02d1c544a97 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Mon, 4 Jun 2007 18:35:41 +0000 Subject: [WATCHDOG] Mixcom Watchdog - clean-up printk's Clean-up printk's. Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/mixcomwd.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index e36c59c..59a3baa 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -287,13 +287,19 @@ static int __init mixcomwd_init(void) ret = misc_register(&mixcomwd_miscdev); if (ret) { - release_region(watchdog_port, 1); - return ret; + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + goto error_misc_register_watchdog; } printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port); return 0; + +error_misc_register_watchdog: + release_region(watchdog_port, 1); + watchdog_port = 0x0000; + return ret; } static void __exit mixcomwd_exit(void) @@ -306,8 +312,8 @@ static void __exit mixcomwd_exit(void) mixcomwd_timer_alive=0; } } - release_region(watchdog_port,1); misc_deregister(&mixcomwd_miscdev); + release_region(watchdog_port,1); } module_init(mixcomwd_init); -- cgit v1.1 From 10a29304f496ddef58473e6c53b5e66d9685536d Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Mon, 4 Jun 2007 19:13:28 +0000 Subject: [WATCHDOG] Mixcom Watchdog - CodingStyle clean-up Small clean-up in line with CodingStyle guide-lines. Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/mixcomwd.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c index 59a3baa..db2ccb8 100644 --- a/drivers/char/watchdog/mixcomwd.c +++ b/drivers/char/watchdog/mixcomwd.c @@ -229,8 +229,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file, return 0; } -static const struct file_operations mixcomwd_fops= -{ +static const struct file_operations mixcomwd_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = mixcomwd_write, @@ -239,8 +238,7 @@ static const struct file_operations mixcomwd_fops= .release = mixcomwd_release, }; -static struct miscdevice mixcomwd_miscdev= -{ +static struct miscdevice mixcomwd_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &mixcomwd_fops, @@ -292,7 +290,8 @@ static int __init mixcomwd_init(void) goto error_misc_register_watchdog; } - printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",VERSION,watchdog_port); + printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n", + VERSION, watchdog_port); return 0; -- cgit v1.1 From a9cb3959ace112295fdb65c99a2928eedba06926 Mon Sep 17 00:00:00 2001 From: Hans-Christian Egtvedt Date: Thu, 7 Jun 2007 16:06:41 -0700 Subject: [WATCHDOG] Watchdog driver for AT32AP700X devices Add support for the built in watchdog in AT32AP700X devices. Tested on AT32AP7000 and ATSTK1000. Hardware documentation can be found in the AT32AP7000 datasheet. Signed-off-by: Hans-Christian Egtvedt Signed-off-by: Haavard Skinnemoen Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/Kconfig | 20 +++ drivers/char/watchdog/Makefile | 3 + drivers/char/watchdog/at32ap700x_wdt.c | 313 +++++++++++++++++++++++++++++++++ 3 files changed, 336 insertions(+) create mode 100644 drivers/char/watchdog/at32ap700x_wdt.c (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 53f5538..520afb8 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -187,6 +187,26 @@ config PNX4008_WATCHDOG Say N if you are unsure. +# AVR32 Architecture + +config AT32AP700X_WDT + tristate "AT32AP700x watchdog" + depends on WATCHDOG && CPU_AT32AP7000 + help + Watchdog timer embedded into AT32AP700x devices. This will reboot + your system when the timeout is reached. + +config AT32AP700X_WDT_TIMEOUT + int "Timeout value for AT32AP700x watchdog" + depends on AT32AP700X_WDT + default "2" + range 1 2 + help + Sets the timeout value for the watchdog in AT32AP700x devices. + Limited by hardware to be 1 or 2 seconds. + + Set to 2 seconds by default. + # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index d90f649..3907ec0 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -36,6 +36,9 @@ obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o +# AVR32 Architecture +obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o + # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c new file mode 100644 index 0000000..036d83b --- /dev/null +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -0,0 +1,313 @@ +/* + * Watchdog driver for Atmel AT32AP700X devices + * + * Copyright (C) 2005-2006 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TIMEOUT_MIN 1 +#define TIMEOUT_DEFAULT CONFIG_AT32AP700X_WDT_TIMEOUT +#define TIMEOUT_MAX 2 + +/* Watchdog registers and write/read macro */ +#define WDT_CTRL 0x00 +#define WDT_CTRL_EN 0 +#define WDT_CTRL_PSEL 8 +#define WDT_CTRL_KEY 24 + +#define WDT_CLR 0x04 + +#define WDT_BIT(name) (1 << WDT_##name) +#define WDT_BF(name,value) ((value) << WDT_##name) + +#define wdt_readl(dev,reg) \ + __raw_readl((dev)->regs + WDT_##reg) +#define wdt_writel(dev,reg,value) \ + __raw_writel((value), (dev)->regs + WDT_##reg) + +struct wdt_at32ap700x { + void __iomem *regs; + int timeout; + int users; + struct miscdevice miscdev; +}; + +static struct wdt_at32ap700x *wdt; + +/* + * Disable the watchdog. + */ +static void inline at32_wdt_stop(void) +{ + unsigned long psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f); + wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0x55)); + wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0xaa)); +} + +/* + * Enable and reset the watchdog. + */ +static void inline at32_wdt_start(void) +{ + /* 0xf is 2^16 divider = 2 sec, 0xe is 2^15 divider = 1 sec */ + unsigned long psel = (wdt->timeout > 1) ? 0xf : 0xe; + + wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN) + | WDT_BF(CTRL_PSEL, psel) + | WDT_BF(CTRL_KEY, 0x55)); + wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN) + | WDT_BF(CTRL_PSEL, psel) + | WDT_BF(CTRL_KEY, 0xaa)); +} + +/* + * Pat the watchdog timer. + */ +static void inline at32_wdt_pat(void) +{ + wdt_writel(wdt, CLR, 0x42); +} + +/* + * Watchdog device is opened, and watchdog starts running. + */ +static int at32_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(1, &wdt->users)) + return -EBUSY; + + at32_wdt_start(); + return nonseekable_open(inode, file); +} + +/* + * Close the watchdog device. If CONFIG_WATCHDOG_NOWAYOUT is _not_ defined then + * the watchdog is also disabled. + */ +static int at32_wdt_close(struct inode *inode, struct file *file) +{ +#ifndef CONFIG_WATCHDOG_NOWAYOUT + at32_wdt_stop(); +#endif + clear_bit(1, &wdt->users); + return 0; +} + +/* + * Change the watchdog time interval. + */ +static int at32_wdt_settimeout(int time) +{ + /* + * All counting occurs at 1 / SLOW_CLOCK (32 kHz) and max prescaler is + * 2 ^ 16 allowing up to 2 seconds timeout. + */ + if ((time < TIMEOUT_MIN) || (time > TIMEOUT_MAX)) + return -EINVAL; + + /* Set new watchdog time. It will be used when at32_wdt_start() is called. */ + wdt->timeout = time; + return 0; +} + +static struct watchdog_info at32_wdt_info = { + .identity = "at32ap700x watchdog", + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, +}; + +/* + * Handle commands from user-space. + */ +static int at32_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret = -ENOTTY; + int time; + void __user *argp = (void __user *)arg; + int __user *p = argp; + + switch(cmd) { + case WDIOC_KEEPALIVE: + at32_wdt_pat(); + ret = 0; + break; + case WDIOC_GETSUPPORT: + ret = copy_to_user(argp, &at32_wdt_info, + sizeof(at32_wdt_info)) ? -EFAULT : 0; + break; + case WDIOC_SETTIMEOUT: + ret = get_user(time, p); + if (ret) + break; + ret = at32_wdt_settimeout(time); + if (ret) + break; + /* Enable new time value */ + at32_wdt_start(); + /* fall through */ + case WDIOC_GETTIMEOUT: + ret = put_user(wdt->timeout, p); + break; + case WDIOC_GETSTATUS: /* fall through */ + case WDIOC_GETBOOTSTATUS: + ret = put_user(0, p); + break; + case WDIOC_SETOPTIONS: + ret = get_user(time, p); + if (ret) + break; + if (time & WDIOS_DISABLECARD) + at32_wdt_stop(); + if (time & WDIOS_ENABLECARD) + at32_wdt_start(); + ret = 0; + break; + } + + return ret; +} + +static ssize_t at32_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + at32_wdt_pat(); + return len; +} + +static const struct file_operations at32_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = at32_wdt_ioctl, + .open = at32_wdt_open, + .release = at32_wdt_close, + .write = at32_wdt_write, +}; + +static int __init at32_wdt_probe(struct platform_device *pdev) +{ + struct resource *regs; + int ret; + + if (wdt) { + dev_dbg(&pdev->dev, "only 1 wdt instance supported.\n"); + return -EBUSY; + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!regs) { + dev_dbg(&pdev->dev, "missing mmio resource\n"); + return -ENXIO; + } + + wdt = kzalloc(sizeof(struct wdt_at32ap700x), GFP_KERNEL); + if (!wdt) { + dev_dbg(&pdev->dev, "no memory for wdt structure\n"); + return -ENOMEM; + } + + wdt->regs = ioremap(regs->start, regs->end - regs->start + 1); + wdt->users = 0; + wdt->miscdev.minor = WATCHDOG_MINOR; + wdt->miscdev.name = "watchdog"; + wdt->miscdev.fops = &at32_wdt_fops; + + if (at32_wdt_settimeout(TIMEOUT_DEFAULT)) { + at32_wdt_settimeout(TIMEOUT_MAX); + dev_dbg(&pdev->dev, + "default timeout invalid, set to %d sec.\n", + TIMEOUT_MAX); + } + + ret = misc_register(&wdt->miscdev); + if (ret) { + dev_dbg(&pdev->dev, "failed to register wdt miscdev\n"); + goto err_register; + } + + platform_set_drvdata(pdev, wdt); + wdt->miscdev.parent = &pdev->dev; + dev_info(&pdev->dev, "AT32AP700X WDT at 0x%p\n", wdt->regs); + + return 0; + +err_register: + kfree(wdt); + wdt = NULL; + return ret; +} + +static int __exit at32_wdt_remove(struct platform_device *pdev) +{ + if (wdt && platform_get_drvdata(pdev) == wdt) { + misc_deregister(&wdt->miscdev); + kfree(wdt); + wdt = NULL; + platform_set_drvdata(pdev, NULL); + } + + return 0; +} + +static void at32_wdt_shutdown(struct platform_device *pdev) +{ + at32_wdt_stop(); +} + +#ifdef CONFIG_PM +static int at32_wdt_suspend(struct platform_device *pdev, pm_message_t message) +{ + at32_wdt_stop(); + return 0; +} + +static int at32_wdt_resume(struct platform_device *pdev) +{ + if (wdt->users) + at32_wdt_start(); + return 0; +} +#endif + +static struct platform_driver at32_wdt_driver = { + .remove = __exit_p(at32_wdt_remove), +#ifdef CONFIG_PM + .suspend = at32_wdt_suspend, + .resume = at32_wdt_resume, +#endif + .driver = { + .name = "at32_wdt", + .owner = THIS_MODULE, + }, + .shutdown = at32_wdt_shutdown, +}; + +static int __init at32_wdt_init(void) +{ + return platform_driver_probe(&at32_wdt_driver, at32_wdt_probe); +} +module_init(at32_wdt_init); + +static void __exit at32_wdt_exit(void) +{ + platform_driver_unregister(&at32_wdt_driver); +} +module_exit(at32_wdt_exit); + +MODULE_AUTHOR("Hans-Christian Egtvedt "); +MODULE_DESCRIPTION("Watchdog driver for Atmel AT32AP700X"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); -- cgit v1.1 From c37f271320d595f46beb5a0ab7833107f461f6b6 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 7 Jun 2007 16:06:43 -0700 Subject: [WATCHDOG] watchdog-driver-for-at32ap700x-devices-fix little fiddles. Cc: Haavard Skinnemoen Cc: Hans-Christian Egtvedt Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/at32ap700x_wdt.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index 036d83b..588b26d 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -16,9 +16,8 @@ #include #include #include - -#include -#include +#include +#include #define TIMEOUT_MIN 1 #define TIMEOUT_DEFAULT CONFIG_AT32AP700X_WDT_TIMEOUT @@ -120,7 +119,10 @@ static int at32_wdt_settimeout(int time) if ((time < TIMEOUT_MIN) || (time > TIMEOUT_MAX)) return -EINVAL; - /* Set new watchdog time. It will be used when at32_wdt_start() is called. */ + /* + * Set new watchdog time. It will be used when at32_wdt_start() is + * called. + */ wdt->timeout = time; return 0; } @@ -141,7 +143,7 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, void __user *argp = (void __user *)arg; int __user *p = argp; - switch(cmd) { + switch (cmd) { case WDIOC_KEEPALIVE: at32_wdt_pat(); ret = 0; @@ -182,7 +184,8 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, return ret; } -static ssize_t at32_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +static ssize_t at32_wdt_write(struct file *file, const char *data, size_t len, + loff_t *ppos) { at32_wdt_pat(); return len; -- cgit v1.1 From 97a2a2ea1ad856d5375fecf689e253adca387602 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 7 Jun 2007 16:08:53 -0700 Subject: [WATCHDOG] watchdog-driver-for-at32ap700x-devices-fix-2 standard ifdef-reduction trick. Cc: Haavard Skinnemoen Cc: Hans-Christian Egtvedt Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/at32ap700x_wdt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index 588b26d..f08ea94 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -283,14 +283,15 @@ static int at32_wdt_resume(struct platform_device *pdev) at32_wdt_start(); return 0; } +#else +#define at32_wdt_suspend NULL +#define at32_wdt_resume NULL #endif static struct platform_driver at32_wdt_driver = { .remove = __exit_p(at32_wdt_remove), -#ifdef CONFIG_PM .suspend = at32_wdt_suspend, .resume = at32_wdt_resume, -#endif .driver = { .name = "at32_wdt", .owner = THIS_MODULE, -- cgit v1.1 From ff73231611127463ee94e72035f6a97f8435b39b Mon Sep 17 00:00:00 2001 From: Hans-Christian Egtvedt Date: Fri, 8 Jun 2007 11:01:47 -0700 Subject: [WATCHDOG] at32ap700x-wdt: add missing iounmap in _remove Signed-off-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/at32ap700x_wdt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index f08ea94..a3e2887 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -257,6 +257,7 @@ static int __exit at32_wdt_remove(struct platform_device *pdev) { if (wdt && platform_get_drvdata(pdev) == wdt) { misc_deregister(&wdt->miscdev); + iounmap(wdt->regs); kfree(wdt); wdt = NULL; platform_set_drvdata(pdev, NULL); -- cgit v1.1 From 47d17763e987ebd5e9266fe3d9af3b22a64d27d8 Mon Sep 17 00:00:00 2001 From: Hans-Christian Egtvedt Date: Fri, 8 Jun 2007 11:03:01 -0700 Subject: [WATCHDOG] at32ap700x-wdt: add iounmap if probe function fails Signed-off-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Signed-off-by: Wim Van Sebroeck Signed-off-by: Andrew Morton --- drivers/char/watchdog/at32ap700x_wdt.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index a3e2887..745d38f 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -223,6 +223,11 @@ static int __init at32_wdt_probe(struct platform_device *pdev) } wdt->regs = ioremap(regs->start, regs->end - regs->start + 1); + if (!wdt->regs) { + ret = -ENOMEM; + dev_dbg(&pdev->dev, "could not map I/O memory\n"); + goto err_free; + } wdt->users = 0; wdt->miscdev.minor = WATCHDOG_MINOR; wdt->miscdev.name = "watchdog"; @@ -238,7 +243,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev) ret = misc_register(&wdt->miscdev); if (ret) { dev_dbg(&pdev->dev, "failed to register wdt miscdev\n"); - goto err_register; + goto err_iounmap; } platform_set_drvdata(pdev, wdt); @@ -247,7 +252,9 @@ static int __init at32_wdt_probe(struct platform_device *pdev) return 0; -err_register: +err_iounmap: + iounmap(wdt->regs); +err_free: kfree(wdt); wdt = NULL; return ret; -- cgit v1.1 From 46b814d6e00c1a1e3127f8f9c254dda310781bec Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 14 Jun 2007 12:08:54 +0100 Subject: [WATCHDOG] s3c2410_wdt announce initialisation Announce the watchdog once the initialisation is complete. This aides debugging problems where the watchdog driver has been loaded and shows the current state for the user. Signed-off-by: Ben Dooks Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/s3c2410_wdt.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 20fa29c..7cc0263 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -348,6 +348,7 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) static int s3c2410wdt_probe(struct platform_device *pdev) { struct resource *res; + unsigned int wtcon; int started = 0; int ret; int size; @@ -433,6 +434,16 @@ static int s3c2410wdt_probe(struct platform_device *pdev) s3c2410wdt_stop(); } + /* print out a statement of readiness */ + + wtcon = readl(wdt_base + S3C2410_WTCON); + + dev_info(&pdev->dev, + "watchdog %sactive, reset %sabled, irq %sabled\n", + (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in", + (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis", + (wtcon & S3C2410_WTCON_INTEN) ? "" : "en"); + return 0; err_clk: -- cgit v1.1 From e8ef92b8dc939cebf0c1fe153e898e5162c2ad05 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 14 Jun 2007 12:08:55 +0100 Subject: [WATCHDOG] change s3c2410_wdt to using dev_() macros for output Move to using dev_info(), dev_dbg() and dev_err() for reporting information from the driver. Signed-off-by: Ben Dooks Signed-off-by: Wim Van Sebroeck --- drivers/char/watchdog/s3c2410_wdt.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 7cc0263..50430bc 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -92,6 +92,7 @@ typedef enum close_state { static DECLARE_MUTEX(open_lock); +static struct device *wdt_dev; /* platform device attached to */ static struct resource *wdt_mem; static struct resource *wdt_irq; static struct clk *wdt_clock; @@ -180,7 +181,7 @@ static int s3c2410wdt_set_heartbeat(int timeout) } if ((count / divisor) >= 0x10000) { - printk(KERN_ERR PFX "timeout %d too big\n", timeout); + dev_err(wdt_dev, "timeout %d too big\n", timeout); return -EINVAL; } } @@ -233,7 +234,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file) if (allow_close == CLOSE_STATE_ALLOW) { s3c2410wdt_stop(); } else { - printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n"); s3c2410wdt_keepalive(); } @@ -338,7 +339,7 @@ static struct miscdevice s3c2410wdt_miscdev = { static irqreturn_t s3c2410wdt_irq(int irqno, void *param) { - printk(KERN_INFO PFX "Watchdog timer expired!\n"); + dev_info(wdt_dev, "watchdog timer expired (irq)\n"); s3c2410wdt_keepalive(); return IRQ_HANDLED; @@ -348,6 +349,7 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) static int s3c2410wdt_probe(struct platform_device *pdev) { struct resource *res; + struct device *dev; unsigned int wtcon; int started = 0; int ret; @@ -355,25 +357,28 @@ static int s3c2410wdt_probe(struct platform_device *pdev) DBG("%s: probe=%p\n", __FUNCTION__, pdev); + dev = &pdev->dev; + wdt_dev = &pdev->dev; + /* get the memory region for the watchdog timer */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { - printk(KERN_INFO PFX "failed to get memory region resouce\n"); + dev_err(dev, "no memory resource specified\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 PFX "failed to get memory region\n"); + dev_err(dev, "failed to get memory region\n"); ret = -ENOENT; goto err_req; } wdt_base = ioremap(res->start, size); if (wdt_base == 0) { - printk(KERN_INFO PFX "failed to ioremap() region\n"); + dev_err(dev, "failed to ioremap() region\n"); ret = -EINVAL; goto err_req; } @@ -382,20 +387,20 @@ static int s3c2410wdt_probe(struct platform_device *pdev) wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (wdt_irq == NULL) { - printk(KERN_INFO PFX "failed to get irq resource\n"); + dev_err(dev, "no irq resource specified\n"); ret = -ENOENT; goto err_map; } ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev); if (ret != 0) { - printk(KERN_INFO PFX "failed to install irq (%d)\n", ret); + dev_err(dev, "failed to install irq (%d)\n", ret); goto err_map; } wdt_clock = clk_get(&pdev->dev, "watchdog"); if (IS_ERR(wdt_clock)) { - printk(KERN_INFO PFX "failed to find watchdog clock source\n"); + dev_err(dev, "failed to find watchdog clock source\n"); ret = PTR_ERR(wdt_clock); goto err_irq; } @@ -409,22 +414,22 @@ static int s3c2410wdt_probe(struct platform_device *pdev) started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); if (started == 0) { - printk(KERN_INFO PFX "tmr_margin value out of range, default %d used\n", + dev_info(dev,"tmr_margin value out of range, default %d used\n", CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); } else { - printk(KERN_INFO PFX "default timer value is out of range, cannot start\n"); + dev_info(dev, "default timer value is out of range, cannot start\n"); } } ret = misc_register(&s3c2410wdt_miscdev); if (ret) { - printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n", + dev_err(dev, "cannot register miscdev on minor=%d (%d)\n", WATCHDOG_MINOR, ret); goto err_clk; } if (tmr_atboot && started == 0) { - printk(KERN_INFO PFX "Starting Watchdog Timer\n"); + dev_info(dev, "starting watchdog timer\n"); s3c2410wdt_start(); } else if (!tmr_atboot) { /* if we're not enabling the watchdog, then ensure it is @@ -438,12 +443,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev) wtcon = readl(wdt_base + S3C2410_WTCON); - dev_info(&pdev->dev, - "watchdog %sactive, reset %sabled, irq %sabled\n", + dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n", (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in", (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis", (wtcon & S3C2410_WTCON_INTEN) ? "" : "en"); - + return 0; err_clk: -- cgit v1.1 From c0ead7e0ff996f0cfa91a73fa674fdca5c05798a Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Sun, 17 Jun 2007 19:34:23 +0000 Subject: [WATCHDOG] at32ap700x_wdt.c - checkpatch.pl-0.05 clean-up's need space after that ',' (ctx:VxV) inline keyword should sit between storage class and type Signed-off-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Signed-off-by: Wim Van Sebroeck Cc: Andrew Morton --- drivers/char/watchdog/at32ap700x_wdt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index 745d38f..8abe1c7 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -32,11 +32,11 @@ #define WDT_CLR 0x04 #define WDT_BIT(name) (1 << WDT_##name) -#define WDT_BF(name,value) ((value) << WDT_##name) +#define WDT_BF(name, value) ((value) << WDT_##name) -#define wdt_readl(dev,reg) \ +#define wdt_readl(dev, reg) \ __raw_readl((dev)->regs + WDT_##reg) -#define wdt_writel(dev,reg,value) \ +#define wdt_writel(dev, reg, value) \ __raw_writel((value), (dev)->regs + WDT_##reg) struct wdt_at32ap700x { @@ -51,7 +51,7 @@ static struct wdt_at32ap700x *wdt; /* * Disable the watchdog. */ -static void inline at32_wdt_stop(void) +static inline void at32_wdt_stop(void) { unsigned long psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f); wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0x55)); @@ -61,7 +61,7 @@ static void inline at32_wdt_stop(void) /* * Enable and reset the watchdog. */ -static void inline at32_wdt_start(void) +static inline void at32_wdt_start(void) { /* 0xf is 2^16 divider = 2 sec, 0xe is 2^15 divider = 1 sec */ unsigned long psel = (wdt->timeout > 1) ? 0xf : 0xe; @@ -77,7 +77,7 @@ static void inline at32_wdt_start(void) /* * Pat the watchdog timer. */ -static void inline at32_wdt_pat(void) +static inline void at32_wdt_pat(void) { wdt_writel(wdt, CLR, 0x42); } -- cgit v1.1 From 726c9f611a4079b5265e7ede1d66ed455ac6343c Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Mon, 18 Jun 2007 22:49:35 +0200 Subject: [WATCHDOG] at32ap700x_wdt.c - timeout module parameter patch integrate the timeout/heartbeat as a module parameter and not as a CONFIG_* value. Signed-off-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Signed-off-by: Wim Van Sebroeck Cc: Andrew Morton --- drivers/char/watchdog/Kconfig | 11 ----------- drivers/char/watchdog/at32ap700x_wdt.c | 18 +++++++++++++----- 2 files changed, 13 insertions(+), 16 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 520afb8..2f48ba3 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -196,17 +196,6 @@ config AT32AP700X_WDT Watchdog timer embedded into AT32AP700x devices. This will reboot your system when the timeout is reached. -config AT32AP700X_WDT_TIMEOUT - int "Timeout value for AT32AP700x watchdog" - depends on AT32AP700X_WDT - default "2" - range 1 2 - help - Sets the timeout value for the watchdog in AT32AP700x devices. - Limited by hardware to be 1 or 2 seconds. - - Set to 2 seconds by default. - # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index 8abe1c7..6e7c958 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -20,8 +20,15 @@ #include #define TIMEOUT_MIN 1 -#define TIMEOUT_DEFAULT CONFIG_AT32AP700X_WDT_TIMEOUT #define TIMEOUT_MAX 2 +#define TIMEOUT_DEFAULT TIMEOUT_MAX + +/* module parameters */ +static int timeout = TIMEOUT_DEFAULT; +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout, + "Timeout value. Limited to be 1 or 2 seconds. (default=" + __MODULE_STRING(TIMEOUT_DEFAULT) ")"); /* Watchdog registers and write/read macro */ #define WDT_CTRL 0x00 @@ -233,11 +240,11 @@ static int __init at32_wdt_probe(struct platform_device *pdev) wdt->miscdev.name = "watchdog"; wdt->miscdev.fops = &at32_wdt_fops; - if (at32_wdt_settimeout(TIMEOUT_DEFAULT)) { - at32_wdt_settimeout(TIMEOUT_MAX); + if (at32_wdt_settimeout(timeout)) { + at32_wdt_settimeout(TIMEOUT_DEFAULT); dev_dbg(&pdev->dev, "default timeout invalid, set to %d sec.\n", - TIMEOUT_MAX); + TIMEOUT_DEFAULT); } ret = misc_register(&wdt->miscdev); @@ -248,7 +255,8 @@ static int __init at32_wdt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wdt); wdt->miscdev.parent = &pdev->dev; - dev_info(&pdev->dev, "AT32AP700X WDT at 0x%p\n", wdt->regs); + dev_info(&pdev->dev, "AT32AP700X WDT at 0x%p, timeout %d sec\n", + wdt->regs, wdt->timeout); return 0; -- cgit v1.1 From 28401140a27b7ebc5a686dbfc345e3724d274738 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Wed, 20 Jun 2007 23:36:43 +0200 Subject: [WATCHDOG] at32ap700x_wdt.c - Add nowayout + MAGICCLOSE features Add nowayout + MAGICCLOSE features. Signed-off-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Signed-off-by: Wim Van Sebroeck Cc: Andrew Morton --- drivers/char/watchdog/at32ap700x_wdt.c | 64 ++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 11 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index 6e7c958..fcd55c6 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -30,6 +30,11 @@ MODULE_PARM_DESC(timeout, "Timeout value. Limited to be 1 or 2 seconds. (default=" __MODULE_STRING(TIMEOUT_DEFAULT) ")"); +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) ")"); + /* Watchdog registers and write/read macro */ #define WDT_CTRL 0x00 #define WDT_CTRL_EN 0 @@ -54,6 +59,7 @@ struct wdt_at32ap700x { }; static struct wdt_at32ap700x *wdt; +static char expect_release; /* * Disable the watchdog. @@ -102,15 +108,19 @@ static int at32_wdt_open(struct inode *inode, struct file *file) } /* - * Close the watchdog device. If CONFIG_WATCHDOG_NOWAYOUT is _not_ defined then - * the watchdog is also disabled. + * Close the watchdog device. */ static int at32_wdt_close(struct inode *inode, struct file *file) { -#ifndef CONFIG_WATCHDOG_NOWAYOUT - at32_wdt_stop(); -#endif + if (expect_release == 42) { + at32_wdt_stop(); + } else { + dev_dbg(wdt->miscdev.parent, + "Unexpected close, not stopping watchdog!\n"); + at32_wdt_pat(); + } clear_bit(1, &wdt->users); + expect_release = 0; return 0; } @@ -136,7 +146,9 @@ static int at32_wdt_settimeout(int time) static struct watchdog_info at32_wdt_info = { .identity = "at32ap700x watchdog", - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, }; /* @@ -191,10 +203,35 @@ static int at32_wdt_ioctl(struct inode *inode, struct file *file, return ret; } -static ssize_t at32_wdt_write(struct file *file, const char *data, size_t len, - loff_t *ppos) +static ssize_t at32_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) { - at32_wdt_pat(); + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + if (!nowayout) { + size_t i; + + /* + * note: just in case someone wrote the magic + * character five months ago... + */ + expect_release = 0; + + /* + * scan to see whether or not we got the magic + * character + */ + for (i = 0; i != len; i++) { + char c; + if (get_user(c, data+i)) + return -EFAULT; + if (c == 'V') + expect_release = 42; + } + } + /* someone wrote to us, we should pat the watchdog */ + at32_wdt_pat(); + } return len; } @@ -255,8 +292,9 @@ static int __init at32_wdt_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wdt); wdt->miscdev.parent = &pdev->dev; - dev_info(&pdev->dev, "AT32AP700X WDT at 0x%p, timeout %d sec\n", - wdt->regs, wdt->timeout); + dev_info(&pdev->dev, + "AT32AP700X WDT at 0x%p, timeout %d sec (nowayout=%d)\n", + wdt->regs, wdt->timeout, nowayout); return 0; @@ -271,6 +309,10 @@ err_free: static int __exit at32_wdt_remove(struct platform_device *pdev) { if (wdt && platform_get_drvdata(pdev) == wdt) { + /* Stop the timer before we leave */ + if (!nowayout) + at32_wdt_stop(); + misc_deregister(&wdt->miscdev); iounmap(wdt->regs); kfree(wdt); -- cgit v1.1 From e75e657756554676f13070266bedbd75d404a0f8 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Tue, 3 Jul 2007 17:59:04 +0000 Subject: [WATCHDOG] at32ap700x_wdt.c - Add spinlock support Add spinlock support so that forked children can't do different io stuff at the same time. Signed-off-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Signed-off-by: Wim Van Sebroeck Cc: Andrew Morton --- drivers/char/watchdog/at32ap700x_wdt.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index fcd55c6..75e852e 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -18,6 +18,7 @@ #include #include #include +#include #define TIMEOUT_MIN 1 #define TIMEOUT_MAX 2 @@ -53,6 +54,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" struct wdt_at32ap700x { void __iomem *regs; + spinlock_t io_lock; int timeout; int users; struct miscdevice miscdev; @@ -66,9 +68,11 @@ static char expect_release; */ static inline void at32_wdt_stop(void) { + spin_lock(&wdt->io_lock); unsigned long psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f); wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0x55)); wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0xaa)); + spin_unlock(&wdt->io_lock); } /* @@ -79,12 +83,14 @@ static inline void at32_wdt_start(void) /* 0xf is 2^16 divider = 2 sec, 0xe is 2^15 divider = 1 sec */ unsigned long psel = (wdt->timeout > 1) ? 0xf : 0xe; + spin_lock(&wdt->io_lock); wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN) | WDT_BF(CTRL_PSEL, psel) | WDT_BF(CTRL_KEY, 0x55)); wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN) | WDT_BF(CTRL_PSEL, psel) | WDT_BF(CTRL_KEY, 0xaa)); + spin_unlock(&wdt->io_lock); } /* @@ -92,7 +98,9 @@ static inline void at32_wdt_start(void) */ static inline void at32_wdt_pat(void) { + spin_lock(&wdt->io_lock); wdt_writel(wdt, CLR, 0x42); + spin_unlock(&wdt->io_lock); } /* @@ -272,6 +280,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "could not map I/O memory\n"); goto err_free; } + spin_lock_init(&wdt->io_lock); wdt->users = 0; wdt->miscdev.minor = WATCHDOG_MINOR; wdt->miscdev.name = "watchdog"; -- cgit v1.1 From 7e2a1498a90aff0e57271bf838a29aaa4e1c6bf9 Mon Sep 17 00:00:00 2001 From: Wim Van Sebroeck Date: Tue, 3 Jul 2007 17:59:29 +0000 Subject: [WATCHDOG] at32ap700x_wdt.c - Fix compilation warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix warning: * ISO C90 forbids mixed declarations and code * passing argument 2 of ‘test_and_set_bit’ from incompatible pointer type * passing argument 2 of ‘clear_bit’ from incompatible pointer type Signed-off-by: Hans-Christian Egtvedt Cc: Haavard Skinnemoen Signed-off-by: Wim Van Sebroeck Cc: Andrew Morton --- drivers/char/watchdog/at32ap700x_wdt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/char/watchdog') diff --git a/drivers/char/watchdog/at32ap700x_wdt.c b/drivers/char/watchdog/at32ap700x_wdt.c index 75e852e..54a5161 100644 --- a/drivers/char/watchdog/at32ap700x_wdt.c +++ b/drivers/char/watchdog/at32ap700x_wdt.c @@ -56,7 +56,7 @@ struct wdt_at32ap700x { void __iomem *regs; spinlock_t io_lock; int timeout; - int users; + unsigned long users; struct miscdevice miscdev; }; @@ -68,8 +68,10 @@ static char expect_release; */ static inline void at32_wdt_stop(void) { + unsigned long psel; + spin_lock(&wdt->io_lock); - unsigned long psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f); + psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f); wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0x55)); wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0xaa)); spin_unlock(&wdt->io_lock); -- cgit v1.1