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 56static unsigned int timeout = WATCHDOG_TIMEOUT; 57static int nowayout = WATCHDOG_NOWAYOUT; 58static const struct watchdog_info bfin_wdt_info; 59static unsigned long open_check; 60static char expect_close; 61static 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 */ 68static 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 */ 80static 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 */ 93static 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 */ 105static 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 */ 118static 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 */ 155static 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 */ 178static 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 */ 203static 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 */ 238static 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 294static 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 */ 305static 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 */ 321static 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 337static 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 346static struct miscdevice bfin_wdt_miscdev = { 347 .minor = WATCHDOG_MINOR, 348 .name = "watchdog", 349 .fops = &bfin_wdt_fops, 350}; 351 352static 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 */ 365static 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 */ 389static 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 */ 400static void bfin_wdt_shutdown(struct platform_device *pdev) 401{ 402 stampit(); 403 404 bfin_wdt_stop(); 405} 406 407static struct platform_device *bfin_wdt_device; 408 409static 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 */ 427static 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 */ 463static void __exit bfin_wdt_exit(void) 464{ 465 platform_device_unregister(bfin_wdt_device); 466 platform_driver_unregister(&bfin_wdt_driver); 467} 468 469module_init(bfin_wdt_init); 470module_exit(bfin_wdt_exit); 471 472MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>"); 473MODULE_DESCRIPTION("Blackfin Watchdog Device Driver"); 474MODULE_LICENSE("GPL"); 475MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 476 477module_param(timeout, uint, 0); 478MODULE_PARM_DESC(timeout, 479 "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" 480 __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); 481 482module_param(nowayout, int, 0); 483MODULE_PARM_DESC(nowayout, 484 "Watchdog cannot be stopped once started (default=" 485 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 486