Merge git://www.linux-watchdog.org/linux-watchdog
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 22 Dec 2012 01:10:29 +0000 (17:10 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 22 Dec 2012 01:10:29 +0000 (17:10 -0800)
Pull watchdog updates from Wim Van Sebroeck:
 "This includes some fixes and code improvements (like
  clk_prepare_enable and clk_disable_unprepare), conversion from the
  omap_wdt and twl4030_wdt drivers to the watchdog framework, addition
  of the SB8x0 chipset support and the DA9055 Watchdog driver and some
  OF support for the davinci_wdt driver."

* git://www.linux-watchdog.org/linux-watchdog: (22 commits)
  watchdog: mei: avoid oops in watchdog unregister code path
  watchdog: Orion: Fix possible null-deference in orion_wdt_probe
  watchdog: sp5100_tco: Add SB8x0 chipset support
  watchdog: davinci_wdt: add OF support
  watchdog: da9052: Fix invalid free of devm_ allocated data
  watchdog: twl4030_wdt: Change TWL4030_MODULE_PM_RECEIVER to TWL_MODULE_PM_RECEIVER
  watchdog: remove depends on CONFIG_EXPERIMENTAL
  watchdog: Convert dev_printk(KERN_<LEVEL> to dev_<level>(
  watchdog: DA9055 Watchdog driver
  watchdog: omap_wdt: eliminate goto
  watchdog: omap_wdt: delete redundant platform_set_drvdata() calls
  watchdog: omap_wdt: convert to devm_ functions
  watchdog: omap_wdt: convert to new watchdog core
  watchdog: WatchDog Timer Driver Core: fix comment
  watchdog: s3c2410_wdt: use clk_prepare_enable and clk_disable_unprepare
  watchdog: imx2_wdt: Select the driver via ARCH_MXC
  watchdog: cpu5wdt.c: add missing del_timer call
  watchdog: hpwdt.c: Increase version string
  watchdog: Convert twl4030_wdt to watchdog core
  davinci_wdt: preparation for switch to common clock framework
  ...

19 files changed:
Documentation/devicetree/bindings/watchdog/davinci-wdt.txt [new file with mode: 0644]
drivers/misc/mei/wd.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/ath79_wdt.c
drivers/watchdog/cpu5wdt.c
drivers/watchdog/da9052_wdt.c
drivers/watchdog/da9055_wdt.c [new file with mode: 0644]
drivers/watchdog/davinci_wdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/mpcore_wdt.c
drivers/watchdog/omap_wdt.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sp5100_tco.c
drivers/watchdog/sp5100_tco.h
drivers/watchdog/sp805_wdt.c
drivers/watchdog/twl4030_wdt.c
include/linux/watchdog.h

diff --git a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt
new file mode 100644 (file)
index 0000000..75558cc
--- /dev/null
@@ -0,0 +1,12 @@
+DaVinci Watchdog Timer (WDT) Controller
+
+Required properties:
+- compatible : Should be "ti,davinci-wdt"
+- reg : Should contain WDT registers location and length
+
+Examples:
+
+wdt: wdt@2320000 {
+       compatible = "ti,davinci-wdt";
+       reg = <0x02320000 0x80>;
+};
index 636409f9667f397c7ea3ea972fda636cf171e81d..9299a8c29a6fbe4846a06647955ea864ea1921de 100644 (file)
@@ -370,7 +370,7 @@ void mei_watchdog_register(struct mei_device *dev)
 
 void mei_watchdog_unregister(struct mei_device *dev)
 {
-       if (test_bit(WDOG_UNREGISTERED, &amt_wd_dev.status))
+       if (watchdog_get_drvdata(&amt_wd_dev) == NULL)
                return;
 
        watchdog_set_drvdata(&amt_wd_dev, NULL);
index ad1bb9382a964dc69af3caeb55e83ec8d5a9bde0..7f809fd4a57f950c94c3d5d280fe471f60ebeaf4 100644 (file)
@@ -76,6 +76,16 @@ config DA9052_WATCHDOG
           Alternatively say M to compile the driver as a module,
           which will be called da9052_wdt.
 
+config DA9055_WATCHDOG
+       tristate "Dialog Semiconductor DA9055 Watchdog"
+       depends on MFD_DA9055
+       help
+         If you say yes here you get support for watchdog on the Dialog
+         Semiconductor DA9055 PMIC.
+
+         This driver can also be built as a module.  If so, the module
+         will be called da9055_wdt.
+
 config WM831X_WATCHDOG
        tristate "WM831x watchdog"
        depends on MFD_WM831X
@@ -232,6 +242,7 @@ config EP93XX_WATCHDOG
 config OMAP_WATCHDOG
        tristate "OMAP Watchdog"
        depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
+       select WATCHDOG_CORE
        help
          Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog.  Say 'Y'
          here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
@@ -300,6 +311,7 @@ config COH901327_WATCHDOG
 config TWL4030_WATCHDOG
        tristate "TWL4030 Watchdog"
        depends on TWL4030_CORE
+       select WATCHDOG_CORE
        help
          Support for TI TWL4030 watchdog.  Say 'Y' here to enable the
          watchdog timer support for TWL4030 chips.
@@ -342,7 +354,7 @@ config MAX63XX_WATCHDOG
 
 config IMX2_WDT
        tristate "IMX2+ Watchdog"
-       depends on IMX_HAVE_PLATFORM_IMX2_WDT
+       depends on ARCH_MXC
        help
          This is the driver for the hardware watchdog
          on the Freescale IMX2 and later processors.
@@ -431,7 +443,7 @@ config ALIM7101_WDT
 
 config F71808E_WDT
        tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
-       depends on X86 && EXPERIMENTAL
+       depends on X86
        help
          This is the driver for the hardware watchdog on the Fintek
          F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
@@ -622,7 +634,7 @@ config IT8712F_WDT
 
 config IT87_WDT
        tristate "IT87 Watchdog Timer"
-       depends on X86 && EXPERIMENTAL
+       depends on X86
        ---help---
          This is the driver for the hardware watchdog on the ITE IT8702,
          IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728
index 572b39bed06a256ff6c79df0b943acbda7e88174..97bbdb3a464844588fa97e526b89eb284f302145 100644 (file)
@@ -164,6 +164,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o
 
 # Architecture Independent
 obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
+obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
 obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
 obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
 obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
index 7c8ede7816b1a1efacf9a196648bcfb2b5bc4c0c..38a999e60c0d7f26f03b2eac77f39e4b2296413a 100644 (file)
@@ -284,6 +284,7 @@ static void ath97_wdt_shutdown(struct platform_device *pdev)
 }
 
 static struct platform_driver ath79_wdt_driver = {
+       .probe          = ath79_wdt_probe,
        .remove         = ath79_wdt_remove,
        .shutdown       = ath97_wdt_shutdown,
        .driver         = {
@@ -292,17 +293,7 @@ static struct platform_driver ath79_wdt_driver = {
        },
 };
 
-static int __init ath79_wdt_init(void)
-{
-       return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe);
-}
-module_init(ath79_wdt_init);
-
-static void __exit ath79_wdt_exit(void)
-{
-       platform_driver_unregister(&ath79_wdt_driver);
-}
-module_exit(ath79_wdt_exit);
+module_platform_driver(ath79_wdt_driver);
 
 MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver");
 MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
index cd87758abac3154d3c411ed8b3ef9194a461f389..f270bb7bc4564126638200c270882da039219c88 100644 (file)
@@ -266,6 +266,7 @@ static void cpu5wdt_exit(void)
        if (cpu5wdt_device.queue) {
                cpu5wdt_device.queue = 0;
                wait_for_completion(&cpu5wdt_device.stop);
+               del_timer(&cpu5wdt_device.timer);
        }
 
        misc_deregister(&cpu5wdt_misc);
index 8be70d8f26809c0fb0a9e5828a3b7e230d9861c1..367445009c64b98e5361eda0082f01f9db4dd707 100644 (file)
@@ -53,10 +53,6 @@ static const struct {
 
 static void da9052_wdt_release_resources(struct kref *r)
 {
-       struct da9052_wdt_data *driver_data =
-               container_of(r, struct da9052_wdt_data, kref);
-
-       kfree(driver_data);
 }
 
 static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c
new file mode 100644 (file)
index 0000000..709ea1a
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * System monitoring driver for DA9055 PMICs.
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/delay.h>
+
+#include <linux/mfd/da9055/core.h>
+#include <linux/mfd/da9055/reg.h>
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+                "Watchdog cannot be stopped once started (default="
+                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define DA9055_DEF_TIMEOUT     4
+#define DA9055_TWDMIN          256
+
+struct da9055_wdt_data {
+       struct watchdog_device wdt;
+       struct da9055 *da9055;
+       struct kref kref;
+};
+
+static const struct {
+       u8 reg_val;
+       int user_time;  /* In seconds */
+} da9055_wdt_maps[] = {
+       { 0, 0 },
+       { 1, 2 },
+       { 2, 4 },
+       { 3, 8 },
+       { 4, 16 },
+       { 5, 32 },
+       { 5, 33 },  /* Actual time  32.768s so included both 32s and 33s */
+       { 6, 65 },
+       { 6, 66 },  /* Actual time 65.536s so include both, 65s and 66s */
+       { 7, 131 },
+};
+
+static int da9055_wdt_set_timeout(struct watchdog_device *wdt_dev,
+                                 unsigned int timeout)
+{
+       struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+       struct da9055 *da9055 = driver_data->da9055;
+       int ret, i;
+
+       for (i = 0; i < ARRAY_SIZE(da9055_wdt_maps); i++)
+               if (da9055_wdt_maps[i].user_time == timeout)
+                       break;
+
+       if (i == ARRAY_SIZE(da9055_wdt_maps))
+               ret = -EINVAL;
+       else
+               ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
+                                       DA9055_TWDSCALE_MASK,
+                                       da9055_wdt_maps[i].reg_val <<
+                                       DA9055_TWDSCALE_SHIFT);
+       if (ret < 0)
+               dev_err(da9055->dev,
+                       "Failed to update timescale bit, %d\n", ret);
+
+       wdt_dev->timeout = timeout;
+
+       return ret;
+}
+
+static int da9055_wdt_ping(struct watchdog_device *wdt_dev)
+{
+       struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+       struct da9055 *da9055 = driver_data->da9055;
+       int ret;
+
+       /*
+        * We have a minimum time for watchdog window called TWDMIN. A write
+        * to the watchdog before this elapsed time will cause an error.
+        */
+       mdelay(DA9055_TWDMIN);
+
+       /* Reset the watchdog timer */
+       ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_E,
+                               DA9055_WATCHDOG_MASK, 1);
+
+       return ret;
+}
+
+static void da9055_wdt_release_resources(struct kref *r)
+{
+       struct da9055_wdt_data *driver_data =
+               container_of(r, struct da9055_wdt_data, kref);
+
+       kfree(driver_data);
+}
+
+static void da9055_wdt_ref(struct watchdog_device *wdt_dev)
+{
+       struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+
+       kref_get(&driver_data->kref);
+}
+
+static void da9055_wdt_unref(struct watchdog_device *wdt_dev)
+{
+       struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+
+       kref_put(&driver_data->kref, da9055_wdt_release_resources);
+}
+
+static int da9055_wdt_start(struct watchdog_device *wdt_dev)
+{
+       return da9055_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+}
+
+static int da9055_wdt_stop(struct watchdog_device *wdt_dev)
+{
+       return da9055_wdt_set_timeout(wdt_dev, 0);
+}
+
+static struct watchdog_info da9055_wdt_info = {
+       .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity       = "DA9055 Watchdog",
+};
+
+static const struct watchdog_ops da9055_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = da9055_wdt_start,
+       .stop = da9055_wdt_stop,
+       .ping = da9055_wdt_ping,
+       .set_timeout = da9055_wdt_set_timeout,
+       .ref = da9055_wdt_ref,
+       .unref = da9055_wdt_unref,
+};
+
+static int da9055_wdt_probe(struct platform_device *pdev)
+{
+       struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
+       struct da9055_wdt_data *driver_data;
+       struct watchdog_device *da9055_wdt;
+       int ret;
+
+       driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
+                                  GFP_KERNEL);
+       if (!driver_data) {
+               dev_err(da9055->dev, "Failed to allocate watchdog device\n");
+               return -ENOMEM;
+       }
+
+       driver_data->da9055 = da9055;
+
+       da9055_wdt = &driver_data->wdt;
+
+       da9055_wdt->timeout = DA9055_DEF_TIMEOUT;
+       da9055_wdt->info = &da9055_wdt_info;
+       da9055_wdt->ops = &da9055_wdt_ops;
+       watchdog_set_nowayout(da9055_wdt, nowayout);
+       watchdog_set_drvdata(da9055_wdt, driver_data);
+
+       kref_init(&driver_data->kref);
+
+       ret = da9055_wdt_stop(da9055_wdt);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
+               goto err;
+       }
+
+       dev_set_drvdata(&pdev->dev, driver_data);
+
+       ret = watchdog_register_device(&driver_data->wdt);
+       if (ret != 0)
+               dev_err(da9055->dev, "watchdog_register_device() failed: %d\n",
+                       ret);
+
+err:
+       return ret;
+}
+
+static int da9055_wdt_remove(struct platform_device *pdev)
+{
+       struct da9055_wdt_data *driver_data = dev_get_drvdata(&pdev->dev);
+
+       watchdog_unregister_device(&driver_data->wdt);
+       kref_put(&driver_data->kref, da9055_wdt_release_resources);
+
+       return 0;
+}
+
+static struct platform_driver da9055_wdt_driver = {
+       .probe = da9055_wdt_probe,
+       .remove = da9055_wdt_remove,
+       .driver = {
+               .name   = "da9055-watchdog",
+       },
+};
+
+module_platform_driver(da9055_wdt_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9055 watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9055-watchdog");
index 8791879e5181d08ee8218cb9c0a1df20acfe1f8c..e8e87246ea6d9dfe722564ce0199b5b2868363a4 100644 (file)
@@ -208,7 +208,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
        if (WARN_ON(IS_ERR(wdt_clk)))
                return PTR_ERR(wdt_clk);
 
-       clk_enable(wdt_clk);
+       clk_prepare_enable(wdt_clk);
 
        if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
                heartbeat = DEFAULT_HEARTBEAT;
@@ -256,16 +256,23 @@ static int davinci_wdt_remove(struct platform_device *pdev)
                wdt_mem = NULL;
        }
 
