static int omap_wdt_release(struct inode *inode, struct file *file) { /* * Shut off the timer unless NOWAYOUT is defined. */ #ifndef CONFIG_WATCHDOG_NOWAYOUT omap_wdt_disable(); if (cpu_is_omap16xx()) { clk_disable(armwdt_ck); /* Disable the clock */ clk_put(armwdt_ck); armwdt_ck = NULL; } if (cpu_is_omap24xx()) { clk_disable(mpu_wdt_ick); /* Disable the clock */ clk_disable(mpu_wdt_fck); /* Disable the clock */ clk_put(mpu_wdt_ick); clk_put(mpu_wdt_fck); mpu_wdt_ick = NULL; mpu_wdt_fck = NULL; } #else printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n"); #endif omap_wdt_users = 0; return 0; }
static int omap_wdt_release(struct inode *inode, struct file *file) { struct omap_wdt_dev *wdev = file->private_data; void __iomem *base = wdev->base; /* * Shut off the timer unless NOWAYOUT is defined. */ #ifndef CONFIG_WATCHDOG_NOWAYOUT pm_runtime_get_sync(wdev->dev); omap_wdt_disable(wdev); /* Disable delay interrupt */ if (kernelpet && wdev->irq) __raw_writel(0x2, base + OMAP_WATCHDOG_WIRQENCLR); pm_runtime_put_sync(wdev->dev); #else printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n"); #endif wdev->omap_wdt_users = 0; return 0; }
static int omap_wdt_start(struct watchdog_device *wdog) { struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog); void __iomem *base = wdev->base; mutex_lock(&wdev->lock); wdev->omap_wdt_users = true; pm_runtime_get_sync(wdev->dev); /* * Make sure the watchdog is disabled. This is unfortunately required * because writing to various registers with the watchdog running has no * effect. */ omap_wdt_disable(wdev); /* initialize prescaler */ while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x01) cpu_relax(); writel_relaxed((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL); while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x01) cpu_relax(); omap_wdt_set_timer(wdev, wdog->timeout); omap_wdt_reload(wdev); /* trigger loading of new timeout value */ omap_wdt_enable(wdev); mutex_unlock(&wdev->lock); return 0; }
static void omap_wdt_shutdown(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) { pm_runtime_get_sync(wdev->dev); omap_wdt_disable(wdev); pm_runtime_put_sync(wdev->dev); } }
static void omap_wdt_shutdown(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); mutex_lock(&wdev->lock); if (wdev->omap_wdt_users) { omap_wdt_disable(wdev); pm_runtime_put_sync(wdev->dev); } mutex_unlock(&wdev->lock); }
static int omap_wdt_stop(struct watchdog_device *wdog) { struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); mutex_lock(&wdev->lock); omap_wdt_disable(wdev); pm_runtime_put_sync(wdev->dev); wdev->omap_wdt_users = false; mutex_unlock(&wdev->lock); return 0; }
static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); mutex_lock(&wdev->lock); if (wdev->omap_wdt_users) { omap_wdt_disable(wdev); pm_runtime_put_sync(wdev->dev); } mutex_unlock(&wdev->lock); return 0; }
static void disable_wdt(struct omap_wdt_dev *wdev) { void __iomem *base = wdev->base; is_wdt_enabled = WDT_DISABLE; pm_runtime_get_sync(wdev->dev); omap_wdt_disable(wdev); /* Disable delay interrupt */ if (kernelpet && wdev->irq) __raw_writel(0x2, base + OMAP_WATCHDOG_WIRQENCLR); pm_runtime_put_sync(wdev->dev); }
static int omap_wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout) { struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); mutex_lock(&wdev->lock); omap_wdt_disable(wdev); omap_wdt_set_timer(wdev, timeout); omap_wdt_enable(wdev); omap_wdt_reload(wdev); wdog->timeout = timeout; mutex_unlock(&wdev->lock); return 0; }
static int omap_wdt_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); #ifdef CONFIG_OMAP_WATCHDOG_CONTROL if (!is_wdt_enabled) return 0; #endif if (wdev->omap_wdt_users) { pm_runtime_get_sync(wdev->dev); omap_wdt_disable(wdev); pm_runtime_put_sync_suspend(wdev->dev); } return 0; }
static int omap_wdt_release(struct inode *inode, struct file *file) { struct omap_wdt_dev *wdev = file->private_data; #ifndef CONFIG_WATCHDOG_NOWAYOUT omap_wdt_disable(wdev); clk_disable(wdev->ick); clk_disable(wdev->fck); #else printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n"); #endif wdev->omap_wdt_users = 0; return 0; }
static int omap_wdt_stop(struct watchdog_device *wdog) { struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); void __iomem *base = wdev->base; mutex_lock(&wdev->lock); omap_wdt_disable(wdev); /* Disable delay interrupt */ if (kernelpet) { __raw_writel(0x0, base + OMAP_WATCHDOG_WIRQWAKEEN); __raw_writel(0x2, base + OMAP_WATCHDOG_WIRQENCLR); } pm_runtime_put_sync(wdev->dev); wdev->omap_wdt_users = false; mutex_unlock(&wdev->lock); return 0; }
static int omap_wdt_release(struct inode *inode, struct file *file) { struct omap_wdt_dev *wdev = file->private_data; /* * Shut off the timer unless NOWAYOUT is defined. */ #ifndef CONFIG_WATCHDOG_NOWAYOUT omap_wdt_disable(wdev); pm_runtime_put_sync(wdev->dev); #else printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n"); #endif wdev->omap_wdt_users = 0; return 0; }
static int omap_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int new_margin; static struct watchdog_info ident = { .identity = "OMAP Watchdog", .options = WDIOF_SETTIMEOUT, .firmware_version = 0, }; switch (cmd) { default: return -ENOTTY; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(ident)); case WDIOC_GETSTATUS: return put_user(0, (int __user *)arg); case WDIOC_GETBOOTSTATUS: if (cpu_is_omap16xx()) return put_user(omap_readw(ARM_SYSST), (int __user *)arg); if (cpu_is_omap24xx()) return put_user(omap_prcm_get_reset_sources(), (int __user *)arg); case WDIOC_KEEPALIVE: omap_wdt_ping(); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_margin, (int __user *)arg)) return -EFAULT; omap_wdt_adjust_timeout(new_margin); omap_wdt_disable(); omap_wdt_set_timeout(); omap_wdt_enable(); omap_wdt_ping(); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timer_margin, (int __user *)arg); } } static const struct file_operations omap_wdt_fops = { .owner = THIS_MODULE, .write = omap_wdt_write, .ioctl = omap_wdt_ioctl, .open = omap_wdt_open, .release = omap_wdt_release, }; static struct miscdevice omap_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &omap_wdt_fops }; static int __init omap_wdt_probe(struct platform_device *pdev) { struct resource *res, *mem; int ret; /* reserve static register mappings */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; mem = request_mem_region(res->start, res->end - res->start + 1, pdev->name); if (mem == NULL) return -EBUSY; platform_set_drvdata(pdev, mem); omap_wdt_users = 0; if (cpu_is_omap16xx()) { armwdt_ck = clk_get(&pdev->dev, "armwdt_ck"); if (IS_ERR(armwdt_ck)) { ret = PTR_ERR(armwdt_ck); armwdt_ck = NULL; goto fail; } } if (cpu_is_omap24xx()) { mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick"); if (IS_ERR(mpu_wdt_ick)) { ret = PTR_ERR(mpu_wdt_ick); mpu_wdt_ick = NULL; goto fail; } mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck"); if (IS_ERR(mpu_wdt_fck)) { ret = PTR_ERR(mpu_wdt_fck); mpu_wdt_fck = NULL; goto fail; } } omap_wdt_disable(); omap_wdt_adjust_timeout(timer_margin); omap_wdt_miscdev.parent = &pdev->dev; ret = misc_register(&omap_wdt_miscdev); if (ret) goto fail; pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin); /* autogate OCP interface clock */ omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG); return 0; fail: if (armwdt_ck) clk_put(armwdt_ck); if (mpu_wdt_ick) clk_put(mpu_wdt_ick); if (mpu_wdt_fck) clk_put(mpu_wdt_fck); release_resource(mem); return ret; } static void omap_wdt_shutdown(struct platform_device *pdev) { omap_wdt_disable(); } static int omap_wdt_remove(struct platform_device *pdev) { struct resource *mem = platform_get_drvdata(pdev); misc_deregister(&omap_wdt_miscdev); release_resource(mem); if (armwdt_ck) clk_put(armwdt_ck); if (mpu_wdt_ick) clk_put(mpu_wdt_ick); if (mpu_wdt_fck) clk_put(mpu_wdt_fck); return 0; } #ifdef CONFIG_PM /* REVISIT ... not clear this is the best way to handle system suspend; and * it's very inappropriate for selective device suspend (e.g. suspending this * through sysfs rather than by stopping the watchdog daemon). Also, this * may not play well enough with NOWAYOUT... */ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) { if (omap_wdt_users) omap_wdt_disable(); return 0; } static int omap_wdt_resume(struct platform_device *pdev) { if (omap_wdt_users) { omap_wdt_enable(); omap_wdt_ping(); } return 0; } #else #define omap_wdt_suspend NULL #define omap_wdt_resume NULL #endif static struct platform_driver omap_wdt_driver = { .probe = omap_wdt_probe, .remove = omap_wdt_remove, .shutdown = omap_wdt_shutdown, .suspend = omap_wdt_suspend, .resume = omap_wdt_resume, .driver = { .owner = THIS_MODULE, .name = "omap_wdt", }, }; static int __init omap_wdt_init(void) { return platform_driver_register(&omap_wdt_driver); } static void __exit omap_wdt_exit(void) { platform_driver_unregister(&omap_wdt_driver); } module_init(omap_wdt_init); module_exit(omap_wdt_exit); MODULE_AUTHOR("George G. Davis"); MODULE_LICENSE("GPL"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); MODULE_ALIAS("platform:omap_wdt");
static long omap_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct omap_wdt_dev *wdev; int new_margin; static const struct watchdog_info ident = { .identity = "OMAP Watchdog", .options = WDIOF_SETTIMEOUT, .firmware_version = 0, }; wdev = file->private_data; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(ident)); case WDIOC_GETSTATUS: return put_user(0, (int __user *)arg); case WDIOC_GETBOOTSTATUS: if (cpu_is_omap16xx()) return put_user(__raw_readw(ARM_SYSST), (int __user *)arg); if (cpu_is_omap24xx()) return put_user(omap_prcm_get_reset_sources(), (int __user *)arg); case WDIOC_KEEPALIVE: pm_runtime_get_sync(wdev->dev); spin_lock(&wdt_lock); omap_wdt_ping(wdev); spin_unlock(&wdt_lock); pm_runtime_put_sync(wdev->dev); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_margin, (int __user *)arg)) return -EFAULT; omap_wdt_adjust_timeout(new_margin); pm_runtime_get_sync(wdev->dev); spin_lock(&wdt_lock); omap_wdt_disable(wdev); omap_wdt_set_timeout(wdev); omap_wdt_enable(wdev); omap_wdt_ping(wdev); spin_unlock(&wdt_lock); pm_runtime_put_sync(wdev->dev); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timer_margin, (int __user *)arg); default: return -ENOTTY; } } static const struct file_operations omap_wdt_fops = { .owner = THIS_MODULE, .write = omap_wdt_write, .unlocked_ioctl = omap_wdt_ioctl, .open = omap_wdt_open, .release = omap_wdt_release, .llseek = no_llseek, }; static int omap_wdt_nb_func(struct notifier_block *nb, unsigned long val, void *v) { struct omap_wdt_dev *wdev = container_of(nb, struct omap_wdt_dev, nb); pm_runtime_get_sync(wdev->dev); omap_wdt_ping(wdev); pm_runtime_put_sync_suspend(wdev->dev); return NOTIFY_OK; } #ifdef CONFIG_OMAP_WATCHDOG_CONTROL static const char ctrl_off[] = "off"; static const char ctrl_on[] = "on"; static ssize_t show_enabled(struct device *dev, struct device_attribute *attr, char *buf) { if (!kernelpet) return sprintf(buf, "The watchdog is disabled permanently.\n"); switch (is_wdt_enabled) { case WDT_DISABLE: return sprintf(buf, "off\n"); case WDT_ENABLE: return sprintf(buf, "on\n"); default: return sprintf(buf, "unknown\n"); } } static void enable_wdt(struct omap_wdt_dev *wdev) { void __iomem *base = wdev->base; is_wdt_enabled = WDT_ENABLE; pm_runtime_get_sync(wdev->dev); /* Enable delay interrupt */ if (kernelpet && wdev->irq) __raw_writel(0x2, base + OMAP_WATCHDOG_WIRQENSET); omap_wdt_enable(wdev); pm_runtime_put_sync(wdev->dev); }
static int omap_wdt_probe(struct platform_device *pdev) { struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev); struct watchdog_device *omap_wdt; struct resource *res; struct omap_wdt_dev *wdev; u32 rs; int ret; omap_wdt = devm_kzalloc(&pdev->dev, sizeof(*omap_wdt), GFP_KERNEL); if (!omap_wdt) return -ENOMEM; wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL); if (!wdev) return -ENOMEM; wdev->omap_wdt_users = false; wdev->dev = &pdev->dev; wdev->wdt_trgr_pattern = 0x1234; mutex_init(&wdev->lock); /* reserve static register mappings */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); wdev->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(wdev->base)) return PTR_ERR(wdev->base); omap_wdt->info = &omap_wdt_info; omap_wdt->ops = &omap_wdt_ops; omap_wdt->min_timeout = TIMER_MARGIN_MIN; omap_wdt->max_timeout = TIMER_MARGIN_MAX; if (timer_margin >= TIMER_MARGIN_MIN && timer_margin <= TIMER_MARGIN_MAX) omap_wdt->timeout = timer_margin; else omap_wdt->timeout = TIMER_MARGIN_DEFAULT; watchdog_set_drvdata(omap_wdt, wdev); watchdog_set_nowayout(omap_wdt, nowayout); platform_set_drvdata(pdev, omap_wdt); pm_runtime_enable(wdev->dev); pm_runtime_get_sync(wdev->dev); if (pdata && pdata->read_reset_sources) rs = pdata->read_reset_sources(); else rs = 0; omap_wdt->bootstatus = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ? WDIOF_CARDRESET : 0; omap_wdt_disable(wdev); ret = watchdog_register_device(omap_wdt); if (ret) { pm_runtime_disable(wdev->dev); return ret; } pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", readl_relaxed(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, omap_wdt->timeout); pm_runtime_put_sync(wdev->dev); return 0; }
static int __devinit omap_wdt_probe(struct platform_device *pdev) { struct resource *res, *mem, *res_irq; struct omap_wdt_dev *wdev; int ret; #ifdef CONFIG_OMAP_WATCHDOG_CONTROL int i; #endif /* reserve static register mappings */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENOENT; goto err_get_resource; } if (omap_wdt_dev) { ret = -EBUSY; goto err_busy; } mem = request_mem_region(res->start, resource_size(res), pdev->name); if (!mem) { ret = -EBUSY; goto err_busy; } res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL); if (!wdev) { ret = -ENOMEM; goto err_kzalloc; } wdev->omap_wdt_users = 0; wdev->mem = mem; wdev->dev = &pdev->dev; wdev->base = ioremap(res->start, resource_size(res)); if (!wdev->base) { ret = -ENOMEM; goto err_ioremap; } if (res_irq) { ret = request_irq(res_irq->start, omap_wdt_interrupt, 0, dev_name(&pdev->dev), wdev); if (ret) goto err_irq; wdev->irq = res_irq->start; } platform_set_drvdata(pdev, wdev); pm_runtime_enable(wdev->dev); pm_runtime_irq_safe(wdev->dev); pm_runtime_get_sync(wdev->dev); omap_wdt_disable(wdev); omap_wdt_adjust_timeout(timer_margin); wdev->omap_wdt_miscdev.parent = &pdev->dev; wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR; wdev->omap_wdt_miscdev.name = "watchdog"; wdev->omap_wdt_miscdev.fops = &omap_wdt_fops; ret = misc_register(&(wdev->omap_wdt_miscdev)); if (ret) goto err_misc; pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, timer_margin); pm_runtime_put_sync(wdev->dev); omap_wdt_dev = pdev; /* if (kernelpet && wdev->irq) { wdev->nb.notifier_call = omap_wdt_nb_func; atomic_notifier_chain_register(&touch_watchdog_notifier_head, &wdev->nb); omap_wdt_setup(wdev); } */ #ifdef CONFIG_OMAP_WATCHDOG_CONTROL for (i = 0; i < ARRAY_SIZE(wdt_attributes); i++) { ret = device_create_file(&pdev->dev, wdt_attributes[i]); if (ret != 0) { printk(KERN_ERR "Failed to create attr %d: %d\n", i, ret); } } if (!is_wdt_enabled) { disable_wdt(wdev); printk(KERN_WARNING "Disable omap watchdog\n"); } #endif return 0; err_misc: platform_set_drvdata(pdev, NULL); if (wdev->irq) free_irq(wdev->irq, wdev); err_irq: iounmap(wdev->base); err_ioremap: wdev->base = NULL; kfree(wdev); err_kzalloc: release_mem_region(res->start, resource_size(res)); err_busy: err_get_resource: return ret; }
static long omap_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct omap_wdt_dev *wdev; int new_margin; static const struct watchdog_info ident = { .identity = "OMAP Watchdog", .options = WDIOF_SETTIMEOUT, .firmware_version = 0, }; wdev = file->private_data; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(ident)); case WDIOC_GETSTATUS: return put_user(0, (int __user *)arg); case WDIOC_GETBOOTSTATUS: if (cpu_is_omap16xx()) return put_user(__raw_readw(ARM_SYSST), (int __user *)arg); if (cpu_is_omap24xx()) return put_user(omap_prcm_get_reset_sources(), (int __user *)arg); case WDIOC_KEEPALIVE: spin_lock(&wdt_lock); omap_wdt_ping(wdev); spin_unlock(&wdt_lock); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_margin, (int __user *)arg)) return -EFAULT; omap_wdt_adjust_timeout(new_margin); spin_lock(&wdt_lock); omap_wdt_disable(wdev); omap_wdt_set_timeout(wdev); omap_wdt_enable(wdev); omap_wdt_ping(wdev); spin_unlock(&wdt_lock); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timer_margin, (int __user *)arg); default: return -ENOTTY; } } static const struct file_operations omap_wdt_fops = { .owner = THIS_MODULE, .write = omap_wdt_write, .unlocked_ioctl = omap_wdt_ioctl, .open = omap_wdt_open, .release = omap_wdt_release, .llseek = no_llseek, }; static int omap_wdt_nb_func(struct notifier_block *nb, unsigned long val, void *v) { struct omap_wdt_dev *wdev = container_of(nb, struct omap_wdt_dev, nb); omap_wdt_ping(wdev); return NOTIFY_OK; } static int __devinit omap_wdt_probe(struct platform_device *pdev) { struct resource *res, *mem, *res_irq; struct omap_wdt_dev *wdev; int ret; /* reserve static register mappings */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENOENT; goto err_get_resource; } if (omap_wdt_dev) { ret = -EBUSY; goto err_busy; } mem = request_mem_region(res->start, resource_size(res), pdev->name); if (!mem) { ret = -EBUSY; goto err_busy; } res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL); if (!wdev) { ret = -ENOMEM; goto err_kzalloc; } wdev->omap_wdt_users = 0; wdev->mem = mem; wdev->dev = &pdev->dev; wdev->base = ioremap(res->start, resource_size(res)); if (!wdev->base) { ret = -ENOMEM; goto err_ioremap; } if (res_irq) { ret = request_irq(res_irq->start, omap_wdt_interrupt, 0, dev_name(&pdev->dev), wdev); if (ret) goto err_irq; wdev->irq = res_irq->start; } platform_set_drvdata(pdev, wdev); /* * Note: PM runtime functions must be used only when watchdog driver * is enabling/disabling. Dynamic handling of clock of watchdog timer on * OMAP4/5 (like provided with runtime API) will cause system failure */ pm_runtime_enable(wdev->dev); pm_runtime_irq_safe(wdev->dev); pm_runtime_get_sync(wdev->dev); omap_wdt_disable(wdev); omap_wdt_adjust_timeout(timer_margin); wdev->omap_wdt_miscdev.parent = &pdev->dev; wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR; wdev->omap_wdt_miscdev.name = "watchdog"; wdev->omap_wdt_miscdev.fops = &omap_wdt_fops; ret = misc_register(&(wdev->omap_wdt_miscdev)); if (ret) goto err_misc; pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, timer_margin); omap_wdt_dev = pdev; if (kernelpet && wdev->irq) { wdev->nb.notifier_call = omap_wdt_nb_func; atomic_notifier_chain_register(&touch_watchdog_notifier_head, &wdev->nb); return omap_wdt_setup(wdev); } pm_runtime_put_sync(wdev->dev); return 0; err_misc: pm_runtime_put_sync(wdev->dev); platform_set_drvdata(pdev, NULL); if (wdev->irq) free_irq(wdev->irq, wdev); err_irq: iounmap(wdev->base); err_ioremap: wdev->base = NULL; kfree(wdev); err_kzalloc: release_mem_region(res->start, resource_size(res)); err_busy: err_get_resource: return ret; } static void omap_wdt_shutdown(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) { omap_wdt_disable(wdev); pm_runtime_put_sync(wdev->dev); } } static int __devexit omap_wdt_remove(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; misc_deregister(&(wdev->omap_wdt_miscdev)); release_mem_region(res->start, resource_size(res)); platform_set_drvdata(pdev, NULL); if (wdev->irq) free_irq(wdev->irq, wdev); if (kernelpet && wdev->irq) atomic_notifier_chain_unregister(&touch_watchdog_notifier_head, &wdev->nb); iounmap(wdev->base); kfree(wdev); omap_wdt_dev = NULL; return 0; } #ifdef CONFIG_PM /* REVISIT ... not clear this is the best way to handle system suspend; and * it's very inappropriate for selective device suspend (e.g. suspending this * through sysfs rather than by stopping the watchdog daemon). Also, this * may not play well enough with NOWAYOUT... */ static int omap_wdt_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) { omap_wdt_disable(wdev); pm_runtime_put_sync_suspend(wdev->dev); } return 0; } static int omap_wdt_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) { pm_runtime_get_sync(wdev->dev); omap_wdt_enable(wdev); omap_wdt_ping(wdev); } return 0; } #else #define omap_wdt_suspend NULL #define omap_wdt_resume NULL #endif static const struct dev_pm_ops omap_wdt_pm_ops = { .suspend_noirq = omap_wdt_suspend, .resume_noirq = omap_wdt_resume, }; static struct platform_driver omap_wdt_driver = { .probe = omap_wdt_probe, .remove = __devexit_p(omap_wdt_remove), .shutdown = omap_wdt_shutdown, .driver = { .owner = THIS_MODULE, .name = "omap_wdt", .pm = &omap_wdt_pm_ops, }, }; static int __init omap_wdt_init(void) { spin_lock_init(&wdt_lock); return platform_driver_register(&omap_wdt_driver); }
static long omap_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct omap_wdt_dev *wdev; int new_margin; static const struct watchdog_info ident = { .identity = "OMAP Watchdog", .options = WDIOF_SETTIMEOUT, .firmware_version = 0, }; wdev = file->private_data; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(ident)); case WDIOC_GETSTATUS: return put_user(0, (int __user *)arg); case WDIOC_GETBOOTSTATUS: if (cpu_is_omap16xx()) return put_user(__raw_readw(ARM_SYSST), (int __user *)arg); if (cpu_is_omap24xx()) return put_user(omap_prcm_get_reset_sources(), (int __user *)arg); case WDIOC_KEEPALIVE: pm_runtime_get_sync(wdev->dev); spin_lock(&wdt_lock); omap_wdt_ping(wdev); spin_unlock(&wdt_lock); pm_runtime_put_sync(wdev->dev); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_margin, (int __user *)arg)) return -EFAULT; omap_wdt_adjust_timeout(new_margin); pm_runtime_get_sync(wdev->dev); spin_lock(&wdt_lock); omap_wdt_disable(wdev); omap_wdt_set_timeout(wdev); omap_wdt_enable(wdev); omap_wdt_ping(wdev); spin_unlock(&wdt_lock); pm_runtime_put_sync(wdev->dev); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(timer_margin, (int __user *)arg); default: return -ENOTTY; } } static const struct file_operations omap_wdt_fops = { .owner = THIS_MODULE, .write = omap_wdt_write, .unlocked_ioctl = omap_wdt_ioctl, .open = omap_wdt_open, .release = omap_wdt_release, .llseek = no_llseek, }; static int __devinit omap_wdt_probe(struct platform_device *pdev) { struct resource *res, *mem; struct omap_wdt_dev *wdev; int ret; /* reserve static register mappings */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENOENT; goto err_get_resource; } if (omap_wdt_dev) { ret = -EBUSY; goto err_busy; } mem = request_mem_region(res->start, resource_size(res), pdev->name); if (!mem) { ret = -EBUSY; goto err_busy; } wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL); if (!wdev) { ret = -ENOMEM; goto err_kzalloc; } wdev->omap_wdt_users = 0; wdev->mem = mem; wdev->dev = &pdev->dev; wdev->base = ioremap(res->start, resource_size(res)); if (!wdev->base) { ret = -ENOMEM; goto err_ioremap; } platform_set_drvdata(pdev, wdev); pm_runtime_enable(wdev->dev); pm_runtime_get_sync(wdev->dev); omap_wdt_disable(wdev); omap_wdt_adjust_timeout(timer_margin); wdev->omap_wdt_miscdev.parent = &pdev->dev; wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR; wdev->omap_wdt_miscdev.name = "watchdog"; wdev->omap_wdt_miscdev.fops = &omap_wdt_fops; ret = misc_register(&(wdev->omap_wdt_miscdev)); if (ret) goto err_misc; pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, timer_margin); pm_runtime_put_sync(wdev->dev); omap_wdt_dev = pdev; return 0; err_misc: platform_set_drvdata(pdev, NULL); iounmap(wdev->base); err_ioremap: wdev->base = NULL; kfree(wdev); err_kzalloc: release_mem_region(res->start, resource_size(res)); err_busy: err_get_resource: return ret; } static void omap_wdt_shutdown(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) { pm_runtime_get_sync(wdev->dev); omap_wdt_disable(wdev); pm_runtime_put_sync(wdev->dev); } } static int __devexit omap_wdt_remove(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; misc_deregister(&(wdev->omap_wdt_miscdev)); release_mem_region(res->start, resource_size(res)); platform_set_drvdata(pdev, NULL); iounmap(wdev->base); kfree(wdev); omap_wdt_dev = NULL; return 0; } #ifdef CONFIG_PM /* REVISIT ... not clear this is the best way to handle system suspend; and * it's very inappropriate for selective device suspend (e.g. suspending this * through sysfs rather than by stopping the watchdog daemon). Also, this * may not play well enough with NOWAYOUT... */ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) { pm_runtime_get_sync(wdev->dev); omap_wdt_disable(wdev); pm_runtime_put_sync(wdev->dev); } return 0; } static int omap_wdt_resume(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) { pm_runtime_get_sync(wdev->dev); omap_wdt_enable(wdev); omap_wdt_ping(wdev); pm_runtime_put_sync(wdev->dev); } return 0; } #else #define omap_wdt_suspend NULL #define omap_wdt_resume NULL #endif static struct platform_driver omap_wdt_driver = { .probe = omap_wdt_probe, .remove = __devexit_p(omap_wdt_remove), .shutdown = omap_wdt_shutdown, .suspend = omap_wdt_suspend, .resume = omap_wdt_resume, .driver = { .owner = THIS_MODULE, .name = "omap_wdt", }, }; static int __init omap_wdt_init(void) { spin_lock_init(&wdt_lock); return platform_driver_register(&omap_wdt_driver); }
static int omap_wdt_probe(struct platform_device *pdev) { struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev); struct resource *res; struct omap_wdt_dev *wdev; int ret; wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL); if (!wdev) return -ENOMEM; wdev->omap_wdt_users = false; wdev->dev = &pdev->dev; wdev->wdt_trgr_pattern = 0x1234; mutex_init(&wdev->lock); /* reserve static register mappings */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); wdev->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(wdev->base)) return PTR_ERR(wdev->base); wdev->wdog.info = &omap_wdt_info; wdev->wdog.ops = &omap_wdt_ops; wdev->wdog.min_timeout = TIMER_MARGIN_MIN; wdev->wdog.max_timeout = TIMER_MARGIN_MAX; wdev->wdog.parent = &pdev->dev; if (watchdog_init_timeout(&wdev->wdog, timer_margin, &pdev->dev) < 0) wdev->wdog.timeout = TIMER_MARGIN_DEFAULT; watchdog_set_nowayout(&wdev->wdog, nowayout); platform_set_drvdata(pdev, wdev); pm_runtime_enable(wdev->dev); pm_runtime_get_sync(wdev->dev); if (pdata && pdata->read_reset_sources) { u32 rs = pdata->read_reset_sources(); if (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) wdev->wdog.bootstatus = WDIOF_CARDRESET; } omap_wdt_disable(wdev); ret = watchdog_register_device(&wdev->wdog); if (ret) { pm_runtime_disable(wdev->dev); return ret; } pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", readl_relaxed(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, wdev->wdog.timeout); pm_runtime_put_sync(wdev->dev); if (early_enable) omap_wdt_start(&wdev->wdog); return 0; }
static int omap_wdt_probe(struct platform_device *pdev) { struct omap_wd_timer_platform_data *pdata = pdev->dev.platform_data; struct watchdog_device *omap_wdt; struct resource *res, *mem; struct omap_wdt_dev *wdev; u32 rs; int ret, irq; omap_wdt = devm_kzalloc(&pdev->dev, sizeof(*omap_wdt), GFP_KERNEL); if (!omap_wdt) return -ENOMEM; /* reserve static register mappings */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), pdev->name); if (!mem) return -EBUSY; wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL); if (!wdev) return -ENOMEM; wdev->omap_wdt_users = false; wdev->mem = mem; wdev->dev = &pdev->dev; wdev->wdt_trgr_pattern = 0x1234; mutex_init(&wdev->lock); wdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!wdev->base) return -ENOMEM; if (pdev->dev.of_node) { if (of_device_is_compatible(pdev->dev.of_node, "ti,omap3-wdt")) kernelpet = 0; } else { if (pdata->ip_rev == WDTIMER2_IP3) kernelpet = 0; } if (kernelpet) { irq = platform_get_irq(pdev, 0); ret = devm_request_irq(&pdev->dev, irq, omap_wdt_interrupt, 0, dev_name(&pdev->dev), omap_wdt); if (ret < 0) dev_err(&pdev->dev, "can't get irq %d, err %d\n", irq, ret); } omap_wdt->info = &omap_wdt_info; omap_wdt->ops = &omap_wdt_ops; omap_wdt->min_timeout = TIMER_MARGIN_MIN; omap_wdt->max_timeout = TIMER_MARGIN_MAX; if (timer_margin >= TIMER_MARGIN_MIN && timer_margin <= TIMER_MARGIN_MAX) omap_wdt->timeout = timer_margin; else omap_wdt->timeout = TIMER_MARGIN_DEFAULT; watchdog_set_drvdata(omap_wdt, wdev); watchdog_set_nowayout(omap_wdt, nowayout); platform_set_drvdata(pdev, omap_wdt); pm_runtime_enable(wdev->dev); pm_runtime_get_sync(wdev->dev); if (pdata && pdata->read_reset_sources) rs = pdata->read_reset_sources(); else rs = 0; omap_wdt->bootstatus = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ? WDIOF_CARDRESET : 0; omap_wdt_disable(wdev); ret = watchdog_register_device(omap_wdt); if (ret) { pm_runtime_disable(wdev->dev); return ret; } pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, omap_wdt->timeout); pm_runtime_put_sync(wdev->dev); if (kernelpet) { ret = omap_wdt_start(omap_wdt); if (ret == 0) set_bit(WDOG_ACTIVE, &omap_wdt->status); } return 0; }
static long omap_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct omap_wdt_dev *wdev; int new_margin; static const struct watchdog_info ident = { .identity = "OMAP Watchdog", .options = WDIOF_SETTIMEOUT, .firmware_version = 0, }; wdev = file->private_data; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info __user *)arg, &ident, sizeof(ident)); case WDIOC_GETSTATUS: return put_user(0, (int __user *)arg); case WDIOC_GETBOOTSTATUS: if (cpu_is_omap16xx()) return put_user(__raw_readw(ARM_SYSST), (int __user *)arg); if (cpu_is_omap24xx()) return put_user(omap_prcm_get_reset_sources(), (int __user *)arg); case WDIOC_KEEPALIVE: spin_lock(&wdt_lock); omap_wdt_ping(wdev); spin_unlock(&wdt_lock); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_margin, (int __user *)arg)) return -EFAULT; omap_wdt_adjust_timeout(new_margin); spin_lock(&wdt_lock); omap_wdt_disable(wdev); omap_wdt_set_timeout(wdev); omap_wdt_enable(wdev); omap_wdt_ping(wdev); spin_unlock(&wdt_lock); case WDIOC_GETTIMEOUT: return put_user(timer_margin, (int __user *)arg); default: return -ENOTTY; } } static const struct file_operations omap_wdt_fops = { .owner = THIS_MODULE, .write = omap_wdt_write, .unlocked_ioctl = omap_wdt_ioctl, .open = omap_wdt_open, .release = omap_wdt_release, }; static int __devinit omap_wdt_probe(struct platform_device *pdev) { struct resource *res, *mem; struct omap_wdt_dev *wdev; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENOENT; goto err_get_resource; } if (omap_wdt_dev) { ret = -EBUSY; goto err_busy; } mem = request_mem_region(res->start, res->end - res->start + 1, pdev->name); if (!mem) { ret = -EBUSY; goto err_busy; } wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL); if (!wdev) { ret = -ENOMEM; goto err_kzalloc; } wdev->omap_wdt_users = 0; wdev->mem = mem; wdev->ick = clk_get(&pdev->dev, "ick"); if (IS_ERR(wdev->ick)) { ret = PTR_ERR(wdev->ick); wdev->ick = NULL; goto err_clk; } wdev->fck = clk_get(&pdev->dev, "fck"); if (IS_ERR(wdev->fck)) { ret = PTR_ERR(wdev->fck); wdev->fck = NULL; goto err_clk; } wdev->base = ioremap(res->start, res->end - res->start + 1); if (!wdev->base) { ret = -ENOMEM; goto err_ioremap; } platform_set_drvdata(pdev, wdev); clk_enable(wdev->ick); clk_enable(wdev->fck); omap_wdt_disable(wdev); omap_wdt_adjust_timeout(timer_margin); wdev->omap_wdt_miscdev.parent = &pdev->dev; wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR; wdev->omap_wdt_miscdev.name = "watchdog"; wdev->omap_wdt_miscdev.fops = &omap_wdt_fops; ret = misc_register(&(wdev->omap_wdt_miscdev)); if (ret) goto err_misc; pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, timer_margin); __raw_writel(0x01, wdev->base + OMAP_WATCHDOG_SYS_CONFIG); clk_disable(wdev->ick); clk_disable(wdev->fck); omap_wdt_dev = pdev; return 0; err_misc: platform_set_drvdata(pdev, NULL); iounmap(wdev->base); err_ioremap: wdev->base = NULL; err_clk: if (wdev->ick) clk_put(wdev->ick); if (wdev->fck) clk_put(wdev->fck); kfree(wdev); err_kzalloc: release_mem_region(res->start, res->end - res->start + 1); err_busy: err_get_resource: return ret; } static void omap_wdt_shutdown(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) omap_wdt_disable(wdev); } static int __devexit omap_wdt_remove(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENOENT; misc_deregister(&(wdev->omap_wdt_miscdev)); release_mem_region(res->start, res->end - res->start + 1); platform_set_drvdata(pdev, NULL); clk_put(wdev->ick); clk_put(wdev->fck); iounmap(wdev->base); kfree(wdev); omap_wdt_dev = NULL; return 0; } #ifdef CONFIG_PM static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) omap_wdt_disable(wdev); return 0; } static int omap_wdt_resume(struct platform_device *pdev) { struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); if (wdev->omap_wdt_users) { omap_wdt_enable(wdev); omap_wdt_ping(wdev); } return 0; } #else #define omap_wdt_suspend NULL #define omap_wdt_resume NULL #endif static struct platform_driver omap_wdt_driver = { .probe = omap_wdt_probe, .remove = __devexit_p(omap_wdt_remove), .shutdown = omap_wdt_shutdown, .suspend = omap_wdt_suspend, .resume = omap_wdt_resume, .driver = { .owner = THIS_MODULE, .name = "omap_wdt", }, }; static int __init omap_wdt_init(void) { spin_lock_init(&wdt_lock); return platform_driver_register(&omap_wdt_driver); }