]> Pileus Git - ~andy/linux/blobdiff - drivers/watchdog/davinci_wdt.c
Merge tag 'sound-3.14' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[~andy/linux] / drivers / watchdog / davinci_wdt.c
index 12591f6596efe54a2d9f58b3cf26547867440685..b1bae03742a9a6cf5a2c32e5746ecc520c45add9 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Watchdog driver for DaVinci DM644x/DM646x processors
  *
- * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2006-2013 Texas Instruments.
  *
  * 2007 (c) MontaVista Software, Inc. This file is licensed under
  * the terms of the GNU General Public License version 2. This program
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
-#include <linux/bitops.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/device.h>
 #include <linux/clk.h>
-#include <linux/slab.h>
 #include <linux/err.h>
 
 #define MODULE_NAME "DAVINCI-WDT: "
 #define WDKEY_SEQ0             (0xa5c6 << 16)
 #define WDKEY_SEQ1             (0xda7e << 16)
 
-static int heartbeat = DEFAULT_HEARTBEAT;
+static int heartbeat;
 
-static DEFINE_SPINLOCK(io_lock);
-static unsigned long wdt_status;
-#define WDT_IN_USE        0
-#define WDT_OK_TO_CLOSE   1
-#define WDT_REGION_INITED 2
-#define WDT_DEVICE_INITED 3
-
-static void __iomem    *wdt_base;
-struct clk             *wdt_clk;
-
-static void wdt_service(void)
-{
-       spin_lock(&io_lock);
-
-       /* put watchdog in service state */
-       iowrite32(WDKEY_SEQ0, wdt_base + WDTCR);
-       /* put watchdog in active state */
-       iowrite32(WDKEY_SEQ1, wdt_base + WDTCR);
-
-       spin_unlock(&io_lock);
-}
+/*
+ * struct to hold data for each WDT device
+ * @base - base io address of WD device
+ * @clk - source clock of WDT
+ * @wdd - hold watchdog device as is in WDT core
+ */
+struct davinci_wdt_device {
+       void __iomem            *base;
+       struct clk              *clk;
+       struct watchdog_device  wdd;
+};
 
-static void wdt_enable(void)
+static int davinci_wdt_start(struct watchdog_device *wdd)
 {
        u32 tgcr;
        u32 timer_margin;
        unsigned long wdt_freq;
+       struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
 
-       wdt_freq = clk_get_rate(wdt_clk);
-
-       spin_lock(&io_lock);
+       wdt_freq = clk_get_rate(davinci_wdt->clk);
 
        /* disable, internal clock source */
-       iowrite32(0, wdt_base + TCR);
+       iowrite32(0, davinci_wdt->base + TCR);
        /* reset timer, set mode to 64-bit watchdog, and unreset */
-       iowrite32(0, wdt_base + TGCR);
+       iowrite32(0, davinci_wdt->base + TGCR);
        tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
-       iowrite32(tgcr, wdt_base + TGCR);
+       iowrite32(tgcr, davinci_wdt->base + TGCR);
        /* clear counter regs */
-       iowrite32(0, wdt_base + TIM12);
-       iowrite32(0, wdt_base + TIM34);
+       iowrite32(0, davinci_wdt->base + TIM12);
+       iowrite32(0, davinci_wdt->base + TIM34);
        /* set timeout period */
-       timer_margin = (((u64)heartbeat * wdt_freq) & 0xffffffff);
-       iowrite32(timer_margin, wdt_base + PRD12);
-       timer_margin = (((u64)heartbeat * wdt_freq) >> 32);
-       iowrite32(timer_margin, wdt_base + PRD34);
+       timer_margin = (((u64)wdd->timeout * wdt_freq) & 0xffffffff);
+       iowrite32(timer_margin, davinci_wdt->base + PRD12);
+       timer_margin = (((u64)wdd->timeout * wdt_freq) >> 32);
+       iowrite32(timer_margin, davinci_wdt->base + PRD34);
        /* enable run continuously */
-       iowrite32(ENAMODE12_PERIODIC, wdt_base + TCR);
+       iowrite32(ENAMODE12_PERIODIC, davinci_wdt->base + TCR);
        /* Once the WDT is in pre-active state write to
         * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
         * write protected (except for the WDKEY field)
         */
        /* put watchdog in pre-active state */
-       iowrite32(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR);
+       iowrite32(WDKEY_SEQ0 | WDEN, davinci_wdt->base + WDTCR);
        /* put watchdog in active state */
-       iowrite32(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR);
-
-       spin_unlock(&io_lock);
+       iowrite32(WDKEY_SEQ1 | WDEN, davinci_wdt->base + WDTCR);
+       return 0;
 }
 
-static int davinci_wdt_open(struct inode *inode, struct file *file)
+static int davinci_wdt_ping(struct watchdog_device *wdd)
 {
-       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-               return -EBUSY;
-
-       wdt_enable();
+       struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
 
-       return nonseekable_open(inode, file);
+       /* put watchdog in service state */
+       iowrite32(WDKEY_SEQ0, davinci_wdt->base + WDTCR);
+       /* put watchdog in active state */
+       iowrite32(WDKEY_SEQ1, davinci_wdt->base + WDTCR);
+       return 0;
 }
 
