This patch implements the current watchdog framework for OMAP WDTimer,
which factored out the common components, so the driver can just focus
on the hardware related parts.

Signed-off-by: Zumeng Chen <[email protected]>
---
 drivers/watchdog/omap_wdt.c |  342 ++++++++++++++++---------------------------
 drivers/watchdog/omap_wdt.h |    5 +
 2 files changed, 128 insertions(+), 219 deletions(-)

diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 8285d65..cc5bc3e 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -24,6 +24,9 @@
  *
  * Copyright (c) 2005 David Brownell
  *     Use the driver model and standard identifiers; handle bigger timeouts.
+ *
+ * Copyright (c) 2012 WindRiver
+ *     Changes cater for the current watchdog framework.
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -33,7 +36,6 @@
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
@@ -50,8 +52,6 @@
 
 #include "omap_wdt.h"
 
-static struct platform_device *omap_wdt_dev;
-
 static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
@@ -59,32 +59,14 @@ MODULE_PARM_DESC(timer_margin, "initial watchdog timeout 
(in seconds)");
 static unsigned int wdt_trgr_pattern = 0x1234;
 static DEFINE_SPINLOCK(wdt_lock);
 
-struct omap_wdt_dev {
+struct omap_wdt_drvdata {
+       struct watchdog_device wdt;
        void __iomem    *base;          /* physical */
        struct device   *dev;
-       int             omap_wdt_users;
        struct resource *mem;
-       struct miscdevice omap_wdt_miscdev;
 };
 
-static void omap_wdt_ping(struct omap_wdt_dev *wdev)
-{
-       void __iomem    *base = wdev->base;
-
-       /* wait for posted write to complete */
-       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
-               cpu_relax();
-
-       wdt_trgr_pattern = ~wdt_trgr_pattern;
-       __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
-
-       /* wait for posted write to complete */
-       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
-               cpu_relax();
-       /* reloaded WCRR from WLDR */
-}
-
-static void omap_wdt_enable(struct omap_wdt_dev *wdev)
+static void omap_wdt_enable(struct omap_wdt_drvdata *wdev)
 {
        void __iomem *base = wdev->base;
 
@@ -98,7 +80,7 @@ static void omap_wdt_enable(struct omap_wdt_dev *wdev)
                cpu_relax();
 }
 
-static void omap_wdt_disable(struct omap_wdt_dev *wdev)
+static void omap_wdt_disable(struct omap_wdt_drvdata *wdev)
 {
        void __iomem *base = wdev->base;
 
@@ -121,12 +103,19 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout)
        timer_margin = new_timeout;
 }
 
-static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
+static int omap_wdt_set_timeout(struct watchdog_device *wdt_dev,
+                                   unsigned int new_timeout)
 {
-       u32 pre_margin = GET_WLDR_VAL(timer_margin);
-       void __iomem *base = wdev->base;
+       u32 pre_margin;
+       struct omap_wdt_drvdata *omap_wdev = watchdog_get_drvdata(wdt_dev);
+       void __iomem *base = omap_wdev->base;
 
-       pm_runtime_get_sync(wdev->dev);
+       pm_runtime_get_sync(omap_wdev->dev);
+       omap_wdt_disable(omap_wdev);
+
+       /* adjust timeout based on the new timeout */
+       omap_wdt_adjust_timeout(new_timeout);
+       pre_margin = GET_WLDR_VAL(timer_margin);
 
        /* just count up at 32 KHz */
        while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
@@ -136,147 +125,88 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev 
*wdev)
        while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04)
                cpu_relax();
 
-       pm_runtime_put_sync(wdev->dev);
+       omap_wdt_enable(omap_wdev);
+       wdt_dev->timeout = new_timeout;
+       pm_runtime_put_sync(omap_wdev->dev);
+       return 0;
 }
 
-/*
- *     Allow only one task to hold it open
- */
-static int omap_wdt_open(struct inode *inode, struct file *file)
+static int omap_wdt_ping(struct watchdog_device *wdt_dev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
-       void __iomem *base = wdev->base;
-
-       if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
-               return -EBUSY;
-
-       pm_runtime_get_sync(wdev->dev);
+       struct omap_wdt_drvdata *omap_wdev = watchdog_get_drvdata(wdt_dev);
+       void __iomem    *base = omap_wdev->base;
 
-       /* initialize prescaler */
-       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
-               cpu_relax();
+       pm_runtime_get_sync(omap_wdev->dev);
+       spin_lock(&wdt_lock);
 
-       __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
-       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
+       /* wait for posted write to complete */
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
 
-       file->private_data = (void *) wdev;
+       wdt_trgr_pattern = ~wdt_trgr_pattern;
+       __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
 
-       omap_wdt_set_timeout(wdev);
-       omap_wdt_ping(wdev); /* trigger loading of new timeout value */
-       omap_wdt_enable(wdev);
+       /* wait for posted write to complete */
+       /* reloaded WCRR from WLDR */
+       while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
+               cpu_relax();
 
-       pm_runtime_put_sync(wdev->dev);
+       spin_unlock(&wdt_lock);
+       pm_runtime_put_sync(omap_wdev->dev);
 
-       return nonseekable_open(inode, file);
+       return 0;
 }
 