-       clk_disable(wdt_clk);
+       clk_disable_unprepare(wdt_clk);
        clk_put(wdt_clk);
 
        return 0;
 }
 
+static const struct of_device_id davinci_wdt_of_match[] = {
+       { .compatible = "ti,davinci-wdt", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, davinci_wdt_of_match);
+
 static struct platform_driver platform_wdt_driver = {
        .driver = {
                .name = "watchdog",
                .owner  = THIS_MODULE,
+               .of_match_table = davinci_wdt_of_match,
        },
        .probe = davinci_wdt_probe,
        .remove = davinci_wdt_remove,
index 8717255ec7be07367c9c5c5dd3fc47bf0b301dc6..11796b9b864eb000e3fba1b0b6a94984d8324232 100644 (file)
@@ -39,7 +39,7 @@
 #endif /* CONFIG_HPWDT_NMI_DECODING */
 #include <asm/nmi.h>
 
-#define HPWDT_VERSION                  "1.3.0"
+#define HPWDT_VERSION                  "1.3.1"
 #define SECS_TO_TICKS(secs)            ((secs) * 1000 / 128)
 #define TICKS_TO_SECS(ticks)           ((ticks) * 128 / 1000)
 #define HPWDT_MAX_TIMER                        TICKS_TO_SECS(65535)
index a84eb551ea2742f08ef977ab45a774021a0b71e4..233cfadcb21f55538310f938ff037b0dbd236225 100644 (file)
@@ -80,8 +80,7 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
 
        /* Check it really was our interrupt */
        if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
-               dev_printk(KERN_CRIT, wdt->dev,
-                                       "Triggered - Reboot ignored.\n");
+               dev_crit(wdt->dev, "Triggered - Reboot ignored\n");
                /* Clear the interrupt on the watchdog */
                writel(1, wdt->base + TWD_WDOG_INTSTAT);
                return IRQ_HANDLED;
@@ -123,7 +122,7 @@ static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
 
 static void mpcore_wdt_start(struct mpcore_wdt *wdt)
 {
-       dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
+       dev_info(wdt->dev, "enabling watchdog\n");
 
        /* This loads the count register but does NOT start the count yet */
        mpcore_wdt_keepalive(wdt);
@@ -180,8 +179,8 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
        if (wdt->expect_close == 42)
                mpcore_wdt_stop(wdt);
        else {
-               dev_printk(KERN_CRIT, wdt->dev,
-                               "unexpected close, not stopping watchdog!\n");
+               dev_crit(wdt->dev,
+                        "unexpected close, not stopping watchdog!\n");
                mpcore_wdt_keepalive(wdt);
        }
        clear_bit(0, &wdt->timer_alive);
@@ -351,9 +350,9 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
                ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
                                "mpcore_wdt", wdt);
                if (ret) {
-                       dev_printk(KERN_ERR, wdt->dev,
-                                       "cannot register IRQ%d for watchdog\n",
-                                       wdt->irq);
+                       dev_err(wdt->dev,
+                               "cannot register IRQ%d for watchdog\n",
+                               wdt->irq);
                        return ret;
                }
        }
@@ -365,9 +364,9 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
        mpcore_wdt_miscdev.parent = &pdev->dev;
        ret = misc_register(&mpcore_wdt_miscdev);
        if (ret) {
-               dev_printk(KERN_ERR, wdt->dev,
+               dev_err(wdt->dev,
                        "cannot register miscdev on minor=%d (err=%d)\n",
-                                                       WATCHDOG_MINOR, ret);
+                       WATCHDOG_MINOR, ret);
                return ret;
        }
 
index 3e3ebbc83fafe8ba194470c0da8d9fe862897684..34ed61ea02b46c86e348970c4bbd39d3724f320f 100644 (file)
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/mm.h>
-#include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
 #include <linux/moduleparam.h>
-#include <linux/bitops.h>
 #include <linux/io.h>
-#include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/omap-wd-timer.h>
 
 #include "omap_wdt.h"
 
-static struct platform_device *omap_wdt_dev;
-
 static unsigned timer_margin;
 module_param(timer_margin, uint, 0);
 MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
 
-static unsigned int wdt_trgr_pattern = 0x1234;
-static DEFINE_SPINLOCK(wdt_lock);
-
 struct omap_wdt_dev {
        void __iomem    *base;          /* physical */
        struct device   *dev;
-       int             omap_wdt_users;
+       bool            omap_wdt_users;
        struct resource *mem;
-       struct miscdevice omap_wdt_miscdev;
+       int             wdt_trgr_pattern;
+       struct mutex    lock;           /* to avoid races with PM */
 };
 
-static void omap_wdt_ping(struct omap_wdt_dev *wdev)
+static void omap_wdt_reload(struct omap_wdt_dev *wdev)
 {
        void __iomem    *base = wdev->base;
 
@@ -74,8 +66,8 @@ static void omap_wdt_ping(struct omap_wdt_dev *wdev)
        while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
                cpu_relax();
 
-       wdt_trgr_pattern = ~wdt_trgr_pattern;
-       __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
+       wdev->wdt_trgr_pattern = ~wdev->wdt_trgr_pattern;
+       __raw_writel(wdev->wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
 
        /* wait for posted write to complete */
        while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
@@ -111,18 +103,10 @@ static void omap_wdt_disable(struct omap_wdt_dev *wdev)
                cpu_relax();
 }
 
-static void omap_wdt_adjust_timeout(unsigned new_timeout)
-{
-       if (new_timeout < TIMER_MARGIN_MIN)
-               new_timeout = TIMER_MARGIN_DEFAULT;
-       if (new_timeout > TIMER_MARGIN_MAX)
-               new_timeout = TIMER_MARGIN_MAX;
-       timer_margin = new_timeout;
-}
-
-static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
+static void omap_wdt_set_timer(struct omap_wdt_dev *wdev,
+                                  unsigned int timeout)
 {
-       u32 pre_margin = GET_WLDR_VAL(timer_margin);
+       u32 pre_margin = GET_WLDR_VAL(timeout);
        void __iomem *base = wdev->base;
 
        /* just count up at 32 KHz */
@@ -134,16 +118,14 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
                cpu_relax();
 }
 
-/*
- *     Allow only one task to hold it open
- */
-static int omap_wdt_open(struct inode *inode, struct file *file)
+static int omap_wdt_start(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
        void __iomem *base = wdev->base;
 
-       if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
-               return -EBUSY;
+       mutex_lock(&wdev->lock);
+
+       wdev->omap_wdt_users = true;
 
        pm_runtime_get_sync(wdev->dev);
 
@@ -155,223 +137,169 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
        while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
                cpu_relax();
 
-       file->private_data = (void *) wdev;
-
-       omap_wdt_set_timeout(wdev);
-       omap_wdt_ping(wdev); /* trigger loading of new timeout value */
+       omap_wdt_set_timer(wdev, wdog->timeout);
+       omap_wdt_reload(wdev); /* trigger loading of new timeout value */
        omap_wdt_enable(wdev);
 
-       return nonseekable_open(inode, file);
+       mutex_unlock(&wdev->lock);
+
+       return 0;
 }
 
-static int omap_wdt_release(struct inode *inode, struct file *file)
+static int omap_wdt_stop(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = file->private_data;
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
-       /*
-        *      Shut off the timer unless NOWAYOUT is defined.
-        */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
+       mutex_lock(&wdev->lock);
        omap_wdt_disable(wdev);
-
        pm_runtime_put_sync(wdev->dev);
-#else
-       pr_crit("Unexpected close, not stopping!\n");
-#endif
-       wdev->omap_wdt_users = 0;
-
+       wdev->omap_wdt_users = false;
+       mutex_unlock(&wdev->lock);
        return 0;
 }
 
-static ssize_t omap_wdt_write(struct file *file, const char __user *data,
-               size_t len, loff_t *ppos)
+static int omap_wdt_ping(struct watchdog_device *wdog)
 {
-       struct omap_wdt_dev *wdev = file->private_data;
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
-       /* Refresh LOAD_TIME. */
-       if (len) {
-               spin_lock(&wdt_lock);
-               omap_wdt_ping(wdev);
-               spin_unlock(&wdt_lock);
-       }
-       return len;
+       mutex_lock(&wdev->lock);
+       omap_wdt_reload(wdev);
+       mutex_unlock(&wdev->lock);
+
+       return 0;
 }
 
-static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
-                                               unsigned long arg)
+static int omap_wdt_set_timeout(struct watchdog_device *wdog,
+                               unsigned int timeout)
 {
-       struct omap_wd_timer_platform_data *pdata;
-       struct omap_wdt_dev *wdev;
-       u32 rs;
-       int new_margin, bs;
-       static const struct watchdog_info ident = {
-               .identity = "OMAP Watchdog",
-               .options = WDIOF_SETTIMEOUT,
-               .firmware_version = 0,
-       };
-
-       wdev = file->private_data;
-       pdata = wdev->dev->platform_data;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user((struct watchdog_info __user *)arg, &ident,
-                               sizeof(ident));
-       case WDIOC_GETSTATUS:
-               return put_user(0, (int __user *)arg);
-       case WDIOC_GETBOOTSTATUS:
-               if (!pdata || !pdata->read_reset_sources)
-                       return put_user(0, (int __user *)arg);
-               rs = pdata->read_reset_sources();
-               bs = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
-                       WDIOF_CARDRESET : 0;
-               return put_user(bs, (int __user *)arg);
-       case WDIOC_KEEPALIVE:
-               spin_lock(&wdt_lock);
-               omap_wdt_ping(wdev);
-               spin_unlock(&wdt_lock);
-               return 0;
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_margin, (int __user *)arg))
-                       return -EFAULT;
-               omap_wdt_adjust_timeout(new_margin);
-
-               spin_lock(&wdt_lock);
-               omap_wdt_disable(wdev);
-               omap_wdt_set_timeout(wdev);
-               omap_wdt_enable(wdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
-               omap_wdt_ping(wdev);
-               spin_unlock(&wdt_lock);
-               /* Fall */
-       case WDIOC_GETTIMEOUT:
-               return put_user(timer_margin, (int __user *)arg);
-       default:
-               return -ENOTTY;
-       }
+       mutex_lock(&wdev->lock);
+       omap_wdt_disable(wdev);
+       omap_wdt_set_timer(wdev, timeout);
+       omap_wdt_enable(wdev);
+       omap_wdt_reload(wdev);
+       wdog->timeout = timeout;
+       mutex_unlock(&wdev->lock);
+
+       return 0;
 }
 
