• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *	W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip
4  *
5  *	(c) Copyright 2005  Jose Goncalves <jose.goncalves@inov.pt>
6  *
7  *      Based on w83877f_wdt.c by Scott Jennings,
8  *           and wdt977.c by Woody Suwalski
9  *
10  *			-----------------------
11  */
12 
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/fs.h>
20 #include <linux/miscdevice.h>
21 #include <linux/init.h>
22 #include <linux/ioport.h>
23 #include <linux/watchdog.h>
24 #include <linux/notifier.h>
25 #include <linux/reboot.h>
26 #include <linux/uaccess.h>
27 #include <linux/io.h>
28 
29 
30 #define WATCHDOG_VERSION  "1.00"
31 #define WATCHDOG_NAME     "W83977F WDT"
32 
33 #define IO_INDEX_PORT     0x3F0
34 #define IO_DATA_PORT      (IO_INDEX_PORT+1)
35 
36 #define UNLOCK_DATA       0x87
37 #define LOCK_DATA         0xAA
38 #define DEVICE_REGISTER   0x07
39 
40 #define	DEFAULT_TIMEOUT   45		/* default timeout in seconds */
41 
42 static	int timeout = DEFAULT_TIMEOUT;
43 static	int timeoutW;			/* timeout in watchdog counter units */
44 static	unsigned long timer_alive;
45 static	int testmode;
46 static	char expect_close;
47 static	DEFINE_SPINLOCK(spinlock);
48 
49 module_param(timeout, int, 0);
50 MODULE_PARM_DESC(timeout,
51 		"Watchdog timeout in seconds (15..7635), default="
52 				__MODULE_STRING(DEFAULT_TIMEOUT) ")");
53 module_param(testmode, int, 0);
54 MODULE_PARM_DESC(testmode, "Watchdog testmode (1 = no reboot), default=0");
55 
56 static bool nowayout = WATCHDOG_NOWAYOUT;
57 module_param(nowayout, bool, 0);
58 MODULE_PARM_DESC(nowayout,
59 		"Watchdog cannot be stopped once started (default="
60 				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
61 
62 /*
63  * Start the watchdog
64  */
65 
wdt_start(void)66 static int wdt_start(void)
67 {
68 	unsigned long flags;
69 
70 	spin_lock_irqsave(&spinlock, flags);
71 
72 	/* Unlock the SuperIO chip */
73 	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
74 	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
75 
76 	/*
77 	 * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
78 	 * F2 has the timeout in watchdog counter units.
79 	 * F3 is set to enable watchdog LED blink at timeout.
80 	 * F4 is used to just clear the TIMEOUT'ed state (bit 0).
81 	 */
82 	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
83 	outb_p(0x08, IO_DATA_PORT);
84 	outb_p(0xF2, IO_INDEX_PORT);
85 	outb_p(timeoutW, IO_DATA_PORT);
86 	outb_p(0xF3, IO_INDEX_PORT);
87 	outb_p(0x08, IO_DATA_PORT);
88 	outb_p(0xF4, IO_INDEX_PORT);
89 	outb_p(0x00, IO_DATA_PORT);
90 
91 	/* Set device Aux2 active */
92 	outb_p(0x30, IO_INDEX_PORT);
93 	outb_p(0x01, IO_DATA_PORT);
94 
95 	/*
96 	 * Select device Aux1 (dev=7) to set GP16 as the watchdog output
97 	 * (in reg E6) and GP13 as the watchdog LED output (in reg E3).
98 	 * Map GP16 at pin 119.
99 	 * In test mode watch the bit 0 on F4 to indicate "triggered" or
100 	 * check watchdog LED on SBC.
101 	 */
102 	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
103 	outb_p(0x07, IO_DATA_PORT);
104 	if (!testmode) {
105 		unsigned pin_map;
106 
107 		outb_p(0xE6, IO_INDEX_PORT);
108 		outb_p(0x0A, IO_DATA_PORT);
109 		outb_p(0x2C, IO_INDEX_PORT);
110 		pin_map = inb_p(IO_DATA_PORT);
111 		pin_map |= 0x10;
112 		pin_map &= ~(0x20);
113 		outb_p(0x2C, IO_INDEX_PORT);
114 		outb_p(pin_map, IO_DATA_PORT);
115 	}
116 	outb_p(0xE3, IO_INDEX_PORT);
117 	outb_p(0x08, IO_DATA_PORT);
118 
119 	/* Set device Aux1 active */
120 	outb_p(0x30, IO_INDEX_PORT);
121 	outb_p(0x01, IO_DATA_PORT);
122 
123 	/* Lock the SuperIO chip */
124 	outb_p(LOCK_DATA, IO_INDEX_PORT);
125 
126 	spin_unlock_irqrestore(&spinlock, flags);
127 
128 	pr_info("activated\n");
129 
130 	return 0;
131 }
132 
133 /*
134  * Stop the watchdog
135  */
136 
wdt_stop(void)137 static int wdt_stop(void)
138 {
139 	unsigned long flags;
140 
141 	spin_lock_irqsave(&spinlock, flags);
142 
143 	/* Unlock the SuperIO chip */
144 	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
145 	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
146 
147 	/*
148 	 * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4.
149 	 * F2 is reset to its default value (watchdog timer disabled).
150 	 * F3 is reset to its default state.
151 	 * F4 clears the TIMEOUT'ed state (bit 0) - back to default.
152 	 */
153 	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
154 	outb_p(0x08, IO_DATA_PORT);
155 	outb_p(0xF2, IO_INDEX_PORT);
156 	outb_p(0xFF, IO_DATA_PORT);
157 	outb_p(0xF3, IO_INDEX_PORT);
158 	outb_p(0x00, IO_DATA_PORT);
159 	outb_p(0xF4, IO_INDEX_PORT);
160 	outb_p(0x00, IO_DATA_PORT);
161 	outb_p(0xF2, IO_INDEX_PORT);
162 	outb_p(0x00, IO_DATA_PORT);
163 
164 	/*
165 	 * Select device Aux1 (dev=7) to set GP16 (in reg E6) and
166 	 * Gp13 (in reg E3) as inputs.
167 	 */
168 	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
169 	outb_p(0x07, IO_DATA_PORT);
170 	if (!testmode) {
171 		outb_p(0xE6, IO_INDEX_PORT);
172 		outb_p(0x01, IO_DATA_PORT);
173 	}
174 	outb_p(0xE3, IO_INDEX_PORT);
175 	outb_p(0x01, IO_DATA_PORT);
176 
177 	/* Lock the SuperIO chip */
178 	outb_p(LOCK_DATA, IO_INDEX_PORT);
179 
180 	spin_unlock_irqrestore(&spinlock, flags);
181 
182 	pr_info("shutdown\n");
183 
184 	return 0;
185 }
186 
187 /*
188  * Send a keepalive ping to the watchdog
189  * This is done by simply re-writing the timeout to reg. 0xF2
190  */
191 
wdt_keepalive(void)192 static int wdt_keepalive(void)
193 {
194 	unsigned long flags;
195 
196 	spin_lock_irqsave(&spinlock, flags);
197 
198 	/* Unlock the SuperIO chip */
199 	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
200 	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
201 
202 	/* Select device Aux2 (device=8) to kick watchdog reg F2 */
203 	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
204 	outb_p(0x08, IO_DATA_PORT);
205 	outb_p(0xF2, IO_INDEX_PORT);
206 	outb_p(timeoutW, IO_DATA_PORT);
207 
208 	/* Lock the SuperIO chip */
209 	outb_p(LOCK_DATA, IO_INDEX_PORT);
210 
211 	spin_unlock_irqrestore(&spinlock, flags);
212 
213 	return 0;
214 }
215 
216 /*
217  * Set the watchdog timeout value
218  */
219 
wdt_set_timeout(int t)220 static int wdt_set_timeout(int t)
221 {
222 	unsigned int tmrval;
223 
224 	/*
225 	 * Convert seconds to watchdog counter time units, rounding up.
226 	 * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup
227 	 * value. This information is supplied in the PCM-5335 manual and was
228 	 * checked by me on a real board. This is a bit strange because W83977f
229 	 * datasheet says counter unit is in minutes!
230 	 */
231 	if (t < 15)
232 		return -EINVAL;
233 
234 	tmrval = ((t + 15) + 29) / 30;
235 
236 	if (tmrval > 255)
237 		return -EINVAL;
238 
239 	/*
240 	 * timeout is the timeout in seconds,
241 	 * timeoutW is the timeout in watchdog counter units.
242 	 */
243 	timeoutW = tmrval;
244 	timeout = (timeoutW * 30) - 15;
245 	return 0;
246 }
247 
248 /*
249  * Get the watchdog status
250  */
251 
wdt_get_status(int * status)252 static int wdt_get_status(int *status)
253 {
254 	int new_status;
255 	unsigned long flags;
256 
257 	spin_lock_irqsave(&spinlock, flags);
258 
259 	/* Unlock the SuperIO chip */
260 	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
261 	outb_p(UNLOCK_DATA, IO_INDEX_PORT);
262 
263 	/* Select device Aux2 (device=8) to read watchdog reg F4 */
264 	outb_p(DEVICE_REGISTER, IO_INDEX_PORT);
265 	outb_p(0x08, IO_DATA_PORT);
266 	outb_p(0xF4, IO_INDEX_PORT);
267 	new_status = inb_p(IO_DATA_PORT);
268 
269 	/* Lock the SuperIO chip */
270 	outb_p(LOCK_DATA, IO_INDEX_PORT);
271 
272 	spin_unlock_irqrestore(&spinlock, flags);
273 
274 	*status = 0;
275 	if (new_status & 1)
276 		*status |= WDIOF_CARDRESET;
277 
278 	return 0;
279 }
280 
281 
282 /*
283  *	/dev/watchdog handling
284  */
285 
wdt_open(struct inode * inode,struct file * file)286 static int wdt_open(struct inode *inode, struct file *file)
287 {
288 	/* If the watchdog is alive we don't need to start it again */
289 	if (test_and_set_bit(0, &timer_alive))
290 		return -EBUSY;
291 
292 	if (nowayout)
293 		__module_get(THIS_MODULE);
294 
295 	wdt_start();
296 	return stream_open(inode, file);
297 }
298 
wdt_release(struct inode * inode,struct file * file)299 static int wdt_release(struct inode *inode, struct file *file)
300 {
301 	/*
302 	 * Shut off the timer.
303 	 * Lock it in if it's a module and we set nowayout
304 	 */
305 	if (expect_close == 42) {
306 		wdt_stop();
307 		clear_bit(0, &timer_alive);
308 	} else {
309 		wdt_keepalive();
310 		pr_crit("unexpected close, not stopping watchdog!\n");
311 	}
312 	expect_close = 0;
313 	return 0;
314 }
315 
316 /*
317  *      wdt_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 
wdt_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)327 static ssize_t wdt_write(struct file *file, const char __user *buf,
328 			    size_t count, loff_t *ppos)
329 {
330 	/* See if we got the magic character 'V' and reload the timer */
331 	if (count) {
332 		if (!nowayout) {
333 			size_t ofs;
334 
335 			/* note: just in case someone wrote the
336 			   magic character long ago */
337 			expect_close = 0;
338 
339 			/* scan to see whether or not we got the
340 			   magic character */
341 			for (ofs = 0; ofs != count; ofs++) {
342 				char c;
343 				if (get_user(c, buf + ofs))
344 					return -EFAULT;
345 				if (c == 'V')
346 					expect_close = 42;
347 			}
348 		}
349 
350 		/* someone wrote to us, we should restart timer */
351 		wdt_keepalive();
352 	}
353 	return count;
354 }
355 
356 /*
357  *      wdt_ioctl:
358  *      @inode: inode of the device
359  *      @file: file handle to the device
360  *      @cmd: watchdog command
361  *      @arg: argument pointer
362  *
363  *      The watchdog API defines a common set of functions for all watchdogs
364  *      according to their available features.
365  */
366 
367 static const struct watchdog_info ident = {
368 	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
369 	.firmware_version =	1,
370 	.identity = WATCHDOG_NAME,
371 };
372 
wdt_ioctl(struct file * file,unsigned int cmd,unsigned long arg)373 static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
374 {
375 	int status;
376 	int new_options, retval = -EINVAL;
377 	int new_timeout;
378 	union {
379 		struct watchdog_info __user *ident;
380 		int __user *i;
381 	} uarg;
382 
383 	uarg.i = (int __user *)arg;
384 
385 	switch (cmd) {
386 	case WDIOC_GETSUPPORT:
387 		return copy_to_user(uarg.ident, &ident,
388 						sizeof(ident)) ? -EFAULT : 0;
389 
390 	case WDIOC_GETSTATUS:
391 		wdt_get_status(&status);
392 		return put_user(status, uarg.i);
393 
394 	case WDIOC_GETBOOTSTATUS:
395 		return put_user(0, uarg.i);
396 
397 	case WDIOC_SETOPTIONS:
398 		if (get_user(new_options, uarg.i))
399 			return -EFAULT;
400 
401 		if (new_options & WDIOS_DISABLECARD) {
402 			wdt_stop();
403 			retval = 0;
404 		}
405 
406 		if (new_options & WDIOS_ENABLECARD) {
407 			wdt_start();
408 			retval = 0;
409 		}
410 
411 		return retval;
412 
413 	case WDIOC_KEEPALIVE:
414 		wdt_keepalive();
415 		return 0;
416 
417 	case WDIOC_SETTIMEOUT:
418 		if (get_user(new_timeout, uarg.i))
419 			return -EFAULT;
420 
421 		if (wdt_set_timeout(new_timeout))
422 			return -EINVAL;
423 
424 		wdt_keepalive();
425 		/* Fall through */
426 
427 	case WDIOC_GETTIMEOUT:
428 		return put_user(timeout, uarg.i);
429 
430 	default:
431 		return -ENOTTY;
432 
433 	}
434 }
435 
wdt_notify_sys(struct notifier_block * this,unsigned long code,void * unused)436 static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
437 	void *unused)
438 {
439 	if (code == SYS_DOWN || code == SYS_HALT)
440 		wdt_stop();
441 	return NOTIFY_DONE;
442 }
443 
444 static const struct file_operations wdt_fops = {
445 	.owner		= THIS_MODULE,
446 	.llseek		= no_llseek,
447 	.write		= wdt_write,
448 	.unlocked_ioctl	= wdt_ioctl,
449 	.open		= wdt_open,
450 	.release	= wdt_release,
451 };
452 
453 static struct miscdevice wdt_miscdev = {
454 	.minor		= WATCHDOG_MINOR,
455 	.name		= "watchdog",
456 	.fops		= &wdt_fops,
457 };
458 
459 static struct notifier_block wdt_notifier = {
460 	.notifier_call = wdt_notify_sys,
461 };
462 
w83977f_wdt_init(void)463 static int __init w83977f_wdt_init(void)
464 {
465 	int rc;
466 
467 	pr_info("driver v%s\n", WATCHDOG_VERSION);
468 
469 	/*
470 	 * Check that the timeout value is within it's range;
471 	 * if not reset to the default
472 	 */
473 	if (wdt_set_timeout(timeout)) {
474 		wdt_set_timeout(DEFAULT_TIMEOUT);
475 		pr_info("timeout value must be 15 <= timeout <= 7635, using %d\n",
476 			DEFAULT_TIMEOUT);
477 	}
478 
479 	if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) {
480 		pr_err("I/O address 0x%04x already in use\n", IO_INDEX_PORT);
481 		rc = -EIO;
482 		goto err_out;
483 	}
484 
485 	rc = register_reboot_notifier(&wdt_notifier);
486 	if (rc) {
487 		pr_err("cannot register reboot notifier (err=%d)\n", rc);
488 		goto err_out_region;
489 	}
490 
491 	rc = misc_register(&wdt_miscdev);
492 	if (rc) {
493 		pr_err("cannot register miscdev on minor=%d (err=%d)\n",
494 		       wdt_miscdev.minor, rc);
495 		goto err_out_reboot;
496 	}
497 
498 	pr_info("initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",
499 		timeout, nowayout, testmode);
500 
501 	return 0;
502 
503 err_out_reboot:
504 	unregister_reboot_notifier(&wdt_notifier);
505 err_out_region:
506 	release_region(IO_INDEX_PORT, 2);
507 err_out:
508 	return rc;
509 }
510 
w83977f_wdt_exit(void)511 static void __exit w83977f_wdt_exit(void)
512 {
513 	wdt_stop();
514 	misc_deregister(&wdt_miscdev);
515 	unregister_reboot_notifier(&wdt_notifier);
516 	release_region(IO_INDEX_PORT, 2);
517 }
518 
519 module_init(w83977f_wdt_init);
520 module_exit(w83977f_wdt_exit);
521 
522 MODULE_AUTHOR("Jose Goncalves <jose.goncalves@inov.pt>");
523 MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip");
524 MODULE_LICENSE("GPL");
525