aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-06-10 22:16:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-10 22:16:36 -0400
commitdfb945473ae8528fd885607b6fa843c676745e0c (patch)
tree5f3c17787f90c2d2112e3c93d944e067c8f8c1f7
parentc5aec4c76af1a2d89ee2f2d4d5463b2ad2d85de5 (diff)
parent78a3bb9e408be6aadcd4a609d14a05038f2a132a (diff)
Merge git://www.linux-watchdog.org/linux-watchdog
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 ...
-rw-r--r--Documentation/devicetree/bindings/watchdog/marvel.txt7
-rw-r--r--arch/powerpc/kernel/setup-common.c27
-rw-r--r--arch/x86/platform/intel-mid/device_libs/Makefile1
-rw-r--r--arch/x86/platform/intel-mid/device_libs/platform_wdt.c72
-rw-r--r--drivers/watchdog/Kconfig49
-rw-r--r--drivers/watchdog/Makefile3
-rw-r--r--drivers/watchdog/ath79_wdt.c16
-rw-r--r--drivers/watchdog/booke_wdt.c51
-rw-r--r--drivers/watchdog/imx2_wdt.c320
-rw-r--r--drivers/watchdog/intel-mid_wdt.c184
-rw-r--r--drivers/watchdog/kempld_wdt.c2
-rw-r--r--drivers/watchdog/of_xilinx_wdt.c2
-rw-r--r--drivers/watchdog/orion_wdt.c213
-rw-r--r--drivers/watchdog/shwdt.c2
-rw-r--r--drivers/watchdog/sp805_wdt.c4
-rw-r--r--drivers/watchdog/sunxi_wdt.c22
-rw-r--r--drivers/watchdog/via_wdt.c2
-rw-r--r--drivers/watchdog/w83627hf_wdt.c15
-rw-r--r--drivers/watchdog/w83697hf_wdt.c460
-rw-r--r--drivers/watchdog/w83697ug_wdt.c397
-rw-r--r--include/linux/platform_data/intel-mid_wdt.h22
21 files changed, 710 insertions, 1161 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt
index de11eb4c121f..97223fddb7bd 100644
--- a/Documentation/devicetree/bindings/watchdog/marvel.txt
+++ b/Documentation/devicetree/bindings/watchdog/marvel.txt
@@ -5,11 +5,18 @@ Required Properties:
5- Compatibility : "marvell,orion-wdt" 5- Compatibility : "marvell,orion-wdt"
6 "marvell,armada-370-wdt" 6 "marvell,armada-370-wdt"
7 "marvell,armada-xp-wdt" 7 "marvell,armada-xp-wdt"
8 "marvell,armada-375-wdt"
9 "marvell,armada-380-wdt"
8 10
9- reg : Should contain two entries: first one with the 11- reg : Should contain two entries: first one with the
10 timer control address, second one with the 12 timer control address, second one with the
11 rstout enable address. 13 rstout enable address.
12 14
15For "marvell,armada-375-wdt" and "marvell,armada-380-wdt":
16
17- reg : A third entry is mandatory and should contain the
18 shared mask/unmask RSTOUT address.
19
13Optional properties: 20Optional properties:
14 21
15- interrupts : Contains the IRQ for watchdog expiration 22- interrupts : Contains the IRQ for watchdog expiration
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index aa0f5edd8570..d4d418376f99 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -728,33 +728,6 @@ static int powerpc_debugfs_init(void)
728arch_initcall(powerpc_debugfs_init); 728arch_initcall(powerpc_debugfs_init);
729#endif 729#endif
730 730
731#ifdef CONFIG_BOOKE_WDT
732extern u32 booke_wdt_enabled;
733extern u32 booke_wdt_period;
734
735/* Checks wdt=x and wdt_period=xx command-line option */
736notrace int __init early_parse_wdt(char *p)
737{
738 if (p && strncmp(p, "0", 1) != 0)
739 booke_wdt_enabled = 1;
740
741 return 0;
742}
743early_param("wdt", early_parse_wdt);
744
745int __init early_parse_wdt_period(char *p)
746{
747 unsigned long ret;
748 if (p) {
749 if (!kstrtol(p, 0, &ret))
750 booke_wdt_period = ret;
751 }
752
753 return 0;
754}
755early_param("wdt_period", early_parse_wdt_period);
756#endif /* CONFIG_BOOKE_WDT */
757
758void ppc_printk_progress(char *s, unsigned short hex) 731void ppc_printk_progress(char *s, unsigned short hex)
759{ 732{
760 pr_info("%s\n", s); 733 pr_info("%s\n", s);
diff --git a/arch/x86/platform/intel-mid/device_libs/Makefile b/arch/x86/platform/intel-mid/device_libs/Makefile
index 097e7a7940d8..af9307f2cc28 100644
--- a/arch/x86/platform/intel-mid/device_libs/Makefile
+++ b/arch/x86/platform/intel-mid/device_libs/Makefile
@@ -20,3 +20,4 @@ obj-$(subst m,y,$(CONFIG_DRM_MEDFIELD)) += platform_tc35876x.o
20obj-$(subst m,y,$(CONFIG_SERIAL_MRST_MAX3110)) += platform_max3111.o 20obj-$(subst m,y,$(CONFIG_SERIAL_MRST_MAX3110)) += platform_max3111.o
21# MISC Devices 21# MISC Devices
22obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o 22obj-$(subst m,y,$(CONFIG_KEYBOARD_GPIO)) += platform_gpio_keys.o
23obj-$(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
index 000000000000..973cf3bfa9fd
--- /dev/null
+++ b/arch/x86/platform/intel-mid/device_libs/platform_wdt.c
@@ -0,0 +1,72 @@
1/*
2 * platform_wdt.c: Watchdog platform library file
3 *
4 * (C) Copyright 2014 Intel Corporation
5 * Author: David Cohen <david.a.cohen@linux.intel.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; version 2
10 * of the License.
11 */
12
13#include <linux/init.h>
14#include <linux/interrupt.h>
15#include <linux/platform_device.h>
16#include <linux/platform_data/intel-mid_wdt.h>
17#include <asm/intel-mid.h>
18#include <asm/io_apic.h>
19
20#define TANGIER_EXT_TIMER0_MSI 15
21
22static struct platform_device wdt_dev = {
23 .name = "intel_mid_wdt",
24 .id = -1,
25};
26
27static int tangier_probe(struct platform_device *pdev)
28{
29 int ioapic;
30 int irq;
31 struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
32 struct io_apic_irq_attr irq_attr = { 0 };
33
34 if (!pdata)
35 return -EINVAL;
36
37 irq = pdata->irq;
38 ioapic = mp_find_ioapic(irq);
39 if (ioapic >= 0) {
40 int ret;
41 irq_attr.ioapic = ioapic;
42 irq_attr.ioapic_pin = irq;
43 irq_attr.trigger = 1;
44 /* irq_attr.polarity = 0; -> Active high */
45 ret = io_apic_set_pci_routing(NULL, irq, &irq_attr);
46 if (ret)
47 return ret;
48 } else {
49 dev_warn(&pdev->dev, "cannot find interrupt %d in ioapic\n",
50 irq);
51 return -EINVAL;
52 }
53
54 return 0;
55}
56
57static struct intel_mid_wdt_pdata tangier_pdata = {
58 .irq = TANGIER_EXT_TIMER0_MSI,
59 .probe = tangier_probe,
60};
61
62static int __init register_mid_wdt(void)
63{
64 if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER) {
65 wdt_dev.dev.platform_data = &tangier_pdata;
66 return platform_device_register(&wdt_dev);
67 }
68
69 return -ENODEV;
70}
71
72rootfs_initcall(register_mid_wdt);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 74ec8fc5cc03..c845527b503a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -272,7 +272,7 @@ config PNX4008_WATCHDOG
272 272
273config IOP_WATCHDOG 273config IOP_WATCHDOG
274 tristate "IOP Watchdog" 274 tristate "IOP Watchdog"
275 depends on PLAT_IOP 275 depends on ARCH_IOP13XX
276 select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X) 276 select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
277 help 277 help
278 Say Y here if to include support for the watchdog timer 278 Say Y here if to include support for the watchdog timer
@@ -378,6 +378,8 @@ config MAX63XX_WATCHDOG
378config IMX2_WDT 378config IMX2_WDT
379 tristate "IMX2+ Watchdog" 379 tristate "IMX2+ Watchdog"
380 depends on ARCH_MXC 380 depends on ARCH_MXC
381 select REGMAP_MMIO
382 select WATCHDOG_CORE
381 help 383 help
382 This is the driver for the hardware watchdog 384 This is the driver for the hardware watchdog
383 on the Freescale IMX2 and later processors. 385 on the Freescale IMX2 and later processors.
@@ -663,6 +665,19 @@ config INTEL_SCU_WATCHDOG
663 665
664 To compile this driver as a module, choose M here. 666 To compile this driver as a module, choose M here.
665 667
668config INTEL_MID_WATCHDOG
669 tristate "Intel MID Watchdog Timer"
670 depends on X86_INTEL_MID
671 select WATCHDOG_CORE
672 ---help---
673 Watchdog timer driver built into the Intel SCU for Intel MID
674 Platforms.
675
676 This driver currently supports only the watchdog evolution
677 implementation in SCU, available for Merrifield generation.
678
679 To compile this driver as a module, choose M here.
680
666config ITCO_WDT 681config ITCO_WDT
667 tristate "Intel TCO Timer/Watchdog" 682 tristate "Intel TCO Timer/Watchdog"
668 depends on (X86 || IA64) && PCI 683 depends on (X86 || IA64) && PCI
@@ -835,7 +850,7 @@ config 60XX_WDT
835 850
836config SBC8360_WDT 851config SBC8360_WDT
837 tristate "SBC8360 Watchdog Timer" 852 tristate "SBC8360 Watchdog Timer"
838 depends on X86 853 depends on X86_32
839 ---help--- 854 ---help---
840 855
841 This is the driver for the hardware watchdog on the SBC8360 Single 856 This is the driver for the hardware watchdog on the SBC8360 Single
@@ -938,36 +953,6 @@ config W83627HF_WDT
938 953
939 Most people will say N. 954 Most people will say N.
940 955
941config W83697HF_WDT
942 tristate "W83697HF/W83697HG Watchdog Timer"
943 depends on X86
944 ---help---
945 This is the driver for the hardware watchdog on the W83697HF/HG
946 chipset as used in Dedibox/VIA motherboards (and likely others).
947 This watchdog simply watches your kernel to make sure it doesn't
948 freeze, and if it does, it reboots your computer after a certain
949 amount of time.
950
951 To compile this driver as a module, choose M here: the
952 module will be called w83697hf_wdt.
953
954 Most people will say N.
955
956config W83697UG_WDT
957 tristate "W83697UG/W83697UF Watchdog Timer"
958 depends on X86
959 ---help---
960 This is the driver for the hardware watchdog on the W83697UG/UF
961 chipset as used in MSI Fuzzy CX700 VIA motherboards (and likely others).
962 This watchdog simply watches your kernel to make sure it doesn't
963 freeze, and if it does, it reboots your computer after a certain
964 amount of time.
965
966 To compile this driver as a module, choose M here: the
967 module will be called w83697ug_wdt.
968
969 Most people will say N.
970
971config W83877F_WDT 956config W83877F_WDT
972 tristate "W83877F (EMACS) Watchdog Timer" 957 tristate "W83877F (EMACS) Watchdog Timer"
973 depends on X86 958 depends on X86
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 1b5f3d5efad5..7b8a91ed20e7 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -107,13 +107,12 @@ obj-$(CONFIG_SMSC_SCH311X_WDT) += sch311x_wdt.o
107obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o 107obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
108obj-$(CONFIG_VIA_WDT) += via_wdt.o 108obj-$(CONFIG_VIA_WDT) += via_wdt.o
109obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o 109obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
110obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
111obj-$(CONFIG_W83697UG_WDT) += w83697ug_wdt.o
112obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o 110obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
113obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o 111obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
114obj-$(CONFIG_MACHZ_WDT) += machzwd.o 112obj-$(CONFIG_MACHZ_WDT) += machzwd.o
115obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o 113obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
116obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o 114obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
115obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o
117 116
118# M32R Architecture 117# M32R Architecture
119 118
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index 399c3fddecf6..41ac4660fb89 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -20,6 +20,7 @@
20#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 20#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
21 21
22#include <linux/bitops.h> 22#include <linux/bitops.h>
23#include <linux/delay.h>
23#include <linux/errno.h> 24#include <linux/errno.h>
24#include <linux/fs.h> 25#include <linux/fs.h>
25#include <linux/io.h> 26#include <linux/io.h>
@@ -90,6 +91,15 @@ static inline void ath79_wdt_keepalive(void)
90static inline void ath79_wdt_enable(void) 91static inline void ath79_wdt_enable(void)
91{ 92{
92 ath79_wdt_keepalive(); 93 ath79_wdt_keepalive();
94
95 /*
96 * Updating the TIMER register requires a few microseconds
97 * on the AR934x SoCs at least. Use a small delay to ensure
98 * that the TIMER register is updated within the hardware
99 * before enabling the watchdog.
100 */
101 udelay(2);
102
93 ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR); 103 ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR);
94 /* flush write */ 104 /* flush write */
95 ath79_wdt_rr(WDOG_REG_CTRL); 105 ath79_wdt_rr(WDOG_REG_CTRL);
@@ -255,7 +265,7 @@ static int ath79_wdt_probe(struct platform_device *pdev)
255 if (IS_ERR(wdt_clk)) 265 if (IS_ERR(wdt_clk))
256 return PTR_ERR(wdt_clk); 266 return PTR_ERR(wdt_clk);
257 267
258 err = clk_enable(wdt_clk); 268 err = clk_prepare_enable(wdt_clk);
259 if (err) 269 if (err)
260 return err; 270 return err;
261 271
@@ -286,14 +296,14 @@ static int ath79_wdt_probe(struct platform_device *pdev)
286 return 0; 296 return 0;
287 297
288err_clk_disable: 298err_clk_disable:
289 clk_disable(wdt_clk); 299 clk_disable_unprepare(wdt_clk);
290 return err; 300 return err;
291} 301}
292 302
293static int ath79_wdt_remove(struct platform_device *pdev) 303static int ath79_wdt_remove(struct platform_device *pdev)
294{ 304{
295 misc_deregister(&ath79_wdt_miscdev); 305 misc_deregister(&ath79_wdt_miscdev);
296 clk_disable(wdt_clk); 306 clk_disable_unprepare(wdt_clk);
297 return 0; 307 return 0;
298} 308}
299 309
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index a8dbceb32914..08a785398eac 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -41,6 +41,28 @@ u32 booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT;
41#define WDTP_MASK (TCR_WP_MASK) 41#define WDTP_MASK (TCR_WP_MASK)
42#endif 42#endif
43 43
44/* Checks wdt=x and wdt_period=xx command-line option */
45notrace int __init early_parse_wdt(char *p)
46{
47 if (p && strncmp(p, "0", 1) != 0)
48 booke_wdt_enabled = 1;
49
50 return 0;
51}
52early_param("wdt", early_parse_wdt);
53
54int __init early_parse_wdt_period(char *p)
55{
56 unsigned long ret;
57 if (p) {
58 if (!kstrtol(p, 0, &ret))
59 booke_wdt_period = ret;
60 }
61
62 return 0;
63}
64early_param("wdt_period", early_parse_wdt_period);
65
44#ifdef CONFIG_PPC_FSL_BOOK3E 66#ifdef CONFIG_PPC_FSL_BOOK3E
45 67
46/* For the specified period, determine the number of seconds 68/* For the specified period, determine the number of seconds
@@ -103,17 +125,18 @@ static unsigned int sec_to_period(unsigned int secs)
103static void __booke_wdt_set(void *data) 125static void __booke_wdt_set(void *data)
104{ 126{
105 u32 val; 127 u32 val;
128 struct watchdog_device *wdog = data;
106 129
107 val = mfspr(SPRN_TCR); 130 val = mfspr(SPRN_TCR);
108 val &= ~WDTP_MASK; 131 val &= ~WDTP_MASK;
109 val |= WDTP(booke_wdt_period); 132 val |= WDTP(sec_to_period(wdog->timeout));
110 133
111 mtspr(SPRN_TCR, val); 134 mtspr(SPRN_TCR, val);
112} 135}
113 136
114static void booke_wdt_set(void) 137static void booke_wdt_set(void *data)
115{ 138{
116 on_each_cpu(__booke_wdt_set, NULL, 0); 139 on_each_cpu(__booke_wdt_set, data, 0);
117} 140}
118 141
119static void __booke_wdt_ping(void *data) 142static void __booke_wdt_ping(void *data)
@@ -131,12 +154,13 @@ static int booke_wdt_ping(struct watchdog_device *wdog)
131static void __booke_wdt_enable(void *data) 154static void __booke_wdt_enable(void *data)
132{ 155{
133 u32 val; 156 u32 val;
157 struct watchdog_device *wdog = data;
134 158
135 /* clear status before enabling watchdog */ 159 /* clear status before enabling watchdog */
136 __booke_wdt_ping(NULL); 160 __booke_wdt_ping(NULL);
137 val = mfspr(SPRN_TCR); 161 val = mfspr(SPRN_TCR);
138 val &= ~WDTP_MASK; 162 val &= ~WDTP_MASK;
139 val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period)); 163 val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(sec_to_period(wdog->timeout)));
140 164
141 mtspr(SPRN_TCR, val); 165 mtspr(SPRN_TCR, val);
142} 166}
@@ -162,25 +186,17 @@ static void __booke_wdt_disable(void *data)
162 186
163} 187}
164 188
165static void __booke_wdt_start(struct watchdog_device *wdog) 189static int booke_wdt_start(struct watchdog_device *wdog)
166{ 190{
167 on_each_cpu(__booke_wdt_enable, NULL, 0); 191 on_each_cpu(__booke_wdt_enable, wdog, 0);
168 pr_debug("watchdog enabled (timeout = %u sec)\n", wdog->timeout); 192 pr_debug("watchdog enabled (timeout = %u sec)\n", wdog->timeout);
169}
170 193
171static int booke_wdt_start(struct watchdog_device *wdog)
172{
173 if (booke_wdt_enabled == 0) {
174 booke_wdt_enabled = 1;
175 __booke_wdt_start(wdog);
176 }
177 return 0; 194 return 0;
178} 195}
179 196
180static int booke_wdt_stop(struct watchdog_device *wdog) 197static int booke_wdt_stop(struct watchdog_device *wdog)
181{ 198{
182 on_each_cpu(__booke_wdt_disable, NULL, 0); 199 on_each_cpu(__booke_wdt_disable, NULL, 0);
183 booke_wdt_enabled = 0;
184 pr_debug("watchdog disabled\n"); 200 pr_debug("watchdog disabled\n");
185 201
186 return 0; 202 return 0;
@@ -191,9 +207,8 @@ static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev,
191{ 207{
192 if (timeout > MAX_WDT_TIMEOUT) 208 if (timeout > MAX_WDT_TIMEOUT)
193 return -EINVAL; 209 return -EINVAL;
194 booke_wdt_period = sec_to_period(timeout);
195 wdt_dev->timeout = timeout; 210 wdt_dev->timeout = timeout;
196 booke_wdt_set(); 211 booke_wdt_set(wdt_dev);
197 212
198 return 0; 213 return 0;
199} 214}
@@ -231,10 +246,10 @@ static int __init booke_wdt_init(void)
231 pr_info("powerpc book-e watchdog driver loaded\n"); 246 pr_info("powerpc book-e watchdog driver loaded\n");
232 booke_wdt_info.firmware_version = cur_cpu_spec->pvr_value; 247 booke_wdt_info.firmware_version = cur_cpu_spec->pvr_value;
233 booke_wdt_set_timeout(&booke_wdt_dev, 248 booke_wdt_set_timeout(&booke_wdt_dev,
234 period_to_sec(CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT)); 249 period_to_sec(booke_wdt_period));
235 watchdog_set_nowayout(&booke_wdt_dev, nowayout); 250 watchdog_set_nowayout(&booke_wdt_dev, nowayout);
236 if (booke_wdt_enabled) 251 if (booke_wdt_enabled)
237 __booke_wdt_start(&booke_wdt_dev); 252 booke_wdt_start(&booke_wdt_dev);
238 253
239 ret = watchdog_register_device(&booke_wdt_dev); 254 ret = watchdog_register_device(&booke_wdt_dev);
240 255
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index dd51d9539b33..9d4874f09948 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -21,19 +21,17 @@
21 * Halt on suspend: Manual Can be automatic 21 * Halt on suspend: Manual Can be automatic
22 */ 22 */
23 23
24#include <linux/clk.h>
24#include <linux/init.h> 25#include <linux/init.h>
26#include <linux/io.h>
27#include <linux/jiffies.h>
25#include <linux/kernel.h> 28#include <linux/kernel.h>
26#include <linux/miscdevice.h>
27#include <linux/module.h> 29#include <linux/module.h>
28#include <linux/moduleparam.h> 30#include <linux/moduleparam.h>
29#include <linux/platform_device.h> 31#include <linux/platform_device.h>
30#include <linux/watchdog.h> 32#include <linux/regmap.h>
31#include <linux/clk.h>
32#include <linux/fs.h>
33#include <linux/io.h>
34#include <linux/uaccess.h>
35#include <linux/timer.h> 33#include <linux/timer.h>
36#include <linux/jiffies.h> 34#include <linux/watchdog.h>
37 35
38#define DRIVER_NAME "imx2-wdt" 36#define DRIVER_NAME "imx2-wdt"
39 37
@@ -55,19 +53,12 @@
55 53
56#define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8) 54#define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
57 55
58#define IMX2_WDT_STATUS_OPEN 0 56struct imx2_wdt_device {
59#define IMX2_WDT_STATUS_STARTED 1
60#define IMX2_WDT_EXPECT_CLOSE 2
61
62static struct {
63 struct clk *clk; 57 struct clk *clk;
64 void __iomem *base; 58 struct regmap *regmap;
65 unsigned timeout;
66 unsigned long status;
67 struct timer_list timer; /* Pings the watchdog when closed */ 59 struct timer_list timer; /* Pings the watchdog when closed */
68} imx2_wdt; 60 struct watchdog_device wdog;
69 61};
70static struct miscdevice imx2_wdt_miscdev;
71 62
72static bool nowayout = WATCHDOG_NOWAYOUT; 63static bool nowayout = WATCHDOG_NOWAYOUT;
73module_param(nowayout, bool, 0); 64module_param(nowayout, bool, 0);
@@ -85,9 +76,12 @@ static const struct watchdog_info imx2_wdt_info = {
85 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, 76 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
86}; 77};
87 78
88static inline void imx2_wdt_setup(void) 79static inline void imx2_wdt_setup(struct watchdog_device *wdog)
89{ 80{
90 u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR); 81 struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
82 u32 val;
83
84 regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
91 85
92 /* Suspend timer in low power mode, write once-only */ 86 /* Suspend timer in low power mode, write once-only */
93 val |= IMX2_WDT_WCR_WDZST; 87 val |= IMX2_WDT_WCR_WDZST;
@@ -98,227 +92,199 @@ static inline void imx2_wdt_setup(void)
98 /* Keep Watchdog Disabled */ 92 /* Keep Watchdog Disabled */
99 val &= ~IMX2_WDT_WCR_WDE; 93 val &= ~IMX2_WDT_WCR_WDE;
100 /* Set the watchdog's Time-Out value */ 94 /* Set the watchdog's Time-Out value */
101 val |= WDOG_SEC_TO_COUNT(imx2_wdt.timeout); 95 val |= WDOG_SEC_TO_COUNT(wdog->timeout);
102 96
103 __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR); 97 regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
104 98
105 /* enable the watchdog */ 99 /* enable the watchdog */
106 val |= IMX2_WDT_WCR_WDE; 100 val |= IMX2_WDT_WCR_WDE;
107 __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR); 101 regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
108} 102}
109 103
110static inline void imx2_wdt_ping(void) 104static inline bool imx2_wdt_is_running(struct imx2_wdt_device *wdev)
111{ 105{
112 __raw_writew(IMX2_WDT_SEQ1, imx2_wdt.base + IMX2_WDT_WSR); 106 u32 val;
113 __raw_writew(IMX2_WDT_SEQ2, imx2_wdt.base + IMX2_WDT_WSR);
114}
115 107
116static void imx2_wdt_timer_ping(unsigned long arg) 108 regmap_read(wdev->regmap, IMX2_WDT_WCR, &val);
117{ 109
118 /* ping it every imx2_wdt.timeout / 2 seconds to prevent reboot */ 110 return val & IMX2_WDT_WCR_WDE;
119 imx2_wdt_ping();
120 mod_timer(&imx2_wdt.timer, jiffies + imx2_wdt.timeout * HZ / 2);
121} 111}
122 112
123static void imx2_wdt_start(void) 113static int imx2_wdt_ping(struct watchdog_device *wdog)
124{ 114{
125 if (!test_and_set_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) { 115 struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
126 /* at our first start we enable clock and do initialisations */
127 clk_prepare_enable(imx2_wdt.clk);
128 116
129 imx2_wdt_setup(); 117 regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ1);
130 } else /* delete the timer that pings the watchdog after close */ 118 regmap_write(wdev->regmap, IMX2_WDT_WSR, IMX2_WDT_SEQ2);
131 del_timer_sync(&imx2_wdt.timer); 119 return 0;
132
133 /* Watchdog is enabled - time to reload the timeout value */
134 imx2_wdt_ping();
135} 120}
136 121
137static void imx2_wdt_stop(void) 122static void imx2_wdt_timer_ping(unsigned long arg)
138{ 123{
139 /* we don't need a clk_disable, it cannot be disabled once started. 124 struct watchdog_device *wdog = (struct watchdog_device *)arg;
140 * We use a timer to ping the watchdog while /dev/watchdog is closed */ 125 struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
141 imx2_wdt_timer_ping(0); 126
127 /* ping it every wdog->timeout / 2 seconds to prevent reboot */
128 imx2_wdt_ping(wdog);
129 mod_timer(&wdev->timer, jiffies + wdog->timeout * HZ / 2);
142} 130}
143 131
144static void imx2_wdt_set_timeout(int new_timeout) 132static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
133 unsigned int new_timeout)
145{ 134{
146 u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR); 135 struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
147 136
148 /* set the new timeout value in the WSR */ 137 regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
149 val &= ~IMX2_WDT_WCR_WT; 138 WDOG_SEC_TO_COUNT(new_timeout));
150 val |= WDOG_SEC_TO_COUNT(new_timeout); 139 return 0;
151 __raw_writew(val, imx2_wdt.base + IMX2_WDT_WCR);
152} 140}
153 141
154static int imx2_wdt_open(struct inode *inode, struct file *file) 142static int imx2_wdt_start(struct watchdog_device *wdog)
155{ 143{
156 if (test_and_set_bit(IMX2_WDT_STATUS_OPEN, &imx2_wdt.status)) 144 struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
157 return -EBUSY; 145
146 if (imx2_wdt_is_running(wdev)) {
147 /* delete the timer that pings the watchdog after close */
148 del_timer_sync(&wdev->timer);
149 imx2_wdt_set_timeout(wdog, wdog->timeout);
150 } else
151 imx2_wdt_setup(wdog);
158 152
159 imx2_wdt_start(); 153 return imx2_wdt_ping(wdog);
160 return nonseekable_open(inode, file);
161} 154}
162 155
163static int imx2_wdt_close(struct inode *inode, struct file *file) 156static int imx2_wdt_stop(struct watchdog_device *wdog)
164{ 157{
165 if (test_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status) && !nowayout) 158 /*
166 imx2_wdt_stop(); 159 * We don't need a clk_disable, it cannot be disabled once started.
167 else { 160 * We use a timer to ping the watchdog while /dev/watchdog is closed
168 dev_crit(imx2_wdt_miscdev.parent, 161 */
169 "Unexpected close: Expect reboot!\n"); 162 imx2_wdt_timer_ping((unsigned long)wdog);
170 imx2_wdt_ping();
171 }
172
173 clear_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
174 clear_bit(IMX2_WDT_STATUS_OPEN, &imx2_wdt.status);
175 return 0; 163 return 0;
176} 164}
177 165
178static long imx2_wdt_ioctl(struct file *file, unsigned int cmd, 166static inline void imx2_wdt_ping_if_active(struct watchdog_device *wdog)
179 unsigned long arg)
180{ 167{
181 void __user *argp = (void __user *)arg; 168 struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
182 int __user *p = argp;
183 int new_value;
184 u16 val;
185
186 switch (cmd) {
187 case WDIOC_GETSUPPORT:
188 return copy_to_user(argp, &imx2_wdt_info,
189 sizeof(struct watchdog_info)) ? -EFAULT : 0;
190
191 case WDIOC_GETSTATUS:
192 return put_user(0, p);
193
194 case WDIOC_GETBOOTSTATUS:
195 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WRSR);
196 new_value = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
197 return put_user(new_value, p);
198
199 case WDIOC_KEEPALIVE:
200 imx2_wdt_ping();
201 return 0;
202
203 case WDIOC_SETTIMEOUT:
204 if (get_user(new_value, p))
205 return -EFAULT;
206 if ((new_value < 1) || (new_value > IMX2_WDT_MAX_TIME))
207 return -EINVAL;
208 imx2_wdt_set_timeout(new_value);
209 imx2_wdt.timeout = new_value;
210 imx2_wdt_ping();
211
212 /* Fallthrough to return current value */
213 case WDIOC_GETTIMEOUT:
214 return put_user(imx2_wdt.timeout, p);
215
216 default:
217 return -ENOTTY;
218 }
219}
220 169
221static ssize_t imx2_wdt_write(struct file *file, const char __user *data, 170 if (imx2_wdt_is_running(wdev)) {
222 size_t len, loff_t *ppos) 171 imx2_wdt_set_timeout(wdog, wdog->timeout);
223{ 172 imx2_wdt_timer_ping((unsigned long)wdog);
224 size_t i;
225 char c;
226
227 if (len == 0) /* Can we see this even ? */
228 return 0;
229
230 clear_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
231 /* scan to see whether or not we got the magic character */
232 for (i = 0; i != len; i++) {
233 if (get_user(c, data + i))
234 return -EFAULT;
235 if (c == 'V')
236 set_bit(IMX2_WDT_EXPECT_CLOSE, &imx2_wdt.status);
237 } 173 }
238
239 imx2_wdt_ping();
240 return len;
241} 174}
242 175
243static const struct file_operations imx2_wdt_fops = { 176static struct watchdog_ops imx2_wdt_ops = {
244 .owner = THIS_MODULE, 177 .owner = THIS_MODULE,
245 .llseek = no_llseek, 178 .start = imx2_wdt_start,
246 .unlocked_ioctl = imx2_wdt_ioctl, 179 .stop = imx2_wdt_stop,
247 .open = imx2_wdt_open, 180 .ping = imx2_wdt_ping,
248 .release = imx2_wdt_close, 181 .set_timeout = imx2_wdt_set_timeout,
249 .write = imx2_wdt_write,
250}; 182};
251 183
252static struct miscdevice imx2_wdt_miscdev = { 184static struct regmap_config imx2_wdt_regmap_config = {
253 .minor = WATCHDOG_MINOR, 185 .reg_bits = 16,
254 .name = "watchdog", 186 .reg_stride = 2,
255 .fops = &imx2_wdt_fops, 187 .val_bits = 16,
188 .max_register = 0x8,
256}; 189};
257 190
258static int __init imx2_wdt_probe(struct platform_device *pdev) 191static int __init imx2_wdt_probe(struct platform_device *pdev)
259{ 192{
260 int ret; 193 struct imx2_wdt_device *wdev;
194 struct watchdog_device *wdog;
261 struct resource *res; 195 struct resource *res;
196 void __iomem *base;
197 int ret;
198 u32 val;
199
200 wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
201 if (!wdev)
202 return -ENOMEM;
262 203
263 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 204 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
264 imx2_wdt.base = devm_ioremap_resource(&pdev->dev, res); 205 base = devm_ioremap_resource(&pdev->dev, res);
265 if (IS_ERR(imx2_wdt.base)) 206 if (IS_ERR(base))
266 return PTR_ERR(imx2_wdt.base); 207 return PTR_ERR(base);
208
209 wdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
210 &imx2_wdt_regmap_config);
211 if (IS_ERR(wdev->regmap)) {
212 dev_err(&pdev->dev, "regmap init failed\n");
213 return PTR_ERR(wdev->regmap);
214 }
267 215
268 imx2_wdt.clk = devm_clk_get(&pdev->dev, NULL); 216 wdev->clk = devm_clk_get(&pdev->dev, NULL);
269 if (IS_ERR(imx2_wdt.clk)) { 217 if (IS_ERR(wdev->clk)) {
270 dev_err(&pdev->dev, "can't get Watchdog clock\n"); 218 dev_err(&pdev->dev, "can't get Watchdog clock\n");
271 return PTR_ERR(imx2_wdt.clk); 219 return PTR_ERR(wdev->clk);
272 } 220 }
273 221
274 imx2_wdt.timeout = clamp_t(unsigned, timeout, 1, IMX2_WDT_MAX_TIME); 222 wdog = &wdev->wdog;
275 if (imx2_wdt.timeout != timeout) 223 wdog->info = &imx2_wdt_info;
276 dev_warn(&pdev->dev, "Initial timeout out of range! " 224 wdog->ops = &imx2_wdt_ops;
277 "Clamped from %u to %u\n", timeout, imx2_wdt.timeout); 225 wdog->min_timeout = 1;
226 wdog->max_timeout = IMX2_WDT_MAX_TIME;
278 227
279 setup_timer(&imx2_wdt.timer, imx2_wdt_timer_ping, 0); 228 clk_prepare_enable(wdev->clk);
280 229
281 imx2_wdt_miscdev.parent = &pdev->dev; 230 regmap_read(wdev->regmap, IMX2_WDT_WRSR, &val);
282 ret = misc_register(&imx2_wdt_miscdev); 231 wdog->bootstatus = val & IMX2_WDT_WRSR_TOUT ? WDIOF_CARDRESET : 0;
283 if (ret)
284 goto fail;
285 232
286 dev_info(&pdev->dev, 233 wdog->timeout = clamp_t(unsigned, timeout, 1, IMX2_WDT_MAX_TIME);
287 "IMX2+ Watchdog Timer enabled. timeout=%ds (nowayout=%d)\n", 234 if (wdog->timeout != timeout)
288 imx2_wdt.timeout, nowayout); 235 dev_warn(&pdev->dev, "Initial timeout out of range! Clamped from %u to %u\n",
289 return 0; 236 timeout, wdog->timeout);
237
238 platform_set_drvdata(pdev, wdog);
239 watchdog_set_drvdata(wdog, wdev);
240 watchdog_set_nowayout(wdog, nowayout);
241 watchdog_init_timeout(wdog, timeout, &pdev->dev);
242
243 setup_timer(&wdev->timer, imx2_wdt_timer_ping, (unsigned long)wdog);
244
245 imx2_wdt_ping_if_active(wdog);
290 246
291fail: 247 ret = watchdog_register_device(wdog);
292 imx2_wdt_miscdev.parent = NULL; 248 if (ret) {
293 return ret; 249 dev_err(&pdev->dev, "cannot register watchdog device\n");
250 return ret;
251 }
252
253 dev_info(&pdev->dev, "timeout %d sec (nowayout=%d)\n",
254 wdog->timeout, nowayout);
255
256 return 0;
294} 257}
295 258
296static int __exit imx2_wdt_remove(struct platform_device *pdev) 259static int __exit imx2_wdt_remove(struct platform_device *pdev)
297{ 260{
298 misc_deregister(&imx2_wdt_miscdev); 261 struct watchdog_device *wdog = platform_get_drvdata(pdev);
262 struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
299 263
300 if (test_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) { 264 watchdog_unregister_device(wdog);
301 del_timer_sync(&imx2_wdt.timer);
302 265
303 dev_crit(imx2_wdt_miscdev.parent, 266 if (imx2_wdt_is_running(wdev)) {
304 "Device removed: Expect reboot!\n"); 267 del_timer_sync(&wdev->timer);
268 imx2_wdt_ping(wdog);
269 dev_crit(&pdev->dev, "Device removed: Expect reboot!\n");
305 } 270 }
306
307 imx2_wdt_miscdev.parent = NULL;
308 return 0; 271 return 0;
309} 272}
310 273
311static void imx2_wdt_shutdown(struct platform_device *pdev) 274static void imx2_wdt_shutdown(struct platform_device *pdev)
312{ 275{
313 if (test_bit(IMX2_WDT_STATUS_STARTED, &imx2_wdt.status)) { 276 struct watchdog_device *wdog = platform_get_drvdata(pdev);
314 /* we are running, we need to delete the timer but will give 277 struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
315 * max timeout before reboot will take place */ 278
316 del_timer_sync(&imx2_wdt.timer); 279 if (imx2_wdt_is_running(wdev)) {
317 imx2_wdt_set_timeout(IMX2_WDT_MAX_TIME); 280 /*
318 imx2_wdt_ping(); 281 * We are running, we need to delete the timer but will
319 282 * give max timeout before reboot will take place
320 dev_crit(imx2_wdt_miscdev.parent, 283 */
321 "Device shutdown: Expect reboot!\n"); 284 del_timer_sync(&wdev->timer);
285 imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
286 imx2_wdt_ping(wdog);
287 dev_crit(&pdev->dev, "Device shutdown: Expect reboot!\n");
322 } 288 }
323} 289}
324 290
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c
new file mode 100644
index 000000000000..ca66e8e74635
--- /dev/null
+++ b/drivers/watchdog/intel-mid_wdt.c
@@ -0,0 +1,184 @@
1/*
2 * intel-mid_wdt: generic Intel MID SCU watchdog driver
3 *
4 * Platforms supported so far:
5 * - Merrifield only
6 *
7 * Copyright (C) 2014 Intel Corporation. All rights reserved.
8 * Contact: David Cohen <david.a.cohen@linux.intel.com>
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU General
12 * Public License as published by the Free Software Foundation.
13 */
14
15#include <linux/interrupt.h>
16#include <linux/module.h>
17#include <linux/nmi.h>
18#include <linux/platform_device.h>
19#include <linux/watchdog.h>
20#include <linux/platform_data/intel-mid_wdt.h>
21
22#include <asm/intel_scu_ipc.h>
23#include <asm/intel-mid.h>
24
25#define IPC_WATCHDOG 0xf8
26
27#define MID_WDT_PRETIMEOUT 15
28#define MID_WDT_TIMEOUT_MIN (1 + MID_WDT_PRETIMEOUT)
29#define MID_WDT_TIMEOUT_MAX 170
30#define MID_WDT_DEFAULT_TIMEOUT 90
31
32/* SCU watchdog messages */
33enum {
34 SCU_WATCHDOG_START = 0,
35 SCU_WATCHDOG_STOP,
36 SCU_WATCHDOG_KEEPALIVE,
37};
38
39static inline int wdt_command(int sub, u32 *in, int inlen)
40{
41 return intel_scu_ipc_command(IPC_WATCHDOG, sub, in, inlen, NULL, 0);
42}
43
44static int wdt_start(struct watchdog_device *wd)
45{
46 int ret, in_size;
47 int timeout = wd->timeout;
48 struct ipc_wd_start {
49 u32 pretimeout;
50 u32 timeout;
51 } ipc_wd_start = { timeout - MID_WDT_PRETIMEOUT, timeout };
52
53 /*
54 * SCU expects the input size for watchdog IPC to
55 * be based on 4 bytes
56 */
57 in_size = DIV_ROUND_UP(sizeof(ipc_wd_start), 4);
58
59 ret = wdt_command(SCU_WATCHDOG_START, (u32 *)&ipc_wd_start, in_size);
60 if (ret) {
61 struct device *dev = watchdog_get_drvdata(wd);
62 dev_crit(dev, "error starting watchdog: %d\n", ret);
63 }
64
65 return ret;
66}
67
68static int wdt_ping(struct watchdog_device *wd)
69{
70 int ret;
71
72 ret = wdt_command(SCU_WATCHDOG_KEEPALIVE, NULL, 0);
73 if (ret) {
74 struct device *dev = watchdog_get_drvdata(wd);
75 dev_crit(dev, "Error executing keepalive: 0x%x\n", ret);
76 }
77
78 return ret;
79}
80
81static int wdt_stop(struct watchdog_device *wd)
82{
83 int ret;
84
85 ret = wdt_command(SCU_WATCHDOG_STOP, NULL, 0);
86 if (ret) {
87 struct device *dev = watchdog_get_drvdata(wd);
88 dev_crit(dev, "Error stopping watchdog: 0x%x\n", ret);
89 }
90
91 return ret;
92}
93
94static irqreturn_t mid_wdt_irq(int irq, void *dev_id)
95{
96 panic("Kernel Watchdog");
97
98 /* This code should not be reached */
99 return IRQ_HANDLED;
100}
101
102static const struct watchdog_info mid_wdt_info = {
103 .identity = "Intel MID SCU watchdog",
104 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
105};
106
107static const struct watchdog_ops mid_wdt_ops = {
108 .owner = THIS_MODULE,
109 .start = wdt_start,
110 .stop = wdt_stop,
111 .ping = wdt_ping,
112};
113
114static int mid_wdt_probe(struct platform_device *pdev)
115{
116 struct watchdog_device *wdt_dev;
117 struct intel_mid_wdt_pdata *pdata = pdev->dev.platform_data;
118 int ret;
119
120 if (!pdata) {
121 dev_err(&pdev->dev, "missing platform data\n");
122 return -EINVAL;
123 }
124
125 if (pdata->probe) {
126 ret = pdata->probe(pdev);
127 if (ret)
128 return ret;
129 }
130
131 wdt_dev = devm_kzalloc(&pdev->dev, sizeof(*wdt_dev), GFP_KERNEL);
132 if (!wdt_dev)
133 return -ENOMEM;
134
135 wdt_dev->info = &mid_wdt_info;
136 wdt_dev->ops = &mid_wdt_ops;
137 wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN;
138 wdt_dev->max_timeout = MID_WDT_TIMEOUT_MAX;
139 wdt_dev->timeout = MID_WDT_DEFAULT_TIMEOUT;
140
141 watchdog_set_drvdata(wdt_dev, &pdev->dev);
142 platform_set_drvdata(pdev, wdt_dev);
143
144 ret = devm_request_irq(&pdev->dev, pdata->irq, mid_wdt_irq,
145 IRQF_SHARED | IRQF_NO_SUSPEND, "watchdog",
146 wdt_dev);
147 if (ret) {
148 dev_err(&pdev->dev, "error requesting warning irq %d\n",
149 pdata->irq);
150 return ret;
151 }
152
153 ret = watchdog_register_device(wdt_dev);
154 if (ret) {
155 dev_err(&pdev->dev, "error registering watchdog device\n");
156 return ret;
157 }
158
159 dev_info(&pdev->dev, "Intel MID watchdog device probed\n");
160
161 return 0;
162}
163
164static int mid_wdt_remove(struct platform_device *pdev)
165{
166 struct watchdog_device *wd = platform_get_drvdata(pdev);
167 watchdog_unregister_device(wd);
168 return 0;
169}
170
171static struct platform_driver mid_wdt_driver = {
172 .probe = mid_wdt_probe,
173 .remove = mid_wdt_remove,
174 .driver = {
175 .owner = THIS_MODULE,
176 .name = "intel_mid_wdt",
177 },
178};
179
180module_platform_driver(mid_wdt_driver);
181
182MODULE_AUTHOR("David Cohen <david.a.cohen@linux.intel.com>");
183MODULE_DESCRIPTION("Watchdog Driver for Intel MID platform");
184MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/kempld_wdt.c b/drivers/watchdog/kempld_wdt.c
index 20dc73844737..d9c1a1601926 100644
--- a/drivers/watchdog/kempld_wdt.c
+++ b/drivers/watchdog/kempld_wdt.c
@@ -162,7 +162,7 @@ static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data,
162 kempld_get_mutex(pld); 162 kempld_get_mutex(pld);
163 stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id)); 163 stage_cfg = kempld_read8(pld, KEMPLD_WDT_STAGE_CFG(stage->id));
164 stage_cfg &= ~STAGE_CFG_PRESCALER_MASK; 164 stage_cfg &= ~STAGE_CFG_PRESCALER_MASK;
165 stage_cfg |= STAGE_CFG_SET_PRESCALER(prescaler); 165 stage_cfg |= STAGE_CFG_SET_PRESCALER(PRESCALER_21);
166 kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg); 166 kempld_write8(pld, KEMPLD_WDT_STAGE_CFG(stage->id), stage_cfg);
167 kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id), 167 kempld_write32(pld, KEMPLD_WDT_STAGE_TIMEOUT(stage->id),
168 stage_timeout); 168 stage_timeout);
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c
index 57ccae8327ff..1e6e28df5d7b 100644
--- a/drivers/watchdog/of_xilinx_wdt.c
+++ b/drivers/watchdog/of_xilinx_wdt.c
@@ -225,7 +225,7 @@ static int xwdt_remove(struct platform_device *pdev)
225} 225}
226 226
227/* Match table for of_platform binding */ 227/* Match table for of_platform binding */
228static struct of_device_id xwdt_of_match[] = { 228static const struct of_device_id xwdt_of_match[] = {
229 { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, 229 { .compatible = "xlnx,xps-timebase-wdt-1.00.a", },
230 { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, 230 { .compatible = "xlnx,xps-timebase-wdt-1.01.a", },
231 {}, 231 {},
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 9b3c41d18703..00d0741228fc 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -55,15 +55,19 @@ struct orion_watchdog_data {
55 int wdt_counter_offset; 55 int wdt_counter_offset;
56 int wdt_enable_bit; 56 int wdt_enable_bit;
57 int rstout_enable_bit; 57 int rstout_enable_bit;
58 int rstout_mask_bit;
58 int (*clock_init)(struct platform_device *, 59 int (*clock_init)(struct platform_device *,
59 struct orion_watchdog *); 60 struct orion_watchdog *);
61 int (*enabled)(struct orion_watchdog *);
60 int (*start)(struct watchdog_device *); 62 int (*start)(struct watchdog_device *);
63 int (*stop)(struct watchdog_device *);
61}; 64};
62 65
63struct orion_watchdog { 66struct orion_watchdog {
64 struct watchdog_device wdt; 67 struct watchdog_device wdt;
65 void __iomem *reg; 68 void __iomem *reg;
66 void __iomem *rstout; 69 void __iomem *rstout;
70 void __iomem *rstout_mask;
67 unsigned long clk_rate; 71 unsigned long clk_rate;
68 struct clk *clk; 72 struct clk *clk;
69 const struct orion_watchdog_data *data; 73 const struct orion_watchdog_data *data;
@@ -142,9 +146,35 @@ static int orion_wdt_ping(struct watchdog_device *wdt_dev)
142 return 0; 146 return 0;
143} 147}
144 148
149static int armada375_start(struct watchdog_device *wdt_dev)
150{
151 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
152 u32 reg;
153
154 /* Set watchdog duration */
155 writel(dev->clk_rate * wdt_dev->timeout,
156 dev->reg + dev->data->wdt_counter_offset);
157
158 /* Clear the watchdog expiration bit */
159 atomic_io_modify(dev->reg + TIMER_A370_STATUS, WDT_A370_EXPIRED, 0);
160
161 /* Enable watchdog timer */
162 atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
163 dev->data->wdt_enable_bit);
164
165 /* Enable reset on watchdog */
166 reg = readl(dev->rstout);
167 reg |= dev->data->rstout_enable_bit;
168 writel(reg, dev->rstout);
169
170 atomic_io_modify(dev->rstout_mask, dev->data->rstout_mask_bit, 0);
171 return 0;
172}
173
145static int armada370_start(struct watchdog_device *wdt_dev) 174static int armada370_start(struct watchdog_device *wdt_dev)
146{ 175{
147 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); 176 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
177 u32 reg;
148 178
149 /* Set watchdog duration */ 179 /* Set watchdog duration */
150 writel(dev->clk_rate * wdt_dev->timeout, 180 writel(dev->clk_rate * wdt_dev->timeout,
@@ -157,8 +187,10 @@ static int armada370_start(struct watchdog_device *wdt_dev)
157 atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 187 atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit,
158 dev->data->wdt_enable_bit); 188 dev->data->wdt_enable_bit);
159 189
160 atomic_io_modify(dev->rstout, dev->data->rstout_enable_bit, 190 /* Enable reset on watchdog */
161 dev->data->rstout_enable_bit); 191 reg = readl(dev->rstout);
192 reg |= dev->data->rstout_enable_bit;
193 writel(reg, dev->rstout);
162 return 0; 194 return 0;
163} 195}
164 196
@@ -189,7 +221,7 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev)
189 return dev->data->start(wdt_dev); 221 return dev->data->start(wdt_dev);
190} 222}
191 223
192static int orion_wdt_stop(struct watchdog_device *wdt_dev) 224static int orion_stop(struct watchdog_device *wdt_dev)
193{ 225{
194 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); 226 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
195 227
@@ -202,7 +234,48 @@ static int orion_wdt_stop(struct watchdog_device *wdt_dev)
202 return 0; 234 return 0;
203} 235}
204 236
205static int orion_wdt_enabled(struct orion_watchdog *dev) 237static int armada375_stop(struct watchdog_device *wdt_dev)
238{
239 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
240 u32 reg;
241
242 /* Disable reset on watchdog */
243 atomic_io_modify(dev->rstout_mask, dev->data->rstout_mask_bit,
244 dev->data->rstout_mask_bit);
245 reg = readl(dev->rstout);
246 reg &= ~dev->data->rstout_enable_bit;
247 writel(reg, dev->rstout);
248
249 /* Disable watchdog timer */
250 atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
251
252 return 0;
253}
254
255static int armada370_stop(struct watchdog_device *wdt_dev)
256{
257 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
258 u32 reg;
259
260 /* Disable reset on watchdog */
261 reg = readl(dev->rstout);
262 reg &= ~dev->data->rstout_enable_bit;
263 writel(reg, dev->rstout);
264
265 /* Disable watchdog timer */
266 atomic_io_modify(dev->reg + TIMER_CTRL, dev->data->wdt_enable_bit, 0);
267
268 return 0;
269}
270
271static int orion_wdt_stop(struct watchdog_device *wdt_dev)
272{
273 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
274
275 return dev->data->stop(wdt_dev);
276}
277
278static int orion_enabled(struct orion_watchdog *dev)
206{ 279{
207 bool enabled, running; 280 bool enabled, running;
208 281
@@ -212,6 +285,24 @@ static int orion_wdt_enabled(struct orion_watchdog *dev)
212 return enabled && running; 285 return enabled && running;
213} 286}
214 287
288static int armada375_enabled(struct orion_watchdog *dev)
289{
290 bool masked, enabled, running;
291
292 masked = readl(dev->rstout_mask) & dev->data->rstout_mask_bit;
293 enabled = readl(dev->rstout) & dev->data->rstout_enable_bit;
294 running = readl(dev->reg + TIMER_CTRL) & dev->data->wdt_enable_bit;
295
296 return !masked && enabled && running;
297}
298
299static int orion_wdt_enabled(struct watchdog_device *wdt_dev)
300{
301 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
302
303 return dev->data->enabled(dev);
304}
305
215static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev) 306static unsigned int orion_wdt_get_timeleft(struct watchdog_device *wdt_dev)
216{ 307{
217 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); 308 struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
@@ -262,10 +353,6 @@ static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev,
262 return devm_ioremap(&pdev->dev, res->start, 353 return devm_ioremap(&pdev->dev, res->start,
263 resource_size(res)); 354 resource_size(res));
264 355
265 /* This workaround works only for "orion-wdt", DT-enabled */
266 if (!of_device_is_compatible(pdev->dev.of_node, "marvell,orion-wdt"))
267 return NULL;
268
269 rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET; 356 rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET;
270 357
271 WARN(1, FW_BUG "falling back to harcoded RSTOUT reg %pa\n", &rstout); 358 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 = {
277 .wdt_enable_bit = BIT(4), 364 .wdt_enable_bit = BIT(4),
278 .wdt_counter_offset = 0x24, 365 .wdt_counter_offset = 0x24,
279 .clock_init = orion_wdt_clock_init, 366 .clock_init = orion_wdt_clock_init,
367 .enabled = orion_enabled,
280 .start = orion_start, 368 .start = orion_start,
369 .stop = orion_stop,
281}; 370};
282 371
283static const struct orion_watchdog_data armada370_data = { 372static const struct orion_watchdog_data armada370_data = {
@@ -285,7 +374,9 @@ static const struct orion_watchdog_data armada370_data = {
285 .wdt_enable_bit = BIT(8), 374 .wdt_enable_bit = BIT(8),
286 .wdt_counter_offset = 0x34, 375 .wdt_counter_offset = 0x34,
287 .clock_init = armada370_wdt_clock_init, 376 .clock_init = armada370_wdt_clock_init,
377 .enabled = orion_enabled,
288 .start = armada370_start, 378 .start = armada370_start,
379 .stop = armada370_stop,
289}; 380};
290 381
291static const struct orion_watchdog_data armadaxp_data = { 382static const struct orion_watchdog_data armadaxp_data = {
@@ -293,7 +384,31 @@ static const struct orion_watchdog_data armadaxp_data = {
293 .wdt_enable_bit = BIT(8), 384 .wdt_enable_bit = BIT(8),
294 .wdt_counter_offset = 0x34, 385 .wdt_counter_offset = 0x34,
295 .clock_init = armadaxp_wdt_clock_init, 386 .clock_init = armadaxp_wdt_clock_init,
387 .enabled = orion_enabled,
296 .start = armada370_start, 388 .start = armada370_start,
389 .stop = armada370_stop,
390};
391
392static const struct orion_watchdog_data armada375_data = {
393 .rstout_enable_bit = BIT(8),
394 .rstout_mask_bit = BIT(10),
395 .wdt_enable_bit = BIT(8),
396 .wdt_counter_offset = 0x34,
397 .clock_init = armada370_wdt_clock_init,
398 .enabled = armada375_enabled,
399 .start = armada375_start,
400 .stop = armada375_stop,
401};
402
403static const struct orion_watchdog_data armada380_data = {
404 .rstout_enable_bit = BIT(8),
405 .rstout_mask_bit = BIT(10),
406 .wdt_enable_bit = BIT(8),
407 .wdt_counter_offset = 0x34,
408 .clock_init = armadaxp_wdt_clock_init,
409 .enabled = armada375_enabled,
410 .start = armada375_start,
411 .stop = armada375_stop,
297}; 412};
298 413
299static const struct of_device_id orion_wdt_of_match_table[] = { 414static 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[] = {
309 .compatible = "marvell,armada-xp-wdt", 424 .compatible = "marvell,armada-xp-wdt",
310 .data = &armadaxp_data, 425 .data = &armadaxp_data,
311 }, 426 },
427 {
428 .compatible = "marvell,armada-375-wdt",
429 .data = &armada375_data,
430 },
431 {
432 .compatible = "marvell,armada-380-wdt",
433 .data = &armada380_data,
434 },
312 {}, 435 {},
313}; 436};
314MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table); 437MODULE_DEVICE_TABLE(of, orion_wdt_of_match_table);
315 438
439static int orion_wdt_get_regs(struct platform_device *pdev,
440 struct orion_watchdog *dev)
441{
442 struct device_node *node = pdev->dev.of_node;
443 struct resource *res;
444
445 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
446 if (!res)
447 return -ENODEV;
448 dev->reg = devm_ioremap(&pdev->dev, res->start,
449 resource_size(res));
450 if (!dev->reg)
451 return -ENOMEM;
452
453 /* Each supported compatible has some RSTOUT register quirk */
454 if (of_device_is_compatible(node, "marvell,orion-wdt")) {
455
456 dev->rstout = orion_wdt_ioremap_rstout(pdev, res->start &
457 INTERNAL_REGS_MASK);
458 if (!dev->rstout)
459 return -ENODEV;
460
461 } else if (of_device_is_compatible(node, "marvell,armada-370-wdt") ||
462 of_device_is_compatible(node, "marvell,armada-xp-wdt")) {
463
464 /* Dedicated RSTOUT register, can be requested. */
465 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
466 dev->rstout = devm_ioremap_resource(&pdev->dev, res);
467 if (IS_ERR(dev->rstout))
468 return PTR_ERR(dev->rstout);
469
470 } else if (of_device_is_compatible(node, "marvell,armada-375-wdt") ||
471 of_device_is_compatible(node, "marvell,armada-380-wdt")) {
472
473 /* Dedicated RSTOUT register, can be requested. */
474 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
475 dev->rstout = devm_ioremap_resource(&pdev->dev, res);
476 if (IS_ERR(dev->rstout))
477 return PTR_ERR(dev->rstout);
478
479 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
480 if (!res)
481 return -ENODEV;
482 dev->rstout_mask = devm_ioremap(&pdev->dev, res->start,
483 resource_size(res));
484 if (!dev->rstout_mask)
485 return -ENOMEM;
486
487 } else {
488 return -ENODEV;
489 }
490
491 return 0;
492}
493
316static int orion_wdt_probe(struct platform_device *pdev) 494static int orion_wdt_probe(struct platform_device *pdev)
317{ 495{
318 struct orion_watchdog *dev; 496 struct orion_watchdog *dev;
319 const struct of_device_id *match; 497 const struct of_device_id *match;
320 unsigned int wdt_max_duration; /* (seconds) */ 498 unsigned int wdt_max_duration; /* (seconds) */
321 struct resource *res;
322 int ret, irq; 499 int ret, irq;
323 500
324 dev = devm_kzalloc(&pdev->dev, sizeof(struct orion_watchdog), 501 dev = devm_kzalloc(&pdev->dev, sizeof(struct orion_watchdog),
@@ -336,19 +513,9 @@ static int orion_wdt_probe(struct platform_device *pdev)
336 dev->wdt.min_timeout = 1; 513 dev->wdt.min_timeout = 1;
337 dev->data = match->data; 514 dev->data = match->data;
338 515
339 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 516 ret = orion_wdt_get_regs(pdev, dev);
340 if (!res) 517 if (ret)
341 return -ENODEV; 518 return ret;
342
343 dev->reg = devm_ioremap(&pdev->dev, res->start,
344 resource_size(res));
345 if (!dev->reg)
346 return -ENOMEM;
347
348 dev->rstout = orion_wdt_ioremap_rstout(pdev, res->start &
349 INTERNAL_REGS_MASK);
350 if (!dev->rstout)
351 return -ENODEV;
352 519
353 ret = dev->data->clock_init(pdev, dev); 520 ret = dev->data->clock_init(pdev, dev);
354 if (ret) { 521 if (ret) {
@@ -371,7 +538,7 @@ static int orion_wdt_probe(struct platform_device *pdev)
371 * removed and re-insterted, or if the bootloader explicitly 538 * removed and re-insterted, or if the bootloader explicitly
372 * set a running watchdog before booting the kernel. 539 * set a running watchdog before booting the kernel.
373 */ 540 */
374 if (!orion_wdt_enabled(dev)) 541 if (!orion_wdt_enabled(&dev->wdt))
375 orion_wdt_stop(&dev->wdt); 542 orion_wdt_stop(&dev->wdt);
376 543
377 /* Request the IRQ only after the watchdog is disabled */ 544 /* Request the IRQ only after the watchdog is disabled */
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
index d04d02b41c32..061756e36cf8 100644
--- a/drivers/watchdog/shwdt.c
+++ b/drivers/watchdog/shwdt.c
@@ -282,8 +282,6 @@ static int sh_wdt_probe(struct platform_device *pdev)
282 wdt->timer.data = (unsigned long)wdt; 282 wdt->timer.data = (unsigned long)wdt;
283 wdt->timer.expires = next_ping_period(clock_division_ratio); 283 wdt->timer.expires = next_ping_period(clock_division_ratio);
284 284
285 platform_set_drvdata(pdev, wdt);
286
287 dev_info(&pdev->dev, "initialized.\n"); 285 dev_info(&pdev->dev, "initialized.\n");
288 286
289 pm_runtime_enable(&pdev->dev); 287 pm_runtime_enable(&pdev->dev);
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 47629d268e0a..c1b03f4235b9 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -59,7 +59,6 @@
59 * @adev: amba device structure of wdt 59 * @adev: amba device structure of wdt
60 * @status: current status of wdt 60 * @status: current status of wdt
61 * @load_val: load value to be set for current timeout 61 * @load_val: load value to be set for current timeout
62 * @timeout: current programmed timeout
63 */ 62 */
64struct sp805_wdt { 63struct sp805_wdt {
65 struct watchdog_device wdd; 64 struct watchdog_device wdd;
@@ -68,7 +67,6 @@ struct sp805_wdt {
68 struct clk *clk; 67 struct clk *clk;
69 struct amba_device *adev; 68 struct amba_device *adev;
70 unsigned int load_val; 69 unsigned int load_val;
71 unsigned int timeout;
72}; 70};
73 71
74static bool nowayout = WATCHDOG_NOWAYOUT; 72static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -98,7 +96,7 @@ static int wdt_setload(struct watchdog_device *wdd, unsigned int timeout)
98 spin_lock(&wdt->lock); 96 spin_lock(&wdt->lock);
99 wdt->load_val = load; 97 wdt->load_val = load;
100 /* roundup timeout to closest positive integer value */ 98 /* roundup timeout to closest positive integer value */
101 wdt->timeout = div_u64((load + 1) * 2 + (rate / 2), rate); 99 wdd->timeout = div_u64((load + 1) * 2 + (rate / 2), rate);
102 spin_unlock(&wdt->lock); 100 spin_unlock(&wdt->lock);
103 101
104 return 0; 102 return 0;
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
index cd00a7836cdc..693b9d2c6e39 100644
--- a/drivers/watchdog/sunxi_wdt.c
+++ b/drivers/watchdog/sunxi_wdt.c
@@ -57,17 +57,17 @@ struct sunxi_wdt_dev {
57 */ 57 */
58 58
59static const int wdt_timeout_map[] = { 59static const int wdt_timeout_map[] = {
60 [1] = 0b0001, /* 1s */ 60 [1] = 0x1, /* 1s */
61 [2] = 0b0010, /* 2s */ 61 [2] = 0x2, /* 2s */
62 [3] = 0b0011, /* 3s */ 62 [3] = 0x3, /* 3s */
63 [4] = 0b0100, /* 4s */ 63 [4] = 0x4, /* 4s */
64 [5] = 0b0101, /* 5s */ 64 [5] = 0x5, /* 5s */
65 [6] = 0b0110, /* 6s */ 65 [6] = 0x6, /* 6s */
66 [8] = 0b0111, /* 8s */ 66 [8] = 0x7, /* 8s */
67 [10] = 0b1000, /* 10s */ 67 [10] = 0x8, /* 10s */
68 [12] = 0b1001, /* 12s */ 68 [12] = 0x9, /* 12s */
69 [14] = 0b1010, /* 14s */ 69 [14] = 0xA, /* 14s */
70 [16] = 0b1011, /* 16s */ 70 [16] = 0xB, /* 16s */
71}; 71};
72 72
73static int sunxi_wdt_ping(struct watchdog_device *wdt_dev) 73static int sunxi_wdt_ping(struct watchdog_device *wdt_dev)
diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c
index d2cd9f0bcb9a..56369c4f1961 100644
--- a/drivers/watchdog/via_wdt.c
+++ b/drivers/watchdog/via_wdt.c
@@ -232,7 +232,7 @@ err_out_disable_device:
232static void wdt_remove(struct pci_dev *pdev) 232static void wdt_remove(struct pci_dev *pdev)
233{ 233{
234 watchdog_unregister_device(&wdt_dev); 234 watchdog_unregister_device(&wdt_dev);
235 del_timer(&timer); 235 del_timer_sync(&timer);
236 iounmap(wdt_mem); 236 iounmap(wdt_mem);
237 release_mem_region(mmio, VIA_WDT_MMIO_LEN); 237 release_mem_region(mmio, VIA_WDT_MMIO_LEN);
238 release_resource(&wdt_res); 238 release_resource(&wdt_res);
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index b1da0c18fd1a..7165704a3e33 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -64,6 +64,10 @@ MODULE_PARM_DESC(nowayout,
64 "Watchdog cannot be stopped once started (default=" 64 "Watchdog cannot be stopped once started (default="
65 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 65 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
66 66
67static int early_disable;
68module_param(early_disable, int, 0);
69MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)");
70
67/* 71/*
68 * Kernel methods. 72 * Kernel methods.
69 */ 73 */
@@ -208,9 +212,14 @@ static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
208 212
209 t = superio_inb(cr_wdt_timeout); 213 t = superio_inb(cr_wdt_timeout);
210 if (t != 0) { 214 if (t != 0) {
211 pr_info("Watchdog already running. Resetting timeout to %d sec\n", 215 if (early_disable) {
212 wdog->timeout); 216 pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
213 superio_outb(cr_wdt_timeout, wdog->timeout); 217 superio_outb(cr_wdt_timeout, 0);
218 } else {
219 pr_info("Watchdog already running. Resetting timeout to %d sec\n",
220 wdog->timeout);
221 superio_outb(cr_wdt_timeout, wdog->timeout);
222 }
214 } 223 }
215 224
216 /* set second mode & disable keyboard turning off watchdog */ 225 /* 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
index e9ea856b8ff2..000000000000
--- a/drivers/watchdog/w83697hf_wdt.c
+++ /dev/null
@@ -1,460 +0,0 @@
1/*
2 * w83697hf/hg WDT driver
3 *
4 * (c) Copyright 2006 Samuel Tardieu <sam@rfc1149.net>
5 * (c) Copyright 2006 Marcus Junker <junker@anduras.de>
6 *
7 * Based on w83627hf_wdt.c which is based on advantechwdt.c
8 * which is based on wdt.c.
9 * Original copyright messages:
10 *
11 * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
12 *
13 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
14 *
15 * (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
16 * All Rights Reserved.
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version
21 * 2 of the License, or (at your option) any later version.
22 *
23 * Neither Marcus Junker nor ANDURAS AG admit liability nor provide
24 * warranty for any of this software. This material is provided
25 * "AS-IS" and at no charge.
26 */
27
28#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
29
30#include <linux/module.h>
31#include <linux/moduleparam.h>
32#include <linux/types.h>
33#include <linux/miscdevice.h>
34#include <linux/watchdog.h>
35#include <linux/fs.h>
36#include <linux/ioport.h>
37#include <linux/notifier.h>
38#include <linux/reboot.h>
39#include <linux/init.h>
40#include <linux/spinlock.h>
41#include <linux/io.h>
42#include <linux/uaccess.h>
43
44
45#define WATCHDOG_NAME "w83697hf/hg WDT"
46#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
47#define WATCHDOG_EARLY_DISABLE 1 /* Disable until userland kicks in */
48
49static unsigned long wdt_is_open;
50static char expect_close;
51static DEFINE_SPINLOCK(io_lock);
52
53/* You must set this - there is no sane way to probe for this board. */
54static int wdt_io = 0x2e;
55module_param(wdt_io, int, 0);
56MODULE_PARM_DESC(wdt_io,
57 "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)");
58
59static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
60module_param(timeout, int, 0);
61MODULE_PARM_DESC(timeout,
62 "Watchdog timeout in seconds. 1<= timeout <=255 (default="
63 __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
64
65static bool nowayout = WATCHDOG_NOWAYOUT;
66module_param(nowayout, bool, 0);
67MODULE_PARM_DESC(nowayout,
68 "Watchdog cannot be stopped once started (default="
69 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
70
71static int early_disable = WATCHDOG_EARLY_DISABLE;
72module_param(early_disable, int, 0);
73MODULE_PARM_DESC(early_disable,
74 "Watchdog gets disabled at boot time (default="
75 __MODULE_STRING(WATCHDOG_EARLY_DISABLE) ")");
76
77/*
78 * Kernel methods.
79 */
80
81#define W83697HF_EFER (wdt_io + 0) /* Extended Function Enable Register */
82#define W83697HF_EFIR (wdt_io + 0) /* Extended Function Index Register
83 (same as EFER) */
84#define W83697HF_EFDR (wdt_io + 1) /* Extended Function Data Register */
85
86static inline void w83697hf_unlock(void)
87{
88 outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */
89 outb_p(0x87, W83697HF_EFER); /* Again according to manual */
90}
91
92static inline void w83697hf_lock(void)
93{
94 outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */
95}
96
97/*
98 * The three functions w83697hf_get_reg(), w83697hf_set_reg() and
99 * w83697hf_write_timeout() must be called with the device unlocked.
100 */
101
102static unsigned char w83697hf_get_reg(unsigned char reg)
103{
104 outb_p(reg, W83697HF_EFIR);
105 return inb_p(W83697HF_EFDR);
106}
107
108static void w83697hf_set_reg(unsigned char reg, unsigned char data)
109{
110 outb_p(reg, W83697HF_EFIR);
111 outb_p(data, W83697HF_EFDR);
112}
113
114static void w83697hf_write_timeout(int timeout)
115{
116 /* Write Timeout counter to CRF4 */
117 w83697hf_set_reg(0xF4, timeout);
118}
119
120static void w83697hf_select_wdt(void)
121{
122 w83697hf_unlock();
123 w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */
124}
125
126static inline void w83697hf_deselect_wdt(void)
127{
128 w83697hf_lock();
129}
130
131static void w83697hf_init(void)
132{
133 unsigned char bbuf;
134
135 w83697hf_select_wdt();
136
137 bbuf = w83697hf_get_reg(0x29);
138 bbuf &= ~0x60;
139 bbuf |= 0x20;
140
141 /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
142 w83697hf_set_reg(0x29, bbuf);
143
144 bbuf = w83697hf_get_reg(0xF3);
145 bbuf &= ~0x04;
146 w83697hf_set_reg(0xF3, bbuf); /* Count mode is seconds */
147
148 w83697hf_deselect_wdt();
149}
150
151static void wdt_ping(void)
152{
153 spin_lock(&io_lock);
154 w83697hf_select_wdt();
155
156 w83697hf_write_timeout(timeout);
157
158 w83697hf_deselect_wdt();
159 spin_unlock(&io_lock);
160}
161
162static void wdt_enable(void)
163{
164 spin_lock(&io_lock);
165 w83697hf_select_wdt();
166
167 w83697hf_write_timeout(timeout);
168 w83697hf_set_reg(0x30, 1); /* Enable timer */
169
170 w83697hf_deselect_wdt();
171 spin_unlock(&io_lock);
172}
173
174static void wdt_disable(void)
175{
176 spin_lock(&io_lock);
177 w83697hf_select_wdt();
178
179 w83697hf_set_reg(0x30, 0); /* Disable timer */
180 w83697hf_write_timeout(0);
181
182 w83697hf_deselect_wdt();
183 spin_unlock(&io_lock);
184}
185
186static unsigned char wdt_running(void)
187{
188 unsigned char t;
189
190 spin_lock(&io_lock);
191 w83697hf_select_wdt();
192
193 t = w83697hf_get_reg(0xF4); /* Read timer */
194
195 w83697hf_deselect_wdt();
196 spin_unlock(&io_lock);
197
198 return t;
199}
200
201static int wdt_set_heartbeat(int t)
202{
203 if (t < 1 || t > 255)
204 return -EINVAL;
205
206 timeout = t;
207 return 0;
208}
209
210static ssize_t wdt_write(struct file *file, const char __user *buf,
211 size_t count, loff_t *ppos)
212{
213 if (count) {
214 if (!nowayout) {
215 size_t i;
216
217 expect_close = 0;
218
219 for (i = 0; i != count; i++) {
220 char c;
221 if (get_user(c, buf + i))
222 return -EFAULT;
223 if (c == 'V')
224 expect_close = 42;
225 }
226 }
227 wdt_ping();
228 }
229 return count;
230}
231
232static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
233{
234 void __user *argp = (void __user *)arg;
235 int __user *p = argp;
236 int new_timeout;
237 static const struct watchdog_info ident = {
238 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT
239 | WDIOF_MAGICCLOSE,
240 .firmware_version = 1,
241 .identity = "W83697HF WDT",
242 };
243
244 switch (cmd) {
245 case WDIOC_GETSUPPORT:
246 if (copy_to_user(argp, &ident, sizeof(ident)))
247 return -EFAULT;
248 break;
249
250 case WDIOC_GETSTATUS:
251 case WDIOC_GETBOOTSTATUS:
252 return put_user(0, p);
253
254 case WDIOC_SETOPTIONS:
255 {
256 int options, retval = -EINVAL;
257
258 if (get_user(options, p))
259 return -EFAULT;
260
261 if (options & WDIOS_DISABLECARD) {
262 wdt_disable();
263 retval = 0;
264 }
265
266 if (options & WDIOS_ENABLECARD) {
267 wdt_enable();
268 retval = 0;
269 }
270
271 return retval;
272 }
273
274 case WDIOC_KEEPALIVE:
275 wdt_ping();
276 break;
277
278 case WDIOC_SETTIMEOUT:
279 if (get_user(new_timeout, p))
280 return -EFAULT;
281 if (wdt_set_heartbeat(new_timeout))
282 return -EINVAL;
283 wdt_ping();
284 /* Fall */
285
286 case WDIOC_GETTIMEOUT:
287 return put_user(timeout, p);
288
289 default:
290 return -ENOTTY;
291 }
292 return 0;
293}
294
295static int wdt_open(struct inode *inode, struct file *file)
296{
297 if (test_and_set_bit(0, &wdt_is_open))
298 return -EBUSY;
299 /*
300 * Activate
301 */
302
303 wdt_enable();
304 return nonseekable_open(inode, file);
305}
306
307static int wdt_close(struct inode *inode, struct file *file)
308{
309 if (expect_close == 42)
310 wdt_disable();
311 else {
312 pr_crit("Unexpected close, not stopping watchdog!\n");
313 wdt_ping();
314 }
315 expect_close = 0;
316 clear_bit(0, &wdt_is_open);
317 return 0;
318}
319
320/*
321 * Notifier for system down
322 */
323
324static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
325 void *unused)
326{
327 if (code == SYS_DOWN || code == SYS_HALT)
328 wdt_disable(); /* Turn the WDT off */
329
330 return NOTIFY_DONE;
331}
332
333/*
334 * Kernel Interfaces
335 */
336
337static const struct file_operations wdt_fops = {
338 .owner = THIS_MODULE,
339 .llseek = no_llseek,
340 .write = wdt_write,
341 .unlocked_ioctl = wdt_ioctl,
342 .open = wdt_open,
343 .release = wdt_close,
344};
345
346static struct miscdevice wdt_miscdev = {
347 .minor = WATCHDOG_MINOR,
348 .name = "watchdog",
349 .fops = &wdt_fops,
350};
351
352/*
353 * The WDT needs to learn about soft shutdowns in order to
354 * turn the timebomb registers off.
355 */
356
357static struct notifier_block wdt_notifier = {
358 .notifier_call = wdt_notify_sys,
359};
360
361static int w83697hf_check_wdt(void)
362{
363 if (!request_region(wdt_io, 2, WATCHDOG_NAME)) {
364 pr_err("I/O address 0x%x already in use\n", wdt_io);
365 return -EIO;
366 }
367
368 pr_debug("Looking for watchdog at address 0x%x\n", wdt_io);
369 w83697hf_unlock();
370 if (w83697hf_get_reg(0x20) == 0x60) {
371 pr_info("watchdog found at address 0x%x\n", wdt_io);
372 w83697hf_lock();
373 return 0;
374 }
375 /* Reprotect in case it was a compatible device */
376 w83697hf_lock();
377
378 pr_info("watchdog not found at address 0x%x\n", wdt_io);
379 release_region(wdt_io, 2);
380 return -EIO;
381}
382
383static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 };
384
385static int __init wdt_init(void)
386{
387 int ret, i, found = 0;
388
389 pr_info("WDT driver for W83697HF/HG initializing\n");
390
391 if (wdt_io == 0) {
392 /* we will autodetect the W83697HF/HG watchdog */
393 for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) {
394 wdt_io = w83697hf_ioports[i];
395 if (!w83697hf_check_wdt())
396 found++;
397 }
398 } else {
399 if (!w83697hf_check_wdt())
400 found++;
401 }
402
403 if (!found) {
404 pr_err("No W83697HF/HG could be found\n");
405 ret = -ENODEV;
406 goto out;
407 }
408
409 w83697hf_init();
410 if (early_disable) {
411 if (wdt_running())
412 pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
413 wdt_disable();
414 }
415
416 if (wdt_set_heartbeat(timeout)) {
417 wdt_set_heartbeat(WATCHDOG_TIMEOUT);
418 pr_info("timeout value must be 1 <= timeout <= 255, using %d\n",
419 WATCHDOG_TIMEOUT);
420 }
421
422 ret = register_reboot_notifier(&wdt_notifier);
423 if (ret != 0) {
424 pr_err("cannot register reboot notifier (err=%d)\n", ret);
425 goto unreg_regions;
426 }
427
428 ret = misc_register(&wdt_miscdev);
429 if (ret != 0) {
430 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
431 WATCHDOG_MINOR, ret);
432 goto unreg_reboot;
433 }
434
435 pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
436 timeout, nowayout);
437
438out:
439 return ret;
440unreg_reboot:
441 unregister_reboot_notifier(&wdt_notifier);
442unreg_regions:
443 release_region(wdt_io, 2);
444 goto out;
445}
446
447static void __exit wdt_exit(void)
448{
449 misc_deregister(&wdt_miscdev);
450 unregister_reboot_notifier(&wdt_notifier);
451 release_region(wdt_io, 2);
452}
453
454module_init(wdt_init);
455module_exit(wdt_exit);
456
457MODULE_LICENSE("GPL");
458MODULE_AUTHOR("Marcus Junker <junker@anduras.de>");
459MODULE_AUTHOR("Samuel Tardieu <sam@rfc1149.net>");
460MODULE_DESCRIPTION("w83697hf/hg WDT driver");
diff --git a/drivers/watchdog/w83697ug_wdt.c b/drivers/watchdog/w83697ug_wdt.c
deleted file mode 100644
index ff58cb74671f..000000000000
--- a/drivers/watchdog/w83697ug_wdt.c
+++ /dev/null
@@ -1,397 +0,0 @@
1/*
2 * w83697ug/uf WDT driver
3 *
4 * (c) Copyright 2008 Flemming Fransen <ff@nrvissing.net>
5 * reused original code to support w83697ug/uf.
6 *
7 * Based on w83627hf_wdt.c which is based on advantechwdt.c
8 * which is based on wdt.c.
9 * Original copyright messages:
10 *
11 * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
12 * added support for W83627THF.
13 *
14 * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
15 *
16 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
17 *
18 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
19 * http://www.redhat.com
20 *
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License
23 * as published by the Free Software Foundation; either version
24 * 2 of the License, or (at your option) any later version.
25 *
26 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
27 * warranty for any of this software. This material is provided
28 * "AS-IS" and at no charge.
29 *
30 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
31 */
32
33#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/types.h>
38#include <linux/miscdevice.h>
39#include <linux/watchdog.h>
40#include <linux/fs.h>
41#include <linux/ioport.h>
42#include <linux/notifier.h>
43#include <linux/reboot.h>
44#include <linux/init.h>
45#include <linux/spinlock.h>
46#include <linux/io.h>
47#include <linux/uaccess.h>
48
49
50#define WATCHDOG_NAME "w83697ug/uf WDT"
51#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
52
53static unsigned long wdt_is_open;
54static char expect_close;
55static DEFINE_SPINLOCK(io_lock);
56
57static int wdt_io = 0x2e;
58module_param(wdt_io, int, 0);
59MODULE_PARM_DESC(wdt_io, "w83697ug/uf WDT io port (default 0x2e)");
60
61static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
62module_param(timeout, int, 0);
63MODULE_PARM_DESC(timeout,
64 "Watchdog timeout in seconds. 1<= timeout <=255 (default="
65 __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
66
67static bool nowayout = WATCHDOG_NOWAYOUT;
68module_param(nowayout, bool, 0);
69MODULE_PARM_DESC(nowayout,
70 "Watchdog cannot be stopped once started (default="
71 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
72
73/*
74 * Kernel methods.
75 */
76
77#define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */
78#define WDT_EFIR (wdt_io+0) /* Extended Function Index Register
79 (same as EFER) */
80#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
81
82static int w83697ug_select_wd_register(void)
83{
84 unsigned char c;
85 unsigned char version;
86
87 outb_p(0x87, WDT_EFER); /* Enter extended function mode */
88 outb_p(0x87, WDT_EFER); /* Again according to manual */
89
90 outb(0x20, WDT_EFER); /* check chip version */
91 version = inb(WDT_EFDR);
92
93 if (version == 0x68) { /* W83697UG */
94 pr_info("Watchdog chip version 0x%02x = W83697UG/UF found at 0x%04x\n",
95 version, wdt_io);
96
97 outb_p(0x2b, WDT_EFER);
98 c = inb_p(WDT_EFDR); /* select WDT0 */
99 c &= ~0x04;
100 outb_p(0x2b, WDT_EFER);
101 outb_p(c, WDT_EFDR); /* set pin118 to WDT0 */
102
103 } else {
104 pr_err("No W83697UG/UF could be found\n");
105 return -ENODEV;
106 }
107
108 outb_p(0x07, WDT_EFER); /* point to logical device number reg */
109 outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
110 outb_p(0x30, WDT_EFER); /* select CR30 */
111 c = inb_p(WDT_EFDR);
112 outb_p(c | 0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
113
114 return 0;
115}
116
117static void w83697ug_unselect_wd_register(void)
118{
119 outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
120}
121
122static int w83697ug_init(void)
123{
124 int ret;
125 unsigned char t;
126
127 ret = w83697ug_select_wd_register();
128 if (ret != 0)
129 return ret;
130
131 outb_p(0xF6, WDT_EFER); /* Select CRF6 */
132 t = inb_p(WDT_EFDR); /* read CRF6 */
133 if (t != 0) {
134 pr_info("Watchdog already running. Resetting timeout to %d sec\n",
135 timeout);
136 outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
137 }
138 outb_p(0xF5, WDT_EFER); /* Select CRF5 */
139 t = inb_p(WDT_EFDR); /* read CRF5 */
140 t &= ~0x0C; /* set second mode &
141 disable keyboard turning off watchdog */
142 outb_p(t, WDT_EFDR); /* Write back to CRF5 */
143
144 w83697ug_unselect_wd_register();
145 return 0;
146}
147
148static void wdt_ctrl(int timeout)
149{
150 spin_lock(&io_lock);
151
152 if (w83697ug_select_wd_register() < 0) {
153 spin_unlock(&io_lock);
154 return;
155 }
156
157 outb_p(0xF4, WDT_EFER); /* Select CRF4 */
158 outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF4 */
159
160 w83697ug_unselect_wd_register();
161
162 spin_unlock(&io_lock);
163}
164
165static int wdt_ping(void)
166{
167 wdt_ctrl(timeout);
168 return 0;
169}
170
171static int wdt_disable(void)
172{
173 wdt_ctrl(0);
174 return 0;
175}
176
177static int wdt_set_heartbeat(int t)
178{
179 if (t < 1 || t > 255)
180 return -EINVAL;
181
182 timeout = t;
183 return 0;
184}
185
186static ssize_t wdt_write(struct file *file, const char __user *buf,
187 size_t count, loff_t *ppos)
188{
189 if (count) {
190 if (!nowayout) {
191 size_t i;
192
193 expect_close = 0;
194
195 for (i = 0; i != count; i++) {
196 char c;
197 if (get_user(c, buf + i))
198 return -EFAULT;
199 if (c == 'V')
200 expect_close = 42;
201 }
202 }
203 wdt_ping();
204 }
205 return count;
206}
207
208static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
209{
210 void __user *argp = (void __user *)arg;
211 int __user *p = argp;
212 int new_timeout;
213 static const struct watchdog_info ident = {
214 .options = WDIOF_KEEPALIVEPING |
215 WDIOF_SETTIMEOUT |
216 WDIOF_MAGICCLOSE,
217 .firmware_version = 1,
218 .identity = "W83697UG WDT",
219 };
220
221 switch (cmd) {
222 case WDIOC_GETSUPPORT:
223 if (copy_to_user(argp, &ident, sizeof(ident)))
224 return -EFAULT;
225 break;
226
227 case WDIOC_GETSTATUS:
228 case WDIOC_GETBOOTSTATUS:
229 return put_user(0, p);
230
231 case WDIOC_SETOPTIONS:
232 {
233 int options, retval = -EINVAL;
234
235 if (get_user(options, p))
236 return -EFAULT;
237
238 if (options & WDIOS_DISABLECARD) {
239 wdt_disable();
240 retval = 0;
241 }
242
243 if (options & WDIOS_ENABLECARD) {
244 wdt_ping();
245 retval = 0;
246 }
247
248 return retval;
249 }
250
251 case WDIOC_KEEPALIVE:
252 wdt_ping();
253 break;
254
255 case WDIOC_SETTIMEOUT:
256 if (get_user(new_timeout, p))
257 return -EFAULT;
258 if (wdt_set_heartbeat(new_timeout))
259 return -EINVAL;
260 wdt_ping();
261 /* Fall */
262
263 case WDIOC_GETTIMEOUT:
264 return put_user(timeout, p);
265
266 default:
267 return -ENOTTY;
268 }
269 return 0;
270}
271
272static int wdt_open(struct inode *inode, struct file *file)
273{
274 if (test_and_set_bit(0, &wdt_is_open))
275 return -EBUSY;
276 /*
277 * Activate
278 */
279
280 wdt_ping();
281 return nonseekable_open(inode, file);
282}
283
284static int wdt_close(struct inode *inode, struct file *file)
285{
286 if (expect_close == 42)
287 wdt_disable();
288 else {
289 pr_crit("Unexpected close, not stopping watchdog!\n");
290 wdt_ping();
291 }
292 expect_close = 0;
293 clear_bit(0, &wdt_is_open);
294 return 0;
295}
296
297/*
298 * Notifier for system down
299 */
300
301static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
302 void *unused)
303{
304 if (code == SYS_DOWN || code == SYS_HALT)
305 wdt_disable(); /* Turn the WDT off */
306
307 return NOTIFY_DONE;
308}
309
310/*
311 * Kernel Interfaces
312 */
313
314static const struct file_operations wdt_fops = {
315 .owner = THIS_MODULE,
316 .llseek = no_llseek,
317 .write = wdt_write,
318 .unlocked_ioctl = wdt_ioctl,
319 .open = wdt_open,
320 .release = wdt_close,
321};
322
323static struct miscdevice wdt_miscdev = {
324 .minor = WATCHDOG_MINOR,
325 .name = "watchdog",
326 .fops = &wdt_fops,
327};
328
329/*
330 * The WDT needs to learn about soft shutdowns in order to
331 * turn the timebomb registers off.
332 */
333
334static struct notifier_block wdt_notifier = {
335 .notifier_call = wdt_notify_sys,
336};
337
338static int __init wdt_init(void)
339{
340 int ret;
341
342 pr_info("WDT driver for the Winbond(TM) W83697UG/UF Super I/O chip initialising\n");
343
344 if (wdt_set_heartbeat(timeout)) {
345 wdt_set_heartbeat(WATCHDOG_TIMEOUT);
346 pr_info("timeout value must be 1<=timeout<=255, using %d\n",
347 WATCHDOG_TIMEOUT);
348 }
349
350 if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
351 pr_err("I/O address 0x%04x already in use\n", wdt_io);
352 ret = -EIO;
353 goto out;
354 }
355
356 ret = w83697ug_init();
357 if (ret != 0)
358 goto unreg_regions;
359
360 ret = register_reboot_notifier(&wdt_notifier);
361 if (ret != 0) {
362 pr_err("cannot register reboot notifier (err=%d)\n", ret);
363 goto unreg_regions;
364 }
365
366 ret = misc_register(&wdt_miscdev);
367 if (ret != 0) {
368 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
369 WATCHDOG_MINOR, ret);
370 goto unreg_reboot;
371 }
372
373 pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
374 timeout, nowayout);
375
376out:
377 return ret;
378unreg_reboot:
379 unregister_reboot_notifier(&wdt_notifier);
380unreg_regions:
381 release_region(wdt_io, 1);
382 goto out;
383}
384
385static void __exit wdt_exit(void)
386{
387 misc_deregister(&wdt_miscdev);
388 unregister_reboot_notifier(&wdt_notifier);
389 release_region(wdt_io, 1);
390}
391
392module_init(wdt_init);
393module_exit(wdt_exit);
394
395MODULE_LICENSE("GPL");
396MODULE_AUTHOR("Flemming Frandsen <ff@nrvissing.net>");
397MODULE_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
index 000000000000..b98253466ace
--- /dev/null
+++ b/include/linux/platform_data/intel-mid_wdt.h
@@ -0,0 +1,22 @@
1/*
2 * intel-mid_wdt: generic Intel MID SCU watchdog driver
3 *
4 * Copyright (C) 2014 Intel Corporation. All rights reserved.
5 * Contact: David Cohen <david.a.cohen@linux.intel.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU General
9 * Public License as published by the Free Software Foundation.
10 */
11
12#ifndef __INTEL_MID_WDT_H__
13#define __INTEL_MID_WDT_H__
14
15#include <linux/platform_device.h>
16
17struct intel_mid_wdt_pdata {
18 int irq;
19 int (*probe)(struct platform_device *pdev);
20};
21
22#endif /*__INTEL_MID_WDT_H__*/