-static const struct file_operations omap_wdt_fops = {
-       .owner = THIS_MODULE,
-       .write = omap_wdt_write,
-       .unlocked_ioctl = omap_wdt_ioctl,
-       .open = omap_wdt_open,
-       .release = omap_wdt_release,
-       .llseek = no_llseek,
+static const struct watchdog_info omap_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity = "OMAP Watchdog",
+};
+
+static const struct watchdog_ops omap_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = omap_wdt_start,
+       .stop           = omap_wdt_stop,
+       .ping           = omap_wdt_ping,
+       .set_timeout    = omap_wdt_set_timeout,
 };
 
 static int omap_wdt_probe(struct platform_device *pdev)
 {
+       struct omap_wd_timer_platform_data *pdata = pdev->dev.platform_data;
+       bool nowayout = WATCHDOG_NOWAYOUT;
+       struct watchdog_device *omap_wdt;
        struct resource *res, *mem;
        struct omap_wdt_dev *wdev;
+       u32 rs;
        int ret;
 
+       omap_wdt = devm_kzalloc(&pdev->dev, sizeof(*omap_wdt), GFP_KERNEL);
+       if (!omap_wdt)
+               return -ENOMEM;
+
        /* reserve static register mappings */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENOENT;
-               goto err_get_resource;
-       }
+       if (!res)
+               return -ENOENT;
 
