]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge git://www.linux-watchdog.org/linux-watchdog
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 11 Jun 2014 02:16:36 +0000 (19:16 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 11 Jun 2014 02:16:36 +0000 (19:16 -0700)
Pull watchdog updates from Wim Van Sebroeck:
 "This contains:
   - addition of the Intel MID watchdog
   - removal of W83697HF and W83697UG drivers (code was merged into
     w83627hf_wdt driver)
   - addition of Armada 375/380 SoC support
   - conversion of imx2_wdt to regmap API and to watchdog core API
   - lots of other small improvements and fixes"

[ Wim was also tagged by gmail as a spammer, but not delayed by days
  unlike Ben ]

* git://www.linux-watchdog.org/linux-watchdog: (25 commits)
  x86: intel-mid: add watchdog platform code for Merrifield
  watchdog: add Intel MID watchdog driver support
  watchdog: sp805: Set watchdog_device->timeout from ->set_timeout()
  booke/watchdog: refine and clean up the codes
  watchdog: iop_wdt only builds for mach-iop13xx
  watchdog: Remove drivers for W83697HF and W83697UG
  watchdog: w83627hf_wdt: Add early_disable module parameter
  ARM: mvebu: Add A375/A380 watchdog binding documentation
  watchdog: orion: Add Armada 375/380 SoC support
  watchdog: orion: Introduce per-SoC enabled() function
  watchdog: orion: Introduce per-SoC stop() function
  watchdog: orion: Remove unneeded atomic access
  watchdog: orion: Introduce a SoC-specific RSTOUT mapping
  watchdog: orion: Move the register ioremap'ing to its own function
  watchdog: xilinx: Make of_device_id array const
  watchdog: imx2_wdt: convert to watchdog core api
  watchdog: imx2_wdt: convert to use regmap API.
  watchdog: imx2_wdt: Sort the header files alphabetically
  watchdog: ath79_wdt: switch to clk_prepare/clk_disable
  watchdog: ath79_wdt: avoid spurious restarts on AR934x
  ...

21 files changed:
Documentation/devicetree/bindings/watchdog/marvel.txt
arch/powerpc/kernel/setup-common.c
arch/x86/platform/intel-mid/device_libs/Makefile
arch/x86/platform/intel-mid/device_libs/platform_wdt.c [new file with mode: 0644]
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/ath79_wdt.c
drivers/watchdog/booke_wdt.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/intel-mid_wdt.c [new file with mode: 0644]
drivers/watchdog/kempld_wdt.c
drivers/watchdog/of_xilinx_wdt.c
drivers/watchdog/orion_wdt.c
drivers/watchdog/shwdt.c
drivers/watchdog/sp805_wdt.c
drivers/watchdog/sunxi_wdt.c
drivers/watchdog/via_wdt.c
drivers/watchdog/w83627hf_wdt.c
drivers/watchdog/w83697hf_wdt.c [deleted file]
drivers/watchdog/w83697ug_wdt.c [deleted file]
include/linux/platform_data/intel-mid_wdt.h [new file with mode: 0644]

index de11eb4c121fff77e119e7ec251707f69badecc5..97223fddb7bdd69ed28c3ec40ea0c2986fa0cf3c 100644 (file)
@@ -5,11 +5,18 @@ Required Properties:
 - Compatibility : "marvell,orion-wdt"
                  "marvell,armada-370-wdt"
                  "marvell,armada-xp-wdt"
+                 "marvell,armada-375-wdt"
+                 "marvell,armada-380-wdt"
 
 - reg          : Should contain two entries: first one with the
                  timer control address, second one with the
                  rstout enable address.
 
+For "marvell,armada-375-wdt" and "marvell,armada-380-wdt":
+
+- reg          : A third entry is mandatory and should contain the
+                  shared mask/unmask RSTOUT address.
+
 Optional properties:
 
 - interrupts   : Contains the IRQ for watchdog expiration
index aa0f5edd85706655e7070a3243b427b957289391..d4d418376f994575f598ee7f9bab58d1db2449ce 100644 (file)
@@ -728,33 +728,6 @@ static int powerpc_debugfs_init(void)
 arch_initcall(powerpc_debugfs_init);
 #endif
 
-#ifdef CONFIG_BOOKE_WDT
-extern u32 booke_wdt_enabled;
-extern u32 booke_wdt_period;
-
-/* Checks wdt=x and wdt_period=xx command-line option */
-notrace int __init early_parse_wdt(char *p)
-{
-       if (p && strncmp(p, "0", 1) != 0)
-               booke_wdt_enabled = 1;
-
-       return 0;
-}
-early_param("wdt", early_parse_wdt);
-
-int __init early_parse_wdt_period(char *p)
-{
-       unsigned long ret;
-       if (p) {
-               if (!kstrtol(p, 0, &ret))
-                       booke_wdt_period = ret;
-       }
-
-       return 0;
-}
-early_param("wdt_period", early_parse_wdt_period);
-#endif /* CONFIG_BOOKE_WDT */
-
 void ppc_printk_progress(char *s, unsigned short hex)
 {
        pr_info("%s\n", s);
index 097e7a7940d850e8111ce704ce80ef0763a95d2f..af9307f2cc28eec45f3831f60f6284615d70757a 100644 (file)
@@ -20,3 +20,4 @@ obj-$(subst m,y,$(CONFIG_DRM_MEDFIELD)) += platform_tc35876x.o
 obj-$(subst m,y,$(CONFIG_SERIAL_MRST_MAX3110)) += platform_max3111.o
 # MISC Devices
 obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o
+obj-$(subst m,y,$(CONFIG_INTEL_MID_WATCHDOG)) += platform_wdt.o
diff --git a/arch/x86/platform/intel-mid/device_libs/platform_wdt.c b/arch/x86/platform/intel-mid/device_libs/platform_wdt.c
new file mode 100644 (file)
index 0000000..973cf3b
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * platform_wdt.c: Watchdog platform library file
+ *
+ * (C) Copyright 2014 Intel Corporation
+ * Author: David Cohen <david.a.cohen@linux.intel.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; version 2
+ * of the License.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/intel-mid_wdt.h>
+#include <asm/intel-mid.h>
+#include <asm/io_apic.h>
+
+#define TANGIER_EXT_TIMER0_MSI 15
+
+static struct platform_device wdt_dev = {
+       .name = "intel_mid_wdt",
+       .id = -1,
+};
+
+static int tangier_probe(struct platform_device *pdev)
+{
+       int ioapic;
+       int irq;
+       struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
+       struct io_apic_irq_attr irq_attr = { 0 };
+
+       if (!pdata)
+               return -EINVAL;
+
+       irq = pdata->irq;
+       ioapic = mp_find_ioapic(irq);
+       if (ioapic >= 0) {
+               int ret;
+               irq_attr.ioapic = ioapic;
+               irq_attr.ioapic_pin = irq;
+               irq_attr.trigger = 1;
+               /* irq_attr.polarity = 0; -> Active high */
+               ret = io_apic_set_pci_routing(NULL, irq, &irq_attr);
+               if (ret)
+                       return ret;
+       } else {
+               dev_warn(&pdev->dev, "cannot find interrupt %d in ioapic\n",
+                        irq);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct intel_mid_wdt_pdata tangier_pdata = {
+       .irq = TANGIER_EXT_TIMER0_MSI,
+       .probe = tangier_probe,
+};
+
+static int __init register_mid_wdt(void)
+{
+       if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
+               wdt_dev.dev.platform_data = &tangier_pdata;
+               return platform_device_register(&wdt_dev);
+       }
+
+       return -ENODEV;
+}
+
+rootfs_initcall(register_mid_wdt);
index 74ec8fc5cc0303fa81fd036c87632c7f8524c824..c845527b503a2e3ae0418bbc1600b724c78507a3 100644 (file)
@@ -272,7 +272,7 @@ config PNX4008_WATCHDOG
 
 config IOP_WATCHDOG
        tristate "IOP Watchdog"
-       depends on PLAT_IOP
+       depends on ARCH_IOP13XX
        select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
        help
          Say Y here if to include support for the watchdog timer
@@ -378,6 +378,8 @@ config MAX63XX_WATCHDOG
 config IMX2_WDT
        tristate "IMX2+ Watchdog"
        depends on ARCH_MXC
+       select REGMAP_MMIO
+       select WATCHDOG_CORE
        help
          This is the driver for the hardware watchdog
          on the Freescale IMX2 and later processors.
@@ -663,6 +665,19 @@ config INTEL_SCU_WATCHDOG
 
          To compile this driver as a module, choose M here.
 
+config INTEL_MID_WATCHDOG
+       tristate "Intel MID Watchdog Timer"
+       depends on X86_INTEL_MID
+       select WATCHDOG_CORE
+       ---help---
+         Watchdog timer driver built into the Intel SCU for Intel MID
+         Platforms.
+
+         This driver currently supports only the watchdog evolution
+         implementation in SCU, available for Merrifield generation.
+
+         To compile this driver as a module, choose M here.
+
 config ITCO_WDT
        tristate "Intel TCO Timer/Watchdog"
        depends on (X86 || IA64) && PCI
@@ -835,7 +850,7 @@ config 60XX_WDT
 
 config SBC8360_WDT
        tristate "SBC8360 Watchdog Timer"
-       depends on X86
+       depends on X86_32
        ---help---
 
          This is the driver for the hardware watchdog on the SBC8360 Single
@@ -938,36 +953,6 @@ config W83627HF_WDT
 
          Most people will say N.
 
-config W83697HF_WDT
-       tristate "W83697HF/W83697HG Watchdog Timer"
-       depends on X86
-       ---help---
-         This is the driver for the hardware watchdog on the W83697HF/HG
-         chipset as used in Dedibox/VIA motherboards (and likely others).
-         This watchdog simply watches your kernel to make sure it doesn't
-         freeze, and if it does, it reboots your computer after a certain
-         amount of time.
-
-         To compile this driver as a module, choose M here: the
-         module will be called w83697hf_wdt.
-
-         Most people will say N.
-
-config W83697UG_WDT
-       tristate "W83697UG/W83697UF Watchdog Timer"
-       depends on X86
-       ---help---
-         This is the driver for the hardware watchdog on the W83697UG/UF
-         chipset as used in MSI Fuzzy CX700 VIA motherboards (and likely others).
-         This watchdog simply watches your kernel to make sure it doesn't
-         freeze, and if it does, it reboots your computer after a certain
-         amount of time.
-
-         To compile this driver as a module, choose M here: the
-         module will be called w83697ug_wdt.
-
-         Most people will say N.
-
 config W83877F_WDT
        tristate "W83877F (EMACS) Watchdog Timer"
        depends on X86
index 1b5f3d5efad5bb20e8f64c9b24b24e61a8d0bd23..7b8a91ed20e749b9e102bd78ad41ff64e7a86442 100644 (file)
@@ -107,13 +107,12 @@ obj-$(CONFIG_SMSC_SCH311X_WDT) += sch311x_wdt.o
 obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
 obj-$(CONFIG_VIA_WDT) += via_wdt.o
 obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
-obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
-obj-$(CONFIG_W83697UG_WDT) += w83697ug_wdt.o
 obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
 obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
 obj-$(CONFIG_MACHZ_WDT) += machzwd.o
 obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
 obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
+obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o
 
 # M32R Architecture
 
index 399c3fddecf6471ac12296ba028f296e54327e43..41ac4660fb891db2fba16b66c73c6293bfe2b3f4 100644 (file)
@@ -20,6 +20,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/bitops.h>
+#include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/io.h>
@@ -90,6 +91,15 @@ static inline void ath79_wdt_keepalive(void)
 static inline void ath79_wdt_enable(void)
 {
        ath79_wdt_keepalive();
+
+       /*
+        * Updating the TIMER register requires a few microseconds
+        * on the AR934x SoCs at least. Use a small delay to ensure
+        * that the TIMER register is updated within the hardware
+        * before enabling the watchdog.
+        */
+       udelay(2);
+
        ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR);
        /* flush write */
        ath79_wdt_rr(WDOG_REG_CTRL);
@@ -255,7 +265,7 @@ static int ath79_wdt_probe(struct platform_device *pdev)
        if (IS_ERR(wdt_clk))
                return PTR_ERR(wdt_clk);
 
-       err = clk_enable(wdt_clk);
+       err = clk_prepare_enable(wdt_clk);
        if (err)
                return err;
 
@@ -286,14 +296,14 @@ static int ath79_wdt_probe(struct platform_device *pdev)
        return 0;
 
 err_clk_disable:
-       clk_disable(wdt_clk);
+       clk_disable_unprepare(wdt_clk);
        return err;
 }
 
 static int ath79_wdt_remove(struct platform_device *pdev)
 {
        misc_deregister(&ath79_wdt_miscdev);
-       clk_disable(wdt_clk);
+       clk_disable_unprepare(wdt_clk);
        return 0;
 }
 
index a8dbceb32914a0e834a8c6b8ae394898c213e527..08a785398eacfd3b54d47f5eb12770632ee339e5 100644 (file)
@@ -41,6 +41,28 @@ u32 booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT;
 #define WDTP_MASK      (TCR_WP_MASK)
 #endif
 
+/* Checks wdt=x and wdt_period=xx command-line option */
+notrace int __init early_parse_wdt(char *p)
+{
+       if (p && strncmp(p, "0", 1) != 0)
+               booke_wdt_enabled = 1;
+
+       return 0;
+}
+early_param("wdt", early_parse_wdt);
+
+int __init early_parse_wdt_period(char *p)
+{
+       unsigned long ret;
+       if (p) {
+               if (!kstrtol(p, 0, &ret))
+                       booke_wdt_period = ret;
+       }
+
+       return 0;
+}
+early_param("wdt_period", early_parse_wdt_period);
+
 #ifdef CONFIG_PPC_FSL_BOOK3E
 
 /* For the specified period, determine the number of seconds
@@ -103,17 +125,18 @@ static unsigned int sec_to_period(unsigned int secs)
 static void __booke_wdt_set(void *data)
 {
        u32 val;
+       struct watchdog_device *wdog = data;
 
        val = mfspr(SPRN_TCR);
        val &= ~WDTP_MASK;
-       val |= WDTP(booke_wdt_period);
+       val |= WDTP(sec_to_period(wdog->timeout));
 
        mtspr(SPRN_TCR, val);
 }
 
-static void booke_wdt_set(void)
+static void booke_wdt_set(void *data)
 {
-       on_each_cpu(__booke_wdt_set, NULL, 0);
+       on_each_cpu(__booke_wdt_set, data, 0);
 }
 
 static void __booke_wdt_ping(void *data)
@@ -131,12 +154,13 @@ static int booke_wdt_ping(struct watchdog_device *wdog)
 static void __booke_wdt_enable(void *data)
 {
        u32 val;
+       struct watchdog_device *wdog = data;
 
        /* clear status before enabling watchdog */
        __booke_wdt_ping(NULL);
        val = mfspr(SPRN_TCR);
        val &= ~WDTP_MASK;
-       val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
+       val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(sec_to_period(wdog->timeout)));
 
        mtspr(SPRN_TCR, val);
 }
