[WATCHDOG] add bcm47xx watchdog driver
[linux-2.6.git] / drivers / watchdog / bfin_wdt.c
index 31dc7a6..c7b3f9d 100644 (file)
@@ -5,7 +5,7 @@
  * Originally based on softdog.c
  * Copyright 2006-2007 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/reboot.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/uaccess.h>
 #include <asm/blackfin.h>
-#include <asm/uaccess.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 WATCHDOG_NAME "bfin-wdt"
 #define PFX WATCHDOG_NAME ": "
@@ -146,7 +153,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);
 
@@ -189,16 +197,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;
 }
 
@@ -212,7 +219,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();
 
@@ -239,7 +246,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
@@ -247,8 +253,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;
@@ -256,59 +262,49 @@ 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;
        }
 }
 
@@ -321,8 +317,8 @@ static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
  *     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)
+static int bfin_wdt_notify_sys(struct notifier_block *this,
+                                       unsigned long code, void *unused)
 {
        stampit();
 
@@ -376,27 +372,13 @@ static int bfin_wdt_resume(struct platform_device *pdev)
 # define bfin_wdt_resume NULL
 #endif
 
-static struct platform_device bfin_wdt_device = {
-       .name          = WATCHDOG_NAME,
-       .id            = -1,
-};
-
-static struct platform_driver bfin_wdt_driver = {
-       .driver    = {
-               .name  = WATCHDOG_NAME,
-               .owner = THIS_MODULE,
-       },
-       .suspend   = bfin_wdt_suspend,
-       .resume    = bfin_wdt_resume,
-};
-
-static 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,
+static const struct file_operations bfin_wdt_fops = {
+       .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 = {
@@ -408,8 +390,8 @@ static struct miscdevice bfin_wdt_miscdev = {
 static struct watchdog_info bfin_wdt_info = {
        .identity = "Blackfin Watchdog",
        .options  = WDIOF_SETTIMEOUT |
-                   WDIOF_KEEPALIVEPING |
-                   WDIOF_MAGICCLOSE,
+                   WDIOF_KEEPALIVEPING |
+                   WDIOF_MAGICCLOSE,
 };
 
 static struct notifier_block bfin_wdt_notifier = {
@@ -417,11 +399,69 @@ static struct notifier_block bfin_wdt_notifier = {
 };
 
 /**
- *     bfin_wdt_init - Initialize module
+ *     bfin_wdt_probe - Initialize module
  *
- *     Registers the device and notifier handler. Actual device
+ *     Registers the misc device and notifier handler.  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);
+               return ret;
+       }
+
+       pr_devinit(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
+              timeout, nowayout);
+
+       return 0;
+}
+
+/**
+ *     bfin_wdt_remove - Initialize module
+ *
+ *     Unregisters the misc device and notifier handler.  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;
+}
+
+static struct platform_device *bfin_wdt_device;
+
+static struct platform_driver bfin_wdt_driver = {
+       .probe     = bfin_wdt_probe,
+       .remove    = __devexit_p(bfin_wdt_remove),
+       .suspend   = bfin_wdt_suspend,
+       .resume    = bfin_wdt_resume,
+       .driver    = {
+               .name  = WATCHDOG_NAME,
+               .owner = THIS_MODULE,
+       },
+};
+
+/**
+ *     bfin_wdt_init - Initialize module
+ *
+ *     Checks the module params and registers the platform device & driver.
+ *     Real work is in the platform probe function.
+ */
 static int __init bfin_wdt_init(void)
 {
        int ret;
@@ -435,44 +475,33 @@ static int __init bfin_wdt_init(void)
        /* Since this is an on-chip device and needs no board-specific
         * resources, we'll handle all the platform device stuff here.
         */
-       ret = platform_device_register(&bfin_wdt_device);
-       if (ret)
-               return ret;
-
-       ret = platform_driver_probe(&bfin_wdt_driver, NULL);
-       if (ret)
-               return ret;
-
-       ret = register_reboot_notifier(&bfin_wdt_notifier);
+       ret = platform_driver_register(&bfin_wdt_driver);
        if (ret) {
-               printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
+               pr_init(KERN_ERR PFX "unable to register driver\n");
                return ret;
        }
 
-       ret = misc_register(&bfin_wdt_miscdev);
-       if (ret) {
-               printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
-                      WATCHDOG_MINOR, ret);
-               unregister_reboot_notifier(&bfin_wdt_notifier);
-               return ret;
+       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);
+               return PTR_ERR(bfin_wdt_device);
        }
 
-       printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
-              timeout, nowayout);
-
        return 0;
 }
 
 /**
  *     bfin_wdt_exit - Deinitialize module
  *
- *     Unregisters the device and notifier handler. Actual device
- *     deinitialization is handled by bfin_wdt_close().
+ *     Back out the platform device & driver steps.  Real work is in the
+ *     platform remove function.
  */
 static void __exit bfin_wdt_exit(void)
 {
-       misc_deregister(&bfin_wdt_miscdev);
-       unregister_reboot_notifier(&bfin_wdt_notifier);
+       platform_device_unregister(bfin_wdt_device);
+       platform_driver_unregister(&bfin_wdt_driver);
 }
 
 module_init(bfin_wdt_init);
@@ -484,7 +513,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) ")");