]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/watchdog/orion5x_wdt.c
libertas: fix format warning
[mv-sheeva.git] / drivers / watchdog / orion5x_wdt.c
index b64ae1a17832c0e6dd53b045af77d805db005b86..7529616739d270cab0143e96b397c25e4aad4a60 100644 (file)
 #include <linux/kernel.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
+#include <linux/platform_device.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
+#include <plat/orion5x_wdt.h>
 
 /*
  * Watchdog timer block registers.
 #define  WDT_EN                        0x0010
 #define WDT_VAL                        (TIMER_VIRT_BASE + 0x0024)
 
-#define ORION5X_TCLK           166666667
-#define WDT_MAX_DURATION       (0xffffffff / ORION5X_TCLK)
+#define WDT_MAX_CYCLE_COUNT    0xffffffff
 #define WDT_IN_USE             0
 #define WDT_OK_TO_CLOSE                1
 
 static int nowayout = WATCHDOG_NOWAYOUT;
-static int heartbeat =  WDT_MAX_DURATION;      /* (seconds) */
+static int heartbeat = -1;             /* module parameter (seconds) */
+static unsigned int wdt_max_duration;  /* (seconds) */
+static unsigned int wdt_tclk;
 static unsigned long wdt_status;
 static spinlock_t wdt_lock;
 
-static void wdt_enable(void)
+static void orion5x_wdt_ping(void)
+{
+       spin_lock(&wdt_lock);
+
+       /* Reload watchdog duration */
+       writel(wdt_tclk * heartbeat, WDT_VAL);
+
+       spin_unlock(&wdt_lock);
+}
+
+static void orion5x_wdt_enable(void)
 {
        u32 reg;
 
        spin_lock(&wdt_lock);
 
        /* Set watchdog duration */
-       writel(ORION5X_TCLK * heartbeat, WDT_VAL);
+       writel(wdt_tclk * heartbeat, WDT_VAL);
 
        /* Clear watchdog timer interrupt */
        reg = readl(BRIDGE_CAUSE);
@@ -66,7 +79,7 @@ static void wdt_enable(void)
        spin_unlock(&wdt_lock);
 }
 
-static void wdt_disable(void)
+static void orion5x_wdt_disable(void)
 {
        u32 reg;
 
@@ -88,7 +101,7 @@ static void wdt_disable(void)
 static int orion5x_wdt_get_timeleft(int *time_left)
 {
        spin_lock(&wdt_lock);
-       *time_left = readl(WDT_VAL) / ORION5X_TCLK;
+       *time_left = readl(WDT_VAL) / wdt_tclk;
        spin_unlock(&wdt_lock);
        return 0;
 }
@@ -98,7 +111,7 @@ static int orion5x_wdt_open(struct inode *inode, struct file *file)
        if (test_and_set_bit(WDT_IN_USE, &wdt_status))
                return -EBUSY;
        clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
-       wdt_enable();
+       orion5x_wdt_enable();
        return nonseekable_open(inode, file);
 }
 
@@ -119,18 +132,28 @@ static ssize_t orion5x_wdt_write(struct file *file, const char *data,
                                        set_bit(WDT_OK_TO_CLOSE, &wdt_status);
                        }
                }
-               wdt_enable();
+               orion5x_wdt_ping();
        }
        return len;
 }
 
