aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/watchdog/hpwdt.txt19
-rw-r--r--drivers/mfd/twl4030-core.c12
-rw-r--r--drivers/watchdog/Kconfig59
-rw-r--r--drivers/watchdog/Makefile5
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c286
-rw-r--r--drivers/watchdog/coh901327_wdt.c537
-rw-r--r--drivers/watchdog/hpwdt.c26
-rw-r--r--drivers/watchdog/omap_wdt.c7
-rw-r--r--drivers/watchdog/pnx833x_wdt.c282
-rw-r--r--drivers/watchdog/stmp3xxx_wdt.c296
-rw-r--r--drivers/watchdog/twl4030_wdt.c272
-rw-r--r--drivers/watchdog/wdt_pci.c122
12 files changed, 1840 insertions, 83 deletions
diff --git a/Documentation/watchdog/hpwdt.txt b/Documentation/watchdog/hpwdt.txt
index 127839e53043..9c24d5ffbb06 100644
--- a/Documentation/watchdog/hpwdt.txt
+++ b/Documentation/watchdog/hpwdt.txt
@@ -19,30 +19,41 @@ Last reviewed: 06/02/2009
19 not be updated in a timely fashion and a hardware system reset (also known as 19 not be updated in a timely fashion and a hardware system reset (also known as
20 an Automatic Server Recovery (ASR)) event will occur. 20 an Automatic Server Recovery (ASR)) event will occur.
21 21
22 The hpwdt driver also has three (3) module parameters. They are the following: 22 The hpwdt driver also has four (4) module parameters. They are the following:
23 23
24 soft_margin - allows the user to set the watchdog timer value 24 soft_margin - allows the user to set the watchdog timer value
25 allow_kdump - allows the user to save off a kernel dump image after an NMI 25 allow_kdump - allows the user to save off a kernel dump image after an NMI
26 nowayout - basic watchdog parameter that does not allow the timer to 26 nowayout - basic watchdog parameter that does not allow the timer to
27 be restarted or an impending ASR to be escaped. 27 be restarted or an impending ASR to be escaped.
28 priority - determines whether or not the hpwdt driver is first on the
29 die_notify list to handle NMIs or last. The default value
30 for this module parameter is 0 or LAST. If the user wants to
31 enable NMI sourcing then reload the hpwdt driver with
32 priority=1 (and boot with nmi_watchdog=0).
28 33
29 NOTE: More information about watchdog drivers in general, including the ioctl 34 NOTE: More information about watchdog drivers in general, including the ioctl
30 interface to /dev/watchdog can be found in 35 interface to /dev/watchdog can be found in
31 Documentation/watchdog/watchdog-api.txt and Documentation/IPMI.txt. 36 Documentation/watchdog/watchdog-api.txt and Documentation/IPMI.txt.
32 37
33 The NMI sourcing capability is disabled when the driver discovers that the 38 The priority parameter was introduced due to other kernel software that relied
34 nmi_watchdog is turned on (nmi_watchdog = 1). This is due to the inability to 39 on handling NMIs (like oprofile). Keeping hpwdt's priority at 0 (or LAST)
40 enables the users of NMIs for non critical events to be work as expected.
41
42 The NMI sourcing capability is disabled by default due to the inability to
35 distinguish between "NMI Watchdog Ticks" and "HW generated NMI events" in the 43 distinguish between "NMI Watchdog Ticks" and "HW generated NMI events" in the
36 Linux kernel. What this means is that the hpwdt nmi handler code is called 44 Linux kernel. What this means is that the hpwdt nmi handler code is called
37 each time the NMI signal fires off. This could amount to several thousands of 45 each time the NMI signal fires off. This could amount to several thousands of
38 NMIs in a matter of seconds. If a user sees the Linux kernel's "dazed and 46 NMIs in a matter of seconds. If a user sees the Linux kernel's "dazed and
39 confused" message in the logs or if the system gets into a hung state, then 47 confused" message in the logs or if the system gets into a hung state, then
40 the user should reboot with nmi_watchdog=0. 48 the hpwdt driver can be reloaded with the "priority" module parameter set
49 (priority=1).
41 50
42 1. If the kernel has not been booted with nmi_watchdog turned off then 51 1. If the kernel has not been booted with nmi_watchdog turned off then
43 edit /boot/grub/menu.lst and place the nmi_watchdog=0 at the end of the 52 edit /boot/grub/menu.lst and place the nmi_watchdog=0 at the end of the
44 currently booting kernel line. 53 currently booting kernel line.
45 2. reboot the sever 54 2. reboot the sever
55 3. Once the system comes up perform a rmmod hpwdt
56 4. insmod /lib/modules/`uname -r`/kernel/drivers/char/watchdog/hpwdt.ko priority=1
46 57
47 Now, the hpwdt can successfully receive and source the NMI and provide a log 58 Now, the hpwdt can successfully receive and source the NMI and provide a log
48 message that details the reason for the NMI (as determined by the HP BIOS). 59 message that details the reason for the NMI (as determined by the HP BIOS).
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
index cd1008c19cd7..ca54996ffd0e 100644
--- a/drivers/mfd/twl4030-core.c
+++ b/drivers/mfd/twl4030-core.c
@@ -101,6 +101,12 @@
101#define twl_has_usb() false 101#define twl_has_usb() false
102#endif 102#endif
103 103
104#if defined(CONFIG_TWL4030_WATCHDOG) || \
105 defined(CONFIG_TWL4030_WATCHDOG_MODULE)
106#define twl_has_watchdog() true
107#else
108#define twl_has_watchdog() false
109#endif
104 110
105/* Triton Core internal information (BEGIN) */ 111/* Triton Core internal information (BEGIN) */
106 112
@@ -526,6 +532,12 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
526 usb_transceiver = child; 532 usb_transceiver = child;
527 } 533 }
528 534
535 if (twl_has_watchdog()) {
536 child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
537 if (IS_ERR(child))
538 return PTR_ERR(child);
539 }
540
529 if (twl_has_regulator()) { 541 if (twl_has_regulator()) {
530 /* 542 /*
531 child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1); 543 child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index b166f2852a64..b1ccc04f3c9a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -240,6 +240,32 @@ config ORION_WATCHDOG
240 To compile this driver as a module, choose M here: the 240 To compile this driver as a module, choose M here: the
241 module will be called orion_wdt. 241 module will be called orion_wdt.
242 242
243config COH901327_WATCHDOG
244 bool "ST-Ericsson COH 901 327 watchdog"
245 depends on ARCH_U300
246 default y if MACH_U300
247 help
248 Say Y here to include Watchdog timer support for the
249 watchdog embedded into the ST-Ericsson U300 series platforms.
250 This watchdog is used to reset the system and thus cannot be
251 compiled as a module.
252
253config TWL4030_WATCHDOG
254 tristate "TWL4030 Watchdog"
255 depends on TWL4030_CORE
256 help
257 Support for TI TWL4030 watchdog. Say 'Y' here to enable the
258 watchdog timer support for TWL4030 chips.
259
260config STMP3XXX_WATCHDOG
261 tristate "Freescale STMP3XXX watchdog"
262 depends on ARCH_STMP3XXX
263 help
264 Say Y here if to include support for the watchdog timer
265 for the Sigmatel STMP37XX/378X SoC.
266 To compile this driver as a module, choose M here: the
267 module will be called stmp3xxx_wdt.
268
243# AVR32 Architecture 269# AVR32 Architecture
244 270
245config AT32AP700X_WDT 271config AT32AP700X_WDT
@@ -703,6 +729,12 @@ config SBC_EPX_C3_WATCHDOG
703 729
704# MIPS Architecture 730# MIPS Architecture
705 731
732config BCM47XX_WDT
733 tristate "Broadcom BCM47xx Watchdog Timer"
734 depends on BCM47XX
735 help
736 Hardware driver for the Broadcom BCM47xx Watchog Timer.
737
706config RC32434_WDT 738config RC32434_WDT
707 tristate "IDT RC32434 SoC Watchdog Timer" 739 tristate "IDT RC32434 SoC Watchdog Timer"
708 depends on MIKROTIK_RB532 740 depends on MIKROTIK_RB532
@@ -729,6 +761,15 @@ config WDT_MTX1
729 Hardware driver for the MTX-1 boards. This is a watchdog timer that 761 Hardware driver for the MTX-1 boards. This is a watchdog timer that
730 will reboot the machine after a 100 seconds timer expired. 762 will reboot the machine after a 100 seconds timer expired.
731 763
764config PNX833X_WDT
765 tristate "PNX833x Hardware Watchdog"
766 depends on SOC_PNX8335
767 help
768 Hardware driver for the PNX833x's watchdog. This is a
769 watchdog timer that will reboot the machine after a programable
770 timer has expired and no process has written to /dev/watchdog during
771 that time.
772
732config WDT_RM9K_GPI 773config WDT_RM9K_GPI
733 tristate "RM9000/GPI hardware watchdog" 774 tristate "RM9000/GPI hardware watchdog"
734 depends on CPU_RM9000 775 depends on CPU_RM9000
@@ -966,24 +1007,16 @@ config WDTPCI
966 ---help--- 1007 ---help---
967 If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N. 1008 If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N.
968 1009
969 To compile this driver as a module, choose M here: the 1010 If you have a PCI-WDT501 watchdog board then you can enable the
970 module will be called wdt_pci. 1011 temperature sensor by setting the type parameter to 501.
971
972config WDT_501_PCI
973 bool "PCI-WDT501 features"
974 depends on WDTPCI
975 help
976 Saying Y here and creating a character special file /dev/temperature
977 with major number 10 and minor number 131 ("man mknod") will give
978 you a thermometer inside your computer: reading from
979 /dev/temperature yields one byte, the temperature in degrees
980 Fahrenheit. This works only if you have a PCI-WDT501 watchdog board
981 installed.
982 1012
983 If you want to enable the Fan Tachometer on the PCI-WDT501, then you 1013 If you want to enable the Fan Tachometer on the PCI-WDT501, then you
984 can do this via the tachometer parameter. Only do this if you have a 1014 can do this via the tachometer parameter. Only do this if you have a
985 fan tachometer actually set up. 1015 fan tachometer actually set up.
986 1016
1017 To compile this driver as a module, choose M here: the
1018 module will be called wdt_pci.
1019
987# 1020#
988# USB-based Watchdog Cards 1021# USB-based Watchdog Cards
989# 1022#
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index c3afa14d5be1..3d774294a2b7 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
28obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o 28obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
29obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o 29obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
30obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o 30obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
31obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
31obj-$(CONFIG_21285_WATCHDOG) += wdt285.o 32obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
32obj-$(CONFIG_977_WATCHDOG) += wdt977.o 33obj-$(CONFIG_977_WATCHDOG) += wdt977.o
33obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o 34obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
@@ -41,6 +42,8 @@ obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
41obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o 42obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
42obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o 43obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
43obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o 44obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
45obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
46obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o
44 47
45# AVR32 Architecture 48# AVR32 Architecture
46obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o 49obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -98,9 +101,11 @@ obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
98# M68KNOMMU Architecture 101# M68KNOMMU Architecture
99 102
100# MIPS Architecture 103# MIPS Architecture
104obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o
101obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o 105obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o
102obj-$(CONFIG_INDYDOG) += indydog.o 106obj-$(CONFIG_INDYDOG) += indydog.o
103obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o 107obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
108obj-$(CONFIG_PNX833X_WDT) += pnx833x_wdt.o
104obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o 109obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
105obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o 110obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
106obj-$(CONFIG_AR7_WDT) += ar7_wdt.o 111obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
new file mode 100644
index 000000000000..5c7011cda6a6
--- /dev/null
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -0,0 +1,286 @@
1/*
2 * Watchdog driver for Broadcom BCM47XX
3 *
4 * Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs>
5 * Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#include <linux/bitops.h>
14#include <linux/errno.h>
15#include <linux/fs.h>
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/miscdevice.h>
19#include <linux/module.h>
20#include <linux/moduleparam.h>
21#include <linux/reboot.h>
22#include <linux/types.h>
23#include <linux/uaccess.h>
24#include <linux/watchdog.h>
25#include <linux/timer.h>
26#include <linux/jiffies.h>
27#include <linux/ssb/ssb_embedded.h>
28#include <asm/mach-bcm47xx/bcm47xx.h>
29
30#define DRV_NAME "bcm47xx_wdt"
31
32#define WDT_DEFAULT_TIME 30 /* seconds */
33#define WDT_MAX_TIME 255 /* seconds */
34
35static int wdt_time = WDT_DEFAULT_TIME;
36static int nowayout = WATCHDOG_NOWAYOUT;
37
38module_param(wdt_time, int, 0);
39MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="
40 __MODULE_STRING(WDT_DEFAULT_TIME) ")");
41
42#ifdef CONFIG_WATCHDOG_NOWAYOUT
43module_param(nowayout, int, 0);
44MODULE_PARM_DESC(nowayout,
45 "Watchdog cannot be stopped once started (default="
46 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
47#endif
48
49static unsigned long bcm47xx_wdt_busy;
50static char expect_release;
51static struct timer_list wdt_timer;
52static atomic_t ticks;
53
54static inline void bcm47xx_wdt_hw_start(void)
55{
56 /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */
57 ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff);
58}
59
60static inline int bcm47xx_wdt_hw_stop(void)
61{
62 return ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
63}
64
65static void bcm47xx_timer_tick(unsigned long unused)
66{
67 if (!atomic_dec_and_test(&ticks)) {
68 bcm47xx_wdt_hw_start();
69 mod_timer(&wdt_timer, jiffies + HZ);
70 } else {
71 printk(KERN_CRIT DRV_NAME "Watchdog will fire soon!!!\n");
72 }
73}
74
75static inline void bcm47xx_wdt_pet(void)
76{
77 atomic_set(&ticks, wdt_time);
78}
79
80static void bcm47xx_wdt_start(void)
81{
82 bcm47xx_wdt_pet();
83 bcm47xx_timer_tick(0);
84}
85
86static void bcm47xx_wdt_pause(void)
87{
88 del_timer_sync(&wdt_timer);
89 bcm47xx_wdt_hw_stop();
90}
91
92static void bcm47xx_wdt_stop(void)
93{
94 bcm47xx_wdt_pause();
95}
96
97static int bcm47xx_wdt_settimeout(int new_time)
98{
99 if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
100 return -EINVAL;
101
102 wdt_time = new_time;
103 return 0;
104}
105
106static int bcm47xx_wdt_open(struct inode *inode, struct file *file)
107{
108 if (test_and_set_bit(0, &bcm47xx_wdt_busy))
109 return -EBUSY;
110
111 bcm47xx_wdt_start();
112 return nonseekable_open(inode, file);
113}
114
115static int bcm47xx_wdt_release(struct inode *inode, struct file *file)
116{
117 if (expect_release == 42) {
118 bcm47xx_wdt_stop();
119 } else {
120 printk(KERN_CRIT DRV_NAME
121 ": Unexpected close, not stopping watchdog!\n");
122 bcm47xx_wdt_start();
123 }
124
125 clear_bit(0, &bcm47xx_wdt_busy);
126 expect_release = 0;
127 return 0;
128}
129
130static ssize_t bcm47xx_wdt_write(struct file *file, const char __user *data,
131 size_t len, loff_t *ppos)
132{
133 if (len) {
134 if (!nowayout) {
135 size_t i;
136
137 expect_release = 0;
138
139 for (i = 0; i != len; i++) {
140 char c;
141 if (get_user(c, data + i))
142 return -EFAULT;
143 if (c == 'V')
144 expect_release = 42;
145 }
146 }
147 bcm47xx_wdt_pet();
148 }
149 return len;
150}
151
152static struct watchdog_info bcm47xx_wdt_info = {
153 .identity = DRV_NAME,
154 .options = WDIOF_SETTIMEOUT |
155 WDIOF_KEEPALIVEPING |
156 WDIOF_MAGICCLOSE,
157};
158
159static long bcm47xx_wdt_ioctl(struct file *file,
160 unsigned int cmd, unsigned long arg)
161{
162 void __user *argp = (void __user *)arg;
163 int __user *p = argp;
164 int new_value, retval = -EINVAL;;
165
166 switch (cmd) {
167 case WDIOC_GETSUPPORT:
168 return copy_to_user(argp, &bcm47xx_wdt_info,
169 sizeof(bcm47xx_wdt_info)) ? -EFAULT : 0;
170
171 case WDIOC_GETSTATUS:
172 case WDIOC_GETBOOTSTATUS:
173 return put_user(0, p);
174
175 case WDIOC_SETOPTIONS:
176 if (get_user(new_value, p))
177 return -EFAULT;
178
179 if (new_value & WDIOS_DISABLECARD) {
180 bcm47xx_wdt_stop();
181 retval = 0;
182 }
183
184 if (new_value & WDIOS_ENABLECARD) {
185 bcm47xx_wdt_start();
186 retval = 0;
187 }
188
189 return retval;
190
191 case WDIOC_KEEPALIVE:
192 bcm47xx_wdt_pet();
193 return 0;
194
195 case WDIOC_SETTIMEOUT:
196 if (get_user(new_value, p))
197 return -EFAULT;
198
199 if (bcm47xx_wdt_settimeout(new_value))
200 return -EINVAL;
201
202 bcm47xx_wdt_pet();
203
204 case WDIOC_GETTIMEOUT:
205 return put_user(wdt_time, p);
206
207 default:
208 return -ENOTTY;
209 }
210}
211
212static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
213 unsigned long code, void *unused)
214{
215 if (code == SYS_DOWN || code == SYS_HALT)
216 bcm47xx_wdt_stop();
217 return NOTIFY_DONE;
218}
219
220static const struct file_operations bcm47xx_wdt_fops = {
221 .owner = THIS_MODULE,
222 .llseek = no_llseek,
223 .unlocked_ioctl = bcm47xx_wdt_ioctl,
224 .open = bcm47xx_wdt_open,
225 .release = bcm47xx_wdt_release,
226 .write = bcm47xx_wdt_write,
227};
228
229static struct miscdevice bcm47xx_wdt_miscdev = {
230 .minor = WATCHDOG_MINOR,
231 .name = "watchdog",
232 .fops = &bcm47xx_wdt_fops,
233};
234
235static struct notifier_block bcm47xx_wdt_notifier = {
236 .notifier_call = bcm47xx_wdt_notify_sys,
237};
238
239static int __init bcm47xx_wdt_init(void)
240{
241 int ret;
242
243 if (bcm47xx_wdt_hw_stop() < 0)
244 return -ENODEV;
245
246 setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L);
247
248 if (bcm47xx_wdt_settimeout(wdt_time)) {
249 bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME);
250 printk(KERN_INFO DRV_NAME ": "
251 "wdt_time value must be 0 < wdt_time < %d, using %d\n",
252 (WDT_MAX_TIME + 1), wdt_time);
253 }
254
255 ret = register_reboot_notifier(&bcm47xx_wdt_notifier);
256 if (ret)
257 return ret;
258
259 ret = misc_register(&bcm47xx_wdt_miscdev);
260 if (ret) {
261 unregister_reboot_notifier(&bcm47xx_wdt_notifier);
262 return ret;
263 }
264
265 printk(KERN_INFO "BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
266 wdt_time, nowayout ? ", nowayout" : "");
267 return 0;
268}
269
270static void __exit bcm47xx_wdt_exit(void)
271{
272 if (!nowayout)
273 bcm47xx_wdt_stop();
274
275 misc_deregister(&bcm47xx_wdt_miscdev);
276
277 unregister_reboot_notifier(&bcm47xx_wdt_notifier);
278}
279
280module_init(bcm47xx_wdt_init);
281module_exit(bcm47xx_wdt_exit);
282
283MODULE_AUTHOR("Aleksandar Radovanovic");
284MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx");
285MODULE_LICENSE("GPL");
286MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c
new file mode 100644
index 000000000000..fecb307d28e9
--- /dev/null
+++ b/drivers/watchdog/coh901327_wdt.c
@@ -0,0 +1,537 @@
1/*
2 * coh901327_wdt.c
3 *
4 * Copyright (C) 2008-2009 ST-Ericsson AB
5 * License terms: GNU General Public License (GPL) version 2
6 * Watchdog driver for the ST-Ericsson AB COH 901 327 IP core
7 * Author: Linus Walleij <linus.walleij@stericsson.com>
8 */
9#include <linux/module.h>
10#include <linux/types.h>
11#include <linux/fs.h>
12#include <linux/miscdevice.h>
13#include <linux/watchdog.h>
14#include <linux/interrupt.h>
15#include <linux/pm.h>
16#include <linux/platform_device.h>
17#include <linux/io.h>
18#include <linux/bitops.h>
19#include <linux/uaccess.h>
20#include <linux/clk.h>
21
22#define DRV_NAME "WDOG COH 901 327"
23
24/*
25 * COH 901 327 register definitions
26 */
27
28/* WDOG_FEED Register 32bit (-/W) */
29#define U300_WDOG_FR 0x00
30#define U300_WDOG_FR_FEED_RESTART_TIMER 0xFEEDU
31/* WDOG_TIMEOUT Register 32bit (R/W) */
32#define U300_WDOG_TR 0x04
33#define U300_WDOG_TR_TIMEOUT_MASK 0x7FFFU
34/* WDOG_DISABLE1 Register 32bit (-/W) */
35#define U300_WDOG_D1R 0x08
36#define U300_WDOG_D1R_DISABLE1_DISABLE_TIMER 0x2BADU
37/* WDOG_DISABLE2 Register 32bit (R/W) */
38#define U300_WDOG_D2R 0x0C
39#define U300_WDOG_D2R_DISABLE2_DISABLE_TIMER 0xCAFEU
40#define U300_WDOG_D2R_DISABLE_STATUS_DISABLED 0xDABEU
41#define U300_WDOG_D2R_DISABLE_STATUS_ENABLED 0x0000U
42/* WDOG_STATUS Register 32bit (R/W) */
43#define U300_WDOG_SR 0x10
44#define U300_WDOG_SR_STATUS_TIMED_OUT 0xCFE8U
45#define U300_WDOG_SR_STATUS_NORMAL 0x0000U
46#define U300_WDOG_SR_RESET_STATUS_RESET 0xE8B4U
47/* WDOG_COUNT Register 32bit (R/-) */
48#define U300_WDOG_CR 0x14
49#define U300_WDOG_CR_VALID_IND 0x8000U
50#define U300_WDOG_CR_VALID_STABLE 0x0000U
51#define U300_WDOG_CR_COUNT_VALUE_MASK 0x7FFFU
52/* WDOG_JTAGOVR Register 32bit (R/W) */
53#define U300_WDOG_JOR 0x18
54#define U300_WDOG_JOR_JTAG_MODE_IND 0x0002U
55#define U300_WDOG_JOR_JTAG_WATCHDOG_ENABLE 0x0001U
56/* WDOG_RESTART Register 32bit (-/W) */
57#define U300_WDOG_RR 0x1C
58#define U300_WDOG_RR_RESTART_VALUE_RESUME 0xACEDU
59/* WDOG_IRQ_EVENT Register 32bit (R/W) */
60#define U300_WDOG_IER 0x20
61#define U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND 0x0001U
62#define U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE 0x0001U
63/* WDOG_IRQ_MASK Register 32bit (R/W) */
64#define U300_WDOG_IMR 0x24
65#define U300_WDOG_IMR_WILL_BARK_IRQ_ENABLE 0x0001U
66/* WDOG_IRQ_FORCE Register 32bit (R/W) */
67#define U300_WDOG_IFR 0x28
68#define U300_WDOG_IFR_WILL_BARK_IRQ_FORCE_ENABLE 0x0001U
69
70/* Default timeout in seconds = 1 minute */
71static int margin = 60;
72static resource_size_t phybase;
73static resource_size_t physize;
74static int irq;
75static void __iomem *virtbase;
76static unsigned long coh901327_users;
77static unsigned long boot_status;
78static u16 wdogenablestore;
79static u16 irqmaskstore;
80static struct device *parent;
81
82/*
83 * The watchdog block is of course always clocked, the
84 * clk_enable()/clk_disable() calls are mainly for performing reference
85 * counting higher up in the clock hierarchy.
86 */
87static struct clk *clk;
88
89/*
90 * Enabling and disabling functions.
91 */
92static void coh901327_enable(u16 timeout)
93{
94 u16 val;
95
96 clk_enable(clk);
97 /* Restart timer if it is disabled */
98 val = readw(virtbase + U300_WDOG_D2R);
99 if (val == U300_WDOG_D2R_DISABLE_STATUS_DISABLED)
100 writew(U300_WDOG_RR_RESTART_VALUE_RESUME,
101 virtbase + U300_WDOG_RR);
102 /* Acknowledge any pending interrupt so it doesn't just fire off */
103 writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE,
104 virtbase + U300_WDOG_IER);
105 /* Enable the watchdog interrupt */
106 writew(U300_WDOG_IMR_WILL_BARK_IRQ_ENABLE, virtbase + U300_WDOG_IMR);
107 /* Activate the watchdog timer */
108 writew(timeout, virtbase + U300_WDOG_TR);
109 /* Start the watchdog timer */
110 writew(U300_WDOG_FR_FEED_RESTART_TIMER, virtbase + U300_WDOG_FR);
111 /*
112 * Extra read so that this change propagate in the watchdog.
113 */
114 (void) readw(virtbase + U300_WDOG_CR);
115 val = readw(virtbase + U300_WDOG_D2R);
116 clk_disable(clk);
117 if (val != U300_WDOG_D2R_DISABLE_STATUS_ENABLED)
118 dev_err(parent,
119 "%s(): watchdog not enabled! D2R value %04x\n",
120 __func__, val);
121}
122
123static void coh901327_disable(void)
124{
125 u16 val;
126
127 clk_enable(clk);
128 /* Disable the watchdog interrupt if it is active */
129 writew(0x0000U, virtbase + U300_WDOG_IMR);
130 /* If the watchdog is currently enabled, attempt to disable it */
131 val = readw(virtbase + U300_WDOG_D2R);
132 if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED) {
133 writew(U300_WDOG_D1R_DISABLE1_DISABLE_TIMER,
134 virtbase + U300_WDOG_D1R);
135 writew(U300_WDOG_D2R_DISABLE2_DISABLE_TIMER,
136 virtbase + U300_WDOG_D2R);
137 /* Write this twice (else problems occur) */
138 writew(U300_WDOG_D2R_DISABLE2_DISABLE_TIMER,
139 virtbase + U300_WDOG_D2R);
140 }
141 val = readw(virtbase + U300_WDOG_D2R);
142 clk_disable(clk);
143 if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED)
144 dev_err(parent,
145 "%s(): watchdog not disabled! D2R value %04x\n",
146 __func__, val);
147}
148
149static void coh901327_start(void)
150{
151 coh901327_enable(margin * 100);
152}
153
154static void coh901327_keepalive(void)
155{
156 clk_enable(clk);
157 /* Feed the watchdog */
158 writew(U300_WDOG_FR_FEED_RESTART_TIMER,
159 virtbase + U300_WDOG_FR);
160 clk_disable(clk);
161}
162
163static int coh901327_settimeout(int time)
164{
165 /*
166 * Max margin is 327 since the 10ms
167 * timeout register is max
168 * 0x7FFF = 327670ms ~= 327s.
169 */
170 if (time <= 0 || time > 327)
171 return -EINVAL;
172
173 margin = time;
174 clk_enable(clk);
175 /* Set new timeout value */
176 writew(margin * 100, virtbase + U300_WDOG_TR);
177 /* Feed the dog */
178 writew(U300_WDOG_FR_FEED_RESTART_TIMER,
179 virtbase + U300_WDOG_FR);
180 clk_disable(clk);
181 return 0;
182}
183
184/*
185 * This interrupt occurs 10 ms before the watchdog WILL bark.
186 */
187static irqreturn_t coh901327_interrupt(int irq, void *data)
188{
189 u16 val;
190
191 /*
192 * Ack IRQ? If this occurs we're FUBAR anyway, so
193 * just acknowledge, disable the interrupt and await the imminent end.
194 * If you at some point need a host of callbacks to be called
195 * when the system is about to watchdog-reset, add them here!
196 *
197 * NOTE: on future versions of this IP-block, it will be possible
198 * to prevent a watchdog reset by feeding the watchdog at this
199 * point.
200 */
201 clk_enable(clk);
202 val = readw(virtbase + U300_WDOG_IER);
203 if (val == U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND)
204 writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE,
205 virtbase + U300_WDOG_IER);
206 writew(0x0000U, virtbase + U300_WDOG_IMR);
207 clk_disable(clk);
208 dev_crit(parent, "watchdog is barking!\n");
209 return IRQ_HANDLED;
210}
211
212/*
213 * Allow only one user (daemon) to open the watchdog
214 */
215static int coh901327_open(struct inode *inode, struct file *file)
216{
217 if (test_and_set_bit(1, &coh901327_users))
218 return -EBUSY;
219 coh901327_start();
220 return nonseekable_open(inode, file);
221}
222
223static int coh901327_release(struct inode *inode, struct file *file)
224{
225 clear_bit(1, &coh901327_users);
226 coh901327_disable();
227 return 0;
228}
229
230static ssize_t coh901327_write(struct file *file, const char __user *data,
231 size_t len, loff_t *ppos)
232{
233 if (len)
234 coh901327_keepalive();
235 return len;
236}
237
238static long coh901327_ioctl(struct file *file, unsigned int cmd,
239 unsigned long arg)
240{
241 int ret = -ENOTTY;
242 u16 val;
243 int time;
244 int new_options;
245 union {
246 struct watchdog_info __user *ident;
247 int __user *i;
248 } uarg;
249 static struct watchdog_info ident = {
250 .options = WDIOF_CARDRESET |
251 WDIOF_SETTIMEOUT |
252 WDIOF_KEEPALIVEPING,
253 .identity = "COH 901 327 Watchdog",
254 .firmware_version = 1,
255 };
256 uarg.i = (int __user *)arg;
257
258 switch (cmd) {
259 case WDIOC_GETSUPPORT:
260 ret = copy_to_user(uarg.ident, &ident,
261 sizeof(ident)) ? -EFAULT : 0;
262 break;
263
264 case WDIOC_GETSTATUS:
265 ret = put_user(0, uarg.i);
266 break;
267
268 case WDIOC_GETBOOTSTATUS:
269 ret = put_user(boot_status, uarg.i);
270 break;
271
272 case WDIOC_SETOPTIONS:
273 ret = get_user(new_options, uarg.i);
274 if (ret)
275 break;
276 if (new_options & WDIOS_DISABLECARD)
277 coh901327_disable();
278 if (new_options & WDIOS_ENABLECARD)
279 coh901327_start();
280 ret = 0;
281 break;
282
283 case WDIOC_KEEPALIVE:
284 coh901327_keepalive();
285 ret = 0;
286 break;
287
288 case WDIOC_SETTIMEOUT:
289 ret = get_user(time, uarg.i);
290 if (ret)
291 break;
292
293 ret = coh901327_settimeout(time);
294 if (ret)
295 break;
296 /* Then fall through to return set value */
297
298 case WDIOC_GETTIMEOUT:
299 ret = put_user(margin, uarg.i);
300 break;
301
302 case WDIOC_GETTIMELEFT:
303 clk_enable(clk);
304 /* Read repeatedly until the value is stable! */
305 val = readw(virtbase + U300_WDOG_CR);
306 while (val & U300_WDOG_CR_VALID_IND)
307 val = readw(virtbase + U300_WDOG_CR);
308 val &= U300_WDOG_CR_COUNT_VALUE_MASK;
309 clk_disable(clk);
310 if (val != 0)
311 val /= 100;
312 ret = put_user(val, uarg.i);
313 break;
314 }
315 return ret;
316}
317
318static const struct file_operations coh901327_fops = {
319 .owner = THIS_MODULE,
320 .llseek = no_llseek,
321 .write = coh901327_write,
322 .unlocked_ioctl = coh901327_ioctl,
323 .open = coh901327_open,
324 .release = coh901327_release,
325};
326
327static struct miscdevice coh901327_miscdev = {
328 .minor = WATCHDOG_MINOR,
329 .name = "watchdog",
330 .fops = &coh901327_fops,
331};
332
333static int __exit coh901327_remove(struct platform_device *pdev)
334{
335 misc_deregister(&coh901327_miscdev);
336 coh901327_disable();
337 free_irq(irq, pdev);
338 clk_put(clk);
339 iounmap(virtbase);
340 release_mem_region(phybase, physize);
341 return 0;
342}
343
344
345static int __init coh901327_probe(struct platform_device *pdev)
346{
347 int ret;
348 u16 val;
349 struct resource *res;
350
351 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
352 if (!res)
353 return -ENOENT;
354
355 parent = &pdev->dev;
356 physize = resource_size(res);
357 phybase = res->start;
358
359 if (request_mem_region(phybase, physize, DRV_NAME) == NULL) {
360 ret = -EBUSY;
361 goto out;
362 }
363
364 virtbase = ioremap(phybase, physize);
365 if (!virtbase) {
366 ret = -ENOMEM;
367 goto out_no_remap;
368 }
369
370 clk = clk_get(&pdev->dev, NULL);
371 if (IS_ERR(clk)) {
372 ret = PTR_ERR(clk);
373 dev_err(&pdev->dev, "could not get clock\n");
374 goto out_no_clk;
375 }
376 ret = clk_enable(clk);
377 if (ret) {
378 dev_err(&pdev->dev, "could not enable clock\n");
379 goto out_no_clk_enable;
380 }
381
382 val = readw(virtbase + U300_WDOG_SR);
383 switch (val) {
384 case U300_WDOG_SR_STATUS_TIMED_OUT:
385 dev_info(&pdev->dev,
386 "watchdog timed out since last chip reset!\n");
387 boot_status = WDIOF_CARDRESET;
388 /* Status will be cleared below */
389 break;
390 case U300_WDOG_SR_STATUS_NORMAL:
391 dev_info(&pdev->dev,
392 "in normal status, no timeouts have occurred.\n");
393 break;
394 default:
395 dev_info(&pdev->dev,
396 "contains an illegal status code (%08x)\n", val);
397 break;
398 }
399
400 val = readw(virtbase + U300_WDOG_D2R);
401 switch (val) {
402 case U300_WDOG_D2R_DISABLE_STATUS_DISABLED:
403 dev_info(&pdev->dev, "currently disabled.\n");
404 break;
405 case U300_WDOG_D2R_DISABLE_STATUS_ENABLED:
406 dev_info(&pdev->dev,
407 "currently enabled! (disabling it now)\n");
408 coh901327_disable();
409 break;
410 default:
411 dev_err(&pdev->dev,
412 "contains an illegal enable/disable code (%08x)\n",
413 val);
414 break;
415 }
416
417 /* Reset the watchdog */
418 writew(U300_WDOG_SR_RESET_STATUS_RESET, virtbase + U300_WDOG_SR);
419
420 irq = platform_get_irq(pdev, 0);
421 if (request_irq(irq, coh901327_interrupt, IRQF_DISABLED,
422 DRV_NAME " Bark", pdev)) {
423 ret = -EIO;
424 goto out_no_irq;
425 }
426
427 clk_disable(clk);
428
429 ret = misc_register(&coh901327_miscdev);
430 if (ret == 0)
431 dev_info(&pdev->dev,
432 "initialized. timer margin=%d sec\n", margin);
433 else
434 goto out_no_wdog;
435
436 return 0;
437
438out_no_wdog:
439 free_irq(irq, pdev);
440out_no_irq:
441 clk_disable(clk);
442out_no_clk_enable:
443 clk_put(clk);
444out_no_clk:
445 iounmap(virtbase);
446out_no_remap:
447 release_mem_region(phybase, SZ_4K);
448out:
449 return ret;
450}
451
452#ifdef CONFIG_PM
453static int coh901327_suspend(struct platform_device *pdev, pm_message_t state)
454{
455 irqmaskstore = readw(virtbase + U300_WDOG_IMR) & 0x0001U;
456 wdogenablestore = readw(virtbase + U300_WDOG_D2R);
457 /* If watchdog is on, disable it here and now */
458 if (wdogenablestore == U300_WDOG_D2R_DISABLE_STATUS_ENABLED)
459 coh901327_disable();
460 return 0;
461}
462
463static int coh901327_resume(struct platform_device *pdev)
464{
465 /* Restore the watchdog interrupt */
466 writew(irqmaskstore, virtbase + U300_WDOG_IMR);
467 if (wdogenablestore == U300_WDOG_D2R_DISABLE_STATUS_ENABLED) {
468 /* Restart the watchdog timer */
469 writew(U300_WDOG_RR_RESTART_VALUE_RESUME,
470 virtbase + U300_WDOG_RR);
471 writew(U300_WDOG_FR_FEED_RESTART_TIMER,
472 virtbase + U300_WDOG_FR);
473 }
474 return 0;
475}
476#else
477#define coh901327_suspend NULL
478#define coh901327_resume NULL
479#endif
480
481/*
482 * Mistreating the watchdog is the only way to perform a software reset of the
483 * system on EMP platforms. So we implement this and export a symbol for it.
484 */
485void coh901327_watchdog_reset(void)
486{
487 /* Enable even if on JTAG too */
488 writew(U300_WDOG_JOR_JTAG_WATCHDOG_ENABLE,
489 virtbase + U300_WDOG_JOR);
490 /*
491 * Timeout = 5s, we have to wait for the watchdog reset to
492 * actually take place: the watchdog will be reloaded with the
493 * default value immediately, so we HAVE to reboot and get back
494 * into the kernel in 30s, or the device will reboot again!
495 * The boot loader will typically deactivate the watchdog, so we
496 * need time enough for the boot loader to get to the point of
497 * deactivating the watchdog before it is shut down by it.
498 *
499 * NOTE: on future versions of the watchdog, this restriction is
500 * gone: the watchdog will be reloaded with a defaul value (1 min)
501 * instead of last value, and you can conveniently set the watchdog
502 * timeout to 10ms (value = 1) without any problems.
503 */
504 coh901327_enable(500);
505 /* Return and await doom */
506}
507
508static struct platform_driver coh901327_driver = {
509 .driver = {
510 .owner = THIS_MODULE,
511 .name = "coh901327_wdog",
512 },
513 .remove = __exit_p(coh901327_remove),
514 .suspend = coh901327_suspend,
515 .resume = coh901327_resume,
516};
517
518static int __init coh901327_init(void)
519{
520 return platform_driver_probe(&coh901327_driver, coh901327_probe);
521}
522module_init(coh901327_init);
523
524static void __exit coh901327_exit(void)
525{
526 platform_driver_unregister(&coh901327_driver);
527}
528module_exit(coh901327_exit);
529
530MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
531MODULE_DESCRIPTION("COH 901 327 Watchdog");
532
533module_param(margin, int, 0);
534MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
535
536MODULE_LICENSE("GPL");
537MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index c0b9169ba5d5..a6c5674c78e6 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -120,7 +120,8 @@ static int nowayout = WATCHDOG_NOWAYOUT;
120static char expect_release; 120static char expect_release;
121static unsigned long hpwdt_is_open; 121static unsigned long hpwdt_is_open;
122static unsigned int allow_kdump; 122static unsigned int allow_kdump;
123static int hpwdt_nmi_sourcing; 123static unsigned int hpwdt_nmi_sourcing;
124static unsigned int priority; /* hpwdt at end of die_notify list */
124 125
125static void __iomem *pci_mem_addr; /* the PCI-memory address */ 126static void __iomem *pci_mem_addr; /* the PCI-memory address */
126static unsigned long __iomem *hpwdt_timer_reg; 127static unsigned long __iomem *hpwdt_timer_reg;
@@ -623,7 +624,7 @@ static struct miscdevice hpwdt_miscdev = {
623 624
624static struct notifier_block die_notifier = { 625static struct notifier_block die_notifier = {
625 .notifier_call = hpwdt_pretimeout, 626 .notifier_call = hpwdt_pretimeout,
626 .priority = 0x7FFFFFFF, 627 .priority = 0,
627}; 628};
628 629
629/* 630/*
@@ -641,7 +642,8 @@ static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev)
641 hpwdt_nmi_sourcing = 1; 642 hpwdt_nmi_sourcing = 1;
642 else 643 else
643 dev_warn(&dev->dev, "NMI sourcing is disabled. To enable this " 644 dev_warn(&dev->dev, "NMI sourcing is disabled. To enable this "
644 "functionality you must reboot with nmi_watchdog=0.\n"); 645 "functionality you must reboot with nmi_watchdog=0 "
646 "and load the hpwdt driver with priority=1.\n");
645} 647}
646#else 648#else
647static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev) 649static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev)
@@ -714,6 +716,14 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev,
714 cmn_regs.u1.rah = 0x0D; 716 cmn_regs.u1.rah = 0x0D;
715 cmn_regs.u1.ral = 0x02; 717 cmn_regs.u1.ral = 0x02;
716 718
719 /*
720 * If the priority is set to 1, then we will be put first on the
721 * die notify list to handle a critical NMI. The default is to
722 * be last so other users of the NMI signal can function.
723 */
724 if (priority)
725 die_notifier.priority = 0x7FFFFFFF;
726
717 retval = register_die_notifier(&die_notifier); 727 retval = register_die_notifier(&die_notifier);
718 if (retval != 0) { 728 if (retval != 0) {
719 dev_warn(&dev->dev, 729 dev_warn(&dev->dev,
@@ -733,9 +743,11 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev,
733 printk(KERN_INFO 743 printk(KERN_INFO
734 "hp Watchdog Timer Driver: %s" 744 "hp Watchdog Timer Driver: %s"
735 ", timer margin: %d seconds (nowayout=%d)" 745 ", timer margin: %d seconds (nowayout=%d)"
736 ", allow kernel dump: %s (default = 0/OFF).\n", 746 ", allow kernel dump: %s (default = 0/OFF)"
747 ", priority: %s (default = 0/LAST).\n",
737 HPWDT_VERSION, soft_margin, nowayout, 748 HPWDT_VERSION, soft_margin, nowayout,
738 (allow_kdump == 0) ? "OFF" : "ON"); 749 (allow_kdump == 0) ? "OFF" : "ON",
750 (priority == 0) ? "LAST" : "FIRST");
739 751
740 return 0; 752 return 0;
741 753
@@ -798,5 +810,9 @@ module_param(nowayout, int, 0);
798MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 810MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
799 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 811 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
800 812
813module_param(priority, int, 0);
814MODULE_PARM_DESC(priority, "The hpwdt driver handles NMIs first or last"
815 " (default = 0/Last)\n");
816
801module_init(hpwdt_init); 817module_init(hpwdt_init);
802module_exit(hpwdt_cleanup); 818module_exit(hpwdt_cleanup);
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index f2713851aaab..3ed571a2ab18 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -159,6 +159,7 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
159 file->private_data = (void *) wdev; 159 file->private_data = (void *) wdev;
160 160
161 omap_wdt_set_timeout(wdev); 161 omap_wdt_set_timeout(wdev);
162 omap_wdt_ping(wdev); /* trigger loading of new timeout value */
162 omap_wdt_enable(wdev); 163 omap_wdt_enable(wdev);
163 164
164 return nonseekable_open(inode, file); 165 return nonseekable_open(inode, file);
@@ -313,6 +314,9 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
313 314
314 platform_set_drvdata(pdev, wdev); 315 platform_set_drvdata(pdev, wdev);
315 316
317 clk_enable(wdev->ick);
318 clk_enable(wdev->fck);
319
316 omap_wdt_disable(wdev); 320 omap_wdt_disable(wdev);
317 omap_wdt_adjust_timeout(timer_margin); 321 omap_wdt_adjust_timeout(timer_margin);
318 322
@@ -332,6 +336,9 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev)
332 /* autogate OCP interface clock */ 336 /* autogate OCP interface clock */
333 __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG); 337 __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG);
334 338
339 clk_disable(wdev->ick);
340 clk_disable(wdev->fck);
341
335 omap_wdt_dev = pdev; 342 omap_wdt_dev = pdev;
336 343
337 return 0; 344 return 0;
diff --git a/drivers/watchdog/pnx833x_wdt.c b/drivers/watchdog/pnx833x_wdt.c
new file mode 100644
index 000000000000..538ec2c05197
--- /dev/null
+++ b/drivers/watchdog/pnx833x_wdt.c
@@ -0,0 +1,282 @@
1/*
2 * PNX833x Hardware Watchdog Driver
3 * Copyright 2008 NXP Semiconductors
4 * Daniel Laird <daniel.j.laird@nxp.com>
5 * Andre McCurdy <andre.mccurdy@nxp.com>
6 *
7 * Heavily based upon - IndyDog 0.3
8 * A Hardware Watchdog Device for SGI IP22
9 *
10 * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 *
17 * based on softdog.c by Alan Cox <alan@redhat.com>
18 */
19
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/types.h>
23#include <linux/kernel.h>
24#include <linux/fs.h>
25#include <linux/mm.h>
26#include <linux/miscdevice.h>
27#include <linux/watchdog.h>
28#include <linux/notifier.h>
29#include <linux/reboot.h>
30#include <linux/init.h>
31#include <asm/mach-pnx833x/pnx833x.h>
32
33#define PFX "pnx833x: "
34#define WATCHDOG_TIMEOUT 30 /* 30 sec Maximum timeout */
35#define WATCHDOG_COUNT_FREQUENCY 68000000U /* Watchdog counts at 68MHZ. */
36
37/** CONFIG block */
38#define PNX833X_CONFIG (0x07000U)
39#define PNX833X_CONFIG_CPU_WATCHDOG (0x54)
40#define PNX833X_CONFIG_CPU_WATCHDOG_COMPARE (0x58)
41#define PNX833X_CONFIG_CPU_COUNTERS_CONTROL (0x1c)
42
43/** RESET block */
44#define PNX833X_RESET (0x08000U)
45#define PNX833X_RESET_CONFIG (0x08)
46
47static int pnx833x_wdt_alive;
48
49/* Set default timeout in MHZ.*/
50static int pnx833x_wdt_timeout = (WATCHDOG_TIMEOUT * WATCHDOG_COUNT_FREQUENCY);
51module_param(pnx833x_wdt_timeout, int, 0);
52MODULE_PARM_DESC(timeout, "Watchdog timeout in Mhz. (68Mhz clock), default="
53 __MODULE_STRING(pnx833x_wdt_timeout) "(30 seconds).");
54
55static int nowayout = WATCHDOG_NOWAYOUT;
56module_param(nowayout, int, 0);
57MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
58 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
59
60static int start_enabled = 1;
61module_param(start_enabled, int, 0);
62MODULE_PARM_DESC(start_enabled, "Watchdog is started on module insertion "
63 "(default=" __MODULE_STRING(start_enabled) ")");
64
65static void pnx833x_wdt_start(void)
66{
67 /* Enable watchdog causing reset. */
68 PNX833X_REG(PNX833X_RESET + PNX833X_RESET_CONFIG) |= 0x1;
69 /* Set timeout.*/
70 PNX833X_REG(PNX833X_CONFIG +
71 PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
72 /* Enable watchdog. */
73 PNX833X_REG(PNX833X_CONFIG +
74 PNX833X_CONFIG_CPU_COUNTERS_CONTROL) |= 0x1;
75
76 printk(KERN_INFO PFX "Started watchdog timer.\n");
77}
78
79static void pnx833x_wdt_stop(void)
80{
81 /* Disable watchdog causing reset. */
82 PNX833X_REG(PNX833X_RESET + PNX833X_CONFIG) &= 0xFFFFFFFE;
83 /* Disable watchdog.*/
84 PNX833X_REG(PNX833X_CONFIG +
85 PNX833X_CONFIG_CPU_COUNTERS_CONTROL) &= 0xFFFFFFFE;
86
87 printk(KERN_INFO PFX "Stopped watchdog timer.\n");
88}
89
90static void pnx833x_wdt_ping(void)
91{
92 PNX833X_REG(PNX833X_CONFIG +
93 PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = pnx833x_wdt_timeout;
94}
95
96/*
97 * Allow only one person to hold it open
98 */
99static int pnx833x_wdt_open(struct inode *inode, struct file *file)
100{
101 if (test_and_set_bit(0, &pnx833x_wdt_alive))
102 return -EBUSY;
103
104 if (nowayout)
105 __module_get(THIS_MODULE);
106
107 /* Activate timer */
108 if (!start_enabled)
109 pnx833x_wdt_start();
110
111 pnx833x_wdt_ping();
112
113 printk(KERN_INFO "Started watchdog timer.\n");
114
115 return nonseekable_open(inode, file);
116}
117
118static int pnx833x_wdt_release(struct inode *inode, struct file *file)
119{
120 /* Shut off the timer.
121 * Lock it in if it's a module and we defined ...NOWAYOUT */
122 if (!nowayout)
123 pnx833x_wdt_stop(); /* Turn the WDT off */
124
125 clear_bit(0, &pnx833x_wdt_alive);
126 return 0;
127}
128
129static ssize_t pnx833x_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
130{
131 /* Refresh the timer. */
132 if (len)
133 pnx833x_wdt_ping();
134
135 return len;
136}
137
138static long pnx833x_wdt_ioctl(struct file *file, unsigned int cmd,
139 unsigned long arg)
140{
141 int options, new_timeout = 0;
142 uint32_t timeout, timeout_left = 0;
143
144 static struct watchdog_info ident = {
145 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT,
146 .firmware_version = 0,
147 .identity = "Hardware Watchdog for PNX833x",
148 };
149
150 switch (cmd) {
151 default:
152 return -ENOTTY;
153
154 case WDIOC_GETSUPPORT:
155 if (copy_to_user((struct watchdog_info *)arg,
156 &ident, sizeof(ident)))
157 return -EFAULT;
158 return 0;
159
160 case WDIOC_GETSTATUS:
161 case WDIOC_GETBOOTSTATUS:
162 return put_user(0, (int *)arg);
163
164 case WDIOC_SETOPTIONS:
165 if (get_user(options, (int *)arg))
166 return -EFAULT;
167
168 if (options & WDIOS_DISABLECARD)
169 pnx833x_wdt_stop();
170
171 if (options & WDIOS_ENABLECARD)
172 pnx833x_wdt_start();
173
174 return 0;
175
176 case WDIOC_KEEPALIVE:
177 pnx833x_wdt_ping();
178 return 0;
179
180 case WDIOC_SETTIMEOUT:
181 {
182 if (get_user(new_timeout, (int *)arg))
183 return -EFAULT;
184
185 pnx833x_wdt_timeout = new_timeout;
186 PNX833X_REG(PNX833X_CONFIG +
187 PNX833X_CONFIG_CPU_WATCHDOG_COMPARE) = new_timeout;
188 return put_user(new_timeout, (int *)arg);
189 }
190
191 case WDIOC_GETTIMEOUT:
192 timeout = PNX833X_REG(PNX833X_CONFIG +
193 PNX833X_CONFIG_CPU_WATCHDOG_COMPARE);
194 return put_user(timeout, (int *)arg);
195
196 case WDIOC_GETTIMELEFT:
197 timeout_left = PNX833X_REG(PNX833X_CONFIG +
198 PNX833X_CONFIG_CPU_WATCHDOG);
199 return put_user(timeout_left, (int *)arg);
200
201 }
202}
203
204static int pnx833x_wdt_notify_sys(struct notifier_block *this,
205 unsigned long code, void *unused)
206{
207 if (code == SYS_DOWN || code == SYS_HALT)
208 pnx833x_wdt_stop(); /* Turn the WDT off */
209
210 return NOTIFY_DONE;
211}
212
213static const struct file_operations pnx833x_wdt_fops = {
214 .owner = THIS_MODULE,
215 .llseek = no_llseek,
216 .write = pnx833x_wdt_write,
217 .unlocked_ioctl = pnx833x_wdt_ioctl,
218 .open = pnx833x_wdt_open,
219 .release = pnx833x_wdt_release,
220};
221
222static struct miscdevice pnx833x_wdt_miscdev = {
223 .minor = WATCHDOG_MINOR,
224 .name = "watchdog",
225 .fops = &pnx833x_wdt_fops,
226};
227
228static struct notifier_block pnx833x_wdt_notifier = {
229 .notifier_call = pnx833x_wdt_notify_sys,
230};
231
232static char banner[] __initdata =
233 KERN_INFO PFX "Hardware Watchdog Timer for PNX833x: Version 0.1\n";
234
235static int __init watchdog_init(void)
236{
237 int ret, cause;
238
239 /* Lets check the reason for the reset.*/
240 cause = PNX833X_REG(PNX833X_RESET);
241 /*If bit 31 is set then watchdog was cause of reset.*/
242 if (cause & 0x80000000) {
243 printk(KERN_INFO PFX "The system was previously reset due to "
244 "the watchdog firing - please investigate...\n");
245 }
246
247 ret = register_reboot_notifier(&pnx833x_wdt_notifier);
248 if (ret) {
249 printk(KERN_ERR PFX
250 "cannot register reboot notifier (err=%d)\n", ret);
251 return ret;
252 }
253
254 ret = misc_register(&pnx833x_wdt_miscdev);
255 if (ret) {
256 printk(KERN_ERR PFX
257 "cannot register miscdev on minor=%d (err=%d)\n",
258 WATCHDOG_MINOR, ret);
259 unregister_reboot_notifier(&pnx833x_wdt_notifier);
260 return ret;
261 }
262
263 printk(banner);
264 if (start_enabled)
265 pnx833x_wdt_start();
266
267 return 0;
268}
269
270static void __exit watchdog_exit(void)
271{
272 misc_deregister(&pnx833x_wdt_miscdev);
273 unregister_reboot_notifier(&pnx833x_wdt_notifier);
274}
275
276module_init(watchdog_init);
277module_exit(watchdog_exit);
278
279MODULE_AUTHOR("Daniel Laird/Andre McCurdy");
280MODULE_DESCRIPTION("Hardware Watchdog Device for PNX833x");
281MODULE_LICENSE("GPL");
282MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c
new file mode 100644
index 000000000000..5dd952681f32
--- /dev/null
+++ b/drivers/watchdog/stmp3xxx_wdt.c
@@ -0,0 +1,296 @@
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#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/fs.h>
12#include <linux/miscdevice.h>
13#include <linux/watchdog.h>
14#include <linux/platform_device.h>
15#include <linux/spinlock.h>
16#include <linux/uaccess.h>
17
18#include <mach/platform.h>
19#include <mach/regs-rtc.h>
20
21#define DEFAULT_HEARTBEAT 19
22#define MAX_HEARTBEAT (0x10000000 >> 6)
23
24/* missing bitmask in headers */
25#define BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER 0x80000000
26
27#define WDT_IN_USE 0
28#define WDT_OK_TO_CLOSE 1
29
30#define WDOG_COUNTER_RATE 1000 /* 1 kHz clock */
31
32static DEFINE_SPINLOCK(stmp3xxx_wdt_io_lock);
33static unsigned long wdt_status;
34static const int nowayout = WATCHDOG_NOWAYOUT;
35static int heartbeat = DEFAULT_HEARTBEAT;
36static unsigned long boot_status;
37
38static void wdt_enable(u32 value)
39{
40 spin_lock(&stmp3xxx_wdt_io_lock);
41 __raw_writel(value, REGS_RTC_BASE + HW_RTC_WATCHDOG);
42 stmp3xxx_setl(BM_RTC_CTRL_WATCHDOGEN, REGS_RTC_BASE + HW_RTC_CTRL);
43 stmp3xxx_setl(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER,
44 REGS_RTC_BASE + HW_RTC_PERSISTENT1);
45 spin_unlock(&stmp3xxx_wdt_io_lock);
46}
47
48static void wdt_disable(void)
49{
50 spin_lock(&stmp3xxx_wdt_io_lock);
51 stmp3xxx_clearl(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER,
52 REGS_RTC_BASE + HW_RTC_PERSISTENT1);
53 stmp3xxx_clearl(BM_RTC_CTRL_WATCHDOGEN, REGS_RTC_BASE + HW_RTC_CTRL);
54 spin_unlock(&stmp3xxx_wdt_io_lock);
55}
56
57static void wdt_ping(void)
58{
59 wdt_enable(heartbeat * WDOG_COUNTER_RATE);
60}
61
62static int stmp3xxx_wdt_open(struct inode *inode, struct file *file)
63{
64 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
65 return -EBUSY;
66
67 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
68 wdt_ping();
69
70 return nonseekable_open(inode, file);
71}
72
73static ssize_t stmp3xxx_wdt_write(struct file *file, const char __user *data,
74 size_t len, loff_t *ppos)
75{
76 if (len) {
77 if (!nowayout) {
78 size_t i;
79
80 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
81
82 for (i = 0; i != len; i++) {
83 char c;
84
85 if (get_user(c, data + i))
86 return -EFAULT;
87 if (c == 'V')
88 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
89 }
90 }
91 wdt_ping();
92 }
93
94 return len;
95}
96
97static struct watchdog_info ident = {
98 .options = WDIOF_CARDRESET |
99 WDIOF_MAGICCLOSE |
100 WDIOF_SETTIMEOUT |
101 WDIOF_KEEPALIVEPING,
102 .identity = "STMP3XXX Watchdog",
103};
104
105static long stmp3xxx_wdt_ioctl(struct file *file, unsigned int cmd,
106 unsigned long arg)
107{
108 void __user *argp = (void __user *)arg;
109 int __user *p = argp;
110 int new_heartbeat, opts;
111 int ret = -ENOTTY;
112
113 switch (cmd) {
114 case WDIOC_GETSUPPORT:
115 ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
116 break;
117
118 case WDIOC_GETSTATUS:
119 ret = put_user(0, p);
120 break;
121
122 case WDIOC_GETBOOTSTATUS:
123 ret = put_user(boot_status, p);
124 break;
125
126 case WDIOC_SETOPTIONS:
127 if (get_user(opts, p)) {
128 ret = -EFAULT;
129 break;
130 }
131 if (opts & WDIOS_DISABLECARD)
132 wdt_disable();
133 else if (opts & WDIOS_ENABLECARD)
134 wdt_ping();
135 else {
136 pr_debug("%s: unknown option 0x%x\n", __func__, opts);
137 ret = -EINVAL;
138 break;
139 }
140 ret = 0;
141 break;
142
143 case WDIOC_KEEPALIVE:
144 wdt_ping();
145 ret = 0;
146 break;
147
148 case WDIOC_SETTIMEOUT:
149 if (get_user(new_heartbeat, p)) {
150 ret = -EFAULT;
151 break;
152 }
153 if (new_heartbeat <= 0 || new_heartbeat > MAX_HEARTBEAT) {
154 ret = -EINVAL;
155 break;
156 }
157
158 heartbeat = new_heartbeat;
159 wdt_ping();
160 /* Fall through */
161
162 case WDIOC_GETTIMEOUT:
163 ret = put_user(heartbeat, p);
164 break;
165 }
166 return ret;
167}
168
169static int stmp3xxx_wdt_release(struct inode *inode, struct file *file)
170{
171 int ret = 0;
172
173 if (!nowayout) {
174 if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
175 wdt_ping();
176 pr_debug("%s: Device closed unexpectdly\n", __func__);
177 ret = -EINVAL;
178 } else {
179 wdt_disable();
180 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
181 }
182 }
183 clear_bit(WDT_IN_USE, &wdt_status);
184
185 return ret;
186}
187
188static const struct file_operations stmp3xxx_wdt_fops = {
189 .owner = THIS_MODULE,
190 .llseek = no_llseek,
191 .write = stmp3xxx_wdt_write,
192 .unlocked_ioctl = stmp3xxx_wdt_ioctl,
193 .open = stmp3xxx_wdt_open,
194 .release = stmp3xxx_wdt_release,
195};
196
197static struct miscdevice stmp3xxx_wdt_miscdev = {
198 .minor = WATCHDOG_MINOR,
199 .name = "watchdog",
200 .fops = &stmp3xxx_wdt_fops,
201};
202
203static int __devinit stmp3xxx_wdt_probe(struct platform_device *pdev)
204{
205 int ret = 0;
206
207 if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
208 heartbeat = DEFAULT_HEARTBEAT;
209
210 boot_status = __raw_readl(REGS_RTC_BASE + HW_RTC_PERSISTENT1) &
211 BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER;
212 boot_status = !!boot_status;
213 stmp3xxx_clearl(BV_RTC_PERSISTENT1_GENERAL__RTC_FORCE_UPDATER,
214 REGS_RTC_BASE + HW_RTC_PERSISTENT1);
215 wdt_disable(); /* disable for now */
216
217 ret = misc_register(&stmp3xxx_wdt_miscdev);
218 if (ret < 0) {
219 dev_err(&pdev->dev, "cannot register misc device\n");
220 return ret;
221 }
222
223 printk(KERN_INFO "stmp3xxx watchdog: initialized, heartbeat %d sec\n",
224 heartbeat);
225
226 return ret;
227}
228
229static int __devexit stmp3xxx_wdt_remove(struct platform_device *pdev)
230{
231 misc_deregister(&stmp3xxx_wdt_miscdev);
232 return 0;
233}
234
235#ifdef CONFIG_PM
236static int wdt_suspended;
237static u32 wdt_saved_time;
238
239static int stmp3xxx_wdt_suspend(struct platform_device *pdev,
240 pm_message_t state)
241{
242 if (__raw_readl(REGS_RTC_BASE + HW_RTC_CTRL) &
243 BM_RTC_CTRL_WATCHDOGEN) {
244 wdt_suspended = 1;
245 wdt_saved_time = __raw_readl(REGS_RTC_BASE + HW_RTC_WATCHDOG);
246 wdt_disable();
247 }
248 return 0;
249}
250
251static int stmp3xxx_wdt_resume(struct platform_device *pdev)
252{
253 if (wdt_suspended) {
254 wdt_enable(wdt_saved_time);
255 wdt_suspended = 0;
256 }
257 return 0;
258}
259#else
260#define stmp3xxx_wdt_suspend NULL
261#define stmp3xxx_wdt_resume NULL
262#endif
263
264static struct platform_driver platform_wdt_driver = {
265 .driver = {
266 .name = "stmp3xxx_wdt",
267 },
268 .probe = stmp3xxx_wdt_probe,
269 .remove = __devexit_p(stmp3xxx_wdt_remove),
270 .suspend = stmp3xxx_wdt_suspend,
271 .resume = stmp3xxx_wdt_resume,
272};
273
274static int __init stmp3xxx_wdt_init(void)
275{
276 return platform_driver_register(&platform_wdt_driver);
277}
278
279static void __exit stmp3xxx_wdt_exit(void)
280{
281 return platform_driver_unregister(&platform_wdt_driver);
282}
283
284module_init(stmp3xxx_wdt_init);
285module_exit(stmp3xxx_wdt_exit);
286
287MODULE_DESCRIPTION("STMP3XXX Watchdog Driver");
288MODULE_LICENSE("GPL");
289
290module_param(heartbeat, int, 0);
291MODULE_PARM_DESC(heartbeat,
292 "Watchdog heartbeat period in seconds from 1 to "
293 __MODULE_STRING(MAX_HEARTBEAT) ", default "
294 __MODULE_STRING(DEFAULT_HEARTBEAT));
295
296MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c
new file mode 100644
index 000000000000..cb46556f2973
--- /dev/null
+++ b/drivers/watchdog/twl4030_wdt.c
@@ -0,0 +1,272 @@
1/*
2 * Copyright (C) Nokia Corporation
3 *
4 * Written by Timo Kokkonen <timo.t.kokkonen at nokia.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/module.h>
22#include <linux/types.h>
23#include <linux/kernel.h>
24#include <linux/fs.h>
25#include <linux/watchdog.h>
26#include <linux/platform_device.h>
27#include <linux/miscdevice.h>
28#include <linux/uaccess.h>
29#include <linux/i2c/twl4030.h>
30
31#define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3
32
33#define TWL4030_WDT_STATE_OPEN 0x1
34#define TWL4030_WDT_STATE_ACTIVE 0x8
35
36static struct platform_device *twl4030_wdt_dev;
37
38struct twl4030_wdt {
39 struct miscdevice miscdev;
40 int timer_margin;
41 unsigned long state;
42};
43
44static int nowayout = WATCHDOG_NOWAYOUT;
45module_param(nowayout, int, 0);
46MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
47 "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
48
49static int twl4030_wdt_write(unsigned char val)
50{
51 return twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val,
52 TWL4030_WATCHDOG_CFG_REG_OFFS);
53}
54
55static int twl4030_wdt_enable(struct twl4030_wdt *wdt)
56{
57 return twl4030_wdt_write(wdt->timer_margin + 1);
58}
59
60static int twl4030_wdt_disable(struct twl4030_wdt *wdt)
61{
62 return twl4030_wdt_write(0);
63}
64
65static int twl4030_wdt_set_timeout(struct twl4030_wdt *wdt, int timeout)
66{
67 if (timeout < 0 || timeout > 30) {
68 dev_warn(wdt->miscdev.parent,
69 "Timeout can only be in the range [0-30] seconds");
70 return -EINVAL;
71 }
72 wdt->timer_margin = timeout;
73 return twl4030_wdt_enable(wdt);
74}
75
76static ssize_t twl4030_wdt_write_fop(struct file *file,
77 const char __user *data, size_t len, loff_t *ppos)
78{
79 struct twl4030_wdt *wdt = file->private_data;
80
81 if (len)
82 twl4030_wdt_enable(wdt);
83
84 return len;
85}
86
87static long twl4030_wdt_ioctl(struct file *file,
88 unsigned int cmd, unsigned long arg)
89{
90 void __user *argp = (void __user *)arg;
91 int __user *p = argp;
92 int new_margin;
93 struct twl4030_wdt *wdt = file->private_data;
94
95 static const struct watchdog_info twl4030_wd_ident = {
96 .identity = "TWL4030 Watchdog",
97 .options = WDIOF_SETTIMEOUT,
98 .firmware_version = 0,
99 };
100
101 switch (cmd) {
102 case WDIOC_GETSUPPORT:
103 return copy_to_user(argp, &twl4030_wd_ident,
104 sizeof(twl4030_wd_ident)) ? -EFAULT : 0;
105
106 case WDIOC_GETSTATUS:
107 case WDIOC_GETBOOTSTATUS:
108 return put_user(0, p);
109
110 case WDIOC_KEEPALIVE:
111 twl4030_wdt_enable(wdt);
112 break;
113
114 case WDIOC_SETTIMEOUT:
115 if (get_user(new_margin, p))
116 return -EFAULT;
117 if (twl4030_wdt_set_timeout(wdt, new_margin))
118 return -EINVAL;
119 return put_user(wdt->timer_margin, p);
120
121 case WDIOC_GETTIMEOUT:
122 return put_user(wdt->timer_margin, p);
123
124 default:
125 return -ENOTTY;
126 }
127
128 return 0;
129}
130
131static int twl4030_wdt_open(struct inode *inode, struct file *file)
132{
133 struct twl4030_wdt *wdt = platform_get_drvdata(twl4030_wdt_dev);
134
135 /* /dev/watchdog can only be opened once */
136 if (test_and_set_bit(0, &wdt->state))
137 return -EBUSY;
138
139 wdt->state |= TWL4030_WDT_STATE_ACTIVE;
140 file->private_data = (void *) wdt;
141
142 twl4030_wdt_enable(wdt);
143 return nonseekable_open(inode, file);
144}
145
146static int twl4030_wdt_release(struct inode *inode, struct file *file)
147{
148 struct twl4030_wdt *wdt = file->private_data;
149 if (nowayout) {
150 dev_alert(wdt->miscdev.parent,
151 "Unexpected close, watchdog still running!\n");
152 twl4030_wdt_enable(wdt);
153 } else {
154 if (twl4030_wdt_disable(wdt))
155 return -EFAULT;
156 wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
157 }
158
159 clear_bit(0, &wdt->state);
160 return 0;
161}
162
163static const struct file_operations twl4030_wdt_fops = {
164 .owner = THIS_MODULE,
165 .llseek = no_llseek,
166 .open = twl4030_wdt_open,
167 .release = twl4030_wdt_release,
168 .unlocked_ioctl = twl4030_wdt_ioctl,
169 .write = twl4030_wdt_write_fop,
170};
171
172static int __devinit twl4030_wdt_probe(struct platform_device *pdev)
173{
174 int ret = 0;
175 struct twl4030_wdt *wdt;
176
177 wdt = kzalloc(sizeof(struct twl4030_wdt), GFP_KERNEL);
178 if (!wdt)
179 return -ENOMEM;
180
181 wdt->state = 0;
182 wdt->timer_margin = 30;
183 wdt->miscdev.parent = &pdev->dev;
184 wdt->miscdev.fops = &twl4030_wdt_fops;
185 wdt->miscdev.minor = WATCHDOG_MINOR;
186 wdt->miscdev.name = "watchdog";
187
188 platform_set_drvdata(pdev, wdt);
189
190 twl4030_wdt_dev = pdev;
191
192 ret = misc_register(&wdt->miscdev);
193 if (ret) {
194 dev_err(wdt->miscdev.parent,
195 "Failed to register misc device\n");
196 platform_set_drvdata(pdev, NULL);
197 kfree(wdt);
198 twl4030_wdt_dev = NULL;
199 return ret;
200 }
201 return 0;
202}
203
204static int __devexit twl4030_wdt_remove(struct platform_device *pdev)
205{
206 struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
207
208 if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
209 if (twl4030_wdt_disable(wdt))
210 return -EFAULT;
211
212 wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
213 misc_deregister(&wdt->miscdev);
214
215 platform_set_drvdata(pdev, NULL);
216 kfree(wdt);
217 twl4030_wdt_dev = NULL;
218
219 return 0;
220}
221
222#ifdef CONFIG_PM
223static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
224{
225 struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
226 if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
227 return twl4030_wdt_disable(wdt);
228
229 return 0;
230}
231
232static int twl4030_wdt_resume(struct platform_device *pdev)
233{
234 struct twl4030_wdt *wdt = platform_get_drvdata(pdev);
235 if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
236 return twl4030_wdt_enable(wdt);
237
238 return 0;
239}
240#else
241#define twl4030_wdt_suspend NULL
242#define twl4030_wdt_resume NULL
243#endif
244
245static struct platform_driver twl4030_wdt_driver = {
246 .probe = twl4030_wdt_probe,
247 .remove = __devexit_p(twl4030_wdt_remove),
248 .suspend = twl4030_wdt_suspend,
249 .resume = twl4030_wdt_resume,
250 .driver = {
251 .owner = THIS_MODULE,
252 .name = "twl4030_wdt",
253 },
254};
255
256static int __devinit twl4030_wdt_init(void)
257{
258 return platform_driver_register(&twl4030_wdt_driver);
259}
260module_init(twl4030_wdt_init);
261
262static void __devexit twl4030_wdt_exit(void)
263{
264 platform_driver_unregister(&twl4030_wdt_driver);
265}
266module_exit(twl4030_wdt_exit);
267
268MODULE_AUTHOR("Nokia Corporation");
269MODULE_LICENSE("GPL");
270MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
271MODULE_ALIAS("platform:twl4030_wdt");
272
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
index c45839a4a34d..7a1bdc7c95a9 100644
--- a/drivers/watchdog/wdt_pci.c
+++ b/drivers/watchdog/wdt_pci.c
@@ -2,7 +2,7 @@
2 * Industrial Computer Source PCI-WDT500/501 driver 2 * Industrial Computer Source PCI-WDT500/501 driver
3 * 3 *
4 * (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>, 4 * (c) Copyright 1996-1997 Alan Cox <alan@lxorguk.ukuu.org.uk>,
5 * All Rights Reserved. 5 * All Rights Reserved.
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
@@ -99,14 +99,16 @@ MODULE_PARM_DESC(nowayout,
99 "Watchdog cannot be stopped once started (default=" 99 "Watchdog cannot be stopped once started (default="
100 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 100 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
101 101
102#ifdef CONFIG_WDT_501_PCI
103/* Support for the Fan Tachometer on the PCI-WDT501 */ 102/* Support for the Fan Tachometer on the PCI-WDT501 */
104static int tachometer; 103static int tachometer;
105
106module_param(tachometer, int, 0); 104module_param(tachometer, int, 0);
107MODULE_PARM_DESC(tachometer, 105MODULE_PARM_DESC(tachometer,
108 "PCI-WDT501 Fan Tachometer support (0=disable, default=0)"); 106 "PCI-WDT501 Fan Tachometer support (0=disable, default=0)");
109#endif /* CONFIG_WDT_501_PCI */ 107
108static int type = 500;
109module_param(type, int, 0);
110MODULE_PARM_DESC(type,
111 "PCI-WDT501 Card type (500 or 501 , default=500)");
110 112
111/* 113/*
112 * Programming support 114 * Programming support
@@ -266,22 +268,21 @@ static int wdtpci_get_status(int *status)
266 *status |= WDIOF_EXTERN1; 268 *status |= WDIOF_EXTERN1;
267 if (new_status & WDC_SR_ISII1) 269 if (new_status & WDC_SR_ISII1)
268 *status |= WDIOF_EXTERN2; 270 *status |= WDIOF_EXTERN2;
269#ifdef CONFIG_WDT_501_PCI 271 if (type == 501) {
270 if (!(new_status & WDC_SR_TGOOD)) 272 if (!(new_status & WDC_SR_TGOOD))
271 *status |= WDIOF_OVERHEAT; 273 *status |= WDIOF_OVERHEAT;
272 if (!(new_status & WDC_SR_PSUOVER)) 274 if (!(new_status & WDC_SR_PSUOVER))
273 *status |= WDIOF_POWEROVER; 275 *status |= WDIOF_POWEROVER;
274 if (!(new_status & WDC_SR_PSUUNDR)) 276 if (!(new_status & WDC_SR_PSUUNDR))
275 *status |= WDIOF_POWERUNDER; 277 *status |= WDIOF_POWERUNDER;
276 if (tachometer) { 278 if (tachometer) {
277 if (!(new_status & WDC_SR_FANGOOD)) 279 if (!(new_status & WDC_SR_FANGOOD))
278 *status |= WDIOF_FANFAULT; 280 *status |= WDIOF_FANFAULT;
281 }
279 } 282 }
280#endif /* CONFIG_WDT_501_PCI */
281 return 0; 283 return 0;
282} 284}
283 285
284#ifdef CONFIG_WDT_501_PCI
285/** 286/**
286 * wdtpci_get_temperature: 287 * wdtpci_get_temperature:
287 * 288 *
@@ -300,7 +301,6 @@ static int wdtpci_get_temperature(int *temperature)
300 *temperature = (c * 11 / 15) + 7; 301 *temperature = (c * 11 / 15) + 7;
301 return 0; 302 return 0;
302} 303}
303#endif /* CONFIG_WDT_501_PCI */
304 304
305/** 305/**
306 * wdtpci_interrupt: 306 * wdtpci_interrupt:
@@ -327,22 +327,22 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
327 327
328 printk(KERN_CRIT PFX "status %d\n", status); 328 printk(KERN_CRIT PFX "status %d\n", status);
329 329
330#ifdef CONFIG_WDT_501_PCI 330 if (type == 501) {
331 if (!(status & WDC_SR_TGOOD)) { 331 if (!(status & WDC_SR_TGOOD)) {
332 u8 alarm = inb(WDT_RT); 332 printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",
333 printk(KERN_CRIT PFX "Overheat alarm.(%d)\n", alarm); 333 inb(WDT_RT));
334 udelay(8); 334 udelay(8);
335 } 335 }
336 if (!(status & WDC_SR_PSUOVER)) 336 if (!(status & WDC_SR_PSUOVER))
337 printk(KERN_CRIT PFX "PSU over voltage.\n"); 337 printk(KERN_CRIT PFX "PSU over voltage.\n");
338 if (!(status & WDC_SR_PSUUNDR)) 338 if (!(status & WDC_SR_PSUUNDR))
339 printk(KERN_CRIT PFX "PSU under voltage.\n"); 339 printk(KERN_CRIT PFX "PSU under voltage.\n");
340 if (tachometer) { 340 if (tachometer) {
341 if (!(status & WDC_SR_FANGOOD)) 341 if (!(status & WDC_SR_FANGOOD))
342 printk(KERN_CRIT PFX "Possible fan fault.\n"); 342 printk(KERN_CRIT PFX "Possible fan fault.\n");
343 }
343 } 344 }
344#endif /* CONFIG_WDT_501_PCI */ 345 if (!(status & WDC_SR_WCCR)) {
345 if (!(status&WDC_SR_WCCR)) {
346#ifdef SOFTWARE_REBOOT 346#ifdef SOFTWARE_REBOOT
347#ifdef ONLY_TESTING 347#ifdef ONLY_TESTING
348 printk(KERN_CRIT PFX "Would Reboot.\n"); 348 printk(KERN_CRIT PFX "Would Reboot.\n");
@@ -371,12 +371,13 @@ static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
371 */ 371 */
372 372
373static ssize_t wdtpci_write(struct file *file, const char __user *buf, 373static ssize_t wdtpci_write(struct file *file, const char __user *buf,
374 size_t count, loff_t *ppos) 374 size_t count, loff_t *ppos)
375{ 375{
376 if (count) { 376 if (count) {
377 if (!nowayout) { 377 if (!nowayout) {
378 size_t i; 378 size_t i;
379 379
380 /* In case it was set long ago */
380 expect_close = 0; 381 expect_close = 0;
381 382
382 for (i = 0; i != count; i++) { 383 for (i = 0; i != count; i++) {
@@ -406,10 +407,10 @@ static ssize_t wdtpci_write(struct file *file, const char __user *buf,
406static long wdtpci_ioctl(struct file *file, unsigned int cmd, 407static long wdtpci_ioctl(struct file *file, unsigned int cmd,
407 unsigned long arg) 408 unsigned long arg)
408{ 409{
409 int new_heartbeat;
410 int status;
411 void __user *argp = (void __user *)arg; 410 void __user *argp = (void __user *)arg;
412 int __user *p = argp; 411 int __user *p = argp;
412 int new_heartbeat;
413 int status;
413 414
414 static struct watchdog_info ident = { 415 static struct watchdog_info ident = {
415 .options = WDIOF_SETTIMEOUT| 416 .options = WDIOF_SETTIMEOUT|
@@ -421,11 +422,12 @@ static long wdtpci_ioctl(struct file *file, unsigned int cmd,
421 422
422 /* Add options according to the card we have */ 423 /* Add options according to the card we have */
423 ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2); 424 ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
424#ifdef CONFIG_WDT_501_PCI 425 if (type == 501) {
425 ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER); 426 ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|
426 if (tachometer) 427 WDIOF_POWEROVER);
427 ident.options |= WDIOF_FANFAULT; 428 if (tachometer)
428#endif /* CONFIG_WDT_501_PCI */ 429 ident.options |= WDIOF_FANFAULT;
430 }
429 431
430 switch (cmd) { 432 switch (cmd) {
431 case WDIOC_GETSUPPORT: 433 case WDIOC_GETSUPPORT:
@@ -503,7 +505,6 @@ static int wdtpci_release(struct inode *inode, struct file *file)
503 return 0; 505 return 0;
504} 506}
505 507
506#ifdef CONFIG_WDT_501_PCI
507/** 508/**
508 * wdtpci_temp_read: 509 * wdtpci_temp_read:
509 * @file: file handle to the watchdog board 510 * @file: file handle to the watchdog board
@@ -554,7 +555,6 @@ static int wdtpci_temp_release(struct inode *inode, struct file *file)
554{ 555{
555 return 0; 556 return 0;
556} 557}
557#endif /* CONFIG_WDT_501_PCI */
558 558
559/** 559/**
560 * notify_sys: 560 * notify_sys:
@@ -596,7 +596,6 @@ static struct miscdevice wdtpci_miscdev = {
596 .fops = &wdtpci_fops, 596 .fops = &wdtpci_fops,
597}; 597};
598 598
599#ifdef CONFIG_WDT_501_PCI
600static const struct file_operations wdtpci_temp_fops = { 599static const struct file_operations wdtpci_temp_fops = {
601 .owner = THIS_MODULE, 600 .owner = THIS_MODULE,
602 .llseek = no_llseek, 601 .llseek = no_llseek,
@@ -610,7 +609,6 @@ static struct miscdevice temp_miscdev = {
610 .name = "temperature", 609 .name = "temperature",
611 .fops = &wdtpci_temp_fops, 610 .fops = &wdtpci_temp_fops,
612}; 611};
613#endif /* CONFIG_WDT_501_PCI */
614 612
615/* 613/*
616 * The WDT card needs to learn about soft shutdowns in order to 614 * The WDT card needs to learn about soft shutdowns in order to
@@ -633,6 +631,11 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
633 return -ENODEV; 631 return -ENODEV;
634 } 632 }
635 633
634 if (type != 500 && type != 501) {
635 printk(KERN_ERR PFX "unknown card type '%d'.\n", type);
636 return -ENODEV;
637 }
638
636 if (pci_enable_device(dev)) { 639 if (pci_enable_device(dev)) {
637 printk(KERN_ERR PFX "Not possible to enable PCI Device\n"); 640 printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
638 return -ENODEV; 641 return -ENODEV;
@@ -678,15 +681,15 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
678 goto out_irq; 681 goto out_irq;
679 } 682 }
680 683
681#ifdef CONFIG_WDT_501_PCI 684 if (type == 501) {
682 ret = misc_register(&temp_miscdev); 685 ret = misc_register(&temp_miscdev);
683 if (ret) { 686 if (ret) {
684 printk(KERN_ERR PFX 687 printk(KERN_ERR PFX
685 "cannot register miscdev on minor=%d (err=%d)\n", 688 "cannot register miscdev on minor=%d (err=%d)\n",
686 TEMP_MINOR, ret); 689 TEMP_MINOR, ret);
687 goto out_rbt; 690 goto out_rbt;
691 }
688 } 692 }
689#endif /* CONFIG_WDT_501_PCI */
690 693
691 ret = misc_register(&wdtpci_miscdev); 694 ret = misc_register(&wdtpci_miscdev);
692 if (ret) { 695 if (ret) {
@@ -698,20 +701,18 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev,
698 701
699 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", 702 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
700 heartbeat, nowayout); 703 heartbeat, nowayout);
701#ifdef CONFIG_WDT_501_PCI 704 if (type == 501)
702 printk(KERN_INFO "wdt: Fan Tachometer is %s\n", 705 printk(KERN_INFO "wdt: Fan Tachometer is %s\n",
703 (tachometer ? "Enabled" : "Disabled")); 706 (tachometer ? "Enabled" : "Disabled"));
704#endif /* CONFIG_WDT_501_PCI */
705 707
706 ret = 0; 708 ret = 0;
707out: 709out:
708 return ret; 710 return ret;
709 711
710out_misc: 712out_misc:
711#ifdef CONFIG_WDT_501_PCI 713 if (type == 501)
712 misc_deregister(&temp_miscdev); 714 misc_deregister(&temp_miscdev);
713out_rbt: 715out_rbt:
714#endif /* CONFIG_WDT_501_PCI */
715 unregister_reboot_notifier(&wdtpci_notifier); 716 unregister_reboot_notifier(&wdtpci_notifier);
716out_irq: 717out_irq:
717 free_irq(irq, &wdtpci_miscdev); 718 free_irq(irq, &wdtpci_miscdev);
@@ -728,9 +729,8 @@ static void __devexit wdtpci_remove_one(struct pci_dev *pdev)
728 /* here we assume only one device will ever have 729 /* here we assume only one device will ever have
729 * been picked up and registered by probe function */ 730 * been picked up and registered by probe function */
730 misc_deregister(&wdtpci_miscdev); 731 misc_deregister(&wdtpci_miscdev);
731#ifdef CONFIG_WDT_501_PCI 732 if (type == 501)
732 misc_deregister(&temp_miscdev); 733 misc_deregister(&temp_miscdev);
733#endif /* CONFIG_WDT_501_PCI */
734 unregister_reboot_notifier(&wdtpci_notifier); 734 unregister_reboot_notifier(&wdtpci_notifier);
735 free_irq(irq, &wdtpci_miscdev); 735 free_irq(irq, &wdtpci_miscdev);
736 release_region(io, 16); 736 release_region(io, 16);