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: 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); }
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 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 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: 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); }