[WATCHDOG] add bcm47xx watchdog driver
[linux-2.6.git] / drivers / watchdog / mtx-1_wdt.c
index a8e6738..08e8a6a 100644 (file)
@@ -1,10 +1,11 @@
 /*
  *      Driver for the MTX-1 Watchdog.
  *
- *      (C) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
+ *      (C) Copyright 2005 4G Systems <info@4g-systems.biz>,
+ *                                                     All Rights Reserved.
  *                              http://www.4g-systems.biz
  *
- *     (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org>
+ *     (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org>
  *
  *      This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
 #include <linux/jiffies.h>
 #include <linux/watchdog.h>
 #include <linux/platform_device.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
 
 #include <asm/mach-au1x00/au1000.h>
-#include <asm/gpio.h>
 
 #define MTX1_WDT_INTERVAL      (5 * HZ)
 
@@ -59,6 +59,7 @@ static int ticks = 100 * HZ;
 
 static struct {
        struct completion stop;
+       spinlock_t lock;
        int running;
        struct timer_list timer;
        int queue;
@@ -71,6 +72,7 @@ static void mtx1_wdt_trigger(unsigned long unused)
 {
        u32 tmp;
 
+       spin_lock(&mtx1_wdt_device.lock);
        if (mtx1_wdt_device.running)
                ticks--;
        /*
@@ -79,13 +81,13 @@ static void mtx1_wdt_trigger(unsigned long unused)
        tmp = au_readl(GPIO2_DIR);
        tmp = (tmp & ~(1 << mtx1_wdt_device.gpio)) |
              ((~tmp) & (1 << mtx1_wdt_device.gpio));
-       au_writel (tmp, GPIO2_DIR);
+       au_writel(tmp, GPIO2_DIR);
 
        if (mtx1_wdt_device.queue && ticks)
                mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
-       else {
+       else
                complete(&mtx1_wdt_device.stop);
-       }
+       spin_unlock(&mtx1_wdt_device.lock);
 }
 
 static void mtx1_wdt_reset(void)
@@ -96,23 +98,29 @@ static void mtx1_wdt_reset(void)
 
 static void mtx1_wdt_start(void)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&mtx1_wdt_device.lock, flags);
        if (!mtx1_wdt_device.queue) {
                mtx1_wdt_device.queue = 1;
                gpio_set_value(mtx1_wdt_device.gpio, 1);
                mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
        }
        mtx1_wdt_device.running++;
+       spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags);
 }
 
 static int mtx1_wdt_stop(void)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&mtx1_wdt_device.lock, flags);
        if (mtx1_wdt_device.queue) {
                mtx1_wdt_device.queue = 0;
                gpio_set_value(mtx1_wdt_device.gpio, 0);
        }
-
        ticks = mtx1_wdt_device.default_ticks;
-
+       spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags);
        return 0;
 }
 
@@ -122,7 +130,6 @@ static int mtx1_wdt_open(struct inode *inode, struct file *file)
 {
        if (test_and_set_bit(0, &mtx1_wdt_device.inuse))
                return -EBUSY;
-
        return nonseekable_open(inode, file);
 }
 
@@ -133,54 +140,51 @@ static int mtx1_wdt_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long mtx1_wdt_ioctl(struct file *file, unsigned int cmd,
+                                                       unsigned long arg)
 {
        void __user *argp = (void __user *)arg;
+       int __user *p = (int __user *)argp;
        unsigned int value;
-       static struct watchdog_info ident =
-       {
+       static const struct watchdog_info ident = {
                .options = WDIOF_CARDRESET,
                .identity = "MTX-1 WDT",
        };
 
-       switch(cmd) {
-               case WDIOC_KEEPALIVE:
-                       mtx1_wdt_reset();
-                       break;
-               case WDIOC_GETSTATUS:
-               case WDIOC_GETBOOTSTATUS:
-                       if ( copy_to_user(argp, &value, sizeof(int)) )
-                               return -EFAULT;
-                       break;
-               case WDIOC_GETSUPPORT:
-                       if ( copy_to_user(argp, &ident, sizeof(ident)) )
-                               return -EFAULT;
-                       break;
-               case WDIOC_SETOPTIONS:
-                       if ( copy_from_user(&value, argp, sizeof(int)) )
-                               return -EFAULT;
-                       switch(value) {
-                               case WDIOS_ENABLECARD:
-                                       mtx1_wdt_start();
-                                       break;
-                               case WDIOS_DISABLECARD:
-                                       return mtx1_wdt_stop();
-                               default:
-                                       return -EINVAL;
-                       }
-                       break;
-               default:
-                       return -ENOTTY;
+       switch (cmd) {
+       case WDIOC_GETSUPPORT:
+               if (copy_to_user(argp, &ident, sizeof(ident)))
+                       return -EFAULT;
+               break;
+       case WDIOC_GETSTATUS:
+       case WDIOC_GETBOOTSTATUS:
+               put_user(0, p);
+               break;
+       case WDIOC_SETOPTIONS:
+               if (get_user(value, p))
+                       return -EFAULT;
+               if (value & WDIOS_ENABLECARD)
+                       mtx1_wdt_start();
+               else if (value & WDIOS_DISABLECARD)
+                       mtx1_wdt_stop();
+               else
+                       return -EINVAL;
+               return 0;
+       case WDIOC_KEEPALIVE:
+               mtx1_wdt_reset();
+               break;
+       default:
+               return -ENOTTY;
        }
        return 0;
 }
 
 
-static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+static ssize_t mtx1_wdt_write(struct file *file, const char *buf,
+                                               size_t count, loff_t *ppos)
 {
        if (!count)
                return -EIO;
-
        mtx1_wdt_reset();
        return count;
 }
@@ -188,49 +192,46 @@ static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count,
 static const struct file_operations mtx1_wdt_fops = {
        .owner          = THIS_MODULE,
        .llseek         = no_llseek,
-       .ioctl          = mtx1_wdt_ioctl,
+       .unlocked_ioctl = mtx1_wdt_ioctl,
        .open           = mtx1_wdt_open,
        .write          = mtx1_wdt_write,
-       .release        = mtx1_wdt_release
+       .release        = mtx1_wdt_release,
 };
 
 
 static struct miscdevice mtx1_wdt_misc = {
        .minor  = WATCHDOG_MINOR,
        .name   = "watchdog",
-       .fops   = &mtx1_wdt_fops
+       .fops   = &mtx1_wdt_fops,
 };
 
 
-static int mtx1_wdt_probe(struct platform_device *pdev)
+static int __devinit mtx1_wdt_probe(struct platform_device *pdev)
 {
        int ret;
 
        mtx1_wdt_device.gpio = pdev->resource[0].start;
 
-       if ((ret = misc_register(&mtx1_wdt_misc)) < 0) {
-               printk(KERN_ERR " mtx-1_wdt : failed to register\n");
-               return ret;
-       }
-
+       spin_lock_init(&mtx1_wdt_device.lock);
        init_completion(&mtx1_wdt_device.stop);
        mtx1_wdt_device.queue = 0;
-
        clear_bit(0, &mtx1_wdt_device.inuse);
-
        setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L);
-
        mtx1_wdt_device.default_ticks = ticks;
 
+       ret = misc_register(&mtx1_wdt_misc);
+       if (ret < 0) {
+               printk(KERN_ERR " mtx-1_wdt : failed to register\n");
+               return ret;
+       }
        mtx1_wdt_start();
-
        printk(KERN_INFO "MTX-1 Watchdog driver\n");
-
        return 0;
 }
 
-static int mtx1_wdt_remove(struct platform_device *pdev)
+static int __devexit mtx1_wdt_remove(struct platform_device *pdev)
 {
+       /* FIXME: do we need to lock this test ? */
        if (mtx1_wdt_device.queue) {
                mtx1_wdt_device.queue = 0;
                wait_for_completion(&mtx1_wdt_device.stop);
@@ -241,7 +242,7 @@ static int mtx1_wdt_remove(struct platform_device *pdev)
 
 static struct platform_driver mtx1_wdt = {
        .probe = mtx1_wdt_probe,
-       .remove = mtx1_wdt_remove,
+       .remove = __devexit_p(mtx1_wdt_remove),
        .driver.name = "mtx1-wdt",
        .driver.owner = THIS_MODULE,
 };