@@ -162,25 +186,17 @@ static void __booke_wdt_disable(void *data)
 
 }
 
-static void __booke_wdt_start(struct watchdog_device *wdog)
+static int booke_wdt_start(struct watchdog_device *wdog)
 {
-       on_each_cpu(__booke_wdt_enable, NULL, 0);
+       on_each_cpu(__booke_wdt_enable, wdog, 0);
        pr_debug("watchdog enabled (timeout = %u sec)\n", wdog->timeout);
-}
 
-static int booke_wdt_start(struct watchdog_device *wdog)
-{
-       if (booke_wdt_enabled == 0) {
-               booke_wdt_enabled = 1;
-               __booke_wdt_start(wdog);
-       }
        return 0;
 }
 
 static int booke_wdt_stop(struct watchdog_device *wdog)
 {
        on_each_cpu(__booke_wdt_disable, NULL, 0);
-       booke_wdt_enabled = 0;
        pr_debug("watchdog disabled\n");
 
        return 0;
@@ -191,9 +207,8 @@ static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev,
 {
        if (timeout > MAX_WDT_TIMEOUT)
                return -EINVAL;
-       booke_wdt_period = sec_to_period(timeout);
        wdt_dev->timeout = timeout;
-       booke_wdt_set();
+       booke_wdt_set(wdt_dev);
 
        return 0;
 }
@@ -231,10 +246,10 @@ static int __init booke_wdt_init(void)
        pr_info("powerpc book-e watchdog driver loaded\n");
        booke_wdt_info.firmware_version = cur_cpu_spec->pvr_value;
        booke_wdt_set_timeout(&booke_wdt_dev,
-                             period_to_sec(CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT));
+                             period_to_sec(booke_wdt_period));
        watchdog_set_nowayout(&booke_wdt_dev, nowayout);
        if (booke_wdt_enabled)
-               __booke_wdt_start(&booke_wdt_dev);
+               booke_wdt_start(&booke_wdt_dev);
 
        ret = watchdog_register_device(&booke_wdt_dev);
 
index dd51d9539b33df6ea6b9aa9960d9f0fa5fe7c169..9d4874f09948aa2110fc207730f57d0fe1772fbd 100644 (file)
  * Halt on suspend:    Manual          Can be automatic
  */
 
+#include <linux/clk.h>
 #include <linux/init.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
 #include <linux/kernel.h>
-#include <linux/miscdevice.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
-#include <linux/watchdog.h>
-#include <linux/clk.h>
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
+#include <linux/regmap.h>
 #include <linux/timer.h>
-#include <linux/jiffies.h>
+#include <linux/watchdog.h>
 
 #define DRIVER_NAME "imx2-wdt"
 
 
 #define WDOG_SEC_TO_COUNT(s)   ((s * 2 - 1) << 8)
 
-#define IMX2_WDT_STATUS_OPEN   0
-#define IMX2_WDT_STATUS_STARTED        1
-#define IMX2_WDT_EXPECT_CLOSE  2
-
-static struct {
+struct imx2_wdt_device {
        struct clk *clk;
-       void __iomem *base;
-       unsigned timeout;
-       unsigned long status;
+       struct regmap *regmap;
        struct timer_list timer;        /* Pings the watchdog when closed */
-} imx2_wdt;
-
-static struct miscdevice imx2_wdt_miscdev;
+       struct watchdog_device wdog;
+};
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
@@ -85,9 +76,12 @@ static const struct watchdog_info imx2_wdt_info = {
        .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
 };
 
