drm/nouveau: match U/DP script against SOR link
[safe/jmp/linux-2.6] / drivers / watchdog / bfin_wdt.c
index 03b3e3d..9042a95 100644 (file)
@@ -1,11 +1,10 @@
 /*
  * Blackfin On-Chip Watchdog Driver
- *  Supports BF53[123]/BF53[467]/BF54[2489]/BF561
  *
  * Originally based on softdog.c
- * Copyright 2006-2007 Analog Devices Inc.
+ * Copyright 2006-2010 Analog Devices Inc.
  * Copyright 2006-2007 Michele d'Amico
- * Copyright 1996 Alan Cox <alan@redhat.com>
+ * Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>
  *
  * Enter bugs at http://blackfin.uclinux.org/
  *
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/fs.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/uaccess.h>
 #include <asm/blackfin.h>
-#include <asm/uaccess.h>
+#include <asm/bfin_watchdog.h>
 
-#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
+#define stamp(fmt, args...) \
+       pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
 #define stampit() stamp("here i am")
-#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
-#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
+#define pr_devinit(fmt, args...) \
+       ({ static const __devinitconst char __fmt[] = fmt; \
+       printk(__fmt, ## args); })
+#define pr_init(fmt, args...) \
+       ({ static const __initconst char __fmt[] = fmt; \
+       printk(__fmt, ## args); })
 
 #define WATCHDOG_NAME "bfin-wdt"
 #define PFX WATCHDOG_NAME ": "
 # define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x)
 #endif
 
-/* Bit in SWRST that indicates boot caused by watchdog */
-#define SWRST_RESET_WDOG 0x4000
-
-/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */
-#define WDOG_EXPIRED 0x8000
-
-/* Masks for WDEV field in WDOG_CTL register */
-#define ICTL_RESET   0x0
-#define ICTL_NMI     0x2
-#define ICTL_GPI     0x4
-#define ICTL_NONE    0x6
-#define ICTL_MASK    0x6
-
-/* Masks for WDEN field in WDOG_CTL register */
-#define WDEN_MASK    0x0FF0
-#define WDEN_ENABLE  0x0000
-#define WDEN_DISABLE 0x0AD0
-
 /* some defaults */
 #define WATCHDOG_TIMEOUT 20
 
 static unsigned int timeout = WATCHDOG_TIMEOUT;
 static int nowayout = WATCHDOG_NOWAYOUT;
-static struct watchdog_info bfin_wdt_info;
+static const struct watchdog_info bfin_wdt_info;
 static unsigned long open_check;
 static char expect_close;
 static DEFINE_SPINLOCK(bfin_wdt_spinlock);
