]> pilppa.com Git - linux-2.6-omap-h63xx.git/commitdiff
[PATCH] ARM: OMAP: WDT cleanups
authorDavid Brownell <dbrownell@users.sourceforge.net>
Tue, 26 Jul 2005 10:31:22 +0000 (03:31 -0700)
committerTony Lindgren <tony@atomide.com>
Tue, 26 Jul 2005 10:31:22 +0000 (03:31 -0700)
Various cleanups to the OMAP watchdog driver:

    * match other watchdog drivers
- file name is /dev/watchdog, as known by watchdog tools
- module alias as the watchdog miscdev (for KMOD)
- warn if the NOWAYOUT logic ever triggers
- default to 60 second timeout, per standard watchdog package
    * update limits:
- allow much larger timeouts than 32 seconds (up to 1 day)
- set up the prescaler (timeouts could trigger after months)
    * autogate the interface clock
    * misc stuff:
- comment updates
- move clock get/put to init/exit sections
- "sparse" fixes
- ... etc

So among other things the busybox "watchdog" command is now unlikely to
reboot right away using its default timeout, since the kernel default
is no longer so unusually short.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Tony Lindgren <tony@atomide.com>
drivers/char/watchdog/omap1610_wdt.c
drivers/char/watchdog/omap1610_wdt.h

index e610e40015494298c0c16ad62bacfcead893faa0..deae24fa5d8d1f3ffa6d2f93745c7a0d2dcf2a5f 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/omap1610_wdt.c
  *
- * Watchdog driver for the TI OMAP
+ * Watchdog driver for the TI OMAP 16xx 32KHz (non-secure) watchdog
  *
  * Author: MontaVista Software, Inc.
  *         <gdavis@mvista.com> or <source@mvista.com>
  *     Based on SoftDog driver by Alan Cox <alan@redhat.com>
  *
  * Copyright (c) 2004 Texas Instruments.
- *
- * 1. Modified to support OMAP1610 32-KHz watchdog timer
- * 2. Ported to 2.6 kernel
- *
- *
- * TODO:
- * 1. Need to disable watchdog when entering chip idle mode.
+ *     1. Modified to support OMAP1610 32-KHz watchdog timer
+ *     2. Ported to 2.6 kernel
  */
 
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/moduleparam.h>
+
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/hardware.h>
 #include <asm/bitops.h>
 #include <asm/hardware/clock.h>
 
-#include <linux/moduleparam.h>
 #include "omap1610_wdt.h"
 
-static int timer_margin;       /* in seconds */
-static int pre_margin;
+
+static unsigned timer_margin;
+module_param(timer_margin, uint, 0);
+MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
+
 static int omap_wdt_users;
-static struct clk *armwdt_ck = 0;
-static struct miscdevice omap_wdt_miscdev; /* Forward declaration */
+static struct clk *armwdt_ck = NULL;
 
 static unsigned int wdt_trgr_pattern = 0x1234;
 
@@ -64,7 +62,7 @@ omap_wdt_ping(void)
        wdt_trgr_pattern = ~wdt_trgr_pattern;
        omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
        while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08) ;        /* wait for posted write to complete */
-       return;
+       /* reloaded WCRR from WLDR */
 }
 
 static void
@@ -75,7 +73,6 @@ omap_wdt_enable(void)
        while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) ;
        omap_writel(0x4444, OMAP_WATCHDOG_SPR);
        while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10) ;
-       return;
 }
 
 static void
@@ -86,11 +83,32 @@ omap_wdt_disable(void)
        while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) ;
        omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
        while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10) ;
-       return;
 }
 
+static void
+omap_wdt_adjust_timeout(unsigned new_timeout)
+{
+       if (new_timeout < TIMER_MARGIN_MIN)
+               new_timeout = TIMER_MARGIN_DEFAULT;
+       if (new_timeout > TIMER_MARGIN_MAX)
+               new_timeout = TIMER_MARGIN_MAX;
+       timer_margin = new_timeout;
+}
+
+static void
+omap_wdt_set_timeout(void)
+{
+       u32     pre_margin = GET_WLDR_VAL(timer_margin);
+
+       /* just count up at 32 KHz */
+       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04) continue;
+       omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
+       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04) continue;
+}
+
+
 /*
- *     Allow only one person to hold it open
+ *     Allow only one task to hold it open
  */
 
 static int