-static int omap_wdt_release(struct inode *inode, struct file *file)
+static int omap_wdt_start(struct watchdog_device *wdt_dev)
 {
-       struct omap_wdt_dev *wdev = file->private_data;
+       struct omap_wdt_drvdata *omap_wdev = watchdog_get_drvdata(wdt_dev);
+       void __iomem *base = omap_wdev->base;
 
-       /*
-        *      Shut off the timer unless NOWAYOUT is defined.
-        */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
-       pm_runtime_get_sync(wdev->dev);
+       pm_runtime_get_sync(omap_wdev->dev);
+       /* initialize prescaler */
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
+               cpu_relax();
 
-       omap_wdt_disable(wdev);
+       __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL);
+       while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
+               cpu_relax();
 
-       pm_runtime_put_sync(wdev->dev);
-#else
-       pr_crit("Unexpected close, not stopping!\n");
-#endif
-       wdev->omap_wdt_users = 0;
+       omap_wdt_set_timeout(&omap_wdev->wdt, timer_margin);
+       pm_runtime_put_sync(omap_wdev->dev);
 
        return 0;
 }
 
-static ssize_t omap_wdt_write(struct file *file, const char __user *data,
-               size_t len, loff_t *ppos)
+static int omap_wdt_stop(struct watchdog_device *wdt_dev)
 {
-       struct omap_wdt_dev *wdev = file->private_data;
-
-       /* Refresh LOAD_TIME. */
-       if (len) {
-               pm_runtime_get_sync(wdev->dev);
-               spin_lock(&wdt_lock);
-               omap_wdt_ping(wdev);
-               spin_unlock(&wdt_lock);
-               pm_runtime_put_sync(wdev->dev);
-       }
-       return len;
-}
+       struct omap_wdt_drvdata *omap_wdev = watchdog_get_drvdata(wdt_dev);
 
-static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
-                                               unsigned long arg)
-{
-       struct omap_wdt_dev *wdev;
-       int new_margin;
-       static const struct watchdog_info ident = {
-               .identity = "OMAP Watchdog",
-               .options = WDIOF_SETTIMEOUT,
-               .firmware_version = 0,
-       };
-
-       wdev = file->private_data;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user((struct watchdog_info __user *)arg, &ident,
-                               sizeof(ident));
-       case WDIOC_GETSTATUS:
-               return put_user(0, (int __user *)arg);
-       case WDIOC_GETBOOTSTATUS:
-               if (cpu_is_omap16xx())
-                       return put_user(__raw_readw(ARM_SYSST),
-                                       (int __user *)arg);
-               if (cpu_is_omap24xx())
-                       return put_user(omap_prcm_get_reset_sources(),
-                                       (int __user *)arg);
-               return put_user(0, (int __user *)arg);
-       case WDIOC_KEEPALIVE:
-               pm_runtime_get_sync(wdev->dev);
-               spin_lock(&wdt_lock);
-               omap_wdt_ping(wdev);
-               spin_unlock(&wdt_lock);
-               pm_runtime_put_sync(wdev->dev);
-               return 0;
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_margin, (int __user *)arg))
-                       return -EFAULT;
-               omap_wdt_adjust_timeout(new_margin);
-
-               pm_runtime_get_sync(wdev->dev);
-               spin_lock(&wdt_lock);
-               omap_wdt_disable(wdev);
-               omap_wdt_set_timeout(wdev);
-               omap_wdt_enable(wdev);
-
-               omap_wdt_ping(wdev);
-               spin_unlock(&wdt_lock);
-               pm_runtime_put_sync(wdev->dev);
-               /* Fall */
-       case WDIOC_GETTIMEOUT:
-               return put_user(timer_margin, (int __user *)arg);
-       default:
-               return -ENOTTY;
-       }
+       pm_runtime_get_sync(omap_wdev->dev);
+       omap_wdt_disable(omap_wdev);
+       pm_runtime_put_sync(omap_wdev->dev);
+
+       return 0;
 }
 