-       if (omap_wdt_dev) {
-               ret = -EBUSY;
-               goto err_busy;
-       }
+       mem = devm_request_mem_region(&pdev->dev, res->start,
+                                     resource_size(res), pdev->name);
+       if (!mem)
+               return -EBUSY;
 
-       mem = request_mem_region(res->start, resource_size(res), pdev->name);
-       if (!mem) {
-               ret = -EBUSY;
-               goto err_busy;
-       }
+       wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
+       if (!wdev)
+               return -ENOMEM;
 
-       wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
-       if (!wdev) {
-               ret = -ENOMEM;
-               goto err_kzalloc;
-       }
+       wdev->omap_wdt_users    = false;
+       wdev->mem               = mem;
+       wdev->dev               = &pdev->dev;
+       wdev->wdt_trgr_pattern  = 0x1234;
+       mutex_init(&wdev->lock);
 
-       wdev->omap_wdt_users = 0;
-       wdev->mem = mem;
-       wdev->dev = &pdev->dev;
+       wdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+       if (!wdev->base)
+               return -ENOMEM;
 
-       wdev->base = ioremap(res->start, resource_size(res));
-       if (!wdev->base) {
-               ret = -ENOMEM;
-               goto err_ioremap;
-       }
+       omap_wdt->info        = &omap_wdt_info;
+       omap_wdt->ops         = &omap_wdt_ops;
+       omap_wdt->min_timeout = TIMER_MARGIN_MIN;
+       omap_wdt->max_timeout = TIMER_MARGIN_MAX;
+
+       if (timer_margin >= TIMER_MARGIN_MIN &&
+           timer_margin <= TIMER_MARGIN_MAX)
+               omap_wdt->timeout = timer_margin;
+       else
+               omap_wdt->timeout = TIMER_MARGIN_DEFAULT;
 
-       platform_set_drvdata(pdev, wdev);
+       watchdog_set_drvdata(omap_wdt, wdev);
+       watchdog_set_nowayout(omap_wdt, nowayout);
+
+       platform_set_drvdata(pdev, omap_wdt);
 
        pm_runtime_enable(wdev->dev);
        pm_runtime_get_sync(wdev->dev);
 
-       omap_wdt_disable(wdev);
-       omap_wdt_adjust_timeout(timer_margin);
+       if (pdata && pdata->read_reset_sources)
+               rs = pdata->read_reset_sources();
+       else
+               rs = 0;
+       omap_wdt->bootstatus = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
+                               WDIOF_CARDRESET : 0;
 
-       wdev->omap_wdt_miscdev.parent = &pdev->dev;
-       wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
-       wdev->omap_wdt_miscdev.name = "watchdog";
-       wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
+       omap_wdt_disable(wdev);
 
-       ret = misc_register(&(wdev->omap_wdt_miscdev));
-       if (ret)
-               goto err_misc;
+       ret = watchdog_register_device(omap_wdt);
+       if (ret) {
+               pm_runtime_disable(wdev->dev);
+               return ret;
+       }
 
        pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
                __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
-               timer_margin);
+               omap_wdt->timeout);
 
        pm_runtime_put_sync(wdev->dev);
 
-       omap_wdt_dev = pdev;
-
        return 0;
-
-err_misc:
-       pm_runtime_disable(wdev->dev);
-       platform_set_drvdata(pdev, NULL);
-       iounmap(wdev->base);
-
-err_ioremap:
-       wdev->base = NULL;
-       kfree(wdev);
-
-err_kzalloc:
-       release_mem_region(res->start, resource_size(res));
-
-err_busy:
-err_get_resource:
-
-       return ret;
 }
 
 static void omap_wdt_shutdown(struct platform_device *pdev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
+       mutex_lock(&wdev->lock);
        if (wdev->omap_wdt_users) {
                omap_wdt_disable(wdev);
                pm_runtime_put_sync(wdev->dev);
        }
+       mutex_unlock(&wdev->lock);
 }
 
 static int omap_wdt_remove(struct platform_device *pdev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        pm_runtime_disable(wdev->dev);
-       if (!res)
-               return -ENOENT;
-
-       misc_deregister(&(wdev->omap_wdt_miscdev));
-       release_mem_region(res->start, resource_size(res));
-       platform_set_drvdata(pdev, NULL);
-
-       iounmap(wdev->base);
-
-       kfree(wdev);
-       omap_wdt_dev = NULL;
+       watchdog_unregister_device(wdog);
 
        return 0;
 }
@@ -386,25 +314,31 @@ static int omap_wdt_remove(struct platform_device *pdev)
 
 static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
+       mutex_lock(&wdev->lock);
        if (wdev->omap_wdt_users) {
                omap_wdt_disable(wdev);
                pm_runtime_put_sync(wdev->dev);
        }
+       mutex_unlock(&wdev->lock);
 
        return 0;
 }
 
 static int omap_wdt_resume(struct platform_device *pdev)
 {
-       struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
 
+       mutex_lock(&wdev->lock);
        if (wdev->omap_wdt_users) {
                pm_runtime_get_sync(wdev->dev);
                omap_wdt_enable(wdev);
-               omap_wdt_ping(wdev);
+               omap_wdt_reload(wdev);
        }
+       mutex_unlock(&wdev->lock);
 
        return 0;
 }
@@ -437,5 +371,4 @@ module_platform_driver(omap_wdt_driver);
 
 MODULE_AUTHOR("George G. Davis");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS("platform:omap_wdt");
