1 /*
2  * Blackfin On-Chip Watchdog Driver
3  *
4  * Originally based on softdog.c
5  * Copyright 2006-2010 Analog Devices Inc.
6  * Copyright 2006-2007 Michele d'Amico
7  * Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>
8  *
9  * Enter bugs at http://blackfin.uclinux.org/
10  *
11  * Licensed under the GPL-2 or later.
12  */
13 
14 #include <linux/platform_device.h>
15 #include <linux/module.h>
16 #include <linux/moduleparam.h>
17 #include <linux/types.h>
18 #include <linux/timer.h>
19 #include <linux/miscdevice.h>
20 #include <linux/watchdog.h>
21 #include <linux/fs.h>
22 #include <linux/init.h>
23 #include <linux/interrupt.h>
24 #include <linux/uaccess.h>
25 #include <asm/blackfin.h>
26 #include <asm/bfin_watchdog.h>
27 
28 #define stamp(fmt, args...) \
29 	pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
30 #define stampit() stamp("here i am")
31 #define pr_devinit(fmt, args...) \
32 	({ static const __devinitconst char __fmt[] = fmt; \
33 	printk(__fmt, ## args); })
34 #define pr_init(fmt, args...) \
35 	({ static const __initconst char __fmt[] = fmt; \
36 	printk(__fmt, ## args); })
37 
38 #define WATCHDOG_NAME "bfin-wdt"
39 #define PFX WATCHDOG_NAME ": "
40 
41 /* The BF561 has two watchdogs (one per core), but since Linux
42  * only runs on core A, we'll just work with that one.
43  */
44 #ifdef BF561_FAMILY
45 # define bfin_read_WDOG_CTL()    bfin_read_WDOGA_CTL()
46 # define bfin_read_WDOG_CNT()    bfin_read_WDOGA_CNT()
47 # define bfin_read_WDOG_STAT()   bfin_read_WDOGA_STAT()
48 # define bfin_write_WDOG_CTL(x)  bfin_write_WDOGA_CTL(x)
49 # define bfin_write_WDOG_CNT(x)  bfin_write_WDOGA_CNT(x)
50 # define bfin_write_WDOG_STAT(x) bfin_write_WDOGA_STAT(x)
51 #endif
52 
53 /* some defaults */
54 #define WATCHDOG_TIMEOUT 20
55 
56 static unsigned int timeout = WATCHDOG_TIMEOUT;
57 static int nowayout = WATCHDOG_NOWAYOUT;
58 static const struct watchdog_info bfin_wdt_info;
59 static unsigned long open_check;
60 static char expect_close;
61 static DEFINE_SPINLOCK(bfin_wdt_spinlock);
62 
63 /**
64  *	bfin_wdt_keepalive - Keep the Userspace Watchdog Alive
65  *
66  *	The Userspace watchdog got a KeepAlive: schedule the next timeout.
67  */
bfin_wdt_keepalive(void)68 static int bfin_wdt_keepalive(void)
69 {
70 	stampit();
71 	bfin_write_WDOG_STAT(0);
72 	return 0;
73 }
74 
75 /**
76  *	bfin_wdt_stop - Stop the Watchdog
77  *
78  *	Stops the on-chip watchdog.
79  */
bfin_wdt_stop(void)80 static int bfin_wdt_stop(void)
81 {
82 	stampit();
83 	bfin_write_WDOG_CTL(WDEN_DISABLE);
84 	return 0;
85 }
86 
87 /**
88  *	bfin_wdt_start - Start the Watchdog
89  *
90  *	Starts the on-chip watchdog.  Automatically loads WDOG_CNT
91  *	into WDOG_STAT for us.
92  */
bfin_wdt_start(void)93 static int bfin_wdt_start(void)
94 {
95 	stampit();
96 	bfin_write_WDOG_CTL(WDEN_ENABLE | ICTL_RESET);
97 	return 0;
98 }
99 
100 /**
101  *	bfin_wdt_running - Check Watchdog status
102  *
103  *	See if the watchdog is running.
104  */
bfin_wdt_running(void)105 static int bfin_wdt_running(void)
106 {
107 	stampit();
108 	return ((bfin_read_WDOG_CTL() & WDEN_MASK) != WDEN_DISABLE);
109 }
110 
111 /**
112  *	bfin_wdt_set_timeout - Set the Userspace Watchdog timeout
113  *	@t: new timeout value (in seconds)
114  *
115  *	Translate the specified timeout in seconds into System Clock
116  *	terms which is what the on-chip Watchdog requires.
117  */
bfin_wdt_set_timeout(unsigned long t)118 static int bfin_wdt_set_timeout(unsigned long t)
119 {
120 	u32 cnt, max_t, sclk;
121 	unsigned long flags;
122 
123 	sclk = get_sclk();
124 	max_t = -1 / sclk;
125 	cnt = t * sclk;
126 	stamp("maxtimeout=%us newtimeout=%lus (cnt=%#x)", max_t, t, cnt);
127 
128 	if (t > max_t) {
129 		printk(KERN_WARNING PFX "timeout value is too large\n");
130 		return -EINVAL;
131 	}
132 
133 	spin_lock_irqsave(&bfin_wdt_spinlock, flags);
134 	{
135 		int run = bfin_wdt_running();
136 		bfin_wdt_stop();
137 		bfin_write_WDOG_CNT(cnt);
138 		if (run)
139 			bfin_wdt_start();
140 	}
141 	spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
142 
143 	timeout = t;
144 
145 	return 0;
146 }
147 
148 /**
149  *	bfin_wdt_open - Open the Device
150  *	@inode: inode of device
151  *	@file: file handle of device
152  *
153  *	Watchdog device is opened and started.
154  */
bfin_wdt_open(struct inode * inode,struct file * file)155 static int bfin_wdt_open(struct inode *inode, struct file *file)
156 {
157 	stampit();
158 
159 	if (test_and_set_bit(0, &open_check))
160 		return -EBUSY;
161 
162 	if (nowayout)
163 		__module_get(THIS_MODULE);
164 
165 	bfin_wdt_keepalive();
166 	bfin_wdt_start();
167 
168 	return nonseekable_open(inode, file);
169 }
170 
171 /**
172  *	bfin_wdt_close - Close the Device
173  *	@inode: inode of device
174  *	@file: file handle of device
175  *
176  *	Watchdog device is closed and stopped.
177  */
bfin_wdt_release(struct inode * inode,struct file * file)178 static int bfin_wdt_release(struct inode *inode, struct file *file)
179 {
180 	stampit();
181 
182 	if (expect_close == 42)
183 		bfin_wdt_stop();
184 	else {
185 		printk(KERN_CRIT PFX
186 			"Unexpected close, not stopping watchdog!\n");
187 		bfin_wdt_keepalive();
188 	}
189 	expect_close = 0;
190 	clear_bit(0, &open_check);
191 	return 0;
192 }
193 
194 /**
195  *	bfin_wdt_write - Write to Device
196  *	@file: file handle of device
197  *	@buf: buffer to write
198  *	@count: length of buffer
199  *	@ppos: offset
200  *
201  *	Pings the watchdog on write.
202  */
bfin_wdt_write(struct file * file,const char __user * data,size_t len,loff_t * ppos)203 static ssize_t bfin_wdt_write(struct file *file, const char __user *data,
204 						size_t len, loff_t *ppos)
205 {
206 	stampit();
207 
208 	if (len) {
209 		if (!nowayout) {
210 			size_t i;
211 
212 			/* In case it was set long ago */
213 			expect_close = 0;
214 
215 			for (i = 0; i != len; i++) {
216 				char c;
217 				if (get_user(c, data + i))
218 					return -EFAULT;
219 				if (c == 'V')
220 					expect_close = 42;
221 			}
222 		}
223 		bfin_wdt_keepalive();
224 	}
225 
226 	return len;
227 }
228 
229 /**
230  *	bfin_wdt_ioctl - Query Device
231  *	@file: file handle of device
232  *	@cmd: watchdog command
233  *	@arg: argument
234  *
235  *	Query basic information from the device or ping it, as outlined by the
236  *	watchdog API.
237  */
bfin_wdt_ioctl(struct file * file,unsigned int cmd,unsigned long arg)238 static long bfin_wdt_ioctl(struct file *file,
239 				unsigned int cmd, unsigned long arg)
240 {
241 	void __user *argp = (void __user *)arg;
242 	int __user *p = argp;
243 
244 	stampit();
245 
246 	switch (cmd) {
247 	case WDIOC_GETSUPPORT:
248 		if (copy_to_user(argp, &bfin_wdt_info, sizeof(bfin_wdt_info)))
249 			return -EFAULT;
250 		else
251 			return 0;
252 	case WDIOC_GETSTATUS:
253 	case WDIOC_GETBOOTSTATUS:
254 		return put_user(!!(_bfin_swrst & SWRST_RESET_WDOG), p);
255 	case WDIOC_SETOPTIONS: {
256 		unsigned long flags;
257 		int options, ret = -EINVAL;
258 
259 		if (get_user(options, p))
260 			return -EFAULT;
261 
262 		spin_lock_irqsave(&bfin_wdt_spinlock, flags);
263 		if (options & WDIOS_DISABLECARD) {
264 			bfin_wdt_stop();
265 			ret = 0;
266 		}
267 		if (options & WDIOS_ENABLECARD) {
268 			bfin_wdt_start();
269 			ret = 0;
270 		}
271 		spin_unlock_irqrestore(&bfin_wdt_spinlock, flags);
272 		return ret;
273 	}
274 	case WDIOC_KEEPALIVE:
275 		bfin_wdt_keepalive();
276 		return 0;
277 	case WDIOC_SETTIMEOUT: {
278 		int new_timeout;
279 
280 		if (get_user(new_timeout, p))
281 			return -EFAULT;
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 	default:
289 		return -ENOTTY;
290 	}
291 }
292 
293 #ifdef CONFIG_PM
294 static int state_before_suspend;
295 
296 /**
297  *	bfin_wdt_suspend - suspend the watchdog
298  *	@pdev: device being suspended
299  *	@state: requested suspend state
300  *
301  *	Remember if the watchdog was running and stop it.
302  *	TODO: is this even right?  Doesn't seem to be any
303  *	      standard in the watchdog world ...
304  */
bfin_wdt_suspend(struct platform_device * pdev,pm_message_t state)305 static int bfin_wdt_suspend(struct platform_device *pdev, pm_message_t state)
306 {
307 	stampit();
308 
309 	state_before_suspend = bfin_wdt_running();
310 	bfin_wdt_stop();
311 
312 	return 0;
313 }
314 
315 /**
316  *	bfin_wdt_resume - resume the watchdog
317  *	@pdev: device being resumed
318  *
319  *	If the watchdog was running, turn it back on.
320  */
bfin_wdt_resume(struct platform_device * pdev)321 static int bfin_wdt_resume(struct platform_device *pdev)
322 {
323 	stampit();
324 
325 	if (state_before_suspend) {
326 		bfin_wdt_set_timeout(timeout);
327 		bfin_wdt_start();
328 	}
329 
330 	return 0;
331 }
332 #else
333 # define bfin_wdt_suspend NULL
334 # define bfin_wdt_resume NULL
335 #endif
336 
337 static const struct file_operations bfin_wdt_fops = {
338 	.owner		= THIS_MODULE,
339 	.llseek		= no_llseek,
340 	.write		= bfin_wdt_write,
341 	.unlocked_ioctl	= bfin_wdt_ioctl,
342 	.open		= bfin_wdt_open,
343 	.release	= bfin_wdt_release,
344 };
345 
346 static struct miscdevice bfin_wdt_miscdev = {
347 	.minor    = WATCHDOG_MINOR,
348 	.name     = "watchdog",
349 	.fops     = &bfin_wdt_fops,
350 };
351 
352 static const struct watchdog_info bfin_wdt_info = {
353 	.identity = "Blackfin Watchdog",
354 	.options  = WDIOF_SETTIMEOUT |
355 		    WDIOF_KEEPALIVEPING |
356 		    WDIOF_MAGICCLOSE,
357 };
358 
359 /**
360  *	bfin_wdt_probe - Initialize module
361  *
362  *	Registers the misc device.  Actual device
363  *	initialization is handled by bfin_wdt_open().
364  */
bfin_wdt_probe(struct platform_device * pdev)365 static int __devinit bfin_wdt_probe(struct platform_device *pdev)
366 {
367 	int ret;
368 
369 	ret = misc_register(&bfin_wdt_miscdev);
370 	if (ret) {
371 		pr_devinit(KERN_ERR PFX
372 			"cannot register miscdev on minor=%d (err=%d)\n",
373 				WATCHDOG_MINOR, ret);
374 		return ret;
375 	}
376 
377 	pr_devinit(KERN_INFO PFX "initialized: timeout=%d sec (nowayout=%d)\n",
378 	       timeout, nowayout);
379 
380 	return 0;
381 }
382 
383 /**
384  *	bfin_wdt_remove - Initialize module
385  *
386  *	Unregisters the misc device.  Actual device
387  *	deinitialization is handled by bfin_wdt_close().
388  */
bfin_wdt_remove(struct platform_device * pdev)389 static int __devexit bfin_wdt_remove(struct platform_device *pdev)
390 {
391 	misc_deregister(&bfin_wdt_miscdev);
392 	return 0;
393 }
394 
395 /**
396  *	bfin_wdt_shutdown - Soft Shutdown Handler
397  *
398  *	Handles the soft shutdown event.
399  */
bfin_wdt_shutdown(struct platform_device * pdev)400 static void bfin_wdt_shutdown(struct platform_device *pdev)
401 {
402 	stampit();
403 
404 	bfin_wdt_stop();
405 }
406 
407 static struct platform_device *bfin_wdt_device;
408 
409 static struct platform_driver bfin_wdt_driver = {
410 	.probe     = bfin_wdt_probe,
411 	.remove    = __devexit_p(bfin_wdt_remove),
412 	.shutdown  = bfin_wdt_shutdown,
413 	.suspend   = bfin_wdt_suspend,
414 	.resume    = bfin_wdt_resume,
415 	.driver    = {
416 		.name  = WATCHDOG_NAME,
417 		.owner = THIS_MODULE,
418 	},
419 };
420 
421 /**
422  *	bfin_wdt_init - Initialize module
423  *
424  *	Checks the module params and registers the platform device & driver.
425  *	Real work is in the platform probe function.
426  */
bfin_wdt_init(void)427 static int __init bfin_wdt_init(void)
428 {
429 	int ret;
430 
431 	stampit();
432 
433 	/* Check that the timeout value is within range */
434 	if (bfin_wdt_set_timeout(timeout))
435 		return -EINVAL;
436 
437 	/* Since this is an on-chip device and needs no board-specific
438 	 * resources, we'll handle all the platform device stuff here.
439 	 */
440 	ret = platform_driver_register(&bfin_wdt_driver);
441 	if (ret) {
442 		pr_init(KERN_ERR PFX "unable to register driver\n");
443 		return ret;
444 	}
445 
446 	bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME,
447 								-1, NULL, 0);
448 	if (IS_ERR(bfin_wdt_device)) {
449 		pr_init(KERN_ERR PFX "unable to register device\n");
450 		platform_driver_unregister(&bfin_wdt_driver);
451 		return PTR_ERR(bfin_wdt_device);
452 	}
453 
454 	return 0;
455 }
456 
457 /**
458  *	bfin_wdt_exit - Deinitialize module
459  *
460  *	Back out the platform device & driver steps.  Real work is in the
461  *	platform remove function.
462  */
bfin_wdt_exit(void)463 static void __exit bfin_wdt_exit(void)
464 {
465 	platform_device_unregister(bfin_wdt_device);
466 	platform_driver_unregister(&bfin_wdt_driver);
467 }
468 
469 module_init(bfin_wdt_init);
470 module_exit(bfin_wdt_exit);
471 
472 MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>");
473 MODULE_DESCRIPTION("Blackfin Watchdog Device Driver");
474 MODULE_LICENSE("GPL");
475 MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
476 
477 module_param(timeout, uint, 0);
478 MODULE_PARM_DESC(timeout,
479 	"Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default="
480 		__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
481 
482 module_param(nowayout, int, 0);
483 MODULE_PARM_DESC(nowayout,
484 	"Watchdog cannot be stopped once started (default="
485 		__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
486