From patchwork Mon Jul 9 07:35:26 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zumeng Chen X-Patchwork-Id: 1171491 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 E732E3FC2A for ; Mon, 9 Jul 2012 07:55:38 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1So8cq-0007th-3p; Mon, 09 Jul 2012 07:43:20 +0000 Received: from mail.windriver.com ([147.11.1.11]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1So8Vl-0006aw-Ds for linux-arm-kernel@lists.infradead.org; Mon, 09 Jul 2012 07:36:11 +0000 Received: from ALA-HCA.corp.ad.wrs.com (ala-hca [147.11.189.40]) by mail.windriver.com (8.14.3/8.14.3) with ESMTP id q697ZbJi026015 (version=TLSv1/SSLv3 cipher=AES128-SHA bits=128 verify=FAIL); Mon, 9 Jul 2012 00:35:37 -0700 (PDT) Received: from pek-yocto-build2.corp.ad.wrs.com (128.224.162.103) by ALA-HCA.corp.ad.wrs.com (147.11.189.50) with Microsoft SMTP Server id 14.1.255.0; Mon, 9 Jul 2012 00:35:36 -0700 From: Zumeng Chen To: , , Subject: [PATCH v2 1/3] Watchdog: Omap: Changes for the new watchdog framework Date: Mon, 9 Jul 2012 15:35:26 +0800 Message-ID: <1341819328-3514-2-git-send-email-zumeng.chen@windriver.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1341819328-3514-1-git-send-email-zumeng.chen@windriver.com> References: <1341819328-3514-1-git-send-email-zumeng.chen@windriver.com> MIME-Version: 1.0 X-Spam-Note: CRM114 invocation failed X-Spam-Score: -4.2 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [147.11.1.11 listed in list.dnswl.org] -0.0 T_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: tony@atomide.com, paul.gortmaker@windriver.com, linux-omap@vger.kernel.org, linux-watchdog@vger.kernel.org, linux-arm-kernel@lists.infradead.org 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: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This patch implements the current watchdog framework for OMAP WDTimer, which factored out the common components, so the driver can just focus on the hardware related parts. Signed-off-by: Zumeng Chen --- drivers/watchdog/omap_wdt.c | 342 ++++++++++++++++--------------------------- drivers/watchdog/omap_wdt.h | 5 + 2 files changed, 128 insertions(+), 219 deletions(-) diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index 8285d65..cc5bc3e 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -24,6 +24,9 @@ * * Copyright (c) 2005 David Brownell * Use the driver model and standard identifiers; handle bigger timeouts. + * + * Copyright (c) 2012 WindRiver + * Changes cater for the current watchdog framework. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -33,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -50,8 +52,6 @@ #include "omap_wdt.h" -static struct platform_device *omap_wdt_dev; - static unsigned timer_margin; module_param(timer_margin, uint, 0); MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); @@ -59,32 +59,14 @@ MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); static unsigned int wdt_trgr_pattern = 0x1234; static DEFINE_SPINLOCK(wdt_lock); -struct omap_wdt_dev { +struct omap_wdt_drvdata { + struct watchdog_device wdt; void __iomem *base; /* physical */ struct device *dev; - int omap_wdt_users; struct resource *mem; - struct miscdevice omap_wdt_miscdev; }; -static void omap_wdt_ping(struct omap_wdt_dev *wdev) -{ - void __iomem *base = wdev->base; - - /* wait for posted write to complete */ - while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) - cpu_relax(); - - wdt_trgr_pattern = ~wdt_trgr_pattern; - __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR)); - - /* wait for posted write to complete */ - while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) - cpu_relax(); - /* reloaded WCRR from WLDR */ -} - -static void omap_wdt_enable(struct omap_wdt_dev *wdev) +static void omap_wdt_enable(struct omap_wdt_drvdata *wdev) { void __iomem *base = wdev->base; @@ -98,7 +80,7 @@ static void omap_wdt_enable(struct omap_wdt_dev *wdev) cpu_relax(); } -static void omap_wdt_disable(struct omap_wdt_dev *wdev) +static void omap_wdt_disable(struct omap_wdt_drvdata *wdev) { void __iomem *base = wdev->base; @@ -121,12 +103,19 @@ static void omap_wdt_adjust_timeout(unsigned new_timeout) timer_margin = new_timeout; } -static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev) +static int omap_wdt_set_timeout(struct watchdog_device *wdt_dev, + unsigned int new_timeout) { - u32 pre_margin = GET_WLDR_VAL(timer_margin); - void __iomem *base = wdev->base; + u32 pre_margin; + struct omap_wdt_drvdata *omap_wdev = watchdog_get_drvdata(wdt_dev); + void __iomem *base = omap_wdev->base; - pm_runtime_get_sync(wdev->dev); + pm_runtime_get_sync(omap_wdev->dev); + omap_wdt_disable(omap_wdev); + + /* adjust timeout based on the new timeout */ + omap_wdt_adjust_timeout(new_timeout); + pre_margin = GET_WLDR_VAL(timer_margin); /* just count up at 32 KHz */ while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04) @@ -136,147 +125,88 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev) while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x04) cpu_relax(); - pm_runtime_put_sync(wdev->dev); + omap_wdt_enable(omap_wdev); + wdt_dev->timeout = new_timeout; + pm_runtime_put_sync(omap_wdev->dev); + return 0; } -/* - * Allow only one task to hold it open - */ -static int omap_wdt_open(struct inode *inode, struct file *file) +static int omap_wdt_ping(struct watchdog_device *wdt_dev) { - struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev); - void __iomem *base = wdev->base; - - if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users))) - return -EBUSY; - - pm_runtime_get_sync(wdev->dev); + struct omap_wdt_drvdata *omap_wdev = watchdog_get_drvdata(wdt_dev); + void __iomem *base = omap_wdev->base; - /* initialize prescaler */ - while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) - cpu_relax(); + pm_runtime_get_sync(omap_wdev->dev); + spin_lock(&wdt_lock); - __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL); - while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) + /* wait for posted write to complete */ + while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) cpu_relax(); - file->private_data = (void *) wdev; + wdt_trgr_pattern = ~wdt_trgr_pattern; + __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR)); - omap_wdt_set_timeout(wdev); - omap_wdt_ping(wdev); /* trigger loading of new timeout value */ - omap_wdt_enable(wdev); + /* wait for posted write to complete */ + /* reloaded WCRR from WLDR */ + while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) + cpu_relax(); - pm_runtime_put_sync(wdev->dev); + spin_unlock(&wdt_lock); + pm_runtime_put_sync(omap_wdev->dev); - return nonseekable_open(inode, file); + return 0; } -static int omap_wdt_release(struct inode *inode, struct file *file) +static int omap_wdt_start(struct watchdog_device *wdt_dev) { - struct omap_wdt_dev *wdev = file->private_data; + struct omap_wdt_drvdata *omap_wdev = watchdog_get_drvdata(wdt_dev); + void __iomem *base = omap_wdev->base; - /* - * Shut off the timer unless NOWAYOUT is defined. - */ -#ifndef CONFIG_WATCHDOG_NOWAYOUT - pm_runtime_get_sync(wdev->dev); + pm_runtime_get_sync(omap_wdev->dev); + /* initialize prescaler */ + while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) + cpu_relax(); - omap_wdt_disable(wdev); + __raw_writel((1 << 5) | (PTV << 2), base + OMAP_WATCHDOG_CNTRL); + while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) + cpu_relax(); - pm_runtime_put_sync(wdev->dev); -#else - pr_crit("Unexpected close, not stopping!\n"); -#endif - wdev->omap_wdt_users = 0; + omap_wdt_set_timeout(&omap_wdev->wdt, timer_margin); + pm_runtime_put_sync(omap_wdev->dev); return 0; } -static ssize_t omap_wdt_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) +static int omap_wdt_stop(struct watchdog_device *wdt_dev) { - struct omap_wdt_dev *wdev = file->private_data; - - /* Refresh LOAD_TIME. */ - if (len) { - 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 len; -} + struct omap_wdt_drvdata *omap_wdev = watchdog_get_drvdata(wdt_dev); -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); - return put_user(0, (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; - } + pm_runtime_get_sync(omap_wdev->dev); + omap_wdt_disable(omap_wdev); + pm_runtime_put_sync(omap_wdev->dev); + + return 0; } -static const struct file_operations omap_wdt_fops = { +static const struct watchdog_ops omap_wdt_ops = { .owner = THIS_MODULE, - .write = omap_wdt_write, - .unlocked_ioctl = omap_wdt_ioctl, - .open = omap_wdt_open, - .release = omap_wdt_release, - .llseek = no_llseek, + .start = omap_wdt_start, + .stop = omap_wdt_stop, + .ping = omap_wdt_ping, + .set_timeout = omap_wdt_set_timeout, +}; + +static const struct watchdog_info omap_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | + WDIOF_CARDRESET, + .identity = "Omap Watchdog", }; static int __devinit omap_wdt_probe(struct platform_device *pdev) { + struct omap_wdt_drvdata *omap_drvdata; + struct watchdog_device *omap_wdev; struct resource *res, *mem; - struct omap_wdt_dev *wdev; int ret; /* reserve static register mappings */ @@ -286,68 +216,62 @@ static int __devinit omap_wdt_probe(struct platform_device *pdev) 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) { + omap_drvdata = devm_kzalloc(&pdev->dev, sizeof(struct omap_wdt_drvdata), + GFP_KERNEL); + if (!omap_drvdata) { + dev_err(&pdev->dev, "Unable to allocate watchdog device\n"); ret = -ENOMEM; goto err_kzalloc; } - wdev->omap_wdt_users = 0; - wdev->mem = mem; - wdev->dev = &pdev->dev; + omap_drvdata->dev = &pdev->dev; + omap_wdev = &omap_drvdata->wdt; + omap_wdev->info = &omap_wdt_info; + omap_wdev->ops = &omap_wdt_ops; + omap_wdev->timeout = TIMER_MARGIN_DEFAULT; + omap_wdev->min_timeout = 1; + omap_wdev->max_timeout = TIMER_MARGIN_MAX; +#ifdef CONFIG_WATCHDOG_NOWAYOUT + watchdog_set_nowayout(omap_wdev, true); +#endif + watchdog_set_drvdata(omap_wdev, omap_drvdata); - wdev->base = ioremap(res->start, resource_size(res)); - if (!wdev->base) { + omap_drvdata->base = ioremap(res->start, resource_size(res)); + if (!omap_drvdata->base) { ret = -ENOMEM; - goto err_ioremap; + goto err_kzalloc; } - 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; + ret = watchdog_register_device(&omap_drvdata->wdt); + if (ret < 0) + goto err_register_wd; + + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + omap_wdt_disable(omap_drvdata); + pm_runtime_put_sync(&pdev->dev); + platform_set_drvdata(pdev, omap_drvdata); + + /* For omap16xx we just keep it original as-is */ + if (cpu_is_omap16xx()) + omap_wdev->bootstatus = __raw_readw(ARM_SYSST); + else + omap_wdev->bootstatus = (omap_prcm_get_reset_sources() & 0x10) + >> OMAP3_PRM_RSTST_WD_BIT; + pr_info("OMAP WDTimer Rev 0x%02x: Initial timeout %dsec status= 0x%x\n", + __raw_readl(omap_drvdata->base + OMAP_WATCHDOG_REV) + & 0xFF, timer_margin, omap_wdev->bootstatus); return 0; -err_misc: - pm_runtime_disable(wdev->dev); - platform_set_drvdata(pdev, NULL); - iounmap(wdev->base); - -err_ioremap: - wdev->base = NULL; - kfree(wdev); +err_register_wd: + iounmap(omap_drvdata->base); err_kzalloc: release_mem_region(res->start, resource_size(res)); @@ -358,34 +282,17 @@ 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 omap_wdt_drvdata *omap_wdev = platform_get_drvdata(pdev); struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pm_runtime_disable(wdev->dev); - if (!res) - return -ENOENT; + pm_runtime_disable(&pdev->dev); - 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; + iounmap(omap_wdev->base); return 0; } @@ -400,12 +307,12 @@ static int __devexit omap_wdt_remove(struct platform_device *pdev) static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) { - struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); + struct omap_wdt_drvdata *omap_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); + if (test_bit(WDOG_DEV_OPEN, &omap_wdev->wdt.status)) { + pm_runtime_get_sync(&pdev->dev); + omap_wdt_disable(omap_wdev); + pm_runtime_put_sync(&pdev->dev); } return 0; @@ -413,13 +320,12 @@ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) 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); + struct omap_wdt_drvdata *omap_wdev = platform_get_drvdata(pdev); + if (test_bit(WDOG_DEV_OPEN, &omap_wdev->wdt.status)) { + pm_runtime_get_sync(&pdev->dev); + omap_wdt_enable(omap_wdev); + omap_wdt_ping(&omap_wdev->wdt); + pm_runtime_put_sync(&pdev->dev); } return 0; @@ -433,7 +339,6 @@ static int omap_wdt_resume(struct platform_device *pdev) 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 = { @@ -446,5 +351,4 @@ module_platform_driver(omap_wdt_driver); MODULE_AUTHOR("George G. Davis"); MODULE_LICENSE("GPL"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); MODULE_ALIAS("platform:omap_wdt"); diff --git a/drivers/watchdog/omap_wdt.h b/drivers/watchdog/omap_wdt.h index 09b774c..cf5f037 100644 --- a/drivers/watchdog/omap_wdt.h +++ b/drivers/watchdog/omap_wdt.h @@ -51,4 +51,9 @@ #define PTV 0 /* prescale */ #define GET_WLDR_VAL(secs) (0xffffffff - ((secs) * (32768/(1<