static int mxc_wdt_resume(struct platform_device *pdev) { if (mxc_wdt_users) { mxc_wdt_enable(); mxc_wdt_ping(); } return 0; }
static int mxc_wdt_open(struct inode *inode, struct file *file) { if (test_and_set_bit(1, (unsigned long *)&mxc_wdt_users)) return -EBUSY; mxc_wdt_config(); mxc_wdt_set_timeout(); mxc_wdt_enable(); mxc_wdt_ping(); return 0; }
static int mxc_wdt_open(struct inode *inode, struct file *file) { if (test_and_set_bit(1, (unsigned long *)&mxc_wdt_users)) return -EBUSY; mxc_wdt_config(wdt_base_reg); mxc_wdt_set_timeout(wdt_base_reg); mxc_wdt_enable(wdt_base_reg); mxc_wdt_ping(wdt_base_reg); #ifdef CONFIG_MACH_MX51_ERDOS opened = 1; #endif /* CONFIG_MACH_MX51_ERDOS */ return 0; }
static int mxc_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int new_margin; int bootr; static struct watchdog_info ident = { .identity = "MXC Watchdog", .options = WDIOF_SETTIMEOUT, .firmware_version = 0, }; switch (cmd) { default: return -ENOIOCTLCMD; 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: bootr = mxc_wdt_get_bootreason(wdt_base_reg); return put_user(bootr, (int __user *)arg); case WDIOC_KEEPALIVE: mxc_wdt_ping(wdt_base_reg); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_margin, (int __user *)arg)) return -EFAULT; mxc_wdt_adjust_timeout(new_margin); mxc_wdt_disable(wdt_base_reg); mxc_wdt_set_timeout(wdt_base_reg); mxc_wdt_enable(wdt_base_reg); mxc_wdt_ping(wdt_base_reg); return 0; case WDIOC_GETTIMEOUT: mxc_wdt_ping(wdt_base_reg); new_margin = mxc_wdt_get_timeout(wdt_base_reg); return put_user(new_margin, (int __user *)arg); } } static struct file_operations mxc_wdt_fops = { .owner = THIS_MODULE, .write = mxc_wdt_write, .ioctl = mxc_wdt_ioctl, .open = mxc_wdt_open, .release = mxc_wdt_release, }; static struct miscdevice mxc_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &mxc_wdt_fops }; static int __init mxc_wdt_probe(struct platform_device *pdev) { struct resource *res, *mem; int ret; /* reserve static register mappings */ res = platform_get_resource(pdev, IORESOURCE_MEM, dev_num); 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); wdt_base_reg = IO_ADDRESS(res->start); mxc_wdt_disable(wdt_base_reg); mxc_wdt_adjust_timeout(timer_margin); mxc_wdt_users = 0; mxc_wdt_miscdev.this_device = &pdev->dev; mxc_wdt_clk = clk_get(NULL, "wdog_clk"); clk_enable(mxc_wdt_clk); ret = misc_register(&mxc_wdt_miscdev); if (ret) goto fail; pr_info("MXC Watchdog # %d Timer: initial timeout %d sec\n", dev_num, timer_margin); return 0; fail: release_resource(mem); pr_info("MXC Watchdog Probe failed\n"); return ret; } static void mxc_wdt_shutdown(struct platform_device *pdev) { struct resource *res = platform_get_drvdata(pdev); mxc_wdt_disable(wdt_base_reg); pr_info("MXC Watchdog # %d shutdown\n", dev_num); } static int __exit mxc_wdt_remove(struct platform_device *pdev) { struct resource *mem = platform_get_drvdata(pdev); misc_deregister(&mxc_wdt_miscdev); release_resource(mem); pr_info("MXC Watchdog # %d removed\n", dev_num); 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 mxc_wdt_suspend(struct platform_device *pdev, pm_message_t state) { struct resource *res = platform_get_drvdata(pdev); if (mxc_wdt_users) { mxc_wdt_disable(wdt_base_reg); } return 0; } static int mxc_wdt_resume(struct platform_device *pdev) { struct resource *res = platform_get_drvdata(pdev); if (mxc_wdt_users) { mxc_wdt_enable(wdt_base_reg); mxc_wdt_ping(wdt_base_reg); } return 0; } #else #define mxc_wdt_suspend NULL #define mxc_wdt_resume NULL #endif static struct platform_driver mxc_wdt_driver = { .driver = { .owner = THIS_MODULE, .name = "mxc_wdt", }, .probe = mxc_wdt_probe, .shutdown = mxc_wdt_shutdown, .remove = __exit_p(mxc_wdt_remove), .suspend = mxc_wdt_suspend, .resume = mxc_wdt_resume, }; static int __init mxc_wdt_init(void) { pr_info("MXC WatchDog Driver %s\n", DVR_VER); if ((timer_margin < TIMER_MARGIN_MIN) || (timer_margin > TIMER_MARGIN_MAX)) { pr_info("MXC watchdog error. wrong timer_margin %d\n", timer_margin); pr_info(" Range: %d to %d seconds\n", TIMER_MARGIN_MIN, TIMER_MARGIN_MAX); return -EINVAL; } return platform_driver_register(&mxc_wdt_driver); }
static int mxc_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { unsigned int new_margin; int boot_reason; static struct watchdog_info ident = { .identity = "MXC Watchdog", .options = WDIOF_SETTIMEOUT, .firmware_version = 0, }; switch (cmd) { default: return -ENOIOCTLCMD; 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: boot_reason = mxc_wdt_get_boot_reason(); return put_user(boot_reason, (unsigned int __user *)arg); case WDIOC_KEEPALIVE: mxc_wdt_ping(); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_margin, (unsigned int __user *)arg)) return -EFAULT; mxc_wdt_adjust_timeout(new_margin); mxc_wdt_disable(); mxc_wdt_set_timeout(); mxc_wdt_enable(); mxc_wdt_ping(); return 0; case WDIOC_GETTIMEOUT: mxc_wdt_ping(); new_margin = mxc_wdt_get_timeout(); return put_user(new_margin, (unsigned int __user *)arg); } } static struct file_operations mxc_wdt_fops = { .owner = THIS_MODULE, .write = mxc_wdt_write, .ioctl = mxc_wdt_ioctl, .open = mxc_wdt_open, .release = mxc_wdt_release, }; static struct miscdevice mxc_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &mxc_wdt_fops }; static int __init mxc_wdt_probe(struct platform_device *pdev) { int ret; mxc_wdt_disable(); mxc_wdt_adjust_timeout(timer_margin); mxc_wdt_users = 0; mxc_wdt_miscdev.dev = &pdev->dev; mxc_wdt_clk = clk_get(NULL, "wdog_clk"); clk_enable(mxc_wdt_clk); ret = misc_register(&mxc_wdt_miscdev); if (ret) goto fail; pr_info("MXC Watchdog Timer: initial timeout %d sec\n", timer_margin); return 0; fail: pr_info("MXC Watchdog Probe failed\n"); return ret; } static void mxc_wdt_shutdown(struct platform_device *pdev) { mxc_wdt_disable(); pr_info("MXC Watchdog shutdown\n"); }
static int mxc_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int new_margin; int bootr; static struct watchdog_info ident = { .identity = "MXC Watchdog", .options = WDIOF_SETTIMEOUT, .firmware_version = 0, }; switch (cmd) { default: return -ENOIOCTLCMD; 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: bootr = mxc_wdt_get_bootreason(wdt_base_reg); return put_user(bootr, (int __user *)arg); case WDIOC_KEEPALIVE: mxc_wdt_ping(wdt_base_reg); #ifdef CONFIG_MACH_MX51_ERDOS mxc_wdt_staticstics [2]++; #endif /* CONFIG_MACH_MX51_ERDOS */ return 0; case WDIOC_SETTIMEOUT: if (get_user(new_margin, (int __user *)arg)) return -EFAULT; mxc_wdt_adjust_timeout(new_margin); mxc_wdt_disable(wdt_base_reg); mxc_wdt_set_timeout(wdt_base_reg); mxc_wdt_enable(wdt_base_reg); mxc_wdt_ping(wdt_base_reg); return 0; case WDIOC_GETTIMEOUT: mxc_wdt_ping(wdt_base_reg); new_margin = mxc_wdt_get_timeout(wdt_base_reg); return put_user(new_margin, (int __user *)arg); } } static struct file_operations mxc_wdt_fops = { .owner = THIS_MODULE, .write = mxc_wdt_write, .ioctl = mxc_wdt_ioctl, .open = mxc_wdt_open, .release = mxc_wdt_release, }; static struct miscdevice mxc_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &mxc_wdt_fops }; #ifdef CONFIG_MACH_MX51_ERDOS /* * wdt_self_workqueue_handler */ static void wdt_self_workqueue_handler (struct work_struct *work) { mxc_wdt_staticstics [0]++; if (opened == 0) { /* * WDT heartbeat */ mxc_wdt_staticstics [1]++; mxc_wdt_ping (wdt_base_reg); /* * next interval */ schedule_delayed_work (&wdt_self_work, 60 * HZ); } } /* * wdt_self_start */ static void wdt_self_start (void) { /* * delay work create */ INIT_DELAYED_WORK (&wdt_self_work, wdt_self_workqueue_handler); schedule_delayed_work (&wdt_self_work, HZ); mxc_wdt_config (wdt_base_reg); mxc_wdt_set_timeout (wdt_base_reg); mxc_wdt_enable (wdt_base_reg); }