index 0478b001b1efbb1621613e07b438fa4bbad7cf32..7c18b3bffcf74ab0845fb8796659d297c618e6ed 100644 (file)
@@ -156,6 +156,8 @@ static int orion_wdt_probe(struct platform_device *pdev)
        wdt_tclk = clk_get_rate(clk);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
        wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
        if (!wdt_reg)
                return -ENOMEM;
index b0dab10fc6a5122a2947addcf78238a30476a5a9..27bcd4e2c4a4f3b2063aa2f38a4fc6927f0e565d 100644 (file)
@@ -354,7 +354,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
                goto err_map;
        }
 
-       clk_enable(wdt_clock);
+       clk_prepare_enable(wdt_clock);
 
        ret = s3c2410wdt_cpufreq_register();
        if (ret < 0) {
@@ -421,7 +421,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        s3c2410wdt_cpufreq_deregister();
 
  err_clk:
-       clk_disable(wdt_clock);
+       clk_disable_unprepare(wdt_clock);
        clk_put(wdt_clock);
        wdt_clock = NULL;
 
@@ -445,7 +445,7 @@ static int s3c2410wdt_remove(struct platform_device *dev)
 
        s3c2410wdt_cpufreq_deregister();
 
-       clk_disable(wdt_clock);
+       clk_disable_unprepare(wdt_clock);
        clk_put(wdt_clock);
        wdt_clock = NULL;
 
index b3876812ff075327a57cb33d55f7c9c684fa9dcc..2b0e000d4377de2714cbadcfb557c32c33a16321 100644 (file)
@@ -13,7 +13,9 @@
  *     as published by the Free Software Foundation; either version
  *     2 of the License, or (at your option) any later version.
  *
- *     See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide"
+ *     See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide",
+ *         AMD Publication 45482 "AMD SB800-Series Southbridges Register
+ *                                                           Reference Guide"
  */
 
 /*
 #include "sp5100_tco.h"
 
 /* Module and version information */
-#define TCO_VERSION "0.01"
+#define TCO_VERSION "0.03"
 #define TCO_MODULE_NAME "SP5100 TCO timer"
 #define TCO_DRIVER_NAME   TCO_MODULE_NAME ", v" TCO_VERSION
 
 /* internal variables */
 static u32 tcobase_phys;
+static u32 resbase_phys;
+static u32 tco_wdt_fired;
 static void __iomem *tcobase;
 static unsigned int pm_iobase;
 static DEFINE_SPINLOCK(tco_lock);      /* Guards the hardware */
 static unsigned long timer_alive;
 static char tco_expect_close;
 static struct pci_dev *sp5100_tco_pci;
+static struct resource wdt_res = {
+       .name = "Watchdog Timer",
+       .flags = IORESOURCE_MEM,
+};
 
 /* the watchdog platform device */
 static struct platform_device *sp5100_tco_platform_device;
@@ -64,9 +72,15 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 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) ")");
 
+static unsigned int force_addr;
+module_param(force_addr, uint, 0);
+MODULE_PARM_DESC(force_addr, "Force the use of specified MMIO address."
+               " ONLY USE THIS PARAMETER IF YOU REALLY KNOW"
+               " WHAT YOU ARE DOING (default=none)");
+
 /*
  * Some TCO specific functions
  */
@@ -122,6 +136,79 @@ static int tco_timer_set_heartbeat(int t)
        return 0;
 }
 
+static void tco_timer_enable(void)
+{
+       int val;
+
+       if (sp5100_tco_pci->revision >= 0x40) {
+               /* For SB800 or later */
+               /* Set the Watchdog timer resolution to 1 sec */
+               outb(SB800_PM_WATCHDOG_CONFIG, SB800_IO_PM_INDEX_REG);
+               val = inb(SB800_IO_PM_DATA_REG);
+               val |= SB800_PM_WATCHDOG_SECOND_RES;
+               outb(val, SB800_IO_PM_DATA_REG);
+
+               /* Enable watchdog decode bit and watchdog timer */
+               outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG);
+               val = inb(SB800_IO_PM_DATA_REG);
+               val |= SB800_PCI_WATCHDOG_DECODE_EN;
+               val &= ~SB800_PM_WATCHDOG_DISABLE;
+               outb(val, SB800_IO_PM_DATA_REG);
+       } else {
+               /* For SP5100 or SB7x0 */
+               /* Enable watchdog decode bit */
+               pci_read_config_dword(sp5100_tco_pci,
+                                     SP5100_PCI_WATCHDOG_MISC_REG,
+                                     &val);
+
+               val |= SP5100_PCI_WATCHDOG_DECODE_EN;
+
+               pci_write_config_dword(sp5100_tco_pci,
+                                      SP5100_PCI_WATCHDOG_MISC_REG,
+                                      val);
+
+               /* Enable Watchdog timer and set the resolution to 1 sec */
+               outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
+               val = inb(SP5100_IO_PM_DATA_REG);
+               val |= SP5100_PM_WATCHDOG_SECOND_RES;
+               val &= ~SP5100_PM_WATCHDOG_DISABLE;
+               outb(val, SP5100_IO_PM_DATA_REG);
+       }
+}
+
+static void tco_timer_disable(void)
+{
+       int val;
+
+       if (sp5100_tco_pci->revision >= 0x40) {
+               /* For SB800 or later */
+               /* Enable watchdog decode bit and Disable watchdog timer */
+               outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG);
+               val = inb(SB800_IO_PM_DATA_REG);
+               val |= SB800_PCI_WATCHDOG_DECODE_EN;
+               val |= SB800_PM_WATCHDOG_DISABLE;
+               outb(val, SB800_IO_PM_DATA_REG);
+       } else {
+               /* For SP5100 or SB7x0 */
+               /* Enable watchdog decode bit */
+               pci_read_config_dword(sp5100_tco_pci,
+                                     SP5100_PCI_WATCHDOG_MISC_REG,
+                                     &val);
+
+               val |= SP5100_PCI_WATCHDOG_DECODE_EN;
+
+               pci_write_config_dword(sp5100_tco_pci,
+                                      SP5100_PCI_WATCHDOG_MISC_REG,
+                                      val);
+
+               /* Disable Watchdog timer */
+               outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
+               val = inb(SP5100_IO_PM_DATA_REG);
+               val |= SP5100_PM_WATCHDOG_DISABLE;
+               outb(val, SP5100_IO_PM_DATA_REG);
+       }
+}
+
 /*
  *     /dev/watchdog handling
  */
@@ -270,11 +357,12 @@ MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl);
 /*
  * Init & exit routines
  */
-
 static unsigned char sp5100_tco_setupdevice(void)
 {
        struct pci_dev *dev = NULL;
+       const char *dev_name = NULL;
        u32 val;
+       u32 index_reg, data_reg, base_addr;
 
        /* Match the PCI device */
        for_each_pci_dev(dev) {
@@ -287,29 +375,160 @@ static unsigned char sp5100_tco_setupdevice(void)
        if (!sp5100_tco_pci)
                return 0;
 
+       pr_info("PCI Revision ID: 0x%x\n", sp5100_tco_pci->revision);
+
+       /*
+        * Determine type of southbridge chipset.
+        */
+       if (sp5100_tco_pci->revision >= 0x40) {
+               dev_name = SB800_DEVNAME;
+               index_reg = SB800_IO_PM_INDEX_REG;
+               data_reg = SB800_IO_PM_DATA_REG;
+               base_addr = SB800_PM_WATCHDOG_BASE;
+       } else {
+               dev_name = SP5100_DEVNAME;
+               index_reg = SP5100_IO_PM_INDEX_REG;
+               data_reg = SP5100_IO_PM_DATA_REG;
+               base_addr = SP5100_PM_WATCHDOG_BASE;
+       }
+
        /* Request the IO ports used by this driver */
        pm_iobase = SP5100_IO_PM_INDEX_REG;
-       if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) {
+       if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, dev_name)) {
                pr_err("I/O address 0x%04x already in use\n", pm_iobase);
                goto exit;
        }
 