-static inline void imx2_wdt_setup(void)
+static inline void imx2_wdt_setup(struct watchdog_device *wdog)
 {
-       u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR);
+       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+       u32 val;
+
+       regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
 
        /* Suspend timer in low power mode, write once-only */
        val |= IMX2_WDT_WCR_WDZST;
@@ -98,227 +92,199 @@ static inline void imx2_wdt_setup(void)
        /* Keep Watchdog Disabled */
        val &= ~IMX2_WDT_WCR_WDE;
        /* Set the watchdog's Time-Out value */
-       val |= WDOG_SEC_TO_COUNT(imx2_wdt.timeout);
+       val |= WDOG_SEC_TO_COUNT(wdog->timeout);
 
-       __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
+       regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
 
        /* enable the watchdog */
        val |= IMX2_WDT_WCR_WDE;
-       __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
+       regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
 }
 
-static inline void imx2_wdt_ping(void)
+static inline bool imx2_wdt_is_running(struct imx2_wdt_device *wdev)
 {
-       __raw_writew(IMX2_WDT_SEQ1, imx2_wdt.base + IMX2_WDT_WSR);
-       __raw_writew(IMX2_WDT_SEQ2, imx2_wdt.base + IMX2_WDT_WSR);
-}
+       u32 val;
 
-static void imx2_wdt_timer_ping(unsigned long arg)
-{
-       /* ping it every imx2_wdt.timeout / 2 seconds to prevent reboot */
-       imx2_wdt_ping();
-       mod_timer(&imx2_wdt.timer, jiffies + imx2_wdt.timeout * HZ / 2);
+       regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
+
+       return val & IMX2_WDT_WCR_WDE;
 }
 
-static void imx2_wdt_start(void)
+static int imx2_wdt_ping(struct watchdog_device *wdog)
 {
-       if (!test_and_set_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) {
-               /* at our first start we enable clock and do initialisations */
-               clk_prepare_enable(imx2_wdt.clk);
+       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
-               imx2_wdt_setup();
-       } else  /* delete the timer that pings the watchdog after close */
-               del_timer_sync(&imx2_wdt.timer);
-
-       /* Watchdog is enabled - time to reload the timeout value */
-       imx2_wdt_ping();
+       regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
+       regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
+       return 0;
 }
 
-static void imx2_wdt_stop(void)
+static void imx2_wdt_timer_ping(unsigned long arg)
 {
-       /* we don't need a clk_disable, it cannot be disabled once started.
-        * We use a timer to ping the watchdog while /dev/watchdog is closed */
-       imx2_wdt_timer_ping(0);
+       struct watchdog_device *wdog = (struct watchdog_device *)arg;
+       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+
+       /* ping it every wdog->timeout / 2 seconds to prevent reboot */
+       imx2_wdt_ping(wdog);
+       mod_timer(&wdev->timer, jiffies + wdog->timeout * HZ / 2);
 }
 
-static void imx2_wdt_set_timeout(int new_timeout)
+static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
+                               unsigned int new_timeout)
 {
-       u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR);
+       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
-       /* set the new timeout value in the WSR */
-       val &= ~IMX2_WDT_WCR_WT;
-       val |= WDOG_SEC_TO_COUNT(new_timeout);
-       __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
+       regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
+                          WDOG_SEC_TO_COUNT(new_timeout));
+       return 0;
 }
 
-static int imx2_wdt_open(struct inode *inode, struct file *file)
+static int imx2_wdt_start(struct watchdog_device *wdog)
 {
-       if (test_and_set_bit(IMX2_WDT_STATUS_OPEN, &imx2_wdt.status))
-               return -EBUSY;
+       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+
+       if (imx2_wdt_is_running(wdev)) {
+               /* delete the timer that pings the watchdog after close */
+               del_timer_sync(&wdev->timer);
+               imx2_wdt_set_timeout(wdog, wdog->timeout);
+       } else
+               imx2_wdt_setup(wdog);
 
-       imx2_wdt_start();
-       return nonseekable_open(inode, file);
+       return imx2_wdt_ping(wdog);
 }
 
-static int imx2_wdt_close(struct inode *inode, struct file *file)
+static int imx2_wdt_stop(struct watchdog_device *wdog)
 {
-       if (test_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status) && !nowayout)
-               imx2_wdt_stop();
-       else {
-               dev_crit(imx2_wdt_miscdev.parent,
-                       "Unexpected close: Expect reboot!\n");
-               imx2_wdt_ping();
-       }
-
-       clear_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
-       clear_bit(IMX2_WDT_STATUS_OPEN, &imx2_wdt.status);
+       /*
+        * We don't need a clk_disable, it cannot be disabled once started.
+        * We use a timer to ping the watchdog while /dev/watchdog is closed
+        */
+       imx2_wdt_timer_ping((unsigned long)wdog);
        return 0;
 }
 
-static long imx2_wdt_ioctl(struct file *file, unsigned int cmd,
-                                                       unsigned long arg)
+static inline void imx2_wdt_ping_if_active(struct watchdog_device *wdog)
 {
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       int new_value;
-       u16 val;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user(argp, &imx2_wdt_info,
-                       sizeof(struct watchdog_info)) ? -EFAULT : 0;
-
-       case WDIOC_GETSTATUS:
-               return put_user(0, p);
-
-       case WDIOC_GETBOOTSTATUS:
-               val = __raw_readw(imx2_wdt.base + IMX2_WDT_WRSR);
-               new_value = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
-               return put_user(new_value, p);
-
-       case WDIOC_KEEPALIVE:
-               imx2_wdt_ping();
-               return 0;
-
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_value, p))
-                       return -EFAULT;
-               if ((new_value < 1) || (new_value > IMX2_WDT_MAX_TIME))
-                       return -EINVAL;
-               imx2_wdt_set_timeout(new_value);
-               imx2_wdt.timeout = new_value;
-               imx2_wdt_ping();
-
-               /* Fallthrough to return current value */
-       case WDIOC_GETTIMEOUT:
-               return put_user(imx2_wdt.timeout, p);
-
-       default:
-               return -ENOTTY;
-       }
-}
+       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
-static ssize_t imx2_wdt_write(struct file *file, const char __user *data,
-                                               size_t len, loff_t *ppos)
-{
-       size_t i;
-       char c;
-
-       if (len == 0)   /* Can we see this even ? */
-               return 0;
-
-       clear_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
-       /* scan to see whether or not we got the magic character */
-       for (i = 0; i != len; i++) {
-               if (get_user(c, data + i))
-                       return -EFAULT;
-               if (c == 'V')
-                       set_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
+       if (imx2_wdt_is_running(wdev)) {
+               imx2_wdt_set_timeout(wdog, wdog->timeout);
+               imx2_wdt_timer_ping((unsigned long)wdog);
        }
-
-       imx2_wdt_ping();
-       return len;
 }
 
-static const struct file_operations imx2_wdt_fops = {
+static struct watchdog_ops imx2_wdt_ops = {
        .owner = THIS_MODULE,
-       .llseek = no_llseek,
-       .unlocked_ioctl = imx2_wdt_ioctl,
-       .open = imx2_wdt_open,
-       .release = imx2_wdt_close,
-       .write = imx2_wdt_write,
+       .start = imx2_wdt_start,
+       .stop = imx2_wdt_stop,
+       .ping = imx2_wdt_ping,
+       .set_timeout = imx2_wdt_set_timeout,
 };
 
-static struct miscdevice imx2_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &imx2_wdt_fops,
+static struct regmap_config imx2_wdt_regmap_config = {
+       .reg_bits = 16,
+       .reg_stride = 2,
+       .val_bits = 16,
+       .max_register = 0x8,
 };
 
 static int __init imx2_wdt_probe(struct platform_device *pdev)
 {
-       int ret;
+       struct imx2_wdt_device *wdev;
+       struct watchdog_device *wdog;
        struct resource *res;
+       void __iomem *base;
+       int ret;
+       u32 val;
+
+       wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
+       if (!wdev)
+               return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       imx2_wdt.base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(imx2_wdt.base))
-               return PTR_ERR(imx2_wdt.base);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       wdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
+                                                &imx2_wdt_regmap_config);
+       if (IS_ERR(wdev->regmap)) {
+               dev_err(&pdev->dev, "regmap init failed\n");
+               return PTR_ERR(wdev->regmap);
+       }
 
-       imx2_wdt.clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(imx2_wdt.clk)) {
+       wdev->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(wdev->clk)) {
                dev_err(&pdev->dev, "can't get Watchdog clock\n");
-               return PTR_ERR(imx2_wdt.clk);
+               return PTR_ERR(wdev->clk);
        }
 
-       imx2_wdt.timeout = clamp_t(unsigned, timeout, 1, IMX2_WDT_MAX_TIME);
-       if (imx2_wdt.timeout != timeout)
-               dev_warn(&pdev->dev, "Initial timeout out of range! "
-                       "Clamped from %u to %u\n", timeout, imx2_wdt.timeout);
+       wdog                    = &wdev->wdog;
+       wdog->info              = &imx2_wdt_info;
+       wdog->ops               = &imx2_wdt_ops;
+       wdog->min_timeout       = 1;
+       wdog->max_timeout       = IMX2_WDT_MAX_TIME;
 
-       setup_timer(&imx2_wdt.timer, imx2_wdt_timer_ping, 0);
+       clk_prepare_enable(wdev->clk);
 