-static const struct file_operations omap_wdt_fops = {
+static const struct watchdog_ops omap_wdt_ops = {
        .owner = THIS_MODULE,
-       .write = omap_wdt_write,
-       .unlocked_ioctl = omap_wdt_ioctl,
-       .open = omap_wdt_open,
-       .release = omap_wdt_release,
-       .llseek = no_llseek,
+       .start = omap_wdt_start,
+       .stop = omap_wdt_stop,
+       .ping = omap_wdt_ping,
+       .set_timeout = omap_wdt_set_timeout,
+};
+
+static const struct watchdog_info omap_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
+                  WDIOF_CARDRESET,
+       .identity = "Omap Watchdog",
 };
 
 static int __devinit omap_wdt_probe(struct platform_device *pdev)
 {
+       struct omap_wdt_drvdata *omap_drvdata;
+       struct watchdog_device *omap_wdev;
        struct resource *res, *mem;
-       struct omap_wdt_dev *wdev;
        int ret;
 
        /* reserve static register mappings */
@@ -286,68 +216,62 @@ static int __devinit omap_wdt_probe(struct 
platform_device *pdev)
                goto err_get_resource;
        }
 
-       if (omap_wdt_dev) {
-               ret = -EBUSY;
-               goto err_busy;
-       }
-
        mem = request_mem_region(res->start, resource_size(res), pdev->name);
        if (!mem) {
                ret = -EBUSY;
                goto err_busy;
        }
 
-       wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
-       if (!wdev) {
+       omap_drvdata = devm_kzalloc(&pdev->dev, sizeof(struct omap_wdt_drvdata),
+                              GFP_KERNEL);
+       if (!omap_drvdata) {
+               dev_err(&pdev->dev, "Unable to allocate watchdog device\n");
                ret = -ENOMEM;
                goto err_kzalloc;
        }
 
-       wdev->omap_wdt_users = 0;
-       wdev->mem = mem;
-       wdev->dev = &pdev->dev;
+       omap_drvdata->dev = &pdev->dev;
+       omap_wdev = &omap_drvdata->wdt;
+       omap_wdev->info = &omap_wdt_info;
+       omap_wdev->ops = &omap_wdt_ops;
+       omap_wdev->timeout = TIMER_MARGIN_DEFAULT;
+       omap_wdev->min_timeout = 1;
+       omap_wdev->max_timeout = TIMER_MARGIN_MAX;
+#ifdef CONFIG_WATCHDOG_NOWAYOUT
+       watchdog_set_nowayout(omap_wdev, true);
+#endif
+       watchdog_set_drvdata(omap_wdev, omap_drvdata);
 
-       wdev->base = ioremap(res->start, resource_size(res));
-       if (!wdev->base) {
+       omap_drvdata->base = ioremap(res->start, resource_size(res));
+       if (!omap_drvdata->base) {
                ret = -ENOMEM;
-               goto err_ioremap;
+               goto err_kzalloc;
        }
 
-       platform_set_drvdata(pdev, wdev);
-
-       pm_runtime_enable(wdev->dev);
-       pm_runtime_get_sync(wdev->dev);
-
-       omap_wdt_disable(wdev);
-       omap_wdt_adjust_timeout(timer_margin);
-
-       wdev->omap_wdt_miscdev.parent = &pdev->dev;
-       wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
-       wdev->omap_wdt_miscdev.name = "watchdog";
-       wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
-
-       ret = misc_register(&(wdev->omap_wdt_miscdev));
-       if (ret)
-               goto err_misc;
-
-       pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
-               __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
-               timer_margin);
-
-       pm_runtime_put_sync(wdev->dev);
-
-       omap_wdt_dev = pdev;
+       ret = watchdog_register_device(&omap_drvdata->wdt);
+       if (ret < 0)
+               goto err_register_wd;
+
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+       omap_wdt_disable(omap_drvdata);
+       pm_runtime_put_sync(&pdev->dev);
+       platform_set_drvdata(pdev, omap_drvdata);
+
+       /* For omap16xx we just keep it original as-is */
+       if (cpu_is_omap16xx())
+               omap_wdev->bootstatus = __raw_readw(ARM_SYSST);
+       else
+               omap_wdev->bootstatus = (omap_prcm_get_reset_sources() & 0x10)
+                                        >> OMAP3_PRM_RSTST_WD_BIT;
+       pr_info("OMAP WDTimer Rev 0x%02x: Initial timeout %dsec status= 0x%x\n",
+                __raw_readl(omap_drvdata->base + OMAP_WATCHDOG_REV)
+                & 0xFF, timer_margin, omap_wdev->bootstatus);
 
        return 0;
 
-err_misc:
-       pm_runtime_disable(wdev->dev);
-       platform_set_drvdata(pdev, NULL);
-       iounmap(wdev->base);
-
-err_ioremap:
-       wdev->base = NULL;
-       kfree(wdev);
+err_register_wd:
+       iounmap(omap_drvdata->base);
 
 err_kzalloc:
        release_mem_region(res->start, resource_size(res));
@@ -358,34 +282,17 @@ err_get_resource:
        return ret;
 }
 