-       /* Find the watchdog base address. */
-       outb(SP5100_PM_WATCHDOG_BASE3, SP5100_IO_PM_INDEX_REG);
-       val = inb(SP5100_IO_PM_DATA_REG);
-       outb(SP5100_PM_WATCHDOG_BASE2, SP5100_IO_PM_INDEX_REG);
-       val = val << 8 | inb(SP5100_IO_PM_DATA_REG);
-       outb(SP5100_PM_WATCHDOG_BASE1, SP5100_IO_PM_INDEX_REG);
-       val = val << 8 | inb(SP5100_IO_PM_DATA_REG);
-       outb(SP5100_PM_WATCHDOG_BASE0, SP5100_IO_PM_INDEX_REG);
-       /* Low three bits of BASE0 are reserved. */
-       val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8);
+       /*
+        * First, Find the watchdog timer MMIO address from indirect I/O.
+        */
+       outb(base_addr+3, index_reg);
+       val = inb(data_reg);
+       outb(base_addr+2, index_reg);
+       val = val << 8 | inb(data_reg);
+       outb(base_addr+1, index_reg);
+       val = val << 8 | inb(data_reg);
+       outb(base_addr+0, index_reg);
+       /* Low three bits of BASE are reserved */
+       val = val << 8 | (inb(data_reg) & 0xf8);
+
+       pr_debug("Got 0x%04x from indirect I/O\n", val);
+
+       /* Check MMIO address conflict */
+       if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
+                                                               dev_name))
+               goto setup_wdt;
+       else
+               pr_debug("MMIO address 0x%04x already in use\n", val);
+
+       /*
+        * Secondly, Find the watchdog timer MMIO address
+        * from SBResource_MMIO register.
+        */
+       if (sp5100_tco_pci->revision >= 0x40) {
+               /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
+               outb(SB800_PM_ACPI_MMIO_EN+3, SB800_IO_PM_INDEX_REG);
+               val = inb(SB800_IO_PM_DATA_REG);
+               outb(SB800_PM_ACPI_MMIO_EN+2, SB800_IO_PM_INDEX_REG);
+               val = val << 8 | inb(SB800_IO_PM_DATA_REG);
+               outb(SB800_PM_ACPI_MMIO_EN+1, SB800_IO_PM_INDEX_REG);
+               val = val << 8 | inb(SB800_IO_PM_DATA_REG);
+               outb(SB800_PM_ACPI_MMIO_EN+0, SB800_IO_PM_INDEX_REG);
+               val = val << 8 | inb(SB800_IO_PM_DATA_REG);
+       } else {
+               /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
+               pci_read_config_dword(sp5100_tco_pci,
+                                     SP5100_SB_RESOURCE_MMIO_BASE, &val);
+       }
+
+       /* The SBResource_MMIO is enabled and mapped memory space? */
+       if ((val & (SB800_ACPI_MMIO_DECODE_EN | SB800_ACPI_MMIO_SEL)) ==
+                                                 SB800_ACPI_MMIO_DECODE_EN) {
+               /* Clear unnecessary the low twelve bits */
+               val &= ~0xFFF;
+               /* Add the Watchdog Timer offset to base address. */
+               val += SB800_PM_WDT_MMIO_OFFSET;
+               /* Check MMIO address conflict */
+               if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
+                                                                  dev_name)) {
+                       pr_debug("Got 0x%04x from SBResource_MMIO register\n",
+                               val);
+                       goto setup_wdt;
+               } else
+                       pr_debug("MMIO address 0x%04x already in use\n", val);
+       } else
+               pr_debug("SBResource_MMIO is disabled(0x%04x)\n", val);
+
+       /*
+        * Lastly re-programming the watchdog timer MMIO address,
+        * This method is a last resort...
+        *
+        * Before re-programming, to ensure that the watchdog timer
+        * is disabled, disable the watchdog timer.
+        */
+       tco_timer_disable();
+
+       if (force_addr) {
+               /*
+                * Force the use of watchdog timer MMIO address, and aligned to
+                * 8byte boundary.
+                */
+               force_addr &= ~0x7;
+               val = force_addr;
+
+               pr_info("Force the use of 0x%04x as MMIO address\n", val);
+       } else {
+               /*
+                * Get empty slot into the resource tree for watchdog timer.
+                */
+               if (allocate_resource(&iomem_resource,
+                                     &wdt_res,
+                                     SP5100_WDT_MEM_MAP_SIZE,
+                                     0xf0000000,
+                                     0xfffffff8,
+                                     0x8,
+                                     NULL,
+                                     NULL)) {
+                       pr_err("MMIO allocation failed\n");
+                       goto unreg_region;
+               }
+
+               val = resbase_phys = wdt_res.start;
+               pr_debug("Got 0x%04x from resource tree\n", val);
+       }
+
+       /* Restore to the low three bits, if chipset is SB8x0(or later) */
+       if (sp5100_tco_pci->revision >= 0x40) {
+               u8 reserved_bit;
+               reserved_bit = inb(base_addr) & 0x7;
+               val |= (u32)reserved_bit;
+       }
+
+       /* Re-programming the watchdog timer base address */
+       outb(base_addr+0, index_reg);
+       /* Low three bits of BASE are reserved */
+       outb((val >>  0) & 0xf8, data_reg);
+       outb(base_addr+1, index_reg);
+       outb((val >>  8) & 0xff, data_reg);
+       outb(base_addr+2, index_reg);
+       outb((val >> 16) & 0xff, data_reg);
+       outb(base_addr+3, index_reg);
+       outb((val >> 24) & 0xff, data_reg);
+
+       /*
+        * Clear unnecessary the low three bits,
+        * if chipset is SB8x0(or later)
+        */
+       if (sp5100_tco_pci->revision >= 0x40)
+               val &= ~0x7;
 
        if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
-                                                               "SP5100 TCO")) {
-               pr_err("mmio address 0x%04x already in use\n", val);
-               goto unreg_region;
+                                                                  dev_name)) {
+               pr_err("MMIO address 0x%04x already in use\n", val);
+               goto unreg_resource;
        }
+
+setup_wdt:
        tcobase_phys = val;
 
        tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
@@ -318,26 +537,18 @@ static unsigned char sp5100_tco_setupdevice(void)
                goto unreg_mem_region;
        }
 
-       /* Enable watchdog decode bit */
-       pci_read_config_dword(sp5100_tco_pci,
-                             SP5100_PCI_WATCHDOG_MISC_REG,
-                             &val);
-
-       val |= SP5100_PCI_WATCHDOG_DECODE_EN;
+       pr_info("Using 0x%04x for watchdog MMIO address\n", val);
 
-       pci_write_config_dword(sp5100_tco_pci,
-                              SP5100_PCI_WATCHDOG_MISC_REG,
-                              val);
+       /* Setup the watchdog timer */
+       tco_timer_enable();
 
-       /* Enable Watchdog timer and set the resolution to 1 sec. */
-       outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
-       val = inb(SP5100_IO_PM_DATA_REG);
-       val |= SP5100_PM_WATCHDOG_SECOND_RES;
-       val &= ~SP5100_PM_WATCHDOG_DISABLE;
-       outb(val, SP5100_IO_PM_DATA_REG);
-
-       /* Check that the watchdog action is set to reset the system. */
+       /* Check that the watchdog action is set to reset the system */
        val = readl(SP5100_WDT_CONTROL(tcobase));
+       /*
+        * Save WatchDogFired status, because WatchDogFired flag is
+        * cleared here.
+        */
+       tco_wdt_fired = val & SP5100_PM_WATCHDOG_FIRED;
        val &= ~SP5100_PM_WATCHDOG_ACTION_RESET;
        writel(val, SP5100_WDT_CONTROL(tcobase));
 
@@ -355,6 +566,9 @@ static unsigned char sp5100_tco_setupdevice(void)
 
 unreg_mem_region:
        release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
+unreg_resource:
+       if (resbase_phys)
+               release_resource(&wdt_res);
 unreg_region:
        release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
 exit:
@@ -364,23 +578,18 @@ exit:
 static int sp5100_tco_init(struct platform_device *dev)
 {
        int ret;
-       u32 val;
+       char addr_str[16];
 
-       /* Check whether or not the hardware watchdog is there. If found, then
+       /*
+        * Check whether or not the hardware watchdog is there. If found, then
         * set it up.
         */
        if (!sp5100_tco_setupdevice())
                return -ENODEV;
 
        /* Check to see if last reboot was due to watchdog timeout */
-       pr_info("Watchdog reboot %sdetected\n",
-               readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ?
-               "" : "not ");
-
-       /* Clear out the old status */
-       val = readl(SP5100_WDT_CONTROL(tcobase));
-       val &= ~SP5100_PM_WATCHDOG_FIRED;
-       writel(val, SP5100_WDT_CONTROL(tcobase));
+       pr_info("Last reboot was %striggered by watchdog.\n",
+               tco_wdt_fired ? "" : "not ");
 
        /*
         * Check that the heartbeat value is within it's range.
@@ -400,14 +609,24 @@ static int sp5100_tco_init(struct platform_device *dev)
 
        clear_bit(0, &timer_alive);
 
-       pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
-               tcobase, heartbeat, nowayout);
+       /* Show module parameters */
+       if (force_addr == tcobase_phys)
+               /* The force_addr is vaild */
+               sprintf(addr_str, "0x%04x", force_addr);
+       else
+               strcpy(addr_str, "none");
+
+       pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d, "
+               "force_addr=%s)\n",
+               tcobase, heartbeat, nowayout, addr_str);
 
        return 0;
 
 exit:
        iounmap(tcobase);
        release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
+       if (resbase_phys)
+               release_resource(&wdt_res);
        release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
        return ret;
 }
@@ -422,6 +641,8 @@ static void sp5100_tco_cleanup(void)
        misc_deregister(&sp5100_tco_miscdev);
        iounmap(tcobase);
        release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
+       if (resbase_phys)
+               release_resource(&wdt_res);
        release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
 }
 
@@ -451,7 +672,7 @@ static int __init sp5100_tco_init_module(void)
 {
        int err;
 
-       pr_info("SP5100 TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
+       pr_info("SP5100/SB800 TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
 
        err = platform_driver_register(&sp5100_tco_driver);
        if (err)
@@ -475,13 +696,13 @@ static void __exit sp5100_tco_cleanup_module(void)
 {
        platform_device_unregister(sp5100_tco_platform_device);
        platform_driver_unregister(&sp5100_tco_driver);
-       pr_info("SP5100 TCO Watchdog Module Unloaded\n");
+       pr_info("SP5100/SB800 TCO Watchdog Module Unloaded\n");
 }
 
 module_init(sp5100_tco_init_module);
 module_exit(sp5100_tco_cleanup_module);
 
 MODULE_AUTHOR("Priyanka Gupta");
-MODULE_DESCRIPTION("TCO timer driver for SP5100 chipset");
+MODULE_DESCRIPTION("TCO timer driver for SP5100/SB800 chipset");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
index a5a16cc90a340b3fe29d73f7ad389ac58519077a..71594a0c14b735f56decde5e1ac5e01543fbda6c 100644 (file)
@@ -9,33 +9,57 @@
 /*
  * Some address definitions for the Watchdog
  */
-
 #define SP5100_WDT_MEM_MAP_SIZE                0x08
 #define SP5100_WDT_CONTROL(base)       ((base) + 0x00) /* Watchdog Control */
 #define SP5100_WDT_COUNT(base)         ((base) + 0x04) /* Watchdog Count */
 
-#define SP5100_WDT_START_STOP_BIT      1
+#define SP5100_WDT_START_STOP_BIT      (1 << 0)
 #define SP5100_WDT_TRIGGER_BIT         (1 << 7)
 
-#define SP5100_PCI_WATCHDOG_MISC_REG   0x41
-#define SP5100_PCI_WATCHDOG_DECODE_EN  (1 << 3)
-
 #define SP5100_PM_IOPORTS_SIZE         0x02
 
-/* These two IO registers are hardcoded and there doesn't seem to be a way to
+/*
+ * These two IO registers are hardcoded and there doesn't seem to be a way to
  * read them from a register.
  */
+
+/*  For SP5100/SB7x0 chipset */
 #define SP5100_IO_PM_INDEX_REG         0xCD6
 #define SP5100_IO_PM_DATA_REG          0xCD7
 
+#define SP5100_SB_RESOURCE_MMIO_BASE   0x9C
+
 #define SP5100_PM_WATCHDOG_CONTROL     0x69
-#define SP5100_PM_WATCHDOG_BASE0       0x6C
-#define SP5100_PM_WATCHDOG_BASE1       0x6D
-#define SP5100_PM_WATCHDOG_BASE2       0x6E
-#define SP5100_PM_WATCHDOG_BASE3       0x6F
+#define SP5100_PM_WATCHDOG_BASE                0x6C
 
 #define SP5100_PM_WATCHDOG_FIRED       (1 << 1)
 #define SP5100_PM_WATCHDOG_ACTION_RESET        (1 << 2)
 
-#define SP5100_PM_WATCHDOG_DISABLE     1
+#define SP5100_PCI_WATCHDOG_MISC_REG   0x41
+#define SP5100_PCI_WATCHDOG_DECODE_EN  (1 << 3)
+
+#define SP5100_PM_WATCHDOG_DISABLE     (1 << 0)
 #define SP5100_PM_WATCHDOG_SECOND_RES  (3 << 1)
+
+#define SP5100_DEVNAME                 "SP5100 TCO"
+
+
+/*  For SB8x0(or later) chipset */
+#define SB800_IO_PM_INDEX_REG          0xCD6
+#define SB800_IO_PM_DATA_REG           0xCD7
+
+#define SB800_PM_ACPI_MMIO_EN          0x24
+#define SB800_PM_WATCHDOG_CONTROL      0x48
+#define SB800_PM_WATCHDOG_BASE         0x48
+#define SB800_PM_WATCHDOG_CONFIG       0x4C
+
+#define SB800_PCI_WATCHDOG_DECODE_EN   (1 << 0)
+#define SB800_PM_WATCHDOG_DISABLE      (1 << 2)
+#define SB800_PM_WATCHDOG_SECOND_RES   (3 << 0)
+#define SB800_ACPI_MMIO_DECODE_EN      (1 << 0)
+#define SB800_ACPI_MMIO_SEL            (1 << 2)
+
+
+#define SB800_PM_WDT_MMIO_OFFSET       0xB00
+
+#define SB800_DEVNAME                  "SB800 TCO"
index 76c73cbf00407a89e0176a3d69782988687d3f6e..8872642505c0a71a027ccbce25d2e9f3eebe468a 100644 (file)
@@ -130,16 +130,10 @@ static int wdt_config(struct watchdog_device *wdd, bool ping)
        int ret;
 
        if (!ping) {
-               ret = clk_prepare(wdt->clk);
-               if (ret) {
-                       dev_err(&wdt->adev->dev, "clock prepare fail");
-                       return ret;
-               }
 
-               ret = clk_enable(wdt->clk);
+               ret = clk_prepare_enable(wdt->clk);
                if (ret) {
                        dev_err(&wdt->adev->dev, "clock enable fail");
-                       clk_unprepare(wdt->clk);
                        return ret;
                }
        }
@@ -190,8 +184,7 @@ static int wdt_disable(struct watchdog_device *wdd)
        readl_relaxed(wdt->base + WDTLOCK);
        spin_unlock(&wdt->lock);
 
-       clk_disable(wdt->clk);
-       clk_unprepare(wdt->clk);
+       clk_disable_unprepare(wdt->clk);
 
        return 0;
 }
index 9f54b1da7185ecf535b401f6daeb238c0a6e0eb7..81918cf8993bafebdd7585df879ad4e0c47aba59 100644 (file)
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/watchdog.h>
 #include <linux/platform_device.h>
-#include <linux/miscdevice.h>
-#include <linux/uaccess.h>
 #include <linux/i2c/twl.h>
 
 #define TWL4030_WATCHDOG_CFG_REG_OFFS  0x3
 
-#define TWL4030_WDT_STATE_OPEN         0x1
-#define TWL4030_WDT_STATE_ACTIVE       0x8
-
-static struct platform_device *twl4030_wdt_dev;
-
-struct twl4030_wdt {
-       struct miscdevice       miscdev;
-       int                     timer_margin;
-       unsigned long           state;
-};
-
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
@@ -49,175 +35,75 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
 
 static int twl4030_wdt_write(unsigned char val)
 {
-       return twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val,
+       return twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, val,
                                        TWL4030_WATCHDOG_CFG_REG_OFFS);
 }
 
-static int twl4030_wdt_enable(struct twl4030_wdt *wdt)
+static int twl4030_wdt_start(struct watchdog_device *wdt)
 {
-       return twl4030_wdt_write(wdt->timer_margin + 1);
+       return twl4030_wdt_write(wdt->timeout + 1);
 }
 
-static int twl4030_wdt_disable(struct twl4030_wdt *wdt)
+static int twl4030_wdt_stop(struct watchdog_device *wdt)
 {
        return twl4030_wdt_write(0);
 }
 
-static int twl4030_wdt_set_timeout(struct twl4030_wdt *wdt, int timeout)
-{
-       if (timeout < 0 || timeout > 30) {
-               dev_warn(wdt->miscdev.parent,
-                       "Timeout can only be in the range [0-30] seconds");
-               return -EINVAL;
-       }
-       wdt->timer_margin = timeout;
-       return twl4030_wdt_enable(wdt);
-}
-
-static ssize_t twl4030_wdt_write_fop(struct file *file,
-               const char __user *data, size_t len, loff_t *ppos)
+static int twl4030_wdt_set_timeout(struct watchdog_device *wdt,
+                                  unsigned int timeout)
 {
-       struct twl4030_wdt *wdt = file->private_data;
-
-       if (len)
-               twl4030_wdt_enable(wdt);
-
-       return len;
-}
-
-static long twl4030_wdt_ioctl(struct file *file,
-               unsigned int cmd, unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       int new_margin;
-       struct twl4030_wdt *wdt = file->private_data;
-
-       static const struct watchdog_info twl4030_wd_ident = {
-               .identity = "TWL4030 Watchdog",
-               .options = WDIOF_SETTIMEOUT,
-               .firmware_version = 0,
-       };
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user(argp, &twl4030_wd_ident,
-                               sizeof(twl4030_wd_ident)) ? -EFAULT : 0;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               return put_user(0, p);
-
-       case WDIOC_KEEPALIVE:
-               twl4030_wdt_enable(wdt);
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_margin, p))
-                       return -EFAULT;
-               if (twl4030_wdt_set_timeout(wdt, new_margin))
-                       return -EINVAL;
-               return put_user(wdt->timer_margin, p);
-
-       case WDIOC_GETTIMEOUT:
-               return put_user(wdt->timer_margin, p);
-
-       default:
-               return -ENOTTY;
-       }
-
+       wdt->timeout = timeout;
        return 0;
 }
 