@@ -132,13 +117,15 @@ static int bfin_wdt_running(void)
  */
 static int bfin_wdt_set_timeout(unsigned long t)
 {
-       u32 cnt;
+       u32 cnt, max_t, sclk;
        unsigned long flags;
 
-       stampit();
+       sclk = get_sclk();
+       max_t = -1 / sclk;
+       cnt = t * sclk;
+       stamp("maxtimeout=%us newtimeout=%lus (cnt=%#x)", max_t, t, cnt);
 
-       cnt = t * get_sclk();
-       if (cnt < get_sclk()) {
+       if (t > max_t) {
                printk(KERN_WARNING PFX "timeout value is too large\n");
                return -EINVAL;
        }
@@ -148,7 +135,8 @@ static int bfin_wdt_set_timeout(unsigned long t)
                int run = bfin_wdt_running();
                bfin_wdt_stop();
                bfin_write_WDOG_CNT(cnt);
-               if (run) bfin_wdt_start();
+               if (run)
+                       bfin_wdt_start();
        }
        spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
 
@@ -191,16 +179,15 @@ static int bfin_wdt_release(struct inode *inode, struct file *file)
 {
        stampit();
 
-       if (expect_close == 42) {
+       if (expect_close == 42)
                bfin_wdt_stop();
-       } else {
-               printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+       else {
+               printk(KERN_CRIT PFX
+                       "Unexpected close, not stopping watchdog!\n");
                bfin_wdt_keepalive();
        }
-
        expect_close = 0;
        clear_bit(0, &open_check);
-
        return 0;
 }
 
@@ -214,7 +201,7 @@ static int bfin_wdt_release(struct inode *inode, struct file *file)
  *     Pings the watchdog on write.
  */
 static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
-                              size_t len, loff_t *ppos)
+                                               size_t len, loff_t *ppos)
 {
        stampit();
 
@@ -241,7 +228,6 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
 
 /**
  *     bfin_wdt_ioctl - Query Device
- *     @inode: inode of device
  *     @file: file handle of device
  *     @cmd: watchdog command
  *     @arg: argument
@@ -249,8 +235,8 @@ static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
  *     Query basic information from the device or ping it, as outlined by the
  *     watchdog API.
  */
-static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
-                          unsigned int cmd, unsigned long arg)
+static long bfin_wdt_ioctl(struct file *file,
+                               unsigned int cmd, unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
        int __user *p = argp;
@@ -258,80 +244,50 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
        stampit();
 
        switch (cmd) {
-               default:
-                       return -ENOTTY;
-
-               case WDIOC_GETSUPPORT:
-                       if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
-                               return -EFAULT;
-                       else
-                               return 0;
-
-               case WDIOC_GETSTATUS:
-               case WDIOC_GETBOOTSTATUS:
-                       return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
-
-               case WDIOC_KEEPALIVE:
-                       bfin_wdt_keepalive();
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
+                       return -EFAULT;
+               else
                        return 0;
-
-               case WDIOC_SETTIMEOUT: {
-                       int new_timeout;
-
-                       if (get_user(new_timeout, p))
-                               return -EFAULT;
-
-                       if (bfin_wdt_set_timeout(new_timeout))
-                               return -EINVAL;
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
+       case WDIOC_SETOPTIONS: {
+               unsigned long flags;
+               int options, ret = -EINVAL;
+
+               if (get_user(options, p))
+                       return -EFAULT;
+
+               spin_lock_irqsave(&bfin_wdt_spinlock, flags);
+               if (options & WDIOS_DISABLECARD) {
+                       bfin_wdt_stop();
+                       ret = 0;
                }
-                       /* Fall */
-               case WDIOC_GETTIMEOUT:
-                       return put_user(timeout, p);
-
-               case WDIOC_SETOPTIONS: {
-                       unsigned long flags;
-                       int options, ret = -EINVAL;
-
-                       if (get_user(options, p))
-                               return -EFAULT;
-
-                       spin_lock_irqsave(&bfin_wdt_spinlock, flags);
-
-                       if (options & WDIOS_DISABLECARD) {
-                               bfin_wdt_stop();
-                               ret = 0;
-                       }
-
-                       if (options & WDIOS_ENABLECARD) {
-                               bfin_wdt_start();
-                               ret = 0;
-                       }
-
-                       spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
-
-                       return ret;
+               if (options & WDIOS_ENABLECARD) {
+                       bfin_wdt_start();
+                       ret = 0;
                }
+               spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
+               return ret;
+       }
+       case WDIOC_KEEPALIVE:
+               bfin_wdt_keepalive();
+               return 0;
+       case WDIOC_SETTIMEOUT: {
+               int new_timeout;
+
+               if (get_user(new_timeout, p))
+                       return -EFAULT;
+               if (bfin_wdt_set_timeout(new_timeout))
+                       return -EINVAL;
+       }
+       /* Fall */
+       case WDIOC_GETTIMEOUT:
+               return put_user(timeout, p);
+       default:
+               return -ENOTTY;
        }
-}
-
-/**
- *     bfin_wdt_notify_sys - Notifier Handler
- *     @this: notifier block
- *     @code: notifier event
- *     @unused: unused
- *
- *     Handles specific events, such as turning off the watchdog during a
- *     shutdown event.
- */
-static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code,
-                               void *unused)
-{
-       stampit();
-
-       if (code == SYS_DOWN || code == SYS_HALT)
-               bfin_wdt_stop();
-
-       return NOTIFY_DONE;
 }
 
 #ifdef CONFIG_PM
@@ -379,12 +335,12 @@ static int bfin_wdt_resume(struct platform_device *pdev)
 #endif
 
 static const struct file_operations bfin_wdt_fops = {
-       .owner    = THIS_MODULE,
-       .llseek   = no_llseek,
-       .write    = bfin_wdt_write,
-       .ioctl    = bfin_wdt_ioctl,
-       .open     = bfin_wdt_open,
-       .release  = bfin_wdt_release,
+       .owner          = THIS_MODULE,
+       .llseek         = no_llseek,
+       .write          = bfin_wdt_write,
+       .unlocked_ioctl = bfin_wdt_ioctl,
+       .open           = bfin_wdt_open,
+       .release        = bfin_wdt_release,
 };
 
 static struct miscdevice bfin_wdt_miscdev = {
@@ -393,38 +349,28 @@ static struct miscdevice bfin_wdt_miscdev = {
        .fops     = &bfin_wdt_fops,
 };
 
-static struct watchdog_info bfin_wdt_info = {
+static const struct watchdog_info bfin_wdt_info = {
        .identity = "Blackfin Watchdog",
        .options  = WDIOF_SETTIMEOUT |
-                   WDIOF_KEEPALIVEPING |
-                   WDIOF_MAGICCLOSE,
-};
-
-static struct notifier_block bfin_wdt_notifier = {
-       .notifier_call = bfin_wdt_notify_sys,
+                   WDIOF_KEEPALIVEPING |
+                   WDIOF_MAGICCLOSE,
 };
 
 /**
  *     bfin_wdt_probe - Initialize module
  *
- *     Registers the misc device and notifier handler.  Actual device
+ *     Registers the misc device.  Actual device
  *     initialization is handled by bfin_wdt_open().
  */
 static int __devinit bfin_wdt_probe(struct platform_device *pdev)
 {
        int ret;
 
-       ret = register_reboot_notifier(&bfin_wdt_notifier);
-       if (ret) {
-               pr_devinit(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
-               return ret;
-       }
-
        ret = misc_register(&bfin_wdt_miscdev);
        if (ret) {
-               pr_devinit(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-                      WATCHDOG_MINOR, ret);
-               unregister_reboot_notifier(&bfin_wdt_notifier);
+               pr_devinit(KERN_ERR PFX
+                       "cannot register miscdev on minor=%d (err=%d)\n",
+                               WATCHDOG_MINOR, ret);
                return ret;
        }
 
@@ -437,21 +383,33 @@ static int __devinit bfin_wdt_probe(struct platform_device *pdev)
 /**
  *     bfin_wdt_remove - Initialize module
  *
- *     Unregisters the misc device and notifier handler.  Actual device
+ *     Unregisters the misc device.  Actual device
  *     deinitialization is handled by bfin_wdt_close().
  */
 static int __devexit bfin_wdt_remove(struct platform_device *pdev)
 {
        misc_deregister(&bfin_wdt_miscdev);
-       unregister_reboot_notifier(&bfin_wdt_notifier);
        return 0;
 }
 
+/**
+ *     bfin_wdt_shutdown - Soft Shutdown Handler
+ *
+ *     Handles the soft shutdown event.
+ */
+static void bfin_wdt_shutdown(struct platform_device *pdev)
+{
+       stampit();
+
+       bfin_wdt_stop();
+}
+
 static struct platform_device *bfin_wdt_device;
 
 static struct platform_driver bfin_wdt_driver = {
        .probe     = bfin_wdt_probe,
        .remove    = __devexit_p(bfin_wdt_remove),
+       .shutdown  = bfin_wdt_shutdown,
        .suspend   = bfin_wdt_suspend,
        .resume    = bfin_wdt_resume,
        .driver    = {
@@ -485,7 +443,8 @@ static int __init bfin_wdt_init(void)
                return ret;
        }
 
-       bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0);
+       bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME,
+                                                               -1, NULL, 0);
        if (IS_ERR(bfin_wdt_device)) {
                pr_init(KERN_ERR PFX "unable to register device\n");
                platform_driver_unregister(&bfin_wdt_driver);
@@ -516,7 +475,11 @@ MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 
 module_param(timeout, uint, 0);
-MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
+MODULE_PARM_DESC(timeout,
+       "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default="
+               __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
 
 module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+MODULE_PARM_DESC(nowayout,
+       "Watchdog cannot be stopped once started (default="
+               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");