ssize_t dw_wdt_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset) { if (!len) return 0; if (!nowayout) { size_t i; dw_wdt.expect_close = 0; for (i = 0; i < len; ++i) { char c; if (get_user(c, buf + i)) return -EFAULT; if (c == 'V') { dw_wdt.expect_close = 1; break; } } } dw_wdt_set_next_heartbeat(); mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); return len; }
static int dw_wdt_set_top(unsigned top_s) { int i, top_val = DW_WDT_MAX_TOP; /* * Iterate over the timeout values until we find the closest match. We * always look for >=. */ for (i = 0; i <= DW_WDT_MAX_TOP; ++i) if (dw_wdt_top_in_seconds(i) >= top_s) { top_val = i; break; } /* * Set the new value in the watchdog. Some versions of dw_wdt * have have TOPINIT in the TIMEOUT_RANGE register (as per * CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1). On those we * effectively get a pat of the watchdog right here. */ writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); /* * Add an explicit pat to handle versions of the watchdog that * don't have TOPINIT. This won't hurt on versions that have * it. */ dw_wdt_keepalive(); dw_wdt_set_next_heartbeat(); return dw_wdt_top_in_seconds(top_val); }
static int dw_wdt_open(struct inode *inode, struct file *filp) { if (test_and_set_bit(0, &dw_wdt.in_use)) return -EBUSY; /* Make sure we don't get unloaded. */ __module_get(THIS_MODULE); spin_lock(&dw_wdt.lock); if (!dw_wdt_is_enabled()) { /* * The watchdog is not currently enabled. Set the timeout to * the maximum and then start it. */ dw_wdt_set_top(DW_WDT_MAX_TOP); writel(WDOG_CONTROL_REG_WDT_EN_MASK, dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); } dw_wdt_set_next_heartbeat(); spin_unlock(&dw_wdt.lock); return nonseekable_open(inode, filp); }
static int dw_wdt_set_top(unsigned top_s) { int i, top_val = DW_WDT_MAX_TOP; for (i = 0; i <= DW_WDT_MAX_TOP; ++i) if (dw_wdt_top_in_seconds(i) >= top_s) { top_val = i; break; } writel(top_val, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); dw_wdt_set_next_heartbeat(); return dw_wdt_top_in_seconds(top_val); }
static int __devinit dw_wdt_drv_probe(struct platform_device *pdev) { int ret; struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) return -EINVAL; if (!devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), "dw_wdt")) return -ENOMEM; dw_wdt.regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); if (!dw_wdt.regs) return -ENOMEM; dw_wdt.clk = clk_get(&pdev->dev, NULL); if (IS_ERR(dw_wdt.clk)) return PTR_ERR(dw_wdt.clk); ret = clk_enable(dw_wdt.clk); if (ret) goto out_put_clk; spin_lock_init(&dw_wdt.lock); ret = misc_register(&dw_wdt_miscdev); if (ret) goto out_disable_clk; dw_wdt_set_next_heartbeat(); setup_timer(&dw_wdt.timer, dw_wdt_ping, 0); mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); return 0; out_disable_clk: clk_disable(dw_wdt.clk); out_put_clk: clk_put(dw_wdt.clk); return ret; }
static int dw_wdt_open(struct inode *inode, struct file *filp) { if (test_and_set_bit(0, &dw_wdt.in_use)) return -EBUSY; __module_get(THIS_MODULE); spin_lock(&dw_wdt.lock); if (!dw_wdt_is_enabled()) { dw_wdt_set_top(DW_WDT_MAX_TOP); writel(WDOG_CONTROL_REG_WDT_EN_MASK, dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); } dw_wdt_set_next_heartbeat(); spin_unlock(&dw_wdt.lock); return nonseekable_open(inode, filp); }
static int dw_wdt_set_top(unsigned top_s) { int i, top_val = DW_WDT_MAX_TOP; /* * Iterate over the timeout values until we find the closest match. We * always look for >=. */ for (i = 0; i <= DW_WDT_MAX_TOP; ++i) if (dw_wdt_top_in_seconds(i) >= top_s) { top_val = i; break; } /* Set the new value in the watchdog. */ writel(top_val, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); dw_wdt_set_next_heartbeat(); return dw_wdt_top_in_seconds(top_val); }
static long dw_wdt_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { unsigned long val; int timeout; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &dw_wdt_ident, sizeof(dw_wdt_ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0, (int *)arg); case WDIOC_KEEPALIVE: dw_wdt_set_next_heartbeat(); return 0; case WDIOC_SETTIMEOUT: if (get_user(val, (int __user *)arg)) return -EFAULT; timeout = dw_wdt_set_top(val); return put_user(timeout , (int __user *)arg); case WDIOC_GETTIMEOUT: return put_user(dw_wdt_get_top(), (int __user *)arg); case WDIOC_GETTIMELEFT: if (get_user(val, (int __user *)arg)) return -EFAULT; return put_user(dw_wdt_time_left(), (int __user *)arg); default: return -ENOTTY; } }
static int dw_wdt_drv_probe(struct platform_device *pdev) { int ret; struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) return -EINVAL; dw_wdt.regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(dw_wdt.regs)) return PTR_ERR(dw_wdt.regs); dw_wdt.clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dw_wdt.clk)) return PTR_ERR(dw_wdt.clk); ret = clk_prepare_enable(dw_wdt.clk); if (ret) return ret; spin_lock_init(&dw_wdt.lock); ret = misc_register(&dw_wdt_miscdev); if (ret) goto out_disable_clk; dw_wdt_set_next_heartbeat(); setup_timer(&dw_wdt.timer, dw_wdt_ping, 0); mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); return 0; out_disable_clk: clk_disable_unprepare(dw_wdt.clk); return ret; }