-       imx2_wdt_miscdev.parent = &pdev->dev;
-       ret = misc_register(&imx2_wdt_miscdev);
-       if (ret)
-               goto fail;
+       regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val);
+       wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
 
-       dev_info(&pdev->dev,
-               "IMX2+ Watchdog Timer enabled. timeout=%ds (nowayout=%d)\n",
-                                               imx2_wdt.timeout, nowayout);
-       return 0;
+       wdog->timeout = clamp_t(unsigned, timeout, 1, IMX2_WDT_MAX_TIME);
+       if (wdog->timeout != timeout)
+               dev_warn(&pdev->dev, "Initial timeout out of range! Clamped from %u to %u\n",
+                        timeout, wdog->timeout);
+
+       platform_set_drvdata(pdev, wdog);
+       watchdog_set_drvdata(wdog, wdev);
+       watchdog_set_nowayout(wdog, nowayout);
+       watchdog_init_timeout(wdog, timeout, &pdev->dev);
+
+       setup_timer(&wdev->timer, imx2_wdt_timer_ping, (unsigned long)wdog);
+
+       imx2_wdt_ping_if_active(wdog);
 
-fail:
-       imx2_wdt_miscdev.parent = NULL;
-       return ret;
+       ret = watchdog_register_device(wdog);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot register watchdog device\n");
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "timeout %d sec (nowayout=%d)\n",
+                wdog->timeout, nowayout);
+
+       return 0;
 }
 
 static int __exit imx2_wdt_remove(struct platform_device *pdev)
 {
-       misc_deregister(&imx2_wdt_miscdev);
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
 
-       if (test_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) {
-               del_timer_sync(&imx2_wdt.timer);
+       watchdog_unregister_device(wdog);
 
-               dev_crit(imx2_wdt_miscdev.parent,
-                       "Device removed: Expect reboot!\n");
+       if (imx2_wdt_is_running(wdev)) {
+               del_timer_sync(&wdev->timer);
+               imx2_wdt_ping(wdog);
+               dev_crit(&pdev->dev, "Device removed: Expect reboot!\n");
        }
-
-       imx2_wdt_miscdev.parent = NULL;
        return 0;
 }
 
 static void imx2_wdt_shutdown(struct platform_device *pdev)
 {
-       if (test_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) {
-               /* we are running, we need to delete the timer but will give
-                * max timeout before reboot will take place */
-               del_timer_sync(&imx2_wdt.timer);
-               imx2_wdt_set_timeout(IMX2_WDT_MAX_TIME);
-               imx2_wdt_ping();
-
-               dev_crit(imx2_wdt_miscdev.parent,
-                       "Device shutdown: Expect reboot!\n");
+       struct watchdog_device *wdog = platform_get_drvdata(pdev);
+       struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+
+       if (imx2_wdt_is_running(wdev)) {
+               /*
+                * We are running, we need to delete the timer but will
+                * give max timeout before reboot will take place
+                */
+               del_timer_sync(&wdev->timer);
+               imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+               imx2_wdt_ping(wdog);
+               dev_crit(&pdev->dev, "Device shutdown: Expect reboot!\n");
        }
 }
 
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c
new file mode 100644 (file)
index 0000000..ca66e8e
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ *      intel-mid_wdt: generic Intel MID SCU watchdog driver
+ *
+ *      Platforms supported so far:
+ *      - Merrifield only
+ *
+ *      Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *      Contact: David Cohen <david.a.cohen@linux.intel.com>
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of version 2 of the GNU General
+ *      Public License as published by the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/nmi.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/platform_data/intel-mid_wdt.h>
+
+#include <asm/intel_scu_ipc.h>
+#include <asm/intel-mid.h>
+
+#define IPC_WATCHDOG 0xf8
+
+#define MID_WDT_PRETIMEOUT             15
+#define MID_WDT_TIMEOUT_MIN            (1 + MID_WDT_PRETIMEOUT)
+#define MID_WDT_TIMEOUT_MAX            170
+#define MID_WDT_DEFAULT_TIMEOUT                90
+
+/* SCU watchdog messages */
+enum {
+       SCU_WATCHDOG_START = 0,
+       SCU_WATCHDOG_STOP,
+       SCU_WATCHDOG_KEEPALIVE,
+};
+
+static inline int wdt_command(int sub, u32 *in, int inlen)
+{
+       return intel_scu_ipc_command(IPC_WATCHDOG, sub, in, inlen, NULL, 0);
+}
+
+static int wdt_start(struct watchdog_device *wd)
+{
+       int ret, in_size;
+       int timeout = wd->timeout;
+       struct ipc_wd_start {
+               u32 pretimeout;
+               u32 timeout;
+       } ipc_wd_start = { timeout - MID_WDT_PRETIMEOUT, timeout };
+
+       /*
+        * SCU expects the input size for watchdog IPC to
+        * be based on 4 bytes
+        */
+       in_size = DIV_ROUND_UP(sizeof(ipc_wd_start), 4);
+
+       ret = wdt_command(SCU_WATCHDOG_START, (u32 *)&ipc_wd_start, in_size);
+       if (ret) {
+               struct device *dev = watchdog_get_drvdata(wd);
+               dev_crit(dev, "error starting watchdog: %d\n", ret);
+       }
+
+       return ret;
+}
+
+static int wdt_ping(struct watchdog_device *wd)
+{
+       int ret;
+
+       ret = wdt_command(SCU_WATCHDOG_KEEPALIVE, NULL, 0);
+       if (ret) {
+               struct device *dev = watchdog_get_drvdata(wd);
+               dev_crit(dev, "Error executing keepalive: 0x%x\n", ret);
+       }
+
+       return ret;
+}
+
+static int wdt_stop(struct watchdog_device *wd)
+{
+       int ret;
+
+       ret = wdt_command(SCU_WATCHDOG_STOP, NULL, 0);
+       if (ret) {
+               struct device *dev = watchdog_get_drvdata(wd);
+               dev_crit(dev, "Error stopping watchdog: 0x%x\n", ret);
+       }
+
+       return ret;
+}
+
+static irqreturn_t mid_wdt_irq(int irq, void *dev_id)
+{
+       panic("Kernel Watchdog");
+
+       /* This code should not be reached */
+       return IRQ_HANDLED;
+}
+
+static const struct watchdog_info mid_wdt_info = {
+       .identity = "Intel MID SCU watchdog",
+       .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
+};
+
+static const struct watchdog_ops mid_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = wdt_start,
+       .stop = wdt_stop,
+       .ping = wdt_ping,
+};
+
+static int mid_wdt_probe(struct platform_device *pdev)
+{
+       struct watchdog_device *wdt_dev;
+       struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
+       int ret;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "missing platform data\n");
+               return -EINVAL;
+       }
+
+       if (pdata->probe) {
+               ret = pdata->probe(pdev);
+               if (ret)
+                       return ret;
+       }
+
+       wdt_dev = devm_kzalloc(&pdev->dev, sizeof(*wdt_dev), GFP_KERNEL);
+       if (!wdt_dev)
+               return -ENOMEM;
+
+       wdt_dev->info = &mid_wdt_info;
+       wdt_dev->ops = &mid_wdt_ops;
+       wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN;
+       wdt_dev->max_timeout = MID_WDT_TIMEOUT_MAX;
+       wdt_dev->timeout = MID_WDT_DEFAULT_TIMEOUT;
+
+       watchdog_set_drvdata(wdt_dev, &pdev->dev);
+       platform_set_drvdata(pdev, wdt_dev);
+
+       ret = devm_request_irq(&pdev->dev, pdata->irq, mid_wdt_irq,
+                              IRQF_SHARED | IRQF_NO_SUSPEND, "watchdog",
+                              wdt_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "error requesting warning irq %d\n",
+                       pdata->irq);
+               return ret;
+       }
+
+       ret = watchdog_register_device(wdt_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "error registering watchdog device\n");
+               return ret;
+       }
+
+       dev_info(&pdev->dev, "Intel MID watchdog device probed\n");
+
+       return 0;
+}
+
+static int mid_wdt_remove(struct platform_device *pdev)
+{
+       struct watchdog_device *wd = platform_get_drvdata(pdev);
+       watchdog_unregister_device(wd);
+       return 0;
+}
+
+static struct platform_driver mid_wdt_driver = {
+       .probe          = mid_wdt_probe,
+       .remove         = mid_wdt_remove,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "intel_mid_wdt",
+       },
+};
+
+module_platform_driver(mid_wdt_driver);
+
+MODULE_AUTHOR("David Cohen <david.a.cohen@linux.intel.com>");
+MODULE_DESCRIPTION("Watchdog Driver for Intel MID platform");
+MODULE_LICENSE("GPL");
index 20dc73844737a99cf30aa6852f6bfceb06d04984..d9c1a1601926e277c628905a2d54b582ec128eab 100644 (file)
@@ -162,7 +162,7 @@ static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data,
        kempld_get_mutex(pld);
        stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
        stage_cfg &= ~STAGE_CFG_PRESCALER_MASK;
-       stage_cfg |= STAGE_CFG_SET_PRESCALER(prescaler);
+       stage_cfg |= STAGE_CFG_SET_PRESCALER(PRESCALER_21);
        kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
        kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id),
                        stage_timeout);
index 57ccae8327ff96b0072b2013f8ebb9fb2499006d..1e6e28df5d7b8030973c7a0c50d83466fb5b3b2e 100644 (file)
@@ -225,7 +225,7 @@ static int xwdt_remove(struct platform_device *pdev)
 }
 
 /* Match table for of_platform binding */