@@ -99,17 +117,15 @@ omap_wdt_open(struct inode *inode, struct file *file)
        if (test_and_set_bit(1, (unsigned long *) &omap_wdt_users))
                return -EBUSY;
 
-       if (armwdt_ck == 0 || IS_ERR(armwdt_ck)) {
-               armwdt_ck = clk_get(omap_wdt_miscdev.dev, "armwdt_ck");
-               if (IS_ERR(armwdt_ck)) {
-                       omap_wdt_users = 0;
-                       return PTR_ERR(armwdt_ck);
-               }
-               clk_use(armwdt_ck);     /* Enable the clock */
-       }
+       clk_use(armwdt_ck);     /* Enable the clock */
 
-       omap_wdt_enable();
+       /* initialize prescaler */
+       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01) continue;
+       omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
+       while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01) continue;
 
+       omap_wdt_set_timeout();
+       omap_wdt_enable();
        return 0;
 }
 
@@ -117,32 +133,28 @@ static int
 omap_wdt_release(struct inode *inode, struct file *file)
 {
        /*
-        *      Shut off the timer.
-        *      Lock it in if it's a module and we defined ...NOWAYOUT
+        *      Shut off the timer unless NOWAYOUT is defined.
         */
 #ifndef CONFIG_WATCHDOG_NOWAYOUT
        omap_wdt_disable();
        clk_unuse(armwdt_ck);   /* Disable the clock */
        clk_put(armwdt_ck);
-       armwdt_ck = 0;
+       armwdt_ck = NULL;
+#else
+       printk(KERN_CRIT "omap1610_wdt: Unexpected close, not stopping!\n");
 #endif
        omap_wdt_users = 0;
        return 0;
 }
 
 static ssize_t
-omap_wdt_write(struct file *file, const char *data, size_t len, loff_t * ppos)
+omap_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;
-
        /* Refresh LOAD_TIME. */
-       if (len) {
+       if (len)
                omap_wdt_ping();
-               return 1;
-       }
-       return 0;
+       return len;
 }
 
 static int
@@ -160,52 +172,43 @@ omap_wdt_ioctl(struct inode *inode, struct file *file,
        default:
                return -ENOIOCTLCMD;
        case WDIOC_GETSUPPORT:
-               return copy_to_user((struct watchdog_info *) arg, &ident,
+               return copy_to_user((struct watchdog_info __user *) arg, &ident,
                                    sizeof (ident));
        case WDIOC_GETSTATUS:
-               return put_user(0, (int *) arg);
+               return put_user(0, (int __user *) arg);
        case WDIOC_GETBOOTSTATUS:
-               return put_user(omap_readw(ARM_SYSST), (int *) arg);
+               return put_user(omap_readw(ARM_SYSST), (int __user *) arg);
        case WDIOC_KEEPALIVE:
                omap_wdt_ping();
                return 0;
        case WDIOC_SETTIMEOUT:
-               if (get_user(new_margin, (int *) arg))
+               if (get_user(new_margin, (int __user *) arg))
                        return -EFAULT;
-               if ((new_margin < TIMER_MARGIN_MIN)
-                   || (new_margin > TIMER_MARGIN_MAX))
-                       timer_margin = TIMER_MARGIN_MAX;        /* default timeout */
-               else
-                       timer_margin = new_margin;
-               pre_margin = GET_WLDR_VAL(timer_margin);
+               omap_wdt_adjust_timeout(new_margin);
 
                omap_wdt_disable();
-
-               while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x04) ;        /* wait for posted write to complete */
-               omap_writel(pre_margin, (OMAP_WATCHDOG_LDR));
-               while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x04) ;        /* wait for posted write to complete */
-
+               omap_wdt_set_timeout();
                omap_wdt_enable();
 
                omap_wdt_ping();
                /* Fall */
        case WDIOC_GETTIMEOUT:
-               return put_user(timer_margin, (int *) arg);
+               return put_user(timer_margin, (int __user *) arg);
        }
 }
 
 static struct file_operations omap_wdt_fops = {
-       .owner = THIS_MODULE,
-       .write = omap_wdt_write,
-       .ioctl = omap_wdt_ioctl,
-       .open = omap_wdt_open,
-       .release = omap_wdt_release,
+       .owner          = THIS_MODULE,
+       .write          = omap_wdt_write,
+       .ioctl          = omap_wdt_ioctl,
+       .open           = omap_wdt_open,
+       .release        = omap_wdt_release,
 };
 
 static struct miscdevice omap_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "omap_wdt",
-       .fops = &omap_wdt_fops
+       .minor          = WATCHDOG_MINOR,
+       .name           = "watchdog",
+       .fops           = &omap_wdt_fops
 };
 
 static int __init
@@ -213,26 +216,38 @@ omap_wdt_init(void)
 {
        int ret;
 
-       ret = misc_register(&omap_wdt_miscdev);
-
-       if (ret)
-               return ret;
+       omap_wdt_users = 0;
+       armwdt_ck = clk_get(NULL, "armwdt_ck");
+       if (IS_ERR(armwdt_ck)) {
+               ret = PTR_ERR(armwdt_ck);
+               armwdt_ck = NULL;
+               goto fail;
+       }
 
        omap_wdt_disable();
+       omap_wdt_adjust_timeout(timer_margin);
 
-       if (timer_margin < 1 || timer_margin > 32)
-               timer_margin = 32;
+       ret = misc_register(&omap_wdt_miscdev);
+       if (ret)
+               goto fail;
 
-       printk(KERN_INFO "%s: TI OMAP Watchdog Timer: timer margin %d sec\n",
-              omap_wdt_miscdev.name, timer_margin);
+       pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
 
+       /* autogate OCP interface clock */
+       omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
        return 0;
+
+fail:
+       if (armwdt_ck)
+               clk_put(armwdt_ck);
+       return ret;
 }
 
 static void __exit
 omap_wdt_exit(void)
 {
        misc_deregister(&omap_wdt_miscdev);
+       clk_put(armwdt_ck);
 }
 
 module_init(omap_wdt_init);
@@ -240,4 +255,4 @@ module_exit(omap_wdt_exit);
 
 MODULE_AUTHOR("George G. Davis");
 MODULE_LICENSE("GPL");
-module_param(timer_margin, int, 0);
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index 48a0e80ef526678ec2ca752f0e99eccd3ba270fb..460d6569820eb6d1a9700430c863809eef921ef9 100644 (file)
 #define OMAP_WATCHDOG_WPS              (OMAP_WATCHDOG_BASE + 0x34)
 #define OMAP_WATCHDOG_SPR              (OMAP_WATCHDOG_BASE + 0x48)
 
-#define TIMER_MARGIN_MAX               32      /* Default is 32 seconds */
-#define TIMER_MARGIN_MIN               1
+/* Using the prescaler, the OMAP watchdog could go for many
+ * months before firing.  These limits work without scaling,
+ * with the 60 second default assumed by most tools and docs.
+ */
+#define TIMER_MARGIN_MAX       (24 * 60 * 60)  /* 1 day */
+#define TIMER_MARGIN_DEFAULT   60              /* 60 secs */
+#define TIMER_MARGIN_MIN       1
 
-#define GET_WLDR_VAL(x)                        (0xffffffff - ((x) * 32768)) + 1
+#define PTV                    0               /* prescale */
+#define GET_WLDR_VAL(secs)     (0xffffffff - ((secs) * (32768/(1<<PTV))) + 1)
 
 #endif                         /* _OMAP_WATCHDOG_H */