From patchwork Wed Dec 5 01:34:21 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenyou Yang X-Patchwork-Id: 1840011 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork1.kernel.org (Postfix) with ESMTP id 96ED53FC64 for ; Wed, 5 Dec 2012 01:42:49 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Tg3xq-0003re-EA; Wed, 05 Dec 2012 01:39:54 +0000 Received: from newsmtp5.atmel.com ([204.2.163.5] helo=sjogate2.atmel.com) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Tg3wv-0003a2-8E for linux-arm-kernel@lists.infradead.org; Wed, 05 Dec 2012 01:39:01 +0000 Received: from penbh01.corp.atmel.com ([10.168.5.31]) by sjogate2.atmel.com (8.13.6/8.13.6) with ESMTP id qB51XZqV023329; Tue, 4 Dec 2012 17:33:36 -0800 (PST) Received: from penmb01.corp.atmel.com ([10.168.5.33]) by penbh01.corp.atmel.com with Microsoft SMTPSVC(6.0.3790.3959); Wed, 5 Dec 2012 09:38:46 +0800 Received: from shaarm01.corp.atmel.com ([10.217.6.34]) by penmb01.corp.atmel.com with Microsoft SMTPSVC(6.0.3790.3959); Wed, 5 Dec 2012 09:38:37 +0800 From: Wenyou Yang To: linux-arm-kernel@lists.infradead.org Subject: [v2 PATCH 2/8] watchdog/at91sam9_wdt: Convert to use the watchdog framework Date: Wed, 5 Dec 2012 09:34:21 +0800 Message-Id: <1354671267-19277-3-git-send-email-wenyou.yang@atmel.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1354671267-19277-1-git-send-email-wenyou.yang@atmel.com> References: <1354671267-19277-1-git-send-email-wenyou.yang@atmel.com> X-OriginalArrivalTime: 05 Dec 2012 01:38:38.0538 (UTC) FILETIME=[3FBDFAA0:01CDD289] X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121204_203857_913099_729129C0 X-CRM114-Status: GOOD ( 25.23 ) X-Spam-Score: -2.6 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 SPF_PASS SPF: sender matches SPF record -0.7 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: linux-watchdog@vger.kernel.org, JM.Lin@atmel.com, nicolas.ferre@atmel.com, linux-kernel@vger.kernel.org, wenyou.yang@atmel.com, wim@iguana.be, plagnioj@jcrosoft.com X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org According to the kernel document: convert_drivers_to_kernel_api.txt, remove the file_operations struct, miscdevice, and obsolete includes Since the at91sam watchdog inherent characteristics, add the watchdog operations: at91wdt_start, at91wdt_stop and at91wdt_ping. Signed-off-by: Wenyou Yang Cc: wim@iguana.be Cc: linux-watchdog@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- drivers/watchdog/at91sam9_wdt.c | 203 +++++++++++++++------------------------ 1 file changed, 75 insertions(+), 128 deletions(-) diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index f10a897..92467d4 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -13,16 +13,17 @@ * The Watchdog Timer Mode Register can be only written to once. If the * timeout need to be set from Linux, be sure that the bootstrap or the * bootloader doesn't write to this register. + * The Watchdog Timer default is running with maximum counter value + * (WDV=0xfff) at reset, i.e., at power-up. It MUST be either disabled + * or be reprogrammed within the maxinum margin(16s). */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include #include -#include #include #include #include @@ -31,7 +32,6 @@ #include #include #include -#include #include #include "at91sam9_wdt.h" @@ -65,8 +65,6 @@ module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -static void at91_ping(unsigned long data); - struct at91wdt_drvdata { void __iomem *phybase; bool is_enable; /* indicate if the watchdog is eabled */ @@ -88,6 +86,11 @@ static inline void wdt_write(struct at91wdt_drvdata *driver_data, writel_relaxed((val), driver_data->phybase + field); } +static inline bool watchdog_is_open(struct watchdog_device *wddev) +{ + return test_bit(WDOG_DEV_OPEN, &wddev->status); +} + /* * Reload the watchdog timer. (ie, pat the watchdog) */ @@ -99,7 +102,7 @@ static inline void at91_wdt_reset(struct at91wdt_drvdata *driver_data) /* * Timer tick */ -static void at91_ping(unsigned long data) +static void at91wdt_timer_tick(unsigned long data) { struct watchdog_device *wddev = (struct watchdog_device *)data; struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev); @@ -107,45 +110,30 @@ static void at91_ping(unsigned long data) if (time_before(jiffies, driver_data->next_heartbeat)) { at91_wdt_reset(driver_data); mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT); + + if (!watchdog_is_open(wddev)) + driver_data->next_heartbeat = jiffies + + wddev->timeout * HZ; } else pr_crit("I will reset your machine !\n"); } -/* - * Watchdog device is opened, and watchdog starts running. - */ -static int at91_wdt_open(struct inode *inode, struct file *file) -{ - driver_data->next_heartbeat = jiffies + heartbeat * HZ; - mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT); - - return nonseekable_open(inode, file); -} - -/* - * Close the watchdog device. - */ -static int at91_wdt_close(struct inode *inode, struct file *file) -{ - del_timer(&driver_data->timer); - - return 0; -} - -/* - * Set the watchdog time interval in 1/256Hz (write-once) - * Counter is 12 bit. - */ -static int at91_wdt_settimeout(unsigned int timeout) +static int at91wdt_enable(struct watchdog_device *wddev, unsigned int timeout) { + struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev); unsigned int reg; - unsigned int mr; - /* Check if disabled */ - mr = wdt_read(AT91_WDT_MR); - if (mr & AT91_WDT_WDDIS) { - pr_err("sorry, watchdog is disabled\n"); - return -EIO; + /* + * Check if the watchdog is disabled, + * if disabled, the reason is the bootstrap or the bootloader has + * written the Watchdog Timer Mode Register to disable the + * watchdog timer + */ + reg = wdt_read(driver_data, AT91_WDT_MR); + if (reg & AT91_WDT_WDDIS) { + driver_data->is_enable = false; + pr_info("sorry, watchdog is disabled\n"); + return -1; } /* @@ -159,7 +147,9 @@ static int at91_wdt_settimeout(unsigned int timeout) | AT91_WDT_WDDBGHLT /* disabled in debug mode */ | AT91_WDT_WDD /* restart at any time */ | (timeout & AT91_WDT_WDV); /* timer value */ - wdt_write(AT91_WDT_MR, reg); + wdt_write(driver_data, AT91_WDT_MR, reg); + + driver_data->is_enable = true; return 0; } @@ -170,99 +160,61 @@ static const struct watchdog_info at91_wdt_info = { WDIOF_MAGICCLOSE, }; -/* - * Handle commands from user-space. - */ -static long at91_wdt_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) +static int at91wdt_start(struct watchdog_device *wddev) { - void __user *argp = (void __user *)arg; - int __user *p = argp; - int new_value; - - switch (cmd) { - case WDIOC_GETSUPPORT: - return copy_to_user(argp, &at91_wdt_info, - sizeof(at91_wdt_info)) ? -EFAULT : 0; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); + struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev); - case WDIOC_KEEPALIVE: - driver_data->next_heartbeat = jiffies + heartbeat * HZ; + if (driver_data->is_enable) { + driver_data->next_heartbeat = jiffies + wddev->timeout * HZ; + mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT); return 0; - - case WDIOC_SETTIMEOUT: - if (get_user(new_value, p)) - return -EFAULT; - - heartbeat = new_value; - driver_data->next_heartbeat = jiffies + heartbeat * HZ; - - return put_user(new_value, p); /* return current value */ - - case WDIOC_GETTIMEOUT: - return put_user(heartbeat, p); - } - return -ENOTTY; + } else + return -EIO; } -/* - * Pat the watchdog whenever device is written to. - */ -static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, - loff_t *ppos) +static int at91wdt_stop(struct watchdog_device *wddev) { - if (!len) - return 0; - - /* Scan for magic character */ - if (!nowayout) { - size_t i; - + struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev); - for (i = 0; i < len; i++) { - char c; - if (get_user(c, data + i)) - return -EFAULT; - } - } - } + if (driver_data->is_enable) + return -EIO; + else + return 0; +} - driver_data->next_heartbeat = jiffies + heartbeat * HZ; +static int at91wdt_ping(struct watchdog_device *wddev) +{ + struct at91wdt_drvdata *driver_data = watchdog_get_drvdata(wddev); - return len; + if (driver_data->is_enable) { + driver_data->next_heartbeat = jiffies + wddev->timeout * HZ; + mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT); + return 0; + } else + return -EIO; } - /* ......................................................................... */ -static const struct file_operations at91wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .unlocked_ioctl = at91_wdt_ioctl, - .open = at91_wdt_open, - .release = at91_wdt_close, - .write = at91_wdt_write, -}; - -static struct miscdevice at91wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &at91wdt_fops, +static struct watchdog_ops at91wdt_ops = { + .owner = THIS_MODULE, + .start = at91wdt_start, + .stop = at91wdt_stop, + .ping = at91wdt_ping, }; static struct watchdog_device at91wdt_wdd __initdata = { .timeout = WDT_HEARTBEAT, .min_timeout = MIN_HEARTBEAT, .max_timeout = MAX_HEARTBEAT, + .info = &at91_wdt_info, + .ops = &at91wdt_ops, }; static int __init at91wdt_probe(struct platform_device *pdev) { struct at91wdt_drvdata *driver_data; struct resource *r; - int res; + int ret; driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data), GFP_KERNEL); @@ -273,32 +225,32 @@ static int __init at91wdt_probe(struct platform_device *pdev) watchdog_set_drvdata(&at91wdt_wdd, driver_data); - if (at91wdt_miscdev.parent) - return -EBUSY; - at91wdt_miscdev.parent = &pdev->dev; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) return -ENODEV; + driver_data->phybase = ioremap(r->start, resource_size(r)); if (!driver_data->phybase) { dev_err(&pdev->dev, "failed to map registers, aborting.\n"); return -ENOMEM; } - watchdog_init_timeout(&at91wdt_wdd, heartbeat, pdev->dev.of_node); + ret = watchdog_register_device(&at91wdt_wdd); + if (ret) { + dev_err(&pdev->dev, "cannot register watchdog (%d)\n", ret); + return ret; + } - /* Set watchdog */ - res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000)); - if (res) - return res; + watchdog_init_timeout(&at91wdt_wdd, heartbeat, pdev->dev.of_node); - res = misc_register(&at91wdt_miscdev); - if (res) - return res; + ret = at91wdt_enable(&at91wdt_wdd, ms_to_ticks(WDT_HW_TIMEOUT * 1000)); + if (ret) { + pr_info("the watchdog has been disabled\n"); + return 0; + } driver_data->next_heartbeat = jiffies + at91wdt_wdd.timeout * HZ; - setup_timer(&driver_data->timer, at91_ping, + setup_timer(&driver_data->timer, at91wdt_timer_tick, (unsigned long)&at91wdt_wdd); mod_timer(&driver_data->timer, jiffies + WDT_TIMEOUT); @@ -310,13 +262,9 @@ static int __init at91wdt_probe(struct platform_device *pdev) static int __exit at91wdt_remove(struct platform_device *pdev) { - int res; + watchdog_unregister_device(&at91wdt_wdd); - res = misc_deregister(&at91wdt_miscdev); - if (!res) - at91wdt_miscdev.parent = NULL; - - return res; + return 0; } #if defined(CONFIG_OF) @@ -353,4 +301,3 @@ module_exit(at91sam_wdt_exit); MODULE_AUTHOR("Renaud CERRATO "); MODULE_DESCRIPTION("Watchdog driver for Atmel AT91SAM9x processors"); MODULE_LICENSE("GPL"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);