-static struct of_device_id xwdt_of_match[] = {
+static const struct of_device_id xwdt_of_match[] = {
        { .compatible = "xlnx,xps-timebase-wdt-1.00.a", },
        { .compatible = "xlnx,xps-timebase-wdt-1.01.a", },
        {},
index 9b3c41d1870370860d582f4e8e74cf5a290d54f6..00d0741228fc04fc80fd9b002d00f7c2587a0f86 100644 (file)
@@ -55,15 +55,19 @@ struct orion_watchdog_data {
        int wdt_counter_offset;
        int wdt_enable_bit;
        int rstout_enable_bit;
+       int rstout_mask_bit;
        int (*clock_init)(struct platform_device *,
                          struct orion_watchdog *);
+       int (*enabled)(struct orion_watchdog *);
        int (*start)(struct watchdog_device *);
+       int (*stop)(struct watchdog_device *);
 };
 
 struct orion_watchdog {
        struct watchdog_device wdt;
        void __iomem *reg;
        void __iomem *rstout;
+       void __iomem *rstout_mask;
        unsigned long clk_rate;
        struct clk *clk;
        const struct orion_watchdog_data *data;
@@ -142,9 +146,35 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
        return 0;
 }
 
+static int armada375_start(struct watchdog_device *wdt_dev)
+{
+       struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+       u32 reg;
+
+       /* Set watchdog duration */
+       writel(dev->clk_rate * wdt_dev->timeout,
+              dev->reg + dev->data->wdt_counter_offset);
+
+       /* Clear the watchdog expiration bit */
+       atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0);
+
+       /* Enable watchdog timer */
+       atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
+                                               dev->data->wdt_enable_bit);
+
+       /* Enable reset on watchdog */
+       reg = readl(dev->rstout);
+       reg |= dev->data->rstout_enable_bit;
+       writel(reg, dev->rstout);
+
+       atomic_io_modify(dev->rstout_mask, dev->data->rstout_mask_bit, 0);
+       return 0;
+}
+
 static int armada370_start(struct watchdog_device *wdt_dev)
 {
        struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+       u32 reg;
 
        /* Set watchdog duration */
        writel(dev->clk_rate * wdt_dev->timeout,
@@ -157,8 +187,10 @@ static int armada370_start(struct watchdog_device *wdt_dev)
        atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
                                                dev->data->wdt_enable_bit);
 
-       atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit,
-                                     dev->data->rstout_enable_bit);
+       /* Enable reset on watchdog */
+       reg = readl(dev->rstout);
+       reg |= dev->data->rstout_enable_bit;
+       writel(reg, dev->rstout);
        return 0;
 }
 
@@ -189,7 +221,7 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
        return dev->data->start(wdt_dev);
 }
 
-static int orion_wdt_stop(struct watchdog_device *wdt_dev)
+static int orion_stop(struct watchdog_device *wdt_dev)
 {
        struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
 
@@ -202,7 +234,48 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)
        return 0;
 }
 
-static int orion_wdt_enabled(struct orion_watchdog *dev)
+static int armada375_stop(struct watchdog_device *wdt_dev)
+{
+       struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+       u32 reg;
+
+       /* Disable reset on watchdog */
+       atomic_io_modify(dev->rstout_mask, dev->data->rstout_mask_bit,
+                                          dev->data->rstout_mask_bit);
+       reg = readl(dev->rstout);
+       reg &= ~dev->data->rstout_enable_bit;
+       writel(reg, dev->rstout);
+
+       /* Disable watchdog timer */
+       atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
+
+       return 0;
+}
+
+static int armada370_stop(struct watchdog_device *wdt_dev)
+{
+       struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+       u32 reg;
+
+       /* Disable reset on watchdog */
+       reg = readl(dev->rstout);
+       reg &= ~dev->data->rstout_enable_bit;
+       writel(reg, dev->rstout);
+
+       /* Disable watchdog timer */
+       atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
+
+       return 0;
+}
+
+static int orion_wdt_stop(struct watchdog_device *wdt_dev)
+{
+       struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+       return dev->data->stop(wdt_dev);
+}
+
+static int orion_enabled(struct orion_watchdog *dev)
 {
        bool enabled, running;
 
@@ -212,6 +285,24 @@ static int orion_wdt_enabled(struct orion_watchdog *dev)
        return enabled && running;
 }
 
