]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/watchdog/orion5x_wdt.c
ARM: OMAP: Enable idlemodes for DMA OCP
[linux-2.6-omap-h63xx.git] / drivers / watchdog / orion5x_wdt.c
index b64ae1a17832c0e6dd53b045af77d805db005b86..e81441f103dd8fa11fbd5e8a44f1647656cacae4 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;
 
@@ -46,7 +49,7 @@ static void wdt_enable(void)
        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);
@@ -88,7 +91,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;
 }
@@ -158,7 +161,7 @@ static long orion5x_wdt_ioctl(struct file *file, unsigned int cmd,
                if (ret)
                        break;
 
-               if (time <= 0 || time > WDT_MAX_DURATION) {
+               if (time <= 0 || time > wdt_max_duration) {
                        ret = -EINVAL;
                        break;
                }
@@ -210,23 +213,69 @@ 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 (heartbeat <= 0 || heartbeat > wdt_max_duration)
+               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)) {
+               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 struct platform_driver orion5x_wdt_driver = {
+       .probe          = orion5x_wdt_probe,
+       .remove         = __devexit_p(orion5x_wdt_remove),
+       .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,8 +285,7 @@ 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, "Watchdog heartbeat in seconds");
 
 module_param(nowayout, int, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");