aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-29 19:57:43 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-29 19:57:43 -0800
commit17c7f85460d6b0e2bd11a736683bd81c4388474f (patch)
tree44a50a722b7a3de27bc4943f52fdb0fee336dfb5
parentf7a6ad9fa24e4511a143e2b7b8a0d55864fe2edf (diff)
parentea3d4011a871e1802e201086195c61e6dbeaf6d5 (diff)
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck: - new driver for bcm281xx watchdog device - new driver for gpio based watchdog devices - remove DEFINE_PCI_DEVICE_TABLE macro for watchdog device drivers - conversion of davinci_wdt and mpc8xxx_wdt to watchdog core - improvements on davinci_wdt, at91/dt, at91sam9_wdt and s3c2410_wdt - Auto-detect IO address and expand supported chips on w836* super-I/O chipsets - core: Make dt "timeout-sec" property work on drivers w/out min/max - fix Kconfig dependencies - sirf: Remove redundant of_match_ptr helper - mach-moxart: add restart handler - hpwdt patch to display better panic information - imx2_wdt: disable watchdog timer during low power mode * git://www.linux-watchdog.org/linux-watchdog: (31 commits) watchdog: w83627hf_wdt: Reset watchdog trigger during initialization watchdog: w83627hf: Add support for W83697HF and W83697UG watchdog: w83627hf: Auto-detect IO address and supported chips watchdog: at91sam9_wdt: increase security margin on watchdog counter reset watchdog: at91sam9_wdt: avoid spurious watchdog reset during init watchdog: at91sam9_wdt: fix secs_to_ticks ARM: at91/dt: add watchdog properties to kizbox board ARM: at91/dt: add sam9 watchdog default options to SoCs watchdog: at91sam9_wdt: update device tree doc watchdog: at91sam9_wdt: better watchdog support watchdog: sp805_wdt depends also on ARM64 watchdog: mach-moxart: add restart handler watchdog: mpc8xxx_wdt convert to watchdog core watchdog: sirf: Remove redundant of_match_ptr helper watchdog: hpwdt patch to display informative string watchdog: dw_wdt: remove build dependencies watchdog: imx2_wdt: disable watchdog timer during low power mode watchdog: s3c2410_wdt: Report when the watchdog reset the system watchdog: s3c2410_wdt: use syscon regmap interface to configure pmu register watchdog: s3c2410_wdt: Handle rounding a little better for timeout ...
-rw-r--r--Documentation/devicetree/bindings/watchdog/atmel-wdt.txt30
-rw-r--r--Documentation/devicetree/bindings/watchdog/davinci-wdt.txt16
-rw-r--r--Documentation/devicetree/bindings/watchdog/gpio-wdt.txt23
-rw-r--r--Documentation/devicetree/bindings/watchdog/samsung-wdt.txt21
-rw-r--r--arch/arm/boot/dts/at91sam9260.dtsi5
-rw-r--r--arch/arm/boot/dts/at91sam9263.dtsi5
-rw-r--r--arch/arm/boot/dts/at91sam9g45.dtsi5
-rw-r--r--arch/arm/boot/dts/at91sam9n12.dtsi5
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi5
-rw-r--r--arch/arm/boot/dts/kizbox.dts6
-rw-r--r--arch/arm/boot/dts/sama5d3.dtsi5
-rw-r--r--arch/arm/configs/bcm_defconfig3
-rw-r--r--drivers/watchdog/Kconfig59
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/alim1535_wdt.c2
-rw-r--r--drivers/watchdog/alim7101_wdt.c2
-rw-r--r--drivers/watchdog/at91sam9_wdt.c320
-rw-r--r--drivers/watchdog/bcm_kona_wdt.c368
-rw-r--r--drivers/watchdog/davinci_wdt.c221
-rw-r--r--drivers/watchdog/dw_wdt.c2
-rw-r--r--drivers/watchdog/gpio_wdt.c254
-rw-r--r--drivers/watchdog/hpwdt.c13
-rw-r--r--drivers/watchdog/i6300esb.c2
-rw-r--r--drivers/watchdog/imx2_wdt.c4
-rw-r--r--drivers/watchdog/moxart_wdt.c15
-rw-r--r--drivers/watchdog/mpc8xxx_wdt.c110
-rw-r--r--drivers/watchdog/nv_tco.c2
-rw-r--r--drivers/watchdog/pcwd_pci.c2
-rw-r--r--drivers/watchdog/s3c2410_wdt.c203
-rw-r--r--drivers/watchdog/sirfsoc_wdt.c2
-rw-r--r--drivers/watchdog/sp5100_tco.c2
-rw-r--r--drivers/watchdog/via_wdt.c2
-rw-r--r--drivers/watchdog/w83627hf_wdt.c234
-rw-r--r--drivers/watchdog/watchdog_core.c4
-rw-r--r--drivers/watchdog/wdt_pci.c2
35 files changed, 1598 insertions, 358 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
index fcdd48f7dcf..f90e294d763 100644
--- a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
@@ -9,11 +9,37 @@ Required properties:
Optional properties:
- timeout-sec: contains the watchdog timeout in seconds.
+- interrupts : Should contain WDT interrupt.
+- atmel,max-heartbeat-sec : Should contain the maximum heartbeat value in
+ seconds. This value should be less or equal to 16. It is used to
+ compute the WDV field.
+- atmel,min-heartbeat-sec : Should contain the minimum heartbeat value in
+ seconds. This value must be smaller than the max-heartbeat-sec value.
+ It is used to compute the WDD field.
+- atmel,watchdog-type : Should be "hardware" or "software". Hardware watchdog
+ use the at91 watchdog reset. Software watchdog use the watchdog
+ interrupt to trigger a software reset.
+- atmel,reset-type : Should be "proc" or "all".
+ "all" : assert peripherals and processor reset signals
+ "proc" : assert the processor reset signal
+ This is valid only when using "hardware" watchdog.
+- atmel,disable : Should be present if you want to disable the watchdog.
+- atmel,idle-halt : Should be present if you want to stop the watchdog when
+ entering idle state.
+- atmel,dbg-halt : Should be present if you want to stop the watchdog when
+ entering debug state.
Example:
-
watchdog@fffffd40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffd40 0x10>;
- timeout-sec = <10>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+ timeout-sec = <15>;
+ atmel,watchdog-type = "hardware";
+ atmel,reset-type = "all";
+ atmel,dbg-halt;
+ atmel,idle-halt;
+ atmel,max-heartbeat-sec = <16>;
+ atmel,min-heartbeat-sec = <0>;
+ status = "okay";
};
diff --git a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt
index 75558ccd9a0..e60b9a13bdc 100644
--- a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt
@@ -1,12 +1,24 @@
-DaVinci Watchdog Timer (WDT) Controller
+Texas Instruments DaVinci/Keystone Watchdog Timer (WDT) Controller
Required properties:
-- compatible : Should be "ti,davinci-wdt"
+- compatible : Should be "ti,davinci-wdt", "ti,keystone-wdt"
- reg : Should contain WDT registers location and length
+Optional properties:
+- timeout-sec : Contains the watchdog timeout in seconds
+- clocks : the clock feeding the watchdog timer.
+ Needed if platform uses clocks.
+ See clock-bindings.txt
+
+Documentation:
+Davinci DM646x - http://www.ti.com/lit/ug/spruer5b/spruer5b.pdf
+Keystone - http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf
+
Examples:
wdt: wdt@2320000 {
compatible = "ti,davinci-wdt";
reg = <0x02320000 0x80>;
+ timeout-sec = <30>;
+ clocks = <&clkwdtimer0>;
};
diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
new file mode 100644
index 00000000000..37afec19494
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
@@ -0,0 +1,23 @@
+* GPIO-controlled Watchdog
+
+Required Properties:
+- compatible: Should contain "linux,wdt-gpio".
+- gpios: From common gpio binding; gpio connection to WDT reset pin.
+- hw_algo: The algorithm used by the driver. Should be one of the
+ following values:
+ - toggle: Either a high-to-low or a low-to-high transition clears
+ the WDT counter. The watchdog timer is disabled when GPIO is
+ left floating or connected to a three-state buffer.
+ - level: Low or high level starts counting WDT timeout,
+ the opposite level disables the WDT. Active level is determined
+ by the GPIO flags.
+- hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds).
+
+Example:
+ watchdog: watchdog {
+ /* ADM706 */
+ compatible = "linux,wdt-gpio";
+ gpios = <&gpio3 9 GPIO_ACTIVE_LOW>;
+ hw_algo = "toggle";
+ hw_margin_ms = <1600>;
+ };
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
index 2aa486cc1ff..cfff37511aa 100644
--- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
@@ -5,10 +5,29 @@ after a preset amount of time during which the WDT reset event has not
occurred.
Required properties:
-- compatible : should be "samsung,s3c2410-wdt"
+- compatible : should be one among the following
+ (a) "samsung,s3c2410-wdt" for Exynos4 and previous SoCs
+ (b) "samsung,exynos5250-wdt" for Exynos5250
+ (c) "samsung,exynos5420-wdt" for Exynos5420
+
- reg : base physical address of the controller and length of memory mapped
region.
- interrupts : interrupt number to the cpu.
+- samsung,syscon-phandle : reference to syscon node (This property required only
+ in case of compatible being "samsung,exynos5250-wdt" or "samsung,exynos5420-wdt".
+ In case of Exynos5250 and 5420 this property points to syscon node holding the PMU
+ base address)
Optional properties:
- timeout-sec : contains the watchdog timeout in seconds.
+
+Example:
+
+watchdog@101D0000 {
+ compatible = "samsung,exynos5250-wdt";
+ reg = <0x101D0000 0x100>;
+ interrupts = <0 42 0>;
+ clocks = <&clock 336>;
+ clock-names = "watchdog";
+ samsung,syscon-phandle = <&pmu_syscon>;
+};
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index 56ee8282a7a..997901f7ed7 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -648,6 +648,11 @@
watchdog@fffffd40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffd40 0x10>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+ atmel,watchdog-type = "hardware";
+ atmel,reset-type = "all";
+ atmel,dbg-halt;
+ atmel,idle-halt;
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index c8fa9b9f07e..0042f73068b 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -552,6 +552,11 @@
watchdog@fffffd40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffd40 0x10>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+ atmel,watchdog-type = "hardware";
+ atmel,reset-type = "all";
+ atmel,dbg-halt;
+ atmel,idle-halt;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index ef0857cb171..cbcc058b26b 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -706,6 +706,11 @@
watchdog@fffffd40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffd40 0x10>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+ atmel,watchdog-type = "hardware";
+ atmel,reset-type = "all";
+ atmel,dbg-halt;
+ atmel,idle-halt;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index 7248270a3ea..394e6ce2afb 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -541,6 +541,11 @@
watchdog@fffffe40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffe40 0x10>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+ atmel,watchdog-type = "hardware";
+ atmel,reset-type = "all";
+ atmel,dbg-halt;
+ atmel,idle-halt;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 6e5e9cfc3c4..174219de92f 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -754,6 +754,11 @@
watchdog@fffffe40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffe40 0x10>;
+ interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+ atmel,watchdog-type = "hardware";
+ atmel,reset-type = "all";
+ atmel,dbg-halt;
+ atmel,idle-halt;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/kizbox.dts b/arch/arm/boot/dts/kizbox.dts
index 02df1914a47..928f6eef2d5 100644
--- a/arch/arm/boot/dts/kizbox.dts
+++ b/arch/arm/boot/dts/kizbox.dts
@@ -53,6 +53,12 @@
status = "okay";
};
+ watchdog@fffffd40 {
+ timeout-sec = <15>;
+ atmel,max-heartbeat-sec = <16>;
+ atmel,min-heartbeat-sec = <0>;
+ status = "okay";
+ };
};
nand0: nand@40000000 {
diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi
index 1105558d188..52447c17537 100644
--- a/arch/arm/boot/dts/sama5d3.dtsi
+++ b/arch/arm/boot/dts/sama5d3.dtsi
@@ -1092,6 +1092,11 @@
watchdog@fffffe40 {
compatible = "atmel,at91sam9260-wdt";
reg = <0xfffffe40 0x10>;
+ interrupts = <4 IRQ_TYPE_LEVEL_HIGH 7>;
+ atmel,watchdog-type = "hardware";
+ atmel,reset-type = "all";
+ atmel,dbg-halt;
+ atmel,idle-halt;
status = "disabled";
};
diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig
index 2c38fdf1951..2519d6de064 100644
--- a/arch/arm/configs/bcm_defconfig
+++ b/arch/arm/configs/bcm_defconfig
@@ -126,3 +126,6 @@ CONFIG_CRC7=y
CONFIG_XZ_DEC=y
CONFIG_AVERAGE=y
CONFIG_PINCTRL_CAPRI=y
+CONFIG_WATCHDOG=y
+CONFIG_BCM_KONA_WDT=y
+CONFIG_BCM_KONA_WDT_DEBUG=y
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 5be6e919f78..4c4c566c52a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -87,6 +87,14 @@ config DA9055_WATCHDOG
This driver can also be built as a module. If so, the module
will be called da9055_wdt.
+config GPIO_WATCHDOG
+ tristate "Watchdog device controlled through GPIO-line"
+ depends on OF_GPIO
+ select WATCHDOG_CORE
+ help
+ If you say yes here you get support for watchdog device
+ controlled through GPIO-line.
+
config WM831X_WATCHDOG
tristate "WM831x watchdog"
depends on MFD_WM831X
@@ -109,7 +117,7 @@ config WM8350_WATCHDOG
config ARM_SP805_WATCHDOG
tristate "ARM SP805 Watchdog"
- depends on ARM && ARM_AMBA
+ depends on (ARM || ARM64) && ARM_AMBA
select WATCHDOG_CORE
help
ARM Primecell SP805 Watchdog timer. This will reboot your system when
@@ -188,6 +196,7 @@ config S3C2410_WATCHDOG
tristate "S3C2410 Watchdog"
depends on HAVE_S3C2410_WATCHDOG
select WATCHDOG_CORE
+ select MFD_SYSCON if ARCH_EXYNOS5
help
Watchdog timer block in the Samsung SoCs. This will reboot
the system when the timer expires with the watchdog enabled.
@@ -214,10 +223,9 @@ config SA1100_WATCHDOG
config DW_WATCHDOG
tristate "Synopsys DesignWare watchdog"
- depends on ARM && HAVE_CLK
help
Say Y here if to include support for the Synopsys DesignWare
- watchdog timer found in many ARM chips.
+ watchdog timer found in many chips.
To compile this driver as a module, choose M here: the
module will be called dw_wdt.
@@ -270,10 +278,11 @@ config IOP_WATCHDOG
config DAVINCI_WATCHDOG
tristate "DaVinci watchdog"
- depends on ARCH_DAVINCI
+ depends on ARCH_DAVINCI || ARCH_KEYSTONE
+ select WATCHDOG_CORE
help
Say Y here if to include support for the watchdog timer
- in the DaVinci DM644x/DM646x processors.
+ in the DaVinci DM644x/DM646x or Keystone processors.
To compile this driver as a module, choose M here: the
module will be called davinci_wdt.
@@ -883,13 +892,22 @@ config VIA_WDT
Most people will say N.
config W83627HF_WDT
- tristate "W83627HF/W83627DHG Watchdog Timer"
+ tristate "Watchdog timer for W83627HF/W83627DHG and compatibles"
depends on X86
select WATCHDOG_CORE
---help---
- This is the driver for the hardware watchdog on the W83627HF chipset
- as used in Advantech PC-9578 and Tyan S2721-533 motherboards
- (and likely others). The driver also supports the W83627DHG chip.
+ This is the driver for the hardware watchdog on the following
+ Super I/O chips.
+ W83627DHG/DHG-P/EHF/EHG/F/G/HF/S/SF/THF/UHG/UG
+ W83637HF
+ W83667HG/HG-B
+ W83687THF
+ W83697HF
+ W83697UG
+ NCT6775
+ NCT6776
+ NCT6779
+
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.
@@ -1139,6 +1157,28 @@ config BCM2835_WDT
To compile this driver as a loadable module, choose M here.
The module will be called bcm2835_wdt.
+config BCM_KONA_WDT
+ tristate "BCM Kona Watchdog"
+ depends on ARCH_BCM
+ select WATCHDOG_CORE
+ help
+ Support for the watchdog timer on the following Broadcom BCM281xx
+ family, which includes BCM11130, BCM11140, BCM11351, BCM28145 and
+ BCM28155 variants.
+
+ Say 'Y' or 'M' here to enable the driver. The module will be called
+ bcm_kona_wdt.
+
+config BCM_KONA_WDT_DEBUG
+ bool "DEBUGFS support for BCM Kona Watchdog"
+ depends on BCM_KONA_WDT
+ help
+ If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides
+ access to the driver's internal data structures as well as watchdog
+ timer hardware registres.
+
+ If in doubt, say 'N'.
+
config LANTIQ_WDT
tristate "Lantiq SoC watchdog"
depends on LANTIQ
@@ -1171,6 +1211,7 @@ config MPC5200_WDT
config 8xxx_WDT
tristate "MPC8xxx Platform Watchdog Timer"
depends on PPC_8xx || PPC_83xx || PPC_86xx
+ select WATCHDOG_CORE
help
This driver is for a SoC level watchdog that exists on some
Freescale PowerPC processors. So far this driver supports:
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 91bd95a64ba..985a66cda76 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o
obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o
+obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -171,6 +172,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o
# Architecture Independent
obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
+obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o
obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
index fbb7b94cabf..3a17fbd39f8 100644
--- a/drivers/watchdog/alim1535_wdt.c
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this,
* want to register another driver on the same PCI id.
*/
-static DEFINE_PCI_DEVICE_TABLE(ali_pci_tbl) __used = {
+static const struct pci_device_id ali_pci_tbl[] __used = {
{ PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
{ PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
{ 0, },
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
index 12f0b762b52..996b2f7d330 100644
--- a/drivers/watchdog/alim7101_wdt.c
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -414,7 +414,7 @@ err_out:
module_init(alim7101_wdt_init);
module_exit(alim7101_wdt_unload);
-static DEFINE_PCI_DEVICE_TABLE(alim7101_pci_tbl) __used = {
+static const struct pci_device_id alim7101_pci_tbl[] __used = {
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
{ PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
{ }
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index be37dde4f86..489729b2629 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -19,11 +19,13 @@
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/types.h>
#include <linux/watchdog.h>
#include <linux/jiffies.h>
@@ -31,22 +33,33 @@
#include <linux/bitops.h>
#include <linux/uaccess.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include "at91sam9_wdt.h"
#define DRV_NAME "AT91SAM9 Watchdog"
-#define wdt_read(field) \
- __raw_readl(at91wdt_private.base + field)
-#define wdt_write(field, val) \
- __raw_writel((val), at91wdt_private.base + field)
+#define wdt_read(wdt, field) \
+ __raw_readl((wdt)->base + (field))
+#define wdt_write(wtd, field, val) \
+ __raw_writel((val), (wdt)->base + (field))
/* AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
* use this to convert a watchdog
* value from/to milliseconds.
*/
-#define ms_to_ticks(t) (((t << 8) / 1000) - 1)
-#define ticks_to_ms(t) (((t + 1) * 1000) >> 8)
+#define ticks_to_hz_rounddown(t) ((((t) + 1) * HZ) >> 8)
+#define ticks_to_hz_roundup(t) (((((t) + 1) * HZ) + 255) >> 8)
+#define ticks_to_secs(t) (((t) + 1) >> 8)
+#define secs_to_ticks(s) ((s) ? (((s) << 8) - 1) : 0)
+
+#define WDT_MR_RESET 0x3FFF2FFF
+
+/* Watchdog max counter value in ticks */
+#define WDT_COUNTER_MAX_TICKS 0xFFF
+
+/* Watchdog max delta/value in secs */
+#define WDT_COUNTER_MAX_SECS ticks_to_secs(WDT_COUNTER_MAX_TICKS)
/* Hardware timeout in seconds */
#define WDT_HW_TIMEOUT 2
@@ -66,23 +79,40 @@ module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
"(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-static struct watchdog_device at91_wdt_dev;
-static void at91_ping(unsigned long data);
-
-static struct {
+#define to_wdt(wdd) container_of(wdd, struct at91wdt, wdd)
+struct at91wdt {
+ struct watchdog_device wdd;
void __iomem *base;
unsigned long next_heartbeat; /* the next_heartbeat for the timer */
struct timer_list timer; /* The timer that pings the watchdog */
-} at91wdt_private;
+ u32 mr;
+ u32 mr_mask;
+ unsigned long heartbeat; /* WDT heartbeat in jiffies */
+ bool nowayout;
+ unsigned int irq;
+};
/* ......................................................................... */
+static irqreturn_t wdt_interrupt(int irq, void *dev_id)
+{
+ struct at91wdt *wdt = (struct at91wdt *)dev_id;
+
+ if (wdt_read(wdt, AT91_WDT_SR)) {
+ pr_crit("at91sam9 WDT software reset\n");
+ emergency_restart();
+ pr_crit("Reboot didn't ?????\n");
+ }
+
+ return IRQ_HANDLED;
+}
+
/*
* Reload the watchdog timer. (ie, pat the watchdog)
*/
-static inline void at91_wdt_reset(void)
+static inline void at91_wdt_reset(struct at91wdt *wdt)
{
- wdt_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
+ wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
}
/*
@@ -90,26 +120,21 @@ static inline void at91_wdt_reset(void)
*/
static void at91_ping(unsigned long data)
{
- if (time_before(jiffies, at91wdt_private.next_heartbeat) ||
- (!watchdog_active(&at91_wdt_dev))) {
- at91_wdt_reset();
- mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
- } else
+ struct at91wdt *wdt = (struct at91wdt *)data;
+ if (time_before(jiffies, wdt->next_heartbeat) ||
+ !watchdog_active(&wdt->wdd)) {
+ at91_wdt_reset(wdt);
+ mod_timer(&wdt->timer, jiffies + wdt->heartbeat);
+ } else {
pr_crit("I will reset your machine !\n");
-}
-
-static int at91_wdt_ping(struct watchdog_device *wdd)
-{
- /* calculate when the next userspace timeout will be */
- at91wdt_private.next_heartbeat = jiffies + wdd->timeout * HZ;
- return 0;
+ }
}
static int at91_wdt_start(struct watchdog_device *wdd)
{
- /* calculate the next userspace timeout and modify the timer */
- at91_wdt_ping(wdd);
- mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+ struct at91wdt *wdt = to_wdt(wdd);
+ /* calculate when the next userspace timeout will be */
+ wdt->next_heartbeat = jiffies + wdd->timeout * HZ;
return 0;
}
@@ -122,39 +147,104 @@ static int at91_wdt_stop(struct watchdog_device *wdd)
static int at91_wdt_set_timeout(struct watchdog_device *wdd, unsigned int new_timeout)
{
wdd->timeout = new_timeout;
- return 0;
+ return at91_wdt_start(wdd);
}
-/*
- * Set the watchdog time interval in 1/256Hz (write-once)
- * Counter is 12 bit.
- */
-static int at91_wdt_settimeout(unsigned int timeout)
+static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
{
- unsigned int reg;
- unsigned int mr;
-
- /* Check if disabled */
- mr = wdt_read(AT91_WDT_MR);
- if (mr & AT91_WDT_WDDIS) {
- pr_err("sorry, watchdog is disabled\n");
- return -EIO;
+ u32 tmp;
+ u32 delta;
+ u32 value;
+ int err;
+ u32 mask = wdt->mr_mask;
+ unsigned long min_heartbeat = 1;
+ unsigned long max_heartbeat;
+ struct device *dev = &pdev->dev;
+
+ tmp = wdt_read(wdt, AT91_WDT_MR);
+ if ((tmp & mask) != (wdt->mr & mask)) {
+ if (tmp == WDT_MR_RESET) {
+ wdt_write(wdt, AT91_WDT_MR, wdt->mr);
+ tmp = wdt_read(wdt, AT91_WDT_MR);
+ }
+ }
+
+ if (tmp & AT91_WDT_WDDIS) {
+ if (wdt->mr & AT91_WDT_WDDIS)
+ return 0;
+ dev_err(dev, "watchdog is disabled\n");
+ return -EINVAL;
+ }
+
+ value = tmp & AT91_WDT_WDV;
+ delta = (tmp & AT91_WDT_WDD) >> 16;
+
+ if (delta < value)
+ min_heartbeat = ticks_to_hz_roundup(value - delta);
+
+ max_heartbeat = ticks_to_hz_rounddown(value);
+ if (!max_heartbeat) {
+ dev_err(dev,
+ "heartbeat is too small for the system to handle it correctly\n");
+ return -EINVAL;
}
/*
- * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
- *
- * Since WDV is a 12-bit counter, the maximum period is
- * 4096 / 256 = 16 seconds.
+ * Try to reset the watchdog counter 4 or 2 times more often than
+ * actually requested, to avoid spurious watchdog reset.
+ * If this is not possible because of the min_heartbeat value, reset
+ * it at the min_heartbeat period.
*/
- reg = AT91_WDT_WDRSTEN /* causes watchdog reset */
- /* | AT91_WDT_WDRPROC causes processor reset only */
- | AT91_WDT_WDDBGHLT /* disabled in debug mode */
- | AT91_WDT_WDD /* restart at any time */
- | (timeout & AT91_WDT_WDV); /* timer value */
- wdt_write(AT91_WDT_MR, reg);
+ if ((max_heartbeat / 4) >= min_heartbeat)
+ wdt->heartbeat = max_heartbeat / 4;
+ else if ((max_heartbeat / 2) >= min_heartbeat)
+ wdt->heartbeat = max_heartbeat / 2;
+ else
+ wdt->heartbeat = min_heartbeat;
+
+ if (max_heartbeat < min_heartbeat + 4)
+ dev_warn(dev,
+ "min heartbeat and max heartbeat might be too close for the system to handle it correctly\n");
+
+ if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) {
+ err = request_irq(wdt->irq, wdt_interrupt,
+ IRQF_SHARED | IRQF_IRQPOLL,
+ pdev->name, wdt);
+ if (err)
+ return err;
+ }
+
+ if ((tmp & wdt->mr_mask) != (wdt->mr & wdt->mr_mask))
+ dev_warn(dev,
+ "watchdog already configured differently (mr = %x expecting %x)\n",
+ tmp & wdt->mr_mask, wdt->mr & wdt->mr_mask);
+
+ setup_timer(&wdt->timer, at91_ping, (unsigned long)wdt);
+
+ /*
+ * Use min_heartbeat the first time to avoid spurious watchdog reset:
+ * we don't know for how long the watchdog counter is running, and
+ * - resetting it right now might trigger a watchdog fault reset
+ * - waiting for heartbeat time might lead to a watchdog timeout
+ * reset
+ */
+ mod_timer(&wdt->timer, jiffies + min_heartbeat);
+
+ /* Try to set timeout from device tree first */
+ if (watchdog_init_timeout(&wdt->wdd, 0, dev))
+ watchdog_init_timeout(&wdt->wdd, heartbeat, dev);
+ watchdog_set_nowayout(&wdt->wdd, wdt->nowayout);
+ err = watchdog_register_device(&wdt->wdd);
+ if (err)
+ goto out_stop_timer;
+
+ wdt->next_heartbeat = jiffies + wdt->wdd.timeout * HZ;
return 0;
+
+out_stop_timer:
+ del_timer(&wdt->timer);
+ return err;
}
/* .........................................