+static int armada375_enabled(struct orion_watchdog *dev)
+{
+       bool masked, enabled, running;
+
+       masked = readl(dev->rstout_mask) & dev->data->rstout_mask_bit;
+       enabled = readl(dev->rstout) & dev->data->rstout_enable_bit;
+       running = readl(dev->reg + TIMER_CTRL) & dev->data->wdt_enable_bit;
+
+       return !masked && enabled && running;
+}
+
+static int orion_wdt_enabled(struct watchdog_device *wdt_dev)
+{
+       struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
+
+       return dev->data->enabled(dev);
+}
+
 static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
 {
        struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -262,10 +353,6 @@ static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev,
                return devm_ioremap(&pdev->dev, res->start,
                                    resource_size(res));
 
-       /* This workaround works only for "orion-wdt", DT-enabled */
-       if (!of_device_is_compatible(pdev->dev.of_node, "marvell,orion-wdt"))
-               return NULL;
-
        rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET;
 
        WARN(1, FW_BUG "falling back to harcoded RSTOUT reg %pa\n", &rstout);
@@ -277,7 +364,9 @@ static const struct orion_watchdog_data orion_data = {
        .wdt_enable_bit = BIT(4),
        .wdt_counter_offset = 0x24,
        .clock_init = orion_wdt_clock_init,
+       .enabled = orion_enabled,
        .start = orion_start,
+       .stop = orion_stop,
 };
 
 static const struct orion_watchdog_data armada370_data = {
@@ -285,7 +374,9 @@ static const struct orion_watchdog_data armada370_data = {
        .wdt_enable_bit = BIT(8),
        .wdt_counter_offset = 0x34,
        .clock_init = armada370_wdt_clock_init,
+       .enabled = orion_enabled,
        .start = armada370_start,
+       .stop = armada370_stop,
 };
 
 static const struct orion_watchdog_data armadaxp_data = {
@@ -293,7 +384,31 @@ static const struct orion_watchdog_data armadaxp_data = {
        .wdt_enable_bit = BIT(8),
        .wdt_counter_offset = 0x34,
        .clock_init = armadaxp_wdt_clock_init,
+       .enabled = orion_enabled,
        .start = armada370_start,
+       .stop = armada370_stop,
+};
+
+static const struct orion_watchdog_data armada375_data = {
+       .rstout_enable_bit = BIT(8),
+       .rstout_mask_bit = BIT(10),
+       .wdt_enable_bit = BIT(8),
+       .wdt_counter_offset = 0x34,
+       .clock_init = armada370_wdt_clock_init,
+       .enabled = armada375_enabled,
+       .start = armada375_start,
+       .stop = armada375_stop,
+};
+
+static const struct orion_watchdog_data armada380_data = {
+       .rstout_enable_bit = BIT(8),
+       .rstout_mask_bit = BIT(10),
+       .wdt_enable_bit = BIT(8),
+       .wdt_counter_offset = 0x34,
+       .clock_init = armadaxp_wdt_clock_init,
+       .enabled = armada375_enabled,
+       .start = armada375_start,
+       .stop = armada375_stop,
 };
 
 static const struct of_device_id orion_wdt_of_match_table[] = {
@@ -309,16 +424,78 @@ static const struct of_device_id orion_wdt_of_match_table[] = {
                .compatible = "marvell,armada-xp-wdt",
                .data = &armadaxp_data,
        },
+       {
+               .compatible = "marvell,armada-375-wdt",
+               .data = &armada375_data,
+       },
+       {
+               .compatible = "marvell,armada-380-wdt",
+               .data = &armada380_data,
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
 
+static int orion_wdt_get_regs(struct platform_device *pdev,
+                             struct orion_watchdog *dev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+       dev->reg = devm_ioremap(&pdev->dev, res->start,
+                               resource_size(res));
+       if (!dev->reg)
+               return -ENOMEM;
+
+       /* Each supported compatible has some RSTOUT register quirk */
+       if (of_device_is_compatible(node, "marvell,orion-wdt")) {
+
+               dev->rstout = orion_wdt_ioremap_rstout(pdev, res->start &
+                                                      INTERNAL_REGS_MASK);
+               if (!dev->rstout)
+                       return -ENODEV;
+
+       } else if (of_device_is_compatible(node, "marvell,armada-370-wdt") ||
+                  of_device_is_compatible(node, "marvell,armada-xp-wdt")) {
+
+               /* Dedicated RSTOUT register, can be requested. */
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               dev->rstout = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(dev->rstout))
+                       return PTR_ERR(dev->rstout);
+
+       } else if (of_device_is_compatible(node, "marvell,armada-375-wdt") ||
+                  of_device_is_compatible(node, "marvell,armada-380-wdt")) {
+
+               /* Dedicated RSTOUT register, can be requested. */
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+               dev->rstout = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(dev->rstout))
+                       return PTR_ERR(dev->rstout);
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+               if (!res)
+                       return -ENODEV;
+               dev->rstout_mask = devm_ioremap(&pdev->dev, res->start,
+                                               resource_size(res));
+               if (!dev->rstout_mask)
+                       return -ENOMEM;
+
+       } else {
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
 static int orion_wdt_probe(struct platform_device *pdev)
 {
        struct orion_watchdog *dev;
        const struct of_device_id *match;
        unsigned int wdt_max_duration;  /* (seconds) */
-       struct resource *res;
        int ret, irq;
 
        dev = devm_kzalloc(&pdev->dev, sizeof(struct orion_watchdog),
@@ -336,19 +513,9 @@ static int orion_wdt_probe(struct platform_device *pdev)
        dev->wdt.min_timeout = 1;
        dev->data = match->data;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       dev->reg = devm_ioremap(&pdev->dev, res->start,
-                              resource_size(res));
-       if (!dev->reg)
-               return -ENOMEM;
-
-       dev->rstout = orion_wdt_ioremap_rstout(pdev, res->start &
-                                                    INTERNAL_REGS_MASK);
-       if (!dev->rstout)
-               return -ENODEV;
+       ret = orion_wdt_get_regs(pdev, dev);
+       if (ret)
+               return ret;
 
        ret = dev->data->clock_init(pdev, dev);
        if (ret) {
@@ -371,7 +538,7 @@ static int orion_wdt_probe(struct platform_device *pdev)
         * removed and re-insterted, or if the bootloader explicitly
         * set a running watchdog before booting the kernel.
         */
-       if (!orion_wdt_enabled(dev))
+       if (!orion_wdt_enabled(&dev->wdt))
                orion_wdt_stop(&dev->wdt);
 
        /* Request the IRQ only after the watchdog is disabled */
index d04d02b41c329d9de7467d110ad2f595125bdc79..061756e36cf8ddabeed3854b41aa615221bcb62e 100644 (file)
@@ -282,8 +282,6 @@ static int sh_wdt_probe(struct platform_device *pdev)
        wdt->timer.data         = (unsigned long)wdt;
        wdt->timer.expires      = next_ping_period(clock_division_ratio);
 
-       platform_set_drvdata(pdev, wdt);
-
        dev_info(&pdev->dev, "initialized.\n");
 
        pm_runtime_enable(&pdev->dev);
index 47629d268e0a674a74899a8c620dc128476508ea..c1b03f4235b99807d479672abdc6da0243107837 100644 (file)
@@ -59,7 +59,6 @@
  * @adev: amba device structure of wdt
  * @status: current status of wdt
  * @load_val: load value to be set for current timeout
- * @timeout: current programmed timeout
  */
 struct sp805_wdt {
        struct watchdog_device          wdd;
@@ -68,7 +67,6 @@ struct sp805_wdt {
        struct clk                      *clk;
        struct amba_device              *adev;
        unsigned int                    load_val;
-       unsigned int                    timeout;
 };
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -98,7 +96,7 @@ static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout)
        spin_lock(&wdt->lock);
        wdt->load_val = load;
        /* roundup timeout to closest positive integer value */
-       wdt->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
+       wdd->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
        spin_unlock(&wdt->lock);
 
        return 0;
index cd00a7836cdc1450ad78a6ecacf35be1048bb4c4..693b9d2c6e39e0606524675bcf16d20ebfba876b 100644 (file)
@@ -57,17 +57,17 @@ struct sunxi_wdt_dev {
  */
 
 static const int wdt_timeout_map[] = {
-       [1] = 0b0001,  /* 1s  */
-       [2] = 0b0010,  /* 2s  */
-       [3] = 0b0011,  /* 3s  */
-       [4] = 0b0100,  /* 4s  */
-       [5] = 0b0101,  /* 5s  */
-       [6] = 0b0110,  /* 6s  */
-       [8] = 0b0111,  /* 8s  */
-       [10] = 0b1000, /* 10s */
-       [12] = 0b1001, /* 12s */
-       [14] = 0b1010, /* 14s */
-       [16] = 0b1011, /* 16s */
+       [1] = 0x1,  /* 1s  */
+       [2] = 0x2,  /* 2s  */
+       [3] = 0x3,  /* 3s  */
+       [4] = 0x4,  /* 4s  */
+       [5] = 0x5,  /* 5s  */
+       [6] = 0x6,  /* 6s  */
+       [8] = 0x7,  /* 8s  */
+       [10] = 0x8, /* 10s */
+       [12] = 0x9, /* 12s */
+       [14] = 0xA, /* 14s */
+       [16] = 0xB, /* 16s */
 };
 
 static int sunxi_wdt_ping(struct watchdog_device *wdt_dev)
index d2cd9f0bcb9a2df915472446f295139f04fc0ede..56369c4f1961d0c2001094f680a6c7ed81c54ca2 100644 (file)
@@ -232,7 +232,7 @@ err_out_disable_device:
 static void wdt_remove(struct pci_dev *pdev)
 {
        watchdog_unregister_device(&wdt_dev);
-       del_timer(&timer);
+       del_timer_sync(&timer);
        iounmap(wdt_mem);
        release_mem_region(mmio, VIA_WDT_MMIO_LEN);
        release_resource(&wdt_res);
index b1da0c18fd1ac4b9d02cdb9bf9245699a83d3e3c..7165704a3e33e2e4fdd034562492122baf990ff2 100644 (file)
@@ -64,6 +64,10 @@ MODULE_PARM_DESC(nowayout,
                "Watchdog cannot be stopped once started (default="
                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
+static int early_disable;
+module_param(early_disable, int, 0);
+MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)");
+
 /*
  *     Kernel methods.
  */
@@ -208,9 +212,14 @@ static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
 
        t = superio_inb(cr_wdt_timeout);
        if (t != 0) {
-               pr_info("Watchdog already running. Resetting timeout to %d sec\n",
-                       wdog->timeout);
-               superio_outb(cr_wdt_timeout, wdog->timeout);
+               if (early_disable) {
+                       pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
+                       superio_outb(cr_wdt_timeout, 0);
+               } else {
+                       pr_info("Watchdog already running. Resetting timeout to %d sec\n",
+                               wdog->timeout);
+                       superio_outb(cr_wdt_timeout, wdog->timeout);
+               }
        }
 
        /* set second mode & disable keyboard turning off watchdog */
diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c
deleted file mode 100644 (file)
index e9ea856..0000000
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- *     w83697hf/hg WDT driver
- *
- *     (c) Copyright 2006 Samuel Tardieu <sam@rfc1149.net>
- *     (c) Copyright 2006 Marcus Junker <junker@anduras.de>
- *
- *     Based on w83627hf_wdt.c which is based on advantechwdt.c
- *     which is based on wdt.c.
- *     Original copyright messages:
- *
- *     (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
- *
- *     (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
- *
- *     (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
- *                                             All Rights Reserved.
- *
- *     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.
- *
- *     Neither Marcus Junker nor ANDURAS AG admit liability nor provide
- *     warranty for any of this software. This material is provided
- *     "AS-IS" and at no charge.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/fs.h>
-#include <linux/ioport.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-
-
-#define WATCHDOG_NAME "w83697hf/hg WDT"
-#define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
-#define WATCHDOG_EARLY_DISABLE 1       /* Disable until userland kicks in */
-
-static unsigned long wdt_is_open;
-static char expect_close;
-static DEFINE_SPINLOCK(io_lock);
-
-/* You must set this - there is no sane way to probe for this board. */
-static int wdt_io = 0x2e;
-module_param(wdt_io, int, 0);
-MODULE_PARM_DESC(wdt_io,
-               "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)");
-
-static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
-module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout,
-       "Watchdog timeout in seconds. 1<= timeout <=255 (default="
-                               __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-
-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) ")");
-
-static int early_disable = WATCHDOG_EARLY_DISABLE;
-module_param(early_disable, int, 0);
-MODULE_PARM_DESC(early_disable,
-       "Watchdog gets disabled at boot time (default="
-                               __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")");
-
-/*
- *     Kernel methods.
- */
-
-#define W83697HF_EFER (wdt_io + 0)  /* Extended Function Enable Register */
-#define W83697HF_EFIR (wdt_io + 0)  /* Extended Function Index Register
-                                                       (same as EFER) */
-#define W83697HF_EFDR (wdt_io + 1)  /* Extended Function Data Register */
-
-static inline void w83697hf_unlock(void)
-{
-       outb_p(0x87, W83697HF_EFER);    /* Enter extended function mode */
-       outb_p(0x87, W83697HF_EFER);    /* Again according to manual */
-}
-
-static inline void w83697hf_lock(void)
-{
-       outb_p(0xAA, W83697HF_EFER);    /* Leave extended function mode */
-}
-
-/*
- *     The three functions w83697hf_get_reg(), w83697hf_set_reg() and
- *     w83697hf_write_timeout() must be called with the device unlocked.
- */
-
-static unsigned char w83697hf_get_reg(unsigned char reg)
-{
-       outb_p(reg, W83697HF_EFIR);
-       return inb_p(W83697HF_EFDR);
-}
-
-static void w83697hf_set_reg(unsigned char reg, unsigned char data)
-{
-       outb_p(reg, W83697HF_EFIR);
-       outb_p(data, W83697HF_EFDR);
-}
-
-static void w83697hf_write_timeout(int timeout)
-{
-       /* Write Timeout counter to CRF4 */
-       w83697hf_set_reg(0xF4, timeout);
-}
-
-static void w83697hf_select_wdt(void)
-{
-       w83697hf_unlock();
-       w83697hf_set_reg(0x07, 0x08);   /* Switch to logic device 8 (GPIO2) */
-}
-
-static inline void w83697hf_deselect_wdt(void)
-{
-       w83697hf_lock();
-}
-
-static void w83697hf_init(void)
-{
-       unsigned char bbuf;
-
-       w83697hf_select_wdt();
-
-       bbuf = w83697hf_get_reg(0x29);
-       bbuf &= ~0x60;
-       bbuf |= 0x20;
-
-       /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
-       w83697hf_set_reg(0x29, bbuf);
-
-       bbuf = w83697hf_get_reg(0xF3);
-       bbuf &= ~0x04;
-       w83697hf_set_reg(0xF3, bbuf);   /* Count mode is seconds */
-
-       w83697hf_deselect_wdt();
-}
-
-static void wdt_ping(void)
-{
-       spin_lock(&io_lock);
-       w83697hf_select_wdt();
-
-       w83697hf_write_timeout(timeout);
-
-       w83697hf_deselect_wdt();
-       spin_unlock(&io_lock);
-}
-
-static void wdt_enable(void)
-{
-       spin_lock(&io_lock);
-       w83697hf_select_wdt();
-
-       w83697hf_write_timeout(timeout);
-       w83697hf_set_reg(0x30, 1);      /* Enable timer */
-
-       w83697hf_deselect_wdt();
-       spin_unlock(&io_lock);
-}
-
-static void wdt_disable(void)
-{
-       spin_lock(&io_lock);
-       w83697hf_select_wdt();
-
-       w83697hf_set_reg(0x30, 0);      /* Disable timer */
-       w83697hf_write_timeout(0);
-
-       w83697hf_deselect_wdt();
-       spin_unlock(&io_lock);
-}
-
-static unsigned char wdt_running(void)
-{
-       unsigned char t;
-
-       spin_lock(&io_lock);
-       w83697hf_select_wdt();
-
-       t = w83697hf_get_reg(0xF4);     /* Read timer */
-
-       w83697hf_deselect_wdt();
-       spin_unlock(&io_lock);
-
-       return t;
-}
-
-static int wdt_set_heartbeat(int t)
-{
-       if (t < 1 || t > 255)
-               return -EINVAL;
-
-       timeout = t;
-       return 0;
-}
-
-static ssize_t wdt_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
-{
-       if (count) {
-               if (!nowayout) {
-                       size_t i;
-
-                       expect_close = 0;
-
-                       for (i = 0; i != count; i++) {
-                               char c;
-                               if (get_user(c, buf + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       expect_close = 42;
-                       }
-               }
-               wdt_ping();
-       }
-       return count;
-}
-
-static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       int new_timeout;
-       static const struct watchdog_info ident = {
-               .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
-                                                       | WDIOF_MAGICCLOSE,
-               .firmware_version = 1,
-               .identity = "W83697HF WDT",
-       };
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               if (copy_to_user(argp, &ident, sizeof(ident)))
-                       return -EFAULT;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               return put_user(0, p);
-
-       case WDIOC_SETOPTIONS:
-       {
-               int options, retval = -EINVAL;
-
-               if (get_user(options, p))
-                       return -EFAULT;
-
-               if (options & WDIOS_DISABLECARD) {
-                       wdt_disable();
-                       retval = 0;
-               }
-
-               if (options & WDIOS_ENABLECARD) {
-                       wdt_enable();
-                       retval = 0;
-               }
-
-               return retval;
-       }
-
-       case WDIOC_KEEPALIVE:
-               wdt_ping();
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_timeout, p))
-                       return -EFAULT;
-               if (wdt_set_heartbeat(new_timeout))
-                       return -EINVAL;
-               wdt_ping();
-               /* Fall */
-
-       case WDIOC_GETTIMEOUT:
-               return put_user(timeout, p);
-
-       default:
-               return -ENOTTY;
-       }
-       return 0;
-}
-
-static int wdt_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(0, &wdt_is_open))
-               return -EBUSY;
-       /*
-        *      Activate
-        */
-
-       wdt_enable();
-       return nonseekable_open(inode, file);
-}
-
-static int wdt_close(struct inode *inode, struct file *file)
-{
-       if (expect_close == 42)
-               wdt_disable();
-       else {
-               pr_crit("Unexpected close, not stopping watchdog!\n");
-               wdt_ping();
-       }
-       expect_close = 0;
-       clear_bit(0, &wdt_is_open);
-       return 0;
-}
-
-/*
- *     Notifier for system down
- */
-
-static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
-       void *unused)
-{
-       if (code == SYS_DOWN || code == SYS_HALT)
-               wdt_disable();  /* Turn the WDT off */
-
-       return NOTIFY_DONE;
-}
-
-/*
- *     Kernel Interfaces
- */
-
-static const struct file_operations wdt_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = wdt_write,
-       .unlocked_ioctl = wdt_ioctl,
-       .open           = wdt_open,
-       .release        = wdt_close,
-};
-
-static struct miscdevice wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &wdt_fops,
-};
-
-/*
- *     The WDT needs to learn about soft shutdowns in order to
- *     turn the timebomb registers off.
- */
-
-static struct notifier_block wdt_notifier = {
-       .notifier_call = wdt_notify_sys,
-};
-
-static int w83697hf_check_wdt(void)
-{
-       if (!request_region(wdt_io, 2, WATCHDOG_NAME)) {
-               pr_err("I/O address 0x%x already in use\n", wdt_io);
-               return -EIO;
-       }
-
-       pr_debug("Looking for watchdog at address 0x%x\n", wdt_io);
-       w83697hf_unlock();
-       if (w83697hf_get_reg(0x20) == 0x60) {
-               pr_info("watchdog found at address 0x%x\n", wdt_io);
-               w83697hf_lock();
-               return 0;
-       }
-       /* Reprotect in case it was a compatible device */
-       w83697hf_lock();
-
-       pr_info("watchdog not found at address 0x%x\n", wdt_io);
-       release_region(wdt_io, 2);
-       return -EIO;
-}
-
-static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 };
-
-static int __init wdt_init(void)
-{
-       int ret, i, found = 0;
-
-       pr_info("WDT driver for W83697HF/HG initializing\n");
-
-       if (wdt_io == 0) {
-               /* we will autodetect the W83697HF/HG watchdog */
-               for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) {
-                       wdt_io = w83697hf_ioports[i];
-                       if (!w83697hf_check_wdt())
-                               found++;
-               }
-       } else {
-               if (!w83697hf_check_wdt())
-                       found++;
-       }
-
-       if (!found) {
-               pr_err("No W83697HF/HG could be found\n");
-               ret = -ENODEV;
-               goto out;
-       }
-
-       w83697hf_init();
-       if (early_disable) {
-               if (wdt_running())
-                       pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
-               wdt_disable();
-       }
-
-       if (wdt_set_heartbeat(timeout)) {
-               wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-               pr_info("timeout value must be 1 <= timeout <= 255, using %d\n",
-                       WATCHDOG_TIMEOUT);
-       }
-
-       ret = register_reboot_notifier(&wdt_notifier);
-       if (ret != 0) {
-               pr_err("cannot register reboot notifier (err=%d)\n", ret);
-               goto unreg_regions;
-       }
-
-       ret = misc_register(&wdt_miscdev);
-       if (ret != 0) {
-               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-                      WATCHDOG_MINOR, ret);
-               goto unreg_reboot;
-       }
-
-       pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
-               timeout, nowayout);
-
-out:
-       return ret;
-unreg_reboot:
-       unregister_reboot_notifier(&wdt_notifier);
-unreg_regions:
-       release_region(wdt_io, 2);
-       goto out;
-}
-
-static void __exit wdt_exit(void)
-{
-       misc_deregister(&wdt_miscdev);
-       unregister_reboot_notifier(&wdt_notifier);
-       release_region(wdt_io, 2);
-}
-
-module_init(wdt_init);
-module_exit(wdt_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Marcus Junker <junker@anduras.de>");
-MODULE_AUTHOR("Samuel Tardieu <sam@rfc1149.net>");
-MODULE_DESCRIPTION("w83697hf/hg WDT driver");
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
deleted file mode 100644 (file)
index ff58cb7..0000000
+++ /dev/null
@@ -1,397 +0,0 @@
-/*
- *     w83697ug/uf WDT driver
- *
- *     (c) Copyright 2008 Flemming Fransen <ff@nrvissing.net>
- *             reused original code to support w83697ug/uf.
- *
- *     Based on w83627hf_wdt.c which is based on advantechwdt.c
- *     which is based on wdt.c.
- *     Original copyright messages:
- *
- *     (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
- *             added support for W83627THF.
- *
- *     (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
- *
- *     (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
- *
- *     (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
- *                             http://www.redhat.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.
- *
- *     Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
- *     warranty for any of this software. This material is provided
- *     "AS-IS" and at no charge.
- *
- *     (c) Copyright 1995    Alan Cox <alan@redhat.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/fs.h>
-#include <linux/ioport.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/uaccess.h>
-
-
-#define WATCHDOG_NAME "w83697ug/uf WDT"
-#define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
-
-static unsigned long wdt_is_open;
-static char expect_close;
-static DEFINE_SPINLOCK(io_lock);
-
-static int wdt_io = 0x2e;
-module_param(wdt_io, int, 0);
-MODULE_PARM_DESC(wdt_io, "w83697ug/uf WDT io port (default 0x2e)");
-
-static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
-module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout,
-       "Watchdog timeout in seconds. 1<= timeout <=255 (default="
-                               __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
-
-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) ")");
-
-/*
- *     Kernel methods.
- */
-
-#define WDT_EFER (wdt_io+0)   /* Extended Function Enable Registers */
-#define WDT_EFIR (wdt_io+0)   /* Extended Function Index Register
-                                                       (same as EFER) */
-#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
-
-static int w83697ug_select_wd_register(void)
-{
-       unsigned char c;
-       unsigned char version;
-
-       outb_p(0x87, WDT_EFER); /* Enter extended function mode */
-       outb_p(0x87, WDT_EFER); /* Again according to manual */
-
-       outb(0x20, WDT_EFER);   /* check chip version   */
-       version = inb(WDT_EFDR);
-
-       if (version == 0x68) {  /* W83697UG             */
-               pr_info("Watchdog chip version 0x%02x = W83697UG/UF found at 0x%04x\n",
-                       version, wdt_io);
-
-               outb_p(0x2b, WDT_EFER);
-               c = inb_p(WDT_EFDR);    /* select WDT0 */
-               c &= ~0x04;
-               outb_p(0x2b, WDT_EFER);
-               outb_p(c, WDT_EFDR);    /* set pin118 to WDT0 */
-
-       } else {
-               pr_err("No W83697UG/UF could be found\n");
-               return -ENODEV;
-       }
-
-       outb_p(0x07, WDT_EFER); /* point to logical device number reg */
-       outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
-       outb_p(0x30, WDT_EFER); /* select CR30 */
-       c = inb_p(WDT_EFDR);
-       outb_p(c | 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
-
-       return 0;
-}
-
-static void w83697ug_unselect_wd_register(void)
-{
-       outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
-}
-
-static int w83697ug_init(void)
-{
-       int ret;
-       unsigned char t;
-
-       ret = w83697ug_select_wd_register();
-       if (ret != 0)
-               return ret;
-
-       outb_p(0xF6, WDT_EFER); /* Select CRF6 */
-       t = inb_p(WDT_EFDR);    /* read CRF6 */
-       if (t != 0) {
-               pr_info("Watchdog already running. Resetting timeout to %d sec\n",
-                       timeout);
-               outb_p(timeout, WDT_EFDR);    /* Write back to CRF6 */
-       }
-       outb_p(0xF5, WDT_EFER); /* Select CRF5 */
-       t = inb_p(WDT_EFDR);    /* read CRF5 */
-       t &= ~0x0C;             /* set second mode &
-                                       disable keyboard turning off watchdog */
-       outb_p(t, WDT_EFDR);    /* Write back to CRF5 */
-
-       w83697ug_unselect_wd_register();
-       return 0;
-}
-
-static void wdt_ctrl(int timeout)
-{
-       spin_lock(&io_lock);
-
-       if (w83697ug_select_wd_register() < 0) {
-               spin_unlock(&io_lock);
-               return;
-       }
-
-       outb_p(0xF4, WDT_EFER);    /* Select CRF4 */
-       outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */
-
-       w83697ug_unselect_wd_register();
-
-       spin_unlock(&io_lock);
-}
-
-static int wdt_ping(void)
-{
-       wdt_ctrl(timeout);
-       return 0;
-}
-
-static int wdt_disable(void)
-{
-       wdt_ctrl(0);
-       return 0;
-}
-
-static int wdt_set_heartbeat(int t)
-{
-       if (t < 1 || t > 255)
-               return -EINVAL;
-
-       timeout = t;
-       return 0;
-}
-
-static ssize_t wdt_write(struct file *file, const char __user *buf,
-                                               size_t count, loff_t *ppos)
-{
-       if (count) {
-               if (!nowayout) {
-                       size_t i;
-
-                       expect_close = 0;
-
-                       for (i = 0; i != count; i++) {
-                               char c;
-                               if (get_user(c, buf + i))
-                                       return -EFAULT;
-                               if (c == 'V')
-                                       expect_close = 42;
-                       }
-               }
-               wdt_ping();
-       }
-       return count;
-}
-
-static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       int new_timeout;
-       static const struct watchdog_info ident = {
-               .options =              WDIOF_KEEPALIVEPING |
-                                       WDIOF_SETTIMEOUT |
-                                       WDIOF_MAGICCLOSE,
-               .firmware_version =     1,
-               .identity =             "W83697UG WDT",
-       };
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               if (copy_to_user(argp, &ident, sizeof(ident)))
-                       return -EFAULT;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               return put_user(0, p);
-
-       case WDIOC_SETOPTIONS:
-       {
-               int options, retval = -EINVAL;
-
-               if (get_user(options, p))
-                       return -EFAULT;
-
-               if (options & WDIOS_DISABLECARD) {
-                       wdt_disable();
-                       retval = 0;
-               }
-
-               if (options & WDIOS_ENABLECARD) {
-                       wdt_ping();
-                       retval = 0;
-               }
-
-               return retval;
-       }
-
-       case WDIOC_KEEPALIVE:
-               wdt_ping();
-               break;
-
-       case WDIOC_SETTIMEOUT:
-               if (get_user(new_timeout, p))
-                       return -EFAULT;
-               if (wdt_set_heartbeat(new_timeout))
-                       return -EINVAL;
-               wdt_ping();
-               /* Fall */
-
-       case WDIOC_GETTIMEOUT:
-               return put_user(timeout, p);
-
-       default:
-               return -ENOTTY;
-       }
-       return 0;
-}
-
-static int wdt_open(struct inode *inode, struct file *file)
-{
-       if (test_and_set_bit(0, &wdt_is_open))
-               return -EBUSY;
-       /*
-        *      Activate
-        */
-
-       wdt_ping();
-       return nonseekable_open(inode, file);
-}
-
-static int wdt_close(struct inode *inode, struct file *file)
-{
-       if (expect_close == 42)
-               wdt_disable();
-       else {
-               pr_crit("Unexpected close, not stopping watchdog!\n");
-               wdt_ping();
-       }
-       expect_close = 0;
-       clear_bit(0, &wdt_is_open);
-       return 0;
-}
-
-/*
- *     Notifier for system down
- */
-
-static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
-       void *unused)
-{
-       if (code == SYS_DOWN || code == SYS_HALT)
-               wdt_disable();  /* Turn the WDT off */
-
-       return NOTIFY_DONE;
-}
-
-/*
- *     Kernel Interfaces
- */
-
-static const struct file_operations wdt_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = wdt_write,
-       .unlocked_ioctl = wdt_ioctl,
-       .open           = wdt_open,
-       .release        = wdt_close,
-};
-
-static struct miscdevice wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &wdt_fops,
-};
-
-/*
- *     The WDT needs to learn about soft shutdowns in order to
- *     turn the timebomb registers off.
- */
-
-static struct notifier_block wdt_notifier = {
-       .notifier_call = wdt_notify_sys,
-};
-
-static int __init wdt_init(void)
-{
-       int ret;
-
-       pr_info("WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising\n");
-
-       if (wdt_set_heartbeat(timeout)) {
-               wdt_set_heartbeat(WATCHDOG_TIMEOUT);
-               pr_info("timeout value must be 1<=timeout<=255, using %d\n",
-                       WATCHDOG_TIMEOUT);
-       }
-
-       if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
-               pr_err("I/O address 0x%04x already in use\n", wdt_io);
-               ret = -EIO;
-               goto out;
-       }
-
-       ret = w83697ug_init();
-       if (ret != 0)
-               goto unreg_regions;
-
-       ret = register_reboot_notifier(&wdt_notifier);
-       if (ret != 0) {
-               pr_err("cannot register reboot notifier (err=%d)\n", ret);
-               goto unreg_regions;
-       }
-
-       ret = misc_register(&wdt_miscdev);
-       if (ret != 0) {
-               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-                      WATCHDOG_MINOR, ret);
-               goto unreg_reboot;
-       }
-
-       pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
-               timeout, nowayout);
-
-out:
-       return ret;
-unreg_reboot:
-       unregister_reboot_notifier(&wdt_notifier);
-unreg_regions:
-       release_region(wdt_io, 1);
-       goto out;
-}
-
-static void __exit wdt_exit(void)
-{
-       misc_deregister(&wdt_miscdev);
-       unregister_reboot_notifier(&wdt_notifier);
-       release_region(wdt_io, 1);
-}
-
-module_init(wdt_init);
-module_exit(wdt_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Flemming Frandsen <ff@nrvissing.net>");
-MODULE_DESCRIPTION("w83697ug/uf WDT driver");
diff --git a/include/linux/platform_data/intel-mid_wdt.h b/include/linux/platform_data/intel-mid_wdt.h
new file mode 100644 (file)
index 0000000..b982534
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ *      intel-mid_wdt: generic Intel MID SCU watchdog driver
+ *
+ *      Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *      Contact: David Cohen <david.a.cohen@linux.intel.com>
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of version 2 of the GNU General
+ *      Public License as published by the Free Software Foundation.
+ */
+
+#ifndef __INTEL_MID_WDT_H__
+#define __INTEL_MID_WDT_H__
+
+#include <linux/platform_device.h>
+
+struct intel_mid_wdt_pdata {
+       int irq;
+       int (*probe)(struct platform_device *pdev);
+};
+
+#endif /*__INTEL_MID_WDT_H__*/