aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-21 17:10:29 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-21 17:10:29 -0800
commit4fe19a136a8871e5fc6e44d72979f18a4968c2ab (patch)
tree785366514a250acd3f38f91686f2c886dc34cfb9
parent769cb858c23ba7379ea27208624b444cd7b61af2 (diff)
parentd692170037c0338b31dac5ac4722c1360a4b5257 (diff)
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck: "This includes some fixes and code improvements (like clk_prepare_enable and clk_disable_unprepare), conversion from the omap_wdt and twl4030_wdt drivers to the watchdog framework, addition of the SB8x0 chipset support and the DA9055 Watchdog driver and some OF support for the davinci_wdt driver." * git://www.linux-watchdog.org/linux-watchdog: (22 commits) watchdog: mei: avoid oops in watchdog unregister code path watchdog: Orion: Fix possible null-deference in orion_wdt_probe watchdog: sp5100_tco: Add SB8x0 chipset support watchdog: davinci_wdt: add OF support watchdog: da9052: Fix invalid free of devm_ allocated data watchdog: twl4030_wdt: Change TWL4030_MODULE_PM_RECEIVER to TWL_MODULE_PM_RECEIVER watchdog: remove depends on CONFIG_EXPERIMENTAL watchdog: Convert dev_printk(KERN_<LEVEL> to dev_<level>( watchdog: DA9055 Watchdog driver watchdog: omap_wdt: eliminate goto watchdog: omap_wdt: delete redundant platform_set_drvdata() calls watchdog: omap_wdt: convert to devm_ functions watchdog: omap_wdt: convert to new watchdog core watchdog: WatchDog Timer Driver Core: fix comment watchdog: s3c2410_wdt: use clk_prepare_enable and clk_disable_unprepare watchdog: imx2_wdt: Select the driver via ARCH_MXC watchdog: cpu5wdt.c: add missing del_timer call watchdog: hpwdt.c: Increase version string watchdog: Convert twl4030_wdt to watchdog core davinci_wdt: preparation for switch to common clock framework ...
-rw-r--r--Documentation/devicetree/bindings/watchdog/davinci-wdt.txt12
-rw-r--r--drivers/misc/mei/wd.c2
-rw-r--r--drivers/watchdog/Kconfig18
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/ath79_wdt.c13
-rw-r--r--drivers/watchdog/cpu5wdt.c1
-rw-r--r--drivers/watchdog/da9052_wdt.c4
-rw-r--r--drivers/watchdog/da9055_wdt.c216
-rw-r--r--drivers/watchdog/davinci_wdt.c11
-rw-r--r--drivers/watchdog/hpwdt.c2
-rw-r--r--drivers/watchdog/mpcore_wdt.c19
-rw-r--r--drivers/watchdog/omap_wdt.c311
-rw-r--r--drivers/watchdog/orion_wdt.c2
-rw-r--r--drivers/watchdog/s3c2410_wdt.c6
-rw-r--r--drivers/watchdog/sp5100_tco.c321
-rw-r--r--drivers/watchdog/sp5100_tco.h46
-rw-r--r--drivers/watchdog/sp805_wdt.c11
-rw-r--r--drivers/watchdog/twl4030_wdt.c185
-rw-r--r--include/linux/watchdog.h2
19 files changed, 738 insertions, 445 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt
new file mode 100644
index 00000000000..75558ccd9a0
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt
@@ -0,0 +1,12 @@
+DaVinci Watchdog Timer (WDT) Controller
+
+Required properties:
+- compatible : Should be "ti,davinci-wdt"
+- reg : Should contain WDT registers location and length
+
+Examples:
+
+wdt: wdt@2320000 {
+ compatible = "ti,davinci-wdt";
+ reg = <0x02320000 0x80>;
+};
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 636409f9667..9299a8c29a6 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -370,7 +370,7 @@ void mei_watchdog_register(struct mei_device *dev)
void mei_watchdog_unregister(struct mei_device *dev)
{
- if (test_bit(WDOG_UNREGISTERED, &amt_wd_dev.status))
+ if (watchdog_get_drvdata(&amt_wd_dev) == NULL)
return;
watchdog_set_drvdata(&amt_wd_dev, NULL);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index ad1bb9382a9..7f809fd4a57 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -76,6 +76,16 @@ config DA9052_WATCHDOG
Alternatively say M to compile the driver as a module,
which will be called da9052_wdt.
+config DA9055_WATCHDOG
+ tristate "Dialog Semiconductor DA9055 Watchdog"
+ depends on MFD_DA9055
+ help
+ If you say yes here you get support for watchdog on the Dialog
+ Semiconductor DA9055 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called da9055_wdt.
+
config WM831X_WATCHDOG
tristate "WM831x watchdog"
depends on MFD_WM831X
@@ -232,6 +242,7 @@ config EP93XX_WATCHDOG
config OMAP_WATCHDOG
tristate "OMAP Watchdog"
depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
+ select WATCHDOG_CORE
help
Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y'
here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
@@ -300,6 +311,7 @@ config COH901327_WATCHDOG
config TWL4030_WATCHDOG
tristate "TWL4030 Watchdog"
depends on TWL4030_CORE
+ select WATCHDOG_CORE
help
Support for TI TWL4030 watchdog. Say 'Y' here to enable the
watchdog timer support for TWL4030 chips.
@@ -342,7 +354,7 @@ config MAX63XX_WATCHDOG
config IMX2_WDT
tristate "IMX2+ Watchdog"
- depends on IMX_HAVE_PLATFORM_IMX2_WDT
+ depends on ARCH_MXC
help
This is the driver for the hardware watchdog
on the Freescale IMX2 and later processors.
@@ -431,7 +443,7 @@ config ALIM7101_WDT
config F71808E_WDT
tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
- depends on X86 && EXPERIMENTAL
+ depends on X86
help
This is the driver for the hardware watchdog on the Fintek
F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
@@ -622,7 +634,7 @@ config IT8712F_WDT
config IT87_WDT
tristate "IT87 Watchdog Timer"
- depends on X86 && EXPERIMENTAL
+ depends on X86
---help---
This is the driver for the hardware watchdog on the ITE IT8702,
IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 572b39bed06..97bbdb3a464 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -164,6 +164,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o
# Architecture Independent
obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
+obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index 7c8ede7816b..38a999e60c0 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -284,6 +284,7 @@ static void ath97_wdt_shutdown(struct platform_device *pdev)
}
static struct platform_driver ath79_wdt_driver = {
+ .probe = ath79_wdt_probe,
.remove = ath79_wdt_remove,
.shutdown = ath97_wdt_shutdown,
.driver = {
@@ -292,17 +293,7 @@ static struct platform_driver ath79_wdt_driver = {
},
};
-static int __init ath79_wdt_init(void)
-{
- return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe);
-}
-module_init(ath79_wdt_init);
-
-static void __exit ath79_wdt_exit(void)
-{
- platform_driver_unregister(&ath79_wdt_driver);
-}
-module_exit(ath79_wdt_exit);
+module_platform_driver(ath79_wdt_driver);
MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver");
MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c
index cd87758abac..f270bb7bc45 100644
--- a/drivers/watchdog/cpu5wdt.c
+++ b/drivers/watchdog/cpu5wdt.c
@@ -266,6 +266,7 @@ static void cpu5wdt_exit(void)
if (cpu5wdt_device.queue) {
cpu5wdt_device.queue = 0;
wait_for_completion(&cpu5wdt_device.stop);
+ del_timer(&cpu5wdt_device.timer);
}
misc_deregister(&cpu5wdt_misc);
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c
index 8be70d8f268..367445009c6 100644
--- a/drivers/watchdog/da9052_wdt.c
+++ b/drivers/watchdog/da9052_wdt.c
@@ -53,10 +53,6 @@ static const struct {
static void da9052_wdt_release_resources(struct kref *r)
{
- struct da9052_wdt_data *driver_data =
- container_of(r, struct da9052_wdt_data, kref);
-
- kfree(driver_data);
}
static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c
new file mode 100644
index 00000000000..709ea1aefeb
--- /dev/null
+++ b/drivers/watchdog/da9055_wdt.c
@@ -0,0 +1,216 @@
+/*
+ * System monitoring driver for DA9055 PMICs.
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: David Dajun Chen <dchen@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+#include <linux/delay.h>
+
+#include <linux/mfd/da9055/core.h>
+#include <linux/mfd/da9055/reg.h>
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+ "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+#define DA9055_DEF_TIMEOUT 4
+#define DA9055_TWDMIN 256
+
+struct da9055_wdt_data {
+ struct watchdog_device wdt;
+ struct da9055 *da9055;
+ struct kref kref;
+};
+
+static const struct {
+ u8 reg_val;
+ int user_time; /* In seconds */
+} da9055_wdt_maps[] = {
+ { 0, 0 },
+ { 1, 2 },
+ { 2, 4 },
+ { 3, 8 },
+ { 4, 16 },
+ { 5, 32 },
+ { 5, 33 }, /* Actual time 32.768s so included both 32s and 33s */
+ { 6, 65 },
+ { 6, 66 }, /* Actual time 65.536s so include both, 65s and 66s */
+ { 7, 131 },
+};
+
+static int da9055_wdt_set_timeout(struct watchdog_device *wdt_dev,
+ unsigned int timeout)
+{
+ struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+ struct da9055 *da9055 = driver_data->da9055;
+ int ret, i;
+
+ for (i = 0; i < ARRAY_SIZE(da9055_wdt_maps); i++)
+ if (da9055_wdt_maps[i].user_time == timeout)
+ break;
+
+ if (i == ARRAY_SIZE(da9055_wdt_maps))
+ ret = -EINVAL;
+ else
+ ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
+ DA9055_TWDSCALE_MASK,
+ da9055_wdt_maps[i].reg_val <<
+ DA9055_TWDSCALE_SHIFT);
+ if (ret < 0)
+ dev_err(da9055->dev,
+ "Failed to update timescale bit, %d\n", ret);
+
+ wdt_dev->timeout = timeout;
+
+ return ret;
+}
+
+static int da9055_wdt_ping(struct watchdog_device *wdt_dev)
+{
+ struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+ struct da9055 *da9055 = driver_data->da9055;
+ int ret;
+
+ /*
+ * We have a minimum time for watchdog window called TWDMIN. A write
+ * to the watchdog before this elapsed time will cause an error.
+ */
+ mdelay(DA9055_TWDMIN);
+
+ /* Reset the watchdog timer */
+ ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_E,
+ DA9055_WATCHDOG_MASK, 1);
+
+ return ret;
+}
+
+static void da9055_wdt_release_resources(struct kref *r)
+{
+ struct da9055_wdt_data *driver_data =
+ container_of(r, struct da9055_wdt_data, kref);
+
+ kfree(driver_data);
+}
+
+static void da9055_wdt_ref(struct watchdog_device *wdt_dev)
+{
+ struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+
+ kref_get(&driver_data->kref);
+}
+
+static void da9055_wdt_unref(struct watchdog_device *wdt_dev)
+{
+ struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
+
+ kref_put(&driver_data->kref, da9055_wdt_release_resources);
+}
+
+static int da9055_wdt_start(struct watchdog_device *wdt_dev)
+{
+ return da9055_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+}
+
+static int da9055_wdt_stop(struct watchdog_device *wdt_dev)
+{
+ return da9055_wdt_set_timeout(wdt_dev, 0);
+}
+
+static struct watchdog_info da9055_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "DA9055 Watchdog",
+};
+
+static const struct watchdog_ops da9055_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = da9055_wdt_start,
+ .stop = da9055_wdt_stop,
+ .ping = da9055_wdt_ping,
+ .set_timeout = da9055_wdt_set_timeout,
+ .ref = da9055_wdt_ref,
+ .unref = da9055_wdt_unref,
+};
+
+static int da9055_wdt_probe(struct platform_device *pdev)
+{
+ struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
+ struct da9055_wdt_data *driver_data;
+ struct watchdog_device *da9055_wdt;
+ int ret;
+
+ driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
+ GFP_KERNEL);
+ if (!driver_data) {
+ dev_err(da9055->dev, "Failed to allocate watchdog device\n");
+ return -ENOMEM;
+ }
+
+ driver_data->da9055 = da9055;
+
+ da9055_wdt = &driver_data->wdt;
+
+ da9055_wdt->timeout = DA9055_DEF_TIMEOUT;
+ da9055_wdt->info = &da9055_wdt_info;
+ da9055_wdt->ops = &da9055_wdt_ops;
+ watchdog_set_nowayout(da9055_wdt, nowayout);
+ watchdog_set_drvdata(da9055_wdt, driver_data);
+
+ kref_init(&driver_data->kref);
+
+ ret = da9055_wdt_stop(da9055_wdt);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
+ goto err;
+ }
+
+ dev_set_drvdata(&pdev->dev, driver_data);
+
+ ret = watchdog_register_device(&driver_data->wdt);
+ if (ret != 0)
+ dev_err(da9055->dev, "watchdog_register_device() failed: %d\n",
+ ret);
+
+err:
+ return ret;
+}
+
+static int da9055_wdt_remove(struct platform_device *pdev)
+{
+ struct da9055_wdt_data *driver_data = dev_get_drvdata(&pdev->dev);
+
+ watchdog_unregister_device(&driver_data->wdt);
+ kref_put(&driver_data->kref, da9055_wdt_release_resources);
+
+ return 0;
+}
+
+static struct platform_driver da9055_wdt_driver = {
+ .probe = da9055_wdt_probe,
+ .remove = da9055_wdt_remove,
+ .driver = {
+ .name = "da9055-watchdog",
+ },
+};
+
+module_platform_driver(da9055_wdt_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("DA9055 watchdog");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9055-watchdog");
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index 8791879e518..e8e87246ea6 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -208,7 +208,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
if (WARN_ON(IS_ERR(wdt_clk)))
return PTR_ERR(wdt_clk);
- clk_enable(wdt_clk);
+ clk_prepare_enable(wdt_clk);
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT;
@@ -256,16 +256,23 @@ static int davinci_wdt_remove(struct platform_device *pdev)
wdt_mem = NULL;
}
- clk_disable(wdt_clk);
+ clk_disable_unprepare(wdt_clk);
clk_put(wdt_clk);
return 0;
}
+static const struct of_device_id davinci_wdt_of_match[] = {
+ { .compatible = "ti,davinci-wdt", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, davinci_wdt_of_match);
+
static struct platform_driver platform_wdt_driver = {
.driver = {
.name = "watchdog",
.owner = THIS_MODULE,
+ .of_match_table = davinci_wdt_of_match,
},
.probe = davinci_wdt_probe,
.remove = davinci_wdt_remove,
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 8717255ec7b..11796b9b864 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -39,7 +39,7 @@
#endif /* CONFIG_HPWDT_NMI_DECODING */
#include <asm/nmi.h>
-#define HPWDT_VERSION "1.3.0"
+#define HPWDT_VERSION "1.3.1"
#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index a84eb551ea2..233cfadcb21 100644
--- a/drivers/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -80,8 +80,7 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
/* Check it really was our interrupt */
if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
- dev_printk(KERN_CRIT, wdt->dev,
- "Triggered - Reboot ignored.\n");
+ dev_crit(wdt->dev, "Triggered - Reboot ignored\n");
/* Clear the interrupt on the watchdog */
writel(1, wdt->base + TWD_WDOG_INTSTAT);
return IRQ_HANDLED;
@@ -123,7 +122,7 @@ static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
static void mpcore_wdt_start(struct mpcore_wdt *wdt)
{
- dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n");
+ dev_info(wdt->dev, "enabling watchdog\n");
/* This loads the count register but does NOT start the count yet */
mpcore_wdt_keepalive(wdt);
@@ -180,8 +179,8 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
if (wdt->expect_close == 42)
mpcore_wdt_stop(wdt);
else {
- dev_printk(KERN_CRIT, wdt->dev,
- "unexpected close, not stopping watchdog!\n");
+ dev_crit(wdt->dev,
+ "unexpected close, not stopping watchdog!\n");
mpcore_wdt_keepalive(wdt);
}
clear_bit(0, &wdt->timer_alive);
@@ -351,9 +350,9 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
"mpcore_wdt", wdt);
if (ret) {
- dev_printk(KERN_ERR, wdt->dev,
- "cannot register IRQ%d for watchdog\n",
- wdt->irq);
+ dev_err(wdt->dev,
+ "cannot register IRQ%d for watchdog\n",
+ wdt->irq);
return ret;
}
}
@@ -365,9 +364,9 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
mpcore_wdt_miscdev.parent = &pdev->dev;
ret = misc_register(&mpcore_wdt_miscdev);
if (ret) {
- dev_printk(KERN_ERR, wdt->dev,
+ dev_err(wdt->dev,
"cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
+ WATCHDOG_MINOR, ret);
return ret;
}
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 3e3ebbc83fa..34ed61ea02b 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -31,42 +31,34 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <linux/fs.h>
#include <linux/mm.h>
-#include <linux/miscdevice.h>
#include <linux/watchdog.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/moduleparam.h>
-#include <linux/bitops.h>
#include <linux/io.h>
-#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/omap-wd-timer.h>
#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)");
-static unsigned int wdt_trgr_pattern = 0x1234;
-static DEFINE_SPINLOCK(wdt_lock);
-
struct omap_wdt_dev {
void __iomem *base; /* physical */
struct device *dev;
- int omap_wdt_users;
+ bool omap_wdt_users;
struct resource *mem;
- struct miscdevice omap_wdt_miscdev;
+ int wdt_trgr_pattern;
+ struct mutex lock; /* to avoid races with PM */
};
-static void omap_wdt_ping(struct omap_wdt_dev *wdev)
+static void omap_wdt_reload(struct omap_wdt_dev *wdev)
{
void __iomem *base = wdev->base;
@@ -74,8 +66,8 @@ static void omap_wdt_ping(struct omap_wdt_dev *wdev)
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));
+ wdev->wdt_trgr_pattern = ~wdev->wdt_trgr_pattern;
+ __raw_writel(wdev->wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
/* wait for posted write to complete */
while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
@@ -111,18 +103,10 @@ static void omap_wdt_disable(struct omap_wdt_dev *wdev)
cpu_relax();
}
-static void omap_wdt_adjust_timeout(unsigned new_timeout)
-{
- if (new_timeout < TIMER_MARGIN_MIN)
- new_timeout = TIMER_MARGIN_DEFAULT;
- if (new_timeout > TIMER_MARGIN_MAX)
- new_timeout = TIMER_MARGIN_MAX;
- timer_margin = new_timeout;
-}
-
-static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
+static void omap_wdt_set_timer(struct omap_wdt_dev *wdev,
+ unsigned int timeout)
{
- u32 pre_margin = GET_WLDR_VAL(timer_margin);
+ u32 pre_margin = GET_WLDR_VAL(timeout);
void __iomem *base = wdev->base;
/* just count up at 32 KHz */
@@ -134,16 +118,14 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
cpu_relax();
}
-/*
- * Allow only one task to hold it open
- */
-static int omap_wdt_open(struct inode *inode, struct file *file)
+static int omap_wdt_start(struct watchdog_device *wdog)
{
- struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev);
+ struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
void __iomem *base = wdev->base;
- if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users)))
- return -EBUSY;
+ mutex_lock(&wdev->lock);
+
+ wdev->omap_wdt_users = true;
pm_runtime_get_sync(wdev->dev);
@@ -155,223 +137,169 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
cpu_relax();
- file->private_data = (void *) wdev;
-
- omap_wdt_set_timeout(wdev);
- omap_wdt_ping(wdev); /* trigger loading of new timeout value */
+ omap_wdt_set_timer(wdev, wdog->timeout);
+ omap_wdt_reload(wdev); /* trigger loading of new timeout value */
omap_wdt_enable(wdev);
- return nonseekable_open(inode, file);
+ mutex_unlock(&wdev->lock);
+
+ return 0;
}
-static int omap_wdt_release(struct inode *inode, struct file *file)
+static int omap_wdt_stop(struct watchdog_device *wdog)
{
- struct omap_wdt_dev *wdev = file->private_data;
+ struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
- /*
- * Shut off the timer unless NOWAYOUT is defined.
- */
-#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ mutex_lock(&wdev->lock);
omap_wdt_disable(wdev);
-
pm_runtime_put_sync(wdev->dev);
-#else
- pr_crit("Unexpected close, not stopping!\n");
-#endif
- wdev->omap_wdt_users = 0;
-
+ wdev->omap_wdt_users = false;
+ mutex_unlock(&wdev->lock);
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_ping(struct watchdog_device *wdog)
{
- struct omap_wdt_dev *wdev = file->private_data;
+ struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
- /* Refresh LOAD_TIME. */
- if (len) {
- spin_lock(&wdt_lock);
- omap_wdt_ping(wdev);
- spin_unlock(&wdt_lock);
- }
- return len;
+ mutex_lock(&wdev->lock);
+ omap_wdt_reload(wdev);
+ mutex_unlock(&wdev->lock);
+
+ return 0;
}
-static long omap_wdt_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static int omap_wdt_set_timeout(struct watchdog_device *wdog,
+ unsigned int timeout)
{
- struct omap_wd_timer_platform_data *pdata;
- struct omap_wdt_dev *wdev;
- u32 rs;
- int new_margin, bs;
- static const struct watchdog_info ident = {
- .identity = "OMAP Watchdog",
- .options = WDIOF_SETTIMEOUT,
- .firmware_version = 0,
- };
-
- wdev = file->private_data;
- pdata = wdev->dev->platform_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 (!pdata || !pdata->read_reset_sources)
- return put_user(0, (int __user *)arg);
- rs = pdata->read_reset_sources();
- bs = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
- WDIOF_CARDRESET : 0;
- return put_user(bs, (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);
+ struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
- omap_wdt_ping(wdev);
- spin_unlock(&wdt_lock);
- /* Fall */
- case WDIOC_GETTIMEOUT:
- return put_user(timer_margin, (int __user *)arg);
- default:
- return -ENOTTY;
- }
+ 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 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 const struct watchdog_info omap_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "OMAP Watchdog",
+};
+
+static const struct watchdog_ops omap_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = omap_wdt_start,
+ .stop = omap_wdt_stop,
+ .ping = omap_wdt_ping,
+ .set_timeout = omap_wdt_set_timeout,
};
static int omap_wdt_probe(struct platform_device *pdev)
{
+ struct omap_wd_timer_platform_data *pdata = pdev->dev.platform_data;
+ bool nowayout = WATCHDOG_NOWAYOUT;
+ struct watchdog_device *omap_wdt;
struct resource *res, *mem;
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;
+
/* reserve static register mappings */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENOENT;
- goto err_get_resource;
- }
+ if (!res)
+ return -ENOENT;
- if (omap_wdt_dev) {
- ret = -EBUSY;
- goto err_busy;
- }
+ mem = devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name);
+ if (!mem)
+ return -EBUSY;
- mem = request_mem_region(res->start, resource_size(res), pdev->name);
- if (!mem) {
- ret = -EBUSY;
- goto err_busy;
- }
+ wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
+ if (!wdev)
+ return -ENOMEM;
- wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL);
- if (!wdev) {
- ret = -ENOMEM;
- goto err_kzalloc;
- }
+ wdev->omap_wdt_users = false;
+ wdev->mem = mem;
+ wdev->dev = &pdev->dev;
+ wdev->wdt_trgr_pattern = 0x1234;
+ mutex_init(&wdev->lock);
- wdev->omap_wdt_users = 0;
- wdev->mem = mem;
- wdev->dev = &pdev->dev;
+ wdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
+ if (!wdev->base)
+ return -ENOMEM;
- wdev->base = ioremap(res->start, resource_size(res));
- if (!wdev->base) {
- ret = -ENOMEM;
- goto err_ioremap;
- }
+ 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;
- platform_set_drvdata(pdev, wdev);
+ 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);
- omap_wdt_disable(wdev);
- omap_wdt_adjust_timeout(timer_margin);
+ 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;
- 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;
+ omap_wdt_disable(wdev);
- ret = misc_register(&(wdev->omap_wdt_miscdev));
- if (ret)
- goto err_misc;
+ 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,
- timer_margin);
+ omap_wdt->timeout);
pm_runtime_put_sync(wdev->dev);
- omap_wdt_dev = pdev;
-
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_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);
+ struct watchdog_device *wdog = platform_get_drvdata(pdev);
+ struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ 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_remove(struct platform_device *pdev)
{
- struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
+ struct watchdog_device *wdog = platform_get_drvdata(pdev);
+ struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pm_runtime_disable(wdev->dev);
- 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;
+ watchdog_unregister_device(wdog);
return 0;
}
@@ -386,25 +314,31 @@ static int 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 watchdog_device *wdog = platform_get_drvdata(pdev);
+ struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ mutex_lock(&wdev->lock);
if (wdev->omap_wdt_users) {
omap_wdt_disable(wdev);
p