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 51static unsigned int timeout = WATCHDOG_TIMEOUT; 52static bool nowayout = WATCHDOG_NOWAYOUT; 53static const struct watchdog_info bfin_wdt_info; 54static unsigned long open_check; 55static char expect_close; 56static 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 */ 63static 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 */ 75static 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 */ 88static 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 */ 100static 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 */ 113static 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 */ 150static 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 */ 173static 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 */ 197static 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 */ 232static 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 288static 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 */ 299static 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 */ 315static 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 331static 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 340static struct miscdevice bfin_wdt_miscdev = { 341 .minor = WATCHDOG_MINOR, 342 .name = "watchdog", 343 .fops = &bfin_wdt_fops, 344}; 345 346static 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 */ 359static int 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 */ 382static int 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 */ 393static void bfin_wdt_shutdown(struct platform_device *pdev) 394{ 395 stampit(); 396 397 bfin_wdt_stop(); 398} 399 400static struct platform_device *bfin_wdt_device; 401 402static struct platform_driver bfin_wdt_driver = { 403 .probe = bfin_wdt_probe, 404 .remove = 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 }, 411}; 412 413/** 414 * bfin_wdt_init - Initialize module 415 * 416 * Checks the module params and registers the platform device & driver. 417 * Real work is in the platform probe function. 418 */ 419static int __init bfin_wdt_init(void) 420{ 421 int ret; 422 423 stampit(); 424 425 /* Check that the timeout value is within range */ 426 if (bfin_wdt_set_timeout(timeout)) 427 return -EINVAL; 428 429 /* Since this is an on-chip device and needs no board-specific 430 * resources, we'll handle all the platform device stuff here. 431 */ 432 ret = platform_driver_register(&bfin_wdt_driver); 433 if (ret) { 434 pr_err("unable to register driver\n"); 435 return ret; 436 } 437 438 bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME, 439 -1, NULL, 0); 440 if (IS_ERR(bfin_wdt_device)) { 441 pr_err("unable to register device\n"); 442 platform_driver_unregister(&bfin_wdt_driver); 443 return PTR_ERR(bfin_wdt_device); 444 } 445 446 return 0; 447} 448 449/** 450 * bfin_wdt_exit - Deinitialize module 451 * 452 * Back out the platform device & driver steps. Real work is in the 453 * platform remove function. 454 */ 455static void __exit bfin_wdt_exit(void) 456{ 457 platform_device_unregister(bfin_wdt_device); 458 platform_driver_unregister(&bfin_wdt_driver); 459} 460 461module_init(bfin_wdt_init); 462module_exit(bfin_wdt_exit); 463 464MODULE_AUTHOR("Michele d'Amico, Mike Frysinger <vapier@gentoo.org>"); 465MODULE_DESCRIPTION("Blackfin Watchdog Device Driver"); 466MODULE_LICENSE("GPL"); 467 468module_param(timeout, uint, 0); 469MODULE_PARM_DESC(timeout, 470 "Watchdog timeout in seconds. (1<=timeout<=((2^32)/SCLK), default=" 471 __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); 472 473module_param(nowayout, bool, 0); 474MODULE_PARM_DESC(nowayout, 475 "Watchdog cannot be stopped once started (default=" 476 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 477