-static struct watchdog_info ident = {
+static int orion5x_wdt_settimeout(int new_time)
+{
+       if ((new_time <= 0) || (new_time > wdt_max_duration))
+               return -EINVAL;
+
+       /* Set new watchdog time to be used when
+        * orion5x_wdt_enable() or orion5x_wdt_ping() is called. */
+       heartbeat = new_time;
+       return 0;
+}
+
+static const struct watchdog_info ident = {
        .options        = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
                          WDIOF_KEEPALIVEPING,
        .identity       = "Orion5x Watchdog",
 };
 
-
 static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
                                unsigned long arg)
 {
@@ -149,7 +172,7 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
                break;
 
        case WDIOC_KEEPALIVE:
-               wdt_enable();
+               orion5x_wdt_ping();
                ret = 0;
                break;
 
@@ -158,12 +181,11 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
                if (ret)
                        break;
 
-               if (time <= 0 || time > WDT_MAX_DURATION) {
+               if (orion5x_wdt_settimeout(time)) {
                        ret = -EINVAL;
                        break;
                }
-               heartbeat = time;
-               wdt_enable();
+               orion5x_wdt_ping();
                /* Fall through */
 
        case WDIOC_GETTIMEOUT:
@@ -184,7 +206,7 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
 static int orion5x_wdt_release(struct inode *inode, struct file *file)
 {
        if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
-               wdt_disable();
+               orion5x_wdt_disable();
        else
                printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
                                        "timer will not stop\n");
@@ -210,23 +232,76 @@ static struct miscdevice orion5x_wdt_miscdev = {
        .fops           = &orion5x_wdt_fops,
 };
 
-static int __init orion5x_wdt_init(void)
+static int __devinit orion5x_wdt_probe(struct platform_device *pdev)
 {
+       struct orion5x_wdt_platform_data *pdata = pdev->dev.platform_data;
        int ret;
 
-       spin_lock_init(&wdt_lock);
+       if (pdata) {
+               wdt_tclk = pdata->tclk;
+       } else {
+               printk(KERN_ERR "Orion5x Watchdog misses platform data\n");
+               return -ENODEV;
+       }
+
+       if (orion5x_wdt_miscdev.parent)
+               return -EBUSY;
+       orion5x_wdt_miscdev.parent = &pdev->dev;
+
+       wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
+       if (orion5x_wdt_settimeout(heartbeat))
+               heartbeat = wdt_max_duration;
 
        ret = misc_register(&orion5x_wdt_miscdev);
-       if (ret == 0)
-               printk("Orion5x Watchdog Timer: heartbeat %d sec\n",
-                                                               heartbeat);
+       if (ret)
+               return ret;
+
+       printk(KERN_INFO "Orion5x Watchdog Timer: Initial timeout %d sec%s\n",
+                               heartbeat, nowayout ? ", nowayout" : "");
+       return 0;
+}
+
+static int __devexit orion5x_wdt_remove(struct platform_device *pdev)
+{
+       int ret;
+
+       if (test_bit(WDT_IN_USE, &wdt_status)) {
+               orion5x_wdt_disable();
+               clear_bit(WDT_IN_USE, &wdt_status);
+       }
+
+       ret = misc_deregister(&orion5x_wdt_miscdev);
+       if (!ret)
+               orion5x_wdt_miscdev.parent = NULL;
 
        return ret;
 }
 
+static void orion5x_wdt_shutdown(struct platform_device *pdev)
+{
+       if (test_bit(WDT_IN_USE, &wdt_status))
+               orion5x_wdt_disable();
+}
+
+static struct platform_driver orion5x_wdt_driver = {
+       .probe          = orion5x_wdt_probe,
+       .remove         = __devexit_p(orion5x_wdt_remove),
+       .shutdown       = orion5x_wdt_shutdown,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "orion5x_wdt",
+       },
+};
+
+static int __init orion5x_wdt_init(void)
+{
+       spin_lock_init(&wdt_lock);
+       return platform_driver_register(&orion5x_wdt_driver);
+}
+
 static void __exit orion5x_wdt_exit(void)
 {
-       misc_deregister(&orion5x_wdt_miscdev);
+       platform_driver_unregister(&orion5x_wdt_driver);
 }
 
 module_init(orion5x_wdt_init);
@@ -236,11 +311,11 @@ MODULE_AUTHOR("Sylver Bruneau <sylver.bruneau@googlemail.com>");
 MODULE_DESCRIPTION("Orion5x Processor Watchdog");
 
 module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default is "
-                                       __MODULE_STRING(WDT_MAX_DURATION) ")");
+MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds");
 
 module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                               __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);