diff options
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 fcdd48f7dcff..f90e294d7631 100644 --- a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt | |||
@@ -9,11 +9,37 @@ Required properties: | |||
9 | 9 | ||
10 | Optional properties: | 10 | Optional properties: |
11 | - timeout-sec: contains the watchdog timeout in seconds. | 11 | - timeout-sec: contains the watchdog timeout in seconds. |
12 | - interrupts : Should contain WDT interrupt. | ||
13 | - atmel,max-heartbeat-sec : Should contain the maximum heartbeat value in | ||
14 | seconds. This value should be less or equal to 16. It is used to | ||
15 | compute the WDV field. | ||
16 | - atmel,min-heartbeat-sec : Should contain the minimum heartbeat value in | ||
17 | seconds. This value must be smaller than the max-heartbeat-sec value. | ||
18 | It is used to compute the WDD field. | ||
19 | - atmel,watchdog-type : Should be "hardware" or "software". Hardware watchdog | ||
20 | use the at91 watchdog reset. Software watchdog use the watchdog | ||
21 | interrupt to trigger a software reset. | ||
22 | - atmel,reset-type : Should be "proc" or "all". | ||
23 | "all" : assert peripherals and processor reset signals | ||
24 | "proc" : assert the processor reset signal | ||
25 | This is valid only when using "hardware" watchdog. | ||
26 | - atmel,disable : Should be present if you want to disable the watchdog. | ||
27 | - atmel,idle-halt : Should be present if you want to stop the watchdog when | ||
28 | entering idle state. | ||
29 | - atmel,dbg-halt : Should be present if you want to stop the watchdog when | ||
30 | entering debug state. | ||
12 | 31 | ||
13 | Example: | 32 | Example: |
14 | |||
15 | watchdog@fffffd40 { | 33 | watchdog@fffffd40 { |
16 | compatible = "atmel,at91sam9260-wdt"; | 34 | compatible = "atmel,at91sam9260-wdt"; |
17 | reg = <0xfffffd40 0x10>; | 35 | reg = <0xfffffd40 0x10>; |
18 | timeout-sec = <10>; | 36 | interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; |
37 | timeout-sec = <15>; | ||
38 | atmel,watchdog-type = "hardware"; | ||
39 | atmel,reset-type = "all"; | ||
40 | atmel,dbg-halt; | ||
41 | atmel,idle-halt; | ||
42 | atmel,max-heartbeat-sec = <16>; | ||
43 | atmel,min-heartbeat-sec = <0>; | ||
44 | status = "okay"; | ||
19 | }; | 45 | }; |
diff --git a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt index 75558ccd9a05..e60b9a13bdcb 100644 --- a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt | |||
@@ -1,12 +1,24 @@ | |||
1 | DaVinci Watchdog Timer (WDT) Controller | 1 | Texas Instruments DaVinci/Keystone Watchdog Timer (WDT) Controller |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : Should be "ti,davinci-wdt" | 4 | - compatible : Should be "ti,davinci-wdt", "ti,keystone-wdt" |
5 | - reg : Should contain WDT registers location and length | 5 | - reg : Should contain WDT registers location and length |
6 | 6 | ||
7 | Optional properties: | ||
8 | - timeout-sec : Contains the watchdog timeout in seconds | ||
9 | - clocks : the clock feeding the watchdog timer. | ||
10 | Needed if platform uses clocks. | ||
11 | See clock-bindings.txt | ||
12 | |||
13 | Documentation: | ||
14 | Davinci DM646x - http://www.ti.com/lit/ug/spruer5b/spruer5b.pdf | ||
15 | Keystone - http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf | ||
16 | |||
7 | Examples: | 17 | Examples: |
8 | 18 | ||
9 | wdt: wdt@2320000 { | 19 | wdt: wdt@2320000 { |
10 | compatible = "ti,davinci-wdt"; | 20 | compatible = "ti,davinci-wdt"; |
11 | reg = <0x02320000 0x80>; | 21 | reg = <0x02320000 0x80>; |
22 | timeout-sec = <30>; | ||
23 | clocks = <&clkwdtimer0>; | ||
12 | }; | 24 | }; |
diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt new file mode 100644 index 000000000000..37afec194949 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt | |||
@@ -0,0 +1,23 @@ | |||
1 | * GPIO-controlled Watchdog | ||
2 | |||
3 | Required Properties: | ||
4 | - compatible: Should contain "linux,wdt-gpio". | ||
5 | - gpios: From common gpio binding; gpio connection to WDT reset pin. | ||
6 | - hw_algo: The algorithm used by the driver. Should be one of the | ||
7 | following values: | ||
8 | - toggle: Either a high-to-low or a low-to-high transition clears | ||
9 | the WDT counter. The watchdog timer is disabled when GPIO is | ||
10 | left floating or connected to a three-state buffer. | ||
11 | - level: Low or high level starts counting WDT timeout, | ||
12 | the opposite level disables the WDT. Active level is determined | ||
13 | by the GPIO flags. | ||
14 | - hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds). | ||
15 | |||
16 | Example: | ||
17 | watchdog: watchdog { | ||
18 | /* ADM706 */ | ||
19 | compatible = "linux,wdt-gpio"; | ||
20 | gpios = <&gpio3 9 GPIO_ACTIVE_LOW>; | ||
21 | hw_algo = "toggle"; | ||
22 | hw_margin_ms = <1600>; | ||
23 | }; | ||
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt index 2aa486cc1ff6..cfff37511aac 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 | |||
5 | occurred. | 5 | occurred. |
6 | 6 | ||
7 | Required properties: | 7 | Required properties: |
8 | - compatible : should be "samsung,s3c2410-wdt" | 8 | - compatible : should be one among the following |
9 | (a) "samsung,s3c2410-wdt" for Exynos4 and previous SoCs | ||
10 | (b) "samsung,exynos5250-wdt" for Exynos5250 | ||
11 | (c) "samsung,exynos5420-wdt" for Exynos5420 | ||
12 | |||
9 | - reg : base physical address of the controller and length of memory mapped | 13 | - reg : base physical address of the controller and length of memory mapped |
10 | region. | 14 | region. |
11 | - interrupts : interrupt number to the cpu. | 15 | - interrupts : interrupt number to the cpu. |
16 | - samsung,syscon-phandle : reference to syscon node (This property required only | ||
17 | in case of compatible being "samsung,exynos5250-wdt" or "samsung,exynos5420-wdt". | ||
18 | In case of Exynos5250 and 5420 this property points to syscon node holding the PMU | ||
19 | base address) | ||
12 | 20 | ||
13 | Optional properties: | 21 | Optional properties: |
14 | - timeout-sec : contains the watchdog timeout in seconds. | 22 | - timeout-sec : contains the watchdog timeout in seconds. |
23 | |||
24 | Example: | ||
25 | |||
26 | watchdog@101D0000 { | ||
27 | compatible = "samsung,exynos5250-wdt"; | ||
28 | reg = <0x101D0000 0x100>; | ||
29 | interrupts = <0 42 0>; | ||
30 | clocks = <&clock 336>; | ||
31 | clock-names = "watchdog"; | ||
32 | samsung,syscon-phandle = <&pmu_syscon>; | ||
33 | }; | ||
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index 56ee8282a7a8..997901f7ed73 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi | |||
@@ -648,6 +648,11 @@ | |||
648 | watchdog@fffffd40 { | 648 | watchdog@fffffd40 { |
649 | compatible = "atmel,at91sam9260-wdt"; | 649 | compatible = "atmel,at91sam9260-wdt"; |
650 | reg = <0xfffffd40 0x10>; | 650 | reg = <0xfffffd40 0x10>; |
651 | interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; | ||
652 | atmel,watchdog-type = "hardware"; | ||
653 | atmel,reset-type = "all"; | ||
654 | atmel,dbg-halt; | ||
655 | atmel,idle-halt; | ||
651 | status = "disabled"; | 656 | status = "disabled"; |
652 | }; | 657 | }; |
653 | }; | 658 | }; |
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index c8fa9b9f07e3..0042f73068b0 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi | |||
@@ -552,6 +552,11 @@ | |||
552 | watchdog@fffffd40 { | 552 | watchdog@fffffd40 { |
553 | compatible = "atmel,at91sam9260-wdt"; | 553 | compatible = "atmel,at91sam9260-wdt"; |
554 | reg = <0xfffffd40 0x10>; | 554 | reg = <0xfffffd40 0x10>; |
555 | interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; | ||
556 | atmel,watchdog-type = "hardware"; | ||
557 | atmel,reset-type = "all"; | ||
558 | atmel,dbg-halt; | ||
559 | atmel,idle-halt; | ||
555 | status = "disabled"; | 560 | status = "disabled"; |
556 | }; | 561 | }; |
557 | 562 | ||
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index ef0857cb171c..cbcc058b26b4 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi | |||
@@ -706,6 +706,11 @@ | |||
706 | watchdog@fffffd40 { | 706 | watchdog@fffffd40 { |
707 | compatible = "atmel,at91sam9260-wdt"; | 707 | compatible = "atmel,at91sam9260-wdt"; |
708 | reg = <0xfffffd40 0x10>; | 708 | reg = <0xfffffd40 0x10>; |
709 | interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; | ||
710 | atmel,watchdog-type = "hardware"; | ||
711 | atmel,reset-type = "all"; | ||
712 | atmel,dbg-halt; | ||
713 | atmel,idle-halt; | ||
709 | status = "disabled"; | 714 | status = "disabled"; |
710 | }; | 715 | }; |
711 | 716 | ||
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index 7248270a3ea6..394e6ce2afb7 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi | |||
@@ -541,6 +541,11 @@ | |||
541 | watchdog@fffffe40 { | 541 | watchdog@fffffe40 { |
542 | compatible = "atmel,at91sam9260-wdt"; | 542 | compatible = "atmel,at91sam9260-wdt"; |
543 | reg = <0xfffffe40 0x10>; | 543 | reg = <0xfffffe40 0x10>; |
544 | interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; | ||
545 | atmel,watchdog-type = "hardware"; | ||
546 | atmel,reset-type = "all"; | ||
547 | atmel,dbg-halt; | ||
548 | atmel,idle-halt; | ||
544 | status = "disabled"; | 549 | status = "disabled"; |
545 | }; | 550 | }; |
546 | 551 | ||
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 6e5e9cfc3c49..174219de92fa 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi | |||
@@ -754,6 +754,11 @@ | |||
754 | watchdog@fffffe40 { | 754 | watchdog@fffffe40 { |
755 | compatible = "atmel,at91sam9260-wdt"; | 755 | compatible = "atmel,at91sam9260-wdt"; |
756 | reg = <0xfffffe40 0x10>; | 756 | reg = <0xfffffe40 0x10>; |
757 | interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; | ||
758 | atmel,watchdog-type = "hardware"; | ||
759 | atmel,reset-type = "all"; | ||
760 | atmel,dbg-halt; | ||
761 | atmel,idle-halt; | ||
757 | status = "disabled"; | 762 | status = "disabled"; |
758 | }; | 763 | }; |
759 | 764 | ||
diff --git a/arch/arm/boot/dts/kizbox.dts b/arch/arm/boot/dts/kizbox.dts index 02df1914a47c..928f6eef2d59 100644 --- a/arch/arm/boot/dts/kizbox.dts +++ b/arch/arm/boot/dts/kizbox.dts | |||
@@ -53,6 +53,12 @@ | |||
53 | status = "okay"; | 53 | status = "okay"; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | watchdog@fffffd40 { | ||
57 | timeout-sec = <15>; | ||
58 | atmel,max-heartbeat-sec = <16>; | ||
59 | atmel,min-heartbeat-sec = <0>; | ||
60 | status = "okay"; | ||
61 | }; | ||
56 | }; | 62 | }; |
57 | 63 | ||
58 | nand0: nand@40000000 { | 64 | nand0: nand@40000000 { |
diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 1105558d188b..52447c17537a 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi | |||
@@ -1092,6 +1092,11 @@ | |||
1092 | watchdog@fffffe40 { | 1092 | watchdog@fffffe40 { |
1093 | compatible = "atmel,at91sam9260-wdt"; | 1093 | compatible = "atmel,at91sam9260-wdt"; |
1094 | reg = <0xfffffe40 0x10>; | 1094 | reg = <0xfffffe40 0x10>; |
1095 | interrupts = <4 IRQ_TYPE_LEVEL_HIGH 7>; | ||
1096 | atmel,watchdog-type = "hardware"; | ||
1097 | atmel,reset-type = "all"; | ||
1098 | atmel,dbg-halt; | ||
1099 | atmel,idle-halt; | ||
1095 | status = "disabled"; | 1100 | status = "disabled"; |
1096 | }; | 1101 | }; |
1097 | 1102 | ||
diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig index 2c38fdf1951d..2519d6de0640 100644 --- a/arch/arm/configs/bcm_defconfig +++ b/arch/arm/configs/bcm_defconfig | |||
@@ -126,3 +126,6 @@ CONFIG_CRC7=y | |||
126 | CONFIG_XZ_DEC=y | 126 | CONFIG_XZ_DEC=y |
127 | CONFIG_AVERAGE=y | 127 | CONFIG_AVERAGE=y |
128 | CONFIG_PINCTRL_CAPRI=y | 128 | CONFIG_PINCTRL_CAPRI=y |
129 | CONFIG_WATCHDOG=y | ||
130 | CONFIG_BCM_KONA_WDT=y | ||
131 | CONFIG_BCM_KONA_WDT_DEBUG=y | ||
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 5be6e919f785..4c4c566c52a3 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -87,6 +87,14 @@ config DA9055_WATCHDOG | |||
87 | This driver can also be built as a module. If so, the module | 87 | This driver can also be built as a module. If so, the module |
88 | will be called da9055_wdt. | 88 | will be called da9055_wdt. |
89 | 89 | ||
90 | config GPIO_WATCHDOG | ||
91 | tristate "Watchdog device controlled through GPIO-line" | ||
92 | depends on OF_GPIO | ||
93 | select WATCHDOG_CORE | ||
94 | help | ||
95 | If you say yes here you get support for watchdog device | ||
96 | controlled through GPIO-line. | ||
97 | |||
90 | config WM831X_WATCHDOG | 98 | config WM831X_WATCHDOG |
91 | tristate "WM831x watchdog" | 99 | tristate "WM831x watchdog" |
92 | depends on MFD_WM831X | 100 | depends on MFD_WM831X |
@@ -109,7 +117,7 @@ config WM8350_WATCHDOG | |||
109 | 117 | ||
110 | config ARM_SP805_WATCHDOG | 118 | config ARM_SP805_WATCHDOG |
111 | tristate "ARM SP805 Watchdog" | 119 | tristate "ARM SP805 Watchdog" |
112 | depends on ARM && ARM_AMBA | 120 | depends on (ARM || ARM64) && ARM_AMBA |
113 | select WATCHDOG_CORE | 121 | select WATCHDOG_CORE |
114 | help | 122 | help |
115 | ARM Primecell SP805 Watchdog timer. This will reboot your system when | 123 | ARM Primecell SP805 Watchdog timer. This will reboot your system when |
@@ -188,6 +196,7 @@ config S3C2410_WATCHDOG | |||
188 | tristate "S3C2410 Watchdog" | 196 | tristate "S3C2410 Watchdog" |
189 | depends on HAVE_S3C2410_WATCHDOG | 197 | depends on HAVE_S3C2410_WATCHDOG |
190 | select WATCHDOG_CORE | 198 | select WATCHDOG_CORE |
199 | select MFD_SYSCON if ARCH_EXYNOS5 | ||
191 | help | 200 | help |
192 | Watchdog timer block in the Samsung SoCs. This will reboot | 201 | Watchdog timer block in the Samsung SoCs. This will reboot |
193 | the system when the timer expires with the watchdog enabled. | 202 | the system when the timer expires with the watchdog enabled. |
@@ -214,10 +223,9 @@ config SA1100_WATCHDOG | |||
214 | 223 | ||
215 | config DW_WATCHDOG | 224 | config DW_WATCHDOG |
216 | tristate "Synopsys DesignWare watchdog" | 225 | tristate "Synopsys DesignWare watchdog" |
217 | depends on ARM && HAVE_CLK | ||
218 | help | 226 | help |
219 | Say Y here if to include support for the Synopsys DesignWare | 227 | Say Y here if to include support for the Synopsys DesignWare |
220 | watchdog timer found in many ARM chips. | 228 | watchdog timer found in many chips. |
221 | To compile this driver as a module, choose M here: the | 229 | To compile this driver as a module, choose M here: the |
222 | module will be called dw_wdt. | 230 | module will be called dw_wdt. |
223 | 231 | ||
@@ -270,10 +278,11 @@ config IOP_WATCHDOG | |||
270 | 278 | ||
271 | config DAVINCI_WATCHDOG | 279 | config DAVINCI_WATCHDOG |
272 | tristate "DaVinci watchdog" | 280 | tristate "DaVinci watchdog" |
273 | depends on ARCH_DAVINCI | 281 | depends on ARCH_DAVINCI || ARCH_KEYSTONE |
282 | select WATCHDOG_CORE | ||
274 | help | 283 | help |
275 | Say Y here if to include support for the watchdog timer | 284 | Say Y here if to include support for the watchdog timer |
276 | in the DaVinci DM644x/DM646x processors. | 285 | in the DaVinci DM644x/DM646x or Keystone processors. |
277 | To compile this driver as a module, choose M here: the | 286 | To compile this driver as a module, choose M here: the |
278 | module will be called davinci_wdt. | 287 | module will be called davinci_wdt. |
279 | 288 | ||
@@ -883,13 +892,22 @@ config VIA_WDT | |||
883 | Most people will say N. | 892 | Most people will say N. |
884 | 893 | ||
885 | config W83627HF_WDT | 894 | config W83627HF_WDT |
886 | tristate "W83627HF/W83627DHG Watchdog Timer" | 895 | tristate "Watchdog timer for W83627HF/W83627DHG and compatibles" |
887 | depends on X86 | 896 | depends on X86 |
888 | select WATCHDOG_CORE | 897 | select WATCHDOG_CORE |
889 | ---help--- | 898 | ---help--- |
890 | This is the driver for the hardware watchdog on the W83627HF chipset | 899 | This is the driver for the hardware watchdog on the following |
891 | as used in Advantech PC-9578 and Tyan S2721-533 motherboards | 900 | Super I/O chips. |
892 | (and likely others). The driver also supports the W83627DHG chip. | 901 | W83627DHG/DHG-P/EHF/EHG/F/G/HF/S/SF/THF/UHG/UG |
902 | W83637HF | ||
903 | W83667HG/HG-B | ||
904 | W83687THF | ||
905 | W83697HF | ||
906 | W83697UG | ||
907 | NCT6775 | ||
908 | NCT6776 | ||
909 | NCT6779 | ||
910 | |||
893 | This watchdog simply watches your kernel to make sure it doesn't | 911 | This watchdog simply watches your kernel to make sure it doesn't |
894 | freeze, and if it does, it reboots your computer after a certain | 912 | freeze, and if it does, it reboots your computer after a certain |
895 | amount of time. | 913 | amount of time. |
@@ -1139,6 +1157,28 @@ config BCM2835_WDT | |||
1139 | To compile this driver as a loadable module, choose M here. | 1157 | To compile this driver as a loadable module, choose M here. |
1140 | The module will be called bcm2835_wdt. | 1158 | The module will be called bcm2835_wdt. |
1141 | 1159 | ||
1160 | config BCM_KONA_WDT | ||
1161 | tristate "BCM Kona Watchdog" | ||
1162 | depends on ARCH_BCM | ||
1163 | select WATCHDOG_CORE | ||
1164 | help | ||
1165 | Support for the watchdog timer on the following Broadcom BCM281xx | ||
1166 | family, which includes BCM11130, BCM11140, BCM11351, BCM28145 and | ||
1167 | BCM28155 variants. | ||
1168 | |||
1169 | Say 'Y' or 'M' here to enable the driver. The module will be called | ||
1170 | bcm_kona_wdt. | ||
1171 | |||
1172 | config BCM_KONA_WDT_DEBUG | ||
1173 | bool "DEBUGFS support for BCM Kona Watchdog" | ||
1174 | depends on BCM_KONA_WDT | ||
1175 | help | ||
1176 | If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides | ||
1177 | access to the driver's internal data structures as well as watchdog | ||
1178 | timer hardware registres. | ||
1179 | |||
1180 | If in doubt, say 'N'. | ||
1181 | |||
1142 | config LANTIQ_WDT | 1182 | config LANTIQ_WDT |
1143 | tristate "Lantiq SoC watchdog" | 1183 | tristate "Lantiq SoC watchdog" |
1144 | depends on LANTIQ | 1184 | depends on LANTIQ |
@@ -1171,6 +1211,7 @@ config MPC5200_WDT | |||
1171 | config 8xxx_WDT | 1211 | config 8xxx_WDT |
1172 | tristate "MPC8xxx Platform Watchdog Timer" | 1212 | tristate "MPC8xxx Platform Watchdog Timer" |
1173 | depends on PPC_8xx || PPC_83xx || PPC_86xx | 1213 | depends on PPC_8xx || PPC_83xx || PPC_86xx |
1214 | select WATCHDOG_CORE | ||
1174 | help | 1215 | help |
1175 | This driver is for a SoC level watchdog that exists on some | 1216 | This driver is for a SoC level watchdog that exists on some |
1176 | Freescale PowerPC processors. So far this driver supports: | 1217 | Freescale PowerPC processors. So far this driver supports: |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 91bd95a64baf..985a66cda76f 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
@@ -57,6 +57,7 @@ obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o | |||
57 | obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o | 57 | obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o |
58 | obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o | 58 | obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o |
59 | obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o | 59 | obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o |
60 | obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o | ||
60 | 61 | ||
61 | # AVR32 Architecture | 62 | # AVR32 Architecture |
62 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o | 63 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o |
@@ -171,6 +172,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o | |||
171 | # Architecture Independent | 172 | # Architecture Independent |
172 | obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o | 173 | obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o |
173 | obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o | 174 | obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o |
175 | obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o | ||
174 | obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o | 176 | obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o |
175 | obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o | 177 | obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o |
176 | obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o | 178 | obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o |
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c index fbb7b94cabfd..3a17fbd39f8a 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, | |||
301 | * want to register another driver on the same PCI id. | 301 | * want to register another driver on the same PCI id. |
302 | */ | 302 | */ |
303 | 303 | ||
304 | static DEFINE_PCI_DEVICE_TABLE(ali_pci_tbl) __used = { | 304 | static const struct pci_device_id ali_pci_tbl[] __used = { |
305 | { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,}, | 305 | { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,}, |
306 | { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,}, | 306 | { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,}, |
307 | { 0, }, | 307 | { 0, }, |
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c index 12f0b762b528..996b2f7d330e 100644 --- a/drivers/watchdog/alim7101_wdt.c +++ b/drivers/watchdog/alim7101_wdt.c | |||
@@ -414,7 +414,7 @@ err_out: | |||
414 | module_init(alim7101_wdt_init); | 414 | module_init(alim7101_wdt_init); |
415 | module_exit(alim7101_wdt_unload); | 415 | module_exit(alim7101_wdt_unload); |
416 | 416 | ||
417 | static DEFINE_PCI_DEVICE_TABLE(alim7101_pci_tbl) __used = { | 417 | static const struct pci_device_id alim7101_pci_tbl[] __used = { |
418 | { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) }, | 418 | { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) }, |
419 | { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, | 419 | { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, |
420 | { } | 420 | { } |
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index be37dde4f864..489729b26298 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c | |||
@@ -19,11 +19,13 @@ | |||
19 | 19 | ||
20 | #include <linux/errno.h> | 20 | #include <linux/errno.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/interrupt.h> | ||
22 | #include <linux/io.h> | 23 | #include <linux/io.h> |
23 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
24 | #include <linux/module.h> | 25 | #include <linux/module.h> |
25 | #include <linux/moduleparam.h> | 26 | #include <linux/moduleparam.h> |
26 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/reboot.h> | ||
27 | #include <linux/types.h> | 29 | #include <linux/types.h> |
28 | #include <linux/watchdog.h> | 30 | #include <linux/watchdog.h> |
29 | #include <linux/jiffies.h> | 31 | #include <linux/jiffies.h> |
@@ -31,22 +33,33 @@ | |||
31 | #include <linux/bitops.h> | 33 | #include <linux/bitops.h> |
32 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
33 | #include <linux/of.h> | 35 | #include <linux/of.h> |
36 | #include <linux/of_irq.h> | ||
34 | 37 | ||
35 | #include "at91sam9_wdt.h" | 38 | #include "at91sam9_wdt.h" |
36 | 39 | ||
37 | #define DRV_NAME "AT91SAM9 Watchdog" | 40 | #define DRV_NAME "AT91SAM9 Watchdog" |
38 | 41 | ||
39 | #define wdt_read(field) \ | 42 | #define wdt_read(wdt, field) \ |
40 | __raw_readl(at91wdt_private.base + field) | 43 | __raw_readl((wdt)->base + (field)) |
41 | #define wdt_write(field, val) \ | 44 | #define wdt_write(wtd, field, val) \ |
42 | __raw_writel((val), at91wdt_private.base + field) | 45 | __raw_writel((val), (wdt)->base + (field)) |
43 | 46 | ||
44 | /* AT91SAM9 watchdog runs a 12bit counter @ 256Hz, | 47 | /* AT91SAM9 watchdog runs a 12bit counter @ 256Hz, |
45 | * use this to convert a watchdog | 48 | * use this to convert a watchdog |
46 | * value from/to milliseconds. | 49 | * value from/to milliseconds. |
47 | */ | 50 | */ |
48 | #define ms_to_ticks(t) (((t << 8) / 1000) - 1) | 51 | #define ticks_to_hz_rounddown(t) ((((t) + 1) * HZ) >> 8) |
49 | #define ticks_to_ms(t) (((t + 1) * 1000) >> 8) | 52 | #define ticks_to_hz_roundup(t) (((((t) + 1) * HZ) + 255) >> 8) |
53 | #define ticks_to_secs(t) (((t) + 1) >> 8) | ||
54 | #define secs_to_ticks(s) ((s) ? (((s) << 8) - 1) : 0) | ||
55 | |||
56 | #define WDT_MR_RESET 0x3FFF2FFF | ||
57 | |||
58 | /* Watchdog max counter value in ticks */ | ||
59 | #define WDT_COUNTER_MAX_TICKS 0xFFF | ||
60 | |||
61 | /* Watchdog max delta/value in secs */ | ||
62 | #define WDT_COUNTER_MAX_SECS ticks_to_secs(WDT_COUNTER_MAX_TICKS) | ||
50 | 63 | ||
51 | /* Hardware timeout in seconds */ | 64 | /* Hardware timeout in seconds */ |
52 | #define WDT_HW_TIMEOUT 2 | 65 | #define WDT_HW_TIMEOUT 2 |
@@ -66,23 +79,40 @@ module_param(nowayout, bool, 0); | |||
66 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " | 79 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " |
67 | "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 80 | "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
68 | 81 | ||
69 | static struct watchdog_device at91_wdt_dev; | 82 | #define to_wdt(wdd) container_of(wdd, struct at91wdt, wdd) |
70 | static void at91_ping(unsigned long data); | 83 | struct at91wdt { |
71 | 84 | struct watchdog_device wdd; | |
72 | static struct { | ||
73 | void __iomem *base; | 85 | void __iomem *base; |
74 | unsigned long next_heartbeat; /* the next_heartbeat for the timer */ | 86 | unsigned long next_heartbeat; /* the next_heartbeat for the timer */ |
75 | struct timer_list timer; /* The timer that pings the watchdog */ | 87 | struct timer_list timer; /* The timer that pings the watchdog */ |
76 | } at91wdt_private; | 88 | u32 mr; |
89 | u32 mr_mask; | ||
90 | unsigned long heartbeat; /* WDT heartbeat in jiffies */ | ||
91 | bool nowayout; | ||
92 | unsigned int irq; | ||
93 | }; | ||
77 | 94 | ||
78 | /* ......................................................................... */ | 95 | /* ......................................................................... */ |
79 | 96 | ||
97 | static irqreturn_t wdt_interrupt(int irq, void *dev_id) | ||
98 | { | ||
99 | struct at91wdt *wdt = (struct at91wdt *)dev_id; | ||
100 | |||
101 | if (wdt_read(wdt, AT91_WDT_SR)) { | ||
102 | pr_crit("at91sam9 WDT software reset\n"); | ||
103 | emergency_restart(); | ||
104 | pr_crit("Reboot didn't ?????\n"); | ||
105 | } | ||
106 | |||
107 | return IRQ_HANDLED; | ||
108 | } | ||
109 | |||
80 | /* | 110 | /* |
81 | * Reload the watchdog timer. (ie, pat the watchdog) | 111 | * Reload the watchdog timer. (ie, pat the watchdog) |
82 | */ | 112 | */ |
83 | static inline void at91_wdt_reset(void) | 113 | static inline void at91_wdt_reset(struct at91wdt *wdt) |
84 | { | 114 | { |
85 | wdt_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); | 115 | wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); |
86 | } | 116 | } |
87 | 117 | ||
88 | /* | 118 | /* |
@@ -90,26 +120,21 @@ static inline void at91_wdt_reset(void) | |||
90 | */ | 120 | */ |
91 | static void at91_ping(unsigned long data) | 121 | static void at91_ping(unsigned long data) |
92 | { | 122 | { |
93 | if (time_before(jiffies, at91wdt_private.next_heartbeat) || | 123 | struct at91wdt *wdt = (struct at91wdt *)data; |
94 | (!watchdog_active(&at91_wdt_dev))) { | 124 | if (time_before(jiffies, wdt->next_heartbeat) || |
95 | at91_wdt_reset(); | 125 | !watchdog_active(&wdt->wdd)) { |
96 | mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); | 126 | at91_wdt_reset(wdt); |
97 | } else | 127 | mod_timer(&wdt->timer, jiffies + wdt->heartbeat); |
128 | } else { | ||
98 | pr_crit("I will reset your machine !\n"); | 129 | pr_crit("I will reset your machine !\n"); |
99 | } | 130 | } |
100 | |||
101 | static int at91_wdt_ping(struct watchdog_device *wdd) | ||
102 | { | ||
103 | /* calculate when the next userspace timeout will be */ | ||
104 | at91wdt_private.next_heartbeat = jiffies + wdd->timeout * HZ; | ||
105 | return 0; | ||
106 | } | 131 | } |
107 | 132 | ||
108 | static int at91_wdt_start(struct watchdog_device *wdd) | 133 | static int at91_wdt_start(struct watchdog_device *wdd) |
109 | { | 134 | { |
110 | /* calculate the next userspace timeout and modify the timer */ | 135 | struct at91wdt *wdt = to_wdt(wdd); |
111 | at91_wdt_ping(wdd); | 136 | /* calculate when the next userspace timeout will be */ |
112 | mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); | 137 | wdt->next_heartbeat = jiffies + wdd->timeout * HZ; |
113 | return 0; | 138 | return 0; |
114 | } | 139 | } |
115 | 140 | ||
@@ -122,39 +147,104 @@ static int at91_wdt_stop(struct watchdog_device *wdd) | |||
122 | static int at91_wdt_set_timeout(struct watchdog_device *wdd, unsigned int new_timeout) | 147 | static int at91_wdt_set_timeout(struct watchdog_device *wdd, unsigned int new_timeout) |
123 | { | 148 | { |
124 | wdd->timeout = new_timeout; | 149 | wdd->timeout = new_timeout; |
125 | return 0; | 150 | return at91_wdt_start(wdd); |
126 | } | 151 | } |
127 | 152 | ||
128 | /* | 153 | static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt) |
129 | * Set the watchdog time interval in 1/256Hz (write-once) | ||
130 | * Counter is 12 bit. | ||
131 | */ | ||
132 | static int at91_wdt_settimeout(unsigned int timeout) | ||
133 | { | 154 | { |
134 | unsigned int reg; | 155 | u32 tmp; |
135 | unsigned int mr; | 156 | u32 delta; |
136 | 157 | u32 value; | |
137 | /* Check if disabled */ | 158 | int err; |
138 | mr = wdt_read(AT91_WDT_MR); | 159 | u32 mask = wdt->mr_mask; |
139 | if (mr & AT91_WDT_WDDIS) { | 160 | unsigned long min_heartbeat = 1; |
140 | pr_err("sorry, watchdog is disabled\n"); | 161 | unsigned long max_heartbeat; |
141 | return -EIO; | 162 | struct device *dev = &pdev->dev; |
163 | |||
164 | tmp = wdt_read(wdt, AT91_WDT_MR); | ||
165 | if ((tmp & mask) != (wdt->mr & mask)) { | ||
166 | if (tmp == WDT_MR_RESET) { | ||
167 | wdt_write(wdt, AT91_WDT_MR, wdt->mr); | ||
168 | tmp = wdt_read(wdt, AT91_WDT_MR); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | if (tmp & AT91_WDT_WDDIS) { | ||
173 | if (wdt->mr & AT91_WDT_WDDIS) | ||
174 | return 0; | ||
175 | dev_err(dev, "watchdog is disabled\n"); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | value = tmp & AT91_WDT_WDV; | ||
180 | delta = (tmp & AT91_WDT_WDD) >> 16; | ||
181 | |||
182 | if (delta < value) | ||
183 | min_heartbeat = ticks_to_hz_roundup(value - delta); | ||
184 | |||
185 | max_heartbeat = ticks_to_hz_rounddown(value); | ||
186 | if (!max_heartbeat) { | ||
187 | dev_err(dev, | ||
188 | "heartbeat is too small for the system to handle it correctly\n"); | ||
189 | return -EINVAL; | ||
142 | } | 190 | } |
143 | 191 | ||
144 | /* | 192 | /* |
145 | * All counting occurs at SLOW_CLOCK / 128 = 256 Hz | 193 | * Try to reset the watchdog counter 4 or 2 times more often than |
146 | * | 194 | * actually requested, to avoid spurious watchdog reset. |
147 | * Since WDV is a 12-bit counter, the maximum period is | 195 | * If this is not possible because of the min_heartbeat value, reset |
148 | * 4096 / 256 = 16 seconds. | 196 | * it at the min_heartbeat period. |
149 | */ | 197 | */ |
150 | reg = AT91_WDT_WDRSTEN /* causes watchdog reset */ | 198 | if ((max_heartbeat / 4) >= min_heartbeat) |
151 | /* | AT91_WDT_WDRPROC causes processor reset only */ | 199 | wdt->heartbeat = max_heartbeat / 4; |
152 | | AT91_WDT_WDDBGHLT /* disabled in debug mode */ | 200 | else if ((max_heartbeat / 2) >= min_heartbeat) |
153 | | AT91_WDT_WDD /* restart at any time */ | 201 | wdt->heartbeat = max_heartbeat / 2; |
154 | | (timeout & AT91_WDT_WDV); /* timer value */ | 202 | else |
155 | wdt_write(AT91_WDT_MR, reg); | 203 | wdt->heartbeat = min_heartbeat; |
204 | |||
205 | if (max_heartbeat < min_heartbeat + 4) | ||
206 | dev_warn(dev, | ||
207 | "min heartbeat and max heartbeat might be too close for the system to handle it correctly\n"); | ||
208 | |||
209 | if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) { | ||
210 | err = request_irq(wdt->irq, wdt_interrupt, | ||
211 | IRQF_SHARED | IRQF_IRQPOLL, | ||
212 | pdev->name, wdt); | ||
213 | if (err) | ||
214 | return err; | ||
215 | } | ||
216 | |||
217 | if ((tmp & wdt->mr_mask) != (wdt->mr & wdt->mr_mask)) | ||
218 | dev_warn(dev, | ||
219 | "watchdog already configured differently (mr = %x expecting %x)\n", | ||
220 | tmp & wdt->mr_mask, wdt->mr & wdt->mr_mask); | ||
221 | |||
222 | setup_timer(&wdt->timer, at91_ping, (unsigned long)wdt); | ||
223 | |||
224 | /* | ||
225 | * Use min_heartbeat the first time to avoid spurious watchdog reset: | ||
226 | * we don't know for how long the watchdog counter is running, and | ||
227 | * - resetting it right now might trigger a watchdog fault reset | ||
228 | * - waiting for heartbeat time might lead to a watchdog timeout | ||
229 | * reset | ||
230 | */ | ||
231 | mod_timer(&wdt->timer, jiffies + min_heartbeat); | ||
232 | |||
233 | /* Try to set timeout from device tree first */ | ||
234 | if (watchdog_init_timeout(&wdt->wdd, 0, dev)) | ||
235 | watchdog_init_timeout(&wdt->wdd, heartbeat, dev); | ||
236 | watchdog_set_nowayout(&wdt->wdd, wdt->nowayout); | ||
237 | err = watchdog_register_device(&wdt->wdd); | ||
238 | if (err) | ||
239 | goto out_stop_timer; | ||
240 | |||
241 | wdt->next_heartbeat = jiffies + wdt->wdd.timeout * HZ; | ||
156 | 242 | ||
157 | return 0; | 243 | return 0; |
244 | |||
245 | out_stop_timer: | ||
246 | del_timer(&wdt->timer); | ||
247 | return err; | ||
158 | } | 248 | } |
159 | 249 | ||
160 | /* ......................................................................... */ | 250 | /* ......................................................................... */ |
@@ -169,61 +259,123 @@ static const struct watchdog_ops at91_wdt_ops = { | |||
169 | .owner = THIS_MODULE, | 259 | .owner = THIS_MODULE, |
170 | .start = at91_wdt_start, | 260 | .start = at91_wdt_start, |
171 | .stop = at91_wdt_stop, | 261 | .stop = at91_wdt_stop, |
172 | .ping = at91_wdt_ping, | ||
173 | .set_timeout = at91_wdt_set_timeout, | 262 | .set_timeout = at91_wdt_set_timeout, |
174 | }; | 263 | }; |
175 | 264 | ||
176 | static struct watchdog_device at91_wdt_dev = { | 265 | #if defined(CONFIG_OF) |
177 | .info = &at91_wdt_info, | 266 | static int of_at91wdt_init(struct device_node *np, struct at91wdt *wdt) |
178 | .ops = &at91_wdt_ops, | 267 | { |
179 | .timeout = WDT_HEARTBEAT, | 268 | u32 min = 0; |
180 | .min_timeout = 1, | 269 | u32 max = WDT_COUNTER_MAX_SECS; |
181 | .max_timeout = 0xFFFF, | 270 | const char *tmp; |
182 | }; | 271 | |
272 | /* Get the interrupts property */ | ||
273 | wdt->irq = irq_of_parse_and_map(np, 0); | ||
274 | if (!wdt->irq) | ||
275 | dev_warn(wdt->wdd.parent, "failed to get IRQ from DT\n"); | ||
276 | |||
277 | if (!of_property_read_u32_index(np, "atmel,max-heartbeat-sec", 0, | ||
278 | &max)) { | ||
279 | if (!max || max > WDT_COUNTER_MAX_SECS) | ||
280 | max = WDT_COUNTER_MAX_SECS; | ||
281 | |||
282 | if (!of_property_read_u32_index(np, "atmel,min-heartbeat-sec", | ||
283 | 0, &min)) { | ||
284 | if (min >= max) | ||
285 | min = max - 1; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | min = secs_to_ticks(min); | ||
290 | max = secs_to_ticks(max); | ||
291 | |||
292 | wdt->mr_mask = 0x3FFFFFFF; | ||
293 | wdt->mr = 0; | ||
294 | if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && | ||
295 | !strcmp(tmp, "software")) { | ||
296 | wdt->mr |= AT91_WDT_WDFIEN; | ||
297 | wdt->mr_mask &= ~AT91_WDT_WDRPROC; | ||
298 | } else { | ||
299 | wdt->mr |= AT91_WDT_WDRSTEN; | ||
300 | } | ||
301 | |||
302 | if (!of_property_read_string(np, "atmel,reset-type", &tmp) && | ||
303 | !strcmp(tmp, "proc")) | ||
304 | wdt->mr |= AT91_WDT_WDRPROC; | ||
305 | |||
306 | if (of_property_read_bool(np, "atmel,disable")) { | ||
307 | wdt->mr |= AT91_WDT_WDDIS; | ||
308 | wdt->mr_mask &= AT91_WDT_WDDIS; | ||
309 | } | ||
310 | |||
311 | if (of_property_read_bool(np, "atmel,idle-halt")) | ||
312 | wdt->mr |= AT91_WDT_WDIDLEHLT; | ||
313 | |||
314 | if (of_property_read_bool(np, "atmel,dbg-halt")) | ||
315 | wdt->mr |= AT91_WDT_WDDBGHLT; | ||
316 | |||
317 | wdt->mr |= max | ((max - min) << 16); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | #else | ||
322 | static inline int of_at91wdt_init(struct device_node *np, struct at91wdt *wdt) | ||
323 | { | ||
324 | return 0; | ||
325 | } | ||
326 | #endif | ||
183 | 327 | ||
184 | static int __init at91wdt_probe(struct platform_device *pdev) | 328 | static int __init at91wdt_probe(struct platform_device *pdev) |
185 | { | 329 | { |
186 | struct resource *r; | 330 | struct resource *r; |
187 | int res; | 331 | int err; |
332 | struct at91wdt *wdt; | ||
188 | 333 | ||
189 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 334 | wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); |
190 | if (!r) | 335 | if (!wdt) |
191 | return -ENODEV; | ||
192 | at91wdt_private.base = ioremap(r->start, resource_size(r)); | ||
193 | if (!at91wdt_private.base) { | ||
194 | dev_err(&pdev->dev, "failed to map registers, aborting.\n"); | ||
195 | return -ENOMEM; | 336 | return -ENOMEM; |
196 | } | ||
197 | 337 | ||
198 | at91_wdt_dev.parent = &pdev->dev; | 338 | wdt->mr = (WDT_HW_TIMEOUT * 256) | AT91_WDT_WDRSTEN | AT91_WDT_WDD | |
199 | watchdog_init_timeout(&at91_wdt_dev, heartbeat, &pdev->dev); | 339 | AT91_WDT_WDDBGHLT | AT91_WDT_WDIDLEHLT; |
200 | watchdog_set_nowayout(&at91_wdt_dev, nowayout); | 340 | wdt->mr_mask = 0x3FFFFFFF; |
341 | wdt->nowayout = nowayout; | ||
342 | wdt->wdd.parent = &pdev->dev; | ||
343 | wdt->wdd.info = &at91_wdt_info; | ||
344 | wdt->wdd.ops = &at91_wdt_ops; | ||
345 | wdt->wdd.timeout = WDT_HEARTBEAT; | ||
346 | wdt->wdd.min_timeout = 1; | ||
347 | wdt->wdd.max_timeout = 0xFFFF; | ||
201 | 348 | ||
202 | /* Set watchdog */ | 349 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
203 | res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000)); | 350 | wdt->base = devm_ioremap_resource(&pdev->dev, r); |
204 | if (res) | 351 | if (IS_ERR(wdt->base)) |
205 | return res; | 352 | return PTR_ERR(wdt->base); |
353 | |||
354 | if (pdev->dev.of_node) { | ||
355 | err = of_at91wdt_init(pdev->dev.of_node, wdt); | ||
356 | if (err) | ||
357 | return err; | ||
358 | } | ||
206 | 359 | ||
207 | res = watchdog_register_device(&at91_wdt_dev); | 360 | err = at91_wdt_init(pdev, wdt); |
208 | if (res) | 361 | if (err) |
209 | return res; | 362 | return err; |
210 | 363 | ||
211 | at91wdt_private.next_heartbeat = jiffies + at91_wdt_dev.timeout * HZ; | 364 | platform_set_drvdata(pdev, wdt); |
212 | setup_timer(&at91wdt_private.timer, at91_ping, 0); | ||
213 | mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); | ||
214 | 365 | ||
215 | pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n", | 366 | pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n", |
216 | at91_wdt_dev.timeout, nowayout); | 367 | wdt->wdd.timeout, wdt->nowayout); |
217 | 368 | ||
218 | return 0; | 369 | return 0; |
219 | } | 370 | } |
220 | 371 | ||
221 | static int __exit at91wdt_remove(struct platform_device *pdev) | 372 | static int __exit at91wdt_remove(struct platform_device *pdev) |
222 | { | 373 | { |
223 | watchdog_unregister_device(&at91_wdt_dev); | 374 | struct at91wdt *wdt = platform_get_drvdata(pdev); |
375 | watchdog_unregister_device(&wdt->wdd); | ||
224 | 376 | ||
225 | pr_warn("I quit now, hardware will probably reboot!\n"); | 377 | pr_warn("I quit now, hardware will probably reboot!\n"); |
226 | del_timer(&at91wdt_private.timer); | 378 | del_timer(&wdt->timer); |
227 | 379 | ||
228 | return 0; | 380 | return 0; |
229 | } | 381 | } |
diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c new file mode 100644 index 000000000000..9c248099f4a2 --- /dev/null +++ b/drivers/watchdog/bcm_kona_wdt.c | |||
@@ -0,0 +1,368 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Broadcom Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License as | ||
6 | * published by the Free Software Foundation version 2. | ||
7 | * | ||
8 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
9 | * kind, whether express or implied; without even the implied warranty | ||
10 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/debugfs.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of_address.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/watchdog.h> | ||
22 | |||
23 | #define SECWDOG_CTRL_REG 0x00000000 | ||
24 | #define SECWDOG_COUNT_REG 0x00000004 | ||
25 | |||
26 | #define SECWDOG_RESERVED_MASK 0x1dffffff | ||
27 | #define SECWDOG_WD_LOAD_FLAG 0x10000000 | ||
28 | #define SECWDOG_EN_MASK 0x08000000 | ||
29 | #define SECWDOG_SRSTEN_MASK 0x04000000 | ||
30 | #define SECWDOG_RES_MASK 0x00f00000 | ||
31 | #define SECWDOG_COUNT_MASK 0x000fffff | ||
32 | |||
33 | #define SECWDOG_MAX_COUNT SECWDOG_COUNT_MASK | ||
34 | #define SECWDOG_CLKS_SHIFT 20 | ||
35 | #define SECWDOG_MAX_RES 15 | ||
36 | #define SECWDOG_DEFAULT_RESOLUTION 4 | ||
37 | #define SECWDOG_MAX_TRY 1000 | ||
38 | |||
39 | #define SECS_TO_TICKS(x, w) ((x) << (w)->resolution) | ||
40 | #define TICKS_TO_SECS(x, w) ((x) >> (w)->resolution) | ||
41 | |||
42 | #define BCM_KONA_WDT_NAME "bcm_kona_wdt" | ||
43 | |||
44 | struct bcm_kona_wdt { | ||
45 | void __iomem *base; | ||
46 | /* | ||
47 | * One watchdog tick is 1/(2^resolution) seconds. Resolution can take | ||
48 | * the values 0-15, meaning one tick can be 1s to 30.52us. Our default | ||
49 | * resolution of 4 means one tick is 62.5ms. | ||
50 | * | ||
51 | * The watchdog counter is 20 bits. Depending on resolution, the maximum | ||
52 | * counter value of 0xfffff expires after about 12 days (resolution 0) | ||
53 | * down to only 32s (resolution 15). The default resolution of 4 gives | ||
54 | * us a maximum of about 18 hours and 12 minutes before the watchdog | ||
55 | * times out. | ||
56 | */ | ||
57 | int resolution; | ||
58 | spinlock_t lock; | ||
59 | #ifdef CONFIG_BCM_KONA_WDT_DEBUG | ||
60 | unsigned long busy_count; | ||
61 | struct dentry *debugfs; | ||
62 | #endif | ||
63 | }; | ||
64 | |||
65 | static int secure_register_read(struct bcm_kona_wdt *wdt, uint32_t offset) | ||
66 | { | ||
67 | uint32_t val; | ||
68 | unsigned count = 0; | ||
69 | |||
70 | /* | ||
71 | * If the WD_LOAD_FLAG is set, the watchdog counter field is being | ||
72 | * updated in hardware. Once the WD timer is updated in hardware, it | ||
73 | * gets cleared. | ||
74 | */ | ||
75 | do { | ||
76 | if (unlikely(count > 1)) | ||
77 | udelay(5); | ||
78 | val = readl_relaxed(wdt->base + offset); | ||
79 | count++; | ||
80 | } while ((val & SECWDOG_WD_LOAD_FLAG) && count < SECWDOG_MAX_TRY); | ||
81 | |||
82 | #ifdef CONFIG_BCM_KONA_WDT_DEBUG | ||
83 | /* Remember the maximum number iterations due to WD_LOAD_FLAG */ | ||
84 | if (count > wdt->busy_count) | ||
85 | wdt->busy_count = count; | ||
86 | #endif | ||
87 | |||
88 | /* This is the only place we return a negative value. */ | ||
89 | if (val & SECWDOG_WD_LOAD_FLAG) | ||
90 | return -ETIMEDOUT; | ||
91 | |||
92 | /* We always mask out reserved bits. */ | ||
93 | val &= SECWDOG_RESERVED_MASK; | ||
94 | |||
95 | return val; | ||
96 | } | ||
97 | |||
98 | #ifdef CONFIG_BCM_KONA_WDT_DEBUG | ||
99 | |||
100 | static int bcm_kona_wdt_dbg_show(struct seq_file *s, void *data) | ||
101 | { | ||
102 | int ctl_val, cur_val, ret; | ||
103 | unsigned long flags; | ||
104 | struct bcm_kona_wdt *wdt = s->private; | ||
105 | |||
106 | if (!wdt) | ||
107 | return seq_puts(s, "No device pointer\n"); | ||
108 | |||
109 | spin_lock_irqsave(&wdt->lock, flags); | ||
110 | ctl_val = secure_register_read(wdt, SECWDOG_CTRL_REG); | ||
111 | cur_val = secure_register_read(wdt, SECWDOG_COUNT_REG); | ||
112 | spin_unlock_irqrestore(&wdt->lock, flags); | ||
113 | |||
114 | if (ctl_val < 0 || cur_val < 0) { | ||
115 | ret = seq_puts(s, "Error accessing hardware\n"); | ||
116 | } else { | ||
117 | int ctl, cur, ctl_sec, cur_sec, res; | ||
118 | |||
119 | ctl = ctl_val & SECWDOG_COUNT_MASK; | ||
120 | res = (ctl_val & SECWDOG_RES_MASK) >> SECWDOG_CLKS_SHIFT; | ||
121 | cur = cur_val & SECWDOG_COUNT_MASK; | ||
122 | ctl_sec = TICKS_TO_SECS(ctl, wdt); | ||
123 | cur_sec = TICKS_TO_SECS(cur, wdt); | ||
124 | ret = seq_printf(s, "Resolution: %d / %d\n" | ||
125 | "Control: %d s / %d (%#x) ticks\n" | ||
126 | "Current: %d s / %d (%#x) ticks\n" | ||
127 | "Busy count: %lu\n", res, | ||
128 | wdt->resolution, ctl_sec, ctl, ctl, cur_sec, | ||
129 | cur, cur, wdt->busy_count); | ||
130 | } | ||
131 | |||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | static int bcm_kona_dbg_open(struct inode *inode, struct file *file) | ||
136 | { | ||
137 | return single_open(file, bcm_kona_wdt_dbg_show, inode->i_private); | ||
138 | } | ||
139 | |||
140 | static const struct file_operations bcm_kona_dbg_operations = { | ||
141 | .open = bcm_kona_dbg_open, | ||
142 | .read = seq_read, | ||
143 | .llseek = seq_lseek, | ||
144 | .release = single_release, | ||
145 | }; | ||
146 | |||
147 | static void bcm_kona_wdt_debug_init(struct platform_device *pdev) | ||
148 | { | ||
149 | struct dentry *dir; | ||
150 | struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev); | ||
151 | |||
152 | if (!wdt) | ||
153 | return; | ||
154 | |||
155 | wdt->debugfs = NULL; | ||
156 | |||
157 | dir = debugfs_create_dir(BCM_KONA_WDT_NAME, NULL); | ||
158 | if (IS_ERR_OR_NULL(dir)) | ||
159 | return; | ||
160 | |||
161 | if (debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt, | ||
162 | &bcm_kona_dbg_operations)) | ||
163 | wdt->debugfs = dir; | ||
164 | else | ||
165 | debugfs_remove_recursive(dir); | ||
166 | } | ||
167 | |||
168 | static void bcm_kona_wdt_debug_exit(struct platform_device *pdev) | ||
169 | { | ||
170 | struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev); | ||
171 | |||
172 | if (wdt && wdt->debugfs) { | ||
173 | debugfs_remove_recursive(wdt->debugfs); | ||
174 | wdt->debugfs = NULL; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | #else | ||
179 | |||
180 | static void bcm_kona_wdt_debug_init(struct platform_device *pdev) {} | ||
181 | static void bcm_kona_wdt_debug_exit(struct platform_device *pdev) {} | ||
182 | |||
183 | #endif /* CONFIG_BCM_KONA_WDT_DEBUG */ | ||
184 | |||
185 | static int bcm_kona_wdt_ctrl_reg_modify(struct bcm_kona_wdt *wdt, | ||
186 | unsigned mask, unsigned newval) | ||
187 | { | ||
188 | int val; | ||
189 | unsigned long flags; | ||
190 | int ret = 0; | ||
191 | |||
192 | spin_lock_irqsave(&wdt->lock, flags); | ||
193 | |||
194 | val = secure_register_read(wdt, SECWDOG_CTRL_REG); | ||
195 | if (val < 0) { | ||
196 | ret = val; | ||
197 | } else { | ||
198 | val &= ~mask; | ||
199 | val |= newval; | ||
200 | writel_relaxed(val, wdt->base + SECWDOG_CTRL_REG); | ||
201 | } | ||
202 | |||
203 | spin_unlock_irqrestore(&wdt->lock, flags); | ||
204 | |||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | static int bcm_kona_wdt_set_resolution_reg(struct bcm_kona_wdt *wdt) | ||
209 | { | ||
210 | if (wdt->resolution > SECWDOG_MAX_RES) | ||
211 | return -EINVAL; | ||
212 | |||
213 | return bcm_kona_wdt_ctrl_reg_modify(wdt, SECWDOG_RES_MASK, | ||
214 | wdt->resolution << SECWDOG_CLKS_SHIFT); | ||
215 | } | ||
216 | |||
217 | static int bcm_kona_wdt_set_timeout_reg(struct watchdog_device *wdog, | ||
218 | unsigned watchdog_flags) | ||
219 | { | ||
220 | struct bcm_kona_wdt *wdt = watchdog_get_drvdata(wdog); | ||
221 | |||
222 | return bcm_kona_wdt_ctrl_reg_modify(wdt, SECWDOG_COUNT_MASK, | ||
223 | SECS_TO_TICKS(wdog->timeout, wdt) | | ||
224 | watchdog_flags); | ||
225 | } | ||
226 | |||
227 | static int bcm_kona_wdt_set_timeout(struct watchdog_device *wdog, | ||
228 | unsigned int t) | ||
229 | { | ||
230 | wdog->timeout = t; | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static unsigned int bcm_kona_wdt_get_timeleft(struct watchdog_device *wdog) | ||
235 | { | ||
236 | struct bcm_kona_wdt *wdt = watchdog_get_drvdata(wdog); | ||
237 | int val; | ||
238 | unsigned long flags; | ||
239 | |||
240 | spin_lock_irqsave(&wdt->lock, flags); | ||
241 | val = secure_register_read(wdt, SECWDOG_COUNT_REG); | ||
242 | spin_unlock_irqrestore(&wdt->lock, flags); | ||
243 | |||
244 | if (val < 0) | ||
245 | return val; | ||
246 | |||
247 | return TICKS_TO_SECS(val & SECWDOG_COUNT_MASK, wdt); | ||
248 | } | ||
249 | |||
250 | static int bcm_kona_wdt_start(struct watchdog_device *wdog) | ||
251 | { | ||
252 | return bcm_kona_wdt_set_timeout_reg(wdog, | ||
253 | SECWDOG_EN_MASK | SECWDOG_SRSTEN_MASK); | ||
254 | } | ||
255 | |||
256 | static int bcm_kona_wdt_stop(struct watchdog_device *wdog) | ||
257 | { | ||
258 | struct bcm_kona_wdt *wdt = watchdog_get_drvdata(wdog); | ||
259 | |||
260 | return bcm_kona_wdt_ctrl_reg_modify(wdt, SECWDOG_EN_MASK | | ||
261 | SECWDOG_SRSTEN_MASK, 0); | ||
262 | } | ||
263 | |||
264 | static struct watchdog_ops bcm_kona_wdt_ops = { | ||
265 | .owner = THIS_MODULE, | ||
266 | .start = bcm_kona_wdt_start, | ||
267 | .stop = bcm_kona_wdt_stop, | ||
268 | .set_timeout = bcm_kona_wdt_set_timeout, | ||
269 | .get_timeleft = bcm_kona_wdt_get_timeleft, | ||
270 | }; | ||
271 | |||
272 | static struct watchdog_info bcm_kona_wdt_info = { | ||
273 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | | ||
274 | WDIOF_KEEPALIVEPING, | ||
275 | .identity = "Broadcom Kona Watchdog Timer", | ||
276 | }; | ||
277 | |||
278 | static struct watchdog_device bcm_kona_wdt_wdd = { | ||
279 | .info = &bcm_kona_wdt_info, | ||
280 | .ops = &bcm_kona_wdt_ops, | ||
281 | .min_timeout = 1, | ||
282 | .max_timeout = SECWDOG_MAX_COUNT >> SECWDOG_DEFAULT_RESOLUTION, | ||
283 | .timeout = SECWDOG_MAX_COUNT >> SECWDOG_DEFAULT_RESOLUTION, | ||
284 | }; | ||
285 | |||
286 | static void bcm_kona_wdt_shutdown(struct platform_device *pdev) | ||
287 | { | ||
288 | bcm_kona_wdt_stop(&bcm_kona_wdt_wdd); | ||
289 | } | ||
290 | |||
291 | static int bcm_kona_wdt_probe(struct platform_device *pdev) | ||
292 | { | ||
293 | struct device *dev = &pdev->dev; | ||
294 | struct bcm_kona_wdt *wdt; | ||
295 | struct resource *res; | ||
296 | int ret; | ||
297 | |||
298 | wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); | ||
299 | if (!wdt) | ||
300 | return -ENOMEM; | ||
301 | |||
302 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
303 | wdt->base = devm_ioremap_resource(dev, res); | ||
304 | if (IS_ERR(wdt->base)) | ||
305 | return -ENODEV; | ||
306 | |||
307 | wdt->resolution = SECWDOG_DEFAULT_RESOLUTION; | ||
308 | ret = bcm_kona_wdt_set_resolution_reg(wdt); | ||
309 | if (ret) { | ||
310 | dev_err(dev, "Failed to set resolution (error: %d)", ret); | ||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | spin_lock_init(&wdt->lock); | ||
315 | platform_set_drvdata(pdev, wdt); | ||
316 | watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt); | ||
317 | |||
318 | ret = bcm_kona_wdt_set_timeout_reg(&bcm_kona_wdt_wdd, 0); | ||
319 | if (ret) { | ||
320 | dev_err(dev, "Failed set watchdog timeout"); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | ret = watchdog_register_device(&bcm_kona_wdt_wdd); | ||
325 | if (ret) { | ||
326 | dev_err(dev, "Failed to register watchdog device"); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | bcm_kona_wdt_debug_init(pdev); | ||
331 | dev_dbg(dev, "Broadcom Kona Watchdog Timer"); | ||
332 | |||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int bcm_kona_wdt_remove(struct platform_device *pdev) | ||
337 | { | ||
338 | bcm_kona_wdt_debug_exit(pdev); | ||
339 | bcm_kona_wdt_shutdown(pdev); | ||
340 | watchdog_unregister_device(&bcm_kona_wdt_wdd); | ||
341 | dev_dbg(&pdev->dev, "Watchdog driver disabled"); | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static const struct of_device_id bcm_kona_wdt_of_match[] = { | ||
347 | { .compatible = "brcm,kona-wdt", }, | ||
348 | {}, | ||
349 | }; | ||
350 | MODULE_DEVICE_TABLE(of, bcm_kona_wdt_of_match); | ||
351 | |||
352 | static struct platform_driver bcm_kona_wdt_driver = { | ||
353 | .driver = { | ||
354 | .name = BCM_KONA_WDT_NAME, | ||
355 | .owner = THIS_MODULE, | ||
356 | .of_match_table = bcm_kona_wdt_of_match, | ||
357 | }, | ||
358 | .probe = bcm_kona_wdt_probe, | ||
359 | .remove = bcm_kona_wdt_remove, | ||
360 | .shutdown = bcm_kona_wdt_shutdown, | ||
361 | }; | ||
362 | |||
363 | module_platform_driver(bcm_kona_wdt_driver); | ||
364 | |||
365 | MODULE_ALIAS("platform:" BCM_KONA_WDT_NAME); | ||
366 | MODULE_AUTHOR("Markus Mayer <mmayer@broadcom.com>"); | ||
367 | MODULE_DESCRIPTION("Broadcom Kona Watchdog Driver"); | ||
368 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index 12591f6596ef..b1bae03742a9 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Watchdog driver for DaVinci DM644x/DM646x processors | 4 | * Watchdog driver for DaVinci DM644x/DM646x processors |
5 | * | 5 | * |
6 | * Copyright (C) 2006 Texas Instruments. | 6 | * Copyright (C) 2006-2013 Texas Instruments. |
7 | * | 7 | * |
8 | * 2007 (c) MontaVista Software, Inc. This file is licensed under | 8 | * 2007 (c) MontaVista Software, Inc. This file is licensed under |
9 | * the terms of the GNU General Public License version 2. This program | 9 | * the terms of the GNU General Public License version 2. This program |
@@ -15,18 +15,12 @@ | |||
15 | #include <linux/moduleparam.h> | 15 | #include <linux/moduleparam.h> |
16 | #include <linux/types.h> | 16 | #include <linux/types.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/fs.h> | ||
19 | #include <linux/miscdevice.h> | ||
20 | #include <linux/watchdog.h> | 18 | #include <linux/watchdog.h> |
21 | #include <linux/init.h> | 19 | #include <linux/init.h> |
22 | #include <linux/bitops.h> | ||
23 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/uaccess.h> | ||
26 | #include <linux/io.h> | 21 | #include <linux/io.h> |
27 | #include <linux/device.h> | 22 | #include <linux/device.h> |
28 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
29 | #include <linux/slab.h> | ||
30 | #include <linux/err.h> | 24 | #include <linux/err.h> |
31 | 25 | ||
32 | #define MODULE_NAME "DAVINCI-WDT: " | 26 | #define MODULE_NAME "DAVINCI-WDT: " |
@@ -61,142 +55,103 @@ | |||
61 | #define WDKEY_SEQ0 (0xa5c6 << 16) | 55 | #define WDKEY_SEQ0 (0xa5c6 << 16) |
62 | #define WDKEY_SEQ1 (0xda7e << 16) | 56 | #define WDKEY_SEQ1 (0xda7e << 16) |
63 | 57 | ||
64 | static int heartbeat = DEFAULT_HEARTBEAT; | 58 | static int heartbeat; |
65 | 59 | ||
66 | static DEFINE_SPINLOCK(io_lock); | 60 | /* |
67 | static unsigned long wdt_status; | 61 | * struct to hold data for each WDT device |
68 | #define WDT_IN_USE 0 | 62 | * @base - base io address of WD device |
69 | #define WDT_OK_TO_CLOSE 1 | 63 | * @clk - source clock of WDT |
70 | #define WDT_REGION_INITED 2 | 64 | * @wdd - hold watchdog device as is in WDT core |
71 | #define WDT_DEVICE_INITED 3 | 65 | */ |
72 | 66 | struct davinci_wdt_device { | |
73 | static void __iomem *wdt_base; | 67 | void __iomem *base; |
74 | struct clk *wdt_clk; | 68 | struct clk *clk; |
75 | 69 | struct watchdog_device wdd; | |
76 | static void wdt_service(void) | 70 | }; |
77 | { | ||
78 | spin_lock(&io_lock); | ||
79 | |||
80 | /* put watchdog in service state */ | ||
81 | iowrite32(WDKEY_SEQ0, wdt_base + WDTCR); | ||
82 | /* put watchdog in active state */ | ||
83 | iowrite32(WDKEY_SEQ1, wdt_base + WDTCR); | ||
84 | |||
85 | spin_unlock(&io_lock); | ||
86 | } | ||
87 | 71 | ||
88 | static void wdt_enable(void) | 72 | static int davinci_wdt_start(struct watchdog_device *wdd) |
89 | { | 73 | { |
90 | u32 tgcr; | 74 | u32 tgcr; |
91 | u32 timer_margin; | 75 | u32 timer_margin; |
92 | unsigned long wdt_freq; | 76 | unsigned long wdt_freq; |
77 | struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd); | ||
93 | 78 | ||
94 | wdt_freq = clk_get_rate(wdt_clk); | 79 | wdt_freq = clk_get_rate(davinci_wdt->clk); |
95 | |||
96 | spin_lock(&io_lock); | ||
97 | 80 | ||
98 | /* disable, internal clock source */ | 81 | /* disable, internal clock source */ |
99 | iowrite32(0, wdt_base + TCR); | 82 | iowrite32(0, davinci_wdt->base + TCR); |
100 | /* reset timer, set mode to 64-bit watchdog, and unreset */ | 83 | /* reset timer, set mode to 64-bit watchdog, and unreset */ |
101 | iowrite32(0, wdt_base + TGCR); | 84 | iowrite32(0, davinci_wdt->base + TGCR); |
102 | tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET; | 85 | tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET; |
103 | iowrite32(tgcr, wdt_base + TGCR); | 86 | iowrite32(tgcr, davinci_wdt->base + TGCR); |
104 | /* clear counter regs */ | 87 | /* clear counter regs */ |
105 | iowrite32(0, wdt_base + TIM12); | 88 | iowrite32(0, davinci_wdt->base + TIM12); |
106 | iowrite32(0, wdt_base + TIM34); | 89 | iowrite32(0, davinci_wdt->base + TIM34); |
107 | /* set timeout period */ | 90 | /* set timeout period */ |
108 | timer_margin = (((u64)heartbeat * wdt_freq) & 0xffffffff); | 91 | timer_margin = (((u64)wdd->timeout * wdt_freq) & 0xffffffff); |
109 | iowrite32(timer_margin, wdt_base + PRD12); | 92 | iowrite32(timer_margin, davinci_wdt->base + PRD12); |
110 | timer_margin = (((u64)heartbeat * wdt_freq) >> 32); | 93 | timer_margin = (((u64)wdd->timeout * wdt_freq) >> 32); |
111 | iowrite32(timer_margin, wdt_base + PRD34); | 94 | iowrite32(timer_margin, davinci_wdt->base + PRD34); |
112 | /* enable run continuously */ | 95 | /* enable run continuously */ |
113 | iowrite32(ENAMODE12_PERIODIC, wdt_base + TCR); | 96 | iowrite32(ENAMODE12_PERIODIC, davinci_wdt->base + TCR); |
114 | /* Once the WDT is in pre-active state write to | 97 | /* Once the WDT is in pre-active state write to |
115 | * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are | 98 | * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are |
116 | * write protected (except for the WDKEY field) | 99 | * write protected (except for the WDKEY field) |
117 | */ | 100 | */ |
118 | /* put watchdog in pre-active state */ | 101 | /* put watchdog in pre-active state */ |
119 | iowrite32(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR); | 102 | iowrite32(WDKEY_SEQ0 | WDEN, davinci_wdt->base + WDTCR); |
120 | /* put watchdog in active state */ | 103 | /* put watchdog in active state */ |
121 | iowrite32(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR); | 104 | iowrite32(WDKEY_SEQ1 | WDEN, davinci_wdt->base + WDTCR); |
122 | 105 | return 0; | |
123 | spin_unlock(&io_lock); | ||
124 | } | 106 | } |
125 | 107 | ||
126 | static int davinci_wdt_open(struct inode *inode, struct file *file) | 108 | static int davinci_wdt_ping(struct watchdog_device *wdd) |
127 | { | 109 | { |
128 | if (test_and_set_bit(WDT_IN_USE, &wdt_status)) | 110 | struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd); |
129 | return -EBUSY; | ||
130 | |||
131 | wdt_enable(); | ||
132 | 111 | ||
133 | return nonseekable_open(inode, file); | 112 | /* put watchdog in service state */ |
113 | iowrite32(WDKEY_SEQ0, davinci_wdt->base + WDTCR); | ||
114 | /* put watchdog in active state */ | ||
115 | iowrite32(WDKEY_SEQ1, davinci_wdt->base + WDTCR); | ||
116 | return 0; | ||
134 | } | 117 | } |
135 | 118 | ||
136 | static ssize_t | 119 | static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd) |
137 | davinci_wdt_write(struct file *file, const char *data, size_t len, | ||
138 | loff_t *ppos) | ||
139 | { | 120 | { |
140 | if (len) | 121 | u64 timer_counter; |
141 | wdt_service(); | 122 | unsigned long freq; |
123 | u32 val; | ||
124 | struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd); | ||
142 | 125 | ||
143 | return len; | 126 | /* if timeout has occured then return 0 */ |
144 | } | 127 | val = ioread32(davinci_wdt->base + WDTCR); |
128 | if (val & WDFLAG) | ||
129 | return 0; | ||
145 | 130 | ||
146 | static const struct watchdog_info ident = { | 131 | freq = clk_get_rate(davinci_wdt->clk); |
147 | .options = WDIOF_KEEPALIVEPING, | ||
148 | .identity = "DaVinci Watchdog", | ||
149 | }; | ||
150 | 132 | ||
151 | static long davinci_wdt_ioctl(struct file *file, | 133 | if (!freq) |
152 | unsigned int cmd, unsigned long arg) | 134 | return 0; |
153 | { | ||
154 | int ret = -ENOTTY; | ||
155 | |||
156 | switch (cmd) { | ||
157 | case WDIOC_GETSUPPORT: | ||
158 | ret = copy_to_user((struct watchdog_info *)arg, &ident, | ||
159 | sizeof(ident)) ? -EFAULT : 0; | ||
160 | break; | ||
161 | |||
162 | case WDIOC_GETSTATUS: | ||
163 | case WDIOC_GETBOOTSTATUS: | ||
164 | ret = put_user(0, (int *)arg); | ||
165 | break; | ||
166 | |||
167 | case WDIOC_KEEPALIVE: | ||
168 | wdt_service(); | ||
169 | ret = 0; | ||
170 | break; | ||
171 | |||
172 | case WDIOC_GETTIMEOUT: | ||
173 | ret = put_user(heartbeat, (int *)arg); | ||
174 | break; | ||
175 | } | ||
176 | return ret; | ||
177 | } | ||
178 | 135 | ||
179 | static int davinci_wdt_release(struct inode *inode, struct file *file) | 136 | timer_counter = ioread32(davinci_wdt->base + TIM12); |
180 | { | 137 | timer_counter |= ((u64)ioread32(davinci_wdt->base + TIM34) << 32); |
181 | wdt_service(); | ||
182 | clear_bit(WDT_IN_USE, &wdt_status); | ||
183 | 138 | ||
184 | return 0; | 139 | do_div(timer_counter, freq); |
140 | |||
141 | return wdd->timeout - timer_counter; | ||
185 | } | 142 | } |
186 | 143 | ||
187 | static const struct file_operations davinci_wdt_fops = { | 144 | static const struct watchdog_info davinci_wdt_info = { |
188 | .owner = THIS_MODULE, | 145 | .options = WDIOF_KEEPALIVEPING, |
189 | .llseek = no_llseek, | 146 | .identity = "DaVinci/Keystone Watchdog", |
190 | .write = davinci_wdt_write, | ||
191 | .unlocked_ioctl = davinci_wdt_ioctl, | ||
192 | .open = davinci_wdt_open, | ||
193 | .release = davinci_wdt_release, | ||
194 | }; | 147 | }; |
195 | 148 | ||
196 | static struct miscdevice davinci_wdt_miscdev = { | 149 | static const struct watchdog_ops davinci_wdt_ops = { |
197 | .minor = WATCHDOG_MINOR, | 150 | .owner = THIS_MODULE, |
198 | .name = "watchdog", | 151 | .start = davinci_wdt_start, |
199 | .fops = &davinci_wdt_fops, | 152 | .stop = davinci_wdt_ping, |
153 | .ping = davinci_wdt_ping, | ||
154 | .get_timeleft = davinci_wdt_get_timeleft, | ||
200 | }; | 155 | }; |
201 | 156 | ||
202 | static int davinci_wdt_probe(struct platform_device *pdev) | 157 | static int davinci_wdt_probe(struct platform_device *pdev) |
@@ -204,37 +159,53 @@ static int davinci_wdt_probe(struct platform_device *pdev) | |||
204 | int ret = 0; | 159 | int ret = 0; |
205 | struct device *dev = &pdev->dev; | 160 | struct device *dev = &pdev->dev; |
206 | struct resource *wdt_mem; | 161 | struct resource *wdt_mem; |
162 | struct watchdog_device *wdd; | ||
163 | struct davinci_wdt_device *davinci_wdt; | ||
164 | |||
165 | davinci_wdt = devm_kzalloc(dev, sizeof(*davinci_wdt), GFP_KERNEL); | ||
166 | if (!davinci_wdt) | ||
167 | return -ENOMEM; | ||
207 | 168 | ||
208 | wdt_clk = devm_clk_get(dev, NULL); | 169 | davinci_wdt->clk = devm_clk_get(dev, NULL); |
209 | if (WARN_ON(IS_ERR(wdt_clk))) | 170 | if (WARN_ON(IS_ERR(davinci_wdt->clk))) |
210 | return PTR_ERR(wdt_clk); | 171 | return PTR_ERR(davinci_wdt->clk); |
211 | 172 | ||
212 | clk_prepare_enable(wdt_clk); | 173 | clk_prepare_enable(davinci_wdt->clk); |
213 | 174 | ||
214 | if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) | 175 | platform_set_drvdata(pdev, davinci_wdt); |
215 | heartbeat = DEFAULT_HEARTBEAT; | ||
216 | 176 | ||
217 | dev_info(dev, "heartbeat %d sec\n", heartbeat); | 177 | wdd = &davinci_wdt->wdd; |
178 | wdd->info = &davinci_wdt_info; | ||
179 | wdd->ops = &davinci_wdt_ops; | ||
180 | wdd->min_timeout = 1; | ||
181 | wdd->max_timeout = MAX_HEARTBEAT; | ||
182 | wdd->timeout = DEFAULT_HEARTBEAT; | ||
183 | |||
184 | watchdog_init_timeout(wdd, heartbeat, dev); | ||
185 | |||
186 | dev_info(dev, "heartbeat %d sec\n", wdd->timeout); | ||
187 | |||
188 | watchdog_set_drvdata(wdd, davinci_wdt); | ||
189 | watchdog_set_nowayout(wdd, 1); | ||
218 | 190 | ||
219 | wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 191 | wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
220 | wdt_base = devm_ioremap_resource(dev, wdt_mem); | 192 | davinci_wdt->base = devm_ioremap_resource(dev, wdt_mem); |
221 | if (IS_ERR(wdt_base)) | 193 | if (IS_ERR(davinci_wdt->base)) |
222 | return PTR_ERR(wdt_base); | 194 | return PTR_ERR(davinci_wdt->base); |
223 | 195 | ||
224 | ret = misc_register(&davinci_wdt_miscdev); | 196 | ret = watchdog_register_device(wdd); |
225 | if (ret < 0) { | 197 | if (ret < 0) |
226 | dev_err(dev, "cannot register misc device\n"); | 198 | dev_err(dev, "cannot register watchdog device\n"); |
227 | } else { | ||
228 | set_bit(WDT_DEVICE_INITED, &wdt_status); | ||
229 | } | ||
230 | 199 | ||
231 | return ret; | 200 | return ret; |
232 | } | 201 | } |
233 | 202 | ||
234 | static int davinci_wdt_remove(struct platform_device *pdev) | 203 | static int davinci_wdt_remove(struct platform_device *pdev) |
235 | { | 204 | { |
236 | misc_deregister(&davinci_wdt_miscdev); | 205 | struct davinci_wdt_device *davinci_wdt = platform_get_drvdata(pdev); |
237 | clk_disable_unprepare(wdt_clk); | 206 | |
207 | watchdog_unregister_device(&davinci_wdt->wdd); | ||
208 | clk_disable_unprepare(davinci_wdt->clk); | ||
238 | 209 | ||
239 | return 0; | 210 | return 0; |
240 | } | 211 | } |
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index a46f5c7ee7ff..ee4f86ba83ec 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c | |||
@@ -8,7 +8,7 @@ | |||
8 | * 2 of the License, or (at your option) any later version. | 8 | * 2 of the License, or (at your option) any later version. |
9 | * | 9 | * |
10 | * This file implements a driver for the Synopsys DesignWare watchdog device | 10 | * This file implements a driver for the Synopsys DesignWare watchdog device |
11 | * in the many ARM subsystems. The watchdog has 16 different timeout periods | 11 | * in the many subsystems. The watchdog has 16 different timeout periods |
12 | * and these are a function of the input clock frequency. | 12 | * and these are a function of the input clock frequency. |
13 | * | 13 | * |
14 | * The DesignWare watchdog cannot be stopped once it has been started so we | 14 | * The DesignWare watchdog cannot be stopped once it has been started so we |
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c new file mode 100644 index 000000000000..220a9e07cfd5 --- /dev/null +++ b/drivers/watchdog/gpio_wdt.c | |||
@@ -0,0 +1,254 @@ | |||
1 | /* | ||
2 | * Driver for watchdog device controlled through GPIO-line | ||
3 | * | ||
4 | * Author: 2013, Alexander Shiyan <shc_work@mail.ru> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/err.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/notifier.h> | ||
16 | #include <linux/of_gpio.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/reboot.h> | ||
19 | #include <linux/watchdog.h> | ||
20 | |||
21 | #define SOFT_TIMEOUT_MIN 1 | ||
22 | #define SOFT_TIMEOUT_DEF 60 | ||
23 | #define SOFT_TIMEOUT_MAX 0xffff | ||
24 | |||
25 | enum { | ||
26 | HW_ALGO_TOGGLE, | ||
27 | HW_ALGO_LEVEL, | ||
28 | }; | ||
29 | |||
30 | struct gpio_wdt_priv { | ||
31 | int gpio; | ||
32 | bool active_low; | ||
33 | bool state; | ||
34 | unsigned int hw_algo; | ||
35 | unsigned int hw_margin; | ||
36 | unsigned long last_jiffies; | ||
37 | struct notifier_block notifier; | ||
38 | struct timer_list timer; | ||
39 | struct watchdog_device wdd; | ||
40 | }; | ||
41 | |||
42 | static void gpio_wdt_disable(struct gpio_wdt_priv *priv) | ||
43 | { | ||
44 | gpio_set_value_cansleep(priv->gpio, !priv->active_low); | ||
45 | |||
46 | /* Put GPIO back to tristate */ | ||
47 | if (priv->hw_algo == HW_ALGO_TOGGLE) | ||
48 | gpio_direction_input(priv->gpio); | ||
49 | } | ||
50 | |||
51 | static int gpio_wdt_start(struct watchdog_device *wdd) | ||
52 | { | ||
53 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||
54 | |||
55 | priv->state = priv->active_low; | ||
56 | gpio_direction_output(priv->gpio, priv->state); | ||
57 | priv->last_jiffies = jiffies; | ||
58 | mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin); | ||
59 | |||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | static int gpio_wdt_stop(struct watchdog_device *wdd) | ||
64 | { | ||
65 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||
66 | |||
67 | mod_timer(&priv->timer, 0); | ||
68 | gpio_wdt_disable(priv); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int gpio_wdt_ping(struct watchdog_device *wdd) | ||
74 | { | ||
75 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||
76 | |||
77 | priv->last_jiffies = jiffies; | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int gpio_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) | ||
83 | { | ||
84 | wdd->timeout = t; | ||
85 | |||
86 | return gpio_wdt_ping(wdd); | ||
87 | } | ||
88 | |||
89 | static void gpio_wdt_hwping(unsigned long data) | ||
90 | { | ||
91 | struct watchdog_device *wdd = (struct watchdog_device *)data; | ||
92 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||
93 | |||
94 | if (time_after(jiffies, priv->last_jiffies + | ||
95 | msecs_to_jiffies(wdd->timeout * 1000))) { | ||
96 | dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | /* Restart timer */ | ||
101 | mod_timer(&priv->timer, jiffies + priv->hw_margin); | ||
102 | |||
103 | switch (priv->hw_algo) { | ||
104 | case HW_ALGO_TOGGLE: | ||
105 | /* Toggle output pin */ | ||
106 | priv->state = !priv->state; | ||
107 | gpio_set_value_cansleep(priv->gpio, priv->state); | ||
108 | break; | ||
109 | case HW_ALGO_LEVEL: | ||
110 | /* Pulse */ | ||
111 | gpio_set_value_cansleep(priv->gpio, !priv->active_low); | ||
112 | udelay(1); | ||
113 | gpio_set_value_cansleep(priv->gpio, priv->active_low); | ||
114 | break; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | static int gpio_wdt_notify_sys(struct notifier_block *nb, unsigned long code, | ||
119 | void *unused) | ||
120 | { | ||
121 | struct gpio_wdt_priv *priv = container_of(nb, struct gpio_wdt_priv, | ||
122 | notifier); | ||
123 | |||
124 | mod_timer(&priv->timer, 0); | ||
125 | |||
126 | switch (code) { | ||
127 | case SYS_HALT: | ||
128 | case SYS_POWER_OFF: | ||
129 | gpio_wdt_disable(priv); | ||
130 | break; | ||
131 | default: | ||
132 | break; | ||
133 | } | ||
134 | |||
135 | return NOTIFY_DONE; | ||
136 | } | ||
137 | |||
138 | static const struct watchdog_info gpio_wdt_ident = { | ||
139 | .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | | ||
140 | WDIOF_SETTIMEOUT, | ||
141 | .identity = "GPIO Watchdog", | ||
142 | }; | ||
143 | |||
144 | static const struct watchdog_ops gpio_wdt_ops = { | ||
145 | .owner = THIS_MODULE, | ||
146 | .start = gpio_wdt_start, | ||
147 | .stop = gpio_wdt_stop, | ||
148 | .ping = gpio_wdt_ping, | ||
149 | .set_timeout = gpio_wdt_set_timeout, | ||
150 | }; | ||
151 | |||
152 | static int gpio_wdt_probe(struct platform_device *pdev) | ||
153 | { | ||
154 | struct gpio_wdt_priv *priv; | ||
155 | enum of_gpio_flags flags; | ||
156 | unsigned int hw_margin; | ||
157 | unsigned long f = 0; | ||
158 | const char *algo; | ||
159 | int ret; | ||
160 | |||
161 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
162 | if (!priv) | ||
163 | return -ENOMEM; | ||
164 | |||
165 | priv->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags); | ||
166 | if (!gpio_is_valid(priv->gpio)) | ||
167 | return priv->gpio; | ||
168 | |||
169 | priv->active_low = flags & OF_GPIO_ACTIVE_LOW; | ||
170 | |||
171 | ret = of_property_read_string(pdev->dev.of_node, "hw_algo", &algo); | ||
172 | if (ret) | ||
173 | return ret; | ||
174 | if (!strncmp(algo, "toggle", 6)) { | ||
175 | priv->hw_algo = HW_ALGO_TOGGLE; | ||
176 | f = GPIOF_IN; | ||
177 | } else if (!strncmp(algo, "level", 5)) { | ||
178 | priv->hw_algo = HW_ALGO_LEVEL; | ||
179 | f = priv->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; | ||
180 | } else { | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | ret = devm_gpio_request_one(&pdev->dev, priv->gpio, f, | ||
185 | dev_name(&pdev->dev)); | ||
186 | if (ret) | ||
187 | return ret; | ||
188 | |||
189 | ret = of_property_read_u32(pdev->dev.of_node, | ||
190 | "hw_margin_ms", &hw_margin); | ||
191 | if (ret) | ||
192 | return ret; | ||
193 | /* Disallow values lower than 2 and higher than 65535 ms */ | ||
194 | if (hw_margin < 2 || hw_margin > 65535) | ||
195 | return -EINVAL; | ||
196 | |||
197 | /* Use safe value (1/2 of real timeout) */ | ||
198 | priv->hw_margin = msecs_to_jiffies(hw_margin / 2); | ||
199 | |||
200 | watchdog_set_drvdata(&priv->wdd, priv); | ||
201 | |||
202 | priv->wdd.info = &gpio_wdt_ident; | ||
203 | priv->wdd.ops = &gpio_wdt_ops; | ||
204 | priv->wdd.min_timeout = SOFT_TIMEOUT_MIN; | ||
205 | priv->wdd.max_timeout = SOFT_TIMEOUT_MAX; | ||
206 | |||
207 | if (watchdog_init_timeout(&priv->wdd, 0, &pdev->dev) < 0) | ||
208 | priv->wdd.timeout = SOFT_TIMEOUT_DEF; | ||
209 | |||
210 | setup_timer(&priv->timer, gpio_wdt_hwping, (unsigned long)&priv->wdd); | ||
211 | |||
212 | ret = watchdog_register_device(&priv->wdd); | ||
213 | if (ret) | ||
214 | return ret; | ||
215 | |||
216 | priv->notifier.notifier_call = gpio_wdt_notify_sys; | ||
217 | ret = register_reboot_notifier(&priv->notifier); | ||
218 | if (ret) | ||
219 | watchdog_unregister_device(&priv->wdd); | ||
220 | |||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | static int gpio_wdt_remove(struct platform_device *pdev) | ||
225 | { | ||
226 | struct gpio_wdt_priv *priv = platform_get_drvdata(pdev); | ||
227 | |||
228 | del_timer_sync(&priv->timer); | ||
229 | unregister_reboot_notifier(&priv->notifier); | ||
230 | watchdog_unregister_device(&priv->wdd); | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static const struct of_device_id gpio_wdt_dt_ids[] = { | ||
236 | { .compatible = "linux,wdt-gpio", }, | ||
237 | { } | ||
238 | }; | ||
239 | MODULE_DEVICE_TABLE(of, gpio_wdt_dt_ids); | ||
240 | |||
241 | static struct platform_driver gpio_wdt_driver = { | ||
242 | .driver = { | ||
243 | .name = "gpio-wdt", | ||
244 | .owner = THIS_MODULE, | ||
245 | .of_match_table = gpio_wdt_dt_ids, | ||
246 | }, | ||
247 | .probe = gpio_wdt_probe, | ||
248 | .remove = gpio_wdt_remove, | ||
249 | }; | ||
250 | module_platform_driver(gpio_wdt_driver); | ||
251 | |||
252 | MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); | ||
253 | MODULE_DESCRIPTION("GPIO Watchdog"); | ||
254 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 45b979d9dd13..2b75e8b47279 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
@@ -39,7 +39,7 @@ | |||
39 | #endif /* CONFIG_HPWDT_NMI_DECODING */ | 39 | #endif /* CONFIG_HPWDT_NMI_DECODING */ |
40 | #include <asm/nmi.h> | 40 | #include <asm/nmi.h> |
41 | 41 | ||
42 | #define HPWDT_VERSION "1.3.2" | 42 | #define HPWDT_VERSION "1.3.3" |
43 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) | 43 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) |
44 | #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) | 44 | #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) |
45 | #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) | 45 | #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) |
@@ -55,7 +55,7 @@ static void __iomem *pci_mem_addr; /* the PCI-memory address */ | |||
55 | static unsigned long __iomem *hpwdt_timer_reg; | 55 | static unsigned long __iomem *hpwdt_timer_reg; |
56 | static unsigned long __iomem *hpwdt_timer_con; | 56 | static unsigned long __iomem *hpwdt_timer_con; |
57 | 57 | ||
58 | static DEFINE_PCI_DEVICE_TABLE(hpwdt_devices) = { | 58 | static const struct pci_device_id hpwdt_devices[] = { |
59 | { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */ | 59 | { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */ |
60 | { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */ | 60 | { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */ |
61 | {0}, /* terminate list */ | 61 | {0}, /* terminate list */ |
@@ -501,8 +501,13 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) | |||
501 | "but unable to determine source.\n"); | 501 | "but unable to determine source.\n"); |
502 | } | 502 | } |
503 | } | 503 | } |
504 | panic("An NMI occurred, please see the Integrated " | 504 | panic("An NMI occurred. Depending on your system the reason " |
505 | "Management Log for details.\n"); | 505 | "for the NMI is logged in any one of the following " |
506 | "resources:\n" | ||
507 | "1. Integrated Management Log (IML)\n" | ||
508 | "2. OA Syslog\n" | ||
509 | "3. OA Forward Progress Log\n" | ||
510 | "4. iLO Event Log"); | ||
506 | 511 | ||
507 | out: | 512 | out: |
508 | return NMI_DONE; | 513 | return NMI_DONE; |
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c index a72fe9361ddf..25a2bfdb4e9d 100644 --- a/drivers/watchdog/i6300esb.c +++ b/drivers/watchdog/i6300esb.c | |||
@@ -334,7 +334,7 @@ static struct miscdevice esb_miscdev = { | |||
334 | /* | 334 | /* |
335 | * Data for PCI driver interface | 335 | * Data for PCI driver interface |
336 | */ | 336 | */ |
337 | static DEFINE_PCI_DEVICE_TABLE(esb_pci_tbl) = { | 337 | static const struct pci_device_id esb_pci_tbl[] = { |
338 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, | 338 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, |
339 | { 0, }, /* End of list */ | 339 | { 0, }, /* End of list */ |
340 | }; | 340 | }; |
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index b4786bccc42c..dd51d9539b33 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * Watchdog driver for IMX2 and later processors | 2 | * Watchdog driver for IMX2 and later processors |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. <w.sang@pengutronix.de> | 4 | * Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. <w.sang@pengutronix.de> |
5 | * Copyright (C) 2014 Freescale Semiconductor, Inc. | ||
5 | * | 6 | * |
6 | * some parts adapted by similar drivers from Darius Augulis and Vladimir | 7 | * some parts adapted by similar drivers from Darius Augulis and Vladimir |
7 | * Zapolskiy, additional improvements by Wim Van Sebroeck. | 8 | * Zapolskiy, additional improvements by Wim Van Sebroeck. |
@@ -40,6 +41,7 @@ | |||
40 | #define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */ | 41 | #define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */ |
41 | #define IMX2_WDT_WCR_WRE (1 << 3) /* -> WDOG Reset Enable */ | 42 | #define IMX2_WDT_WCR_WRE (1 << 3) /* -> WDOG Reset Enable */ |
42 | #define IMX2_WDT_WCR_WDE (1 << 2) /* -> Watchdog Enable */ | 43 | #define IMX2_WDT_WCR_WDE (1 << 2) /* -> Watchdog Enable */ |
44 | #define IMX2_WDT_WCR_WDZST (1 << 0) /* -> Watchdog timer Suspend */ | ||
43 | 45 | ||
44 | #define IMX2_WDT_WSR 0x02 /* Service Register */ | 46 | #define IMX2_WDT_WSR 0x02 /* Service Register */ |
45 | #define IMX2_WDT_SEQ1 0x5555 /* -> service sequence 1 */ | 47 | #define IMX2_WDT_SEQ1 0x5555 /* -> service sequence 1 */ |
@@ -87,6 +89,8 @@ static inline void imx2_wdt_setup(void) | |||
87 | { | 89 | { |
88 | u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR); | 90 | u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR); |
89 | 91 | ||
92 | /* Suspend timer in low power mode, write once-only */ | ||
93 | val |= IMX2_WDT_WCR_WDZST; | ||
90 | /* Strip the old watchdog Time-Out value */ | 94 | /* Strip the old watchdog Time-Out value */ |
91 | val &= ~IMX2_WDT_WCR_WT; | 95 | val &= ~IMX2_WDT_WCR_WT; |
92 | /* Generate reset if WDOG times out */ | 96 | /* Generate reset if WDOG times out */ |
diff --git a/drivers/watchdog/moxart_wdt.c b/drivers/watchdog/moxart_wdt.c index 4166e4d116a8..4aa3a8a876fe 100644 --- a/drivers/watchdog/moxart_wdt.c +++ b/drivers/watchdog/moxart_wdt.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/watchdog.h> | 19 | #include <linux/watchdog.h> |
20 | #include <linux/moduleparam.h> | 20 | #include <linux/moduleparam.h> |
21 | 21 | ||
22 | #include <asm/system_misc.h> | ||
23 | |||
22 | #define REG_COUNT 0x4 | 24 | #define REG_COUNT 0x4 |
23 | #define REG_MODE 0x8 | 25 | #define REG_MODE 0x8 |
24 | #define REG_ENABLE 0xC | 26 | #define REG_ENABLE 0xC |
@@ -29,8 +31,17 @@ struct moxart_wdt_dev { | |||
29 | unsigned int clock_frequency; | 31 | unsigned int clock_frequency; |
30 | }; | 32 | }; |
31 | 33 | ||
34 | static struct moxart_wdt_dev *moxart_restart_ctx; | ||
35 | |||
32 | static int heartbeat; | 36 | static int heartbeat; |
33 | 37 | ||
38 | static void moxart_wdt_restart(enum reboot_mode reboot_mode, const char *cmd) | ||
39 | { | ||
40 | writel(1, moxart_restart_ctx->base + REG_COUNT); | ||
41 | writel(0x5ab9, moxart_restart_ctx->base + REG_MODE); | ||
42 | writel(0x03, moxart_restart_ctx->base + REG_ENABLE); | ||
43 | } | ||
44 | |||
34 | static int moxart_wdt_stop(struct watchdog_device *wdt_dev) | 45 | static int moxart_wdt_stop(struct watchdog_device *wdt_dev) |
35 | { | 46 | { |
36 | struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev); | 47 | struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev); |
@@ -125,6 +136,9 @@ static int moxart_wdt_probe(struct platform_device *pdev) | |||
125 | if (err) | 136 | if (err) |
126 | return err; | 137 | return err; |
127 | 138 | ||
139 | moxart_restart_ctx = moxart_wdt; | ||
140 | arm_pm_restart = moxart_wdt_restart; | ||
141 | |||
128 | dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n", | 142 | dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n", |
129 | moxart_wdt->dev.timeout, nowayout); | 143 | moxart_wdt->dev.timeout, nowayout); |
130 | 144 | ||
@@ -135,6 +149,7 @@ static int moxart_wdt_remove(struct platform_device *pdev) | |||
135 | { | 149 | { |
136 | struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev); | 150 | struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev); |
137 | 151 | ||
152 | arm_pm_restart = NULL; | ||
138 | moxart_wdt_stop(&moxart_wdt->dev); | 153 | moxart_wdt_stop(&moxart_wdt->dev); |
139 | watchdog_unregister_device(&moxart_wdt->dev); | 154 | watchdog_unregister_device(&moxart_wdt->dev); |
140 | 155 | ||
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index d82152077fd9..c1f65b4c0aa4 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c | |||
@@ -73,9 +73,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " | |||
73 | * to 0 | 73 | * to 0 |
74 | */ | 74 | */ |
75 | static int prescale = 1; | 75 | static int prescale = 1; |
76 | static unsigned int timeout_sec; | ||
77 | 76 | ||
78 | static unsigned long wdt_is_open; | ||
79 | static DEFINE_SPINLOCK(wdt_spinlock); | 77 | static DEFINE_SPINLOCK(wdt_spinlock); |
80 | 78 | ||
81 | static void mpc8xxx_wdt_keepalive(void) | 79 | static void mpc8xxx_wdt_keepalive(void) |
@@ -87,39 +85,23 @@ static void mpc8xxx_wdt_keepalive(void) | |||
87 | spin_unlock(&wdt_spinlock); | 85 | spin_unlock(&wdt_spinlock); |
88 | } | 86 | } |
89 | 87 | ||
88 | static struct watchdog_device mpc8xxx_wdt_dev; | ||
90 | static void mpc8xxx_wdt_timer_ping(unsigned long arg); | 89 | static void mpc8xxx_wdt_timer_ping(unsigned long arg); |
91 | static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, 0); | 90 | static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, |
91 | (unsigned long)&mpc8xxx_wdt_dev); | ||
92 | 92 | ||
93 | static void mpc8xxx_wdt_timer_ping(unsigned long arg) | 93 | static void mpc8xxx_wdt_timer_ping(unsigned long arg) |
94 | { | 94 | { |
95 | struct watchdog_device *w = (struct watchdog_device *)arg; | ||
96 | |||
95 | mpc8xxx_wdt_keepalive(); | 97 | mpc8xxx_wdt_keepalive(); |
96 | /* We're pinging it twice faster than needed, just to be sure. */ | 98 | /* We're pinging it twice faster than needed, just to be sure. */ |
97 | mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2); | 99 | mod_timer(&wdt_timer, jiffies + HZ * w->timeout / 2); |
98 | } | ||
99 | |||
100 | static void mpc8xxx_wdt_pr_warn(const char *msg) | ||
101 | { | ||
102 | pr_crit("%s, expect the %s soon!\n", msg, | ||
103 | reset ? "reset" : "machine check exception"); | ||
104 | } | 100 | } |
105 | 101 | ||
106 | static ssize_t mpc8xxx_wdt_write(struct file *file, const char __user *buf, | 102 | static int mpc8xxx_wdt_start(struct watchdog_device *w) |
107 | size_t count, loff_t *ppos) | ||
108 | { | ||
109 | if (count) | ||
110 | mpc8xxx_wdt_keepalive(); | ||
111 | return count; | ||
112 | } | ||
113 | |||
114 | static int mpc8xxx_wdt_open(struct inode *inode, struct file *file) | ||
115 | { | 103 | { |
116 | u32 tmp = SWCRR_SWEN; | 104 | u32 tmp = SWCRR_SWEN; |
117 | if (test_and_set_bit(0, &wdt_is_open)) | ||
118 | return -EBUSY; | ||
119 | |||
120 | /* Once we start the watchdog we can't stop it */ | ||
121 | if (nowayout) | ||
122 | __module_get(THIS_MODULE); | ||
123 | 105 | ||
124 | /* Good, fire up the show */ | 106 | /* Good, fire up the show */ |
125 | if (prescale) | 107 | if (prescale) |
@@ -133,59 +115,37 @@ static int mpc8xxx_wdt_open(struct inode *inode, struct file *file) | |||
133 | 115 | ||
134 | del_timer_sync(&wdt_timer); | 116 | del_timer_sync(&wdt_timer); |
135 | 117 | ||
136 | return nonseekable_open(inode, file); | 118 | return 0; |
137 | } | 119 | } |
138 | 120 | ||
139 | static int mpc8xxx_wdt_release(struct inode *inode, struct file *file) | 121 | static int mpc8xxx_wdt_ping(struct watchdog_device *w) |
140 | { | 122 | { |
141 | if (!nowayout) | 123 | mpc8xxx_wdt_keepalive(); |
142 | mpc8xxx_wdt_timer_ping(0); | ||
143 | else | ||
144 | mpc8xxx_wdt_pr_warn("watchdog closed"); | ||
145 | clear_bit(0, &wdt_is_open); | ||
146 | return 0; | 124 | return 0; |
147 | } | 125 | } |
148 | 126 | ||
149 | static long mpc8xxx_wdt_ioctl(struct file *file, unsigned int cmd, | 127 | static int mpc8xxx_wdt_stop(struct watchdog_device *w) |
150 | unsigned long arg) | ||
151 | { | 128 | { |
152 | void __user *argp = (void __user *)arg; | 129 | mod_timer(&wdt_timer, jiffies); |
153 | int __user *p = argp; | 130 | return 0; |
154 | static const struct watchdog_info ident = { | ||
155 | .options = WDIOF_KEEPALIVEPING, | ||
156 | .firmware_version = 1, | ||
157 | .identity = "MPC8xxx", | ||
158 | }; | ||
159 | |||
160 | switch (cmd) { | ||
161 | case WDIOC_GETSUPPORT: | ||
162 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
163 | case WDIOC_GETSTATUS: | ||
164 | case WDIOC_GETBOOTSTATUS: | ||
165 | return put_user(0, p); | ||
166 | case WDIOC_KEEPALIVE: | ||
167 | mpc8xxx_wdt_keepalive(); | ||
168 | return 0; | ||
169 | case WDIOC_GETTIMEOUT: | ||
170 | return put_user(timeout_sec, p); | ||
171 | default: | ||
172 | return -ENOTTY; | ||
173 | } | ||
174 | } | 131 | } |
175 | 132 | ||
176 | static const struct file_operations mpc8xxx_wdt_fops = { | 133 | static struct watchdog_info mpc8xxx_wdt_info = { |
177 | .owner = THIS_MODULE, | 134 | .options = WDIOF_KEEPALIVEPING, |
178 | .llseek = no_llseek, | 135 | .firmware_version = 1, |
179 | .write = mpc8xxx_wdt_write, | 136 | .identity = "MPC8xxx", |
180 | .unlocked_ioctl = mpc8xxx_wdt_ioctl, | ||
181 | .open = mpc8xxx_wdt_open, | ||
182 | .release = mpc8xxx_wdt_release, | ||
183 | }; | 137 | }; |
184 | 138 | ||
185 | static struct miscdevice mpc8xxx_wdt_miscdev = { | 139 | static struct watchdog_ops mpc8xxx_wdt_ops = { |
186 | .minor = WATCHDOG_MINOR, | 140 | .owner = THIS_MODULE, |
187 | .name = "watchdog", | 141 | .start = mpc8xxx_wdt_start, |
188 | .fops = &mpc8xxx_wdt_fops, | 142 | .ping = mpc8xxx_wdt_ping, |
143 | .stop = mpc8xxx_wdt_stop, | ||
144 | }; | ||
145 | |||
146 | static struct watchdog_device mpc8xxx_wdt_dev = { | ||
147 | .info = &mpc8xxx_wdt_info, | ||
148 | .ops = &mpc8xxx_wdt_ops, | ||
189 | }; | 149 | }; |
190 | 150 | ||
191 | static const struct of_device_id mpc8xxx_wdt_match[]; | 151 | static const struct of_device_id mpc8xxx_wdt_match[]; |
@@ -197,6 +157,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) | |||
197 | const struct mpc8xxx_wdt_type *wdt_type; | 157 | const struct mpc8xxx_wdt_type *wdt_type; |
198 | u32 freq = fsl_get_sys_freq(); | 158 | u32 freq = fsl_get_sys_freq(); |
199 | bool enabled; | 159 | bool enabled; |
160 | unsigned int timeout_sec; | ||
200 | 161 | ||
201 | match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev); | 162 | match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev); |
202 | if (!match) | 163 | if (!match) |
@@ -223,6 +184,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) | |||
223 | else | 184 | else |
224 | timeout_sec = timeout / freq; | 185 | timeout_sec = timeout / freq; |
225 | 186 | ||
187 | mpc8xxx_wdt_dev.timeout = timeout_sec; | ||
226 | #ifdef MODULE | 188 | #ifdef MODULE |
227 | ret = mpc8xxx_wdt_init_late(); | 189 | ret = mpc8xxx_wdt_init_late(); |
228 | if (ret) | 190 | if (ret) |
@@ -238,7 +200,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) | |||
238 | * userspace handles it. | 200 | * userspace handles it. |
239 | */ | 201 | */ |
240 | if (enabled) | 202 | if (enabled) |
241 | mpc8xxx_wdt_timer_ping(0); | 203 | mod_timer(&wdt_timer, jiffies); |
242 | return 0; | 204 | return 0; |
243 | err_unmap: | 205 | err_unmap: |
244 | iounmap(wd_base); | 206 | iounmap(wd_base); |
@@ -248,9 +210,10 @@ err_unmap: | |||
248 | 210 | ||
249 | static int mpc8xxx_wdt_remove(struct platform_device *ofdev) | 211 | static int mpc8xxx_wdt_remove(struct platform_device *ofdev) |
250 | { | 212 | { |
251 | mpc8xxx_wdt_pr_warn("watchdog removed"); | 213 | pr_crit("Watchdog removed, expect the %s soon!\n", |
214 | reset ? "reset" : "machine check exception"); | ||
252 | del_timer_sync(&wdt_timer); | 215 | del_timer_sync(&wdt_timer); |
253 | misc_deregister(&mpc8xxx_wdt_miscdev); | 216 | watchdog_unregister_device(&mpc8xxx_wdt_dev); |
254 | iounmap(wd_base); | 217 | iounmap(wd_base); |
255 | 218 | ||
256 | return 0; | 219 | return 0; |
@@ -302,10 +265,11 @@ static int mpc8xxx_wdt_init_late(void) | |||
302 | if (!wd_base) | 265 | if (!wd_base) |
303 | return -ENODEV; | 266 | return -ENODEV; |
304 | 267 | ||
305 | ret = misc_register(&mpc8xxx_wdt_miscdev); | 268 | watchdog_set_nowayout(&mpc8xxx_wdt_dev, nowayout); |
269 | |||
270 | ret = watchdog_register_device(&mpc8xxx_wdt_dev); | ||
306 | if (ret) { | 271 | if (ret) { |
307 | pr_err("cannot register miscdev on minor=%d (err=%d)\n", | 272 | pr_err("cannot register watchdog device (err=%d)\n", ret); |
308 | WATCHDOG_MINOR, ret); | ||
309 | return ret; | 273 | return ret; |
310 | } | 274 | } |
311 | return 0; | 275 | return 0; |
diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c index 231e5b9d5c8e..0b9ec61e1313 100644 --- a/drivers/watchdog/nv_tco.c +++ b/drivers/watchdog/nv_tco.c | |||
@@ -289,7 +289,7 @@ static struct miscdevice nv_tco_miscdev = { | |||
289 | * register a pci_driver, because someone else might one day | 289 | * register a pci_driver, because someone else might one day |
290 | * want to register another driver on the same PCI id. | 290 | * want to register another driver on the same PCI id. |
291 | */ | 291 | */ |
292 | static DEFINE_PCI_DEVICE_TABLE(tco_pci_tbl) = { | 292 | static const struct pci_device_id tco_pci_tbl[] = { |
293 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS, | 293 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS, |
294 | PCI_ANY_ID, PCI_ANY_ID, }, | 294 | PCI_ANY_ID, PCI_ANY_ID, }, |
295 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, | 295 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, |
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c index b4864f254b48..c0d07eef2640 100644 --- a/drivers/watchdog/pcwd_pci.c +++ b/drivers/watchdog/pcwd_pci.c | |||
@@ -801,7 +801,7 @@ static void pcipcwd_card_exit(struct pci_dev *pdev) | |||
801 | cards_found--; | 801 | cards_found--; |
802 | } | 802 | } |
803 | 803 | ||
804 | static DEFINE_PCI_DEVICE_TABLE(pcipcwd_pci_tbl) = { | 804 | static const struct pci_device_id pcipcwd_pci_tbl[] = { |
805 | { PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD, | 805 | { PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD, |
806 | PCI_ANY_ID, PCI_ANY_ID, }, | 806 | PCI_ANY_ID, PCI_ANY_ID, }, |
807 | { 0 }, /* End of list */ | 807 | { 0 }, /* End of list */ |
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 7d8fd041ee25..aec946df6ed9 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
41 | #include <linux/err.h> | 41 | #include <linux/err.h> |
42 | #include <linux/of.h> | 42 | #include <linux/of.h> |
43 | #include <linux/mfd/syscon.h> | ||
44 | #include <linux/regmap.h> | ||
43 | 45 | ||
44 | #define S3C2410_WTCON 0x00 | 46 | #define S3C2410_WTCON 0x00 |
45 | #define S3C2410_WTDAT 0x04 | 47 | #define S3C2410_WTDAT 0x04 |
@@ -60,6 +62,16 @@ | |||
60 | #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) | 62 | #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) |
61 | #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) | 63 | #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) |
62 | 64 | ||
65 | #define EXYNOS5_RST_STAT_REG_OFFSET 0x0404 | ||
66 | #define EXYNOS5_WDT_DISABLE_REG_OFFSET 0x0408 | ||
67 | #define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c | ||
68 | #define QUIRK_HAS_PMU_CONFIG (1 << 0) | ||
69 | #define QUIRK_HAS_RST_STAT (1 << 1) | ||
70 | |||
71 | /* These quirks require that we have a PMU register map */ | ||
72 | #define QUIRKS_HAVE_PMUREG (QUIRK_HAS_PMU_CONFIG | \ | ||
73 | QUIRK_HAS_RST_STAT) | ||
74 | |||
63 | static bool nowayout = WATCHDOG_NOWAYOUT; | 75 | static bool nowayout = WATCHDOG_NOWAYOUT; |
64 | static int tmr_margin; | 76 | static int tmr_margin; |
65 | static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; | 77 | static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; |
@@ -83,6 +95,30 @@ MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " | |||
83 | "0 to reboot (default 0)"); | 95 | "0 to reboot (default 0)"); |
84 | MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); | 96 | MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); |
85 | 97 | ||
98 | /** | ||
99 | * struct s3c2410_wdt_variant - Per-variant config data | ||
100 | * | ||
101 | * @disable_reg: Offset in pmureg for the register that disables the watchdog | ||
102 | * timer reset functionality. | ||
103 | * @mask_reset_reg: Offset in pmureg for the register that masks the watchdog | ||
104 | * timer reset functionality. | ||
105 | * @mask_bit: Bit number for the watchdog timer in the disable register and the | ||
106 | * mask reset register. | ||
107 | * @rst_stat_reg: Offset in pmureg for the register that has the reset status. | ||
108 | * @rst_stat_bit: Bit number in the rst_stat register indicating a watchdog | ||
109 | * reset. | ||
110 | * @quirks: A bitfield of quirks. | ||
111 | */ | ||
112 | |||
113 | struct s3c2410_wdt_variant { | ||
114 | int disable_reg; | ||
115 | int mask_reset_reg; | ||
116 | int mask_bit; | ||
117 | int rst_stat_reg; | ||
118 | int rst_stat_bit; | ||
119 | u32 quirks; | ||
120 | }; | ||
121 | |||
86 | struct s3c2410_wdt { | 122 | struct s3c2410_wdt { |
87 | struct device *dev; | 123 | struct device *dev; |
88 | struct clk *clock; | 124 | struct clk *clock; |
@@ -93,8 +129,54 @@ struct s3c2410_wdt { | |||
93 | unsigned long wtdat_save; | 129 | unsigned long wtdat_save; |
94 | struct watchdog_device wdt_device; | 130 | struct watchdog_device wdt_device; |
95 | struct notifier_block freq_transition; | 131 | struct notifier_block freq_transition; |
132 | struct s3c2410_wdt_variant *drv_data; | ||
133 | struct regmap *pmureg; | ||
96 | }; | 134 | }; |
97 | 135 | ||
136 | static const struct s3c2410_wdt_variant drv_data_s3c2410 = { | ||
137 | .quirks = 0 | ||
138 | }; | ||
139 | |||
140 | #ifdef CONFIG_OF | ||
141 | static const struct s3c2410_wdt_variant drv_data_exynos5250 = { | ||
142 | .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, | ||
143 | .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, | ||
144 | .mask_bit = 20, | ||
145 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, | ||
146 | .rst_stat_bit = 20, | ||
147 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, | ||
148 | }; | ||
149 | |||
150 | static const struct s3c2410_wdt_variant drv_data_exynos5420 = { | ||
151 | .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, | ||
152 | .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, | ||
153 | .mask_bit = 0, | ||
154 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, | ||
155 | .rst_stat_bit = 9, | ||
156 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, | ||
157 | }; | ||
158 | |||
159 | static const struct of_device_id s3c2410_wdt_match[] = { | ||
160 | { .compatible = "samsung,s3c2410-wdt", | ||
161 | .data = &drv_data_s3c2410 }, | ||
162 | { .compatible = "samsung,exynos5250-wdt", | ||
163 | .data = &drv_data_exynos5250 }, | ||
164 | { .compatible = "samsung,exynos5420-wdt", | ||
165 | .data = &drv_data_exynos5420 }, | ||
166 | {}, | ||
167 | }; | ||
168 | MODULE_DEVICE_TABLE(of, s3c2410_wdt_match); | ||
169 | #endif | ||
170 | |||
171 | static const struct platform_device_id s3c2410_wdt_ids[] = { | ||
172 | { | ||
173 | .name = "s3c2410-wdt", | ||
174 | .driver_data = (unsigned long)&drv_data_s3c2410, | ||
175 | }, | ||
176 | {} | ||
177 | }; | ||
178 | MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids); | ||
179 | |||
98 | /* watchdog control routines */ | 180 | /* watchdog control routines */ |
99 | 181 | ||
100 | #define DBG(fmt, ...) \ | 182 | #define DBG(fmt, ...) \ |
@@ -110,6 +192,35 @@ static inline struct s3c2410_wdt *freq_to_wdt(struct notifier_block *nb) | |||
110 | return container_of(nb, struct s3c2410_wdt, freq_transition); | 192 | return container_of(nb, struct s3c2410_wdt, freq_transition); |
111 | } | 193 | } |
112 | 194 | ||
195 | static int s3c2410wdt_mask_and_disable_reset(struct s3c2410_wdt *wdt, bool mask) | ||
196 | { | ||
197 | int ret; | ||
198 | u32 mask_val = 1 << wdt->drv_data->mask_bit; | ||
199 | u32 val = 0; | ||
200 | |||
201 | /* No need to do anything if no PMU CONFIG needed */ | ||
202 | if (!(wdt->drv_data->quirks & QUIRK_HAS_PMU_CONFIG)) | ||
203 | return 0; | ||
204 | |||
205 | if (mask) | ||
206 | val = mask_val; | ||
207 | |||
208 | ret = regmap_update_bits(wdt->pmureg, | ||
209 | wdt->drv_data->disable_reg, | ||
210 | mask_val, val); | ||
211 | if (ret < 0) | ||
212 | goto error; | ||
213 | |||
214 | ret = regmap_update_bits(wdt->pmureg, | ||
215 | wdt->drv_data->mask_reset_reg, | ||
216 | mask_val, val); | ||
217 | error: | ||
218 | if (ret < 0) | ||
219 | dev_err(wdt->dev, "failed to update reg(%d)\n", ret); | ||
220 | |||
221 | return ret; | ||
222 | } | ||
223 | |||
113 | static int s3c2410wdt_keepalive(struct watchdog_device *wdd) | 224 | static int s3c2410wdt_keepalive(struct watchdog_device *wdd) |
114 | { | 225 | { |
115 | struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); | 226 | struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); |
@@ -188,7 +299,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou | |||
188 | if (timeout < 1) | 299 | if (timeout < 1) |
189 | return -EINVAL; | 300 | return -EINVAL; |
190 | 301 | ||
191 | freq /= 128; | 302 | freq = DIV_ROUND_UP(freq, 128); |
192 | count = timeout * freq; | 303 | count = timeout * freq; |
193 | 304 | ||
194 | DBG("%s: count=%d, timeout=%d, freq=%lu\n", | 305 | DBG("%s: count=%d, timeout=%d, freq=%lu\n", |
@@ -200,21 +311,18 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou | |||
200 | */ | 311 | */ |
201 | 312 | ||
202 | if (count >= 0x10000) { | 313 | if (count >= 0x10000) { |
203 | for (divisor = 1; divisor <= 0x100; divisor++) { | 314 | divisor = DIV_ROUND_UP(count, 0xffff); |
204 | if ((count / divisor) < 0x10000) | ||
205 | break; | ||
206 | } | ||
207 | 315 | ||
208 | if ((count / divisor) >= 0x10000) { | 316 | if (divisor > 0x100) { |
209 | dev_err(wdt->dev, "timeout %d too big\n", timeout); | 317 | dev_err(wdt->dev, "timeout %d too big\n", timeout); |
210 | return -EINVAL; | 318 | return -EINVAL; |
211 | } | 319 | } |
212 | } | 320 | } |
213 | 321 | ||
214 | DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", | 322 | DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", |
215 | __func__, timeout, divisor, count, count/divisor); | 323 | __func__, timeout, divisor, count, DIV_ROUND_UP(count, divisor)); |
216 | 324 | ||
217 | count /= divisor; | 325 | count = DIV_ROUND_UP(count, divisor); |
218 | wdt->count = count; | 326 | wdt->count = count; |
219 | 327 | ||
220 | /* update the pre-scaler */ | 328 | /* update the pre-scaler */ |
@@ -264,7 +372,7 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) | |||
264 | return IRQ_HANDLED; | 372 | return IRQ_HANDLED; |
265 | } | 373 | } |
266 | 374 | ||
267 | #ifdef CONFIG_CPU_FREQ | 375 | #ifdef CONFIG_ARM_S3C24XX_CPUFREQ |
268 | 376 | ||
269 | static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, | 377 | static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, |
270 | unsigned long val, void *data) | 378 | unsigned long val, void *data) |
@@ -331,6 +439,37 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) | |||
331 | } | 439 | } |
332 | #endif | 440 | #endif |
333 | 441 | ||
442 | static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) | ||
443 | { | ||
444 | unsigned int rst_stat; | ||
445 | int ret; | ||
446 | |||
447 | if (!(wdt->drv_data->quirks & QUIRK_HAS_RST_STAT)) | ||
448 | return 0; | ||
449 | |||
450 | ret = regmap_read(wdt->pmureg, wdt->drv_data->rst_stat_reg, &rst_stat); | ||
451 | if (ret) | ||
452 | dev_warn(wdt->dev, "Couldn't get RST_STAT register\n"); | ||
453 | else if (rst_stat & BIT(wdt->drv_data->rst_stat_bit)) | ||
454 | return WDIOF_CARDRESET; | ||
455 | |||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | /* s3c2410_get_wdt_driver_data */ | ||
460 | static inline struct s3c2410_wdt_variant * | ||
461 | get_wdt_drv_data(struct platform_device *pdev) | ||
462 | { | ||
463 | if (pdev->dev.of_node) { | ||
464 | const struct of_device_id *match; | ||
465 | match = of_match_node(s3c2410_wdt_match, pdev->dev.of_node); | ||
466 | return (struct s3c2410_wdt_variant *)match->data; | ||
467 | } else { | ||
468 | return (struct s3c2410_wdt_variant *) | ||
469 | platform_get_device_id(pdev)->driver_data; | ||
470 | } | ||
471 | } | ||
472 | |||
334 | static int s3c2410wdt_probe(struct platform_device *pdev) | 473 | static int s3c2410wdt_probe(struct platform_device *pdev) |
335 | { | 474 | { |
336 | struct device *dev; | 475 | struct device *dev; |
@@ -353,6 +492,16 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
353 | spin_lock_init(&wdt->lock); | 492 | spin_lock_init(&wdt->lock); |
354 | wdt->wdt_device = s3c2410_wdd; | 493 | wdt->wdt_device = s3c2410_wdd; |
355 | 494 | ||
495 | wdt->drv_data = get_wdt_drv_data(pdev); | ||
496 | if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) { | ||
497 | wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
498 | "samsung,syscon-phandle"); | ||
499 | if (IS_ERR(wdt->pmureg)) { | ||
500 | dev_err(dev, "syscon regmap lookup failed.\n"); | ||
501 | return PTR_ERR(wdt->pmureg); | ||
502 | } | ||
503 | } | ||
504 | |||
356 | wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 505 | wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
357 | if (wdt_irq == NULL) { | 506 | if (wdt_irq == NULL) { |
358 | dev_err(dev, "no irq resource specified\n"); | 507 | dev_err(dev, "no irq resource specified\n"); |
@@ -415,12 +564,18 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
415 | 564 | ||
416 | watchdog_set_nowayout(&wdt->wdt_device, nowayout); | 565 | watchdog_set_nowayout(&wdt->wdt_device, nowayout); |
417 | 566 | ||
567 | wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt); | ||
568 | |||
418 | ret = watchdog_register_device(&wdt->wdt_device); | 569 | ret = watchdog_register_device(&wdt->wdt_device); |
419 | if (ret) { | 570 | if (ret) { |
420 | dev_err(dev, "cannot register watchdog (%d)\n", ret); | 571 | dev_err(dev, "cannot register watchdog (%d)\n", ret); |
421 | goto err_cpufreq; | 572 | goto err_cpufreq; |
422 | } | 573 | } |
423 | 574 | ||
575 | ret = s3c2410wdt_mask_and_disable_reset(wdt, false); | ||
576 | if (ret < 0) | ||
577 | goto err_unregister; | ||
578 | |||
424 | if (tmr_atboot && started == 0) { | 579 | if (tmr_atboot && started == 0) { |
425 | dev_info(dev, "starting watchdog timer\n"); | 580 | dev_info(dev, "starting watchdog timer\n"); |
426 | s3c2410wdt_start(&wdt->wdt_device); | 581 | s3c2410wdt_start(&wdt->wdt_device); |
@@ -445,6 +600,9 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
445 | 600 | ||
446 | return 0; | 601 | return 0; |
447 | 602 | ||
603 | err_unregister: | ||
604 | watchdog_unregister_device(&wdt->wdt_device); | ||
605 | |||
448 | err_cpufreq: | 606 | err_cpufreq: |
449 | s3c2410wdt_cpufreq_deregister(wdt); | 607 | s3c2410wdt_cpufreq_deregister(wdt); |
450 | 608 | ||
@@ -458,8 +616,13 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
458 | 616 | ||
459 | static int s3c2410wdt_remove(struct platform_device *dev) | 617 | static int s3c2410wdt_remove(struct platform_device *dev) |
460 | { | 618 | { |
619 | int ret; | ||
461 | struct s3c2410_wdt *wdt = platform_get_drvdata(dev); | 620 | struct s3c2410_wdt *wdt = platform_get_drvdata(dev); |
462 | 621 | ||
622 | ret = s3c2410wdt_mask_and_disable_reset(wdt, true); | ||
623 | if (ret < 0) | ||
624 | return ret; | ||
625 | |||
463 | watchdog_unregister_device(&wdt->wdt_device); | 626 | watchdog_unregister_device(&wdt->wdt_device); |
464 | 627 | ||
465 | s3c2410wdt_cpufreq_deregister(wdt); | 628 | s3c2410wdt_cpufreq_deregister(wdt); |
@@ -474,6 +637,8 @@ static void s3c2410wdt_shutdown(struct platform_device *dev) | |||
474 | { | 637 | { |
475 | struct s3c2410_wdt *wdt = platform_get_drvdata(dev); | 638 | struct s3c2410_wdt *wdt = platform_get_drvdata(dev); |
476 | 639 | ||
640 | s3c2410wdt_mask_and_disable_reset(wdt, true); | ||
641 | |||
477 | s3c2410wdt_stop(&wdt->wdt_device); | 642 | s3c2410wdt_stop(&wdt->wdt_device); |
478 | } | 643 | } |
479 | 644 | ||
@@ -481,12 +646,17 @@ static void s3c2410wdt_shutdown(struct platform_device *dev) | |||
481 | 646 | ||
482 | static int s3c2410wdt_suspend(struct device *dev) | 647 | static int s3c2410wdt_suspend(struct device *dev) |
483 | { | 648 | { |
649 | int ret; | ||
484 | struct s3c2410_wdt *wdt = dev_get_drvdata(dev); | 650 | struct s3c2410_wdt *wdt = dev_get_drvdata(dev); |
485 | 651 | ||
486 | /* Save watchdog state, and turn it off. */ | 652 | /* Save watchdog state, and turn it off. */ |
487 | wdt->wtcon_save = readl(wdt->reg_base + S3C2410_WTCON); | 653 | wdt->wtcon_save = readl(wdt->reg_base + S3C2410_WTCON); |
488 | wdt->wtdat_save = readl(wdt->reg_base + S3C2410_WTDAT); | 654 | wdt->wtdat_save = readl(wdt->reg_base + S3C2410_WTDAT); |
489 | 655 | ||
656 | ret = s3c2410wdt_mask_and_disable_reset(wdt, true); | ||
657 | if (ret < 0) | ||
658 | return ret; | ||
659 | |||
490 | /* Note that WTCNT doesn't need to be saved. */ | 660 | /* Note that WTCNT doesn't need to be saved. */ |
491 | s3c2410wdt_stop(&wdt->wdt_device); | 661 | s3c2410wdt_stop(&wdt->wdt_device); |
492 | 662 | ||
@@ -495,6 +665,7 @@ static int s3c2410wdt_suspend(struct device *dev) | |||
495 | 665 | ||
496 | static int s3c2410wdt_resume(struct device *dev) | 666 | static int s3c2410wdt_resume(struct device *dev) |
497 | { | 667 | { |
668 | int ret; | ||
498 | struct s3c2410_wdt *wdt = dev_get_drvdata(dev); | 669 | struct s3c2410_wdt *wdt = dev_get_drvdata(dev); |
499 | 670 | ||
500 | /* Restore watchdog state. */ | 671 | /* Restore watchdog state. */ |
@@ -502,6 +673,10 @@ static int s3c2410wdt_resume(struct device *dev) | |||
502 | writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTCNT);/* Reset count */ | 673 | writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTCNT);/* Reset count */ |
503 | writel(wdt->wtcon_save, wdt->reg_base + S3C2410_WTCON); | 674 | writel(wdt->wtcon_save, wdt->reg_base + S3C2410_WTCON); |
504 | 675 | ||
676 | ret = s3c2410wdt_mask_and_disable_reset(wdt, false); | ||
677 | if (ret < 0) | ||
678 | return ret; | ||
679 | |||
505 | dev_info(dev, "watchdog %sabled\n", | 680 | dev_info(dev, "watchdog %sabled\n", |
506 | (wdt->wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); | 681 | (wdt->wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); |
507 | 682 | ||
@@ -512,18 +687,11 @@ static int s3c2410wdt_resume(struct device *dev) | |||
512 | static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend, | 687 | static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend, |
513 | s3c2410wdt_resume); | 688 | s3c2410wdt_resume); |
514 | 689 | ||
515 | #ifdef CONFIG_OF | ||
516 | static const struct of_device_id s3c2410_wdt_match[] = { | ||
517 | { .compatible = "samsung,s3c2410-wdt" }, | ||
518 | {}, | ||
519 | }; | ||
520 | MODULE_DEVICE_TABLE(of, s3c2410_wdt_match); | ||
521 | #endif | ||
522 | |||
523 | static struct platform_driver s3c2410wdt_driver = { | 690 | static struct platform_driver s3c2410wdt_driver = { |
524 | .probe = s3c2410wdt_probe, | 691 | .probe = s3c2410wdt_probe, |
525 | .remove = s3c2410wdt_remove, | 692 | .remove = s3c2410wdt_remove, |
526 | .shutdown = s3c2410wdt_shutdown, | 693 | .shutdown = s3c2410wdt_shutdown, |
694 | .id_table = s3c2410_wdt_ids, | ||
527 | .driver = { | 695 | .driver = { |
528 | .owner = THIS_MODULE, | 696 | .owner = THIS_MODULE, |
529 | .name = "s3c2410-wdt", | 697 | .name = "s3c2410-wdt", |
@@ -538,4 +706,3 @@ MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, " | |||
538 | "Dimitry Andric <dimitry.andric@tomtom.com>"); | 706 | "Dimitry Andric <dimitry.andric@tomtom.com>"); |
539 | MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver"); | 707 | MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver"); |
540 | MODULE_LICENSE("GPL"); | 708 | MODULE_LICENSE("GPL"); |
541 | MODULE_ALIAS("platform:s3c2410-wdt"); | ||
diff --git a/drivers/watchdog/sirfsoc_wdt.c b/drivers/watchdog/sirfsoc_wdt.c index ced3edc95957..702d07870808 100644 --- a/drivers/watchdog/sirfsoc_wdt.c +++ b/drivers/watchdog/sirfsoc_wdt.c | |||
@@ -212,7 +212,7 @@ static struct platform_driver sirfsoc_wdt_driver = { | |||
212 | .name = "sirfsoc-wdt", | 212 | .name = "sirfsoc-wdt", |
213 | .owner = THIS_MODULE, | 213 | .owner = THIS_MODULE, |
214 | .pm = &sirfsoc_wdt_pm_ops, | 214 | .pm = &sirfsoc_wdt_pm_ops, |
215 | .of_match_table = of_match_ptr(sirfsoc_wdt_of_match), | 215 | .of_match_table = sirfsoc_wdt_of_match, |
216 | }, | 216 | }, |
217 | .probe = sirfsoc_wdt_probe, | 217 | .probe = sirfsoc_wdt_probe, |
218 | .remove = sirfsoc_wdt_remove, | 218 | .remove = sirfsoc_wdt_remove, |
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c index ce63a1bbf395..5cca9cddb87d 100644 --- a/drivers/watchdog/sp5100_tco.c +++ b/drivers/watchdog/sp5100_tco.c | |||
@@ -303,7 +303,7 @@ static struct miscdevice sp5100_tco_miscdev = { | |||
303 | * register a pci_driver, because someone else might | 303 | * register a pci_driver, because someone else might |
304 | * want to register another driver on the same PCI id. | 304 | * want to register another driver on the same PCI id. |
305 | */ | 305 | */ |
306 | static DEFINE_PCI_DEVICE_TABLE(sp5100_tco_pci_tbl) = { | 306 | static const struct pci_device_id sp5100_tco_pci_tbl[] = { |
307 | { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID, | 307 | { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID, |
308 | PCI_ANY_ID, }, | 308 | PCI_ANY_ID, }, |
309 | { 0, }, /* End of list */ | 309 | { 0, }, /* End of list */ |
diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c index 1a68f760cf86..d2cd9f0bcb9a 100644 --- a/drivers/watchdog/via_wdt.c +++ b/drivers/watchdog/via_wdt.c | |||
@@ -239,7 +239,7 @@ static void wdt_remove(struct pci_dev *pdev) | |||
239 | pci_disable_device(pdev); | 239 | pci_disable_device(pdev); |
240 | } | 240 | } |
241 | 241 | ||
242 | static DEFINE_PCI_DEVICE_TABLE(wdt_pci_table) = { | 242 | static const struct pci_device_id wdt_pci_table[] = { |
243 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700) }, | 243 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700) }, |
244 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800) }, | 244 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800) }, |
245 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, | 245 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) }, |
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index e24b21082874..b1da0c18fd1a 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c | |||
@@ -44,10 +44,13 @@ | |||
44 | #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" | 44 | #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" |
45 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ | 45 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ |
46 | 46 | ||
47 | /* You must set this - there is no sane way to probe for this board. */ | 47 | static int wdt_io; |
48 | static int wdt_io = 0x2E; | 48 | static int cr_wdt_timeout; /* WDT timeout register */ |
49 | module_param(wdt_io, int, 0); | 49 | static int cr_wdt_control; /* WDT control register */ |
50 | MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); | 50 | |
51 | enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, | ||
52 | w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, | ||
53 | w83667hg_b, nct6775, nct6776, nct6779 }; | ||
51 | 54 | ||
52 | static int timeout; /* in seconds */ | 55 | static int timeout; /* in seconds */ |
53 | module_param(timeout, int, 0); | 56 | module_param(timeout, int, 0); |
@@ -72,6 +75,29 @@ MODULE_PARM_DESC(nowayout, | |||
72 | 75 | ||
73 | #define W83627HF_LD_WDT 0x08 | 76 | #define W83627HF_LD_WDT 0x08 |
74 | 77 | ||
78 | #define W83627HF_ID 0x52 | ||
79 | #define W83627S_ID 0x59 | ||
80 | #define W83697HF_ID 0x60 | ||
81 | #define W83697UG_ID 0x68 | ||
82 | #define W83637HF_ID 0x70 | ||
83 | #define W83627THF_ID 0x82 | ||
84 | #define W83687THF_ID 0x85 | ||
85 | #define W83627EHF_ID 0x88 | ||
86 | #define W83627DHG_ID 0xa0 | ||
87 | #define W83627UHG_ID 0xa2 | ||
88 | #define W83667HG_ID 0xa5 | ||
89 | #define W83627DHG_P_ID 0xb0 | ||
90 | #define W83667HG_B_ID 0xb3 | ||
91 | #define NCT6775_ID 0xb4 | ||
92 | #define NCT6776_ID 0xc3 | ||
93 | #define NCT6779_ID 0xc5 | ||
94 | |||
95 | #define W83627HF_WDT_TIMEOUT 0xf6 | ||
96 | #define W83697HF_WDT_TIMEOUT 0xf4 | ||
97 | |||
98 | #define W83627HF_WDT_CONTROL 0xf5 | ||
99 | #define W83697HF_WDT_CONTROL 0xf3 | ||
100 | |||
75 | static void superio_outb(int reg, int val) | 101 | static void superio_outb(int reg, int val) |
76 | { | 102 | { |
77 | outb(reg, WDT_EFER); | 103 | outb(reg, WDT_EFER); |
@@ -106,10 +132,7 @@ static void superio_exit(void) | |||
106 | release_region(wdt_io, 2); | 132 | release_region(wdt_io, 2); |
107 | } | 133 | } |
108 | 134 | ||
109 | /* tyan motherboards seem to set F5 to 0x4C ? | 135 | static int w83627hf_init(struct watchdog_device *wdog, enum chips chip) |
110 | * So explicitly init to appropriate value. */ | ||
111 | |||
112 | static int w83627hf_init(struct watchdog_device *wdog) | ||
113 | { | 136 | { |
114 | int ret; | 137 | int ret; |
115 | unsigned char t; | 138 | unsigned char t; |
@@ -119,35 +142,83 @@ static int w83627hf_init(struct watchdog_device *wdog) | |||
119 | return ret; | 142 | return ret; |
120 | 143 | ||
121 | superio_select(W83627HF_LD_WDT); | 144 | superio_select(W83627HF_LD_WDT); |
122 | t = superio_inb(0x20); /* check chip version */ | ||
123 | if (t == 0x82) { /* W83627THF */ | ||
124 | t = (superio_inb(0x2b) & 0xf7); | ||
125 | superio_outb(0x2b, t | 0x04); /* set GPIO3 to WDT0 */ | ||
126 | } else if (t == 0x88 || t == 0xa0) { /* W83627EHF / W83627DHG */ | ||
127 | t = superio_inb(0x2d); | ||
128 | superio_outb(0x2d, t & ~0x01); /* set GPIO5 to WDT0 */ | ||
129 | } | ||
130 | 145 | ||
131 | /* set CR30 bit 0 to activate GPIO2 */ | 146 | /* set CR30 bit 0 to activate GPIO2 */ |
132 | t = superio_inb(0x30); | 147 | t = superio_inb(0x30); |
133 | if (!(t & 0x01)) | 148 | if (!(t & 0x01)) |
134 | superio_outb(0x30, t | 0x01); | 149 | superio_outb(0x30, t | 0x01); |
135 | 150 | ||
136 | t = superio_inb(0xF6); | 151 | switch (chip) { |
152 | case w83627hf: | ||
153 | case w83627s: | ||
154 | t = superio_inb(0x2B) & ~0x10; | ||
155 | superio_outb(0x2B, t); /* set GPIO24 to WDT0 */ | ||
156 | break; | ||
157 | case w83697hf: | ||
158 | /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ | ||
159 | t = superio_inb(0x29) & ~0x60; | ||
160 | t |= 0x20; | ||
161 | superio_outb(0x29, t); | ||
162 | break; | ||
163 | case w83697ug: | ||
164 | /* Set pin 118 to WDTO# mode */ | ||
165 | t = superio_inb(0x2b) & ~0x04; | ||
166 | superio_outb(0x2b, t); | ||
167 | break; | ||
168 | case w83627thf: | ||
169 | t = (superio_inb(0x2B) & ~0x08) | 0x04; | ||
170 | superio_outb(0x2B, t); /* set GPIO3 to WDT0 */ | ||
171 | break; | ||
172 | case w83627dhg: | ||
173 | case w83627dhg_p: | ||
174 | t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */ | ||
175 | superio_outb(0x2D, t); /* set GPIO5 to WDT0 */ | ||
176 | t = superio_inb(cr_wdt_control); | ||
177 | t |= 0x02; /* enable the WDTO# output low pulse | ||
178 | * to the KBRST# pin */ | ||
179 | superio_outb(cr_wdt_control, t); | ||
180 | break; | ||
181 | case w83637hf: | ||
182 | break; | ||
183 | case w83687thf: | ||
184 | t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */ | ||
185 | superio_outb(0x2C, t); | ||
186 | break; | ||
187 | case w83627ehf: | ||
188 | case w83627uhg: | ||
189 | case w83667hg: | ||
190 | case w83667hg_b: | ||
191 | case nct6775: | ||
192 | case nct6776: | ||
193 | case nct6779: | ||
194 | /* | ||
195 | * These chips have a fixed WDTO# output pin (W83627UHG), | ||
196 | * or support more than one WDTO# output pin. | ||
197 | * Don't touch its configuration, and hope the BIOS | ||
198 | * does the right thing. | ||
199 | */ | ||
200 | t = superio_inb(cr_wdt_control); | ||
201 | t |= 0x02; /* enable the WDTO# output low pulse | ||
202 | * to the KBRST# pin */ | ||
203 | superio_outb(cr_wdt_control, t); | ||
204 | break; | ||
205 | default: | ||
206 | break; | ||
207 | } | ||
208 | |||
209 | t = superio_inb(cr_wdt_timeout); | ||
137 | if (t != 0) { | 210 | if (t != 0) { |
138 | pr_info("Watchdog already running. Resetting timeout to %d sec\n", | 211 | pr_info("Watchdog already running. Resetting timeout to %d sec\n", |
139 | wdog->timeout); | 212 | wdog->timeout); |
140 | superio_outb(0xF6, wdog->timeout); | 213 | superio_outb(cr_wdt_timeout, wdog->timeout); |
141 | } | 214 | } |
142 | 215 | ||
143 | /* set second mode & disable keyboard turning off watchdog */ | 216 | /* set second mode & disable keyboard turning off watchdog */ |
144 | t = superio_inb(0xF5) & ~0x0C; | 217 | t = superio_inb(cr_wdt_control) & ~0x0C; |
145 | /* enable the WDTO# output low pulse to the KBRST# pin */ | 218 | superio_outb(cr_wdt_control, t); |
146 | t |= 0x02; | ||
147 | superio_outb(0xF5, t); | ||
148 | 219 | ||
149 | /* disable keyboard & mouse turning off watchdog */ | 220 | /* reset trigger, disable keyboard & mouse turning off watchdog */ |
150 | t = superio_inb(0xF7) & ~0xC0; | 221 | t = superio_inb(0xF7) & ~0xD0; |
151 | superio_outb(0xF7, t); | 222 | superio_outb(0xF7, t); |
152 | 223 | ||
153 | superio_exit(); | 224 | superio_exit(); |
@@ -164,7 +235,7 @@ static int wdt_set_time(unsigned int timeout) | |||
164 | return ret; | 235 | return ret; |
165 | 236 | ||
166 | superio_select(W83627HF_LD_WDT); | 237 | superio_select(W83627HF_LD_WDT); |
167 | superio_outb(0xF6, timeout); | 238 | superio_outb(cr_wdt_timeout, timeout); |
168 | superio_exit(); | 239 | superio_exit(); |
169 | 240 | ||
170 | return 0; | 241 | return 0; |
@@ -197,7 +268,7 @@ static unsigned int wdt_get_time(struct watchdog_device *wdog) | |||
197 | return 0; | 268 | return 0; |
198 | 269 | ||
199 | superio_select(W83627HF_LD_WDT); | 270 | superio_select(W83627HF_LD_WDT); |
200 | timeleft = superio_inb(0xF6); | 271 | timeleft = superio_inb(cr_wdt_timeout); |
201 | superio_exit(); | 272 | superio_exit(); |
202 | 273 | ||
203 | return timeleft; | 274 | return timeleft; |
@@ -249,16 +320,123 @@ static struct notifier_block wdt_notifier = { | |||
249 | .notifier_call = wdt_notify_sys, | 320 | .notifier_call = wdt_notify_sys, |
250 | }; | 321 | }; |
251 | 322 | ||
323 | static int wdt_find(int addr) | ||
324 | { | ||
325 | u8 val; | ||
326 | int ret; | ||
327 | |||
328 | cr_wdt_timeout = W83627HF_WDT_TIMEOUT; | ||
329 | cr_wdt_control = W83627HF_WDT_CONTROL; | ||
330 | |||
331 | ret = superio_enter(); | ||
332 | if (ret) | ||
333 | return ret; | ||
334 | superio_select(W83627HF_LD_WDT); | ||
335 | val = superio_inb(0x20); | ||
336 | switch (val) { | ||
337 | case W83627HF_ID: | ||
338 | ret = w83627hf; | ||
339 | break; | ||
340 | case W83627S_ID: | ||
341 | ret = w83627s; | ||
342 | break; | ||
343 | case W83697HF_ID: | ||
344 | ret = w83697hf; | ||
345 | cr_wdt_timeout = W83697HF_WDT_TIMEOUT; | ||
346 | cr_wdt_control = W83697HF_WDT_CONTROL; | ||
347 | break; | ||
348 | case W83697UG_ID: | ||
349 | ret = w83697ug; | ||
350 | cr_wdt_timeout = W83697HF_WDT_TIMEOUT; | ||
351 | cr_wdt_control = W83697HF_WDT_CONTROL; | ||
352 | break; | ||
353 | case W83637HF_ID: | ||
354 | ret = w83637hf; | ||
355 | break; | ||
356 | case W83627THF_ID: | ||
357 | ret = w83627thf; | ||
358 | break; | ||
359 | case W83687THF_ID: | ||
360 | ret = w83687thf; | ||
361 | break; | ||
362 | case W83627EHF_ID: | ||
363 | ret = w83627ehf; | ||
364 | break; | ||
365 | case W83627DHG_ID: | ||
366 | ret = w83627dhg; | ||
367 | break; | ||
368 | case W83627DHG_P_ID: | ||
369 | ret = w83627dhg_p; | ||
370 | break; | ||
371 | case W83627UHG_ID: | ||
372 | ret = w83627uhg; | ||
373 | break; | ||
374 | case W83667HG_ID: | ||
375 | ret = w83667hg; | ||
376 | break; | ||
377 | case W83667HG_B_ID: | ||
378 | ret = w83667hg_b; | ||
379 | break; | ||
380 | case NCT6775_ID: | ||
381 | ret = nct6775; | ||
382 | break; | ||
383 | case NCT6776_ID: | ||
384 | ret = nct6776; | ||
385 | break; | ||
386 | case NCT6779_ID: | ||
387 | ret = nct6779; | ||
388 | break; | ||
389 | case 0xff: | ||
390 | ret = -ENODEV; | ||
391 | break; | ||
392 | default: | ||
393 | ret = -ENODEV; | ||
394 | pr_err("Unsupported chip ID: 0x%02x\n", val); | ||
395 | break; | ||
396 | } | ||
397 | superio_exit(); | ||
398 | return ret; | ||
399 | } | ||
400 | |||
252 | static int __init wdt_init(void) | 401 | static int __init wdt_init(void) |
253 | { | 402 | { |
254 | int ret; | 403 | int ret; |
404 | int chip; | ||
405 | const char * const chip_name[] = { | ||
406 | "W83627HF", | ||
407 | "W83627S", | ||
408 | "W83697HF", | ||
409 | "W83697UG", | ||
410 | "W83637HF", | ||
411 | "W83627THF", | ||
412 | "W83687THF", | ||
413 | "W83627EHF", | ||
414 | "W83627DHG", | ||
415 | "W83627UHG", | ||
416 | "W83667HG", | ||
417 | "W83667DHG-P", | ||
418 | "W83667HG-B", | ||
419 | "NCT6775", | ||
420 | "NCT6776", | ||
421 | "NCT6779", | ||
422 | }; | ||
423 | |||
424 | wdt_io = 0x2e; | ||
425 | chip = wdt_find(0x2e); | ||
426 | if (chip < 0) { | ||
427 | wdt_io = 0x4e; | ||
428 | chip = wdt_find(0x4e); | ||
429 | if (chip < 0) | ||
430 | return chip; | ||
431 | } | ||
255 | 432 | ||
256 | pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n"); | 433 | pr_info("WDT driver for %s Super I/O chip initialising\n", |
434 | chip_name[chip]); | ||
257 | 435 | ||
258 | watchdog_init_timeout(&wdt_dev, timeout, NULL); | 436 | watchdog_init_timeout(&wdt_dev, timeout, NULL); |
259 | watchdog_set_nowayout(&wdt_dev, nowayout); | 437 | watchdog_set_nowayout(&wdt_dev, nowayout); |
260 | 438 | ||
261 | ret = w83627hf_init(&wdt_dev); | 439 | ret = w83627hf_init(&wdt_dev, chip); |
262 | if (ret) { | 440 | if (ret) { |
263 | pr_err("failed to initialize watchdog (err=%d)\n", ret); | 441 | pr_err("failed to initialize watchdog (err=%d)\n", ret); |
264 | return ret; | 442 | return ret; |
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index 461336c4519f..cec9b559647d 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c | |||
@@ -78,7 +78,7 @@ int watchdog_init_timeout(struct watchdog_device *wdd, | |||
78 | watchdog_check_min_max_timeout(wdd); | 78 | watchdog_check_min_max_timeout(wdd); |
79 | 79 | ||
80 | /* try to get the timeout module parameter first */ | 80 | /* try to get the timeout module parameter first */ |
81 | if (!watchdog_timeout_invalid(wdd, timeout_parm)) { | 81 | if (!watchdog_timeout_invalid(wdd, timeout_parm) && timeout_parm) { |
82 | wdd->timeout = timeout_parm; | 82 | wdd->timeout = timeout_parm; |
83 | return ret; | 83 | return ret; |
84 | } | 84 | } |
@@ -89,7 +89,7 @@ int watchdog_init_timeout(struct watchdog_device *wdd, | |||
89 | if (dev == NULL || dev->of_node == NULL) | 89 | if (dev == NULL || dev->of_node == NULL) |
90 | return ret; | 90 | return ret; |
91 | of_property_read_u32(dev->of_node, "timeout-sec", &t); | 91 | of_property_read_u32(dev->of_node, "timeout-sec", &t); |
92 | if (!watchdog_timeout_invalid(wdd, t)) | 92 | if (!watchdog_timeout_invalid(wdd, t) && t) |
93 | wdd->timeout = t; | 93 | wdd->timeout = t; |
94 | else | 94 | else |
95 | ret = -EINVAL; | 95 | ret = -EINVAL; |
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c index ee89ba4dea63..3dc578e71211 100644 --- a/drivers/watchdog/wdt_pci.c +++ b/drivers/watchdog/wdt_pci.c | |||
@@ -720,7 +720,7 @@ static void wdtpci_remove_one(struct pci_dev *pdev) | |||
720 | } | 720 | } |
721 | 721 | ||
722 | 722 | ||
723 | static DEFINE_PCI_DEVICE_TABLE(wdtpci_pci_tbl) = { | 723 | static const struct pci_device_id wdtpci_pci_tbl[] = { |
724 | { | 724 | { |
725 | .vendor = PCI_VENDOR_ID_ACCESSIO, | 725 | .vendor = PCI_VENDOR_ID_ACCESSIO, |
726 | .device = PCI_DEVICE_ID_ACCESSIO_WDG_CSM, | 726 | .device = PCI_DEVICE_ID_ACCESSIO_WDG_CSM, |