static void rc32434_wdt_start(void) { u32 or, nand; spin_lock(&rc32434_wdt_device.io_lock); /* zero the counter before enabling */ writel(0, &wdt_reg->wtcount); /* don't generate a non-maskable interrupt, * do a warm reset instead */ nand = 1 << RC32434_ERR_WNE; or = 1 << RC32434_ERR_WRE; /* reset the ERRCS timeout bit in case it's set */ nand |= 1 << RC32434_ERR_WTO; SET_BITS(wdt_reg->errcs, or, nand); /* set the timeout (either default or based on module param) */ rc32434_wdt_set(timeout); /* reset WTC timeout bit and enable WDT */ nand = 1 << RC32434_WTC_TO; or = 1 << RC32434_WTC_EN; SET_BITS(wdt_reg->wtc, or, nand); spin_unlock(&rc32434_wdt_device.io_lock); pr_info("Started watchdog timer\n"); }
static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; int new_timeout; unsigned int value; static const struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .identity = "RC32434_WDT Watchdog", }; switch (cmd) { case WDIOC_GETSUPPORT: if (copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; break; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: value = 0; if (copy_to_user(argp, &value, sizeof(int))) return -EFAULT; break; case WDIOC_SETOPTIONS: if (copy_from_user(&value, argp, sizeof(int))) return -EFAULT; switch (value) { case WDIOS_ENABLECARD: rc32434_wdt_start(); break; case WDIOS_DISABLECARD: rc32434_wdt_stop(); break; default: return -EINVAL; } break; case WDIOC_KEEPALIVE: rc32434_wdt_ping(); break; case WDIOC_SETTIMEOUT: if (copy_from_user(&new_timeout, argp, sizeof(int))) return -EFAULT; if (rc32434_wdt_set(new_timeout)) return -EINVAL; /* Fall through */ case WDIOC_GETTIMEOUT: return copy_to_user(argp, &timeout, sizeof(int)); default: return -ENOTTY; } return 0; } static const struct file_operations rc32434_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = rc32434_wdt_write, .unlocked_ioctl = rc32434_wdt_ioctl, .open = rc32434_wdt_open, .release = rc32434_wdt_release, }; static struct miscdevice rc32434_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &rc32434_wdt_fops, }; static int __devinit rc32434_wdt_probe(struct platform_device *pdev) { int ret; struct resource *r; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb532_wdt_res"); if (!r) { pr_err("failed to retrieve resources\n"); return -ENODEV; } wdt_reg = ioremap_nocache(r->start, resource_size(r)); if (!wdt_reg) { pr_err("failed to remap I/O resources\n"); return -ENXIO; } spin_lock_init(&rc32434_wdt_device.io_lock); /* Make sure the watchdog is not running */ rc32434_wdt_stop(); /* Check that the heartbeat value is within it's range; * if not reset to the default */ if (rc32434_wdt_set(timeout)) { rc32434_wdt_set(WATCHDOG_TIMEOUT); pr_info("timeout value must be between 0 and %d\n", WTCOMP2SEC((u32)-1)); } ret = misc_register(&rc32434_wdt_miscdev); if (ret < 0) { pr_err("failed to register watchdog device\n"); goto unmap; } pr_info("Watchdog Timer version " VERSION ", timer margin: %d sec\n", timeout); return 0; unmap: iounmap(wdt_reg); return ret; } static int __devexit rc32434_wdt_remove(struct platform_device *pdev) { misc_deregister(&rc32434_wdt_miscdev); iounmap(wdt_reg); return 0; }
static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; int new_timeout; unsigned int value; static struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .identity = "RC32434_WDT Watchdog", }; switch (cmd) { case WDIOC_KEEPALIVE: rc32434_wdt_reset(); break; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: value = readl(&wdt_reg->wtcount); if (copy_to_user(argp, &value, sizeof(int))) return -EFAULT; break; case WDIOC_GETSUPPORT: if (copy_to_user(argp, &ident, sizeof(ident))) return -EFAULT; break; case WDIOC_SETOPTIONS: if (copy_from_user(&value, argp, sizeof(int))) return -EFAULT; switch (value) { case WDIOS_ENABLECARD: rc32434_wdt_start(); break; case WDIOS_DISABLECARD: rc32434_wdt_stop(); default: return -EINVAL; } break; case WDIOC_SETTIMEOUT: if (copy_from_user(&new_timeout, argp, sizeof(int))) return -EFAULT; if (new_timeout < 1) return -EINVAL; if (new_timeout > MAX_TIMEOUT) return -EINVAL; rc32434_wdt_set(new_timeout); case WDIOC_GETTIMEOUT: return copy_to_user(argp, &timeout, sizeof(int)); default: return -ENOTTY; } return 0; } static struct file_operations rc32434_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = rc32434_wdt_write, .unlocked_ioctl = rc32434_wdt_ioctl, .open = rc32434_wdt_open, .release = rc32434_wdt_release, }; static struct miscdevice rc32434_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &rc32434_wdt_fops, }; static char banner[] = KERN_INFO KBUILD_MODNAME ": Watchdog Timer version " VERSION ", timer margin: %d sec\n"; static int rc32434_wdt_probe(struct platform_device *pdev) { int ret; struct resource *r; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb500_wdt_res"); if (!r) { printk(KERN_ERR KBUILD_MODNAME "failed to retrieve resources\n"); return -ENODEV; } wdt_reg = ioremap_nocache(r->start, r->end - r->start); if (!wdt_reg) { printk(KERN_ERR KBUILD_MODNAME "failed to remap I/O resources\n"); return -ENXIO; } ret = misc_register(&rc32434_wdt_miscdev); if (ret < 0) { printk(KERN_ERR KBUILD_MODNAME "failed to register watchdog device\n"); goto unmap; } init_completion(&rc32434_wdt_device.stop); rc32434_wdt_device.queue = 0; clear_bit(0, &rc32434_wdt_device.inuse); setup_timer(&rc32434_wdt_device.timer, rc32434_wdt_update, 0L); rc32434_wdt_device.default_ticks = ticks; rc32434_wdt_start(); printk(banner, timeout); return 0; unmap: iounmap(wdt_reg); return ret; } static int rc32434_wdt_remove(struct platform_device *pdev) { if (rc32434_wdt_device.queue) { rc32434_wdt_device.queue = 0; wait_for_completion(&rc32434_wdt_device.stop); } misc_deregister(&rc32434_wdt_miscdev); iounmap(wdt_reg); return 0; } static struct platform_driver rc32434_wdt = { .probe = rc32434_wdt_probe, .remove = rc32434_wdt_remove, .driver = { .name = "rc32434_wdt", } }; static int __init rc32434_wdt_init(void) { return platform_driver_register(&rc32434_wdt); } static void __exit rc32434_wdt_exit(void) { platform_driver_unregister(&rc32434_wdt); }