Commit 1950f499 authored by Paul Mundt's avatar Paul Mundt

watchdog: shwdt: Conversion to watchdog core.

Fairly straightforward conversion to utilize watchdog core support.
Signed-off-by: default avatarPaul Mundt <lethal@linux-sh.org>
parent 40968126
...@@ -1138,6 +1138,7 @@ config ZVM_WATCHDOG ...@@ -1138,6 +1138,7 @@ config ZVM_WATCHDOG
config SH_WDT config SH_WDT
tristate "SuperH Watchdog" tristate "SuperH Watchdog"
depends on SUPERH && (CPU_SH3 || CPU_SH4) depends on SUPERH && (CPU_SH3 || CPU_SH4)
select WATCHDOG_CORE
help help
This driver adds watchdog support for the integrated watchdog in the This driver adds watchdog support for the integrated watchdog in the
SuperH processors. If you have one of these processors and wish SuperH processors. If you have one of these processors and wish
......
...@@ -27,12 +27,10 @@ ...@@ -27,12 +27,10 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/ioport.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/uaccess.h>
#include <asm/watchdog.h> #include <asm/watchdog.h>
#define DRV_NAME "sh-wdt" #define DRV_NAME "sh-wdt"
...@@ -67,8 +65,6 @@ ...@@ -67,8 +65,6 @@
static int clock_division_ratio = WTCSR_CKS_4096; static int clock_division_ratio = WTCSR_CKS_4096;
#define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4)) #define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4))
static const struct watchdog_info sh_wdt_info;
static struct platform_device *sh_wdt_dev;
static DEFINE_SPINLOCK(shwdt_lock); static DEFINE_SPINLOCK(shwdt_lock);
#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
...@@ -86,8 +82,9 @@ struct sh_wdt { ...@@ -86,8 +82,9 @@ struct sh_wdt {
char expect_close; char expect_close;
}; };
static void sh_wdt_start(struct sh_wdt *wdt) static int sh_wdt_start(struct watchdog_device *wdt_dev)
{ {
struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags; unsigned long flags;
u8 csr; u8 csr;
...@@ -121,10 +118,13 @@ static void sh_wdt_start(struct sh_wdt *wdt) ...@@ -121,10 +118,13 @@ static void sh_wdt_start(struct sh_wdt *wdt)
sh_wdt_write_rstcsr(csr); sh_wdt_write_rstcsr(csr);
#endif #endif
spin_unlock_irqrestore(&shwdt_lock, flags); spin_unlock_irqrestore(&shwdt_lock, flags);
return 0;
} }
static void sh_wdt_stop(struct sh_wdt *wdt) static int sh_wdt_stop(struct watchdog_device *wdt_dev)
{ {
struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
unsigned long flags; unsigned long flags;
u8 csr; u8 csr;
...@@ -137,18 +137,22 @@ static void sh_wdt_stop(struct sh_wdt *wdt) ...@@ -137,18 +137,22 @@ static void sh_wdt_stop(struct sh_wdt *wdt)
sh_wdt_write_csr(csr); sh_wdt_write_csr(csr);
spin_unlock_irqrestore(&shwdt_lock, flags); spin_unlock_irqrestore(&shwdt_lock, flags);
return 0;
} }
static inline void sh_wdt_keepalive(struct sh_wdt *wdt) static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&shwdt_lock, flags); spin_lock_irqsave(&shwdt_lock, flags);
next_heartbeat = jiffies + (heartbeat * HZ); next_heartbeat = jiffies + (heartbeat * HZ);
spin_unlock_irqrestore(&shwdt_lock, flags); spin_unlock_irqrestore(&shwdt_lock, flags);
return 0;
} }
static int sh_wdt_set_heartbeat(int t) static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
{ {
unsigned long flags; unsigned long flags;
...@@ -157,7 +161,9 @@ static int sh_wdt_set_heartbeat(int t) ...@@ -157,7 +161,9 @@ static int sh_wdt_set_heartbeat(int t)
spin_lock_irqsave(&shwdt_lock, flags); spin_lock_irqsave(&shwdt_lock, flags);
heartbeat = t; heartbeat = t;
wdt_dev->timeout = t;
spin_unlock_irqrestore(&shwdt_lock, flags); spin_unlock_irqrestore(&shwdt_lock, flags);
return 0; return 0;
} }
...@@ -183,123 +189,6 @@ static void sh_wdt_ping(unsigned long data) ...@@ -183,123 +189,6 @@ static void sh_wdt_ping(unsigned long data)
spin_unlock_irqrestore(&shwdt_lock, flags); spin_unlock_irqrestore(&shwdt_lock, flags);
} }
static int sh_wdt_open(struct inode *inode, struct file *file)
{
struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev);
if (test_and_set_bit(0, &wdt->enabled))
return -EBUSY;
if (nowayout)
__module_get(THIS_MODULE);
file->private_data = wdt;
sh_wdt_start(wdt);
return nonseekable_open(inode, file);
}
static int sh_wdt_close(struct inode *inode, struct file *file)
{
struct sh_wdt *wdt = file->private_data;
if (wdt->expect_close == 42) {
sh_wdt_stop(wdt);
} else {
dev_crit(wdt->dev, "Unexpected close, not "
"stopping watchdog!\n");
sh_wdt_keepalive(wdt);
}
clear_bit(0, &wdt->enabled);
wdt->expect_close = 0;
return 0;
}
static ssize_t sh_wdt_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
struct sh_wdt *wdt = file->private_data;
if (count) {
if (!nowayout) {
size_t i;
wdt->expect_close = 0;
for (i = 0; i != count; i++) {
char c;
if (get_user(c, buf + i))
return -EFAULT;
if (c == 'V')
wdt->expect_close = 42;
}
}
sh_wdt_keepalive(wdt);
}
return count;
}
static long sh_wdt_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
struct sh_wdt *wdt = file->private_data;
int new_heartbeat;
int options, retval = -EINVAL;
switch (cmd) {
case WDIOC_GETSUPPORT:
return copy_to_user((struct watchdog_info *)arg,
&sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0;
case WDIOC_GETSTATUS:
case WDIOC_GETBOOTSTATUS:
return put_user(0, (int *)arg);
case WDIOC_SETOPTIONS:
if (get_user(options, (int *)arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
sh_wdt_stop(wdt);
retval = 0;
}
if (options & WDIOS_ENABLECARD) {
sh_wdt_start(wdt);
retval = 0;
}
return retval;
case WDIOC_KEEPALIVE:
sh_wdt_keepalive(wdt);
return 0;
case WDIOC_SETTIMEOUT:
if (get_user(new_heartbeat, (int *)arg))
return -EFAULT;
if (sh_wdt_set_heartbeat(new_heartbeat))
return -EINVAL;
sh_wdt_keepalive(wdt);
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, (int *)arg);
default:
return -ENOTTY;
}
return 0;
}
static const struct file_operations sh_wdt_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.write = sh_wdt_write,
.unlocked_ioctl = sh_wdt_ioctl,
.open = sh_wdt_open,
.release = sh_wdt_close,
};
static const struct watchdog_info sh_wdt_info = { static const struct watchdog_info sh_wdt_info = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
WDIOF_MAGICCLOSE, WDIOF_MAGICCLOSE,
...@@ -307,10 +196,17 @@ static const struct watchdog_info sh_wdt_info = { ...@@ -307,10 +196,17 @@ static const struct watchdog_info sh_wdt_info = {
.identity = "SH WDT", .identity = "SH WDT",
}; };
static struct miscdevice sh_wdt_miscdev = { static const struct watchdog_ops sh_wdt_ops = {
.minor = WATCHDOG_MINOR, .owner = THIS_MODULE,
.name = "watchdog", .start = sh_wdt_start,
.fops = &sh_wdt_fops, .stop = sh_wdt_stop,
.ping = sh_wdt_keepalive,
.set_timeout = sh_wdt_set_heartbeat,
};
static struct watchdog_device sh_wdt_dev = {
.info = &sh_wdt_info,
.ops = &sh_wdt_ops,
}; };
static int __devinit sh_wdt_probe(struct platform_device *pdev) static int __devinit sh_wdt_probe(struct platform_device *pdev)
...@@ -348,13 +244,25 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev) ...@@ -348,13 +244,25 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
goto out_err; goto out_err;
} }
sh_wdt_miscdev.parent = wdt->dev; rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
if (unlikely(rc)) {
/* Default timeout if invalid */
sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
dev_warn(&pdev->dev,
"heartbeat value must be 1<=x<=3600, using %d\n",
sh_wdt_dev.timeout);
}
dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
sh_wdt_dev.timeout, nowayout);
watchdog_set_nowayout(&sh_wdt_dev, nowayout);
watchdog_set_drvdata(&sh_wdt_dev, wdt);
rc = misc_register(&sh_wdt_miscdev); rc = watchdog_register_device(&sh_wdt_dev);
if (unlikely(rc)) { if (unlikely(rc)) {
dev_err(&pdev->dev, dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
"Can't register miscdev on minor=%d (err=%d)\n",
sh_wdt_miscdev.minor, rc);
goto out_unmap; goto out_unmap;
} }
...@@ -364,7 +272,6 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev) ...@@ -364,7 +272,6 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev)
wdt->timer.expires = next_ping_period(clock_division_ratio); wdt->timer.expires = next_ping_period(clock_division_ratio);
platform_set_drvdata(pdev, wdt); platform_set_drvdata(pdev, wdt);
sh_wdt_dev = pdev;
dev_info(&pdev->dev, "initialized.\n"); dev_info(&pdev->dev, "initialized.\n");
...@@ -387,9 +294,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev) ...@@ -387,9 +294,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev)
platform_set_drvdata(pdev, NULL); platform_set_drvdata(pdev, NULL);
misc_deregister(&sh_wdt_miscdev); watchdog_unregister_device(&sh_wdt_dev);
sh_wdt_dev = NULL;
devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); devm_release_mem_region(&pdev->dev, res->start, resource_size(res));
devm_iounmap(&pdev->dev, wdt->base); devm_iounmap(&pdev->dev, wdt->base);
...@@ -400,9 +305,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev) ...@@ -400,9 +305,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev)
static void sh_wdt_shutdown(struct platform_device *pdev) static void sh_wdt_shutdown(struct platform_device *pdev)
{ {
struct sh_wdt *wdt = platform_get_drvdata(pdev); sh_wdt_stop(&sh_wdt_dev);
sh_wdt_stop(wdt);
} }
static struct platform_driver sh_wdt_driver = { static struct platform_driver sh_wdt_driver = {
...@@ -418,8 +321,6 @@ static struct platform_driver sh_wdt_driver = { ...@@ -418,8 +321,6 @@ static struct platform_driver sh_wdt_driver = {
static int __init sh_wdt_init(void) static int __init sh_wdt_init(void)
{ {
int rc;
if (unlikely(clock_division_ratio < 0x5 || if (unlikely(clock_division_ratio < 0x5 ||
clock_division_ratio > 0x7)) { clock_division_ratio > 0x7)) {
clock_division_ratio = WTCSR_CKS_4096; clock_division_ratio = WTCSR_CKS_4096;
...@@ -428,17 +329,6 @@ static int __init sh_wdt_init(void) ...@@ -428,17 +329,6 @@ static int __init sh_wdt_init(void)
clock_division_ratio); clock_division_ratio);
} }
rc = sh_wdt_set_heartbeat(heartbeat);
if (unlikely(rc)) {
heartbeat = WATCHDOG_HEARTBEAT;
pr_info("heartbeat value must be 1<=x<=3600, using %d\n",
heartbeat);
}
pr_info("configured with heartbeat=%d sec (nowayout=%d)\n",
heartbeat, nowayout);
return platform_driver_register(&sh_wdt_driver); return platform_driver_register(&sh_wdt_driver);
} }
......
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