Commit 3539fc54 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull watchdog changes from Wim Van Sebroeck:
 - conversion of iTCO_wdt and orion_wdt to the generic watchdog API
 - uses module_platform_driver() for s3c2410_wdt
 - Adds support for Jetway JNF99 Motherboard
 - various fixes

* git://www.linux-watchdog.org/linux-watchdog:
  watchdog: orion_wdt: Convert driver to watchdog core
  watchdog: s3c2410_wdt: Use module_platform_driver()
  watchdog: sch311x_wdt: Fix Polarity when starting watchdog
  Watchdog: OMAP: Fix the runtime pm code to avoid module getting stuck intransition state.
  watchdog: ie6xx_wdt: section mismatch in ie6xx_wdt_probe()
  watchdog: bcm63xx_wdt: fix driver section mismatch
  watchdog: iTCO_wdt.c: convert to watchdog core
  char/ipmi: remove local ioctl defines replaced by generic ones
  watchdog: xilinx: Read clock frequency directly from DT node
  watchdog: coh901327_wdt: use clk_prepare/unprepare
  watchdog: f71808e_wdt: Add support for Jetway JNF99 motherboard
parents 2b849570 0dd6e484
...@@ -141,17 +141,6 @@ ...@@ -141,17 +141,6 @@
#define IPMI_WDOG_TIMER_NOT_INIT_RESP 0x80 #define IPMI_WDOG_TIMER_NOT_INIT_RESP 0x80
/* These are here until the real ones get into the watchdog.h interface. */
#ifndef WDIOC_GETTIMEOUT
#define WDIOC_GETTIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 20, int)
#endif
#ifndef WDIOC_SET_PRETIMEOUT
#define WDIOC_SET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 21, int)
#endif
#ifndef WDIOC_GET_PRETIMEOUT
#define WDIOC_GET_PRETIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 22, int)
#endif
static DEFINE_MUTEX(ipmi_watchdog_mutex); static DEFINE_MUTEX(ipmi_watchdog_mutex);
static bool nowayout = WATCHDOG_NOWAYOUT; static bool nowayout = WATCHDOG_NOWAYOUT;
...@@ -732,7 +721,6 @@ static int ipmi_ioctl(struct file *file, ...@@ -732,7 +721,6 @@ static int ipmi_ioctl(struct file *file,
return -EFAULT; return -EFAULT;
return 0; return 0;
case WDIOC_SET_PRETIMEOUT:
case WDIOC_SETPRETIMEOUT: case WDIOC_SETPRETIMEOUT:
i = copy_from_user(&val, argp, sizeof(int)); i = copy_from_user(&val, argp, sizeof(int));
if (i) if (i)
...@@ -740,7 +728,6 @@ static int ipmi_ioctl(struct file *file, ...@@ -740,7 +728,6 @@ static int ipmi_ioctl(struct file *file,
pretimeout = val; pretimeout = val;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
case WDIOC_GET_PRETIMEOUT:
case WDIOC_GETPRETIMEOUT: case WDIOC_GETPRETIMEOUT:
i = copy_to_user(argp, &pretimeout, sizeof(pretimeout)); i = copy_to_user(argp, &pretimeout, sizeof(pretimeout));
if (i) if (i)
......
...@@ -279,6 +279,7 @@ config DAVINCI_WATCHDOG ...@@ -279,6 +279,7 @@ config DAVINCI_WATCHDOG
config ORION_WATCHDOG config ORION_WATCHDOG
tristate "Orion watchdog" tristate "Orion watchdog"
depends on ARCH_ORION5X || ARCH_KIRKWOOD depends on ARCH_ORION5X || ARCH_KIRKWOOD
select WATCHDOG_CORE
help help
Say Y here if to include support for the watchdog timer Say Y here if to include support for the watchdog timer
in the Marvell Orion5x and Kirkwood ARM SoCs. in the Marvell Orion5x and Kirkwood ARM SoCs.
...@@ -578,6 +579,7 @@ config INTEL_SCU_WATCHDOG ...@@ -578,6 +579,7 @@ config INTEL_SCU_WATCHDOG
config ITCO_WDT config ITCO_WDT
tristate "Intel TCO Timer/Watchdog" tristate "Intel TCO Timer/Watchdog"
depends on (X86 || IA64) && PCI depends on (X86 || IA64) && PCI
select WATCHDOG_CORE
select LPC_ICH select LPC_ICH
---help--- ---help---
Hardware driver for the intel TCO timer based watchdog devices. Hardware driver for the intel TCO timer based watchdog devices.
......
...@@ -302,7 +302,7 @@ static void bcm63xx_wdt_shutdown(struct platform_device *pdev) ...@@ -302,7 +302,7 @@ static void bcm63xx_wdt_shutdown(struct platform_device *pdev)
bcm63xx_wdt_pause(); bcm63xx_wdt_pause();
} }
static struct platform_driver bcm63xx_wdt = { static struct platform_driver bcm63xx_wdt_driver = {
.probe = bcm63xx_wdt_probe, .probe = bcm63xx_wdt_probe,
.remove = __devexit_p(bcm63xx_wdt_remove), .remove = __devexit_p(bcm63xx_wdt_remove),
.shutdown = bcm63xx_wdt_shutdown, .shutdown = bcm63xx_wdt_shutdown,
...@@ -312,7 +312,7 @@ static struct platform_driver bcm63xx_wdt = { ...@@ -312,7 +312,7 @@ static struct platform_driver bcm63xx_wdt = {
} }
}; };
module_platform_driver(bcm63xx_wdt); module_platform_driver(bcm63xx_wdt_driver);
MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>"); MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>");
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
......
...@@ -263,6 +263,7 @@ static int __exit coh901327_remove(struct platform_device *pdev) ...@@ -263,6 +263,7 @@ static int __exit coh901327_remove(struct platform_device *pdev)
watchdog_unregister_device(&coh901327_wdt); watchdog_unregister_device(&coh901327_wdt);
coh901327_disable(); coh901327_disable();
free_irq(irq, pdev); free_irq(irq, pdev);
clk_unprepare(clk);
clk_put(clk); clk_put(clk);
iounmap(virtbase); iounmap(virtbase);
release_mem_region(phybase, physize); release_mem_region(phybase, physize);
...@@ -300,9 +301,9 @@ static int __init coh901327_probe(struct platform_device *pdev) ...@@ -300,9 +301,9 @@ static int __init coh901327_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "could not get clock\n"); dev_err(&pdev->dev, "could not get clock\n");
goto out_no_clk; goto out_no_clk;
} }
ret = clk_enable(clk); ret = clk_prepare_enable(clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "could not enable clock\n"); dev_err(&pdev->dev, "could not prepare and enable clock\n");
goto out_no_clk_enable; goto out_no_clk_enable;
} }
...@@ -369,7 +370,7 @@ static int __init coh901327_probe(struct platform_device *pdev) ...@@ -369,7 +370,7 @@ static int __init coh901327_probe(struct platform_device *pdev)
out_no_wdog: out_no_wdog:
free_irq(irq, pdev); free_irq(irq, pdev);
out_no_irq: out_no_irq:
clk_disable(clk); clk_disable_unprepare(clk);
out_no_clk_enable: out_no_clk_enable:
clk_put(clk); clk_put(clk);
out_no_clk: out_no_clk:
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#define SIO_F71858_ID 0x0507 /* Chipset ID */ #define SIO_F71858_ID 0x0507 /* Chipset ID */
#define SIO_F71862_ID 0x0601 /* Chipset ID */ #define SIO_F71862_ID 0x0601 /* Chipset ID */
#define SIO_F71869_ID 0x0814 /* Chipset ID */ #define SIO_F71869_ID 0x0814 /* Chipset ID */
#define SIO_F71869A_ID 0x1007 /* Chipset ID */
#define SIO_F71882_ID 0x0541 /* Chipset ID */ #define SIO_F71882_ID 0x0541 /* Chipset ID */
#define SIO_F71889_ID 0x0723 /* Chipset ID */ #define SIO_F71889_ID 0x0723 /* Chipset ID */
...@@ -195,7 +196,7 @@ static inline int superio_enter(int base) ...@@ -195,7 +196,7 @@ static inline int superio_enter(int base)
return -EBUSY; return -EBUSY;
} }
/* according to the datasheet the key must be send twice! */ /* according to the datasheet the key must be sent twice! */
outb(SIO_UNLOCK_KEY, base); outb(SIO_UNLOCK_KEY, base);
outb(SIO_UNLOCK_KEY, base); outb(SIO_UNLOCK_KEY, base);
...@@ -756,6 +757,7 @@ static int __init f71808e_find(int sioaddr) ...@@ -756,6 +757,7 @@ static int __init f71808e_find(int sioaddr)
err = f71862fg_pin_configure(0); /* validate module parameter */ err = f71862fg_pin_configure(0); /* validate module parameter */
break; break;
case SIO_F71869_ID: case SIO_F71869_ID:
case SIO_F71869A_ID:
watchdog.type = f71869; watchdog.type = f71869;
break; break;
case SIO_F71882_ID: case SIO_F71882_ID:
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
/* Module and version information */ /* Module and version information */
#define DRV_NAME "iTCO_wdt" #define DRV_NAME "iTCO_wdt"
#define DRV_VERSION "1.07" #define DRV_VERSION "1.10"
/* Includes */ /* Includes */
#include <linux/module.h> /* For module specific items */ #include <linux/module.h> /* For module specific items */
...@@ -88,8 +88,6 @@ ...@@ -88,8 +88,6 @@
#define TCOv2_TMR (TCOBASE + 0x12) /* TCOv2 Timer Initial Value */ #define TCOv2_TMR (TCOBASE + 0x12) /* TCOv2 Timer Initial Value */
/* internal variables */ /* internal variables */
static unsigned long is_active;
static char expect_release;
static struct { /* this is private data for the iTCO_wdt device */ static struct { /* this is private data for the iTCO_wdt device */
/* TCO version/generation */ /* TCO version/generation */
unsigned int iTCO_version; unsigned int iTCO_version;
...@@ -106,12 +104,12 @@ static struct { /* this is private data for the iTCO_wdt device */ ...@@ -106,12 +104,12 @@ static struct { /* this is private data for the iTCO_wdt device */
} iTCO_wdt_private; } iTCO_wdt_private;
/* module parameters */ /* module parameters */
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ #define WATCHDOG_TIMEOUT 30 /* 30 sec default heartbeat */
static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ static int heartbeat = WATCHDOG_TIMEOUT; /* in seconds */
module_param(heartbeat, int, 0); module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. " MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
"5..76 (TCO v1) or 3..614 (TCO v2), default=" "5..76 (TCO v1) or 3..614 (TCO v2), default="
__MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
static bool nowayout = WATCHDOG_NOWAYOUT; static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0); module_param(nowayout, bool, 0);
...@@ -178,13 +176,13 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void) ...@@ -178,13 +176,13 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void)
return ret; /* returns: 0 = OK, -EIO = Error */ return ret; /* returns: 0 = OK, -EIO = Error */
} }
static int iTCO_wdt_start(void) static int iTCO_wdt_start(struct watchdog_device *wd_dev)
{ {
unsigned int val; unsigned int val;
spin_lock(&iTCO_wdt_private.io_lock); spin_lock(&iTCO_wdt_private.io_lock);
iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, heartbeat); iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, wd_dev->timeout);
/* disable chipset's NO_REBOOT bit */ /* disable chipset's NO_REBOOT bit */
if (iTCO_wdt_unset_NO_REBOOT_bit()) { if (iTCO_wdt_unset_NO_REBOOT_bit()) {
...@@ -212,7 +210,7 @@ static int iTCO_wdt_start(void) ...@@ -212,7 +210,7 @@ static int iTCO_wdt_start(void)
return 0; return 0;
} }
static int iTCO_wdt_stop(void) static int iTCO_wdt_stop(struct watchdog_device *wd_dev)
{ {
unsigned int val; unsigned int val;
...@@ -236,11 +234,11 @@ static int iTCO_wdt_stop(void) ...@@ -236,11 +234,11 @@ static int iTCO_wdt_stop(void)
return 0; return 0;
} }
static int iTCO_wdt_keepalive(void) static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
{ {
spin_lock(&iTCO_wdt_private.io_lock); spin_lock(&iTCO_wdt_private.io_lock);
iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, heartbeat); iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, wd_dev->timeout);
/* Reload the timer by writing to the TCO Timer Counter register */ /* Reload the timer by writing to the TCO Timer Counter register */
if (iTCO_wdt_private.iTCO_version == 2) if (iTCO_wdt_private.iTCO_version == 2)
...@@ -257,7 +255,7 @@ static int iTCO_wdt_keepalive(void) ...@@ -257,7 +255,7 @@ static int iTCO_wdt_keepalive(void)
return 0; return 0;
} }
static int iTCO_wdt_set_heartbeat(int t) static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
{ {
unsigned int val16; unsigned int val16;
unsigned char val8; unsigned char val8;
...@@ -304,14 +302,15 @@ static int iTCO_wdt_set_heartbeat(int t) ...@@ -304,14 +302,15 @@ static int iTCO_wdt_set_heartbeat(int t)
return -EINVAL; return -EINVAL;
} }
heartbeat = t; wd_dev->timeout = t;
return 0; return 0;
} }
static int iTCO_wdt_get_timeleft(int *time_left) static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
{ {
unsigned int val16; unsigned int val16;
unsigned char val8; unsigned char val8;
unsigned int time_left = 0;
/* read the TCO Timer */ /* read the TCO Timer */
if (iTCO_wdt_private.iTCO_version == 2) { if (iTCO_wdt_private.iTCO_version == 2) {
...@@ -320,7 +319,7 @@ static int iTCO_wdt_get_timeleft(int *time_left) ...@@ -320,7 +319,7 @@ static int iTCO_wdt_get_timeleft(int *time_left)
val16 &= 0x3ff; val16 &= 0x3ff;
spin_unlock(&iTCO_wdt_private.io_lock); spin_unlock(&iTCO_wdt_private.io_lock);
*time_left = (val16 * 6) / 10; time_left = (val16 * 6) / 10;
} else if (iTCO_wdt_private.iTCO_version == 1) { } else if (iTCO_wdt_private.iTCO_version == 1) {
spin_lock(&iTCO_wdt_private.io_lock); spin_lock(&iTCO_wdt_private.io_lock);
val8 = inb(TCO_RLD); val8 = inb(TCO_RLD);
...@@ -329,156 +328,35 @@ static int iTCO_wdt_get_timeleft(int *time_left) ...@@ -329,156 +328,35 @@ static int iTCO_wdt_get_timeleft(int *time_left)
val8 += (inb(TCOv1_TMR) & 0x3f); val8 += (inb(TCOv1_TMR) & 0x3f);
spin_unlock(&iTCO_wdt_private.io_lock); spin_unlock(&iTCO_wdt_private.io_lock);
*time_left = (val8 * 6) / 10; time_left = (val8 * 6) / 10;
} else
return -EINVAL;
return 0;
}
/*
* /dev/watchdog handling
*/
static int iTCO_wdt_open(struct inode *inode, struct file *file)
{
/* /dev/watchdog can only be opened once */
if (test_and_set_bit(0, &is_active))
return -EBUSY;
/*
* Reload and activate timer
*/
iTCO_wdt_start();
return nonseekable_open(inode, file);
}
static int iTCO_wdt_release(struct inode *inode, struct file *file)
{
/*
* Shut off the timer.
*/
if (expect_release == 42) {
iTCO_wdt_stop();
} else {
pr_crit("Unexpected close, not stopping watchdog!\n");
iTCO_wdt_keepalive();
}
clear_bit(0, &is_active);
expect_release = 0;
return 0;
}
static ssize_t iTCO_wdt_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
/* See if we got the magic character 'V' and reload the timer */
if (len) {
if (!nowayout) {
size_t i;
/* note: just in case someone wrote the magic
character five months ago... */
expect_release = 0;
/* scan to see whether or not we got the
magic character */
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
expect_release = 42;
}
}
/* someone wrote to us, we should reload the timer */
iTCO_wdt_keepalive();
}
return len;
}
static long iTCO_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
int new_options, retval = -EINVAL;
int new_heartbeat;
void __user *argp = (void __user *)arg;
int __user *p = argp;
static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = DRV_NAME,
};
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, p);
case WDIOC_SETOPTIONS:
{
if (get_user(new_options, p))
return -EFAULT;
if (new_options & WDIOS_DISABLECARD) {
iTCO_wdt_stop();
retval = 0;
}
if (new_options & WDIOS_ENABLECARD) {
iTCO_wdt_keepalive();
iTCO_wdt_start();
retval = 0;
}
return retval;
}
case WDIOC_KEEPALIVE:
iTCO_wdt_keepalive();
return 0;
case WDIOC_SETTIMEOUT:
{
if (get_user(new_heartbeat, p))
return -EFAULT;
if (iTCO_wdt_set_heartbeat(new_heartbeat))
return -EINVAL;
iTCO_wdt_keepalive();
/* Fall */
}
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, p);
case WDIOC_GETTIMELEFT:
{
int time_left;
if (iTCO_wdt_get_timeleft(&time_left))
return -EINVAL;
return put_user(time_left, p);
}
default:
return -ENOTTY;
} }
return time_left;
} }
/* /*
* Kernel Interfaces * Kernel Interfaces
*/ */
static const struct file_operations iTCO_wdt_fops = { static const struct watchdog_info ident = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
.firmware_version = 0,
.identity = DRV_NAME,
};
static const struct watchdog_ops iTCO_wdt_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = no_llseek, .start = iTCO_wdt_start,
.write = iTCO_wdt_write, .stop = iTCO_wdt_stop,
.unlocked_ioctl = iTCO_wdt_ioctl, .ping = iTCO_wdt_ping,
.open = iTCO_wdt_open, .set_timeout = iTCO_wdt_set_timeout,
.release = iTCO_wdt_release, .get_timeleft = iTCO_wdt_get_timeleft,
}; };
static struct miscdevice iTCO_wdt_miscdev = { static struct watchdog_device iTCO_wdt_watchdog_dev = {
.minor = WATCHDOG_MINOR, .info = &ident,
.name = "watchdog", .ops = &iTCO_wdt_ops,
.fops = &iTCO_wdt_fops,
}; };
/* /*
...@@ -489,10 +367,10 @@ static void __devexit iTCO_wdt_cleanup(void) ...@@ -489,10 +367,10 @@ static void __devexit iTCO_wdt_cleanup(void)
{ {
/* Stop the timer before we leave */ /* Stop the timer before we leave */
if (!nowayout) if (!nowayout)
iTCO_wdt_stop(); iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
/* Deregister */ /* Deregister */
misc_deregister(&iTCO_wdt_miscdev); watchdog_unregister_device(&iTCO_wdt_watchdog_dev);
/* release resources */ /* release resources */
release_region(iTCO_wdt_private.tco_res->start, release_region(iTCO_wdt_private.tco_res->start,
...@@ -605,20 +483,25 @@ static int __devinit iTCO_wdt_probe(struct platform_device *dev) ...@@ -605,20 +483,25 @@ static int __devinit iTCO_wdt_probe(struct platform_device *dev)
outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */ outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */ outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */
iTCO_wdt_watchdog_dev.bootstatus = 0;
iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT;
watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout);
iTCO_wdt_watchdog_dev.parent = dev->dev.parent;
/* Make sure the watchdog is not running */ /* Make sure the watchdog is not running */
iTCO_wdt_stop(); iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
/* Check that the heartbeat value is within it's range; /* Check that the heartbeat value is within it's range;
if not reset to the default */ if not reset to the default */
if (iTCO_wdt_set_heartbeat(heartbeat)) { if (iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, heartbeat)) {
iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT); iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, WATCHDOG_TIMEOUT);
pr_info("timeout value out of range, using %d\n", heartbeat); pr_info("timeout value out of range, using %d\n",
WATCHDOG_TIMEOUT);
} }
ret = misc_register(&iTCO_wdt_miscdev); ret = watchdog_register_device(&iTCO_wdt_watchdog_dev);
if (ret != 0) { if (ret != 0) {
pr_err("cannot register miscdev on minor=%d (err=%d)\n", pr_err("cannot register watchdog device (err=%d)\n", ret);
WATCHDOG_MINOR, ret);
goto unreg_tco; goto unreg_tco;
} }
...@@ -659,7 +542,7 @@ static int __devexit iTCO_wdt_remove(struct platform_device *dev) ...@@ -659,7 +542,7 @@ static int __devexit iTCO_wdt_remove(struct platform_device *dev)
static void iTCO_wdt_shutdown(struct platform_device *dev) static void iTCO_wdt_shutdown(struct platform_device *dev)
{ {
iTCO_wdt_stop(); iTCO_wdt_stop(NULL);
} }
static struct platform_driver iTCO_wdt_driver = { static struct platform_driver iTCO_wdt_driver = {
......
...@@ -232,7 +232,7 @@ static void __devinit ie6xx_wdt_debugfs_init(void) ...@@ -232,7 +232,7 @@ static void __devinit ie6xx_wdt_debugfs_init(void)
S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_dbg_operations); S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_dbg_operations);
} }
static void __devexit ie6xx_wdt_debugfs_exit(void) static void ie6xx_wdt_debugfs_exit(void)
{ {
debugfs_remove(ie6xx_wdt_data.debugfs); debugfs_remove(ie6xx_wdt_data.debugfs);
} }
...@@ -242,7 +242,7 @@ static void __devinit ie6xx_wdt_debugfs_init(void) ...@@ -242,7 +242,7 @@ static void __devinit ie6xx_wdt_debugfs_init(void)
{ {
} }
static void __devexit ie6xx_wdt_debugfs_exit(void) static void ie6xx_wdt_debugfs_exit(void)
{ {
} }
#endif #endif
......
...@@ -297,7 +297,7 @@ static int __devinit xwdt_probe(struct platform_device *pdev) ...@@ -297,7 +297,7 @@ static int __devinit xwdt_probe(struct platform_device *pdev)
no_timeout = 0; no_timeout = 0;
pfreq = (u32 *)of_get_property(pdev->dev.of_node->parent, pfreq = (u32 *)of_get_property(pdev->dev.of_node,
"clock-frequency", NULL); "clock-frequency", NULL);
if (pfreq == NULL) { if (pfreq == NULL) {
......
...@@ -126,8 +126,6 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev) ...@@ -126,8 +126,6 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
u32 pre_margin = GET_WLDR_VAL(timer_margin); u32 pre_margin = GET_WLDR_VAL(timer_margin);
void __iomem *base = wdev->base; void __iomem *base = wdev->base;
pm_runtime_get_sync(wdev->dev);
/* just count up at 32 KHz */ /* just count up at 32 KHz */
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04) while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax(); cpu_relax();
...@@ -135,8 +133,6 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev) ...@@ -135,8 +133,6 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
__raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR); __raw_writel(pre_margin, base + OMAP_WATCHDOG_LDR);
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04) while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
cpu_relax(); cpu_relax();
pm_runtime_put_sync(wdev->dev);
} }
/* /*
...@@ -166,8 +162,6 @@ static int omap_wdt_open(struct inode *inode, struct file *file) ...@@ -166,8 +162,6 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
omap_wdt_ping(wdev); /* trigger loading of new timeout value */ omap_wdt_ping(wdev); /* trigger loading of new timeout value */
omap_wdt_enable(wdev); omap_wdt_enable(wdev);
pm_runtime_put_sync(wdev->dev);
return nonseekable_open(inode, file); return nonseekable_open(inode, file);
} }
...@@ -179,8 +173,6 @@ static int omap_wdt_release(struct inode *inode, struct file *file) ...@@ -179,8 +173,6 @@ static int omap_wdt_release(struct inode *inode, struct file *file)
* Shut off the timer unless NOWAYOUT is defined. * Shut off the timer unless NOWAYOUT is defined.
*/ */
#ifndef CONFIG_WATCHDOG_NOWAYOUT #ifndef CONFIG_WATCHDOG_NOWAYOUT
pm_runtime_get_sync(wdev->dev);
omap_wdt_disable(wdev); omap_wdt_disable(wdev);
pm_runtime_put_sync(wdev->dev); pm_runtime_put_sync(wdev->dev);
...@@ -199,11 +191,9 @@ static ssize_t omap_wdt_write(struct file *file, const char __user *data, ...@@ -199,11 +191,9 @@ static ssize_t omap_wdt_write(struct file *file, const char __user *data,
/* Refresh LOAD_TIME. */ /* Refresh LOAD_TIME. */
if (len) { if (len) {
pm_runtime_get_sync(wdev->dev);
spin_lock(&wdt_lock); spin_lock(&wdt_lock);
omap_wdt_ping(wdev); omap_wdt_ping(wdev);
spin_unlock(&wdt_lock); spin_unlock(&wdt_lock);
pm_runtime_put_sync(wdev->dev);
} }
return len; return len;
} }
...@@ -236,18 +226,15 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -236,18 +226,15 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
(int __user *)arg); (int __user *)arg);
return put_user(0, (int __user *)arg); return put_user(0, (int __user *)arg);
case WDIOC_KEEPALIVE: case WDIOC_KEEPALIVE:
pm_runtime_get_sync(wdev->dev);
spin_lock(&wdt_lock); spin_lock(&wdt_lock);
omap_wdt_ping(wdev); omap_wdt_ping(wdev);
spin_unlock(&wdt_lock); spin_unlock(&wdt_lock);
pm_runtime_put_sync(wdev->dev);
return 0; return 0;
case WDIOC_SETTIMEOUT: case WDIOC_SETTIMEOUT:
if (get_user(new_margin, (int __user *)arg)) if (get_user(new_margin, (int __user *)arg))
return -EFAULT; return -EFAULT;
omap_wdt_adjust_timeout(new_margin); omap_wdt_adjust_timeout(new_margin);
pm_runtime_get_sync(wdev->dev);
spin_lock(&wdt_lock); spin_lock(&wdt_lock);
omap_wdt_disable(wdev); omap_wdt_disable(wdev);
omap_wdt_set_timeout(wdev); omap_wdt_set_timeout(wdev);
...@@ -255,7 +242,6 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd, ...@@ -255,7 +242,6 @@ static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
omap_wdt_ping(wdev); omap_wdt_ping(wdev);
spin_unlock(&wdt_lock); spin_unlock(&wdt_lock);
pm_runtime_put_sync(wdev->dev);
/* Fall */ /* Fall */
case WDIOC_GETTIMEOUT: case WDIOC_GETTIMEOUT:
return put_user(timer_margin, (int __user *)arg); return put_user(timer_margin, (int __user *)arg);
...@@ -363,7 +349,6 @@ static void omap_wdt_shutdown(struct platform_device *pdev) ...@@ -363,7 +349,6 @@ static void omap_wdt_shutdown(struct platform_device *pdev)
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
if (wdev->omap_wdt_users) { if (wdev->omap_wdt_users) {
pm_runtime_get_sync(wdev->dev);
omap_wdt_disable(wdev); omap_wdt_disable(wdev);
pm_runtime_put_sync(wdev->dev); pm_runtime_put_sync(wdev->dev);
} }
...@@ -403,7 +388,6 @@ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) ...@@ -403,7 +388,6 @@ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
if (wdev->omap_wdt_users) { if (wdev->omap_wdt_users) {
pm_runtime_get_sync(wdev->dev);
omap_wdt_disable(wdev); omap_wdt_disable(wdev);
pm_runtime_put_sync(wdev->dev); pm_runtime_put_sync(wdev->dev);
} }
...@@ -419,7 +403,6 @@ static int omap_wdt_resume(struct platform_device *pdev) ...@@ -419,7 +403,6 @@ static int omap_wdt_resume(struct platform_device *pdev)
pm_runtime_get_sync(wdev->dev); pm_runtime_get_sync(wdev->dev);
omap_wdt_enable(wdev); omap_wdt_enable(wdev);
omap_wdt_ping(wdev); omap_wdt_ping(wdev);
pm_runtime_put_sync(wdev->dev);
} }
return 0; return 0;
......
...@@ -16,22 +16,21 @@ ...@@ -16,22 +16,21 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h>
#include <mach/bridge-regs.h> #include <mach/bridge-regs.h>
/* /*
* Watchdog timer block registers. * Watchdog timer block registers.
*/ */
#define TIMER_CTRL 0x0000 #define TIMER_CTRL 0x0000
#define WDT_EN 0x0010 #define WDT_EN 0x0010
#define WDT_VAL 0x0024 #define WDT_VAL 0x0024
#define WDT_MAX_CYCLE_COUNT 0xffffffff #define WDT_MAX_CYCLE_COUNT 0xffffffff
...@@ -44,27 +43,27 @@ static unsigned int wdt_max_duration; /* (seconds) */ ...@@ -44,27 +43,27 @@ static unsigned int wdt_max_duration; /* (seconds) */
static struct clk *clk; static struct clk *clk;
static unsigned int wdt_tclk; static unsigned int wdt_tclk;
static void __iomem *wdt_reg; static void __iomem *wdt_reg;
static unsigned long wdt_status;
static DEFINE_SPINLOCK(wdt_lock); static DEFINE_SPINLOCK(wdt_lock);
static void orion_wdt_ping(void) static int orion_wdt_ping(struct watchdog_device *wdt_dev)
{ {
spin_lock(&wdt_lock); spin_lock(&wdt_lock);
/* Reload watchdog duration */ /* Reload watchdog duration */
writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL); writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
spin_unlock(&wdt_lock); spin_unlock(&wdt_lock);
return 0;
} }
static void orion_wdt_enable(void) static int orion_wdt_start(struct watchdog_device *wdt_dev)
{ {
u32 reg; u32 reg;
spin_lock(&wdt_lock); spin_lock(&wdt_lock);
/* Set watchdog duration */ /* Set watchdog duration */
writel(wdt_tclk * heartbeat, wdt_reg + WDT_VAL); writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL);
/* Clear watchdog timer interrupt */ /* Clear watchdog timer interrupt */
reg = readl(BRIDGE_CAUSE); reg = readl(BRIDGE_CAUSE);
...@@ -82,9 +81,10 @@ static void orion_wdt_enable(void) ...@@ -82,9 +81,10 @@ static void orion_wdt_enable(void)
writel(reg, RSTOUTn_MASK); writel(reg, RSTOUTn_MASK);
spin_unlock(&wdt_lock); spin_unlock(&wdt_lock);
return 0;
} }
static void orion_wdt_disable(void) static int orion_wdt_stop(struct watchdog_device *wdt_dev)
{ {
u32 reg; u32 reg;
...@@ -101,139 +101,44 @@ static void orion_wdt_disable(void) ...@@ -101,139 +101,44 @@ static void orion_wdt_disable(void)
writel(reg, wdt_reg + TIMER_CTRL); writel(reg, wdt_reg + TIMER_CTRL);
spin_unlock(&wdt_lock); spin_unlock(&wdt_lock);
return 0;
} }
static int orion_wdt_get_timeleft(int *time_left) static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
{ {
unsigned int time_left;
spin_lock(&wdt_lock); spin_lock(&wdt_lock);
*time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk; time_left = readl(wdt_reg + WDT_VAL) / wdt_tclk;
spin_unlock(&wdt_lock); spin_unlock(&wdt_lock);
return 0;
}
static int orion_wdt_open(struct inode *inode, struct file *file) return time_left;
{
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
orion_wdt_enable();
return nonseekable_open(inode, file);
} }
static ssize_t orion_wdt_write(struct file *file, const char *data, static int orion_wdt_set_timeout(struct watchdog_device *wdt_dev,
size_t len, loff_t *ppos) unsigned int timeout)
{ {
if (len) { wdt_dev->timeout = timeout;
if (!nowayout) {
size_t i;
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
for (i = 0; i != len; i++) {
char c;
if (get_user(c, data + i))
return -EFAULT;
if (c == 'V')
set_bit(WDT_OK_TO_CLOSE, &wdt_status);
}
}
orion_wdt_ping();
}
return len;
}
static int orion_wdt_settimeout(int new_time)
{
if ((new_time <= 0) || (new_time > wdt_max_duration))
return -EINVAL;
/* Set new watchdog time to be used when
* orion_wdt_enable() or orion_wdt_ping() is called. */
heartbeat = new_time;
return 0; return 0;
} }
static const struct watchdog_info ident = { static const struct watchdog_info orion_wdt_info = {
.options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
WDIOF_KEEPALIVEPING, .identity = "Orion Watchdog",
.identity = "Orion Watchdog",
}; };
static long orion_wdt_ioctl(struct file *file, unsigned int cmd, static const struct watchdog_ops orion_wdt_ops = {
unsigned long arg) .owner = THIS_MODULE,
{ .start = orion_wdt_start,
int ret = -ENOTTY; .stop = orion_wdt_stop,
int time; .ping = orion_wdt_ping,
.set_timeout = orion_wdt_set_timeout,
switch (cmd) { .get_timeleft = orion_wdt_get_timeleft,
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_KEEPALIVE:
orion_wdt_ping();
ret = 0;
break;
case WDIOC_SETTIMEOUT:
ret = get_user(time, (int *)arg);
if (ret)
break;
if (orion_wdt_settimeout(time)) {
ret = -EINVAL;
break;
}
orion_wdt_ping();
/* Fall through */
case WDIOC_GETTIMEOUT:
ret = put_user(heartbeat, (int *)arg);
break;
case WDIOC_GETTIMELEFT:
if (orion_wdt_get_timeleft(&time)) {
ret = -EINVAL;
break;
}
ret = put_user(time, (int *)arg);
break;
}
return ret;
}
static int orion_wdt_release(struct inode *inode, struct file *file)
{
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
orion_wdt_disable();
else
pr_crit("Device closed unexpectedly - timer will not stop\n");
clear_bit(WDT_IN_USE, &wdt_status);
clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
return 0;
}
static const struct file_operations orion_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = orion_wdt_write,
.unlocked_ioctl = orion_wdt_ioctl,
.open = orion_wdt_open,
.release = orion_wdt_release,
}; };
static struct miscdevice orion_wdt_miscdev = { static struct watchdog_device orion_wdt = {
.minor = WATCHDOG_MINOR, .info = &orion_wdt_info,
.name = "watchdog", .ops = &orion_wdt_ops,
.fops = &orion_wdt_fops,
}; };
static int __devinit orion_wdt_probe(struct platform_device *pdev) static int __devinit orion_wdt_probe(struct platform_device *pdev)
...@@ -241,29 +146,34 @@ static int __devinit orion_wdt_probe(struct platform_device *pdev) ...@@ -241,29 +146,34 @@ static int __devinit orion_wdt_probe(struct platform_device *pdev)
struct resource *res; struct resource *res;
int ret; int ret;
clk = clk_get(&pdev->dev, NULL); clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
printk(KERN_ERR "Orion Watchdog missing clock\n"); dev_err(&pdev->dev, "Orion Watchdog missing clock\n");
return -ENODEV; return -ENODEV;
} }
clk_prepare_enable(clk); clk_prepare_enable(clk);
wdt_tclk = clk_get_rate(clk); wdt_tclk = clk_get_rate(clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
wdt_reg = ioremap(res->start, resource_size(res)); if (!wdt_reg)
return -ENOMEM;
if (orion_wdt_miscdev.parent)
return -EBUSY;
orion_wdt_miscdev.parent = &pdev->dev;
wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
if (orion_wdt_settimeout(heartbeat))
if ((heartbeat < 1) || (heartbeat > wdt_max_duration))
heartbeat = wdt_max_duration; heartbeat = wdt_max_duration;
ret = misc_register(&orion_wdt_miscdev); orion_wdt.timeout = heartbeat;
if (ret) orion_wdt.min_timeout = 1;
orion_wdt.max_timeout = wdt_max_duration;
watchdog_set_nowayout(&orion_wdt, nowayout);
ret = watchdog_register_device(&orion_wdt);
if (ret) {
clk_disable_unprepare(clk);
return ret; return ret;
}
pr_info("Initial timeout %d sec%s\n", pr_info("Initial timeout %d sec%s\n",
heartbeat, nowayout ? ", nowayout" : ""); heartbeat, nowayout ? ", nowayout" : "");
...@@ -272,27 +182,14 @@ static int __devinit orion_wdt_probe(struct platform_device *pdev) ...@@ -272,27 +182,14 @@ static int __devinit orion_wdt_probe(struct platform_device *pdev)
static int __devexit orion_wdt_remove(struct platform_device *pdev) static int __devexit orion_wdt_remove(struct platform_device *pdev)
{ {
int ret; watchdog_unregister_device(&orion_wdt);
if (test_bit(WDT_IN_USE, &wdt_status)) {
orion_wdt_disable();
clear_bit(WDT_IN_USE, &wdt_status);
}
ret = misc_deregister(&orion_wdt_miscdev);
if (!ret)
orion_wdt_miscdev.parent = NULL;
clk_disable_unprepare(clk); clk_disable_unprepare(clk);
clk_put(clk); return 0;
return ret;
} }
static void orion_wdt_shutdown(struct platform_device *pdev) static void orion_wdt_shutdown(struct platform_device *pdev)
{ {
if (test_bit(WDT_IN_USE, &wdt_status)) orion_wdt_stop(&orion_wdt);
orion_wdt_disable();
} }
static struct platform_driver orion_wdt_driver = { static struct platform_driver orion_wdt_driver = {
......
...@@ -519,21 +519,7 @@ static struct platform_driver s3c2410wdt_driver = { ...@@ -519,21 +519,7 @@ static struct platform_driver s3c2410wdt_driver = {
}, },
}; };
module_platform_driver(s3c2410wdt_driver);
static int __init watchdog_init(void)
{
pr_info("S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n");
return platform_driver_register(&s3c2410wdt_driver);
}
static void __exit watchdog_exit(void)
{
platform_driver_unregister(&s3c2410wdt_driver);
}
module_init(watchdog_init);
module_exit(watchdog_exit);
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, " MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, "
"Dimitry Andric <dimitry.andric@tomtom.com>"); "Dimitry Andric <dimitry.andric@tomtom.com>");
......
...@@ -136,6 +136,8 @@ static void sch311x_wdt_set_timeout(int t) ...@@ -136,6 +136,8 @@ static void sch311x_wdt_set_timeout(int t)
static void sch311x_wdt_start(void) static void sch311x_wdt_start(void)
{ {
unsigned char t;
spin_lock(&sch311x_wdt_data.io_lock); spin_lock(&sch311x_wdt_data.io_lock);
/* set watchdog's timeout */ /* set watchdog's timeout */
...@@ -149,7 +151,8 @@ static void sch311x_wdt_start(void) ...@@ -149,7 +151,8 @@ static void sch311x_wdt_start(void)
* Bit 4-6 (Reserved) * Bit 4-6 (Reserved)
* Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain * Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
*/ */
outb(0x0e, sch311x_wdt_data.runtime_reg + GP60); t = inb(sch311x_wdt_data.runtime_reg + GP60);
outb((t & ~0x0d) | 0x0c, sch311x_wdt_data.runtime_reg + GP60);
spin_unlock(&sch311x_wdt_data.io_lock); spin_unlock(&sch311x_wdt_data.io_lock);
...@@ -157,10 +160,13 @@ static void sch311x_wdt_start(void) ...@@ -157,10 +160,13 @@ static void sch311x_wdt_start(void)
static void sch311x_wdt_stop(void) static void sch311x_wdt_stop(void)
{ {
unsigned char t;
spin_lock(&sch311x_wdt_data.io_lock); spin_lock(&sch311x_wdt_data.io_lock);
/* stop the watchdog */ /* stop the watchdog */
outb(0x01, sch311x_wdt_data.runtime_reg + GP60); t = inb(sch311x_wdt_data.runtime_reg + GP60);
outb((t & ~0x0d) | 0x01, sch311x_wdt_data.runtime_reg + GP60);
/* disable timeout by setting it to 0 */ /* disable timeout by setting it to 0 */
sch311x_wdt_set_timeout(0); sch311x_wdt_set_timeout(0);
......
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