aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@linux.intel.com>2013-04-20 12:16:44 -0400
committerH. Peter Anvin <hpa@linux.intel.com>2013-04-20 12:16:44 -0400
commitf53f292eeaa234615c31a1306babe703fc4263f2 (patch)
tree707b0933a20f7dc05495e974243a23b5c9f8c918 /drivers/watchdog
parent15b9c359f288b09003cb70f7ed204affc0c6614d (diff)
parenta9499fa7cd3fd4824a7202d00c766b269fa3bda6 (diff)
Merge remote-tracking branch 'efi/chainsaw' into x86/efi
Resolved Conflicts: drivers/firmware/efivars.c fs/efivarsfs/file.c Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig47
-rw-r--r--drivers/watchdog/Makefile4
-rw-r--r--drivers/watchdog/ar7_wdt.c8
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c12
-rw-r--r--drivers/watchdog/at91rm9200_wdt.c9
-rw-r--r--drivers/watchdog/at91sam9_wdt.c181
-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/coh901327_wdt.c12
-rw-r--r--drivers/watchdog/cpwd.c4
-rw-r--r--drivers/watchdog/davinci_wdt.c29
-rw-r--r--drivers/watchdog/dw_wdt.c6
-rw-r--r--drivers/watchdog/gef_wdt.c1
-rw-r--r--drivers/watchdog/imx2_wdt.c20
-rw-r--r--drivers/watchdog/jz4740_wdt.c6
-rw-r--r--drivers/watchdog/lantiq_wdt.c8
-rw-r--r--drivers/watchdog/max63xx_wdt.c7
-rw-r--r--drivers/watchdog/omap_wdt.c6
-rw-r--r--drivers/watchdog/orion_wdt.c11
-rw-r--r--drivers/watchdog/pnx4008_wdt.c13
-rw-r--r--drivers/watchdog/retu_wdt.c178
-rw-r--r--drivers/watchdog/s3c2410_wdt.c48
-rw-r--r--drivers/watchdog/sp5100_tco.c135
-rw-r--r--drivers/watchdog/sp5100_tco.h2
-rw-r--r--drivers/watchdog/stmp3xxx_rtc_wdt.c111
-rw-r--r--drivers/watchdog/stmp3xxx_wdt.c288
-rw-r--r--drivers/watchdog/txx9wdt.c19
-rw-r--r--drivers/watchdog/ux500_wdt.c171
-rw-r--r--drivers/watchdog/watchdog_core.c66
-rw-r--r--drivers/watchdog/watchdog_dev.c3
31 files changed, 945 insertions, 1050 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 7f809fd4a57f..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"
@@ -364,6 +367,30 @@ config IMX2_WDT
364 To compile this driver as a module, choose M here: the 367 To compile this driver as a module, choose M here: the
365 module will be called imx2_wdt. 368 module will be called imx2_wdt.
366 369
370config UX500_WATCHDOG
371 tristate "ST-Ericsson Ux500 watchdog"
372 depends on MFD_DB8500_PRCMU
373 select WATCHDOG_CORE
374 default y
375 help
376 Say Y here to include Watchdog timer support for the watchdog
377 existing in the prcmu of ST-Ericsson Ux500 series platforms.
378
379 To compile this driver as a module, choose M here: the
380 module will be called ux500_wdt.
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
367# AVR32 Architecture 394# AVR32 Architecture
368 395
369config AT32AP700X_WDT 396config AT32AP700X_WDT
@@ -581,7 +608,7 @@ config IE6XX_WDT
581 608
582config INTEL_SCU_WATCHDOG 609config INTEL_SCU_WATCHDOG
583 bool "Intel SCU Watchdog for Mobile Platforms" 610 bool "Intel SCU Watchdog for Mobile Platforms"
584 depends on X86_MRST 611 depends on X86_INTEL_MID
585 ---help--- 612 ---help---
586 Hardware driver for the watchdog time built into the Intel SCU 613 Hardware driver for the watchdog time built into the Intel SCU
587 for Intel Mobile Platforms. 614 for Intel Mobile Platforms.
@@ -971,6 +998,7 @@ config ATH79_WDT
971config BCM47XX_WDT 998config BCM47XX_WDT
972 tristate "Broadcom BCM47xx Watchdog Timer" 999 tristate "Broadcom BCM47xx Watchdog Timer"
973 depends on BCM47XX 1000 depends on BCM47XX
1001 select WATCHDOG_CORE
974 help 1002 help
975 Hardware driver for the Broadcom BCM47xx Watchdog Timer. 1003 Hardware driver for the Broadcom BCM47xx Watchdog Timer.
976 1004
@@ -1119,6 +1147,7 @@ config PIKA_WDT
1119config BOOKE_WDT 1147config BOOKE_WDT
1120 tristate "PowerPC Book-E Watchdog Timer" 1148 tristate "PowerPC Book-E Watchdog Timer"
1121 depends on BOOKE || 4xx 1149 depends on BOOKE || 4xx
1150 select WATCHDOG_CORE
1122 ---help--- 1151 ---help---
1123 Watchdog driver for PowerPC Book-E chips, such as the Freescale 1152 Watchdog driver for PowerPC Book-E chips, such as the Freescale
1124 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 97bbdb3a4648..a300b948f254 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -48,10 +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
56obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
55 57
56# AVR32 Architecture 58# AVR32 Architecture
57obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o 59obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/ar7_wdt.c b/drivers/watchdog/ar7_wdt.c
index 3003e2a9580b..2f3cc8fb471a 100644
--- a/drivers/watchdog/ar7_wdt.c
+++ b/drivers/watchdog/ar7_wdt.c
@@ -285,11 +285,9 @@ static int ar7_wdt_probe(struct platform_device *pdev)
285 return -ENODEV; 285 return -ENODEV;
286 } 286 }
287 287
288 ar7_wdt = devm_request_and_ioremap(&pdev->dev, ar7_regs_wdt); 288 ar7_wdt = devm_ioremap_resource(&pdev->dev, ar7_regs_wdt);
289 if (!ar7_wdt) { 289 if (IS_ERR(ar7_wdt))
290 pr_err("could not ioremap registers\n"); 290 return PTR_ERR(ar7_wdt);
291 return -ENXIO;
292 }
293 291
294 vbus_clk = clk_get(NULL, "vbus"); 292 vbus_clk = clk_get(NULL, "vbus");
295 if (IS_ERR(vbus_clk)) { 293 if (IS_ERR(vbus_clk)) {
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c
index 2896430ce42c..7a715e3e6828 100644
--- a/drivers/watchdog/at32ap700x_wdt.c
+++ b/drivers/watchdog/at32ap700x_wdt.c
@@ -436,17 +436,7 @@ static struct platform_driver at32_wdt_driver = {
436 .shutdown = at32_wdt_shutdown, 436 .shutdown = at32_wdt_shutdown,
437}; 437};
438 438
439static int __init at32_wdt_init(void) 439module_platform_driver_probe(at32_wdt_driver, at32_wdt_probe);
440{
441 return platform_driver_probe(&at32_wdt_driver, at32_wdt_probe);
442}
443module_init(at32_wdt_init);
444
445static void __exit at32_wdt_exit(void)
446{
447 platform_driver_unregister(&at32_wdt_driver);
448}
449module_exit(at32_wdt_exit);
450 440
451MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>"); 441MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
452MODULE_DESCRIPTION("Watchdog driver for Atmel AT32AP700X"); 442MODULE_DESCRIPTION("Watchdog driver for Atmel AT32AP700X");
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 dc42e44b6bc1..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};
@@ -321,20 +246,8 @@ static struct platform_driver at91wdt_driver = {
321 }, 246 },
322}; 247};
323 248
324static int __init at91sam_wdt_init(void) 249module_platform_driver_probe(at91wdt_driver, at91wdt_probe);
325{
326 return platform_driver_probe(&at91wdt_driver, at91wdt_probe);
327}
328
329static void __exit at91sam_wdt_exit(void)
330{
331 platform_driver_unregister(&at91wdt_driver);
332}
333
334module_init(at91sam_wdt_init);
335module_exit(at91sam_wdt_exit);
336 250
337MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>"); 251MODULE_AUTHOR("Renaud CERRATO <r.cerrato@til-technologies.fr>");
338MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors"); 252MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors");
339MODULE_LICENSE("GPL"); 253MODULE_LICENSE("GPL");
340MODULE_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/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
index cb5da5c3ece2..b9b8a8be6f12 100644
--- a/drivers/watchdog/coh901327_wdt.c
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -451,17 +451,7 @@ static struct platform_driver coh901327_driver = {
451 .resume = coh901327_resume, 451 .resume = coh901327_resume,
452}; 452};
453 453
454static int __init coh901327_init(void) 454module_platform_driver_probe(coh901327_driver, coh901327_probe);
455{
456 return platform_driver_probe(&coh901327_driver, coh901327_probe);
457}
458module_init(coh901327_init);
459
460static void __exit coh901327_exit(void)
461{
462 platform_driver_unregister(&coh901327_driver);
463}
464module_exit(coh901327_exit);
465 455
466MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); 456MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
467MODULE_DESCRIPTION("COH 901 327 Watchdog"); 457MODULE_DESCRIPTION("COH 901 327 Watchdog");
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 11d55ce5ca81..70387582843f 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -411,7 +411,7 @@ static long cpwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
411 .identity = DRIVER_NAME, 411 .identity = DRIVER_NAME,
412 }; 412 };
413 void __user *argp = (void __user *)arg; 413 void __user *argp = (void __user *)arg;
414 struct inode *inode = file->f_path.dentry->d_inode; 414 struct inode *inode = file_inode(file);
415 int index = iminor(inode) - WD0_MINOR; 415 int index = iminor(inode) - WD0_MINOR;
416 struct cpwd *p = cpwd_device; 416 struct cpwd *p = cpwd_device;
417 int setopt = 0; 417 int setopt = 0;
@@ -499,7 +499,7 @@ static long cpwd_compat_ioctl(struct file *file, unsigned int cmd,
499static ssize_t cpwd_write(struct file *file, const char __user *buf, 499static ssize_t cpwd_write(struct file *file, const char __user *buf,
500 size_t count, loff_t *ppos) 500 size_t count, loff_t *ppos)
501{ 501{
502 struct inode *inode = file->f_path.dentry->d_inode; 502 struct inode *inode = file_inode(file);
503 struct cpwd *p = cpwd_device; 503 struct cpwd *p = cpwd_device;
504 int index = iminor(inode); 504 int index = iminor(inode);
505 505
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/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index a0eba3c40e25..203766989382 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -301,9 +301,9 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
301 if (!mem) 301 if (!mem)
302 return -EINVAL; 302 return -EINVAL;
303 303
304 dw_wdt.regs = devm_request_and_ioremap(&pdev->dev, mem); 304 dw_wdt.regs = devm_ioremap_resource(&pdev->dev, mem);
305 if (!dw_wdt.regs) 305 if (IS_ERR(dw_wdt.regs))
306 return -ENOMEM; 306 return PTR_ERR(dw_wdt.regs);
307 307
308 dw_wdt.clk = clk_get(&pdev->dev, NULL); 308 dw_wdt.clk = clk_get(&pdev->dev, NULL);
309 if (IS_ERR(dw_wdt.clk)) 309 if (IS_ERR(dw_wdt.clk))
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/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 9a45d0294cf4..ff908823688c 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -262,11 +262,9 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
262 return -ENODEV; 262 return -ENODEV;
263 } 263 }
264 264
265 imx2_wdt.base = devm_request_and_ioremap(&pdev->dev, res); 265 imx2_wdt.base = devm_ioremap_resource(&pdev->dev, res);
266 if (!imx2_wdt.base) { 266 if (IS_ERR(imx2_wdt.base))
267 dev_err(&pdev->dev, "ioremap failed\n"); 267 return PTR_ERR(imx2_wdt.base);
268 return -ENOMEM;
269 }
270 268
271 imx2_wdt.clk = clk_get(&pdev->dev, NULL); 269 imx2_wdt.clk = clk_get(&pdev->dev, NULL);
272 if (IS_ERR(imx2_wdt.clk)) { 270 if (IS_ERR(imx2_wdt.clk)) {
@@ -342,17 +340,7 @@ static struct platform_driver imx2_wdt_driver = {
342 }, 340 },
343}; 341};
344 342
345static int __init imx2_wdt_init(void) 343module_platform_driver_probe(imx2_wdt_driver, imx2_wdt_probe);
346{
347 return platform_driver_probe(&imx2_wdt_driver, imx2_wdt_probe);
348}
349module_init(imx2_wdt_init);
350
351static void __exit imx2_wdt_exit(void)
352{
353 platform_driver_unregister(&imx2_wdt_driver);
354}
355module_exit(imx2_wdt_exit);
356 344
357MODULE_AUTHOR("Wolfram Sang"); 345MODULE_AUTHOR("Wolfram Sang");
358MODULE_DESCRIPTION("Watchdog driver for IMX2 and later"); 346MODULE_DESCRIPTION("Watchdog driver for IMX2 and later");
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
index a61408fa0c94..1cb25f69a96d 100644
--- a/drivers/watchdog/jz4740_wdt.c
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -171,9 +171,9 @@ static int jz4740_wdt_probe(struct platform_device *pdev)
171 watchdog_set_drvdata(jz4740_wdt, drvdata); 171 watchdog_set_drvdata(jz4740_wdt, drvdata);
172 172
173 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 173 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
174 drvdata->base = devm_request_and_ioremap(&pdev->dev, res); 174 drvdata->base = devm_ioremap_resource(&pdev->dev, res);
175 if (drvdata->base == NULL) { 175 if (IS_ERR(drvdata->base)) {
176 ret = -EBUSY; 176 ret = PTR_ERR(drvdata->base);
177 goto err_out; 177 goto err_out;
178 } 178 }
179 179
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c
index 79fe01b42339..088fd0c9d888 100644
--- a/drivers/watchdog/lantiq_wdt.c
+++ b/drivers/watchdog/lantiq_wdt.c
@@ -197,11 +197,9 @@ ltq_wdt_probe(struct platform_device *pdev)
197 return -ENOENT; 197 return -ENOENT;
198 } 198 }
199 199
200 ltq_wdt_membase = devm_request_and_ioremap(&pdev->dev, res); 200 ltq_wdt_membase = devm_ioremap_resource(&pdev->dev, res);
201 if (!ltq_wdt_membase) { 201 if (IS_ERR(ltq_wdt_membase))
202 dev_err(&pdev->dev, "cannot remap I/O memory region\n"); 202 return PTR_ERR(ltq_wdt_membase);
203 return -ENOMEM;
204 }
205 203
206 /* we do not need to enable the clock as it is always running */ 204 /* we do not need to enable the clock as it is always running */
207 clk = clk_get_io(); 205 clk = clk_get_io();
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
index 773c661723ca..cc9d328086ed 100644
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -14,6 +14,7 @@
14 * another interface, some abstraction will have to be introduced. 14 * another interface, some abstraction will have to be introduced.
15 */ 15 */
16 16
17#include <linux/err.h>
17#include <linux/module.h> 18#include <linux/module.h>
18#include <linux/moduleparam.h> 19#include <linux/moduleparam.h>
19#include <linux/types.h> 20#include <linux/types.h>
@@ -198,9 +199,9 @@ static int max63xx_wdt_probe(struct platform_device *pdev)
198 heartbeat = current_timeout->twd; 199 heartbeat = current_timeout->twd;
199 200
200 wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 201 wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
201 wdt_base = devm_request_and_ioremap(&pdev->dev, wdt_mem); 202 wdt_base = devm_ioremap_resource(&pdev->dev, wdt_mem);
202 if (!wdt_base) 203 if (IS_ERR(wdt_base))
203 return -ENOMEM; 204 return PTR_ERR(wdt_base);
204 205
205 max63xx_wdt_dev.timeout = heartbeat; 206 max63xx_wdt_dev.timeout = heartbeat;
206 watchdog_set_nowayout(&max63xx_wdt_dev, nowayout); 207 watchdog_set_nowayout(&max63xx_wdt_dev, nowayout);
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 dcba5dab6c29..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,13 +152,12 @@ 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_request_and_ioremap(&pdev->dev, r); 158 wdt_base = devm_ioremap_resource(&pdev->dev, r);
159 if (!wdt_base) 159 if (IS_ERR(wdt_base))
160 return -EADDRINUSE; 160 return PTR_ERR(wdt_base);
161 161
162 wdt_clk = clk_get(&pdev->dev, NULL); 162 wdt_clk = clk_get(&pdev->dev, NULL);
163 if (IS_ERR(wdt_clk)) 163 if (IS_ERR(wdt_clk))
@@ -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..0e9d8c479c35 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -40,13 +40,12 @@
40#include "sp5100_tco.h" 40#include "sp5100_tco.h"
41 41
42/* Module and version information */ 42/* Module and version information */
43#define TCO_VERSION "0.03" 43#define TCO_VERSION "0.05"
44#define TCO_MODULE_NAME "SP5100 TCO timer" 44#define TCO_MODULE_NAME "SP5100 TCO timer"
45#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION 45#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
46 46
47/* internal variables */ 47/* internal variables */
48static u32 tcobase_phys; 48static u32 tcobase_phys;
49static u32 resbase_phys;
50static u32 tco_wdt_fired; 49static u32 tco_wdt_fired;
51static void __iomem *tcobase; 50static void __iomem *tcobase;
52static unsigned int pm_iobase; 51static unsigned int pm_iobase;
@@ -54,10 +53,6 @@ static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */
54static unsigned long timer_alive; 53static unsigned long timer_alive;
55static char tco_expect_close; 54static char tco_expect_close;
56static struct pci_dev *sp5100_tco_pci; 55static struct pci_dev *sp5100_tco_pci;
57static struct resource wdt_res = {
58 .name = "Watchdog Timer",
59 .flags = IORESOURCE_MEM,
60};
61 56
62/* the watchdog platform device */ 57/* the watchdog platform device */
63static struct platform_device *sp5100_tco_platform_device; 58static struct platform_device *sp5100_tco_platform_device;
@@ -75,12 +70,6 @@ module_param(nowayout, bool, 0);
75MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started." 70MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started."
76 " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 71 " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
77 72
78static unsigned int force_addr;
79module_param(force_addr, uint, 0);
80MODULE_PARM_DESC(force_addr, "Force the use of specified MMIO address."
81 " ONLY USE THIS PARAMETER IF YOU REALLY KNOW"
82 " WHAT YOU ARE DOING (default=none)");
83
84/* 73/*
85 * Some TCO specific functions 74 * Some TCO specific functions
86 */ 75 */
@@ -176,39 +165,6 @@ static void tco_timer_enable(void)
176 } 165 }
177} 166}
178 167
179static void tco_timer_disable(void)
180{
181 int val;
182
183 if (sp5100_tco_pci->revision >= 0x40) {
184 /* For SB800 or later */
185 /* Enable watchdog decode bit and Disable watchdog timer */
186 outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG);
187 val = inb(SB800_IO_PM_DATA_REG);
188 val |= SB800_PCI_WATCHDOG_DECODE_EN;
189 val |= SB800_PM_WATCHDOG_DISABLE;
190 outb(val, SB800_IO_PM_DATA_REG);
191 } else {
192 /* For SP5100 or SB7x0 */
193 /* Enable watchdog decode bit */
194 pci_read_config_dword(sp5100_tco_pci,
195 SP5100_PCI_WATCHDOG_MISC_REG,
196 &val);
197
198 val |= SP5100_PCI_WATCHDOG_DECODE_EN;
199
200 pci_write_config_dword(sp5100_tco_pci,
201 SP5100_PCI_WATCHDOG_MISC_REG,
202 val);
203
204 /* Disable Watchdog timer */
205 outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
206 val = inb(SP5100_IO_PM_DATA_REG);
207 val |= SP5100_PM_WATCHDOG_DISABLE;
208 outb(val, SP5100_IO_PM_DATA_REG);
209 }
210}
211
212/* 168/*
213 * /dev/watchdog handling 169 * /dev/watchdog handling
214 */ 170 */
@@ -459,74 +415,8 @@ static unsigned char sp5100_tco_setupdevice(void)
459 } else 415 } else
460 pr_debug("SBResource_MMIO is disabled(0x%04x)\n", val); 416 pr_debug("SBResource_MMIO is disabled(0x%04x)\n", val);
461 417
462 /* 418 pr_notice("failed to find MMIO address, giving up.\n");
463 * Lastly re-programming the watchdog timer MMIO address, 419 goto unreg_region;
464 * This method is a last resort...
465 *
466 * Before re-programming, to ensure that the watchdog timer
467 * is disabled, disable the watchdog timer.
468 */
469 tco_timer_disable();
470
471 if (force_addr) {
472 /*
473 * Force the use of watchdog timer MMIO address, and aligned to
474 * 8byte boundary.
475 */
476 force_addr &= ~0x7;
477 val = force_addr;
478
479 pr_info("Force the use of 0x%04x as MMIO address\n", val);
480 } else {
481 /*
482 * Get empty slot into the resource tree for watchdog timer.
483 */
484 if (allocate_resource(&iomem_resource,
485 &wdt_res,
486 SP5100_WDT_MEM_MAP_SIZE,
487 0xf0000000,
488 0xfffffff8,
489 0x8,
490 NULL,
491 NULL)) {
492 pr_err("MMIO allocation failed\n");
493 goto unreg_region;
494 }
495
496 val = resbase_phys = wdt_res.start;
497 pr_debug("Got 0x%04x from resource tree\n", val);
498 }
499
500 /* Restore to the low three bits, if chipset is SB8x0(or later) */
501 if (sp5100_tco_pci->revision >= 0x40) {
502 u8 reserved_bit;
503 reserved_bit = inb(base_addr) & 0x7;
504 val |= (u32)reserved_bit;
505 }
506
507 /* Re-programming the watchdog timer base address */
508 outb(base_addr+0, index_reg);
509 /* Low three bits of BASE are reserved */
510 outb((val >> 0) & 0xf8, data_reg);
511 outb(base_addr+1, index_reg);
512 outb((val >> 8) & 0xff, data_reg);
513 outb(base_addr+2, index_reg);
514 outb((val >> 16) & 0xff, data_reg);
515 outb(base_addr+3, index_reg);
516 outb((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
525 if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
526 dev_name)) {
527 pr_err("MMIO address 0x%04x already in use\n", val);
528 goto unreg_resource;
529 }
530 420
531setup_wdt: 421setup_wdt:
532 tcobase_phys = val; 422 tcobase_phys = val;
@@ -566,9 +456,6 @@ setup_wdt:
566 456
567unreg_mem_region: 457unreg_mem_region:
568 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 458 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
569unreg_resource:
570 if (resbase_phys)
571 release_resource(&wdt_res);
572unreg_region: 459unreg_region:
573 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 460 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
574exit: 461exit:
@@ -578,7 +465,6 @@ exit:
578static int sp5100_tco_init(struct platform_device *dev) 465static int sp5100_tco_init(struct platform_device *dev)
579{ 466{
580 int ret; 467 int ret;
581 char addr_str[16];
582 468
583 /* 469 /*
584 * Check whether or not the hardware watchdog is there. If found, then 470 * Check whether or not the hardware watchdog is there. If found, then
@@ -610,23 +496,14 @@ static int sp5100_tco_init(struct platform_device *dev)
610 clear_bit(0, &timer_alive); 496 clear_bit(0, &timer_alive);
611 497
612 /* Show module parameters */ 498 /* Show module parameters */
613 if (force_addr == tcobase_phys) 499 pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
614 /* The force_addr is vaild */ 500 tcobase, heartbeat, nowayout);
615 sprintf(addr_str, "0x%04x", force_addr);
616 else
617 strcpy(addr_str, "none");
618
619 pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d, "
620 "force_addr=%s)\n",
621 tcobase, heartbeat, nowayout, addr_str);
622 501
623 return 0; 502 return 0;
624 503
625exit: 504exit:
626 iounmap(tcobase); 505 iounmap(tcobase);
627 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 506 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
628 if (resbase_phys)
629 release_resource(&wdt_res);
630 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 507 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
631 return ret; 508 return ret;
632} 509}
@@ -641,8 +518,6 @@ static void sp5100_tco_cleanup(void)
641 misc_deregister(&sp5100_tco_miscdev); 518 misc_deregister(&sp5100_tco_miscdev);
642 iounmap(tcobase); 519 iounmap(tcobase);
643 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 520 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
644 if (resbase_phys)
645 release_resource(&wdt_res);
646 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 521 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
647} 522}
648 523
diff --git a/drivers/watchdog/sp5100_tco.h b/drivers/watchdog/sp5100_tco.h
index 71594a0c14b7..2b28c00da0df 100644
--- a/drivers/watchdog/sp5100_tco.h
+++ b/drivers/watchdog/sp5100_tco.h
@@ -57,7 +57,7 @@
57#define SB800_PM_WATCHDOG_DISABLE (1 << 2) 57#define SB800_PM_WATCHDOG_DISABLE (1 << 2)
58#define SB800_PM_WATCHDOG_SECOND_RES (3 << 0) 58#define SB800_PM_WATCHDOG_SECOND_RES (3 << 0)
59#define SB800_ACPI_MMIO_DECODE_EN (1 << 0) 59#define SB800_ACPI_MMIO_DECODE_EN (1 << 0)
60#define SB800_ACPI_MMIO_SEL (1 << 2) 60#define SB800_ACPI_MMIO_SEL (1 << 1)
61 61
62 62
63#define SB800_PM_WDT_MMIO_OFFSET 0xB00 63#define SB800_PM_WDT_MMIO_OFFSET 0xB00
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/txx9wdt.c b/drivers/watchdog/txx9wdt.c
index 98e16373e640..88f23c5cfddb 100644
--- a/drivers/watchdog/txx9wdt.c
+++ b/drivers/watchdog/txx9wdt.c
@@ -121,9 +121,9 @@ static int __init txx9wdt_probe(struct platform_device *dev)
121 } 121 }
122 122
123 res = platform_get_resource(dev, IORESOURCE_MEM, 0); 123 res = platform_get_resource(dev, IORESOURCE_MEM, 0);
124 txx9wdt_reg = devm_request_and_ioremap(&dev->dev, res); 124 txx9wdt_reg = devm_ioremap_resource(&dev->dev, res);
125 if (!txx9wdt_reg) { 125 if (IS_ERR(txx9wdt_reg)) {
126 ret = -EBUSY; 126 ret = PTR_ERR(txx9wdt_reg);
127 goto exit; 127 goto exit;
128 } 128 }
129 129
@@ -172,18 +172,7 @@ static struct platform_driver txx9wdt_driver = {
172 }, 172 },
173}; 173};
174 174
175static int __init watchdog_init(void) 175module_platform_driver_probe(txx9wdt_driver, txx9wdt_probe);
176{
177 return platform_driver_probe(&txx9wdt_driver, txx9wdt_probe);
178}
179
180static void __exit watchdog_exit(void)
181{
182 platform_driver_unregister(&txx9wdt_driver);
183}
184
185module_init(watchdog_init);
186module_exit(watchdog_exit);
187 176
188MODULE_DESCRIPTION("TXx9 Watchdog Driver"); 177MODULE_DESCRIPTION("TXx9 Watchdog Driver");
189MODULE_LICENSE("GPL"); 178MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/ux500_wdt.c b/drivers/watchdog/ux500_wdt.c
new file mode 100644
index 000000000000..a614d84121c3
--- /dev/null
+++ b/drivers/watchdog/ux500_wdt.c
@@ -0,0 +1,171 @@
1/*
2 * Copyright (C) ST-Ericsson SA 2011-2013
3 *
4 * License Terms: GNU General Public License v2
5 *
6 * Author: Mathieu Poirier <mathieu.poirier@linaro.org> for ST-Ericsson
7 * Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
8 */
9
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/moduleparam.h>
15#include <linux/miscdevice.h>
16#include <linux/err.h>
17#include <linux/uaccess.h>
18#include <linux/watchdog.h>
19#include <linux/platform_device.h>
20#include <linux/platform_data/ux500_wdt.h>
21
22#include <linux/mfd/dbx500-prcmu.h>
23
24#define WATCHDOG_TIMEOUT 600 /* 10 minutes */
25
26#define WATCHDOG_MIN 0
27#define WATCHDOG_MAX28 268435 /* 28 bit resolution in ms == 268435.455 s */
28#define WATCHDOG_MAX32 4294967 /* 32 bit resolution in ms == 4294967.295 s */
29
30static unsigned int timeout = WATCHDOG_TIMEOUT;
31module_param(timeout, uint, 0);
32MODULE_PARM_DESC(timeout,
33 "Watchdog timeout in seconds. default="
34 __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
35
36static bool nowayout = WATCHDOG_NOWAYOUT;
37module_param(nowayout, bool, 0);
38MODULE_PARM_DESC(nowayout,
39 "Watchdog cannot be stopped once started (default="
40 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
41
42static int ux500_wdt_start(struct watchdog_device *wdd)
43{
44 return prcmu_enable_a9wdog(PRCMU_WDOG_ALL);
45}
46
47static int ux500_wdt_stop(struct watchdog_device *wdd)
48{
49 return prcmu_disable_a9wdog(PRCMU_WDOG_ALL);
50}
51
52static int ux500_wdt_keepalive(struct watchdog_device *wdd)
53{
54 return prcmu_kick_a9wdog(PRCMU_WDOG_ALL);
55}
56
57static int ux500_wdt_set_timeout(struct watchdog_device *wdd,
58 unsigned int timeout)
59{
60 ux500_wdt_stop(wdd);
61 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
62 ux500_wdt_start(wdd);
63
64 return 0;
65}
66
67static const struct watchdog_info ux500_wdt_info = {
68 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
69 .identity = "Ux500 WDT",
70 .firmware_version = 1,
71};
72
73static const struct watchdog_ops ux500_wdt_ops = {
74 .owner = THIS_MODULE,
75 .start = ux500_wdt_start,
76 .stop = ux500_wdt_stop,
77 .ping = ux500_wdt_keepalive,
78 .set_timeout = ux500_wdt_set_timeout,
79};
80
81static struct watchdog_device ux500_wdt = {
82 .info = &ux500_wdt_info,
83 .ops = &ux500_wdt_ops,
84 .min_timeout = WATCHDOG_MIN,
85 .max_timeout = WATCHDOG_MAX32,
86};
87
88static int ux500_wdt_probe(struct platform_device *pdev)
89{
90 int ret;
91 struct ux500_wdt_data *pdata = pdev->dev.platform_data;
92
93 if (pdata) {
94 if (pdata->timeout > 0)
95 timeout = pdata->timeout;
96 if (pdata->has_28_bits_resolution)
97 ux500_wdt.max_timeout = WATCHDOG_MAX28;
98 }
99
100 watchdog_set_nowayout(&ux500_wdt, nowayout);
101
102 /* disable auto off on sleep */
103 prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
104
105 /* set HW initial value */
106 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
107
108 ret = watchdog_register_device(&ux500_wdt);
109 if (ret)
110 return ret;
111
112 dev_info(&pdev->dev, "initialized\n");
113
114 return 0;
115}
116
117static int ux500_wdt_remove(struct platform_device *dev)
118{
119 watchdog_unregister_device(&ux500_wdt);
120
121 return 0;
122}
123
124#ifdef CONFIG_PM
125static int ux500_wdt_suspend(struct platform_device *pdev,
126 pm_message_t state)
127{
128 if (watchdog_active(&ux500_wdt)) {
129 ux500_wdt_stop(&ux500_wdt);
130 prcmu_config_a9wdog(PRCMU_WDOG_CPU1, true);
131
132 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
133 ux500_wdt_start(&ux500_wdt);
134 }
135 return 0;
136}
137
138static int ux500_wdt_resume(struct platform_device *pdev)
139{
140 if (watchdog_active(&ux500_wdt)) {
141 ux500_wdt_stop(&ux500_wdt);
142 prcmu_config_a9wdog(PRCMU_WDOG_CPU1, false);
143
144 prcmu_load_a9wdog(PRCMU_WDOG_ALL, timeout * 1000);
145 ux500_wdt_start(&ux500_wdt);
146 }
147 return 0;
148}
149#else
150#define ux500_wdt_suspend NULL
151#define ux500_wdt_resume NULL
152#endif
153
154static struct platform_driver ux500_wdt_driver = {
155 .probe = ux500_wdt_probe,
156 .remove = ux500_wdt_remove,
157 .suspend = ux500_wdt_suspend,
158 .resume = ux500_wdt_resume,
159 .driver = {
160 .owner = THIS_MODULE,
161 .name = "ux500_wdt",
162 },
163};
164
165module_platform_driver(ux500_wdt_driver);
166
167MODULE_AUTHOR("Jonas Aaberg <jonas.aberg@stericsson.com>");
168MODULE_DESCRIPTION("Ux500 Watchdog Driver");
169MODULE_LICENSE("GPL");
170MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
171MODULE_ALIAS("platform:ux500_wdt");
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);