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