-static int twl4030_wdt_open(struct inode *inode, struct file *file)
-{
-       struct twl4030_wdt *wdt = platform_get_drvdata(twl4030_wdt_dev);
-
-       /* /dev/watchdog can only be opened once */
-       if (test_and_set_bit(0, &wdt->state))
-               return -EBUSY;
-
-       wdt->state |= TWL4030_WDT_STATE_ACTIVE;
-       file->private_data = (void *) wdt;
-
-       twl4030_wdt_enable(wdt);
-       return nonseekable_open(inode, file);
-}
-
-static int twl4030_wdt_release(struct inode *inode, struct file *file)
-{
-       struct twl4030_wdt *wdt = file->private_data;
-       if (nowayout) {
-               dev_alert(wdt->miscdev.parent,
-                      "Unexpected close, watchdog still running!\n");
-               twl4030_wdt_enable(wdt);
-       } else {
-               if (twl4030_wdt_disable(wdt))
-                       return -EFAULT;
-               wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
-       }
-
-       clear_bit(0, &wdt->state);
-       return 0;
-}
+static const struct watchdog_info twl4030_wdt_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+       .identity = "TWL4030 Watchdog",
+};
 
-static const struct file_operations twl4030_wdt_fops = {
+static const struct watchdog_ops twl4030_wdt_ops = {
        .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = twl4030_wdt_open,
-       .release        = twl4030_wdt_release,
-       .unlocked_ioctl = twl4030_wdt_ioctl,
-       .write          = twl4030_wdt_write_fop,
+       .start          = twl4030_wdt_start,
+       .stop           = twl4030_wdt_stop,
+       .set_timeout    = twl4030_wdt_set_timeout,
 };
 
 static int twl4030_wdt_probe(struct platform_device *pdev)
 {
        int ret = 0;
-       struct twl4030_wdt *wdt;
+       struct watchdog_device *wdt;
 
-       wdt = kzalloc(sizeof(struct twl4030_wdt), GFP_KERNEL);
+       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
 
-       wdt->state              = 0;
-       wdt->timer_margin       = 30;
-       wdt->miscdev.parent     = &pdev->dev;
-       wdt->miscdev.fops       = &twl4030_wdt_fops;
-       wdt->miscdev.minor      = WATCHDOG_MINOR;
-       wdt->miscdev.name       = "watchdog";
+       wdt->info               = &twl4030_wdt_info;
+       wdt->ops                = &twl4030_wdt_ops;
+       wdt->status             = 0;
+       wdt->timeout            = 30;
+       wdt->min_timeout        = 1;
+       wdt->max_timeout        = 30;
 
+       watchdog_set_nowayout(wdt, nowayout);
        platform_set_drvdata(pdev, wdt);
 
-       twl4030_wdt_dev = pdev;
+       twl4030_wdt_stop(wdt);
 
-       twl4030_wdt_disable(wdt);
-
-       ret = misc_register(&wdt->miscdev);
+       ret = watchdog_register_device(wdt);
        if (ret) {
-               dev_err(wdt->miscdev.parent,
-                       "Failed to register misc device\n");
                platform_set_drvdata(pdev, NULL);
-               kfree(wdt);
-               twl4030_wdt_dev = NULL;
                return ret;
        }
+
        return 0;
 }
 
 static int twl4030_wdt_remove(struct platform_device *pdev)
 {
-       struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
-
-       if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
-               if (twl4030_wdt_disable(wdt))
-                       return -EFAULT;
-
-       wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
-       misc_deregister(&wdt->miscdev);
+       struct watchdog_device *wdt = platform_get_drvdata(pdev);
 
+       watchdog_unregister_device(wdt);
        platform_set_drvdata(pdev, NULL);
-       kfree(wdt);
-       twl4030_wdt_dev = NULL;
 
        return 0;
 }
@@ -225,18 +111,18 @@ static int twl4030_wdt_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM
 static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
 {
-       struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
-       if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
-               return twl4030_wdt_disable(wdt);
+       struct watchdog_device *wdt = platform_get_drvdata(pdev);
+       if (watchdog_active(wdt))
+               return twl4030_wdt_stop(wdt);
 
        return 0;
 }
 
 static int twl4030_wdt_resume(struct platform_device *pdev)
 {
-       struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
-       if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
-               return twl4030_wdt_enable(wdt);
+       struct watchdog_device *wdt = platform_get_drvdata(pdev);
+       if (watchdog_active(wdt))
+               return twl4030_wdt_start(wdt);
 
        return 0;
 }
@@ -260,6 +146,5 @@ module_platform_driver(twl4030_wdt_driver);
 
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
 MODULE_ALIAS("platform:twl4030_wdt");
 
index 87490ac4bd87c72909aa8171e12ec8381af54f8c..3a9df2f43be642a7cbad15f678ef29c7f85f27e5 100644 (file)
@@ -129,7 +129,7 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
        return wdd->driver_data;
 }
 
-/* drivers/watchdog/core/watchdog_core.c */
+/* drivers/watchdog/watchdog_core.c */
 extern int watchdog_register_device(struct watchdog_device *);
 extern void watchdog_unregister_device(struct watchdog_device *);