-static ssize_t
-davinci_wdt_write(struct file *file, const char *data, size_t len,
-                 loff_t *ppos)
+static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd)
 {
-       if (len)
-               wdt_service();
+       u64 timer_counter;
+       unsigned long freq;
+       u32 val;
+       struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
 
-       return len;
-}
+       /* if timeout has occured then return 0 */
+       val = ioread32(davinci_wdt->base + WDTCR);
+       if (val & WDFLAG)
+               return 0;
 
-static const struct watchdog_info ident = {
-       .options = WDIOF_KEEPALIVEPING,
-       .identity = "DaVinci Watchdog",
-};
+       freq = clk_get_rate(davinci_wdt->clk);
 
-static long davinci_wdt_ioctl(struct file *file,
-                                       unsigned int cmd, unsigned long arg)
-{
-       int ret = -ENOTTY;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info *)arg, &ident,
-                                  sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               wdt_service();
-               ret = 0;
-               break;
-
-       case WDIOC_GETTIMEOUT:
-               ret = put_user(heartbeat, (int *)arg);
-               break;
-       }
-       return ret;
-}
+       if (!freq)
+               return 0;
 
-static int davinci_wdt_release(struct inode *inode, struct file *file)
-{
-       wdt_service();
-       clear_bit(WDT_IN_USE, &wdt_status);
+       timer_counter = ioread32(davinci_wdt->base + TIM12);
+       timer_counter |= ((u64)ioread32(davinci_wdt->base + TIM34) << 32);
 
-       return 0;
+       do_div(timer_counter, freq);
+
+       return wdd->timeout - timer_counter;
 }
 
-static const struct file_operations davinci_wdt_fops = {
-       .owner = THIS_MODULE,
-       .llseek = no_llseek,
-       .write = davinci_wdt_write,
-       .unlocked_ioctl = davinci_wdt_ioctl,
-       .open = davinci_wdt_open,
-       .release = davinci_wdt_release,
+static const struct watchdog_info davinci_wdt_info = {
+       .options = WDIOF_KEEPALIVEPING,
+       .identity = "DaVinci/Keystone Watchdog",
 };
 
-static struct miscdevice davinci_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &davinci_wdt_fops,
+static const struct watchdog_ops davinci_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = davinci_wdt_start,
+       .stop           = davinci_wdt_ping,
+       .ping           = davinci_wdt_ping,
+       .get_timeleft   = davinci_wdt_get_timeleft,
 };
 
 static int davinci_wdt_probe(struct platform_device *pdev)
@@ -204,37 +159,53 @@ static int davinci_wdt_probe(struct platform_device *pdev)
        int ret = 0;
        struct device *dev = &pdev->dev;
        struct resource  *wdt_mem;
+       struct watchdog_device *wdd;
+       struct davinci_wdt_device *davinci_wdt;
+
+       davinci_wdt = devm_kzalloc(dev, sizeof(*davinci_wdt), GFP_KERNEL);
+       if (!davinci_wdt)
+               return -ENOMEM;
 
-       wdt_clk = devm_clk_get(dev, NULL);
-       if (WARN_ON(IS_ERR(wdt_clk)))
-               return PTR_ERR(wdt_clk);
+       davinci_wdt->clk = devm_clk_get(dev, NULL);
+       if (WARN_ON(IS_ERR(davinci_wdt->clk)))
+               return PTR_ERR(davinci_wdt->clk);
 
-       clk_prepare_enable(wdt_clk);
+       clk_prepare_enable(davinci_wdt->clk);
 
-       if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
-               heartbeat = DEFAULT_HEARTBEAT;
+       platform_set_drvdata(pdev, davinci_wdt);
 
-       dev_info(dev, "heartbeat %d sec\n", heartbeat);
+       wdd                     = &davinci_wdt->wdd;
+       wdd->info               = &davinci_wdt_info;
+       wdd->ops                = &davinci_wdt_ops;
+       wdd->min_timeout        = 1;
+       wdd->max_timeout        = MAX_HEARTBEAT;
+       wdd->timeout            = DEFAULT_HEARTBEAT;
+
+       watchdog_init_timeout(wdd, heartbeat, dev);
+
+       dev_info(dev, "heartbeat %d sec\n", wdd->timeout);
+
+       watchdog_set_drvdata(wdd, davinci_wdt);
+       watchdog_set_nowayout(wdd, 1);
 
        wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt_base = devm_ioremap_resource(dev, wdt_mem);
-       if (IS_ERR(wdt_base))
-               return PTR_ERR(wdt_base);
+       davinci_wdt->base = devm_ioremap_resource(dev, wdt_mem);
+       if (IS_ERR(davinci_wdt->base))
+               return PTR_ERR(davinci_wdt->base);
 
-       ret = misc_register(&davinci_wdt_miscdev);
-       if (ret < 0) {
-               dev_err(dev, "cannot register misc device\n");
-       } else {
-               set_bit(WDT_DEVICE_INITED, &wdt_status);
-       }
+       ret = watchdog_register_device(wdd);
+       if (ret < 0)
+               dev_err(dev, "cannot register watchdog device\n");
 
        return ret;
 }
 
 static int davinci_wdt_remove(struct platform_device *pdev)
 {
-       misc_deregister(&davinci_wdt_miscdev);
-       clk_disable_unprepare(wdt_clk);
+       struct davinci_wdt_device *davinci_wdt = platform_get_drvdata(pdev);
+
+       watchdog_unregister_device(&davinci_wdt->wdd);
+       clk_disable_unprepare(davinci_wdt->clk);
 
        return 0;
 }