aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/watchdog/atmel-at91rm9200-wdt.txt9
-rw-r--r--Documentation/devicetree/bindings/watchdog/atmel-wdt.txt4
-rw-r--r--Documentation/devicetree/bindings/watchdog/marvel.txt5
-rw-r--r--Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt4
-rw-r--r--Documentation/devicetree/bindings/watchdog/qca-ar7130-wdt.txt13
-rw-r--r--Documentation/devicetree/bindings/watchdog/samsung-wdt.txt3
-rw-r--r--Documentation/watchdog/watchdog-kernel-api.txt14
-rw-r--r--arch/mips/ath79/dev-common.c15
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c64
-rw-r--r--drivers/watchdog/Kconfig35
-rw-r--r--drivers/watchdog/Makefile3
-rw-r--r--drivers/watchdog/at91rm9200_wdt.c9
-rw-r--r--drivers/watchdog/at91sam9_wdt.c168
-rw-r--r--drivers/watchdog/ath79_wdt.c66
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c339
-rw-r--r--drivers/watchdog/booke_wdt.c185
-rw-r--r--drivers/watchdog/davinci_wdt.c29
-rw-r--r--drivers/watchdog/gef_wdt.c1
-rw-r--r--drivers/watchdog/omap_wdt.c6
-rw-r--r--drivers/watchdog/orion_wdt.c11
-rw-r--r--drivers/watchdog/pnx4008_wdt.c7
-rw-r--r--drivers/watchdog/retu_wdt.c178
-rw-r--r--drivers/watchdog/s3c2410_wdt.c48
-rw-r--r--drivers/watchdog/sp5100_tco.c27
-rw-r--r--drivers/watchdog/stmp3xxx_rtc_wdt.c111
-rw-r--r--drivers/watchdog/stmp3xxx_wdt.c288
-rw-r--r--drivers/watchdog/watchdog_core.c66
-rw-r--r--drivers/watchdog/watchdog_dev.c3
-rw-r--r--include/linux/bcm47xx_wdt.h9
-rw-r--r--include/linux/stmp3xxx_rtc_wdt.h15
-rw-r--r--include/linux/watchdog.h9
31 files changed, 888 insertions, 856 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/atmel-at91rm9200-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-at91rm9200-wdt.txt
new file mode 100644
index 000000000000..d4d86cf8f9eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/atmel-at91rm9200-wdt.txt
@@ -0,0 +1,9 @@
1Atmel AT91RM9200 System Timer Watchdog
2
3Required properties:
4- compatible: must be "atmel,at91sam9260-wdt".
5
6Example:
7 watchdog@fffffd00 {
8 compatible = "atmel,at91rm9200-wdt";
9 };
diff --git a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
index 2957ebb5aa71..fcdd48f7dcff 100644
--- a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
@@ -7,9 +7,13 @@ Required properties:
7- reg: physical base address of the controller and length of memory mapped 7- reg: physical base address of the controller and length of memory mapped
8 region. 8 region.
9 9
10Optional properties:
11- timeout-sec: contains the watchdog timeout in seconds.
12
10Example: 13Example:
11 14
12 watchdog@fffffd40 { 15 watchdog@fffffd40 {
13 compatible = "atmel,at91sam9260-wdt"; 16 compatible = "atmel,at91sam9260-wdt";
14 reg = <0xfffffd40 0x10>; 17 reg = <0xfffffd40 0x10>;
18 timeout-sec = <10>;
15 }; 19 };
diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt
index 0b2503ab0a05..5dc8d30061ce 100644
--- a/Documentation/devicetree/bindings/watchdog/marvel.txt
+++ b/Documentation/devicetree/bindings/watchdog/marvel.txt
@@ -5,10 +5,15 @@ Required Properties:
5- Compatibility : "marvell,orion-wdt" 5- Compatibility : "marvell,orion-wdt"
6- reg : Address of the timer registers 6- reg : Address of the timer registers
7 7
8Optional properties:
9
10- timeout-sec : Contains the watchdog timeout in seconds
11
8Example: 12Example:
9 13
10 wdt@20300 { 14 wdt@20300 {
11 compatible = "marvell,orion-wdt"; 15 compatible = "marvell,orion-wdt";
12 reg = <0x20300 0x28>; 16 reg = <0x20300 0x28>;
17 timeout-sec = <10>;
13 status = "okay"; 18 status = "okay";
14 }; 19 };
diff --git a/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt b/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt
index 7c7f6887c796..556d06c17c92 100644
--- a/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/pnx4008-wdt.txt
@@ -5,9 +5,13 @@ Required properties:
5- reg: physical base address of the controller and length of memory mapped 5- reg: physical base address of the controller and length of memory mapped
6 region. 6 region.
7 7
8Optional properties:
9- timeout-sec: contains the watchdog timeout in seconds.
10
8Example: 11Example:
9 12
10 watchdog@4003C000 { 13 watchdog@4003C000 {
11 compatible = "nxp,pnx4008-wdt"; 14 compatible = "nxp,pnx4008-wdt";
12 reg = <0x4003C000 0x1000>; 15 reg = <0x4003C000 0x1000>;
16 timeout-sec = <10>;
13 }; 17 };
diff --git a/Documentation/devicetree/bindings/watchdog/qca-ar7130-wdt.txt b/Documentation/devicetree/bindings/watchdog/qca-ar7130-wdt.txt
new file mode 100644
index 000000000000..7a89e5f85415
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/qca-ar7130-wdt.txt
@@ -0,0 +1,13 @@
1* Qualcomm Atheros AR7130 Watchdog Timer (WDT) Controller
2
3Required properties:
4- compatible: must be "qca,ar7130-wdt"
5- reg: physical base address of the controller and length of memory mapped
6 region.
7
8Example:
9
10wdt@18060008 {
11 compatible = "qca,ar9330-wdt", "qca,ar7130-wdt";
12 reg = <0x18060008 0x8>;
13};
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
index ce0d8e78ed8f..2aa486cc1ff6 100644
--- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
@@ -9,3 +9,6 @@ Required properties:
9- reg : base physical address of the controller and length of memory mapped 9- reg : base physical address of the controller and length of memory mapped
10 region. 10 region.
11- interrupts : interrupt number to the cpu. 11- interrupts : interrupt number to the cpu.
12
13Optional properties:
14- timeout-sec : contains the watchdog timeout in seconds.
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt
index 086638f6c82d..a0438f3957ca 100644
--- a/Documentation/watchdog/watchdog-kernel-api.txt
+++ b/Documentation/watchdog/watchdog-kernel-api.txt
@@ -1,6 +1,6 @@
1The Linux WatchDog Timer Driver Core kernel API. 1The Linux WatchDog Timer Driver Core kernel API.
2=============================================== 2===============================================
3Last reviewed: 22-May-2012 3Last reviewed: 12-Feb-2013
4 4
5Wim Van Sebroeck <wim@iguana.be> 5Wim Van Sebroeck <wim@iguana.be>
6 6
@@ -212,3 +212,15 @@ driver specific data to and a pointer to the data itself.
212The watchdog_get_drvdata function allows you to retrieve driver specific data. 212The watchdog_get_drvdata function allows you to retrieve driver specific data.
213The argument of this function is the watchdog device where you want to retrieve 213The argument of this function is the watchdog device where you want to retrieve
214data from. The function returns the pointer to the driver specific data. 214data from. The function returns the pointer to the driver specific data.
215
216To initialize the timeout field, the following function can be used:
217
218extern int watchdog_init_timeout(struct watchdog_device *wdd,
219 unsigned int timeout_parm, struct device *dev);
220
221The watchdog_init_timeout function allows you to initialize the timeout field
222using the module timeout parameter or by retrieving the timeout-sec property from
223the device tree (if the module timeout parameter is invalid). Best practice is
224to set the default timeout value as timeout value in the watchdog_device and
225then use this function to set the user "preferred" timeout value.
226This routine returns zero on success and a negative errno code for failure.
diff --git a/arch/mips/ath79/dev-common.c b/arch/mips/ath79/dev-common.c
index 9516aab27139..a3a2741d0688 100644
--- a/arch/mips/ath79/dev-common.c
+++ b/arch/mips/ath79/dev-common.c
@@ -102,12 +102,15 @@ void __init ath79_register_uart(void)
102 } 102 }
103} 103}
104 104
105static struct platform_device ath79_wdt_device = {
106 .name = "ath79-wdt",
107 .id = -1,
108};
109
110void __init ath79_register_wdt(void) 105void __init ath79_register_wdt(void)
111{ 106{
112 platform_device_register(&ath79_wdt_device); 107 struct resource res;
108
109 memset(&res, 0, sizeof(res));
110
111 res.flags = IORESOURCE_MEM;
112 res.start = AR71XX_RESET_BASE + AR71XX_RESET_REG_WDOG_CTRL;
113 res.end = res.start + 0x8 - 1;
114
115 platform_device_register_simple("ath79-wdt", -1, &res, 1);
113} 116}
diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c
index b2a8ed99b2bf..98f0d3c30738 100644
--- a/drivers/rtc/rtc-stmp3xxx.c
+++ b/drivers/rtc/rtc-stmp3xxx.c
@@ -27,6 +27,8 @@
27#include <linux/slab.h> 27#include <linux/slab.h>
28#include <linux/of_device.h> 28#include <linux/of_device.h>
29#include <linux/of.h> 29#include <linux/of.h>
30#include <linux/stmp_device.h>
31#include <linux/stmp3xxx_rtc_wdt.h>
30 32
31#include <mach/common.h> 33#include <mach/common.h>
32 34
@@ -36,6 +38,7 @@
36#define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 38#define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001
37#define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002 39#define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002
38#define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004 40#define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004
41#define STMP3XXX_RTC_CTRL_WATCHDOGEN 0x00000010
39 42
40#define STMP3XXX_RTC_STAT 0x10 43#define STMP3XXX_RTC_STAT 0x10
41#define STMP3XXX_RTC_STAT_STALE_SHIFT 16 44#define STMP3XXX_RTC_STAT_STALE_SHIFT 16
@@ -45,6 +48,8 @@
45 48
46#define STMP3XXX_RTC_ALARM 0x40 49#define STMP3XXX_RTC_ALARM 0x40
47 50
51#define STMP3XXX_RTC_WATCHDOG 0x50
52
48#define STMP3XXX_RTC_PERSISTENT0 0x60 53#define STMP3XXX_RTC_PERSISTENT0 0x60
49#define STMP3XXX_RTC_PERSISTENT0_SET 0x64 54#define STMP3XXX_RTC_PERSISTENT0_SET 0x64
50#define STMP3XXX_RTC_PERSISTENT0_CLR 0x68 55#define STMP3XXX_RTC_PERSISTENT0_CLR 0x68
@@ -52,12 +57,70 @@
52#define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004 57#define STMP3XXX_RTC_PERSISTENT0_ALARM_EN 0x00000004
53#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080 58#define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE 0x00000080
54 59
60#define STMP3XXX_RTC_PERSISTENT1 0x70
61/* missing bitmask in headers */
62#define STMP3XXX_RTC_PERSISTENT1_FORCE_UPDATER 0x80000000
63
55struct stmp3xxx_rtc_data { 64struct stmp3xxx_rtc_data {
56 struct rtc_device *rtc; 65 struct rtc_device *rtc;
57 void __iomem *io; 66 void __iomem *io;
58 int irq_alarm; 67 int irq_alarm;
59}; 68};
60 69
70#if IS_ENABLED(CONFIG_STMP3XXX_RTC_WATCHDOG)
71/**
72 * stmp3xxx_wdt_set_timeout - configure the watchdog inside the STMP3xxx RTC
73 * @dev: the parent device of the watchdog (= the RTC)
74 * @timeout: the desired value for the timeout register of the watchdog.
75 * 0 disables the watchdog
76 *
77 * The watchdog needs one register and two bits which are in the RTC domain.
78 * To handle the resource conflict, the RTC driver will create another
79 * platform_device for the watchdog driver as a child of the RTC device.
80 * The watchdog driver is passed the below accessor function via platform_data
81 * to configure the watchdog. Locking is not needed because accessing SET/CLR
82 * registers is atomic.
83 */
84
85static void stmp3xxx_wdt_set_timeout(struct device *dev, u32 timeout)
86{
87 struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev);
88
89 if (timeout) {
90 writel(timeout, rtc_data->io + STMP3XXX_RTC_WATCHDOG);
91 writel(STMP3XXX_RTC_CTRL_WATCHDOGEN,
92 rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_SET);
93 writel(STMP3XXX_RTC_PERSISTENT1_FORCE_UPDATER,
94 rtc_data->io + STMP3XXX_RTC_PERSISTENT1 + STMP_OFFSET_REG_SET);
95 } else {
96 writel(STMP3XXX_RTC_CTRL_WATCHDOGEN,
97 rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR);
98 writel(STMP3XXX_RTC_PERSISTENT1_FORCE_UPDATER,
99 rtc_data->io + STMP3XXX_RTC_PERSISTENT1 + STMP_OFFSET_REG_CLR);
100 }
101}
102
103static struct stmp3xxx_wdt_pdata wdt_pdata = {
104 .wdt_set_timeout = stmp3xxx_wdt_set_timeout,
105};
106
107static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev)
108{
109 struct platform_device *wdt_pdev =
110 platform_device_alloc("stmp3xxx_rtc_wdt", rtc_pdev->id);
111
112 if (wdt_pdev) {
113 wdt_pdev->dev.parent = &rtc_pdev->dev;
114 wdt_pdev->dev.platform_data = &wdt_pdata;
115 platform_device_add(wdt_pdev);
116 }
117}
118#else
119static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev)
120{
121}
122#endif /* CONFIG_STMP3XXX_RTC_WATCHDOG */
123
61static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) 124static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data)
62{ 125{
63 /* 126 /*
@@ -233,6 +296,7 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev)
233 goto out_irq_alarm; 296 goto out_irq_alarm;
234 } 297 }
235 298
299 stmp3xxx_wdt_register(pdev);
236 return 0; 300 return 0;
237 301
238out_irq_alarm: 302out_irq_alarm:
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 26e1fdbddf69..9fcc70c11cea 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -79,6 +79,7 @@ config DA9052_WATCHDOG
79config DA9055_WATCHDOG 79config DA9055_WATCHDOG
80 tristate "Dialog Semiconductor DA9055 Watchdog" 80 tristate "Dialog Semiconductor DA9055 Watchdog"
81 depends on MFD_DA9055 81 depends on MFD_DA9055
82 select WATCHDOG_CORE
82 help 83 help
83 If you say yes here you get support for watchdog on the Dialog 84 If you say yes here you get support for watchdog on the Dialog
84 Semiconductor DA9055 PMIC. 85 Semiconductor DA9055 PMIC.
@@ -108,7 +109,7 @@ config WM8350_WATCHDOG
108 109
109config ARM_SP805_WATCHDOG 110config ARM_SP805_WATCHDOG
110 tristate "ARM SP805 Watchdog" 111 tristate "ARM SP805 Watchdog"
111 depends on ARM_AMBA 112 depends on ARM && ARM_AMBA
112 select WATCHDOG_CORE 113 select WATCHDOG_CORE
113 help 114 help
114 ARM Primecell SP805 Watchdog timer. This will reboot your system when 115 ARM Primecell SP805 Watchdog timer. This will reboot your system when
@@ -116,7 +117,7 @@ config ARM_SP805_WATCHDOG
116 117
117config AT91RM9200_WATCHDOG 118config AT91RM9200_WATCHDOG
118 tristate "AT91RM9200 watchdog" 119 tristate "AT91RM9200 watchdog"
119 depends on ARCH_AT91RM9200 120 depends on ARCH_AT91
120 help 121 help
121 Watchdog timer embedded into AT91RM9200 chips. This will reboot your 122 Watchdog timer embedded into AT91RM9200 chips. This will reboot your
122 system when the timeout is reached. 123 system when the timeout is reached.
@@ -124,6 +125,7 @@ config AT91RM9200_WATCHDOG
124config AT91SAM9X_WATCHDOG 125config AT91SAM9X_WATCHDOG
125 tristate "AT91SAM9X / AT91CAP9 watchdog" 126 tristate "AT91SAM9X / AT91CAP9 watchdog"
126 depends on ARCH_AT91 && !ARCH_AT91RM9200 127 depends on ARCH_AT91 && !ARCH_AT91RM9200
128 select WATCHDOG_CORE
127 help 129 help
128 Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will 130 Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will
129 reboot your system when the timeout is reached. 131 reboot your system when the timeout is reached.
@@ -316,14 +318,15 @@ config TWL4030_WATCHDOG
316 Support for TI TWL4030 watchdog. Say 'Y' here to enable the 318 Support for TI TWL4030 watchdog. Say 'Y' here to enable the
317 watchdog timer support for TWL4030 chips. 319 watchdog timer support for TWL4030 chips.
318 320
319config STMP3XXX_WATCHDOG 321config STMP3XXX_RTC_WATCHDOG
320 tristate "Freescale STMP3XXX watchdog" 322 tristate "Freescale STMP3XXX & i.MX23/28 watchdog"
321 depends on ARCH_STMP3XXX 323 depends on RTC_DRV_STMP
324 select WATCHDOG_CORE
322 help 325 help
323 Say Y here if to include support for the watchdog timer 326 Say Y here to include support for the watchdog timer inside
324 for the Sigmatel STMP37XX/378X SoC. 327 the RTC for the STMP37XX/378X or i.MX23/28 SoC.
325 To compile this driver as a module, choose M here: the 328 To compile this driver as a module, choose M here: the
326 module will be called stmp3xxx_wdt. 329 module will be called stmp3xxx_rtc_wdt.
327 330
328config NUC900_WATCHDOG 331config NUC900_WATCHDOG
329 tristate "Nuvoton NUC900 watchdog" 332 tristate "Nuvoton NUC900 watchdog"
@@ -376,6 +379,18 @@ config UX500_WATCHDOG
376 To compile this driver as a module, choose M here: the 379 To compile this driver as a module, choose M here: the
377 module will be called ux500_wdt. 380 module will be called ux500_wdt.
378 381
382config RETU_WATCHDOG
383 tristate "Retu watchdog"
384 depends on MFD_RETU
385 select WATCHDOG_CORE
386 help
387 Retu watchdog driver for Nokia Internet Tablets (770, N800,
388 N810). At least on N800 the watchdog cannot be disabled, so
389 this driver is essential and you should enable it.
390
391 To compile this driver as a module, choose M here: the
392 module will be called retu_wdt.
393
379# AVR32 Architecture 394# AVR32 Architecture
380 395
381config AT32AP700X_WDT 396config AT32AP700X_WDT
@@ -593,7 +608,7 @@ config IE6XX_WDT
593 608
594config INTEL_SCU_WATCHDOG 609config INTEL_SCU_WATCHDOG
595 bool "Intel SCU Watchdog for Mobile Platforms" 610 bool "Intel SCU Watchdog for Mobile Platforms"
596 depends on X86_MRST 611 depends on X86_INTEL_MID
597 ---help--- 612 ---help---
598 Hardware driver for the watchdog time built into the Intel SCU 613 Hardware driver for the watchdog time built into the Intel SCU
599 for Intel Mobile Platforms. 614 for Intel Mobile Platforms.
@@ -983,6 +998,7 @@ config ATH79_WDT
983config BCM47XX_WDT 998config BCM47XX_WDT
984 tristate "Broadcom BCM47xx Watchdog Timer" 999 tristate "Broadcom BCM47xx Watchdog Timer"
985 depends on BCM47XX 1000 depends on BCM47XX
1001 select WATCHDOG_CORE
986 help 1002 help
987 Hardware driver for the Broadcom BCM47xx Watchdog Timer. 1003 Hardware driver for the Broadcom BCM47xx Watchdog Timer.
988 1004
@@ -1131,6 +1147,7 @@ config PIKA_WDT
1131config BOOKE_WDT 1147config BOOKE_WDT
1132 tristate "PowerPC Book-E Watchdog Timer" 1148 tristate "PowerPC Book-E Watchdog Timer"
1133 depends on BOOKE || 4xx 1149 depends on BOOKE || 4xx
1150 select WATCHDOG_CORE
1134 ---help--- 1151 ---help---
1135 Watchdog driver for PowerPC Book-E chips, such as the Freescale 1152 Watchdog driver for PowerPC Book-E chips, such as the Freescale
1136 MPC85xx SOCs and the IBM PowerPC 440. 1153 MPC85xx SOCs and the IBM PowerPC 440.
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index bec86ee6e9e3..a300b948f254 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -48,11 +48,12 @@ obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
48obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o 48obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
49obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o 49obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
50obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o 50obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
51obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o 51obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
52obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o 52obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
53obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o 53obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
54obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o 54obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
55obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o 55obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
56obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
56 57
57# AVR32 Architecture 58# AVR32 Architecture
58obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o 59obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c
index 89831ed24a4f..1c75260b987c 100644
--- a/drivers/watchdog/at91rm9200_wdt.c
+++ b/drivers/watchdog/at91rm9200_wdt.c
@@ -24,6 +24,8 @@
24#include <linux/types.h> 24#include <linux/types.h>
25#include <linux/watchdog.h> 25#include <linux/watchdog.h>
26#include <linux/uaccess.h> 26#include <linux/uaccess.h>
27#include <linux/of.h>
28#include <linux/of_device.h>
27#include <mach/at91_st.h> 29#include <mach/at91_st.h>
28 30
29#define WDT_DEFAULT_TIME 5 /* seconds */ 31#define WDT_DEFAULT_TIME 5 /* seconds */
@@ -252,6 +254,12 @@ static int at91wdt_resume(struct platform_device *pdev)
252#define at91wdt_resume NULL 254#define at91wdt_resume NULL
253#endif 255#endif
254 256
257static const struct of_device_id at91_wdt_dt_ids[] = {
258 { .compatible = "atmel,at91rm9200-wdt" },
259 { /* sentinel */ }
260};
261MODULE_DEVICE_TABLE(of, at91_wdt_dt_ids);
262
255static struct platform_driver at91wdt_driver = { 263static struct platform_driver at91wdt_driver = {
256 .probe = at91wdt_probe, 264 .probe = at91wdt_probe,
257 .remove = at91wdt_remove, 265 .remove = at91wdt_remove,
@@ -261,6 +269,7 @@ static struct platform_driver at91wdt_driver = {
261 .driver = { 269 .driver = {
262 .name = "at91_wdt", 270 .name = "at91_wdt",
263 .owner = THIS_MODULE, 271 .owner = THIS_MODULE,
272 .of_match_table = of_match_ptr(at91_wdt_dt_ids),
264 }, 273 },
265}; 274};
266 275
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index c08933cc565e..be37dde4f864 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -18,11 +18,9 @@
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19 19
20#include <linux/errno.h> 20#include <linux/errno.h>
21#include <linux/fs.h>
22#include <linux/init.h> 21#include <linux/init.h>
23#include <linux/io.h> 22#include <linux/io.h>
24#include <linux/kernel.h> 23#include <linux/kernel.h>
25#include <linux/miscdevice.h>
26#include <linux/module.h> 24#include <linux/module.h>
27#include <linux/moduleparam.h> 25#include <linux/moduleparam.h>
28#include <linux/platform_device.h> 26#include <linux/platform_device.h>
@@ -58,7 +56,7 @@
58 56
59/* User land timeout */ 57/* User land timeout */
60#define WDT_HEARTBEAT 15 58#define WDT_HEARTBEAT 15
61static int heartbeat = WDT_HEARTBEAT; 59static int heartbeat;
62module_param(heartbeat, int, 0); 60module_param(heartbeat, int, 0);
63MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. " 61MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
64 "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")"); 62 "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")");
@@ -68,19 +66,17 @@ module_param(nowayout, bool, 0);
68MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 66MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
69 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 67 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
70 68
69static struct watchdog_device at91_wdt_dev;
71static void at91_ping(unsigned long data); 70static void at91_ping(unsigned long data);
72 71
73static struct { 72static struct {
74 void __iomem *base; 73 void __iomem *base;
75 unsigned long next_heartbeat; /* the next_heartbeat for the timer */ 74 unsigned long next_heartbeat; /* the next_heartbeat for the timer */
76 unsigned long open;
77 char expect_close;
78 struct timer_list timer; /* The timer that pings the watchdog */ 75 struct timer_list timer; /* The timer that pings the watchdog */
79} at91wdt_private; 76} at91wdt_private;
80 77
81/* ......................................................................... */ 78/* ......................................................................... */
82 79
83
84/* 80/*
85 * Reload the watchdog timer. (ie, pat the watchdog) 81 * Reload the watchdog timer. (ie, pat the watchdog)
86 */ 82 */
@@ -95,39 +91,37 @@ static inline void at91_wdt_reset(void)
95static void at91_ping(unsigned long data) 91static void at91_ping(unsigned long data)
96{ 92{
97 if (time_before(jiffies, at91wdt_private.next_heartbeat) || 93 if (time_before(jiffies, at91wdt_private.next_heartbeat) ||
98 (!nowayout && !at91wdt_private.open)) { 94 (!watchdog_active(&at91_wdt_dev))) {
99 at91_wdt_reset(); 95 at91_wdt_reset();
100 mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); 96 mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
101 } else 97 } else
102 pr_crit("I will reset your machine !\n"); 98 pr_crit("I will reset your machine !\n");
103} 99}
104 100
105/* 101static int at91_wdt_ping(struct watchdog_device *wdd)
106 * Watchdog device is opened, and watchdog starts running.
107 */
108static int at91_wdt_open(struct inode *inode, struct file *file)
109{ 102{
110 if (test_and_set_bit(0, &at91wdt_private.open)) 103 /* calculate when the next userspace timeout will be */
111 return -EBUSY; 104 at91wdt_private.next_heartbeat = jiffies + wdd->timeout * HZ;
105 return 0;
106}
112 107
113 at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ; 108static int at91_wdt_start(struct watchdog_device *wdd)
109{
110 /* calculate the next userspace timeout and modify the timer */
111 at91_wdt_ping(wdd);
114 mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); 112 mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
115 113 return 0;
116 return nonseekable_open(inode, file);
117} 114}
118 115
119/* 116static int at91_wdt_stop(struct watchdog_device *wdd)
120 * Close the watchdog device.
121 */
122static int at91_wdt_close(struct inode *inode, struct file *file)
123{ 117{
124 clear_bit(0, &at91wdt_private.open); 118 /* The watchdog timer hardware can not be stopped... */
125 119 return 0;
126 /* stop internal ping */ 120}
127 if (!at91wdt_private.expect_close)
128 del_timer(&at91wdt_private.timer);
129 121
130 at91wdt_private.expect_close = 0; 122static int at91_wdt_set_timeout(struct watchdog_device *wdd, unsigned int new_timeout)
123{
124 wdd->timeout = new_timeout;
131 return 0; 125 return 0;
132} 126}
133 127
@@ -163,96 +157,28 @@ static int at91_wdt_settimeout(unsigned int timeout)
163 return 0; 157 return 0;
164} 158}
165 159
160/* ......................................................................... */
161
166static const struct watchdog_info at91_wdt_info = { 162static const struct watchdog_info at91_wdt_info = {
167 .identity = DRV_NAME, 163 .identity = DRV_NAME,
168 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | 164 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
169 WDIOF_MAGICCLOSE, 165 WDIOF_MAGICCLOSE,
170}; 166};
171 167
172/* 168static const struct watchdog_ops at91_wdt_ops = {
173 * Handle commands from user-space. 169 .owner = THIS_MODULE,
174 */ 170 .start = at91_wdt_start,
175static long at91_wdt_ioctl(struct file *file, 171 .stop = at91_wdt_stop,
176 unsigned int cmd, unsigned long arg) 172 .ping = at91_wdt_ping,
177{ 173 .set_timeout = at91_wdt_set_timeout,
178 void __user *argp = (void __user *)arg;
179 int __user *p = argp;
180 int new_value;
181
182 switch (cmd) {
183 case WDIOC_GETSUPPORT:
184 return copy_to_user(argp, &at91_wdt_info,
185 sizeof(at91_wdt_info)) ? -EFAULT : 0;
186
187 case WDIOC_GETSTATUS:
188 case WDIOC_GETBOOTSTATUS:
189 return put_user(0, p);
190
191 case WDIOC_KEEPALIVE:
192 at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
193 return 0;
194
195 case WDIOC_SETTIMEOUT:
196 if (get_user(new_value, p))
197 return -EFAULT;
198
199 heartbeat = new_value;
200 at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
201
202 return put_user(new_value, p); /* return current value */
203
204 case WDIOC_GETTIMEOUT:
205 return put_user(heartbeat, p);
206 }
207 return -ENOTTY;
208}
209
210/*
211 * Pat the watchdog whenever device is written to.
212 */
213static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len,
214 loff_t *ppos)
215{
216 if (!len)
217 return 0;
218
219 /* Scan for magic character */
220 if (!nowayout) {
221 size_t i;
222
223 at91wdt_private.expect_close = 0;
224
225 for (i = 0; i < len; i++) {
226 char c;
227 if (get_user(c, data + i))
228 return -EFAULT;
229 if (c == 'V') {
230 at91wdt_private.expect_close = 42;
231 break;
232 }
233 }
234 }
235
236 at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ;
237
238 return len;
239}
240
241/* ......................................................................... */
242
243static const struct file_operations at91wdt_fops = {
244 .owner = THIS_MODULE,
245 .llseek = no_llseek,
246 .unlocked_ioctl = at91_wdt_ioctl,
247 .open = at91_wdt_open,
248 .release = at91_wdt_close,
249 .write = at91_wdt_write,
250}; 174};
251 175
252static struct miscdevice at91wdt_miscdev = { 176static struct watchdog_device at91_wdt_dev = {
253 .minor = WATCHDOG_MINOR, 177 .info = &at91_wdt_info,
254 .name = "watchdog", 178 .ops = &at91_wdt_ops,
255 .fops = &at91wdt_fops, 179 .timeout = WDT_HEARTBEAT,
180 .min_timeout = 1,
181 .max_timeout = 0xFFFF,
256}; 182};
257 183
258static int __init at91wdt_probe(struct platform_device *pdev) 184static int __init at91wdt_probe(struct platform_device *pdev)
@@ -260,10 +186,6 @@ static int __init at91wdt_probe(struct platform_device *pdev)
260 struct resource *r; 186 struct resource *r;
261 int res; 187 int res;
262 188
263 if (at91wdt_miscdev.parent)
264 return -EBUSY;
265 at91wdt_miscdev.parent = &pdev->dev;
266
267 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 189 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
268 if (!r) 190 if (!r)
269 return -ENODEV; 191 return -ENODEV;
@@ -273,38 +195,41 @@ static int __init at91wdt_probe(struct platform_device *pdev)
273 return -ENOMEM; 195 return -ENOMEM;
274 } 196 }
275 197
198 at91_wdt_dev.parent = &pdev->dev;
199 watchdog_init_timeout(&at91_wdt_dev, heartbeat, &pdev->dev);
200 watchdog_set_nowayout(&at91_wdt_dev, nowayout);
201
276 /* Set watchdog */ 202 /* Set watchdog */
277 res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000)); 203 res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000));
278 if (res) 204 if (res)
279 return res; 205 return res;
280 206
281 res = misc_register(&at91wdt_miscdev); 207 res = watchdog_register_device(&at91_wdt_dev);
282 if (res) 208 if (res)
283 return res; 209 return res;
284 210
285 at91wdt_private.next_heartbeat = jiffies + heartbeat * HZ; 211 at91wdt_private.next_heartbeat = jiffies + at91_wdt_dev.timeout * HZ;
286 setup_timer(&at91wdt_private.timer, at91_ping, 0); 212 setup_timer(&at91wdt_private.timer, at91_ping, 0);
287 mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT); 213 mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
288 214
289 pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n", 215 pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n",
290 heartbeat, nowayout); 216 at91_wdt_dev.timeout, nowayout);
291 217
292 return 0; 218 return 0;
293} 219}
294 220
295static int __exit at91wdt_remove(struct platform_device *pdev) 221static int __exit at91wdt_remove(struct platform_device *pdev)
296{ 222{
297 int res; 223 watchdog_unregister_device(&at91_wdt_dev);
298 224
299 res = misc_deregister(&at91wdt_miscdev); 225 pr_warn("I quit now, hardware will probably reboot!\n");
300 if (!res) 226 del_timer(&at91wdt_private.timer);
301 at91wdt_miscdev.parent = NULL;
302 227
303 return res; 228 return 0;
304} 229}
305 230
306#if defined(CONFIG_OF) 231#if defined(CONFIG_OF)
307static const struct of_device_id at91_wdt_dt_ids[] __initconst = { 232static const struct of_device_id at91_wdt_dt_ids[] = {
308 { .compatible = "atmel,at91sam9260-wdt" }, 233 { .compatible = "atmel,at91sam9260-wdt" },
309 { /* sentinel */ } 234 { /* sentinel */ }
310}; 235};
@@ -326,4 +251,3 @@ module_platform_driver_probe(at91wdt_driver, at91wdt_probe);
326MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>"); 251MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>");
327MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors"); 252MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
328MODULE_LICENSE("GPL"); 253MODULE_LICENSE("GPL");
329MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index 38a999e60c0d..898799074a13 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -23,6 +23,7 @@
23#include <linux/errno.h> 23#include <linux/errno.h>
24#include <linux/fs.h> 24#include <linux/fs.h>
25#include <linux/init.h> 25#include <linux/init.h>
26#include <linux/io.h>
26#include <linux/kernel.h> 27#include <linux/kernel.h>
27#include <linux/miscdevice.h> 28#include <linux/miscdevice.h>
28#include <linux/module.h> 29#include <linux/module.h>
@@ -32,14 +33,16 @@
32#include <linux/watchdog.h> 33#include <linux/watchdog.h>
33#include <linux/clk.h> 34#include <linux/clk.h>
34#include <linux/err.h> 35#include <linux/err.h>
35 36#include <linux/of.h>
36#include <asm/mach-ath79/ath79.h> 37#include <linux/of_platform.h>
37#include <asm/mach-ath79/ar71xx_regs.h>
38 38
39#define DRIVER_NAME "ath79-wdt" 39#define DRIVER_NAME "ath79-wdt"
40 40
41#define WDT_TIMEOUT 15 /* seconds */ 41#define WDT_TIMEOUT 15 /* seconds */
42 42
43#define WDOG_REG_CTRL 0x00
44#define WDOG_REG_TIMER 0x04
45
43#define WDOG_CTRL_LAST_RESET BIT(31) 46#define WDOG_CTRL_LAST_RESET BIT(31)
44#define WDOG_CTRL_ACTION_MASK 3 47#define WDOG_CTRL_ACTION_MASK 3
45#define WDOG_CTRL_ACTION_NONE 0 /* no action */ 48#define WDOG_CTRL_ACTION_NONE 0 /* no action */
@@ -66,27 +69,38 @@ static struct clk *wdt_clk;
66static unsigned long wdt_freq; 69static unsigned long wdt_freq;
67static int boot_status; 70static int boot_status;
68static int max_timeout; 71static int max_timeout;
72static void __iomem *wdt_base;
73
74static inline void ath79_wdt_wr(unsigned reg, u32 val)
75{
76 iowrite32(val, wdt_base + reg);
77}
78
79static inline u32 ath79_wdt_rr(unsigned reg)
80{
81 return ioread32(wdt_base + reg);
82}
69 83
70static inline void ath79_wdt_keepalive(void) 84static inline void ath79_wdt_keepalive(void)
71{ 85{
72 ath79_reset_wr(AR71XX_RESET_REG_WDOG, wdt_freq * timeout); 86 ath79_wdt_wr(WDOG_REG_TIMER, wdt_freq * timeout);
73 /* flush write */ 87 /* flush write */
74 ath79_reset_rr(AR71XX_RESET_REG_WDOG); 88 ath79_wdt_rr(WDOG_REG_TIMER);
75} 89}
76 90
77static inline void ath79_wdt_enable(void) 91static inline void ath79_wdt_enable(void)
78{ 92{
79 ath79_wdt_keepalive(); 93 ath79_wdt_keepalive();
80 ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR); 94 ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR);
81 /* flush write */ 95 /* flush write */
82 ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL); 96 ath79_wdt_rr(WDOG_REG_CTRL);
83} 97}
84 98
85static inline void ath79_wdt_disable(void) 99static inline void ath79_wdt_disable(void)
86{ 100{
87 ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_NONE); 101 ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_NONE);
88 /* flush write */ 102 /* flush write */
89 ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL); 103 ath79_wdt_rr(WDOG_REG_CTRL);
90} 104}
91 105
92static int ath79_wdt_set_timeout(int val) 106static int ath79_wdt_set_timeout(int val)
@@ -226,16 +240,32 @@ static struct miscdevice ath79_wdt_miscdev = {
226 240
227static int ath79_wdt_probe(struct platform_device *pdev) 241static int ath79_wdt_probe(struct platform_device *pdev)
228{ 242{
243 struct resource *res;
229 u32 ctrl; 244 u32 ctrl;
230 int err; 245 int err;
231 246
232 wdt_clk = clk_get(&pdev->dev, "wdt"); 247 if (wdt_base)
248 return -EBUSY;
249
250 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
251 if (!res) {
252 dev_err(&pdev->dev, "no memory resource found\n");
253 return -EINVAL;
254 }
255
256 wdt_base = devm_request_and_ioremap(&pdev->dev, res);
257 if (!wdt_base) {
258 dev_err(&pdev->dev, "unable to remap memory region\n");
259 return -ENOMEM;
260 }
261
262 wdt_clk = devm_clk_get(&pdev->dev, "wdt");
233 if (IS_ERR(wdt_clk)) 263 if (IS_ERR(wdt_clk))
234 return PTR_ERR(wdt_clk); 264 return PTR_ERR(wdt_clk);
235 265
236 err = clk_enable(wdt_clk); 266 err = clk_enable(wdt_clk);
237 if (err) 267 if (err)
238 goto err_clk_put; 268 return err;
239 269
240 wdt_freq = clk_get_rate(wdt_clk); 270 wdt_freq = clk_get_rate(wdt_clk);
241 if (!wdt_freq) { 271 if (!wdt_freq) {
@@ -251,7 +281,7 @@ static int ath79_wdt_probe(struct platform_device *pdev)
251 max_timeout, timeout); 281 max_timeout, timeout);
252 } 282 }
253 283
254 ctrl = ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL); 284 ctrl = ath79_wdt_rr(WDOG_REG_CTRL);
255 boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0; 285 boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0;
256 286
257 err = misc_register(&ath79_wdt_miscdev); 287 err = misc_register(&ath79_wdt_miscdev);
@@ -265,8 +295,6 @@ static int ath79_wdt_probe(struct platform_device *pdev)
265 295
266err_clk_disable: 296err_clk_disable:
267 clk_disable(wdt_clk); 297 clk_disable(wdt_clk);
268err_clk_put:
269 clk_put(wdt_clk);
270 return err; 298 return err;
271} 299}
272 300
@@ -274,7 +302,6 @@ static int ath79_wdt_remove(struct platform_device *pdev)
274{ 302{
275 misc_deregister(&ath79_wdt_miscdev); 303 misc_deregister(&ath79_wdt_miscdev);
276 clk_disable(wdt_clk); 304 clk_disable(wdt_clk);
277 clk_put(wdt_clk);
278 return 0; 305 return 0;
279} 306}
280 307
@@ -283,6 +310,14 @@ static void ath97_wdt_shutdown(struct platform_device *pdev)
283 ath79_wdt_disable(); 310 ath79_wdt_disable();
284} 311}
285 312
313#ifdef CONFIG_OF
314static const struct of_device_id ath79_wdt_match[] = {
315 { .compatible = "qca,ar7130-wdt" },
316 {},
317};
318MODULE_DEVICE_TABLE(of, ath79_wdt_match);
319#endif
320
286static struct platform_driver ath79_wdt_driver = { 321static struct platform_driver ath79_wdt_driver = {
287 .probe = ath79_wdt_probe, 322 .probe = ath79_wdt_probe,
288 .remove = ath79_wdt_remove, 323 .remove = ath79_wdt_remove,
@@ -290,6 +325,7 @@ static struct platform_driver ath79_wdt_driver = {
290 .driver = { 325 .driver = {
291 .name = DRIVER_NAME, 326 .name = DRIVER_NAME,
292 .owner = THIS_MODULE, 327 .owner = THIS_MODULE,
328 .of_match_table = of_match_ptr(ath79_wdt_match),
293 }, 329 },
294}; 330};
295 331
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index bc0e91e78e86..b4021a2b459b 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -3,6 +3,7 @@
3 * 3 *
4 * Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs> 4 * Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs>
5 * Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr> 5 * Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr>
6 * Copyright (C) 2012-2013 Hauke Mehrtens <hauke@hauke-m.de>
6 * 7 *
7 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 9 * modify it under the terms of the GNU General Public License
@@ -12,165 +13,143 @@
12 13
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 15
16#include <linux/bcm47xx_wdt.h>
15#include <linux/bitops.h> 17#include <linux/bitops.h>
16#include <linux/errno.h> 18#include <linux/errno.h>
17#include <linux/fs.h>
18#include <linux/init.h> 19#include <linux/init.h>
19#include <linux/kernel.h> 20#include <linux/kernel.h>
20#include <linux/miscdevice.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/moduleparam.h> 22#include <linux/moduleparam.h>
23#include <linux/platform_device.h>
23#include <linux/reboot.h> 24#include <linux/reboot.h>
24#include <linux/types.h> 25#include <linux/types.h>
25#include <linux/uaccess.h>
26#include <linux/watchdog.h> 26#include <linux/watchdog.h>
27#include <linux/timer.h> 27#include <linux/timer.h>
28#include <linux/jiffies.h> 28#include <linux/jiffies.h>
29#include <linux/ssb/ssb_embedded.h>
30#include <asm/mach-bcm47xx/bcm47xx.h>
31 29
32#define DRV_NAME "bcm47xx_wdt" 30#define DRV_NAME "bcm47xx_wdt"
33 31
34#define WDT_DEFAULT_TIME 30 /* seconds */ 32#define WDT_DEFAULT_TIME 30 /* seconds */
35#define WDT_MAX_TIME 255 /* seconds */ 33#define WDT_SOFTTIMER_MAX 255 /* seconds */
34#define WDT_SOFTTIMER_THRESHOLD 60 /* seconds */
36 35
37static int wdt_time = WDT_DEFAULT_TIME; 36static int timeout = WDT_DEFAULT_TIME;
38static bool nowayout = WATCHDOG_NOWAYOUT; 37static bool nowayout = WATCHDOG_NOWAYOUT;
39 38
40module_param(wdt_time, int, 0); 39module_param(timeout, int, 0);
41MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default=" 40MODULE_PARM_DESC(timeout, "Watchdog time in seconds. (default="
42 __MODULE_STRING(WDT_DEFAULT_TIME) ")"); 41 __MODULE_STRING(WDT_DEFAULT_TIME) ")");
43 42
44#ifdef CONFIG_WATCHDOG_NOWAYOUT
45module_param(nowayout, bool, 0); 43module_param(nowayout, bool, 0);
46MODULE_PARM_DESC(nowayout, 44MODULE_PARM_DESC(nowayout,
47 "Watchdog cannot be stopped once started (default=" 45 "Watchdog cannot be stopped once started (default="
48 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 46 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
49#endif
50 47
51static unsigned long bcm47xx_wdt_busy; 48static inline struct bcm47xx_wdt *bcm47xx_wdt_get(struct watchdog_device *wdd)
52static char expect_release;
53static struct timer_list wdt_timer;
54static atomic_t ticks;
55
56static inline void bcm47xx_wdt_hw_start(void)
57{ 49{
58 /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */ 50 return container_of(wdd, struct bcm47xx_wdt, wdd);
59 switch (bcm47xx_bus_type) {
60#ifdef CONFIG_BCM47XX_SSB
61 case BCM47XX_BUS_TYPE_SSB:
62 ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff);
63 break;
64#endif
65#ifdef CONFIG_BCM47XX_BCMA
66 case BCM47XX_BUS_TYPE_BCMA:
67 bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc,
68 0xfffffff);
69 break;
70#endif
71 }
72} 51}
73 52
74static inline int bcm47xx_wdt_hw_stop(void) 53static int bcm47xx_wdt_hard_keepalive(struct watchdog_device *wdd)
75{ 54{
76 switch (bcm47xx_bus_type) { 55 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
77#ifdef CONFIG_BCM47XX_SSB
78 case BCM47XX_BUS_TYPE_SSB:
79 return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0);
80#endif
81#ifdef CONFIG_BCM47XX_BCMA
82 case BCM47XX_BUS_TYPE_BCMA:
83 bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0);
84 return 0;
85#endif
86 }
87 return -EINVAL;
88}
89 56
90static void bcm47xx_timer_tick(unsigned long unused) 57 wdt->timer_set_ms(wdt, wdd->timeout * 1000);
91{ 58
92 if (!atomic_dec_and_test(&ticks)) { 59 return 0;
93 bcm47xx_wdt_hw_start();
94 mod_timer(&wdt_timer, jiffies + HZ);
95 } else {
96 pr_crit("Watchdog will fire soon!!!\n");
97 }
98} 60}
99 61
100static inline void bcm47xx_wdt_pet(void) 62static int bcm47xx_wdt_hard_start(struct watchdog_device *wdd)
101{ 63{
102 atomic_set(&ticks, wdt_time); 64 return 0;
103} 65}
104 66
105static void bcm47xx_wdt_start(void) 67static int bcm47xx_wdt_hard_stop(struct watchdog_device *wdd)
106{ 68{
107 bcm47xx_wdt_pet(); 69 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
108 bcm47xx_timer_tick(0); 70
71 wdt->timer_set(wdt, 0);
72
73 return 0;
109} 74}
110 75
111static void bcm47xx_wdt_pause(void) 76static int bcm47xx_wdt_hard_set_timeout(struct watchdog_device *wdd,
77 unsigned int new_time)
112{ 78{
113 del_timer_sync(&wdt_timer); 79 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
114 bcm47xx_wdt_hw_stop(); 80 u32 max_timer = wdt->max_timer_ms;
81
82 if (new_time < 1 || new_time > max_timer / 1000) {
83 pr_warn("timeout value must be 1<=x<=%d, using %d\n",
84 max_timer / 1000, new_time);
85 return -EINVAL;
86 }
87
88 wdd->timeout = new_time;
89 return 0;
115} 90}
116 91
117static void bcm47xx_wdt_stop(void) 92static struct watchdog_ops bcm47xx_wdt_hard_ops = {
93 .owner = THIS_MODULE,
94 .start = bcm47xx_wdt_hard_start,
95 .stop = bcm47xx_wdt_hard_stop,
96 .ping = bcm47xx_wdt_hard_keepalive,
97 .set_timeout = bcm47xx_wdt_hard_set_timeout,
98};
99
100static void bcm47xx_wdt_soft_timer_tick(unsigned long data)
118{ 101{
119 bcm47xx_wdt_pause(); 102 struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data;
103 u32 next_tick = min(wdt->wdd.timeout * 1000, wdt->max_timer_ms);
104
105 if (!atomic_dec_and_test(&wdt->soft_ticks)) {
106 wdt->timer_set_ms(wdt, next_tick);
107 mod_timer(&wdt->soft_timer, jiffies + HZ);
108 } else {
109 pr_crit("Watchdog will fire soon!!!\n");
110 }
120} 111}
121 112
122static int bcm47xx_wdt_settimeout(int new_time) 113static int bcm47xx_wdt_soft_keepalive(struct watchdog_device *wdd)
123{ 114{
124 if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) 115 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
125 return -EINVAL; 116
117 atomic_set(&wdt->soft_ticks, wdd->timeout);
126 118
127 wdt_time = new_time;
128 return 0; 119 return 0;
129} 120}
130 121
131static int bcm47xx_wdt_open(struct inode *inode, struct file *file) 122static int bcm47xx_wdt_soft_start(struct watchdog_device *wdd)
132{ 123{
133 if (test_and_set_bit(0, &bcm47xx_wdt_busy)) 124 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
134 return -EBUSY; 125
126 bcm47xx_wdt_soft_keepalive(wdd);
127 bcm47xx_wdt_soft_timer_tick((unsigned long)wdt);
135 128
136 bcm47xx_wdt_start(); 129 return 0;
137 return nonseekable_open(inode, file);
138} 130}
139 131
140static int bcm47xx_wdt_release(struct inode *inode, struct file *file) 132static int bcm47xx_wdt_soft_stop(struct watchdog_device *wdd)
141{ 133{
142 if (expect_release == 42) { 134 struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
143 bcm47xx_wdt_stop(); 135
144 } else { 136 del_timer_sync(&wdt->soft_timer);
145 pr_crit("Unexpected close, not stopping watchdog!\n"); 137 wdt->timer_set(wdt, 0);
146 bcm47xx_wdt_start();
147 }
148 138
149 clear_bit(0, &bcm47xx_wdt_busy);
150 expect_release = 0;
151 return 0; 139 return 0;
152} 140}
153 141
154static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data, 142static int bcm47xx_wdt_soft_set_timeout(struct watchdog_device *wdd,
155 size_t len, loff_t *ppos) 143 unsigned int new_time)
156{ 144{
157 if (len) { 145 if (new_time < 1 || new_time > WDT_SOFTTIMER_MAX) {
158 if (!nowayout) { 146 pr_warn("timeout value must be 1<=x<=%d, using %d\n",
159 size_t i; 147 WDT_SOFTTIMER_MAX, new_time);
160 148 return -EINVAL;
161 expect_release = 0;
162
163 for (i = 0; i != len; i++) {
164 char c;
165 if (get_user(c, data + i))
166 return -EFAULT;
167 if (c == 'V')
168 expect_release = 42;
169 }
170 }
171 bcm47xx_wdt_pet();
172 } 149 }
173 return len; 150
151 wdd->timeout = new_time;
152 return 0;
174} 153}
175 154
176static const struct watchdog_info bcm47xx_wdt_info = { 155static const struct watchdog_info bcm47xx_wdt_info = {
@@ -180,130 +159,100 @@ static const struct watchdog_info bcm47xx_wdt_info = {
180 WDIOF_MAGICCLOSE, 159 WDIOF_MAGICCLOSE,
181}; 160};
182 161
183static long bcm47xx_wdt_ioctl(struct file *file,
184 unsigned int cmd, unsigned long arg)
185{
186 void __user *argp = (void __user *)arg;
187 int __user *p = argp;
188 int new_value, retval = -EINVAL;
189
190 switch (cmd) {
191 case WDIOC_GETSUPPORT:
192 return copy_to_user(argp, &bcm47xx_wdt_info,
193 sizeof(bcm47xx_wdt_info)) ? -EFAULT : 0;
194
195 case WDIOC_GETSTATUS:
196 case WDIOC_GETBOOTSTATUS:
197 return put_user(0, p);
198
199 case WDIOC_SETOPTIONS:
200 if (get_user(new_value, p))
201 return -EFAULT;
202
203 if (new_value & WDIOS_DISABLECARD) {
204 bcm47xx_wdt_stop();
205 retval = 0;
206 }
207
208 if (new_value & WDIOS_ENABLECARD) {
209 bcm47xx_wdt_start();
210 retval = 0;
211 }
212
213 return retval;
214
215 case WDIOC_KEEPALIVE:
216 bcm47xx_wdt_pet();
217 return 0;
218
219 case WDIOC_SETTIMEOUT:
220 if (get_user(new_value, p))
221 return -EFAULT;
222
223 if (bcm47xx_wdt_settimeout(new_value))
224 return -EINVAL;
225
226 bcm47xx_wdt_pet();
227
228 case WDIOC_GETTIMEOUT:
229 return put_user(wdt_time, p);
230
231 default:
232 return -ENOTTY;
233 }
234}
235
236static int bcm47xx_wdt_notify_sys(struct notifier_block *this, 162static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
237 unsigned long code, void *unused) 163 unsigned long code, void *unused)
238{ 164{
165 struct bcm47xx_wdt *wdt;
166
167 wdt = container_of(this, struct bcm47xx_wdt, notifier);
239 if (code == SYS_DOWN || code == SYS_HALT) 168 if (code == SYS_DOWN || code == SYS_HALT)
240 bcm47xx_wdt_stop(); 169 wdt->wdd.ops->stop(&wdt->wdd);
241 return NOTIFY_DONE; 170 return NOTIFY_DONE;
242} 171}
243 172
244static const struct file_operations bcm47xx_wdt_fops = { 173static struct watchdog_ops bcm47xx_wdt_soft_ops = {
245 .owner = THIS_MODULE, 174 .owner = THIS_MODULE,
246 .llseek = no_llseek, 175 .start = bcm47xx_wdt_soft_start,
247 .unlocked_ioctl = bcm47xx_wdt_ioctl, 176 .stop = bcm47xx_wdt_soft_stop,
248 .open = bcm47xx_wdt_open, 177 .ping = bcm47xx_wdt_soft_keepalive,
249 .release = bcm47xx_wdt_release, 178 .set_timeout = bcm47xx_wdt_soft_set_timeout,
250 .write = bcm47xx_wdt_write,
251};
252
253static struct miscdevice bcm47xx_wdt_miscdev = {
254 .minor = WATCHDOG_MINOR,
255 .name = "watchdog",
256 .fops = &bcm47xx_wdt_fops,
257};
258
259static struct notifier_block bcm47xx_wdt_notifier = {
260 .notifier_call = bcm47xx_wdt_notify_sys,
261}; 179};
262 180
263static int __init bcm47xx_wdt_init(void) 181static int bcm47xx_wdt_probe(struct platform_device *pdev)
264{ 182{
265 int ret; 183 int ret;
184 bool soft;
185 struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
266 186
267 if (bcm47xx_wdt_hw_stop() < 0) 187 if (!wdt)
268 return -ENODEV; 188 return -ENXIO;
269 189
270 setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L); 190 soft = wdt->max_timer_ms < WDT_SOFTTIMER_THRESHOLD * 1000;
271 191
272 if (bcm47xx_wdt_settimeout(wdt_time)) { 192 if (soft) {
273 bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME); 193 wdt->wdd.ops = &bcm47xx_wdt_soft_ops;
274 pr_info("wdt_time value must be 0 < wdt_time < %d, using %d\n", 194 setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick,
275 (WDT_MAX_TIME + 1), wdt_time); 195 (long unsigned int)wdt);
196 } else {
197 wdt->wdd.ops = &bcm47xx_wdt_hard_ops;
276 } 198 }
277 199
278 ret = register_reboot_notifier(&bcm47xx_wdt_notifier); 200 wdt->wdd.info = &bcm47xx_wdt_info;
201 wdt->wdd.timeout = WDT_DEFAULT_TIME;
202 ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout);
279 if (ret) 203 if (ret)
280 return ret; 204 goto err_timer;
205 watchdog_set_nowayout(&wdt->wdd, nowayout);
281 206
282 ret = misc_register(&bcm47xx_wdt_miscdev); 207 wdt->notifier.notifier_call = &bcm47xx_wdt_notify_sys;
283 if (ret) { 208
284 unregister_reboot_notifier(&bcm47xx_wdt_notifier); 209 ret = register_reboot_notifier(&wdt->notifier);
285 return ret; 210 if (ret)
286 } 211 goto err_timer;
287 212
288 pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n", 213 ret = watchdog_register_device(&wdt->wdd);
289 wdt_time, nowayout ? ", nowayout" : ""); 214 if (ret)
215 goto err_notifier;
216
217 dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n",
218 timeout, nowayout ? ", nowayout" : "",
219 soft ? ", Software Timer" : "");
290 return 0; 220 return 0;
221
222err_notifier:
223 unregister_reboot_notifier(&wdt->notifier);
224err_timer:
225 if (soft)
226 del_timer_sync(&wdt->soft_timer);
227
228 return ret;
291} 229}
292 230
293static void __exit bcm47xx_wdt_exit(void) 231static int bcm47xx_wdt_remove(struct platform_device *pdev)
294{ 232{
295 if (!nowayout) 233 struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
296 bcm47xx_wdt_stop();
297 234
298 misc_deregister(&bcm47xx_wdt_miscdev); 235 if (!wdt)
236 return -ENXIO;
299 237
300 unregister_reboot_notifier(&bcm47xx_wdt_notifier); 238 watchdog_unregister_device(&wdt->wdd);
239 unregister_reboot_notifier(&wdt->notifier);
240
241 return 0;
301} 242}
302 243
303module_init(bcm47xx_wdt_init); 244static struct platform_driver bcm47xx_wdt_driver = {
304module_exit(bcm47xx_wdt_exit); 245 .driver = {
246 .owner = THIS_MODULE,
247 .name = "bcm47xx-wdt",
248 },
249 .probe = bcm47xx_wdt_probe,
250 .remove = bcm47xx_wdt_remove,
251};
252
253module_platform_driver(bcm47xx_wdt_driver);
305 254
306MODULE_AUTHOR("Aleksandar Radovanovic"); 255MODULE_AUTHOR("Aleksandar Radovanovic");
256MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
307MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx"); 257MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx");
308MODULE_LICENSE("GPL"); 258MODULE_LICENSE("GPL");
309MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
index c0bc92d8e438..a8dbceb32914 100644
--- a/drivers/watchdog/booke_wdt.c
+++ b/drivers/watchdog/booke_wdt.c
@@ -15,12 +15,8 @@
15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16 16
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/fs.h>
19#include <linux/smp.h> 18#include <linux/smp.h>
20#include <linux/miscdevice.h>
21#include <linux/notifier.h>
22#include <linux/watchdog.h> 19#include <linux/watchdog.h>
23#include <linux/uaccess.h>
24 20
25#include <asm/reg_booke.h> 21#include <asm/reg_booke.h>
26#include <asm/time.h> 22#include <asm/time.h>
@@ -45,7 +41,7 @@ u32 booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT;
45#define WDTP_MASK (TCR_WP_MASK) 41#define WDTP_MASK (TCR_WP_MASK)
46#endif 42#endif
47 43
48static DEFINE_SPINLOCK(booke_wdt_lock); 44#ifdef CONFIG_PPC_FSL_BOOK3E
49 45
50/* For the specified period, determine the number of seconds 46/* For the specified period, determine the number of seconds
51 * corresponding to the reset time. There will be a watchdog 47 * corresponding to the reset time. There will be a watchdog
@@ -86,6 +82,24 @@ static unsigned int sec_to_period(unsigned int secs)
86 return 0; 82 return 0;
87} 83}
88 84
85#define MAX_WDT_TIMEOUT period_to_sec(1)
86
87#else /* CONFIG_PPC_FSL_BOOK3E */
88
89static unsigned long long period_to_sec(unsigned int period)
90{
91 return period;
92}
93
94static unsigned int sec_to_period(unsigned int secs)
95{
96 return secs;
97}
98
99#define MAX_WDT_TIMEOUT 3 /* from Kconfig */
100
101#endif /* !CONFIG_PPC_FSL_BOOK3E */
102
89static void __booke_wdt_set(void *data) 103static void __booke_wdt_set(void *data)
90{ 104{
91 u32 val; 105 u32 val;
@@ -107,9 +121,11 @@ static void __booke_wdt_ping(void *data)
107 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); 121 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
108} 122}
109 123
110static void booke_wdt_ping(void) 124static int booke_wdt_ping(struct watchdog_device *wdog)
111{ 125{
112 on_each_cpu(__booke_wdt_ping, NULL, 0); 126 on_each_cpu(__booke_wdt_ping, NULL, 0);
127
128 return 0;
113} 129}
114 130
115static void __booke_wdt_enable(void *data) 131static void __booke_wdt_enable(void *data)
@@ -146,152 +162,81 @@ static void __booke_wdt_disable(void *data)
146 162
147} 163}
148 164
149static ssize_t booke_wdt_write(struct file *file, const char __user *buf, 165static void __booke_wdt_start(struct watchdog_device *wdog)
150 size_t count, loff_t *ppos)
151{ 166{
152 booke_wdt_ping(); 167 on_each_cpu(__booke_wdt_enable, NULL, 0);
153 return count; 168 pr_debug("watchdog enabled (timeout = %u sec)\n", wdog->timeout);
154} 169}
155 170
156static struct watchdog_info ident = { 171static int booke_wdt_start(struct watchdog_device *wdog)
157 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
158 .identity = "PowerPC Book-E Watchdog",
159};
160
161static long booke_wdt_ioctl(struct file *file,
162 unsigned int cmd, unsigned long arg)
163{ 172{
164 u32 tmp = 0;
165 u32 __user *p = (u32 __user *)arg;
166
167 switch (cmd) {
168 case WDIOC_GETSUPPORT:
169 return copy_to_user(p, &ident, sizeof(ident)) ? -EFAULT : 0;
170 case WDIOC_GETSTATUS:
171 return put_user(0, p);
172 case WDIOC_GETBOOTSTATUS:
173 /* XXX: something is clearing TSR */
174 tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
175 /* returns CARDRESET if last reset was caused by the WDT */
176 return put_user((tmp ? WDIOF_CARDRESET : 0), p);
177 case WDIOC_SETOPTIONS:
178 if (get_user(tmp, p))
179 return -EFAULT;
180 if (tmp == WDIOS_ENABLECARD) {
181 booke_wdt_ping();
182 break;
183 } else
184 return -EINVAL;
185 return 0;
186 case WDIOC_KEEPALIVE:
187 booke_wdt_ping();
188 return 0;
189 case WDIOC_SETTIMEOUT:
190 if (get_user(tmp, p))
191 return -EFAULT;
192#ifdef CONFIG_PPC_FSL_BOOK3E
193 /* period of 1 gives the largest possible timeout */
194 if (tmp > period_to_sec(1))
195 return -EINVAL;
196 booke_wdt_period = sec_to_period(tmp);
197#else
198 booke_wdt_period = tmp;
199#endif
200 booke_wdt_set();
201 /* Fall */
202 case WDIOC_GETTIMEOUT:
203#ifdef CONFIG_FSL_BOOKE
204 return put_user(period_to_sec(booke_wdt_period), p);
205#else
206 return put_user(booke_wdt_period, p);
207#endif
208 default:
209 return -ENOTTY;
210 }
211
212 return 0;
213}
214
215/* wdt_is_active stores whether or not the /dev/watchdog device is opened */
216static unsigned long wdt_is_active;
217
218static int booke_wdt_open(struct inode *inode, struct file *file)
219{
220 /* /dev/watchdog can only be opened once */
221 if (test_and_set_bit(0, &wdt_is_active))
222 return -EBUSY;
223
224 spin_lock(&booke_wdt_lock);
225 if (booke_wdt_enabled == 0) { 173 if (booke_wdt_enabled == 0) {
226 booke_wdt_enabled = 1; 174 booke_wdt_enabled = 1;
227 on_each_cpu(__booke_wdt_enable, NULL, 0); 175 __booke_wdt_start(wdog);
228 pr_debug("watchdog enabled (timeout = %llu sec)\n",
229 period_to_sec(booke_wdt_period));
230 } 176 }
231 spin_unlock(&booke_wdt_lock); 177 return 0;
232
233 return nonseekable_open(inode, file);
234} 178}
235 179
236static int booke_wdt_release(struct inode *inode, struct file *file) 180static int booke_wdt_stop(struct watchdog_device *wdog)
237{ 181{
238#ifndef CONFIG_WATCHDOG_NOWAYOUT
239 /* Normally, the watchdog is disabled when /dev/watchdog is closed, but
240 * if CONFIG_WATCHDOG_NOWAYOUT is defined, then it means that the
241 * watchdog should remain enabled. So we disable it only if
242 * CONFIG_WATCHDOG_NOWAYOUT is not defined.
243 */
244 on_each_cpu(__booke_wdt_disable, NULL, 0); 182 on_each_cpu(__booke_wdt_disable, NULL, 0);
245 booke_wdt_enabled = 0; 183 booke_wdt_enabled = 0;
246 pr_debug("watchdog disabled\n"); 184 pr_debug("watchdog disabled\n");
247#endif
248 185
249 clear_bit(0, &wdt_is_active); 186 return 0;
187}
188
189static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev,
190 unsigned int timeout)
191{
192 if (timeout > MAX_WDT_TIMEOUT)
193 return -EINVAL;
194 booke_wdt_period = sec_to_period(timeout);
195 wdt_dev->timeout = timeout;
196 booke_wdt_set();
250 197
251 return 0; 198 return 0;
252} 199}
253 200
254static const struct file_operations booke_wdt_fops = { 201static struct watchdog_info booke_wdt_info = {
202 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
203 .identity = "PowerPC Book-E Watchdog",
204};
205
206static struct watchdog_ops booke_wdt_ops = {
255 .owner = THIS_MODULE, 207 .owner = THIS_MODULE,
256 .llseek = no_llseek, 208 .start = booke_wdt_start,
257 .write = booke_wdt_write, 209 .stop = booke_wdt_stop,
258 .unlocked_ioctl = booke_wdt_ioctl, 210 .ping = booke_wdt_ping,
259 .open = booke_wdt_open, 211 .set_timeout = booke_wdt_set_timeout,
260 .release = booke_wdt_release,
261}; 212};
262 213
263static struct miscdevice booke_wdt_miscdev = { 214static struct watchdog_device booke_wdt_dev = {
264 .minor = WATCHDOG_MINOR, 215 .info = &booke_wdt_info,
265 .name = "watchdog", 216 .ops = &booke_wdt_ops,
266 .fops = &booke_wdt_fops, 217 .min_timeout = 1,
218 .max_timeout = 0xFFFF
267}; 219};
268 220
269static void __exit booke_wdt_exit(void) 221static void __exit booke_wdt_exit(void)
270{ 222{
271 misc_deregister(&booke_wdt_miscdev); 223 watchdog_unregister_device(&booke_wdt_dev);
272} 224}
273 225
274static int __init booke_wdt_init(void) 226static int __init booke_wdt_init(void)
275{ 227{
276 int ret = 0; 228 int ret = 0;
229 bool nowayout = WATCHDOG_NOWAYOUT;
277 230
278 pr_info("powerpc book-e watchdog driver loaded\n"); 231 pr_info("powerpc book-e watchdog driver loaded\n");
279 ident.firmware_version = cur_cpu_spec->pvr_value; 232 booke_wdt_info.firmware_version = cur_cpu_spec->pvr_value;
280 233 booke_wdt_set_timeout(&booke_wdt_dev,
281 ret = misc_register(&booke_wdt_miscdev); 234 period_to_sec(CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT));
282 if (ret) { 235 watchdog_set_nowayout(&booke_wdt_dev, nowayout);
283 pr_err("cannot register device (minor=%u, ret=%i)\n", 236 if (booke_wdt_enabled)
284 WATCHDOG_MINOR, ret); 237 __booke_wdt_start(&booke_wdt_dev);
285 return ret; 238
286 } 239 ret = watchdog_register_device(&booke_wdt_dev);
287
288 spin_lock(&booke_wdt_lock);
289 if (booke_wdt_enabled == 1) {
290 pr_info("watchdog enabled (timeout = %llu sec)\n",
291 period_to_sec(booke_wdt_period));
292 on_each_cpu(__booke_wdt_enable, NULL, 0);
293 }
294 spin_unlock(&booke_wdt_lock);
295 240
296 return ret; 241 return ret;
297} 242}
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index e8e87246ea6d..7df1fdca9e78 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -69,7 +69,6 @@ static unsigned long wdt_status;
69#define WDT_REGION_INITED 2 69#define WDT_REGION_INITED 2
70#define WDT_DEVICE_INITED 3 70#define WDT_DEVICE_INITED 3
71 71
72static struct resource *wdt_mem;
73static void __iomem *wdt_base; 72static void __iomem *wdt_base;
74struct clk *wdt_clk; 73struct clk *wdt_clk;
75 74
@@ -201,10 +200,11 @@ static struct miscdevice davinci_wdt_miscdev = {
201 200
202static int davinci_wdt_probe(struct platform_device *pdev) 201static int davinci_wdt_probe(struct platform_device *pdev)
203{ 202{
204 int ret = 0, size; 203 int ret = 0;
205 struct device *dev = &pdev->dev; 204 struct device *dev = &pdev->dev;
205 struct resource *wdt_mem;
206 206
207 wdt_clk = clk_get(dev, NULL); 207 wdt_clk = devm_clk_get(dev, NULL);
208 if (WARN_ON(IS_ERR(wdt_clk))) 208 if (WARN_ON(IS_ERR(wdt_clk)))
209 return PTR_ERR(wdt_clk); 209 return PTR_ERR(wdt_clk);
210 210
@@ -221,43 +221,26 @@ static int davinci_wdt_probe(struct platform_device *pdev)
221 return -ENOENT; 221 return -ENOENT;
222 } 222 }
223 223
224 size = resource_size(wdt_mem); 224 wdt_base = devm_request_and_ioremap(dev, wdt_mem);
225 if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
226 dev_err(dev, "failed to get memory region\n");
227 return -ENOENT;
228 }
229
230 wdt_base = ioremap(wdt_mem->start, size);
231 if (!wdt_base) { 225 if (!wdt_base) {
232 dev_err(dev, "failed to map memory region\n"); 226 dev_err(dev, "ioremap failed\n");
233 release_mem_region(wdt_mem->start, size); 227 return -EADDRNOTAVAIL;
234 wdt_mem = NULL;
235 return -ENOMEM;
236 } 228 }
237 229
238 ret = misc_register(&davinci_wdt_miscdev); 230 ret = misc_register(&davinci_wdt_miscdev);
239 if (ret < 0) { 231 if (ret < 0) {
240 dev_err(dev, "cannot register misc device\n"); 232 dev_err(dev, "cannot register misc device\n");
241 release_mem_region(wdt_mem->start, size);
242 wdt_mem = NULL;
243 } else { 233 } else {
244 set_bit(WDT_DEVICE_INITED, &wdt_status); 234 set_bit(WDT_DEVICE_INITED, &wdt_status);
245 } 235 }
246 236
247 iounmap(wdt_base);
248 return ret; 237 return ret;
249} 238}
250 239
251static int davinci_wdt_remove(struct platform_device *pdev) 240static int davinci_wdt_remove(struct platform_device *pdev)
252{ 241{
253 misc_deregister(&davinci_wdt_miscdev); 242 misc_deregister(&davinci_wdt_miscdev);
254 if (wdt_mem) {
255 release_mem_region(wdt_mem->start, resource_size(wdt_mem));
256 wdt_mem = NULL;
257 }
258
259 clk_disable_unprepare(wdt_clk); 243 clk_disable_unprepare(wdt_clk);
260 clk_put(wdt_clk);
261 244
262 return 0; 245 return 0;
263} 246}
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c
index b9c5b58e59d3..257cfbad21da 100644
--- a/drivers/watchdog/gef_wdt.c
+++ b/drivers/watchdog/gef_wdt.c
@@ -310,6 +310,7 @@ static struct platform_driver gef_wdt_driver = {
310 .of_match_table = gef_wdt_ids, 310 .of_match_table = gef_wdt_ids,
311 }, 311 },
312 .probe = gef_wdt_probe, 312 .probe = gef_wdt_probe,
313 .remove = gef_wdt_remove,
313}; 314};
314 315
315static int __init gef_wdt_init(void) 316static int __init gef_wdt_init(void)
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index b0e541d022e6..af88ffd1068f 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -45,6 +45,11 @@
45 45
46#include "omap_wdt.h" 46#include "omap_wdt.h"
47 47
48static bool nowayout = WATCHDOG_NOWAYOUT;
49module_param(nowayout, bool, 0);
50MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
51 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
52
48static unsigned timer_margin; 53static unsigned timer_margin;
49module_param(timer_margin, uint, 0); 54module_param(timer_margin, uint, 0);
50MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); 55MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
@@ -201,7 +206,6 @@ static const struct watchdog_ops omap_wdt_ops = {
201static int omap_wdt_probe(struct platform_device *pdev) 206static int omap_wdt_probe(struct platform_device *pdev)
202{ 207{
203 struct omap_wd_timer_platform_data *pdata = pdev->dev.platform_data; 208 struct omap_wd_timer_platform_data *pdata = pdev->dev.platform_data;
204 bool nowayout = WATCHDOG_NOWAYOUT;
205 struct watchdog_device *omap_wdt; 209 struct watchdog_device *omap_wdt;
206 struct resource *res, *mem; 210 struct resource *res, *mem;
207 struct omap_wdt_dev *wdev; 211 struct omap_wdt_dev *wdev;
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 7c18b3bffcf7..da577980d390 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -140,6 +140,7 @@ static const struct watchdog_ops orion_wdt_ops = {
140static struct watchdog_device orion_wdt = { 140static struct watchdog_device orion_wdt = {
141 .info = &orion_wdt_info, 141 .info = &orion_wdt_info,
142 .ops = &orion_wdt_ops, 142 .ops = &orion_wdt_ops,
143 .min_timeout = 1,
143}; 144};
144 145
145static int orion_wdt_probe(struct platform_device *pdev) 146static int orion_wdt_probe(struct platform_device *pdev)
@@ -164,12 +165,9 @@ static int orion_wdt_probe(struct platform_device *pdev)
164 165
165 wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk; 166 wdt_max_duration = WDT_MAX_CYCLE_COUNT / wdt_tclk;
166 167
167 if ((heartbeat < 1) || (heartbeat > wdt_max_duration)) 168 orion_wdt.timeout = wdt_max_duration;
168 heartbeat = wdt_max_duration;
169
170 orion_wdt.timeout = heartbeat;
171 orion_wdt.min_timeout = 1;
172 orion_wdt.max_timeout = wdt_max_duration; 169 orion_wdt.max_timeout = wdt_max_duration;
170 watchdog_init_timeout(&orion_wdt, heartbeat, &pdev->dev);
173 171
174 watchdog_set_nowayout(&orion_wdt, nowayout); 172 watchdog_set_nowayout(&orion_wdt, nowayout);
175 ret = watchdog_register_device(&orion_wdt); 173 ret = watchdog_register_device(&orion_wdt);
@@ -179,7 +177,7 @@ static int orion_wdt_probe(struct platform_device *pdev)
179 } 177 }
180 178
181 pr_info("Initial timeout %d sec%s\n", 179 pr_info("Initial timeout %d sec%s\n",
182 heartbeat, nowayout ? ", nowayout" : ""); 180 orion_wdt.timeout, nowayout ? ", nowayout" : "");
183 return 0; 181 return 0;
184} 182}
185 183
@@ -225,4 +223,5 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
225 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 223 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
226 224
227MODULE_LICENSE("GPL"); 225MODULE_LICENSE("GPL");
226MODULE_ALIAS("platform:orion_wdt");
228MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 227MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index de1f3fa1d787..a3684a30eb69 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -142,6 +142,7 @@ static const struct watchdog_ops pnx4008_wdt_ops = {
142static struct watchdog_device pnx4008_wdd = { 142static struct watchdog_device pnx4008_wdd = {
143 .info = &pnx4008_wdt_ident, 143 .info = &pnx4008_wdt_ident,
144 .ops = &pnx4008_wdt_ops, 144 .ops = &pnx4008_wdt_ops,
145 .timeout = DEFAULT_HEARTBEAT,
145 .min_timeout = 1, 146 .min_timeout = 1,
146 .max_timeout = MAX_HEARTBEAT, 147 .max_timeout = MAX_HEARTBEAT,
147}; 148};
@@ -151,8 +152,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
151 struct resource *r; 152 struct resource *r;
152 int ret = 0; 153 int ret = 0;
153 154
154 if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) 155 watchdog_init_timeout(&pnx4008_wdd, heartbeat, &pdev->dev);
155 heartbeat = DEFAULT_HEARTBEAT;
156 156
157 r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 157 r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
158 wdt_base = devm_ioremap_resource(&pdev->dev, r); 158 wdt_base = devm_ioremap_resource(&pdev->dev, r);
@@ -167,7 +167,6 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
167 if (ret) 167 if (ret)
168 goto out; 168 goto out;
169 169
170 pnx4008_wdd.timeout = heartbeat;
171 pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ? 170 pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
172 WDIOF_CARDRESET : 0; 171 WDIOF_CARDRESET : 0;
173 watchdog_set_nowayout(&pnx4008_wdd, nowayout); 172 watchdog_set_nowayout(&pnx4008_wdd, nowayout);
@@ -181,7 +180,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
181 } 180 }
182 181
183 dev_info(&pdev->dev, "PNX4008 Watchdog Timer: heartbeat %d sec\n", 182 dev_info(&pdev->dev, "PNX4008 Watchdog Timer: heartbeat %d sec\n",
184 heartbeat); 183 pnx4008_wdd.timeout);
185 184
186 return 0; 185 return 0;
187 186
diff --git a/drivers/watchdog/retu_wdt.c b/drivers/watchdog/retu_wdt.c
new file mode 100644
index 000000000000..f53615dc633d
--- /dev/null
+++ b/drivers/watchdog/retu_wdt.c
@@ -0,0 +1,178 @@
1/*
2 * Retu watchdog driver
3 *
4 * Copyright (C) 2004, 2005 Nokia Corporation
5 *
6 * Based on code written by Amit Kucheria and Michael Buesch.
7 * Rewritten by Aaro Koskinen.
8 *
9 * This file is subject to the terms and conditions of the GNU General
10 * Public License. See the file "COPYING" in the main directory of this
11 * archive for more details.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/errno.h>
22#include <linux/device.h>
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/mfd/retu.h>
26#include <linux/watchdog.h>
27#include <linux/platform_device.h>
28
29/* Watchdog timer values in seconds */
30#define RETU_WDT_MAX_TIMER 63
31
32struct retu_wdt_dev {
33 struct retu_dev *rdev;
34 struct device *dev;
35 struct delayed_work ping_work;
36};
37
38/*
39 * Since Retu watchdog cannot be disabled in hardware, we must kick it
40 * with a timer until userspace watchdog software takes over. If
41 * CONFIG_WATCHDOG_NOWAYOUT is set, we never start the feeding.
42 */
43static void retu_wdt_ping_enable(struct retu_wdt_dev *wdev)
44{
45 retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER);
46 schedule_delayed_work(&wdev->ping_work,
47 round_jiffies_relative(RETU_WDT_MAX_TIMER * HZ / 2));
48}
49
50static void retu_wdt_ping_disable(struct retu_wdt_dev *wdev)
51{
52 retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER);
53 cancel_delayed_work_sync(&wdev->ping_work);
54}
55
56static void retu_wdt_ping_work(struct work_struct *work)
57{
58 struct retu_wdt_dev *wdev = container_of(to_delayed_work(work),
59 struct retu_wdt_dev, ping_work);
60 retu_wdt_ping_enable(wdev);
61}
62
63static int retu_wdt_start(struct watchdog_device *wdog)
64{
65 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
66
67 retu_wdt_ping_disable(wdev);
68
69 return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
70}
71
72static int retu_wdt_stop(struct watchdog_device *wdog)
73{
74 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
75
76 retu_wdt_ping_enable(wdev);
77
78 return 0;
79}
80
81static int retu_wdt_ping(struct watchdog_device *wdog)
82{
83 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
84
85 return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
86}
87
88static int retu_wdt_set_timeout(struct watchdog_device *wdog,
89 unsigned int timeout)
90{
91 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
92
93 wdog->timeout = timeout;
94 return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
95}
96
97static const struct watchdog_info retu_wdt_info = {
98 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
99 .identity = "Retu watchdog",
100};
101
102static const struct watchdog_ops retu_wdt_ops = {
103 .owner = THIS_MODULE,
104 .start = retu_wdt_start,
105 .stop = retu_wdt_stop,
106 .ping = retu_wdt_ping,
107 .set_timeout = retu_wdt_set_timeout,
108};
109
110static int retu_wdt_probe(struct platform_device *pdev)
111{
112 struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent);
113 bool nowayout = WATCHDOG_NOWAYOUT;
114 struct watchdog_device *retu_wdt;
115 struct retu_wdt_dev *wdev;
116 int ret;
117
118 retu_wdt = devm_kzalloc(&pdev->dev, sizeof(*retu_wdt), GFP_KERNEL);
119 if (!retu_wdt)
120 return -ENOMEM;
121
122 wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
123 if (!wdev)
124 return -ENOMEM;
125
126 retu_wdt->info = &retu_wdt_info;
127 retu_wdt->ops = &retu_wdt_ops;
128 retu_wdt->timeout = RETU_WDT_MAX_TIMER;
129 retu_wdt->min_timeout = 0;
130 retu_wdt->max_timeout = RETU_WDT_MAX_TIMER;
131
132 watchdog_set_drvdata(retu_wdt, wdev);
133 watchdog_set_nowayout(retu_wdt, nowayout);
134
135 wdev->rdev = rdev;
136 wdev->dev = &pdev->dev;
137
138 INIT_DELAYED_WORK(&wdev->ping_work, retu_wdt_ping_work);
139
140 ret = watchdog_register_device(retu_wdt);
141 if (ret < 0)
142 return ret;
143
144 if (nowayout)
145 retu_wdt_ping(retu_wdt);
146 else
147 retu_wdt_ping_enable(wdev);
148
149 platform_set_drvdata(pdev, retu_wdt);
150
151 return 0;
152}
153
154static int retu_wdt_remove(struct platform_device *pdev)
155{
156 struct watchdog_device *wdog = platform_get_drvdata(pdev);
157 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
158
159 watchdog_unregister_device(wdog);
160 cancel_delayed_work_sync(&wdev->ping_work);
161
162 return 0;
163}
164
165static struct platform_driver retu_wdt_driver = {
166 .probe = retu_wdt_probe,
167 .remove = retu_wdt_remove,
168 .driver = {
169 .name = "retu-wdt",
170 },
171};
172module_platform_driver(retu_wdt_driver);
173
174MODULE_ALIAS("platform:retu-wdt");
175MODULE_DESCRIPTION("Retu watchdog");
176MODULE_AUTHOR("Amit Kucheria");
177MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
178MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 27bcd4e2c4a4..c1a221cbeae4 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -53,7 +53,7 @@
53#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) 53#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
54 54
55static bool nowayout = WATCHDOG_NOWAYOUT; 55static bool nowayout = WATCHDOG_NOWAYOUT;
56static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME; 56static int tmr_margin;
57static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; 57static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
58static int soft_noboot; 58static int soft_noboot;
59static int debug; 59static int debug;
@@ -226,6 +226,7 @@ static struct watchdog_ops s3c2410wdt_ops = {
226static struct watchdog_device s3c2410_wdd = { 226static struct watchdog_device s3c2410_wdd = {
227 .info = &s3c2410_wdt_ident, 227 .info = &s3c2410_wdt_ident,
228 .ops = &s3c2410wdt_ops, 228 .ops = &s3c2410wdt_ops,
229 .timeout = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME,
229}; 230};
230 231
231/* interrupt handler code */ 232/* interrupt handler code */
@@ -309,7 +310,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
309 unsigned int wtcon; 310 unsigned int wtcon;
310 int started = 0; 311 int started = 0;
311 int ret; 312 int ret;
312 int size;
313 313
314 DBG("%s: probe=%p\n", __func__, pdev); 314 DBG("%s: probe=%p\n", __func__, pdev);
315 315
@@ -330,28 +330,20 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
330 } 330 }
331 331
332 /* get the memory region for the watchdog timer */ 332 /* get the memory region for the watchdog timer */
333 333 wdt_base = devm_request_and_ioremap(dev, wdt_mem);
334 size = resource_size(wdt_mem);
335 if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
336 dev_err(dev, "failed to get memory region\n");
337 ret = -EBUSY;
338 goto err;
339 }
340
341 wdt_base = ioremap(wdt_mem->start, size);
342 if (wdt_base == NULL) { 334 if (wdt_base == NULL) {
343 dev_err(dev, "failed to ioremap() region\n"); 335 dev_err(dev, "failed to devm_request_and_ioremap() region\n");
344 ret = -EINVAL; 336 ret = -ENOMEM;
345 goto err_req; 337 goto err;
346 } 338 }
347 339
348 DBG("probe: mapped wdt_base=%p\n", wdt_base); 340 DBG("probe: mapped wdt_base=%p\n", wdt_base);
349 341
350 wdt_clock = clk_get(&pdev->dev, "watchdog"); 342 wdt_clock = devm_clk_get(dev, "watchdog");
351 if (IS_ERR(wdt_clock)) { 343 if (IS_ERR(wdt_clock)) {
352 dev_err(dev, "failed to find watchdog clock source\n"); 344 dev_err(dev, "failed to find watchdog clock source\n");
353 ret = PTR_ERR(wdt_clock); 345 ret = PTR_ERR(wdt_clock);
354 goto err_map; 346 goto err;
355 } 347 }
356 348
357 clk_prepare_enable(wdt_clock); 349 clk_prepare_enable(wdt_clock);
@@ -365,7 +357,8 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
365 /* see if we can actually set the requested timer margin, and if 357 /* see if we can actually set the requested timer margin, and if
366 * not, try the default value */ 358 * not, try the default value */
367 359
368 if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, tmr_margin)) { 360 watchdog_init_timeout(&s3c2410_wdd, tmr_margin, &pdev->dev);
361 if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout)) {
369 started = s3c2410wdt_set_heartbeat(&s3c2410_wdd, 362 started = s3c2410wdt_set_heartbeat(&s3c2410_wdd,
370 CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); 363 CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
371 364
@@ -378,7 +371,8 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
378 "cannot start\n"); 371 "cannot start\n");
379 } 372 }
380 373
381 ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev); 374 ret = devm_request_irq(dev, wdt_irq->start, s3c2410wdt_irq, 0,
375 pdev->name, pdev);
382 if (ret != 0) { 376 if (ret != 0) {
383 dev_err(dev, "failed to install irq (%d)\n", ret); 377 dev_err(dev, "failed to install irq (%d)\n", ret);
384 goto err_cpufreq; 378 goto err_cpufreq;
@@ -389,7 +383,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
389 ret = watchdog_register_device(&s3c2410_wdd); 383 ret = watchdog_register_device(&s3c2410_wdd);
390 if (ret) { 384 if (ret) {
391 dev_err(dev, "cannot register watchdog (%d)\n", ret); 385 dev_err(dev, "cannot register watchdog (%d)\n", ret);
392 goto err_irq; 386 goto err_cpufreq;
393 } 387 }
394 388
395 if (tmr_atboot && started == 0) { 389 if (tmr_atboot && started == 0) {
@@ -414,23 +408,13 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
414 408
415 return 0; 409 return 0;
416 410
417 err_irq:
418 free_irq(wdt_irq->start, pdev);
419
420 err_cpufreq: 411 err_cpufreq:
421 s3c2410wdt_cpufreq_deregister(); 412 s3c2410wdt_cpufreq_deregister();
422 413
423 err_clk: 414 err_clk:
424 clk_disable_unprepare(wdt_clock); 415 clk_disable_unprepare(wdt_clock);
425 clk_put(wdt_clock);
426 wdt_clock = NULL; 416 wdt_clock = NULL;
427 417
428 err_map:
429 iounmap(wdt_base);
430
431 err_req:
432 release_mem_region(wdt_mem->start, size);
433
434 err: 418 err:
435 wdt_irq = NULL; 419 wdt_irq = NULL;
436 wdt_mem = NULL; 420 wdt_mem = NULL;
@@ -441,17 +425,11 @@ static int s3c2410wdt_remove(struct platform_device *dev)
441{ 425{
442 watchdog_unregister_device(&s3c2410_wdd); 426 watchdog_unregister_device(&s3c2410_wdd);
443 427
444 free_irq(wdt_irq->start, dev);
445
446 s3c2410wdt_cpufreq_deregister(); 428 s3c2410wdt_cpufreq_deregister();
447 429
448 clk_disable_unprepare(wdt_clock); 430 clk_disable_unprepare(wdt_clock);
449 clk_put(wdt_clock);
450 wdt_clock = NULL; 431 wdt_clock = NULL;
451 432
452 iounmap(wdt_base);
453
454 release_mem_region(wdt_mem->start, resource_size(wdt_mem));
455 wdt_irq = NULL; 433 wdt_irq = NULL;
456 wdt_mem = NULL; 434 wdt_mem = NULL;
457 return 0; 435 return 0;
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index 2b0e000d4377..e3b8f757d2d3 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -361,7 +361,7 @@ static unsigned char sp5100_tco_setupdevice(void)
361{ 361{
362 struct pci_dev *dev = NULL; 362 struct pci_dev *dev = NULL;
363 const char *dev_name = NULL; 363 const char *dev_name = NULL;
364 u32 val; 364 u32 val, tmp_val;
365 u32 index_reg, data_reg, base_addr; 365 u32 index_reg, data_reg, base_addr;
366 366
367 /* Match the PCI device */ 367 /* Match the PCI device */
@@ -497,30 +497,19 @@ static unsigned char sp5100_tco_setupdevice(void)
497 pr_debug("Got 0x%04x from resource tree\n", val); 497 pr_debug("Got 0x%04x from resource tree\n", val);
498 } 498 }
499 499
500 /* Restore to the low three bits, if chipset is SB8x0(or later) */ 500 /* Restore to the low three bits */
501 if (sp5100_tco_pci->revision >= 0x40) { 501 outb(base_addr+0, index_reg);
502 u8 reserved_bit; 502 tmp_val = val | (inb(data_reg) & 0x7);
503 reserved_bit = inb(base_addr) & 0x7;
504 val |= (u32)reserved_bit;
505 }
506 503
507 /* Re-programming the watchdog timer base address */ 504 /* Re-programming the watchdog timer base address */
508 outb(base_addr+0, index_reg); 505 outb(base_addr+0, index_reg);
509 /* Low three bits of BASE are reserved */ 506 outb((tmp_val >> 0) & 0xff, data_reg);
510 outb((val >> 0) & 0xf8, data_reg);
511 outb(base_addr+1, index_reg); 507 outb(base_addr+1, index_reg);
512 outb((val >> 8) & 0xff, data_reg); 508 outb((tmp_val >> 8) & 0xff, data_reg);
513 outb(base_addr+2, index_reg); 509 outb(base_addr+2, index_reg);
514 outb((val >> 16) & 0xff, data_reg); 510 outb((tmp_val >> 16) & 0xff, data_reg);
515 outb(base_addr+3, index_reg); 511 outb(base_addr+3, index_reg);
516 outb((val >> 24) & 0xff, data_reg); 512 outb((tmp_val >> 24) & 0xff, data_reg);
517
518 /*
519 * Clear unnecessary the low three bits,
520 * if chipset is SB8x0(or later)
521 */
522 if (sp5100_tco_pci->revision >= 0x40)
523 val &= ~0x7;
524 513
525 if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, 514 if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
526 dev_name)) { 515 dev_name)) {
diff --git a/drivers/watchdog/stmp3xxx_rtc_wdt.c b/drivers/watchdog/stmp3xxx_rtc_wdt.c
new file mode 100644
index 000000000000..c97e98dcde62
--- /dev/null
+++ b/drivers/watchdog/stmp3xxx_rtc_wdt.c
@@ -0,0 +1,111 @@
1/*
2 * Watchdog driver for the RTC based watchdog in STMP3xxx and i.MX23/28
3 *
4 * Author: Wolfram Sang <w.sang@pengutronix.de>
5 *
6 * Copyright (C) 2011-12 Wolfram Sang, Pengutronix
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 */
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/miscdevice.h>
16#include <linux/watchdog.h>
17#include <linux/platform_device.h>
18#include <linux/stmp3xxx_rtc_wdt.h>
19
20#define WDOG_TICK_RATE 1000 /* 1 kHz clock */
21#define STMP3XXX_DEFAULT_TIMEOUT 19
22#define STMP3XXX_MAX_TIMEOUT (UINT_MAX / WDOG_TICK_RATE)
23
24static int heartbeat = STMP3XXX_DEFAULT_TIMEOUT;
25module_param(heartbeat, uint, 0);
26MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat period in seconds from 1 to "
27 __MODULE_STRING(STMP3XXX_MAX_TIMEOUT) ", default "
28 __MODULE_STRING(STMP3XXX_DEFAULT_TIMEOUT));
29
30static int wdt_start(struct watchdog_device *wdd)
31{
32 struct device *dev = watchdog_get_drvdata(wdd);
33 struct stmp3xxx_wdt_pdata *pdata = dev->platform_data;
34
35 pdata->wdt_set_timeout(dev->parent, wdd->timeout * WDOG_TICK_RATE);
36 return 0;
37}
38
39static int wdt_stop(struct watchdog_device *wdd)
40{
41 struct device *dev = watchdog_get_drvdata(wdd);
42 struct stmp3xxx_wdt_pdata *pdata = dev->platform_data;
43
44 pdata->wdt_set_timeout(dev->parent, 0);
45 return 0;
46}
47
48static int wdt_set_timeout(struct watchdog_device *wdd, unsigned new_timeout)
49{
50 wdd->timeout = new_timeout;
51 return wdt_start(wdd);
52}
53
54static const struct watchdog_info stmp3xxx_wdt_ident = {
55 .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
56 .identity = "STMP3XXX RTC Watchdog",
57};
58
59static const struct watchdog_ops stmp3xxx_wdt_ops = {
60 .owner = THIS_MODULE,
61 .start = wdt_start,
62 .stop = wdt_stop,
63 .set_timeout = wdt_set_timeout,
64};
65
66static struct watchdog_device stmp3xxx_wdd = {
67 .info = &stmp3xxx_wdt_ident,
68 .ops = &stmp3xxx_wdt_ops,
69 .min_timeout = 1,
70 .max_timeout = STMP3XXX_MAX_TIMEOUT,
71 .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
72};
73
74static int stmp3xxx_wdt_probe(struct platform_device *pdev)
75{
76 int ret;
77
78 watchdog_set_drvdata(&stmp3xxx_wdd, &pdev->dev);
79
80 stmp3xxx_wdd.timeout = clamp_t(unsigned, heartbeat, 1, STMP3XXX_MAX_TIMEOUT);
81
82 ret = watchdog_register_device(&stmp3xxx_wdd);
83 if (ret < 0) {
84 dev_err(&pdev->dev, "cannot register watchdog device\n");
85 return ret;
86 }
87
88 dev_info(&pdev->dev, "initialized watchdog with heartbeat %ds\n",
89 stmp3xxx_wdd.timeout);
90 return 0;
91}
92
93static int stmp3xxx_wdt_remove(struct platform_device *pdev)
94{
95 watchdog_unregister_device(&stmp3xxx_wdd);
96 return 0;
97}
98
99static struct platform_driver stmp3xxx_wdt_driver = {
100 .driver = {
101 .name = "stmp3xxx_rtc_wdt",
102 },
103 .probe = stmp3xxx_wdt_probe,
104 .remove = stmp3xxx_wdt_remove,
105};
106module_platform_driver(stmp3xxx_wdt_driver);
107
108MODULE_DESCRIPTION("STMP3XXX RTC Watchdog Driver");
109MODULE_LICENSE("GPL v2");
110MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
111MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c
deleted file mode 100644
index 1f4f69728fee..000000000000
--- a/drivers/watchdog/stmp3xxx_wdt.c
+++ /dev/null
@@ -1,288 +0,0 @@
1/*
2 * Watchdog driver for Freescale STMP37XX/STMP378X
3 *
4 * Author: Vitaly Wool <vital@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12#include <linux/init.h>
13#include <linux/kernel.h>
14#include <linux/fs.h>
15#include <linux/miscdevice.h>
16#include <linux/watchdog.h>
17#include <linux/platform_device.h>
18#include <linux/spinlock.h>
19#include <linux/uaccess.h>
20#include <linux/module.h>
21
22#include <mach/platform.h>
23#include <mach/regs-rtc.h>
24
25#define DEFAULT_HEARTBEAT 19
26#define MAX_HEARTBEAT (0x10000000 >> 6)
27
28/* missing bitmask in headers */
29#define BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER 0x80000000
30
31#define WDT_IN_USE 0
32#define WDT_OK_TO_CLOSE 1
33
34#define WDOG_COUNTER_RATE 1000 /* 1 kHz clock */
35
36static DEFINE_SPINLOCK(stmp3xxx_wdt_io_lock);
37static unsigned long wdt_status;
38static const bool nowayout = WATCHDOG_NOWAYOUT;
39static int heartbeat = DEFAULT_HEARTBEAT;
40static unsigned long boot_status;
41
42static void wdt_enable(u32 value)
43{
44 spin_lock(&stmp3xxx_wdt_io_lock);
45 __raw_writel(value, REGS_RTC_BASE + HW_RTC_WATCHDOG);
46 stmp3xxx_setl(BM_RTC_CTRL_WATCHDOGEN, REGS_RTC_BASE + HW_RTC_CTRL);
47 stmp3xxx_setl(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER,
48 REGS_RTC_BASE + HW_RTC_PERSISTENT1);
49 spin_unlock(&stmp3xxx_wdt_io_lock);
50}
51
52static void wdt_disable(void)
53{
54 spin_lock(&stmp3xxx_wdt_io_lock);
55 stmp3xxx_clearl(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER,
56 REGS_RTC_BASE + HW_RTC_PERSISTENT1);
57 stmp3xxx_clearl(BM_RTC_CTRL_WATCHDOGEN, REGS_RTC_BASE + HW_RTC_CTRL);
58 spin_unlock(&stmp3xxx_wdt_io_lock);
59}
60
61static void wdt_ping(void)
62{
63 wdt_enable(heartbeat * WDOG_COUNTER_RATE);
64}
65
66static int stmp3xxx_wdt_open(struct inode *inode, struct file *file)
67{
68 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
69 return -EBUSY;
70
71 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
72 wdt_ping();
73
74 return nonseekable_open(inode, file);
75}
76
77static ssize_t stmp3xxx_wdt_write(struct file *file, const char __user *data,
78 size_t len, loff_t *ppos)
79{
80 if (len) {
81 if (!nowayout) {
82 size_t i;
83
84 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
85
86 for (i = 0; i != len; i++) {
87 char c;
88
89 if (get_user(c, data + i))
90 return -EFAULT;
91 if (c == 'V')
92 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
93 }
94 }
95 wdt_ping();
96 }
97
98 return len;
99}
100
101static const struct watchdog_info ident = {
102 .options = WDIOF_CARDRESET |
103 WDIOF_MAGICCLOSE |
104 WDIOF_SETTIMEOUT |
105 WDIOF_KEEPALIVEPING,
106 .identity = "STMP3XXX Watchdog",
107};
108
109static long stmp3xxx_wdt_ioctl(struct file *file, unsigned int cmd,
110 unsigned long arg)
111{
112 void __user *argp = (void __user *)arg;
113 int __user *p = argp;
114 int new_heartbeat, opts;
115 int ret = -ENOTTY;
116
117 switch (cmd) {
118 case WDIOC_GETSUPPORT:
119 ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
120 break;
121
122 case WDIOC_GETSTATUS:
123 ret = put_user(0, p);
124 break;
125
126 case WDIOC_GETBOOTSTATUS:
127 ret = put_user(boot_status, p);
128 break;
129
130 case WDIOC_SETOPTIONS:
131 if (get_user(opts, p)) {
132 ret = -EFAULT;
133 break;
134 }
135 if (opts & WDIOS_DISABLECARD)
136 wdt_disable();
137 else if (opts & WDIOS_ENABLECARD)
138 wdt_ping();
139 else {
140 pr_debug("%s: unknown option 0x%x\n", __func__, opts);
141 ret = -EINVAL;
142 break;
143 }
144 ret = 0;
145 break;
146
147 case WDIOC_KEEPALIVE:
148 wdt_ping();
149 ret = 0;
150 break;
151
152 case WDIOC_SETTIMEOUT:
153 if (get_user(new_heartbeat, p)) {
154 ret = -EFAULT;
155 break;
156 }
157 if (new_heartbeat <= 0 || new_heartbeat > MAX_HEARTBEAT) {
158 ret = -EINVAL;
159 break;
160 }
161
162 heartbeat = new_heartbeat;
163 wdt_ping();
164 /* Fall through */
165
166 case WDIOC_GETTIMEOUT:
167 ret = put_user(heartbeat, p);
168 break;
169 }
170 return ret;
171}
172
173static int stmp3xxx_wdt_release(struct inode *inode, struct file *file)
174{
175 int ret = 0;
176
177 if (!nowayout) {
178 if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
179 wdt_ping();
180 pr_debug("%s: Device closed unexpectedly\n", __func__);
181 ret = -EINVAL;
182 } else {
183 wdt_disable();
184 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
185 }
186 }
187 clear_bit(WDT_IN_USE, &wdt_status);
188
189 return ret;
190}
191
192static const struct file_operations stmp3xxx_wdt_fops = {
193 .owner = THIS_MODULE,
194 .llseek = no_llseek,
195 .write = stmp3xxx_wdt_write,
196 .unlocked_ioctl = stmp3xxx_wdt_ioctl,
197 .open = stmp3xxx_wdt_open,
198 .release = stmp3xxx_wdt_release,
199};
200
201static struct miscdevice stmp3xxx_wdt_miscdev = {
202 .minor = WATCHDOG_MINOR,
203 .name = "watchdog",
204 .fops = &stmp3xxx_wdt_fops,
205};
206
207static int stmp3xxx_wdt_probe(struct platform_device *pdev)
208{
209 int ret = 0;
210
211 if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
212 heartbeat = DEFAULT_HEARTBEAT;
213
214 boot_status = __raw_readl(REGS_RTC_BASE + HW_RTC_PERSISTENT1) &
215 BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER;
216 boot_status = !!boot_status;
217 stmp3xxx_clearl(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER,
218 REGS_RTC_BASE + HW_RTC_PERSISTENT1);
219 wdt_disable(); /* disable for now */
220
221 ret = misc_register(&stmp3xxx_wdt_miscdev);
222 if (ret < 0) {
223 dev_err(&pdev->dev, "cannot register misc device\n");
224 return ret;
225 }
226
227 pr_info("initialized, heartbeat %d sec\n", heartbeat);
228
229 return ret;
230}
231
232static int stmp3xxx_wdt_remove(struct platform_device *pdev)
233{
234 misc_deregister(&stmp3xxx_wdt_miscdev);
235 return 0;
236}
237
238#ifdef CONFIG_PM
239static int wdt_suspended;
240static u32 wdt_saved_time;
241
242static int stmp3xxx_wdt_suspend(struct platform_device *pdev,
243 pm_message_t state)
244{
245 if (__raw_readl(REGS_RTC_BASE + HW_RTC_CTRL) &
246 BM_RTC_CTRL_WATCHDOGEN) {
247 wdt_suspended = 1;
248 wdt_saved_time = __raw_readl(REGS_RTC_BASE + HW_RTC_WATCHDOG);
249 wdt_disable();
250 }
251 return 0;
252}
253
254static int stmp3xxx_wdt_resume(struct platform_device *pdev)
255{
256 if (wdt_suspended) {
257 wdt_enable(wdt_saved_time);
258 wdt_suspended = 0;
259 }
260 return 0;
261}
262#else
263#define stmp3xxx_wdt_suspend NULL
264#define stmp3xxx_wdt_resume NULL
265#endif
266
267static struct platform_driver platform_wdt_driver = {
268 .driver = {
269 .name = "stmp3xxx_wdt",
270 },
271 .probe = stmp3xxx_wdt_probe,
272 .remove = stmp3xxx_wdt_remove,
273 .suspend = stmp3xxx_wdt_suspend,
274 .resume = stmp3xxx_wdt_resume,
275};
276
277module_platform_driver(platform_wdt_driver);
278
279MODULE_DESCRIPTION("STMP3XXX Watchdog Driver");
280MODULE_LICENSE("GPL");
281
282module_param(heartbeat, int, 0);
283MODULE_PARM_DESC(heartbeat,
284 "Watchdog heartbeat period in seconds from 1 to "
285 __MODULE_STRING(MAX_HEARTBEAT) ", default "
286 __MODULE_STRING(DEFAULT_HEARTBEAT));
287
288MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c
index 3796434991fa..05d18b4c661b 100644
--- a/drivers/watchdog/watchdog_core.c
+++ b/drivers/watchdog/watchdog_core.c
@@ -36,12 +36,68 @@
36#include <linux/init.h> /* For __init/__exit/... */ 36#include <linux/init.h> /* For __init/__exit/... */
37#include <linux/idr.h> /* For ida_* macros */ 37#include <linux/idr.h> /* For ida_* macros */
38#include <linux/err.h> /* For IS_ERR macros */ 38#include <linux/err.h> /* For IS_ERR macros */
39#include <linux/of.h> /* For of_get_timeout_sec */
39 40
40#include "watchdog_core.h" /* For watchdog_dev_register/... */ 41#include "watchdog_core.h" /* For watchdog_dev_register/... */
41 42
42static DEFINE_IDA(watchdog_ida); 43static DEFINE_IDA(watchdog_ida);
43static struct class *watchdog_class; 44static struct class *watchdog_class;
44 45
46static void watchdog_check_min_max_timeout(struct watchdog_device *wdd)
47{
48 /*
49 * Check that we have valid min and max timeout values, if
50 * not reset them both to 0 (=not used or unknown)
51 */
52 if (wdd->min_timeout > wdd->max_timeout) {
53 pr_info("Invalid min and max timeout values, resetting to 0!\n");
54 wdd->min_timeout = 0;
55 wdd->max_timeout = 0;
56 }
57}
58
59/**
60 * watchdog_init_timeout() - initialize the timeout field
61 * @timeout_parm: timeout module parameter
62 * @dev: Device that stores the timeout-sec property
63 *
64 * Initialize the timeout field of the watchdog_device struct with either the
65 * timeout module parameter (if it is valid value) or the timeout-sec property
66 * (only if it is a valid value and the timeout_parm is out of bounds).
67 * If none of them are valid then we keep the old value (which should normally
68 * be the default timeout value.
69 *
70 * A zero is returned on success and -EINVAL for failure.
71 */
72int watchdog_init_timeout(struct watchdog_device *wdd,
73 unsigned int timeout_parm, struct device *dev)
74{
75 unsigned int t = 0;
76 int ret = 0;
77
78 watchdog_check_min_max_timeout(wdd);
79
80 /* try to get the tiemout module parameter first */
81 if (!watchdog_timeout_invalid(wdd, timeout_parm)) {
82 wdd->timeout = timeout_parm;
83 return ret;
84 }
85 if (timeout_parm)
86 ret = -EINVAL;
87
88 /* try to get the timeout_sec property */
89 if (dev == NULL || dev->of_node == NULL)
90 return ret;
91 of_property_read_u32(dev->of_node, "timeout-sec", &t);
92 if (!watchdog_timeout_invalid(wdd, t))
93 wdd->timeout = t;
94 else
95 ret = -EINVAL;
96
97 return ret;
98}
99EXPORT_SYMBOL_GPL(watchdog_init_timeout);
100
45/** 101/**
46 * watchdog_register_device() - register a watchdog device 102 * watchdog_register_device() - register a watchdog device
47 * @wdd: watchdog device 103 * @wdd: watchdog device
@@ -63,15 +119,7 @@ int watchdog_register_device(struct watchdog_device *wdd)
63 if (wdd->ops->start == NULL || wdd->ops->stop == NULL) 119 if (wdd->ops->start == NULL || wdd->ops->stop == NULL)
64 return -EINVAL; 120 return -EINVAL;
65 121
66 /* 122 watchdog_check_min_max_timeout(wdd);
67 * Check that we have valid min and max timeout values, if
68 * not reset them both to 0 (=not used or unknown)
69 */
70 if (wdd->min_timeout > wdd->max_timeout) {
71 pr_info("Invalid min and max timeout values, resetting to 0!\n");
72 wdd->min_timeout = 0;
73 wdd->max_timeout = 0;
74 }
75 123
76 /* 124 /*
77 * Note: now that all watchdog_device data has been verified, we 125 * Note: now that all watchdog_device data has been verified, we
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index ef8edecfc526..08b48bbf9f4b 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -200,8 +200,7 @@ static int watchdog_set_timeout(struct watchdog_device *wddev,
200 !(wddev->info->options & WDIOF_SETTIMEOUT)) 200 !(wddev->info->options & WDIOF_SETTIMEOUT))
201 return -EOPNOTSUPP; 201 return -EOPNOTSUPP;
202 202
203 if ((wddev->max_timeout != 0) && 203 if (watchdog_timeout_invalid(wddev, timeout))
204 (timeout < wddev->min_timeout || timeout > wddev->max_timeout))
205 return -EINVAL; 204 return -EINVAL;
206 205
207 mutex_lock(&wddev->lock); 206 mutex_lock(&wddev->lock);
diff --git a/include/linux/bcm47xx_wdt.h b/include/linux/bcm47xx_wdt.h
index e5dfc256485b..b708786d4cbf 100644
--- a/include/linux/bcm47xx_wdt.h
+++ b/include/linux/bcm47xx_wdt.h
@@ -1,7 +1,10 @@
1#ifndef LINUX_BCM47XX_WDT_H_ 1#ifndef LINUX_BCM47XX_WDT_H_
2#define LINUX_BCM47XX_WDT_H_ 2#define LINUX_BCM47XX_WDT_H_
3 3
4#include <linux/notifier.h>
5#include <linux/timer.h>
4#include <linux/types.h> 6#include <linux/types.h>
7#include <linux/watchdog.h>
5 8
6 9
7struct bcm47xx_wdt { 10struct bcm47xx_wdt {
@@ -10,6 +13,12 @@ struct bcm47xx_wdt {
10 u32 max_timer_ms; 13 u32 max_timer_ms;
11 14
12 void *driver_data; 15 void *driver_data;
16
17 struct watchdog_device wdd;
18 struct notifier_block notifier;
19
20 struct timer_list soft_timer;
21 atomic_t soft_ticks;
13}; 22};
14 23
15static inline void *bcm47xx_wdt_get_drvdata(struct bcm47xx_wdt *wdt) 24static inline void *bcm47xx_wdt_get_drvdata(struct bcm47xx_wdt *wdt)
diff --git a/include/linux/stmp3xxx_rtc_wdt.h b/include/linux/stmp3xxx_rtc_wdt.h
new file mode 100644
index 000000000000..1dd12c96231b
--- /dev/null
+++ b/include/linux/stmp3xxx_rtc_wdt.h
@@ -0,0 +1,15 @@
1/*
2 * stmp3xxx_rtc_wdt.h
3 *
4 * Copyright (C) 2011 Wolfram Sang, Pengutronix e.K.
5 *
6 * This file is released under the GPLv2.
7 */
8#ifndef __LINUX_STMP3XXX_RTC_WDT_H
9#define __LINUX_STMP3XXX_RTC_WDT_H
10
11struct stmp3xxx_wdt_pdata {
12 void (*wdt_set_timeout)(struct device *dev, u32 timeout);
13};
14
15#endif /* __LINUX_STMP3XXX_RTC_WDT_H */
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 3a9df2f43be6..2a3038ee17a3 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -118,6 +118,13 @@ static inline void watchdog_set_nowayout(struct watchdog_device *wdd, bool noway
118 set_bit(WDOG_NO_WAY_OUT, &wdd->status); 118 set_bit(WDOG_NO_WAY_OUT, &wdd->status);
119} 119}
120 120
121/* Use the following function to check if a timeout value is invalid */
122static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t)
123{
124 return ((wdd->max_timeout != 0) &&
125 (t < wdd->min_timeout || t > wdd->max_timeout));
126}
127
121/* Use the following functions to manipulate watchdog driver specific data */ 128/* Use the following functions to manipulate watchdog driver specific data */
122static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) 129static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data)
123{ 130{
@@ -130,6 +137,8 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd)
130} 137}
131 138
132/* drivers/watchdog/watchdog_core.c */ 139/* drivers/watchdog/watchdog_core.c */
140extern int watchdog_init_timeout(struct watchdog_device *wdd,
141 unsigned int timeout_parm, struct device *dev);
133extern int watchdog_register_device(struct watchdog_device *); 142extern int watchdog_register_device(struct watchdog_device *);
134extern void watchdog_unregister_device(struct watchdog_device *); 143extern void watchdog_unregister_device(struct watchdog_device *);
135 144