-static void omap_wdt_shutdown(struct platform_device *pdev)
-{
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
-
-       if (wdev->omap_wdt_users) {
-               pm_runtime_get_sync(wdev->dev);
-               omap_wdt_disable(wdev);
-               pm_runtime_put_sync(wdev->dev);
-       }
-}
-
 static int __devexit omap_wdt_remove(struct platform_device *pdev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct omap_wdt_drvdata *omap_wdev = platform_get_drvdata(pdev);
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       pm_runtime_disable(wdev->dev);
-       if (!res)
-               return -ENOENT;
+       pm_runtime_disable(&pdev->dev);
 
-       misc_deregister(&(wdev->omap_wdt_miscdev));
        release_mem_region(res->start, resource_size(res));
        platform_set_drvdata(pdev, NULL);
 
-       iounmap(wdev->base);
-
-       kfree(wdev);
-       omap_wdt_dev = NULL;
+       iounmap(omap_wdev->base);
 
        return 0;
 }
@@ -400,12 +307,12 @@ static int __devexit omap_wdt_remove(struct 
platform_device *pdev)
 
 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_drvdata *omap_wdev = platform_get_drvdata(pdev);
 
-       if (wdev->omap_wdt_users) {
-               pm_runtime_get_sync(wdev->dev);
-               omap_wdt_disable(wdev);
-               pm_runtime_put_sync(wdev->dev);
+       if (test_bit(WDOG_DEV_OPEN, &omap_wdev->wdt.status)) {
+               pm_runtime_get_sync(&pdev->dev);
+               omap_wdt_disable(omap_wdev);
+               pm_runtime_put_sync(&pdev->dev);
        }
 
        return 0;
@@ -413,13 +320,12 @@ static int omap_wdt_suspend(struct platform_device *pdev, 
pm_message_t state)
 
 static int omap_wdt_resume(struct platform_device *pdev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
-
-       if (wdev->omap_wdt_users) {
-               pm_runtime_get_sync(wdev->dev);
-               omap_wdt_enable(wdev);
-               omap_wdt_ping(wdev);
-               pm_runtime_put_sync(wdev->dev);
+       struct omap_wdt_drvdata *omap_wdev = platform_get_drvdata(pdev);
+       if (test_bit(WDOG_DEV_OPEN, &omap_wdev->wdt.status)) {
+               pm_runtime_get_sync(&pdev->dev);
+               omap_wdt_enable(omap_wdev);
+               omap_wdt_ping(&omap_wdev->wdt);
+               pm_runtime_put_sync(&pdev->dev);
        }
 
        return 0;
@@ -433,7 +339,6 @@ static int omap_wdt_resume(struct platform_device *pdev)
 static struct platform_driver omap_wdt_driver = {
        .probe          = omap_wdt_probe,
        .remove         = __devexit_p(omap_wdt_remove),
-       .shutdown       = omap_wdt_shutdown,
        .suspend        = omap_wdt_suspend,
        .resume         = omap_wdt_resume,
        .driver         = {
@@ -446,5 +351,4 @@ module_platform_driver(omap_wdt_driver);
 
 MODULE_AUTHOR("George G. Davis");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS("platform:omap_wdt");
diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
index 09b774c..cf5f037 100644
--- a/drivers/watchdog/omap_wdt.h
+++ b/drivers/watchdog/omap_wdt.h
@@ -51,4 +51,9 @@
 #define PTV                    0       /* prescale */
 #define GET_WLDR_VAL(secs)     (0xffffffff - ((secs) * (32768/(1<<PTV))) + 1)
 
+/* MPU_WD_RST bit in PRM_RSTST show Omap WDTimer reset event.
+ * 0x0 = 0x0 : No watchdog reset.
+ * 0x1 = 0x1 : watchdog reset has occurred. */
+#define OMAP3_PRM_RSTST_WD_BIT         4
+
 #endif                         /* _OMAP_WATCHDOG_H */
-- 
1.7.5.4

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to