aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorWim Van Sebroeck <wim@iguana.be>2007-08-17 04:38:02 -0400
committerWim Van Sebroeck <wim@iguana.be>2007-10-18 06:39:03 -0400
commitb7e04f8c61a46d742de23af5d7ca2b41b33e40ac (patch)
treec52a7ea568648e2d8ed0d423098b42298de2058b /drivers/watchdog
parentd85714d81cc0408daddb68c10f7fd69eafe7c213 (diff)
mv watchdog tree under drivers
move watchdog tree from drivers/char/watchdog to drivers/watchdog. Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/Kconfig853
-rw-r--r--drivers/watchdog/Makefile120
-rw-r--r--drivers/watchdog/acquirewdt.c348
-rw-r--r--drivers/watchdog/advantechwdt.c362
-rw-r--r--drivers/watchdog/alim1535_wdt.c465
-rw-r--r--drivers/watchdog/alim7101_wdt.c423
-rw-r--r--drivers/watchdog/at32ap700x_wdt.c386
-rw-r--r--drivers/watchdog/at91rm9200_wdt.c288
-rw-r--r--drivers/watchdog/bfin_wdt.c490
-rw-r--r--drivers/watchdog/booke_wdt.c194
-rw-r--r--drivers/watchdog/cpu5wdt.c304
-rw-r--r--drivers/watchdog/davinci_wdt.c281
-rw-r--r--drivers/watchdog/ep93xx_wdt.c253
-rw-r--r--drivers/watchdog/eurotechwdt.c473
-rw-r--r--drivers/watchdog/i6300esb.c527
-rw-r--r--drivers/watchdog/iTCO_vendor_support.c307
-rw-r--r--drivers/watchdog/iTCO_wdt.c804
-rw-r--r--drivers/watchdog/ib700wdt.c408
-rw-r--r--drivers/watchdog/ibmasr.c403
-rw-r--r--drivers/watchdog/indydog.c215
-rw-r--r--drivers/watchdog/iop_wdt.c262
-rw-r--r--drivers/watchdog/ixp2000_wdt.c219
-rw-r--r--drivers/watchdog/ixp4xx_wdt.c225
-rw-r--r--drivers/watchdog/ks8695_wdt.c308
-rw-r--r--drivers/watchdog/machzwd.c489
-rw-r--r--drivers/watchdog/mixcomwd.c330
-rw-r--r--drivers/watchdog/mpc5200_wdt.c286
-rw-r--r--drivers/watchdog/mpc83xx_wdt.c231
-rw-r--r--drivers/watchdog/mpc8xx_wdt.c169
-rw-r--r--drivers/watchdog/mpcore_wdt.c435
-rw-r--r--drivers/watchdog/mtx-1_wdt.c239
-rw-r--r--drivers/watchdog/mv64x60_wdt.c326
-rw-r--r--drivers/watchdog/omap_wdt.c389
-rw-r--r--drivers/watchdog/omap_wdt.h64
-rw-r--r--drivers/watchdog/pc87413_wdt.c635
-rw-r--r--drivers/watchdog/pcwd.c1013
-rw-r--r--drivers/watchdog/pcwd_pci.c832
-rw-r--r--drivers/watchdog/pcwd_usb.c824
-rw-r--r--drivers/watchdog/pnx4008_wdt.c358
-rw-r--r--drivers/watchdog/rm9k_wdt.c420
-rw-r--r--drivers/watchdog/s3c2410_wdt.c563
-rw-r--r--drivers/watchdog/sa1100_wdt.c190
-rw-r--r--drivers/watchdog/sbc60xxwdt.c400
-rw-r--r--drivers/watchdog/sbc8360.c413
-rw-r--r--drivers/watchdog/sbc_epx_c3.c223
-rw-r--r--drivers/watchdog/sc1200wdt.c463
-rw-r--r--drivers/watchdog/sc520_wdt.c435
-rw-r--r--drivers/watchdog/scx200_wdt.c269
-rw-r--r--drivers/watchdog/shwdt.c485
-rw-r--r--drivers/watchdog/smsc37b787_wdt.c627
-rw-r--r--drivers/watchdog/softdog.c310
-rw-r--r--drivers/watchdog/w83627hf_wdt.c390
-rw-r--r--drivers/watchdog/w83697hf_wdt.c450
-rw-r--r--drivers/watchdog/w83877f_wdt.c415
-rw-r--r--drivers/watchdog/w83977f_wdt.c542
-rw-r--r--drivers/watchdog/wafer5823wdt.c325
-rw-r--r--drivers/watchdog/wd501p.h51
-rw-r--r--drivers/watchdog/wdrtas.c695
-rw-r--r--drivers/watchdog/wdt.c640
-rw-r--r--drivers/watchdog/wdt285.c229
-rw-r--r--drivers/watchdog/wdt977.c519
-rw-r--r--drivers/watchdog/wdt_pci.c756
62 files changed, 25348 insertions, 0 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
new file mode 100644
index 000000000000..37bddc1802de
--- /dev/null
+++ b/drivers/watchdog/Kconfig
@@ -0,0 +1,853 @@
1#
2# Watchdog device configuration
3#
4
5menuconfig WATCHDOG
6 bool "Watchdog Timer Support"
7 ---help---
8 If you say Y here (and to one of the following options) and create a
9 character special file /dev/watchdog with major number 10 and minor
10 number 130 using mknod ("man mknod"), you will get a watchdog, i.e.:
11 subsequently opening the file and then failing to write to it for
12 longer than 1 minute will result in rebooting the machine. This
13 could be useful for a networked machine that needs to come back
14 on-line as fast as possible after a lock-up. There's both a watchdog
15 implementation entirely in software (which can sometimes fail to
16 reboot the machine) and a driver for hardware watchdog boards, which
17 are more robust and can also keep track of the temperature inside
18 your computer. For details, read <file:Documentation/watchdog/watchdog.txt>
19 in the kernel source.
20
21 The watchdog is usually used together with the watchdog daemon
22 which is available from
23 <ftp://ibiblio.org/pub/Linux/system/daemons/watchdog/>. This daemon can
24 also monitor NFS connections and can reboot the machine when the process
25 table is full.
26
27 If unsure, say N.
28
29if WATCHDOG
30
31config WATCHDOG_NOWAYOUT
32 bool "Disable watchdog shutdown on close"
33 help
34 The default watchdog behaviour (which you get if you say N here) is
35 to stop the timer if the process managing it closes the file
36 /dev/watchdog. It's always remotely possible that this process might
37 get killed. If you say Y here, the watchdog cannot be stopped once
38 it has been started.
39
40#
41# General Watchdog drivers
42#
43
44comment "Watchdog Device Drivers"
45
46# Architecture Independent
47
48config SOFT_WATCHDOG
49 tristate "Software watchdog"
50 help
51 A software monitoring watchdog. This will fail to reboot your system
52 from some situations that the hardware watchdog will recover
53 from. Equally it's a lot cheaper to install.
54
55 To compile this driver as a module, choose M here: the
56 module will be called softdog.
57
58# ALPHA Architecture
59
60# ARM Architecture
61
62config AT91RM9200_WATCHDOG
63 tristate "AT91RM9200 watchdog"
64 depends on ARCH_AT91RM9200
65 help
66 Watchdog timer embedded into AT91RM9200 chips. This will reboot your
67 system when the timeout is reached.
68
69config 21285_WATCHDOG
70 tristate "DC21285 watchdog"
71 depends on FOOTBRIDGE
72 help
73 The Intel Footbridge chip contains a built-in watchdog circuit. Say Y
74 here if you wish to use this. Alternatively say M to compile the
75 driver as a module, which will be called wdt285.
76
77 This driver does not work on all machines. In particular, early CATS
78 boards have hardware problems that will cause the machine to simply
79 lock up if the watchdog fires.
80
81 "If in doubt, leave it out" - say N.
82
83config 977_WATCHDOG
84 tristate "NetWinder WB83C977 watchdog"
85 depends on FOOTBRIDGE && ARCH_NETWINDER
86 help
87 Say Y here to include support for the WB977 watchdog included in
88 NetWinder machines. Alternatively say M to compile the driver as
89 a module, which will be called wdt977.
90
91 Not sure? It's safe to say N.
92
93config IXP2000_WATCHDOG
94 tristate "IXP2000 Watchdog"
95 depends on ARCH_IXP2000
96 help
97 Say Y here if to include support for the watchdog timer
98 in the Intel IXP2000(2400, 2800, 2850) network processors.
99 This driver can be built as a module by choosing M. The module
100 will be called ixp2000_wdt.
101
102 Say N if you are unsure.
103
104config IXP4XX_WATCHDOG
105 tristate "IXP4xx Watchdog"
106 depends on ARCH_IXP4XX
107 help
108 Say Y here if to include support for the watchdog timer
109 in the Intel IXP4xx network processors. This driver can
110 be built as a module by choosing M. The module will
111 be called ixp4xx_wdt.
112
113 Note: The internal IXP4xx watchdog does a soft CPU reset
114 which doesn't reset any peripherals. There are circumstances
115 where the watchdog will fail to reset the board correctly
116 (e.g., if the boot ROM is in an unreadable state).
117
118 Say N if you are unsure.
119
120config KS8695_WATCHDOG
121 tristate "KS8695 watchdog"
122 depends on ARCH_KS8695
123 help
124 Watchdog timer embedded into KS8695 processor. This will reboot your
125 system when the timeout is reached.
126
127config S3C2410_WATCHDOG
128 tristate "S3C2410 Watchdog"
129 depends on ARCH_S3C2410
130 help
131 Watchdog timer block in the Samsung S3C2410 chips. This will
132 reboot the system when the timer expires with the watchdog
133 enabled.
134
135 The driver is limited by the speed of the system's PCLK
136 signal, so with reasonably fast systems (PCLK around 50-66MHz)
137 then watchdog intervals of over approximately 20seconds are
138 unavailable.
139
140 The driver can be built as a module by choosing M, and will
141 be called s3c2410_wdt
142
143config SA1100_WATCHDOG
144 tristate "SA1100/PXA2xx watchdog"
145 depends on ARCH_SA1100 || ARCH_PXA
146 help
147 Watchdog timer embedded into SA11x0 and PXA2xx chips. This will
148 reboot your system when timeout is reached.
149
150 NOTE: once enabled, this timer cannot be disabled.
151
152 To compile this driver as a module, choose M here: the
153 module will be called sa1100_wdt.
154
155config MPCORE_WATCHDOG
156 tristate "MPcore watchdog"
157 depends on ARM_MPCORE_PLATFORM && LOCAL_TIMERS
158 help
159 Watchdog timer embedded into the MPcore system.
160
161 To compile this driver as a module, choose M here: the
162 module will be called mpcore_wdt.
163
164config EP93XX_WATCHDOG
165 tristate "EP93xx Watchdog"
166 depends on ARCH_EP93XX
167 help
168 Say Y here if to include support for the watchdog timer
169 embedded in the Cirrus Logic EP93xx family of devices.
170
171 To compile this driver as a module, choose M here: the
172 module will be called ep93xx_wdt.
173
174config OMAP_WATCHDOG
175 tristate "OMAP Watchdog"
176 depends on ARCH_OMAP16XX || ARCH_OMAP24XX
177 help
178 Support for TI OMAP1610/OMAP1710/OMAP2420 watchdog. Say 'Y' here to
179 enable the OMAP1610/OMAP1710 watchdog timer.
180
181config PNX4008_WATCHDOG
182 tristate "PNX4008 Watchdog"
183 depends on ARCH_PNX4008
184 help
185 Say Y here if to include support for the watchdog timer
186 in the PNX4008 processor.
187 This driver can be built as a module by choosing M. The module
188 will be called pnx4008_wdt.
189
190 Say N if you are unsure.
191
192config IOP_WATCHDOG
193 tristate "IOP Watchdog"
194 depends on PLAT_IOP
195 select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X)
196 help
197 Say Y here if to include support for the watchdog timer
198 in the Intel IOP3XX & IOP13XX I/O Processors. This driver can
199 be built as a module by choosing M. The module will
200 be called iop_wdt.
201
202 Note: The IOP13XX watchdog does an Internal Bus Reset which will
203 affect both cores and the peripherals of the IOP. The ATU-X
204 and/or ATUe configuration registers will remain intact, but if
205 operating as an Root Complex and/or Central Resource, the PCI-X
206 and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER.
207
208config DAVINCI_WATCHDOG
209 tristate "DaVinci watchdog"
210 depends on ARCH_DAVINCI
211 help
212 Say Y here if to include support for the watchdog timer
213 in the DaVinci DM644x/DM646x processors.
214 To compile this driver as a module, choose M here: the
215 module will be called davinci_wdt.
216
217 NOTE: once enabled, this timer cannot be disabled.
218 Say N if you are unsure.
219
220# ARM26 Architecture
221
222# AVR32 Architecture
223
224config AT32AP700X_WDT
225 tristate "AT32AP700x watchdog"
226 depends on CPU_AT32AP7000
227 help
228 Watchdog timer embedded into AT32AP700x devices. This will reboot
229 your system when the timeout is reached.
230
231# BLACKFIN Architecture
232
233config BFIN_WDT
234 tristate "Blackfin On-Chip Watchdog Timer"
235 depends on BLACKFIN
236 ---help---
237 If you say yes here you will get support for the Blackfin On-Chip
238 Watchdog Timer. If you have one of these processors and wish to
239 have watchdog support enabled, say Y, otherwise say N.
240
241 To compile this driver as a module, choose M here: the
242 module will be called bfin_wdt.
243
244# CRIS Architecture
245
246# FRV Architecture
247
248# H8300 Architecture
249
250# X86 (i386 + ia64 + x86_64) Architecture
251
252config ACQUIRE_WDT
253 tristate "Acquire SBC Watchdog Timer"
254 depends on X86
255 ---help---
256 This is the driver for the hardware watchdog on Single Board
257 Computers produced by Acquire Inc (and others). This watchdog
258 simply watches your kernel to make sure it doesn't freeze, and if
259 it does, it reboots your computer after a certain amount of time.
260
261 To compile this driver as a module, choose M here: the
262 module will be called acquirewdt.
263
264 Most people will say N.
265
266config ADVANTECH_WDT
267 tristate "Advantech SBC Watchdog Timer"
268 depends on X86
269 help
270 If you are configuring a Linux kernel for the Advantech single-board
271 computer, say `Y' here to support its built-in watchdog timer
272 feature. More information can be found at
273 <http://www.advantech.com.tw/products/>
274
275config ALIM1535_WDT
276 tristate "ALi M1535 PMU Watchdog Timer"
277 depends on X86 && PCI
278 ---help---
279 This is the driver for the hardware watchdog on the ALi M1535 PMU.
280
281 To compile this driver as a module, choose M here: the
282 module will be called alim1535_wdt.
283
284 Most people will say N.
285
286config ALIM7101_WDT
287 tristate "ALi M7101 PMU Computer Watchdog"
288 depends on X86 && PCI
289 help
290 This is the driver for the hardware watchdog on the ALi M7101 PMU
291 as used in the x86 Cobalt servers.
292
293 To compile this driver as a module, choose M here: the
294 module will be called alim7101_wdt.
295
296 Most people will say N.
297
298config SC520_WDT
299 tristate "AMD Elan SC520 processor Watchdog"
300 depends on X86
301 help
302 This is the driver for the hardware watchdog built in to the
303 AMD "Elan" SC520 microcomputer commonly used in embedded systems.
304 This watchdog simply watches your kernel to make sure it doesn't
305 freeze, and if it does, it reboots your computer after a certain
306 amount of time.
307
308 You can compile this driver directly into the kernel, or use
309 it as a module. The module will be called sc520_wdt.
310
311config EUROTECH_WDT
312 tristate "Eurotech CPU-1220/1410 Watchdog Timer"
313 depends on X86
314 help
315 Enable support for the watchdog timer on the Eurotech CPU-1220 and
316 CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product
317 information are at <http://www.eurotech.it/>.
318
319config IB700_WDT
320 tristate "IB700 SBC Watchdog Timer"
321 depends on X86
322 ---help---
323 This is the driver for the hardware watchdog on the IB700 Single
324 Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog
325 simply watches your kernel to make sure it doesn't freeze, and if
326 it does, it reboots your computer after a certain amount of time.
327
328 This driver is like the WDT501 driver but for slightly different hardware.
329
330 To compile this driver as a module, choose M here: the
331 module will be called ib700wdt.
332
333 Most people will say N.
334
335config IBMASR
336 tristate "IBM Automatic Server Restart"
337 depends on X86
338 help
339 This is the driver for the IBM Automatic Server Restart watchdog
340 timer built-in into some eServer xSeries machines.
341
342 To compile this driver as a module, choose M here: the
343 module will be called ibmasr.
344
345config WAFER_WDT
346 tristate "ICP Wafer 5823 Single Board Computer Watchdog"
347 depends on X86
348 help
349 This is a driver for the hardware watchdog on the ICP Wafer 5823
350 Single Board Computer (and probably other similar models).
351
352 To compile this driver as a module, choose M here: the
353 module will be called wafer5823wdt.
354
355config I6300ESB_WDT
356 tristate "Intel 6300ESB Timer/Watchdog"
357 depends on X86 && PCI
358 ---help---
359 Hardware driver for the watchdog timer built into the Intel
360 6300ESB controller hub.
361
362 To compile this driver as a module, choose M here: the
363 module will be called i6300esb.
364
365config ITCO_WDT
366 tristate "Intel TCO Timer/Watchdog"
367 depends on (X86 || IA64) && PCI
368 ---help---
369 Hardware driver for the intel TCO timer based watchdog devices.
370 These drivers are included in the Intel 82801 I/O Controller
371 Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB
372 controller hub.
373
374 The TCO (Total Cost of Ownership) timer is a watchdog timer
375 that will reboot the machine after its second expiration. The
376 expiration time can be configured with the "heartbeat" parameter.
377
378 On some motherboards the driver may fail to reset the chipset's
379 NO_REBOOT flag which prevents the watchdog from rebooting the
380 machine. If this is the case you will get a kernel message like
381 "failed to reset NO_REBOOT flag, reboot disabled by hardware".
382
383 To compile this driver as a module, choose M here: the
384 module will be called iTCO_wdt.
385
386config ITCO_VENDOR_SUPPORT
387 bool "Intel TCO Timer/Watchdog Specific Vendor Support"
388 depends on ITCO_WDT
389 ---help---
390 Add vendor specific support to the intel TCO timer based watchdog
391 devices. At this moment we only have additional support for some
392 SuperMicro Inc. motherboards.
393
394config SC1200_WDT
395 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
396 depends on X86
397 help
398 This is a driver for National Semiconductor PC87307/PC97307 hardware
399 watchdog cards as found on the SC1200. This watchdog is mainly used
400 for power management purposes and can be used to power down the device
401 during inactivity periods (includes interrupt activity monitoring).
402
403 To compile this driver as a module, choose M here: the
404 module will be called sc1200wdt.
405
406 Most people will say N.
407
408config SCx200_WDT
409 tristate "National Semiconductor SCx200 Watchdog"
410 depends on SCx200 && PCI
411 help
412 Enable the built-in watchdog timer support on the National
413 Semiconductor SCx200 processors.
414
415 If compiled as a module, it will be called scx200_wdt.
416
417config PC87413_WDT
418 tristate "NS PC87413 watchdog"
419 depends on X86
420 ---help---
421 This is the driver for the hardware watchdog on the PC87413 chipset
422 This watchdog simply watches your kernel to make sure it doesn't
423 freeze, and if it does, it reboots your computer after a certain
424 amount of time.
425
426 To compile this driver as a module, choose M here: the
427 module will be called pc87413_wdt.
428
429 Most people will say N.
430
431config 60XX_WDT
432 tristate "SBC-60XX Watchdog Timer"
433 depends on X86
434 help
435 This driver can be used with the watchdog timer found on some
436 single board computers, namely the 6010 PII based computer.
437 It may well work with other cards. It reads port 0x443 to enable
438 and re-set the watchdog timer, and reads port 0x45 to disable
439 the watchdog. If you have a card that behave in similar ways,
440 you can probably make this driver work with your card as well.
441
442 You can compile this driver directly into the kernel, or use
443 it as a module. The module will be called sbc60xxwdt.
444
445config SBC8360_WDT
446 tristate "SBC8360 Watchdog Timer"
447 depends on X86
448 ---help---
449
450 This is the driver for the hardware watchdog on the SBC8360 Single
451 Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com).
452
453 To compile this driver as a module, choose M here: the
454 module will be called sbc8360.ko.
455
456 Most people will say N.
457
458config CPU5_WDT
459 tristate "SMA CPU5 Watchdog"
460 depends on X86
461 ---help---
462 TBD.
463 To compile this driver as a module, choose M here: the
464 module will be called cpu5wdt.
465
466config SMSC37B787_WDT
467 tristate "Winbond SMsC37B787 Watchdog Timer"
468 depends on X86
469 ---help---
470 This is the driver for the hardware watchdog component on the
471 Winbond SMsC37B787 chipset as used on the NetRunner Mainboard
472 from Vision Systems and maybe others.
473
474 This watchdog simply watches your kernel to make sure it doesn't
475 freeze, and if it does, it reboots your computer after a certain
476 amount of time.
477
478 Usually a userspace daemon will notify the kernel WDT driver that
479 userspace is still alive, at regular intervals.
480
481 To compile this driver as a module, choose M here: the
482 module will be called smsc37b787_wdt.
483
484 Most people will say N.
485
486config W83627HF_WDT
487 tristate "W83627HF Watchdog Timer"
488 depends on X86
489 ---help---
490 This is the driver for the hardware watchdog on the W83627HF chipset
491 as used in Advantech PC-9578 and Tyan S2721-533 motherboards
492 (and likely others). This watchdog simply watches your kernel to
493 make sure it doesn't freeze, and if it does, it reboots your computer
494 after a certain amount of time.
495
496 To compile this driver as a module, choose M here: the
497 module will be called w83627hf_wdt.
498
499 Most people will say N.
500
501config W83697HF_WDT
502 tristate "W83697HF/W83697HG Watchdog Timer"
503 depends on X86
504 ---help---
505 This is the driver for the hardware watchdog on the W83697HF/HG
506 chipset as used in Dedibox/VIA motherboards (and likely others).
507 This watchdog simply watches your kernel to make sure it doesn't
508 freeze, and if it does, it reboots your computer after a certain
509 amount of time.
510
511 To compile this driver as a module, choose M here: the
512 module will be called w83697hf_wdt.
513
514 Most people will say N.
515
516config W83877F_WDT
517 tristate "W83877F (EMACS) Watchdog Timer"
518 depends on X86
519 ---help---
520 This is the driver for the hardware watchdog on the W83877F chipset
521 as used in EMACS PC-104 motherboards (and likely others). This
522 watchdog simply watches your kernel to make sure it doesn't freeze,
523 and if it does, it reboots your computer after a certain amount of
524 time.
525
526 To compile this driver as a module, choose M here: the
527 module will be called w83877f_wdt.
528
529 Most people will say N.
530
531config W83977F_WDT
532 tristate "W83977F (PCM-5335) Watchdog Timer"
533 depends on X86
534 ---help---
535 This is the driver for the hardware watchdog on the W83977F I/O chip
536 as used in AAEON's PCM-5335 SBC (and likely others). This
537 watchdog simply watches your kernel to make sure it doesn't freeze,
538 and if it does, it reboots your computer after a certain amount of
539 time.
540
541 To compile this driver as a module, choose M here: the
542 module will be called w83977f_wdt.
543
544config MACHZ_WDT
545 tristate "ZF MachZ Watchdog"
546 depends on X86
547 ---help---
548 If you are using a ZF Micro MachZ processor, say Y here, otherwise
549 N. This is the driver for the watchdog timer built-in on that
550 processor using ZF-Logic interface. This watchdog simply watches
551 your kernel to make sure it doesn't freeze, and if it does, it
552 reboots your computer after a certain amount of time.
553
554 To compile this driver as a module, choose M here: the
555 module will be called machzwd.
556
557config SBC_EPX_C3_WATCHDOG
558 tristate "Winsystems SBC EPX-C3 watchdog"
559 depends on X86
560 ---help---
561 This is the driver for the built-in watchdog timer on the EPX-C3
562 Single-board computer made by Winsystems, Inc.
563
564 *Note*: This hardware watchdog is not probeable and thus there
565 is no way to know if writing to its IO address will corrupt
566 your system or have any real effect. The only way to be sure
567 that this driver does what you want is to make sure you
568 are running it on an EPX-C3 from Winsystems with the watchdog
569 timer at IO address 0x1ee and 0x1ef. It will write to both those
570 IO ports. Basically, the assumption is made that if you compile
571 this driver into your kernel and/or load it as a module, that you
572 know what you are doing and that you are in fact running on an
573 EPX-C3 board!
574
575 To compile this driver as a module, choose M here: the
576 module will be called sbc_epx_c3.
577
578# M32R Architecture
579
580# M68K Architecture
581
582# M68KNOMMU Architecture
583
584# MIPS Architecture
585
586config INDYDOG
587 tristate "Indy/I2 Hardware Watchdog"
588 depends on SGI_IP22
589 help
590 Hardware driver for the Indy's/I2's watchdog. This is a
591 watchdog timer that will reboot the machine after a 60 second
592 timer expired and no process has written to /dev/watchdog during
593 that time.
594
595config WDT_MTX1
596 tristate "MTX-1 Hardware Watchdog"
597 depends on MIPS_MTX1
598 help
599 Hardware driver for the MTX-1 boards. This is a watchdog timer that
600 will reboot the machine after a 100 seconds timer expired.
601
602config WDT_RM9K_GPI
603 tristate "RM9000/GPI hardware watchdog"
604 depends on CPU_RM9000
605 help
606 Watchdog implementation using the GPI hardware found on
607 PMC-Sierra RM9xxx CPUs.
608
609 To compile this driver as a module, choose M here: the
610 module will be called rm9k_wdt.
611
612# PARISC Architecture
613
614# POWERPC Architecture
615
616config MPC5200_WDT
617 tristate "MPC5200 Watchdog Timer"
618 depends on PPC_MPC52xx
619
620config 8xx_WDT
621 tristate "MPC8xx Watchdog Timer"
622 depends on 8xx
623
624config 83xx_WDT
625 tristate "MPC83xx Watchdog Timer"
626 depends on PPC_83xx
627
628config MV64X60_WDT
629 tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
630 depends on MV64X60
631
632config BOOKE_WDT
633 bool "PowerPC Book-E Watchdog Timer"
634 depends on BOOKE || 4xx
635 ---help---
636 Please see Documentation/watchdog/watchdog-api.txt for
637 more information.
638
639# PPC64 Architecture
640
641config WATCHDOG_RTAS
642 tristate "RTAS watchdog"
643 depends on PPC_RTAS
644 help
645 This driver adds watchdog support for the RTAS watchdog.
646
647 To compile this driver as a module, choose M here. The module
648 will be called wdrtas.
649
650# S390 Architecture
651
652config ZVM_WATCHDOG
653 tristate "z/VM Watchdog Timer"
654 depends on S390
655 help
656 IBM s/390 and zSeries machines running under z/VM 5.1 or later
657 provide a virtual watchdog timer to their guest that cause a
658 user define Control Program command to be executed after a
659 timeout.
660
661 To compile this driver as a module, choose M here. The module
662 will be called vmwatchdog.
663
664# SUPERH (sh + sh64) Architecture
665
666config SH_WDT
667 tristate "SuperH Watchdog"
668 depends on SUPERH && (CPU_SH3 || CPU_SH4)
669 help
670 This driver adds watchdog support for the integrated watchdog in the
671 SuperH processors. If you have one of these processors and wish
672 to have watchdog support enabled, say Y, otherwise say N.
673
674 As a side note, saying Y here will automatically boost HZ to 1000
675 so that the timer has a chance to clear the overflow counter. On
676 slower systems (such as the SH-2 and SH-3) this will likely yield
677 some performance issues. As such, the WDT should be avoided here
678 unless it is absolutely necessary.
679
680 To compile this driver as a module, choose M here: the
681 module will be called shwdt.
682
683config SH_WDT_MMAP
684 bool "Allow mmap of SH WDT"
685 default n
686 depends on SH_WDT
687 help
688 If you say Y here, user applications will be able to mmap the
689 WDT/CPG registers.
690
691# SPARC Architecture
692
693# SPARC64 Architecture
694
695config WATCHDOG_CP1XXX
696 tristate "CP1XXX Hardware Watchdog support"
697 depends on SPARC64 && PCI
698 ---help---
699 This is the driver for the hardware watchdog timers present on
700 Sun Microsystems CompactPCI models CP1400 and CP1500.
701
702 To compile this driver as a module, choose M here: the
703 module will be called cpwatchdog.
704
705 If you do not have a CompactPCI model CP1400 or CP1500, or
706 another UltraSPARC-IIi-cEngine boardset with hardware watchdog,
707 you should say N to this option.
708
709config WATCHDOG_RIO
710 tristate "RIO Hardware Watchdog support"
711 depends on SPARC64 && PCI
712 help
713 Say Y here to support the hardware watchdog capability on Sun RIO
714 machines. The watchdog timeout period is normally one minute but
715 can be changed with a boot-time parameter.
716
717# V850 Architecture
718
719# XTENSA Architecture
720
721#
722# ISA-based Watchdog Cards
723#
724
725comment "ISA-based Watchdog Cards"
726 depends on ISA
727
728config PCWATCHDOG
729 tristate "Berkshire Products ISA-PC Watchdog"
730 depends on ISA
731 ---help---
732 This is the driver for the Berkshire Products ISA-PC Watchdog card.
733 This card simply watches your kernel to make sure it doesn't freeze,
734 and if it does, it reboots your computer after a certain amount of
735 time. This driver is like the WDT501 driver but for different
736 hardware. Please read <file:Documentation/watchdog/pcwd-watchdog.txt>. The PC
737 watchdog cards can be ordered from <http://www.berkprod.com/>.
738
739 To compile this driver as a module, choose M here: the
740 module will be called pcwd.
741
742 Most people will say N.
743
744config MIXCOMWD
745 tristate "Mixcom Watchdog"
746 depends on ISA
747 ---help---
748 This is a driver for the Mixcom hardware watchdog cards. This
749 watchdog simply watches your kernel to make sure it doesn't freeze,
750 and if it does, it reboots your computer after a certain amount of
751 time.
752
753 To compile this driver as a module, choose M here: the
754 module will be called mixcomwd.
755
756 Most people will say N.
757
758config WDT
759 tristate "WDT Watchdog timer"
760 depends on ISA
761 ---help---
762 If you have a WDT500P or WDT501P watchdog board, say Y here,
763 otherwise N. It is not possible to probe for this board, which means
764 that you have to inform the kernel about the IO port and IRQ that
765 is needed (you can do this via the io and irq parameters)
766
767 To compile this driver as a module, choose M here: the
768 module will be called wdt.
769
770config WDT_501
771 bool "WDT501 features"
772 depends on WDT
773 help
774 Saying Y here and creating a character special file /dev/temperature
775 with major number 10 and minor number 131 ("man mknod") will give
776 you a thermometer inside your computer: reading from
777 /dev/temperature yields one byte, the temperature in degrees
778 Fahrenheit. This works only if you have a WDT501P watchdog board
779 installed.
780
781 If you want to enable the Fan Tachometer on the WDT501P, then you
782 can do this via the tachometer parameter. Only do this if you have a
783 fan tachometer actually set up.
784
785#
786# PCI-based Watchdog Cards
787#
788
789comment "PCI-based Watchdog Cards"
790 depends on PCI
791
792config PCIPCWATCHDOG
793 tristate "Berkshire Products PCI-PC Watchdog"
794 depends on PCI
795 ---help---
796 This is the driver for the Berkshire Products PCI-PC Watchdog card.
797 This card simply watches your kernel to make sure it doesn't freeze,
798 and if it does, it reboots your computer after a certain amount of
799 time. The card can also monitor the internal temperature of the PC.
800 More info is available at <http://www.berkprod.com/pci_pc_watchdog.htm>.
801
802 To compile this driver as a module, choose M here: the
803 module will be called pcwd_pci.
804
805 Most people will say N.
806
807config WDTPCI
808 tristate "PCI-WDT500/501 Watchdog timer"
809 depends on PCI
810 ---help---
811 If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N.
812
813 To compile this driver as a module, choose M here: the
814 module will be called wdt_pci.
815
816config WDT_501_PCI
817 bool "PCI-WDT501 features"
818 depends on WDTPCI
819 help
820 Saying Y here and creating a character special file /dev/temperature
821 with major number 10 and minor number 131 ("man mknod") will give
822 you a thermometer inside your computer: reading from
823 /dev/temperature yields one byte, the temperature in degrees
824 Fahrenheit. This works only if you have a PCI-WDT501 watchdog board
825 installed.
826
827 If you want to enable the Fan Tachometer on the PCI-WDT501, then you
828 can do this via the tachometer parameter. Only do this if you have a
829 fan tachometer actually set up.
830
831#
832# USB-based Watchdog Cards
833#
834
835comment "USB-based Watchdog Cards"
836 depends on USB
837
838config USBPCWATCHDOG
839 tristate "Berkshire Products USB-PC Watchdog"
840 depends on USB
841 ---help---
842 This is the driver for the Berkshire Products USB-PC Watchdog card.
843 This card simply watches your kernel to make sure it doesn't freeze,
844 and if it does, it reboots your computer after a certain amount of
845 time. The card can also monitor the internal temperature of the PC.
846 More info is available at <http://www.berkprod.com/usb_pc_watchdog.htm>.
847
848 To compile this driver as a module, choose M here: the
849 module will be called pcwd_usb.
850
851 Most people will say N.
852
853endif # WATCHDOG
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
new file mode 100644
index 000000000000..389f8b14ccc4
--- /dev/null
+++ b/drivers/watchdog/Makefile
@@ -0,0 +1,120 @@
1#
2# Makefile for the WatchDog device drivers.
3#
4
5# Only one watchdog can succeed. We probe the ISA/PCI/USB based
6# watchdog-cards first, then the architecture specific watchdog
7# drivers and then the architecture independant "softdog" driver.
8# This means that if your ISA/PCI/USB card isn't detected that
9# you can fall back to an architecture specific driver and if
10# that also fails then you can fall back to the software watchdog
11# to give you some cover.
12
13# ISA-based Watchdog Cards
14obj-$(CONFIG_PCWATCHDOG) += pcwd.o
15obj-$(CONFIG_MIXCOMWD) += mixcomwd.o
16obj-$(CONFIG_WDT) += wdt.o
17
18# PCI-based Watchdog Cards
19obj-$(CONFIG_PCIPCWATCHDOG) += pcwd_pci.o
20obj-$(CONFIG_WDTPCI) += wdt_pci.o
21
22# USB-based Watchdog Cards
23obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
24
25# ALPHA Architecture
26
27# ARM Architecture
28obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
29obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
30obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
31obj-$(CONFIG_977_WATCHDOG) += wdt977.o
32obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
33obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
34obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
35obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
36obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
37obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
38obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
39obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
40obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
41obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
42
43# ARM26 Architecture
44
45# AVR32 Architecture
46obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
47
48# BLACKFIN Architecture
49obj-$(CONFIG_BFIN_WDT) += bfin_wdt.o
50
51# CRIS Architecture
52
53# FRV Architecture
54
55# H8300 Architecture
56
57# X86 (i386 + ia64 + x86_64) Architecture
58obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
59obj-$(CONFIG_ADVANTECH_WDT) += advantechwdt.o
60obj-$(CONFIG_ALIM1535_WDT) += alim1535_wdt.o
61obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o
62obj-$(CONFIG_SC520_WDT) += sc520_wdt.o
63obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o
64obj-$(CONFIG_IB700_WDT) += ib700wdt.o
65obj-$(CONFIG_IBMASR) += ibmasr.o
66obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o
67obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o
68obj-$(CONFIG_ITCO_WDT) += iTCO_wdt.o iTCO_vendor_support.o
69obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
70obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
71obj-$(CONFIG_PC87413_WDT) += pc87413_wdt.o
72obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
73obj-$(CONFIG_SBC8360_WDT) += sbc8360.o
74obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
75obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
76obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
77obj-$(CONFIG_W83697HF_WDT) += w83697hf_wdt.o
78obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
79obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o
80obj-$(CONFIG_MACHZ_WDT) += machzwd.o
81obj-$(CONFIG_SBC_EPX_C3_WATCHDOG) += sbc_epx_c3.o
82
83# M32R Architecture
84
85# M68K Architecture
86
87# M68KNOMMU Architecture
88
89# MIPS Architecture
90obj-$(CONFIG_INDYDOG) += indydog.o
91obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o
92obj-$(CONFIG_WDT_RM9K_GPI) += rm9k_wdt.o
93
94# PARISC Architecture
95
96# POWERPC Architecture
97obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o
98obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o
99obj-$(CONFIG_83xx_WDT) += mpc83xx_wdt.o
100obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
101obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
102
103# PPC64 Architecture
104obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
105
106# S390 Architecture
107
108# SUPERH (sh + sh64) Architecture
109obj-$(CONFIG_SH_WDT) += shwdt.o
110
111# SPARC Architecture
112
113# SPARC64 Architecture
114
115# V850 Architecture
116
117# XTENSA Architecture
118
119# Architecture Independant
120obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
diff --git a/drivers/watchdog/acquirewdt.c b/drivers/watchdog/acquirewdt.c
new file mode 100644
index 000000000000..85269c365a10
--- /dev/null
+++ b/drivers/watchdog/acquirewdt.c
@@ -0,0 +1,348 @@
1/*
2 * Acquire Single Board Computer Watchdog Timer driver
3 *
4 * Based on wdt.c. Original copyright messages:
5 *
6 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
7 * http://www.redhat.com
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
15 * warranty for any of this software. This material is provided
16 * "AS-IS" and at no charge.
17 *
18 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
19 *
20 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
21 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
22 * Can't add timeout - driver doesn't allow changing value
23 */
24
25/*
26 * Theory of Operation:
27 * The Watch-Dog Timer is provided to ensure that standalone
28 * Systems can always recover from catastrophic conditions that
29 * caused the CPU to crash. This condition may have occured by
30 * external EMI or a software bug. When the CPU stops working
31 * correctly, hardware on the board will either perform a hardware
32 * reset (cold boot) or a non-maskable interrupt (NMI) to bring the
33 * system back to a known state.
34 *
35 * The Watch-Dog Timer is controlled by two I/O Ports.
36 * 443 hex - Read - Enable or refresh the Watch-Dog Timer
37 * 043 hex - Read - Disable the Watch-Dog Timer
38 *
39 * To enable the Watch-Dog Timer, a read from I/O port 443h must
40 * be performed. This will enable and activate the countdown timer
41 * which will eventually time out and either reset the CPU or cause
42 * an NMI depending on the setting of a jumper. To ensure that this
43 * reset condition does not occur, the Watch-Dog Timer must be
44 * periodically refreshed by reading the same I/O port 443h.
45 * The Watch-Dog Timer is disabled by reading I/O port 043h.
46 *
47 * The Watch-Dog Timer Time-Out Period is set via jumpers.
48 * It can be 1, 2, 10, 20, 110 or 220 seconds.
49 */
50
51/*
52 * Includes, defines, variables, module parameters, ...
53 */
54
55/* Includes */
56#include <linux/module.h> /* For module specific items */
57#include <linux/moduleparam.h> /* For new moduleparam's */
58#include <linux/types.h> /* For standard types (like size_t) */
59#include <linux/errno.h> /* For the -ENODEV/... values */
60#include <linux/kernel.h> /* For printk/panic/... */
61#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
62#include <linux/watchdog.h> /* For the watchdog specific items */
63#include <linux/fs.h> /* For file operations */
64#include <linux/ioport.h> /* For io-port access */
65#include <linux/platform_device.h> /* For platform_driver framework */
66#include <linux/init.h> /* For __init/__exit/... */
67
68#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
69#include <asm/io.h> /* For inb/outb/... */
70
71/* Module information */
72#define DRV_NAME "acquirewdt"
73#define PFX DRV_NAME ": "
74#define WATCHDOG_NAME "Acquire WDT"
75#define WATCHDOG_HEARTBEAT 0 /* There is no way to see what the correct time-out period is */
76
77/* internal variables */
78static struct platform_device *acq_platform_device; /* the watchdog platform device */
79static unsigned long acq_is_open;
80static char expect_close;
81
82/* module parameters */
83static int wdt_stop = 0x43; /* You must set this - there is no sane way to probe for this board. */
84module_param(wdt_stop, int, 0);
85MODULE_PARM_DESC(wdt_stop, "Acquire WDT 'stop' io port (default 0x43)");
86
87static int wdt_start = 0x443; /* You must set this - there is no sane way to probe for this board. */
88module_param(wdt_start, int, 0);
89MODULE_PARM_DESC(wdt_start, "Acquire WDT 'start' io port (default 0x443)");
90
91static int nowayout = WATCHDOG_NOWAYOUT;
92module_param(nowayout, int, 0);
93MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
94
95/*
96 * Watchdog Operations
97 */
98
99static void acq_keepalive(void)
100{
101 /* Write a watchdog value */
102 inb_p(wdt_start);
103}
104
105static void acq_stop(void)
106{
107 /* Turn the card off */
108 inb_p(wdt_stop);
109}
110
111/*
112 * /dev/watchdog handling
113 */
114
115static ssize_t acq_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
116{
117 /* See if we got the magic character 'V' and reload the timer */
118 if(count) {
119 if (!nowayout) {
120 size_t i;
121
122 /* note: just in case someone wrote the magic character
123 * five months ago... */
124 expect_close = 0;
125
126 /* scan to see whether or not we got the magic character */
127 for (i = 0; i != count; i++) {
128 char c;
129 if (get_user(c, buf + i))
130 return -EFAULT;
131 if (c == 'V')
132 expect_close = 42;
133 }
134 }
135
136 /* Well, anyhow someone wrote to us, we should return that favour */
137 acq_keepalive();
138 }
139 return count;
140}
141
142static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
143 unsigned long arg)
144{
145 int options, retval = -EINVAL;
146 void __user *argp = (void __user *)arg;
147 int __user *p = argp;
148 static struct watchdog_info ident =
149 {
150 .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
151 .firmware_version = 1,
152 .identity = WATCHDOG_NAME,
153 };
154
155 switch(cmd)
156 {
157 case WDIOC_GETSUPPORT:
158 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
159
160 case WDIOC_GETSTATUS:
161 case WDIOC_GETBOOTSTATUS:
162 return put_user(0, p);
163
164 case WDIOC_KEEPALIVE:
165 acq_keepalive();
166 return 0;
167
168 case WDIOC_GETTIMEOUT:
169 return put_user(WATCHDOG_HEARTBEAT, p);
170
171 case WDIOC_SETOPTIONS:
172 {
173 if (get_user(options, p))
174 return -EFAULT;
175
176 if (options & WDIOS_DISABLECARD)
177 {
178 acq_stop();
179 retval = 0;
180 }
181
182 if (options & WDIOS_ENABLECARD)
183 {
184 acq_keepalive();
185 retval = 0;
186 }
187
188 return retval;
189 }
190
191 default:
192 return -ENOTTY;
193 }
194}
195
196static int acq_open(struct inode *inode, struct file *file)
197{
198 if (test_and_set_bit(0, &acq_is_open))
199 return -EBUSY;
200
201 if (nowayout)
202 __module_get(THIS_MODULE);
203
204 /* Activate */
205 acq_keepalive();
206 return nonseekable_open(inode, file);
207}
208
209static int acq_close(struct inode *inode, struct file *file)
210{
211 if (expect_close == 42) {
212 acq_stop();
213 } else {
214 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
215 acq_keepalive();
216 }
217 clear_bit(0, &acq_is_open);
218 expect_close = 0;
219 return 0;
220}
221
222/*
223 * Kernel Interfaces
224 */
225
226static const struct file_operations acq_fops = {
227 .owner = THIS_MODULE,
228 .llseek = no_llseek,
229 .write = acq_write,
230 .ioctl = acq_ioctl,
231 .open = acq_open,
232 .release = acq_close,
233};
234
235static struct miscdevice acq_miscdev = {
236 .minor = WATCHDOG_MINOR,
237 .name = "watchdog",
238 .fops = &acq_fops,
239};
240
241/*
242 * Init & exit routines
243 */
244
245static int __devinit acq_probe(struct platform_device *dev)
246{
247 int ret;
248
249 if (wdt_stop != wdt_start) {
250 if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
251 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
252 wdt_stop);
253 ret = -EIO;
254 goto out;
255 }
256 }
257
258 if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
259 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
260 wdt_start);
261 ret = -EIO;
262 goto unreg_stop;
263 }
264
265 ret = misc_register(&acq_miscdev);
266 if (ret != 0) {
267 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
268 WATCHDOG_MINOR, ret);
269 goto unreg_regions;
270 }
271
272 printk (KERN_INFO PFX "initialized. (nowayout=%d)\n",
273 nowayout);
274
275 return 0;
276
277unreg_regions:
278 release_region(wdt_start, 1);
279unreg_stop:
280 if (wdt_stop != wdt_start)
281 release_region(wdt_stop, 1);
282out:
283 return ret;
284}
285
286static int __devexit acq_remove(struct platform_device *dev)
287{
288 misc_deregister(&acq_miscdev);
289 release_region(wdt_start,1);
290 if(wdt_stop != wdt_start)
291 release_region(wdt_stop,1);
292
293 return 0;
294}
295
296static void acq_shutdown(struct platform_device *dev)
297{
298 /* Turn the WDT off if we have a soft shutdown */
299 acq_stop();
300}
301
302static struct platform_driver acquirewdt_driver = {
303 .probe = acq_probe,
304 .remove = __devexit_p(acq_remove),
305 .shutdown = acq_shutdown,
306 .driver = {
307 .owner = THIS_MODULE,
308 .name = DRV_NAME,
309 },
310};
311
312static int __init acq_init(void)
313{
314 int err;
315
316 printk(KERN_INFO "WDT driver for Acquire single board computer initialising.\n");
317
318 err = platform_driver_register(&acquirewdt_driver);
319 if (err)
320 return err;
321
322 acq_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
323 if (IS_ERR(acq_platform_device)) {
324 err = PTR_ERR(acq_platform_device);
325 goto unreg_platform_driver;
326 }
327
328 return 0;
329
330unreg_platform_driver:
331 platform_driver_unregister(&acquirewdt_driver);
332 return err;
333}
334
335static void __exit acq_exit(void)
336{
337 platform_device_unregister(acq_platform_device);
338 platform_driver_unregister(&acquirewdt_driver);
339 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
340}
341
342module_init(acq_init);
343module_exit(acq_exit);
344
345MODULE_AUTHOR("David Woodhouse");
346MODULE_DESCRIPTION("Acquire Inc. Single Board Computer Watchdog Timer driver");
347MODULE_LICENSE("GPL");
348MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/advantechwdt.c b/drivers/watchdog/advantechwdt.c
new file mode 100644
index 000000000000..8121cc247343
--- /dev/null
+++ b/drivers/watchdog/advantechwdt.c
@@ -0,0 +1,362 @@
1/*
2 * Advantech Single Board Computer WDT driver
3 *
4 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
5 *
6 * Based on acquirewdt.c which is based on wdt.c.
7 * Original copyright messages:
8 *
9 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
10 * http://www.redhat.com
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 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
18 * warranty for any of this software. This material is provided
19 * "AS-IS" and at no charge.
20 *
21 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
22 *
23 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
24 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
25 *
26 * 16-Oct-2002 Rob Radez <rob@osinvestor.com>
27 * Clean up ioctls, clean up init + exit, add expect close support,
28 * add wdt_start and wdt_stop as parameters.
29 */
30
31#include <linux/module.h>
32#include <linux/moduleparam.h>
33#include <linux/types.h>
34#include <linux/miscdevice.h>
35#include <linux/watchdog.h>
36#include <linux/fs.h>
37#include <linux/ioport.h>
38#include <linux/platform_device.h>
39#include <linux/init.h>
40
41#include <asm/io.h>
42#include <asm/uaccess.h>
43#include <asm/system.h>
44
45#define DRV_NAME "advantechwdt"
46#define PFX DRV_NAME ": "
47#define WATCHDOG_NAME "Advantech WDT"
48#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
49
50static struct platform_device *advwdt_platform_device; /* the watchdog platform device */
51static unsigned long advwdt_is_open;
52static char adv_expect_close;
53
54/*
55 * You must set these - there is no sane way to probe for this board.
56 *
57 * To enable or restart, write the timeout value in seconds (1 to 63)
58 * to I/O port wdt_start. To disable, read I/O port wdt_stop.
59 * Both are 0x443 for most boards (tested on a PCA-6276VE-00B1), but
60 * check your manual (at least the PCA-6159 seems to be different -
61 * the manual says wdt_stop is 0x43, not 0x443).
62 * (0x43 is also a write-only control register for the 8254 timer!)
63 */
64
65static int wdt_stop = 0x443;
66module_param(wdt_stop, int, 0);
67MODULE_PARM_DESC(wdt_stop, "Advantech WDT 'stop' io port (default 0x443)");
68
69static int wdt_start = 0x443;
70module_param(wdt_start, int, 0);
71MODULE_PARM_DESC(wdt_start, "Advantech WDT 'start' io port (default 0x443)");
72
73static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
74module_param(timeout, int, 0);
75MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=63, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
76
77static int nowayout = WATCHDOG_NOWAYOUT;
78module_param(nowayout, int, 0);
79MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
80
81/*
82 * Watchdog Operations
83 */
84
85static void
86advwdt_ping(void)
87{
88 /* Write a watchdog value */
89 outb_p(timeout, wdt_start);
90}
91
92static void
93advwdt_disable(void)
94{
95 inb_p(wdt_stop);
96}
97
98static int
99advwdt_set_heartbeat(int t)
100{
101 if ((t < 1) || (t > 63))
102 return -EINVAL;
103
104 timeout = t;
105 return 0;
106}
107
108/*
109 * /dev/watchdog handling
110 */
111
112static ssize_t
113advwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
114{
115 if (count) {
116 if (!nowayout) {
117 size_t i;
118
119 adv_expect_close = 0;
120
121 for (i = 0; i != count; i++) {
122 char c;
123 if (get_user(c, buf+i))
124 return -EFAULT;
125 if (c == 'V')
126 adv_expect_close = 42;
127 }
128 }
129 advwdt_ping();
130 }
131 return count;
132}
133
134static int
135advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
136 unsigned long arg)
137{
138 int new_timeout;
139 void __user *argp = (void __user *)arg;
140 int __user *p = argp;
141 static struct watchdog_info ident = {
142 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
143 .firmware_version = 1,
144 .identity = WATCHDOG_NAME,
145 };
146
147 switch (cmd) {
148 case WDIOC_GETSUPPORT:
149 if (copy_to_user(argp, &ident, sizeof(ident)))
150 return -EFAULT;
151 break;
152
153 case WDIOC_GETSTATUS:
154 case WDIOC_GETBOOTSTATUS:
155 return put_user(0, p);
156
157 case WDIOC_KEEPALIVE:
158 advwdt_ping();
159 break;
160
161 case WDIOC_SETTIMEOUT:
162 if (get_user(new_timeout, p))
163 return -EFAULT;
164 if (advwdt_set_heartbeat(new_timeout))
165 return -EINVAL;
166 advwdt_ping();
167 /* Fall */
168
169 case WDIOC_GETTIMEOUT:
170 return put_user(timeout, p);
171
172 case WDIOC_SETOPTIONS:
173 {
174 int options, retval = -EINVAL;
175
176 if (get_user(options, p))
177 return -EFAULT;
178
179 if (options & WDIOS_DISABLECARD) {
180 advwdt_disable();
181 retval = 0;
182 }
183
184 if (options & WDIOS_ENABLECARD) {
185 advwdt_ping();
186 retval = 0;
187 }
188
189 return retval;
190 }
191
192 default:
193 return -ENOTTY;
194 }
195 return 0;
196}
197
198static int
199advwdt_open(struct inode *inode, struct file *file)
200{
201 if (test_and_set_bit(0, &advwdt_is_open))
202 return -EBUSY;
203 /*
204 * Activate
205 */
206
207 advwdt_ping();
208 return nonseekable_open(inode, file);
209}
210
211static int
212advwdt_close(struct inode *inode, struct file *file)
213{
214 if (adv_expect_close == 42) {
215 advwdt_disable();
216 } else {
217 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
218 advwdt_ping();
219 }
220 clear_bit(0, &advwdt_is_open);
221 adv_expect_close = 0;
222 return 0;
223}
224
225/*
226 * Kernel Interfaces
227 */
228
229static const struct file_operations advwdt_fops = {
230 .owner = THIS_MODULE,
231 .llseek = no_llseek,
232 .write = advwdt_write,
233 .ioctl = advwdt_ioctl,
234 .open = advwdt_open,
235 .release = advwdt_close,
236};
237
238static struct miscdevice advwdt_miscdev = {
239 .minor = WATCHDOG_MINOR,
240 .name = "watchdog",
241 .fops = &advwdt_fops,
242};
243
244/*
245 * Init & exit routines
246 */
247
248static int __devinit
249advwdt_probe(struct platform_device *dev)
250{
251 int ret;
252
253 if (wdt_stop != wdt_start) {
254 if (!request_region(wdt_stop, 1, WATCHDOG_NAME)) {
255 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
256 wdt_stop);
257 ret = -EIO;
258 goto out;
259 }
260 }
261
262 if (!request_region(wdt_start, 1, WATCHDOG_NAME)) {
263 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
264 wdt_start);
265 ret = -EIO;
266 goto unreg_stop;
267 }
268
269 /* Check that the heartbeat value is within it's range ; if not reset to the default */
270 if (advwdt_set_heartbeat(timeout)) {
271 advwdt_set_heartbeat(WATCHDOG_TIMEOUT);
272 printk (KERN_INFO PFX "timeout value must be 1<=x<=63, using %d\n",
273 timeout);
274 }
275
276 ret = misc_register(&advwdt_miscdev);
277 if (ret != 0) {
278 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
279 WATCHDOG_MINOR, ret);
280 goto unreg_regions;
281 }
282
283 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
284 timeout, nowayout);
285
286out:
287 return ret;
288unreg_regions:
289 release_region(wdt_start, 1);
290unreg_stop:
291 if (wdt_stop != wdt_start)
292 release_region(wdt_stop, 1);
293 goto out;
294}
295
296static int __devexit
297advwdt_remove(struct platform_device *dev)
298{
299 misc_deregister(&advwdt_miscdev);
300 release_region(wdt_start,1);
301 if(wdt_stop != wdt_start)
302 release_region(wdt_stop,1);
303
304 return 0;
305}
306
307static void
308advwdt_shutdown(struct platform_device *dev)
309{
310 /* Turn the WDT off if we have a soft shutdown */
311 advwdt_disable();
312}
313
314static struct platform_driver advwdt_driver = {
315 .probe = advwdt_probe,
316 .remove = __devexit_p(advwdt_remove),
317 .shutdown = advwdt_shutdown,
318 .driver = {
319 .owner = THIS_MODULE,
320 .name = DRV_NAME,
321 },
322};
323
324static int __init
325advwdt_init(void)
326{
327 int err;
328
329 printk(KERN_INFO "WDT driver for Advantech single board computer initialising.\n");
330
331 err = platform_driver_register(&advwdt_driver);
332 if (err)
333 return err;
334
335 advwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
336 if (IS_ERR(advwdt_platform_device)) {
337 err = PTR_ERR(advwdt_platform_device);
338 goto unreg_platform_driver;
339 }
340
341 return 0;
342
343unreg_platform_driver:
344 platform_driver_unregister(&advwdt_driver);
345 return err;
346}
347
348static void __exit
349advwdt_exit(void)
350{
351 platform_device_unregister(advwdt_platform_device);
352 platform_driver_unregister(&advwdt_driver);
353 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
354}
355
356module_init(advwdt_init);
357module_exit(advwdt_exit);
358
359MODULE_LICENSE("GPL");
360MODULE_AUTHOR("Marek Michalkiewicz <marekm@linux.org.pl>");
361MODULE_DESCRIPTION("Advantech Single Board Computer WDT driver");
362MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/alim1535_wdt.c b/drivers/watchdog/alim1535_wdt.c
new file mode 100644
index 000000000000..c404fc69e7e6
--- /dev/null
+++ b/drivers/watchdog/alim1535_wdt.c
@@ -0,0 +1,465 @@
1/*
2 * Watchdog for the 7101 PMU version found in the ALi M1535 chipsets
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 */
9
10#include <linux/module.h>
11#include <linux/moduleparam.h>
12#include <linux/types.h>
13#include <linux/miscdevice.h>
14#include <linux/watchdog.h>
15#include <linux/ioport.h>
16#include <linux/notifier.h>
17#include <linux/reboot.h>
18#include <linux/init.h>
19#include <linux/fs.h>
20#include <linux/pci.h>
21
22#include <asm/uaccess.h>
23#include <asm/io.h>
24
25#define WATCHDOG_NAME "ALi_M1535"
26#define PFX WATCHDOG_NAME ": "
27#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
28
29/* internal variables */
30static unsigned long ali_is_open;
31static char ali_expect_release;
32static struct pci_dev *ali_pci;
33static u32 ali_timeout_bits; /* stores the computed timeout */
34static spinlock_t ali_lock; /* Guards the hardware */
35
36/* module parameters */
37static int timeout = WATCHDOG_TIMEOUT;
38module_param(timeout, int, 0);
39MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (0<timeout<18000, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
40
41static int nowayout = WATCHDOG_NOWAYOUT;
42module_param(nowayout, int, 0);
43MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
44
45/*
46 * ali_start - start watchdog countdown
47 *
48 * Starts the timer running providing the timer has a counter
49 * configuration set.
50 */
51
52static void ali_start(void)
53{
54 u32 val;
55
56 spin_lock(&ali_lock);
57
58 pci_read_config_dword(ali_pci, 0xCC, &val);
59 val &= ~0x3F; /* Mask count */
60 val |= (1<<25) | ali_timeout_bits;
61 pci_write_config_dword(ali_pci, 0xCC, val);
62
63 spin_unlock(&ali_lock);
64}
65
66/*
67 * ali_stop - stop the timer countdown
68 *
69 * Stop the ALi watchdog countdown
70 */
71
72static void ali_stop(void)
73{
74 u32 val;
75
76 spin_lock(&ali_lock);
77
78 pci_read_config_dword(ali_pci, 0xCC, &val);
79 val &= ~0x3F; /* Mask count to zero (disabled) */
80 val &= ~(1<<25);/* and for safety mask the reset enable */
81 pci_write_config_dword(ali_pci, 0xCC, val);
82
83 spin_unlock(&ali_lock);
84}
85
86/*
87 * ali_keepalive - send a keepalive to the watchdog
88 *
89 * Send a keepalive to the timer (actually we restart the timer).
90 */
91
92static void ali_keepalive(void)
93{
94 ali_start();
95}
96
97/*
98 * ali_settimer - compute the timer reload value
99 * @t: time in seconds
100 *
101 * Computes the timeout values needed
102 */
103
104static int ali_settimer(int t)
105{
106 if(t < 0)
107 return -EINVAL;
108 else if(t < 60)
109 ali_timeout_bits = t|(1<<6);
110 else if(t < 3600)
111 ali_timeout_bits = (t/60)|(1<<7);
112 else if(t < 18000)
113 ali_timeout_bits = (t/300)|(1<<6)|(1<<7);
114 else return -EINVAL;
115
116 timeout = t;
117 return 0;
118}
119
120/*
121 * /dev/watchdog handling
122 */
123
124/*
125 * ali_write - writes to ALi watchdog
126 * @file: file from VFS
127 * @data: user address of data
128 * @len: length of data
129 * @ppos: pointer to the file offset
130 *
131 * Handle a write to the ALi watchdog. Writing to the file pings
132 * the watchdog and resets it. Writing the magic 'V' sequence allows
133 * the next close to turn off the watchdog.
134 */
135
136static ssize_t ali_write(struct file *file, const char __user *data,
137 size_t len, loff_t * ppos)
138{
139 /* See if we got the magic character 'V' and reload the timer */
140 if (len) {
141 if (!nowayout) {
142 size_t i;
143
144 /* note: just in case someone wrote the magic character
145 * five months ago... */
146 ali_expect_release = 0;
147
148 /* scan to see whether or not we got the magic character */
149 for (i = 0; i != len; i++) {
150 char c;
151 if(get_user(c, data+i))
152 return -EFAULT;
153 if (c == 'V')
154 ali_expect_release = 42;
155 }
156 }
157
158 /* someone wrote to us, we should reload the timer */
159 ali_start();
160 }
161 return len;
162}
163
164/*
165 * ali_ioctl - handle watchdog ioctls
166 * @inode: VFS inode
167 * @file: VFS file pointer
168 * @cmd: ioctl number
169 * @arg: arguments to the ioctl
170 *
171 * Handle the watchdog ioctls supported by the ALi driver. Really
172 * we want an extension to enable irq ack monitoring and the like
173 */
174
175static int ali_ioctl(struct inode *inode, struct file *file,
176 unsigned int cmd, unsigned long arg)
177{
178 void __user *argp = (void __user *)arg;
179 int __user *p = argp;
180 static struct watchdog_info ident = {
181 .options = WDIOF_KEEPALIVEPING |
182 WDIOF_SETTIMEOUT |
183 WDIOF_MAGICCLOSE,
184 .firmware_version = 0,
185 .identity = "ALi M1535 WatchDog Timer",
186 };
187
188 switch (cmd) {
189 case WDIOC_GETSUPPORT:
190 return copy_to_user(argp, &ident,
191 sizeof (ident)) ? -EFAULT : 0;
192
193 case WDIOC_GETSTATUS:
194 case WDIOC_GETBOOTSTATUS:
195 return put_user(0, p);
196
197 case WDIOC_KEEPALIVE:
198 ali_keepalive();
199 return 0;
200
201 case WDIOC_SETOPTIONS:
202 {
203 int new_options, retval = -EINVAL;
204
205 if (get_user (new_options, p))
206 return -EFAULT;
207
208 if (new_options & WDIOS_DISABLECARD) {
209 ali_stop();
210 retval = 0;
211 }
212
213 if (new_options & WDIOS_ENABLECARD) {
214 ali_start();
215 retval = 0;
216 }
217
218 return retval;
219 }
220
221 case WDIOC_SETTIMEOUT:
222 {
223 int new_timeout;
224
225 if (get_user(new_timeout, p))
226 return -EFAULT;
227
228 if (ali_settimer(new_timeout))
229 return -EINVAL;
230
231 ali_keepalive();
232 /* Fall */
233 }
234
235 case WDIOC_GETTIMEOUT:
236 return put_user(timeout, p);
237
238 default:
239 return -ENOTTY;
240 }
241}
242
243/*
244 * ali_open - handle open of ali watchdog
245 * @inode: inode from VFS
246 * @file: file from VFS
247 *
248 * Open the ALi watchdog device. Ensure only one person opens it
249 * at a time. Also start the watchdog running.
250 */
251
252static int ali_open(struct inode *inode, struct file *file)
253{
254 /* /dev/watchdog can only be opened once */
255 if (test_and_set_bit(0, &ali_is_open))
256 return -EBUSY;
257
258 /* Activate */
259 ali_start();
260 return nonseekable_open(inode, file);
261}
262
263/*
264 * ali_release - close an ALi watchdog
265 * @inode: inode from VFS
266 * @file: file from VFS
267 *
268 * Close the ALi watchdog device. Actual shutdown of the timer
269 * only occurs if the magic sequence has been set.
270 */
271
272static int ali_release(struct inode *inode, struct file *file)
273{
274 /*
275 * Shut off the timer.
276 */
277 if (ali_expect_release == 42) {
278 ali_stop();
279 } else {
280 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
281 ali_keepalive();
282 }
283 clear_bit(0, &ali_is_open);
284 ali_expect_release = 0;
285 return 0;
286}
287
288/*
289 * ali_notify_sys - System down notifier
290 *
291 * Notifier for system down
292 */
293
294
295static int ali_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
296{
297 if (code==SYS_DOWN || code==SYS_HALT) {
298 /* Turn the WDT off */
299 ali_stop();
300 }
301
302 return NOTIFY_DONE;
303}
304
305/*
306 * Data for PCI driver interface
307 *
308 * This data only exists for exporting the supported
309 * PCI ids via MODULE_DEVICE_TABLE. We do not actually
310 * register a pci_driver, because someone else might one day
311 * want to register another driver on the same PCI id.
312 */
313
314static struct pci_device_id ali_pci_tbl[] = {
315 { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
316 { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
317 { 0, },
318};
319MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
320
321/*
322 * ali_find_watchdog - find a 1535 and 7101
323 *
324 * Scans the PCI hardware for a 1535 series bridge and matching 7101
325 * watchdog device. This may be overtight but it is better to be safe
326 */
327
328static int __init ali_find_watchdog(void)
329{
330 struct pci_dev *pdev;
331 u32 wdog;
332
333 /* Check for a 1533/1535 series bridge */
334 pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
335 if (pdev == NULL)
336 pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1533, NULL);
337 if (pdev == NULL)
338 return -ENODEV;
339 pci_dev_put(pdev);
340
341 /* Check for the a 7101 PMU */
342 pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
343 if(pdev == NULL)
344 return -ENODEV;
345
346 if(pci_enable_device(pdev)) {
347 pci_dev_put(pdev);
348 return -EIO;
349 }
350
351 ali_pci = pdev;
352
353 /*
354 * Initialize the timer bits
355 */
356 pci_read_config_dword(pdev, 0xCC, &wdog);
357
358 wdog &= ~0x3F; /* Timer bits */
359 wdog &= ~((1<<27)|(1<<26)|(1<<25)|(1<<24)); /* Issued events */
360 wdog &= ~((1<<16)|(1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)); /* No monitor bits */
361
362 pci_write_config_dword(pdev, 0xCC, wdog);
363
364 return 0;
365}
366
367/*
368 * Kernel Interfaces
369 */
370
371static const struct file_operations ali_fops = {
372 .owner = THIS_MODULE,
373 .llseek = no_llseek,
374 .write = ali_write,
375 .ioctl = ali_ioctl,
376 .open = ali_open,
377 .release = ali_release,
378};
379
380static struct miscdevice ali_miscdev = {
381 .minor = WATCHDOG_MINOR,
382 .name = "watchdog",
383 .fops = &ali_fops,
384};
385
386static struct notifier_block ali_notifier = {
387 .notifier_call = ali_notify_sys,
388};
389
390/*
391 * watchdog_init - module initialiser
392 *
393 * Scan for a suitable watchdog and if so initialize it. Return an error
394 * if we cannot, the error causes the module to unload
395 */
396
397static int __init watchdog_init(void)
398{
399 int ret;
400
401 spin_lock_init(&ali_lock);
402
403 /* Check whether or not the hardware watchdog is there */
404 if (ali_find_watchdog() != 0) {
405 return -ENODEV;
406 }
407
408 /* Check that the timeout value is within it's range ; if not reset to the default */
409 if (timeout < 1 || timeout >= 18000) {
410 timeout = WATCHDOG_TIMEOUT;
411 printk(KERN_INFO PFX "timeout value must be 0<timeout<18000, using %d\n",
412 timeout);
413 }
414
415 /* Calculate the watchdog's timeout */
416 ali_settimer(timeout);
417
418 ret = misc_register(&ali_miscdev);
419 if (ret != 0) {
420 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
421 WATCHDOG_MINOR, ret);
422 goto out;
423 }
424
425 ret = register_reboot_notifier(&ali_notifier);
426 if (ret != 0) {
427 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
428 ret);
429 goto unreg_miscdev;
430 }
431
432 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
433 timeout, nowayout);
434
435out:
436 return ret;
437unreg_miscdev:
438 misc_deregister(&ali_miscdev);
439 goto out;
440}
441
442/*
443 * watchdog_exit - module de-initialiser
444 *
445 * Called while unloading a successfully installed watchdog module.
446 */
447
448static void __exit watchdog_exit(void)
449{
450 /* Stop the timer before we leave */
451 ali_stop();
452
453 /* Deregister */
454 unregister_reboot_notifier(&ali_notifier);
455 misc_deregister(&ali_miscdev);
456 pci_dev_put(ali_pci);
457}
458
459module_init(watchdog_init);
460module_exit(watchdog_exit);
461
462MODULE_AUTHOR("Alan Cox");
463MODULE_DESCRIPTION("ALi M1535 PMU Watchdog Timer driver");
464MODULE_LICENSE("GPL");
465MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/alim7101_wdt.c b/drivers/watchdog/alim7101_wdt.c
new file mode 100644
index 000000000000..67aed9f8c362
--- /dev/null
+++ b/drivers/watchdog/alim7101_wdt.c
@@ -0,0 +1,423 @@
1/*
2 * ALi M7101 PMU Computer Watchdog Timer driver
3 *
4 * Based on w83877f_wdt.c by Scott Jennings <linuxdrivers@oro.net>
5 * and the Cobalt kernel WDT timer driver by Tim Hockin
6 * <thockin@cobaltnet.com>
7 *
8 * (c)2002 Steve Hill <steve@navaho.co.uk>
9 *
10 * This WDT driver is different from most other Linux WDT
11 * drivers in that the driver will ping the watchdog by itself,
12 * because this particular WDT has a very short timeout (1.6
13 * seconds) and it would be insane to count on any userspace
14 * daemon always getting scheduled within that time frame.
15 *
16 * Additions:
17 * Aug 23, 2004 - Added use_gpio module parameter for use on revision a1d PMUs
18 * found on very old cobalt hardware.
19 * -- Mike Waychison <michael.waychison@sun.com>
20 */
21
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/types.h>
25#include <linux/timer.h>
26#include <linux/miscdevice.h>
27#include <linux/watchdog.h>
28#include <linux/ioport.h>
29#include <linux/notifier.h>
30#include <linux/reboot.h>
31#include <linux/init.h>
32#include <linux/fs.h>
33#include <linux/pci.h>
34
35#include <asm/io.h>
36#include <asm/uaccess.h>
37#include <asm/system.h>
38
39#define OUR_NAME "alim7101_wdt"
40#define PFX OUR_NAME ": "
41
42#define WDT_ENABLE 0x9C
43#define WDT_DISABLE 0x8C
44
45#define ALI_7101_WDT 0x92
46#define ALI_7101_GPIO 0x7D
47#define ALI_7101_GPIO_O 0x7E
48#define ALI_WDT_ARM 0x01
49
50/*
51 * We're going to use a 1 second timeout.
52 * If we reset the watchdog every ~250ms we should be safe. */
53
54#define WDT_INTERVAL (HZ/4+1)
55
56/*
57 * We must not require too good response from the userspace daemon.
58 * Here we require the userspace daemon to send us a heartbeat
59 * char to /dev/watchdog every 30 seconds.
60 */
61
62#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
63static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
64module_param(timeout, int, 0);
65MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
66
67static int use_gpio = 0; /* Use the pic (for a1d revision alim7101) */
68module_param(use_gpio, int, 0);
69MODULE_PARM_DESC(use_gpio, "Use the gpio watchdog. (required by old cobalt boards)");
70
71static void wdt_timer_ping(unsigned long);
72static DEFINE_TIMER(timer, wdt_timer_ping, 0, 1);
73static unsigned long next_heartbeat;
74static unsigned long wdt_is_open;
75static char wdt_expect_close;
76static struct pci_dev *alim7101_pmu;
77
78static int nowayout = WATCHDOG_NOWAYOUT;
79module_param(nowayout, int, 0);
80MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
81 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
82
83/*
84 * Whack the dog
85 */
86
87static void wdt_timer_ping(unsigned long data)
88{
89 /* If we got a heartbeat pulse within the WDT_US_INTERVAL
90 * we agree to ping the WDT
91 */
92 char tmp;
93
94 if(time_before(jiffies, next_heartbeat))
95 {
96 /* Ping the WDT (this is actually a disarm/arm sequence) */
97 pci_read_config_byte(alim7101_pmu, 0x92, &tmp);
98 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
99 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM));
100 if (use_gpio) {
101 pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
102 pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp
103 | 0x20);
104 pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp
105 & ~0x20);
106 }
107 } else {
108 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
109 }
110 /* Re-set the timer interval */
111 mod_timer(&timer, jiffies + WDT_INTERVAL);
112}
113
114/*
115 * Utility routines
116 */
117
118static void wdt_change(int writeval)
119{
120 char tmp;
121
122 pci_read_config_byte(alim7101_pmu, ALI_7101_WDT, &tmp);
123 if (writeval == WDT_ENABLE) {
124 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp | ALI_WDT_ARM));
125 if (use_gpio) {
126 pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
127 pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp & ~0x20);
128 }
129
130 } else {
131 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, (tmp & ~ALI_WDT_ARM));
132 if (use_gpio) {
133 pci_read_config_byte(alim7101_pmu, ALI_7101_GPIO_O, &tmp);
134 pci_write_config_byte(alim7101_pmu, ALI_7101_GPIO_O, tmp | 0x20);
135 }
136 }
137}
138
139static void wdt_startup(void)
140{
141 next_heartbeat = jiffies + (timeout * HZ);
142
143 /* We must enable before we kick off the timer in case the timer
144 occurs as we ping it */
145
146 wdt_change(WDT_ENABLE);
147
148 /* Start the timer */
149 mod_timer(&timer, jiffies + WDT_INTERVAL);
150
151 printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
152}
153
154static void wdt_turnoff(void)
155{
156 /* Stop the timer */
157 del_timer_sync(&timer);
158 wdt_change(WDT_DISABLE);
159 printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
160}
161
162static void wdt_keepalive(void)
163{
164 /* user land ping */
165 next_heartbeat = jiffies + (timeout * HZ);
166}
167
168/*
169 * /dev/watchdog handling
170 */
171
172static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
173{
174 /* See if we got the magic character 'V' and reload the timer */
175 if(count) {
176 if (!nowayout) {
177 size_t ofs;
178
179 /* note: just in case someone wrote the magic character
180 * five months ago... */
181 wdt_expect_close = 0;
182
183 /* now scan */
184 for (ofs = 0; ofs != count; ofs++) {
185 char c;
186 if (get_user(c, buf+ofs))
187 return -EFAULT;
188 if (c == 'V')
189 wdt_expect_close = 42;
190 }
191 }
192 /* someone wrote to us, we should restart timer */
193 wdt_keepalive();
194 }
195 return count;
196}
197
198static int fop_open(struct inode * inode, struct file * file)
199{
200 /* Just in case we're already talking to someone... */
201 if(test_and_set_bit(0, &wdt_is_open))
202 return -EBUSY;
203 /* Good, fire up the show */
204 wdt_startup();
205 return nonseekable_open(inode, file);
206}
207
208static int fop_close(struct inode * inode, struct file * file)
209{
210 if(wdt_expect_close == 42)
211 wdt_turnoff();
212 else {
213 /* wim: shouldn't there be a: del_timer(&timer); */
214 printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n");
215 }
216 clear_bit(0, &wdt_is_open);
217 wdt_expect_close = 0;
218 return 0;
219}
220
221static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
222{
223 void __user *argp = (void __user *)arg;
224 int __user *p = argp;
225 static struct watchdog_info ident =
226 {
227 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
228 .firmware_version = 1,
229 .identity = "ALiM7101",
230 };
231
232 switch(cmd)
233 {
234 case WDIOC_GETSUPPORT:
235 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
236 case WDIOC_GETSTATUS:
237 case WDIOC_GETBOOTSTATUS:
238 return put_user(0, p);
239 case WDIOC_KEEPALIVE:
240 wdt_keepalive();
241 return 0;
242 case WDIOC_SETOPTIONS:
243 {
244 int new_options, retval = -EINVAL;
245
246 if(get_user(new_options, p))
247 return -EFAULT;
248
249 if(new_options & WDIOS_DISABLECARD) {
250 wdt_turnoff();
251 retval = 0;
252 }
253
254 if(new_options & WDIOS_ENABLECARD) {
255 wdt_startup();
256 retval = 0;
257 }
258
259 return retval;
260 }
261 case WDIOC_SETTIMEOUT:
262 {
263 int new_timeout;
264
265 if(get_user(new_timeout, p))
266 return -EFAULT;
267
268 if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
269 return -EINVAL;
270
271 timeout = new_timeout;
272 wdt_keepalive();
273 /* Fall through */
274 }
275 case WDIOC_GETTIMEOUT:
276 return put_user(timeout, p);
277 default:
278 return -ENOTTY;
279 }
280}
281
282static const struct file_operations wdt_fops = {
283 .owner= THIS_MODULE,
284 .llseek= no_llseek,
285 .write= fop_write,
286 .open= fop_open,
287 .release= fop_close,
288 .ioctl= fop_ioctl,
289};
290
291static struct miscdevice wdt_miscdev = {
292 .minor=WATCHDOG_MINOR,
293 .name="watchdog",
294 .fops=&wdt_fops,
295};
296
297/*
298 * Notifier for system down
299 */
300
301static int wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
302{
303 if (code==SYS_DOWN || code==SYS_HALT)
304 wdt_turnoff();
305
306 if (code==SYS_RESTART) {
307 /*
308 * Cobalt devices have no way of rebooting themselves other than
309 * getting the watchdog to pull reset, so we restart the watchdog on
310 * reboot with no heartbeat
311 */
312 wdt_change(WDT_ENABLE);
313 printk(KERN_INFO PFX "Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n");
314 }
315 return NOTIFY_DONE;
316}
317
318/*
319 * The WDT needs to learn about soft shutdowns in order to
320 * turn the timebomb registers off.
321 */
322
323static struct notifier_block wdt_notifier=
324{
325 .notifier_call = wdt_notify_sys,
326};
327
328static void __exit alim7101_wdt_unload(void)
329{
330 wdt_turnoff();
331 /* Deregister */
332 misc_deregister(&wdt_miscdev);
333 unregister_reboot_notifier(&wdt_notifier);
334 pci_dev_put(alim7101_pmu);
335}
336
337static int __init alim7101_wdt_init(void)
338{
339 int rc = -EBUSY;
340 struct pci_dev *ali1543_south;
341 char tmp;
342
343 printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n");
344 alim7101_pmu = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
345 NULL);
346 if (!alim7101_pmu) {
347 printk(KERN_INFO PFX "ALi M7101 PMU not present - WDT not set\n");
348 return -EBUSY;
349 }
350
351 /* Set the WDT in the PMU to 1 second */
352 pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02);
353
354 ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
355 NULL);
356 if (!ali1543_south) {
357 printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n");
358 goto err_out;
359 }
360 pci_read_config_byte(ali1543_south, 0x5e, &tmp);
361 pci_dev_put(ali1543_south);
362 if ((tmp & 0x1e) == 0x00) {
363 if (!use_gpio) {
364 printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n");
365 goto err_out;
366 }
367 nowayout = 1;
368 } else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
369 printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
370 goto err_out;
371 }
372
373 if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
374 {
375 timeout = WATCHDOG_TIMEOUT;
376 printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
377 timeout);
378 }
379
380 rc = misc_register(&wdt_miscdev);
381 if (rc) {
382 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
383 wdt_miscdev.minor, rc);
384 goto err_out;
385 }
386
387 rc = register_reboot_notifier(&wdt_notifier);
388 if (rc) {
389 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
390 rc);
391 goto err_out_miscdev;
392 }
393
394 if (nowayout) {
395 __module_get(THIS_MODULE);
396 }
397
398 printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n",
399 timeout, nowayout);
400 return 0;
401
402err_out_miscdev:
403 misc_deregister(&wdt_miscdev);
404err_out:
405 pci_dev_put(alim7101_pmu);
406 return rc;
407}
408
409module_init(alim7101_wdt_init);
410module_exit(alim7101_wdt_unload);
411
412static struct pci_device_id alim7101_pci_tbl[] __devinitdata = {
413 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
414 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
415 { }
416};
417
418MODULE_DEVICE_TABLE(pci, alim7101_pci_tbl);
419
420MODULE_AUTHOR("Steve Hill");
421MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver");
422MODULE_LICENSE("GPL");
423MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c
new file mode 100644
index 000000000000..54a516169d07
--- /dev/null
+++ b/drivers/watchdog/at32ap700x_wdt.c
@@ -0,0 +1,386 @@
1/*
2 * Watchdog driver for Atmel AT32AP700X devices
3 *
4 * Copyright (C) 2005-2006 Atmel Corporation
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 version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/miscdevice.h>
16#include <linux/fs.h>
17#include <linux/platform_device.h>
18#include <linux/watchdog.h>
19#include <linux/uaccess.h>
20#include <linux/io.h>
21#include <linux/spinlock.h>
22
23#define TIMEOUT_MIN 1
24#define TIMEOUT_MAX 2
25#define TIMEOUT_DEFAULT TIMEOUT_MAX
26
27/* module parameters */
28static int timeout = TIMEOUT_DEFAULT;
29module_param(timeout, int, 0);
30MODULE_PARM_DESC(timeout,
31 "Timeout value. Limited to be 1 or 2 seconds. (default="
32 __MODULE_STRING(TIMEOUT_DEFAULT) ")");
33
34static int nowayout = WATCHDOG_NOWAYOUT;
35module_param(nowayout, int, 0);
36MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
37 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
38
39/* Watchdog registers and write/read macro */
40#define WDT_CTRL 0x00
41#define WDT_CTRL_EN 0
42#define WDT_CTRL_PSEL 8
43#define WDT_CTRL_KEY 24
44
45#define WDT_CLR 0x04
46
47#define WDT_BIT(name) (1 << WDT_##name)
48#define WDT_BF(name, value) ((value) << WDT_##name)
49
50#define wdt_readl(dev, reg) \
51 __raw_readl((dev)->regs + WDT_##reg)
52#define wdt_writel(dev, reg, value) \
53 __raw_writel((value), (dev)->regs + WDT_##reg)
54
55struct wdt_at32ap700x {
56 void __iomem *regs;
57 spinlock_t io_lock;
58 int timeout;
59 unsigned long users;
60 struct miscdevice miscdev;
61};
62
63static struct wdt_at32ap700x *wdt;
64static char expect_release;
65
66/*
67 * Disable the watchdog.
68 */
69static inline void at32_wdt_stop(void)
70{
71 unsigned long psel;
72
73 spin_lock(&wdt->io_lock);
74 psel = wdt_readl(wdt, CTRL) & WDT_BF(CTRL_PSEL, 0x0f);
75 wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0x55));
76 wdt_writel(wdt, CTRL, psel | WDT_BF(CTRL_KEY, 0xaa));
77 spin_unlock(&wdt->io_lock);
78}
79
80/*
81 * Enable and reset the watchdog.
82 */
83static inline void at32_wdt_start(void)
84{
85 /* 0xf is 2^16 divider = 2 sec, 0xe is 2^15 divider = 1 sec */
86 unsigned long psel = (wdt->timeout > 1) ? 0xf : 0xe;
87
88 spin_lock(&wdt->io_lock);
89 wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
90 | WDT_BF(CTRL_PSEL, psel)
91 | WDT_BF(CTRL_KEY, 0x55));
92 wdt_writel(wdt, CTRL, WDT_BIT(CTRL_EN)
93 | WDT_BF(CTRL_PSEL, psel)
94 | WDT_BF(CTRL_KEY, 0xaa));
95 spin_unlock(&wdt->io_lock);
96}
97
98/*
99 * Pat the watchdog timer.
100 */
101static inline void at32_wdt_pat(void)
102{
103 spin_lock(&wdt->io_lock);
104 wdt_writel(wdt, CLR, 0x42);
105 spin_unlock(&wdt->io_lock);
106}
107
108/*
109 * Watchdog device is opened, and watchdog starts running.
110 */
111static int at32_wdt_open(struct inode *inode, struct file *file)
112{
113 if (test_and_set_bit(1, &wdt->users))
114 return -EBUSY;
115
116 at32_wdt_start();
117 return nonseekable_open(inode, file);
118}
119
120/*
121 * Close the watchdog device.
122 */
123static int at32_wdt_close(struct inode *inode, struct file *file)
124{
125 if (expect_release == 42) {
126 at32_wdt_stop();
127 } else {
128 dev_dbg(wdt->miscdev.parent,
129 "Unexpected close, not stopping watchdog!\n");
130 at32_wdt_pat();
131 }
132 clear_bit(1, &wdt->users);
133 expect_release = 0;
134 return 0;
135}
136
137/*
138 * Change the watchdog time interval.
139 */
140static int at32_wdt_settimeout(int time)
141{
142 /*
143 * All counting occurs at 1 / SLOW_CLOCK (32 kHz) and max prescaler is
144 * 2 ^ 16 allowing up to 2 seconds timeout.
145 */
146 if ((time < TIMEOUT_MIN) || (time > TIMEOUT_MAX))
147 return -EINVAL;
148
149 /*
150 * Set new watchdog time. It will be used when at32_wdt_start() is
151 * called.
152 */
153 wdt->timeout = time;
154 return 0;
155}
156
157static struct watchdog_info at32_wdt_info = {
158 .identity = "at32ap700x watchdog",
159 .options = WDIOF_SETTIMEOUT |
160 WDIOF_KEEPALIVEPING |
161 WDIOF_MAGICCLOSE,
162};
163
164/*
165 * Handle commands from user-space.
166 */
167static int at32_wdt_ioctl(struct inode *inode, struct file *file,
168 unsigned int cmd, unsigned long arg)
169{
170 int ret = -ENOTTY;
171 int time;
172 void __user *argp = (void __user *)arg;
173 int __user *p = argp;
174
175 switch (cmd) {
176 case WDIOC_KEEPALIVE:
177 at32_wdt_pat();
178 ret = 0;
179 break;
180 case WDIOC_GETSUPPORT:
181 ret = copy_to_user(argp, &at32_wdt_info,
182 sizeof(at32_wdt_info)) ? -EFAULT : 0;
183 break;
184 case WDIOC_SETTIMEOUT:
185 ret = get_user(time, p);
186 if (ret)
187 break;
188 ret = at32_wdt_settimeout(time);
189 if (ret)
190 break;
191 /* Enable new time value */
192 at32_wdt_start();
193 /* fall through */
194 case WDIOC_GETTIMEOUT:
195 ret = put_user(wdt->timeout, p);
196 break;
197 case WDIOC_GETSTATUS: /* fall through */
198 case WDIOC_GETBOOTSTATUS:
199 ret = put_user(0, p);
200 break;
201 case WDIOC_SETOPTIONS:
202 ret = get_user(time, p);
203 if (ret)
204 break;
205 if (time & WDIOS_DISABLECARD)
206 at32_wdt_stop();
207 if (time & WDIOS_ENABLECARD)
208 at32_wdt_start();
209 ret = 0;
210 break;
211 }
212
213 return ret;
214}
215
216static ssize_t at32_wdt_write(struct file *file, const char __user *data,
217 size_t len, loff_t *ppos)
218{
219 /* See if we got the magic character 'V' and reload the timer */
220 if (len) {
221 if (!nowayout) {
222 size_t i;
223
224 /*
225 * note: just in case someone wrote the magic
226 * character five months ago...
227 */
228 expect_release = 0;
229
230 /*
231 * scan to see whether or not we got the magic
232 * character
233 */
234 for (i = 0; i != len; i++) {
235 char c;
236 if (get_user(c, data+i))
237 return -EFAULT;
238 if (c == 'V')
239 expect_release = 42;
240 }
241 }
242 /* someone wrote to us, we should pat the watchdog */
243 at32_wdt_pat();
244 }
245 return len;
246}
247
248static const struct file_operations at32_wdt_fops = {
249 .owner = THIS_MODULE,
250 .llseek = no_llseek,
251 .ioctl = at32_wdt_ioctl,
252 .open = at32_wdt_open,
253 .release = at32_wdt_close,
254 .write = at32_wdt_write,
255};
256
257static int __init at32_wdt_probe(struct platform_device *pdev)
258{
259 struct resource *regs;
260 int ret;
261
262 if (wdt) {
263 dev_dbg(&pdev->dev, "only 1 wdt instance supported.\n");
264 return -EBUSY;
265 }
266
267 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
268 if (!regs) {
269 dev_dbg(&pdev->dev, "missing mmio resource\n");
270 return -ENXIO;
271 }
272
273 wdt = kzalloc(sizeof(struct wdt_at32ap700x), GFP_KERNEL);
274 if (!wdt) {
275 dev_dbg(&pdev->dev, "no memory for wdt structure\n");
276 return -ENOMEM;
277 }
278
279 wdt->regs = ioremap(regs->start, regs->end - regs->start + 1);
280 if (!wdt->regs) {
281 ret = -ENOMEM;
282 dev_dbg(&pdev->dev, "could not map I/O memory\n");
283 goto err_free;
284 }
285 spin_lock_init(&wdt->io_lock);
286 wdt->users = 0;
287 wdt->miscdev.minor = WATCHDOG_MINOR;
288 wdt->miscdev.name = "watchdog";
289 wdt->miscdev.fops = &at32_wdt_fops;
290
291 if (at32_wdt_settimeout(timeout)) {
292 at32_wdt_settimeout(TIMEOUT_DEFAULT);
293 dev_dbg(&pdev->dev,
294 "default timeout invalid, set to %d sec.\n",
295 TIMEOUT_DEFAULT);
296 }
297
298 ret = misc_register(&wdt->miscdev);
299 if (ret) {
300 dev_dbg(&pdev->dev, "failed to register wdt miscdev\n");
301 goto err_iounmap;
302 }
303
304 platform_set_drvdata(pdev, wdt);
305 wdt->miscdev.parent = &pdev->dev;
306 dev_info(&pdev->dev,
307 "AT32AP700X WDT at 0x%p, timeout %d sec (nowayout=%d)\n",
308 wdt->regs, wdt->timeout, nowayout);
309
310 return 0;
311
312err_iounmap:
313 iounmap(wdt->regs);
314err_free:
315 kfree(wdt);
316 wdt = NULL;
317 return ret;
318}
319
320static int __exit at32_wdt_remove(struct platform_device *pdev)
321{
322 if (wdt && platform_get_drvdata(pdev) == wdt) {
323 /* Stop the timer before we leave */
324 if (!nowayout)
325 at32_wdt_stop();
326
327 misc_deregister(&wdt->miscdev);
328 iounmap(wdt->regs);
329 kfree(wdt);
330 wdt = NULL;
331 platform_set_drvdata(pdev, NULL);
332 }
333
334 return 0;
335}
336
337static void at32_wdt_shutdown(struct platform_device *pdev)
338{
339 at32_wdt_stop();
340}
341
342#ifdef CONFIG_PM
343static int at32_wdt_suspend(struct platform_device *pdev, pm_message_t message)
344{
345 at32_wdt_stop();
346 return 0;
347}
348
349static int at32_wdt_resume(struct platform_device *pdev)
350{
351 if (wdt->users)
352 at32_wdt_start();
353 return 0;
354}
355#else
356#define at32_wdt_suspend NULL
357#define at32_wdt_resume NULL
358#endif
359
360static struct platform_driver at32_wdt_driver = {
361 .remove = __exit_p(at32_wdt_remove),
362 .suspend = at32_wdt_suspend,
363 .resume = at32_wdt_resume,
364 .driver = {
365 .name = "at32_wdt",
366 .owner = THIS_MODULE,
367 },
368 .shutdown = at32_wdt_shutdown,
369};
370
371static int __init at32_wdt_init(void)
372{
373 return platform_driver_probe(&at32_wdt_driver, at32_wdt_probe);
374}
375module_init(at32_wdt_init);
376
377static void __exit at32_wdt_exit(void)
378{
379 platform_driver_unregister(&at32_wdt_driver);
380}
381module_exit(at32_wdt_exit);
382
383MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
384MODULE_DESCRIPTION("Watchdog driver for Atmel AT32AP700X");
385MODULE_LICENSE("GPL");
386MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c
new file mode 100644
index 000000000000..38bd37372599
--- /dev/null
+++ b/drivers/watchdog/at91rm9200_wdt.c
@@ -0,0 +1,288 @@
1/*
2 * Watchdog driver for Atmel AT91RM9200 (Thunder)
3 *
4 * Copyright (C) 2003 SAN People (Pty) Ltd
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/errno.h>
13#include <linux/fs.h>
14#include <linux/init.h>
15#include <linux/kernel.h>
16#include <linux/miscdevice.h>
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/platform_device.h>
20#include <linux/types.h>
21#include <linux/watchdog.h>
22#include <asm/bitops.h>
23#include <asm/uaccess.h>
24#include <asm/arch/at91_st.h>
25
26
27#define WDT_DEFAULT_TIME 5 /* seconds */
28#define WDT_MAX_TIME 256 /* seconds */
29
30static int wdt_time = WDT_DEFAULT_TIME;
31static int nowayout = WATCHDOG_NOWAYOUT;
32
33module_param(wdt_time, int, 0);
34MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
35
36#ifdef CONFIG_WATCHDOG_NOWAYOUT
37module_param(nowayout, int, 0);
38MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
39#endif
40
41
42static unsigned long at91wdt_busy;
43
44/* ......................................................................... */
45
46/*
47 * Disable the watchdog.
48 */
49static void inline at91_wdt_stop(void)
50{
51 at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN);
52}
53
54/*
55 * Enable and reset the watchdog.
56 */
57static void inline at91_wdt_start(void)
58{
59 at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV));
60 at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
61}
62
63/*
64 * Reload the watchdog timer. (ie, pat the watchdog)
65 */
66static void inline at91_wdt_reload(void)
67{
68 at91_sys_write(AT91_ST_CR, AT91_ST_WDRST);
69}
70
71/* ......................................................................... */
72
73/*
74 * Watchdog device is opened, and watchdog starts running.
75 */
76static int at91_wdt_open(struct inode *inode, struct file *file)
77{
78 if (test_and_set_bit(0, &at91wdt_busy))
79 return -EBUSY;
80
81 at91_wdt_start();
82 return nonseekable_open(inode, file);
83}
84
85/*
86 * Close the watchdog device.
87 * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also
88 * disabled.
89 */
90static int at91_wdt_close(struct inode *inode, struct file *file)
91{
92 if (!nowayout)
93 at91_wdt_stop(); /* Disable the watchdog when file is closed */
94
95 clear_bit(0, &at91wdt_busy);
96 return 0;
97}
98
99/*
100 * Change the watchdog time interval.
101 */
102static int at91_wdt_settimeout(int new_time)
103{
104 /*
105 * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
106 *
107 * Since WDV is a 16-bit counter, the maximum period is
108 * 65536 / 0.256 = 256 seconds.
109 */
110 if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
111 return -EINVAL;
112
113 /* Set new watchdog time. It will be used when at91_wdt_start() is called. */
114 wdt_time = new_time;
115 return 0;
116}
117
118static struct watchdog_info at91_wdt_info = {
119 .identity = "at91 watchdog",
120 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
121};
122
123/*
124 * Handle commands from user-space.
125 */
126static int at91_wdt_ioctl(struct inode *inode, struct file *file,
127 unsigned int cmd, unsigned long arg)
128{
129 void __user *argp = (void __user *)arg;
130 int __user *p = argp;
131 int new_value;
132
133 switch(cmd) {
134 case WDIOC_KEEPALIVE:
135 at91_wdt_reload(); /* pat the watchdog */
136 return 0;
137
138 case WDIOC_GETSUPPORT:
139 return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0;
140
141 case WDIOC_SETTIMEOUT:
142 if (get_user(new_value, p))
143 return -EFAULT;
144
145 if (at91_wdt_settimeout(new_value))
146 return -EINVAL;
147
148 /* Enable new time value */
149 at91_wdt_start();
150
151 /* Return current value */
152 return put_user(wdt_time, p);
153
154 case WDIOC_GETTIMEOUT:
155 return put_user(wdt_time, p);
156
157 case WDIOC_GETSTATUS:
158 case WDIOC_GETBOOTSTATUS:
159 return put_user(0, p);
160
161 case WDIOC_SETOPTIONS:
162 if (get_user(new_value, p))
163 return -EFAULT;
164
165 if (new_value & WDIOS_DISABLECARD)
166 at91_wdt_stop();
167 if (new_value & WDIOS_ENABLECARD)
168 at91_wdt_start();
169 return 0;
170
171 default:
172 return -ENOTTY;
173 }
174}
175
176/*
177 * Pat the watchdog whenever device is written to.
178 */
179static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
180{
181 at91_wdt_reload(); /* pat the watchdog */
182 return len;
183}
184
185/* ......................................................................... */
186
187static const struct file_operations at91wdt_fops = {
188 .owner = THIS_MODULE,
189 .llseek = no_llseek,
190 .ioctl = at91_wdt_ioctl,
191 .open = at91_wdt_open,
192 .release = at91_wdt_close,
193 .write = at91_wdt_write,
194};
195
196static struct miscdevice at91wdt_miscdev = {
197 .minor = WATCHDOG_MINOR,
198 .name = "watchdog",
199 .fops = &at91wdt_fops,
200};
201
202static int __init at91wdt_probe(struct platform_device *pdev)
203{
204 int res;
205
206 if (at91wdt_miscdev.parent)
207 return -EBUSY;
208 at91wdt_miscdev.parent = &pdev->dev;
209
210 res = misc_register(&at91wdt_miscdev);
211 if (res)
212 return res;
213
214 printk("AT91 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : "");
215 return 0;
216}
217
218static int __exit at91wdt_remove(struct platform_device *pdev)
219{
220 int res;
221
222 res = misc_deregister(&at91wdt_miscdev);
223 if (!res)
224 at91wdt_miscdev.parent = NULL;
225
226 return res;
227}
228
229static void at91wdt_shutdown(struct platform_device *pdev)
230{
231 at91_wdt_stop();
232}
233
234#ifdef CONFIG_PM
235
236static int at91wdt_suspend(struct platform_device *pdev, pm_message_t message)
237{
238 at91_wdt_stop();
239 return 0;
240}
241
242static int at91wdt_resume(struct platform_device *pdev)
243{
244 if (at91wdt_busy)
245 at91_wdt_start();
246 return 0;
247}
248
249#else
250#define at91wdt_suspend NULL
251#define at91wdt_resume NULL
252#endif
253
254static struct platform_driver at91wdt_driver = {
255 .probe = at91wdt_probe,
256 .remove = __exit_p(at91wdt_remove),
257 .shutdown = at91wdt_shutdown,
258 .suspend = at91wdt_suspend,
259 .resume = at91wdt_resume,
260 .driver = {
261 .name = "at91_wdt",
262 .owner = THIS_MODULE,
263 },
264};
265
266static int __init at91_wdt_init(void)
267{
268 /* Check that the heartbeat value is within range; if not reset to the default */
269 if (at91_wdt_settimeout(wdt_time)) {
270 at91_wdt_settimeout(WDT_DEFAULT_TIME);
271 pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
272 }
273
274 return platform_driver_register(&at91wdt_driver);
275}
276
277static void __exit at91_wdt_exit(void)
278{
279 platform_driver_unregister(&at91wdt_driver);
280}
281
282module_init(at91_wdt_init);
283module_exit(at91_wdt_exit);
284
285MODULE_AUTHOR("Andrew Victor");
286MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200");
287MODULE_LICENSE("GPL");
288MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/bfin_wdt.c b/drivers/watchdog/bfin_wdt.c
new file mode 100644
index 000000000000..309d27913fc1
--- /dev/null
+++ b/drivers/watchdog/bfin_wdt.c
@@ -0,0 +1,490 @@
1/*
2 * Blackfin On-Chip Watchdog Driver
3 * Supports BF53[123]/BF53[467]/BF54[2489]/BF561
4 *
5 * Originally based on softdog.c
6 * Copyright 2006-2007 Analog Devices Inc.
7 * Copyright 2006-2007 Michele d'Amico
8 * Copyright 1996 Alan Cox <alan@redhat.com>
9 *
10 * Enter bugs at http://blackfin.uclinux.org/
11 *
12 * Licensed under the GPL-2 or later.
13 */
14
15#include <linux/platform_device.h>
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/types.h>
19#include <linux/timer.h>
20#include <linux/miscdevice.h>
21#include <linux/watchdog.h>
22#include <linux/fs.h>
23#include <linux/notifier.h>
24#include <linux/reboot.h>
25#include <linux/init.h>
26#include <linux/interrupt.h>
27#include <asm/blackfin.h>
28#include <asm/uaccess.h>
29
30#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
31#define stampit() stamp("here i am")
32
33#define WATCHDOG_NAME "bfin-wdt"
34#define PFX WATCHDOG_NAME ": "
35
36/* The BF561 has two watchdogs (one per core), but since Linux
37 * only runs on core A, we'll just work with that one.
38 */
39#ifdef BF561_FAMILY
40# define bfin_read_WDOG_CTL() bfin_read_WDOGA_CTL()
41# define bfin_read_WDOG_CNT() bfin_read_WDOGA_CNT()
42# define bfin_read_WDOG_STAT() bfin_read_WDOGA_STAT()
43# define bfin_write_WDOG_CTL(x) bfin_write_WDOGA_CTL(x)
44# define bfin_write_WDOG_CNT(x) bfin_write_WDOGA_CNT(x)
45# define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x)
46#endif
47
48/* Bit in SWRST that indicates boot caused by watchdog */
49#define SWRST_RESET_WDOG 0x4000
50
51/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */
52#define WDOG_EXPIRED 0x8000
53
54/* Masks for WDEV field in WDOG_CTL register */
55#define ICTL_RESET 0x0
56#define ICTL_NMI 0x2
57#define ICTL_GPI 0x4
58#define ICTL_NONE 0x6
59#define ICTL_MASK 0x6
60
61/* Masks for WDEN field in WDOG_CTL register */
62#define WDEN_MASK 0x0FF0
63#define WDEN_ENABLE 0x0000
64#define WDEN_DISABLE 0x0AD0
65
66/* some defaults */
67#define WATCHDOG_TIMEOUT 20
68
69static unsigned int timeout = WATCHDOG_TIMEOUT;
70static int nowayout = WATCHDOG_NOWAYOUT;
71static struct watchdog_info bfin_wdt_info;
72static unsigned long open_check;
73static char expect_close;
74static spinlock_t bfin_wdt_spinlock = SPIN_LOCK_UNLOCKED;
75
76/**
77 * bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
78 *
79 * The Userspace watchdog got a KeepAlive: schedule the next timeout.
80 */
81static int bfin_wdt_keepalive(void)
82{
83 stampit();
84 bfin_write_WDOG_STAT(0);
85 return 0;
86}
87
88/**
89 * bfin_wdt_stop - Stop the Watchdog
90 *
91 * Stops the on-chip watchdog.
92 */
93static int bfin_wdt_stop(void)
94{
95 stampit();
96 bfin_write_WDOG_CTL(WDEN_DISABLE);
97 return 0;
98}
99
100/**
101 * bfin_wdt_start - Start the Watchdog
102 *
103 * Starts the on-chip watchdog. Automatically loads WDOG_CNT
104 * into WDOG_STAT for us.
105 */
106static int bfin_wdt_start(void)
107{
108 stampit();
109 bfin_write_WDOG_CTL(WDEN_ENABLE | ICTL_RESET);
110 return 0;
111}
112
113/**
114 * bfin_wdt_running - Check Watchdog status
115 *
116 * See if the watchdog is running.
117 */
118static int bfin_wdt_running(void)
119{
120 stampit();
121 return ((bfin_read_WDOG_CTL() & WDEN_MASK) != WDEN_DISABLE);
122}
123
124/**
125 * bfin_wdt_set_timeout - Set the Userspace Watchdog timeout
126 * @t: new timeout value (in seconds)
127 *
128 * Translate the specified timeout in seconds into System Clock
129 * terms which is what the on-chip Watchdog requires.
130 */
131static int bfin_wdt_set_timeout(unsigned long t)
132{
133 u32 cnt;
134 unsigned long flags;
135
136 stampit();
137
138 cnt = t * get_sclk();
139 if (cnt < get_sclk()) {
140 printk(KERN_WARNING PFX "timeout value is too large\n");
141 return -EINVAL;
142 }
143
144 spin_lock_irqsave(&bfin_wdt_spinlock, flags);
145 {
146 int run = bfin_wdt_running();
147 bfin_wdt_stop();
148 bfin_write_WDOG_CNT(cnt);
149 if (run) bfin_wdt_start();
150 }
151 spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
152
153 timeout = t;
154
155 return 0;
156}
157
158/**
159 * bfin_wdt_open - Open the Device
160 * @inode: inode of device
161 * @file: file handle of device
162 *
163 * Watchdog device is opened and started.
164 */
165static int bfin_wdt_open(struct inode *inode, struct file *file)
166{
167 stampit();
168
169 if (test_and_set_bit(0, &open_check))
170 return -EBUSY;
171
172 if (nowayout)
173 __module_get(THIS_MODULE);
174
175 bfin_wdt_keepalive();
176 bfin_wdt_start();
177
178 return nonseekable_open(inode, file);
179}
180
181/**
182 * bfin_wdt_close - Close the Device
183 * @inode: inode of device
184 * @file: file handle of device
185 *
186 * Watchdog device is closed and stopped.
187 */
188static int bfin_wdt_release(struct inode *inode, struct file *file)
189{
190 stampit();
191
192 if (expect_close == 42) {
193 bfin_wdt_stop();
194 } else {
195 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
196 bfin_wdt_keepalive();
197 }
198
199 expect_close = 0;
200 clear_bit(0, &open_check);
201
202 return 0;
203}
204
205/**
206 * bfin_wdt_write - Write to Device
207 * @file: file handle of device
208 * @buf: buffer to write
209 * @count: length of buffer
210 * @ppos: offset
211 *
212 * Pings the watchdog on write.
213 */
214static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
215 size_t len, loff_t *ppos)
216{
217 stampit();
218
219 if (len) {
220 if (!nowayout) {
221 size_t i;
222
223 /* In case it was set long ago */
224 expect_close = 0;
225
226 for (i = 0; i != len; i++) {
227 char c;
228 if (get_user(c, data + i))
229 return -EFAULT;
230 if (c == 'V')
231 expect_close = 42;
232 }
233 }
234 bfin_wdt_keepalive();
235 }
236
237 return len;
238}
239
240/**
241 * bfin_wdt_ioctl - Query Device
242 * @inode: inode of device
243 * @file: file handle of device
244 * @cmd: watchdog command
245 * @arg: argument
246 *
247 * Query basic information from the device or ping it, as outlined by the
248 * watchdog API.
249 */
250static int bfin_wdt_ioctl(struct inode *inode, struct file *file,
251 unsigned int cmd, unsigned long arg)
252{
253 void __user *argp = (void __user *)arg;
254 int __user *p = argp;
255
256 stampit();
257
258 switch (cmd) {
259 default:
260 return -ENOTTY;
261
262 case WDIOC_GETSUPPORT:
263 if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
264 return -EFAULT;
265 else
266 return 0;
267
268 case WDIOC_GETSTATUS:
269 case WDIOC_GETBOOTSTATUS:
270 return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
271
272 case WDIOC_KEEPALIVE:
273 bfin_wdt_keepalive();
274 return 0;
275
276 case WDIOC_SETTIMEOUT: {
277 int new_timeout;
278
279 if (get_user(new_timeout, p))
280 return -EFAULT;
281
282 if (bfin_wdt_set_timeout(new_timeout))
283 return -EINVAL;
284 }
285 /* Fall */
286 case WDIOC_GETTIMEOUT:
287 return put_user(timeout, p);
288
289 case WDIOC_SETOPTIONS: {
290 unsigned long flags;
291 int options, ret = -EINVAL;
292
293 if (get_user(options, p))
294 return -EFAULT;
295
296 spin_lock_irqsave(&bfin_wdt_spinlock, flags);
297
298 if (options & WDIOS_DISABLECARD) {
299 bfin_wdt_stop();
300 ret = 0;
301 }
302
303 if (options & WDIOS_ENABLECARD) {
304 bfin_wdt_start();
305 ret = 0;
306 }
307
308 spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
309
310 return ret;
311 }
312 }
313}
314
315/**
316 * bfin_wdt_notify_sys - Notifier Handler
317 * @this: notifier block
318 * @code: notifier event
319 * @unused: unused
320 *
321 * Handles specific events, such as turning off the watchdog during a
322 * shutdown event.
323 */
324static int bfin_wdt_notify_sys(struct notifier_block *this, unsigned long code,
325 void *unused)
326{
327 stampit();
328
329 if (code == SYS_DOWN || code == SYS_HALT)
330 bfin_wdt_stop();
331
332 return NOTIFY_DONE;
333}
334
335#ifdef CONFIG_PM
336static int state_before_suspend;
337
338/**
339 * bfin_wdt_suspend - suspend the watchdog
340 * @pdev: device being suspended
341 * @state: requested suspend state
342 *
343 * Remember if the watchdog was running and stop it.
344 * TODO: is this even right? Doesn't seem to be any
345 * standard in the watchdog world ...
346 */
347static int bfin_wdt_suspend(struct platform_device *pdev, pm_message_t state)
348{
349 stampit();
350
351 state_before_suspend = bfin_wdt_running();
352 bfin_wdt_stop();
353
354 return 0;
355}
356
357/**
358 * bfin_wdt_resume - resume the watchdog
359 * @pdev: device being resumed
360 *
361 * If the watchdog was running, turn it back on.
362 */
363static int bfin_wdt_resume(struct platform_device *pdev)
364{
365 stampit();
366
367 if (state_before_suspend) {
368 bfin_wdt_set_timeout(timeout);
369 bfin_wdt_start();
370 }
371
372 return 0;
373}
374#else
375# define bfin_wdt_suspend NULL
376# define bfin_wdt_resume NULL
377#endif
378
379static struct platform_device bfin_wdt_device = {
380 .name = WATCHDOG_NAME,
381 .id = -1,
382};
383
384static struct platform_driver bfin_wdt_driver = {
385 .driver = {
386 .name = WATCHDOG_NAME,
387 .owner = THIS_MODULE,
388 },
389 .suspend = bfin_wdt_suspend,
390 .resume = bfin_wdt_resume,
391};
392
393static struct file_operations bfin_wdt_fops = {
394 .owner = THIS_MODULE,
395 .llseek = no_llseek,
396 .write = bfin_wdt_write,
397 .ioctl = bfin_wdt_ioctl,
398 .open = bfin_wdt_open,
399 .release = bfin_wdt_release,
400};
401
402static struct miscdevice bfin_wdt_miscdev = {
403 .minor = WATCHDOG_MINOR,
404 .name = "watchdog",
405 .fops = &bfin_wdt_fops,
406};
407
408static struct watchdog_info bfin_wdt_info = {
409 .identity = "Blackfin Watchdog",
410 .options = WDIOF_SETTIMEOUT |
411 WDIOF_KEEPALIVEPING |
412 WDIOF_MAGICCLOSE,
413};
414
415static struct notifier_block bfin_wdt_notifier = {
416 .notifier_call = bfin_wdt_notify_sys,
417};
418
419/**
420 * bfin_wdt_init - Initialize module
421 *
422 * Registers the device and notifier handler. Actual device
423 * initialization is handled by bfin_wdt_open().
424 */
425static int __init bfin_wdt_init(void)
426{
427 int ret;
428
429 stampit();
430
431 /* Check that the timeout value is within range */
432 if (bfin_wdt_set_timeout(timeout))
433 return -EINVAL;
434
435 /* Since this is an on-chip device and needs no board-specific
436 * resources, we'll handle all the platform device stuff here.
437 */
438 ret = platform_device_register(&bfin_wdt_device);
439 if (ret)
440 return ret;
441
442 ret = platform_driver_probe(&bfin_wdt_driver, NULL);
443 if (ret)
444 return ret;
445
446 ret = register_reboot_notifier(&bfin_wdt_notifier);
447 if (ret) {
448 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
449 return ret;
450 }
451
452 ret = misc_register(&bfin_wdt_miscdev);
453 if (ret) {
454 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
455 WATCHDOG_MINOR, ret);
456 unregister_reboot_notifier(&bfin_wdt_notifier);
457 return ret;
458 }
459
460 printk(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
461 timeout, nowayout);
462
463 return 0;
464}
465
466/**
467 * bfin_wdt_exit - Deinitialize module
468 *
469 * Unregisters the device and notifier handler. Actual device
470 * deinitialization is handled by bfin_wdt_close().
471 */
472static void __exit bfin_wdt_exit(void)
473{
474 misc_deregister(&bfin_wdt_miscdev);
475 unregister_reboot_notifier(&bfin_wdt_notifier);
476}
477
478module_init(bfin_wdt_init);
479module_exit(bfin_wdt_exit);
480
481MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>");
482MODULE_DESCRIPTION("Blackfin Watchdog Device Driver");
483MODULE_LICENSE("GPL");
484MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
485
486module_param(timeout, uint, 0);
487MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
488
489module_param(nowayout, int, 0);
490MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c
new file mode 100644
index 000000000000..d362f5bf658a
--- /dev/null
+++ b/drivers/watchdog/booke_wdt.c
@@ -0,0 +1,194 @@
1/*
2 * drivers/char/watchdog/booke_wdt.c
3 *
4 * Watchdog timer for PowerPC Book-E systems
5 *
6 * Author: Matthew McClintock
7 * Maintainer: Kumar Gala <galak@kernel.crashing.org>
8 *
9 * Copyright 2005 Freescale Semiconductor Inc.
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16
17#include <linux/module.h>
18#include <linux/fs.h>
19#include <linux/miscdevice.h>
20#include <linux/notifier.h>
21#include <linux/watchdog.h>
22
23#include <asm/reg_booke.h>
24#include <asm/uaccess.h>
25#include <asm/system.h>
26
27/* If the kernel parameter wdt=1, the watchdog will be enabled at boot.
28 * Also, the wdt_period sets the watchdog timer period timeout.
29 * For E500 cpus the wdt_period sets which bit changing from 0->1 will
30 * trigger a watchog timeout. This watchdog timeout will occur 3 times, the
31 * first time nothing will happen, the second time a watchdog exception will
32 * occur, and the final time the board will reset.
33 */
34
35#ifdef CONFIG_FSL_BOOKE
36#define WDT_PERIOD_DEFAULT 63 /* Ex. wdt_period=28 bus=333Mhz , reset=~40sec */
37#else
38#define WDT_PERIOD_DEFAULT 3 /* Refer to the PPC40x and PPC4xx manuals */
39#endif /* for timing information */
40
41u32 booke_wdt_enabled = 0;
42u32 booke_wdt_period = WDT_PERIOD_DEFAULT;
43
44#ifdef CONFIG_FSL_BOOKE
45#define WDTP(x) ((((63-x)&0x3)<<30)|(((63-x)&0x3c)<<15))
46#else
47#define WDTP(x) (TCR_WP(x))
48#endif
49
50/*
51 * booke_wdt_ping:
52 */
53static __inline__ void booke_wdt_ping(void)
54{
55 mtspr(SPRN_TSR, TSR_ENW|TSR_WIS);
56}
57
58/*
59 * booke_wdt_enable:
60 */
61static __inline__ void booke_wdt_enable(void)
62{
63 u32 val;
64
65 /* clear status before enabling watchdog */
66 booke_wdt_ping();
67 val = mfspr(SPRN_TCR);
68 val |= (TCR_WIE|TCR_WRC(WRC_CHIP)|WDTP(booke_wdt_period));
69
70 mtspr(SPRN_TCR, val);
71}
72
73/*
74 * booke_wdt_write:
75 */
76static ssize_t booke_wdt_write (struct file *file, const char __user *buf,
77 size_t count, loff_t *ppos)
78{
79 booke_wdt_ping();
80 return count;
81}
82
83static struct watchdog_info ident = {
84 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
85 .firmware_version = 0,
86 .identity = "PowerPC Book-E Watchdog",
87};
88
89/*
90 * booke_wdt_ioctl:
91 */
92static int booke_wdt_ioctl (struct inode *inode, struct file *file,
93 unsigned int cmd, unsigned long arg)
94{
95 u32 tmp = 0;
96 u32 __user *p = (u32 __user *)arg;
97
98 switch (cmd) {
99 case WDIOC_GETSUPPORT:
100 if (copy_to_user ((struct watchdog_info __user *) arg, &ident,
101 sizeof(struct watchdog_info)))
102 return -EFAULT;
103 case WDIOC_GETSTATUS:
104 return put_user(ident.options, p);
105 case WDIOC_GETBOOTSTATUS:
106 /* XXX: something is clearing TSR */
107 tmp = mfspr(SPRN_TSR) & TSR_WRS(3);
108 /* returns 1 if last reset was caused by the WDT */
109 return (tmp ? 1 : 0);
110 case WDIOC_KEEPALIVE:
111 booke_wdt_ping();
112 return 0;
113 case WDIOC_SETTIMEOUT:
114 if (get_user(booke_wdt_period, p))
115 return -EFAULT;
116 mtspr(SPRN_TCR, (mfspr(SPRN_TCR)&~WDTP(0))|WDTP(booke_wdt_period));
117 return 0;
118 case WDIOC_GETTIMEOUT:
119 return put_user(booke_wdt_period, p);
120 case WDIOC_SETOPTIONS:
121 if (get_user(tmp, p))
122 return -EINVAL;
123 if (tmp == WDIOS_ENABLECARD) {
124 booke_wdt_ping();
125 break;
126 } else
127 return -EINVAL;
128 return 0;
129 default:
130 return -ENOTTY;
131 }
132
133 return 0;
134}
135/*
136 * booke_wdt_open:
137 */
138static int booke_wdt_open (struct inode *inode, struct file *file)
139{
140 if (booke_wdt_enabled == 0) {
141 booke_wdt_enabled = 1;
142 booke_wdt_enable();
143 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
144 booke_wdt_period);
145 }
146
147 return nonseekable_open(inode, file);
148}
149
150static const struct file_operations booke_wdt_fops = {
151 .owner = THIS_MODULE,
152 .llseek = no_llseek,
153 .write = booke_wdt_write,
154 .ioctl = booke_wdt_ioctl,
155 .open = booke_wdt_open,
156};
157
158static struct miscdevice booke_wdt_miscdev = {
159 .minor = WATCHDOG_MINOR,
160 .name = "watchdog",
161 .fops = &booke_wdt_fops,
162};
163
164static void __exit booke_wdt_exit(void)
165{
166 misc_deregister(&booke_wdt_miscdev);
167}
168
169/*
170 * booke_wdt_init:
171 */
172static int __init booke_wdt_init(void)
173{
174 int ret = 0;
175
176 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Loaded\n");
177 ident.firmware_version = cur_cpu_spec->pvr_value;
178
179 ret = misc_register(&booke_wdt_miscdev);
180 if (ret) {
181 printk (KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n",
182 WATCHDOG_MINOR, ret);
183 return ret;
184 }
185
186 if (booke_wdt_enabled == 1) {
187 printk (KERN_INFO "PowerPC Book-E Watchdog Timer Enabled (wdt_period=%d)\n",
188 booke_wdt_period);
189 booke_wdt_enable();
190 }
191
192 return ret;
193}
194device_initcall(booke_wdt_init);
diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c
new file mode 100644
index 000000000000..5941ca601a3a
--- /dev/null
+++ b/drivers/watchdog/cpu5wdt.c
@@ -0,0 +1,304 @@
1/*
2 * sma cpu5 watchdog driver
3 *
4 * Copyright (C) 2003 Heiko Ronsdorf <hero@ihg.uni-duisburg.de>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/types.h>
25#include <linux/errno.h>
26#include <linux/miscdevice.h>
27#include <linux/fs.h>
28#include <linux/init.h>
29#include <linux/ioport.h>
30#include <linux/timer.h>
31#include <linux/completion.h>
32#include <linux/jiffies.h>
33#include <asm/io.h>
34#include <asm/uaccess.h>
35
36#include <linux/watchdog.h>
37
38/* adjustable parameters */
39
40static int verbose = 0;
41static int port = 0x91;
42static int ticks = 10000;
43
44#define PFX "cpu5wdt: "
45
46#define CPU5WDT_EXTENT 0x0A
47
48#define CPU5WDT_STATUS_REG 0x00
49#define CPU5WDT_TIME_A_REG 0x02
50#define CPU5WDT_TIME_B_REG 0x03
51#define CPU5WDT_MODE_REG 0x04
52#define CPU5WDT_TRIGGER_REG 0x07
53#define CPU5WDT_ENABLE_REG 0x08
54#define CPU5WDT_RESET_REG 0x09
55
56#define CPU5WDT_INTERVAL (HZ/10+1)
57
58/* some device data */
59
60static struct {
61 struct completion stop;
62 volatile int running;
63 struct timer_list timer;
64 volatile int queue;
65 int default_ticks;
66 unsigned long inuse;
67} cpu5wdt_device;
68
69/* generic helper functions */
70
71static void cpu5wdt_trigger(unsigned long unused)
72{
73 if ( verbose > 2 )
74 printk(KERN_DEBUG PFX "trigger at %i ticks\n", ticks);
75
76 if( cpu5wdt_device.running )
77 ticks--;
78
79 /* keep watchdog alive */
80 outb(1, port + CPU5WDT_TRIGGER_REG);
81
82 /* requeue?? */
83 if (cpu5wdt_device.queue && ticks)
84 mod_timer(&cpu5wdt_device.timer, jiffies + CPU5WDT_INTERVAL);
85 else {
86 /* ticks doesn't matter anyway */
87 complete(&cpu5wdt_device.stop);
88 }
89
90}
91
92static void cpu5wdt_reset(void)
93{
94 ticks = cpu5wdt_device.default_ticks;
95
96 if ( verbose )
97 printk(KERN_DEBUG PFX "reset (%i ticks)\n", (int) ticks);
98
99}
100
101static void cpu5wdt_start(void)
102{
103 if ( !cpu5wdt_device.queue ) {
104 cpu5wdt_device.queue = 1;
105 outb(0, port + CPU5WDT_TIME_A_REG);
106 outb(0, port + CPU5WDT_TIME_B_REG);
107 outb(1, port + CPU5WDT_MODE_REG);
108 outb(0, port + CPU5WDT_RESET_REG);
109 outb(0, port + CPU5WDT_ENABLE_REG);
110 mod_timer(&cpu5wdt_device.timer, jiffies + CPU5WDT_INTERVAL);
111 }
112 /* if process dies, counter is not decremented */
113 cpu5wdt_device.running++;
114}
115
116static int cpu5wdt_stop(void)
117{
118 if ( cpu5wdt_device.running )
119 cpu5wdt_device.running = 0;
120
121 ticks = cpu5wdt_device.default_ticks;
122
123 if ( verbose )
124 printk(KERN_CRIT PFX "stop not possible\n");
125
126 return -EIO;
127}
128
129/* filesystem operations */
130
131static int cpu5wdt_open(struct inode *inode, struct file *file)
132{
133 if ( test_and_set_bit(0, &cpu5wdt_device.inuse) )
134 return -EBUSY;
135
136 return nonseekable_open(inode, file);
137}
138
139static int cpu5wdt_release(struct inode *inode, struct file *file)
140{
141 clear_bit(0, &cpu5wdt_device.inuse);
142 return 0;
143}
144
145static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
146{
147 void __user *argp = (void __user *)arg;
148 unsigned int value;
149 static struct watchdog_info ident =
150 {
151 .options = WDIOF_CARDRESET,
152 .identity = "CPU5 WDT",
153 };
154
155 switch(cmd) {
156 case WDIOC_KEEPALIVE:
157 cpu5wdt_reset();
158 break;
159 case WDIOC_GETSTATUS:
160 value = inb(port + CPU5WDT_STATUS_REG);
161 value = (value >> 2) & 1;
162 if ( copy_to_user(argp, &value, sizeof(int)) )
163 return -EFAULT;
164 break;
165 case WDIOC_GETBOOTSTATUS:
166 if ( copy_to_user(argp, &value, sizeof(int)) )
167 return -EFAULT;
168 break;
169 case WDIOC_GETSUPPORT:
170 if ( copy_to_user(argp, &ident, sizeof(ident)) )
171 return -EFAULT;
172 break;
173 case WDIOC_SETOPTIONS:
174 if ( copy_from_user(&value, argp, sizeof(int)) )
175 return -EFAULT;
176 switch(value) {
177 case WDIOS_ENABLECARD:
178 cpu5wdt_start();
179 break;
180 case WDIOS_DISABLECARD:
181 return cpu5wdt_stop();
182 default:
183 return -EINVAL;
184 }
185 break;
186 default:
187 return -ENOTTY;
188 }
189 return 0;
190}
191
192static ssize_t cpu5wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
193{
194 if ( !count )
195 return -EIO;
196
197 cpu5wdt_reset();
198
199 return count;
200}
201
202static const struct file_operations cpu5wdt_fops = {
203 .owner = THIS_MODULE,
204 .llseek = no_llseek,
205 .ioctl = cpu5wdt_ioctl,
206 .open = cpu5wdt_open,
207 .write = cpu5wdt_write,
208 .release = cpu5wdt_release,
209};
210
211static struct miscdevice cpu5wdt_misc = {
212 .minor = WATCHDOG_MINOR,
213 .name = "watchdog",
214 .fops = &cpu5wdt_fops,
215};
216
217/* init/exit function */
218
219static int __devinit cpu5wdt_init(void)
220{
221 unsigned int val;
222 int err;
223
224 if ( verbose )
225 printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose);
226
227 if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) {
228 printk(KERN_ERR PFX "request_region failed\n");
229 err = -EBUSY;
230 goto no_port;
231 }
232
233 if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
234 printk(KERN_ERR PFX "misc_register failed\n");
235 goto no_misc;
236 }
237
238 /* watchdog reboot? */
239 val = inb(port + CPU5WDT_STATUS_REG);
240 val = (val >> 2) & 1;
241 if ( !val )
242 printk(KERN_INFO PFX "sorry, was my fault\n");
243
244 init_completion(&cpu5wdt_device.stop);
245 cpu5wdt_device.queue = 0;
246
247 clear_bit(0, &cpu5wdt_device.inuse);
248
249 setup_timer(&cpu5wdt_device.timer, cpu5wdt_trigger, 0);
250
251 cpu5wdt_device.default_ticks = ticks;
252
253 printk(KERN_INFO PFX "init success\n");
254
255 return 0;
256
257no_misc:
258 release_region(port, CPU5WDT_EXTENT);
259no_port:
260 return err;
261}
262
263static int __devinit cpu5wdt_init_module(void)
264{
265 return cpu5wdt_init();
266}
267
268static void __devexit cpu5wdt_exit(void)
269{
270 if ( cpu5wdt_device.queue ) {
271 cpu5wdt_device.queue = 0;
272 wait_for_completion(&cpu5wdt_device.stop);
273 }
274
275 misc_deregister(&cpu5wdt_misc);
276
277 release_region(port, CPU5WDT_EXTENT);
278
279}
280
281static void __devexit cpu5wdt_exit_module(void)
282{
283 cpu5wdt_exit();
284}
285
286/* module entry points */
287
288module_init(cpu5wdt_init_module);
289module_exit(cpu5wdt_exit_module);
290
291MODULE_AUTHOR("Heiko Ronsdorf <hero@ihg.uni-duisburg.de>");
292MODULE_DESCRIPTION("sma cpu5 watchdog driver");
293MODULE_SUPPORTED_DEVICE("sma cpu5 watchdog");
294MODULE_LICENSE("GPL");
295MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
296
297module_param(port, int, 0);
298MODULE_PARM_DESC(port, "base address of watchdog card, default is 0x91");
299
300module_param(verbose, int, 0);
301MODULE_PARM_DESC(verbose, "be verbose, default is 0 (no)");
302
303module_param(ticks, int, 0);
304MODULE_PARM_DESC(ticks, "count down ticks, default is 10000");
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
new file mode 100644
index 000000000000..19db5302ba6e
--- /dev/null
+++ b/drivers/watchdog/davinci_wdt.c
@@ -0,0 +1,281 @@
1/*
2 * drivers/char/watchdog/davinci_wdt.c
3 *
4 * Watchdog driver for DaVinci DM644x/DM646x processors
5 *
6 * Copyright (C) 2006 Texas Instruments.
7 *
8 * 2007 (c) MontaVista Software, Inc. This file is licensed under
9 * the terms of the GNU General Public License version 2. This program
10 * is licensed "as is" without any warranty of any kind, whether express
11 * or implied.
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/fs.h>
19#include <linux/miscdevice.h>
20#include <linux/watchdog.h>
21#include <linux/init.h>
22#include <linux/bitops.h>
23#include <linux/platform_device.h>
24#include <linux/spinlock.h>
25
26#include <asm/hardware.h>
27#include <asm/uaccess.h>
28#include <asm/io.h>
29
30#define MODULE_NAME "DAVINCI-WDT: "
31
32#define DEFAULT_HEARTBEAT 60
33#define MAX_HEARTBEAT 600 /* really the max margin is 264/27MHz*/
34
35/* Timer register set definition */
36#define PID12 (0x0)
37#define EMUMGT (0x4)
38#define TIM12 (0x10)
39#define TIM34 (0x14)
40#define PRD12 (0x18)
41#define PRD34 (0x1C)
42#define TCR (0x20)
43#define TGCR (0x24)
44#define WDTCR (0x28)
45
46/* TCR bit definitions */
47#define ENAMODE12_DISABLED (0 << 6)
48#define ENAMODE12_ONESHOT (1 << 6)
49#define ENAMODE12_PERIODIC (2 << 6)
50
51/* TGCR bit definitions */
52#define TIM12RS_UNRESET (1 << 0)
53#define TIM34RS_UNRESET (1 << 1)
54#define TIMMODE_64BIT_WDOG (2 << 2)
55
56/* WDTCR bit definitions */
57#define WDEN (1 << 14)
58#define WDFLAG (1 << 15)
59#define WDKEY_SEQ0 (0xa5c6 << 16)
60#define WDKEY_SEQ1 (0xda7e << 16)
61
62static int heartbeat = DEFAULT_HEARTBEAT;
63
64static spinlock_t io_lock;
65static unsigned long wdt_status;
66#define WDT_IN_USE 0
67#define WDT_OK_TO_CLOSE 1
68#define WDT_REGION_INITED 2
69#define WDT_DEVICE_INITED 3
70
71static struct resource *wdt_mem;
72static void __iomem *wdt_base;
73
74static void wdt_service(void)
75{
76 spin_lock(&io_lock);
77
78 /* put watchdog in service state */
79 davinci_writel(WDKEY_SEQ0, wdt_base + WDTCR);
80 /* put watchdog in active state */
81 davinci_writel(WDKEY_SEQ1, wdt_base + WDTCR);
82
83 spin_unlock(&io_lock);
84}
85
86static void wdt_enable(void)
87{
88 u32 tgcr;
89 u32 timer_margin;
90
91 spin_lock(&io_lock);
92
93 /* disable, internal clock source */
94 davinci_writel(0, wdt_base + TCR);
95 /* reset timer, set mode to 64-bit watchdog, and unreset */
96 davinci_writel(0, wdt_base + TGCR);
97 tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
98 davinci_writel(tgcr, wdt_base + TGCR);
99 /* clear counter regs */
100 davinci_writel(0, wdt_base + TIM12);
101 davinci_writel(0, wdt_base + TIM34);
102 /* set timeout period */
103 timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) & 0xffffffff);
104 davinci_writel(timer_margin, wdt_base + PRD12);
105 timer_margin = (((u64)heartbeat * CLOCK_TICK_RATE) >> 32);
106 davinci_writel(timer_margin, wdt_base + PRD34);
107 /* enable run continuously */
108 davinci_writel(ENAMODE12_PERIODIC, wdt_base + TCR);
109 /* Once the WDT is in pre-active state write to
110 * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
111 * write protected (except for the WDKEY field)
112 */
113 /* put watchdog in pre-active state */
114 davinci_writel(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR);
115 /* put watchdog in active state */
116 davinci_writel(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR);
117
118 spin_unlock(&io_lock);
119}
120
121static int davinci_wdt_open(struct inode *inode, struct file *file)
122{
123 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
124 return -EBUSY;
125
126 wdt_enable();
127
128 return nonseekable_open(inode, file);
129}
130
131static ssize_t
132davinci_wdt_write(struct file *file, const char *data, size_t len,
133 loff_t *ppos)
134{
135 if (len)
136 wdt_service();
137
138 return len;
139}
140
141static struct watchdog_info ident = {
142 .options = WDIOF_KEEPALIVEPING,
143 .identity = "DaVinci Watchdog",
144};
145
146static int
147davinci_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
148 unsigned long arg)
149{
150 int ret = -ENOTTY;
151
152 switch (cmd) {
153 case WDIOC_GETSUPPORT:
154 ret = copy_to_user((struct watchdog_info *)arg, &ident,
155 sizeof(ident)) ? -EFAULT : 0;
156 break;
157
158 case WDIOC_GETSTATUS:
159 case WDIOC_GETBOOTSTATUS:
160 ret = put_user(0, (int *)arg);
161 break;
162
163 case WDIOC_GETTIMEOUT:
164 ret = put_user(heartbeat, (int *)arg);
165 break;
166
167 case WDIOC_KEEPALIVE:
168 wdt_service();
169 ret = 0;
170 break;
171 }
172 return ret;
173}
174
175static int davinci_wdt_release(struct inode *inode, struct file *file)
176{
177 wdt_service();
178 clear_bit(WDT_IN_USE, &wdt_status);
179
180 return 0;
181}
182
183static const struct file_operations davinci_wdt_fops = {
184 .owner = THIS_MODULE,
185 .llseek = no_llseek,
186 .write = davinci_wdt_write,
187 .ioctl = davinci_wdt_ioctl,
188 .open = davinci_wdt_open,
189 .release = davinci_wdt_release,
190};
191
192static struct miscdevice davinci_wdt_miscdev = {
193 .minor = WATCHDOG_MINOR,
194 .name = "watchdog",
195 .fops = &davinci_wdt_fops,
196};
197
198static int davinci_wdt_probe(struct platform_device *pdev)
199{
200 int ret = 0, size;
201 struct resource *res;
202
203 spin_lock_init(&io_lock);
204
205 if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
206 heartbeat = DEFAULT_HEARTBEAT;
207
208 printk(KERN_INFO MODULE_NAME
209 "DaVinci Watchdog Timer: heartbeat %d sec\n", heartbeat);
210
211 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
212 if (res == NULL) {
213 printk(KERN_INFO MODULE_NAME
214 "failed to get memory region resource\n");
215 return -ENOENT;
216 }
217
218 size = res->end - res->start + 1;
219 wdt_mem = request_mem_region(res->start, size, pdev->name);
220
221 if (wdt_mem == NULL) {
222 printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
223 return -ENOENT;
224 }
225 wdt_base = (void __iomem *)(res->start);
226
227 ret = misc_register(&davinci_wdt_miscdev);
228 if (ret < 0) {
229 printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
230 release_resource(wdt_mem);
231 kfree(wdt_mem);
232 } else {
233 set_bit(WDT_DEVICE_INITED, &wdt_status);
234 }
235
236 return ret;
237}
238
239static int davinci_wdt_remove(struct platform_device *pdev)
240{
241 misc_deregister(&davinci_wdt_miscdev);
242 if (wdt_mem) {
243 release_resource(wdt_mem);
244 kfree(wdt_mem);
245 wdt_mem = NULL;
246 }
247 return 0;
248}
249
250static struct platform_driver platform_wdt_driver = {
251 .driver = {
252 .name = "watchdog",
253 },
254 .probe = davinci_wdt_probe,
255 .remove = davinci_wdt_remove,
256};
257
258static int __init davinci_wdt_init(void)
259{
260 return platform_driver_register(&platform_wdt_driver);
261}
262
263static void __exit davinci_wdt_exit(void)
264{
265 return platform_driver_unregister(&platform_wdt_driver);
266}
267
268module_init(davinci_wdt_init);
269module_exit(davinci_wdt_exit);
270
271MODULE_AUTHOR("Texas Instruments");
272MODULE_DESCRIPTION("DaVinci Watchdog Driver");
273
274module_param(heartbeat, int, 0);
275MODULE_PARM_DESC(heartbeat,
276 "Watchdog heartbeat period in seconds from 1 to "
277 __MODULE_STRING(MAX_HEARTBEAT) ", default "
278 __MODULE_STRING(DEFAULT_HEARTBEAT));
279
280MODULE_LICENSE("GPL");
281MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c
new file mode 100644
index 000000000000..0e4787a0bb87
--- /dev/null
+++ b/drivers/watchdog/ep93xx_wdt.c
@@ -0,0 +1,253 @@
1/*
2 * Watchdog driver for Cirrus Logic EP93xx family of devices.
3 *
4 * Copyright (c) 2004 Ray Lehtiniemi
5 * Copyright (c) 2006 Tower Technologies
6 * Based on ep93xx driver, bits from alim7101_wdt.c
7 *
8 * Authors: Ray Lehtiniemi <rayl@mail.com>,
9 * Alessandro Zummo <a.zummo@towertech.it>
10 *
11 * This file is licensed under the terms of the GNU General Public
12 * License version 2. This program is licensed "as is" without any
13 * warranty of any kind, whether express or implied.
14 *
15 * This watchdog fires after 250msec, which is a too short interval
16 * for us to rely on the user space daemon alone. So we ping the
17 * wdt each ~200msec and eventually stop doing it if the user space
18 * daemon dies.
19 *
20 * TODO:
21 *
22 * - Test last reset from watchdog status
23 * - Add a few missing ioctls
24 */
25
26#include <linux/module.h>
27#include <linux/fs.h>
28#include <linux/miscdevice.h>
29#include <linux/watchdog.h>
30#include <linux/timer.h>
31
32#include <asm/hardware.h>
33#include <asm/uaccess.h>
34
35#define WDT_VERSION "0.3"
36#define PFX "ep93xx_wdt: "
37
38/* default timeout (secs) */
39#define WDT_TIMEOUT 30
40
41static int nowayout = WATCHDOG_NOWAYOUT;
42static int timeout = WDT_TIMEOUT;
43
44static struct timer_list timer;
45static unsigned long next_heartbeat;
46static unsigned long wdt_status;
47static unsigned long boot_status;
48
49#define WDT_IN_USE 0
50#define WDT_OK_TO_CLOSE 1
51
52#define EP93XX_WDT_REG(x) (EP93XX_WATCHDOG_BASE + (x))
53#define EP93XX_WDT_WATCHDOG EP93XX_WDT_REG(0x00)
54#define EP93XX_WDT_WDSTATUS EP93XX_WDT_REG(0x04)
55
56/* reset the wdt every ~200ms */
57#define WDT_INTERVAL (HZ/5)
58
59static void wdt_enable(void)
60{
61 __raw_writew(0xaaaa, EP93XX_WDT_WATCHDOG);
62}
63
64static void wdt_disable(void)
65{
66 __raw_writew(0xaa55, EP93XX_WDT_WATCHDOG);
67}
68
69static inline void wdt_ping(void)
70{
71 __raw_writew(0x5555, EP93XX_WDT_WATCHDOG);
72}
73
74static void wdt_startup(void)
75{
76 next_heartbeat = jiffies + (timeout * HZ);
77
78 wdt_enable();
79 mod_timer(&timer, jiffies + WDT_INTERVAL);
80}
81
82static void wdt_shutdown(void)
83{
84 del_timer_sync(&timer);
85 wdt_disable();
86}
87
88static void wdt_keepalive(void)
89{
90 /* user land ping */
91 next_heartbeat = jiffies + (timeout * HZ);
92}
93
94static int ep93xx_wdt_open(struct inode *inode, struct file *file)
95{
96 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
97 return -EBUSY;
98
99 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
100
101 wdt_startup();
102
103 return nonseekable_open(inode, file);
104}
105
106static ssize_t
107ep93xx_wdt_write(struct file *file, const char __user *data, size_t len,
108 loff_t *ppos)
109{
110 if (len) {
111 if (!nowayout) {
112 size_t i;
113
114 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
115
116 for (i = 0; i != len; i++) {
117 char c;
118
119 if (get_user(c, data + i))
120 return -EFAULT;
121
122 if (c == 'V')
123 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
124 else
125 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
126 }
127 }
128 wdt_keepalive();
129 }
130
131 return len;
132}
133
134static struct watchdog_info ident = {
135 .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE,
136 .identity = "EP93xx Watchdog",
137};
138
139static int
140ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
141 unsigned long arg)
142{
143 int ret = -ENOTTY;
144
145 switch (cmd) {
146 case WDIOC_GETSUPPORT:
147 ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
148 sizeof(ident)) ? -EFAULT : 0;
149 break;
150
151 case WDIOC_GETSTATUS:
152 ret = put_user(0, (int __user *)arg);
153 break;
154
155 case WDIOC_GETBOOTSTATUS:
156 ret = put_user(boot_status, (int __user *)arg);
157 break;
158
159 case WDIOC_GETTIMEOUT:
160 /* actually, it is 0.250 seconds.... */
161 ret = put_user(1, (int __user *)arg);
162 break;
163
164 case WDIOC_KEEPALIVE:
165 wdt_keepalive();
166 ret = 0;
167 break;
168 }
169 return ret;
170}
171
172static int ep93xx_wdt_release(struct inode *inode, struct file *file)
173{
174 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
175 wdt_shutdown();
176 else
177 printk(KERN_CRIT PFX "Device closed unexpectedly - "
178 "timer will not stop\n");
179
180 clear_bit(WDT_IN_USE, &wdt_status);
181 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
182
183 return 0;
184}
185
186static const struct file_operations ep93xx_wdt_fops = {
187 .owner = THIS_MODULE,
188 .write = ep93xx_wdt_write,
189 .ioctl = ep93xx_wdt_ioctl,
190 .open = ep93xx_wdt_open,
191 .release = ep93xx_wdt_release,
192};
193
194static struct miscdevice ep93xx_wdt_miscdev = {
195 .minor = WATCHDOG_MINOR,
196 .name = "watchdog",
197 .fops = &ep93xx_wdt_fops,
198};
199
200static void ep93xx_timer_ping(unsigned long data)
201{
202 if (time_before(jiffies, next_heartbeat))
203 wdt_ping();
204
205 /* Re-set the timer interval */
206 mod_timer(&timer, jiffies + WDT_INTERVAL);
207}
208
209static int __init ep93xx_wdt_init(void)
210{
211 int err;
212
213 err = misc_register(&ep93xx_wdt_miscdev);
214
215 boot_status = __raw_readl(EP93XX_WDT_WATCHDOG) & 0x01 ? 1 : 0;
216
217 printk(KERN_INFO PFX "EP93XX watchdog, driver version "
218 WDT_VERSION "%s\n",
219 (__raw_readl(EP93XX_WDT_WATCHDOG) & 0x08)
220 ? " (nCS1 disable detected)" : "");
221
222 if (timeout < 1 || timeout > 3600) {
223 timeout = WDT_TIMEOUT;
224 printk(KERN_INFO PFX
225 "timeout value must be 1<=x<=3600, using %d\n",
226 timeout);
227 }
228
229 setup_timer(&timer, ep93xx_timer_ping, 1);
230 return err;
231}
232
233static void __exit ep93xx_wdt_exit(void)
234{
235 wdt_shutdown();
236 misc_deregister(&ep93xx_wdt_miscdev);
237}
238
239module_init(ep93xx_wdt_init);
240module_exit(ep93xx_wdt_exit);
241
242module_param(nowayout, int, 0);
243MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
244
245module_param(timeout, int, 0);
246MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
247
248MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>,"
249 "Alessandro Zummo <a.zummo@towertech.it>");
250MODULE_DESCRIPTION("EP93xx Watchdog");
251MODULE_LICENSE("GPL");
252MODULE_VERSION(WDT_VERSION);
253MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c
new file mode 100644
index 000000000000..b14e9d1f164d
--- /dev/null
+++ b/drivers/watchdog/eurotechwdt.c
@@ -0,0 +1,473 @@
1/*
2 * Eurotech CPU-1220/1410/1420 on board WDT driver
3 *
4 * (c) Copyright 2001 Ascensit <support@ascensit.com>
5 * (c) Copyright 2001 Rodolfo Giometti <giometti@ascensit.com>
6 * (c) Copyright 2002 Rob Radez <rob@osinvestor.com>
7 *
8 * Based on wdt.c.
9 * Original copyright messages:
10 *
11 * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
12 * http://www.redhat.com
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version
17 * 2 of the License, or (at your option) any later version.
18 *
19 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
20 * warranty for any of this software. This material is provided
21 * "AS-IS" and at no charge.
22 *
23 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>*
24 */
25
26/* Changelog:
27 *
28 * 2001 - Rodolfo Giometti
29 * Initial release
30 *
31 * 2002/04/25 - Rob Radez
32 * clean up #includes
33 * clean up locking
34 * make __setup param unique
35 * proper options in watchdog_info
36 * add WDIOC_GETSTATUS and WDIOC_SETOPTIONS ioctls
37 * add expect_close support
38 *
39 * 2002.05.30 - Joel Becker <joel.becker@oracle.com>
40 * Added Matt Domsch's nowayout module option.
41 */
42
43/*
44 * The eurotech CPU-1220/1410/1420's watchdog is a part
45 * of the on-board SUPER I/O device SMSC FDC 37B782.
46 */
47
48#include <linux/interrupt.h>
49#include <linux/module.h>
50#include <linux/moduleparam.h>
51#include <linux/types.h>
52#include <linux/miscdevice.h>
53#include <linux/watchdog.h>
54#include <linux/fs.h>
55#include <linux/ioport.h>
56#include <linux/notifier.h>
57#include <linux/reboot.h>
58#include <linux/init.h>
59
60#include <asm/io.h>
61#include <asm/uaccess.h>
62#include <asm/system.h>
63
64static unsigned long eurwdt_is_open;
65static int eurwdt_timeout;
66static char eur_expect_close;
67
68/*
69 * You must set these - there is no sane way to probe for this board.
70 * You can use eurwdt=x,y to set these now.
71 */
72
73static int io = 0x3f0;
74static int irq = 10;
75static char *ev = "int";
76
77#define WDT_TIMEOUT 60 /* 1 minute */
78
79static int nowayout = WATCHDOG_NOWAYOUT;
80module_param(nowayout, int, 0);
81MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
82
83/*
84 * Some symbolic names
85 */
86
87#define WDT_CTRL_REG 0x30
88#define WDT_OUTPIN_CFG 0xe2
89#define WDT_EVENT_INT 0x00
90#define WDT_EVENT_REBOOT 0x08
91#define WDT_UNIT_SEL 0xf1
92#define WDT_UNIT_SECS 0x80
93#define WDT_TIMEOUT_VAL 0xf2
94#define WDT_TIMER_CFG 0xf3
95
96
97module_param(io, int, 0);
98MODULE_PARM_DESC(io, "Eurotech WDT io port (default=0x3f0)");
99module_param(irq, int, 0);
100MODULE_PARM_DESC(irq, "Eurotech WDT irq (default=10)");
101module_param(ev, charp, 0);
102MODULE_PARM_DESC(ev, "Eurotech WDT event type (default is `int')");
103
104
105/*
106 * Programming support
107 */
108
109static inline void eurwdt_write_reg(u8 index, u8 data)
110{
111 outb(index, io);
112 outb(data, io+1);
113}
114
115static inline void eurwdt_lock_chip(void)
116{
117 outb(0xaa, io);
118}
119
120static inline void eurwdt_unlock_chip(void)
121{
122 outb(0x55, io);
123 eurwdt_write_reg(0x07, 0x08); /* set the logical device */
124}
125
126static inline void eurwdt_set_timeout(int timeout)
127{
128 eurwdt_write_reg(WDT_TIMEOUT_VAL, (u8) timeout);
129}
130
131static inline void eurwdt_disable_timer(void)
132{
133 eurwdt_set_timeout(0);
134}
135
136static void eurwdt_activate_timer(void)
137{
138 eurwdt_disable_timer();
139 eurwdt_write_reg(WDT_CTRL_REG, 0x01); /* activate the WDT */
140 eurwdt_write_reg(WDT_OUTPIN_CFG, !strcmp("int", ev) ? WDT_EVENT_INT : WDT_EVENT_REBOOT);
141
142 /* Setting interrupt line */
143 if (irq == 2 || irq > 15 || irq < 0) {
144 printk(KERN_ERR ": invalid irq number\n");
145 irq = 0; /* if invalid we disable interrupt */
146 }
147 if (irq == 0)
148 printk(KERN_INFO ": interrupt disabled\n");
149
150 eurwdt_write_reg(WDT_TIMER_CFG, irq<<4);
151
152 eurwdt_write_reg(WDT_UNIT_SEL, WDT_UNIT_SECS); /* we use seconds */
153 eurwdt_set_timeout(0); /* the default timeout */
154}
155
156
157/*
158 * Kernel methods.
159 */
160
161static irqreturn_t eurwdt_interrupt(int irq, void *dev_id)
162{
163 printk(KERN_CRIT "timeout WDT timeout\n");
164
165#ifdef ONLY_TESTING
166 printk(KERN_CRIT "Would Reboot.\n");
167#else
168 printk(KERN_CRIT "Initiating system reboot.\n");
169 emergency_restart();
170#endif
171 return IRQ_HANDLED;
172}
173
174
175/**
176 * eurwdt_ping:
177 *
178 * Reload counter one with the watchdog timeout.
179 */
180
181static void eurwdt_ping(void)
182{
183 /* Write the watchdog default value */
184 eurwdt_set_timeout(eurwdt_timeout);
185}
186
187/**
188 * eurwdt_write:
189 * @file: file handle to the watchdog
190 * @buf: buffer to write (unused as data does not matter here
191 * @count: count of bytes
192 * @ppos: pointer to the position to write. No seeks allowed
193 *
194 * A write to a watchdog device is defined as a keepalive signal. Any
195 * write of data will do, as we we don't define content meaning.
196 */
197
198static ssize_t eurwdt_write(struct file *file, const char __user *buf,
199size_t count, loff_t *ppos)
200{
201 if (count) {
202 if (!nowayout) {
203 size_t i;
204
205 eur_expect_close = 0;
206
207 for (i = 0; i != count; i++) {
208 char c;
209 if(get_user(c, buf+i))
210 return -EFAULT;
211 if (c == 'V')
212 eur_expect_close = 42;
213 }
214 }
215 eurwdt_ping(); /* the default timeout */
216 }
217
218 return count;
219}
220
221/**
222 * eurwdt_ioctl:
223 * @inode: inode of the device
224 * @file: file handle to the device
225 * @cmd: watchdog command
226 * @arg: argument pointer
227 *
228 * The watchdog API defines a common set of functions for all watchdogs
229 * according to their available features.
230 */
231
232static int eurwdt_ioctl(struct inode *inode, struct file *file,
233 unsigned int cmd, unsigned long arg)
234{
235 void __user *argp = (void __user *)arg;
236 int __user *p = argp;
237 static struct watchdog_info ident = {
238 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
239 .firmware_version = 1,
240 .identity = "WDT Eurotech CPU-1220/1410",
241 };
242
243 int time;
244 int options, retval = -EINVAL;
245
246 switch(cmd) {
247 default:
248 return -ENOTTY;
249
250 case WDIOC_GETSUPPORT:
251 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
252
253 case WDIOC_GETSTATUS:
254 case WDIOC_GETBOOTSTATUS:
255 return put_user(0, p);
256
257 case WDIOC_KEEPALIVE:
258 eurwdt_ping();
259 return 0;
260
261 case WDIOC_SETTIMEOUT:
262 if (copy_from_user(&time, p, sizeof(int)))
263 return -EFAULT;
264
265 /* Sanity check */
266 if (time < 0 || time > 255)
267 return -EINVAL;
268
269 eurwdt_timeout = time;
270 eurwdt_set_timeout(time);
271 /* Fall */
272
273 case WDIOC_GETTIMEOUT:
274 return put_user(eurwdt_timeout, p);
275
276 case WDIOC_SETOPTIONS:
277 if (get_user(options, p))
278 return -EFAULT;
279 if (options & WDIOS_DISABLECARD) {
280 eurwdt_disable_timer();
281 retval = 0;
282 }
283 if (options & WDIOS_ENABLECARD) {
284 eurwdt_activate_timer();
285 eurwdt_ping();
286 retval = 0;
287 }
288 return retval;
289 }
290}
291
292/**
293 * eurwdt_open:
294 * @inode: inode of device
295 * @file: file handle to device
296 *
297 * The misc device has been opened. The watchdog device is single
298 * open and on opening we load the counter.
299 */
300
301static int eurwdt_open(struct inode *inode, struct file *file)
302{
303 if (test_and_set_bit(0, &eurwdt_is_open))
304 return -EBUSY;
305 eurwdt_timeout = WDT_TIMEOUT; /* initial timeout */
306 /* Activate the WDT */
307 eurwdt_activate_timer();
308 return nonseekable_open(inode, file);
309}
310
311/**
312 * eurwdt_release:
313 * @inode: inode to board
314 * @file: file handle to board
315 *
316 * The watchdog has a configurable API. There is a religious dispute
317 * between people who want their watchdog to be able to shut down and
318 * those who want to be sure if the watchdog manager dies the machine
319 * reboots. In the former case we disable the counters, in the latter
320 * case you have to open it again very soon.
321 */
322
323static int eurwdt_release(struct inode *inode, struct file *file)
324{
325 if (eur_expect_close == 42) {
326 eurwdt_disable_timer();
327 } else {
328 printk(KERN_CRIT "eurwdt: Unexpected close, not stopping watchdog!\n");
329 eurwdt_ping();
330 }
331 clear_bit(0, &eurwdt_is_open);
332 eur_expect_close = 0;
333 return 0;
334}
335
336/**
337 * eurwdt_notify_sys:
338 * @this: our notifier block
339 * @code: the event being reported
340 * @unused: unused
341 *
342 * Our notifier is called on system shutdowns. We want to turn the card
343 * off at reboot otherwise the machine will reboot again during memory
344 * test or worse yet during the following fsck. This would suck, in fact
345 * trust me - if it happens it does suck.
346 */
347
348static int eurwdt_notify_sys(struct notifier_block *this, unsigned long code,
349 void *unused)
350{
351 if (code == SYS_DOWN || code == SYS_HALT) {
352 /* Turn the card off */
353 eurwdt_disable_timer();
354 }
355
356 return NOTIFY_DONE;
357}
358
359/*
360 * Kernel Interfaces
361 */
362
363
364static const struct file_operations eurwdt_fops = {
365 .owner = THIS_MODULE,
366 .llseek = no_llseek,
367 .write = eurwdt_write,
368 .ioctl = eurwdt_ioctl,
369 .open = eurwdt_open,
370 .release = eurwdt_release,
371};
372
373static struct miscdevice eurwdt_miscdev = {
374 .minor = WATCHDOG_MINOR,
375 .name = "watchdog",
376 .fops = &eurwdt_fops,
377};
378
379/*
380 * The WDT card needs to learn about soft shutdowns in order to
381 * turn the timebomb registers off.
382 */
383
384static struct notifier_block eurwdt_notifier = {
385 .notifier_call = eurwdt_notify_sys,
386};
387
388/**
389 * cleanup_module:
390 *
391 * Unload the watchdog. You cannot do this with any file handles open.
392 * If your watchdog is set to continue ticking on close and you unload
393 * it, well it keeps ticking. We won't get the interrupt but the board
394 * will not touch PC memory so all is fine. You just have to load a new
395 * module in 60 seconds or reboot.
396 */
397
398static void __exit eurwdt_exit(void)
399{
400 eurwdt_lock_chip();
401
402 misc_deregister(&eurwdt_miscdev);
403
404 unregister_reboot_notifier(&eurwdt_notifier);
405 release_region(io, 2);
406 free_irq(irq, NULL);
407}
408
409/**
410 * eurwdt_init:
411 *
412 * Set up the WDT watchdog board. After grabbing the resources
413 * we require we need also to unlock the device.
414 * The open() function will actually kick the board off.
415 */
416
417static int __init eurwdt_init(void)
418{
419 int ret;
420
421 ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL);
422 if(ret) {
423 printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
424 goto out;
425 }
426
427 if (!request_region(io, 2, "eurwdt")) {
428 printk(KERN_ERR "eurwdt: IO %X is not free.\n", io);
429 ret = -EBUSY;
430 goto outirq;
431 }
432
433 ret = register_reboot_notifier(&eurwdt_notifier);
434 if (ret) {
435 printk(KERN_ERR "eurwdt: can't register reboot notifier (err=%d)\n", ret);
436 goto outreg;
437 }
438
439 ret = misc_register(&eurwdt_miscdev);
440 if (ret) {
441 printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
442 WATCHDOG_MINOR);
443 goto outreboot;
444 }
445
446 eurwdt_unlock_chip();
447
448 ret = 0;
449 printk(KERN_INFO "Eurotech WDT driver 0.01 at %X (Interrupt %d)"
450 " - timeout event: %s\n",
451 io, irq, (!strcmp("int", ev) ? "int" : "reboot"));
452
453out:
454 return ret;
455
456outreboot:
457 unregister_reboot_notifier(&eurwdt_notifier);
458
459outreg:
460 release_region(io, 2);
461
462outirq:
463 free_irq(irq, NULL);
464 goto out;
465}
466
467module_init(eurwdt_init);
468module_exit(eurwdt_exit);
469
470MODULE_AUTHOR("Rodolfo Giometti");
471MODULE_DESCRIPTION("Driver for Eurotech CPU-1220/1410 on board watchdog");
472MODULE_LICENSE("GPL");
473MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/i6300esb.c b/drivers/watchdog/i6300esb.c
new file mode 100644
index 000000000000..c5982502c03d
--- /dev/null
+++ b/drivers/watchdog/i6300esb.c
@@ -0,0 +1,527 @@
1/*
2 * i6300esb: Watchdog timer driver for Intel 6300ESB chipset
3 *
4 * (c) Copyright 2004 Google Inc.
5 * (c) Copyright 2005 David Härdeman <david@2gen.com>
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 * based on i810-tco.c which is in turn based on softdog.c
13 *
14 * The timer is implemented in the following I/O controller hubs:
15 * (See the intel documentation on http://developer.intel.com.)
16 * 6300ESB chip : document number 300641-003
17 *
18 * 2004YYZZ Ross Biro
19 * Initial version 0.01
20 * 2004YYZZ Ross Biro
21 * Version 0.02
22 * 20050210 David Härdeman <david@2gen.com>
23 * Ported driver to kernel 2.6
24 */
25
26/*
27 * Includes, defines, variables, module parameters, ...
28 */
29
30#include <linux/module.h>
31#include <linux/types.h>
32#include <linux/kernel.h>
33#include <linux/fs.h>
34#include <linux/mm.h>
35#include <linux/miscdevice.h>
36#include <linux/watchdog.h>
37#include <linux/reboot.h>
38#include <linux/init.h>
39#include <linux/pci.h>
40#include <linux/ioport.h>
41
42#include <asm/uaccess.h>
43#include <asm/io.h>
44
45/* Module and version information */
46#define ESB_VERSION "0.03"
47#define ESB_MODULE_NAME "i6300ESB timer"
48#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION
49#define PFX ESB_MODULE_NAME ": "
50
51/* PCI configuration registers */
52#define ESB_CONFIG_REG 0x60 /* Config register */
53#define ESB_LOCK_REG 0x68 /* WDT lock register */
54
55/* Memory mapped registers */
56#define ESB_TIMER1_REG BASEADDR + 0x00 /* Timer1 value after each reset */
57#define ESB_TIMER2_REG BASEADDR + 0x04 /* Timer2 value after each reset */
58#define ESB_GINTSR_REG BASEADDR + 0x08 /* General Interrupt Status Register */
59#define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */
60
61/* Lock register bits */
62#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */
63#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */
64#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */
65
66/* Config register bits */
67#define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */
68#define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */
69#define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */
70
71/* Reload register bits */
72#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */
73
74/* Magic constants */
75#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */
76#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */
77
78/* internal variables */
79static void __iomem *BASEADDR;
80static spinlock_t esb_lock; /* Guards the hardware */
81static unsigned long timer_alive;
82static struct pci_dev *esb_pci;
83static unsigned short triggered; /* The status of the watchdog upon boot */
84static char esb_expect_close;
85
86/* module parameters */
87#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (1<heartbeat<2*1023) */
88static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
89module_param(heartbeat, int, 0);
90MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
91
92static int nowayout = WATCHDOG_NOWAYOUT;
93module_param(nowayout, int, 0);
94MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
95
96/*
97 * Some i6300ESB specific functions
98 */
99
100/*
101 * Prepare for reloading the timer by unlocking the proper registers.
102 * This is performed by first writing 0x80 followed by 0x86 to the
103 * reload register. After this the appropriate registers can be written
104 * to once before they need to be unlocked again.
105 */
106static inline void esb_unlock_registers(void) {
107 writeb(ESB_UNLOCK1, ESB_RELOAD_REG);
108 writeb(ESB_UNLOCK2, ESB_RELOAD_REG);
109}
110
111static void esb_timer_start(void)
112{
113 u8 val;
114
115 /* Enable or Enable + Lock? */
116 val = 0x02 | (nowayout ? 0x01 : 0x00);
117
118 pci_write_config_byte(esb_pci, ESB_LOCK_REG, val);
119}
120
121static int esb_timer_stop(void)
122{
123 u8 val;
124
125 spin_lock(&esb_lock);
126 /* First, reset timers as suggested by the docs */
127 esb_unlock_registers();
128 writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
129 /* Then disable the WDT */
130 pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0);
131 pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val);
132 spin_unlock(&esb_lock);
133
134 /* Returns 0 if the timer was disabled, non-zero otherwise */
135 return (val & 0x01);
136}
137
138static void esb_timer_keepalive(void)
139{
140 spin_lock(&esb_lock);
141 esb_unlock_registers();
142 writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
143 /* FIXME: Do we need to flush anything here? */
144 spin_unlock(&esb_lock);
145}
146
147static int esb_timer_set_heartbeat(int time)
148{
149 u32 val;
150
151 if (time < 0x1 || time > (2 * 0x03ff))
152 return -EINVAL;
153
154 spin_lock(&esb_lock);
155
156 /* We shift by 9, so if we are passed a value of 1 sec,
157 * val will be 1 << 9 = 512, then write that to two
158 * timers => 2 * 512 = 1024 (which is decremented at 1KHz)
159 */
160 val = time << 9;
161
162 /* Write timer 1 */
163 esb_unlock_registers();
164 writel(val, ESB_TIMER1_REG);
165
166 /* Write timer 2 */
167 esb_unlock_registers();
168 writel(val, ESB_TIMER2_REG);
169
170 /* Reload */
171 esb_unlock_registers();
172 writew(ESB_WDT_RELOAD, ESB_RELOAD_REG);
173
174 /* FIXME: Do we need to flush everything out? */
175
176 /* Done */
177 heartbeat = time;
178 spin_unlock(&esb_lock);
179 return 0;
180}
181
182static int esb_timer_read (void)
183{
184 u32 count;
185
186 /* This isn't documented, and doesn't take into
187 * acount which stage is running, but it looks
188 * like a 20 bit count down, so we might as well report it.
189 */
190 pci_read_config_dword(esb_pci, 0x64, &count);
191 return (int)count;
192}
193
194/*
195 * /dev/watchdog handling
196 */
197
198static int esb_open (struct inode *inode, struct file *file)
199{
200 /* /dev/watchdog can only be opened once */
201 if (test_and_set_bit(0, &timer_alive))
202 return -EBUSY;
203
204 /* Reload and activate timer */
205 esb_timer_keepalive ();
206 esb_timer_start ();
207
208 return nonseekable_open(inode, file);
209}
210
211static int esb_release (struct inode *inode, struct file *file)
212{
213 /* Shut off the timer. */
214 if (esb_expect_close == 42) {
215 esb_timer_stop ();
216 } else {
217 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
218 esb_timer_keepalive ();
219 }
220 clear_bit(0, &timer_alive);
221 esb_expect_close = 0;
222 return 0;
223}
224
225static ssize_t esb_write (struct file *file, const char __user *data,
226 size_t len, loff_t * ppos)
227{
228 /* See if we got the magic character 'V' and reload the timer */
229 if (len) {
230 if (!nowayout) {
231 size_t i;
232
233 /* note: just in case someone wrote the magic character
234 * five months ago... */
235 esb_expect_close = 0;
236
237 /* scan to see whether or not we got the magic character */
238 for (i = 0; i != len; i++) {
239 char c;
240 if(get_user(c, data+i))
241 return -EFAULT;
242 if (c == 'V')
243 esb_expect_close = 42;
244 }
245 }
246
247 /* someone wrote to us, we should reload the timer */
248 esb_timer_keepalive ();
249 }
250 return len;
251}
252
253static int esb_ioctl (struct inode *inode, struct file *file,
254 unsigned int cmd, unsigned long arg)
255{
256 int new_options, retval = -EINVAL;
257 int new_heartbeat;
258 void __user *argp = (void __user *)arg;
259 int __user *p = argp;
260 static struct watchdog_info ident = {
261 .options = WDIOF_SETTIMEOUT |
262 WDIOF_KEEPALIVEPING |
263 WDIOF_MAGICCLOSE,
264 .firmware_version = 0,
265 .identity = ESB_MODULE_NAME,
266 };
267
268 switch (cmd) {
269 case WDIOC_GETSUPPORT:
270 return copy_to_user(argp, &ident,
271 sizeof (ident)) ? -EFAULT : 0;
272
273 case WDIOC_GETSTATUS:
274 return put_user (esb_timer_read(), p);
275
276 case WDIOC_GETBOOTSTATUS:
277 return put_user (triggered, p);
278
279 case WDIOC_KEEPALIVE:
280 esb_timer_keepalive ();
281 return 0;
282
283 case WDIOC_SETOPTIONS:
284 {
285 if (get_user (new_options, p))
286 return -EFAULT;
287
288 if (new_options & WDIOS_DISABLECARD) {
289 esb_timer_stop ();
290 retval = 0;
291 }
292
293 if (new_options & WDIOS_ENABLECARD) {
294 esb_timer_keepalive ();
295 esb_timer_start ();
296 retval = 0;
297 }
298
299 return retval;
300 }
301
302 case WDIOC_SETTIMEOUT:
303 {
304 if (get_user(new_heartbeat, p))
305 return -EFAULT;
306
307 if (esb_timer_set_heartbeat(new_heartbeat))
308 return -EINVAL;
309
310 esb_timer_keepalive ();
311 /* Fall */
312 }
313
314 case WDIOC_GETTIMEOUT:
315 return put_user(heartbeat, p);
316
317 default:
318 return -ENOTTY;
319 }
320}
321
322/*
323 * Notify system
324 */
325
326static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused)
327{
328 if (code==SYS_DOWN || code==SYS_HALT) {
329 /* Turn the WDT off */
330 esb_timer_stop ();
331 }
332
333 return NOTIFY_DONE;
334}
335
336/*
337 * Kernel Interfaces
338 */
339
340static const struct file_operations esb_fops = {
341 .owner = THIS_MODULE,
342 .llseek = no_llseek,
343 .write = esb_write,
344 .ioctl = esb_ioctl,
345 .open = esb_open,
346 .release = esb_release,
347};
348
349static struct miscdevice esb_miscdev = {
350 .minor = WATCHDOG_MINOR,
351 .name = "watchdog",
352 .fops = &esb_fops,
353};
354
355static struct notifier_block esb_notifier = {
356 .notifier_call = esb_notify_sys,
357};
358
359/*
360 * Data for PCI driver interface
361 *
362 * This data only exists for exporting the supported
363 * PCI ids via MODULE_DEVICE_TABLE. We do not actually
364 * register a pci_driver, because someone else might one day
365 * want to register another driver on the same PCI id.
366 */
367static struct pci_device_id esb_pci_tbl[] = {
368 { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
369 { 0, }, /* End of list */
370};
371MODULE_DEVICE_TABLE (pci, esb_pci_tbl);
372
373/*
374 * Init & exit routines
375 */
376
377static unsigned char __init esb_getdevice (void)
378{
379 u8 val1;
380 unsigned short val2;
381
382 struct pci_dev *dev = NULL;
383 /*
384 * Find the PCI device
385 */
386
387 for_each_pci_dev(dev) {
388 if (pci_match_id(esb_pci_tbl, dev)) {
389 esb_pci = dev;
390 break;
391 }
392 }
393
394 if (esb_pci) {
395 if (pci_enable_device(esb_pci)) {
396 printk (KERN_ERR PFX "failed to enable device\n");
397 goto err_devput;
398 }
399
400 if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) {
401 printk (KERN_ERR PFX "failed to request region\n");
402 goto err_disable;
403 }
404
405 BASEADDR = ioremap(pci_resource_start(esb_pci, 0),
406 pci_resource_len(esb_pci, 0));
407 if (BASEADDR == NULL) {
408 /* Something's wrong here, BASEADDR has to be set */
409 printk (KERN_ERR PFX "failed to get BASEADDR\n");
410 goto err_release;
411 }
412
413 /*
414 * The watchdog has two timers, it can be setup so that the
415 * expiry of timer1 results in an interrupt and the expiry of
416 * timer2 results in a reboot. We set it to not generate
417 * any interrupts as there is not much we can do with it
418 * right now.
419 *
420 * We also enable reboots and set the timer frequency to
421 * the PCI clock divided by 2^15 (approx 1KHz).
422 */
423 pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003);
424
425 /* Check that the WDT isn't already locked */
426 pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1);
427 if (val1 & ESB_WDT_LOCK)
428 printk (KERN_WARNING PFX "nowayout already set\n");
429
430 /* Set the timer to watchdog mode and disable it for now */
431 pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00);
432
433 /* Check if the watchdog was previously triggered */
434 esb_unlock_registers();
435 val2 = readw(ESB_RELOAD_REG);
436 triggered = (val2 & (0x01 << 9) >> 9);
437
438 /* Reset trigger flag and timers */
439 esb_unlock_registers();
440 writew((0x11 << 8), ESB_RELOAD_REG);
441
442 /* Done */
443 return 1;
444
445err_release:
446 pci_release_region(esb_pci, 0);
447err_disable:
448 pci_disable_device(esb_pci);
449err_devput:
450 pci_dev_put(esb_pci);
451 }
452 return 0;
453}
454
455static int __init watchdog_init (void)
456{
457 int ret;
458
459 spin_lock_init(&esb_lock);
460
461 /* Check whether or not the hardware watchdog is there */
462 if (!esb_getdevice () || esb_pci == NULL)
463 return -ENODEV;
464
465 /* Check that the heartbeat value is within it's range ; if not reset to the default */
466 if (esb_timer_set_heartbeat (heartbeat)) {
467 esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT);
468 printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n",
469 heartbeat);
470 }
471
472 ret = register_reboot_notifier(&esb_notifier);
473 if (ret != 0) {
474 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
475 ret);
476 goto err_unmap;
477 }
478
479 ret = misc_register(&esb_miscdev);
480 if (ret != 0) {
481 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
482 WATCHDOG_MINOR, ret);
483 goto err_notifier;
484 }
485
486 esb_timer_stop ();
487
488 printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n",
489 BASEADDR, heartbeat, nowayout);
490
491 return 0;
492
493err_notifier:
494 unregister_reboot_notifier(&esb_notifier);
495err_unmap:
496 iounmap(BASEADDR);
497/* err_release: */
498 pci_release_region(esb_pci, 0);
499/* err_disable: */
500 pci_disable_device(esb_pci);
501/* err_devput: */
502 pci_dev_put(esb_pci);
503 return ret;
504}
505
506static void __exit watchdog_cleanup (void)
507{
508 /* Stop the timer before we leave */
509 if (!nowayout)
510 esb_timer_stop ();
511
512 /* Deregister */
513 misc_deregister(&esb_miscdev);
514 unregister_reboot_notifier(&esb_notifier);
515 iounmap(BASEADDR);
516 pci_release_region(esb_pci, 0);
517 pci_disable_device(esb_pci);
518 pci_dev_put(esb_pci);
519}
520
521module_init(watchdog_init);
522module_exit(watchdog_cleanup);
523
524MODULE_AUTHOR("Ross Biro and David Härdeman");
525MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets");
526MODULE_LICENSE("GPL");
527MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/iTCO_vendor_support.c b/drivers/watchdog/iTCO_vendor_support.c
new file mode 100644
index 000000000000..415083990097
--- /dev/null
+++ b/drivers/watchdog/iTCO_vendor_support.c
@@ -0,0 +1,307 @@
1/*
2 * intel TCO vendor specific watchdog driver support
3 *
4 * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
12 * provide warranty for any of this software. This material is
13 * provided "AS-IS" and at no charge.
14 */
15
16/*
17 * Includes, defines, variables, module parameters, ...
18 */
19
20/* Module and version information */
21#define DRV_NAME "iTCO_vendor_support"
22#define DRV_VERSION "1.01"
23#define DRV_RELDATE "11-Nov-2006"
24#define PFX DRV_NAME ": "
25
26/* Includes */
27#include <linux/module.h> /* For module specific items */
28#include <linux/moduleparam.h> /* For new moduleparam's */
29#include <linux/types.h> /* For standard types (like size_t) */
30#include <linux/errno.h> /* For the -ENODEV/... values */
31#include <linux/kernel.h> /* For printk/panic/... */
32#include <linux/init.h> /* For __init/__exit/... */
33#include <linux/ioport.h> /* For io-port access */
34
35#include <asm/io.h> /* For inb/outb/... */
36
37/* iTCO defines */
38#define SMI_EN acpibase + 0x30 /* SMI Control and Enable Register */
39#define TCOBASE acpibase + 0x60 /* TCO base address */
40#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
41
42/* List of vendor support modes */
43#define SUPERMICRO_OLD_BOARD 1 /* SuperMicro Pentium 3 Era 370SSE+-OEM1/P3TSSE */
44#define SUPERMICRO_NEW_BOARD 2 /* SuperMicro Pentium 4 / Xeon 4 / EMT64T Era Systems */
45
46static int vendorsupport = 0;
47module_param(vendorsupport, int, 0);
48MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (none), 1=SuperMicro Pent3, 2=SuperMicro Pent4+");
49
50/*
51 * Vendor Specific Support
52 */
53
54/*
55 * Vendor Support: 1
56 * Board: Super Micro Computer Inc. 370SSE+-OEM1/P3TSSE
57 * iTCO chipset: ICH2
58 *
59 * Code contributed by: R. Seretny <lkpatches@paypc.com>
60 * Documentation obtained by R. Seretny from SuperMicro Technical Support
61 *
62 * To enable Watchdog function:
63 * BIOS setup -> Power -> TCO Logic SMI Enable -> Within5Minutes
64 * This setting enables SMI to clear the watchdog expired flag.
65 * If BIOS or CPU fail which may cause SMI hang, then system will
66 * reboot. When application starts to use watchdog function,
67 * application has to take over the control from SMI.
68 *
69 * For P3TSSE, J36 jumper needs to be removed to enable the Watchdog
70 * function.
71 *
72 * Note: The system will reboot when Expire Flag is set TWICE.
73 * So, if the watchdog timer is 20 seconds, then the maximum hang
74 * time is about 40 seconds, and the minimum hang time is about
75 * 20.6 seconds.
76 */
77
78static void supermicro_old_pre_start(unsigned long acpibase)
79{
80 unsigned long val32;
81
82 val32 = inl(SMI_EN);
83 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
84 outl(val32, SMI_EN); /* Needed to activate watchdog */
85}
86
87static void supermicro_old_pre_stop(unsigned long acpibase)
88{
89 unsigned long val32;
90
91 val32 = inl(SMI_EN);
92 val32 &= 0x00002000; /* Turn on SMI clearing watchdog */
93 outl(val32, SMI_EN); /* Needed to deactivate watchdog */
94}
95
96static void supermicro_old_pre_keepalive(unsigned long acpibase)
97{
98 /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
99 /* Clear "Expire Flag" (Bit 3 of TC01_STS register) */
100 outb(0x08, TCO1_STS);
101}
102
103/*
104 * Vendor Support: 2
105 * Board: Super Micro Computer Inc. P4SBx, P4DPx
106 * iTCO chipset: ICH4
107 *
108 * Code contributed by: R. Seretny <lkpatches@paypc.com>
109 * Documentation obtained by R. Seretny from SuperMicro Technical Support
110 *
111 * To enable Watchdog function:
112 * 1. BIOS
113 * For P4SBx:
114 * BIOS setup -> Advanced -> Integrated Peripherals -> Watch Dog Feature
115 * For P4DPx:
116 * BIOS setup -> Advanced -> I/O Device Configuration -> Watch Dog
117 * This setting enables or disables Watchdog function. When enabled, the
118 * default watchdog timer is set to be 5 minutes (about 4’35â€). It is
119 * enough to load and run the OS. The application (service or driver) has
120 * to take over the control once OS is running up and before watchdog
121 * expires.
122 *
123 * 2. JUMPER
124 * For P4SBx: JP39
125 * For P4DPx: JP37
126 * This jumper is used for safety. Closed is enabled. This jumper
127 * prevents user enables watchdog in BIOS by accident.
128 *
129 * To enable Watch Dog function, both BIOS and JUMPER must be enabled.
130 *
131 * The documentation lists motherboards P4SBx and P4DPx series as of
132 * 20-March-2002. However, this code works flawlessly with much newer
133 * motherboards, such as my X6DHR-8G2 (SuperServer 6014H-82).
134 *
135 * The original iTCO driver as written does not actually reset the
136 * watchdog timer on these machines, as a result they reboot after five
137 * minutes.
138 *
139 * NOTE: You may leave the Watchdog function disabled in the SuperMicro
140 * BIOS to avoid a "boot-race"... This driver will enable watchdog
141 * functionality even if it's disabled in the BIOS once the /dev/watchdog
142 * file is opened.
143 */
144
145/* I/O Port's */
146#define SM_REGINDEX 0x2e /* SuperMicro ICH4+ Register Index */
147#define SM_DATAIO 0x2f /* SuperMicro ICH4+ Register Data I/O */
148
149/* Control Register's */
150#define SM_CTLPAGESW 0x07 /* SuperMicro ICH4+ Control Page Switch */
151#define SM_CTLPAGE 0x08 /* SuperMicro ICH4+ Control Page Num */
152
153#define SM_WATCHENABLE 0x30 /* Watchdog enable: Bit 0: 0=off, 1=on */
154
155#define SM_WATCHPAGE 0x87 /* Watchdog unlock control page */
156
157#define SM_ENDWATCH 0xAA /* Watchdog lock control page */
158
159#define SM_COUNTMODE 0xf5 /* Watchdog count mode select */
160 /* (Bit 3: 0 = seconds, 1 = minutes */
161
162#define SM_WATCHTIMER 0xf6 /* 8-bits, Watchdog timer counter (RW) */
163
164#define SM_RESETCONTROL 0xf7 /* Watchdog reset control */
165 /* Bit 6: timer is reset by kbd interrupt */
166 /* Bit 7: timer is reset by mouse interrupt */
167
168static void supermicro_new_unlock_watchdog(void)
169{
170 outb(SM_WATCHPAGE, SM_REGINDEX); /* Write 0x87 to port 0x2e twice */
171 outb(SM_WATCHPAGE, SM_REGINDEX);
172
173 outb(SM_CTLPAGESW, SM_REGINDEX); /* Switch to watchdog control page */
174 outb(SM_CTLPAGE, SM_DATAIO);
175}
176
177static void supermicro_new_lock_watchdog(void)
178{
179 outb(SM_ENDWATCH, SM_REGINDEX);
180}
181
182static void supermicro_new_pre_start(unsigned int heartbeat)
183{
184 unsigned int val;
185
186 supermicro_new_unlock_watchdog();
187
188 /* Watchdog timer setting needs to be in seconds*/
189 outb(SM_COUNTMODE, SM_REGINDEX);
190 val = inb(SM_DATAIO);
191 val &= 0xF7;
192 outb(val, SM_DATAIO);
193
194 /* Write heartbeat interval to WDOG */
195 outb (SM_WATCHTIMER, SM_REGINDEX);
196 outb((heartbeat & 255), SM_DATAIO);
197
198 /* Make sure keyboard/mouse interrupts don't interfere */
199 outb(SM_RESETCONTROL, SM_REGINDEX);
200 val = inb(SM_DATAIO);
201 val &= 0x3f;
202 outb(val, SM_DATAIO);
203
204 /* enable watchdog by setting bit 0 of Watchdog Enable to 1 */
205 outb(SM_WATCHENABLE, SM_REGINDEX);
206 val = inb(SM_DATAIO);
207 val |= 0x01;
208 outb(val, SM_DATAIO);
209
210 supermicro_new_lock_watchdog();
211}
212
213static void supermicro_new_pre_stop(void)
214{
215 unsigned int val;
216
217 supermicro_new_unlock_watchdog();
218
219 /* disable watchdog by setting bit 0 of Watchdog Enable to 0 */
220 outb(SM_WATCHENABLE, SM_REGINDEX);
221 val = inb(SM_DATAIO);
222 val &= 0xFE;
223 outb(val, SM_DATAIO);
224
225 supermicro_new_lock_watchdog();
226}
227
228static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
229{
230 supermicro_new_unlock_watchdog();
231
232 /* reset watchdog timeout to heartveat value */
233 outb(SM_WATCHTIMER, SM_REGINDEX);
234 outb((heartbeat & 255), SM_DATAIO);
235
236 supermicro_new_lock_watchdog();
237}
238
239/*
240 * Generic Support Functions
241 */
242
243void iTCO_vendor_pre_start(unsigned long acpibase,
244 unsigned int heartbeat)
245{
246 if (vendorsupport == SUPERMICRO_OLD_BOARD)
247 supermicro_old_pre_start(acpibase);
248 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
249 supermicro_new_pre_start(heartbeat);
250}
251EXPORT_SYMBOL(iTCO_vendor_pre_start);
252
253void iTCO_vendor_pre_stop(unsigned long acpibase)
254{
255 if (vendorsupport == SUPERMICRO_OLD_BOARD)
256 supermicro_old_pre_stop(acpibase);
257 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
258 supermicro_new_pre_stop();
259}
260EXPORT_SYMBOL(iTCO_vendor_pre_stop);
261
262void iTCO_vendor_pre_keepalive(unsigned long acpibase, unsigned int heartbeat)
263{
264 if (vendorsupport == SUPERMICRO_OLD_BOARD)
265 supermicro_old_pre_keepalive(acpibase);
266 else if (vendorsupport == SUPERMICRO_NEW_BOARD)
267 supermicro_new_pre_set_heartbeat(heartbeat);
268}
269EXPORT_SYMBOL(iTCO_vendor_pre_keepalive);
270
271void iTCO_vendor_pre_set_heartbeat(unsigned int heartbeat)
272{
273 if (vendorsupport == SUPERMICRO_NEW_BOARD)
274 supermicro_new_pre_set_heartbeat(heartbeat);
275}
276EXPORT_SYMBOL(iTCO_vendor_pre_set_heartbeat);
277
278int iTCO_vendor_check_noreboot_on(void)
279{
280 switch(vendorsupport) {
281 case SUPERMICRO_OLD_BOARD:
282 return 0;
283 default:
284 return 1;
285 }
286}
287EXPORT_SYMBOL(iTCO_vendor_check_noreboot_on);
288
289static int __init iTCO_vendor_init_module(void)
290{
291 printk (KERN_INFO PFX "vendor-support=%d\n", vendorsupport);
292 return 0;
293}
294
295static void __exit iTCO_vendor_exit_module(void)
296{
297 printk (KERN_INFO PFX "Module Unloaded\n");
298}
299
300module_init(iTCO_vendor_init_module);
301module_exit(iTCO_vendor_exit_module);
302
303MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>, R. Seretny <lkpatches@paypc.com>");
304MODULE_DESCRIPTION("Intel TCO Vendor Specific WatchDog Timer Driver Support");
305MODULE_VERSION(DRV_VERSION);
306MODULE_LICENSE("GPL");
307
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c
new file mode 100644
index 000000000000..cd5a565bc3a0
--- /dev/null
+++ b/drivers/watchdog/iTCO_wdt.c
@@ -0,0 +1,804 @@
1/*
2 * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
3 *
4 * (c) Copyright 2006-2007 Wim Van Sebroeck <wim@iguana.be>.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
12 * provide warranty for any of this software. This material is
13 * provided "AS-IS" and at no charge.
14 *
15 * The TCO watchdog is implemented in the following I/O controller hubs:
16 * (See the intel documentation on http://developer.intel.com.)
17 * 82801AA (ICH) : document number 290655-003, 290677-014,
18 * 82801AB (ICHO) : document number 290655-003, 290677-014,
19 * 82801BA (ICH2) : document number 290687-002, 298242-027,
20 * 82801BAM (ICH2-M) : document number 290687-002, 298242-027,
21 * 82801CA (ICH3-S) : document number 290733-003, 290739-013,
22 * 82801CAM (ICH3-M) : document number 290716-001, 290718-007,
23 * 82801DB (ICH4) : document number 290744-001, 290745-020,
24 * 82801DBM (ICH4-M) : document number 252337-001, 252663-005,
25 * 82801E (C-ICH) : document number 273599-001, 273645-002,
26 * 82801EB (ICH5) : document number 252516-001, 252517-003,
27 * 82801ER (ICH5R) : document number 252516-001, 252517-003,
28 * 82801FB (ICH6) : document number 301473-002, 301474-007,
29 * 82801FR (ICH6R) : document number 301473-002, 301474-007,
30 * 82801FBM (ICH6-M) : document number 301473-002, 301474-007,
31 * 82801FW (ICH6W) : document number 301473-001, 301474-007,
32 * 82801FRW (ICH6RW) : document number 301473-001, 301474-007,
33 * 82801GB (ICH7) : document number 307013-002, 307014-009,
34 * 82801GR (ICH7R) : document number 307013-002, 307014-009,
35 * 82801GDH (ICH7DH) : document number 307013-002, 307014-009,
36 * 82801GBM (ICH7-M) : document number 307013-002, 307014-009,
37 * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009,
38 * 82801HB (ICH8) : document number 313056-002, 313057-004,
39 * 82801HR (ICH8R) : document number 313056-002, 313057-004,
40 * 82801HH (ICH8DH) : document number 313056-002, 313057-004,
41 * 82801HO (ICH8DO) : document number 313056-002, 313057-004,
42 * 82801IB (ICH9) : document number 316972-001, 316973-001,
43 * 82801IR (ICH9R) : document number 316972-001, 316973-001,
44 * 82801IH (ICH9DH) : document number 316972-001, 316973-001,
45 * 6300ESB (6300ESB) : document number 300641-003, 300884-010,
46 * 631xESB (631xESB) : document number 313082-001, 313075-005,
47 * 632xESB (632xESB) : document number 313082-001, 313075-005
48 */
49
50/*
51 * Includes, defines, variables, module parameters, ...
52 */
53
54/* Module and version information */
55#define DRV_NAME "iTCO_wdt"
56#define DRV_VERSION "1.02"
57#define DRV_RELDATE "26-Jul-2007"
58#define PFX DRV_NAME ": "
59
60/* Includes */
61#include <linux/module.h> /* For module specific items */
62#include <linux/moduleparam.h> /* For new moduleparam's */
63#include <linux/types.h> /* For standard types (like size_t) */
64#include <linux/errno.h> /* For the -ENODEV/... values */
65#include <linux/kernel.h> /* For printk/panic/... */
66#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
67#include <linux/watchdog.h> /* For the watchdog specific items */
68#include <linux/init.h> /* For __init/__exit/... */
69#include <linux/fs.h> /* For file operations */
70#include <linux/platform_device.h> /* For platform_driver framework */
71#include <linux/pci.h> /* For pci functions */
72#include <linux/ioport.h> /* For io-port access */
73#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
74
75#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
76#include <asm/io.h> /* For inb/outb/... */
77
78/* TCO related info */
79enum iTCO_chipsets {
80 TCO_ICH = 0, /* ICH */
81 TCO_ICH0, /* ICH0 */
82 TCO_ICH2, /* ICH2 */
83 TCO_ICH2M, /* ICH2-M */
84 TCO_ICH3, /* ICH3-S */
85 TCO_ICH3M, /* ICH3-M */
86 TCO_ICH4, /* ICH4 */
87 TCO_ICH4M, /* ICH4-M */
88 TCO_CICH, /* C-ICH */
89 TCO_ICH5, /* ICH5 & ICH5R */
90 TCO_6300ESB, /* 6300ESB */
91 TCO_ICH6, /* ICH6 & ICH6R */
92 TCO_ICH6M, /* ICH6-M */
93 TCO_ICH6W, /* ICH6W & ICH6RW */
94 TCO_ICH7, /* ICH7 & ICH7R */
95 TCO_ICH7M, /* ICH7-M */
96 TCO_ICH7MDH, /* ICH7-M DH */
97 TCO_ICH8, /* ICH8 & ICH8R */
98 TCO_ICH8DH, /* ICH8DH */
99 TCO_ICH8DO, /* ICH8DO */
100 TCO_ICH9, /* ICH9 */
101 TCO_ICH9R, /* ICH9R */
102 TCO_ICH9DH, /* ICH9DH */
103 TCO_631XESB, /* 631xESB/632xESB */
104};
105
106static struct {
107 char *name;
108 unsigned int iTCO_version;
109} iTCO_chipset_info[] __devinitdata = {
110 {"ICH", 1},
111 {"ICH0", 1},
112 {"ICH2", 1},
113 {"ICH2-M", 1},
114 {"ICH3-S", 1},
115 {"ICH3-M", 1},
116 {"ICH4", 1},
117 {"ICH4-M", 1},
118 {"C-ICH", 1},
119 {"ICH5 or ICH5R", 1},
120 {"6300ESB", 1},
121 {"ICH6 or ICH6R", 2},
122 {"ICH6-M", 2},
123 {"ICH6W or ICH6RW", 2},
124 {"ICH7 or ICH7R", 2},
125 {"ICH7-M", 2},
126 {"ICH7-M DH", 2},
127 {"ICH8 or ICH8R", 2},
128 {"ICH8DH", 2},
129 {"ICH8DO", 2},
130 {"ICH9", 2},
131 {"ICH9R", 2},
132 {"ICH9DH", 2},
133 {"631xESB/632xESB", 2},
134 {NULL,0}
135};
136
137/*
138 * This data only exists for exporting the supported PCI ids
139 * via MODULE_DEVICE_TABLE. We do not actually register a
140 * pci_driver, because the I/O Controller Hub has also other
141 * functions that probably will be registered by other drivers.
142 */
143static struct pci_device_id iTCO_wdt_pci_tbl[] = {
144 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH },
145 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH0 },
146 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2 },
147 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2M },
148 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3 },
149 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3M },
150 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4 },
151 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4M },
152 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_CICH },
153 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH5 },
154 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_6300ESB },
155 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6 },
156 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6M },
157 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6W },
158 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 },
159 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M },
160 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH },
161 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8 },
162 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DH },
163 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH8DO },
164 { PCI_VENDOR_ID_INTEL, 0x2918, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9 },
165 { PCI_VENDOR_ID_INTEL, 0x2916, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9R },
166 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH9DH },
167 { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
168 { PCI_VENDOR_ID_INTEL, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
169 { PCI_VENDOR_ID_INTEL, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
170 { PCI_VENDOR_ID_INTEL, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
171 { PCI_VENDOR_ID_INTEL, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
172 { PCI_VENDOR_ID_INTEL, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
173 { PCI_VENDOR_ID_INTEL, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
174 { PCI_VENDOR_ID_INTEL, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
175 { PCI_VENDOR_ID_INTEL, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
176 { PCI_VENDOR_ID_INTEL, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
177 { PCI_VENDOR_ID_INTEL, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
178 { PCI_VENDOR_ID_INTEL, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
179 { PCI_VENDOR_ID_INTEL, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
180 { PCI_VENDOR_ID_INTEL, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
181 { PCI_VENDOR_ID_INTEL, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
182 { PCI_VENDOR_ID_INTEL, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_631XESB },
183 { 0, }, /* End of list */
184};
185MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
186
187/* Address definitions for the TCO */
188#define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 /* TCO base address */
189#define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 /* SMI Control and Enable Register */
190
191#define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */
192#define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */
193#define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
194#define TCO_DAT_OUT TCOBASE + 0x03 /* TCO Data Out Register */
195#define TCO1_STS TCOBASE + 0x04 /* TCO1 Status Register */
196#define TCO2_STS TCOBASE + 0x06 /* TCO2 Status Register */
197#define TCO1_CNT TCOBASE + 0x08 /* TCO1 Control Register */
198#define TCO2_CNT TCOBASE + 0x0a /* TCO2 Control Register */
199#define TCOv2_TMR TCOBASE + 0x12 /* TCOv2 Timer Initial Value */
200
201/* internal variables */
202static unsigned long is_active;
203static char expect_release;
204static struct { /* this is private data for the iTCO_wdt device */
205 unsigned int iTCO_version; /* TCO version/generation */
206 unsigned long ACPIBASE; /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
207 unsigned long __iomem *gcs; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */
208 spinlock_t io_lock; /* the lock for io operations */
209 struct pci_dev *pdev; /* the PCI-device */
210} iTCO_wdt_private;
211
212static struct platform_device *iTCO_wdt_platform_device; /* the watchdog platform device */
213
214/* module parameters */
215#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
216static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
217module_param(heartbeat, int, 0);
218MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO v1) or 613 (TCO v2), default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
219
220static int nowayout = WATCHDOG_NOWAYOUT;
221module_param(nowayout, int, 0);
222MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
223
224/* iTCO Vendor Specific Support hooks */
225#ifdef CONFIG_ITCO_VENDOR_SUPPORT
226extern void iTCO_vendor_pre_start(unsigned long, unsigned int);
227extern void iTCO_vendor_pre_stop(unsigned long);
228extern void iTCO_vendor_pre_keepalive(unsigned long, unsigned int);
229extern void iTCO_vendor_pre_set_heartbeat(unsigned int);
230extern int iTCO_vendor_check_noreboot_on(void);
231#else
232#define iTCO_vendor_pre_start(acpibase, heartbeat) {}
233#define iTCO_vendor_pre_stop(acpibase) {}
234#define iTCO_vendor_pre_keepalive(acpibase,heartbeat) {}
235#define iTCO_vendor_pre_set_heartbeat(heartbeat) {}
236#define iTCO_vendor_check_noreboot_on() 1 /* 1=check noreboot; 0=don't check */
237#endif
238
239/*
240 * Some TCO specific functions
241 */
242
243static inline unsigned int seconds_to_ticks(int seconds)
244{
245 /* the internal timer is stored as ticks which decrement
246 * every 0.6 seconds */
247 return (seconds * 10) / 6;
248}
249
250static void iTCO_wdt_set_NO_REBOOT_bit(void)
251{
252 u32 val32;
253
254 /* Set the NO_REBOOT bit: this disables reboots */
255 if (iTCO_wdt_private.iTCO_version == 2) {
256 val32 = readl(iTCO_wdt_private.gcs);
257 val32 |= 0x00000020;
258 writel(val32, iTCO_wdt_private.gcs);
259 } else if (iTCO_wdt_private.iTCO_version == 1) {
260 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
261 val32 |= 0x00000002;
262 pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
263 }
264}
265
266static int iTCO_wdt_unset_NO_REBOOT_bit(void)
267{
268 int ret = 0;
269 u32 val32;
270
271 /* Unset the NO_REBOOT bit: this enables reboots */
272 if (iTCO_wdt_private.iTCO_version == 2) {
273 val32 = readl(iTCO_wdt_private.gcs);
274 val32 &= 0xffffffdf;
275 writel(val32, iTCO_wdt_private.gcs);
276
277 val32 = readl(iTCO_wdt_private.gcs);
278 if (val32 & 0x00000020)
279 ret = -EIO;
280 } else if (iTCO_wdt_private.iTCO_version == 1) {
281 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
282 val32 &= 0xfffffffd;
283 pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
284
285 pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
286 if (val32 & 0x00000002)
287 ret = -EIO;
288 }
289
290 return ret; /* returns: 0 = OK, -EIO = Error */
291}
292
293static int iTCO_wdt_start(void)
294{
295 unsigned int val;
296
297 spin_lock(&iTCO_wdt_private.io_lock);
298
299 iTCO_vendor_pre_start(iTCO_wdt_private.ACPIBASE, heartbeat);
300
301 /* disable chipset's NO_REBOOT bit */
302 if (iTCO_wdt_unset_NO_REBOOT_bit()) {
303 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
304 return -EIO;
305 }
306
307 /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
308 val = inw(TCO1_CNT);
309 val &= 0xf7ff;
310 outw(val, TCO1_CNT);
311 val = inw(TCO1_CNT);
312 spin_unlock(&iTCO_wdt_private.io_lock);
313
314 if (val & 0x0800)
315 return -1;
316 return 0;
317}
318
319static int iTCO_wdt_stop(void)
320{
321 unsigned int val;
322
323 spin_lock(&iTCO_wdt_private.io_lock);
324
325 iTCO_vendor_pre_stop(iTCO_wdt_private.ACPIBASE);
326
327 /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
328 val = inw(TCO1_CNT);
329 val |= 0x0800;
330 outw(val, TCO1_CNT);
331 val = inw(TCO1_CNT);
332
333 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
334 iTCO_wdt_set_NO_REBOOT_bit();
335
336 spin_unlock(&iTCO_wdt_private.io_lock);
337
338 if ((val & 0x0800) == 0)
339 return -1;
340 return 0;
341}
342
343static int iTCO_wdt_keepalive(void)
344{
345 spin_lock(&iTCO_wdt_private.io_lock);
346
347 iTCO_vendor_pre_keepalive(iTCO_wdt_private.ACPIBASE, heartbeat);
348
349 /* Reload the timer by writing to the TCO Timer Counter register */
350 if (iTCO_wdt_private.iTCO_version == 2) {
351 outw(0x01, TCO_RLD);
352 } else if (iTCO_wdt_private.iTCO_version == 1) {
353 outb(0x01, TCO_RLD);
354 }
355
356 spin_unlock(&iTCO_wdt_private.io_lock);
357 return 0;
358}
359
360static int iTCO_wdt_set_heartbeat(int t)
361{
362 unsigned int val16;
363 unsigned char val8;
364 unsigned int tmrval;
365
366 tmrval = seconds_to_ticks(t);
367 /* from the specs: */
368 /* "Values of 0h-3h are ignored and should not be attempted" */
369 if (tmrval < 0x04)
370 return -EINVAL;
371 if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
372 ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
373 return -EINVAL;
374
375 iTCO_vendor_pre_set_heartbeat(tmrval);
376
377 /* Write new heartbeat to watchdog */
378 if (iTCO_wdt_private.iTCO_version == 2) {
379 spin_lock(&iTCO_wdt_private.io_lock);
380 val16 = inw(TCOv2_TMR);
381 val16 &= 0xfc00;
382 val16 |= tmrval;
383 outw(val16, TCOv2_TMR);
384 val16 = inw(TCOv2_TMR);
385 spin_unlock(&iTCO_wdt_private.io_lock);
386
387 if ((val16 & 0x3ff) != tmrval)
388 return -EINVAL;
389 } else if (iTCO_wdt_private.iTCO_version == 1) {
390 spin_lock(&iTCO_wdt_private.io_lock);
391 val8 = inb(TCOv1_TMR);
392 val8 &= 0xc0;
393 val8 |= (tmrval & 0xff);
394 outb(val8, TCOv1_TMR);
395 val8 = inb(TCOv1_TMR);
396 spin_unlock(&iTCO_wdt_private.io_lock);
397
398 if ((val8 & 0x3f) != tmrval)
399 return -EINVAL;
400 }
401
402 heartbeat = t;
403 return 0;
404}
405
406static int iTCO_wdt_get_timeleft (int *time_left)
407{
408 unsigned int val16;
409 unsigned char val8;
410
411 /* read the TCO Timer */
412 if (iTCO_wdt_private.iTCO_version == 2) {
413 spin_lock(&iTCO_wdt_private.io_lock);
414 val16 = inw(TCO_RLD);
415 val16 &= 0x3ff;
416 spin_unlock(&iTCO_wdt_private.io_lock);
417
418 *time_left = (val16 * 6) / 10;
419 } else if (iTCO_wdt_private.iTCO_version == 1) {
420 spin_lock(&iTCO_wdt_private.io_lock);
421 val8 = inb(TCO_RLD);
422 val8 &= 0x3f;
423 spin_unlock(&iTCO_wdt_private.io_lock);
424
425 *time_left = (val8 * 6) / 10;
426 } else
427 return -EINVAL;
428 return 0;
429}
430
431/*
432 * /dev/watchdog handling
433 */
434
435static int iTCO_wdt_open (struct inode *inode, struct file *file)
436{
437 /* /dev/watchdog can only be opened once */
438 if (test_and_set_bit(0, &is_active))
439 return -EBUSY;
440
441 /*
442 * Reload and activate timer
443 */
444 iTCO_wdt_keepalive();
445 iTCO_wdt_start();
446 return nonseekable_open(inode, file);
447}
448
449static int iTCO_wdt_release (struct inode *inode, struct file *file)
450{
451 /*
452 * Shut off the timer.
453 */
454 if (expect_release == 42) {
455 iTCO_wdt_stop();
456 } else {
457 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
458 iTCO_wdt_keepalive();
459 }
460 clear_bit(0, &is_active);
461 expect_release = 0;
462 return 0;
463}
464
465static ssize_t iTCO_wdt_write (struct file *file, const char __user *data,
466 size_t len, loff_t * ppos)
467{
468 /* See if we got the magic character 'V' and reload the timer */
469 if (len) {
470 if (!nowayout) {
471 size_t i;
472
473 /* note: just in case someone wrote the magic character
474 * five months ago... */
475 expect_release = 0;
476
477 /* scan to see whether or not we got the magic character */
478 for (i = 0; i != len; i++) {
479 char c;
480 if (get_user(c, data+i))
481 return -EFAULT;
482 if (c == 'V')
483 expect_release = 42;
484 }
485 }
486
487 /* someone wrote to us, we should reload the timer */
488 iTCO_wdt_keepalive();
489 }
490 return len;
491}
492
493static int iTCO_wdt_ioctl (struct inode *inode, struct file *file,
494 unsigned int cmd, unsigned long arg)
495{
496 int new_options, retval = -EINVAL;
497 int new_heartbeat;
498 void __user *argp = (void __user *)arg;
499 int __user *p = argp;
500 static struct watchdog_info ident = {
501 .options = WDIOF_SETTIMEOUT |
502 WDIOF_KEEPALIVEPING |
503 WDIOF_MAGICCLOSE,
504 .firmware_version = 0,
505 .identity = DRV_NAME,
506 };
507
508 switch (cmd) {
509 case WDIOC_GETSUPPORT:
510 return copy_to_user(argp, &ident,
511 sizeof (ident)) ? -EFAULT : 0;
512
513 case WDIOC_GETSTATUS:
514 case WDIOC_GETBOOTSTATUS:
515 return put_user(0, p);
516
517 case WDIOC_KEEPALIVE:
518 iTCO_wdt_keepalive();
519 return 0;
520
521 case WDIOC_SETOPTIONS:
522 {
523 if (get_user(new_options, p))
524 return -EFAULT;
525
526 if (new_options & WDIOS_DISABLECARD) {
527 iTCO_wdt_stop();
528 retval = 0;
529 }
530
531 if (new_options & WDIOS_ENABLECARD) {
532 iTCO_wdt_keepalive();
533 iTCO_wdt_start();
534 retval = 0;
535 }
536
537 return retval;
538 }
539
540 case WDIOC_SETTIMEOUT:
541 {
542 if (get_user(new_heartbeat, p))
543 return -EFAULT;
544
545 if (iTCO_wdt_set_heartbeat(new_heartbeat))
546 return -EINVAL;
547
548 iTCO_wdt_keepalive();
549 /* Fall */
550 }
551
552 case WDIOC_GETTIMEOUT:
553 return put_user(heartbeat, p);
554
555 case WDIOC_GETTIMELEFT:
556 {
557 int time_left;
558
559 if (iTCO_wdt_get_timeleft(&time_left))
560 return -EINVAL;
561
562 return put_user(time_left, p);
563 }
564
565 default:
566 return -ENOTTY;
567 }
568}
569
570/*
571 * Kernel Interfaces
572 */
573
574static const struct file_operations iTCO_wdt_fops = {
575 .owner = THIS_MODULE,
576 .llseek = no_llseek,
577 .write = iTCO_wdt_write,
578 .ioctl = iTCO_wdt_ioctl,
579 .open = iTCO_wdt_open,
580 .release = iTCO_wdt_release,
581};
582
583static struct miscdevice iTCO_wdt_miscdev = {
584 .minor = WATCHDOG_MINOR,
585 .name = "watchdog",
586 .fops = &iTCO_wdt_fops,
587};
588
589/*
590 * Init & exit routines
591 */
592
593static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev)
594{
595 int ret;
596 u32 base_address;
597 unsigned long RCBA;
598 unsigned long val32;
599
600 /*
601 * Find the ACPI/PM base I/O address which is the base
602 * for the TCO registers (TCOBASE=ACPIBASE + 0x60)
603 * ACPIBASE is bits [15:7] from 0x40-0x43
604 */
605 pci_read_config_dword(pdev, 0x40, &base_address);
606 base_address &= 0x0000ff80;
607 if (base_address == 0x00000000) {
608 /* Something's wrong here, ACPIBASE has to be set */
609 printk(KERN_ERR PFX "failed to get TCOBASE address\n");
610 pci_dev_put(pdev);
611 return -ENODEV;
612 }
613 iTCO_wdt_private.iTCO_version = iTCO_chipset_info[ent->driver_data].iTCO_version;
614 iTCO_wdt_private.ACPIBASE = base_address;
615 iTCO_wdt_private.pdev = pdev;
616
617 /* Get the Memory-Mapped GCS register, we need it for the NO_REBOOT flag (TCO v2) */
618 /* To get access to it you have to read RCBA from PCI Config space 0xf0
619 and use it as base. GCS = RCBA + ICH6_GCS(0x3410). */
620 if (iTCO_wdt_private.iTCO_version == 2) {
621 pci_read_config_dword(pdev, 0xf0, &base_address);
622 RCBA = base_address & 0xffffc000;
623 iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410),4);
624 }
625
626 /* Check chipset's NO_REBOOT bit */
627 if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
628 printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
629 ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
630 goto out;
631 }
632
633 /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
634 iTCO_wdt_set_NO_REBOOT_bit();
635
636 /* Set the TCO_EN bit in SMI_EN register */
637 if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
638 printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
639 SMI_EN );
640 ret = -EIO;
641 goto out;
642 }
643 val32 = inl(SMI_EN);
644 val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
645 outl(val32, SMI_EN);
646 release_region(SMI_EN, 4);
647
648 /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */
649 if (!request_region (TCOBASE, 0x20, "iTCO_wdt")) {
650 printk (KERN_ERR PFX "I/O address 0x%04lx already in use\n",
651 TCOBASE);
652 ret = -EIO;
653 goto out;
654 }
655
656 printk(KERN_INFO PFX "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
657 iTCO_chipset_info[ent->driver_data].name,
658 iTCO_chipset_info[ent->driver_data].iTCO_version,
659 TCOBASE);
660
661 /* Clear out the (probably old) status */
662 outb(0, TCO1_STS);
663 outb(3, TCO2_STS);
664
665 /* Make sure the watchdog is not running */
666 iTCO_wdt_stop();
667
668 /* Check that the heartbeat value is within it's range ; if not reset to the default */
669 if (iTCO_wdt_set_heartbeat(heartbeat)) {
670 iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
671 printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39 (TCO v1) or 613 (TCO v2), using %d\n",
672 heartbeat);
673 }
674
675 ret = misc_register(&iTCO_wdt_miscdev);
676 if (ret != 0) {
677 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
678 WATCHDOG_MINOR, ret);
679 goto unreg_region;
680 }
681
682 printk (KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
683 heartbeat, nowayout);
684
685 return 0;
686
687unreg_region:
688 release_region (TCOBASE, 0x20);
689out:
690 if (iTCO_wdt_private.iTCO_version == 2)
691 iounmap(iTCO_wdt_private.gcs);
692 pci_dev_put(iTCO_wdt_private.pdev);
693 iTCO_wdt_private.ACPIBASE = 0;
694 return ret;
695}
696
697static void iTCO_wdt_cleanup(void)
698{
699 /* Stop the timer before we leave */
700 if (!nowayout)
701 iTCO_wdt_stop();
702
703 /* Deregister */
704 misc_deregister(&iTCO_wdt_miscdev);
705 release_region(TCOBASE, 0x20);
706 if (iTCO_wdt_private.iTCO_version == 2)
707 iounmap(iTCO_wdt_private.gcs);
708 pci_dev_put(iTCO_wdt_private.pdev);
709 iTCO_wdt_private.ACPIBASE = 0;
710}
711
712static int iTCO_wdt_probe(struct platform_device *dev)
713{
714 int found = 0;
715 struct pci_dev *pdev = NULL;
716 const struct pci_device_id *ent;
717
718 spin_lock_init(&iTCO_wdt_private.io_lock);
719
720 for_each_pci_dev(pdev) {
721 ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
722 if (ent) {
723 if (!(iTCO_wdt_init(pdev, ent, dev))) {
724 found++;
725 break;
726 }
727 }
728 }
729
730 if (!found) {
731 printk(KERN_INFO PFX "No card detected\n");
732 return -ENODEV;
733 }
734
735 return 0;
736}
737
738static int iTCO_wdt_remove(struct platform_device *dev)
739{
740 if (iTCO_wdt_private.ACPIBASE)
741 iTCO_wdt_cleanup();
742
743 return 0;
744}
745
746static void iTCO_wdt_shutdown(struct platform_device *dev)
747{
748 iTCO_wdt_stop();
749}
750
751#define iTCO_wdt_suspend NULL
752#define iTCO_wdt_resume NULL
753
754static struct platform_driver iTCO_wdt_driver = {
755 .probe = iTCO_wdt_probe,
756 .remove = iTCO_wdt_remove,
757 .shutdown = iTCO_wdt_shutdown,
758 .suspend = iTCO_wdt_suspend,
759 .resume = iTCO_wdt_resume,
760 .driver = {
761 .owner = THIS_MODULE,
762 .name = DRV_NAME,
763 },
764};
765
766static int __init iTCO_wdt_init_module(void)
767{
768 int err;
769
770 printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s (%s)\n",
771 DRV_VERSION, DRV_RELDATE);
772
773 err = platform_driver_register(&iTCO_wdt_driver);
774 if (err)
775 return err;
776
777 iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
778 if (IS_ERR(iTCO_wdt_platform_device)) {
779 err = PTR_ERR(iTCO_wdt_platform_device);
780 goto unreg_platform_driver;
781 }
782
783 return 0;
784
785unreg_platform_driver:
786 platform_driver_unregister(&iTCO_wdt_driver);
787 return err;
788}
789
790static void __exit iTCO_wdt_cleanup_module(void)
791{
792 platform_device_unregister(iTCO_wdt_platform_device);
793 platform_driver_unregister(&iTCO_wdt_driver);
794 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
795}
796
797module_init(iTCO_wdt_init_module);
798module_exit(iTCO_wdt_cleanup_module);
799
800MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
801MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
802MODULE_VERSION(DRV_VERSION);
803MODULE_LICENSE("GPL");
804MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/ib700wdt.c b/drivers/watchdog/ib700wdt.c
new file mode 100644
index 000000000000..c3a60f52ccb9
--- /dev/null
+++ b/drivers/watchdog/ib700wdt.c
@@ -0,0 +1,408 @@
1/*
2 * IB700 Single Board Computer WDT driver
3 *
4 * (c) Copyright 2001 Charles Howes <chowes@vsol.net>
5 *
6 * Based on advantechwdt.c which is based on acquirewdt.c which
7 * is based on wdt.c.
8 *
9 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
10 *
11 * Based on acquirewdt.c which is based on wdt.c.
12 * Original copyright messages:
13 *
14 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
15 * http://www.redhat.com
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version
20 * 2 of the License, or (at your option) any later version.
21 *
22 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
23 * warranty for any of this software. This material is provided
24 * "AS-IS" and at no charge.
25 *
26 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
27 *
28 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
29 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
30 * Added timeout module option to override default
31 *
32 */
33
34#include <linux/module.h>
35#include <linux/types.h>
36#include <linux/miscdevice.h>
37#include <linux/watchdog.h>
38#include <linux/ioport.h>
39#include <linux/fs.h>
40#include <linux/init.h>
41#include <linux/spinlock.h>
42#include <linux/moduleparam.h>
43#include <linux/platform_device.h>
44
45#include <asm/io.h>
46#include <asm/uaccess.h>
47#include <asm/system.h>
48
49static struct platform_device *ibwdt_platform_device;
50static unsigned long ibwdt_is_open;
51static spinlock_t ibwdt_lock;
52static char expect_close;
53
54/* Module information */
55#define DRV_NAME "ib700wdt"
56#define PFX DRV_NAME ": "
57
58/*
59 *
60 * Watchdog Timer Configuration
61 *
62 * The function of the watchdog timer is to reset the system
63 * automatically and is defined at I/O port 0443H. To enable the
64 * watchdog timer and allow the system to reset, write I/O port 0443H.
65 * To disable the timer, write I/O port 0441H for the system to stop the
66 * watchdog function. The timer has a tolerance of 20% for its
67 * intervals.
68 *
69 * The following describes how the timer should be programmed.
70 *
71 * Enabling Watchdog:
72 * MOV AX,000FH (Choose the values from 0 to F)
73 * MOV DX,0443H
74 * OUT DX,AX
75 *
76 * Disabling Watchdog:
77 * MOV AX,000FH (Any value is fine.)
78 * MOV DX,0441H
79 * OUT DX,AX
80 *
81 * Watchdog timer control table:
82 * Level Value Time/sec | Level Value Time/sec
83 * 1 F 0 | 9 7 16
84 * 2 E 2 | 10 6 18
85 * 3 D 4 | 11 5 20
86 * 4 C 6 | 12 4 22
87 * 5 B 8 | 13 3 24
88 * 6 A 10 | 14 2 26
89 * 7 9 12 | 15 1 28
90 * 8 8 14 | 16 0 30
91 *
92 */
93
94static int wd_times[] = {
95 30, /* 0x0 */
96 28, /* 0x1 */
97 26, /* 0x2 */
98 24, /* 0x3 */
99 22, /* 0x4 */
100 20, /* 0x5 */
101 18, /* 0x6 */
102 16, /* 0x7 */
103 14, /* 0x8 */
104 12, /* 0x9 */
105 10, /* 0xA */
106 8, /* 0xB */
107 6, /* 0xC */
108 4, /* 0xD */
109 2, /* 0xE */
110 0, /* 0xF */
111};
112
113#define WDT_STOP 0x441
114#define WDT_START 0x443
115
116/* Default timeout */
117#define WD_TIMO 0 /* 30 seconds +/- 20%, from table */
118
119static int wd_margin = WD_TIMO;
120
121static int nowayout = WATCHDOG_NOWAYOUT;
122module_param(nowayout, int, 0);
123MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
124
125
126/*
127 * Watchdog Operations
128 */
129
130static void
131ibwdt_ping(void)
132{
133 spin_lock(&ibwdt_lock);
134
135 /* Write a watchdog value */
136 outb_p(wd_margin, WDT_START);
137
138 spin_unlock(&ibwdt_lock);
139}
140
141static void
142ibwdt_disable(void)
143{
144 spin_lock(&ibwdt_lock);
145 outb_p(0, WDT_STOP);
146 spin_unlock(&ibwdt_lock);
147}
148
149static int
150ibwdt_set_heartbeat(int t)
151{
152 int i;
153
154 if ((t < 0) || (t > 30))
155 return -EINVAL;
156
157 for (i = 0x0F; i > -1; i--)
158 if (wd_times[i] > t)
159 break;
160 wd_margin = i;
161 return 0;
162}
163
164/*
165 * /dev/watchdog handling
166 */
167
168static ssize_t
169ibwdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
170{
171 if (count) {
172 if (!nowayout) {
173 size_t i;
174
175 /* In case it was set long ago */
176 expect_close = 0;
177
178 for (i = 0; i != count; i++) {
179 char c;
180 if (get_user(c, buf + i))
181 return -EFAULT;
182 if (c == 'V')
183 expect_close = 42;
184 }
185 }
186 ibwdt_ping();
187 }
188 return count;
189}
190
191static int
192ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
193 unsigned long arg)
194{
195 int new_margin;
196 void __user *argp = (void __user *)arg;
197 int __user *p = argp;
198
199 static struct watchdog_info ident = {
200 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
201 .firmware_version = 1,
202 .identity = "IB700 WDT",
203 };
204
205 switch (cmd) {
206 case WDIOC_GETSUPPORT:
207 if (copy_to_user(argp, &ident, sizeof(ident)))
208 return -EFAULT;
209 break;
210
211 case WDIOC_GETSTATUS:
212 case WDIOC_GETBOOTSTATUS:
213 return put_user(0, p);
214
215 case WDIOC_KEEPALIVE:
216 ibwdt_ping();
217 break;
218
219 case WDIOC_SETTIMEOUT:
220 if (get_user(new_margin, p))
221 return -EFAULT;
222 if (ibwdt_set_heartbeat(new_margin))
223 return -EINVAL;
224 ibwdt_ping();
225 /* Fall */
226
227 case WDIOC_GETTIMEOUT:
228 return put_user(wd_times[wd_margin], p);
229
230 case WDIOC_SETOPTIONS:
231 {
232 int options, retval = -EINVAL;
233
234 if (get_user(options, p))
235 return -EFAULT;
236
237 if (options & WDIOS_DISABLECARD) {
238 ibwdt_disable();
239 retval = 0;
240 }
241
242 if (options & WDIOS_ENABLECARD) {
243 ibwdt_ping();
244 retval = 0;
245 }
246
247 return retval;
248 }
249
250 default:
251 return -ENOTTY;
252 }
253 return 0;
254}
255
256static int
257ibwdt_open(struct inode *inode, struct file *file)
258{
259 if (test_and_set_bit(0, &ibwdt_is_open)) {
260 return -EBUSY;
261 }
262 if (nowayout)
263 __module_get(THIS_MODULE);
264
265 /* Activate */
266 ibwdt_ping();
267 return nonseekable_open(inode, file);
268}
269
270static int
271ibwdt_close(struct inode *inode, struct file *file)
272{
273 if (expect_close == 42) {
274 ibwdt_disable();
275 } else {
276 printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
277 ibwdt_ping();
278 }
279 clear_bit(0, &ibwdt_is_open);
280 expect_close = 0;
281 return 0;
282}
283
284/*
285 * Kernel Interfaces
286 */
287
288static const struct file_operations ibwdt_fops = {
289 .owner = THIS_MODULE,
290 .llseek = no_llseek,
291 .write = ibwdt_write,
292 .ioctl = ibwdt_ioctl,
293 .open = ibwdt_open,
294 .release = ibwdt_close,
295};
296
297static struct miscdevice ibwdt_miscdev = {
298 .minor = WATCHDOG_MINOR,
299 .name = "watchdog",
300 .fops = &ibwdt_fops,
301};
302
303/*
304 * Init & exit routines
305 */
306
307static int __devinit ibwdt_probe(struct platform_device *dev)
308{
309 int res;
310
311 spin_lock_init(&ibwdt_lock);
312
313#if WDT_START != WDT_STOP
314 if (!request_region(WDT_STOP, 1, "IB700 WDT")) {
315 printk (KERN_ERR PFX "STOP method I/O %X is not available.\n", WDT_STOP);
316 res = -EIO;
317 goto out_nostopreg;
318 }
319#endif
320
321 if (!request_region(WDT_START, 1, "IB700 WDT")) {
322 printk (KERN_ERR PFX "START method I/O %X is not available.\n", WDT_START);
323 res = -EIO;
324 goto out_nostartreg;
325 }
326
327 res = misc_register(&ibwdt_miscdev);
328 if (res) {
329 printk (KERN_ERR PFX "failed to register misc device\n");
330 goto out_nomisc;
331 }
332 return 0;
333
334out_nomisc:
335 release_region(WDT_START, 1);
336out_nostartreg:
337#if WDT_START != WDT_STOP
338 release_region(WDT_STOP, 1);
339#endif
340out_nostopreg:
341 return res;
342}
343
344static int __devexit ibwdt_remove(struct platform_device *dev)
345{
346 misc_deregister(&ibwdt_miscdev);
347 release_region(WDT_START,1);
348#if WDT_START != WDT_STOP
349 release_region(WDT_STOP,1);
350#endif
351 return 0;
352}
353
354static void ibwdt_shutdown(struct platform_device *dev)
355{
356 /* Turn the WDT off if we have a soft shutdown */
357 ibwdt_disable();
358}
359
360static struct platform_driver ibwdt_driver = {
361 .probe = ibwdt_probe,
362 .remove = __devexit_p(ibwdt_remove),
363 .shutdown = ibwdt_shutdown,
364 .driver = {
365 .owner = THIS_MODULE,
366 .name = DRV_NAME,
367 },
368};
369
370static int __init ibwdt_init(void)
371{
372 int err;
373
374 printk(KERN_INFO PFX "WDT driver for IB700 single board computer initialising.\n");
375
376 err = platform_driver_register(&ibwdt_driver);
377 if (err)
378 return err;
379
380 ibwdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
381 if (IS_ERR(ibwdt_platform_device)) {
382 err = PTR_ERR(ibwdt_platform_device);
383 goto unreg_platform_driver;
384 }
385
386 return 0;
387
388unreg_platform_driver:
389 platform_driver_unregister(&ibwdt_driver);
390 return err;
391}
392
393static void __exit ibwdt_exit(void)
394{
395 platform_device_unregister(ibwdt_platform_device);
396 platform_driver_unregister(&ibwdt_driver);
397 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
398}
399
400module_init(ibwdt_init);
401module_exit(ibwdt_exit);
402
403MODULE_AUTHOR("Charles Howes <chowes@vsol.net>");
404MODULE_DESCRIPTION("IB700 SBC watchdog driver");
405MODULE_LICENSE("GPL");
406MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
407
408/* end of ib700wdt.c */
diff --git a/drivers/watchdog/ibmasr.c b/drivers/watchdog/ibmasr.c
new file mode 100644
index 000000000000..94155f6136c2
--- /dev/null
+++ b/drivers/watchdog/ibmasr.c
@@ -0,0 +1,403 @@
1/*
2 * IBM Automatic Server Restart driver.
3 *
4 * Copyright (c) 2005 Andrey Panin <pazke@donpac.ru>
5 *
6 * Based on driver written by Pete Reynolds.
7 * Copyright (c) IBM Corporation, 1998-2004.
8 *
9 * This software may be used and distributed according to the terms
10 * of the GNU Public License, incorporated herein by reference.
11 */
12
13#include <linux/fs.h>
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/module.h>
17#include <linux/pci.h>
18#include <linux/timer.h>
19#include <linux/miscdevice.h>
20#include <linux/watchdog.h>
21#include <linux/dmi.h>
22
23#include <asm/io.h>
24#include <asm/uaccess.h>
25
26
27enum {
28 ASMTYPE_UNKNOWN,
29 ASMTYPE_TOPAZ,
30 ASMTYPE_JASPER,
31 ASMTYPE_PEARL,
32 ASMTYPE_JUNIPER,
33 ASMTYPE_SPRUCE,
34};
35
36#define PFX "ibmasr: "
37
38#define TOPAZ_ASR_REG_OFFSET 4
39#define TOPAZ_ASR_TOGGLE 0x40
40#define TOPAZ_ASR_DISABLE 0x80
41
42/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */
43#define PEARL_BASE 0xe04
44#define PEARL_WRITE 0xe06
45#define PEARL_READ 0xe07
46
47#define PEARL_ASR_DISABLE_MASK 0x80 /* bit 7: disable = 1, enable = 0 */
48#define PEARL_ASR_TOGGLE_MASK 0x40 /* bit 6: 0, then 1, then 0 */
49
50/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */
51#define JASPER_ASR_REG_OFFSET 0x38
52
53#define JASPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1, enable = 0 */
54#define JASPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */
55
56#define JUNIPER_BASE_ADDRESS 0x54b /* Base address of Juniper ASR */
57#define JUNIPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1 enable = 0 */
58#define JUNIPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */
59
60#define SPRUCE_BASE_ADDRESS 0x118e /* Base address of Spruce ASR */
61#define SPRUCE_ASR_DISABLE_MASK 0x01 /* bit 1: disable = 1 enable = 0 */
62#define SPRUCE_ASR_TOGGLE_MASK 0x02 /* bit 0: 0, then 1, then 0 */
63
64
65static int nowayout = WATCHDOG_NOWAYOUT;
66
67static unsigned long asr_is_open;
68static char asr_expect_close;
69
70static unsigned int asr_type, asr_base, asr_length;
71static unsigned int asr_read_addr, asr_write_addr;
72static unsigned char asr_toggle_mask, asr_disable_mask;
73
74static void asr_toggle(void)
75{
76 unsigned char reg = inb(asr_read_addr);
77
78 outb(reg & ~asr_toggle_mask, asr_write_addr);
79 reg = inb(asr_read_addr);
80
81 outb(reg | asr_toggle_mask, asr_write_addr);
82 reg = inb(asr_read_addr);
83
84 outb(reg & ~asr_toggle_mask, asr_write_addr);
85 reg = inb(asr_read_addr);
86}
87
88static void asr_enable(void)
89{
90 unsigned char reg;
91
92 if (asr_type == ASMTYPE_TOPAZ) {
93 /* asr_write_addr == asr_read_addr */
94 reg = inb(asr_read_addr);
95 outb(reg & ~(TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE),
96 asr_read_addr);
97 } else {
98 /*
99 * First make sure the hardware timer is reset by toggling
100 * ASR hardware timer line.
101 */
102 asr_toggle();
103
104 reg = inb(asr_read_addr);
105 outb(reg & ~asr_disable_mask, asr_write_addr);
106 }
107 reg = inb(asr_read_addr);
108}
109
110static void asr_disable(void)
111{
112 unsigned char reg = inb(asr_read_addr);
113
114 if (asr_type == ASMTYPE_TOPAZ)
115 /* asr_write_addr == asr_read_addr */
116 outb(reg | TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE,
117 asr_read_addr);
118 else {
119 outb(reg | asr_toggle_mask, asr_write_addr);
120 reg = inb(asr_read_addr);
121
122 outb(reg | asr_disable_mask, asr_write_addr);
123 }
124 reg = inb(asr_read_addr);
125}
126
127static int __init asr_get_base_address(void)
128{
129 unsigned char low, high;
130 const char *type = "";
131
132 asr_length = 1;
133
134 switch (asr_type) {
135 case ASMTYPE_TOPAZ:
136 /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */
137 outb(0x07, 0x2e);
138 outb(0x07, 0x2f);
139
140 /* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */
141 outb(0x60, 0x2e);
142 high = inb(0x2f);
143
144 /* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */
145 outb(0x61, 0x2e);
146 low = inb(0x2f);
147
148 asr_base = (high << 16) | low;
149 asr_read_addr = asr_write_addr =
150 asr_base + TOPAZ_ASR_REG_OFFSET;
151 asr_length = 5;
152
153 break;
154
155 case ASMTYPE_JASPER:
156 type = "Jaspers ";
157
158 /* FIXME: need to use pci_config_lock here, but it's not exported */
159
160/* spin_lock_irqsave(&pci_config_lock, flags);*/
161
162 /* Select the SuperIO chip in the PCI I/O port register */
163 outl(0x8000f858, 0xcf8);
164
165 /*
166 * Read the base address for the SuperIO chip.
167 * Only the lower 16 bits are valid, but the address is word
168 * aligned so the last bit must be masked off.
169 */
170 asr_base = inl(0xcfc) & 0xfffe;
171
172/* spin_unlock_irqrestore(&pci_config_lock, flags);*/
173
174 asr_read_addr = asr_write_addr =
175 asr_base + JASPER_ASR_REG_OFFSET;
176 asr_toggle_mask = JASPER_ASR_TOGGLE_MASK;
177 asr_disable_mask = JASPER_ASR_DISABLE_MASK;
178 asr_length = JASPER_ASR_REG_OFFSET + 1;
179
180 break;
181
182 case ASMTYPE_PEARL:
183 type = "Pearls ";
184 asr_base = PEARL_BASE;
185 asr_read_addr = PEARL_READ;
186 asr_write_addr = PEARL_WRITE;
187 asr_toggle_mask = PEARL_ASR_TOGGLE_MASK;
188 asr_disable_mask = PEARL_ASR_DISABLE_MASK;
189 asr_length = 4;
190 break;
191
192 case ASMTYPE_JUNIPER:
193 type = "Junipers ";
194 asr_base = JUNIPER_BASE_ADDRESS;
195 asr_read_addr = asr_write_addr = asr_base;
196 asr_toggle_mask = JUNIPER_ASR_TOGGLE_MASK;
197 asr_disable_mask = JUNIPER_ASR_DISABLE_MASK;
198 break;
199
200 case ASMTYPE_SPRUCE:
201 type = "Spruce's ";
202 asr_base = SPRUCE_BASE_ADDRESS;
203 asr_read_addr = asr_write_addr = asr_base;
204 asr_toggle_mask = SPRUCE_ASR_TOGGLE_MASK;
205 asr_disable_mask = SPRUCE_ASR_DISABLE_MASK;
206 break;
207 }
208
209 if (!request_region(asr_base, asr_length, "ibmasr")) {
210 printk(KERN_ERR PFX "address %#x already in use\n",
211 asr_base);
212 return -EBUSY;
213 }
214
215 printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base);
216
217 return 0;
218}
219
220
221static ssize_t asr_write(struct file *file, const char __user *buf,
222 size_t count, loff_t *ppos)
223{
224 if (count) {
225 if (!nowayout) {
226 size_t i;
227
228 /* In case it was set long ago */
229 asr_expect_close = 0;
230
231 for (i = 0; i != count; i++) {
232 char c;
233 if (get_user(c, buf + i))
234 return -EFAULT;
235 if (c == 'V')
236 asr_expect_close = 42;
237 }
238 }
239 asr_toggle();
240 }
241 return count;
242}
243
244static int asr_ioctl(struct inode *inode, struct file *file,
245 unsigned int cmd, unsigned long arg)
246{
247 static const struct watchdog_info ident = {
248 .options = WDIOF_KEEPALIVEPING |
249 WDIOF_MAGICCLOSE,
250 .identity = "IBM ASR"
251 };
252 void __user *argp = (void __user *)arg;
253 int __user *p = argp;
254 int heartbeat;
255
256 switch (cmd) {
257 case WDIOC_GETSUPPORT:
258 return copy_to_user(argp, &ident, sizeof(ident)) ?
259 -EFAULT : 0;
260
261 case WDIOC_GETSTATUS:
262 case WDIOC_GETBOOTSTATUS:
263 return put_user(0, p);
264
265 case WDIOC_KEEPALIVE:
266 asr_toggle();
267 return 0;
268
269 /*
270 * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT
271 * and WDIOC_GETTIMEOUT always returns 256.
272 */
273 case WDIOC_GETTIMEOUT:
274 heartbeat = 256;
275 return put_user(heartbeat, p);
276
277 case WDIOC_SETOPTIONS: {
278 int new_options, retval = -EINVAL;
279
280 if (get_user(new_options, p))
281 return -EFAULT;
282
283 if (new_options & WDIOS_DISABLECARD) {
284 asr_disable();
285 retval = 0;
286 }
287
288 if (new_options & WDIOS_ENABLECARD) {
289 asr_enable();
290 asr_toggle();
291 retval = 0;
292 }
293
294 return retval;
295 }
296 }
297
298 return -ENOTTY;
299}
300
301static int asr_open(struct inode *inode, struct file *file)
302{
303 if(test_and_set_bit(0, &asr_is_open))
304 return -EBUSY;
305
306 asr_toggle();
307 asr_enable();
308
309 return nonseekable_open(inode, file);
310}
311
312static int asr_release(struct inode *inode, struct file *file)
313{
314 if (asr_expect_close == 42)
315 asr_disable();
316 else {
317 printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
318 asr_toggle();
319 }
320 clear_bit(0, &asr_is_open);
321 asr_expect_close = 0;
322 return 0;
323}
324
325static const struct file_operations asr_fops = {
326 .owner = THIS_MODULE,
327 .llseek = no_llseek,
328 .write = asr_write,
329 .ioctl = asr_ioctl,
330 .open = asr_open,
331 .release = asr_release,
332};
333
334static struct miscdevice asr_miscdev = {
335 .minor = WATCHDOG_MINOR,
336 .name = "watchdog",
337 .fops = &asr_fops,
338};
339
340
341struct ibmasr_id {
342 const char *desc;
343 int type;
344};
345
346static struct ibmasr_id __initdata ibmasr_id_table[] = {
347 { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ },
348 { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL },
349 { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER },
350 { "IBM Automatic Server Restart - Machine Type 8482", ASMTYPE_JUNIPER },
351 { "IBM Automatic Server Restart - Machine Type 8648", ASMTYPE_SPRUCE },
352 { NULL }
353};
354
355static int __init ibmasr_init(void)
356{
357 struct ibmasr_id *id;
358 int rc;
359
360 for (id = ibmasr_id_table; id->desc; id++) {
361 if (dmi_find_device(DMI_DEV_TYPE_OTHER, id->desc, NULL)) {
362 asr_type = id->type;
363 break;
364 }
365 }
366
367 if (!asr_type)
368 return -ENODEV;
369
370 rc = asr_get_base_address();
371 if (rc)
372 return rc;
373
374 rc = misc_register(&asr_miscdev);
375 if (rc < 0) {
376 release_region(asr_base, asr_length);
377 printk(KERN_ERR PFX "failed to register misc device\n");
378 return rc;
379 }
380
381 return 0;
382}
383
384static void __exit ibmasr_exit(void)
385{
386 if (!nowayout)
387 asr_disable();
388
389 misc_deregister(&asr_miscdev);
390
391 release_region(asr_base, asr_length);
392}
393
394module_init(ibmasr_init);
395module_exit(ibmasr_exit);
396
397module_param(nowayout, int, 0);
398MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
399
400MODULE_DESCRIPTION("IBM Automatic Server Restart driver");
401MODULE_AUTHOR("Andrey Panin");
402MODULE_LICENSE("GPL");
403MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/indydog.c b/drivers/watchdog/indydog.c
new file mode 100644
index 000000000000..788245bdaa7f
--- /dev/null
+++ b/drivers/watchdog/indydog.c
@@ -0,0 +1,215 @@
1/*
2 * IndyDog 0.3 A Hardware Watchdog Device for SGI IP22
3 *
4 * (c) Copyright 2002 Guido Guenther <agx@sigxcpu.org>, All Rights Reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * based on softdog.c by Alan Cox <alan@redhat.com>
12 */
13
14#include <linux/module.h>
15#include <linux/moduleparam.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/fs.h>
19#include <linux/mm.h>
20#include <linux/miscdevice.h>
21#include <linux/watchdog.h>
22#include <linux/notifier.h>
23#include <linux/reboot.h>
24#include <linux/init.h>
25#include <asm/uaccess.h>
26#include <asm/sgi/mc.h>
27
28#define PFX "indydog: "
29static int indydog_alive;
30
31#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
32
33static int nowayout = WATCHDOG_NOWAYOUT;
34module_param(nowayout, int, 0);
35MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
36
37static void indydog_start(void)
38{
39 u32 mc_ctrl0 = sgimc->cpuctrl0;
40
41 mc_ctrl0 = sgimc->cpuctrl0 | SGIMC_CCTRL0_WDOG;
42 sgimc->cpuctrl0 = mc_ctrl0;
43}
44
45static void indydog_stop(void)
46{
47 u32 mc_ctrl0 = sgimc->cpuctrl0;
48
49 mc_ctrl0 &= ~SGIMC_CCTRL0_WDOG;
50 sgimc->cpuctrl0 = mc_ctrl0;
51
52 printk(KERN_INFO PFX "Stopped watchdog timer.\n");
53}
54
55static void indydog_ping(void)
56{
57 sgimc->watchdogt = 0;
58}
59
60/*
61 * Allow only one person to hold it open
62 */
63static int indydog_open(struct inode *inode, struct file *file)
64{
65 if (indydog_alive)
66 return -EBUSY;
67
68 if (nowayout)
69 __module_get(THIS_MODULE);
70
71 /* Activate timer */
72 indydog_start();
73 indydog_ping();
74
75 indydog_alive = 1;
76 printk(KERN_INFO "Started watchdog timer.\n");
77
78 return nonseekable_open(inode, file);
79}
80
81static int indydog_release(struct inode *inode, struct file *file)
82{
83 /* Shut off the timer.
84 * Lock it in if it's a module and we defined ...NOWAYOUT */
85 if (!nowayout)
86 indydog_stop(); /* Turn the WDT off */
87
88 indydog_alive = 0;
89
90 return 0;
91}
92
93static ssize_t indydog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
94{
95 /* Refresh the timer. */
96 if (len) {
97 indydog_ping();
98 }
99 return len;
100}
101
102static int indydog_ioctl(struct inode *inode, struct file *file,
103 unsigned int cmd, unsigned long arg)
104{
105 int options, retval = -EINVAL;
106 static struct watchdog_info ident = {
107 .options = WDIOF_KEEPALIVEPING |
108 WDIOF_MAGICCLOSE,
109 .firmware_version = 0,
110 .identity = "Hardware Watchdog for SGI IP22",
111 };
112
113 switch (cmd) {
114 default:
115 return -ENOTTY;
116 case WDIOC_GETSUPPORT:
117 if (copy_to_user((struct watchdog_info *)arg,
118 &ident, sizeof(ident)))
119 return -EFAULT;
120 return 0;
121 case WDIOC_GETSTATUS:
122 case WDIOC_GETBOOTSTATUS:
123 return put_user(0,(int *)arg);
124 case WDIOC_KEEPALIVE:
125 indydog_ping();
126 return 0;
127 case WDIOC_GETTIMEOUT:
128 return put_user(WATCHDOG_TIMEOUT,(int *)arg);
129 case WDIOC_SETOPTIONS:
130 {
131 if (get_user(options, (int *)arg))
132 return -EFAULT;
133
134 if (options & WDIOS_DISABLECARD) {
135 indydog_stop();
136 retval = 0;
137 }
138
139 if (options & WDIOS_ENABLECARD) {
140 indydog_start();
141 retval = 0;
142 }
143
144 return retval;
145 }
146 }
147}
148
149static int indydog_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
150{
151 if (code == SYS_DOWN || code == SYS_HALT)
152 indydog_stop(); /* Turn the WDT off */
153
154 return NOTIFY_DONE;
155}
156
157static const struct file_operations indydog_fops = {
158 .owner = THIS_MODULE,
159 .llseek = no_llseek,
160 .write = indydog_write,
161 .ioctl = indydog_ioctl,
162 .open = indydog_open,
163 .release = indydog_release,
164};
165
166static struct miscdevice indydog_miscdev = {
167 .minor = WATCHDOG_MINOR,
168 .name = "watchdog",
169 .fops = &indydog_fops,
170};
171
172static struct notifier_block indydog_notifier = {
173 .notifier_call = indydog_notify_sys,
174};
175
176static char banner[] __initdata =
177 KERN_INFO PFX "Hardware Watchdog Timer for SGI IP22: 0.3\n";
178
179static int __init watchdog_init(void)
180{
181 int ret;
182
183 ret = register_reboot_notifier(&indydog_notifier);
184 if (ret) {
185 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
186 ret);
187 return ret;
188 }
189
190 ret = misc_register(&indydog_miscdev);
191 if (ret) {
192 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
193 WATCHDOG_MINOR, ret);
194 unregister_reboot_notifier(&indydog_notifier);
195 return ret;
196 }
197
198 printk(banner);
199
200 return 0;
201}
202
203static void __exit watchdog_exit(void)
204{
205 misc_deregister(&indydog_miscdev);
206 unregister_reboot_notifier(&indydog_notifier);
207}
208
209module_init(watchdog_init);
210module_exit(watchdog_exit);
211
212MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
213MODULE_DESCRIPTION("Hardware Watchdog Device for SGI IP22");
214MODULE_LICENSE("GPL");
215MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/iop_wdt.c b/drivers/watchdog/iop_wdt.c
new file mode 100644
index 000000000000..bbbd91af754d
--- /dev/null
+++ b/drivers/watchdog/iop_wdt.c
@@ -0,0 +1,262 @@
1/*
2 * drivers/char/watchdog/iop_wdt.c
3 *
4 * WDT driver for Intel I/O Processors
5 * Copyright (C) 2005, Intel Corporation.
6 *
7 * Based on ixp4xx driver, Copyright 2004 (c) MontaVista, Software, Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2, as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
20 * Place - Suite 330, Boston, MA 02111-1307 USA.
21 *
22 * Curt E Bruns <curt.e.bruns@intel.com>
23 * Peter Milne <peter.milne@d-tacq.com>
24 * Dan Williams <dan.j.williams@intel.com>
25 */
26
27#include <linux/module.h>
28#include <linux/kernel.h>
29#include <linux/fs.h>
30#include <linux/init.h>
31#include <linux/device.h>
32#include <linux/miscdevice.h>
33#include <linux/watchdog.h>
34#include <linux/uaccess.h>
35#include <asm/hardware.h>
36
37static int nowayout = WATCHDOG_NOWAYOUT;
38static unsigned long wdt_status;
39static unsigned long boot_status;
40
41#define WDT_IN_USE 0
42#define WDT_OK_TO_CLOSE 1
43#define WDT_ENABLED 2
44
45static unsigned long iop_watchdog_timeout(void)
46{
47 return (0xffffffffUL / get_iop_tick_rate());
48}
49
50/**
51 * wdt_supports_disable - determine if we are accessing a iop13xx watchdog
52 * or iop3xx by whether it has a disable command
53 */
54static int wdt_supports_disable(void)
55{
56 int can_disable;
57
58 if (IOP_WDTCR_EN_ARM != IOP_WDTCR_DIS_ARM)
59 can_disable = 1;
60 else
61 can_disable = 0;
62
63 return can_disable;
64}
65
66static void wdt_enable(void)
67{
68 /* Arm and enable the Timer to starting counting down from 0xFFFF.FFFF
69 * Takes approx. 10.7s to timeout
70 */
71 write_wdtcr(IOP_WDTCR_EN_ARM);
72 write_wdtcr(IOP_WDTCR_EN);
73}
74
75/* returns 0 if the timer was successfully disabled */
76static int wdt_disable(void)
77{
78 /* Stop Counting */
79 if (wdt_supports_disable()) {
80 write_wdtcr(IOP_WDTCR_DIS_ARM);
81 write_wdtcr(IOP_WDTCR_DIS);
82 clear_bit(WDT_ENABLED, &wdt_status);
83 printk(KERN_INFO "WATCHDOG: Disabled\n");
84 return 0;
85 } else
86 return 1;
87}
88
89static int iop_wdt_open(struct inode *inode, struct file *file)
90{
91 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
92 return -EBUSY;
93
94 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
95
96 wdt_enable();
97
98 set_bit(WDT_ENABLED, &wdt_status);
99
100 return nonseekable_open(inode, file);
101}
102
103static ssize_t
104iop_wdt_write(struct file *file, const char *data, size_t len,
105 loff_t *ppos)
106{
107 if (len) {
108 if (!nowayout) {
109 size_t i;
110
111 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
112
113 for (i = 0; i != len; i++) {
114 char c;
115
116 if (get_user(c, data + i))
117 return -EFAULT;
118 if (c == 'V')
119 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
120 }
121 }
122 wdt_enable();
123 }
124
125 return len;
126}
127
128static struct watchdog_info ident = {
129 .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
130 .identity = "iop watchdog",
131};
132
133static int
134iop_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
135 unsigned long arg)
136{
137 int options;
138 int ret = -ENOTTY;
139
140 switch (cmd) {
141 case WDIOC_GETSUPPORT:
142 if (copy_to_user
143 ((struct watchdog_info *)arg, &ident, sizeof ident))
144 ret = -EFAULT;
145 else
146 ret = 0;
147 break;
148
149 case WDIOC_GETSTATUS:
150 ret = put_user(0, (int *)arg);
151 break;
152
153 case WDIOC_GETBOOTSTATUS:
154 ret = put_user(boot_status, (int *)arg);
155 break;
156
157 case WDIOC_GETTIMEOUT:
158 ret = put_user(iop_watchdog_timeout(), (int *)arg);
159 break;
160
161 case WDIOC_KEEPALIVE:
162 wdt_enable();
163 ret = 0;
164 break;
165
166 case WDIOC_SETOPTIONS:
167 if (get_user(options, (int *)arg))
168 return -EFAULT;
169
170 if (options & WDIOS_DISABLECARD) {
171 if (!nowayout) {
172 if (wdt_disable() == 0) {
173 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
174 ret = 0;
175 } else
176 ret = -ENXIO;
177 } else
178 ret = 0;
179 }
180
181 if (options & WDIOS_ENABLECARD) {
182 wdt_enable();
183 ret = 0;
184 }
185 break;
186 }
187
188 return ret;
189}
190
191static int iop_wdt_release(struct inode *inode, struct file *file)
192{
193 int state = 1;
194 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
195 if (test_bit(WDT_ENABLED, &wdt_status))
196 state = wdt_disable();
197
198 /* if the timer is not disbaled reload and notify that we are still
199 * going down
200 */
201 if (state != 0) {
202 wdt_enable();
203 printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
204 "reset in %lu seconds\n", iop_watchdog_timeout());
205 }
206
207 clear_bit(WDT_IN_USE, &wdt_status);
208 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
209
210 return 0;
211}
212
213static const struct file_operations iop_wdt_fops = {
214 .owner = THIS_MODULE,
215 .llseek = no_llseek,
216 .write = iop_wdt_write,
217 .ioctl = iop_wdt_ioctl,
218 .open = iop_wdt_open,
219 .release = iop_wdt_release,
220};
221
222static struct miscdevice iop_wdt_miscdev = {
223 .minor = WATCHDOG_MINOR,
224 .name = "watchdog",
225 .fops = &iop_wdt_fops,
226};
227
228static int __init iop_wdt_init(void)
229{
230 int ret;
231
232 ret = misc_register(&iop_wdt_miscdev);
233 if (ret == 0)
234 printk("iop watchdog timer: timeout %lu sec\n",
235 iop_watchdog_timeout());
236
237 /* check if the reset was caused by the watchdog timer */
238 boot_status = (read_rcsr() & IOP_RCSR_WDT) ? WDIOF_CARDRESET : 0;
239
240 /* Configure Watchdog Timeout to cause an Internal Bus (IB) Reset
241 * NOTE: An IB Reset will Reset both cores in the IOP342
242 */
243 write_wdtsr(IOP13XX_WDTCR_IB_RESET);
244
245 return ret;
246}
247
248static void __exit iop_wdt_exit(void)
249{
250 misc_deregister(&iop_wdt_miscdev);
251}
252
253module_init(iop_wdt_init);
254module_exit(iop_wdt_exit);
255
256module_param(nowayout, int, 0);
257MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
258
259MODULE_AUTHOR("Curt E Bruns <curt.e.bruns@intel.com>");
260MODULE_DESCRIPTION("iop watchdog timer driver");
261MODULE_LICENSE("GPL");
262MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/ixp2000_wdt.c b/drivers/watchdog/ixp2000_wdt.c
new file mode 100644
index 000000000000..dc7548dcaf35
--- /dev/null
+++ b/drivers/watchdog/ixp2000_wdt.c
@@ -0,0 +1,219 @@
1/*
2 * drivers/char/watchdog/ixp2000_wdt.c
3 *
4 * Watchdog driver for Intel IXP2000 network processors
5 *
6 * Adapted from the IXP4xx watchdog driver by Lennert Buytenhek.
7 * The original version carries these notices:
8 *
9 * Author: Deepak Saxena <dsaxena@plexity.net>
10 *
11 * Copyright 2004 (c) MontaVista, Software, Inc.
12 * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
13 *
14 * This file is licensed under the terms of the GNU General Public
15 * License version 2. This program is licensed "as is" without any
16 * warranty of any kind, whether express or implied.
17 */
18
19#include <linux/module.h>
20#include <linux/moduleparam.h>
21#include <linux/types.h>
22#include <linux/kernel.h>
23#include <linux/fs.h>
24#include <linux/miscdevice.h>
25#include <linux/watchdog.h>
26#include <linux/init.h>
27#include <linux/bitops.h>
28
29#include <asm/hardware.h>
30#include <asm/uaccess.h>
31
32static int nowayout = WATCHDOG_NOWAYOUT;
33static unsigned int heartbeat = 60; /* (secs) Default is 1 minute */
34static unsigned long wdt_status;
35
36#define WDT_IN_USE 0
37#define WDT_OK_TO_CLOSE 1
38
39static unsigned long wdt_tick_rate;
40
41static void
42wdt_enable(void)
43{
44 ixp2000_reg_write(IXP2000_RESET0, *(IXP2000_RESET0) | WDT_RESET_ENABLE);
45 ixp2000_reg_write(IXP2000_TWDE, WDT_ENABLE);
46 ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
47 ixp2000_reg_write(IXP2000_T4_CTL, TIMER_DIVIDER_256 | TIMER_ENABLE);
48}
49
50static void
51wdt_disable(void)
52{
53 ixp2000_reg_write(IXP2000_T4_CTL, 0);
54}
55
56static void
57wdt_keepalive(void)
58{
59 ixp2000_reg_write(IXP2000_T4_CLD, heartbeat * wdt_tick_rate);
60}
61
62static int
63ixp2000_wdt_open(struct inode *inode, struct file *file)
64{
65 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
66 return -EBUSY;
67
68 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
69
70 wdt_enable();
71
72 return nonseekable_open(inode, file);
73}
74
75static ssize_t
76ixp2000_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
77{
78 if (len) {
79 if (!nowayout) {
80 size_t i;
81
82 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
83
84 for (i = 0; i != len; i++) {
85 char c;
86
87 if (get_user(c, data + i))
88 return -EFAULT;
89 if (c == 'V')
90 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
91 }
92 }
93 wdt_keepalive();
94 }
95
96 return len;
97}
98
99
100static struct watchdog_info ident = {
101 .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT |
102 WDIOF_KEEPALIVEPING,
103 .identity = "IXP2000 Watchdog",
104};
105
106static int
107ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
108 unsigned long arg)
109{
110 int ret = -ENOTTY;
111 int time;
112
113 switch (cmd) {
114 case WDIOC_GETSUPPORT:
115 ret = copy_to_user((struct watchdog_info *)arg, &ident,
116 sizeof(ident)) ? -EFAULT : 0;
117 break;
118
119 case WDIOC_GETSTATUS:
120 ret = put_user(0, (int *)arg);
121 break;
122
123 case WDIOC_GETBOOTSTATUS:
124 ret = put_user(0, (int *)arg);
125 break;
126
127 case WDIOC_SETTIMEOUT:
128 ret = get_user(time, (int *)arg);
129 if (ret)
130 break;
131
132 if (time <= 0 || time > 60) {
133 ret = -EINVAL;
134 break;
135 }
136
137 heartbeat = time;
138 wdt_keepalive();
139 /* Fall through */
140
141 case WDIOC_GETTIMEOUT:
142 ret = put_user(heartbeat, (int *)arg);
143 break;
144
145 case WDIOC_KEEPALIVE:
146 wdt_enable();
147 ret = 0;
148 break;
149 }
150
151 return ret;
152}
153
154static int
155ixp2000_wdt_release(struct inode *inode, struct file *file)
156{
157 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
158 wdt_disable();
159 } else {
160 printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
161 "timer will not stop\n");
162 }
163
164 clear_bit(WDT_IN_USE, &wdt_status);
165 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
166
167 return 0;
168}
169
170
171static const struct file_operations ixp2000_wdt_fops =
172{
173 .owner = THIS_MODULE,
174 .llseek = no_llseek,
175 .write = ixp2000_wdt_write,
176 .ioctl = ixp2000_wdt_ioctl,
177 .open = ixp2000_wdt_open,
178 .release = ixp2000_wdt_release,
179};
180
181static struct miscdevice ixp2000_wdt_miscdev =
182{
183 .minor = WATCHDOG_MINOR,
184 .name = "watchdog",
185 .fops = &ixp2000_wdt_fops,
186};
187
188static int __init ixp2000_wdt_init(void)
189{
190 if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) {
191 printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n");
192 return -EIO;
193 }
194
195 wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256;
196
197 return misc_register(&ixp2000_wdt_miscdev);
198}
199
200static void __exit ixp2000_wdt_exit(void)
201{
202 misc_deregister(&ixp2000_wdt_miscdev);
203}
204
205module_init(ixp2000_wdt_init);
206module_exit(ixp2000_wdt_exit);
207
208MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
209MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog");
210
211module_param(heartbeat, int, 0);
212MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
213
214module_param(nowayout, int, 0);
215MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
216
217MODULE_LICENSE("GPL");
218MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
219
diff --git a/drivers/watchdog/ixp4xx_wdt.c b/drivers/watchdog/ixp4xx_wdt.c
new file mode 100644
index 000000000000..5864bb865cfe
--- /dev/null
+++ b/drivers/watchdog/ixp4xx_wdt.c
@@ -0,0 +1,225 @@
1/*
2 * drivers/char/watchdog/ixp4xx_wdt.c
3 *
4 * Watchdog driver for Intel IXP4xx network processors
5 *
6 * Author: Deepak Saxena <dsaxena@plexity.net>
7 *
8 * Copyright 2004 (c) MontaVista, Software, Inc.
9 * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
10 *
11 * This file is licensed under the terms of the GNU General Public
12 * License version 2. This program is licensed "as is" without any
13 * warranty of any kind, whether express or implied.
14 */
15
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/types.h>
19#include <linux/kernel.h>
20#include <linux/fs.h>
21#include <linux/miscdevice.h>
22#include <linux/watchdog.h>
23#include <linux/init.h>
24#include <linux/bitops.h>
25
26#include <asm/hardware.h>
27#include <asm/uaccess.h>
28
29static int nowayout = WATCHDOG_NOWAYOUT;
30static int heartbeat = 60; /* (secs) Default is 1 minute */
31static unsigned long wdt_status;
32static unsigned long boot_status;
33
34#define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL)
35
36#define WDT_IN_USE 0
37#define WDT_OK_TO_CLOSE 1
38
39static void
40wdt_enable(void)
41{
42 *IXP4XX_OSWK = IXP4XX_WDT_KEY;
43 *IXP4XX_OSWE = 0;
44 *IXP4XX_OSWT = WDT_TICK_RATE * heartbeat;
45 *IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
46 *IXP4XX_OSWK = 0;
47}
48
49static void
50wdt_disable(void)
51{
52 *IXP4XX_OSWK = IXP4XX_WDT_KEY;
53 *IXP4XX_OSWE = 0;
54 *IXP4XX_OSWK = 0;
55}
56
57static int
58ixp4xx_wdt_open(struct inode *inode, struct file *file)
59{
60 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
61 return -EBUSY;
62
63 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
64
65 wdt_enable();
66
67 return nonseekable_open(inode, file);
68}
69
70static ssize_t
71ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
72{
73 if (len) {
74 if (!nowayout) {
75 size_t i;
76
77 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
78
79 for (i = 0; i != len; i++) {
80 char c;
81
82 if (get_user(c, data + i))
83 return -EFAULT;
84 if (c == 'V')
85 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
86 }
87 }
88 wdt_enable();
89 }
90
91 return len;
92}
93
94static struct watchdog_info ident = {
95 .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
96 WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
97 .identity = "IXP4xx Watchdog",
98};
99
100
101static int
102ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
103 unsigned long arg)
104{
105 int ret = -ENOTTY;
106 int time;
107
108 switch (cmd) {
109 case WDIOC_GETSUPPORT:
110 ret = copy_to_user((struct watchdog_info *)arg, &ident,
111 sizeof(ident)) ? -EFAULT : 0;
112 break;
113
114 case WDIOC_GETSTATUS:
115 ret = put_user(0, (int *)arg);
116 break;
117
118 case WDIOC_GETBOOTSTATUS:
119 ret = put_user(boot_status, (int *)arg);
120 break;
121
122 case WDIOC_SETTIMEOUT:
123 ret = get_user(time, (int *)arg);
124 if (ret)
125 break;
126
127 if (time <= 0 || time > 60) {
128 ret = -EINVAL;
129 break;
130 }
131
132 heartbeat = time;
133 wdt_enable();
134 /* Fall through */
135
136 case WDIOC_GETTIMEOUT:
137 ret = put_user(heartbeat, (int *)arg);
138 break;
139
140 case WDIOC_KEEPALIVE:
141 wdt_enable();
142 ret = 0;
143 break;
144 }
145 return ret;
146}
147
148static int
149ixp4xx_wdt_release(struct inode *inode, struct file *file)
150{
151 if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
152 wdt_disable();
153 } else {
154 printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
155 "timer will not stop\n");
156 }
157
158 clear_bit(WDT_IN_USE, &wdt_status);
159 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
160
161 return 0;
162}
163
164
165static const struct file_operations ixp4xx_wdt_fops =
166{
167 .owner = THIS_MODULE,
168 .llseek = no_llseek,
169 .write = ixp4xx_wdt_write,
170 .ioctl = ixp4xx_wdt_ioctl,
171 .open = ixp4xx_wdt_open,
172 .release = ixp4xx_wdt_release,
173};
174
175static struct miscdevice ixp4xx_wdt_miscdev =
176{
177 .minor = WATCHDOG_MINOR,
178 .name = "watchdog",
179 .fops = &ixp4xx_wdt_fops,
180};
181
182static int __init ixp4xx_wdt_init(void)
183{
184 int ret;
185 unsigned long processor_id;
186
187 asm("mrc p15, 0, %0, cr0, cr0, 0;" : "=r"(processor_id) :);
188 if (!(processor_id & 0xf) && !cpu_is_ixp46x()) {
189 printk("IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected - "
190 "watchdog disabled\n");
191
192 return -ENODEV;
193 }
194
195 ret = misc_register(&ixp4xx_wdt_miscdev);
196 if (ret == 0)
197 printk("IXP4xx Watchdog Timer: heartbeat %d sec\n", heartbeat);
198
199 boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
200 WDIOF_CARDRESET : 0;
201
202 return ret;
203}
204
205static void __exit ixp4xx_wdt_exit(void)
206{
207 misc_deregister(&ixp4xx_wdt_miscdev);
208}
209
210
211module_init(ixp4xx_wdt_init);
212module_exit(ixp4xx_wdt_exit);
213
214MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
215MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
216
217module_param(heartbeat, int, 0);
218MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
219
220module_param(nowayout, int, 0);
221MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
222
223MODULE_LICENSE("GPL");
224MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
225
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c
new file mode 100644
index 000000000000..7150fb945eaf
--- /dev/null
+++ b/drivers/watchdog/ks8695_wdt.c
@@ -0,0 +1,308 @@
1/*
2 * Watchdog driver for Kendin/Micrel KS8695.
3 *
4 * (C) 2007 Andrew Victor
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 version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/errno.h>
12#include <linux/fs.h>
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/miscdevice.h>
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/platform_device.h>
19#include <linux/types.h>
20#include <linux/watchdog.h>
21#include <asm/bitops.h>
22#include <asm/io.h>
23#include <asm/uaccess.h>
24#include <asm/arch/regs-timer.h>
25
26
27#define WDT_DEFAULT_TIME 5 /* seconds */
28#define WDT_MAX_TIME 171 /* seconds */
29
30static int wdt_time = WDT_DEFAULT_TIME;
31static int nowayout = WATCHDOG_NOWAYOUT;
32
33module_param(wdt_time, int, 0);
34MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")");
35
36#ifdef CONFIG_WATCHDOG_NOWAYOUT
37module_param(nowayout, int, 0);
38MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
39#endif
40
41
42static unsigned long ks8695wdt_busy;
43
44/* ......................................................................... */
45
46/*
47 * Disable the watchdog.
48 */
49static void inline ks8695_wdt_stop(void)
50{
51 unsigned long tmcon;
52
53 /* disable timer0 */
54 tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
55 __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
56}
57
58/*
59 * Enable and reset the watchdog.
60 */
61static void inline ks8695_wdt_start(void)
62{
63 unsigned long tmcon;
64 unsigned long tval = wdt_time * CLOCK_TICK_RATE;
65
66 /* disable timer0 */
67 tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
68 __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
69
70 /* program timer0 */
71 __raw_writel(tval | T0TC_WATCHDOG, KS8695_TMR_VA + KS8695_T0TC);
72
73 /* re-enable timer0 */
74 tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
75 __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
76}
77
78/*
79 * Reload the watchdog timer. (ie, pat the watchdog)
80 */
81static void inline ks8695_wdt_reload(void)
82{
83 unsigned long tmcon;
84
85 /* disable, then re-enable timer0 */
86 tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON);
87 __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
88 __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON);
89}
90
91/*
92 * Change the watchdog time interval.
93 */
94static int ks8695_wdt_settimeout(int new_time)
95{
96 /*
97 * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
98 *
99 * Since WDV is a 16-bit counter, the maximum period is
100 * 65536 / 0.256 = 256 seconds.
101 */
102 if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
103 return -EINVAL;
104
105 /* Set new watchdog time. It will be used when ks8695_wdt_start() is called. */
106 wdt_time = new_time;
107 return 0;
108}
109
110/* ......................................................................... */
111
112/*
113 * Watchdog device is opened, and watchdog starts running.
114 */
115static int ks8695_wdt_open(struct inode *inode, struct file *file)
116{
117 if (test_and_set_bit(0, &ks8695wdt_busy))
118 return -EBUSY;
119
120 ks8695_wdt_start();
121 return nonseekable_open(inode, file);
122}
123
124/*
125 * Close the watchdog device.
126 * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also
127 * disabled.
128 */
129static int ks8695_wdt_close(struct inode *inode, struct file *file)
130{
131 if (!nowayout)
132 ks8695_wdt_stop(); /* Disable the watchdog when file is closed */
133
134 clear_bit(0, &ks8695wdt_busy);
135 return 0;
136}
137
138static struct watchdog_info ks8695_wdt_info = {
139 .identity = "ks8695 watchdog",
140 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
141};
142
143/*
144 * Handle commands from user-space.
145 */
146static int ks8695_wdt_ioctl(struct inode *inode, struct file *file,
147 unsigned int cmd, unsigned long arg)
148{
149 void __user *argp = (void __user *)arg;
150 int __user *p = argp;
151 int new_value;
152
153 switch(cmd) {
154 case WDIOC_KEEPALIVE:
155 ks8695_wdt_reload(); /* pat the watchdog */
156 return 0;
157
158 case WDIOC_GETSUPPORT:
159 return copy_to_user(argp, &ks8695_wdt_info, sizeof(ks8695_wdt_info)) ? -EFAULT : 0;
160
161 case WDIOC_SETTIMEOUT:
162 if (get_user(new_value, p))
163 return -EFAULT;
164
165 if (ks8695_wdt_settimeout(new_value))
166 return -EINVAL;
167
168 /* Enable new time value */
169 ks8695_wdt_start();
170
171 /* Return current value */
172 return put_user(wdt_time, p);
173
174 case WDIOC_GETTIMEOUT:
175 return put_user(wdt_time, p);
176
177 case WDIOC_GETSTATUS:
178 case WDIOC_GETBOOTSTATUS:
179 return put_user(0, p);
180
181 case WDIOC_SETOPTIONS:
182 if (get_user(new_value, p))
183 return -EFAULT;
184
185 if (new_value & WDIOS_DISABLECARD)
186 ks8695_wdt_stop();
187 if (new_value & WDIOS_ENABLECARD)
188 ks8695_wdt_start();
189 return 0;
190
191 default:
192 return -ENOTTY;
193 }
194}
195
196/*
197 * Pat the watchdog whenever device is written to.
198 */
199static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
200{
201 ks8695_wdt_reload(); /* pat the watchdog */
202 return len;
203}
204
205/* ......................................................................... */
206
207static const struct file_operations ks8695wdt_fops = {
208 .owner = THIS_MODULE,
209 .llseek = no_llseek,
210 .ioctl = ks8695_wdt_ioctl,
211 .open = ks8695_wdt_open,
212 .release = ks8695_wdt_close,
213 .write = ks8695_wdt_write,
214};
215
216static struct miscdevice ks8695wdt_miscdev = {
217 .minor = WATCHDOG_MINOR,
218 .name = "watchdog",
219 .fops = &ks8695wdt_fops,
220};
221
222static int __init ks8695wdt_probe(struct platform_device *pdev)
223{
224 int res;
225
226 if (ks8695wdt_miscdev.parent)
227 return -EBUSY;
228 ks8695wdt_miscdev.parent = &pdev->dev;
229
230 res = misc_register(&ks8695wdt_miscdev);
231 if (res)
232 return res;
233
234 printk("KS8695 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : "");
235 return 0;
236}
237
238static int __exit ks8695wdt_remove(struct platform_device *pdev)
239{
240 int res;
241
242 res = misc_deregister(&ks8695wdt_miscdev);
243 if (!res)
244 ks8695wdt_miscdev.parent = NULL;
245
246 return res;
247}
248
249static void ks8695wdt_shutdown(struct platform_device *pdev)
250{
251 ks8695_wdt_stop();
252}
253
254#ifdef CONFIG_PM
255
256static int ks8695wdt_suspend(struct platform_device *pdev, pm_message_t message)
257{
258 ks8695_wdt_stop();
259 return 0;
260}
261
262static int ks8695wdt_resume(struct platform_device *pdev)
263{
264 if (ks8695wdt_busy)
265 ks8695_wdt_start();
266 return 0;
267}
268
269#else
270#define ks8695wdt_suspend NULL
271#define ks8695wdt_resume NULL
272#endif
273
274static struct platform_driver ks8695wdt_driver = {
275 .probe = ks8695wdt_probe,
276 .remove = __exit_p(ks8695wdt_remove),
277 .shutdown = ks8695wdt_shutdown,
278 .suspend = ks8695wdt_suspend,
279 .resume = ks8695wdt_resume,
280 .driver = {
281 .name = "ks8695_wdt",
282 .owner = THIS_MODULE,
283 },
284};
285
286static int __init ks8695_wdt_init(void)
287{
288 /* Check that the heartbeat value is within range; if not reset to the default */
289 if (ks8695_wdt_settimeout(wdt_time)) {
290 ks8695_wdt_settimeout(WDT_DEFAULT_TIME);
291 pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n", wdt_time, WDT_MAX_TIME);
292 }
293
294 return platform_driver_register(&ks8695wdt_driver);
295}
296
297static void __exit ks8695_wdt_exit(void)
298{
299 platform_driver_unregister(&ks8695wdt_driver);
300}
301
302module_init(ks8695_wdt_init);
303module_exit(ks8695_wdt_exit);
304
305MODULE_AUTHOR("Andrew Victor");
306MODULE_DESCRIPTION("Watchdog driver for KS8695");
307MODULE_LICENSE("GPL");
308MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/machzwd.c b/drivers/watchdog/machzwd.c
new file mode 100644
index 000000000000..6d35bb112a5f
--- /dev/null
+++ b/drivers/watchdog/machzwd.c
@@ -0,0 +1,489 @@
1/*
2 * MachZ ZF-Logic Watchdog Timer driver for Linux
3 *
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * The author does NOT admit liability nor provide warranty for
11 * any of this software. This material is provided "AS-IS" in
12 * the hope that it may be useful for others.
13 *
14 * Author: Fernando Fuganti <fuganti@conectiva.com.br>
15 *
16 * Based on sbc60xxwdt.c by Jakob Oestergaard
17 *
18 *
19 * We have two timers (wd#1, wd#2) driven by a 32 KHz clock with the
20 * following periods:
21 * wd#1 - 2 seconds;
22 * wd#2 - 7.2 ms;
23 * After the expiration of wd#1, it can generate a NMI, SCI, SMI, or
24 * a system RESET and it starts wd#2 that unconditionaly will RESET
25 * the system when the counter reaches zero.
26 *
27 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
28 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
29 */
30
31#include <linux/module.h>
32#include <linux/moduleparam.h>
33#include <linux/types.h>
34#include <linux/timer.h>
35#include <linux/jiffies.h>
36#include <linux/miscdevice.h>
37#include <linux/watchdog.h>
38#include <linux/fs.h>
39#include <linux/ioport.h>
40#include <linux/notifier.h>
41#include <linux/reboot.h>
42#include <linux/init.h>
43
44#include <asm/io.h>
45#include <asm/uaccess.h>
46#include <asm/system.h>
47
48/* ports */
49#define ZF_IOBASE 0x218
50#define INDEX 0x218
51#define DATA_B 0x219
52#define DATA_W 0x21A
53#define DATA_D 0x21A
54
55/* indexes */ /* size */
56#define ZFL_VERSION 0x02 /* 16 */
57#define CONTROL 0x10 /* 16 */
58#define STATUS 0x12 /* 8 */
59#define COUNTER_1 0x0C /* 16 */
60#define COUNTER_2 0x0E /* 8 */
61#define PULSE_LEN 0x0F /* 8 */
62
63/* controls */
64#define ENABLE_WD1 0x0001
65#define ENABLE_WD2 0x0002
66#define RESET_WD1 0x0010
67#define RESET_WD2 0x0020
68#define GEN_SCI 0x0100
69#define GEN_NMI 0x0200
70#define GEN_SMI 0x0400
71#define GEN_RESET 0x0800
72
73
74/* utilities */
75
76#define WD1 0
77#define WD2 1
78
79#define zf_writew(port, data) { outb(port, INDEX); outw(data, DATA_W); }
80#define zf_writeb(port, data) { outb(port, INDEX); outb(data, DATA_B); }
81#define zf_get_ZFL_version() zf_readw(ZFL_VERSION)
82
83
84static unsigned short zf_readw(unsigned char port)
85{
86 outb(port, INDEX);
87 return inw(DATA_W);
88}
89
90
91MODULE_AUTHOR("Fernando Fuganti <fuganti@conectiva.com.br>");
92MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver");
93MODULE_LICENSE("GPL");
94MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
95
96static int nowayout = WATCHDOG_NOWAYOUT;
97module_param(nowayout, int, 0);
98MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
99
100#define PFX "machzwd"
101
102static struct watchdog_info zf_info = {
103 .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
104 .firmware_version = 1,
105 .identity = "ZF-Logic watchdog",
106};
107
108
109/*
110 * action refers to action taken when watchdog resets
111 * 0 = GEN_RESET
112 * 1 = GEN_SMI
113 * 2 = GEN_NMI
114 * 3 = GEN_SCI
115 * defaults to GEN_RESET (0)
116 */
117static int action = 0;
118module_param(action, int, 0);
119MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*) 1 = SMI 2 = NMI 3 = SCI");
120
121static void zf_ping(unsigned long data);
122
123static int zf_action = GEN_RESET;
124static unsigned long zf_is_open;
125static char zf_expect_close;
126static spinlock_t zf_lock;
127static spinlock_t zf_port_lock;
128static DEFINE_TIMER(zf_timer, zf_ping, 0, 0);
129static unsigned long next_heartbeat = 0;
130
131
132/* timeout for user land heart beat (10 seconds) */
133#define ZF_USER_TIMEO (HZ*10)
134
135/* timeout for hardware watchdog (~500ms) */
136#define ZF_HW_TIMEO (HZ/2)
137
138/* number of ticks on WD#1 (driven by a 32KHz clock, 2s) */
139#define ZF_CTIMEOUT 0xffff
140
141#ifndef ZF_DEBUG
142# define dprintk(format, args...)
143#else
144# define dprintk(format, args...) printk(KERN_DEBUG PFX ":%s:%d: " format, __FUNCTION__, __LINE__ , ## args)
145#endif
146
147
148static inline void zf_set_status(unsigned char new)
149{
150 zf_writeb(STATUS, new);
151}
152
153
154/* CONTROL register functions */
155
156static inline unsigned short zf_get_control(void)
157{
158 return zf_readw(CONTROL);
159}
160
161static inline void zf_set_control(unsigned short new)
162{
163 zf_writew(CONTROL, new);
164}
165
166
167/* WD#? counter functions */
168/*
169 * Just set counter value
170 */
171
172static inline void zf_set_timer(unsigned short new, unsigned char n)
173{
174 switch(n){
175 case WD1:
176 zf_writew(COUNTER_1, new);
177 case WD2:
178 zf_writeb(COUNTER_2, new > 0xff ? 0xff : new);
179 default:
180 return;
181 }
182}
183
184/*
185 * stop hardware timer
186 */
187static void zf_timer_off(void)
188{
189 unsigned int ctrl_reg = 0;
190 unsigned long flags;
191
192 /* stop internal ping */
193 del_timer_sync(&zf_timer);
194
195 spin_lock_irqsave(&zf_port_lock, flags);
196 /* stop watchdog timer */
197 ctrl_reg = zf_get_control();
198 ctrl_reg |= (ENABLE_WD1|ENABLE_WD2); /* disable wd1 and wd2 */
199 ctrl_reg &= ~(ENABLE_WD1|ENABLE_WD2);
200 zf_set_control(ctrl_reg);
201 spin_unlock_irqrestore(&zf_port_lock, flags);
202
203 printk(KERN_INFO PFX ": Watchdog timer is now disabled\n");
204}
205
206
207/*
208 * start hardware timer
209 */
210static void zf_timer_on(void)
211{
212 unsigned int ctrl_reg = 0;
213 unsigned long flags;
214
215 spin_lock_irqsave(&zf_port_lock, flags);
216
217 zf_writeb(PULSE_LEN, 0xff);
218
219 zf_set_timer(ZF_CTIMEOUT, WD1);
220
221 /* user land ping */
222 next_heartbeat = jiffies + ZF_USER_TIMEO;
223
224 /* start the timer for internal ping */
225 mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
226
227 /* start watchdog timer */
228 ctrl_reg = zf_get_control();
229 ctrl_reg |= (ENABLE_WD1|zf_action);
230 zf_set_control(ctrl_reg);
231 spin_unlock_irqrestore(&zf_port_lock, flags);
232
233 printk(KERN_INFO PFX ": Watchdog timer is now enabled\n");
234}
235
236
237static void zf_ping(unsigned long data)
238{
239 unsigned int ctrl_reg = 0;
240 unsigned long flags;
241
242 zf_writeb(COUNTER_2, 0xff);
243
244 if(time_before(jiffies, next_heartbeat)){
245
246 dprintk("time_before: %ld\n", next_heartbeat - jiffies);
247
248 /*
249 * reset event is activated by transition from 0 to 1 on
250 * RESET_WD1 bit and we assume that it is already zero...
251 */
252
253 spin_lock_irqsave(&zf_port_lock, flags);
254 ctrl_reg = zf_get_control();
255 ctrl_reg |= RESET_WD1;
256 zf_set_control(ctrl_reg);
257
258 /* ...and nothing changes until here */
259 ctrl_reg &= ~(RESET_WD1);
260 zf_set_control(ctrl_reg);
261 spin_unlock_irqrestore(&zf_port_lock, flags);
262
263 mod_timer(&zf_timer, jiffies + ZF_HW_TIMEO);
264 }else{
265 printk(KERN_CRIT PFX ": I will reset your machine\n");
266 }
267}
268
269static ssize_t zf_write(struct file *file, const char __user *buf, size_t count,
270 loff_t *ppos)
271{
272 /* See if we got the magic character */
273 if(count){
274
275 /*
276 * no need to check for close confirmation
277 * no way to disable watchdog ;)
278 */
279 if (!nowayout) {
280 size_t ofs;
281
282 /*
283 * note: just in case someone wrote the magic character
284 * five months ago...
285 */
286 zf_expect_close = 0;
287
288 /* now scan */
289 for (ofs = 0; ofs != count; ofs++){
290 char c;
291 if (get_user(c, buf + ofs))
292 return -EFAULT;
293 if (c == 'V'){
294 zf_expect_close = 42;
295 dprintk("zf_expect_close = 42\n");
296 }
297 }
298 }
299
300 /*
301 * Well, anyhow someone wrote to us,
302 * we should return that favour
303 */
304 next_heartbeat = jiffies + ZF_USER_TIMEO;
305 dprintk("user ping at %ld\n", jiffies);
306
307 }
308
309 return count;
310}
311
312static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
313 unsigned long arg)
314{
315 void __user *argp = (void __user *)arg;
316 int __user *p = argp;
317 switch (cmd) {
318 case WDIOC_GETSUPPORT:
319 if (copy_to_user(argp, &zf_info, sizeof(zf_info)))
320 return -EFAULT;
321 break;
322
323 case WDIOC_GETSTATUS:
324 case WDIOC_GETBOOTSTATUS:
325 return put_user(0, p);
326
327 case WDIOC_KEEPALIVE:
328 zf_ping(0);
329 break;
330
331 default:
332 return -ENOTTY;
333 }
334
335 return 0;
336}
337
338static int zf_open(struct inode *inode, struct file *file)
339{
340 spin_lock(&zf_lock);
341 if(test_and_set_bit(0, &zf_is_open)) {
342 spin_unlock(&zf_lock);
343 return -EBUSY;
344 }
345
346 if (nowayout)
347 __module_get(THIS_MODULE);
348
349 spin_unlock(&zf_lock);
350
351 zf_timer_on();
352
353 return nonseekable_open(inode, file);
354}
355
356static int zf_close(struct inode *inode, struct file *file)
357{
358 if(zf_expect_close == 42){
359 zf_timer_off();
360 } else {
361 del_timer(&zf_timer);
362 printk(KERN_ERR PFX ": device file closed unexpectedly. Will not stop the WDT!\n");
363 }
364
365 spin_lock(&zf_lock);
366 clear_bit(0, &zf_is_open);
367 spin_unlock(&zf_lock);
368
369 zf_expect_close = 0;
370
371 return 0;
372}
373
374/*
375 * Notifier for system down
376 */
377
378static int zf_notify_sys(struct notifier_block *this, unsigned long code,
379 void *unused)
380{
381 if(code == SYS_DOWN || code == SYS_HALT){
382 zf_timer_off();
383 }
384
385 return NOTIFY_DONE;
386}
387
388
389
390
391static const struct file_operations zf_fops = {
392 .owner = THIS_MODULE,
393 .llseek = no_llseek,
394 .write = zf_write,
395 .ioctl = zf_ioctl,
396 .open = zf_open,
397 .release = zf_close,
398};
399
400static struct miscdevice zf_miscdev = {
401 .minor = WATCHDOG_MINOR,
402 .name = "watchdog",
403 .fops = &zf_fops,
404};
405
406
407/*
408 * The device needs to learn about soft shutdowns in order to
409 * turn the timebomb registers off.
410 */
411static struct notifier_block zf_notifier = {
412 .notifier_call = zf_notify_sys,
413};
414
415static void __init zf_show_action(int act)
416{
417 char *str[] = { "RESET", "SMI", "NMI", "SCI" };
418
419 printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]);
420}
421
422static int __init zf_init(void)
423{
424 int ret;
425
426 printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n");
427
428 ret = zf_get_ZFL_version();
429 if ((!ret) || (ret == 0xffff)) {
430 printk(KERN_WARNING PFX ": no ZF-Logic found\n");
431 return -ENODEV;
432 }
433
434 if((action <= 3) && (action >= 0)){
435 zf_action = zf_action>>action;
436 } else
437 action = 0;
438
439 zf_show_action(action);
440
441 spin_lock_init(&zf_lock);
442 spin_lock_init(&zf_port_lock);
443
444 if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
445 printk(KERN_ERR "cannot reserve I/O ports at %d\n",
446 ZF_IOBASE);
447 ret = -EBUSY;
448 goto no_region;
449 }
450
451 ret = register_reboot_notifier(&zf_notifier);
452 if(ret){
453 printk(KERN_ERR "can't register reboot notifier (err=%d)\n",
454 ret);
455 goto no_reboot;
456 }
457
458 ret = misc_register(&zf_miscdev);
459 if (ret){
460 printk(KERN_ERR "can't misc_register on minor=%d\n",
461 WATCHDOG_MINOR);
462 goto no_misc;
463 }
464
465 zf_set_status(0);
466 zf_set_control(0);
467
468 return 0;
469
470no_misc:
471 unregister_reboot_notifier(&zf_notifier);
472no_reboot:
473 release_region(ZF_IOBASE, 3);
474no_region:
475 return ret;
476}
477
478
479static void __exit zf_exit(void)
480{
481 zf_timer_off();
482
483 misc_deregister(&zf_miscdev);
484 unregister_reboot_notifier(&zf_notifier);
485 release_region(ZF_IOBASE, 3);
486}
487
488module_init(zf_init);
489module_exit(zf_exit);
diff --git a/drivers/watchdog/mixcomwd.c b/drivers/watchdog/mixcomwd.c
new file mode 100644
index 000000000000..1adf1d56027d
--- /dev/null
+++ b/drivers/watchdog/mixcomwd.c
@@ -0,0 +1,330 @@
1/*
2 * MixCom Watchdog: A Simple Hardware Watchdog Device
3 * Based on Softdog driver by Alan Cox and PC Watchdog driver by Ken Hollis
4 *
5 * Author: Gergely Madarasz <gorgo@itc.hu>
6 *
7 * Copyright (c) 1999 ITConsult-Pro Co. <info@itc.hu>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * Version 0.1 (99/04/15):
15 * - first version
16 *
17 * Version 0.2 (99/06/16):
18 * - added kernel timer watchdog ping after close
19 * since the hardware does not support watchdog shutdown
20 *
21 * Version 0.3 (99/06/21):
22 * - added WDIOC_GETSTATUS and WDIOC_GETSUPPORT ioctl calls
23 *
24 * Version 0.3.1 (99/06/22):
25 * - allow module removal while internal timer is active,
26 * print warning about probable reset
27 *
28 * Version 0.4 (99/11/15):
29 * - support for one more type board
30 *
31 * Version 0.5 (2001/12/14) Matt Domsch <Matt_Domsch@dell.com>
32 * - added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
33 *
34 * Version 0.6 (2002/04/12): Rob Radez <rob@osinvestor.com>
35 * - make mixcomwd_opened unsigned,
36 * removed lock_kernel/unlock_kernel from mixcomwd_release,
37 * modified ioctl a bit to conform to API
38 *
39 */
40
41#define VERSION "0.6"
42#define WATCHDOG_NAME "mixcomwd"
43#define PFX WATCHDOG_NAME ": "
44
45#include <linux/module.h>
46#include <linux/moduleparam.h>
47#include <linux/types.h>
48#include <linux/miscdevice.h>
49#include <linux/ioport.h>
50#include <linux/watchdog.h>
51#include <linux/fs.h>
52#include <linux/reboot.h>
53#include <linux/init.h>
54#include <linux/jiffies.h>
55#include <linux/timer.h>
56#include <asm/uaccess.h>
57#include <asm/io.h>
58
59/*
60 * We have two types of cards that can be probed:
61 * 1) The Mixcom cards: these cards can be found at addresses
62 * 0x180, 0x280, 0x380 with an additional offset of 0xc10.
63 * (Or 0xd90, 0xe90, 0xf90).
64 * 2) The FlashCOM cards: these cards can be set up at
65 * 0x300 -> 0x378, in 0x8 jumps with an offset of 0x04.
66 * (Or 0x304 -> 0x37c in 0x8 jumps).
67 * Each card has it's own ID.
68 */
69#define MIXCOM_ID 0x11
70#define FLASHCOM_ID 0x18
71static struct {
72 int ioport;
73 int id;
74} mixcomwd_io_info[] __devinitdata = {
75 /* The Mixcom cards */
76 {0x0d90, MIXCOM_ID},
77 {0x0e90, MIXCOM_ID},
78 {0x0f90, MIXCOM_ID},
79 /* The FlashCOM cards */
80 {0x0304, FLASHCOM_ID},
81 {0x030c, FLASHCOM_ID},
82 {0x0314, FLASHCOM_ID},
83 {0x031c, FLASHCOM_ID},
84 {0x0324, FLASHCOM_ID},
85 {0x032c, FLASHCOM_ID},
86 {0x0334, FLASHCOM_ID},
87 {0x033c, FLASHCOM_ID},
88 {0x0344, FLASHCOM_ID},
89 {0x034c, FLASHCOM_ID},
90 {0x0354, FLASHCOM_ID},
91 {0x035c, FLASHCOM_ID},
92 {0x0364, FLASHCOM_ID},
93 {0x036c, FLASHCOM_ID},
94 {0x0374, FLASHCOM_ID},
95 {0x037c, FLASHCOM_ID},
96 /* The end of the list */
97 {0x0000, 0},
98};
99
100static void mixcomwd_timerfun(unsigned long d);
101
102static unsigned long mixcomwd_opened; /* long req'd for setbit --RR */
103
104static int watchdog_port;
105static int mixcomwd_timer_alive;
106static DEFINE_TIMER(mixcomwd_timer, mixcomwd_timerfun, 0, 0);
107static char expect_close;
108
109static int nowayout = WATCHDOG_NOWAYOUT;
110module_param(nowayout, int, 0);
111MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
112
113static void mixcomwd_ping(void)
114{
115 outb_p(55,watchdog_port);
116 return;
117}
118
119static void mixcomwd_timerfun(unsigned long d)
120{
121 mixcomwd_ping();
122
123 mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
124}
125
126/*
127 * Allow only one person to hold it open
128 */
129
130static int mixcomwd_open(struct inode *inode, struct file *file)
131{
132 if(test_and_set_bit(0,&mixcomwd_opened)) {
133 return -EBUSY;
134 }
135 mixcomwd_ping();
136
137 if (nowayout) {
138 /*
139 * fops_get() code via open() has already done
140 * a try_module_get() so it is safe to do the
141 * __module_get().
142 */
143 __module_get(THIS_MODULE);
144 } else {
145 if(mixcomwd_timer_alive) {
146 del_timer(&mixcomwd_timer);
147 mixcomwd_timer_alive=0;
148 }
149 }
150 return nonseekable_open(inode, file);
151}
152
153static int mixcomwd_release(struct inode *inode, struct file *file)
154{
155 if (expect_close == 42) {
156 if(mixcomwd_timer_alive) {
157 printk(KERN_ERR PFX "release called while internal timer alive");
158 return -EBUSY;
159 }
160 mixcomwd_timer_alive=1;
161 mod_timer(&mixcomwd_timer, jiffies + 5 * HZ);
162 } else {
163 printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
164 }
165
166 clear_bit(0,&mixcomwd_opened);
167 expect_close=0;
168 return 0;
169}
170
171
172static ssize_t mixcomwd_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
173{
174 if(len)
175 {
176 if (!nowayout) {
177 size_t i;
178
179 /* In case it was set long ago */
180 expect_close = 0;
181
182 for (i = 0; i != len; i++) {
183 char c;
184 if (get_user(c, data + i))
185 return -EFAULT;
186 if (c == 'V')
187 expect_close = 42;
188 }
189 }
190 mixcomwd_ping();
191 }
192 return len;
193}
194
195static int mixcomwd_ioctl(struct inode *inode, struct file *file,
196 unsigned int cmd, unsigned long arg)
197{
198 void __user *argp = (void __user *)arg;
199 int __user *p = argp;
200 int status;
201 static struct watchdog_info ident = {
202 .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
203 .firmware_version = 1,
204 .identity = "MixCOM watchdog",
205 };
206
207 switch(cmd)
208 {
209 case WDIOC_GETSTATUS:
210 status=mixcomwd_opened;
211 if (!nowayout) {
212 status|=mixcomwd_timer_alive;
213 }
214 if (copy_to_user(p, &status, sizeof(int))) {
215 return -EFAULT;
216 }
217 break;
218 case WDIOC_GETBOOTSTATUS:
219 if (copy_to_user(p, &status, sizeof(int))) {
220 return -EFAULT;
221 }
222 break;
223 case WDIOC_GETSUPPORT:
224 if (copy_to_user(argp, &ident, sizeof(ident))) {
225 return -EFAULT;
226 }
227 break;
228 case WDIOC_KEEPALIVE:
229 mixcomwd_ping();
230 break;
231 default:
232 return -ENOTTY;
233 }
234 return 0;
235}
236
237static const struct file_operations mixcomwd_fops = {
238 .owner = THIS_MODULE,
239 .llseek = no_llseek,
240 .write = mixcomwd_write,
241 .ioctl = mixcomwd_ioctl,
242 .open = mixcomwd_open,
243 .release = mixcomwd_release,
244};
245
246static struct miscdevice mixcomwd_miscdev = {
247 .minor = WATCHDOG_MINOR,
248 .name = "watchdog",
249 .fops = &mixcomwd_fops,
250};
251
252static int __init checkcard(int port, int card_id)
253{
254 int id;
255
256 if (!request_region(port, 1, "MixCOM watchdog")) {
257 return 0;
258 }
259
260 id=inb_p(port);
261 if (card_id==MIXCOM_ID)
262 id &= 0x3f;
263
264 if (id!=card_id) {
265 release_region(port, 1);
266 return 0;
267 }
268 return 1;
269}
270
271static int __init mixcomwd_init(void)
272{
273 int i;
274 int ret;
275 int found=0;
276
277 for (i = 0; !found && mixcomwd_io_info[i].ioport != 0; i++) {
278 if (checkcard(mixcomwd_io_info[i].ioport,
279 mixcomwd_io_info[i].id)) {
280 found = 1;
281 watchdog_port = mixcomwd_io_info[i].ioport;
282 }
283 }
284
285 if (!found) {
286 printk(KERN_ERR PFX "No card detected, or port not available.\n");
287 return -ENODEV;
288 }
289
290 ret = misc_register(&mixcomwd_miscdev);
291 if (ret)
292 {
293 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
294 WATCHDOG_MINOR, ret);
295 goto error_misc_register_watchdog;
296 }
297
298 printk(KERN_INFO "MixCOM watchdog driver v%s, watchdog port at 0x%3x\n",
299 VERSION, watchdog_port);
300
301 return 0;
302
303error_misc_register_watchdog:
304 release_region(watchdog_port, 1);
305 watchdog_port = 0x0000;
306 return ret;
307}
308
309static void __exit mixcomwd_exit(void)
310{
311 if (!nowayout) {
312 if(mixcomwd_timer_alive) {
313 printk(KERN_WARNING PFX "I quit now, hardware will"
314 " probably reboot!\n");
315 del_timer_sync(&mixcomwd_timer);
316 mixcomwd_timer_alive=0;
317 }
318 }
319 misc_deregister(&mixcomwd_miscdev);
320 release_region(watchdog_port,1);
321}
322
323module_init(mixcomwd_init);
324module_exit(mixcomwd_exit);
325
326MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
327MODULE_DESCRIPTION("MixCom Watchdog driver");
328MODULE_VERSION(VERSION);
329MODULE_LICENSE("GPL");
330MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/mpc5200_wdt.c b/drivers/watchdog/mpc5200_wdt.c
new file mode 100644
index 000000000000..9cfb97576623
--- /dev/null
+++ b/drivers/watchdog/mpc5200_wdt.c
@@ -0,0 +1,286 @@
1#include <linux/init.h>
2#include <linux/module.h>
3#include <linux/miscdevice.h>
4#include <linux/watchdog.h>
5#include <linux/io.h>
6#include <linux/spinlock.h>
7#include <asm/of_platform.h>
8#include <asm/uaccess.h>
9#include <asm/mpc52xx.h>
10
11
12#define GPT_MODE_WDT (1<<15)
13#define GPT_MODE_CE (1<<12)
14#define GPT_MODE_MS_TIMER (0x4)
15
16
17struct mpc5200_wdt {
18 unsigned count; /* timer ticks before watchdog kicks in */
19 long ipb_freq;
20 struct miscdevice miscdev;
21 struct resource mem;
22 struct mpc52xx_gpt __iomem *regs;
23 spinlock_t io_lock;
24};
25
26/* is_active stores wether or not the /dev/watchdog device is opened */
27static unsigned long is_active;
28
29/* misc devices don't provide a way, to get back to 'dev' or 'miscdev' from
30 * file operations, which sucks. But there can be max 1 watchdog anyway, so...
31 */
32static struct mpc5200_wdt *wdt_global;
33
34
35/* helper to calculate timeout in timer counts */
36static void mpc5200_wdt_set_timeout(struct mpc5200_wdt *wdt, int timeout)
37{
38 /* use biggest prescaler of 64k */
39 wdt->count = (wdt->ipb_freq + 0xffff) / 0x10000 * timeout;
40
41 if (wdt->count > 0xffff)
42 wdt->count = 0xffff;
43}
44/* return timeout in seconds (calculated from timer count) */
45static int mpc5200_wdt_get_timeout(struct mpc5200_wdt *wdt)
46{
47 return wdt->count * 0x10000 / wdt->ipb_freq;
48}
49
50
51/* watchdog operations */
52static int mpc5200_wdt_start(struct mpc5200_wdt *wdt)
53{
54 spin_lock(&wdt->io_lock);
55 /* disable */
56 out_be32(&wdt->regs->mode, 0);
57 /* set timeout, with maximum prescaler */
58 out_be32(&wdt->regs->count, 0x0 | wdt->count);
59 /* enable watchdog */
60 out_be32(&wdt->regs->mode, GPT_MODE_CE | GPT_MODE_WDT | GPT_MODE_MS_TIMER);
61 spin_unlock(&wdt->io_lock);
62
63 return 0;
64}
65static int mpc5200_wdt_ping(struct mpc5200_wdt *wdt)
66{
67 spin_lock(&wdt->io_lock);
68 /* writing A5 to OCPW resets the watchdog */
69 out_be32(&wdt->regs->mode, 0xA5000000 | (0xffffff & in_be32(&wdt->regs->mode)));
70 spin_unlock(&wdt->io_lock);
71 return 0;
72}
73static int mpc5200_wdt_stop(struct mpc5200_wdt *wdt)
74{
75 spin_lock(&wdt->io_lock);
76 /* disable */
77 out_be32(&wdt->regs->mode, 0);
78 spin_unlock(&wdt->io_lock);
79 return 0;
80}
81
82
83/* file operations */
84static ssize_t mpc5200_wdt_write(struct file *file, const char __user *data,
85 size_t len, loff_t *ppos)
86{
87 struct mpc5200_wdt *wdt = file->private_data;
88 mpc5200_wdt_ping(wdt);
89 return 0;
90}
91static struct watchdog_info mpc5200_wdt_info = {
92 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
93 .identity = "mpc5200 watchdog on GPT0",
94};
95static int mpc5200_wdt_ioctl(struct inode *inode, struct file *file,
96 unsigned int cmd, unsigned long arg)
97{
98 struct mpc5200_wdt *wdt = file->private_data;
99 int __user *data = (int __user *)arg;
100 int timeout;
101 int ret = 0;
102
103 switch (cmd) {
104 case WDIOC_GETSUPPORT:
105 ret = copy_to_user(data, &mpc5200_wdt_info,
106 sizeof(mpc5200_wdt_info));
107 if (ret)
108 ret = -EFAULT;
109 break;
110
111 case WDIOC_GETSTATUS:
112 case WDIOC_GETBOOTSTATUS:
113 ret = put_user(0, data);
114 break;
115
116 case WDIOC_KEEPALIVE:
117 mpc5200_wdt_ping(wdt);
118 break;
119
120 case WDIOC_SETTIMEOUT:
121 ret = get_user(timeout, data);
122 if (ret)
123 break;
124 mpc5200_wdt_set_timeout(wdt, timeout);
125 mpc5200_wdt_start(wdt);
126 /* fall through and return the timeout */
127
128 case WDIOC_GETTIMEOUT:
129 timeout = mpc5200_wdt_get_timeout(wdt);
130 ret = put_user(timeout, data);
131 break;
132
133 default:
134 ret = -ENOTTY;
135 }
136 return ret;
137}
138static int mpc5200_wdt_open(struct inode *inode, struct file *file)
139{
140 /* /dev/watchdog can only be opened once */
141 if (test_and_set_bit(0, &is_active))
142 return -EBUSY;
143
144 /* Set and activate the watchdog */
145 mpc5200_wdt_set_timeout(wdt_global, 30);
146 mpc5200_wdt_start(wdt_global);
147 file->private_data = wdt_global;
148 return nonseekable_open(inode, file);
149}
150static int mpc5200_wdt_release(struct inode *inode, struct file *file)
151{
152#if WATCHDOG_NOWAYOUT == 0
153 struct mpc5200_wdt *wdt = file->private_data;
154 mpc5200_wdt_stop(wdt);
155 wdt->count = 0; /* == disabled */
156#endif
157 clear_bit(0, &is_active);
158 return 0;
159}
160
161static struct file_operations mpc5200_wdt_fops = {
162 .owner = THIS_MODULE,
163 .write = mpc5200_wdt_write,
164 .ioctl = mpc5200_wdt_ioctl,
165 .open = mpc5200_wdt_open,
166 .release = mpc5200_wdt_release,
167};
168
169/* module operations */
170static int mpc5200_wdt_probe(struct of_device *op, const struct of_device_id *match)
171{
172 struct mpc5200_wdt *wdt;
173 int err;
174 const void *has_wdt;
175 int size;
176
177 has_wdt = of_get_property(op->node, "has-wdt", NULL);
178 if (!has_wdt)
179 return -ENODEV;
180
181 wdt = kzalloc(sizeof(*wdt), GFP_KERNEL);
182 if (!wdt)
183 return -ENOMEM;
184
185 wdt->ipb_freq = mpc52xx_find_ipb_freq(op->node);
186
187 err = of_address_to_resource(op->node, 0, &wdt->mem);
188 if (err)
189 goto out_free;
190 size = wdt->mem.end - wdt->mem.start + 1;
191 if (!request_mem_region(wdt->mem.start, size, "mpc5200_wdt")) {
192 err = -ENODEV;
193 goto out_free;
194 }
195 wdt->regs = ioremap(wdt->mem.start, size);
196 if (!wdt->regs) {
197 err = -ENODEV;
198 goto out_release;
199 }
200
201 dev_set_drvdata(&op->dev, wdt);
202 spin_lock_init(&wdt->io_lock);
203
204 wdt->miscdev = (struct miscdevice) {
205 .minor = WATCHDOG_MINOR,
206 .name = "watchdog",
207 .fops = &mpc5200_wdt_fops,
208 .parent = &op->dev,
209 };
210 wdt_global = wdt;
211 err = misc_register(&wdt->miscdev);
212 if (!err)
213 return 0;
214
215 iounmap(wdt->regs);
216 out_release:
217 release_mem_region(wdt->mem.start, size);
218 out_free:
219 kfree(wdt);
220 return err;
221}
222
223static int mpc5200_wdt_remove(struct of_device *op)
224{
225 struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
226
227 mpc5200_wdt_stop(wdt);
228 misc_deregister(&wdt->miscdev);
229 iounmap(wdt->regs);
230 release_mem_region(wdt->mem.start, wdt->mem.end - wdt->mem.start + 1);
231 kfree(wdt);
232
233 return 0;
234}
235static int mpc5200_wdt_suspend(struct of_device *op, pm_message_t state)
236{
237 struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
238 mpc5200_wdt_stop(wdt);
239 return 0;
240}
241static int mpc5200_wdt_resume(struct of_device *op)
242{
243 struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
244 if (wdt->count)
245 mpc5200_wdt_start(wdt);
246 return 0;
247}
248static int mpc5200_wdt_shutdown(struct of_device *op)
249{
250 struct mpc5200_wdt *wdt = dev_get_drvdata(&op->dev);
251 mpc5200_wdt_stop(wdt);
252 return 0;
253}
254
255static struct of_device_id mpc5200_wdt_match[] = {
256 { .compatible = "mpc5200-gpt", },
257 {},
258};
259static struct of_platform_driver mpc5200_wdt_driver = {
260 .owner = THIS_MODULE,
261 .name = "mpc5200-gpt-wdt",
262 .match_table = mpc5200_wdt_match,
263 .probe = mpc5200_wdt_probe,
264 .remove = mpc5200_wdt_remove,
265 .suspend = mpc5200_wdt_suspend,
266 .resume = mpc5200_wdt_resume,
267 .shutdown = mpc5200_wdt_shutdown,
268};
269
270
271static int __init mpc5200_wdt_init(void)
272{
273 return of_register_platform_driver(&mpc5200_wdt_driver);
274}
275
276static void __exit mpc5200_wdt_exit(void)
277{
278 of_unregister_platform_driver(&mpc5200_wdt_driver);
279}
280
281module_init(mpc5200_wdt_init);
282module_exit(mpc5200_wdt_exit);
283
284MODULE_AUTHOR("Domen Puncer <domen.puncer@telargo.com>");
285MODULE_LICENSE("Dual BSD/GPL");
286MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/mpc83xx_wdt.c b/drivers/watchdog/mpc83xx_wdt.c
new file mode 100644
index 000000000000..a0bf95fb9763
--- /dev/null
+++ b/drivers/watchdog/mpc83xx_wdt.c
@@ -0,0 +1,231 @@
1/*
2 * mpc83xx_wdt.c - MPC83xx watchdog userspace interface
3 *
4 * Authors: Dave Updegraff <dave@cray.org>
5 * Kumar Gala <galak@kernel.crashing.org>
6 * Attribution: from 83xx_wst: Florian Schirmer <jolt@tuxbox.org>
7 * ..and from sc520_wdt
8 *
9 * Note: it appears that you can only actually ENABLE or DISABLE the thing
10 * once after POR. Once enabled, you cannot disable, and vice versa.
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 */
17
18#include <linux/fs.h>
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/miscdevice.h>
22#include <linux/platform_device.h>
23#include <linux/module.h>
24#include <linux/watchdog.h>
25#include <asm/io.h>
26#include <asm/uaccess.h>
27
28struct mpc83xx_wdt {
29 __be32 res0;
30 __be32 swcrr; /* System watchdog control register */
31#define SWCRR_SWTC 0xFFFF0000 /* Software Watchdog Time Count. */
32#define SWCRR_SWEN 0x00000004 /* Watchdog Enable bit. */
33#define SWCRR_SWRI 0x00000002 /* Software Watchdog Reset/Interrupt Select bit.*/
34#define SWCRR_SWPR 0x00000001 /* Software Watchdog Counter Prescale bit. */
35 __be32 swcnr; /* System watchdog count register */
36 u8 res1[2];
37 __be16 swsrr; /* System watchdog service register */
38 u8 res2[0xF0];
39};
40
41static struct mpc83xx_wdt __iomem *wd_base;
42
43static u16 timeout = 0xffff;
44module_param(timeout, ushort, 0);
45MODULE_PARM_DESC(timeout, "Watchdog timeout in ticks. (0<timeout<65536, default=65535");
46
47static int reset = 1;
48module_param(reset, bool, 0);
49MODULE_PARM_DESC(reset, "Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset");
50
51/*
52 * We always prescale, but if someone really doesn't want to they can set this
53 * to 0
54 */
55static int prescale = 1;
56static unsigned int timeout_sec;
57
58static unsigned long wdt_is_open;
59static spinlock_t wdt_spinlock;
60
61static void mpc83xx_wdt_keepalive(void)
62{
63 /* Ping the WDT */
64 spin_lock(&wdt_spinlock);
65 out_be16(&wd_base->swsrr, 0x556c);
66 out_be16(&wd_base->swsrr, 0xaa39);
67 spin_unlock(&wdt_spinlock);
68}
69
70static ssize_t mpc83xx_wdt_write(struct file *file, const char __user *buf,
71 size_t count, loff_t *ppos)
72{
73 if (count)
74 mpc83xx_wdt_keepalive();
75 return count;
76}
77
78static int mpc83xx_wdt_open(struct inode *inode, struct file *file)
79{
80 u32 tmp = SWCRR_SWEN;
81 if (test_and_set_bit(0, &wdt_is_open))
82 return -EBUSY;
83
84 /* Once we start the watchdog we can't stop it */
85 __module_get(THIS_MODULE);
86
87 /* Good, fire up the show */
88 if (prescale)
89 tmp |= SWCRR_SWPR;
90 if (reset)
91 tmp |= SWCRR_SWRI;
92
93 tmp |= timeout << 16;
94
95 out_be32(&wd_base->swcrr, tmp);
96
97 return nonseekable_open(inode, file);
98}
99
100static int mpc83xx_wdt_release(struct inode *inode, struct file *file)
101{
102 printk(KERN_CRIT "Unexpected close, not stopping watchdog!\n");
103 mpc83xx_wdt_keepalive();
104 clear_bit(0, &wdt_is_open);
105 return 0;
106}
107
108static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
109 unsigned int cmd, unsigned long arg)
110{
111 void __user *argp = (void __user *)arg;
112 int __user *p = argp;
113 static struct watchdog_info ident = {
114 .options = WDIOF_KEEPALIVEPING,
115 .firmware_version = 1,
116 .identity = "MPC83xx",
117 };
118
119 switch (cmd) {
120 case WDIOC_GETSUPPORT:
121 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
122 case WDIOC_GETSTATUS:
123 case WDIOC_GETBOOTSTATUS:
124 return put_user(0, p);
125 case WDIOC_KEEPALIVE:
126 mpc83xx_wdt_keepalive();
127 return 0;
128 case WDIOC_GETTIMEOUT:
129 return put_user(timeout_sec, p);
130 default:
131 return -ENOTTY;
132 }
133}
134
135static const struct file_operations mpc83xx_wdt_fops = {
136 .owner = THIS_MODULE,
137 .llseek = no_llseek,
138 .write = mpc83xx_wdt_write,
139 .ioctl = mpc83xx_wdt_ioctl,
140 .open = mpc83xx_wdt_open,
141 .release = mpc83xx_wdt_release,
142};
143
144static struct miscdevice mpc83xx_wdt_miscdev = {
145 .minor = WATCHDOG_MINOR,
146 .name = "watchdog",
147 .fops = &mpc83xx_wdt_fops,
148};
149
150static int __devinit mpc83xx_wdt_probe(struct platform_device *dev)
151{
152 struct resource *r;
153 int ret;
154 unsigned int *freq = dev->dev.platform_data;
155
156 /* get a pointer to the register memory */
157 r = platform_get_resource(dev, IORESOURCE_MEM, 0);
158
159 if (!r) {
160 ret = -ENODEV;
161 goto err_out;
162 }
163
164 wd_base = ioremap(r->start, sizeof (struct mpc83xx_wdt));
165
166 if (wd_base == NULL) {
167 ret = -ENOMEM;
168 goto err_out;
169 }
170
171 ret = misc_register(&mpc83xx_wdt_miscdev);
172 if (ret) {
173 printk(KERN_ERR "cannot register miscdev on minor=%d "
174 "(err=%d)\n",
175 WATCHDOG_MINOR, ret);
176 goto err_unmap;
177 }
178
179 /* Calculate the timeout in seconds */
180 if (prescale)
181 timeout_sec = (timeout * 0x10000) / (*freq);
182 else
183 timeout_sec = timeout / (*freq);
184
185 printk(KERN_INFO "WDT driver for MPC83xx initialized. "
186 "mode:%s timeout=%d (%d seconds)\n",
187 reset ? "reset":"interrupt", timeout, timeout_sec);
188
189 spin_lock_init(&wdt_spinlock);
190
191 return 0;
192
193err_unmap:
194 iounmap(wd_base);
195err_out:
196 return ret;
197}
198
199static int __devexit mpc83xx_wdt_remove(struct platform_device *dev)
200{
201 misc_deregister(&mpc83xx_wdt_miscdev);
202 iounmap(wd_base);
203
204 return 0;
205}
206
207static struct platform_driver mpc83xx_wdt_driver = {
208 .probe = mpc83xx_wdt_probe,
209 .remove = __devexit_p(mpc83xx_wdt_remove),
210 .driver = {
211 .name = "mpc83xx_wdt",
212 },
213};
214
215static int __init mpc83xx_wdt_init(void)
216{
217 return platform_driver_register(&mpc83xx_wdt_driver);
218}
219
220static void __exit mpc83xx_wdt_exit(void)
221{
222 platform_driver_unregister(&mpc83xx_wdt_driver);
223}
224
225module_init(mpc83xx_wdt_init);
226module_exit(mpc83xx_wdt_exit);
227
228MODULE_AUTHOR("Dave Updegraff, Kumar Gala");
229MODULE_DESCRIPTION("Driver for watchdog timer in MPC83xx uProcessor");
230MODULE_LICENSE("GPL");
231MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/mpc8xx_wdt.c b/drivers/watchdog/mpc8xx_wdt.c
new file mode 100644
index 000000000000..85b5734403a5
--- /dev/null
+++ b/drivers/watchdog/mpc8xx_wdt.c
@@ -0,0 +1,169 @@
1/*
2 * mpc8xx_wdt.c - MPC8xx watchdog userspace interface
3 *
4 * Author: Florian Schirmer <jolt@tuxbox.org>
5 *
6 * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
10 */
11
12#include <linux/fs.h>
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/miscdevice.h>
16#include <linux/module.h>
17#include <linux/watchdog.h>
18#include <asm/8xx_immap.h>
19#include <asm/uaccess.h>
20#include <asm/io.h>
21#include <syslib/m8xx_wdt.h>
22
23static unsigned long wdt_opened;
24static int wdt_status;
25
26static void mpc8xx_wdt_handler_disable(void)
27{
28 volatile uint __iomem *piscr;
29 piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
30
31 if (!m8xx_has_internal_rtc)
32 m8xx_wdt_stop_timer();
33 else
34 out_be32(piscr, in_be32(piscr) & ~(PISCR_PIE | PISCR_PTE));
35
36 printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler deactivated\n");
37}
38
39static void mpc8xx_wdt_handler_enable(void)
40{
41 volatile uint __iomem *piscr;
42 piscr = (uint *)&((immap_t*)IMAP_ADDR)->im_sit.sit_piscr;
43
44 if (!m8xx_has_internal_rtc)
45 m8xx_wdt_install_timer();
46 else
47 out_be32(piscr, in_be32(piscr) | PISCR_PIE | PISCR_PTE);
48
49 printk(KERN_NOTICE "mpc8xx_wdt: keep-alive handler activated\n");
50}
51
52static int mpc8xx_wdt_open(struct inode *inode, struct file *file)
53{
54 if (test_and_set_bit(0, &wdt_opened))
55 return -EBUSY;
56
57 m8xx_wdt_reset();
58 mpc8xx_wdt_handler_disable();
59
60 return nonseekable_open(inode, file);
61}
62
63static int mpc8xx_wdt_release(struct inode *inode, struct file *file)
64{
65 m8xx_wdt_reset();
66
67#if !defined(CONFIG_WATCHDOG_NOWAYOUT)
68 mpc8xx_wdt_handler_enable();
69#endif
70
71 clear_bit(0, &wdt_opened);
72
73 return 0;
74}
75
76static ssize_t mpc8xx_wdt_write(struct file *file, const char *data, size_t len,
77 loff_t * ppos)
78{
79 if (len)
80 m8xx_wdt_reset();
81
82 return len;
83}
84
85static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
86 unsigned int cmd, unsigned long arg)
87{
88 int timeout;
89 static struct watchdog_info info = {
90 .options = WDIOF_KEEPALIVEPING,
91 .firmware_version = 0,
92 .identity = "MPC8xx watchdog",
93 };
94
95 switch (cmd) {
96 case WDIOC_GETSUPPORT:
97 if (copy_to_user((void *)arg, &info, sizeof(info)))
98 return -EFAULT;
99 break;
100
101 case WDIOC_GETSTATUS:
102 case WDIOC_GETBOOTSTATUS:
103 if (put_user(wdt_status, (int *)arg))
104 return -EFAULT;
105 wdt_status &= ~WDIOF_KEEPALIVEPING;
106 break;
107
108 case WDIOC_GETTEMP:
109 return -EOPNOTSUPP;
110
111 case WDIOC_SETOPTIONS:
112 return -EOPNOTSUPP;
113
114 case WDIOC_KEEPALIVE:
115 m8xx_wdt_reset();
116 wdt_status |= WDIOF_KEEPALIVEPING;
117 break;
118
119 case WDIOC_SETTIMEOUT:
120 return -EOPNOTSUPP;
121
122 case WDIOC_GETTIMEOUT:
123 timeout = m8xx_wdt_get_timeout();
124 if (put_user(timeout, (int *)arg))
125 return -EFAULT;
126 break;
127
128 default:
129 return -ENOTTY;
130 }
131
132 return 0;
133}
134
135static const struct file_operations mpc8xx_wdt_fops = {
136 .owner = THIS_MODULE,
137 .llseek = no_llseek,
138 .write = mpc8xx_wdt_write,
139 .ioctl = mpc8xx_wdt_ioctl,
140 .open = mpc8xx_wdt_open,
141 .release = mpc8xx_wdt_release,
142};
143
144static struct miscdevice mpc8xx_wdt_miscdev = {
145 .minor = WATCHDOG_MINOR,
146 .name = "watchdog",
147 .fops = &mpc8xx_wdt_fops,
148};
149
150static int __init mpc8xx_wdt_init(void)
151{
152 return misc_register(&mpc8xx_wdt_miscdev);
153}
154
155static void __exit mpc8xx_wdt_exit(void)
156{
157 misc_deregister(&mpc8xx_wdt_miscdev);
158
159 m8xx_wdt_reset();
160 mpc8xx_wdt_handler_enable();
161}
162
163module_init(mpc8xx_wdt_init);
164module_exit(mpc8xx_wdt_exit);
165
166MODULE_AUTHOR("Florian Schirmer <jolt@tuxbox.org>");
167MODULE_DESCRIPTION("MPC8xx watchdog driver");
168MODULE_LICENSE("GPL");
169MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
new file mode 100644
index 000000000000..0d2b27735419
--- /dev/null
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -0,0 +1,435 @@
1/*
2 * Watchdog driver for the mpcore watchdog timer
3 *
4 * (c) Copyright 2004 ARM Limited
5 *
6 * Based on the SoftDog driver:
7 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
8 * http://www.redhat.com
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
14 *
15 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
16 * warranty for any of this software. This material is provided
17 * "AS-IS" and at no charge.
18 *
19 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
20 *
21 */
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/types.h>
25#include <linux/miscdevice.h>
26#include <linux/watchdog.h>
27#include <linux/fs.h>
28#include <linux/reboot.h>
29#include <linux/init.h>
30#include <linux/interrupt.h>
31#include <linux/platform_device.h>
32
33#include <asm/hardware/arm_twd.h>
34#include <asm/uaccess.h>
35
36struct mpcore_wdt {
37 unsigned long timer_alive;
38 struct device *dev;
39 void __iomem *base;
40 int irq;
41 unsigned int perturb;
42 char expect_close;
43};
44
45static struct platform_device *mpcore_wdt_dev;
46
47extern unsigned int mpcore_timer_rate;
48
49#define TIMER_MARGIN 60
50static int mpcore_margin = TIMER_MARGIN;
51module_param(mpcore_margin, int, 0);
52MODULE_PARM_DESC(mpcore_margin, "MPcore timer margin in seconds. (0<mpcore_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")");
53
54static int nowayout = WATCHDOG_NOWAYOUT;
55module_param(nowayout, int, 0);
56MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
57
58#define ONLY_TESTING 0
59static int mpcore_noboot = ONLY_TESTING;
60module_param(mpcore_noboot, int, 0);
61MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, set to 1 to ignore reboots, 0 to reboot (default=" __MODULE_STRING(ONLY_TESTING) ")");
62
63/*
64 * This is the interrupt handler. Note that we only use this
65 * in testing mode, so don't actually do a reboot here.
66 */
67static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
68{
69 struct mpcore_wdt *wdt = arg;
70
71 /* Check it really was our interrupt */
72 if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
73 dev_printk(KERN_CRIT, wdt->dev, "Triggered - Reboot ignored.\n");
74
75 /* Clear the interrupt on the watchdog */
76 writel(1, wdt->base + TWD_WDOG_INTSTAT);
77
78 return IRQ_HANDLED;
79 }
80
81 return IRQ_NONE;
82}
83
84/*
85 * mpcore_wdt_keepalive - reload the timer
86 *
87 * Note that the spec says a DIFFERENT value must be written to the reload
88 * register each time. The "perturb" variable deals with this by adding 1
89 * to the count every other time the function is called.
90 */
91static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt)
92{
93 unsigned int count;
94
95 /* Assume prescale is set to 256 */
96 count = (mpcore_timer_rate / 256) * mpcore_margin;
97
98 /* Reload the counter */
99 writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD);
100
101 wdt->perturb = wdt->perturb ? 0 : 1;
102}
103
104static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
105{
106 writel(0x12345678, wdt->base + TWD_WDOG_DISABLE);
107 writel(0x87654321, wdt->base + TWD_WDOG_DISABLE);
108 writel(0x0, wdt->base + TWD_WDOG_CONTROL);
109}
110
111static void mpcore_wdt_start(struct mpcore_wdt *wdt)
112{
113 dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
114
115 /* This loads the count register but does NOT start the count yet */
116 mpcore_wdt_keepalive(wdt);
117
118 if (mpcore_noboot) {
119 /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */
120 writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL);
121 } else {
122 /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */
123 writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL);
124 }
125}
126
127static int mpcore_wdt_set_heartbeat(int t)
128{
129 if (t < 0x0001 || t > 0xFFFF)
130 return -EINVAL;
131
132 mpcore_margin = t;
133 return 0;
134}
135
136/*
137 * /dev/watchdog handling
138 */
139static int mpcore_wdt_open(struct inode *inode, struct file *file)
140{
141 struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_dev);
142
143 if (test_and_set_bit(0, &wdt->timer_alive))
144 return -EBUSY;
145
146 if (nowayout)
147 __module_get(THIS_MODULE);
148
149 file->private_data = wdt;
150
151 /*
152 * Activate timer
153 */
154 mpcore_wdt_start(wdt);
155
156 return nonseekable_open(inode, file);
157}
158
159static int mpcore_wdt_release(struct inode *inode, struct file *file)
160{
161 struct mpcore_wdt *wdt = file->private_data;
162
163 /*
164 * Shut off the timer.
165 * Lock it in if it's a module and we set nowayout
166 */
167 if (wdt->expect_close == 42) {
168 mpcore_wdt_stop(wdt);
169 } else {
170 dev_printk(KERN_CRIT, wdt->dev, "unexpected close, not stopping watchdog!\n");
171 mpcore_wdt_keepalive(wdt);
172 }
173 clear_bit(0, &wdt->timer_alive);
174 wdt->expect_close = 0;
175 return 0;
176}
177
178static ssize_t mpcore_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
179{
180 struct mpcore_wdt *wdt = file->private_data;
181
182 /*
183 * Refresh the timer.
184 */
185 if (len) {
186 if (!nowayout) {
187 size_t i;
188
189 /* In case it was set long ago */
190 wdt->expect_close = 0;
191
192 for (i = 0; i != len; i++) {
193 char c;
194
195 if (get_user(c, data + i))
196 return -EFAULT;
197 if (c == 'V')
198 wdt->expect_close = 42;
199 }
200 }
201 mpcore_wdt_keepalive(wdt);
202 }
203 return len;
204}
205
206static struct watchdog_info ident = {
207 .options = WDIOF_SETTIMEOUT |
208 WDIOF_KEEPALIVEPING |
209 WDIOF_MAGICCLOSE,
210 .identity = "MPcore Watchdog",
211};
212
213static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
214 unsigned int cmd, unsigned long arg)
215{
216 struct mpcore_wdt *wdt = file->private_data;
217 int ret;
218 union {
219 struct watchdog_info ident;
220 int i;
221 } uarg;
222
223 if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
224 return -ENOTTY;
225
226 if (_IOC_DIR(cmd) & _IOC_WRITE) {
227 ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
228 if (ret)
229 return -EFAULT;
230 }
231
232 switch (cmd) {
233 case WDIOC_GETSUPPORT:
234 uarg.ident = ident;
235 ret = 0;
236 break;
237
238 case WDIOC_SETOPTIONS:
239 ret = -EINVAL;
240 if (uarg.i & WDIOS_DISABLECARD) {
241 mpcore_wdt_stop(wdt);
242 ret = 0;
243 }
244 if (uarg.i & WDIOS_ENABLECARD) {
245 mpcore_wdt_start(wdt);
246 ret = 0;
247 }
248 break;
249
250 case WDIOC_GETSTATUS:
251 case WDIOC_GETBOOTSTATUS:
252 uarg.i = 0;
253 ret = 0;
254 break;
255
256 case WDIOC_KEEPALIVE:
257 mpcore_wdt_keepalive(wdt);
258 ret = 0;
259 break;
260
261 case WDIOC_SETTIMEOUT:
262 ret = mpcore_wdt_set_heartbeat(uarg.i);
263 if (ret)
264 break;
265
266 mpcore_wdt_keepalive(wdt);
267 /* Fall */
268 case WDIOC_GETTIMEOUT:
269 uarg.i = mpcore_margin;
270 ret = 0;
271 break;
272
273 default:
274 return -ENOTTY;
275 }
276
277 if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
278 ret = copy_to_user((void __user *)arg, &uarg, _IOC_SIZE(cmd));
279 if (ret)
280 ret = -EFAULT;
281 }
282 return ret;
283}
284
285/*
286 * System shutdown handler. Turn off the watchdog if we're
287 * restarting or halting the system.
288 */
289static void mpcore_wdt_shutdown(struct platform_device *dev)
290{
291 struct mpcore_wdt *wdt = platform_get_drvdata(dev);
292
293 if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT)
294 mpcore_wdt_stop(wdt);
295}
296
297/*
298 * Kernel Interfaces
299 */
300static const struct file_operations mpcore_wdt_fops = {
301 .owner = THIS_MODULE,
302 .llseek = no_llseek,
303 .write = mpcore_wdt_write,
304 .ioctl = mpcore_wdt_ioctl,
305 .open = mpcore_wdt_open,
306 .release = mpcore_wdt_release,
307};
308
309static struct miscdevice mpcore_wdt_miscdev = {
310 .minor = WATCHDOG_MINOR,
311 .name = "watchdog",
312 .fops = &mpcore_wdt_fops,
313};
314
315static int __devinit mpcore_wdt_probe(struct platform_device *dev)
316{
317 struct mpcore_wdt *wdt;
318 struct resource *res;
319 int ret;
320
321 /* We only accept one device, and it must have an id of -1 */
322 if (dev->id != -1)
323 return -ENODEV;
324
325 res = platform_get_resource(dev, IORESOURCE_MEM, 0);
326 if (!res) {
327 ret = -ENODEV;
328 goto err_out;
329 }
330
331 wdt = kzalloc(sizeof(struct mpcore_wdt), GFP_KERNEL);
332 if (!wdt) {
333 ret = -ENOMEM;
334 goto err_out;
335 }
336
337 wdt->dev = &dev->dev;
338 wdt->irq = platform_get_irq(dev, 0);
339 if (wdt->irq < 0) {
340 ret = -ENXIO;
341 goto err_free;
342 }
343 wdt->base = ioremap(res->start, res->end - res->start + 1);
344 if (!wdt->base) {
345 ret = -ENOMEM;
346 goto err_free;
347 }
348
349 mpcore_wdt_miscdev.parent = &dev->dev;
350 ret = misc_register(&mpcore_wdt_miscdev);
351 if (ret) {
352 dev_printk(KERN_ERR, _dev, "cannot register miscdev on minor=%d (err=%d)\n",
353 WATCHDOG_MINOR, ret);
354 goto err_misc;
355 }
356
357 ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED, "mpcore_wdt", wdt);
358 if (ret) {
359 dev_printk(KERN_ERR, _dev, "cannot register IRQ%d for watchdog\n", wdt->irq);
360 goto err_irq;
361 }
362
363 mpcore_wdt_stop(wdt);
364 platform_set_drvdata(&dev->dev, wdt);
365 mpcore_wdt_dev = dev;
366
367 return 0;
368
369 err_irq:
370 misc_deregister(&mpcore_wdt_miscdev);
371 err_misc:
372 iounmap(wdt->base);
373 err_free:
374 kfree(wdt);
375 err_out:
376 return ret;
377}
378
379static int __devexit mpcore_wdt_remove(struct platform_device *dev)
380{
381 struct mpcore_wdt *wdt = platform_get_drvdata(dev);
382
383 platform_set_drvdata(dev, NULL);
384
385 misc_deregister(&mpcore_wdt_miscdev);
386
387 mpcore_wdt_dev = NULL;
388
389 free_irq(wdt->irq, wdt);
390 iounmap(wdt->base);
391 kfree(wdt);
392 return 0;
393}
394
395static struct platform_driver mpcore_wdt_driver = {
396 .probe = mpcore_wdt_probe,
397 .remove = __devexit_p(mpcore_wdt_remove),
398 .shutdown = mpcore_wdt_shutdown,
399 .driver = {
400 .owner = THIS_MODULE,
401 .name = "mpcore_wdt",
402 },
403};
404
405static char banner[] __initdata = KERN_INFO "MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n";
406
407static int __init mpcore_wdt_init(void)
408{
409 /*
410 * Check that the margin value is within it's range;
411 * if not reset to the default
412 */
413 if (mpcore_wdt_set_heartbeat(mpcore_margin)) {
414 mpcore_wdt_set_heartbeat(TIMER_MARGIN);
415 printk(KERN_INFO "mpcore_margin value must be 0<mpcore_margin<65536, using %d\n",
416 TIMER_MARGIN);
417 }
418
419 printk(banner, mpcore_noboot, mpcore_margin, nowayout);
420
421 return platform_driver_register(&mpcore_wdt_driver);
422}
423
424static void __exit mpcore_wdt_exit(void)
425{
426 platform_driver_unregister(&mpcore_wdt_driver);
427}
428
429module_init(mpcore_wdt_init);
430module_exit(mpcore_wdt_exit);
431
432MODULE_AUTHOR("ARM Limited");
433MODULE_DESCRIPTION("MPcore Watchdog Device Driver");
434MODULE_LICENSE("GPL");
435MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c
new file mode 100644
index 000000000000..dcfd401a7ad7
--- /dev/null
+++ b/drivers/watchdog/mtx-1_wdt.c
@@ -0,0 +1,239 @@
1/*
2 * Driver for the MTX-1 Watchdog.
3 *
4 * (C) Copyright 2005 4G Systems <info@4g-systems.biz>, All Rights Reserved.
5 * http://www.4g-systems.biz
6 *
7 * (C) Copyright 2007 OpenWrt.org, Florian Fainelli <florian@openwrt.org>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * Neither Michael Stickel nor 4G Systems admit liability nor provide
15 * warranty for any of this software. This material is provided
16 * "AS-IS" and at no charge.
17 *
18 * (c) Copyright 2005 4G Systems <info@4g-systems.biz>
19 *
20 * Release 0.01.
21 * Author: Michael Stickel michael.stickel@4g-systems.biz
22 *
23 * Release 0.02.
24 * Author: Florian Fainelli florian@openwrt.org
25 * use the Linux watchdog/timer APIs
26 *
27 * The Watchdog is configured to reset the MTX-1
28 * if it is not triggered for 100 seconds.
29 * It should not be triggered more often than 1.6 seconds.
30 *
31 * A timer triggers the watchdog every 5 seconds, until
32 * it is opened for the first time. After the first open
33 * it MUST be triggered every 2..95 seconds.
34 */
35
36#include <linux/module.h>
37#include <linux/moduleparam.h>
38#include <linux/types.h>
39#include <linux/errno.h>
40#include <linux/miscdevice.h>
41#include <linux/fs.h>
42#include <linux/init.h>
43#include <linux/ioport.h>
44#include <linux/timer.h>
45#include <linux/completion.h>
46#include <linux/jiffies.h>
47#include <linux/watchdog.h>
48#include <asm/io.h>
49#include <asm/uaccess.h>
50
51#include <asm/mach-au1x00/au1000.h>
52
53#define MTX1_WDT_INTERVAL (5 * HZ)
54
55static int ticks = 100 * HZ;
56
57static struct {
58 struct completion stop;
59 volatile int running;
60 struct timer_list timer;
61 volatile int queue;
62 int default_ticks;
63 unsigned long inuse;
64} mtx1_wdt_device;
65
66static void mtx1_wdt_trigger(unsigned long unused)
67{
68 u32 tmp;
69
70 if (mtx1_wdt_device.running)
71 ticks--;
72 /*
73 * toggle GPIO2_15
74 */
75 tmp = au_readl(GPIO2_DIR);
76 tmp = (tmp & ~(1<<15)) | ((~tmp) & (1<<15));
77 au_writel (tmp, GPIO2_DIR);
78
79 if (mtx1_wdt_device.queue && ticks)
80 mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
81 else {
82 complete(&mtx1_wdt_device.stop);
83 }
84}
85
86static void mtx1_wdt_reset(void)
87{
88 ticks = mtx1_wdt_device.default_ticks;
89}
90
91
92static void mtx1_wdt_start(void)
93{
94 if (!mtx1_wdt_device.queue) {
95 mtx1_wdt_device.queue = 1;
96 au_writel (au_readl(GPIO2_DIR) | (u32)(1<<15), GPIO2_DIR);
97 mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL);
98 }
99 mtx1_wdt_device.running++;
100}
101
102static int mtx1_wdt_stop(void)
103{
104 if (mtx1_wdt_device.queue) {
105 mtx1_wdt_device.queue = 0;
106 au_writel (au_readl(GPIO2_DIR) & ~((u32)(1<<15)), GPIO2_DIR);
107 }
108
109 ticks = mtx1_wdt_device.default_ticks;
110
111 return 0;
112}
113
114/* Filesystem functions */
115
116static int mtx1_wdt_open(struct inode *inode, struct file *file)
117{
118 if (test_and_set_bit(0, &mtx1_wdt_device.inuse))
119 return -EBUSY;
120
121 return nonseekable_open(inode, file);
122}
123
124
125static int mtx1_wdt_release(struct inode *inode, struct file *file)
126{
127 clear_bit(0, &mtx1_wdt_device.inuse);
128 return 0;
129}
130
131static int mtx1_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
132{
133 void __user *argp = (void __user *)arg;
134 unsigned int value;
135 static struct watchdog_info ident =
136 {
137 .options = WDIOF_CARDRESET,
138 .identity = "MTX-1 WDT",
139 };
140
141 switch(cmd) {
142 case WDIOC_KEEPALIVE:
143 mtx1_wdt_reset();
144 break;
145 case WDIOC_GETSTATUS:
146 case WDIOC_GETBOOTSTATUS:
147 if ( copy_to_user(argp, &value, sizeof(int)) )
148 return -EFAULT;
149 break;
150 case WDIOC_GETSUPPORT:
151 if ( copy_to_user(argp, &ident, sizeof(ident)) )
152 return -EFAULT;
153 break;
154 case WDIOC_SETOPTIONS:
155 if ( copy_from_user(&value, argp, sizeof(int)) )
156 return -EFAULT;
157 switch(value) {
158 case WDIOS_ENABLECARD:
159 mtx1_wdt_start();
160 break;
161 case WDIOS_DISABLECARD:
162 return mtx1_wdt_stop();
163 default:
164 return -EINVAL;
165 }
166 break;
167 default:
168 return -ENOTTY;
169 }
170 return 0;
171}
172
173
174static ssize_t mtx1_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
175{
176 if (!count)
177 return -EIO;
178
179 mtx1_wdt_reset();
180 return count;
181}
182
183static struct file_operations mtx1_wdt_fops = {
184 .owner = THIS_MODULE,
185 .llseek = no_llseek,
186 .ioctl = mtx1_wdt_ioctl,
187 .open = mtx1_wdt_open,
188 .write = mtx1_wdt_write,
189 .release = mtx1_wdt_release
190};
191
192
193static struct miscdevice mtx1_wdt_misc = {
194 .minor = WATCHDOG_MINOR,
195 .name = "watchdog",
196 .fops = &mtx1_wdt_fops
197};
198
199
200static int __init mtx1_wdt_init(void)
201{
202 int ret;
203
204 if ((ret = misc_register(&mtx1_wdt_misc)) < 0) {
205 printk(KERN_ERR " mtx-1_wdt : failed to register\n");
206 return ret;
207 }
208
209 init_completion(&mtx1_wdt_device.stop);
210 mtx1_wdt_device.queue = 0;
211
212 clear_bit(0, &mtx1_wdt_device.inuse);
213
214 setup_timer(&mtx1_wdt_device.timer, mtx1_wdt_trigger, 0L);
215
216 mtx1_wdt_device.default_ticks = ticks;
217
218 mtx1_wdt_start();
219
220 printk(KERN_INFO "MTX-1 Watchdog driver\n");
221
222 return 0;
223}
224
225static void __exit mtx1_wdt_exit(void)
226{
227 if (mtx1_wdt_device.queue) {
228 mtx1_wdt_device.queue = 0;
229 wait_for_completion(&mtx1_wdt_device.stop);
230 }
231 misc_deregister(&mtx1_wdt_misc);
232}
233
234module_init(mtx1_wdt_init);
235module_exit(mtx1_wdt_exit);
236
237MODULE_AUTHOR("Michael Stickel, Florian Fainelli");
238MODULE_DESCRIPTION("Driver for the MTX-1 watchdog");
239MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c
new file mode 100644
index 000000000000..0365c317f7e1
--- /dev/null
+++ b/drivers/watchdog/mv64x60_wdt.c
@@ -0,0 +1,326 @@
1/*
2 * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface
3 *
4 * Author: James Chapman <jchapman@katalix.com>
5 *
6 * Platform-specific setup code should configure the dog to generate
7 * interrupt or reset as required. This code only enables/disables
8 * and services the watchdog.
9 *
10 * Derived from mpc8xx_wdt.c, with the following copyright.
11 *
12 * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
13 * the terms of the GNU General Public License version 2. This program
14 * is licensed "as is" without any warranty of any kind, whether express
15 * or implied.
16 */
17
18#include <linux/fs.h>
19#include <linux/init.h>
20#include <linux/kernel.h>
21#include <linux/miscdevice.h>
22#include <linux/module.h>
23#include <linux/watchdog.h>
24#include <linux/platform_device.h>
25
26#include <linux/mv643xx.h>
27#include <asm/uaccess.h>
28#include <asm/io.h>
29
30#define MV64x60_WDT_WDC_OFFSET 0
31
32/*
33 * The watchdog configuration register contains a pair of 2-bit fields,
34 * 1. a reload field, bits 27-26, which triggers a reload of
35 * the countdown register, and
36 * 2. an enable field, bits 25-24, which toggles between
37 * enabling and disabling the watchdog timer.
38 * Bit 31 is a read-only field which indicates whether the
39 * watchdog timer is currently enabled.
40 *
41 * The low 24 bits contain the timer reload value.
42 */
43#define MV64x60_WDC_ENABLE_SHIFT 24
44#define MV64x60_WDC_SERVICE_SHIFT 26
45#define MV64x60_WDC_ENABLED_SHIFT 31
46
47#define MV64x60_WDC_ENABLED_TRUE 1
48#define MV64x60_WDC_ENABLED_FALSE 0
49
50/* Flags bits */
51#define MV64x60_WDOG_FLAG_OPENED 0
52
53static unsigned long wdt_flags;
54static int wdt_status;
55static void __iomem *mv64x60_wdt_regs;
56static int mv64x60_wdt_timeout;
57static int mv64x60_wdt_count;
58static unsigned int bus_clk;
59static char expect_close;
60static DEFINE_SPINLOCK(mv64x60_wdt_spinlock);
61
62static int nowayout = WATCHDOG_NOWAYOUT;
63module_param(nowayout, int, 0);
64MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
65
66static int mv64x60_wdt_toggle_wdc(int enabled_predicate, int field_shift)
67{
68 u32 data;
69 u32 enabled;
70 int ret = 0;
71
72 spin_lock(&mv64x60_wdt_spinlock);
73 data = readl(mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
74 enabled = (data >> MV64x60_WDC_ENABLED_SHIFT) & 1;
75
76 /* only toggle the requested field if enabled state matches predicate */
77 if ((enabled ^ enabled_predicate) == 0) {
78 /* We write a 1, then a 2 -- to the appropriate field */
79 data = (1 << field_shift) | mv64x60_wdt_count;
80 writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
81
82 data = (2 << field_shift) | mv64x60_wdt_count;
83 writel(data, mv64x60_wdt_regs + MV64x60_WDT_WDC_OFFSET);
84 ret = 1;
85 }
86 spin_unlock(&mv64x60_wdt_spinlock);
87
88 return ret;
89}
90
91static void mv64x60_wdt_service(void)
92{
93 mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
94 MV64x60_WDC_SERVICE_SHIFT);
95}
96
97static void mv64x60_wdt_handler_enable(void)
98{
99 if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_FALSE,
100 MV64x60_WDC_ENABLE_SHIFT)) {
101 mv64x60_wdt_service();
102 printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n");
103 }
104}
105
106static void mv64x60_wdt_handler_disable(void)
107{
108 if (mv64x60_wdt_toggle_wdc(MV64x60_WDC_ENABLED_TRUE,
109 MV64x60_WDC_ENABLE_SHIFT))
110 printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n");
111}
112
113static void mv64x60_wdt_set_timeout(unsigned int timeout)
114{
115 /* maximum bus cycle count is 0xFFFFFFFF */
116 if (timeout > 0xFFFFFFFF / bus_clk)
117 timeout = 0xFFFFFFFF / bus_clk;
118
119 mv64x60_wdt_count = timeout * bus_clk >> 8;
120 mv64x60_wdt_timeout = timeout;
121}
122
123static int mv64x60_wdt_open(struct inode *inode, struct file *file)
124{
125 if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags))
126 return -EBUSY;
127
128 if (nowayout)
129 __module_get(THIS_MODULE);
130
131 mv64x60_wdt_handler_enable();
132
133 return nonseekable_open(inode, file);
134}
135
136static int mv64x60_wdt_release(struct inode *inode, struct file *file)
137{
138 if (expect_close == 42)
139 mv64x60_wdt_handler_disable();
140 else {
141 printk(KERN_CRIT
142 "mv64x60_wdt: unexpected close, not stopping timer!\n");
143 mv64x60_wdt_service();
144 }
145 expect_close = 0;
146
147 clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags);
148
149 return 0;
150}
151
152static ssize_t mv64x60_wdt_write(struct file *file, const char __user *data,
153 size_t len, loff_t * ppos)
154{
155 if (len) {
156 if (!nowayout) {
157 size_t i;
158
159 expect_close = 0;
160
161 for (i = 0; i != len; i++) {
162 char c;
163 if(get_user(c, data + i))
164 return -EFAULT;
165 if (c == 'V')
166 expect_close = 42;
167 }
168 }
169 mv64x60_wdt_service();
170 }
171
172 return len;
173}
174
175static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
176 unsigned int cmd, unsigned long arg)
177{
178 int timeout;
179 int options;
180 void __user *argp = (void __user *)arg;
181 static struct watchdog_info info = {
182 .options = WDIOF_SETTIMEOUT |
183 WDIOF_MAGICCLOSE |
184 WDIOF_KEEPALIVEPING,
185 .firmware_version = 0,
186 .identity = "MV64x60 watchdog",
187 };
188
189 switch (cmd) {
190 case WDIOC_GETSUPPORT:
191 if (copy_to_user(argp, &info, sizeof(info)))
192 return -EFAULT;
193 break;
194
195 case WDIOC_GETSTATUS:
196 case WDIOC_GETBOOTSTATUS:
197 if (put_user(wdt_status, (int __user *)argp))
198 return -EFAULT;
199 wdt_status &= ~WDIOF_KEEPALIVEPING;
200 break;
201
202 case WDIOC_GETTEMP:
203 return -EOPNOTSUPP;
204
205 case WDIOC_SETOPTIONS:
206 if (get_user(options, (int __user *)argp))
207 return -EFAULT;
208
209 if (options & WDIOS_DISABLECARD)
210 mv64x60_wdt_handler_disable();
211
212 if (options & WDIOS_ENABLECARD)
213 mv64x60_wdt_handler_enable();
214 break;
215
216 case WDIOC_KEEPALIVE:
217 mv64x60_wdt_service();
218 wdt_status |= WDIOF_KEEPALIVEPING;
219 break;
220
221 case WDIOC_SETTIMEOUT:
222 if (get_user(timeout, (int __user *)argp))
223 return -EFAULT;
224 mv64x60_wdt_set_timeout(timeout);
225 /* Fall through */
226
227 case WDIOC_GETTIMEOUT:
228 if (put_user(mv64x60_wdt_timeout, (int __user *)argp))
229 return -EFAULT;
230 break;
231
232 default:
233 return -ENOTTY;
234 }
235
236 return 0;
237}
238
239static const struct file_operations mv64x60_wdt_fops = {
240 .owner = THIS_MODULE,
241 .llseek = no_llseek,
242 .write = mv64x60_wdt_write,
243 .ioctl = mv64x60_wdt_ioctl,
244 .open = mv64x60_wdt_open,
245 .release = mv64x60_wdt_release,
246};
247
248static struct miscdevice mv64x60_wdt_miscdev = {
249 .minor = WATCHDOG_MINOR,
250 .name = "watchdog",
251 .fops = &mv64x60_wdt_fops,
252};
253
254static int __devinit mv64x60_wdt_probe(struct platform_device *dev)
255{
256 struct mv64x60_wdt_pdata *pdata = dev->dev.platform_data;
257 struct resource *r;
258 int timeout = 10;
259
260 bus_clk = 133; /* in MHz */
261 if (pdata) {
262 timeout = pdata->timeout;
263 bus_clk = pdata->bus_clk;
264 }
265
266 /* Since bus_clk is truncated MHz, actual frequency could be
267 * up to 1MHz higher. Round up, since it's better to time out
268 * too late than too soon.
269 */
270 bus_clk++;
271 bus_clk *= 1000000; /* convert to Hz */
272
273 r = platform_get_resource(dev, IORESOURCE_MEM, 0);
274 if (!r)
275 return -ENODEV;
276
277 mv64x60_wdt_regs = ioremap(r->start, r->end - r->start + 1);
278 if (mv64x60_wdt_regs == NULL)
279 return -ENOMEM;
280
281 mv64x60_wdt_set_timeout(timeout);
282
283 mv64x60_wdt_handler_disable(); /* in case timer was already running */
284
285 return misc_register(&mv64x60_wdt_miscdev);
286}
287
288static int __devexit mv64x60_wdt_remove(struct platform_device *dev)
289{
290 misc_deregister(&mv64x60_wdt_miscdev);
291
292 mv64x60_wdt_handler_disable();
293
294 iounmap(mv64x60_wdt_regs);
295
296 return 0;
297}
298
299static struct platform_driver mv64x60_wdt_driver = {
300 .probe = mv64x60_wdt_probe,
301 .remove = __devexit_p(mv64x60_wdt_remove),
302 .driver = {
303 .owner = THIS_MODULE,
304 .name = MV64x60_WDT_NAME,
305 },
306};
307
308static int __init mv64x60_wdt_init(void)
309{
310 printk(KERN_INFO "MV64x60 watchdog driver\n");
311
312 return platform_driver_register(&mv64x60_wdt_driver);
313}
314
315static void __exit mv64x60_wdt_exit(void)
316{
317 platform_driver_unregister(&mv64x60_wdt_driver);
318}
319
320module_init(mv64x60_wdt_init);
321module_exit(mv64x60_wdt_exit);
322
323MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
324MODULE_DESCRIPTION("MV64x60 watchdog driver");
325MODULE_LICENSE("GPL");
326MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
new file mode 100644
index 000000000000..719b066f73c4
--- /dev/null
+++ b/drivers/watchdog/omap_wdt.c
@@ -0,0 +1,389 @@
1/*
2 * linux/drivers/char/watchdog/omap_wdt.c
3 *
4 * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
5 *
6 * Author: MontaVista Software, Inc.
7 * <gdavis@mvista.com> or <source@mvista.com>
8 *
9 * 2003 (c) MontaVista Software, Inc. This file is licensed under the
10 * terms of the GNU General Public License version 2. This program is
11 * licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 *
14 * History:
15 *
16 * 20030527: George G. Davis <gdavis@mvista.com>
17 * Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c
18 * (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
19 * Based on SoftDog driver by Alan Cox <alan@redhat.com>
20 *
21 * Copyright (c) 2004 Texas Instruments.
22 * 1. Modified to support OMAP1610 32-KHz watchdog timer
23 * 2. Ported to 2.6 kernel
24 *
25 * Copyright (c) 2005 David Brownell
26 * Use the driver model and standard identifiers; handle bigger timeouts.
27 */
28
29#include <linux/module.h>
30#include <linux/types.h>
31#include <linux/kernel.h>
32#include <linux/fs.h>
33#include <linux/mm.h>
34#include <linux/miscdevice.h>
35#include <linux/watchdog.h>
36#include <linux/reboot.h>
37#include <linux/init.h>
38#include <linux/err.h>
39#include <linux/platform_device.h>
40#include <linux/moduleparam.h>
41#include <linux/clk.h>
42
43#include <asm/io.h>
44#include <asm/uaccess.h>
45#include <asm/hardware.h>
46#include <asm/bitops.h>
47
48#include <asm/arch/prcm.h>
49
50#include "omap_wdt.h"
51
52static unsigned timer_margin;
53module_param(timer_margin, uint, 0);
54MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
55
56static int omap_wdt_users;
57static struct clk *armwdt_ck = NULL;
58static struct clk *mpu_wdt_ick = NULL;
59static struct clk *mpu_wdt_fck = NULL;
60
61static unsigned int wdt_trgr_pattern = 0x1234;
62
63static void omap_wdt_ping(void)
64{
65 /* wait for posted write to complete */
66 while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
67 cpu_relax();
68 wdt_trgr_pattern = ~wdt_trgr_pattern;
69 omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
70 /* wait for posted write to complete */
71 while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
72 cpu_relax();
73 /* reloaded WCRR from WLDR */
74}
75
76static void omap_wdt_enable(void)
77{
78 /* Sequence to enable the watchdog */
79 omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
80 while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
81 cpu_relax();
82 omap_writel(0x4444, OMAP_WATCHDOG_SPR);
83 while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
84 cpu_relax();
85}
86
87static void omap_wdt_disable(void)
88{
89 /* sequence required to disable watchdog */
90 omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
91 while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
92 cpu_relax();
93 omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
94 while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
95 cpu_relax();
96}
97
98static void omap_wdt_adjust_timeout(unsigned new_timeout)
99{
100 if (new_timeout < TIMER_MARGIN_MIN)
101 new_timeout = TIMER_MARGIN_DEFAULT;
102 if (new_timeout > TIMER_MARGIN_MAX)
103 new_timeout = TIMER_MARGIN_MAX;
104 timer_margin = new_timeout;
105}
106
107static void omap_wdt_set_timeout(void)
108{
109 u32 pre_margin = GET_WLDR_VAL(timer_margin);
110
111 /* just count up at 32 KHz */
112 while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
113 cpu_relax();
114 omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
115 while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
116 cpu_relax();
117}
118
119/*
120 * Allow only one task to hold it open
121 */
122
123static int omap_wdt_open(struct inode *inode, struct file *file)
124{
125 if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
126 return -EBUSY;
127
128 if (cpu_is_omap16xx())
129 clk_enable(armwdt_ck); /* Enable the clock */
130
131 if (cpu_is_omap24xx()) {
132 clk_enable(mpu_wdt_ick); /* Enable the interface clock */
133 clk_enable(mpu_wdt_fck); /* Enable the functional clock */
134 }
135
136 /* initialize prescaler */
137 while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
138 cpu_relax();
139 omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
140 while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
141 cpu_relax();
142
143 omap_wdt_set_timeout();
144 omap_wdt_enable();
145 return nonseekable_open(inode, file);
146}
147
148static int omap_wdt_release(struct inode *inode, struct file *file)
149{
150 /*
151 * Shut off the timer unless NOWAYOUT is defined.
152 */
153#ifndef CONFIG_WATCHDOG_NOWAYOUT
154 omap_wdt_disable();
155
156 if (cpu_is_omap16xx()) {
157 clk_disable(armwdt_ck); /* Disable the clock */
158 clk_put(armwdt_ck);
159 armwdt_ck = NULL;
160 }
161
162 if (cpu_is_omap24xx()) {
163 clk_disable(mpu_wdt_ick); /* Disable the clock */
164 clk_disable(mpu_wdt_fck); /* Disable the clock */
165 clk_put(mpu_wdt_ick);
166 clk_put(mpu_wdt_fck);
167 mpu_wdt_ick = NULL;
168 mpu_wdt_fck = NULL;
169 }
170#else
171 printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
172#endif
173 omap_wdt_users = 0;
174 return 0;
175}
176
177static ssize_t
178omap_wdt_write(struct file *file, const char __user *data,
179 size_t len, loff_t *ppos)
180{
181 /* Refresh LOAD_TIME. */
182 if (len)
183 omap_wdt_ping();
184 return len;
185}
186
187static int
188omap_wdt_ioctl(struct inode *inode, struct file *file,
189 unsigned int cmd, unsigned long arg)
190{
191 int new_margin;
192 static struct watchdog_info ident = {
193 .identity = "OMAP Watchdog",
194 .options = WDIOF_SETTIMEOUT,
195 .firmware_version = 0,
196 };
197
198 switch (cmd) {
199 default:
200 return -ENOTTY;
201 case WDIOC_GETSUPPORT:
202 return copy_to_user((struct watchdog_info __user *)arg, &ident,
203 sizeof(ident));
204 case WDIOC_GETSTATUS:
205 return put_user(0, (int __user *)arg);
206 case WDIOC_GETBOOTSTATUS:
207 if (cpu_is_omap16xx())
208 return put_user(omap_readw(ARM_SYSST),
209 (int __user *)arg);
210 if (cpu_is_omap24xx())
211 return put_user(omap_prcm_get_reset_sources(),
212 (int __user *)arg);
213 case WDIOC_KEEPALIVE:
214 omap_wdt_ping();
215 return 0;
216 case WDIOC_SETTIMEOUT:
217 if (get_user(new_margin, (int __user *)arg))
218 return -EFAULT;
219 omap_wdt_adjust_timeout(new_margin);
220
221 omap_wdt_disable();
222 omap_wdt_set_timeout();
223 omap_wdt_enable();
224
225 omap_wdt_ping();
226 /* Fall */
227 case WDIOC_GETTIMEOUT:
228 return put_user(timer_margin, (int __user *)arg);
229 }
230}
231
232static const struct file_operations omap_wdt_fops = {
233 .owner = THIS_MODULE,
234 .write = omap_wdt_write,
235 .ioctl = omap_wdt_ioctl,
236 .open = omap_wdt_open,
237 .release = omap_wdt_release,
238};
239
240static struct miscdevice omap_wdt_miscdev = {
241 .minor = WATCHDOG_MINOR,
242 .name = "watchdog",
243 .fops = &omap_wdt_fops
244};
245
246static int __init omap_wdt_probe(struct platform_device *pdev)
247{
248 struct resource *res, *mem;
249 int ret;
250
251 /* reserve static register mappings */
252 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
253 if (!res)
254 return -ENOENT;
255
256 mem = request_mem_region(res->start, res->end - res->start + 1,
257 pdev->name);
258 if (mem == NULL)
259 return -EBUSY;
260
261 platform_set_drvdata(pdev, mem);
262
263 omap_wdt_users = 0;
264
265 if (cpu_is_omap16xx()) {
266 armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
267 if (IS_ERR(armwdt_ck)) {
268 ret = PTR_ERR(armwdt_ck);
269 armwdt_ck = NULL;
270 goto fail;
271 }
272 }
273
274 if (cpu_is_omap24xx()) {
275 mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
276 if (IS_ERR(mpu_wdt_ick)) {
277 ret = PTR_ERR(mpu_wdt_ick);
278 mpu_wdt_ick = NULL;
279 goto fail;
280 }
281 mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
282 if (IS_ERR(mpu_wdt_fck)) {
283 ret = PTR_ERR(mpu_wdt_fck);
284 mpu_wdt_fck = NULL;
285 goto fail;
286 }
287 }
288
289 omap_wdt_disable();
290 omap_wdt_adjust_timeout(timer_margin);
291
292 omap_wdt_miscdev.parent = &pdev->dev;
293 ret = misc_register(&omap_wdt_miscdev);
294 if (ret)
295 goto fail;
296
297 pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
298
299 /* autogate OCP interface clock */
300 omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
301 return 0;
302
303fail:
304 if (armwdt_ck)
305 clk_put(armwdt_ck);
306 if (mpu_wdt_ick)
307 clk_put(mpu_wdt_ick);
308 if (mpu_wdt_fck)
309 clk_put(mpu_wdt_fck);
310 release_resource(mem);
311 return ret;
312}
313
314static void omap_wdt_shutdown(struct platform_device *pdev)
315{
316 omap_wdt_disable();
317}
318
319static int omap_wdt_remove(struct platform_device *pdev)
320{
321 struct resource *mem = platform_get_drvdata(pdev);
322 misc_deregister(&omap_wdt_miscdev);
323 release_resource(mem);
324 if (armwdt_ck)
325 clk_put(armwdt_ck);
326 if (mpu_wdt_ick)
327 clk_put(mpu_wdt_ick);
328 if (mpu_wdt_fck)
329 clk_put(mpu_wdt_fck);
330 return 0;
331}
332
333#ifdef CONFIG_PM
334
335/* REVISIT ... not clear this is the best way to handle system suspend; and
336 * it's very inappropriate for selective device suspend (e.g. suspending this
337 * through sysfs rather than by stopping the watchdog daemon). Also, this
338 * may not play well enough with NOWAYOUT...
339 */
340
341static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
342{
343 if (omap_wdt_users)
344 omap_wdt_disable();
345 return 0;
346}
347
348static int omap_wdt_resume(struct platform_device *pdev)
349{
350 if (omap_wdt_users) {
351 omap_wdt_enable();
352 omap_wdt_ping();
353 }
354 return 0;
355}
356
357#else
358#define omap_wdt_suspend NULL
359#define omap_wdt_resume NULL
360#endif
361
362static struct platform_driver omap_wdt_driver = {
363 .probe = omap_wdt_probe,
364 .remove = omap_wdt_remove,
365 .shutdown = omap_wdt_shutdown,
366 .suspend = omap_wdt_suspend,
367 .resume = omap_wdt_resume,
368 .driver = {
369 .owner = THIS_MODULE,
370 .name = "omap_wdt",
371 },
372};
373
374static int __init omap_wdt_init(void)
375{
376 return platform_driver_register(&omap_wdt_driver);
377}
378
379static void __exit omap_wdt_exit(void)
380{
381 platform_driver_unregister(&omap_wdt_driver);
382}
383
384module_init(omap_wdt_init);
385module_exit(omap_wdt_exit);
386
387MODULE_AUTHOR("George G. Davis");
388MODULE_LICENSE("GPL");
389MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h
new file mode 100644
index 000000000000..52a532a5114a
--- /dev/null
+++ b/drivers/watchdog/omap_wdt.h
@@ -0,0 +1,64 @@
1/*
2 * linux/drivers/char/watchdog/omap_wdt.h
3 *
4 * BRIEF MODULE DESCRIPTION
5 * OMAP Watchdog timer register definitions
6 *
7 * Copyright (C) 2004 Texas Instruments.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
20 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 675 Mass Ave, Cambridge, MA 02139, USA.
28 */
29
30#ifndef _OMAP_WATCHDOG_H
31#define _OMAP_WATCHDOG_H
32
33#define OMAP1610_WATCHDOG_BASE 0xfffeb000
34#define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */
35
36#ifdef CONFIG_ARCH_OMAP24XX
37#define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE
38#else
39#define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE
40#define RM_RSTST_WKUP 0
41#endif
42
43#define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00)
44#define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10)
45#define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14)
46#define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24)
47#define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28)
48#define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c)
49#define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30)
50#define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34)
51#define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48)
52
53/* Using the prescaler, the OMAP watchdog could go for many
54 * months before firing. These limits work without scaling,
55 * with the 60 second default assumed by most tools and docs.
56 */
57#define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */
58#define TIMER_MARGIN_DEFAULT 60 /* 60 secs */
59#define TIMER_MARGIN_MIN 1
60
61#define PTV 0 /* prescale */
62#define GET_WLDR_VAL(secs) (0xffffffff - ((secs) * (32768/(1<<PTV))) + 1)
63
64#endif /* _OMAP_WATCHDOG_H */
diff --git a/drivers/watchdog/pc87413_wdt.c b/drivers/watchdog/pc87413_wdt.c
new file mode 100644
index 000000000000..3d3deae0d64b
--- /dev/null
+++ b/drivers/watchdog/pc87413_wdt.c
@@ -0,0 +1,635 @@
1/*
2 * NS pc87413-wdt Watchdog Timer driver for Linux 2.6.x.x
3 *
4 * This code is based on wdt.c with original copyright.
5 *
6 * (C) Copyright 2006 Sven Anders, <anders@anduras.de>
7 * and Marcus Junker, <junker@anduras.de>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version
12 * 2 of the License, or (at your option) any later version.
13 *
14 * Neither Sven Anders, Marcus Junker nor ANDURAS AG
15 * admit liability nor provide warranty for any of this software.
16 * This material is provided "AS-IS" and at no charge.
17 *
18 * Release 1.1
19 */
20
21#include <linux/module.h>
22#include <linux/types.h>
23#include <linux/miscdevice.h>
24#include <linux/watchdog.h>
25#include <linux/ioport.h>
26#include <linux/delay.h>
27#include <linux/notifier.h>
28#include <linux/fs.h>
29#include <linux/reboot.h>
30#include <linux/init.h>
31#include <linux/spinlock.h>
32#include <linux/moduleparam.h>
33#include <linux/version.h>
34
35#include <asm/io.h>
36#include <asm/uaccess.h>
37#include <asm/system.h>
38
39/* #define DEBUG 1 */
40
41#define DEFAULT_TIMEOUT 1 /* 1 minute */
42#define MAX_TIMEOUT 255
43
44#define VERSION "1.1"
45#define MODNAME "pc87413 WDT"
46#define PFX MODNAME ": "
47#define DPFX MODNAME " - DEBUG: "
48
49#define WDT_INDEX_IO_PORT (io+0) /* I/O port base (index register) */
50#define WDT_DATA_IO_PORT (WDT_INDEX_IO_PORT+1)
51#define SWC_LDN 0x04
52#define SIOCFG2 0x22 /* Serial IO register */
53#define WDCTL 0x10 /* Watchdog-Timer-Controll-Register */
54#define WDTO 0x11 /* Watchdog timeout register */
55#define WDCFG 0x12 /* Watchdog config register */
56
57static int io = 0x2E; /* Address used on Portwell Boards */
58
59static int timeout = DEFAULT_TIMEOUT; /* timeout value */
60static unsigned long timer_enabled = 0; /* is the timer enabled? */
61
62static char expect_close; /* is the close expected? */
63
64static spinlock_t io_lock; /* to guard the watchdog from io races */
65
66static int nowayout = WATCHDOG_NOWAYOUT;
67
68/* -- Low level function ----------------------------------------*/
69
70/* Select pins for Watchdog output */
71
72static inline void pc87413_select_wdt_out (void)
73{
74 unsigned int cr_data = 0;
75
76 /* Step 1: Select multiple pin,pin55,as WDT output */
77
78 outb_p(SIOCFG2, WDT_INDEX_IO_PORT);
79
80 cr_data = inb (WDT_DATA_IO_PORT);
81
82 cr_data |= 0x80; /* Set Bit7 to 1*/
83 outb_p(SIOCFG2, WDT_INDEX_IO_PORT);
84
85 outb_p(cr_data, WDT_DATA_IO_PORT);
86
87#ifdef DEBUG
88 printk(KERN_INFO DPFX "Select multiple pin,pin55,as WDT output:"
89 " Bit7 to 1: %d\n", cr_data);
90#endif
91}
92
93/* Enable SWC functions */
94
95static inline void pc87413_enable_swc(void)
96{
97 unsigned int cr_data=0;
98
99 /* Step 2: Enable SWC functions */
100
101 outb_p(0x07, WDT_INDEX_IO_PORT); /* Point SWC_LDN (LDN=4) */
102 outb_p(SWC_LDN, WDT_DATA_IO_PORT);
103
104 outb_p(0x30, WDT_INDEX_IO_PORT); /* Read Index 0x30 First */
105 cr_data = inb(WDT_DATA_IO_PORT);
106 cr_data |= 0x01; /* Set Bit0 to 1 */
107 outb_p(0x30, WDT_INDEX_IO_PORT);
108 outb_p(cr_data, WDT_DATA_IO_PORT); /* Index0x30_bit0P1 */
109
110#ifdef DEBUG
111 printk(KERN_INFO DPFX "pc87413 - Enable SWC functions\n");
112#endif
113}
114
115/* Read SWC I/O base address */
116
117static inline unsigned int pc87413_get_swc_base(void)
118{
119 unsigned int swc_base_addr = 0;
120 unsigned char addr_l, addr_h = 0;
121
122 /* Step 3: Read SWC I/O Base Address */
123
124 outb_p(0x60, WDT_INDEX_IO_PORT); /* Read Index 0x60 */
125 addr_h = inb(WDT_DATA_IO_PORT);
126
127 outb_p(0x61, WDT_INDEX_IO_PORT); /* Read Index 0x61 */
128
129 addr_l = inb(WDT_DATA_IO_PORT);
130
131 swc_base_addr = (addr_h << 8) + addr_l;
132
133#ifdef DEBUG
134 printk(KERN_INFO DPFX "Read SWC I/O Base Address: low %d, high %d,"
135 " res %d\n", addr_l, addr_h, swc_base_addr);
136#endif
137
138 return swc_base_addr;
139}
140
141/* Select Bank 3 of SWC */
142
143static inline void pc87413_swc_bank3(unsigned int swc_base_addr)
144{
145 /* Step 4: Select Bank3 of SWC */
146
147 outb_p(inb(swc_base_addr + 0x0f) | 0x03, swc_base_addr + 0x0f);
148
149#ifdef DEBUG
150 printk(KERN_INFO DPFX "Select Bank3 of SWC\n");
151#endif
152}
153
154/* Set watchdog timeout to x minutes */
155
156static inline void pc87413_programm_wdto(unsigned int swc_base_addr,
157 char pc87413_time)
158{
159 /* Step 5: Programm WDTO, Twd. */
160
161 outb_p(pc87413_time, swc_base_addr + WDTO);
162
163#ifdef DEBUG
164 printk(KERN_INFO DPFX "Set WDTO to %d minutes\n", pc87413_time);
165#endif
166}
167
168/* Enable WDEN */
169
170static inline void pc87413_enable_wden(unsigned int swc_base_addr)
171{
172 /* Step 6: Enable WDEN */
173
174 outb_p(inb (swc_base_addr + WDCTL) | 0x01, swc_base_addr + WDCTL);
175
176#ifdef DEBUG
177 printk(KERN_INFO DPFX "Enable WDEN\n");
178#endif
179}
180
181/* Enable SW_WD_TREN */
182static inline void pc87413_enable_sw_wd_tren(unsigned int swc_base_addr)
183{
184 /* Enable SW_WD_TREN */
185
186 outb_p(inb (swc_base_addr + WDCFG) | 0x80, swc_base_addr + WDCFG);
187
188#ifdef DEBUG
189 printk(KERN_INFO DPFX "Enable SW_WD_TREN\n");
190#endif
191}
192
193/* Disable SW_WD_TREN */
194
195static inline void pc87413_disable_sw_wd_tren(unsigned int swc_base_addr)
196{
197 /* Disable SW_WD_TREN */
198
199 outb_p(inb (swc_base_addr + WDCFG) & 0x7f, swc_base_addr + WDCFG);
200
201#ifdef DEBUG
202 printk(KERN_INFO DPFX "pc87413 - Disable SW_WD_TREN\n");
203#endif
204}
205
206/* Enable SW_WD_TRG */
207
208static inline void pc87413_enable_sw_wd_trg(unsigned int swc_base_addr)
209{
210 /* Enable SW_WD_TRG */
211
212 outb_p(inb (swc_base_addr + WDCTL) | 0x80, swc_base_addr + WDCTL);
213
214#ifdef DEBUG
215 printk(KERN_INFO DPFX "pc87413 - Enable SW_WD_TRG\n");
216#endif
217}
218
219/* Disable SW_WD_TRG */
220
221static inline void pc87413_disable_sw_wd_trg(unsigned int swc_base_addr)
222{
223 /* Disable SW_WD_TRG */
224
225 outb_p(inb (swc_base_addr + WDCTL) & 0x7f, swc_base_addr + WDCTL);
226
227#ifdef DEBUG
228 printk(KERN_INFO DPFX "Disable SW_WD_TRG\n");
229#endif
230}
231
232/* -- Higher level functions ------------------------------------*/
233
234/* Enable the watchdog */
235
236static void pc87413_enable(void)
237{
238 unsigned int swc_base_addr;
239
240 spin_lock(&io_lock);
241
242 pc87413_select_wdt_out();
243 pc87413_enable_swc();
244 swc_base_addr = pc87413_get_swc_base();
245 pc87413_swc_bank3(swc_base_addr);
246 pc87413_programm_wdto(swc_base_addr, timeout);
247 pc87413_enable_wden(swc_base_addr);
248 pc87413_enable_sw_wd_tren(swc_base_addr);
249 pc87413_enable_sw_wd_trg(swc_base_addr);
250
251 spin_unlock(&io_lock);
252}
253
254/* Disable the watchdog */
255
256static void pc87413_disable(void)
257{
258 unsigned int swc_base_addr;
259
260 spin_lock(&io_lock);
261
262 pc87413_select_wdt_out();
263 pc87413_enable_swc();
264 swc_base_addr = pc87413_get_swc_base();
265 pc87413_swc_bank3(swc_base_addr);
266 pc87413_disable_sw_wd_tren(swc_base_addr);
267 pc87413_disable_sw_wd_trg(swc_base_addr);
268 pc87413_programm_wdto(swc_base_addr, 0);
269
270 spin_unlock(&io_lock);
271}
272
273/* Refresh the watchdog */
274
275static void pc87413_refresh(void)
276{
277 unsigned int swc_base_addr;
278
279 spin_lock(&io_lock);
280
281 pc87413_select_wdt_out();
282 pc87413_enable_swc();
283 swc_base_addr = pc87413_get_swc_base();
284 pc87413_swc_bank3(swc_base_addr);
285 pc87413_disable_sw_wd_tren(swc_base_addr);
286 pc87413_disable_sw_wd_trg(swc_base_addr);
287 pc87413_programm_wdto(swc_base_addr, timeout);
288 pc87413_enable_wden(swc_base_addr);
289 pc87413_enable_sw_wd_tren(swc_base_addr);
290 pc87413_enable_sw_wd_trg(swc_base_addr);
291
292 spin_unlock(&io_lock);
293}
294
295/* -- File operations -------------------------------------------*/
296
297/**
298 * pc87413_open:
299 * @inode: inode of device
300 * @file: file handle to device
301 *
302 */
303
304static int pc87413_open(struct inode *inode, struct file *file)
305{
306 /* /dev/watchdog can only be opened once */
307
308 if (test_and_set_bit(0, &timer_enabled))
309 return -EBUSY;
310
311 if (nowayout)
312 __module_get(THIS_MODULE);
313
314 /* Reload and activate timer */
315 pc87413_refresh();
316
317 printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to"
318 " %d minute(s).\n", timeout);
319
320 return nonseekable_open(inode, file);
321}
322
323/**
324 * pc87413_release:
325 * @inode: inode to board
326 * @file: file handle to board
327 *
328 * The watchdog has a configurable API. There is a religious dispute
329 * between people who want their watchdog to be able to shut down and
330 * those who want to be sure if the watchdog manager dies the machine
331 * reboots. In the former case we disable the counters, in the latter
332 * case you have to open it again very soon.
333 */
334
335static int pc87413_release(struct inode *inode, struct file *file)
336{
337 /* Shut off the timer. */
338
339 if (expect_close == 42) {
340 pc87413_disable();
341 printk(KERN_INFO MODNAME "Watchdog disabled,"
342 " sleeping again...\n");
343 } else {
344 printk(KERN_CRIT MODNAME "Unexpected close, not stopping"
345 " watchdog!\n");
346 pc87413_refresh();
347 }
348
349 clear_bit(0, &timer_enabled);
350 expect_close = 0;
351
352 return 0;
353}
354
355/**
356 * pc87413_status:
357 *
358 * return, if the watchdog is enabled (timeout is set...)
359 */
360
361
362static int pc87413_status(void)
363{
364 return 0; /* currently not supported */
365}
366
367/**
368 * pc87413_write:
369 * @file: file handle to the watchdog
370 * @data: data buffer to write
371 * @len: length in bytes
372 * @ppos: pointer to the position to write. No seeks allowed
373 *
374 * A write to a watchdog device is defined as a keepalive signal. Any
375 * write of data will do, as we we don't define content meaning.
376 */
377
378static ssize_t pc87413_write(struct file *file, const char __user *data,
379 size_t len, loff_t *ppos)
380{
381 /* See if we got the magic character 'V' and reload the timer */
382 if (len) {
383 if (!nowayout) {
384 size_t i;
385
386 /* reset expect flag */
387 expect_close = 0;
388
389 /* scan to see whether or not we got the magic character */
390 for (i = 0; i != len; i++) {
391 char c;
392 if (get_user(c, data+i))
393 return -EFAULT;
394 if (c == 'V')
395 expect_close = 42;
396 }
397 }
398
399 /* someone wrote to us, we should reload the timer */
400 pc87413_refresh();
401 }
402 return len;
403}
404
405/**
406 * pc87413_ioctl:
407 * @inode: inode of the device
408 * @file: file handle to the device
409 * @cmd: watchdog command
410 * @arg: argument pointer
411 *
412 * The watchdog API defines a common set of functions for all watchdogs
413 * according to their available features. We only actually usefully support
414 * querying capabilities and current status.
415 */
416
417static int pc87413_ioctl(struct inode *inode, struct file *file,
418 unsigned int cmd, unsigned long arg)
419{
420 int new_timeout;
421
422 union {
423 struct watchdog_info __user *ident;
424 int __user *i;
425 } uarg;
426
427 static struct watchdog_info ident = {
428 .options = WDIOF_KEEPALIVEPING |
429 WDIOF_SETTIMEOUT |
430 WDIOF_MAGICCLOSE,
431 .firmware_version = 1,
432 .identity = "PC87413(HF/F) watchdog"
433 };
434
435 uarg.i = (int __user *)arg;
436
437 switch(cmd) {
438 default:
439 return -ENOTTY;
440
441 case WDIOC_GETSUPPORT:
442 return copy_to_user(uarg.ident, &ident,
443 sizeof(ident)) ? -EFAULT : 0;
444
445 case WDIOC_GETSTATUS:
446 return put_user(pc87413_status(), uarg.i);
447
448 case WDIOC_GETBOOTSTATUS:
449 return put_user(0, uarg.i);
450
451 case WDIOC_KEEPALIVE:
452 pc87413_refresh();
453#ifdef DEBUG
454 printk(KERN_INFO DPFX "keepalive\n");
455#endif
456 return 0;
457
458 case WDIOC_SETTIMEOUT:
459 if (get_user(new_timeout, uarg.i))
460 return -EFAULT;
461
462 // the API states this is given in secs
463 new_timeout /= 60;
464
465 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
466 return -EINVAL;
467
468 timeout = new_timeout;
469 pc87413_refresh();
470
471 // fall through and return the new timeout...
472
473 case WDIOC_GETTIMEOUT:
474
475 new_timeout = timeout * 60;
476
477 return put_user(new_timeout, uarg.i);
478
479 case WDIOC_SETOPTIONS:
480 {
481 int options, retval = -EINVAL;
482
483 if (get_user(options, uarg.i))
484 return -EFAULT;
485
486 if (options & WDIOS_DISABLECARD) {
487 pc87413_disable();
488 retval = 0;
489 }
490
491 if (options & WDIOS_ENABLECARD) {
492 pc87413_enable();
493 retval = 0;
494 }
495
496 return retval;
497 }
498 }
499}
500
501/* -- Notifier funtions -----------------------------------------*/
502
503/**
504 * notify_sys:
505 * @this: our notifier block
506 * @code: the event being reported
507 * @unused: unused
508 *
509 * Our notifier is called on system shutdowns. We want to turn the card
510 * off at reboot otherwise the machine will reboot again during memory
511 * test or worse yet during the following fsck. This would suck, in fact
512 * trust me - if it happens it does suck.
513 */
514
515static int pc87413_notify_sys(struct notifier_block *this,
516 unsigned long code,
517 void *unused)
518{
519 if (code == SYS_DOWN || code == SYS_HALT)
520 {
521 /* Turn the card off */
522 pc87413_disable();
523 }
524 return NOTIFY_DONE;
525}
526
527/* -- Module's structures ---------------------------------------*/
528
529static const struct file_operations pc87413_fops = {
530 .owner = THIS_MODULE,
531 .llseek = no_llseek,
532 .write = pc87413_write,
533 .ioctl = pc87413_ioctl,
534 .open = pc87413_open,
535 .release = pc87413_release,
536};
537
538static struct notifier_block pc87413_notifier =
539{
540 .notifier_call = pc87413_notify_sys,
541};
542
543static struct miscdevice pc87413_miscdev=
544{
545 .minor = WATCHDOG_MINOR,
546 .name = "watchdog",
547 .fops = &pc87413_fops
548};
549
550/* -- Module init functions -------------------------------------*/
551
552/**
553 * pc87413_init: module's "constructor"
554 *
555 * Set up the WDT watchdog board. All we have to do is grab the
556 * resources we require and bitch if anyone beat us to them.
557 * The open() function will actually kick the board off.
558 */
559
560static int __init pc87413_init(void)
561{
562 int ret;
563
564 spin_lock_init(&io_lock);
565
566 printk(KERN_INFO PFX "Version " VERSION " at io 0x%X\n", WDT_INDEX_IO_PORT);
567
568 /* request_region(io, 2, "pc87413"); */
569
570 ret = register_reboot_notifier(&pc87413_notifier);
571 if (ret != 0) {
572 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
573 ret);
574 }
575
576 ret = misc_register(&pc87413_miscdev);
577
578 if (ret != 0) {
579 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
580 WATCHDOG_MINOR, ret);
581 unregister_reboot_notifier(&pc87413_notifier);
582 return ret;
583 }
584
585 printk(KERN_INFO PFX "initialized. timeout=%d min \n", timeout);
586
587 pc87413_enable();
588
589 return 0;
590}
591
592/**
593 * pc87413_exit: module's "destructor"
594 *
595 * Unload the watchdog. You cannot do this with any file handles open.
596 * If your watchdog is set to continue ticking on close and you unload
597 * it, well it keeps ticking. We won't get the interrupt but the board
598 * will not touch PC memory so all is fine. You just have to load a new
599 * module in 60 seconds or reboot.
600 */
601
602static void __exit pc87413_exit(void)
603{
604 /* Stop the timer before we leave */
605 if (!nowayout)
606 {
607 pc87413_disable();
608 printk(KERN_INFO MODNAME "Watchdog disabled.\n");
609 }
610
611 misc_deregister(&pc87413_miscdev);
612 unregister_reboot_notifier(&pc87413_notifier);
613 /* release_region(io,2); */
614
615 printk(MODNAME " watchdog component driver removed.\n");
616}
617
618module_init(pc87413_init);
619module_exit(pc87413_exit);
620
621MODULE_AUTHOR("Sven Anders <anders@anduras.de>, Marcus Junker <junker@anduras.de>,");
622MODULE_DESCRIPTION("PC87413 WDT driver");
623MODULE_LICENSE("GPL");
624
625MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
626
627module_param(io, int, 0);
628MODULE_PARM_DESC(io, MODNAME " I/O port (default: " __MODULE_STRING(io) ").");
629
630module_param(timeout, int, 0);
631MODULE_PARM_DESC(timeout, "Watchdog timeout in minutes (default=" __MODULE_STRING(timeout) ").");
632
633module_param(nowayout, int, 0);
634MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
635
diff --git a/drivers/watchdog/pcwd.c b/drivers/watchdog/pcwd.c
new file mode 100644
index 000000000000..7b41434fac8c
--- /dev/null
+++ b/drivers/watchdog/pcwd.c
@@ -0,0 +1,1013 @@
1/*
2 * PC Watchdog Driver
3 * by Ken Hollis (khollis@bitgate.com)
4 *
5 * Permission granted from Simon Machell (smachell@berkprod.com)
6 * Written for the Linux Kernel, and GPLed by Ken Hollis
7 *
8 * 960107 Added request_region routines, modulized the whole thing.
9 * 960108 Fixed end-of-file pointer (Thanks to Dan Hollis), added
10 * WD_TIMEOUT define.
11 * 960216 Added eof marker on the file, and changed verbose messages.
12 * 960716 Made functional and cosmetic changes to the source for
13 * inclusion in Linux 2.0.x kernels, thanks to Alan Cox.
14 * 960717 Removed read/seek routines, replaced with ioctl. Also, added
15 * check_region command due to Alan's suggestion.
16 * 960821 Made changes to compile in newer 2.0.x kernels. Added
17 * "cold reboot sense" entry.
18 * 960825 Made a few changes to code, deleted some defines and made
19 * typedefs to replace them. Made heartbeat reset only available
20 * via ioctl, and removed the write routine.
21 * 960828 Added new items for PC Watchdog Rev.C card.
22 * 960829 Changed around all of the IOCTLs, added new features,
23 * added watchdog disable/re-enable routines. Added firmware
24 * version reporting. Added read routine for temperature.
25 * Removed some extra defines, added an autodetect Revision
26 * routine.
27 * 961006 Revised some documentation, fixed some cosmetic bugs. Made
28 * drivers to panic the system if it's overheating at bootup.
29 * 961118 Changed some verbiage on some of the output, tidied up
30 * code bits, and added compatibility to 2.1.x.
31 * 970912 Enabled board on open and disable on close.
32 * 971107 Took account of recent VFS changes (broke read).
33 * 971210 Disable board on initialisation in case board already ticking.
34 * 971222 Changed open/close for temperature handling
35 * Michael Meskes <meskes@debian.org>.
36 * 980112 Used minor numbers from include/linux/miscdevice.h
37 * 990403 Clear reset status after reading control status register in
38 * pcwd_showprevstate(). [Marc Boucher <marc@mbsi.ca>]
39 * 990605 Made changes to code to support Firmware 1.22a, added
40 * fairly useless proc entry.
41 * 990610 removed said useless proc code for the merge <alan>
42 * 000403 Removed last traces of proc code. <davej>
43 * 011214 Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT <Matt_Domsch@dell.com>
44 * Added timeout module option to override default
45 */
46
47/*
48 * A bells and whistles driver is available from http://www.pcwd.de/
49 * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
50 */
51
52#include <linux/module.h> /* For module specific items */
53#include <linux/moduleparam.h> /* For new moduleparam's */
54#include <linux/types.h> /* For standard types (like size_t) */
55#include <linux/errno.h> /* For the -ENODEV/... values */
56#include <linux/kernel.h> /* For printk/panic/... */
57#include <linux/delay.h> /* For mdelay function */
58#include <linux/timer.h> /* For timer related operations */
59#include <linux/jiffies.h> /* For jiffies stuff */
60#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
61#include <linux/watchdog.h> /* For the watchdog specific items */
62#include <linux/reboot.h> /* For kernel_power_off() */
63#include <linux/init.h> /* For __init/__exit/... */
64#include <linux/fs.h> /* For file operations */
65#include <linux/isa.h> /* For isa devices */
66#include <linux/ioport.h> /* For io-port access */
67#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
68
69#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
70#include <asm/io.h> /* For inb/outb/... */
71
72/* Module and version information */
73#define WATCHDOG_VERSION "1.20"
74#define WATCHDOG_DATE "18 Feb 2007"
75#define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog"
76#define WATCHDOG_NAME "pcwd"
77#define PFX WATCHDOG_NAME ": "
78#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION " (" WATCHDOG_DATE ")\n"
79#define WD_VER WATCHDOG_VERSION " (" WATCHDOG_DATE ")"
80
81/*
82 * It should be noted that PCWD_REVISION_B was removed because A and B
83 * are essentially the same types of card, with the exception that B
84 * has temperature reporting. Since I didn't receive a Rev.B card,
85 * the Rev.B card is not supported. (It's a good thing too, as they
86 * are no longer in production.)
87 */
88#define PCWD_REVISION_A 1
89#define PCWD_REVISION_C 2
90
91/*
92 * These are the auto-probe addresses available.
93 *
94 * Revision A only uses ports 0x270 and 0x370. Revision C introduced 0x350.
95 * Revision A has an address range of 2 addresses, while Revision C has 4.
96 */
97#define PCWD_ISA_NR_CARDS 3
98static int pcwd_ioports[] = { 0x270, 0x350, 0x370, 0x000 };
99
100/*
101 * These are the defines that describe the control status bits for the
102 * PCI-PC Watchdog card.
103*/
104/* Port 1 : Control Status #1 for the PC Watchdog card, revision A. */
105#define WD_WDRST 0x01 /* Previously reset state */
106#define WD_T110 0x02 /* Temperature overheat sense */
107#define WD_HRTBT 0x04 /* Heartbeat sense */
108#define WD_RLY2 0x08 /* External relay triggered */
109#define WD_SRLY2 0x80 /* Software external relay triggered */
110/* Port 1 : Control Status #1 for the PC Watchdog card, revision C. */
111#define WD_REVC_WTRP 0x01 /* Watchdog Trip status */
112#define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */
113#define WD_REVC_TTRP 0x04 /* Temperature Trip status */
114#define WD_REVC_RL2A 0x08 /* Relay 2 activated by on-board processor */
115#define WD_REVC_RL1A 0x10 /* Relay 1 active */
116#define WD_REVC_R2DS 0x40 /* Relay 2 disable */
117#define WD_REVC_RLY2 0x80 /* Relay 2 activated? */
118/* Port 2 : Control Status #2 */
119#define WD_WDIS 0x10 /* Watchdog Disabled */
120#define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */
121#define WD_SSEL 0x40 /* Watchdog Switch Select (1:SW1 <-> 0:SW2) */
122#define WD_WCMD 0x80 /* Watchdog Command Mode */
123
124/* max. time we give an ISA watchdog card to process a command */
125/* 500ms for each 4 bit response (according to spec.) */
126#define ISA_COMMAND_TIMEOUT 1000
127
128/* Watchdog's internal commands */
129#define CMD_ISA_IDLE 0x00
130#define CMD_ISA_VERSION_INTEGER 0x01
131#define CMD_ISA_VERSION_TENTH 0x02
132#define CMD_ISA_VERSION_HUNDRETH 0x03
133#define CMD_ISA_VERSION_MINOR 0x04
134#define CMD_ISA_SWITCH_SETTINGS 0x05
135#define CMD_ISA_RESET_PC 0x06
136#define CMD_ISA_ARM_0 0x07
137#define CMD_ISA_ARM_30 0x08
138#define CMD_ISA_ARM_60 0x09
139#define CMD_ISA_DELAY_TIME_2SECS 0x0A
140#define CMD_ISA_DELAY_TIME_4SECS 0x0B
141#define CMD_ISA_DELAY_TIME_8SECS 0x0C
142#define CMD_ISA_RESET_RELAYS 0x0D
143
144/* Watchdog's Dip Switch heartbeat values */
145static const int heartbeat_tbl [] = {
146 20, /* OFF-OFF-OFF = 20 Sec */
147 40, /* OFF-OFF-ON = 40 Sec */
148 60, /* OFF-ON-OFF = 1 Min */
149 300, /* OFF-ON-ON = 5 Min */
150 600, /* ON-OFF-OFF = 10 Min */
151 1800, /* ON-OFF-ON = 30 Min */
152 3600, /* ON-ON-OFF = 1 Hour */
153 7200, /* ON-ON-ON = 2 hour */
154};
155
156/*
157 * We are using an kernel timer to do the pinging of the watchdog
158 * every ~500ms. We try to set the internal heartbeat of the
159 * watchdog to 2 ms.
160 */
161
162#define WDT_INTERVAL (HZ/2+1)
163
164/* We can only use 1 card due to the /dev/watchdog restriction */
165static int cards_found;
166
167/* internal variables */
168static atomic_t open_allowed = ATOMIC_INIT(1);
169static char expect_close;
170static int temp_panic;
171static struct { /* this is private data for each ISA-PC watchdog card */
172 char fw_ver_str[6]; /* The cards firmware version */
173 int revision; /* The card's revision */
174 int supports_temp; /* Wether or not the card has a temperature device */
175 int command_mode; /* Wether or not the card is in command mode */
176 int boot_status; /* The card's boot status */
177 int io_addr; /* The cards I/O address */
178 spinlock_t io_lock; /* the lock for io operations */
179 struct timer_list timer; /* The timer that pings the watchdog */
180 unsigned long next_heartbeat; /* the next_heartbeat for the timer */
181} pcwd_private;
182
183/* module parameters */
184#define QUIET 0 /* Default */
185#define VERBOSE 1 /* Verbose */
186#define DEBUG 2 /* print fancy stuff too */
187static int debug = QUIET;
188module_param(debug, int, 0);
189MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");
190
191#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */
192static int heartbeat = WATCHDOG_HEARTBEAT;
193module_param(heartbeat, int, 0);
194MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<=heartbeat<=7200 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
195
196static int nowayout = WATCHDOG_NOWAYOUT;
197module_param(nowayout, int, 0);
198MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
199
200/*
201 * Internal functions
202 */
203
204static int send_isa_command(int cmd)
205{
206 int i;
207 int control_status;
208 int port0, last_port0; /* Double read for stabilising */
209
210 if (debug >= DEBUG)
211 printk(KERN_DEBUG PFX "sending following data cmd=0x%02x\n",
212 cmd);
213
214 /* The WCMD bit must be 1 and the command is only 4 bits in size */
215 control_status = (cmd & 0x0F) | WD_WCMD;
216 outb_p(control_status, pcwd_private.io_addr + 2);
217 udelay(ISA_COMMAND_TIMEOUT);
218
219 port0 = inb_p(pcwd_private.io_addr);
220 for (i = 0; i < 25; ++i) {
221 last_port0 = port0;
222 port0 = inb_p(pcwd_private.io_addr);
223
224 if (port0 == last_port0)
225 break; /* Data is stable */
226
227 udelay (250);
228 }
229
230 if (debug >= DEBUG)
231 printk(KERN_DEBUG PFX "received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n",
232 cmd, port0, last_port0);
233
234 return port0;
235}
236
237static int set_command_mode(void)
238{
239 int i, found=0, count=0;
240
241 /* Set the card into command mode */
242 spin_lock(&pcwd_private.io_lock);
243 while ((!found) && (count < 3)) {
244 i = send_isa_command(CMD_ISA_IDLE);
245
246 if (i == 0x00)
247 found = 1;
248 else if (i == 0xF3) {
249 /* Card does not like what we've done to it */
250 outb_p(0x00, pcwd_private.io_addr + 2);
251 udelay(1200); /* Spec says wait 1ms */
252 outb_p(0x00, pcwd_private.io_addr + 2);
253 udelay(ISA_COMMAND_TIMEOUT);
254 }
255 count++;
256 }
257 spin_unlock(&pcwd_private.io_lock);
258 pcwd_private.command_mode = found;
259
260 if (debug >= DEBUG)
261 printk(KERN_DEBUG PFX "command_mode=%d\n",
262 pcwd_private.command_mode);
263
264 return(found);
265}
266
267static void unset_command_mode(void)
268{
269 /* Set the card into normal mode */
270 spin_lock(&pcwd_private.io_lock);
271 outb_p(0x00, pcwd_private.io_addr + 2);
272 udelay(ISA_COMMAND_TIMEOUT);
273 spin_unlock(&pcwd_private.io_lock);
274
275 pcwd_private.command_mode = 0;
276
277 if (debug >= DEBUG)
278 printk(KERN_DEBUG PFX "command_mode=%d\n",
279 pcwd_private.command_mode);
280}
281
282static inline void pcwd_check_temperature_support(void)
283{
284 if (inb(pcwd_private.io_addr) != 0xF0)
285 pcwd_private.supports_temp = 1;
286}
287
288static inline void pcwd_get_firmware(void)
289{
290 int one, ten, hund, minor;
291
292 strcpy(pcwd_private.fw_ver_str, "ERROR");
293
294 if (set_command_mode()) {
295 one = send_isa_command(CMD_ISA_VERSION_INTEGER);
296 ten = send_isa_command(CMD_ISA_VERSION_TENTH);
297 hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH);
298 minor = send_isa_command(CMD_ISA_VERSION_MINOR);
299 sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", one, ten, hund, minor);
300 }
301 unset_command_mode();
302
303 return;
304}
305
306static inline int pcwd_get_option_switches(void)
307{
308 int option_switches=0;
309
310 if (set_command_mode()) {
311 /* Get switch settings */
312 option_switches = send_isa_command(CMD_ISA_SWITCH_SETTINGS);
313 }
314
315 unset_command_mode();
316 return(option_switches);
317}
318
319static void pcwd_show_card_info(void)
320{
321 int option_switches;
322
323 /* Get some extra info from the hardware (in command/debug/diag mode) */
324 if (pcwd_private.revision == PCWD_REVISION_A)
325 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr);
326 else if (pcwd_private.revision == PCWD_REVISION_C) {
327 pcwd_get_firmware();
328 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n",
329 pcwd_private.io_addr, pcwd_private.fw_ver_str);
330 option_switches = pcwd_get_option_switches();
331 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
332 option_switches,
333 ((option_switches & 0x10) ? "ON" : "OFF"),
334 ((option_switches & 0x08) ? "ON" : "OFF"));
335
336 /* Reprogram internal heartbeat to 2 seconds */
337 if (set_command_mode()) {
338 send_isa_command(CMD_ISA_DELAY_TIME_2SECS);
339 unset_command_mode();
340 }
341 }
342
343 if (pcwd_private.supports_temp)
344 printk(KERN_INFO PFX "Temperature Option Detected\n");
345
346 if (pcwd_private.boot_status & WDIOF_CARDRESET)
347 printk(KERN_INFO PFX "Previous reboot was caused by the card\n");
348
349 if (pcwd_private.boot_status & WDIOF_OVERHEAT) {
350 printk(KERN_EMERG PFX "Card senses a CPU Overheat. Panicking!\n");
351 printk(KERN_EMERG PFX "CPU Overheat\n");
352 }
353
354 if (pcwd_private.boot_status == 0)
355 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
356}
357
358static void pcwd_timer_ping(unsigned long data)
359{
360 int wdrst_stat;
361
362 /* If we got a heartbeat pulse within the WDT_INTERVAL
363 * we agree to ping the WDT */
364 if(time_before(jiffies, pcwd_private.next_heartbeat)) {
365 /* Ping the watchdog */
366 spin_lock(&pcwd_private.io_lock);
367 if (pcwd_private.revision == PCWD_REVISION_A) {
368 /* Rev A cards are reset by setting the WD_WDRST bit in register 1 */
369 wdrst_stat = inb_p(pcwd_private.io_addr);
370 wdrst_stat &= 0x0F;
371 wdrst_stat |= WD_WDRST;
372
373 outb_p(wdrst_stat, pcwd_private.io_addr + 1);
374 } else {
375 /* Re-trigger watchdog by writing to port 0 */
376 outb_p(0x00, pcwd_private.io_addr);
377 }
378
379 /* Re-set the timer interval */
380 mod_timer(&pcwd_private.timer, jiffies + WDT_INTERVAL);
381
382 spin_unlock(&pcwd_private.io_lock);
383 } else {
384 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
385 }
386}
387
388static int pcwd_start(void)
389{
390 int stat_reg;
391
392 pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
393
394 /* Start the timer */
395 mod_timer(&pcwd_private.timer, jiffies + WDT_INTERVAL);
396
397 /* Enable the port */
398 if (pcwd_private.revision == PCWD_REVISION_C) {
399 spin_lock(&pcwd_private.io_lock);
400 outb_p(0x00, pcwd_private.io_addr + 3);
401 udelay(ISA_COMMAND_TIMEOUT);
402 stat_reg = inb_p(pcwd_private.io_addr + 2);
403 spin_unlock(&pcwd_private.io_lock);
404 if (stat_reg & WD_WDIS) {
405 printk(KERN_INFO PFX "Could not start watchdog\n");
406 return -EIO;
407 }
408 }
409
410 if (debug >= VERBOSE)
411 printk(KERN_DEBUG PFX "Watchdog started\n");
412
413 return 0;
414}
415
416static int pcwd_stop(void)
417{
418 int stat_reg;
419
420 /* Stop the timer */
421 del_timer(&pcwd_private.timer);
422
423 /* Disable the board */
424 if (pcwd_private.revision == PCWD_REVISION_C) {
425 spin_lock(&pcwd_private.io_lock);
426 outb_p(0xA5, pcwd_private.io_addr + 3);
427 udelay(ISA_COMMAND_TIMEOUT);
428 outb_p(0xA5, pcwd_private.io_addr + 3);
429 udelay(ISA_COMMAND_TIMEOUT);
430 stat_reg = inb_p(pcwd_private.io_addr + 2);
431 spin_unlock(&pcwd_private.io_lock);
432 if ((stat_reg & WD_WDIS) == 0) {
433 printk(KERN_INFO PFX "Could not stop watchdog\n");
434 return -EIO;
435 }
436 }
437
438 if (debug >= VERBOSE)
439 printk(KERN_DEBUG PFX "Watchdog stopped\n");
440
441 return 0;
442}
443
444static int pcwd_keepalive(void)
445{
446 /* user land ping */
447 pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ);
448
449 if (debug >= DEBUG)
450 printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
451
452 return 0;
453}
454
455static int pcwd_set_heartbeat(int t)
456{
457 if ((t < 2) || (t > 7200)) /* arbitrary upper limit */
458 return -EINVAL;
459
460 heartbeat = t;
461
462 if (debug >= VERBOSE)
463 printk(KERN_DEBUG PFX "New heartbeat: %d\n",
464 heartbeat);
465
466 return 0;
467}
468
469static int pcwd_get_status(int *status)
470{
471 int control_status;
472
473 *status=0;
474 spin_lock(&pcwd_private.io_lock);
475 if (pcwd_private.revision == PCWD_REVISION_A)
476 /* Rev A cards return status information from
477 * the base register, which is used for the
478 * temperature in other cards. */
479 control_status = inb(pcwd_private.io_addr);
480 else {
481 /* Rev C cards return card status in the base
482 * address + 1 register. And use different bits
483 * to indicate a card initiated reset, and an
484 * over-temperature condition. And the reboot
485 * status can be reset. */
486 control_status = inb(pcwd_private.io_addr + 1);
487 }
488 spin_unlock(&pcwd_private.io_lock);
489
490 if (pcwd_private.revision == PCWD_REVISION_A) {
491 if (control_status & WD_WDRST)
492 *status |= WDIOF_CARDRESET;
493
494 if (control_status & WD_T110) {
495 *status |= WDIOF_OVERHEAT;
496 if (temp_panic) {
497 printk(KERN_INFO PFX "Temperature overheat trip!\n");
498 kernel_power_off();
499 /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
500 }
501 }
502 } else {
503 if (control_status & WD_REVC_WTRP)
504 *status |= WDIOF_CARDRESET;
505
506 if (control_status & WD_REVC_TTRP) {
507 *status |= WDIOF_OVERHEAT;
508 if (temp_panic) {
509 printk(KERN_INFO PFX "Temperature overheat trip!\n");
510 kernel_power_off();
511 /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */
512 }
513 }
514 }
515
516 return 0;
517}
518
519static int pcwd_clear_status(void)
520{
521 int control_status;
522
523 if (pcwd_private.revision == PCWD_REVISION_C) {
524 spin_lock(&pcwd_private.io_lock);
525
526 if (debug >= VERBOSE)
527 printk(KERN_INFO PFX "clearing watchdog trip status\n");
528
529 control_status = inb_p(pcwd_private.io_addr + 1);
530
531 if (debug >= DEBUG) {
532 printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status);
533 printk(KERN_DEBUG PFX "sending: 0x%02x\n",
534 (control_status & WD_REVC_R2DS));
535 }
536
537 /* clear reset status & Keep Relay 2 disable state as it is */
538 outb_p((control_status & WD_REVC_R2DS), pcwd_private.io_addr + 1);
539
540 spin_unlock(&pcwd_private.io_lock);
541 }
542 return 0;
543}
544
545static int pcwd_get_temperature(int *temperature)
546{
547 /* check that port 0 gives temperature info and no command results */
548 if (pcwd_private.command_mode)
549 return -1;
550
551 *temperature = 0;
552 if (!pcwd_private.supports_temp)
553 return -ENODEV;
554
555 /*
556 * Convert celsius to fahrenheit, since this was
557 * the decided 'standard' for this return value.
558 */
559 spin_lock(&pcwd_private.io_lock);
560 *temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32;
561 spin_unlock(&pcwd_private.io_lock);
562
563 if (debug >= DEBUG) {
564 printk(KERN_DEBUG PFX "temperature is: %d F\n",
565 *temperature);
566 }
567
568 return 0;
569}
570
571/*
572 * /dev/watchdog handling
573 */
574
575static int pcwd_ioctl(struct inode *inode, struct file *file,
576 unsigned int cmd, unsigned long arg)
577{
578 int rv;
579 int status;
580 int temperature;
581 int new_heartbeat;
582 int __user *argp = (int __user *)arg;
583 static struct watchdog_info ident = {
584 .options = WDIOF_OVERHEAT |
585 WDIOF_CARDRESET |
586 WDIOF_KEEPALIVEPING |
587 WDIOF_SETTIMEOUT |
588 WDIOF_MAGICCLOSE,
589 .firmware_version = 1,
590 .identity = "PCWD",
591 };
592
593 switch(cmd) {
594 default:
595 return -ENOTTY;
596
597 case WDIOC_GETSUPPORT:
598 if(copy_to_user(argp, &ident, sizeof(ident)))
599 return -EFAULT;
600 return 0;
601
602 case WDIOC_GETSTATUS:
603 pcwd_get_status(&status);
604 return put_user(status, argp);
605
606 case WDIOC_GETBOOTSTATUS:
607 return put_user(pcwd_private.boot_status, argp);
608
609 case WDIOC_GETTEMP:
610 if (pcwd_get_temperature(&temperature))
611 return -EFAULT;
612
613 return put_user(temperature, argp);
614
615 case WDIOC_SETOPTIONS:
616 if (pcwd_private.revision == PCWD_REVISION_C)
617 {
618 if(copy_from_user(&rv, argp, sizeof(int)))
619 return -EFAULT;
620
621 if (rv & WDIOS_DISABLECARD)
622 {
623 return pcwd_stop();
624 }
625
626 if (rv & WDIOS_ENABLECARD)
627 {
628 return pcwd_start();
629 }
630
631 if (rv & WDIOS_TEMPPANIC)
632 {
633 temp_panic = 1;
634 }
635 }
636 return -EINVAL;
637
638 case WDIOC_KEEPALIVE:
639 pcwd_keepalive();
640 return 0;
641
642 case WDIOC_SETTIMEOUT:
643 if (get_user(new_heartbeat, argp))
644 return -EFAULT;
645
646 if (pcwd_set_heartbeat(new_heartbeat))
647 return -EINVAL;
648
649 pcwd_keepalive();
650 /* Fall */
651
652 case WDIOC_GETTIMEOUT:
653 return put_user(heartbeat, argp);
654 }
655
656 return 0;
657}
658
659static ssize_t pcwd_write(struct file *file, const char __user *buf, size_t len,
660 loff_t *ppos)
661{
662 if (len) {
663 if (!nowayout) {
664 size_t i;
665
666 /* In case it was set long ago */
667 expect_close = 0;
668
669 for (i = 0; i != len; i++) {
670 char c;
671
672 if (get_user(c, buf + i))
673 return -EFAULT;
674 if (c == 'V')
675 expect_close = 42;
676 }
677 }
678 pcwd_keepalive();
679 }
680 return len;
681}
682
683static int pcwd_open(struct inode *inode, struct file *file)
684{
685 if (!atomic_dec_and_test(&open_allowed) ) {
686 if (debug >= VERBOSE)
687 printk(KERN_ERR PFX "Attempt to open already opened device.\n");
688 atomic_inc( &open_allowed );
689 return -EBUSY;
690 }
691
692 if (nowayout)
693 __module_get(THIS_MODULE);
694
695 /* Activate */
696 pcwd_start();
697 pcwd_keepalive();
698 return nonseekable_open(inode, file);
699}
700
701static int pcwd_close(struct inode *inode, struct file *file)
702{
703 if (expect_close == 42) {
704 pcwd_stop();
705 } else {
706 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
707 pcwd_keepalive();
708 }
709 expect_close = 0;
710 atomic_inc( &open_allowed );
711 return 0;
712}
713
714/*
715 * /dev/temperature handling
716 */
717
718static ssize_t pcwd_temp_read(struct file *file, char __user *buf, size_t count,
719 loff_t *ppos)
720{
721 int temperature;
722
723 if (pcwd_get_temperature(&temperature))
724 return -EFAULT;
725
726 if (copy_to_user(buf, &temperature, 1))
727 return -EFAULT;
728
729 return 1;
730}
731
732static int pcwd_temp_open(struct inode *inode, struct file *file)
733{
734 if (!pcwd_private.supports_temp)
735 return -ENODEV;
736
737 return nonseekable_open(inode, file);
738}
739
740static int pcwd_temp_close(struct inode *inode, struct file *file)
741{
742 return 0;
743}
744
745/*
746 * Kernel Interfaces
747 */
748
749static const struct file_operations pcwd_fops = {
750 .owner = THIS_MODULE,
751 .llseek = no_llseek,
752 .write = pcwd_write,
753 .ioctl = pcwd_ioctl,
754 .open = pcwd_open,
755 .release = pcwd_close,
756};
757
758static struct miscdevice pcwd_miscdev = {
759 .minor = WATCHDOG_MINOR,
760 .name = "watchdog",
761 .fops = &pcwd_fops,
762};
763
764static const struct file_operations pcwd_temp_fops = {
765 .owner = THIS_MODULE,
766 .llseek = no_llseek,
767 .read = pcwd_temp_read,
768 .open = pcwd_temp_open,
769 .release = pcwd_temp_close,
770};
771
772static struct miscdevice temp_miscdev = {
773 .minor = TEMP_MINOR,
774 .name = "temperature",
775 .fops = &pcwd_temp_fops,
776};
777
778/*
779 * Init & exit routines
780 */
781
782static inline int get_revision(void)
783{
784 int r = PCWD_REVISION_C;
785
786 spin_lock(&pcwd_private.io_lock);
787 /* REV A cards use only 2 io ports; test
788 * presumes a floating bus reads as 0xff. */
789 if ((inb(pcwd_private.io_addr + 2) == 0xFF) ||
790 (inb(pcwd_private.io_addr + 3) == 0xFF))
791 r=PCWD_REVISION_A;
792 spin_unlock(&pcwd_private.io_lock);
793
794 return r;
795}
796
797/*
798 * The ISA cards have a heartbeat bit in one of the registers, which
799 * register is card dependent. The heartbeat bit is monitored, and if
800 * found, is considered proof that a Berkshire card has been found.
801 * The initial rate is once per second at board start up, then twice
802 * per second for normal operation.
803 */
804static int __devinit pcwd_isa_match(struct device *dev, unsigned int id)
805{
806 int base_addr=pcwd_ioports[id];
807 int port0, last_port0; /* Reg 0, in case it's REV A */
808 int port1, last_port1; /* Register 1 for REV C cards */
809 int i;
810 int retval;
811
812 if (debug >= DEBUG)
813 printk(KERN_DEBUG PFX "pcwd_isa_match id=%d\n",
814 id);
815
816 if (!request_region (base_addr, 4, "PCWD")) {
817 printk(KERN_INFO PFX "Port 0x%04x unavailable\n", base_addr);
818 return 0;
819 }
820
821 retval = 0;
822
823 port0 = inb_p(base_addr); /* For REV A boards */
824 port1 = inb_p(base_addr + 1); /* For REV C boards */
825 if (port0 != 0xff || port1 != 0xff) {
826 /* Not an 'ff' from a floating bus, so must be a card! */
827 for (i = 0; i < 4; ++i) {
828
829 msleep(500);
830
831 last_port0 = port0;
832 last_port1 = port1;
833
834 port0 = inb_p(base_addr);
835 port1 = inb_p(base_addr + 1);
836
837 /* Has either hearbeat bit changed? */
838 if ((port0 ^ last_port0) & WD_HRTBT ||
839 (port1 ^ last_port1) & WD_REVC_HRBT) {
840 retval = 1;
841 break;
842 }
843 }
844 }
845 release_region (base_addr, 4);
846
847 return retval;
848}
849
850static int __devinit pcwd_isa_probe(struct device *dev, unsigned int id)
851{
852 int ret;
853
854 if (debug >= DEBUG)
855 printk(KERN_DEBUG PFX "pcwd_isa_probe id=%d\n",
856 id);
857
858 cards_found++;
859 if (cards_found == 1)
860 printk(KERN_INFO PFX "v%s Ken Hollis (kenji@bitgate.com)\n", WD_VER);
861
862 if (cards_found > 1) {
863 printk(KERN_ERR PFX "This driver only supports 1 device\n");
864 return -ENODEV;
865 }
866
867 if (pcwd_ioports[id] == 0x0000) {
868 printk(KERN_ERR PFX "No I/O-Address for card detected\n");
869 return -ENODEV;
870 }
871 pcwd_private.io_addr = pcwd_ioports[id];
872
873 spin_lock_init(&pcwd_private.io_lock);
874
875 /* Check card's revision */
876 pcwd_private.revision = get_revision();
877
878 if (!request_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4, "PCWD")) {
879 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
880 pcwd_private.io_addr);
881 ret=-EIO;
882 goto error_request_region;
883 }
884
885 /* Initial variables */
886 pcwd_private.supports_temp = 0;
887 temp_panic = 0;
888 pcwd_private.boot_status = 0x0000;
889
890 /* get the boot_status */
891 pcwd_get_status(&pcwd_private.boot_status);
892
893 /* clear the "card caused reboot" flag */
894 pcwd_clear_status();
895
896 setup_timer(&pcwd_private.timer, pcwd_timer_ping, 0);
897
898 /* Disable the board */
899 pcwd_stop();
900
901 /* Check whether or not the card supports the temperature device */
902 pcwd_check_temperature_support();
903
904 /* Show info about the card itself */
905 pcwd_show_card_info();
906
907 /* If heartbeat = 0 then we use the heartbeat from the dip-switches */
908 if (heartbeat == 0)
909 heartbeat = heartbeat_tbl[(pcwd_get_option_switches() & 0x07)];
910
911 /* Check that the heartbeat value is within it's range ; if not reset to the default */
912 if (pcwd_set_heartbeat(heartbeat)) {
913 pcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
914 printk(KERN_INFO PFX "heartbeat value must be 2<=heartbeat<=7200, using %d\n",
915 WATCHDOG_HEARTBEAT);
916 }
917
918 if (pcwd_private.supports_temp) {
919 ret = misc_register(&temp_miscdev);
920 if (ret) {
921 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
922 TEMP_MINOR, ret);
923 goto error_misc_register_temp;
924 }
925 }
926
927 ret = misc_register(&pcwd_miscdev);
928 if (ret) {
929 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
930 WATCHDOG_MINOR, ret);
931 goto error_misc_register_watchdog;
932 }
933
934 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
935 heartbeat, nowayout);
936
937 return 0;
938
939error_misc_register_watchdog:
940 if (pcwd_private.supports_temp)
941 misc_deregister(&temp_miscdev);
942error_misc_register_temp:
943 release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
944error_request_region:
945 pcwd_private.io_addr = 0x0000;
946 cards_found--;
947 return ret;
948}
949
950static int __devexit pcwd_isa_remove(struct device *dev, unsigned int id)
951{
952 if (debug >= DEBUG)
953 printk(KERN_DEBUG PFX "pcwd_isa_remove id=%d\n",
954 id);
955
956 if (!pcwd_private.io_addr)
957 return 1;
958
959 /* Disable the board */
960 if (!nowayout)
961 pcwd_stop();
962
963 /* Deregister */
964 misc_deregister(&pcwd_miscdev);
965 if (pcwd_private.supports_temp)
966 misc_deregister(&temp_miscdev);
967 release_region(pcwd_private.io_addr, (pcwd_private.revision == PCWD_REVISION_A) ? 2 : 4);
968 pcwd_private.io_addr = 0x0000;
969 cards_found--;
970
971 return 0;
972}
973
974static void pcwd_isa_shutdown(struct device *dev, unsigned int id)
975{
976 if (debug >= DEBUG)
977 printk(KERN_DEBUG PFX "pcwd_isa_shutdown id=%d\n",
978 id);
979
980 pcwd_stop();
981}
982
983static struct isa_driver pcwd_isa_driver = {
984 .match = pcwd_isa_match,
985 .probe = pcwd_isa_probe,
986 .remove = __devexit_p(pcwd_isa_remove),
987 .shutdown = pcwd_isa_shutdown,
988 .driver = {
989 .owner = THIS_MODULE,
990 .name = WATCHDOG_NAME,
991 },
992};
993
994static int __init pcwd_init_module(void)
995{
996 return isa_register_driver(&pcwd_isa_driver, PCWD_ISA_NR_CARDS);
997}
998
999static void __exit pcwd_cleanup_module(void)
1000{
1001 isa_unregister_driver(&pcwd_isa_driver);
1002 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
1003}
1004
1005module_init(pcwd_init_module);
1006module_exit(pcwd_cleanup_module);
1007
1008MODULE_AUTHOR("Ken Hollis <kenji@bitgate.com>, Wim Van Sebroeck <wim@iguana.be>");
1009MODULE_DESCRIPTION("Berkshire ISA-PC Watchdog driver");
1010MODULE_VERSION(WATCHDOG_VERSION);
1011MODULE_LICENSE("GPL");
1012MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
1013MODULE_ALIAS_MISCDEV(TEMP_MINOR);
diff --git a/drivers/watchdog/pcwd_pci.c b/drivers/watchdog/pcwd_pci.c
new file mode 100644
index 000000000000..61a89e959642
--- /dev/null
+++ b/drivers/watchdog/pcwd_pci.c
@@ -0,0 +1,832 @@
1/*
2 * Berkshire PCI-PC Watchdog Card Driver
3 *
4 * (c) Copyright 2003-2007 Wim Van Sebroeck <wim@iguana.be>.
5 *
6 * Based on source code of the following authors:
7 * Ken Hollis <kenji@bitgate.com>,
8 * Lindsay Harris <lindsay@bluegum.com>,
9 * Alan Cox <alan@redhat.com>,
10 * Matt Domsch <Matt_Domsch@dell.com>,
11 * Rob Radez <rob@osinvestor.com>
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
17 *
18 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
19 * provide warranty for any of this software. This material is
20 * provided "AS-IS" and at no charge.
21 */
22
23/*
24 * A bells and whistles driver is available from:
25 * http://www.kernel.org/pub/linux/kernel/people/wim/pcwd/pcwd_pci/
26 *
27 * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
28 */
29
30/*
31 * Includes, defines, variables, module parameters, ...
32 */
33
34#include <linux/module.h> /* For module specific items */
35#include <linux/moduleparam.h> /* For new moduleparam's */
36#include <linux/types.h> /* For standard types (like size_t) */
37#include <linux/errno.h> /* For the -ENODEV/... values */
38#include <linux/kernel.h> /* For printk/panic/... */
39#include <linux/delay.h> /* For mdelay function */
40#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
41#include <linux/watchdog.h> /* For the watchdog specific items */
42#include <linux/notifier.h> /* For notifier support */
43#include <linux/reboot.h> /* For reboot_notifier stuff */
44#include <linux/init.h> /* For __init/__exit/... */
45#include <linux/fs.h> /* For file operations */
46#include <linux/pci.h> /* For pci functions */
47#include <linux/ioport.h> /* For io-port access */
48#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
49
50#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
51#include <asm/io.h> /* For inb/outb/... */
52
53/* Module and version information */
54#define WATCHDOG_VERSION "1.03"
55#define WATCHDOG_DATE "21 Jan 2007"
56#define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog"
57#define WATCHDOG_NAME "pcwd_pci"
58#define PFX WATCHDOG_NAME ": "
59#define DRIVER_VERSION WATCHDOG_DRIVER_NAME " driver, v" WATCHDOG_VERSION " (" WATCHDOG_DATE ")\n"
60
61/* Stuff for the PCI ID's */
62#ifndef PCI_VENDOR_ID_QUICKLOGIC
63#define PCI_VENDOR_ID_QUICKLOGIC 0x11e3
64#endif
65
66#ifndef PCI_DEVICE_ID_WATCHDOG_PCIPCWD
67#define PCI_DEVICE_ID_WATCHDOG_PCIPCWD 0x5030
68#endif
69
70/*
71 * These are the defines that describe the control status bits for the
72 * PCI-PC Watchdog card.
73 */
74/* Port 1 : Control Status #1 */
75#define WD_PCI_WTRP 0x01 /* Watchdog Trip status */
76#define WD_PCI_HRBT 0x02 /* Watchdog Heartbeat */
77#define WD_PCI_TTRP 0x04 /* Temperature Trip status */
78#define WD_PCI_RL2A 0x08 /* Relay 2 Active */
79#define WD_PCI_RL1A 0x10 /* Relay 1 Active */
80#define WD_PCI_R2DS 0x40 /* Relay 2 Disable Temperature-trip/reset */
81#define WD_PCI_RLY2 0x80 /* Activate Relay 2 on the board */
82/* Port 2 : Control Status #2 */
83#define WD_PCI_WDIS 0x10 /* Watchdog Disable */
84#define WD_PCI_ENTP 0x20 /* Enable Temperature Trip Reset */
85#define WD_PCI_WRSP 0x40 /* Watchdog wrote response */
86#define WD_PCI_PCMD 0x80 /* PC has sent command */
87
88/* according to documentation max. time to process a command for the pci
89 * watchdog card is 100 ms, so we give it 150 ms to do it's job */
90#define PCI_COMMAND_TIMEOUT 150
91
92/* Watchdog's internal commands */
93#define CMD_GET_STATUS 0x04
94#define CMD_GET_FIRMWARE_VERSION 0x08
95#define CMD_READ_WATCHDOG_TIMEOUT 0x18
96#define CMD_WRITE_WATCHDOG_TIMEOUT 0x19
97#define CMD_GET_CLEAR_RESET_COUNT 0x84
98
99/* Watchdog's Dip Switch heartbeat values */
100static const int heartbeat_tbl [] = {
101 5, /* OFF-OFF-OFF = 5 Sec */
102 10, /* OFF-OFF-ON = 10 Sec */
103 30, /* OFF-ON-OFF = 30 Sec */
104 60, /* OFF-ON-ON = 1 Min */
105 300, /* ON-OFF-OFF = 5 Min */
106 600, /* ON-OFF-ON = 10 Min */
107 1800, /* ON-ON-OFF = 30 Min */
108 3600, /* ON-ON-ON = 1 hour */
109};
110
111/* We can only use 1 card due to the /dev/watchdog restriction */
112static int cards_found;
113
114/* internal variables */
115static int temp_panic;
116static unsigned long is_active;
117static char expect_release;
118static struct { /* this is private data for each PCI-PC watchdog card */
119 int supports_temp; /* Wether or not the card has a temperature device */
120 int boot_status; /* The card's boot status */
121 unsigned long io_addr; /* The cards I/O address */
122 spinlock_t io_lock; /* the lock for io operations */
123 struct pci_dev *pdev; /* the PCI-device */
124} pcipcwd_private;
125
126/* module parameters */
127#define QUIET 0 /* Default */
128#define VERBOSE 1 /* Verbose */
129#define DEBUG 2 /* print fancy stuff too */
130static int debug = QUIET;
131module_param(debug, int, 0);
132MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)");
133
134#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */
135static int heartbeat = WATCHDOG_HEARTBEAT;
136module_param(heartbeat, int, 0);
137MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
138
139static int nowayout = WATCHDOG_NOWAYOUT;
140module_param(nowayout, int, 0);
141MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
142
143/*
144 * Internal functions
145 */
146
147static int send_command(int cmd, int *msb, int *lsb)
148{
149 int got_response, count;
150
151 if (debug >= DEBUG)
152 printk(KERN_DEBUG PFX "sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x\n",
153 cmd, *msb, *lsb);
154
155 spin_lock(&pcipcwd_private.io_lock);
156 /* If a command requires data it should be written first.
157 * Data for commands with 8 bits of data should be written to port 4.
158 * Commands with 16 bits of data, should be written as LSB to port 4
159 * and MSB to port 5.
160 * After the required data has been written then write the command to
161 * port 6. */
162 outb_p(*lsb, pcipcwd_private.io_addr + 4);
163 outb_p(*msb, pcipcwd_private.io_addr + 5);
164 outb_p(cmd, pcipcwd_private.io_addr + 6);
165
166 /* wait till the pci card processed the command, signaled by
167 * the WRSP bit in port 2 and give it a max. timeout of
168 * PCI_COMMAND_TIMEOUT to process */
169 got_response = inb_p(pcipcwd_private.io_addr + 2) & WD_PCI_WRSP;
170 for (count = 0; (count < PCI_COMMAND_TIMEOUT) && (!got_response); count++) {
171 mdelay(1);
172 got_response = inb_p(pcipcwd_private.io_addr + 2) & WD_PCI_WRSP;
173 }
174
175 if (debug >= DEBUG) {
176 if (got_response) {
177 printk(KERN_DEBUG PFX "time to process command was: %d ms\n",
178 count);
179 } else {
180 printk(KERN_DEBUG PFX "card did not respond on command!\n");
181 }
182 }
183
184 if (got_response) {
185 /* read back response */
186 *lsb = inb_p(pcipcwd_private.io_addr + 4);
187 *msb = inb_p(pcipcwd_private.io_addr + 5);
188
189 /* clear WRSP bit */
190 inb_p(pcipcwd_private.io_addr + 6);
191
192 if (debug >= DEBUG)
193 printk(KERN_DEBUG PFX "received following data for cmd=0x%02x: msb=0x%02x lsb=0x%02x\n",
194 cmd, *msb, *lsb);
195 }
196
197 spin_unlock(&pcipcwd_private.io_lock);
198
199 return got_response;
200}
201
202static inline void pcipcwd_check_temperature_support(void)
203{
204 if (inb_p(pcipcwd_private.io_addr) != 0xF0)
205 pcipcwd_private.supports_temp = 1;
206}
207
208static int pcipcwd_get_option_switches(void)
209{
210 int option_switches;
211
212 option_switches = inb_p(pcipcwd_private.io_addr + 3);
213 return option_switches;
214}
215
216static void pcipcwd_show_card_info(void)
217{
218 int got_fw_rev, fw_rev_major, fw_rev_minor;
219 char fw_ver_str[20]; /* The cards firmware version */
220 int option_switches;
221
222 got_fw_rev = send_command(CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
223 if (got_fw_rev) {
224 sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
225 } else {
226 sprintf(fw_ver_str, "<card no answer>");
227 }
228
229 /* Get switch settings */
230 option_switches = pcipcwd_get_option_switches();
231
232 printk(KERN_INFO PFX "Found card at port 0x%04x (Firmware: %s) %s temp option\n",
233 (int) pcipcwd_private.io_addr, fw_ver_str,
234 (pcipcwd_private.supports_temp ? "with" : "without"));
235
236 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
237 option_switches,
238 ((option_switches & 0x10) ? "ON" : "OFF"),
239 ((option_switches & 0x08) ? "ON" : "OFF"));
240
241 if (pcipcwd_private.boot_status & WDIOF_CARDRESET)
242 printk(KERN_INFO PFX "Previous reset was caused by the Watchdog card\n");
243
244 if (pcipcwd_private.boot_status & WDIOF_OVERHEAT)
245 printk(KERN_INFO PFX "Card sensed a CPU Overheat\n");
246
247 if (pcipcwd_private.boot_status == 0)
248 printk(KERN_INFO PFX "No previous trip detected - Cold boot or reset\n");
249}
250
251static int pcipcwd_start(void)
252{
253 int stat_reg;
254
255 spin_lock(&pcipcwd_private.io_lock);
256 outb_p(0x00, pcipcwd_private.io_addr + 3);
257 udelay(1000);
258
259 stat_reg = inb_p(pcipcwd_private.io_addr + 2);
260 spin_unlock(&pcipcwd_private.io_lock);
261
262 if (stat_reg & WD_PCI_WDIS) {
263 printk(KERN_ERR PFX "Card timer not enabled\n");
264 return -1;
265 }
266
267 if (debug >= VERBOSE)
268 printk(KERN_DEBUG PFX "Watchdog started\n");
269
270 return 0;
271}
272
273static int pcipcwd_stop(void)
274{
275 int stat_reg;
276
277 spin_lock(&pcipcwd_private.io_lock);
278 outb_p(0xA5, pcipcwd_private.io_addr + 3);
279 udelay(1000);
280
281 outb_p(0xA5, pcipcwd_private.io_addr + 3);
282 udelay(1000);
283
284 stat_reg = inb_p(pcipcwd_private.io_addr + 2);
285 spin_unlock(&pcipcwd_private.io_lock);
286
287 if (!(stat_reg & WD_PCI_WDIS)) {
288 printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");
289 return -1;
290 }
291
292 if (debug >= VERBOSE)
293 printk(KERN_DEBUG PFX "Watchdog stopped\n");
294
295 return 0;
296}
297
298static int pcipcwd_keepalive(void)
299{
300 /* Re-trigger watchdog by writing to port 0 */
301 spin_lock(&pcipcwd_private.io_lock);
302 outb_p(0x42, pcipcwd_private.io_addr); /* send out any data */
303 spin_unlock(&pcipcwd_private.io_lock);
304
305 if (debug >= DEBUG)
306 printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n");
307
308 return 0;
309}
310
311static int pcipcwd_set_heartbeat(int t)
312{
313 int t_msb = t / 256;
314 int t_lsb = t % 256;
315
316 if ((t < 0x0001) || (t > 0xFFFF))
317 return -EINVAL;
318
319 /* Write new heartbeat to watchdog */
320 send_command(CMD_WRITE_WATCHDOG_TIMEOUT, &t_msb, &t_lsb);
321
322 heartbeat = t;
323 if (debug >= VERBOSE)
324 printk(KERN_DEBUG PFX "New heartbeat: %d\n",
325 heartbeat);
326
327 return 0;
328}
329
330static int pcipcwd_get_status(int *status)
331{
332 int control_status;
333
334 *status=0;
335 control_status = inb_p(pcipcwd_private.io_addr + 1);
336 if (control_status & WD_PCI_WTRP)
337 *status |= WDIOF_CARDRESET;
338 if (control_status & WD_PCI_TTRP) {
339 *status |= WDIOF_OVERHEAT;
340 if (temp_panic)
341 panic(PFX "Temperature overheat trip!\n");
342 }
343
344 if (debug >= DEBUG)
345 printk(KERN_DEBUG PFX "Control Status #1: 0x%02x\n",
346 control_status);
347
348 return 0;
349}
350
351static int pcipcwd_clear_status(void)
352{
353 int control_status;
354 int msb;
355 int reset_counter;
356
357 if (debug >= VERBOSE)
358 printk(KERN_INFO PFX "clearing watchdog trip status & LED\n");
359
360 control_status = inb_p(pcipcwd_private.io_addr + 1);
361
362 if (debug >= DEBUG) {
363 printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status);
364 printk(KERN_DEBUG PFX "sending: 0x%02x\n",
365 (control_status & WD_PCI_R2DS) | WD_PCI_WTRP);
366 }
367
368 /* clear trip status & LED and keep mode of relay 2 */
369 outb_p((control_status & WD_PCI_R2DS) | WD_PCI_WTRP, pcipcwd_private.io_addr + 1);
370
371 /* clear reset counter */
372 msb=0;
373 reset_counter=0xff;
374 send_command(CMD_GET_CLEAR_RESET_COUNT, &msb, &reset_counter);
375
376 if (debug >= DEBUG) {
377 printk(KERN_DEBUG PFX "reset count was: 0x%02x\n",
378 reset_counter);
379 }
380
381 return 0;
382}
383
384static int pcipcwd_get_temperature(int *temperature)
385{
386 *temperature = 0;
387 if (!pcipcwd_private.supports_temp)
388 return -ENODEV;
389
390 spin_lock(&pcipcwd_private.io_lock);
391 *temperature = inb_p(pcipcwd_private.io_addr);
392 spin_unlock(&pcipcwd_private.io_lock);
393
394 /*
395 * Convert celsius to fahrenheit, since this was
396 * the decided 'standard' for this return value.
397 */
398 *temperature = (*temperature * 9 / 5) + 32;
399
400 if (debug >= DEBUG) {
401 printk(KERN_DEBUG PFX "temperature is: %d F\n",
402 *temperature);
403 }
404
405 return 0;
406}
407
408static int pcipcwd_get_timeleft(int *time_left)
409{
410 int msb;
411 int lsb;
412
413 /* Read the time that's left before rebooting */
414 /* Note: if the board is not yet armed then we will read 0xFFFF */
415 send_command(CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
416
417 *time_left = (msb << 8) + lsb;
418
419 if (debug >= VERBOSE)
420 printk(KERN_DEBUG PFX "Time left before next reboot: %d\n",
421 *time_left);
422
423 return 0;
424}
425
426/*
427 * /dev/watchdog handling
428 */
429
430static ssize_t pcipcwd_write(struct file *file, const char __user *data,
431 size_t len, loff_t *ppos)
432{
433 /* See if we got the magic character 'V' and reload the timer */
434 if (len) {
435 if (!nowayout) {
436 size_t i;
437
438 /* note: just in case someone wrote the magic character
439 * five months ago... */
440 expect_release = 0;
441
442 /* scan to see whether or not we got the magic character */
443 for (i = 0; i != len; i++) {
444 char c;
445 if(get_user(c, data+i))
446 return -EFAULT;
447 if (c == 'V')
448 expect_release = 42;
449 }
450 }
451
452 /* someone wrote to us, we should reload the timer */
453 pcipcwd_keepalive();
454 }
455 return len;
456}
457
458static int pcipcwd_ioctl(struct inode *inode, struct file *file,
459 unsigned int cmd, unsigned long arg)
460{
461 void __user *argp = (void __user *)arg;
462 int __user *p = argp;
463 static struct watchdog_info ident = {
464 .options = WDIOF_OVERHEAT |
465 WDIOF_CARDRESET |
466 WDIOF_KEEPALIVEPING |
467 WDIOF_SETTIMEOUT |
468 WDIOF_MAGICCLOSE,
469 .firmware_version = 1,
470 .identity = WATCHDOG_DRIVER_NAME,
471 };
472
473 switch (cmd) {
474 case WDIOC_GETSUPPORT:
475 return copy_to_user(argp, &ident,
476 sizeof (ident)) ? -EFAULT : 0;
477
478 case WDIOC_GETSTATUS:
479 {
480 int status;
481
482 pcipcwd_get_status(&status);
483
484 return put_user(status, p);
485 }
486
487 case WDIOC_GETBOOTSTATUS:
488 return put_user(pcipcwd_private.boot_status, p);
489
490 case WDIOC_GETTEMP:
491 {
492 int temperature;
493
494 if (pcipcwd_get_temperature(&temperature))
495 return -EFAULT;
496
497 return put_user(temperature, p);
498 }
499
500 case WDIOC_KEEPALIVE:
501 pcipcwd_keepalive();
502 return 0;
503
504 case WDIOC_SETOPTIONS:
505 {
506 int new_options, retval = -EINVAL;
507
508 if (get_user (new_options, p))
509 return -EFAULT;
510
511 if (new_options & WDIOS_DISABLECARD) {
512 if (pcipcwd_stop())
513 return -EIO;
514 retval = 0;
515 }
516
517 if (new_options & WDIOS_ENABLECARD) {
518 if (pcipcwd_start())
519 return -EIO;
520 retval = 0;
521 }
522
523 if (new_options & WDIOS_TEMPPANIC) {
524 temp_panic = 1;
525 retval = 0;
526 }
527
528 return retval;
529 }
530
531 case WDIOC_SETTIMEOUT:
532 {
533 int new_heartbeat;
534
535 if (get_user(new_heartbeat, p))
536 return -EFAULT;
537
538 if (pcipcwd_set_heartbeat(new_heartbeat))
539 return -EINVAL;
540
541 pcipcwd_keepalive();
542 /* Fall */
543 }
544
545 case WDIOC_GETTIMEOUT:
546 return put_user(heartbeat, p);
547
548 case WDIOC_GETTIMELEFT:
549 {
550 int time_left;
551
552 if (pcipcwd_get_timeleft(&time_left))
553 return -EFAULT;
554
555 return put_user(time_left, p);
556 }
557
558 default:
559 return -ENOTTY;
560 }
561}
562
563static int pcipcwd_open(struct inode *inode, struct file *file)
564{
565 /* /dev/watchdog can only be opened once */
566 if (test_and_set_bit(0, &is_active)) {
567 if (debug >= VERBOSE)
568 printk(KERN_ERR PFX "Attempt to open already opened device.\n");
569 return -EBUSY;
570 }
571
572 /* Activate */
573 pcipcwd_start();
574 pcipcwd_keepalive();
575 return nonseekable_open(inode, file);
576}
577
578static int pcipcwd_release(struct inode *inode, struct file *file)
579{
580 /*
581 * Shut off the timer.
582 */
583 if (expect_release == 42) {
584 pcipcwd_stop();
585 } else {
586 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
587 pcipcwd_keepalive();
588 }
589 expect_release = 0;
590 clear_bit(0, &is_active);
591 return 0;
592}
593
594/*
595 * /dev/temperature handling
596 */
597
598static ssize_t pcipcwd_temp_read(struct file *file, char __user *data,
599 size_t len, loff_t *ppos)
600{
601 int temperature;
602
603 if (pcipcwd_get_temperature(&temperature))
604 return -EFAULT;
605
606 if (copy_to_user (data, &temperature, 1))
607 return -EFAULT;
608
609 return 1;
610}
611
612static int pcipcwd_temp_open(struct inode *inode, struct file *file)
613{
614 if (!pcipcwd_private.supports_temp)
615 return -ENODEV;
616
617 return nonseekable_open(inode, file);
618}
619
620static int pcipcwd_temp_release(struct inode *inode, struct file *file)
621{
622 return 0;
623}
624
625/*
626 * Notify system
627 */
628
629static int pcipcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
630{
631 if (code==SYS_DOWN || code==SYS_HALT) {
632 /* Turn the WDT off */
633 pcipcwd_stop();
634 }
635
636 return NOTIFY_DONE;
637}
638
639/*
640 * Kernel Interfaces
641 */
642
643static const struct file_operations pcipcwd_fops = {
644 .owner = THIS_MODULE,
645 .llseek = no_llseek,
646 .write = pcipcwd_write,
647 .ioctl = pcipcwd_ioctl,
648 .open = pcipcwd_open,
649 .release = pcipcwd_release,
650};
651
652static struct miscdevice pcipcwd_miscdev = {
653 .minor = WATCHDOG_MINOR,
654 .name = "watchdog",
655 .fops = &pcipcwd_fops,
656};
657
658static const struct file_operations pcipcwd_temp_fops = {
659 .owner = THIS_MODULE,
660 .llseek = no_llseek,
661 .read = pcipcwd_temp_read,
662 .open = pcipcwd_temp_open,
663 .release = pcipcwd_temp_release,
664};
665
666static struct miscdevice pcipcwd_temp_miscdev = {
667 .minor = TEMP_MINOR,
668 .name = "temperature",
669 .fops = &pcipcwd_temp_fops,
670};
671
672static struct notifier_block pcipcwd_notifier = {
673 .notifier_call = pcipcwd_notify_sys,
674};
675
676/*
677 * Init & exit routines
678 */
679
680static int __devinit pcipcwd_card_init(struct pci_dev *pdev,
681 const struct pci_device_id *ent)
682{
683 int ret = -EIO;
684
685 cards_found++;
686 if (cards_found == 1)
687 printk(KERN_INFO PFX DRIVER_VERSION);
688
689 if (cards_found > 1) {
690 printk(KERN_ERR PFX "This driver only supports 1 device\n");
691 return -ENODEV;
692 }
693
694 if (pci_enable_device(pdev)) {
695 printk(KERN_ERR PFX "Not possible to enable PCI Device\n");
696 return -ENODEV;
697 }
698
699 if (pci_resource_start(pdev, 0) == 0x0000) {
700 printk(KERN_ERR PFX "No I/O-Address for card detected\n");
701 ret = -ENODEV;
702 goto err_out_disable_device;
703 }
704
705 pcipcwd_private.pdev = pdev;
706 pcipcwd_private.io_addr = pci_resource_start(pdev, 0);
707
708 if (pci_request_regions(pdev, WATCHDOG_NAME)) {
709 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
710 (int) pcipcwd_private.io_addr);
711 ret = -EIO;
712 goto err_out_disable_device;
713 }
714
715 /* get the boot_status */
716 pcipcwd_get_status(&pcipcwd_private.boot_status);
717
718 /* clear the "card caused reboot" flag */
719 pcipcwd_clear_status();
720
721 /* disable card */
722 pcipcwd_stop();
723
724 /* Check whether or not the card supports the temperature device */
725 pcipcwd_check_temperature_support();
726
727 /* Show info about the card itself */
728 pcipcwd_show_card_info();
729
730 /* If heartbeat = 0 then we use the heartbeat from the dip-switches */
731 if (heartbeat == 0)
732 heartbeat = heartbeat_tbl[(pcipcwd_get_option_switches() & 0x07)];
733
734 /* Check that the heartbeat value is within it's range ; if not reset to the default */
735 if (pcipcwd_set_heartbeat(heartbeat)) {
736 pcipcwd_set_heartbeat(WATCHDOG_HEARTBEAT);
737 printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
738 WATCHDOG_HEARTBEAT);
739 }
740
741 ret = register_reboot_notifier(&pcipcwd_notifier);
742 if (ret != 0) {
743 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
744 ret);
745 goto err_out_release_region;
746 }
747
748 if (pcipcwd_private.supports_temp) {
749 ret = misc_register(&pcipcwd_temp_miscdev);
750 if (ret != 0) {
751 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
752 TEMP_MINOR, ret);
753 goto err_out_unregister_reboot;
754 }
755 }
756
757 ret = misc_register(&pcipcwd_miscdev);
758 if (ret != 0) {
759 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
760 WATCHDOG_MINOR, ret);
761 goto err_out_misc_deregister;
762 }
763
764 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
765 heartbeat, nowayout);
766
767 return 0;
768
769err_out_misc_deregister:
770 if (pcipcwd_private.supports_temp)
771 misc_deregister(&pcipcwd_temp_miscdev);
772err_out_unregister_reboot:
773 unregister_reboot_notifier(&pcipcwd_notifier);
774err_out_release_region:
775 pci_release_regions(pdev);
776err_out_disable_device:
777 pci_disable_device(pdev);
778 return ret;
779}
780
781static void __devexit pcipcwd_card_exit(struct pci_dev *pdev)
782{
783 /* Stop the timer before we leave */
784 if (!nowayout)
785 pcipcwd_stop();
786
787 /* Deregister */
788 misc_deregister(&pcipcwd_miscdev);
789 if (pcipcwd_private.supports_temp)
790 misc_deregister(&pcipcwd_temp_miscdev);
791 unregister_reboot_notifier(&pcipcwd_notifier);
792 pci_release_regions(pdev);
793 pci_disable_device(pdev);
794 cards_found--;
795}
796
797static struct pci_device_id pcipcwd_pci_tbl[] = {
798 { PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
799 PCI_ANY_ID, PCI_ANY_ID, },
800 { 0 }, /* End of list */
801};
802MODULE_DEVICE_TABLE(pci, pcipcwd_pci_tbl);
803
804static struct pci_driver pcipcwd_driver = {
805 .name = WATCHDOG_NAME,
806 .id_table = pcipcwd_pci_tbl,
807 .probe = pcipcwd_card_init,
808 .remove = __devexit_p(pcipcwd_card_exit),
809};
810
811static int __init pcipcwd_init_module(void)
812{
813 spin_lock_init(&pcipcwd_private.io_lock);
814
815 return pci_register_driver(&pcipcwd_driver);
816}
817
818static void __exit pcipcwd_cleanup_module(void)
819{
820 pci_unregister_driver(&pcipcwd_driver);
821
822 printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
823}
824
825module_init(pcipcwd_init_module);
826module_exit(pcipcwd_cleanup_module);
827
828MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
829MODULE_DESCRIPTION("Berkshire PCI-PC Watchdog driver");
830MODULE_LICENSE("GPL");
831MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
832MODULE_ALIAS_MISCDEV(TEMP_MINOR);
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c
new file mode 100644
index 000000000000..0f3fd6c9c354
--- /dev/null
+++ b/drivers/watchdog/pcwd_usb.c
@@ -0,0 +1,824 @@
1/*
2 * Berkshire USB-PC Watchdog Card Driver
3 *
4 * (c) Copyright 2004-2007 Wim Van Sebroeck <wim@iguana.be>.
5 *
6 * Based on source code of the following authors:
7 * Ken Hollis <kenji@bitgate.com>,
8 * Alan Cox <alan@redhat.com>,
9 * Matt Domsch <Matt_Domsch@dell.com>,
10 * Rob Radez <rob@osinvestor.com>,
11 * Greg Kroah-Hartman <greg@kroah.com>
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
17 *
18 * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
19 * provide warranty for any of this software. This material is
20 * provided "AS-IS" and at no charge.
21 *
22 * Thanks also to Simon Machell at Berkshire Products Inc. for
23 * providing the test hardware. More info is available at
24 * http://www.berkprod.com/ or http://www.pcwatchdog.com/
25 */
26
27#include <linux/module.h> /* For module specific items */
28#include <linux/moduleparam.h> /* For new moduleparam's */
29#include <linux/types.h> /* For standard types (like size_t) */
30#include <linux/errno.h> /* For the -ENODEV/... values */
31#include <linux/kernel.h> /* For printk/panic/... */
32#include <linux/delay.h> /* For mdelay function */
33#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
34#include <linux/watchdog.h> /* For the watchdog specific items */
35#include <linux/notifier.h> /* For notifier support */
36#include <linux/reboot.h> /* For reboot_notifier stuff */
37#include <linux/init.h> /* For __init/__exit/... */
38#include <linux/fs.h> /* For file operations */
39#include <linux/usb.h> /* For USB functions */
40#include <linux/slab.h> /* For kmalloc, ... */
41#include <linux/mutex.h> /* For mutex locking */
42#include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */
43
44#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
45
46
47#ifdef CONFIG_USB_DEBUG
48 static int debug = 1;
49#else
50 static int debug;
51#endif
52
53/* Use our own dbg macro */
54#undef dbg
55#define dbg(format, arg...) do { if (debug) printk(KERN_DEBUG PFX format "\n" , ## arg); } while (0)
56
57
58/* Module and Version Information */
59#define DRIVER_VERSION "1.02"
60#define DRIVER_DATE "21 Jan 2007"
61#define DRIVER_AUTHOR "Wim Van Sebroeck <wim@iguana.be>"
62#define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
63#define DRIVER_LICENSE "GPL"
64#define DRIVER_NAME "pcwd_usb"
65#define PFX DRIVER_NAME ": "
66
67MODULE_AUTHOR(DRIVER_AUTHOR);
68MODULE_DESCRIPTION(DRIVER_DESC);
69MODULE_LICENSE(DRIVER_LICENSE);
70MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
71MODULE_ALIAS_MISCDEV(TEMP_MINOR);
72
73/* Module Parameters */
74module_param(debug, int, 0);
75MODULE_PARM_DESC(debug, "Debug enabled or not");
76
77#define WATCHDOG_HEARTBEAT 0 /* default heartbeat = delay-time from dip-switches */
78static int heartbeat = WATCHDOG_HEARTBEAT;
79module_param(heartbeat, int, 0);
80MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
81
82static int nowayout = WATCHDOG_NOWAYOUT;
83module_param(nowayout, int, 0);
84MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
85
86/* The vendor and product id's for the USB-PC Watchdog card */
87#define USB_PCWD_VENDOR_ID 0x0c98
88#define USB_PCWD_PRODUCT_ID 0x1140
89
90/* table of devices that work with this driver */
91static struct usb_device_id usb_pcwd_table [] = {
92 { USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) },
93 { } /* Terminating entry */
94};
95MODULE_DEVICE_TABLE (usb, usb_pcwd_table);
96
97/* according to documentation max. time to process a command for the USB
98 * watchdog card is 100 or 200 ms, so we give it 250 ms to do it's job */
99#define USB_COMMAND_TIMEOUT 250
100
101/* Watchdog's internal commands */
102#define CMD_READ_TEMP 0x02 /* Read Temperature; Re-trigger Watchdog */
103#define CMD_TRIGGER CMD_READ_TEMP
104#define CMD_GET_STATUS 0x04 /* Get Status Information */
105#define CMD_GET_FIRMWARE_VERSION 0x08 /* Get Firmware Version */
106#define CMD_GET_DIP_SWITCH_SETTINGS 0x0c /* Get Dip Switch Settings */
107#define CMD_READ_WATCHDOG_TIMEOUT 0x18 /* Read Current Watchdog Time */
108#define CMD_WRITE_WATCHDOG_TIMEOUT 0x19 /* Write Current Watchdog Time */
109#define CMD_ENABLE_WATCHDOG 0x30 /* Enable / Disable Watchdog */
110#define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG
111
112/* Watchdog's Dip Switch heartbeat values */
113static const int heartbeat_tbl [] = {
114 5, /* OFF-OFF-OFF = 5 Sec */
115 10, /* OFF-OFF-ON = 10 Sec */
116 30, /* OFF-ON-OFF = 30 Sec */
117 60, /* OFF-ON-ON = 1 Min */
118 300, /* ON-OFF-OFF = 5 Min */
119 600, /* ON-OFF-ON = 10 Min */
120 1800, /* ON-ON-OFF = 30 Min */
121 3600, /* ON-ON-ON = 1 hour */
122};
123
124/* We can only use 1 card due to the /dev/watchdog restriction */
125static int cards_found;
126
127/* some internal variables */
128static unsigned long is_active;
129static char expect_release;
130
131/* Structure to hold all of our device specific stuff */
132struct usb_pcwd_private {
133 struct usb_device * udev; /* save off the usb device pointer */
134 struct usb_interface * interface; /* the interface for this device */
135
136 unsigned int interface_number; /* the interface number used for cmd's */
137
138 unsigned char * intr_buffer; /* the buffer to intr data */
139 dma_addr_t intr_dma; /* the dma address for the intr buffer */
140 size_t intr_size; /* the size of the intr buffer */
141 struct urb * intr_urb; /* the urb used for the intr pipe */
142
143 unsigned char cmd_command; /* The command that is reported back */
144 unsigned char cmd_data_msb; /* The data MSB that is reported back */
145 unsigned char cmd_data_lsb; /* The data LSB that is reported back */
146 atomic_t cmd_received; /* true if we received a report after a command */
147
148 int exists; /* Wether or not the device exists */
149 struct mutex mtx; /* locks this structure */
150};
151static struct usb_pcwd_private *usb_pcwd_device;
152
153/* prevent races between open() and disconnect() */
154static DEFINE_MUTEX(disconnect_mutex);
155
156/* local function prototypes */
157static int usb_pcwd_probe (struct usb_interface *interface, const struct usb_device_id *id);
158static void usb_pcwd_disconnect (struct usb_interface *interface);
159
160/* usb specific object needed to register this driver with the usb subsystem */
161static struct usb_driver usb_pcwd_driver = {
162 .name = DRIVER_NAME,
163 .probe = usb_pcwd_probe,
164 .disconnect = usb_pcwd_disconnect,
165 .id_table = usb_pcwd_table,
166};
167
168
169static void usb_pcwd_intr_done(struct urb *urb)
170{
171 struct usb_pcwd_private *usb_pcwd = (struct usb_pcwd_private *)urb->context;
172 unsigned char *data = usb_pcwd->intr_buffer;
173 int retval;
174
175 switch (urb->status) {
176 case 0: /* success */
177 break;
178 case -ECONNRESET: /* unlink */
179 case -ENOENT:
180 case -ESHUTDOWN:
181 /* this urb is terminated, clean up */
182 dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
183 return;
184 /* -EPIPE: should clear the halt */
185 default: /* error */
186 dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
187 goto resubmit;
188 }
189
190 dbg("received following data cmd=0x%02x msb=0x%02x lsb=0x%02x",
191 data[0], data[1], data[2]);
192
193 usb_pcwd->cmd_command = data[0];
194 usb_pcwd->cmd_data_msb = data[1];
195 usb_pcwd->cmd_data_lsb = data[2];
196
197 /* notify anyone waiting that the cmd has finished */
198 atomic_set (&usb_pcwd->cmd_received, 1);
199
200resubmit:
201 retval = usb_submit_urb (urb, GFP_ATOMIC);
202 if (retval)
203 printk(KERN_ERR PFX "can't resubmit intr, usb_submit_urb failed with result %d\n",
204 retval);
205}
206
207static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned char cmd,
208 unsigned char *msb, unsigned char *lsb)
209{
210 int got_response, count;
211 unsigned char buf[6];
212
213 /* We will not send any commands if the USB PCWD device does not exist */
214 if ((!usb_pcwd) || (!usb_pcwd->exists))
215 return -1;
216
217 /* The USB PC Watchdog uses a 6 byte report format. The board currently uses
218 * only 3 of the six bytes of the report. */
219 buf[0] = cmd; /* Byte 0 = CMD */
220 buf[1] = *msb; /* Byte 1 = Data MSB */
221 buf[2] = *lsb; /* Byte 2 = Data LSB */
222 buf[3] = buf[4] = buf[5] = 0; /* All other bytes not used */
223
224 dbg("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x",
225 buf[0], buf[1], buf[2]);
226
227 atomic_set (&usb_pcwd->cmd_received, 0);
228
229 if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0),
230 HID_REQ_SET_REPORT, HID_DT_REPORT,
231 0x0200, usb_pcwd->interface_number, buf, sizeof(buf),
232 USB_COMMAND_TIMEOUT) != sizeof(buf)) {
233 dbg("usb_pcwd_send_command: error in usb_control_msg for cmd 0x%x 0x%x 0x%x\n", cmd, *msb, *lsb);
234 }
235 /* wait till the usb card processed the command,
236 * with a max. timeout of USB_COMMAND_TIMEOUT */
237 got_response = 0;
238 for (count = 0; (count < USB_COMMAND_TIMEOUT) && (!got_response); count++) {
239 mdelay(1);
240 if (atomic_read (&usb_pcwd->cmd_received))
241 got_response = 1;
242 }
243
244 if ((got_response) && (cmd == usb_pcwd->cmd_command)) {
245 /* read back response */
246 *msb = usb_pcwd->cmd_data_msb;
247 *lsb = usb_pcwd->cmd_data_lsb;
248 }
249
250 return got_response;
251}
252
253static int usb_pcwd_start(struct usb_pcwd_private *usb_pcwd)
254{
255 unsigned char msb = 0x00;
256 unsigned char lsb = 0x00;
257 int retval;
258
259 /* Enable Watchdog */
260 retval = usb_pcwd_send_command(usb_pcwd, CMD_ENABLE_WATCHDOG, &msb, &lsb);
261
262 if ((retval == 0) || (lsb == 0)) {
263 printk(KERN_ERR PFX "Card did not acknowledge enable attempt\n");
264 return -1;
265 }
266
267 return 0;
268}
269
270static int usb_pcwd_stop(struct usb_pcwd_private *usb_pcwd)
271{
272 unsigned char msb = 0xA5;
273 unsigned char lsb = 0xC3;
274 int retval;
275
276 /* Disable Watchdog */
277 retval = usb_pcwd_send_command(usb_pcwd, CMD_DISABLE_WATCHDOG, &msb, &lsb);
278
279 if ((retval == 0) || (lsb != 0)) {
280 printk(KERN_ERR PFX "Card did not acknowledge disable attempt\n");
281 return -1;
282 }
283
284 return 0;
285}
286
287static int usb_pcwd_keepalive(struct usb_pcwd_private *usb_pcwd)
288{
289 unsigned char dummy;
290
291 /* Re-trigger Watchdog */
292 usb_pcwd_send_command(usb_pcwd, CMD_TRIGGER, &dummy, &dummy);
293
294 return 0;
295}
296
297static int usb_pcwd_set_heartbeat(struct usb_pcwd_private *usb_pcwd, int t)
298{
299 unsigned char msb = t / 256;
300 unsigned char lsb = t % 256;
301
302 if ((t < 0x0001) || (t > 0xFFFF))
303 return -EINVAL;
304
305 /* Write new heartbeat to watchdog */
306 usb_pcwd_send_command(usb_pcwd, CMD_WRITE_WATCHDOG_TIMEOUT, &msb, &lsb);
307
308 heartbeat = t;
309 return 0;
310}
311
312static int usb_pcwd_get_temperature(struct usb_pcwd_private *usb_pcwd, int *temperature)
313{
314 unsigned char msb, lsb;
315
316 usb_pcwd_send_command(usb_pcwd, CMD_READ_TEMP, &msb, &lsb);
317
318 /*
319 * Convert celsius to fahrenheit, since this was
320 * the decided 'standard' for this return value.
321 */
322 *temperature = (lsb * 9 / 5) + 32;
323
324 return 0;
325}
326
327static int usb_pcwd_get_timeleft(struct usb_pcwd_private *usb_pcwd, int *time_left)
328{
329 unsigned char msb, lsb;
330
331 /* Read the time that's left before rebooting */
332 /* Note: if the board is not yet armed then we will read 0xFFFF */
333 usb_pcwd_send_command(usb_pcwd, CMD_READ_WATCHDOG_TIMEOUT, &msb, &lsb);
334
335 *time_left = (msb << 8) + lsb;
336
337 return 0;
338}
339
340/*
341 * /dev/watchdog handling
342 */
343
344static ssize_t usb_pcwd_write(struct file *file, const char __user *data,
345 size_t len, loff_t *ppos)
346{
347 /* See if we got the magic character 'V' and reload the timer */
348 if (len) {
349 if (!nowayout) {
350 size_t i;
351
352 /* note: just in case someone wrote the magic character
353 * five months ago... */
354 expect_release = 0;
355
356 /* scan to see whether or not we got the magic character */
357 for (i = 0; i != len; i++) {
358 char c;
359 if(get_user(c, data+i))
360 return -EFAULT;
361 if (c == 'V')
362 expect_release = 42;
363 }
364 }
365
366 /* someone wrote to us, we should reload the timer */
367 usb_pcwd_keepalive(usb_pcwd_device);
368 }
369 return len;
370}
371
372static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
373 unsigned int cmd, unsigned long arg)
374{
375 void __user *argp = (void __user *)arg;
376 int __user *p = argp;
377 static struct watchdog_info ident = {
378 .options = WDIOF_KEEPALIVEPING |
379 WDIOF_SETTIMEOUT |
380 WDIOF_MAGICCLOSE,
381 .firmware_version = 1,
382 .identity = DRIVER_NAME,
383 };
384
385 switch (cmd) {
386 case WDIOC_GETSUPPORT:
387 return copy_to_user(argp, &ident,
388 sizeof (ident)) ? -EFAULT : 0;
389
390 case WDIOC_GETSTATUS:
391 case WDIOC_GETBOOTSTATUS:
392 return put_user(0, p);
393
394 case WDIOC_GETTEMP:
395 {
396 int temperature;
397
398 if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
399 return -EFAULT;
400
401 return put_user(temperature, p);
402 }
403
404 case WDIOC_KEEPALIVE:
405 usb_pcwd_keepalive(usb_pcwd_device);
406 return 0;
407
408 case WDIOC_SETOPTIONS:
409 {
410 int new_options, retval = -EINVAL;
411
412 if (get_user (new_options, p))
413 return -EFAULT;
414
415 if (new_options & WDIOS_DISABLECARD) {
416 usb_pcwd_stop(usb_pcwd_device);
417 retval = 0;
418 }
419
420 if (new_options & WDIOS_ENABLECARD) {
421 usb_pcwd_start(usb_pcwd_device);
422 retval = 0;
423 }
424
425 return retval;
426 }
427
428 case WDIOC_SETTIMEOUT:
429 {
430 int new_heartbeat;
431
432 if (get_user(new_heartbeat, p))
433 return -EFAULT;
434
435 if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat))
436 return -EINVAL;
437
438 usb_pcwd_keepalive(usb_pcwd_device);
439 /* Fall */
440 }
441
442 case WDIOC_GETTIMEOUT:
443 return put_user(heartbeat, p);
444
445 case WDIOC_GETTIMELEFT:
446 {
447 int time_left;
448
449 if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left))
450 return -EFAULT;
451
452 return put_user(time_left, p);
453 }
454
455 default:
456 return -ENOTTY;
457 }
458}
459
460static int usb_pcwd_open(struct inode *inode, struct file *file)
461{
462 /* /dev/watchdog can only be opened once */
463 if (test_and_set_bit(0, &is_active))
464 return -EBUSY;
465
466 /* Activate */
467 usb_pcwd_start(usb_pcwd_device);
468 usb_pcwd_keepalive(usb_pcwd_device);
469 return nonseekable_open(inode, file);
470}
471
472static int usb_pcwd_release(struct inode *inode, struct file *file)
473{
474 /*
475 * Shut off the timer.
476 */
477 if (expect_release == 42) {
478 usb_pcwd_stop(usb_pcwd_device);
479 } else {
480 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
481 usb_pcwd_keepalive(usb_pcwd_device);
482 }
483 expect_release = 0;
484 clear_bit(0, &is_active);
485 return 0;
486}
487
488/*
489 * /dev/temperature handling
490 */
491
492static ssize_t usb_pcwd_temperature_read(struct file *file, char __user *data,
493 size_t len, loff_t *ppos)
494{
495 int temperature;
496
497 if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
498 return -EFAULT;
499
500 if (copy_to_user(data, &temperature, 1))
501 return -EFAULT;
502
503 return 1;
504}
505
506static int usb_pcwd_temperature_open(struct inode *inode, struct file *file)
507{
508 return nonseekable_open(inode, file);
509}
510
511static int usb_pcwd_temperature_release(struct inode *inode, struct file *file)
512{
513 return 0;
514}
515
516/*
517 * Notify system
518 */
519
520static int usb_pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
521{
522 if (code==SYS_DOWN || code==SYS_HALT) {
523 /* Turn the WDT off */
524 usb_pcwd_stop(usb_pcwd_device);
525 }
526
527 return NOTIFY_DONE;
528}
529
530/*
531 * Kernel Interfaces
532 */
533
534static const struct file_operations usb_pcwd_fops = {
535 .owner = THIS_MODULE,
536 .llseek = no_llseek,
537 .write = usb_pcwd_write,
538 .ioctl = usb_pcwd_ioctl,
539 .open = usb_pcwd_open,
540 .release = usb_pcwd_release,
541};
542
543static struct miscdevice usb_pcwd_miscdev = {
544 .minor = WATCHDOG_MINOR,
545 .name = "watchdog",
546 .fops = &usb_pcwd_fops,
547};
548
549static const struct file_operations usb_pcwd_temperature_fops = {
550 .owner = THIS_MODULE,
551 .llseek = no_llseek,
552 .read = usb_pcwd_temperature_read,
553 .open = usb_pcwd_temperature_open,
554 .release = usb_pcwd_temperature_release,
555};
556
557static struct miscdevice usb_pcwd_temperature_miscdev = {
558 .minor = TEMP_MINOR,
559 .name = "temperature",
560 .fops = &usb_pcwd_temperature_fops,
561};
562
563static struct notifier_block usb_pcwd_notifier = {
564 .notifier_call = usb_pcwd_notify_sys,
565};
566
567/**
568 * usb_pcwd_delete
569 */
570static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd)
571{
572 usb_free_urb(usb_pcwd->intr_urb);
573 if (usb_pcwd->intr_buffer != NULL)
574 usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size,
575 usb_pcwd->intr_buffer, usb_pcwd->intr_dma);
576 kfree (usb_pcwd);
577}
578
579/**
580 * usb_pcwd_probe
581 *
582 * Called by the usb core when a new device is connected that it thinks
583 * this driver might be interested in.
584 */
585static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_device_id *id)
586{
587 struct usb_device *udev = interface_to_usbdev(interface);
588 struct usb_host_interface *iface_desc;
589 struct usb_endpoint_descriptor *endpoint;
590 struct usb_pcwd_private *usb_pcwd = NULL;
591 int pipe, maxp;
592 int retval = -ENOMEM;
593 int got_fw_rev;
594 unsigned char fw_rev_major, fw_rev_minor;
595 char fw_ver_str[20];
596 unsigned char option_switches, dummy;
597
598 cards_found++;
599 if (cards_found > 1) {
600 printk(KERN_ERR PFX "This driver only supports 1 device\n");
601 return -ENODEV;
602 }
603
604 /* get the active interface descriptor */
605 iface_desc = interface->cur_altsetting;
606
607 /* check out that we have a HID device */
608 if (!(iface_desc->desc.bInterfaceClass == USB_CLASS_HID)) {
609 printk(KERN_ERR PFX "The device isn't a Human Interface Device\n");
610 return -ENODEV;
611 }
612
613 /* check out the endpoint: it has to be Interrupt & IN */
614 endpoint = &iface_desc->endpoint[0].desc;
615
616 if (!((endpoint->bEndpointAddress & USB_DIR_IN) &&
617 ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
618 == USB_ENDPOINT_XFER_INT))) {
619 /* we didn't find a Interrupt endpoint with direction IN */
620 printk(KERN_ERR PFX "Couldn't find an INTR & IN endpoint\n");
621 return -ENODEV;
622 }
623
624 /* get a handle to the interrupt data pipe */
625 pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
626 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
627
628 /* allocate memory for our device and initialize it */
629 usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
630 if (usb_pcwd == NULL) {
631 printk(KERN_ERR PFX "Out of memory\n");
632 goto error;
633 }
634
635 usb_pcwd_device = usb_pcwd;
636
637 mutex_init(&usb_pcwd->mtx);
638 usb_pcwd->udev = udev;
639 usb_pcwd->interface = interface;
640 usb_pcwd->interface_number = iface_desc->desc.bInterfaceNumber;
641 usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8);
642
643 /* set up the memory buffer's */
644 if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma))) {
645 printk(KERN_ERR PFX "Out of memory\n");
646 goto error;
647 }
648
649 /* allocate the urb's */
650 usb_pcwd->intr_urb = usb_alloc_urb(0, GFP_KERNEL);
651 if (!usb_pcwd->intr_urb) {
652 printk(KERN_ERR PFX "Out of memory\n");
653 goto error;
654 }
655
656 /* initialise the intr urb's */
657 usb_fill_int_urb(usb_pcwd->intr_urb, udev, pipe,
658 usb_pcwd->intr_buffer, usb_pcwd->intr_size,
659 usb_pcwd_intr_done, usb_pcwd, endpoint->bInterval);
660 usb_pcwd->intr_urb->transfer_dma = usb_pcwd->intr_dma;
661 usb_pcwd->intr_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
662
663 /* register our interrupt URB with the USB system */
664 if (usb_submit_urb(usb_pcwd->intr_urb, GFP_KERNEL)) {
665 printk(KERN_ERR PFX "Problem registering interrupt URB\n");
666 retval = -EIO; /* failure */
667 goto error;
668 }
669
670 /* The device exists and can be communicated with */
671 usb_pcwd->exists = 1;
672
673 /* disable card */
674 usb_pcwd_stop(usb_pcwd);
675
676 /* Get the Firmware Version */
677 got_fw_rev = usb_pcwd_send_command(usb_pcwd, CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor);
678 if (got_fw_rev) {
679 sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor);
680 } else {
681 sprintf(fw_ver_str, "<card no answer>");
682 }
683
684 printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n",
685 fw_ver_str);
686
687 /* Get switch settings */
688 usb_pcwd_send_command(usb_pcwd, CMD_GET_DIP_SWITCH_SETTINGS, &dummy, &option_switches);
689
690 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
691 option_switches,
692 ((option_switches & 0x10) ? "ON" : "OFF"),
693 ((option_switches & 0x08) ? "ON" : "OFF"));
694
695 /* If heartbeat = 0 then we use the heartbeat from the dip-switches */
696 if (heartbeat == 0)
697 heartbeat = heartbeat_tbl[(option_switches & 0x07)];
698
699 /* Check that the heartbeat value is within it's range ; if not reset to the default */
700 if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) {
701 usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT);
702 printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
703 WATCHDOG_HEARTBEAT);
704 }
705
706 retval = register_reboot_notifier(&usb_pcwd_notifier);
707 if (retval != 0) {
708 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
709 retval);
710 goto error;
711 }
712
713 retval = misc_register(&usb_pcwd_temperature_miscdev);
714 if (retval != 0) {
715 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
716 TEMP_MINOR, retval);
717 goto err_out_unregister_reboot;
718 }
719
720 retval = misc_register(&usb_pcwd_miscdev);
721 if (retval != 0) {
722 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
723 WATCHDOG_MINOR, retval);
724 goto err_out_misc_deregister;
725 }
726
727 /* we can register the device now, as it is ready */
728 usb_set_intfdata (interface, usb_pcwd);
729
730 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
731 heartbeat, nowayout);
732
733 return 0;
734
735err_out_misc_deregister:
736 misc_deregister(&usb_pcwd_temperature_miscdev);
737err_out_unregister_reboot:
738 unregister_reboot_notifier(&usb_pcwd_notifier);
739error:
740 if (usb_pcwd)
741 usb_pcwd_delete(usb_pcwd);
742 usb_pcwd_device = NULL;
743 return retval;
744}
745
746
747/**
748 * usb_pcwd_disconnect
749 *
750 * Called by the usb core when the device is removed from the system.
751 *
752 * This routine guarantees that the driver will not submit any more urbs
753 * by clearing dev->udev.
754 */
755static void usb_pcwd_disconnect(struct usb_interface *interface)
756{
757 struct usb_pcwd_private *usb_pcwd;
758
759 /* prevent races with open() */
760 mutex_lock(&disconnect_mutex);
761
762 usb_pcwd = usb_get_intfdata (interface);
763 usb_set_intfdata (interface, NULL);
764
765 mutex_lock(&usb_pcwd->mtx);
766
767 /* Stop the timer before we leave */
768 if (!nowayout)
769 usb_pcwd_stop(usb_pcwd);
770
771 /* We should now stop communicating with the USB PCWD device */
772 usb_pcwd->exists = 0;
773
774 /* Deregister */
775 misc_deregister(&usb_pcwd_miscdev);
776 misc_deregister(&usb_pcwd_temperature_miscdev);
777 unregister_reboot_notifier(&usb_pcwd_notifier);
778
779 mutex_unlock(&usb_pcwd->mtx);
780
781 /* Delete the USB PCWD device */
782 usb_pcwd_delete(usb_pcwd);
783
784 cards_found--;
785
786 mutex_unlock(&disconnect_mutex);
787
788 printk(KERN_INFO PFX "USB PC Watchdog disconnected\n");
789}
790
791
792
793/**
794 * usb_pcwd_init
795 */
796static int __init usb_pcwd_init(void)
797{
798 int result;
799
800 /* register this driver with the USB subsystem */
801 result = usb_register(&usb_pcwd_driver);
802 if (result) {
803 printk(KERN_ERR PFX "usb_register failed. Error number %d\n",
804 result);
805 return result;
806 }
807
808 printk(KERN_INFO PFX DRIVER_DESC " v" DRIVER_VERSION " (" DRIVER_DATE ")\n");
809 return 0;
810}
811
812
813/**
814 * usb_pcwd_exit
815 */
816static void __exit usb_pcwd_exit(void)
817{
818 /* deregister this driver with the USB subsystem */
819 usb_deregister(&usb_pcwd_driver);
820}
821
822
823module_init (usb_pcwd_init);
824module_exit (usb_pcwd_exit);
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
new file mode 100644
index 000000000000..22f8873dd092
--- /dev/null
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -0,0 +1,358 @@
1/*
2 * drivers/char/watchdog/pnx4008_wdt.c
3 *
4 * Watchdog driver for PNX4008 board
5 *
6 * Authors: Dmitry Chigirev <source@mvista.com>,
7 * Vitaly Wool <vitalywool@gmail.com>
8 * Based on sa1100 driver,
9 * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
10 *
11 * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
12 * the terms of the GNU General Public License version 2. This program
13 * is licensed "as is" without any warranty of any kind, whether express
14 * or implied.
15 */
16
17#include <linux/module.h>
18#include <linux/moduleparam.h>
19#include <linux/types.h>
20#include <linux/kernel.h>
21#include <linux/fs.h>
22#include <linux/miscdevice.h>
23#include <linux/watchdog.h>
24#include <linux/init.h>
25#include <linux/bitops.h>
26#include <linux/ioport.h>
27#include <linux/device.h>
28#include <linux/platform_device.h>
29#include <linux/clk.h>
30#include <linux/spinlock.h>
31
32#include <asm/hardware.h>
33#include <asm/uaccess.h>
34#include <asm/io.h>
35
36#define MODULE_NAME "PNX4008-WDT: "
37
38/* WatchDog Timer - Chapter 23 Page 207 */
39
40#define DEFAULT_HEARTBEAT 19
41#define MAX_HEARTBEAT 60
42
43/* Watchdog timer register set definition */
44#define WDTIM_INT(p) ((p) + 0x0)
45#define WDTIM_CTRL(p) ((p) + 0x4)
46#define WDTIM_COUNTER(p) ((p) + 0x8)
47#define WDTIM_MCTRL(p) ((p) + 0xC)
48#define WDTIM_MATCH0(p) ((p) + 0x10)
49#define WDTIM_EMR(p) ((p) + 0x14)
50#define WDTIM_PULSE(p) ((p) + 0x18)
51#define WDTIM_RES(p) ((p) + 0x1C)
52
53/* WDTIM_INT bit definitions */
54#define MATCH_INT 1
55
56/* WDTIM_CTRL bit definitions */
57#define COUNT_ENAB 1
58#define RESET_COUNT (1<<1)
59#define DEBUG_EN (1<<2)
60
61/* WDTIM_MCTRL bit definitions */
62#define MR0_INT 1
63#undef RESET_COUNT0
64#define RESET_COUNT0 (1<<2)
65#define STOP_COUNT0 (1<<2)
66#define M_RES1 (1<<3)
67#define M_RES2 (1<<4)
68#define RESFRC1 (1<<5)
69#define RESFRC2 (1<<6)
70
71/* WDTIM_EMR bit definitions */
72#define EXT_MATCH0 1
73#define MATCH_OUTPUT_HIGH (2<<4) /*a MATCH_CTRL setting */
74
75/* WDTIM_RES bit definitions */
76#define WDOG_RESET 1 /* read only */
77
78#define WDOG_COUNTER_RATE 13000000 /*the counter clock is 13 MHz fixed */
79
80static int nowayout = WATCHDOG_NOWAYOUT;
81static int heartbeat = DEFAULT_HEARTBEAT;
82
83static spinlock_t io_lock;
84static unsigned long wdt_status;
85#define WDT_IN_USE 0
86#define WDT_OK_TO_CLOSE 1
87#define WDT_REGION_INITED 2
88#define WDT_DEVICE_INITED 3
89
90static unsigned long boot_status;
91
92static struct resource *wdt_mem;
93static void __iomem *wdt_base;
94struct clk *wdt_clk;
95
96static void wdt_enable(void)
97{
98 spin_lock(&io_lock);
99
100 if (wdt_clk)
101 clk_set_rate(wdt_clk, 1);
102
103 /* stop counter, initiate counter reset */
104 __raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
105 /*wait for reset to complete. 100% guarantee event */
106 while (__raw_readl(WDTIM_COUNTER(wdt_base)))
107 cpu_relax();
108 /* internal and external reset, stop after that */
109 __raw_writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0,
110 WDTIM_MCTRL(wdt_base));
111 /* configure match output */
112 __raw_writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
113 /* clear interrupt, just in case */
114 __raw_writel(MATCH_INT, WDTIM_INT(wdt_base));
115 /* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */
116 __raw_writel(0xFFFF, WDTIM_PULSE(wdt_base));
117 __raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
118 /*enable counter, stop when debugger active */
119 __raw_writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
120
121 spin_unlock(&io_lock);
122}
123
124static void wdt_disable(void)
125{
126 spin_lock(&io_lock);
127
128 __raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */
129 if (wdt_clk)
130 clk_set_rate(wdt_clk, 0);
131
132 spin_unlock(&io_lock);
133}
134
135static int pnx4008_wdt_open(struct inode *inode, struct file *file)
136{
137 if (test_and_set_bit(WDT_IN_USE, &wdt_status))
138 return -EBUSY;
139
140 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
141
142 wdt_enable();
143
144 return nonseekable_open(inode, file);
145}
146
147static ssize_t
148pnx4008_wdt_write(struct file *file, const char *data, size_t len,
149 loff_t * ppos)
150{
151 if (len) {
152 if (!nowayout) {
153 size_t i;
154
155 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
156
157 for (i = 0; i != len; i++) {
158 char c;
159
160 if (get_user(c, data + i))
161 return -EFAULT;
162 if (c == 'V')
163 set_bit(WDT_OK_TO_CLOSE, &wdt_status);
164 }
165 }
166 wdt_enable();
167 }
168
169 return len;
170}
171
172static struct watchdog_info ident = {
173 .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
174 WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
175 .identity = "PNX4008 Watchdog",
176};
177
178static int
179pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
180 unsigned long arg)
181{
182 int ret = -ENOTTY;
183 int time;
184
185 switch (cmd) {
186 case WDIOC_GETSUPPORT:
187 ret = copy_to_user((struct watchdog_info *)arg, &ident,
188 sizeof(ident)) ? -EFAULT : 0;
189 break;
190
191 case WDIOC_GETSTATUS:
192 ret = put_user(0, (int *)arg);
193 break;
194
195 case WDIOC_GETBOOTSTATUS:
196 ret = put_user(boot_status, (int *)arg);
197 break;
198
199 case WDIOC_SETTIMEOUT:
200 ret = get_user(time, (int *)arg);
201 if (ret)
202 break;
203
204 if (time <= 0 || time > MAX_HEARTBEAT) {
205 ret = -EINVAL;
206 break;
207 }
208
209 heartbeat = time;
210 wdt_enable();
211 /* Fall through */
212
213 case WDIOC_GETTIMEOUT:
214 ret = put_user(heartbeat, (int *)arg);
215 break;
216
217 case WDIOC_KEEPALIVE:
218 wdt_enable();
219 ret = 0;
220 break;
221 }
222 return ret;
223}
224
225static int pnx4008_wdt_release(struct inode *inode, struct file *file)
226{
227 if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status))
228 printk(KERN_WARNING "WATCHDOG: Device closed unexpectdly\n");
229
230 wdt_disable();
231 clear_bit(WDT_IN_USE, &wdt_status);
232 clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
233
234 return 0;
235}
236
237static const struct file_operations pnx4008_wdt_fops = {
238 .owner = THIS_MODULE,
239 .llseek = no_llseek,
240 .write = pnx4008_wdt_write,
241 .ioctl = pnx4008_wdt_ioctl,
242 .open = pnx4008_wdt_open,
243 .release = pnx4008_wdt_release,
244};
245
246static struct miscdevice pnx4008_wdt_miscdev = {
247 .minor = WATCHDOG_MINOR,
248 .name = "watchdog",
249 .fops = &pnx4008_wdt_fops,
250};
251
252static int pnx4008_wdt_probe(struct platform_device *pdev)
253{
254 int ret = 0, size;
255 struct resource *res;
256
257 spin_lock_init(&io_lock);
258
259 if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
260 heartbeat = DEFAULT_HEARTBEAT;
261
262 printk(KERN_INFO MODULE_NAME
263 "PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat);
264
265 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
266 if (res == NULL) {
267 printk(KERN_INFO MODULE_NAME
268 "failed to get memory region resouce\n");
269 return -ENOENT;
270 }
271
272 size = res->end - res->start + 1;
273 wdt_mem = request_mem_region(res->start, size, pdev->name);
274
275 if (wdt_mem == NULL) {
276 printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
277 return -ENOENT;
278 }
279 wdt_base = (void __iomem *)IO_ADDRESS(res->start);
280
281 wdt_clk = clk_get(&pdev->dev, "wdt_ck");
282 if (IS_ERR(wdt_clk)) {
283 ret = PTR_ERR(wdt_clk);
284 release_resource(wdt_mem);
285 kfree(wdt_mem);
286 goto out;
287 } else
288 clk_set_rate(wdt_clk, 1);
289
290 ret = misc_register(&pnx4008_wdt_miscdev);
291 if (ret < 0) {
292 printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
293 release_resource(wdt_mem);
294 kfree(wdt_mem);
295 clk_set_rate(wdt_clk, 0);
296 } else {
297 boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
298 WDIOF_CARDRESET : 0;
299 wdt_disable(); /*disable for now */
300 set_bit(WDT_DEVICE_INITED, &wdt_status);
301 }
302
303out:
304 return ret;
305}
306
307static int pnx4008_wdt_remove(struct platform_device *pdev)
308{
309 misc_deregister(&pnx4008_wdt_miscdev);
310 if (wdt_clk) {
311 clk_set_rate(wdt_clk, 0);
312 clk_put(wdt_clk);
313 wdt_clk = NULL;
314 }
315 if (wdt_mem) {
316 release_resource(wdt_mem);
317 kfree(wdt_mem);
318 wdt_mem = NULL;
319 }
320 return 0;
321}
322
323static struct platform_driver platform_wdt_driver = {
324 .driver = {
325 .name = "watchdog",
326 },
327 .probe = pnx4008_wdt_probe,
328 .remove = pnx4008_wdt_remove,
329};
330
331static int __init pnx4008_wdt_init(void)
332{
333 return platform_driver_register(&platform_wdt_driver);
334}
335
336static void __exit pnx4008_wdt_exit(void)
337{
338 return platform_driver_unregister(&platform_wdt_driver);
339}
340
341module_init(pnx4008_wdt_init);
342module_exit(pnx4008_wdt_exit);
343
344MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
345MODULE_DESCRIPTION("PNX4008 Watchdog Driver");
346
347module_param(heartbeat, int, 0);
348MODULE_PARM_DESC(heartbeat,
349 "Watchdog heartbeat period in seconds from 1 to "
350 __MODULE_STRING(MAX_HEARTBEAT) ", default "
351 __MODULE_STRING(DEFAULT_HEARTBEAT));
352
353module_param(nowayout, int, 0);
354MODULE_PARM_DESC(nowayout,
355 "Set to 1 to keep watchdog running after device release");
356
357MODULE_LICENSE("GPL");
358MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/rm9k_wdt.c b/drivers/watchdog/rm9k_wdt.c
new file mode 100644
index 000000000000..5c921e471564
--- /dev/null
+++ b/drivers/watchdog/rm9k_wdt.c
@@ -0,0 +1,420 @@
1/*
2 * Watchdog implementation for GPI h/w found on PMC-Sierra RM9xxx
3 * chips.
4 *
5 * Copyright (C) 2004 by Basler Vision Technologies AG
6 * Author: Thomas Koeller <thomas.koeller@baslerweb.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
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 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <linux/platform_device.h>
24#include <linux/module.h>
25#include <linux/moduleparam.h>
26#include <linux/interrupt.h>
27#include <linux/fs.h>
28#include <linux/reboot.h>
29#include <linux/notifier.h>
30#include <linux/miscdevice.h>
31#include <linux/watchdog.h>
32#include <asm/io.h>
33#include <asm/atomic.h>
34#include <asm/processor.h>
35#include <asm/uaccess.h>
36#include <asm/system.h>
37#include <asm/rm9k-ocd.h>
38
39#include <rm9k_wdt.h>
40
41
42#define CLOCK 125000000
43#define MAX_TIMEOUT_SECONDS 32
44#define CPCCR 0x0080
45#define CPGIG1SR 0x0044
46#define CPGIG1ER 0x0054
47
48
49/* Function prototypes */
50static irqreturn_t wdt_gpi_irqhdl(int, void *);
51static void wdt_gpi_start(void);
52static void wdt_gpi_stop(void);
53static void wdt_gpi_set_timeout(unsigned int);
54static int wdt_gpi_open(struct inode *, struct file *);
55static int wdt_gpi_release(struct inode *, struct file *);
56static ssize_t wdt_gpi_write(struct file *, const char __user *, size_t, loff_t *);
57static long wdt_gpi_ioctl(struct file *, unsigned int, unsigned long);
58static int wdt_gpi_notify(struct notifier_block *, unsigned long, void *);
59static const struct resource *wdt_gpi_get_resource(struct platform_device *, const char *, unsigned int);
60static int __init wdt_gpi_probe(struct device *);
61static int __exit wdt_gpi_remove(struct device *);
62
63
64static const char wdt_gpi_name[] = "wdt_gpi";
65static atomic_t opencnt;
66static int expect_close;
67static int locked;
68
69
70/* These are set from device resources */
71static void __iomem * wd_regs;
72static unsigned int wd_irq, wd_ctr;
73
74
75/* Module arguments */
76static int timeout = MAX_TIMEOUT_SECONDS;
77module_param(timeout, int, 0444);
78MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
79
80static unsigned long resetaddr = 0xbffdc200;
81module_param(resetaddr, ulong, 0444);
82MODULE_PARM_DESC(resetaddr, "Address to write to to force a reset");
83
84static unsigned long flagaddr = 0xbffdc104;
85module_param(flagaddr, ulong, 0444);
86MODULE_PARM_DESC(flagaddr, "Address to write to boot flags to");
87
88static int powercycle;
89module_param(powercycle, bool, 0444);
90MODULE_PARM_DESC(powercycle, "Cycle power if watchdog expires");
91
92static int nowayout = WATCHDOG_NOWAYOUT;
93module_param(nowayout, bool, 0444);
94MODULE_PARM_DESC(nowayout, "Watchdog cannot be disabled once started");
95
96
97/* Kernel interfaces */
98static const struct file_operations fops = {
99 .owner = THIS_MODULE,
100 .open = wdt_gpi_open,
101 .release = wdt_gpi_release,
102 .write = wdt_gpi_write,
103 .unlocked_ioctl = wdt_gpi_ioctl,
104};
105
106static struct miscdevice miscdev = {
107 .minor = WATCHDOG_MINOR,
108 .name = wdt_gpi_name,
109 .fops = &fops,
110};
111
112static struct notifier_block wdt_gpi_shutdown = {
113 .notifier_call = wdt_gpi_notify,
114};
115
116
117/* Interrupt handler */
118static irqreturn_t wdt_gpi_irqhdl(int irq, void *ctxt)
119{
120 if (!unlikely(__raw_readl(wd_regs + 0x0008) & 0x1))
121 return IRQ_NONE;
122 __raw_writel(0x1, wd_regs + 0x0008);
123
124
125 printk(KERN_CRIT "%s: watchdog expired - resetting system\n",
126 wdt_gpi_name);
127
128 *(volatile char *) flagaddr |= 0x01;
129 *(volatile char *) resetaddr = powercycle ? 0x01 : 0x2;
130 iob();
131 while (1)
132 cpu_relax();
133}
134
135
136/* Watchdog functions */
137static void wdt_gpi_start(void)
138{
139 u32 reg;
140
141 lock_titan_regs();
142 reg = titan_readl(CPGIG1ER);
143 titan_writel(reg | (0x100 << wd_ctr), CPGIG1ER);
144 iob();
145 unlock_titan_regs();
146}
147
148static void wdt_gpi_stop(void)
149{
150 u32 reg;
151
152 lock_titan_regs();
153 reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4));
154 titan_writel(reg, CPCCR);
155 reg = titan_readl(CPGIG1ER);
156 titan_writel(reg & ~(0x100 << wd_ctr), CPGIG1ER);
157 iob();
158 unlock_titan_regs();
159}
160
161static void wdt_gpi_set_timeout(unsigned int to)
162{
163 u32 reg;
164 const u32 wdval = (to * CLOCK) & ~0x0000000f;
165
166 lock_titan_regs();
167 reg = titan_readl(CPCCR) & ~(0xf << (wd_ctr * 4));
168 titan_writel(reg, CPCCR);
169 wmb();
170 __raw_writel(wdval, wd_regs + 0x0000);
171 wmb();
172 titan_writel(reg | (0x2 << (wd_ctr * 4)), CPCCR);
173 wmb();
174 titan_writel(reg | (0x5 << (wd_ctr * 4)), CPCCR);
175 iob();
176 unlock_titan_regs();
177}
178
179
180/* /dev/watchdog operations */
181static int wdt_gpi_open(struct inode *inode, struct file *file)
182{
183 int res;
184
185 if (unlikely(atomic_dec_if_positive(&opencnt) < 0))
186 return -EBUSY;
187
188 expect_close = 0;
189 if (locked) {
190 module_put(THIS_MODULE);
191 free_irq(wd_irq, &miscdev);
192 locked = 0;
193 }
194
195 res = request_irq(wd_irq, wdt_gpi_irqhdl, IRQF_SHARED | IRQF_DISABLED,
196 wdt_gpi_name, &miscdev);
197 if (unlikely(res))
198 return res;
199
200 wdt_gpi_set_timeout(timeout);
201 wdt_gpi_start();
202
203 printk(KERN_INFO "%s: watchdog started, timeout = %u seconds\n",
204 wdt_gpi_name, timeout);
205 return nonseekable_open(inode, file);
206}
207
208static int wdt_gpi_release(struct inode *inode, struct file *file)
209{
210 if (nowayout) {
211 printk(KERN_INFO "%s: no way out - watchdog left running\n",
212 wdt_gpi_name);
213 __module_get(THIS_MODULE);
214 locked = 1;
215 } else {
216 if (expect_close) {
217 wdt_gpi_stop();
218 free_irq(wd_irq, &miscdev);
219 printk(KERN_INFO "%s: watchdog stopped\n", wdt_gpi_name);
220 } else {
221 printk(KERN_CRIT "%s: unexpected close() -"
222 " watchdog left running\n",
223 wdt_gpi_name);
224 wdt_gpi_set_timeout(timeout);
225 __module_get(THIS_MODULE);
226 locked = 1;
227 }
228 }
229
230 atomic_inc(&opencnt);
231 return 0;
232}
233
234static ssize_t
235wdt_gpi_write(struct file *f, const char __user *d, size_t s, loff_t *o)
236{
237 char val;
238
239 wdt_gpi_set_timeout(timeout);
240 expect_close = (s > 0) && !get_user(val, d) && (val == 'V');
241 return s ? 1 : 0;
242}
243
244static long
245wdt_gpi_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
246{
247 long res = -ENOTTY;
248 const long size = _IOC_SIZE(cmd);
249 int stat;
250 void __user *argp = (void __user *)arg;
251 static struct watchdog_info wdinfo = {
252 .identity = "RM9xxx/GPI watchdog",
253 .firmware_version = 0,
254 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
255 };
256
257 if (unlikely(_IOC_TYPE(cmd) != WATCHDOG_IOCTL_BASE))
258 return -ENOTTY;
259
260 if ((_IOC_DIR(cmd) & _IOC_READ)
261 && !access_ok(VERIFY_WRITE, arg, size))
262 return -EFAULT;
263
264 if ((_IOC_DIR(cmd) & _IOC_WRITE)
265 && !access_ok(VERIFY_READ, arg, size))
266 return -EFAULT;
267
268 expect_close = 0;
269
270 switch (cmd) {
271 case WDIOC_GETSUPPORT:
272 wdinfo.options = nowayout ?
273 WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING :
274 WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE;
275 res = __copy_to_user(argp, &wdinfo, size) ? -EFAULT : size;
276 break;
277
278 case WDIOC_GETSTATUS:
279 break;
280
281 case WDIOC_GETBOOTSTATUS:
282 stat = (*(volatile char *) flagaddr & 0x01)
283 ? WDIOF_CARDRESET : 0;
284 res = __copy_to_user(argp, &stat, size) ?
285 -EFAULT : size;
286 break;
287
288 case WDIOC_SETOPTIONS:
289 break;
290
291 case WDIOC_KEEPALIVE:
292 wdt_gpi_set_timeout(timeout);
293 res = size;
294 break;
295
296 case WDIOC_SETTIMEOUT:
297 {
298 int val;
299 if (unlikely(__copy_from_user(&val, argp, size))) {
300 res = -EFAULT;
301 break;
302 }
303
304 if (val > MAX_TIMEOUT_SECONDS)
305 val = MAX_TIMEOUT_SECONDS;
306 timeout = val;
307 wdt_gpi_set_timeout(val);
308 res = size;
309 printk(KERN_INFO "%s: timeout set to %u seconds\n",
310 wdt_gpi_name, timeout);
311 }
312 break;
313
314 case WDIOC_GETTIMEOUT:
315 res = __copy_to_user(argp, &timeout, size) ?
316 -EFAULT : size;
317 break;
318 }
319
320 return res;
321}
322
323
324/* Shutdown notifier */
325static int
326wdt_gpi_notify(struct notifier_block *this, unsigned long code, void *unused)
327{
328 if (code == SYS_DOWN || code == SYS_HALT)
329 wdt_gpi_stop();
330
331 return NOTIFY_DONE;
332}
333
334
335/* Init & exit procedures */
336static const struct resource *
337wdt_gpi_get_resource(struct platform_device *pdv, const char *name,
338 unsigned int type)
339{
340 char buf[80];
341 if (snprintf(buf, sizeof buf, "%s_0", name) >= sizeof buf)
342 return NULL;
343 return platform_get_resource_byname(pdv, type, buf);
344}
345
346/* No hotplugging on the platform bus - use __init */
347static int __init wdt_gpi_probe(struct device *dev)
348{
349 int res;
350 struct platform_device * const pdv = to_platform_device(dev);
351 const struct resource
352 * const rr = wdt_gpi_get_resource(pdv, WDT_RESOURCE_REGS,
353 IORESOURCE_MEM),
354 * const ri = wdt_gpi_get_resource(pdv, WDT_RESOURCE_IRQ,
355 IORESOURCE_IRQ),
356 * const rc = wdt_gpi_get_resource(pdv, WDT_RESOURCE_COUNTER,
357 0);
358
359 if (unlikely(!rr || !ri || !rc))
360 return -ENXIO;
361
362 wd_regs = ioremap_nocache(rr->start, rr->end + 1 - rr->start);
363 if (unlikely(!wd_regs))
364 return -ENOMEM;
365 wd_irq = ri->start;
366 wd_ctr = rc->start;
367 res = misc_register(&miscdev);
368 if (res)
369 iounmap(wd_regs);
370 else
371 register_reboot_notifier(&wdt_gpi_shutdown);
372 return res;
373}
374
375static int __exit wdt_gpi_remove(struct device *dev)
376{
377 int res;
378
379 unregister_reboot_notifier(&wdt_gpi_shutdown);
380 res = misc_deregister(&miscdev);
381 iounmap(wd_regs);
382 wd_regs = NULL;
383 return res;
384}
385
386
387/* Device driver init & exit */
388static struct device_driver wdt_gpi_driver = {
389 .name = (char *) wdt_gpi_name,
390 .bus = &platform_bus_type,
391 .owner = THIS_MODULE,
392 .probe = wdt_gpi_probe,
393 .remove = __exit_p(wdt_gpi_remove),
394 .shutdown = NULL,
395 .suspend = NULL,
396 .resume = NULL,
397};
398
399static int __init wdt_gpi_init_module(void)
400{
401 atomic_set(&opencnt, 1);
402 if (timeout > MAX_TIMEOUT_SECONDS)
403 timeout = MAX_TIMEOUT_SECONDS;
404 return driver_register(&wdt_gpi_driver);
405}
406
407static void __exit wdt_gpi_cleanup_module(void)
408{
409 driver_unregister(&wdt_gpi_driver);
410}
411
412module_init(wdt_gpi_init_module);
413module_exit(wdt_gpi_cleanup_module);
414
415MODULE_AUTHOR("Thomas Koeller <thomas.koeller@baslerweb.com>");
416MODULE_DESCRIPTION("Basler eXcite watchdog driver for gpi devices");
417MODULE_VERSION("0.1");
418MODULE_LICENSE("GPL");
419MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
420
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
new file mode 100644
index 000000000000..5d1c15f83d23
--- /dev/null
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -0,0 +1,563 @@
1/* linux/drivers/char/watchdog/s3c2410_wdt.c
2 *
3 * Copyright (c) 2004 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 Watchdog Timer Support
7 *
8 * Based on, softdog.c by Alan Cox,
9 * (c) Copyright 1996 Alan Cox <alan@redhat.com>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 * Changelog:
26 * 05-Oct-2004 BJD Added semaphore init to stop crashes on open
27 * Fixed tmr_count / wdt_count confusion
28 * Added configurable debug
29 *
30 * 11-Jan-2005 BJD Fixed divide-by-2 in timeout code
31 *
32 * 25-Jan-2005 DA Added suspend/resume support
33 * Replaced reboot notifier with .shutdown method
34 *
35 * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
36*/
37
38#include <linux/module.h>
39#include <linux/moduleparam.h>
40#include <linux/types.h>
41#include <linux/timer.h>
42#include <linux/miscdevice.h>
43#include <linux/watchdog.h>
44#include <linux/fs.h>
45#include <linux/init.h>
46#include <linux/platform_device.h>
47#include <linux/interrupt.h>
48#include <linux/clk.h>
49
50#include <asm/uaccess.h>
51#include <asm/io.h>
52
53#include <asm/arch/map.h>
54
55#undef S3C_VA_WATCHDOG
56#define S3C_VA_WATCHDOG (0)
57
58#include <asm/plat-s3c/regs-watchdog.h>
59
60#define PFX "s3c2410-wdt: "
61
62#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
63#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
64
65static int nowayout = WATCHDOG_NOWAYOUT;
66static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
67static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
68static int soft_noboot = 0;
69static int debug = 0;
70
71module_param(tmr_margin, int, 0);
72module_param(tmr_atboot, int, 0);
73module_param(nowayout, int, 0);
74module_param(soft_noboot, int, 0);
75module_param(debug, int, 0);
76
77MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
78
79MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default=" __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
80
81MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
82
83MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
84
85MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug, (default 0)");
86
87
88typedef enum close_state {
89 CLOSE_STATE_NOT,
90 CLOSE_STATE_ALLOW=0x4021
91} close_state_t;
92
93static DECLARE_MUTEX(open_lock);
94
95static struct device *wdt_dev; /* platform device attached to */
96static struct resource *wdt_mem;
97static struct resource *wdt_irq;
98static struct clk *wdt_clock;
99static void __iomem *wdt_base;
100static unsigned int wdt_count;
101static close_state_t allow_close;
102
103/* watchdog control routines */
104
105#define DBG(msg...) do { \
106 if (debug) \
107 printk(KERN_INFO msg); \
108 } while(0)
109
110/* functions */
111
112static int s3c2410wdt_keepalive(void)
113{
114 writel(wdt_count, wdt_base + S3C2410_WTCNT);
115 return 0;
116}
117
118static int s3c2410wdt_stop(void)
119{
120 unsigned long wtcon;
121
122 wtcon = readl(wdt_base + S3C2410_WTCON);
123 wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
124 writel(wtcon, wdt_base + S3C2410_WTCON);
125
126 return 0;
127}
128
129static int s3c2410wdt_start(void)
130{
131 unsigned long wtcon;
132
133 s3c2410wdt_stop();
134
135 wtcon = readl(wdt_base + S3C2410_WTCON);
136 wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
137
138 if (soft_noboot) {
139 wtcon |= S3C2410_WTCON_INTEN;
140 wtcon &= ~S3C2410_WTCON_RSTEN;
141 } else {
142 wtcon &= ~S3C2410_WTCON_INTEN;
143 wtcon |= S3C2410_WTCON_RSTEN;
144 }
145
146 DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n",
147 __FUNCTION__, wdt_count, wtcon);
148
149 writel(wdt_count, wdt_base + S3C2410_WTDAT);
150 writel(wdt_count, wdt_base + S3C2410_WTCNT);
151 writel(wtcon, wdt_base + S3C2410_WTCON);
152
153 return 0;
154}
155
156static int s3c2410wdt_set_heartbeat(int timeout)
157{
158 unsigned int freq = clk_get_rate(wdt_clock);
159 unsigned int count;
160 unsigned int divisor = 1;
161 unsigned long wtcon;
162
163 if (timeout < 1)
164 return -EINVAL;
165
166 freq /= 128;
167 count = timeout * freq;
168
169 DBG("%s: count=%d, timeout=%d, freq=%d\n",
170 __FUNCTION__, count, timeout, freq);
171
172 /* if the count is bigger than the watchdog register,
173 then work out what we need to do (and if) we can
174 actually make this value
175 */
176
177 if (count >= 0x10000) {
178 for (divisor = 1; divisor <= 0x100; divisor++) {
179 if ((count / divisor) < 0x10000)
180 break;
181 }
182
183 if ((count / divisor) >= 0x10000) {
184 dev_err(wdt_dev, "timeout %d too big\n", timeout);
185 return -EINVAL;
186 }
187 }
188
189 tmr_margin = timeout;
190
191 DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",
192 __FUNCTION__, timeout, divisor, count, count/divisor);
193
194 count /= divisor;
195 wdt_count = count;
196
197 /* update the pre-scaler */
198 wtcon = readl(wdt_base + S3C2410_WTCON);
199 wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
200 wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
201
202 writel(count, wdt_base + S3C2410_WTDAT);
203 writel(wtcon, wdt_base + S3C2410_WTCON);
204
205 return 0;
206}
207
208/*
209 * /dev/watchdog handling
210 */
211
212static int s3c2410wdt_open(struct inode *inode, struct file *file)
213{
214 if(down_trylock(&open_lock))
215 return -EBUSY;
216
217 if (nowayout)
218 __module_get(THIS_MODULE);
219
220 allow_close = CLOSE_STATE_NOT;
221
222 /* start the timer */
223 s3c2410wdt_start();
224 return nonseekable_open(inode, file);
225}
226
227static int s3c2410wdt_release(struct inode *inode, struct file *file)
228{
229 /*
230 * Shut off the timer.
231 * Lock it in if it's a module and we set nowayout
232 */
233
234 if (allow_close == CLOSE_STATE_ALLOW) {
235 s3c2410wdt_stop();
236 } else {
237 dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n");
238 s3c2410wdt_keepalive();
239 }
240
241 allow_close = CLOSE_STATE_NOT;
242 up(&open_lock);
243 return 0;
244}
245
246static ssize_t s3c2410wdt_write(struct file *file, const char __user *data,
247 size_t len, loff_t *ppos)
248{
249 /*
250 * Refresh the timer.
251 */
252 if(len) {
253 if (!nowayout) {
254 size_t i;
255
256 /* In case it was set long ago */
257 allow_close = CLOSE_STATE_NOT;
258
259 for (i = 0; i != len; i++) {
260 char c;
261
262 if (get_user(c, data + i))
263 return -EFAULT;
264 if (c == 'V')
265 allow_close = CLOSE_STATE_ALLOW;
266 }
267 }
268
269 s3c2410wdt_keepalive();
270 }
271 return len;
272}
273
274#define OPTIONS WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE
275
276static struct watchdog_info s3c2410_wdt_ident = {
277 .options = OPTIONS,
278 .firmware_version = 0,
279 .identity = "S3C2410 Watchdog",
280};
281
282
283static int s3c2410wdt_ioctl(struct inode *inode, struct file *file,
284 unsigned int cmd, unsigned long arg)
285{
286 void __user *argp = (void __user *)arg;
287 int __user *p = argp;
288 int new_margin;
289
290 switch (cmd) {
291 default:
292 return -ENOTTY;
293
294 case WDIOC_GETSUPPORT:
295 return copy_to_user(argp, &s3c2410_wdt_ident,
296 sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0;
297
298 case WDIOC_GETSTATUS:
299 case WDIOC_GETBOOTSTATUS:
300 return put_user(0, p);
301
302 case WDIOC_KEEPALIVE:
303 s3c2410wdt_keepalive();
304 return 0;
305
306 case WDIOC_SETTIMEOUT:
307 if (get_user(new_margin, p))
308 return -EFAULT;
309
310 if (s3c2410wdt_set_heartbeat(new_margin))
311 return -EINVAL;
312
313 s3c2410wdt_keepalive();
314 return put_user(tmr_margin, p);
315
316 case WDIOC_GETTIMEOUT:
317 return put_user(tmr_margin, p);
318 }
319}
320
321/* kernel interface */
322
323static const struct file_operations s3c2410wdt_fops = {
324 .owner = THIS_MODULE,
325 .llseek = no_llseek,
326 .write = s3c2410wdt_write,
327 .ioctl = s3c2410wdt_ioctl,
328 .open = s3c2410wdt_open,
329 .release = s3c2410wdt_release,
330};
331
332static struct miscdevice s3c2410wdt_miscdev = {
333 .minor = WATCHDOG_MINOR,
334 .name = "watchdog",
335 .fops = &s3c2410wdt_fops,
336};
337
338/* interrupt handler code */
339
340static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
341{
342 dev_info(wdt_dev, "watchdog timer expired (irq)\n");
343
344 s3c2410wdt_keepalive();
345 return IRQ_HANDLED;
346}
347/* device interface */
348
349static int s3c2410wdt_probe(struct platform_device *pdev)
350{
351 struct resource *res;
352 struct device *dev;
353 unsigned int wtcon;
354 int started = 0;
355 int ret;
356 int size;
357
358 DBG("%s: probe=%p\n", __FUNCTION__, pdev);
359
360 dev = &pdev->dev;
361 wdt_dev = &pdev->dev;
362
363 /* get the memory region for the watchdog timer */
364
365 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
366 if (res == NULL) {
367 dev_err(dev, "no memory resource specified\n");
368 return -ENOENT;
369 }
370
371 size = (res->end-res->start)+1;
372 wdt_mem = request_mem_region(res->start, size, pdev->name);
373 if (wdt_mem == NULL) {
374 dev_err(dev, "failed to get memory region\n");
375 ret = -ENOENT;
376 goto err_req;
377 }
378
379 wdt_base = ioremap(res->start, size);
380 if (wdt_base == 0) {
381 dev_err(dev, "failed to ioremap() region\n");
382 ret = -EINVAL;
383 goto err_req;
384 }
385
386 DBG("probe: mapped wdt_base=%p\n", wdt_base);
387
388 wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
389 if (wdt_irq == NULL) {
390 dev_err(dev, "no irq resource specified\n");
391 ret = -ENOENT;
392 goto err_map;
393 }
394
395 ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
396 if (ret != 0) {
397 dev_err(dev, "failed to install irq (%d)\n", ret);
398 goto err_map;
399 }
400
401 wdt_clock = clk_get(&pdev->dev, "watchdog");
402 if (IS_ERR(wdt_clock)) {
403 dev_err(dev, "failed to find watchdog clock source\n");
404 ret = PTR_ERR(wdt_clock);
405 goto err_irq;
406 }
407
408 clk_enable(wdt_clock);
409
410 /* see if we can actually set the requested timer margin, and if
411 * not, try the default value */
412
413 if (s3c2410wdt_set_heartbeat(tmr_margin)) {
414 started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
415
416 if (started == 0) {
417 dev_info(dev,"tmr_margin value out of range, default %d used\n",
418 CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
419 } else {
420 dev_info(dev, "default timer value is out of range, cannot start\n");
421 }
422 }
423
424 ret = misc_register(&s3c2410wdt_miscdev);
425 if (ret) {
426 dev_err(dev, "cannot register miscdev on minor=%d (%d)\n",
427 WATCHDOG_MINOR, ret);
428 goto err_clk;
429 }
430
431 if (tmr_atboot && started == 0) {
432 dev_info(dev, "starting watchdog timer\n");
433 s3c2410wdt_start();
434 } else if (!tmr_atboot) {
435 /* if we're not enabling the watchdog, then ensure it is
436 * disabled if it has been left running from the bootloader
437 * or other source */
438
439 s3c2410wdt_stop();
440 }
441
442 /* print out a statement of readiness */
443
444 wtcon = readl(wdt_base + S3C2410_WTCON);
445
446 dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
447 (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in",
448 (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis",
449 (wtcon & S3C2410_WTCON_INTEN) ? "" : "en");
450
451 return 0;
452
453 err_clk:
454 clk_disable(wdt_clock);
455 clk_put(wdt_clock);
456
457 err_irq:
458 free_irq(wdt_irq->start, pdev);
459
460 err_map:
461 iounmap(wdt_base);
462
463 err_req:
464 release_resource(wdt_mem);
465 kfree(wdt_mem);
466
467 return ret;
468}
469
470static int s3c2410wdt_remove(struct platform_device *dev)
471{
472 release_resource(wdt_mem);
473 kfree(wdt_mem);
474 wdt_mem = NULL;
475
476 free_irq(wdt_irq->start, dev);
477 wdt_irq = NULL;
478
479 clk_disable(wdt_clock);
480 clk_put(wdt_clock);
481 wdt_clock = NULL;
482
483 iounmap(wdt_base);
484 misc_deregister(&s3c2410wdt_miscdev);
485 return 0;
486}
487
488static void s3c2410wdt_shutdown(struct platform_device *dev)
489{
490 s3c2410wdt_stop();
491}
492
493#ifdef CONFIG_PM
494
495static unsigned long wtcon_save;
496static unsigned long wtdat_save;
497
498static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state)
499{
500 /* Save watchdog state, and turn it off. */
501 wtcon_save = readl(wdt_base + S3C2410_WTCON);
502 wtdat_save = readl(wdt_base + S3C2410_WTDAT);
503
504 /* Note that WTCNT doesn't need to be saved. */
505 s3c2410wdt_stop();
506
507 return 0;
508}
509
510static int s3c2410wdt_resume(struct platform_device *dev)
511{
512 /* Restore watchdog state. */
513
514 writel(wtdat_save, wdt_base + S3C2410_WTDAT);
515 writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
516 writel(wtcon_save, wdt_base + S3C2410_WTCON);
517
518 printk(KERN_INFO PFX "watchdog %sabled\n",
519 (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
520
521 return 0;
522}
523
524#else
525#define s3c2410wdt_suspend NULL
526#define s3c2410wdt_resume NULL
527#endif /* CONFIG_PM */
528
529
530static struct platform_driver s3c2410wdt_driver = {
531 .probe = s3c2410wdt_probe,
532 .remove = s3c2410wdt_remove,
533 .shutdown = s3c2410wdt_shutdown,
534 .suspend = s3c2410wdt_suspend,
535 .resume = s3c2410wdt_resume,
536 .driver = {
537 .owner = THIS_MODULE,
538 .name = "s3c2410-wdt",
539 },
540};
541
542
543static char banner[] __initdata = KERN_INFO "S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics\n";
544
545static int __init watchdog_init(void)
546{
547 printk(banner);
548 return platform_driver_register(&s3c2410wdt_driver);
549}
550
551static void __exit watchdog_exit(void)
552{
553 platform_driver_unregister(&s3c2410wdt_driver);
554}
555
556module_init(watchdog_init);
557module_exit(watchdog_exit);
558
559MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, "
560 "Dimitry Andric <dimitry.andric@tomtom.com>");
561MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
562MODULE_LICENSE("GPL");
563MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c
new file mode 100644
index 000000000000..3475f47aaa45
--- /dev/null
+++ b/drivers/watchdog/sa1100_wdt.c
@@ -0,0 +1,190 @@
1/*
2 * Watchdog driver for the SA11x0/PXA2xx
3 *
4 * (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
5 * Based on SoftDog driver by Alan Cox <alan@redhat.com>
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 * Neither Oleg Drokin nor iXcelerator.com admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
17 *
18 * 27/11/2000 Initial release
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/miscdevice.h>
26#include <linux/watchdog.h>
27#include <linux/init.h>
28
29#ifdef CONFIG_ARCH_PXA
30#include <asm/arch/pxa-regs.h>
31#endif
32
33#include <asm/hardware.h>
34#include <asm/bitops.h>
35#include <asm/uaccess.h>
36
37#define OSCR_FREQ CLOCK_TICK_RATE
38
39static unsigned long sa1100wdt_users;
40static int pre_margin;
41static int boot_status;
42
43/*
44 * Allow only one person to hold it open
45 */
46static int sa1100dog_open(struct inode *inode, struct file *file)
47{
48 if (test_and_set_bit(1,&sa1100wdt_users))
49 return -EBUSY;
50
51 /* Activate SA1100 Watchdog timer */
52 OSMR3 = OSCR + pre_margin;
53 OSSR = OSSR_M3;
54 OWER = OWER_WME;
55 OIER |= OIER_E3;
56 return nonseekable_open(inode, file);
57}
58
59/*
60 * The watchdog cannot be disabled.
61 *
62 * Previous comments suggested that turning off the interrupt by
63 * clearing OIER[E3] would prevent the watchdog timing out but this
64 * does not appear to be true (at least on the PXA255).
65 */
66static int sa1100dog_release(struct inode *inode, struct file *file)
67{
68 printk(KERN_CRIT "WATCHDOG: Device closed - timer will not stop\n");
69
70 clear_bit(1, &sa1100wdt_users);
71
72 return 0;
73}
74
75static ssize_t sa1100dog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
76{
77 if (len)
78 /* Refresh OSMR3 timer. */
79 OSMR3 = OSCR + pre_margin;
80
81 return len;
82}
83
84static struct watchdog_info ident = {
85 .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
86 .identity = "SA1100/PXA255 Watchdog",
87};
88
89static int sa1100dog_ioctl(struct inode *inode, struct file *file,
90 unsigned int cmd, unsigned long arg)
91{
92 int ret = -ENOTTY;
93 int time;
94 void __user *argp = (void __user *)arg;
95 int __user *p = argp;
96
97 switch (cmd) {
98 case WDIOC_GETSUPPORT:
99 ret = copy_to_user(argp, &ident,
100 sizeof(ident)) ? -EFAULT : 0;
101 break;
102
103 case WDIOC_GETSTATUS:
104 ret = put_user(0, p);
105 break;
106
107 case WDIOC_GETBOOTSTATUS:
108 ret = put_user(boot_status, p);
109 break;
110
111 case WDIOC_SETTIMEOUT:
112 ret = get_user(time, p);
113 if (ret)
114 break;
115
116 if (time <= 0 || time > 255) {
117 ret = -EINVAL;
118 break;
119 }
120
121 pre_margin = OSCR_FREQ * time;
122 OSMR3 = OSCR + pre_margin;
123 /*fall through*/
124
125 case WDIOC_GETTIMEOUT:
126 ret = put_user(pre_margin / OSCR_FREQ, p);
127 break;
128
129 case WDIOC_KEEPALIVE:
130 OSMR3 = OSCR + pre_margin;
131 ret = 0;
132 break;
133 }
134 return ret;
135}
136
137static const struct file_operations sa1100dog_fops =
138{
139 .owner = THIS_MODULE,
140 .llseek = no_llseek,
141 .write = sa1100dog_write,
142 .ioctl = sa1100dog_ioctl,
143 .open = sa1100dog_open,
144 .release = sa1100dog_release,
145};
146
147static struct miscdevice sa1100dog_miscdev =
148{
149 .minor = WATCHDOG_MINOR,
150 .name = "watchdog",
151 .fops = &sa1100dog_fops,
152};
153
154static int margin __initdata = 60; /* (secs) Default is 1 minute */
155
156static int __init sa1100dog_init(void)
157{
158 int ret;
159
160 /*
161 * Read the reset status, and save it for later. If
162 * we suspend, RCSR will be cleared, and the watchdog
163 * reset reason will be lost.
164 */
165 boot_status = (RCSR & RCSR_WDR) ? WDIOF_CARDRESET : 0;
166 pre_margin = OSCR_FREQ * margin;
167
168 ret = misc_register(&sa1100dog_miscdev);
169 if (ret == 0)
170 printk("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
171 margin);
172 return ret;
173}
174
175static void __exit sa1100dog_exit(void)
176{
177 misc_deregister(&sa1100dog_miscdev);
178}
179
180module_init(sa1100dog_init);
181module_exit(sa1100dog_exit);
182
183MODULE_AUTHOR("Oleg Drokin <green@crimea.edu>");
184MODULE_DESCRIPTION("SA1100/PXA2xx Watchdog");
185
186module_param(margin, int, 0);
187MODULE_PARM_DESC(margin, "Watchdog margin in seconds (default 60s)");
188
189MODULE_LICENSE("GPL");
190MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sbc60xxwdt.c b/drivers/watchdog/sbc60xxwdt.c
new file mode 100644
index 000000000000..e4f3cb6090bc
--- /dev/null
+++ b/drivers/watchdog/sbc60xxwdt.c
@@ -0,0 +1,400 @@
1/*
2 * 60xx Single Board Computer Watchdog Timer driver for Linux 2.2.x
3 *
4 * Based on acquirewdt.c by Alan Cox.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * The author does NOT admit liability nor provide warranty for
12 * any of this software. This material is provided "AS-IS" in
13 * the hope that it may be useful for others.
14 *
15 * (c) Copyright 2000 Jakob Oestergaard <jakob@unthought.net>
16 *
17 * 12/4 - 2000 [Initial revision]
18 * 25/4 - 2000 Added /dev/watchdog support
19 * 09/5 - 2001 [smj@oro.net] fixed fop_write to "return 1" on success
20 * 12/4 - 2002 [rob@osinvestor.com] eliminate fop_read
21 * fix possible wdt_is_open race
22 * add CONFIG_WATCHDOG_NOWAYOUT support
23 * remove lock_kernel/unlock_kernel pairs
24 * added KERN_* to printk's
25 * got rid of extraneous comments
26 * changed watchdog_info to correctly reflect what the driver offers
27 * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT,
28 * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
29 * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces
30 * use module_param
31 * made timeout (the emulated heartbeat) a module_param
32 * made the keepalive ping an internal subroutine
33 * made wdt_stop and wdt_start module params
34 * added extra printk's for startup problems
35 * added MODULE_AUTHOR and MODULE_DESCRIPTION info
36 *
37 *
38 * This WDT driver is different from the other Linux WDT
39 * drivers in the following ways:
40 * *) The driver will ping the watchdog by itself, because this
41 * particular WDT has a very short timeout (one second) and it
42 * would be insane to count on any userspace daemon always
43 * getting scheduled within that time frame.
44 *
45 */
46
47#include <linux/module.h>
48#include <linux/moduleparam.h>
49#include <linux/types.h>
50#include <linux/timer.h>
51#include <linux/jiffies.h>
52#include <linux/miscdevice.h>
53#include <linux/watchdog.h>
54#include <linux/fs.h>
55#include <linux/ioport.h>
56#include <linux/notifier.h>
57#include <linux/reboot.h>
58#include <linux/init.h>
59
60#include <asm/io.h>
61#include <asm/uaccess.h>
62#include <asm/system.h>
63
64#define OUR_NAME "sbc60xxwdt"
65#define PFX OUR_NAME ": "
66
67/*
68 * You must set these - The driver cannot probe for the settings
69 */
70
71static int wdt_stop = 0x45;
72module_param(wdt_stop, int, 0);
73MODULE_PARM_DESC(wdt_stop, "SBC60xx WDT 'stop' io port (default 0x45)");
74
75static int wdt_start = 0x443;
76module_param(wdt_start, int, 0);
77MODULE_PARM_DESC(wdt_start, "SBC60xx WDT 'start' io port (default 0x443)");
78
79/*
80 * The 60xx board can use watchdog timeout values from one second
81 * to several minutes. The default is one second, so if we reset
82 * the watchdog every ~250ms we should be safe.
83 */
84
85#define WDT_INTERVAL (HZ/4+1)
86
87/*
88 * We must not require too good response from the userspace daemon.
89 * Here we require the userspace daemon to send us a heartbeat
90 * char to /dev/watchdog every 30 seconds.
91 * If the daemon pulses us every 25 seconds, we can still afford
92 * a 5 second scheduling delay on the (high priority) daemon. That
93 * should be sufficient for a box under any load.
94 */
95
96#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
97static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
98module_param(timeout, int, 0);
99MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
100
101static int nowayout = WATCHDOG_NOWAYOUT;
102module_param(nowayout, int, 0);
103MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
104
105static void wdt_timer_ping(unsigned long);
106static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
107static unsigned long next_heartbeat;
108static unsigned long wdt_is_open;
109static char wdt_expect_close;
110
111/*
112 * Whack the dog
113 */
114
115static void wdt_timer_ping(unsigned long data)
116{
117 /* If we got a heartbeat pulse within the WDT_US_INTERVAL
118 * we agree to ping the WDT
119 */
120 if(time_before(jiffies, next_heartbeat))
121 {
122 /* Ping the WDT by reading from wdt_start */
123 inb_p(wdt_start);
124 /* Re-set the timer interval */
125 mod_timer(&timer, jiffies + WDT_INTERVAL);
126 } else {
127 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
128 }
129}
130
131/*
132 * Utility routines
133 */
134
135static void wdt_startup(void)
136{
137 next_heartbeat = jiffies + (timeout * HZ);
138
139 /* Start the timer */
140 mod_timer(&timer, jiffies + WDT_INTERVAL);
141 printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
142}
143
144static void wdt_turnoff(void)
145{
146 /* Stop the timer */
147 del_timer(&timer);
148 inb_p(wdt_stop);
149 printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
150}
151
152static void wdt_keepalive(void)
153{
154 /* user land ping */
155 next_heartbeat = jiffies + (timeout * HZ);
156}
157
158/*
159 * /dev/watchdog handling
160 */
161
162static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
163{
164 /* See if we got the magic character 'V' and reload the timer */
165 if(count)
166 {
167 if (!nowayout)
168 {
169 size_t ofs;
170
171 /* note: just in case someone wrote the magic character
172 * five months ago... */
173 wdt_expect_close = 0;
174
175 /* scan to see whether or not we got the magic character */
176 for(ofs = 0; ofs != count; ofs++)
177 {
178 char c;
179 if(get_user(c, buf+ofs))
180 return -EFAULT;
181 if(c == 'V')
182 wdt_expect_close = 42;
183 }
184 }
185
186 /* Well, anyhow someone wrote to us, we should return that favour */
187 wdt_keepalive();
188 }
189 return count;
190}
191
192static int fop_open(struct inode * inode, struct file * file)
193{
194 /* Just in case we're already talking to someone... */
195 if(test_and_set_bit(0, &wdt_is_open))
196 return -EBUSY;
197
198 if (nowayout)
199 __module_get(THIS_MODULE);
200
201 /* Good, fire up the show */
202 wdt_startup();
203 return nonseekable_open(inode, file);
204}
205
206static int fop_close(struct inode * inode, struct file * file)
207{
208 if(wdt_expect_close == 42)
209 wdt_turnoff();
210 else {
211 del_timer(&timer);
212 printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n");
213 }
214 clear_bit(0, &wdt_is_open);
215 wdt_expect_close = 0;
216 return 0;
217}
218
219static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
220 unsigned long arg)
221{
222 void __user *argp = (void __user *)arg;
223 int __user *p = argp;
224 static struct watchdog_info ident=
225 {
226 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
227 .firmware_version = 1,
228 .identity = "SBC60xx",
229 };
230
231 switch(cmd)
232 {
233 default:
234 return -ENOTTY;
235 case WDIOC_GETSUPPORT:
236 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
237 case WDIOC_GETSTATUS:
238 case WDIOC_GETBOOTSTATUS:
239 return put_user(0, p);
240 case WDIOC_KEEPALIVE:
241 wdt_keepalive();
242 return 0;
243 case WDIOC_SETOPTIONS:
244 {
245 int new_options, retval = -EINVAL;
246
247 if(get_user(new_options, p))
248 return -EFAULT;
249
250 if(new_options & WDIOS_DISABLECARD) {
251 wdt_turnoff();
252 retval = 0;
253 }
254
255 if(new_options & WDIOS_ENABLECARD) {
256 wdt_startup();
257 retval = 0;
258 }
259
260 return retval;
261 }
262 case WDIOC_SETTIMEOUT:
263 {
264 int new_timeout;
265
266 if(get_user(new_timeout, p))
267 return -EFAULT;
268
269 if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
270 return -EINVAL;
271
272 timeout = new_timeout;
273 wdt_keepalive();
274 /* Fall through */
275 }
276 case WDIOC_GETTIMEOUT:
277 return put_user(timeout, p);
278 }
279}
280
281static const struct file_operations wdt_fops = {
282 .owner = THIS_MODULE,
283 .llseek = no_llseek,
284 .write = fop_write,
285 .open = fop_open,
286 .release = fop_close,
287 .ioctl = fop_ioctl,
288};
289
290static struct miscdevice wdt_miscdev = {
291 .minor = WATCHDOG_MINOR,
292 .name = "watchdog",
293 .fops = &wdt_fops,
294};
295
296/*
297 * Notifier for system down
298 */
299
300static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
301 void *unused)
302{
303 if(code==SYS_DOWN || code==SYS_HALT)
304 wdt_turnoff();
305 return NOTIFY_DONE;
306}
307
308/*
309 * The WDT needs to learn about soft shutdowns in order to
310 * turn the timebomb registers off.
311 */
312
313static struct notifier_block wdt_notifier=
314{
315 .notifier_call = wdt_notify_sys,
316};
317
318static void __exit sbc60xxwdt_unload(void)
319{
320 wdt_turnoff();
321
322 /* Deregister */
323 misc_deregister(&wdt_miscdev);
324
325 unregister_reboot_notifier(&wdt_notifier);
326 if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
327 release_region(wdt_stop,1);
328 release_region(wdt_start,1);
329}
330
331static int __init sbc60xxwdt_init(void)
332{
333 int rc = -EBUSY;
334
335 if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
336 {
337 timeout = WATCHDOG_TIMEOUT;
338 printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
339 timeout);
340 }
341
342 if (!request_region(wdt_start, 1, "SBC 60XX WDT"))
343 {
344 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
345 wdt_start);
346 rc = -EIO;
347 goto err_out;
348 }
349
350 /* We cannot reserve 0x45 - the kernel already has! */
351 if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
352 {
353 if (!request_region(wdt_stop, 1, "SBC 60XX WDT"))
354 {
355 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
356 wdt_stop);
357 rc = -EIO;
358 goto err_out_region1;
359 }
360 }
361
362 rc = misc_register(&wdt_miscdev);
363 if (rc)
364 {
365 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
366 wdt_miscdev.minor, rc);
367 goto err_out_region2;
368 }
369
370 rc = register_reboot_notifier(&wdt_notifier);
371 if (rc)
372 {
373 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
374 rc);
375 goto err_out_miscdev;
376 }
377
378 printk(KERN_INFO PFX "WDT driver for 60XX single board computer initialised. timeout=%d sec (nowayout=%d)\n",
379 timeout, nowayout);
380
381 return 0;
382
383err_out_miscdev:
384 misc_deregister(&wdt_miscdev);
385err_out_region2:
386 if ((wdt_stop != 0x45) && (wdt_stop != wdt_start))
387 release_region(wdt_stop,1);
388err_out_region1:
389 release_region(wdt_start,1);
390err_out:
391 return rc;
392}
393
394module_init(sbc60xxwdt_init);
395module_exit(sbc60xxwdt_unload);
396
397MODULE_AUTHOR("Jakob Oestergaard <jakob@unthought.net>");
398MODULE_DESCRIPTION("60xx Single Board Computer Watchdog Timer driver");
399MODULE_LICENSE("GPL");
400MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sbc8360.c b/drivers/watchdog/sbc8360.c
new file mode 100644
index 000000000000..285d85289532
--- /dev/null
+++ b/drivers/watchdog/sbc8360.c
@@ -0,0 +1,413 @@
1/*
2 * SBC8360 Watchdog driver
3 *
4 * (c) Copyright 2005 Webcon, Inc.
5 *
6 * Based on ib700wdt.c, which is based on advantechwdt.c which is based
7 * on acquirewdt.c which is based on wdt.c.
8 *
9 * (c) Copyright 2001 Charles Howes <chowes@vsol.net>
10 *
11 * Based on advantechwdt.c which is based on acquirewdt.c which
12 * is based on wdt.c.
13 *
14 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
15 *
16 * Based on acquirewdt.c which is based on wdt.c.
17 * Original copyright messages:
18 *
19 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
20 * http://www.redhat.com
21 *
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version
25 * 2 of the License, or (at your option) any later version.
26 *
27 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
28 * warranty for any of this software. This material is provided
29 * "AS-IS" and at no charge.
30 *
31 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
32 *
33 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
34 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
35 * Added timeout module option to override default
36 *
37 */
38
39#include <linux/module.h>
40#include <linux/types.h>
41#include <linux/miscdevice.h>
42#include <linux/watchdog.h>
43#include <linux/ioport.h>
44#include <linux/delay.h>
45#include <linux/notifier.h>
46#include <linux/fs.h>
47#include <linux/reboot.h>
48#include <linux/init.h>
49#include <linux/spinlock.h>
50#include <linux/moduleparam.h>
51
52#include <asm/io.h>
53#include <asm/uaccess.h>
54#include <asm/system.h>
55
56static unsigned long sbc8360_is_open;
57static spinlock_t sbc8360_lock;
58static char expect_close;
59
60#define PFX "sbc8360: "
61
62/*
63 *
64 * Watchdog Timer Configuration
65 *
66 * The function of the watchdog timer is to reset the system automatically
67 * and is defined at I/O port 0120H and 0121H. To enable the watchdog timer
68 * and allow the system to reset, write appropriate values from the table
69 * below to I/O port 0120H and 0121H. To disable the timer, write a zero
70 * value to I/O port 0121H for the system to stop the watchdog function.
71 *
72 * The following describes how the timer should be programmed (according to
73 * the vendor documentation)
74 *
75 * Enabling Watchdog:
76 * MOV AX,000AH (enable, phase I)
77 * MOV DX,0120H
78 * OUT DX,AX
79 * MOV AX,000BH (enable, phase II)
80 * MOV DX,0120H
81 * OUT DX,AX
82 * MOV AX,000nH (set multiplier n, from 1-4)
83 * MOV DX,0120H
84 * OUT DX,AX
85 * MOV AX,000mH (set base timer m, from 0-F)
86 * MOV DX,0121H
87 * OUT DX,AX
88 *
89 * Reset timer:
90 * MOV AX,000mH (same as set base timer, above)
91 * MOV DX,0121H
92 * OUT DX,AX
93 *
94 * Disabling Watchdog:
95 * MOV AX,0000H (a zero value)
96 * MOV DX,0120H
97 * OUT DX,AX
98 *
99 * Watchdog timeout configuration values:
100 * N
101 * M | 1 2 3 4
102 * --|----------------------------------
103 * 0 | 0.5s 5s 50s 100s
104 * 1 | 1s 10s 100s 200s
105 * 2 | 1.5s 15s 150s 300s
106 * 3 | 2s 20s 200s 400s
107 * 4 | 2.5s 25s 250s 500s
108 * 5 | 3s 30s 300s 600s
109 * 6 | 3.5s 35s 350s 700s
110 * 7 | 4s 40s 400s 800s
111 * 8 | 4.5s 45s 450s 900s
112 * 9 | 5s 50s 500s 1000s
113 * A | 5.5s 55s 550s 1100s
114 * B | 6s 60s 600s 1200s
115 * C | 6.5s 65s 650s 1300s
116 * D | 7s 70s 700s 1400s
117 * E | 7.5s 75s 750s 1500s
118 * F | 8s 80s 800s 1600s
119 *
120 * Another way to say the same things is:
121 * For N=1, Timeout = (M+1) * 0.5s
122 * For N=2, Timeout = (M+1) * 5s
123 * For N=3, Timeout = (M+1) * 50s
124 * For N=4, Timeout = (M+1) * 100s
125 *
126 */
127
128static int wd_times[64][2] = {
129 {0, 1}, /* 0 = 0.5s */
130 {1, 1}, /* 1 = 1s */
131 {2, 1}, /* 2 = 1.5s */
132 {3, 1}, /* 3 = 2s */
133 {4, 1}, /* 4 = 2.5s */
134 {5, 1}, /* 5 = 3s */
135 {6, 1}, /* 6 = 3.5s */
136 {7, 1}, /* 7 = 4s */
137 {8, 1}, /* 8 = 4.5s */
138 {9, 1}, /* 9 = 5s */
139 {0xA, 1}, /* 10 = 5.5s */
140 {0xB, 1}, /* 11 = 6s */
141 {0xC, 1}, /* 12 = 6.5s */
142 {0xD, 1}, /* 13 = 7s */
143 {0xE, 1}, /* 14 = 7.5s */
144 {0xF, 1}, /* 15 = 8s */
145 {0, 2}, /* 16 = 5s */
146 {1, 2}, /* 17 = 10s */
147 {2, 2}, /* 18 = 15s */
148 {3, 2}, /* 19 = 20s */
149 {4, 2}, /* 20 = 25s */
150 {5, 2}, /* 21 = 30s */
151 {6, 2}, /* 22 = 35s */
152 {7, 2}, /* 23 = 40s */
153 {8, 2}, /* 24 = 45s */
154 {9, 2}, /* 25 = 50s */
155 {0xA, 2}, /* 26 = 55s */
156 {0xB, 2}, /* 27 = 60s */
157 {0xC, 2}, /* 28 = 65s */
158 {0xD, 2}, /* 29 = 70s */
159 {0xE, 2}, /* 30 = 75s */
160 {0xF, 2}, /* 31 = 80s */
161 {0, 3}, /* 32 = 50s */
162 {1, 3}, /* 33 = 100s */
163 {2, 3}, /* 34 = 150s */
164 {3, 3}, /* 35 = 200s */
165 {4, 3}, /* 36 = 250s */
166 {5, 3}, /* 37 = 300s */
167 {6, 3}, /* 38 = 350s */
168 {7, 3}, /* 39 = 400s */
169 {8, 3}, /* 40 = 450s */
170 {9, 3}, /* 41 = 500s */
171 {0xA, 3}, /* 42 = 550s */
172 {0xB, 3}, /* 43 = 600s */
173 {0xC, 3}, /* 44 = 650s */
174 {0xD, 3}, /* 45 = 700s */
175 {0xE, 3}, /* 46 = 750s */
176 {0xF, 3}, /* 47 = 800s */
177 {0, 4}, /* 48 = 100s */
178 {1, 4}, /* 49 = 200s */
179 {2, 4}, /* 50 = 300s */
180 {3, 4}, /* 51 = 400s */
181 {4, 4}, /* 52 = 500s */
182 {5, 4}, /* 53 = 600s */
183 {6, 4}, /* 54 = 700s */
184 {7, 4}, /* 55 = 800s */
185 {8, 4}, /* 56 = 900s */
186 {9, 4}, /* 57 = 1000s */
187 {0xA, 4}, /* 58 = 1100s */
188 {0xB, 4}, /* 59 = 1200s */
189 {0xC, 4}, /* 60 = 1300s */
190 {0xD, 4}, /* 61 = 1400s */
191 {0xE, 4}, /* 62 = 1500s */
192 {0xF, 4} /* 63 = 1600s */
193};
194
195#define SBC8360_ENABLE 0x120
196#define SBC8360_BASETIME 0x121
197
198static int timeout = 27;
199static int wd_margin = 0xB;
200static int wd_multiplier = 2;
201static int nowayout = WATCHDOG_NOWAYOUT;
202
203module_param(timeout, int, 0);
204MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))");
205module_param(nowayout, int, 0);
206MODULE_PARM_DESC(nowayout,
207 "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
208
209/*
210 * Kernel methods.
211 */
212
213/* Activate and pre-configure watchdog */
214static void sbc8360_activate(void)
215{
216 /* Enable the watchdog */
217 outb(0x0A, SBC8360_ENABLE);
218 msleep_interruptible(100);
219 outb(0x0B, SBC8360_ENABLE);
220 msleep_interruptible(100);
221 /* Set timeout multiplier */
222 outb(wd_multiplier, SBC8360_ENABLE);
223 msleep_interruptible(100);
224 /* Nothing happens until first sbc8360_ping() */
225}
226
227/* Kernel pings watchdog */
228static void sbc8360_ping(void)
229{
230 /* Write the base timer register */
231 outb(wd_margin, SBC8360_BASETIME);
232}
233
234/* Userspace pings kernel driver, or requests clean close */
235static ssize_t sbc8360_write(struct file *file, const char __user * buf,
236 size_t count, loff_t * ppos)
237{
238 if (count) {
239 if (!nowayout) {
240 size_t i;
241
242 /* In case it was set long ago */
243 expect_close = 0;
244
245 for (i = 0; i != count; i++) {
246 char c;
247 if (get_user(c, buf + i))
248 return -EFAULT;
249 if (c == 'V')
250 expect_close = 42;
251 }
252 }
253 sbc8360_ping();
254 }
255 return count;
256}
257
258static int sbc8360_open(struct inode *inode, struct file *file)
259{
260 spin_lock(&sbc8360_lock);
261 if (test_and_set_bit(0, &sbc8360_is_open)) {
262 spin_unlock(&sbc8360_lock);
263 return -EBUSY;
264 }
265 if (nowayout)
266 __module_get(THIS_MODULE);
267
268 /* Activate and ping once to start the countdown */
269 spin_unlock(&sbc8360_lock);
270 sbc8360_activate();
271 sbc8360_ping();
272 return nonseekable_open(inode, file);
273}
274
275static int sbc8360_close(struct inode *inode, struct file *file)
276{
277 spin_lock(&sbc8360_lock);
278 if (expect_close == 42)
279 outb(0, SBC8360_ENABLE);
280 else
281 printk(KERN_CRIT PFX
282 "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n");
283
284 clear_bit(0, &sbc8360_is_open);
285 expect_close = 0;
286 spin_unlock(&sbc8360_lock);
287 return 0;
288}
289
290/*
291 * Notifier for system down
292 */
293
294static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code,
295 void *unused)
296{
297 if (code == SYS_DOWN || code == SYS_HALT) {
298 /* Disable the SBC8360 Watchdog */
299 outb(0, SBC8360_ENABLE);
300 }
301 return NOTIFY_DONE;
302}
303
304/*
305 * Kernel Interfaces
306 */
307
308static const struct file_operations sbc8360_fops = {
309 .owner = THIS_MODULE,
310 .llseek = no_llseek,
311 .write = sbc8360_write,
312 .open = sbc8360_open,
313 .release = sbc8360_close,
314};
315
316static struct miscdevice sbc8360_miscdev = {
317 .minor = WATCHDOG_MINOR,
318 .name = "watchdog",
319 .fops = &sbc8360_fops,
320};
321
322/*
323 * The SBC8360 needs to learn about soft shutdowns in order to
324 * turn the timebomb registers off.
325 */
326
327static struct notifier_block sbc8360_notifier = {
328 .notifier_call = sbc8360_notify_sys,
329};
330
331static int __init sbc8360_init(void)
332{
333 int res;
334 unsigned long int mseconds = 60000;
335
336 if (timeout < 0 || timeout > 63) {
337 printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
338 res = -EINVAL;
339 goto out;
340 }
341
342 if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
343 printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
344 SBC8360_ENABLE);
345 res = -EIO;
346 goto out;
347 }
348 if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
349 printk(KERN_ERR PFX
350 "BASETIME method I/O %X is not available.\n",
351 SBC8360_BASETIME);
352 res = -EIO;
353 goto out_nobasetimereg;
354 }
355
356 res = register_reboot_notifier(&sbc8360_notifier);
357 if (res) {
358 printk(KERN_ERR PFX "Failed to register reboot notifier.\n");
359 goto out_noreboot;
360 }
361
362 spin_lock_init(&sbc8360_lock);
363 res = misc_register(&sbc8360_miscdev);
364 if (res) {
365 printk(KERN_ERR PFX "failed to register misc device\n");
366 goto out_nomisc;
367 }
368
369 wd_margin = wd_times[timeout][0];
370 wd_multiplier = wd_times[timeout][1];
371
372 if (wd_multiplier == 1)
373 mseconds = (wd_margin + 1) * 500;
374 else if (wd_multiplier == 2)
375 mseconds = (wd_margin + 1) * 5000;
376 else if (wd_multiplier == 3)
377 mseconds = (wd_margin + 1) * 50000;
378 else if (wd_multiplier == 4)
379 mseconds = (wd_margin + 1) * 100000;
380
381 /* My kingdom for the ability to print "0.5 seconds" in the kernel! */
382 printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds);
383
384 return 0;
385
386 out_nomisc:
387 unregister_reboot_notifier(&sbc8360_notifier);
388 out_noreboot:
389 release_region(SBC8360_BASETIME, 1);
390 out_nobasetimereg:
391 release_region(SBC8360_ENABLE, 1);
392 out:
393 return res;
394}
395
396static void __exit sbc8360_exit(void)
397{
398 misc_deregister(&sbc8360_miscdev);
399 unregister_reboot_notifier(&sbc8360_notifier);
400 release_region(SBC8360_ENABLE, 1);
401 release_region(SBC8360_BASETIME, 1);
402}
403
404module_init(sbc8360_init);
405module_exit(sbc8360_exit);
406
407MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>");
408MODULE_DESCRIPTION("SBC8360 watchdog driver");
409MODULE_LICENSE("GPL");
410MODULE_VERSION("1.01");
411MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
412
413/* end of sbc8360.c */
diff --git a/drivers/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c
new file mode 100644
index 000000000000..82cbd8809a69
--- /dev/null
+++ b/drivers/watchdog/sbc_epx_c3.c
@@ -0,0 +1,223 @@
1/*
2 * SBC EPX C3 0.1 A Hardware Watchdog Device for the Winsystems EPX-C3
3 * single board computer
4 *
5 * (c) Copyright 2006 Calin A. Culianu <calin@ajvar.org>, All Rights
6 * Reserved.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * based on softdog.c by Alan Cox <alan@redhat.com>
14 */
15
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/types.h>
19#include <linux/kernel.h>
20#include <linux/fs.h>
21#include <linux/mm.h>
22#include <linux/miscdevice.h>
23#include <linux/watchdog.h>
24#include <linux/notifier.h>
25#include <linux/reboot.h>
26#include <linux/init.h>
27#include <linux/ioport.h>
28#include <asm/uaccess.h>
29#include <asm/io.h>
30
31#define PFX "epx_c3: "
32static int epx_c3_alive;
33
34#define WATCHDOG_TIMEOUT 1 /* 1 sec default timeout */
35
36static int nowayout = WATCHDOG_NOWAYOUT;
37module_param(nowayout, int, 0);
38MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
39
40#define EPXC3_WATCHDOG_CTL_REG 0x1ee /* write 1 to enable, 0 to disable */
41#define EPXC3_WATCHDOG_PET_REG 0x1ef /* write anything to pet once enabled */
42
43static void epx_c3_start(void)
44{
45 outb(1, EPXC3_WATCHDOG_CTL_REG);
46}
47
48static void epx_c3_stop(void)
49{
50
51 outb(0, EPXC3_WATCHDOG_CTL_REG);
52
53 printk(KERN_INFO PFX "Stopped watchdog timer.\n");
54}
55
56static void epx_c3_pet(void)
57{
58 outb(1, EPXC3_WATCHDOG_PET_REG);
59}
60
61/*
62 * Allow only one person to hold it open
63 */
64static int epx_c3_open(struct inode *inode, struct file *file)
65{
66 if (epx_c3_alive)
67 return -EBUSY;
68
69 if (nowayout)
70 __module_get(THIS_MODULE);
71
72 /* Activate timer */
73 epx_c3_start();
74 epx_c3_pet();
75
76 epx_c3_alive = 1;
77 printk(KERN_INFO "Started watchdog timer.\n");
78
79 return nonseekable_open(inode, file);
80}
81
82static int epx_c3_release(struct inode *inode, struct file *file)
83{
84 /* Shut off the timer.
85 * Lock it in if it's a module and we defined ...NOWAYOUT */
86 if (!nowayout)
87 epx_c3_stop(); /* Turn the WDT off */
88
89 epx_c3_alive = 0;
90
91 return 0;
92}
93
94static ssize_t epx_c3_write(struct file *file, const char __user *data,
95 size_t len, loff_t *ppos)
96{
97 /* Refresh the timer. */
98 if (len)
99 epx_c3_pet();
100 return len;
101}
102
103static int epx_c3_ioctl(struct inode *inode, struct file *file,
104 unsigned int cmd, unsigned long arg)
105{
106 int options, retval = -EINVAL;
107 int __user *argp = (void __user *)arg;
108 static struct watchdog_info ident = {
109 .options = WDIOF_KEEPALIVEPING |
110 WDIOF_MAGICCLOSE,
111 .firmware_version = 0,
112 .identity = "Winsystems EPX-C3 H/W Watchdog",
113 };
114
115 switch (cmd) {
116 case WDIOC_GETSUPPORT:
117 if (copy_to_user(argp, &ident, sizeof(ident)))
118 return -EFAULT;
119 return 0;
120 case WDIOC_GETSTATUS:
121 case WDIOC_GETBOOTSTATUS:
122 return put_user(0, argp);
123 case WDIOC_KEEPALIVE:
124 epx_c3_pet();
125 return 0;
126 case WDIOC_GETTIMEOUT:
127 return put_user(WATCHDOG_TIMEOUT, argp);
128 case WDIOC_SETOPTIONS:
129 if (get_user(options, argp))
130 return -EFAULT;
131
132 if (options & WDIOS_DISABLECARD) {
133 epx_c3_stop();
134 retval = 0;
135 }
136
137 if (options & WDIOS_ENABLECARD) {
138 epx_c3_start();
139 retval = 0;
140 }
141
142 return retval;
143 default:
144 return -ENOTTY;
145 }
146}
147
148static int epx_c3_notify_sys(struct notifier_block *this, unsigned long code,
149 void *unused)
150{
151 if (code == SYS_DOWN || code == SYS_HALT)
152 epx_c3_stop(); /* Turn the WDT off */
153
154 return NOTIFY_DONE;
155}
156
157static const struct file_operations epx_c3_fops = {
158 .owner = THIS_MODULE,
159 .llseek = no_llseek,
160 .write = epx_c3_write,
161 .ioctl = epx_c3_ioctl,
162 .open = epx_c3_open,
163 .release = epx_c3_release,
164};
165
166static struct miscdevice epx_c3_miscdev = {
167 .minor = WATCHDOG_MINOR,
168 .name = "watchdog",
169 .fops = &epx_c3_fops,
170};
171
172static struct notifier_block epx_c3_notifier = {
173 .notifier_call = epx_c3_notify_sys,
174};
175
176static const char banner[] __initdata =
177 KERN_INFO PFX "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n";
178
179static int __init watchdog_init(void)
180{
181 int ret;
182
183 if (!request_region(EPXC3_WATCHDOG_CTL_REG, 2, "epxc3_watchdog"))
184 return -EBUSY;
185
186 ret = register_reboot_notifier(&epx_c3_notifier);
187 if (ret) {
188 printk(KERN_ERR PFX "cannot register reboot notifier "
189 "(err=%d)\n", ret);
190 goto out;
191 }
192
193 ret = misc_register(&epx_c3_miscdev);
194 if (ret) {
195 printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
196 "(err=%d)\n", WATCHDOG_MINOR, ret);
197 unregister_reboot_notifier(&epx_c3_notifier);
198 goto out;
199 }
200
201 printk(banner);
202
203 return 0;
204
205out:
206 release_region(EPXC3_WATCHDOG_CTL_REG, 2);
207 return ret;
208}
209
210static void __exit watchdog_exit(void)
211{
212 misc_deregister(&epx_c3_miscdev);
213 unregister_reboot_notifier(&epx_c3_notifier);
214 release_region(EPXC3_WATCHDOG_CTL_REG, 2);
215}
216
217module_init(watchdog_init);
218module_exit(watchdog_exit);
219
220MODULE_AUTHOR("Calin A. Culianu <calin@ajvar.org>");
221MODULE_DESCRIPTION("Hardware Watchdog Device for Winsystems EPX-C3 SBC. Note that there is no way to probe for this device -- so only use it if you are *sure* you are runnning on this specific SBC system from Winsystems! It writes to IO ports 0x1ee and 0x1ef!");
222MODULE_LICENSE("GPL");
223MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sc1200wdt.c b/drivers/watchdog/sc1200wdt.c
new file mode 100644
index 000000000000..9670d47190d0
--- /dev/null
+++ b/drivers/watchdog/sc1200wdt.c
@@ -0,0 +1,463 @@
1/*
2 * National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
3 * (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>,
4 * All Rights Reserved.
5 * Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively.
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 * The author(s) of this software shall not be held liable for damages
13 * of any nature resulting due to the use of this software. This
14 * software is provided AS-IS with no warranties.
15 *
16 * Changelog:
17 * 20020220 Zwane Mwaikambo Code based on datasheet, no hardware.
18 * 20020221 Zwane Mwaikambo Cleanups as suggested by Jeff Garzik and Alan Cox.
19 * 20020222 Zwane Mwaikambo Added probing.
20 * 20020225 Zwane Mwaikambo Added ISAPNP support.
21 * 20020412 Rob Radez Broke out start/stop functions
22 * <rob@osinvestor.com> Return proper status instead of temperature warning
23 * Add WDIOC_GETBOOTSTATUS and WDIOC_SETOPTIONS ioctls
24 * Fix CONFIG_WATCHDOG_NOWAYOUT
25 * 20020530 Joel Becker Add Matt Domsch's nowayout module option
26 * 20030116 Adam Belay Updated to the latest pnp code
27 *
28 */
29
30#include <linux/module.h>
31#include <linux/moduleparam.h>
32#include <linux/miscdevice.h>
33#include <linux/watchdog.h>
34#include <linux/ioport.h>
35#include <linux/spinlock.h>
36#include <linux/notifier.h>
37#include <linux/reboot.h>
38#include <linux/init.h>
39#include <linux/pnp.h>
40#include <linux/fs.h>
41
42#include <asm/semaphore.h>
43#include <asm/io.h>
44#include <asm/uaccess.h>
45
46#define SC1200_MODULE_VER "build 20020303"
47#define SC1200_MODULE_NAME "sc1200wdt"
48#define PFX SC1200_MODULE_NAME ": "
49
50#define MAX_TIMEOUT 255 /* 255 minutes */
51#define PMIR (io) /* Power Management Index Register */
52#define PMDR (io+1) /* Power Management Data Register */
53
54/* Data Register indexes */
55#define FER1 0x00 /* Function enable register 1 */
56#define FER2 0x01 /* Function enable register 2 */
57#define PMC1 0x02 /* Power Management Ctrl 1 */
58#define PMC2 0x03 /* Power Management Ctrl 2 */
59#define PMC3 0x04 /* Power Management Ctrl 3 */
60#define WDTO 0x05 /* Watchdog timeout register */
61#define WDCF 0x06 /* Watchdog config register */
62#define WDST 0x07 /* Watchdog status register */
63
64/* WDCF bitfields - which devices assert WDO */
65#define KBC_IRQ 0x01 /* Keyboard Controller */
66#define MSE_IRQ 0x02 /* Mouse */
67#define UART1_IRQ 0x03 /* Serial0 */
68#define UART2_IRQ 0x04 /* Serial1 */
69/* 5 -7 are reserved */
70
71static char banner[] __initdata = KERN_INFO PFX SC1200_MODULE_VER;
72static int timeout = 1;
73static int io = -1;
74static int io_len = 2; /* for non plug and play */
75static struct semaphore open_sem;
76static char expect_close;
77static spinlock_t sc1200wdt_lock; /* io port access serialisation */
78
79#if defined CONFIG_PNP
80static int isapnp = 1;
81static struct pnp_dev *wdt_dev;
82
83module_param(isapnp, int, 0);
84MODULE_PARM_DESC(isapnp, "When set to 0 driver ISA PnP support will be disabled");
85#endif
86
87module_param(io, int, 0);
88MODULE_PARM_DESC(io, "io port");
89module_param(timeout, int, 0);
90MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
91
92static int nowayout = WATCHDOG_NOWAYOUT;
93module_param(nowayout, int, 0);
94MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
95
96
97
98/* Read from Data Register */
99static inline void sc1200wdt_read_data(unsigned char index, unsigned char *data)
100{
101 spin_lock(&sc1200wdt_lock);
102 outb_p(index, PMIR);
103 *data = inb(PMDR);
104 spin_unlock(&sc1200wdt_lock);
105}
106
107
108/* Write to Data Register */
109static inline void sc1200wdt_write_data(unsigned char index, unsigned char data)
110{
111 spin_lock(&sc1200wdt_lock);
112 outb_p(index, PMIR);
113 outb(data, PMDR);
114 spin_unlock(&sc1200wdt_lock);
115}
116
117
118static void sc1200wdt_start(void)
119{
120 unsigned char reg;
121
122 sc1200wdt_read_data(WDCF, &reg);
123 /* assert WDO when any of the following interrupts are triggered too */
124 reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ);
125 sc1200wdt_write_data(WDCF, reg);
126 /* set the timeout and get the ball rolling */
127 sc1200wdt_write_data(WDTO, timeout);
128}
129
130
131static void sc1200wdt_stop(void)
132{
133 sc1200wdt_write_data(WDTO, 0);
134}
135
136
137/* This returns the status of the WDO signal, inactive high. */
138static inline int sc1200wdt_status(void)
139{
140 unsigned char ret;
141
142 sc1200wdt_read_data(WDST, &ret);
143 /* If the bit is inactive, the watchdog is enabled, so return
144 * KEEPALIVEPING which is a bit of a kludge because there's nothing
145 * else for enabled/disabled status
146 */
147 return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING; /* bits 1 - 7 are undefined */
148}
149
150
151static int sc1200wdt_open(struct inode *inode, struct file *file)
152{
153 /* allow one at a time */
154 if (down_trylock(&open_sem))
155 return -EBUSY;
156
157 if (timeout > MAX_TIMEOUT)
158 timeout = MAX_TIMEOUT;
159
160 sc1200wdt_start();
161 printk(KERN_INFO PFX "Watchdog enabled, timeout = %d min(s)", timeout);
162
163 return nonseekable_open(inode, file);
164}
165
166
167static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
168{
169 int new_timeout;
170 void __user *argp = (void __user *)arg;
171 int __user *p = argp;
172 static struct watchdog_info ident = {
173 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
174 .firmware_version = 0,
175 .identity = "PC87307/PC97307",
176 };
177
178 switch (cmd) {
179 default:
180 return -ENOTTY;
181
182 case WDIOC_GETSUPPORT:
183 if (copy_to_user(argp, &ident, sizeof ident))
184 return -EFAULT;
185 return 0;
186
187 case WDIOC_GETSTATUS:
188 return put_user(sc1200wdt_status(), p);
189
190 case WDIOC_GETBOOTSTATUS:
191 return put_user(0, p);
192
193 case WDIOC_KEEPALIVE:
194 sc1200wdt_write_data(WDTO, timeout);
195 return 0;
196
197 case WDIOC_SETTIMEOUT:
198 if (get_user(new_timeout, p))
199 return -EFAULT;
200
201 /* the API states this is given in secs */
202 new_timeout /= 60;
203 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
204 return -EINVAL;
205
206 timeout = new_timeout;
207 sc1200wdt_write_data(WDTO, timeout);
208 /* fall through and return the new timeout */
209
210 case WDIOC_GETTIMEOUT:
211 return put_user(timeout * 60, p);
212
213 case WDIOC_SETOPTIONS:
214 {
215 int options, retval = -EINVAL;
216
217 if (get_user(options, p))
218 return -EFAULT;
219
220 if (options & WDIOS_DISABLECARD) {
221 sc1200wdt_stop();
222 retval = 0;
223 }
224
225 if (options & WDIOS_ENABLECARD) {
226 sc1200wdt_start();
227 retval = 0;
228 }
229
230 return retval;
231 }
232 }
233}
234
235
236static int sc1200wdt_release(struct inode *inode, struct file *file)
237{
238 if (expect_close == 42) {
239 sc1200wdt_stop();
240 printk(KERN_INFO PFX "Watchdog disabled\n");
241 } else {
242 sc1200wdt_write_data(WDTO, timeout);
243 printk(KERN_CRIT PFX "Unexpected close!, timeout = %d min(s)\n", timeout);
244 }
245 up(&open_sem);
246 expect_close = 0;
247
248 return 0;
249}
250
251
252static ssize_t sc1200wdt_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
253{
254 if (len) {
255 if (!nowayout) {
256 size_t i;
257
258 expect_close = 0;
259
260 for (i = 0; i != len; i++) {
261 char c;
262
263 if (get_user(c, data+i))
264 return -EFAULT;
265 if (c == 'V')
266 expect_close = 42;
267 }
268 }
269
270 sc1200wdt_write_data(WDTO, timeout);
271 return len;
272 }
273
274 return 0;
275}
276
277
278static int sc1200wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
279{
280 if (code == SYS_DOWN || code == SYS_HALT)
281 sc1200wdt_stop();
282
283 return NOTIFY_DONE;
284}
285
286
287static struct notifier_block sc1200wdt_notifier =
288{
289 .notifier_call = sc1200wdt_notify_sys,
290};
291
292static const struct file_operations sc1200wdt_fops =
293{
294 .owner = THIS_MODULE,
295 .llseek = no_llseek,
296 .write = sc1200wdt_write,
297 .ioctl = sc1200wdt_ioctl,
298 .open = sc1200wdt_open,
299 .release = sc1200wdt_release,
300};
301
302static struct miscdevice sc1200wdt_miscdev =
303{
304 .minor = WATCHDOG_MINOR,
305 .name = "watchdog",
306 .fops = &sc1200wdt_fops,
307};
308
309
310static int __init sc1200wdt_probe(void)
311{
312 /* The probe works by reading the PMC3 register's default value of 0x0e
313 * there is one caveat, if the device disables the parallel port or any
314 * of the UARTs we won't be able to detect it.
315 * Nb. This could be done with accuracy by reading the SID registers, but
316 * we don't have access to those io regions.
317 */
318
319 unsigned char reg;
320
321 sc1200wdt_read_data(PMC3, &reg);
322 reg &= 0x0f; /* we don't want the UART busy bits */
323 return (reg == 0x0e) ? 0 : -ENODEV;
324}
325
326
327#if defined CONFIG_PNP
328
329static struct pnp_device_id scl200wdt_pnp_devices[] = {
330 /* National Semiconductor PC87307/PC97307 watchdog component */
331 {.id = "NSC0800", .driver_data = 0},
332 {.id = ""},
333};
334
335static int scl200wdt_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id)
336{
337 /* this driver only supports one card at a time */
338 if (wdt_dev || !isapnp)
339 return -EBUSY;
340
341 wdt_dev = dev;
342 io = pnp_port_start(wdt_dev, 0);
343 io_len = pnp_port_len(wdt_dev, 0);
344
345 if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
346 printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
347 return -EBUSY;
348 }
349
350 printk(KERN_INFO "scl200wdt: PnP device found at io port %#x/%d\n", io, io_len);
351 return 0;
352}
353
354static void scl200wdt_pnp_remove(struct pnp_dev * dev)
355{
356 if (wdt_dev){
357 release_region(io, io_len);
358 wdt_dev = NULL;
359 }
360}
361
362static struct pnp_driver scl200wdt_pnp_driver = {
363 .name = "scl200wdt",
364 .id_table = scl200wdt_pnp_devices,
365 .probe = scl200wdt_pnp_probe,
366 .remove = scl200wdt_pnp_remove,
367};
368
369#endif /* CONFIG_PNP */
370
371
372static int __init sc1200wdt_init(void)
373{
374 int ret;
375
376 printk("%s\n", banner);
377
378 spin_lock_init(&sc1200wdt_lock);
379 sema_init(&open_sem, 1);
380
381#if defined CONFIG_PNP
382 if (isapnp) {
383 ret = pnp_register_driver(&scl200wdt_pnp_driver);
384 if (ret)
385 goto out_clean;
386 }
387#endif
388
389 if (io == -1) {
390 printk(KERN_ERR PFX "io parameter must be specified\n");
391 ret = -EINVAL;
392 goto out_pnp;
393 }
394
395#if defined CONFIG_PNP
396 /* now that the user has specified an IO port and we haven't detected
397 * any devices, disable pnp support */
398 isapnp = 0;
399 pnp_unregister_driver(&scl200wdt_pnp_driver);
400#endif
401
402 if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
403 printk(KERN_ERR PFX "Unable to register IO port %#x\n", io);
404 ret = -EBUSY;
405 goto out_pnp;
406 }
407
408 ret = sc1200wdt_probe();
409 if (ret)
410 goto out_io;
411
412 ret = register_reboot_notifier(&sc1200wdt_notifier);
413 if (ret) {
414 printk(KERN_ERR PFX "Unable to register reboot notifier err = %d\n", ret);
415 goto out_io;
416 }
417
418 ret = misc_register(&sc1200wdt_miscdev);
419 if (ret) {
420 printk(KERN_ERR PFX "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
421 goto out_rbt;
422 }
423
424 /* ret = 0 */
425
426out_clean:
427 return ret;
428
429out_rbt:
430 unregister_reboot_notifier(&sc1200wdt_notifier);
431
432out_io:
433 release_region(io, io_len);
434
435out_pnp:
436#if defined CONFIG_PNP
437 if (isapnp)
438 pnp_unregister_driver(&scl200wdt_pnp_driver);
439#endif
440 goto out_clean;
441}
442
443
444static void __exit sc1200wdt_exit(void)
445{
446 misc_deregister(&sc1200wdt_miscdev);
447 unregister_reboot_notifier(&sc1200wdt_notifier);
448
449#if defined CONFIG_PNP
450 if(isapnp)
451 pnp_unregister_driver(&scl200wdt_pnp_driver);
452 else
453#endif
454 release_region(io, io_len);
455}
456
457module_init(sc1200wdt_init);
458module_exit(sc1200wdt_exit);
459
460MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
461MODULE_DESCRIPTION("Driver for National Semiconductor PC87307/PC97307 watchdog component");
462MODULE_LICENSE("GPL");
463MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c
new file mode 100644
index 000000000000..e8594c64d1e6
--- /dev/null
+++ b/drivers/watchdog/sc520_wdt.c
@@ -0,0 +1,435 @@
1/*
2 * AMD Elan SC520 processor Watchdog Timer driver
3 *
4 * Based on acquirewdt.c by Alan Cox,
5 * and sbc60xxwdt.c by Jakob Oestergaard <jakob@unthought.net>
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 * The authors do NOT admit liability nor provide warranty for
13 * any of this software. This material is provided "AS-IS" in
14 * the hope that it may be useful for others.
15 *
16 * (c) Copyright 2001 Scott Jennings <linuxdrivers@oro.net>
17 * 9/27 - 2001 [Initial release]
18 *
19 * Additional fixes Alan Cox
20 * - Fixed formatting
21 * - Removed debug printks
22 * - Fixed SMP built kernel deadlock
23 * - Switched to private locks not lock_kernel
24 * - Used ioremap/writew/readw
25 * - Added NOWAYOUT support
26 * 4/12 - 2002 Changes by Rob Radez <rob@osinvestor.com>
27 * - Change comments
28 * - Eliminate fop_llseek
29 * - Change CONFIG_WATCHDOG_NOWAYOUT semantics
30 * - Add KERN_* tags to printks
31 * - fix possible wdt_is_open race
32 * - Report proper capabilities in watchdog_info
33 * - Add WDIOC_{GETSTATUS, GETBOOTSTATUS, SETTIMEOUT,
34 * GETTIMEOUT, SETOPTIONS} ioctls
35 * 09/8 - 2003 Changes by Wim Van Sebroeck <wim@iguana.be>
36 * - cleanup of trailing spaces
37 * - added extra printk's for startup problems
38 * - use module_param
39 * - made timeout (the emulated heartbeat) a module_param
40 * - made the keepalive ping an internal subroutine
41 * 3/27 - 2004 Changes by Sean Young <sean@mess.org>
42 * - set MMCR_BASE to 0xfffef000
43 * - CBAR does not need to be read
44 * - removed debugging printks
45 *
46 * This WDT driver is different from most other Linux WDT
47 * drivers in that the driver will ping the watchdog by itself,
48 * because this particular WDT has a very short timeout (1.6
49 * seconds) and it would be insane to count on any userspace
50 * daemon always getting scheduled within that time frame.
51 *
52 * This driver uses memory mapped IO, and spinlock.
53 */
54
55#include <linux/module.h>
56#include <linux/moduleparam.h>
57#include <linux/types.h>
58#include <linux/timer.h>
59#include <linux/miscdevice.h>
60#include <linux/watchdog.h>
61#include <linux/fs.h>
62#include <linux/ioport.h>
63#include <linux/notifier.h>
64#include <linux/reboot.h>
65#include <linux/init.h>
66#include <linux/jiffies.h>
67
68#include <asm/io.h>
69#include <asm/uaccess.h>
70#include <asm/system.h>
71
72#define OUR_NAME "sc520_wdt"
73#define PFX OUR_NAME ": "
74
75/*
76 * The AMD Elan SC520 timeout value is 492us times a power of 2 (0-7)
77 *
78 * 0: 492us 2: 1.01s 4: 4.03s 6: 16.22s
79 * 1: 503ms 3: 2.01s 5: 8.05s 7: 32.21s
80 *
81 * We will program the SC520 watchdog for a timeout of 2.01s.
82 * If we reset the watchdog every ~250ms we should be safe.
83 */
84
85#define WDT_INTERVAL (HZ/4+1)
86
87/*
88 * We must not require too good response from the userspace daemon.
89 * Here we require the userspace daemon to send us a heartbeat
90 * char to /dev/watchdog every 30 seconds.
91 */
92
93#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
94static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
95module_param(timeout, int, 0);
96MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
97
98static int nowayout = WATCHDOG_NOWAYOUT;
99module_param(nowayout, int, 0);
100MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
101
102/*
103 * AMD Elan SC520 - Watchdog Timer Registers
104 */
105#define MMCR_BASE 0xfffef000 /* The default base address */
106#define OFFS_WDTMRCTL 0xCB0 /* Watchdog Timer Control Register */
107
108/* WDT Control Register bit definitions */
109#define WDT_EXP_SEL_01 0x0001 /* [01] Time-out = 496 us (with 33 Mhz clk). */
110#define WDT_EXP_SEL_02 0x0002 /* [02] Time-out = 508 ms (with 33 Mhz clk). */
111#define WDT_EXP_SEL_03 0x0004 /* [03] Time-out = 1.02 s (with 33 Mhz clk). */
112#define WDT_EXP_SEL_04 0x0008 /* [04] Time-out = 2.03 s (with 33 Mhz clk). */
113#define WDT_EXP_SEL_05 0x0010 /* [05] Time-out = 4.07 s (with 33 Mhz clk). */
114#define WDT_EXP_SEL_06 0x0020 /* [06] Time-out = 8.13 s (with 33 Mhz clk). */
115#define WDT_EXP_SEL_07 0x0040 /* [07] Time-out = 16.27s (with 33 Mhz clk). */
116#define WDT_EXP_SEL_08 0x0080 /* [08] Time-out = 32.54s (with 33 Mhz clk). */
117#define WDT_IRQ_FLG 0x1000 /* [12] Interrupt Request Flag */
118#define WDT_WRST_ENB 0x4000 /* [14] Watchdog Timer Reset Enable */
119#define WDT_ENB 0x8000 /* [15] Watchdog Timer Enable */
120
121static __u16 __iomem *wdtmrctl;
122
123static void wdt_timer_ping(unsigned long);
124static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
125static unsigned long next_heartbeat;
126static unsigned long wdt_is_open;
127static char wdt_expect_close;
128static spinlock_t wdt_spinlock;
129
130/*
131 * Whack the dog
132 */
133
134static void wdt_timer_ping(unsigned long data)
135{
136 /* If we got a heartbeat pulse within the WDT_US_INTERVAL
137 * we agree to ping the WDT
138 */
139 if(time_before(jiffies, next_heartbeat))
140 {
141 /* Ping the WDT */
142 spin_lock(&wdt_spinlock);
143 writew(0xAAAA, wdtmrctl);
144 writew(0x5555, wdtmrctl);
145 spin_unlock(&wdt_spinlock);
146
147 /* Re-set the timer interval */
148 mod_timer(&timer, jiffies + WDT_INTERVAL);
149 } else {
150 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
151 }
152}
153
154/*
155 * Utility routines
156 */
157
158static void wdt_config(int writeval)
159{
160 __u16 dummy;
161 unsigned long flags;
162
163 /* buy some time (ping) */
164 spin_lock_irqsave(&wdt_spinlock, flags);
165 dummy=readw(wdtmrctl); /* ensure write synchronization */
166 writew(0xAAAA, wdtmrctl);
167 writew(0x5555, wdtmrctl);
168 /* unlock WDT = make WDT configuration register writable one time */
169 writew(0x3333, wdtmrctl);
170 writew(0xCCCC, wdtmrctl);
171 /* write WDT configuration register */
172 writew(writeval, wdtmrctl);
173 spin_unlock_irqrestore(&wdt_spinlock, flags);
174}
175
176static int wdt_startup(void)
177{
178 next_heartbeat = jiffies + (timeout * HZ);
179
180 /* Start the timer */
181 mod_timer(&timer, jiffies + WDT_INTERVAL);
182
183 /* Start the watchdog */
184 wdt_config(WDT_ENB | WDT_WRST_ENB | WDT_EXP_SEL_04);
185
186 printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
187 return 0;
188}
189
190static int wdt_turnoff(void)
191{
192 /* Stop the timer */
193 del_timer(&timer);
194
195 /* Stop the watchdog */
196 wdt_config(0);
197
198 printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
199 return 0;
200}
201
202static int wdt_keepalive(void)
203{
204 /* user land ping */
205 next_heartbeat = jiffies + (timeout * HZ);
206 return 0;
207}
208
209static int wdt_set_heartbeat(int t)
210{
211 if ((t < 1) || (t > 3600)) /* arbitrary upper limit */
212 return -EINVAL;
213
214 timeout = t;
215 return 0;
216}
217
218/*
219 * /dev/watchdog handling
220 */
221
222static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
223{
224 /* See if we got the magic character 'V' and reload the timer */
225 if(count) {
226 if (!nowayout) {
227 size_t ofs;
228
229 /* note: just in case someone wrote the magic character
230 * five months ago... */
231 wdt_expect_close = 0;
232
233 /* now scan */
234 for(ofs = 0; ofs != count; ofs++) {
235 char c;
236 if (get_user(c, buf + ofs))
237 return -EFAULT;
238 if(c == 'V')
239 wdt_expect_close = 42;
240 }
241 }
242
243 /* Well, anyhow someone wrote to us, we should return that favour */
244 wdt_keepalive();
245 }
246 return count;
247}
248
249static int fop_open(struct inode * inode, struct file * file)
250{
251 /* Just in case we're already talking to someone... */
252 if(test_and_set_bit(0, &wdt_is_open))
253 return -EBUSY;
254 if (nowayout)
255 __module_get(THIS_MODULE);
256
257 /* Good, fire up the show */
258 wdt_startup();
259 return nonseekable_open(inode, file);
260}
261
262static int fop_close(struct inode * inode, struct file * file)
263{
264 if(wdt_expect_close == 42) {
265 wdt_turnoff();
266 } else {
267 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
268 wdt_keepalive();
269 }
270 clear_bit(0, &wdt_is_open);
271 wdt_expect_close = 0;
272 return 0;
273}
274
275static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
276 unsigned long arg)
277{
278 void __user *argp = (void __user *)arg;
279 int __user *p = argp;
280 static struct watchdog_info ident = {
281 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
282 .firmware_version = 1,
283 .identity = "SC520",
284 };
285
286 switch(cmd)
287 {
288 default:
289 return -ENOTTY;
290 case WDIOC_GETSUPPORT:
291 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
292 case WDIOC_GETSTATUS:
293 case WDIOC_GETBOOTSTATUS:
294 return put_user(0, p);
295 case WDIOC_KEEPALIVE:
296 wdt_keepalive();
297 return 0;
298 case WDIOC_SETOPTIONS:
299 {
300 int new_options, retval = -EINVAL;
301
302 if(get_user(new_options, p))
303 return -EFAULT;
304
305 if(new_options & WDIOS_DISABLECARD) {
306 wdt_turnoff();
307 retval = 0;
308 }
309
310 if(new_options & WDIOS_ENABLECARD) {
311 wdt_startup();
312 retval = 0;
313 }
314
315 return retval;
316 }
317 case WDIOC_SETTIMEOUT:
318 {
319 int new_timeout;
320
321 if(get_user(new_timeout, p))
322 return -EFAULT;
323
324 if(wdt_set_heartbeat(new_timeout))
325 return -EINVAL;
326
327 wdt_keepalive();
328 /* Fall through */
329 }
330 case WDIOC_GETTIMEOUT:
331 return put_user(timeout, p);
332 }
333}
334
335static const struct file_operations wdt_fops = {
336 .owner = THIS_MODULE,
337 .llseek = no_llseek,
338 .write = fop_write,
339 .open = fop_open,
340 .release = fop_close,
341 .ioctl = fop_ioctl,
342};
343
344static struct miscdevice wdt_miscdev = {
345 .minor = WATCHDOG_MINOR,
346 .name = "watchdog",
347 .fops = &wdt_fops,
348};
349
350/*
351 * Notifier for system down
352 */
353
354static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
355 void *unused)
356{
357 if(code==SYS_DOWN || code==SYS_HALT)
358 wdt_turnoff();
359 return NOTIFY_DONE;
360}
361
362/*
363 * The WDT needs to learn about soft shutdowns in order to
364 * turn the timebomb registers off.
365 */
366
367static struct notifier_block wdt_notifier = {
368 .notifier_call = wdt_notify_sys,
369};
370
371static void __exit sc520_wdt_unload(void)
372{
373 if (!nowayout)
374 wdt_turnoff();
375
376 /* Deregister */
377 misc_deregister(&wdt_miscdev);
378 unregister_reboot_notifier(&wdt_notifier);
379 iounmap(wdtmrctl);
380}
381
382static int __init sc520_wdt_init(void)
383{
384 int rc = -EBUSY;
385
386 spin_lock_init(&wdt_spinlock);
387
388 /* Check that the timeout value is within it's range ; if not reset to the default */
389 if (wdt_set_heartbeat(timeout)) {
390 wdt_set_heartbeat(WATCHDOG_TIMEOUT);
391 printk(KERN_INFO PFX "timeout value must be 1<=timeout<=3600, using %d\n",
392 WATCHDOG_TIMEOUT);
393 }
394
395 wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2);
396 if (!wdtmrctl) {
397 printk(KERN_ERR PFX "Unable to remap memory\n");
398 rc = -ENOMEM;
399 goto err_out_region2;
400 }
401
402 rc = register_reboot_notifier(&wdt_notifier);
403 if (rc) {
404 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
405 rc);
406 goto err_out_ioremap;
407 }
408
409 rc = misc_register(&wdt_miscdev);
410 if (rc) {
411 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
412 WATCHDOG_MINOR, rc);
413 goto err_out_notifier;
414 }
415
416 printk(KERN_INFO PFX "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n",
417 timeout,nowayout);
418
419 return 0;
420
421err_out_notifier:
422 unregister_reboot_notifier(&wdt_notifier);
423err_out_ioremap:
424 iounmap(wdtmrctl);
425err_out_region2:
426 return rc;
427}
428
429module_init(sc520_wdt_init);
430module_exit(sc520_wdt_unload);
431
432MODULE_AUTHOR("Scott and Bill Jennings");
433MODULE_DESCRIPTION("Driver for watchdog timer in AMD \"Elan\" SC520 uProcessor");
434MODULE_LICENSE("GPL");
435MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/scx200_wdt.c b/drivers/watchdog/scx200_wdt.c
new file mode 100644
index 000000000000..d4fd0fa2f176
--- /dev/null
+++ b/drivers/watchdog/scx200_wdt.c
@@ -0,0 +1,269 @@
1/* drivers/char/watchdog/scx200_wdt.c
2
3 National Semiconductor SCx200 Watchdog support
4
5 Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
6
7 Some code taken from:
8 National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
9 (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>
10
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version.
15
16 The author(s) of this software shall not be held liable for damages
17 of any nature resulting due to the use of this software. This
18 software is provided AS-IS with no warranties. */
19
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/init.h>
23#include <linux/miscdevice.h>
24#include <linux/watchdog.h>
25#include <linux/notifier.h>
26#include <linux/reboot.h>
27#include <linux/fs.h>
28#include <linux/ioport.h>
29#include <linux/scx200.h>
30
31#include <asm/uaccess.h>
32#include <asm/io.h>
33
34#define NAME "scx200_wdt"
35
36MODULE_AUTHOR("Christer Weinigel <wingel@nano-system.com>");
37MODULE_DESCRIPTION("NatSemi SCx200 Watchdog Driver");
38MODULE_LICENSE("GPL");
39MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
40
41static int margin = 60; /* in seconds */
42module_param(margin, int, 0);
43MODULE_PARM_DESC(margin, "Watchdog margin in seconds");
44
45static int nowayout = WATCHDOG_NOWAYOUT;
46module_param(nowayout, int, 0);
47MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
48
49static u16 wdto_restart;
50static struct semaphore open_semaphore;
51static char expect_close;
52
53/* Bits of the WDCNFG register */
54#define W_ENABLE 0x00fa /* Enable watchdog */
55#define W_DISABLE 0x0000 /* Disable watchdog */
56
57/* The scaling factor for the timer, this depends on the value of W_ENABLE */
58#define W_SCALE (32768/1024)
59
60static void scx200_wdt_ping(void)
61{
62 outw(wdto_restart, scx200_cb_base + SCx200_WDT_WDTO);
63}
64
65static void scx200_wdt_update_margin(void)
66{
67 printk(KERN_INFO NAME ": timer margin %d seconds\n", margin);
68 wdto_restart = margin * W_SCALE;
69}
70
71static void scx200_wdt_enable(void)
72{
73 printk(KERN_DEBUG NAME ": enabling watchdog timer, wdto_restart = %d\n",
74 wdto_restart);
75
76 outw(0, scx200_cb_base + SCx200_WDT_WDTO);
77 outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
78 outw(W_ENABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
79
80 scx200_wdt_ping();
81}
82
83static void scx200_wdt_disable(void)
84{
85 printk(KERN_DEBUG NAME ": disabling watchdog timer\n");
86
87 outw(0, scx200_cb_base + SCx200_WDT_WDTO);
88 outb(SCx200_WDT_WDSTS_WDOVF, scx200_cb_base + SCx200_WDT_WDSTS);
89 outw(W_DISABLE, scx200_cb_base + SCx200_WDT_WDCNFG);
90}
91
92static int scx200_wdt_open(struct inode *inode, struct file *file)
93{
94 /* only allow one at a time */
95 if (down_trylock(&open_semaphore))
96 return -EBUSY;
97 scx200_wdt_enable();
98
99 return nonseekable_open(inode, file);
100}
101
102static int scx200_wdt_release(struct inode *inode, struct file *file)
103{
104 if (expect_close != 42) {
105 printk(KERN_WARNING NAME ": watchdog device closed unexpectedly, will not disable the watchdog timer\n");
106 } else if (!nowayout) {
107 scx200_wdt_disable();
108 }
109 expect_close = 0;
110 up(&open_semaphore);
111
112 return 0;
113}
114
115static int scx200_wdt_notify_sys(struct notifier_block *this,
116 unsigned long code, void *unused)
117{
118 if (code == SYS_HALT || code == SYS_POWER_OFF)
119 if (!nowayout)
120 scx200_wdt_disable();
121
122 return NOTIFY_DONE;
123}
124
125static struct notifier_block scx200_wdt_notifier =
126{
127 .notifier_call = scx200_wdt_notify_sys,
128};
129
130static ssize_t scx200_wdt_write(struct file *file, const char __user *data,
131 size_t len, loff_t *ppos)
132{
133 /* check for a magic close character */
134 if (len)
135 {
136 size_t i;
137
138 scx200_wdt_ping();
139
140 expect_close = 0;
141 for (i = 0; i < len; ++i) {
142 char c;
143 if (get_user(c, data+i))
144 return -EFAULT;
145 if (c == 'V')
146 expect_close = 42;
147 }
148
149 return len;
150 }
151
152 return 0;
153}
154
155static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
156 unsigned int cmd, unsigned long arg)
157{
158 void __user *argp = (void __user *)arg;
159 int __user *p = argp;
160 static struct watchdog_info ident = {
161 .identity = "NatSemi SCx200 Watchdog",
162 .firmware_version = 1,
163 .options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
164 };
165 int new_margin;
166
167 switch (cmd) {
168 default:
169 return -ENOTTY;
170 case WDIOC_GETSUPPORT:
171 if(copy_to_user(argp, &ident, sizeof(ident)))
172 return -EFAULT;
173 return 0;
174 case WDIOC_GETSTATUS:
175 case WDIOC_GETBOOTSTATUS:
176 if (put_user(0, p))
177 return -EFAULT;
178 return 0;
179 case WDIOC_KEEPALIVE:
180 scx200_wdt_ping();
181 return 0;
182 case WDIOC_SETTIMEOUT:
183 if (get_user(new_margin, p))
184 return -EFAULT;
185 if (new_margin < 1)
186 return -EINVAL;
187 margin = new_margin;
188 scx200_wdt_update_margin();
189 scx200_wdt_ping();
190 case WDIOC_GETTIMEOUT:
191 if (put_user(margin, p))
192 return -EFAULT;
193 return 0;
194 }
195}
196
197static const struct file_operations scx200_wdt_fops = {
198 .owner = THIS_MODULE,
199 .llseek = no_llseek,
200 .write = scx200_wdt_write,
201 .ioctl = scx200_wdt_ioctl,
202 .open = scx200_wdt_open,
203 .release = scx200_wdt_release,
204};
205
206static struct miscdevice scx200_wdt_miscdev = {
207 .minor = WATCHDOG_MINOR,
208 .name = "watchdog",
209 .fops = &scx200_wdt_fops,
210};
211
212static int __init scx200_wdt_init(void)
213{
214 int r;
215
216 printk(KERN_DEBUG NAME ": NatSemi SCx200 Watchdog Driver\n");
217
218 /* check that we have found the configuration block */
219 if (!scx200_cb_present())
220 return -ENODEV;
221
222 if (!request_region(scx200_cb_base + SCx200_WDT_OFFSET,
223 SCx200_WDT_SIZE,
224 "NatSemi SCx200 Watchdog")) {
225 printk(KERN_WARNING NAME ": watchdog I/O region busy\n");
226 return -EBUSY;
227 }
228
229 scx200_wdt_update_margin();
230 scx200_wdt_disable();
231
232 sema_init(&open_semaphore, 1);
233
234 r = misc_register(&scx200_wdt_miscdev);
235 if (r) {
236 release_region(scx200_cb_base + SCx200_WDT_OFFSET,
237 SCx200_WDT_SIZE);
238 return r;
239 }
240
241 r = register_reboot_notifier(&scx200_wdt_notifier);
242 if (r) {
243 printk(KERN_ERR NAME ": unable to register reboot notifier");
244 misc_deregister(&scx200_wdt_miscdev);
245 release_region(scx200_cb_base + SCx200_WDT_OFFSET,
246 SCx200_WDT_SIZE);
247 return r;
248 }
249
250 return 0;
251}
252
253static void __exit scx200_wdt_cleanup(void)
254{
255 unregister_reboot_notifier(&scx200_wdt_notifier);
256 misc_deregister(&scx200_wdt_miscdev);
257 release_region(scx200_cb_base + SCx200_WDT_OFFSET,
258 SCx200_WDT_SIZE);
259}
260
261module_init(scx200_wdt_init);
262module_exit(scx200_wdt_cleanup);
263
264/*
265 Local variables:
266 compile-command: "make -k -C ../.. SUBDIRS=drivers/char modules"
267 c-basic-offset: 8
268 End:
269*/
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c
new file mode 100644
index 000000000000..cecbedd473a4
--- /dev/null
+++ b/drivers/watchdog/shwdt.c
@@ -0,0 +1,485 @@
1/*
2 * drivers/char/watchdog/shwdt.c
3 *
4 * Watchdog driver for integrated watchdog in the SuperH processors.
5 *
6 * Copyright (C) 2001, 2002, 2003 Paul Mundt <lethal@linux-sh.org>
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 as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 *
13 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
14 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
15 *
16 * 19-Apr-2002 Rob Radez <rob@osinvestor.com>
17 * Added expect close support, made emulated timeout runtime changeable
18 * general cleanups, add some ioctls
19 */
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/init.h>
23#include <linux/types.h>
24#include <linux/miscdevice.h>
25#include <linux/watchdog.h>
26#include <linux/reboot.h>
27#include <linux/notifier.h>
28#include <linux/ioport.h>
29#include <linux/fs.h>
30#include <linux/mm.h>
31#include <asm/io.h>
32#include <asm/uaccess.h>
33#include <asm/watchdog.h>
34
35#define PFX "shwdt: "
36
37/*
38 * Default clock division ratio is 5.25 msecs. For an additional table of
39 * values, consult the asm-sh/watchdog.h. Overload this at module load
40 * time.
41 *
42 * In order for this to work reliably we need to have HZ set to 1000 or
43 * something quite higher than 100 (or we need a proper high-res timer
44 * implementation that will deal with this properly), otherwise the 10ms
45 * resolution of a jiffy is enough to trigger the overflow. For things like
46 * the SH-4 and SH-5, this isn't necessarily that big of a problem, though
47 * for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely
48 * necssary.
49 *
50 * As a result of this timing problem, the only modes that are particularly
51 * feasible are the 4096 and the 2048 divisors, which yeild 5.25 and 2.62ms
52 * overflow periods respectively.
53 *
54 * Also, since we can't really expect userspace to be responsive enough
55 * before the overflow happens, we maintain two seperate timers .. One in
56 * the kernel for clearing out WOVF every 2ms or so (again, this depends on
57 * HZ == 1000), and another for monitoring userspace writes to the WDT device.
58 *
59 * As such, we currently use a configurable heartbeat interval which defaults
60 * to 30s. In this case, the userspace daemon is only responsible for periodic
61 * writes to the device before the next heartbeat is scheduled. If the daemon
62 * misses its deadline, the kernel timer will allow the WDT to overflow.
63 */
64static int clock_division_ratio = WTCSR_CKS_4096;
65
66#define next_ping_period(cks) msecs_to_jiffies(cks - 4)
67
68static void sh_wdt_ping(unsigned long data);
69
70static unsigned long shwdt_is_open;
71static struct watchdog_info sh_wdt_info;
72static char shwdt_expect_close;
73static DEFINE_TIMER(timer, sh_wdt_ping, 0, 0);
74static unsigned long next_heartbeat;
75
76#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
77static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
78
79static int nowayout = WATCHDOG_NOWAYOUT;
80
81/**
82 * sh_wdt_start - Start the Watchdog
83 *
84 * Starts the watchdog.
85 */
86static void sh_wdt_start(void)
87{
88 __u8 csr;
89
90 next_heartbeat = jiffies + (heartbeat * HZ);
91 mod_timer(&timer, next_ping_period(clock_division_ratio));
92
93 csr = sh_wdt_read_csr();
94 csr |= WTCSR_WT | clock_division_ratio;
95 sh_wdt_write_csr(csr);
96
97 sh_wdt_write_cnt(0);
98
99 /*
100 * These processors have a bit of an inconsistent initialization
101 * process.. starting with SH-3, RSTS was moved to WTCSR, and the
102 * RSTCSR register was removed.
103 *
104 * On the SH-2 however, in addition with bits being in different
105 * locations, we must deal with RSTCSR outright..
106 */
107 csr = sh_wdt_read_csr();
108 csr |= WTCSR_TME;
109 csr &= ~WTCSR_RSTS;
110 sh_wdt_write_csr(csr);
111
112#ifdef CONFIG_CPU_SH2
113 /*
114 * Whoever came up with the RSTCSR semantics must've been smoking
115 * some of the good stuff, since in addition to the WTCSR/WTCNT write
116 * brain-damage, it's managed to fuck things up one step further..
117 *
118 * If we need to clear the WOVF bit, the upper byte has to be 0xa5..
119 * but if we want to touch RSTE or RSTS, the upper byte has to be
120 * 0x5a..
121 */
122 csr = sh_wdt_read_rstcsr();
123 csr &= ~RSTCSR_RSTS;
124 sh_wdt_write_rstcsr(csr);
125#endif
126}
127
128/**
129 * sh_wdt_stop - Stop the Watchdog
130 * Stops the watchdog.
131 */
132static void sh_wdt_stop(void)
133{
134 __u8 csr;
135
136 del_timer(&timer);
137
138 csr = sh_wdt_read_csr();
139 csr &= ~WTCSR_TME;
140 sh_wdt_write_csr(csr);
141}
142
143/**
144 * sh_wdt_keepalive - Keep the Userspace Watchdog Alive
145 * The Userspace watchdog got a KeepAlive: schedule the next heartbeat.
146 */
147static inline void sh_wdt_keepalive(void)
148{
149 next_heartbeat = jiffies + (heartbeat * HZ);
150}
151
152/**
153 * sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat
154 * Set the Userspace Watchdog heartbeat
155 */
156static int sh_wdt_set_heartbeat(int t)
157{
158 if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */
159 return -EINVAL;
160
161 heartbeat = t;
162 return 0;
163}
164
165/**
166 * sh_wdt_ping - Ping the Watchdog
167 * @data: Unused
168 *
169 * Clears overflow bit, resets timer counter.
170 */
171static void sh_wdt_ping(unsigned long data)
172{
173 if (time_before(jiffies, next_heartbeat)) {
174 __u8 csr;
175
176 csr = sh_wdt_read_csr();
177 csr &= ~WTCSR_IOVF;
178 sh_wdt_write_csr(csr);
179
180 sh_wdt_write_cnt(0);
181
182 mod_timer(&timer, next_ping_period(clock_division_ratio));
183 } else
184 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping "
185 "the watchdog\n");
186}
187
188/**
189 * sh_wdt_open - Open the Device
190 * @inode: inode of device
191 * @file: file handle of device
192 *
193 * Watchdog device is opened and started.
194 */
195static int sh_wdt_open(struct inode *inode, struct file *file)
196{
197 if (test_and_set_bit(0, &shwdt_is_open))
198 return -EBUSY;
199 if (nowayout)
200 __module_get(THIS_MODULE);
201
202 sh_wdt_start();
203
204 return nonseekable_open(inode, file);
205}
206
207/**
208 * sh_wdt_close - Close the Device
209 * @inode: inode of device
210 * @file: file handle of device
211 *
212 * Watchdog device is closed and stopped.
213 */
214static int sh_wdt_close(struct inode *inode, struct file *file)
215{
216 if (shwdt_expect_close == 42) {
217 sh_wdt_stop();
218 } else {
219 printk(KERN_CRIT PFX "Unexpected close, not "
220 "stopping watchdog!\n");
221 sh_wdt_keepalive();
222 }
223
224 clear_bit(0, &shwdt_is_open);
225 shwdt_expect_close = 0;
226
227 return 0;
228}
229
230/**
231 * sh_wdt_write - Write to Device
232 * @file: file handle of device
233 * @buf: buffer to write
234 * @count: length of buffer
235 * @ppos: offset
236 *
237 * Pings the watchdog on write.
238 */
239static ssize_t sh_wdt_write(struct file *file, const char *buf,
240 size_t count, loff_t *ppos)
241{
242 if (count) {
243 if (!nowayout) {
244 size_t i;
245
246 shwdt_expect_close = 0;
247
248 for (i = 0; i != count; i++) {
249 char c;
250 if (get_user(c, buf + i))
251 return -EFAULT;
252 if (c == 'V')
253 shwdt_expect_close = 42;
254 }
255 }
256 sh_wdt_keepalive();
257 }
258
259 return count;
260}
261
262/**
263 * sh_wdt_mmap - map WDT/CPG registers into userspace
264 * @file: file structure for the device
265 * @vma: VMA to map the registers into
266 *
267 * A simple mmap() implementation for the corner cases where the counter
268 * needs to be mapped in userspace directly. Due to the relatively small
269 * size of the area, neighbouring registers not necessarily tied to the
270 * CPG will also be accessible through the register page, so this remains
271 * configurable for users that really know what they're doing.
272 *
273 * Additionaly, the register page maps in the CPG register base relative
274 * to the nearest page-aligned boundary, which requires that userspace do
275 * the appropriate CPU subtype math for calculating the page offset for
276 * the counter value.
277 */
278static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma)
279{
280 int ret = -ENOSYS;
281
282#ifdef CONFIG_SH_WDT_MMAP
283 unsigned long addr;
284
285 /* Only support the simple cases where we map in a register page. */
286 if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
287 return -EINVAL;
288
289 /*
290 * Pick WTCNT as the start, it's usually the first register after the
291 * FRQCR, and neither one are generally page-aligned out of the box.
292 */
293 addr = WTCNT & ~(PAGE_SIZE - 1);
294
295 vma->vm_flags |= VM_IO;
296 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
297
298 if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
299 PAGE_SIZE, vma->vm_page_prot)) {
300 printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n",
301 __FUNCTION__);
302 return -EAGAIN;
303 }
304
305 ret = 0;
306#endif
307
308 return ret;
309}
310
311/**
312 * sh_wdt_ioctl - Query Device
313 * @inode: inode of device
314 * @file: file handle of device
315 * @cmd: watchdog command
316 * @arg: argument
317 *
318 * Query basic information from the device or ping it, as outlined by the
319 * watchdog API.
320 */
321static int sh_wdt_ioctl(struct inode *inode, struct file *file,
322 unsigned int cmd, unsigned long arg)
323{
324 int new_heartbeat;
325 int options, retval = -EINVAL;
326
327 switch (cmd) {
328 case WDIOC_GETSUPPORT:
329 return copy_to_user((struct watchdog_info *)arg,
330 &sh_wdt_info,
331 sizeof(sh_wdt_info)) ? -EFAULT : 0;
332 case WDIOC_GETSTATUS:
333 case WDIOC_GETBOOTSTATUS:
334 return put_user(0, (int *)arg);
335 case WDIOC_KEEPALIVE:
336 sh_wdt_keepalive();
337 return 0;
338 case WDIOC_SETTIMEOUT:
339 if (get_user(new_heartbeat, (int *)arg))
340 return -EFAULT;
341
342 if (sh_wdt_set_heartbeat(new_heartbeat))
343 return -EINVAL;
344
345 sh_wdt_keepalive();
346 /* Fall */
347 case WDIOC_GETTIMEOUT:
348 return put_user(heartbeat, (int *)arg);
349 case WDIOC_SETOPTIONS:
350 if (get_user(options, (int *)arg))
351 return -EFAULT;
352
353 if (options & WDIOS_DISABLECARD) {
354 sh_wdt_stop();
355 retval = 0;
356 }
357
358 if (options & WDIOS_ENABLECARD) {
359 sh_wdt_start();
360 retval = 0;
361 }
362
363 return retval;
364 default:
365 return -ENOTTY;
366 }
367
368 return 0;
369}
370
371/**
372 * sh_wdt_notify_sys - Notifier Handler
373 * @this: notifier block
374 * @code: notifier event
375 * @unused: unused
376 *
377 * Handles specific events, such as turning off the watchdog during a
378 * shutdown event.
379 */
380static int sh_wdt_notify_sys(struct notifier_block *this,
381 unsigned long code, void *unused)
382{
383 if (code == SYS_DOWN || code == SYS_HALT)
384 sh_wdt_stop();
385
386 return NOTIFY_DONE;
387}
388
389static const struct file_operations sh_wdt_fops = {
390 .owner = THIS_MODULE,
391 .llseek = no_llseek,
392 .write = sh_wdt_write,
393 .ioctl = sh_wdt_ioctl,
394 .open = sh_wdt_open,
395 .release = sh_wdt_close,
396 .mmap = sh_wdt_mmap,
397};
398
399static struct watchdog_info sh_wdt_info = {
400 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
401 WDIOF_MAGICCLOSE,
402 .firmware_version = 1,
403 .identity = "SH WDT",
404};
405
406static struct notifier_block sh_wdt_notifier = {
407 .notifier_call = sh_wdt_notify_sys,
408};
409
410static struct miscdevice sh_wdt_miscdev = {
411 .minor = WATCHDOG_MINOR,
412 .name = "watchdog",
413 .fops = &sh_wdt_fops,
414};
415
416/**
417 * sh_wdt_init - Initialize module
418 * Registers the device and notifier handler. Actual device
419 * initialization is handled by sh_wdt_open().
420 */
421static int __init sh_wdt_init(void)
422{
423 int rc;
424
425 if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) {
426 clock_division_ratio = WTCSR_CKS_4096;
427 printk(KERN_INFO PFX "clock_division_ratio value must "
428 "be 0x5<=x<=0x7, using %d\n", clock_division_ratio);
429 }
430
431 rc = sh_wdt_set_heartbeat(heartbeat);
432 if (unlikely(rc)) {
433 heartbeat = WATCHDOG_HEARTBEAT;
434 printk(KERN_INFO PFX "heartbeat value must "
435 "be 1<=x<=3600, using %d\n", heartbeat);
436 }
437
438 rc = register_reboot_notifier(&sh_wdt_notifier);
439 if (unlikely(rc)) {
440 printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n",
441 rc);
442 return rc;
443 }
444
445 rc = misc_register(&sh_wdt_miscdev);
446 if (unlikely(rc)) {
447 printk(KERN_ERR PFX "Can't register miscdev on "
448 "minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc);
449 unregister_reboot_notifier(&sh_wdt_notifier);
450 return rc;
451 }
452
453 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
454 heartbeat, nowayout);
455
456 return 0;
457}
458
459/**
460 * sh_wdt_exit - Deinitialize module
461 * Unregisters the device and notifier handler. Actual device
462 * deinitialization is handled by sh_wdt_close().
463 */
464static void __exit sh_wdt_exit(void)
465{
466 misc_deregister(&sh_wdt_miscdev);
467 unregister_reboot_notifier(&sh_wdt_notifier);
468}
469
470MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
471MODULE_DESCRIPTION("SuperH watchdog driver");
472MODULE_LICENSE("GPL");
473MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
474
475module_param(clock_division_ratio, int, 0);
476MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")");
477
478module_param(heartbeat, int, 0);
479MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
480
481module_param(nowayout, int, 0);
482MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
483
484module_init(sh_wdt_init);
485module_exit(sh_wdt_exit);
diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c
new file mode 100644
index 000000000000..d3cb0a766020
--- /dev/null
+++ b/drivers/watchdog/smsc37b787_wdt.c
@@ -0,0 +1,627 @@
1/*
2 * SMsC 37B787 Watchdog Timer driver for Linux 2.6.x.x
3 *
4 * Based on acquirewdt.c by Alan Cox <alan@redhat.com>
5 * and some other existing drivers
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 * The authors do NOT admit liability nor provide warranty for
13 * any of this software. This material is provided "AS-IS" in
14 * the hope that it may be useful for others.
15 *
16 * (C) Copyright 2003-2006 Sven Anders <anders@anduras.de>
17 *
18 * History:
19 * 2003 - Created version 1.0 for Linux 2.4.x.
20 * 2006 - Ported to Linux 2.6, added nowayout and MAGICCLOSE
21 * features. Released version 1.1
22 *
23 * Theory of operation:
24 *
25 * A Watchdog Timer (WDT) is a hardware circuit that can
26 * reset the computer system in case of a software fault.
27 * You probably knew that already.
28 *
29 * Usually a userspace daemon will notify the kernel WDT driver
30 * via the /dev/watchdog special device file that userspace is
31 * still alive, at regular intervals. When such a notification
32 * occurs, the driver will usually tell the hardware watchdog
33 * that everything is in order, and that the watchdog should wait
34 * for yet another little while to reset the system.
35 * If userspace fails (RAM error, kernel bug, whatever), the
36 * notifications cease to occur, and the hardware watchdog will
37 * reset the system (causing a reboot) after the timeout occurs.
38 *
39 * Create device with:
40 * mknod /dev/watchdog c 10 130
41 *
42 * For an example userspace keep-alive daemon, see:
43 * Documentation/watchdog/watchdog.txt
44 */
45
46#include <linux/module.h>
47#include <linux/moduleparam.h>
48#include <linux/types.h>
49#include <linux/miscdevice.h>
50#include <linux/watchdog.h>
51#include <linux/delay.h>
52#include <linux/fs.h>
53#include <linux/ioport.h>
54#include <linux/notifier.h>
55#include <linux/reboot.h>
56#include <linux/init.h>
57#include <linux/spinlock.h>
58
59#include <asm/io.h>
60#include <asm/uaccess.h>
61#include <asm/system.h>
62
63/* enable support for minutes as units? */
64/* (does not always work correctly, so disabled by default!) */
65#define SMSC_SUPPORT_MINUTES
66#undef SMSC_SUPPORT_MINUTES
67
68#define MAX_TIMEOUT 255
69
70#define UNIT_SECOND 0
71#define UNIT_MINUTE 1
72
73#define MODNAME "smsc37b787_wdt: "
74#define VERSION "1.1"
75
76#define IOPORT 0x3F0
77#define IOPORT_SIZE 2
78#define IODEV_NO 8
79
80static int unit = UNIT_SECOND; /* timer's unit */
81static int timeout = 60; /* timeout value: default is 60 "units" */
82static unsigned long timer_enabled = 0; /* is the timer enabled? */
83
84static char expect_close; /* is the close expected? */
85
86static spinlock_t io_lock; /* to guard the watchdog from io races */
87
88static int nowayout = WATCHDOG_NOWAYOUT;
89
90/* -- Low level function ----------------------------------------*/
91
92/* unlock the IO chip */
93
94static inline void open_io_config(void)
95{
96 outb(0x55, IOPORT);
97 mdelay(1);
98 outb(0x55, IOPORT);
99}
100
101/* lock the IO chip */
102static inline void close_io_config(void)
103{
104 outb(0xAA, IOPORT);
105}
106
107/* select the IO device */
108static inline void select_io_device(unsigned char devno)
109{
110 outb(0x07, IOPORT);
111 outb(devno, IOPORT+1);
112}
113
114/* write to the control register */
115static inline void write_io_cr(unsigned char reg, unsigned char data)
116{
117 outb(reg, IOPORT);
118 outb(data, IOPORT+1);
119}
120
121/* read from the control register */
122static inline char read_io_cr(unsigned char reg)
123{
124 outb(reg, IOPORT);
125 return inb(IOPORT+1);
126}
127
128/* -- Medium level functions ------------------------------------*/
129
130static inline void gpio_bit12(unsigned char reg)
131{
132 // -- General Purpose I/O Bit 1.2 --
133 // Bit 0, In/Out: 0 = Output, 1 = Input
134 // Bit 1, Polarity: 0 = No Invert, 1 = Invert
135 // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
136 // Bit 3/4, Function select: 00 = GPI/O, 01 = WDT, 10 = P17,
137 // 11 = Either Edge Triggered Intr. 2
138 // Bit 5/6 (Reserved)
139 // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
140 write_io_cr(0xE2, reg);
141}
142
143static inline void gpio_bit13(unsigned char reg)
144{
145 // -- General Purpose I/O Bit 1.3 --
146 // Bit 0, In/Out: 0 = Output, 1 = Input
147 // Bit 1, Polarity: 0 = No Invert, 1 = Invert
148 // Bit 2, Group Enable Intr.: 0 = Disable, 1 = Enable
149 // Bit 3, Function select: 0 = GPI/O, 1 = LED
150 // Bit 4-6 (Reserved)
151 // Bit 7, Output Type: 0 = Push Pull Bit, 1 = Open Drain
152 write_io_cr(0xE3, reg);
153}
154
155static inline void wdt_timer_units(unsigned char new_units)
156{
157 // -- Watchdog timer units --
158 // Bit 0-6 (Reserved)
159 // Bit 7, WDT Time-out Value Units Select
160 // (0 = Minutes, 1 = Seconds)
161 write_io_cr(0xF1, new_units);
162}
163
164static inline void wdt_timeout_value(unsigned char new_timeout)
165{
166 // -- Watchdog Timer Time-out Value --
167 // Bit 0-7 Binary coded units (0=Disabled, 1..255)
168 write_io_cr(0xF2, new_timeout);
169}
170
171static inline void wdt_timer_conf(unsigned char conf)
172{
173 // -- Watchdog timer configuration --
174 // Bit 0 Joystick enable: 0* = No Reset, 1 = Reset WDT upon Gameport I/O
175 // Bit 1 Keyboard enable: 0* = No Reset, 1 = Reset WDT upon KBD Intr.
176 // Bit 2 Mouse enable: 0* = No Reset, 1 = Reset WDT upon Mouse Intr.
177 // Bit 3 Reset the timer
178 // (Wrong in SMsC documentation? Given as: PowerLED Timout Enabled)
179 // Bit 4-7 WDT Interrupt Mapping: (0000* = Disabled,
180 // 0001=IRQ1, 0010=(Invalid), 0011=IRQ3 to 1111=IRQ15)
181 write_io_cr(0xF3, conf);
182}
183
184static inline void wdt_timer_ctrl(unsigned char reg)
185{
186 // -- Watchdog timer control --
187 // Bit 0 Status Bit: 0 = Timer counting, 1 = Timeout occured
188 // Bit 1 Power LED Toggle: 0 = Disable Toggle, 1 = Toggle at 1 Hz
189 // Bit 2 Force Timeout: 1 = Forces WD timeout event (self-cleaning)
190 // Bit 3 P20 Force Timeout enabled:
191 // 0 = P20 activity does not generate the WD timeout event
192 // 1 = P20 Allows rising edge of P20, from the keyboard
193 // controller, to force the WD timeout event.
194 // Bit 4 (Reserved)
195 // -- Soft power management --
196 // Bit 5 Stop Counter: 1 = Stop software power down counter
197 // set via register 0xB8, (self-cleaning)
198 // (Upon read: 0 = Counter running, 1 = Counter stopped)
199 // Bit 6 Restart Counter: 1 = Restart software power down counter
200 // set via register 0xB8, (self-cleaning)
201 // Bit 7 SPOFF: 1 = Force software power down (self-cleaning)
202
203 write_io_cr(0xF4, reg);
204}
205
206/* -- Higher level functions ------------------------------------*/
207
208/* initialize watchdog */
209
210static void wb_smsc_wdt_initialize(void)
211{
212 unsigned char old;
213
214 spin_lock(&io_lock);
215 open_io_config();
216 select_io_device(IODEV_NO);
217
218 // enable the watchdog
219 gpio_bit13(0x08); // Select pin 80 = LED not GPIO
220 gpio_bit12(0x0A); // Set pin 79 = WDT not GPIO/Output/Polarity=Invert
221
222 // disable the timeout
223 wdt_timeout_value(0);
224
225 // reset control register
226 wdt_timer_ctrl(0x00);
227
228 // reset configuration register
229 wdt_timer_conf(0x00);
230
231 // read old (timer units) register
232 old = read_io_cr(0xF1) & 0x7F;
233 if (unit == UNIT_SECOND) old |= 0x80; // set to seconds
234
235 // set the watchdog timer units
236 wdt_timer_units(old);
237
238 close_io_config();
239 spin_unlock(&io_lock);
240}
241
242/* shutdown the watchdog */
243
244static void wb_smsc_wdt_shutdown(void)
245{
246 spin_lock(&io_lock);
247 open_io_config();
248 select_io_device(IODEV_NO);
249
250 // disable the watchdog
251 gpio_bit13(0x09);
252 gpio_bit12(0x09);
253
254 // reset watchdog config register
255 wdt_timer_conf(0x00);
256
257 // reset watchdog control register
258 wdt_timer_ctrl(0x00);
259
260 // disable timeout
261 wdt_timeout_value(0x00);
262
263 close_io_config();
264 spin_unlock(&io_lock);
265}
266
267/* set timeout => enable watchdog */
268
269static void wb_smsc_wdt_set_timeout(unsigned char new_timeout)
270{
271 spin_lock(&io_lock);
272 open_io_config();
273 select_io_device(IODEV_NO);
274
275 // set Power LED to blink, if we enable the timeout
276 wdt_timer_ctrl((new_timeout == 0) ? 0x00 : 0x02);
277
278 // set timeout value
279 wdt_timeout_value(new_timeout);
280
281 close_io_config();
282 spin_unlock(&io_lock);
283}
284
285/* get timeout */
286
287static unsigned char wb_smsc_wdt_get_timeout(void)
288{
289 unsigned char set_timeout;
290
291 spin_lock(&io_lock);
292 open_io_config();
293 select_io_device(IODEV_NO);
294 set_timeout = read_io_cr(0xF2);
295 close_io_config();
296 spin_unlock(&io_lock);
297
298 return set_timeout;
299}
300
301/* disable watchdog */
302
303static void wb_smsc_wdt_disable(void)
304{
305 // set the timeout to 0 to disable the watchdog
306 wb_smsc_wdt_set_timeout(0);
307}
308
309/* enable watchdog by setting the current timeout */
310
311static void wb_smsc_wdt_enable(void)
312{
313 // set the current timeout...
314 wb_smsc_wdt_set_timeout(timeout);
315}
316
317/* reset the timer */
318
319static void wb_smsc_wdt_reset_timer(void)
320{
321 spin_lock(&io_lock);
322 open_io_config();
323 select_io_device(IODEV_NO);
324
325 // reset the timer
326 wdt_timeout_value(timeout);
327 wdt_timer_conf(0x08);
328
329 close_io_config();
330 spin_unlock(&io_lock);
331}
332
333/* return, if the watchdog is enabled (timeout is set...) */
334
335static int wb_smsc_wdt_status(void)
336{
337 return (wb_smsc_wdt_get_timeout() == 0) ? 0 : WDIOF_KEEPALIVEPING;
338}
339
340
341/* -- File operations -------------------------------------------*/
342
343/* open => enable watchdog and set initial timeout */
344
345static int wb_smsc_wdt_open(struct inode *inode, struct file *file)
346{
347 /* /dev/watchdog can only be opened once */
348
349 if (test_and_set_bit(0, &timer_enabled))
350 return -EBUSY;
351
352 if (nowayout)
353 __module_get(THIS_MODULE);
354
355 /* Reload and activate timer */
356 wb_smsc_wdt_enable();
357
358 printk(KERN_INFO MODNAME "Watchdog enabled. Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
359
360 return nonseekable_open(inode, file);
361}
362
363/* close => shut off the timer */
364
365static int wb_smsc_wdt_release(struct inode *inode, struct file *file)
366{
367 /* Shut off the timer. */
368
369 if (expect_close == 42) {
370 wb_smsc_wdt_disable();
371 printk(KERN_INFO MODNAME "Watchdog disabled, sleeping again...\n");
372 } else {
373 printk(KERN_CRIT MODNAME "Unexpected close, not stopping watchdog!\n");
374 wb_smsc_wdt_reset_timer();
375 }
376
377 clear_bit(0, &timer_enabled);
378 expect_close = 0;
379 return 0;
380}
381
382/* write => update the timer to keep the machine alive */
383
384static ssize_t wb_smsc_wdt_write(struct file *file, const char __user *data,
385 size_t len, loff_t *ppos)
386{
387 /* See if we got the magic character 'V' and reload the timer */
388 if (len) {
389 if (!nowayout) {
390 size_t i;
391
392 /* reset expect flag */
393 expect_close = 0;
394
395 /* scan to see whether or not we got the magic character */
396 for (i = 0; i != len; i++) {
397 char c;
398 if (get_user(c, data+i))
399 return -EFAULT;
400 if (c == 'V')
401 expect_close = 42;
402 }
403 }
404
405 /* someone wrote to us, we should reload the timer */
406 wb_smsc_wdt_reset_timer();
407 }
408 return len;
409}
410
411/* ioctl => control interface */
412
413static int wb_smsc_wdt_ioctl(struct inode *inode, struct file *file,
414 unsigned int cmd, unsigned long arg)
415{
416 int new_timeout;
417
418 union {
419 struct watchdog_info __user *ident;
420 int __user *i;
421 } uarg;
422
423 static struct watchdog_info ident = {
424 .options = WDIOF_KEEPALIVEPING |
425 WDIOF_SETTIMEOUT |
426 WDIOF_MAGICCLOSE,
427 .firmware_version = 0,
428 .identity = "SMsC 37B787 Watchdog"
429 };
430
431 uarg.i = (int __user *)arg;
432
433 switch (cmd) {
434 default:
435 return -ENOTTY;
436
437 case WDIOC_GETSUPPORT:
438 return copy_to_user(uarg.ident, &ident,
439 sizeof(ident)) ? -EFAULT : 0;
440
441 case WDIOC_GETSTATUS:
442 return put_user(wb_smsc_wdt_status(), uarg.i);
443
444 case WDIOC_GETBOOTSTATUS:
445 return put_user(0, uarg.i);
446
447 case WDIOC_KEEPALIVE:
448 wb_smsc_wdt_reset_timer();
449 return 0;
450
451 case WDIOC_SETTIMEOUT:
452 if (get_user(new_timeout, uarg.i))
453 return -EFAULT;
454
455 // the API states this is given in secs
456 if (unit == UNIT_MINUTE)
457 new_timeout /= 60;
458
459 if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
460 return -EINVAL;
461
462 timeout = new_timeout;
463 wb_smsc_wdt_set_timeout(timeout);
464
465 // fall through and return the new timeout...
466
467 case WDIOC_GETTIMEOUT:
468
469 new_timeout = timeout;
470
471 if (unit == UNIT_MINUTE)
472 new_timeout *= 60;
473
474 return put_user(new_timeout, uarg.i);
475
476 case WDIOC_SETOPTIONS:
477 {
478 int options, retval = -EINVAL;
479
480 if (get_user(options, uarg.i))
481 return -EFAULT;
482
483 if (options & WDIOS_DISABLECARD) {
484 wb_smsc_wdt_disable();
485 retval = 0;
486 }
487
488 if (options & WDIOS_ENABLECARD) {
489 wb_smsc_wdt_enable();
490 retval = 0;
491 }
492
493 return retval;
494 }
495 }
496}
497
498/* -- Notifier funtions -----------------------------------------*/
499
500static int wb_smsc_wdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
501{
502 if (code == SYS_DOWN || code == SYS_HALT)
503 {
504 // set timeout to 0, to avoid possible race-condition
505 timeout = 0;
506 wb_smsc_wdt_disable();
507 }
508 return NOTIFY_DONE;
509}
510
511/* -- Module's structures ---------------------------------------*/
512
513static const struct file_operations wb_smsc_wdt_fops =
514{
515 .owner = THIS_MODULE,
516 .llseek = no_llseek,
517 .write = wb_smsc_wdt_write,
518 .ioctl = wb_smsc_wdt_ioctl,
519 .open = wb_smsc_wdt_open,
520 .release = wb_smsc_wdt_release,
521};
522
523static struct notifier_block wb_smsc_wdt_notifier =
524{
525 .notifier_call = wb_smsc_wdt_notify_sys,
526};
527
528static struct miscdevice wb_smsc_wdt_miscdev =
529{
530 .minor = WATCHDOG_MINOR,
531 .name = "watchdog",
532 .fops = &wb_smsc_wdt_fops,
533};
534
535/* -- Module init functions -------------------------------------*/
536
537/* module's "constructor" */
538
539static int __init wb_smsc_wdt_init(void)
540{
541 int ret;
542
543 spin_lock_init(&io_lock);
544
545 printk("SMsC 37B787 watchdog component driver " VERSION " initialising...\n");
546
547 if (!request_region(IOPORT, IOPORT_SIZE, "SMsC 37B787 watchdog")) {
548 printk(KERN_ERR MODNAME "Unable to register IO port %#x\n", IOPORT);
549 ret = -EBUSY;
550 goto out_pnp;
551 }
552
553 // set new maximum, if it's too big
554 if (timeout > MAX_TIMEOUT)
555 timeout = MAX_TIMEOUT;
556
557 // init the watchdog timer
558 wb_smsc_wdt_initialize();
559
560 ret = register_reboot_notifier(&wb_smsc_wdt_notifier);
561 if (ret) {
562 printk(KERN_ERR MODNAME "Unable to register reboot notifier err = %d\n", ret);
563 goto out_io;
564 }
565
566 ret = misc_register(&wb_smsc_wdt_miscdev);
567 if (ret) {
568 printk(KERN_ERR MODNAME "Unable to register miscdev on minor %d\n", WATCHDOG_MINOR);
569 goto out_rbt;
570 }
571
572 // output info
573 printk(KERN_INFO MODNAME "Timeout set to %d %s.\n", timeout, (unit == UNIT_SECOND) ? "second(s)" : "minute(s)");
574 printk(KERN_INFO MODNAME "Watchdog initialized and sleeping (nowayout=%d)...\n", nowayout);
575
576 // ret = 0
577
578out_clean:
579 return ret;
580
581out_rbt:
582 unregister_reboot_notifier(&wb_smsc_wdt_notifier);
583
584out_io:
585 release_region(IOPORT, IOPORT_SIZE);
586
587out_pnp:
588 goto out_clean;
589}
590
591/* module's "destructor" */
592
593static void __exit wb_smsc_wdt_exit(void)
594{
595 /* Stop the timer before we leave */
596 if (!nowayout)
597 {
598 wb_smsc_wdt_shutdown();
599 printk(KERN_INFO MODNAME "Watchdog disabled.\n");
600 }
601
602 misc_deregister(&wb_smsc_wdt_miscdev);
603 unregister_reboot_notifier(&wb_smsc_wdt_notifier);
604 release_region(IOPORT, IOPORT_SIZE);
605
606 printk("SMsC 37B787 watchdog component driver removed.\n");
607}
608
609module_init(wb_smsc_wdt_init);
610module_exit(wb_smsc_wdt_exit);
611
612MODULE_AUTHOR("Sven Anders <anders@anduras.de>");
613MODULE_DESCRIPTION("Driver for SMsC 37B787 watchdog component (Version " VERSION ")");
614MODULE_LICENSE("GPL");
615
616MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
617
618#ifdef SMSC_SUPPORT_MINUTES
619module_param(unit, int, 0);
620MODULE_PARM_DESC(unit, "set unit to use, 0=seconds or 1=minutes, default is 0");
621#endif
622
623module_param(timeout, int, 0);
624MODULE_PARM_DESC(timeout, "range is 1-255 units, default is 60");
625
626module_param(nowayout, int, 0);
627MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
new file mode 100644
index 000000000000..9c3694909243
--- /dev/null
+++ b/drivers/watchdog/softdog.c
@@ -0,0 +1,310 @@
1/*
2 * SoftDog 0.07: A Software Watchdog Device
3 *
4 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
5 * http://www.redhat.com
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 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
17 *
18 * Software only watchdog driver. Unlike its big brother the WDT501P
19 * driver this won't always recover a failed machine.
20 *
21 * 03/96: Angelo Haritsis <ah@doc.ic.ac.uk> :
22 * Modularised.
23 * Added soft_margin; use upon insmod to change the timer delay.
24 * NB: uses same minor as wdt (WATCHDOG_MINOR); we could use separate
25 * minors.
26 *
27 * 19980911 Alan Cox
28 * Made SMP safe for 2.3.x
29 *
30 * 20011127 Joel Becker (jlbec@evilplan.org>
31 * Added soft_noboot; Allows testing the softdog trigger without
32 * requiring a recompile.
33 * Added WDIOC_GETTIMEOUT and WDIOC_SETTIMOUT.
34 *
35 * 20020530 Joel Becker <joel.becker@oracle.com>
36 * Added Matt Domsch's nowayout module option.
37 */
38
39#include <linux/module.h>
40#include <linux/moduleparam.h>
41#include <linux/types.h>
42#include <linux/timer.h>
43#include <linux/miscdevice.h>
44#include <linux/watchdog.h>
45#include <linux/fs.h>
46#include <linux/notifier.h>
47#include <linux/reboot.h>
48#include <linux/init.h>
49#include <linux/jiffies.h>
50
51#include <asm/uaccess.h>
52
53#define PFX "SoftDog: "
54
55#define TIMER_MARGIN 60 /* Default is 60 seconds */
56static int soft_margin = TIMER_MARGIN; /* in seconds */
57module_param(soft_margin, int, 0);
58MODULE_PARM_DESC(soft_margin, "Watchdog soft_margin in seconds. (0<soft_margin<65536, default=" __MODULE_STRING(TIMER_MARGIN) ")");
59
60static int nowayout = WATCHDOG_NOWAYOUT;
61module_param(nowayout, int, 0);
62MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
63
64#ifdef ONLY_TESTING
65static int soft_noboot = 1;
66#else
67static int soft_noboot = 0;
68#endif /* ONLY_TESTING */
69
70module_param(soft_noboot, int, 0);
71MODULE_PARM_DESC(soft_noboot, "Softdog action, set to 1 to ignore reboots, 0 to reboot (default depends on ONLY_TESTING)");
72
73/*
74 * Our timer
75 */
76
77static void watchdog_fire(unsigned long);
78
79static struct timer_list watchdog_ticktock =
80 TIMER_INITIALIZER(watchdog_fire, 0, 0);
81static unsigned long driver_open, orphan_timer;
82static char expect_close;
83
84
85/*
86 * If the timer expires..
87 */
88
89static void watchdog_fire(unsigned long data)
90{
91 if (test_and_clear_bit(0, &orphan_timer))
92 module_put(THIS_MODULE);
93
94 if (soft_noboot)
95 printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
96 else
97 {
98 printk(KERN_CRIT PFX "Initiating system reboot.\n");
99 emergency_restart();
100 printk(KERN_CRIT PFX "Reboot didn't ?????\n");
101 }
102}
103
104/*
105 * Softdog operations
106 */
107
108static int softdog_keepalive(void)
109{
110 mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
111 return 0;
112}
113
114static int softdog_stop(void)
115{
116 del_timer(&watchdog_ticktock);
117 return 0;
118}
119
120static int softdog_set_heartbeat(int t)
121{
122 if ((t < 0x0001) || (t > 0xFFFF))
123 return -EINVAL;
124
125 soft_margin = t;
126 return 0;
127}
128
129/*
130 * /dev/watchdog handling
131 */
132
133static int softdog_open(struct inode *inode, struct file *file)
134{
135 if (test_and_set_bit(0, &driver_open))
136 return -EBUSY;
137 if (!test_and_clear_bit(0, &orphan_timer))
138 __module_get(THIS_MODULE);
139 /*
140 * Activate timer
141 */
142 softdog_keepalive();
143 return nonseekable_open(inode, file);
144}
145
146static int softdog_release(struct inode *inode, struct file *file)
147{
148 /*
149 * Shut off the timer.
150 * Lock it in if it's a module and we set nowayout
151 */
152 if (expect_close == 42) {
153 softdog_stop();
154 module_put(THIS_MODULE);
155 } else {
156 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
157 set_bit(0, &orphan_timer);
158 softdog_keepalive();
159 }
160 clear_bit(0, &driver_open);
161 expect_close = 0;
162 return 0;
163}
164
165static ssize_t softdog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
166{
167 /*
168 * Refresh the timer.
169 */
170 if(len) {
171 if (!nowayout) {
172 size_t i;
173
174 /* In case it was set long ago */
175 expect_close = 0;
176
177 for (i = 0; i != len; i++) {
178 char c;
179
180 if (get_user(c, data + i))
181 return -EFAULT;
182 if (c == 'V')
183 expect_close = 42;
184 }
185 }
186 softdog_keepalive();
187 }
188 return len;
189}
190
191static int softdog_ioctl(struct inode *inode, struct file *file,
192 unsigned int cmd, unsigned long arg)
193{
194 void __user *argp = (void __user *)arg;
195 int __user *p = argp;
196 int new_margin;
197 static struct watchdog_info ident = {
198 .options = WDIOF_SETTIMEOUT |
199 WDIOF_KEEPALIVEPING |
200 WDIOF_MAGICCLOSE,
201 .firmware_version = 0,
202 .identity = "Software Watchdog",
203 };
204 switch (cmd) {
205 default:
206 return -ENOTTY;
207 case WDIOC_GETSUPPORT:
208 return copy_to_user(argp, &ident,
209 sizeof(ident)) ? -EFAULT : 0;
210 case WDIOC_GETSTATUS:
211 case WDIOC_GETBOOTSTATUS:
212 return put_user(0, p);
213 case WDIOC_KEEPALIVE:
214 softdog_keepalive();
215 return 0;
216 case WDIOC_SETTIMEOUT:
217 if (get_user(new_margin, p))
218 return -EFAULT;
219 if (softdog_set_heartbeat(new_margin))
220 return -EINVAL;
221 softdog_keepalive();
222 /* Fall */
223 case WDIOC_GETTIMEOUT:
224 return put_user(soft_margin, p);
225 }
226}
227
228/*
229 * Notifier for system down
230 */
231
232static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
233 void *unused)
234{
235 if(code==SYS_DOWN || code==SYS_HALT) {
236 /* Turn the WDT off */
237 softdog_stop();
238 }
239 return NOTIFY_DONE;
240}
241
242/*
243 * Kernel Interfaces
244 */
245
246static const struct file_operations softdog_fops = {
247 .owner = THIS_MODULE,
248 .llseek = no_llseek,
249 .write = softdog_write,
250 .ioctl = softdog_ioctl,
251 .open = softdog_open,
252 .release = softdog_release,
253};
254
255static struct miscdevice softdog_miscdev = {
256 .minor = WATCHDOG_MINOR,
257 .name = "watchdog",
258 .fops = &softdog_fops,
259};
260
261static struct notifier_block softdog_notifier = {
262 .notifier_call = softdog_notify_sys,
263};
264
265static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 initialized. soft_noboot=%d soft_margin=%d sec (nowayout= %d)\n";
266
267static int __init watchdog_init(void)
268{
269 int ret;
270
271 /* Check that the soft_margin value is within it's range ; if not reset to the default */
272 if (softdog_set_heartbeat(soft_margin)) {
273 softdog_set_heartbeat(TIMER_MARGIN);
274 printk(KERN_INFO PFX "soft_margin value must be 0<soft_margin<65536, using %d\n",
275 TIMER_MARGIN);
276 }
277
278 ret = register_reboot_notifier(&softdog_notifier);
279 if (ret) {
280 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
281 ret);
282 return ret;
283 }
284
285 ret = misc_register(&softdog_miscdev);
286 if (ret) {
287 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
288 WATCHDOG_MINOR, ret);
289 unregister_reboot_notifier(&softdog_notifier);
290 return ret;
291 }
292
293 printk(banner, soft_noboot, soft_margin, nowayout);
294
295 return 0;
296}
297
298static void __exit watchdog_exit(void)
299{
300 misc_deregister(&softdog_miscdev);
301 unregister_reboot_notifier(&softdog_notifier);
302}
303
304module_init(watchdog_init);
305module_exit(watchdog_exit);
306
307MODULE_AUTHOR("Alan Cox");
308MODULE_DESCRIPTION("Software Watchdog Device Driver");
309MODULE_LICENSE("GPL");
310MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
new file mode 100644
index 000000000000..df33b3b5a53c
--- /dev/null
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -0,0 +1,390 @@
1/*
2 * w83627hf/thf WDT driver
3 *
4 * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
5 * added support for W83627THF.
6 *
7 * (c) Copyright 2003,2007 Pádraig Brady <P@draigBrady.com>
8 *
9 * Based on advantechwdt.c which is based on wdt.c.
10 * Original copyright messages:
11 *
12 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
13 *
14 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
15 * http://www.redhat.com
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version
20 * 2 of the License, or (at your option) any later version.
21 *
22 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
23 * warranty for any of this software. This material is provided
24 * "AS-IS" and at no charge.
25 *
26 * (c) Copyright 1995 Alan Cox <alan@redhat.com>
27 */
28
29#include <linux/module.h>
30#include <linux/moduleparam.h>
31#include <linux/types.h>
32#include <linux/miscdevice.h>
33#include <linux/watchdog.h>
34#include <linux/fs.h>
35#include <linux/ioport.h>
36#include <linux/notifier.h>
37#include <linux/reboot.h>
38#include <linux/init.h>
39#include <linux/spinlock.h>
40
41#include <asm/io.h>
42#include <asm/uaccess.h>
43#include <asm/system.h>
44
45#define WATCHDOG_NAME "w83627hf/thf/hg WDT"
46#define PFX WATCHDOG_NAME ": "
47#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
48
49static unsigned long wdt_is_open;
50static char expect_close;
51static spinlock_t io_lock;
52
53/* You must set this - there is no sane way to probe for this board. */
54static int wdt_io = 0x2E;
55module_param(wdt_io, int, 0);
56MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
57
58static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
59module_param(timeout, int, 0);
60MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
61
62static int nowayout = WATCHDOG_NOWAYOUT;
63module_param(nowayout, int, 0);
64MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
65
66/*
67 * Kernel methods.
68 */
69
70#define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */
71#define WDT_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */
72#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
73
74static void
75w83627hf_select_wd_register(void)
76{
77 unsigned char c;
78 outb_p(0x87, WDT_EFER); /* Enter extended function mode */
79 outb_p(0x87, WDT_EFER); /* Again according to manual */
80
81 outb(0x20, WDT_EFER); /* check chip version */
82 c = inb(WDT_EFDR);
83 if (c == 0x82) { /* W83627THF */
84 outb_p(0x2b, WDT_EFER); /* select GPIO3 */
85 c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */
86 outb_p(0x2b, WDT_EFER);
87 outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */
88 }
89
90 outb_p(0x07, WDT_EFER); /* point to logical device number reg */
91 outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */
92 outb_p(0x30, WDT_EFER); /* select CR30 */
93 outb_p(0x01, WDT_EFDR); /* set bit 0 to activate GPIO2 */
94}
95
96static void
97w83627hf_unselect_wd_register(void)
98{
99 outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
100}
101
102/* tyan motherboards seem to set F5 to 0x4C ?
103 * So explicitly init to appropriate value. */
104static void
105w83627hf_init(void)
106{
107 unsigned char t;
108
109 w83627hf_select_wd_register();
110
111 outb_p(0xF6, WDT_EFER); /* Select CRF6 */
112 t=inb_p(WDT_EFDR); /* read CRF6 */
113 if (t != 0) {
114 printk (KERN_INFO PFX "Watchdog already running. Resetting timeout to %d sec\n", timeout);
115 outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */
116 }
117
118 outb_p(0xF5, WDT_EFER); /* Select CRF5 */
119 t=inb_p(WDT_EFDR); /* read CRF5 */
120 t&=~0x0C; /* set second mode & disable keyboard turning off watchdog */
121 outb_p(t, WDT_EFDR); /* Write back to CRF5 */
122
123 outb_p(0xF7, WDT_EFER); /* Select CRF7 */
124 t=inb_p(WDT_EFDR); /* read CRF7 */
125 t&=~0xC0; /* disable keyboard & mouse turning off watchdog */
126 outb_p(t, WDT_EFDR); /* Write back to CRF7 */
127
128 w83627hf_unselect_wd_register();
129}
130
131static void
132wdt_ctrl(int timeout)
133{
134 spin_lock(&io_lock);
135
136 w83627hf_select_wd_register();
137
138 outb_p(0xF6, WDT_EFER); /* Select CRF6 */
139 outb_p(timeout, WDT_EFDR); /* Write Timeout counter to CRF6 */
140
141 w83627hf_unselect_wd_register();
142
143 spin_unlock(&io_lock);
144}
145
146static int
147wdt_ping(void)
148{
149 wdt_ctrl(timeout);
150 return 0;
151}
152
153static int
154wdt_disable(void)
155{
156 wdt_ctrl(0);
157 return 0;
158}
159
160static int
161wdt_set_heartbeat(int t)
162{
163 if ((t < 1) || (t > 255))
164 return -EINVAL;
165
166 timeout = t;
167 return 0;
168}
169
170static ssize_t
171wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
172{
173 if (count) {
174 if (!nowayout) {
175 size_t i;
176
177 expect_close = 0;
178
179 for (i = 0; i != count; i++) {
180 char c;
181 if (get_user(c, buf+i))
182 return -EFAULT;
183 if (c == 'V')
184 expect_close = 42;
185 }
186 }
187 wdt_ping();
188 }
189 return count;
190}
191
192static int
193wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
194 unsigned long arg)
195{
196 void __user *argp = (void __user *)arg;
197 int __user *p = argp;
198 int new_timeout;
199 static struct watchdog_info ident = {
200 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
201 .firmware_version = 1,
202 .identity = "W83627HF WDT",
203 };
204
205 switch (cmd) {
206 case WDIOC_GETSUPPORT:
207 if (copy_to_user(argp, &ident, sizeof(ident)))
208 return -EFAULT;
209 break;
210
211 case WDIOC_GETSTATUS:
212 case WDIOC_GETBOOTSTATUS:
213 return put_user(0, p);
214
215 case WDIOC_KEEPALIVE:
216 wdt_ping();
217 break;
218
219 case WDIOC_SETTIMEOUT:
220 if (get_user(new_timeout, p))
221 return -EFAULT;
222 if (wdt_set_heartbeat(new_timeout))
223 return -EINVAL;
224 wdt_ping();
225 /* Fall */
226
227 case WDIOC_GETTIMEOUT:
228 return put_user(timeout, p);
229
230 case WDIOC_SETOPTIONS:
231 {
232 int options, retval = -EINVAL;
233
234 if (get_user(options, p))
235 return -EFAULT;
236
237 if (options & WDIOS_DISABLECARD) {
238 wdt_disable();
239 retval = 0;
240 }
241
242 if (options & WDIOS_ENABLECARD) {
243 wdt_ping();
244 retval = 0;
245 }
246
247 return retval;
248 }
249
250 default:
251 return -ENOTTY;
252 }
253 return 0;
254}
255
256static int
257wdt_open(struct inode *inode, struct file *file)
258{
259 if (test_and_set_bit(0, &wdt_is_open))
260 return -EBUSY;
261 /*
262 * Activate
263 */
264
265 wdt_ping();
266 return nonseekable_open(inode, file);
267}
268
269static int
270wdt_close(struct inode *inode, struct file *file)
271{
272 if (expect_close == 42) {
273 wdt_disable();
274 } else {
275 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
276 wdt_ping();
277 }
278 expect_close = 0;
279 clear_bit(0, &wdt_is_open);
280 return 0;
281}
282
283/*
284 * Notifier for system down
285 */
286
287static int
288wdt_notify_sys(struct notifier_block *this, unsigned long code,
289 void *unused)
290{
291 if (code == SYS_DOWN || code == SYS_HALT) {
292 /* Turn the WDT off */
293 wdt_disable();
294 }
295 return NOTIFY_DONE;
296}
297
298/*
299 * Kernel Interfaces
300 */
301
302static const struct file_operations wdt_fops = {
303 .owner = THIS_MODULE,
304 .llseek = no_llseek,
305 .write = wdt_write,
306 .ioctl = wdt_ioctl,
307 .open = wdt_open,
308 .release = wdt_close,
309};
310
311static struct miscdevice wdt_miscdev = {
312 .minor = WATCHDOG_MINOR,
313 .name = "watchdog",
314 .fops = &wdt_fops,
315};
316
317/*
318 * The WDT needs to learn about soft shutdowns in order to
319 * turn the timebomb registers off.
320 */
321
322static struct notifier_block wdt_notifier = {
323 .notifier_call = wdt_notify_sys,
324};
325
326static int __init
327wdt_init(void)
328{
329 int ret;
330
331 spin_lock_init(&io_lock);
332
333 printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF/HG Super I/O chip initialising.\n");
334
335 if (wdt_set_heartbeat(timeout)) {
336 wdt_set_heartbeat(WATCHDOG_TIMEOUT);
337 printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
338 WATCHDOG_TIMEOUT);
339 }
340
341 if (!request_region(wdt_io, 1, WATCHDOG_NAME)) {
342 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
343 wdt_io);
344 ret = -EIO;
345 goto out;
346 }
347
348 w83627hf_init();
349
350 ret = register_reboot_notifier(&wdt_notifier);
351 if (ret != 0) {
352 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
353 ret);
354 goto unreg_regions;
355 }
356
357 ret = misc_register(&wdt_miscdev);
358 if (ret != 0) {
359 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
360 WATCHDOG_MINOR, ret);
361 goto unreg_reboot;
362 }
363
364 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
365 timeout, nowayout);
366
367out:
368 return ret;
369unreg_reboot:
370 unregister_reboot_notifier(&wdt_notifier);
371unreg_regions:
372 release_region(wdt_io, 1);
373 goto out;
374}
375
376static void __exit
377wdt_exit(void)
378{
379 misc_deregister(&wdt_miscdev);
380 unregister_reboot_notifier(&wdt_notifier);
381 release_region(wdt_io,1);
382}
383
384module_init(wdt_init);
385module_exit(wdt_exit);
386
387MODULE_LICENSE("GPL");
388MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>");
389MODULE_DESCRIPTION("w83627hf/thf WDT driver");
390MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c
new file mode 100644
index 000000000000..d9e821d08deb
--- /dev/null
+++ b/drivers/watchdog/w83697hf_wdt.c
@@ -0,0 +1,450 @@
1/*
2 * w83697hf/hg WDT driver
3 *
4 * (c) Copyright 2006 Samuel Tardieu <sam@rfc1149.net>
5 * (c) Copyright 2006 Marcus Junker <junker@anduras.de>
6 *
7 * Based on w83627hf_wdt.c which is based on advantechwdt.c
8 * which is based on wdt.c.
9 * Original copyright messages:
10 *
11 * (c) Copyright 2003 Pádraig Brady <P@draigBrady.com>
12 *
13 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
14 *
15 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
16 * http://www.redhat.com
17 *
18 * This program is free software; you can redistribute it and/or
19 * modify it under the terms of the GNU General Public License
20 * as published by the Free Software Foundation; either version
21 * 2 of the License, or (at your option) any later version.
22 *
23 * Neither Marcus Junker nor ANDURAS AG admit liability nor provide
24 * warranty for any of this software. This material is provided
25 * "AS-IS" and at no charge.
26 */
27
28#include <linux/module.h>
29#include <linux/moduleparam.h>
30#include <linux/types.h>
31#include <linux/miscdevice.h>
32#include <linux/watchdog.h>
33#include <linux/fs.h>
34#include <linux/ioport.h>
35#include <linux/notifier.h>
36#include <linux/reboot.h>
37#include <linux/init.h>
38#include <linux/spinlock.h>
39
40#include <asm/io.h>
41#include <asm/uaccess.h>
42#include <asm/system.h>
43
44#define WATCHDOG_NAME "w83697hf/hg WDT"
45#define PFX WATCHDOG_NAME ": "
46#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
47
48static unsigned long wdt_is_open;
49static char expect_close;
50static spinlock_t io_lock;
51
52/* You must set this - there is no sane way to probe for this board. */
53static int wdt_io = 0x2e;
54module_param(wdt_io, int, 0);
55MODULE_PARM_DESC(wdt_io, "w83697hf/hg WDT io port (default 0x2e, 0 = autodetect)");
56
57static int timeout = WATCHDOG_TIMEOUT; /* in seconds */
58module_param(timeout, int, 0);
59MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
60
61static int nowayout = WATCHDOG_NOWAYOUT;
62module_param(nowayout, int, 0);
63MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
64
65/*
66 * Kernel methods.
67 */
68
69#define W83697HF_EFER (wdt_io+0) /* Extended Function Enable Register */
70#define W83697HF_EFIR (wdt_io+0) /* Extended Function Index Register (same as EFER) */
71#define W83697HF_EFDR (wdt_io+1) /* Extended Function Data Register */
72
73static inline void
74w83697hf_unlock(void)
75{
76 outb_p(0x87, W83697HF_EFER); /* Enter extended function mode */
77 outb_p(0x87, W83697HF_EFER); /* Again according to manual */
78}
79
80static inline void
81w83697hf_lock(void)
82{
83 outb_p(0xAA, W83697HF_EFER); /* Leave extended function mode */
84}
85
86/*
87 * The three functions w83697hf_get_reg(), w83697hf_set_reg() and
88 * w83697hf_write_timeout() must be called with the device unlocked.
89 */
90
91static unsigned char
92w83697hf_get_reg(unsigned char reg)
93{
94 outb_p(reg, W83697HF_EFIR);
95 return inb_p(W83697HF_EFDR);
96}
97
98static void
99w83697hf_set_reg(unsigned char reg, unsigned char data)
100{
101 outb_p(reg, W83697HF_EFIR);
102 outb_p(data, W83697HF_EFDR);
103}
104
105static void
106w83697hf_write_timeout(int timeout)
107{
108 w83697hf_set_reg(0xF4, timeout); /* Write Timeout counter to CRF4 */
109}
110
111static void
112w83697hf_select_wdt(void)
113{
114 w83697hf_unlock();
115 w83697hf_set_reg(0x07, 0x08); /* Switch to logic device 8 (GPIO2) */
116}
117
118static inline void
119w83697hf_deselect_wdt(void)
120{
121 w83697hf_lock();
122}
123
124static void
125w83697hf_init(void)
126{
127 unsigned char bbuf;
128
129 w83697hf_select_wdt();
130
131 bbuf = w83697hf_get_reg(0x29);
132 bbuf &= ~0x60;
133 bbuf |= 0x20;
134 w83697hf_set_reg(0x29, bbuf); /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
135
136 bbuf = w83697hf_get_reg(0xF3);
137 bbuf &= ~0x04;
138 w83697hf_set_reg(0xF3, bbuf); /* Count mode is seconds */
139
140 w83697hf_deselect_wdt();
141}
142
143static int
144wdt_ping(void)
145{
146 spin_lock(&io_lock);
147 w83697hf_select_wdt();
148
149 w83697hf_write_timeout(timeout);
150
151 w83697hf_deselect_wdt();
152 spin_unlock(&io_lock);
153 return 0;
154}
155
156static int
157wdt_enable(void)
158{
159 spin_lock(&io_lock);
160 w83697hf_select_wdt();
161
162 w83697hf_write_timeout(timeout);
163 w83697hf_set_reg(0x30, 1); /* Enable timer */
164
165 w83697hf_deselect_wdt();
166 spin_unlock(&io_lock);
167 return 0;
168}
169
170static int
171wdt_disable(void)
172{
173 spin_lock(&io_lock);
174 w83697hf_select_wdt();
175
176 w83697hf_set_reg(0x30, 0); /* Disable timer */
177 w83697hf_write_timeout(0);
178
179 w83697hf_deselect_wdt();
180 spin_unlock(&io_lock);
181 return 0;
182}
183
184static int
185wdt_set_heartbeat(int t)
186{
187 if ((t < 1) || (t > 255))
188 return -EINVAL;
189
190 timeout = t;
191 return 0;
192}
193
194static ssize_t
195wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
196{
197 if (count) {
198 if (!nowayout) {
199 size_t i;
200
201 expect_close = 0;
202
203 for (i = 0; i != count; i++) {
204 char c;
205 if (get_user(c, buf+i))
206 return -EFAULT;
207 if (c == 'V')
208 expect_close = 42;
209 }
210 }
211 wdt_ping();
212 }
213 return count;
214}
215
216static int
217wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
218 unsigned long arg)
219{
220 void __user *argp = (void __user *)arg;
221 int __user *p = argp;
222 int new_timeout;
223 static struct watchdog_info ident = {
224 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
225 .firmware_version = 1,
226 .identity = "W83697HF WDT",
227 };
228
229 switch (cmd) {
230 case WDIOC_GETSUPPORT:
231 if (copy_to_user(argp, &ident, sizeof(ident)))
232 return -EFAULT;
233 break;
234
235 case WDIOC_GETSTATUS:
236 case WDIOC_GETBOOTSTATUS:
237 return put_user(0, p);
238
239 case WDIOC_KEEPALIVE:
240 wdt_ping();
241 break;
242
243 case WDIOC_SETTIMEOUT:
244 if (get_user(new_timeout, p))
245 return -EFAULT;
246 if (wdt_set_heartbeat(new_timeout))
247 return -EINVAL;
248 wdt_ping();
249 /* Fall */
250
251 case WDIOC_GETTIMEOUT:
252 return put_user(timeout, p);
253
254 case WDIOC_SETOPTIONS:
255 {
256 int options, retval = -EINVAL;
257
258 if (get_user(options, p))
259 return -EFAULT;
260
261 if (options & WDIOS_DISABLECARD) {
262 wdt_disable();
263 retval = 0;
264 }
265
266 if (options & WDIOS_ENABLECARD) {
267 wdt_enable();
268 retval = 0;
269 }
270
271 return retval;
272 }
273
274 default:
275 return -ENOTTY;
276 }
277 return 0;
278}
279
280static int
281wdt_open(struct inode *inode, struct file *file)
282{
283 if (test_and_set_bit(0, &wdt_is_open))
284 return -EBUSY;
285 /*
286 * Activate
287 */
288
289 wdt_enable();
290 return nonseekable_open(inode, file);
291}
292
293static int
294wdt_close(struct inode *inode, struct file *file)
295{
296 if (expect_close == 42) {
297 wdt_disable();
298 } else {
299 printk (KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
300 wdt_ping();
301 }
302 expect_close = 0;
303 clear_bit(0, &wdt_is_open);
304 return 0;
305}
306
307/*
308 * Notifier for system down
309 */
310
311static int
312wdt_notify_sys(struct notifier_block *this, unsigned long code,
313 void *unused)
314{
315 if (code == SYS_DOWN || code == SYS_HALT) {
316 /* Turn the WDT off */
317 wdt_disable();
318 }
319 return NOTIFY_DONE;
320}
321
322/*
323 * Kernel Interfaces
324 */
325
326static const struct file_operations wdt_fops = {
327 .owner = THIS_MODULE,
328 .llseek = no_llseek,
329 .write = wdt_write,
330 .ioctl = wdt_ioctl,
331 .open = wdt_open,
332 .release = wdt_close,
333};
334
335static struct miscdevice wdt_miscdev = {
336 .minor = WATCHDOG_MINOR,
337 .name = "watchdog",
338 .fops = &wdt_fops,
339};
340
341/*
342 * The WDT needs to learn about soft shutdowns in order to
343 * turn the timebomb registers off.
344 */
345
346static struct notifier_block wdt_notifier = {
347 .notifier_call = wdt_notify_sys,
348};
349
350static int
351w83697hf_check_wdt(void)
352{
353 if (!request_region(wdt_io, 2, WATCHDOG_NAME)) {
354 printk (KERN_ERR PFX "I/O address 0x%x already in use\n", wdt_io);
355 return -EIO;
356 }
357
358 printk (KERN_DEBUG PFX "Looking for watchdog at address 0x%x\n", wdt_io);
359 w83697hf_unlock();
360 if (w83697hf_get_reg(0x20) == 0x60) {
361 printk (KERN_INFO PFX "watchdog found at address 0x%x\n", wdt_io);
362 w83697hf_lock();
363 return 0;
364 }
365 w83697hf_lock(); /* Reprotect in case it was a compatible device */
366
367 printk (KERN_INFO PFX "watchdog not found at address 0x%x\n", wdt_io);
368 release_region(wdt_io, 2);
369 return -EIO;
370}
371
372static int w83697hf_ioports[] = { 0x2e, 0x4e, 0x00 };
373
374static int __init
375wdt_init(void)
376{
377 int ret, i, found = 0;
378
379 spin_lock_init(&io_lock);
380
381 printk (KERN_INFO PFX "WDT driver for W83697HF/HG initializing\n");
382
383 if (wdt_io == 0) {
384 /* we will autodetect the W83697HF/HG watchdog */
385 for (i = 0; ((!found) && (w83697hf_ioports[i] != 0)); i++) {
386 wdt_io = w83697hf_ioports[i];
387 if (!w83697hf_check_wdt())
388 found++;
389 }
390 } else {
391 if (!w83697hf_check_wdt())
392 found++;
393 }
394
395 if (!found) {
396 printk (KERN_ERR PFX "No W83697HF/HG could be found\n");
397 ret = -EIO;
398 goto out;
399 }
400
401 w83697hf_init();
402 wdt_disable(); /* Disable watchdog until first use */
403
404 if (wdt_set_heartbeat(timeout)) {
405 wdt_set_heartbeat(WATCHDOG_TIMEOUT);
406 printk (KERN_INFO PFX "timeout value must be 1<=timeout<=255, using %d\n",
407 WATCHDOG_TIMEOUT);
408 }
409
410 ret = register_reboot_notifier(&wdt_notifier);
411 if (ret != 0) {
412 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
413 ret);
414 goto unreg_regions;
415 }
416
417 ret = misc_register(&wdt_miscdev);
418 if (ret != 0) {
419 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
420 WATCHDOG_MINOR, ret);
421 goto unreg_reboot;
422 }
423
424 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
425 timeout, nowayout);
426
427out:
428 return ret;
429unreg_reboot:
430 unregister_reboot_notifier(&wdt_notifier);
431unreg_regions:
432 release_region(wdt_io, 2);
433 goto out;
434}
435
436static void __exit
437wdt_exit(void)
438{
439 misc_deregister(&wdt_miscdev);
440 unregister_reboot_notifier(&wdt_notifier);
441 release_region(wdt_io, 2);
442}
443
444module_init(wdt_init);
445module_exit(wdt_exit);
446
447MODULE_LICENSE("GPL");
448MODULE_AUTHOR("Marcus Junker <junker@anduras.de>, Samuel Tardieu <sam@rfc1149.net>");
449MODULE_DESCRIPTION("w83697hf/hg WDT driver");
450MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/w83877f_wdt.c b/drivers/watchdog/w83877f_wdt.c
new file mode 100644
index 000000000000..3c88fe18f4f4
--- /dev/null
+++ b/drivers/watchdog/w83877f_wdt.c
@@ -0,0 +1,415 @@
1/*
2 * W83877F Computer Watchdog Timer driver
3 *
4 * Based on acquirewdt.c by Alan Cox,
5 * and sbc60xxwdt.c by Jakob Oestergaard <jakob@unthought.net>
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 * The authors do NOT admit liability nor provide warranty for
13 * any of this software. This material is provided "AS-IS" in
14 * the hope that it may be useful for others.
15 *
16 * (c) Copyright 2001 Scott Jennings <linuxdrivers@oro.net>
17 *
18 * 4/19 - 2001 [Initial revision]
19 * 9/27 - 2001 Added spinlocking
20 * 4/12 - 2002 [rob@osinvestor.com] Eliminate extra comments
21 * Eliminate fop_read
22 * Eliminate extra spin_unlock
23 * Added KERN_* tags to printks
24 * add CONFIG_WATCHDOG_NOWAYOUT support
25 * fix possible wdt_is_open race
26 * changed watchdog_info to correctly reflect what the driver offers
27 * added WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS, WDIOC_SETTIMEOUT,
28 * WDIOC_GETTIMEOUT, and WDIOC_SETOPTIONS ioctls
29 * 09/8 - 2003 [wim@iguana.be] cleanup of trailing spaces
30 * added extra printk's for startup problems
31 * use module_param
32 * made timeout (the emulated heartbeat) a module_param
33 * made the keepalive ping an internal subroutine
34 *
35 * This WDT driver is different from most other Linux WDT
36 * drivers in that the driver will ping the watchdog by itself,
37 * because this particular WDT has a very short timeout (1.6
38 * seconds) and it would be insane to count on any userspace
39 * daemon always getting scheduled within that time frame.
40 */
41
42#include <linux/module.h>
43#include <linux/moduleparam.h>
44#include <linux/types.h>
45#include <linux/timer.h>
46#include <linux/jiffies.h>
47#include <linux/miscdevice.h>
48#include <linux/watchdog.h>
49#include <linux/fs.h>
50#include <linux/ioport.h>
51#include <linux/notifier.h>
52#include <linux/reboot.h>
53#include <linux/init.h>
54#include <asm/io.h>
55#include <asm/uaccess.h>
56#include <asm/system.h>
57
58#define OUR_NAME "w83877f_wdt"
59#define PFX OUR_NAME ": "
60
61#define ENABLE_W83877F_PORT 0x3F0
62#define ENABLE_W83877F 0x87
63#define DISABLE_W83877F 0xAA
64#define WDT_PING 0x443
65#define WDT_REGISTER 0x14
66#define WDT_ENABLE 0x9C
67#define WDT_DISABLE 0x8C
68
69/*
70 * The W83877F seems to be fixed at 1.6s timeout (at least on the
71 * EMACS PC-104 board I'm using). If we reset the watchdog every
72 * ~250ms we should be safe. */
73
74#define WDT_INTERVAL (HZ/4+1)
75
76/*
77 * We must not require too good response from the userspace daemon.
78 * Here we require the userspace daemon to send us a heartbeat
79 * char to /dev/watchdog every 30 seconds.
80 */
81
82#define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */
83static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */
84module_param(timeout, int, 0);
85MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
86
87
88static int nowayout = WATCHDOG_NOWAYOUT;
89module_param(nowayout, int, 0);
90MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
91
92static void wdt_timer_ping(unsigned long);
93static DEFINE_TIMER(timer, wdt_timer_ping, 0, 0);
94static unsigned long next_heartbeat;
95static unsigned long wdt_is_open;
96static char wdt_expect_close;
97static spinlock_t wdt_spinlock;
98
99/*
100 * Whack the dog
101 */
102
103static void wdt_timer_ping(unsigned long data)
104{
105 /* If we got a heartbeat pulse within the WDT_US_INTERVAL
106 * we agree to ping the WDT
107 */
108 if(time_before(jiffies, next_heartbeat))
109 {
110 /* Ping the WDT */
111 spin_lock(&wdt_spinlock);
112
113 /* Ping the WDT by reading from WDT_PING */
114 inb_p(WDT_PING);
115
116 /* Re-set the timer interval */
117 mod_timer(&timer, jiffies + WDT_INTERVAL);
118
119 spin_unlock(&wdt_spinlock);
120
121 } else {
122 printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
123 }
124}
125
126/*
127 * Utility routines
128 */
129
130static void wdt_change(int writeval)
131{
132 unsigned long flags;
133 spin_lock_irqsave(&wdt_spinlock, flags);
134
135 /* buy some time */
136 inb_p(WDT_PING);
137
138 /* make W83877F available */
139 outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT);
140 outb_p(ENABLE_W83877F, ENABLE_W83877F_PORT);
141
142 /* enable watchdog */
143 outb_p(WDT_REGISTER, ENABLE_W83877F_PORT);
144 outb_p(writeval, ENABLE_W83877F_PORT+1);
145
146 /* lock the W8387FF away */
147 outb_p(DISABLE_W83877F, ENABLE_W83877F_PORT);
148
149 spin_unlock_irqrestore(&wdt_spinlock, flags);
150}
151
152static void wdt_startup(void)
153{
154 next_heartbeat = jiffies + (timeout * HZ);
155
156 /* Start the timer */
157 mod_timer(&timer, jiffies + WDT_INTERVAL);
158
159 wdt_change(WDT_ENABLE);
160
161 printk(KERN_INFO PFX "Watchdog timer is now enabled.\n");
162}
163
164static void wdt_turnoff(void)
165{
166 /* Stop the timer */
167 del_timer(&timer);
168
169 wdt_change(WDT_DISABLE);
170
171 printk(KERN_INFO PFX "Watchdog timer is now disabled...\n");
172}
173
174static void wdt_keepalive(void)
175{
176 /* user land ping */
177 next_heartbeat = jiffies + (timeout * HZ);
178}
179
180/*
181 * /dev/watchdog handling
182 */
183
184static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos)
185{
186 /* See if we got the magic character 'V' and reload the timer */
187 if(count)
188 {
189 if (!nowayout)
190 {
191 size_t ofs;
192
193 /* note: just in case someone wrote the magic character
194 * five months ago... */
195 wdt_expect_close = 0;
196
197 /* scan to see whether or not we got the magic character */
198 for(ofs = 0; ofs != count; ofs++)
199 {
200 char c;
201 if (get_user(c, buf + ofs))
202 return -EFAULT;
203 if (c == 'V')
204 wdt_expect_close = 42;
205 }
206 }
207
208 /* someone wrote to us, we should restart timer */
209 wdt_keepalive();
210 }
211 return count;
212}
213
214static int fop_open(struct inode * inode, struct file * file)
215{
216 /* Just in case we're already talking to someone... */
217 if(test_and_set_bit(0, &wdt_is_open))
218 return -EBUSY;
219
220 /* Good, fire up the show */
221 wdt_startup();
222 return nonseekable_open(inode, file);
223}
224
225static int fop_close(struct inode * inode, struct file * file)
226{
227 if(wdt_expect_close == 42)
228 wdt_turnoff();
229 else {
230 del_timer(&timer);
231 printk(KERN_CRIT PFX "device file closed unexpectedly. Will not stop the WDT!\n");
232 }
233 clear_bit(0, &wdt_is_open);
234 wdt_expect_close = 0;
235 return 0;
236}
237
238static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
239 unsigned long arg)
240{
241 void __user *argp = (void __user *)arg;
242 int __user *p = argp;
243 static struct watchdog_info ident=
244 {
245 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
246 .firmware_version = 1,
247 .identity = "W83877F",
248 };
249
250 switch(cmd)
251 {
252 default:
253 return -ENOTTY;
254 case WDIOC_GETSUPPORT:
255 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
256 case WDIOC_GETSTATUS:
257 case WDIOC_GETBOOTSTATUS:
258 return put_user(0, p);
259 case WDIOC_KEEPALIVE:
260 wdt_keepalive();
261 return 0;
262 case WDIOC_SETOPTIONS:
263 {
264 int new_options, retval = -EINVAL;
265
266 if(get_user(new_options, p))
267 return -EFAULT;
268
269 if(new_options & WDIOS_DISABLECARD) {
270 wdt_turnoff();
271 retval = 0;
272 }
273
274 if(new_options & WDIOS_ENABLECARD) {
275 wdt_startup();
276 retval = 0;
277 }
278
279 return retval;
280 }
281 case WDIOC_SETTIMEOUT:
282 {
283 int new_timeout;
284
285 if(get_user(new_timeout, p))
286 return -EFAULT;
287
288 if(new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
289 return -EINVAL;
290
291 timeout = new_timeout;
292 wdt_keepalive();
293 /* Fall through */
294 }
295 case WDIOC_GETTIMEOUT:
296 return put_user(timeout, p);
297 }
298}
299
300static const struct file_operations wdt_fops = {
301 .owner = THIS_MODULE,
302 .llseek = no_llseek,
303 .write = fop_write,
304 .open = fop_open,
305 .release = fop_close,
306 .ioctl = fop_ioctl,
307};
308
309static struct miscdevice wdt_miscdev = {
310 .minor = WATCHDOG_MINOR,
311 .name = "watchdog",
312 .fops = &wdt_fops,
313};
314
315/*
316 * Notifier for system down
317 */
318
319static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
320 void *unused)
321{
322 if(code==SYS_DOWN || code==SYS_HALT)
323 wdt_turnoff();
324 return NOTIFY_DONE;
325}
326
327/*
328 * The WDT needs to learn about soft shutdowns in order to
329 * turn the timebomb registers off.
330 */
331
332static struct notifier_block wdt_notifier=
333{
334 .notifier_call = wdt_notify_sys,
335};
336
337static void __exit w83877f_wdt_unload(void)
338{
339 wdt_turnoff();
340
341 /* Deregister */
342 misc_deregister(&wdt_miscdev);
343
344 unregister_reboot_notifier(&wdt_notifier);
345 release_region(WDT_PING,1);
346 release_region(ENABLE_W83877F_PORT,2);
347}
348
349static int __init w83877f_wdt_init(void)
350{
351 int rc = -EBUSY;
352
353 spin_lock_init(&wdt_spinlock);
354
355 if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
356 {
357 timeout = WATCHDOG_TIMEOUT;
358 printk(KERN_INFO PFX "timeout value must be 1<=x<=3600, using %d\n",
359 timeout);
360 }
361
362 if (!request_region(ENABLE_W83877F_PORT, 2, "W83877F WDT"))
363 {
364 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
365 ENABLE_W83877F_PORT);
366 rc = -EIO;
367 goto err_out;
368 }
369
370 if (!request_region(WDT_PING, 1, "W8387FF WDT"))
371 {
372 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
373 WDT_PING);
374 rc = -EIO;
375 goto err_out_region1;
376 }
377
378 rc = misc_register(&wdt_miscdev);
379 if (rc)
380 {
381 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
382 wdt_miscdev.minor, rc);
383 goto err_out_region2;
384 }
385
386 rc = register_reboot_notifier(&wdt_notifier);
387 if (rc)
388 {
389 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
390 rc);
391 goto err_out_miscdev;
392 }
393
394 printk(KERN_INFO PFX "WDT driver for W83877F initialised. timeout=%d sec (nowayout=%d)\n",
395 timeout, nowayout);
396
397 return 0;
398
399err_out_miscdev:
400 misc_deregister(&wdt_miscdev);
401err_out_region2:
402 release_region(WDT_PING,1);
403err_out_region1:
404 release_region(ENABLE_W83877F_PORT,2);
405err_out:
406 return rc;
407}
408
409module_init(w83877f_wdt_init);
410module_exit(w83877f_wdt_unload);
411
412MODULE_AUTHOR("Scott and Bill Jennings");
413MODULE_DESCRIPTION("Driver for watchdog timer in w83877f chip");
414MODULE_LICENSE("GPL");
415MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
new file mode 100644
index 000000000000..157968442891
--- /dev/null
+++ b/drivers/watchdog/w83977f_wdt.c
@@ -0,0 +1,542 @@
1/*
2 * W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip
3 *
4 * (c) Copyright 2005 Jose Goncalves <jose.goncalves@inov.pt>
5 *
6 * Based on w83877f_wdt.c by Scott Jennings,
7 * and wdt977.c by Woody Suwalski
8 *
9 * -----------------------
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/types.h>
21#include <linux/kernel.h>
22#include <linux/fs.h>
23#include <linux/miscdevice.h>
24#include <linux/init.h>
25#include <linux/ioport.h>
26#include <linux/watchdog.h>
27#include <linux/notifier.h>
28#include <linux/reboot.h>
29
30#include <asm/io.h>
31#include <asm/system.h>
32#include <asm/uaccess.h>
33
34#define WATCHDOG_VERSION "1.00"
35#define WATCHDOG_NAME "W83977F WDT"
36#define PFX WATCHDOG_NAME ": "
37#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
38
39#define IO_INDEX_PORT 0x3F0
40#define IO_DATA_PORT (IO_INDEX_PORT+1)
41
42#define UNLOCK_DATA 0x87
43#define LOCK_DATA 0xAA
44#define DEVICE_REGISTER 0x07
45
46#define DEFAULT_TIMEOUT 45 /* default timeout in seconds */
47
48static int timeout = DEFAULT_TIMEOUT;
49static int timeoutW; /* timeout in watchdog counter units */
50static unsigned long timer_alive;
51static int testmode;
52static char expect_close;
53static spinlock_t spinlock;
54
55module_param(timeout, int, 0);
56MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
57module_param(testmode, int, 0);
58MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
59
60static int nowayout = WATCHDOG_NOWAYOUT;
61module_param(nowayout, int, 0);
62MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
63
64/*
65 * Start the watchdog
66 */
67
68static int wdt_start(void)
69{
70 unsigned long flags;
71
72 spin_lock_irqsave(&spinlock, flags);
73
74 /* Unlock the SuperIO chip */
75 outb_p(UNLOCK_DATA,IO_INDEX_PORT);
76 outb_p(UNLOCK_DATA,IO_INDEX_PORT);
77
78 /*
79 * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
80 * F2 has the timeout in watchdog counter units.
81 * F3 is set to enable watchdog LED blink at timeout.
82 * F4 is used to just clear the TIMEOUT'ed state (bit 0).
83 */
84 outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
85 outb_p(0x08,IO_DATA_PORT);
86 outb_p(0xF2,IO_INDEX_PORT);
87 outb_p(timeoutW,IO_DATA_PORT);
88 outb_p(0xF3,IO_INDEX_PORT);
89 outb_p(0x08,IO_DATA_PORT);
90 outb_p(0xF4,IO_INDEX_PORT);
91 outb_p(0x00,IO_DATA_PORT);
92
93 /* Set device Aux2 active */
94 outb_p(0x30,IO_INDEX_PORT);
95 outb_p(0x01,IO_DATA_PORT);
96
97 /*
98 * Select device Aux1 (dev=7) to set GP16 as the watchdog output
99 * (in reg E6) and GP13 as the watchdog LED output (in reg E3).
100 * Map GP16 at pin 119.
101 * In test mode watch the bit 0 on F4 to indicate "triggered" or
102 * check watchdog LED on SBC.
103 */
104 outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
105 outb_p(0x07,IO_DATA_PORT);
106 if (!testmode)
107 {
108 unsigned pin_map;
109
110 outb_p(0xE6,IO_INDEX_PORT);
111 outb_p(0x0A,IO_DATA_PORT);
112 outb_p(0x2C,IO_INDEX_PORT);
113 pin_map = inb_p(IO_DATA_PORT);
114 pin_map |= 0x10;
115 pin_map &= ~(0x20);
116 outb_p(0x2C,IO_INDEX_PORT);
117 outb_p(pin_map,IO_DATA_PORT);
118 }
119 outb_p(0xE3,IO_INDEX_PORT);
120 outb_p(0x08,IO_DATA_PORT);
121
122 /* Set device Aux1 active */
123 outb_p(0x30,IO_INDEX_PORT);
124 outb_p(0x01,IO_DATA_PORT);
125
126 /* Lock the SuperIO chip */
127 outb_p(LOCK_DATA,IO_INDEX_PORT);
128
129 spin_unlock_irqrestore(&spinlock, flags);
130
131 printk(KERN_INFO PFX "activated.\n");
132
133 return 0;
134}
135
136/*
137 * Stop the watchdog
138 */
139
140static int wdt_stop(void)
141{
142 unsigned long flags;
143
144 spin_lock_irqsave(&spinlock, flags);
145
146 /* Unlock the SuperIO chip */
147 outb_p(UNLOCK_DATA,IO_INDEX_PORT);
148 outb_p(UNLOCK_DATA,IO_INDEX_PORT);
149
150 /*
151 * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
152 * F2 is reset to its default value (watchdog timer disabled).
153 * F3 is reset to its default state.
154 * F4 clears the TIMEOUT'ed state (bit 0) - back to default.
155 */
156 outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
157 outb_p(0x08,IO_DATA_PORT);
158 outb_p(0xF2,IO_INDEX_PORT);
159 outb_p(0xFF,IO_DATA_PORT);
160 outb_p(0xF3,IO_INDEX_PORT);
161 outb_p(0x00,IO_DATA_PORT);
162 outb_p(0xF4,IO_INDEX_PORT);
163 outb_p(0x00,IO_DATA_PORT);
164 outb_p(0xF2,IO_INDEX_PORT);
165 outb_p(0x00,IO_DATA_PORT);
166
167 /*
168 * Select device Aux1 (dev=7) to set GP16 (in reg E6) and
169 * Gp13 (in reg E3) as inputs.
170 */
171 outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
172 outb_p(0x07,IO_DATA_PORT);
173 if (!testmode)
174 {
175 outb_p(0xE6,IO_INDEX_PORT);
176 outb_p(0x01,IO_DATA_PORT);
177 }
178 outb_p(0xE3,IO_INDEX_PORT);
179 outb_p(0x01,IO_DATA_PORT);
180
181 /* Lock the SuperIO chip */
182 outb_p(LOCK_DATA,IO_INDEX_PORT);
183
184 spin_unlock_irqrestore(&spinlock, flags);
185
186 printk(KERN_INFO PFX "shutdown.\n");
187
188 return 0;
189}
190
191/*
192 * Send a keepalive ping to the watchdog
193 * This is done by simply re-writing the timeout to reg. 0xF2
194 */
195
196static int wdt_keepalive(void)
197{
198 unsigned long flags;
199
200 spin_lock_irqsave(&spinlock, flags);
201
202 /* Unlock the SuperIO chip */
203 outb_p(UNLOCK_DATA,IO_INDEX_PORT);
204 outb_p(UNLOCK_DATA,IO_INDEX_PORT);
205
206 /* Select device Aux2 (device=8) to kick watchdog reg F2 */
207 outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
208 outb_p(0x08,IO_DATA_PORT);
209 outb_p(0xF2,IO_INDEX_PORT);
210 outb_p(timeoutW,IO_DATA_PORT);
211
212 /* Lock the SuperIO chip */
213 outb_p(LOCK_DATA,IO_INDEX_PORT);
214
215 spin_unlock_irqrestore(&spinlock, flags);
216
217 return 0;
218}
219
220/*
221 * Set the watchdog timeout value
222 */
223
224static int wdt_set_timeout(int t)
225{
226 int tmrval;
227
228 /*
229 * Convert seconds to watchdog counter time units, rounding up.
230 * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup
231 * value. This information is supplied in the PCM-5335 manual and was
232 * checked by me on a real board. This is a bit strange because W83977f
233 * datasheet says counter unit is in minutes!
234 */
235 if (t < 15)
236 return -EINVAL;
237
238 tmrval = ((t + 15) + 29) / 30;
239
240 if (tmrval > 255)
241 return -EINVAL;
242
243 /*
244 * timeout is the timeout in seconds,
245 * timeoutW is the timeout in watchdog counter units.
246 */
247 timeoutW = tmrval;
248 timeout = (timeoutW * 30) - 15;
249 return 0;
250}
251
252/*
253 * Get the watchdog status
254 */
255
256static int wdt_get_status(int *status)
257{
258 int new_status;
259 unsigned long flags;
260
261 spin_lock_irqsave(&spinlock, flags);
262
263 /* Unlock the SuperIO chip */
264 outb_p(UNLOCK_DATA,IO_INDEX_PORT);
265 outb_p(UNLOCK_DATA,IO_INDEX_PORT);
266
267 /* Select device Aux2 (device=8) to read watchdog reg F4 */
268 outb_p(DEVICE_REGISTER,IO_INDEX_PORT);
269 outb_p(0x08,IO_DATA_PORT);
270 outb_p(0xF4,IO_INDEX_PORT);
271 new_status = inb_p(IO_DATA_PORT);
272
273 /* Lock the SuperIO chip */
274 outb_p(LOCK_DATA,IO_INDEX_PORT);
275
276 spin_unlock_irqrestore(&spinlock, flags);
277
278 *status = 0;
279 if (new_status & 1)
280 *status |= WDIOF_CARDRESET;
281
282 return 0;
283}
284
285
286/*
287 * /dev/watchdog handling
288 */
289
290static int wdt_open(struct inode *inode, struct file *file)
291{
292 /* If the watchdog is alive we don't need to start it again */
293 if( test_and_set_bit(0, &timer_alive) )
294 return -EBUSY;
295
296 if (nowayout)
297 __module_get(THIS_MODULE);
298
299 wdt_start();
300 return nonseekable_open(inode, file);
301}
302
303static int wdt_release(struct inode *inode, struct file *file)
304{
305 /*
306 * Shut off the timer.
307 * Lock it in if it's a module and we set nowayout
308 */
309 if (expect_close == 42)
310 {
311 wdt_stop();
312 clear_bit(0, &timer_alive);
313 } else {
314 wdt_keepalive();
315 printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n");
316 }
317 expect_close = 0;
318 return 0;
319}
320
321/*
322 * wdt_write:
323 * @file: file handle to the watchdog
324 * @buf: buffer to write (unused as data does not matter here
325 * @count: count of bytes
326 * @ppos: pointer to the position to write. No seeks allowed
327 *
328 * A write to a watchdog device is defined as a keepalive signal. Any
329 * write of data will do, as we we don't define content meaning.
330 */
331
332static ssize_t wdt_write(struct file *file, const char __user *buf,
333 size_t count, loff_t *ppos)
334{
335 /* See if we got the magic character 'V' and reload the timer */
336 if(count)
337 {
338 if (!nowayout)
339 {
340 size_t ofs;
341
342 /* note: just in case someone wrote the magic character long ago */
343 expect_close = 0;
344
345 /* scan to see whether or not we got the magic character */
346 for(ofs = 0; ofs != count; ofs++)
347 {
348 char c;
349 if (get_user(c, buf + ofs))
350 return -EFAULT;
351 if (c == 'V') {
352 expect_close = 42;
353 }
354 }
355 }
356
357 /* someone wrote to us, we should restart timer */
358 wdt_keepalive();
359 }
360 return count;
361}
362
363/*
364 * wdt_ioctl:
365 * @inode: inode of the device
366 * @file: file handle to the device
367 * @cmd: watchdog command
368 * @arg: argument pointer
369 *
370 * The watchdog API defines a common set of functions for all watchdogs
371 * according to their available features.
372 */
373
374static struct watchdog_info ident = {
375 .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
376 .firmware_version = 1,
377 .identity = WATCHDOG_NAME,
378};
379
380static int wdt_ioctl(struct inode *inode, struct file *file,
381 unsigned int cmd, unsigned long arg)
382{
383 int status;
384 int new_options, retval = -EINVAL;
385 int new_timeout;
386 union {
387 struct watchdog_info __user *ident;
388 int __user *i;
389 } uarg;
390
391 uarg.i = (int __user *)arg;
392
393 switch(cmd)
394 {
395 default:
396 return -ENOTTY;
397
398 case WDIOC_GETSUPPORT:
399 return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0;
400
401 case WDIOC_GETSTATUS:
402 wdt_get_status(&status);
403 return put_user(status, uarg.i);
404
405 case WDIOC_GETBOOTSTATUS:
406 return put_user(0, uarg.i);
407
408 case WDIOC_KEEPALIVE:
409 wdt_keepalive();
410 return 0;
411
412 case WDIOC_SETOPTIONS:
413 if (get_user (new_options, uarg.i))
414 return -EFAULT;
415
416 if (new_options & WDIOS_DISABLECARD) {
417 wdt_stop();
418 retval = 0;
419 }
420
421 if (new_options & WDIOS_ENABLECARD) {
422 wdt_start();
423 retval = 0;
424 }
425
426 return retval;
427
428 case WDIOC_SETTIMEOUT:
429 if (get_user(new_timeout, uarg.i))
430 return -EFAULT;
431
432 if (wdt_set_timeout(new_timeout))
433 return -EINVAL;
434
435 wdt_keepalive();
436 /* Fall */
437
438 case WDIOC_GETTIMEOUT:
439 return put_user(timeout, uarg.i);
440
441 }
442}
443
444static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
445 void *unused)
446{
447 if (code==SYS_DOWN || code==SYS_HALT)
448 wdt_stop();
449 return NOTIFY_DONE;
450}
451
452static const struct file_operations wdt_fops=
453{
454 .owner = THIS_MODULE,
455 .llseek = no_llseek,
456 .write = wdt_write,
457 .ioctl = wdt_ioctl,
458 .open = wdt_open,
459 .release = wdt_release,
460};
461
462static struct miscdevice wdt_miscdev=
463{
464 .minor = WATCHDOG_MINOR,
465 .name = "watchdog",
466 .fops = &wdt_fops,
467};
468
469static struct notifier_block wdt_notifier = {
470 .notifier_call = wdt_notify_sys,
471};
472
473static int __init w83977f_wdt_init(void)
474{
475 int rc;
476
477 printk(KERN_INFO PFX DRIVER_VERSION);
478
479 spin_lock_init(&spinlock);
480
481 /*
482 * Check that the timeout value is within it's range ;
483 * if not reset to the default
484 */
485 if (wdt_set_timeout(timeout)) {
486 wdt_set_timeout(DEFAULT_TIMEOUT);
487 printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n",
488 DEFAULT_TIMEOUT);
489 }
490
491 if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
492 {
493 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
494 IO_INDEX_PORT);
495 rc = -EIO;
496 goto err_out;
497 }
498
499 rc = misc_register(&wdt_miscdev);
500 if (rc)
501 {
502 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
503 wdt_miscdev.minor, rc);
504 goto err_out_region;
505 }
506
507 rc = register_reboot_notifier(&wdt_notifier);
508 if (rc)
509 {
510 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
511 rc);
512 goto err_out_miscdev;
513 }
514
515 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
516 timeout, nowayout, testmode);
517
518 return 0;
519
520err_out_miscdev:
521 misc_deregister(&wdt_miscdev);
522err_out_region:
523 release_region(IO_INDEX_PORT,2);
524err_out:
525 return rc;
526}
527
528static void __exit w83977f_wdt_exit(void)
529{
530 wdt_stop();
531 misc_deregister(&wdt_miscdev);
532 unregister_reboot_notifier(&wdt_notifier);
533 release_region(IO_INDEX_PORT,2);
534}
535
536module_init(w83977f_wdt_init);
537module_exit(w83977f_wdt_exit);
538
539MODULE_AUTHOR("Jose Goncalves <jose.goncalves@inov.pt>");
540MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip");
541MODULE_LICENSE("GPL");
542MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/wafer5823wdt.c b/drivers/watchdog/wafer5823wdt.c
new file mode 100644
index 000000000000..950905d3c39f
--- /dev/null
+++ b/drivers/watchdog/wafer5823wdt.c
@@ -0,0 +1,325 @@
1/*
2 * ICP Wafer 5823 Single Board Computer WDT driver
3 * http://www.icpamerica.com/wafer_5823.php
4 * May also work on other similar models
5 *
6 * (c) Copyright 2002 Justin Cormack <justin@street-vision.com>
7 *
8 * Release 0.02
9 *
10 * Based on advantechwdt.c which is based on wdt.c.
11 * Original copyright messages:
12 *
13 * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
14 * http://www.redhat.com
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version
19 * 2 of the License, or (at your option) any later version.
20 *
21 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
22 * warranty for any of this software. This material is provided
23 * "AS-IS" and at no charge.
24 *
25 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
26 *
27 */
28
29#include <linux/module.h>
30#include <linux/moduleparam.h>
31#include <linux/miscdevice.h>
32#include <linux/watchdog.h>
33#include <linux/fs.h>
34#include <linux/ioport.h>
35#include <linux/notifier.h>
36#include <linux/reboot.h>
37#include <linux/init.h>
38#include <linux/spinlock.h>
39#include <asm/io.h>
40#include <asm/uaccess.h>
41
42#define WATCHDOG_NAME "Wafer 5823 WDT"
43#define PFX WATCHDOG_NAME ": "
44#define WD_TIMO 60 /* 60 sec default timeout */
45
46static unsigned long wafwdt_is_open;
47static char expect_close;
48static spinlock_t wafwdt_lock;
49
50/*
51 * You must set these - there is no sane way to probe for this board.
52 *
53 * To enable, write the timeout value in seconds (1 to 255) to I/O
54 * port WDT_START, then read the port to start the watchdog. To pat
55 * the dog, read port WDT_STOP to stop the timer, then read WDT_START
56 * to restart it again.
57 */
58
59static int wdt_stop = 0x843;
60static int wdt_start = 0x443;
61
62static int timeout = WD_TIMO; /* in seconds */
63module_param(timeout, int, 0);
64MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. 1<= timeout <=255, default=" __MODULE_STRING(WD_TIMO) ".");
65
66static int nowayout = WATCHDOG_NOWAYOUT;
67module_param(nowayout, int, 0);
68MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
69
70static void wafwdt_ping(void)
71{
72 /* pat watchdog */
73 spin_lock(&wafwdt_lock);
74 inb_p(wdt_stop);
75 inb_p(wdt_start);
76 spin_unlock(&wafwdt_lock);
77}
78
79static void wafwdt_start(void)
80{
81 /* start up watchdog */
82 outb_p(timeout, wdt_start);
83 inb_p(wdt_start);
84}
85
86static void
87wafwdt_stop(void)
88{
89 /* stop watchdog */
90 inb_p(wdt_stop);
91}
92
93static ssize_t wafwdt_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
94{
95 /* See if we got the magic character 'V' and reload the timer */
96 if (count) {
97 if (!nowayout) {
98 size_t i;
99
100 /* In case it was set long ago */
101 expect_close = 0;
102
103 /* scan to see whether or not we got the magic character */
104 for (i = 0; i != count; i++) {
105 char c;
106 if (get_user(c, buf + i))
107 return -EFAULT;
108 if (c == 'V')
109 expect_close = 42;
110 }
111 }
112 /* Well, anyhow someone wrote to us, we should return that favour */
113 wafwdt_ping();
114 }
115 return count;
116}
117
118static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
119 unsigned long arg)
120{
121 int new_timeout;
122 void __user *argp = (void __user *)arg;
123 int __user *p = argp;
124 static struct watchdog_info ident = {
125 .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
126 .firmware_version = 1,
127 .identity = "Wafer 5823 WDT",
128 };
129
130 switch (cmd) {
131 case WDIOC_GETSUPPORT:
132 if (copy_to_user(argp, &ident, sizeof (ident)))
133 return -EFAULT;
134 break;
135
136 case WDIOC_GETSTATUS:
137 case WDIOC_GETBOOTSTATUS:
138 return put_user(0, p);
139
140 case WDIOC_KEEPALIVE:
141 wafwdt_ping();
142 break;
143
144 case WDIOC_SETTIMEOUT:
145 if (get_user(new_timeout, p))
146 return -EFAULT;
147 if ((new_timeout < 1) || (new_timeout > 255))
148 return -EINVAL;
149 timeout = new_timeout;
150 wafwdt_stop();
151 wafwdt_start();
152 /* Fall */
153 case WDIOC_GETTIMEOUT:
154 return put_user(timeout, p);
155
156 case WDIOC_SETOPTIONS:
157 {
158 int options, retval = -EINVAL;
159
160 if (get_user(options, p))
161 return -EFAULT;
162
163 if (options & WDIOS_DISABLECARD) {
164 wafwdt_start();
165 retval = 0;
166 }
167
168 if (options & WDIOS_ENABLECARD) {
169 wafwdt_stop();
170 retval = 0;
171 }
172
173 return retval;
174 }
175
176 default:
177 return -ENOTTY;
178 }
179 return 0;
180}
181
182static int wafwdt_open(struct inode *inode, struct file *file)
183{
184 if (test_and_set_bit(0, &wafwdt_is_open))
185 return -EBUSY;
186
187 /*
188 * Activate
189 */
190 wafwdt_start();
191 return nonseekable_open(inode, file);
192}
193
194static int
195wafwdt_close(struct inode *inode, struct file *file)
196{
197 if (expect_close == 42) {
198 wafwdt_stop();
199 } else {
200 printk(KERN_CRIT PFX "WDT device closed unexpectedly. WDT will not stop!\n");
201 wafwdt_ping();
202 }
203 clear_bit(0, &wafwdt_is_open);
204 expect_close = 0;
205 return 0;
206}
207
208/*
209 * Notifier for system down
210 */
211
212static int wafwdt_notify_sys(struct notifier_block *this, unsigned long code, void *unused)
213{
214 if (code == SYS_DOWN || code == SYS_HALT) {
215 /* Turn the WDT off */
216 wafwdt_stop();
217 }
218 return NOTIFY_DONE;
219}
220
221/*
222 * Kernel Interfaces
223 */
224
225static const struct file_operations wafwdt_fops = {
226 .owner = THIS_MODULE,
227 .llseek = no_llseek,
228 .write = wafwdt_write,
229 .ioctl = wafwdt_ioctl,
230 .open = wafwdt_open,
231 .release = wafwdt_close,
232};
233
234static struct miscdevice wafwdt_miscdev = {
235 .minor = WATCHDOG_MINOR,
236 .name = "watchdog",
237 .fops = &wafwdt_fops,
238};
239
240/*
241 * The WDT needs to learn about soft shutdowns in order to
242 * turn the timebomb registers off.
243 */
244
245static struct notifier_block wafwdt_notifier = {
246 .notifier_call = wafwdt_notify_sys,
247};
248
249static int __init wafwdt_init(void)
250{
251 int ret;
252
253 printk(KERN_INFO "WDT driver for Wafer 5823 single board computer initialising.\n");
254
255 spin_lock_init(&wafwdt_lock);
256
257 if (timeout < 1 || timeout > 255) {
258 timeout = WD_TIMO;
259 printk (KERN_INFO PFX "timeout value must be 1<=x<=255, using %d\n",
260 timeout);
261 }
262
263 if (wdt_stop != wdt_start) {
264 if(!request_region(wdt_stop, 1, "Wafer 5823 WDT")) {
265 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
266 wdt_stop);
267 ret = -EIO;
268 goto error;
269 }
270 }
271
272 if(!request_region(wdt_start, 1, "Wafer 5823 WDT")) {
273 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n",
274 wdt_start);
275 ret = -EIO;
276 goto error2;
277 }
278
279 ret = register_reboot_notifier(&wafwdt_notifier);
280 if (ret != 0) {
281 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
282 ret);
283 goto error3;
284 }
285
286 ret = misc_register(&wafwdt_miscdev);
287 if (ret != 0) {
288 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
289 WATCHDOG_MINOR, ret);
290 goto error4;
291 }
292
293 printk (KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d)\n",
294 timeout, nowayout);
295
296 return ret;
297error4:
298 unregister_reboot_notifier(&wafwdt_notifier);
299error3:
300 release_region(wdt_start, 1);
301error2:
302 if (wdt_stop != wdt_start)
303 release_region(wdt_stop, 1);
304error:
305 return ret;
306}
307
308static void __exit wafwdt_exit(void)
309{
310 misc_deregister(&wafwdt_miscdev);
311 unregister_reboot_notifier(&wafwdt_notifier);
312 if(wdt_stop != wdt_start)
313 release_region(wdt_stop, 1);
314 release_region(wdt_start, 1);
315}
316
317module_init(wafwdt_init);
318module_exit(wafwdt_exit);
319
320MODULE_AUTHOR("Justin Cormack");
321MODULE_DESCRIPTION("ICP Wafer 5823 Single Board Computer WDT driver");
322MODULE_LICENSE("GPL");
323MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
324
325/* end of wafer5823wdt.c */
diff --git a/drivers/watchdog/wd501p.h b/drivers/watchdog/wd501p.h
new file mode 100644
index 000000000000..a4504f40394d
--- /dev/null
+++ b/drivers/watchdog/wd501p.h
@@ -0,0 +1,51 @@
1/*
2 * Industrial Computer Source WDT500/501 driver
3 *
4 * (c) Copyright 1995 CymruNET Ltd
5 * Innovation Centre
6 * Singleton Park
7 * Swansea
8 * Wales
9 * UK
10 * SA2 8PP
11 *
12 * http://www.cymru.net
13 *
14 * This driver is provided under the GNU General Public License, incorporated
15 * herein by reference. The driver is provided without warranty or
16 * support.
17 *
18 * Release 0.04.
19 *
20 */
21
22
23#define WDT_COUNT0 (io+0)
24#define WDT_COUNT1 (io+1)
25#define WDT_COUNT2 (io+2)
26#define WDT_CR (io+3)
27#define WDT_SR (io+4) /* Start buzzer on PCI write */
28#define WDT_RT (io+5) /* Stop buzzer on PCI write */
29#define WDT_BUZZER (io+6) /* PCI only: rd=disable, wr=enable */
30#define WDT_DC (io+7)
31
32/* The following are only on the PCI card, they're outside of I/O space on
33 * the ISA card: */
34#define WDT_CLOCK (io+12) /* COUNT2: rd=16.67MHz, wr=2.0833MHz */
35/* inverted opto isolated reset output: */
36#define WDT_OPTONOTRST (io+13) /* wr=enable, rd=disable */
37/* opto isolated reset output: */
38#define WDT_OPTORST (io+14) /* wr=enable, rd=disable */
39/* programmable outputs: */
40#define WDT_PROGOUT (io+15) /* wr=enable, rd=disable */
41
42 /* FAN 501 500 */
43#define WDC_SR_WCCR 1 /* Active low */ /* X X X */
44#define WDC_SR_TGOOD 2 /* X X - */
45#define WDC_SR_ISOI0 4 /* X X X */
46#define WDC_SR_ISII1 8 /* X X X */
47#define WDC_SR_FANGOOD 16 /* X - - */
48#define WDC_SR_PSUOVER 32 /* Active low */ /* X X - */
49#define WDC_SR_PSUUNDR 64 /* Active low */ /* X X - */
50#define WDC_SR_IRQ 128 /* Active low */ /* X X X */
51
diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c
new file mode 100644
index 000000000000..1d64e277567d
--- /dev/null
+++ b/drivers/watchdog/wdrtas.c
@@ -0,0 +1,695 @@
1/*
2 * FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as
3 * RTAS calls are available
4 */
5
6/*
7 * RTAS watchdog driver
8 *
9 * (C) Copyright IBM Corp. 2005
10 * device driver to exploit watchdog RTAS functions
11 *
12 * Authors : Utz Bacher <utz.bacher@de.ibm.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 */
28
29#include <linux/fs.h>
30#include <linux/init.h>
31#include <linux/kernel.h>
32#include <linux/miscdevice.h>
33#include <linux/module.h>
34#include <linux/notifier.h>
35#include <linux/reboot.h>
36#include <linux/types.h>
37#include <linux/watchdog.h>
38
39#include <asm/rtas.h>
40#include <asm/uaccess.h>
41
42#define WDRTAS_MAGIC_CHAR 42
43#define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \
44 WDIOF_MAGICCLOSE)
45
46MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
47MODULE_DESCRIPTION("RTAS watchdog driver");
48MODULE_LICENSE("GPL");
49MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
50MODULE_ALIAS_MISCDEV(TEMP_MINOR);
51
52#ifdef CONFIG_WATCHDOG_NOWAYOUT
53static int wdrtas_nowayout = 1;
54#else
55static int wdrtas_nowayout = 0;
56#endif
57
58static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
59static char wdrtas_expect_close = 0;
60
61static int wdrtas_interval;
62
63#define WDRTAS_THERMAL_SENSOR 3
64static int wdrtas_token_get_sensor_state;
65#define WDRTAS_SURVEILLANCE_IND 9000
66static int wdrtas_token_set_indicator;
67#define WDRTAS_SP_SPI 28
68static int wdrtas_token_get_sp;
69static int wdrtas_token_event_scan;
70
71#define WDRTAS_DEFAULT_INTERVAL 300
72
73#define WDRTAS_LOGBUFFER_LEN 128
74static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN];
75
76
77/*** watchdog access functions */
78
79/**
80 * wdrtas_set_interval - sets the watchdog interval
81 * @interval: new interval
82 *
83 * returns 0 on success, <0 on failures
84 *
85 * wdrtas_set_interval sets the watchdog keepalive interval by calling the
86 * RTAS function set-indicator (surveillance). The unit of interval is
87 * seconds.
88 */
89static int
90wdrtas_set_interval(int interval)
91{
92 long result;
93 static int print_msg = 10;
94
95 /* rtas uses minutes */
96 interval = (interval + 59) / 60;
97
98 result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
99 WDRTAS_SURVEILLANCE_IND, 0, interval);
100 if ( (result < 0) && (print_msg) ) {
101 printk(KERN_ERR "wdrtas: setting the watchdog to %i "
102 "timeout failed: %li\n", interval, result);
103 print_msg--;
104 }
105
106 return result;
107}
108
109/**
110 * wdrtas_get_interval - returns the current watchdog interval
111 * @fallback_value: value (in seconds) to use, if the RTAS call fails
112 *
113 * returns the interval
114 *
115 * wdrtas_get_interval returns the current watchdog keepalive interval
116 * as reported by the RTAS function ibm,get-system-parameter. The unit
117 * of the return value is seconds.
118 */
119static int
120wdrtas_get_interval(int fallback_value)
121{
122 long result;
123 char value[4];
124
125 result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL,
126 WDRTAS_SP_SPI, (void *)__pa(&value), 4);
127 if ( (value[0] != 0) || (value[1] != 2) || (value[3] != 0) ||
128 (result < 0) ) {
129 printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog "
130 "timeout (%li). Continuing\n", result);
131 return fallback_value;
132 }
133
134 /* rtas uses minutes */
135 return ((int)value[2]) * 60;
136}
137
138/**
139 * wdrtas_timer_start - starts watchdog
140 *
141 * wdrtas_timer_start starts the watchdog by calling the RTAS function
142 * set-interval (surveillance)
143 */
144static void
145wdrtas_timer_start(void)
146{
147 wdrtas_set_interval(wdrtas_interval);
148}
149
150/**
151 * wdrtas_timer_stop - stops watchdog
152 *
153 * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function
154 * set-interval (surveillance)
155 */
156static void
157wdrtas_timer_stop(void)
158{
159 wdrtas_set_interval(0);
160}
161
162/**
163 * wdrtas_log_scanned_event - logs an event we received during keepalive
164 *
165 * wdrtas_log_scanned_event prints a message to the log buffer dumping
166 * the results of the last event-scan call
167 */
168static void
169wdrtas_log_scanned_event(void)
170{
171 int i;
172
173 for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16)
174 printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = "
175 "%02x %02x %02x %02x %02x %02x %02x %02x "
176 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
177 (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
178 wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
179 wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
180 wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
181 wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
182 wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
183 wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
184 wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
185 wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
186}
187
188/**
189 * wdrtas_timer_keepalive - resets watchdog timer to keep system alive
190 *
191 * wdrtas_timer_keepalive restarts the watchdog timer by calling the
192 * RTAS function event-scan and repeats these calls as long as there are
193 * events available. All events will be dumped.
194 */
195static void
196wdrtas_timer_keepalive(void)
197{
198 long result;
199
200 do {
201 result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL,
202 RTAS_EVENT_SCAN_ALL_EVENTS, 0,
203 (void *)__pa(wdrtas_logbuffer),
204 WDRTAS_LOGBUFFER_LEN);
205 if (result < 0)
206 printk(KERN_ERR "wdrtas: event-scan failed: %li\n",
207 result);
208 if (result == 0)
209 wdrtas_log_scanned_event();
210 } while (result == 0);
211}
212
213/**
214 * wdrtas_get_temperature - returns current temperature
215 *
216 * returns temperature or <0 on failures
217 *
218 * wdrtas_get_temperature returns the current temperature in Fahrenheit. It
219 * uses the RTAS call get-sensor-state, token 3 to do so
220 */
221static int
222wdrtas_get_temperature(void)
223{
224 long result;
225 int temperature = 0;
226
227 result = rtas_call(wdrtas_token_get_sensor_state, 2, 2,
228 (void *)__pa(&temperature),
229 WDRTAS_THERMAL_SENSOR, 0);
230
231 if (result < 0)
232 printk(KERN_WARNING "wdrtas: reading the thermal sensor "
233 "faild: %li\n", result);
234 else
235 temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
236
237 return temperature;
238}
239
240/**
241 * wdrtas_get_status - returns the status of the watchdog
242 *
243 * returns a bitmask of defines WDIOF_... as defined in
244 * include/linux/watchdog.h
245 */
246static int
247wdrtas_get_status(void)
248{
249 return 0; /* TODO */
250}
251
252/**
253 * wdrtas_get_boot_status - returns the reason for the last boot
254 *
255 * returns a bitmask of defines WDIOF_... as defined in
256 * include/linux/watchdog.h, indicating why the watchdog rebooted the system
257 */
258static int
259wdrtas_get_boot_status(void)
260{
261 return 0; /* TODO */
262}
263
264/*** watchdog API and operations stuff */
265
266/* wdrtas_write - called when watchdog device is written to
267 * @file: file structure
268 * @buf: user buffer with data
269 * @len: amount to data written
270 * @ppos: position in file
271 *
272 * returns the number of successfully processed characters, which is always
273 * the number of bytes passed to this function
274 *
275 * wdrtas_write processes all the data given to it and looks for the magic
276 * character 'V'. This character allows the watchdog device to be closed
277 * properly.
278 */
279static ssize_t
280wdrtas_write(struct file *file, const char __user *buf,
281 size_t len, loff_t *ppos)
282{
283 int i;
284 char c;
285
286 if (!len)
287 goto out;
288
289 if (!wdrtas_nowayout) {
290 wdrtas_expect_close = 0;
291 /* look for 'V' */
292 for (i = 0; i < len; i++) {
293 if (get_user(c, buf + i))
294 return -EFAULT;
295 /* allow to close device */
296 if (c == 'V')
297 wdrtas_expect_close = WDRTAS_MAGIC_CHAR;
298 }
299 }
300
301 wdrtas_timer_keepalive();
302
303out:
304 return len;
305}
306
307/**
308 * wdrtas_ioctl - ioctl function for the watchdog device
309 * @inode: inode structure
310 * @file: file structure
311 * @cmd: command for ioctl
312 * @arg: argument pointer
313 *
314 * returns 0 on success, <0 on failure
315 *
316 * wdrtas_ioctl implements the watchdog API ioctls
317 */
318static int
319wdrtas_ioctl(struct inode *inode, struct file *file,
320 unsigned int cmd, unsigned long arg)
321{
322 int __user *argp = (void __user *)arg;
323 int i;
324 static struct watchdog_info wdinfo = {
325 .options = WDRTAS_SUPPORTED_MASK,
326 .firmware_version = 0,
327 .identity = "wdrtas"
328 };
329
330 switch (cmd) {
331 case WDIOC_GETSUPPORT:
332 if (copy_to_user(argp, &wdinfo, sizeof(wdinfo)))
333 return -EFAULT;
334 return 0;
335
336 case WDIOC_GETSTATUS:
337 i = wdrtas_get_status();
338 return put_user(i, argp);
339
340 case WDIOC_GETBOOTSTATUS:
341 i = wdrtas_get_boot_status();
342 return put_user(i, argp);
343
344 case WDIOC_GETTEMP:
345 if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE)
346 return -EOPNOTSUPP;
347
348 i = wdrtas_get_temperature();
349 return put_user(i, argp);
350
351 case WDIOC_SETOPTIONS:
352 if (get_user(i, argp))
353 return -EFAULT;
354 if (i & WDIOS_DISABLECARD)
355 wdrtas_timer_stop();
356 if (i & WDIOS_ENABLECARD) {
357 wdrtas_timer_keepalive();
358 wdrtas_timer_start();
359 }
360 if (i & WDIOS_TEMPPANIC) {
361 /* not implemented. Done by H8 */
362 }
363 return 0;
364
365 case WDIOC_KEEPALIVE:
366 wdrtas_timer_keepalive();
367 return 0;
368
369 case WDIOC_SETTIMEOUT:
370 if (get_user(i, argp))
371 return -EFAULT;
372
373 if (wdrtas_set_interval(i))
374 return -EINVAL;
375
376 wdrtas_timer_keepalive();
377
378 if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
379 wdrtas_interval = i;
380 else
381 wdrtas_interval = wdrtas_get_interval(i);
382 /* fallthrough */
383
384 case WDIOC_GETTIMEOUT:
385 return put_user(wdrtas_interval, argp);
386
387 default:
388 return -ENOTTY;
389 }
390}
391
392/**
393 * wdrtas_open - open function of watchdog device
394 * @inode: inode structure
395 * @file: file structure
396 *
397 * returns 0 on success, -EBUSY if the file has been opened already, <0 on
398 * other failures
399 *
400 * function called when watchdog device is opened
401 */
402static int
403wdrtas_open(struct inode *inode, struct file *file)
404{
405 /* only open once */
406 if (atomic_inc_return(&wdrtas_miscdev_open) > 1) {
407 atomic_dec(&wdrtas_miscdev_open);
408 return -EBUSY;
409 }
410
411 wdrtas_timer_start();
412 wdrtas_timer_keepalive();
413
414 return nonseekable_open(inode, file);
415}
416
417/**
418 * wdrtas_close - close function of watchdog device
419 * @inode: inode structure
420 * @file: file structure
421 *
422 * returns 0 on success
423 *
424 * close function. Always succeeds
425 */
426static int
427wdrtas_close(struct inode *inode, struct file *file)
428{
429 /* only stop watchdog, if this was announced using 'V' before */
430 if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
431 wdrtas_timer_stop();
432 else {
433 printk(KERN_WARNING "wdrtas: got unexpected close. Watchdog "
434 "not stopped.\n");
435 wdrtas_timer_keepalive();
436 }
437
438 wdrtas_expect_close = 0;
439 atomic_dec(&wdrtas_miscdev_open);
440 return 0;
441}
442
443/**
444 * wdrtas_temp_read - gives back the temperature in fahrenheit
445 * @file: file structure
446 * @buf: user buffer
447 * @count: number of bytes to be read
448 * @ppos: position in file
449 *
450 * returns always 1 or -EFAULT in case of user space copy failures, <0 on
451 * other failures
452 *
453 * wdrtas_temp_read gives the temperature to the users by copying this
454 * value as one byte into the user space buffer. The unit is Fahrenheit...
455 */
456static ssize_t
457wdrtas_temp_read(struct file *file, char __user *buf,
458 size_t count, loff_t *ppos)
459{
460 int temperature = 0;
461
462 temperature = wdrtas_get_temperature();
463 if (temperature < 0)
464 return temperature;
465
466 if (copy_to_user(buf, &temperature, 1))
467 return -EFAULT;
468
469 return 1;
470}
471
472/**
473 * wdrtas_temp_open - open function of temperature device
474 * @inode: inode structure
475 * @file: file structure
476 *
477 * returns 0 on success, <0 on failure
478 *
479 * function called when temperature device is opened
480 */
481static int
482wdrtas_temp_open(struct inode *inode, struct file *file)
483{
484 return nonseekable_open(inode, file);
485}
486
487/**
488 * wdrtas_temp_close - close function of temperature device
489 * @inode: inode structure
490 * @file: file structure
491 *
492 * returns 0 on success
493 *
494 * close function. Always succeeds
495 */
496static int
497wdrtas_temp_close(struct inode *inode, struct file *file)
498{
499 return 0;
500}
501
502/**
503 * wdrtas_reboot - reboot notifier function
504 * @nb: notifier block structure
505 * @code: reboot code
506 * @ptr: unused
507 *
508 * returns NOTIFY_DONE
509 *
510 * wdrtas_reboot stops the watchdog in case of a reboot
511 */
512static int
513wdrtas_reboot(struct notifier_block *this, unsigned long code, void *ptr)
514{
515 if ( (code==SYS_DOWN) || (code==SYS_HALT) )
516 wdrtas_timer_stop();
517
518 return NOTIFY_DONE;
519}
520
521/*** initialization stuff */
522
523static const struct file_operations wdrtas_fops = {
524 .owner = THIS_MODULE,
525 .llseek = no_llseek,
526 .write = wdrtas_write,
527 .ioctl = wdrtas_ioctl,
528 .open = wdrtas_open,
529 .release = wdrtas_close,
530};
531
532static struct miscdevice wdrtas_miscdev = {
533 .minor = WATCHDOG_MINOR,
534 .name = "watchdog",
535 .fops = &wdrtas_fops,
536};
537
538static const struct file_operations wdrtas_temp_fops = {
539 .owner = THIS_MODULE,
540 .llseek = no_llseek,
541 .read = wdrtas_temp_read,
542 .open = wdrtas_temp_open,
543 .release = wdrtas_temp_close,
544};
545
546static struct miscdevice wdrtas_tempdev = {
547 .minor = TEMP_MINOR,
548 .name = "temperature",
549 .fops = &wdrtas_temp_fops,
550};
551
552static struct notifier_block wdrtas_notifier = {
553 .notifier_call = wdrtas_reboot,
554};
555
556/**
557 * wdrtas_get_tokens - reads in RTAS tokens
558 *
559 * returns 0 on succes, <0 on failure
560 *
561 * wdrtas_get_tokens reads in the tokens for the RTAS calls used in
562 * this watchdog driver. It tolerates, if "get-sensor-state" and
563 * "ibm,get-system-parameter" are not available.
564 */
565static int
566wdrtas_get_tokens(void)
567{
568 wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
569 if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
570 printk(KERN_WARNING "wdrtas: couldn't get token for "
571 "get-sensor-state. Trying to continue without "
572 "temperature support.\n");
573 }
574
575 wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
576 if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
577 printk(KERN_WARNING "wdrtas: couldn't get token for "
578 "ibm,get-system-parameter. Trying to continue with "
579 "a default timeout value of %i seconds.\n",
580 WDRTAS_DEFAULT_INTERVAL);
581 }
582
583 wdrtas_token_set_indicator = rtas_token("set-indicator");
584 if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
585 printk(KERN_ERR "wdrtas: couldn't get token for "
586 "set-indicator. Terminating watchdog code.\n");
587 return -EIO;
588 }
589
590 wdrtas_token_event_scan = rtas_token("event-scan");
591 if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
592 printk(KERN_ERR "wdrtas: couldn't get token for event-scan. "
593 "Terminating watchdog code.\n");
594 return -EIO;
595 }
596
597 return 0;
598}
599
600/**
601 * wdrtas_unregister_devs - unregisters the misc dev handlers
602 *
603 * wdrtas_register_devs unregisters the watchdog and temperature watchdog
604 * misc devs
605 */
606static void
607wdrtas_unregister_devs(void)
608{
609 misc_deregister(&wdrtas_miscdev);
610 if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE)
611 misc_deregister(&wdrtas_tempdev);
612}
613
614/**
615 * wdrtas_register_devs - registers the misc dev handlers
616 *
617 * returns 0 on succes, <0 on failure
618 *
619 * wdrtas_register_devs registers the watchdog and temperature watchdog
620 * misc devs
621 */
622static int
623wdrtas_register_devs(void)
624{
625 int result;
626
627 result = misc_register(&wdrtas_miscdev);
628 if (result) {
629 printk(KERN_ERR "wdrtas: couldn't register watchdog misc "
630 "device. Terminating watchdog code.\n");
631 return result;
632 }
633
634 if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
635 result = misc_register(&wdrtas_tempdev);
636 if (result) {
637 printk(KERN_WARNING "wdrtas: couldn't register "
638 "watchdog temperature misc device. Continuing "
639 "without temperature support.\n");
640 wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
641 }
642 }
643
644 return 0;
645}
646
647/**
648 * wdrtas_init - init function of the watchdog driver
649 *
650 * returns 0 on succes, <0 on failure
651 *
652 * registers the file handlers and the reboot notifier
653 */
654static int __init
655wdrtas_init(void)
656{
657 if (wdrtas_get_tokens())
658 return -ENODEV;
659
660 if (wdrtas_register_devs())
661 return -ENODEV;
662
663 if (register_reboot_notifier(&wdrtas_notifier)) {
664 printk(KERN_ERR "wdrtas: could not register reboot notifier. "
665 "Terminating watchdog code.\n");
666 wdrtas_unregister_devs();
667 return -ENODEV;
668 }
669
670 if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
671 wdrtas_interval = WDRTAS_DEFAULT_INTERVAL;
672 else
673 wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL);
674
675 return 0;
676}
677
678/**
679 * wdrtas_exit - exit function of the watchdog driver
680 *
681 * unregisters the file handlers and the reboot notifier
682 */
683static void __exit
684wdrtas_exit(void)
685{
686 if (!wdrtas_nowayout)
687 wdrtas_timer_stop();
688
689 wdrtas_unregister_devs();
690
691 unregister_reboot_notifier(&wdrtas_notifier);
692}
693
694module_init(wdrtas_init);
695module_exit(wdrtas_exit);
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c
new file mode 100644
index 000000000000..0a3de6a02442
--- /dev/null
+++ b/drivers/watchdog/wdt.c
@@ -0,0 +1,640 @@
1/*
2 * Industrial Computer Source WDT500/501 driver
3 *
4 * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
5 * http://www.redhat.com
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 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
17 *
18 * Release 0.10.
19 *
20 * Fixes
21 * Dave Gregorich : Modularisation and minor bugs
22 * Alan Cox : Added the watchdog ioctl() stuff
23 * Alan Cox : Fixed the reboot problem (as noted by
24 * Matt Crocker).
25 * Alan Cox : Added wdt= boot option
26 * Alan Cox : Cleaned up copy/user stuff
27 * Tim Hockin : Added insmod parameters, comment cleanup
28 * Parameterized timeout
29 * Tigran Aivazian : Restructured wdt_init() to handle failures
30 * Joel Becker : Added WDIOC_GET/SETTIMEOUT
31 * Matt Domsch : Added nowayout module option
32 */
33
34#include <linux/interrupt.h>
35#include <linux/module.h>
36#include <linux/moduleparam.h>
37#include <linux/types.h>
38#include <linux/miscdevice.h>
39#include <linux/watchdog.h>
40#include <linux/fs.h>
41#include <linux/ioport.h>
42#include <linux/notifier.h>
43#include <linux/reboot.h>
44#include <linux/init.h>
45
46#include <asm/io.h>
47#include <asm/uaccess.h>
48#include <asm/system.h>
49#include "wd501p.h"
50
51static unsigned long wdt_is_open;
52static char expect_close;
53
54/*
55 * Module parameters
56 */
57
58#define WD_TIMO 60 /* Default heartbeat = 60 seconds */
59
60static int heartbeat = WD_TIMO;
61static int wd_heartbeat;
62module_param(heartbeat, int, 0);
63MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")");
64
65static int nowayout = WATCHDOG_NOWAYOUT;
66module_param(nowayout, int, 0);
67MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
68
69/* You must set these - there is no sane way to probe for this board. */
70static int io=0x240;
71static int irq=11;
72
73module_param(io, int, 0);
74MODULE_PARM_DESC(io, "WDT io port (default=0x240)");
75module_param(irq, int, 0);
76MODULE_PARM_DESC(irq, "WDT irq (default=11)");
77
78#ifdef CONFIG_WDT_501
79/* Support for the Fan Tachometer on the WDT501-P */
80static int tachometer;
81
82module_param(tachometer, int, 0);
83MODULE_PARM_DESC(tachometer, "WDT501-P Fan Tachometer support (0=disable, default=0)");
84#endif /* CONFIG_WDT_501 */
85
86/*
87 * Programming support
88 */
89
90static void wdt_ctr_mode(int ctr, int mode)
91{
92 ctr<<=6;
93 ctr|=0x30;
94 ctr|=(mode<<1);
95 outb_p(ctr, WDT_CR);
96}
97
98static void wdt_ctr_load(int ctr, int val)
99{
100 outb_p(val&0xFF, WDT_COUNT0+ctr);
101 outb_p(val>>8, WDT_COUNT0+ctr);
102}
103
104/**
105 * wdt_start:
106 *
107 * Start the watchdog driver.
108 */
109
110static int wdt_start(void)
111{
112 inb_p(WDT_DC); /* Disable watchdog */
113 wdt_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */
114 wdt_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */
115 wdt_ctr_mode(2,0); /* Program CTR2 for Mode 0: Pulse on Terminal Count */
116 wdt_ctr_load(0, 8948); /* Count at 100Hz */
117 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
118 wdt_ctr_load(2,65535); /* Length of reset pulse */
119 outb_p(0, WDT_DC); /* Enable watchdog */
120 return 0;
121}
122
123/**
124 * wdt_stop:
125 *
126 * Stop the watchdog driver.
127 */
128
129static int wdt_stop (void)
130{
131 /* Turn the card off */
132 inb_p(WDT_DC); /* Disable watchdog */
133 wdt_ctr_load(2,0); /* 0 length reset pulses now */
134 return 0;
135}
136
137/**
138 * wdt_ping:
139 *
140 * Reload counter one with the watchdog heartbeat. We don't bother reloading
141 * the cascade counter.
142 */
143
144static int wdt_ping(void)
145{
146 /* Write a watchdog value */
147 inb_p(WDT_DC); /* Disable watchdog */
148 wdt_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */
149 wdt_ctr_load(1,wd_heartbeat); /* Heartbeat */
150 outb_p(0, WDT_DC); /* Enable watchdog */
151 return 0;
152}
153
154/**
155 * wdt_set_heartbeat:
156 * @t: the new heartbeat value that needs to be set.
157 *
158 * Set a new heartbeat value for the watchdog device. If the heartbeat value is
159 * incorrect we keep the old value and return -EINVAL. If successfull we
160 * return 0.
161 */
162static int wdt_set_heartbeat(int t)
163{
164 if ((t < 1) || (t > 65535))
165 return -EINVAL;
166
167 heartbeat = t;
168 wd_heartbeat = t * 100;
169 return 0;
170}
171
172/**
173 * wdt_get_status:
174 * @status: the new status.
175 *
176 * Extract the status information from a WDT watchdog device. There are
177 * several board variants so we have to know which bits are valid. Some
178 * bits default to one and some to zero in order to be maximally painful.
179 *
180 * we then map the bits onto the status ioctl flags.
181 */
182
183static int wdt_get_status(int *status)
184{
185 unsigned char new_status=inb_p(WDT_SR);
186
187 *status=0;
188 if (new_status & WDC_SR_ISOI0)
189 *status |= WDIOF_EXTERN1;
190 if (new_status & WDC_SR_ISII1)
191 *status |= WDIOF_EXTERN2;
192#ifdef CONFIG_WDT_501
193 if (!(new_status & WDC_SR_TGOOD))
194 *status |= WDIOF_OVERHEAT;
195 if (!(new_status & WDC_SR_PSUOVER))
196 *status |= WDIOF_POWEROVER;
197 if (!(new_status & WDC_SR_PSUUNDR))
198 *status |= WDIOF_POWERUNDER;
199 if (tachometer) {
200 if (!(new_status & WDC_SR_FANGOOD))
201 *status |= WDIOF_FANFAULT;
202 }
203#endif /* CONFIG_WDT_501 */
204 return 0;
205}
206
207#ifdef CONFIG_WDT_501
208/**
209 * wdt_get_temperature:
210 *
211 * Reports the temperature in degrees Fahrenheit. The API is in
212 * farenheit. It was designed by an imperial measurement luddite.
213 */
214
215static int wdt_get_temperature(int *temperature)
216{
217 unsigned short c=inb_p(WDT_RT);
218
219 *temperature = (c * 11 / 15) + 7;
220 return 0;
221}
222#endif /* CONFIG_WDT_501 */
223
224/**
225 * wdt_interrupt:
226 * @irq: Interrupt number
227 * @dev_id: Unused as we don't allow multiple devices.
228 *
229 * Handle an interrupt from the board. These are raised when the status
230 * map changes in what the board considers an interesting way. That means
231 * a failure condition occurring.
232 */
233
234static irqreturn_t wdt_interrupt(int irq, void *dev_id)
235{
236 /*
237 * Read the status register see what is up and
238 * then printk it.
239 */
240 unsigned char status=inb_p(WDT_SR);
241
242 printk(KERN_CRIT "WDT status %d\n", status);
243
244#ifdef CONFIG_WDT_501
245 if (!(status & WDC_SR_TGOOD))
246 printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT));
247 if (!(status & WDC_SR_PSUOVER))
248 printk(KERN_CRIT "PSU over voltage.\n");
249 if (!(status & WDC_SR_PSUUNDR))
250 printk(KERN_CRIT "PSU under voltage.\n");
251 if (tachometer) {
252 if (!(status & WDC_SR_FANGOOD))
253 printk(KERN_CRIT "Possible fan fault.\n");
254 }
255#endif /* CONFIG_WDT_501 */
256 if (!(status & WDC_SR_WCCR))
257#ifdef SOFTWARE_REBOOT
258#ifdef ONLY_TESTING
259 printk(KERN_CRIT "Would Reboot.\n");
260#else
261 printk(KERN_CRIT "Initiating system reboot.\n");
262 emergency_restart();
263#endif
264#else
265 printk(KERN_CRIT "Reset in 5ms.\n");
266#endif
267 return IRQ_HANDLED;
268}
269
270
271/**
272 * wdt_write:
273 * @file: file handle to the watchdog
274 * @buf: buffer to write (unused as data does not matter here
275 * @count: count of bytes
276 * @ppos: pointer to the position to write. No seeks allowed
277 *
278 * A write to a watchdog device is defined as a keepalive signal. Any
279 * write of data will do, as we we don't define content meaning.
280 */
281
282static ssize_t wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
283{
284 if(count) {
285 if (!nowayout) {
286 size_t i;
287
288 /* In case it was set long ago */
289 expect_close = 0;
290
291 for (i = 0; i != count; i++) {
292 char c;
293 if (get_user(c, buf + i))
294 return -EFAULT;
295 if (c == 'V')
296 expect_close = 42;
297 }
298 }
299 wdt_ping();
300 }
301 return count;
302}
303
304/**
305 * wdt_ioctl:
306 * @inode: inode of the device
307 * @file: file handle to the device
308 * @cmd: watchdog command
309 * @arg: argument pointer
310 *
311 * The watchdog API defines a common set of functions for all watchdogs
312 * according to their available features. We only actually usefully support
313 * querying capabilities and current status.
314 */
315
316static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
317 unsigned long arg)
318{
319 void __user *argp = (void __user *)arg;
320 int __user *p = argp;
321 int new_heartbeat;
322 int status;
323
324 static struct watchdog_info ident = {
325 .options = WDIOF_SETTIMEOUT|
326 WDIOF_MAGICCLOSE|
327 WDIOF_KEEPALIVEPING,
328 .firmware_version = 1,
329 .identity = "WDT500/501",
330 };
331
332 /* Add options according to the card we have */
333 ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
334#ifdef CONFIG_WDT_501
335 ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER);
336 if (tachometer)
337 ident.options |= WDIOF_FANFAULT;
338#endif /* CONFIG_WDT_501 */
339
340 switch(cmd)
341 {
342 default:
343 return -ENOTTY;
344 case WDIOC_GETSUPPORT:
345 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
346
347 case WDIOC_GETSTATUS:
348 wdt_get_status(&status);
349 return put_user(status, p);
350 case WDIOC_GETBOOTSTATUS:
351 return put_user(0, p);
352 case WDIOC_KEEPALIVE:
353 wdt_ping();
354 return 0;
355 case WDIOC_SETTIMEOUT:
356 if (get_user(new_heartbeat, p))
357 return -EFAULT;
358
359 if (wdt_set_heartbeat(new_heartbeat))
360 return -EINVAL;
361
362 wdt_ping();
363 /* Fall */
364 case WDIOC_GETTIMEOUT:
365 return put_user(heartbeat, p);
366 }
367}
368
369/**
370 * wdt_open:
371 * @inode: inode of device
372 * @file: file handle to device
373 *
374 * The watchdog device has been opened. The watchdog device is single
375 * open and on opening we load the counters. Counter zero is a 100Hz
376 * cascade, into counter 1 which downcounts to reboot. When the counter
377 * triggers counter 2 downcounts the length of the reset pulse which
378 * set set to be as long as possible.
379 */
380
381static int wdt_open(struct inode *inode, struct file *file)
382{
383 if(test_and_set_bit(0, &wdt_is_open))
384 return -EBUSY;
385 /*
386 * Activate
387 */
388 wdt_start();
389 return nonseekable_open(inode, file);
390}
391
392/**
393 * wdt_release:
394 * @inode: inode to board
395 * @file: file handle to board
396 *
397 * The watchdog has a configurable API. There is a religious dispute
398 * between people who want their watchdog to be able to shut down and
399 * those who want to be sure if the watchdog manager dies the machine
400 * reboots. In the former case we disable the counters, in the latter
401 * case you have to open it again very soon.
402 */
403
404static int wdt_release(struct inode *inode, struct file *file)
405{
406 if (expect_close == 42) {
407 wdt_stop();
408 clear_bit(0, &wdt_is_open);
409 } else {
410 printk(KERN_CRIT "wdt: WDT device closed unexpectedly. WDT will not stop!\n");
411 wdt_ping();
412 }
413 expect_close = 0;
414 return 0;
415}
416
417#ifdef CONFIG_WDT_501
418/**
419 * wdt_temp_read:
420 * @file: file handle to the watchdog board
421 * @buf: buffer to write 1 byte into
422 * @count: length of buffer
423 * @ptr: offset (no seek allowed)
424 *
425 * Temp_read reports the temperature in degrees Fahrenheit. The API is in
426 * farenheit. It was designed by an imperial measurement luddite.
427 */
428
429static ssize_t wdt_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)
430{
431 int temperature;
432
433 if (wdt_get_temperature(&temperature))
434 return -EFAULT;
435
436 if (copy_to_user (buf, &temperature, 1))
437 return -EFAULT;
438
439 return 1;
440}
441
442/**
443 * wdt_temp_open:
444 * @inode: inode of device
445 * @file: file handle to device
446 *
447 * The temperature device has been opened.
448 */
449
450static int wdt_temp_open(struct inode *inode, struct file *file)
451{
452 return nonseekable_open(inode, file);
453}
454
455/**
456 * wdt_temp_release:
457 * @inode: inode to board
458 * @file: file handle to board
459 *
460 * The temperature device has been closed.
461 */
462
463static int wdt_temp_release(struct inode *inode, struct file *file)
464{
465 return 0;
466}
467#endif /* CONFIG_WDT_501 */
468
469/**
470 * notify_sys:
471 * @this: our notifier block
472 * @code: the event being reported
473 * @unused: unused
474 *
475 * Our notifier is called on system shutdowns. We want to turn the card
476 * off at reboot otherwise the machine will reboot again during memory
477 * test or worse yet during the following fsck. This would suck, in fact
478 * trust me - if it happens it does suck.
479 */
480
481static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
482 void *unused)
483{
484 if(code==SYS_DOWN || code==SYS_HALT) {
485 /* Turn the card off */
486 wdt_stop();
487 }
488 return NOTIFY_DONE;
489}
490
491/*
492 * Kernel Interfaces
493 */
494
495
496static const struct file_operations wdt_fops = {
497 .owner = THIS_MODULE,
498 .llseek = no_llseek,
499 .write = wdt_write,
500 .ioctl = wdt_ioctl,
501 .open = wdt_open,
502 .release = wdt_release,
503};
504
505static struct miscdevice wdt_miscdev = {
506 .minor = WATCHDOG_MINOR,
507 .name = "watchdog",
508 .fops = &wdt_fops,
509};
510
511#ifdef CONFIG_WDT_501
512static const struct file_operations wdt_temp_fops = {
513 .owner = THIS_MODULE,
514 .llseek = no_llseek,
515 .read = wdt_temp_read,
516 .open = wdt_temp_open,
517 .release = wdt_temp_release,
518};
519
520static struct miscdevice temp_miscdev = {
521 .minor = TEMP_MINOR,
522 .name = "temperature",
523 .fops = &wdt_temp_fops,
524};
525#endif /* CONFIG_WDT_501 */
526
527/*
528 * The WDT card needs to learn about soft shutdowns in order to
529 * turn the timebomb registers off.
530 */
531
532static struct notifier_block wdt_notifier = {
533 .notifier_call = wdt_notify_sys,
534};
535
536/**
537 * cleanup_module:
538 *
539 * Unload the watchdog. You cannot do this with any file handles open.
540 * If your watchdog is set to continue ticking on close and you unload
541 * it, well it keeps ticking. We won't get the interrupt but the board
542 * will not touch PC memory so all is fine. You just have to load a new
543 * module in 60 seconds or reboot.
544 */
545
546static void __exit wdt_exit(void)
547{
548 misc_deregister(&wdt_miscdev);
549#ifdef CONFIG_WDT_501
550 misc_deregister(&temp_miscdev);
551#endif /* CONFIG_WDT_501 */
552 unregister_reboot_notifier(&wdt_notifier);
553 free_irq(irq, NULL);
554 release_region(io,8);
555}
556
557/**
558 * wdt_init:
559 *
560 * Set up the WDT watchdog board. All we have to do is grab the
561 * resources we require and bitch if anyone beat us to them.
562 * The open() function will actually kick the board off.
563 */
564
565static int __init wdt_init(void)
566{
567 int ret;
568
569 /* Check that the heartbeat value is within it's range ; if not reset to the default */
570 if (wdt_set_heartbeat(heartbeat)) {
571 wdt_set_heartbeat(WD_TIMO);
572 printk(KERN_INFO "wdt: heartbeat value must be 0<heartbeat<65536, using %d\n",
573 WD_TIMO);
574 }
575
576 if (!request_region(io, 8, "wdt501p")) {
577 printk(KERN_ERR "wdt: I/O address 0x%04x already in use\n", io);
578 ret = -EBUSY;
579 goto out;
580 }
581
582 ret = request_irq(irq, wdt_interrupt, IRQF_DISABLED, "wdt501p", NULL);
583 if(ret) {
584 printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq);
585 goto outreg;
586 }
587
588 ret = register_reboot_notifier(&wdt_notifier);
589 if(ret) {
590 printk(KERN_ERR "wdt: cannot register reboot notifier (err=%d)\n", ret);
591 goto outirq;
592 }
593
594#ifdef CONFIG_WDT_501
595 ret = misc_register(&temp_miscdev);
596 if (ret) {
597 printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n",
598 TEMP_MINOR, ret);
599 goto outrbt;
600 }
601#endif /* CONFIG_WDT_501 */
602
603 ret = misc_register(&wdt_miscdev);
604 if (ret) {
605 printk(KERN_ERR "wdt: cannot register miscdev on minor=%d (err=%d)\n",
606 WATCHDOG_MINOR, ret);
607 goto outmisc;
608 }
609
610 ret = 0;
611 printk(KERN_INFO "WDT500/501-P driver 0.10 at 0x%04x (Interrupt %d). heartbeat=%d sec (nowayout=%d)\n",
612 io, irq, heartbeat, nowayout);
613#ifdef CONFIG_WDT_501
614 printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled"));
615#endif /* CONFIG_WDT_501 */
616
617out:
618 return ret;
619
620outmisc:
621#ifdef CONFIG_WDT_501
622 misc_deregister(&temp_miscdev);
623outrbt:
624#endif /* CONFIG_WDT_501 */
625 unregister_reboot_notifier(&wdt_notifier);
626outirq:
627 free_irq(irq, NULL);
628outreg:
629 release_region(io,8);
630 goto out;
631}
632
633module_init(wdt_init);
634module_exit(wdt_exit);
635
636MODULE_AUTHOR("Alan Cox");
637MODULE_DESCRIPTION("Driver for ISA ICS watchdog cards (WDT500/501)");
638MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
639MODULE_ALIAS_MISCDEV(TEMP_MINOR);
640MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/wdt285.c b/drivers/watchdog/wdt285.c
new file mode 100644
index 000000000000..e4cf661dc890
--- /dev/null
+++ b/drivers/watchdog/wdt285.c
@@ -0,0 +1,229 @@
1/*
2 * Intel 21285 watchdog driver
3 * Copyright (c) Phil Blundell <pb@nexus.co.uk>, 1998
4 *
5 * based on
6 *
7 * SoftDog 0.05: A Software Watchdog Device
8 *
9 * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/moduleparam.h>
20#include <linux/types.h>
21#include <linux/kernel.h>
22#include <linux/fs.h>
23#include <linux/mm.h>
24#include <linux/miscdevice.h>
25#include <linux/watchdog.h>
26#include <linux/reboot.h>
27#include <linux/init.h>
28#include <linux/interrupt.h>
29
30#include <asm/irq.h>
31#include <asm/uaccess.h>
32#include <asm/hardware.h>
33#include <asm/mach-types.h>
34#include <asm/hardware/dec21285.h>
35
36/*
37 * Define this to stop the watchdog actually rebooting the machine.
38 */
39#undef ONLY_TESTING
40
41static unsigned int soft_margin = 60; /* in seconds */
42static unsigned int reload;
43static unsigned long timer_alive;
44
45#ifdef ONLY_TESTING
46/*
47 * If the timer expires..
48 */
49static void watchdog_fire(int irq, void *dev_id)
50{
51 printk(KERN_CRIT "Watchdog: Would Reboot.\n");
52 *CSR_TIMER4_CNTL = 0;
53 *CSR_TIMER4_CLR = 0;
54}
55#endif
56
57/*
58 * Refresh the timer.
59 */
60static void watchdog_ping(void)
61{
62 *CSR_TIMER4_LOAD = reload;
63}
64
65/*
66 * Allow only one person to hold it open
67 */
68static int watchdog_open(struct inode *inode, struct file *file)
69{
70 int ret;
71
72 if (*CSR_SA110_CNTL & (1 << 13))
73 return -EBUSY;
74
75 if (test_and_set_bit(1, &timer_alive))
76 return -EBUSY;
77
78 reload = soft_margin * (mem_fclk_21285 / 256);
79
80 *CSR_TIMER4_CLR = 0;
81 watchdog_ping();
82 *CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD
83 | TIMER_CNTL_DIV256;
84
85#ifdef ONLY_TESTING
86 ret = request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL);
87 if (ret) {
88 *CSR_TIMER4_CNTL = 0;
89 clear_bit(1, &timer_alive);
90 }
91#else
92 /*
93 * Setting this bit is irreversible; once enabled, there is
94 * no way to disable the watchdog.
95 */
96 *CSR_SA110_CNTL |= 1 << 13;
97
98 ret = 0;
99#endif
100 nonseekable_open(inode, file);
101 return ret;
102}
103
104/*
105 * Shut off the timer.
106 * Note: if we really have enabled the watchdog, there
107 * is no way to turn off.
108 */
109static int watchdog_release(struct inode *inode, struct file *file)
110{
111#ifdef ONLY_TESTING
112 free_irq(IRQ_TIMER4, NULL);
113 clear_bit(1, &timer_alive);
114#endif
115 return 0;
116}
117
118static ssize_t
119watchdog_write(struct file *file, const char *data, size_t len, loff_t *ppos)
120{
121 /*
122 * Refresh the timer.
123 */
124 if (len)
125 watchdog_ping();
126
127 return len;
128}
129
130static struct watchdog_info ident = {
131 .options = WDIOF_SETTIMEOUT,
132 .identity = "Footbridge Watchdog",
133};
134
135static int
136watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
137 unsigned long arg)
138{
139 unsigned int new_margin;
140 int ret = -ENOTTY;
141
142 switch(cmd) {
143 case WDIOC_GETSUPPORT:
144 ret = 0;
145 if (copy_to_user((void *)arg, &ident, sizeof(ident)))
146 ret = -EFAULT;
147 break;
148
149 case WDIOC_GETSTATUS:
150 case WDIOC_GETBOOTSTATUS:
151 ret = put_user(0,(int *)arg);
152 break;
153
154 case WDIOC_KEEPALIVE:
155 watchdog_ping();
156 ret = 0;
157 break;
158
159 case WDIOC_SETTIMEOUT:
160 ret = get_user(new_margin, (int *)arg);
161 if (ret)
162 break;
163
164 /* Arbitrary, can't find the card's limits */
165 if (new_margin < 0 || new_margin > 60) {
166 ret = -EINVAL;
167 break;
168 }
169
170 soft_margin = new_margin;
171 reload = soft_margin * (mem_fclk_21285 / 256);
172 watchdog_ping();
173 /* Fall */
174 case WDIOC_GETTIMEOUT:
175 ret = put_user(soft_margin, (int *)arg);
176 break;
177 }
178 return ret;
179}
180
181static const struct file_operations watchdog_fops = {
182 .owner = THIS_MODULE,
183 .llseek = no_llseek,
184 .write = watchdog_write,
185 .ioctl = watchdog_ioctl,
186 .open = watchdog_open,
187 .release = watchdog_release,
188};
189
190static struct miscdevice watchdog_miscdev = {
191 .minor = WATCHDOG_MINOR,
192 .name = "watchdog",
193 .fops = &watchdog_fops,
194};
195
196static int __init footbridge_watchdog_init(void)
197{
198 int retval;
199
200 if (machine_is_netwinder())
201 return -ENODEV;
202
203 retval = misc_register(&watchdog_miscdev);
204 if (retval < 0)
205 return retval;
206
207 printk("Footbridge Watchdog Timer: 0.01, timer margin: %d sec\n",
208 soft_margin);
209
210 if (machine_is_cats())
211 printk("Warning: Watchdog reset may not work on this machine.\n");
212 return 0;
213}
214
215static void __exit footbridge_watchdog_exit(void)
216{
217 misc_deregister(&watchdog_miscdev);
218}
219
220MODULE_AUTHOR("Phil Blundell <pb@nexus.co.uk>");
221MODULE_DESCRIPTION("Footbridge watchdog driver");
222MODULE_LICENSE("GPL");
223MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
224
225module_param(soft_margin, int, 0);
226MODULE_PARM_DESC(soft_margin,"Watchdog timeout in seconds");
227
228module_init(footbridge_watchdog_init);
229module_exit(footbridge_watchdog_exit);
diff --git a/drivers/watchdog/wdt977.c b/drivers/watchdog/wdt977.c
new file mode 100644
index 000000000000..7d300ff7ab07
--- /dev/null
+++ b/drivers/watchdog/wdt977.c
@@ -0,0 +1,519 @@
1/*
2 * Wdt977 0.04: A Watchdog Device for Netwinder W83977AF chip
3 *
4 * (c) Copyright 1998 Rebel.com (Woody Suwalski <woody@netwinder.org>)
5 *
6 * -----------------------
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version
11 * 2 of the License, or (at your option) any later version.
12 *
13 * -----------------------
14 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
15 * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
16 * 19-Dec-2001 Woody Suwalski: Netwinder fixes, ioctl interface
17 * 06-Jan-2002 Woody Suwalski: For compatibility, convert all timeouts
18 * from minutes to seconds.
19 * 07-Jul-2003 Daniele Bellucci: Audit return code of misc_register in
20 * nwwatchdog_init.
21 * 25-Oct-2005 Woody Suwalski: Convert addresses to #defs, add spinlocks
22 * remove limitiation to be used on Netwinders only
23 */
24
25#include <linux/module.h>
26#include <linux/moduleparam.h>
27#include <linux/types.h>
28#include <linux/kernel.h>
29#include <linux/fs.h>
30#include <linux/miscdevice.h>
31#include <linux/init.h>
32#include <linux/ioport.h>
33#include <linux/watchdog.h>
34#include <linux/notifier.h>
35#include <linux/reboot.h>
36
37#include <asm/io.h>
38#include <asm/system.h>
39#include <asm/mach-types.h>
40#include <asm/uaccess.h>
41
42#define WATCHDOG_VERSION "0.04"
43#define WATCHDOG_NAME "Wdt977"
44#define PFX WATCHDOG_NAME ": "
45#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n"
46
47#define IO_INDEX_PORT 0x370 /* on some systems it can be 0x3F0 */
48#define IO_DATA_PORT (IO_INDEX_PORT+1)
49
50#define UNLOCK_DATA 0x87
51#define LOCK_DATA 0xAA
52#define DEVICE_REGISTER 0x07
53
54
55#define DEFAULT_TIMEOUT 60 /* default timeout in seconds */
56
57static int timeout = DEFAULT_TIMEOUT;
58static int timeoutM; /* timeout in minutes */
59static unsigned long timer_alive;
60static int testmode;
61static char expect_close;
62static spinlock_t spinlock;
63
64module_param(timeout, int, 0);
65MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (60..15300), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")");
66module_param(testmode, int, 0);
67MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0");
68
69static int nowayout = WATCHDOG_NOWAYOUT;
70module_param(nowayout, int, 0);
71MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
72
73/*
74 * Start the watchdog
75 */
76
77static int wdt977_start(void)
78{
79 unsigned long flags;
80
81 spin_lock_irqsave(&spinlock, flags);
82
83 /* unlock the SuperIO chip */
84 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
85 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
86
87 /* select device Aux2 (device=8) and set watchdog regs F2, F3 and F4
88 * F2 has the timeout in minutes
89 * F3 could be set to the POWER LED blink (with GP17 set to PowerLed)
90 * at timeout, and to reset timer on kbd/mouse activity (not impl.)
91 * F4 is used to just clear the TIMEOUT'ed state (bit 0)
92 */
93 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
94 outb_p(0x08, IO_DATA_PORT);
95 outb_p(0xF2, IO_INDEX_PORT);
96 outb_p(timeoutM, IO_DATA_PORT);
97 outb_p(0xF3, IO_INDEX_PORT);
98 outb_p(0x00, IO_DATA_PORT); /* another setting is 0E for kbd/mouse/LED */
99 outb_p(0xF4, IO_INDEX_PORT);
100 outb_p(0x00, IO_DATA_PORT);
101
102 /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
103 /* in test mode watch the bit 1 on F4 to indicate "triggered" */
104 if (!testmode)
105 {
106 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
107 outb_p(0x07, IO_DATA_PORT);
108 outb_p(0xE6, IO_INDEX_PORT);
109 outb_p(0x08, IO_DATA_PORT);
110 }
111
112 /* lock the SuperIO chip */
113 outb_p(LOCK_DATA, IO_INDEX_PORT);
114
115 spin_unlock_irqrestore(&spinlock, flags);
116 printk(KERN_INFO PFX "activated.\n");
117
118 return 0;
119}
120
121/*
122 * Stop the watchdog
123 */
124
125static int wdt977_stop(void)
126{
127 unsigned long flags;
128 spin_lock_irqsave(&spinlock, flags);
129
130 /* unlock the SuperIO chip */
131 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
132 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
133
134 /* select device Aux2 (device=8) and set watchdog regs F2,F3 and F4
135 * F3 is reset to its default state
136 * F4 can clear the TIMEOUT'ed state (bit 0) - back to default
137 * We can not use GP17 as a PowerLed, as we use its usage as a RedLed
138 */
139 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
140 outb_p(0x08, IO_DATA_PORT);
141 outb_p(0xF2, IO_INDEX_PORT);
142 outb_p(0xFF, IO_DATA_PORT);
143 outb_p(0xF3, IO_INDEX_PORT);
144 outb_p(0x00, IO_DATA_PORT);
145 outb_p(0xF4, IO_INDEX_PORT);
146 outb_p(0x00, IO_DATA_PORT);
147 outb_p(0xF2, IO_INDEX_PORT);
148 outb_p(0x00, IO_DATA_PORT);
149
150 /* at last select device Aux1 (dev=7) and set GP16 as a watchdog output */
151 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
152 outb_p(0x07, IO_DATA_PORT);
153 outb_p(0xE6, IO_INDEX_PORT);
154 outb_p(0x08, IO_DATA_PORT);
155
156 /* lock the SuperIO chip */
157 outb_p(LOCK_DATA, IO_INDEX_PORT);
158
159 spin_unlock_irqrestore(&spinlock, flags);
160 printk(KERN_INFO PFX "shutdown.\n");
161
162 return 0;
163}
164
165/*
166 * Send a keepalive ping to the watchdog
167 * This is done by simply re-writing the timeout to reg. 0xF2
168 */
169
170static int wdt977_keepalive(void)
171{
172 unsigned long flags;
173 spin_lock_irqsave(&spinlock, flags);
174
175 /* unlock the SuperIO chip */
176 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
177 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
178
179 /* select device Aux2 (device=8) and kicks watchdog reg F2 */
180 /* F2 has the timeout in minutes */
181 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
182 outb_p(0x08, IO_DATA_PORT);
183 outb_p(0xF2, IO_INDEX_PORT);
184 outb_p(timeoutM, IO_DATA_PORT);
185
186 /* lock the SuperIO chip */
187 outb_p(LOCK_DATA, IO_INDEX_PORT);
188 spin_unlock_irqrestore(&spinlock, flags);
189
190 return 0;
191}
192
193/*
194 * Set the watchdog timeout value
195 */
196
197static int wdt977_set_timeout(int t)
198{
199 int tmrval;
200
201 /* convert seconds to minutes, rounding up */
202 tmrval = (t + 59) / 60;
203
204 if (machine_is_netwinder()) {
205 /* we have a hw bug somewhere, so each 977 minute is actually only 30sec
206 * this limits the max timeout to half of device max of 255 minutes...
207 */
208 tmrval += tmrval;
209 }
210
211 if ((tmrval < 1) || (tmrval > 255))
212 return -EINVAL;
213
214 /* timeout is the timeout in seconds, timeoutM is the timeout in minutes) */
215 timeout = t;
216 timeoutM = tmrval;
217 return 0;
218}
219
220/*
221 * Get the watchdog status
222 */
223
224static int wdt977_get_status(int *status)
225{
226 int new_status;
227 unsigned long flags;
228
229 spin_lock_irqsave(&spinlock, flags);
230
231 /* unlock the SuperIO chip */
232 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
233 outb_p(UNLOCK_DATA, IO_INDEX_PORT);
234
235 /* select device Aux2 (device=8) and read watchdog reg F4 */
236 outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
237 outb_p(0x08, IO_DATA_PORT);
238 outb_p(0xF4, IO_INDEX_PORT);
239 new_status = inb_p(IO_DATA_PORT);
240
241 /* lock the SuperIO chip */
242 outb_p(LOCK_DATA, IO_INDEX_PORT);
243
244 spin_unlock_irqrestore(&spinlock, flags);
245
246 *status=0;
247 if (new_status & 1)
248 *status |= WDIOF_CARDRESET;
249
250 return 0;
251}
252
253
254/*
255 * /dev/watchdog handling
256 */
257
258static int wdt977_open(struct inode *inode, struct file *file)
259{
260 /* If the watchdog is alive we don't need to start it again */
261 if( test_and_set_bit(0,&timer_alive) )
262 return -EBUSY;
263
264 if (nowayout)
265 __module_get(THIS_MODULE);
266
267 wdt977_start();
268 return nonseekable_open(inode, file);
269}
270
271static int wdt977_release(struct inode *inode, struct file *file)
272{
273 /*
274 * Shut off the timer.
275 * Lock it in if it's a module and we set nowayout
276 */
277 if (expect_close == 42)
278 {
279 wdt977_stop();
280 clear_bit(0,&timer_alive);
281 } else {
282 wdt977_keepalive();
283 printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
284 }
285 expect_close = 0;
286 return 0;
287}
288
289
290/*
291 * wdt977_write:
292 * @file: file handle to the watchdog
293 * @buf: buffer to write (unused as data does not matter here
294 * @count: count of bytes
295 * @ppos: pointer to the position to write. No seeks allowed
296 *
297 * A write to a watchdog device is defined as a keepalive signal. Any
298 * write of data will do, as we we don't define content meaning.
299 */
300
301static ssize_t wdt977_write(struct file *file, const char __user *buf,
302 size_t count, loff_t *ppos)
303{
304 if (count)
305 {
306 if (!nowayout)
307 {
308 size_t i;
309
310 /* In case it was set long ago */
311 expect_close = 0;
312
313 for (i = 0; i != count; i++)
314 {
315 char c;
316 if (get_user(c, buf + i))
317 return -EFAULT;
318 if (c == 'V')
319 expect_close = 42;
320 }
321 }
322
323 /* someone wrote to us, we should restart timer */
324 wdt977_keepalive();
325 }
326 return count;
327}
328
329/*
330 * wdt977_ioctl:
331 * @inode: inode of the device
332 * @file: file handle to the device
333 * @cmd: watchdog command
334 * @arg: argument pointer
335 *
336 * The watchdog API defines a common set of functions for all watchdogs
337 * according to their available features.
338 */
339
340static struct watchdog_info ident = {
341 .options = WDIOF_SETTIMEOUT |
342 WDIOF_MAGICCLOSE |
343 WDIOF_KEEPALIVEPING,
344 .firmware_version = 1,
345 .identity = WATCHDOG_NAME,
346};
347
348static int wdt977_ioctl(struct inode *inode, struct file *file,
349 unsigned int cmd, unsigned long arg)
350{
351 int status;
352 int new_options, retval = -EINVAL;
353 int new_timeout;
354 union {
355 struct watchdog_info __user *ident;
356 int __user *i;
357 } uarg;
358
359 uarg.i = (int __user *)arg;
360
361 switch(cmd)
362 {
363 default:
364 return -ENOTTY;
365
366 case WDIOC_GETSUPPORT:
367 return copy_to_user(uarg.ident, &ident,
368 sizeof(ident)) ? -EFAULT : 0;
369
370 case WDIOC_GETSTATUS:
371 wdt977_get_status(&status);
372 return put_user(status, uarg.i);
373
374 case WDIOC_GETBOOTSTATUS:
375 return put_user(0, uarg.i);
376
377 case WDIOC_KEEPALIVE:
378 wdt977_keepalive();
379 return 0;
380
381 case WDIOC_SETOPTIONS:
382 if (get_user (new_options, uarg.i))
383 return -EFAULT;
384
385 if (new_options & WDIOS_DISABLECARD) {
386 wdt977_stop();
387 retval = 0;
388 }
389
390 if (new_options & WDIOS_ENABLECARD) {
391 wdt977_start();
392 retval = 0;
393 }
394
395 return retval;
396
397 case WDIOC_SETTIMEOUT:
398 if (get_user(new_timeout, uarg.i))
399 return -EFAULT;
400
401 if (wdt977_set_timeout(new_timeout))
402 return -EINVAL;
403
404 wdt977_keepalive();
405 /* Fall */
406
407 case WDIOC_GETTIMEOUT:
408 return put_user(timeout, uarg.i);
409
410 }
411}
412
413static int wdt977_notify_sys(struct notifier_block *this, unsigned long code,
414 void *unused)
415{
416 if(code==SYS_DOWN || code==SYS_HALT)
417 wdt977_stop();
418 return NOTIFY_DONE;
419}
420
421static const struct file_operations wdt977_fops=
422{
423 .owner = THIS_MODULE,
424 .llseek = no_llseek,
425 .write = wdt977_write,
426 .ioctl = wdt977_ioctl,
427 .open = wdt977_open,
428 .release = wdt977_release,
429};
430
431static struct miscdevice wdt977_miscdev=
432{
433 .minor = WATCHDOG_MINOR,
434 .name = "watchdog",
435 .fops = &wdt977_fops,
436};
437
438static struct notifier_block wdt977_notifier = {
439 .notifier_call = wdt977_notify_sys,
440};
441
442static int __init wd977_init(void)
443{
444 int rc;
445
446 //if (!machine_is_netwinder())
447 // return -ENODEV;
448
449 printk(KERN_INFO PFX DRIVER_VERSION);
450
451 spin_lock_init(&spinlock);
452
453 /* Check that the timeout value is within it's range ; if not reset to the default */
454 if (wdt977_set_timeout(timeout))
455 {
456 wdt977_set_timeout(DEFAULT_TIMEOUT);
457 printk(KERN_INFO PFX "timeout value must be 60<timeout<15300, using %d\n",
458 DEFAULT_TIMEOUT);
459 }
460
461 /* on Netwinder the IOports are already reserved by
462 * arch/arm/mach-footbridge/netwinder-hw.c
463 */
464 if (!machine_is_netwinder())
465 {
466 if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME))
467 {
468 printk(KERN_ERR PFX "I/O address 0x%04x already in use\n",
469 IO_INDEX_PORT);
470 rc = -EIO;
471 goto err_out;
472 }
473 }
474
475 rc = misc_register(&wdt977_miscdev);
476 if (rc)
477 {
478 printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
479 wdt977_miscdev.minor, rc);
480 goto err_out_region;
481 }
482
483 rc = register_reboot_notifier(&wdt977_notifier);
484 if (rc)
485 {
486 printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n",
487 rc);
488 goto err_out_miscdev;
489 }
490
491 printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d, testmode=%i)\n",
492 timeout, nowayout, testmode);
493
494 return 0;
495
496err_out_miscdev:
497 misc_deregister(&wdt977_miscdev);
498err_out_region:
499 if (!machine_is_netwinder())
500 release_region(IO_INDEX_PORT,2);
501err_out:
502 return rc;
503}
504
505static void __exit wd977_exit(void)
506{
507 wdt977_stop();
508 misc_deregister(&wdt977_miscdev);
509 unregister_reboot_notifier(&wdt977_notifier);
510 release_region(IO_INDEX_PORT,2);
511}
512
513module_init(wd977_init);
514module_exit(wd977_exit);
515
516MODULE_AUTHOR("Woody Suwalski <woodys@xandros.com>");
517MODULE_DESCRIPTION("W83977AF Watchdog driver");
518MODULE_LICENSE("GPL");
519MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c
new file mode 100644
index 000000000000..6baf4ae42c9d
--- /dev/null
+++ b/drivers/watchdog/wdt_pci.c
@@ -0,0 +1,756 @@
1/*
2 * Industrial Computer Source PCI-WDT500/501 driver
3 *
4 * (c) Copyright 1996-1997 Alan Cox <alan@redhat.com>, All Rights Reserved.
5 * http://www.redhat.com
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 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
13 * warranty for any of this software. This material is provided
14 * "AS-IS" and at no charge.
15 *
16 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk>
17 *
18 * Release 0.10.
19 *
20 * Fixes
21 * Dave Gregorich : Modularisation and minor bugs
22 * Alan Cox : Added the watchdog ioctl() stuff
23 * Alan Cox : Fixed the reboot problem (as noted by
24 * Matt Crocker).
25 * Alan Cox : Added wdt= boot option
26 * Alan Cox : Cleaned up copy/user stuff
27 * Tim Hockin : Added insmod parameters, comment cleanup
28 * Parameterized timeout
29 * JP Nollmann : Added support for PCI wdt501p
30 * Alan Cox : Split ISA and PCI cards into two drivers
31 * Jeff Garzik : PCI cleanups
32 * Tigran Aivazian : Restructured wdtpci_init_one() to handle failures
33 * Joel Becker : Added WDIOC_GET/SETTIMEOUT
34 * Zwane Mwaikambo : Magic char closing, locking changes, cleanups
35 * Matt Domsch : nowayout module option
36 */
37
38#include <linux/interrupt.h>
39#include <linux/module.h>
40#include <linux/moduleparam.h>
41#include <linux/types.h>
42#include <linux/miscdevice.h>
43#include <linux/watchdog.h>
44#include <linux/ioport.h>
45#include <linux/notifier.h>
46#include <linux/reboot.h>
47#include <linux/init.h>
48#include <linux/fs.h>
49#include <linux/pci.h>
50
51#include <asm/io.h>
52#include <asm/uaccess.h>
53#include <asm/system.h>
54
55#define WDT_IS_PCI
56#include "wd501p.h"
57
58#define PFX "wdt_pci: "
59
60/*
61 * Until Access I/O gets their application for a PCI vendor ID approved,
62 * I don't think that it's appropriate to move these constants into the
63 * regular pci_ids.h file. -- JPN 2000/01/18
64 */
65
66#ifndef PCI_VENDOR_ID_ACCESSIO
67#define PCI_VENDOR_ID_ACCESSIO 0x494f
68#endif
69#ifndef PCI_DEVICE_ID_WDG_CSM
70#define PCI_DEVICE_ID_WDG_CSM 0x22c0
71#endif
72
73/* We can only use 1 card due to the /dev/watchdog restriction */
74static int dev_count;
75
76static struct semaphore open_sem;
77static spinlock_t wdtpci_lock;
78static char expect_close;
79
80static int io;
81static int irq;
82
83/* Default timeout */
84#define WD_TIMO 60 /* Default heartbeat = 60 seconds */
85
86static int heartbeat = WD_TIMO;
87static int wd_heartbeat;
88module_param(heartbeat, int, 0);
89MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WD_TIMO) ")");
90
91static int nowayout = WATCHDOG_NOWAYOUT;
92module_param(nowayout, int, 0);
93MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
94
95#ifdef CONFIG_WDT_501_PCI
96/* Support for the Fan Tachometer on the PCI-WDT501 */
97static int tachometer;
98
99module_param(tachometer, int, 0);
100MODULE_PARM_DESC(tachometer, "PCI-WDT501 Fan Tachometer support (0=disable, default=0)");
101#endif /* CONFIG_WDT_501_PCI */
102
103/*
104 * Programming support
105 */
106
107static void wdtpci_ctr_mode(int ctr, int mode)
108{
109 ctr<<=6;
110 ctr|=0x30;
111 ctr|=(mode<<1);
112 outb_p(ctr, WDT_CR);
113}
114
115static void wdtpci_ctr_load(int ctr, int val)
116{
117 outb_p(val&0xFF, WDT_COUNT0+ctr);
118 outb_p(val>>8, WDT_COUNT0+ctr);
119}
120
121/**
122 * wdtpci_start:
123 *
124 * Start the watchdog driver.
125 */
126
127static int wdtpci_start(void)
128{
129 unsigned long flags;
130
131 spin_lock_irqsave(&wdtpci_lock, flags);
132
133 /*
134 * "pet" the watchdog, as Access says.
135 * This resets the clock outputs.
136 */
137 inb_p(WDT_DC); /* Disable watchdog */
138 wdtpci_ctr_mode(2,0); /* Program CTR2 for Mode 0: Pulse on Terminal Count */
139 outb_p(0, WDT_DC); /* Enable watchdog */
140
141 inb_p(WDT_DC); /* Disable watchdog */
142 outb_p(0, WDT_CLOCK); /* 2.0833MHz clock */
143 inb_p(WDT_BUZZER); /* disable */
144 inb_p(WDT_OPTONOTRST); /* disable */
145 inb_p(WDT_OPTORST); /* disable */
146 inb_p(WDT_PROGOUT); /* disable */
147 wdtpci_ctr_mode(0,3); /* Program CTR0 for Mode 3: Square Wave Generator */
148 wdtpci_ctr_mode(1,2); /* Program CTR1 for Mode 2: Rate Generator */
149 wdtpci_ctr_mode(2,1); /* Program CTR2 for Mode 1: Retriggerable One-Shot */
150 wdtpci_ctr_load(0,20833); /* count at 100Hz */
151 wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */
152 /* DO NOT LOAD CTR2 on PCI card! -- JPN */
153 outb_p(0, WDT_DC); /* Enable watchdog */
154
155 spin_unlock_irqrestore(&wdtpci_lock, flags);
156 return 0;
157}
158
159/**
160 * wdtpci_stop:
161 *
162 * Stop the watchdog driver.
163 */
164
165static int wdtpci_stop (void)
166{
167 unsigned long flags;
168
169 /* Turn the card off */
170 spin_lock_irqsave(&wdtpci_lock, flags);
171 inb_p(WDT_DC); /* Disable watchdog */
172 wdtpci_ctr_load(2,0); /* 0 length reset pulses now */
173 spin_unlock_irqrestore(&wdtpci_lock, flags);
174 return 0;
175}
176
177/**
178 * wdtpci_ping:
179 *
180 * Reload counter one with the watchdog heartbeat. We don't bother reloading
181 * the cascade counter.
182 */
183
184static int wdtpci_ping(void)
185{
186 unsigned long flags;
187
188 /* Write a watchdog value */
189 spin_lock_irqsave(&wdtpci_lock, flags);
190 inb_p(WDT_DC); /* Disable watchdog */
191 wdtpci_ctr_mode(1,2); /* Re-Program CTR1 for Mode 2: Rate Generator */
192 wdtpci_ctr_load(1,wd_heartbeat);/* Heartbeat */
193 outb_p(0, WDT_DC); /* Enable watchdog */
194 spin_unlock_irqrestore(&wdtpci_lock, flags);
195 return 0;
196}
197
198/**
199 * wdtpci_set_heartbeat:
200 * @t: the new heartbeat value that needs to be set.
201 *
202 * Set a new heartbeat value for the watchdog device. If the heartbeat value is
203 * incorrect we keep the old value and return -EINVAL. If successfull we
204 * return 0.
205 */
206static int wdtpci_set_heartbeat(int t)
207{
208 /* Arbitrary, can't find the card's limits */
209 if ((t < 1) || (t > 65535))
210 return -EINVAL;
211
212 heartbeat = t;
213 wd_heartbeat = t * 100;
214 return 0;
215}
216
217/**
218 * wdtpci_get_status:
219 * @status: the new status.
220 *
221 * Extract the status information from a WDT watchdog device. There are
222 * several board variants so we have to know which bits are valid. Some
223 * bits default to one and some to zero in order to be maximally painful.
224 *
225 * we then map the bits onto the status ioctl flags.
226 */
227
228static int wdtpci_get_status(int *status)
229{
230 unsigned char new_status=inb_p(WDT_SR);
231
232 *status=0;
233 if (new_status & WDC_SR_ISOI0)
234 *status |= WDIOF_EXTERN1;
235 if (new_status & WDC_SR_ISII1)
236 *status |= WDIOF_EXTERN2;
237#ifdef CONFIG_WDT_501_PCI
238 if (!(new_status & WDC_SR_TGOOD))
239 *status |= WDIOF_OVERHEAT;
240 if (!(new_status & WDC_SR_PSUOVER))
241 *status |= WDIOF_POWEROVER;
242 if (!(new_status & WDC_SR_PSUUNDR))
243 *status |= WDIOF_POWERUNDER;
244 if (tachometer) {
245 if (!(new_status & WDC_SR_FANGOOD))
246 *status |= WDIOF_FANFAULT;
247 }
248#endif /* CONFIG_WDT_501_PCI */
249 return 0;
250}
251
252#ifdef CONFIG_WDT_501_PCI
253/**
254 * wdtpci_get_temperature:
255 *
256 * Reports the temperature in degrees Fahrenheit. The API is in
257 * farenheit. It was designed by an imperial measurement luddite.
258 */
259
260static int wdtpci_get_temperature(int *temperature)
261{
262 unsigned short c=inb_p(WDT_RT);
263
264 *temperature = (c * 11 / 15) + 7;
265 return 0;
266}
267#endif /* CONFIG_WDT_501_PCI */
268
269/**
270 * wdtpci_interrupt:
271 * @irq: Interrupt number
272 * @dev_id: Unused as we don't allow multiple devices.
273 *
274 * Handle an interrupt from the board. These are raised when the status
275 * map changes in what the board considers an interesting way. That means
276 * a failure condition occurring.
277 */
278
279static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
280{
281 /*
282 * Read the status register see what is up and
283 * then printk it.
284 */
285 unsigned char status=inb_p(WDT_SR);
286
287 printk(KERN_CRIT PFX "status %d\n", status);
288
289#ifdef CONFIG_WDT_501_PCI
290 if (!(status & WDC_SR_TGOOD))
291 printk(KERN_CRIT PFX "Overheat alarm.(%d)\n",inb_p(WDT_RT));
292 if (!(status & WDC_SR_PSUOVER))
293 printk(KERN_CRIT PFX "PSU over voltage.\n");
294 if (!(status & WDC_SR_PSUUNDR))
295 printk(KERN_CRIT PFX "PSU under voltage.\n");
296 if (tachometer) {
297 if (!(status & WDC_SR_FANGOOD))
298 printk(KERN_CRIT PFX "Possible fan fault.\n");
299 }
300#endif /* CONFIG_WDT_501_PCI */
301 if (!(status&WDC_SR_WCCR))
302#ifdef SOFTWARE_REBOOT
303#ifdef ONLY_TESTING
304 printk(KERN_CRIT PFX "Would Reboot.\n");
305#else
306 printk(KERN_CRIT PFX "Initiating system reboot.\n");
307 emergency_restart(NULL);
308#endif
309#else
310 printk(KERN_CRIT PFX "Reset in 5ms.\n");
311#endif
312 return IRQ_HANDLED;
313}
314
315
316/**
317 * wdtpci_write:
318 * @file: file handle to the watchdog
319 * @buf: buffer to write (unused as data does not matter here
320 * @count: count of bytes
321 * @ppos: pointer to the position to write. No seeks allowed
322 *
323 * A write to a watchdog device is defined as a keepalive signal. Any
324 * write of data will do, as we we don't define content meaning.
325 */
326
327static ssize_t wdtpci_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
328{
329 if (count) {
330 if (!nowayout) {
331 size_t i;
332
333 expect_close = 0;
334
335 for (i = 0; i != count; i++) {
336 char c;
337 if(get_user(c, buf+i))
338 return -EFAULT;
339 if (c == 'V')
340 expect_close = 42;
341 }
342 }
343 wdtpci_ping();
344 }
345
346 return count;
347}
348
349/**
350 * wdtpci_ioctl:
351 * @inode: inode of the device
352 * @file: file handle to the device
353 * @cmd: watchdog command
354 * @arg: argument pointer
355 *
356 * The watchdog API defines a common set of functions for all watchdogs
357 * according to their available features. We only actually usefully support
358 * querying capabilities and current status.
359 */
360
361static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
362 unsigned long arg)
363{
364 int new_heartbeat;
365 int status;
366 void __user *argp = (void __user *)arg;
367 int __user *p = argp;
368
369 static struct watchdog_info ident = {
370 .options = WDIOF_SETTIMEOUT|
371 WDIOF_MAGICCLOSE|
372 WDIOF_KEEPALIVEPING,
373 .firmware_version = 1,
374 .identity = "PCI-WDT500/501",
375 };
376
377 /* Add options according to the card we have */
378 ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
379#ifdef CONFIG_WDT_501_PCI
380 ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|WDIOF_POWEROVER);
381 if (tachometer)
382 ident.options |= WDIOF_FANFAULT;
383#endif /* CONFIG_WDT_501_PCI */
384
385 switch(cmd)
386 {
387 default:
388 return -ENOTTY;
389 case WDIOC_GETSUPPORT:
390 return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
391
392 case WDIOC_GETSTATUS:
393 wdtpci_get_status(&status);
394 return put_user(status, p);
395 case WDIOC_GETBOOTSTATUS:
396 return put_user(0, p);
397 case WDIOC_KEEPALIVE:
398 wdtpci_ping();
399 return 0;
400 case WDIOC_SETTIMEOUT:
401 if (get_user(new_heartbeat, p))
402 return -EFAULT;
403
404 if (wdtpci_set_heartbeat(new_heartbeat))
405 return -EINVAL;
406
407 wdtpci_ping();
408 /* Fall */
409 case WDIOC_GETTIMEOUT:
410 return put_user(heartbeat, p);
411 }
412}
413
414/**
415 * wdtpci_open:
416 * @inode: inode of device
417 * @file: file handle to device
418 *
419 * The watchdog device has been opened. The watchdog device is single
420 * open and on opening we load the counters. Counter zero is a 100Hz
421 * cascade, into counter 1 which downcounts to reboot. When the counter
422 * triggers counter 2 downcounts the length of the reset pulse which
423 * set set to be as long as possible.
424 */
425
426static int wdtpci_open(struct inode *inode, struct file *file)
427{
428 if (down_trylock(&open_sem))
429 return -EBUSY;
430
431 if (nowayout) {
432 __module_get(THIS_MODULE);
433 }
434 /*
435 * Activate
436 */
437 wdtpci_start();
438 return nonseekable_open(inode, file);
439}
440
441/**
442 * wdtpci_release:
443 * @inode: inode to board
444 * @file: file handle to board
445 *
446 * The watchdog has a configurable API. There is a religious dispute
447 * between people who want their watchdog to be able to shut down and
448 * those who want to be sure if the watchdog manager dies the machine
449 * reboots. In the former case we disable the counters, in the latter
450 * case you have to open it again very soon.
451 */
452
453static int wdtpci_release(struct inode *inode, struct file *file)
454{
455 if (expect_close == 42) {
456 wdtpci_stop();
457 } else {
458 printk(KERN_CRIT PFX "Unexpected close, not stopping timer!");
459 wdtpci_ping();
460 }
461 expect_close = 0;
462 up(&open_sem);
463 return 0;
464}
465
466#ifdef CONFIG_WDT_501_PCI
467/**
468 * wdtpci_temp_read:
469 * @file: file handle to the watchdog board
470 * @buf: buffer to write 1 byte into
471 * @count: length of buffer
472 * @ptr: offset (no seek allowed)
473 *
474 * Read reports the temperature in degrees Fahrenheit. The API is in
475 * fahrenheit. It was designed by an imperial measurement luddite.
476 */
477
478static ssize_t wdtpci_temp_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)
479{
480 int temperature;
481
482 if (wdtpci_get_temperature(&temperature))
483 return -EFAULT;
484
485 if (copy_to_user (buf, &temperature, 1))
486 return -EFAULT;
487
488 return 1;
489}
490
491/**
492 * wdtpci_temp_open:
493 * @inode: inode of device
494 * @file: file handle to device
495 *
496 * The temperature device has been opened.
497 */
498
499static int wdtpci_temp_open(struct inode *inode, struct file *file)
500{
501 return nonseekable_open(inode, file);
502}
503
504/**
505 * wdtpci_temp_release:
506 * @inode: inode to board
507 * @file: file handle to board
508 *
509 * The temperature device has been closed.
510 */
511
512static int wdtpci_temp_release(struct inode *inode, struct file *file)
513{
514 return 0;
515}
516#endif /* CONFIG_WDT_501_PCI */
517
518/**
519 * notify_sys:
520 * @this: our notifier block
521 * @code: the event being reported
522 * @unused: unused
523 *
524 * Our notifier is called on system shutdowns. We want to turn the card
525 * off at reboot otherwise the machine will reboot again during memory
526 * test or worse yet during the following fsck. This would suck, in fact
527 * trust me - if it happens it does suck.
528 */
529
530static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
531 void *unused)
532{
533 if (code==SYS_DOWN || code==SYS_HALT) {
534 /* Turn the card off */
535 wdtpci_stop();
536 }
537 return NOTIFY_DONE;
538}
539
540/*
541 * Kernel Interfaces
542 */
543
544
545static const struct file_operations wdtpci_fops = {
546 .owner = THIS_MODULE,
547 .llseek = no_llseek,
548 .write = wdtpci_write,
549 .ioctl = wdtpci_ioctl,
550 .open = wdtpci_open,
551 .release = wdtpci_release,
552};
553
554static struct miscdevice wdtpci_miscdev = {
555 .minor = WATCHDOG_MINOR,
556 .name = "watchdog",
557 .fops = &wdtpci_fops,
558};
559
560#ifdef CONFIG_WDT_501_PCI
561static const struct file_operations wdtpci_temp_fops = {
562 .owner = THIS_MODULE,
563 .llseek = no_llseek,
564 .read = wdtpci_temp_read,
565 .open = wdtpci_temp_open,
566 .release = wdtpci_temp_release,
567};
568
569static struct miscdevice temp_miscdev = {
570 .minor = TEMP_MINOR,
571 .name = "temperature",
572 .fops = &wdtpci_temp_fops,
573};
574#endif /* CONFIG_WDT_501_PCI */
575
576/*
577 * The WDT card needs to learn about soft shutdowns in order to
578 * turn the timebomb registers off.
579 */
580
581static struct notifier_block wdtpci_notifier = {
582 .notifier_call = wdtpci_notify_sys,
583};
584
585
586static int __devinit wdtpci_init_one (struct pci_dev *dev,
587 const struct pci_device_id *ent)
588{
589 int ret = -EIO;
590
591 dev_count++;
592 if (dev_count > 1) {
593 printk (KERN_ERR PFX "this driver only supports 1 device\n");
594 return -ENODEV;
595 }
596
597 if (pci_enable_device (dev)) {
598 printk (KERN_ERR PFX "Not possible to enable PCI Device\n");
599 return -ENODEV;
600 }
601
602 if (pci_resource_start (dev, 2) == 0x0000) {
603 printk (KERN_ERR PFX "No I/O-Address for card detected\n");
604 ret = -ENODEV;
605 goto out_pci;
606 }
607
608 sema_init(&open_sem, 1);
609 spin_lock_init(&wdtpci_lock);
610
611 irq = dev->irq;
612 io = pci_resource_start (dev, 2);
613
614 if (request_region (io, 16, "wdt_pci") == NULL) {
615 printk (KERN_ERR PFX "I/O address 0x%04x already in use\n", io);
616 goto out_pci;
617 }
618
619 if (request_irq (irq, wdtpci_interrupt, IRQF_DISABLED | IRQF_SHARED,
620 "wdt_pci", &wdtpci_miscdev)) {
621 printk (KERN_ERR PFX "IRQ %d is not free\n", irq);
622 goto out_reg;
623 }
624
625 printk ("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%04x (Interrupt %d)\n",
626 io, irq);
627
628 /* Check that the heartbeat value is within it's range ; if not reset to the default */
629 if (wdtpci_set_heartbeat(heartbeat)) {
630 wdtpci_set_heartbeat(WD_TIMO);
631 printk(KERN_INFO PFX "heartbeat value must be 0<heartbeat<65536, using %d\n",
632 WD_TIMO);
633 }
634
635 ret = register_reboot_notifier (&wdtpci_notifier);
636 if (ret) {
637 printk (KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", ret);
638 goto out_irq;
639 }
640
641#ifdef CONFIG_WDT_501_PCI
642 ret = misc_register (&temp_miscdev);
643 if (ret) {
644 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
645 TEMP_MINOR, ret);
646 goto out_rbt;
647 }
648#endif /* CONFIG_WDT_501_PCI */
649
650 ret = misc_register (&wdtpci_miscdev);
651 if (ret) {
652 printk (KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
653 WATCHDOG_MINOR, ret);
654 goto out_misc;
655 }
656
657 printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
658 heartbeat, nowayout);
659#ifdef CONFIG_WDT_501_PCI
660 printk(KERN_INFO "wdt: Fan Tachometer is %s\n", (tachometer ? "Enabled" : "Disabled"));
661#endif /* CONFIG_WDT_501_PCI */
662
663 ret = 0;
664out:
665 return ret;
666
667out_misc:
668#ifdef CONFIG_WDT_501_PCI
669 misc_deregister(&temp_miscdev);
670out_rbt:
671#endif /* CONFIG_WDT_501_PCI */
672 unregister_reboot_notifier(&wdtpci_notifier);
673out_irq:
674 free_irq(irq, &wdtpci_miscdev);
675out_reg:
676 release_region (io, 16);
677out_pci:
678 pci_disable_device(dev);
679 goto out;
680}
681
682
683static void __devexit wdtpci_remove_one (struct pci_dev *pdev)
684{
685 /* here we assume only one device will ever have
686 * been picked up and registered by probe function */
687 misc_deregister(&wdtpci_miscdev);
688#ifdef CONFIG_WDT_501_PCI
689 misc_deregister(&temp_miscdev);
690#endif /* CONFIG_WDT_501_PCI */
691 unregister_reboot_notifier(&wdtpci_notifier);
692 free_irq(irq, &wdtpci_miscdev);
693 release_region(io, 16);
694 pci_disable_device(pdev);
695 dev_count--;
696}
697
698
699static struct pci_device_id wdtpci_pci_tbl[] = {
700 {
701 .vendor = PCI_VENDOR_ID_ACCESSIO,
702 .device = PCI_DEVICE_ID_WDG_CSM,
703 .subvendor = PCI_ANY_ID,
704 .subdevice = PCI_ANY_ID,
705 },
706 { 0, }, /* terminate list */
707};
708MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl);
709
710
711static struct pci_driver wdtpci_driver = {
712 .name = "wdt_pci",
713 .id_table = wdtpci_pci_tbl,
714 .probe = wdtpci_init_one,
715 .remove = __devexit_p(wdtpci_remove_one),
716};
717
718
719/**
720 * wdtpci_cleanup:
721 *
722 * Unload the watchdog. You cannot do this with any file handles open.
723 * If your watchdog is set to continue ticking on close and you unload
724 * it, well it keeps ticking. We won't get the interrupt but the board
725 * will not touch PC memory so all is fine. You just have to load a new
726 * module in xx seconds or reboot.
727 */
728
729static void __exit wdtpci_cleanup(void)
730{
731 pci_unregister_driver (&wdtpci_driver);
732}
733
734
735/**
736 * wdtpci_init:
737 *
738 * Set up the WDT watchdog board. All we have to do is grab the
739 * resources we require and bitch if anyone beat us to them.
740 * The open() function will actually kick the board off.
741 */
742
743static int __init wdtpci_init(void)
744{
745 return pci_register_driver (&wdtpci_driver);
746}
747
748
749module_init(wdtpci_init);
750module_exit(wdtpci_cleanup);
751
752MODULE_AUTHOR("JP Nollmann, Alan Cox");
753MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
754MODULE_LICENSE("GPL");
755MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
756MODULE_ALIAS_MISCDEV(TEMP_MINOR);