aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Ellerman <mpe@ellerman.id.au>2015-06-05 17:47:32 +1000
committerMichael Ellerman <mpe@ellerman.id.au>2015-06-05 17:47:32 +1000
commit9d34ffda422ad2078205a03352cb1f97e5711742 (patch)
tree743241c614a0676c29d5e2b83903e14f735ee451
parent76431b9d6aea112d85ab3d6cb6fbbd15b6a9d54f (diff)
parent32e263fc42c8e6ed1165710772afc678c8c248c4 (diff)
downloadlinux-next-9d34ffda422ad2078205a03352cb1f97e5711742.tar.gz
Merge remote-tracking branch 'watchdog/master'
Conflicts: drivers/watchdog/Kconfig drivers/watchdog/st_lpc_wdt.c
-rw-r--r--Documentation/devicetree/bindings/watchdog/digicolor-wdt.txt25
-rw-r--r--Documentation/devicetree/bindings/watchdog/omap-wdt.txt9
-rw-r--r--drivers/watchdog/Kconfig16
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/at91sam9_wdt.c4
-rw-r--r--drivers/watchdog/digicolor_wdt.c205
-rw-r--r--drivers/watchdog/dw_wdt.c8
-rw-r--r--drivers/watchdog/imgpdc_wdt.c84
-rw-r--r--drivers/watchdog/imx2_wdt.c3
-rw-r--r--drivers/watchdog/max63xx_wdt.c2
-rw-r--r--drivers/watchdog/mena21_wdt.c5
-rw-r--r--drivers/watchdog/omap_wdt.c73
-rw-r--r--drivers/watchdog/st_lpc_wdt.c2
13 files changed, 366 insertions, 71 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/digicolor-wdt.txt b/Documentation/devicetree/bindings/watchdog/digicolor-wdt.txt
new file mode 100644
index 0000000000000..a882967e17d4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/digicolor-wdt.txt
@@ -0,0 +1,25 @@
+Conexant Digicolor SoCs Watchdog timer
+
+The watchdog functionality in Conexant Digicolor SoCs relies on the so called
+"Agent Communication" block. This block includes the eight programmable system
+timer counters. The first timer (called "Timer A") is the only one that can be
+used as watchdog.
+
+Required properties:
+
+- compatible : Should be "cnxt,cx92755-wdt"
+- reg : Specifies base physical address and size of the registers
+- clocks : phandle; specifies the clock that drives the timer
+
+Optional properties:
+
+- timeout-sec : Contains the watchdog timeout in seconds
+
+Example:
+
+ watchdog@f0000fc0 {
+ compatible = "cnxt,cx92755-wdt";
+ reg = <0xf0000fc0 0x8>;
+ clocks = <&main_clk>;
+ timeout-sec = <15>;
+ };
diff --git a/Documentation/devicetree/bindings/watchdog/omap-wdt.txt b/Documentation/devicetree/bindings/watchdog/omap-wdt.txt
index c227970671ea3..1fa20e453a2d0 100644
--- a/Documentation/devicetree/bindings/watchdog/omap-wdt.txt
+++ b/Documentation/devicetree/bindings/watchdog/omap-wdt.txt
@@ -1,10 +1,11 @@
TI Watchdog Timer (WDT) Controller for OMAP
Required properties:
-compatible:
-- "ti,omap3-wdt" for OMAP3
-- "ti,omap4-wdt" for OMAP4
-- ti,hwmods: Name of the hwmod associated to the WDT
+- compatible : "ti,omap3-wdt" for OMAP3 or "ti,omap4-wdt" for OMAP4
+- ti,hwmods : Name of the hwmod associated to the WDT
+
+Optional properties:
+- timeout-sec : default watchdog timeout in seconds
Examples:
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 262647bbc6144..8caff7d361c42 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -169,6 +169,7 @@ config AT91SAM9X_WATCHDOG
config CADENCE_WATCHDOG
tristate "Cadence Watchdog Timer"
+ depends on HAS_IOMEM
select WATCHDOG_CORE
help
Say Y here if you want to include support for the watchdog
@@ -408,7 +409,7 @@ config TS72XX_WATCHDOG
config MAX63XX_WATCHDOG
tristate "Max63xx watchdog"
- depends on ARM && HAS_IOMEM
+ depends on HAS_IOMEM
select WATCHDOG_CORE
help
Support for memory mapped max63{69,70,71,72,73,74} watchdog timer.
@@ -475,6 +476,7 @@ config ST_LPC_WATCHDOG
depends on ARCH_STI
depends on OF
select WATCHDOG_CORE
+ select MFD_ST_LPC
help
Say Y here to include STMicroelectronics Low Power Controller
(LPC) based Watchdog timer support.
@@ -526,6 +528,16 @@ config MEDIATEK_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called mtk_wdt.
+config DIGICOLOR_WATCHDOG
+ tristate "Conexant Digicolor SoCs watchdog support"
+ depends on ARCH_DIGICOLOR
+ select WATCHDOG_CORE
+ help
+ Say Y here to include support for the watchdog timer
+ in Conexant Digicolor SoCs.
+ To compile this driver as a module, choose M here: the
+ module will be called digicolor_wdt.
+
# AVR32 Architecture
config AT32AP700X_WDT
@@ -1355,7 +1367,7 @@ config BOOKE_WDT_DEFAULT_TIMEOUT
config MEN_A21_WDT
tristate "MEN A21 VME CPU Carrier Board Watchdog Timer"
select WATCHDOG_CORE
- depends on GPIOLIB
+ depends on GPIOLIB || COMPILE_TEST
help
Watchdog driver for MEN A21 VMEbus CPU Carrier Boards.
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index d98768c7d928c..4e26613a7f52b 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o
obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o
+obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c
index 1443b3c391de4..e4698f7c5f930 100644
--- a/drivers/watchdog/at91sam9_wdt.c
+++ b/drivers/watchdog/at91sam9_wdt.c
@@ -40,9 +40,9 @@
#define DRV_NAME "AT91SAM9 Watchdog"
#define wdt_read(wdt, field) \
- __raw_readl((wdt)->base + (field))
+ readl_relaxed((wdt)->base + (field))
#define wdt_write(wtd, field, val) \
- __raw_writel((val), (wdt)->base + (field))
+ writel_relaxed((val), (wdt)->base + (field))
/* AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
* use this to convert a watchdog
diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c
new file mode 100644
index 0000000000000..31d8e4936611e
--- /dev/null
+++ b/drivers/watchdog/digicolor_wdt.c
@@ -0,0 +1,205 @@
+/*
+ * Watchdog driver for Conexant Digicolor
+ *
+ * Copyright (C) 2015 Paradox Innovation Ltd.
+ *
+ * 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/types.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/platform_device.h>
+#include <linux/of_address.h>
+
+#define TIMER_A_CONTROL 0
+#define TIMER_A_COUNT 4
+
+#define TIMER_A_ENABLE_COUNT BIT(0)
+#define TIMER_A_ENABLE_WATCHDOG BIT(1)
+
+struct dc_wdt {
+ void __iomem *base;
+ struct clk *clk;
+ struct notifier_block restart_handler;
+ spinlock_t lock;
+};
+
+static unsigned timeout;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
+
+static void dc_wdt_set(struct dc_wdt *wdt, u32 ticks)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&wdt->lock, flags);
+
+ writel_relaxed(0, wdt->base + TIMER_A_CONTROL);
+ writel_relaxed(ticks, wdt->base + TIMER_A_COUNT);
+ writel_relaxed(TIMER_A_ENABLE_COUNT | TIMER_A_ENABLE_WATCHDOG,
+ wdt->base + TIMER_A_CONTROL);
+
+ spin_unlock_irqrestore(&wdt->lock, flags);
+}
+
+static int dc_restart_handler(struct notifier_block *this, unsigned long mode,
+ void *cmd)
+{
+ struct dc_wdt *wdt = container_of(this, struct dc_wdt, restart_handler);
+
+ dc_wdt_set(wdt, 1);
+ /* wait for reset to assert... */
+ mdelay(500);
+
+ return NOTIFY_DONE;
+}
+
+static int dc_wdt_start(struct watchdog_device *wdog)
+{
+ struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
+
+ dc_wdt_set(wdt, wdog->timeout * clk_get_rate(wdt->clk));
+
+ return 0;
+}
+
+static int dc_wdt_stop(struct watchdog_device *wdog)
+{
+ struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
+
+ writel_relaxed(0, wdt->base + TIMER_A_CONTROL);
+
+ return 0;
+}
+
+static int dc_wdt_set_timeout(struct watchdog_device *wdog, unsigned int t)
+{
+ struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
+
+ dc_wdt_set(wdt, t * clk_get_rate(wdt->clk));
+ wdog->timeout = t;
+
+ return 0;
+}
+
+static unsigned int dc_wdt_get_timeleft(struct watchdog_device *wdog)
+{
+ struct dc_wdt *wdt = watchdog_get_drvdata(wdog);
+ uint32_t count = readl_relaxed(wdt->base + TIMER_A_COUNT);
+
+ return count / clk_get_rate(wdt->clk);
+}
+
+static struct watchdog_ops dc_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = dc_wdt_start,
+ .stop = dc_wdt_stop,
+ .set_timeout = dc_wdt_set_timeout,
+ .get_timeleft = dc_wdt_get_timeleft,
+};
+
+static struct watchdog_info dc_wdt_info = {
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE
+ | WDIOF_KEEPALIVEPING,
+ .identity = "Conexant Digicolor Watchdog",
+};
+
+static struct watchdog_device dc_wdt_wdd = {
+ .info = &dc_wdt_info,
+ .ops = &dc_wdt_ops,
+ .min_timeout = 1,
+};
+
+static int dc_wdt_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct dc_wdt *wdt;
+ int ret;
+
+ wdt = devm_kzalloc(dev, sizeof(struct dc_wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, wdt);
+
+ wdt->base = of_iomap(np, 0);
+ if (!wdt->base) {
+ dev_err(dev, "Failed to remap watchdog regs");
+ return -ENODEV;
+ }
+
+ wdt->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(wdt->clk)) {
+ ret = PTR_ERR(wdt->clk);
+ goto err_iounmap;
+ }
+ dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk);
+ dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout;
+
+ spin_lock_init(&wdt->lock);
+
+ watchdog_set_drvdata(&dc_wdt_wdd, wdt);
+ watchdog_init_timeout(&dc_wdt_wdd, timeout, dev);
+ ret = watchdog_register_device(&dc_wdt_wdd);
+ if (ret) {
+ dev_err(dev, "Failed to register watchdog device");
+ goto err_iounmap;
+ }
+
+ wdt->restart_handler.notifier_call = dc_restart_handler;
+ wdt->restart_handler.priority = 128;
+ ret = register_restart_handler(&wdt->restart_handler);
+ if (ret)
+ dev_warn(&pdev->dev, "cannot register restart handler\n");
+
+ return 0;
+
+err_iounmap:
+ iounmap(wdt->base);
+ return ret;
+}
+
+static int dc_wdt_remove(struct platform_device *pdev)
+{
+ struct dc_wdt *wdt = platform_get_drvdata(pdev);
+
+ unregister_restart_handler(&wdt->restart_handler);
+ watchdog_unregister_device(&dc_wdt_wdd);
+ iounmap(wdt->base);
+
+ return 0;
+}
+
+static void dc_wdt_shutdown(struct platform_device *pdev)
+{
+ dc_wdt_stop(&dc_wdt_wdd);
+}
+
+static const struct of_device_id dc_wdt_of_match[] = {
+ { .compatible = "cnxt,cx92755-wdt", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dc_wdt_of_match);
+
+static struct platform_driver dc_wdt_driver = {
+ .probe = dc_wdt_probe,
+ .remove = dc_wdt_remove,
+ .shutdown = dc_wdt_shutdown,
+ .driver = {
+ .name = "digicolor-wdt",
+ .of_match_table = dc_wdt_of_match,
+ },
+};
+module_platform_driver(dc_wdt_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Driver for Conexant Digicolor watchdog timer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index d0bb9499d12ca..6ea0634345e99 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -35,7 +35,6 @@
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
-#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/uaccess.h>
#include <linux/watchdog.h>
@@ -61,7 +60,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
#define WDT_TIMEOUT (HZ / 2)
static struct {
- spinlock_t lock;
void __iomem *regs;
struct clk *clk;
unsigned long in_use;
@@ -177,7 +175,6 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
/* Make sure we don't get unloaded. */
__module_get(THIS_MODULE);
- spin_lock(&dw_wdt.lock);
if (!dw_wdt_is_enabled()) {
/*
* The watchdog is not currently enabled. Set the timeout to
@@ -190,8 +187,6 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
dw_wdt_set_next_heartbeat();
- spin_unlock(&dw_wdt.lock);
-
return nonseekable_open(inode, filp);
}
@@ -220,6 +215,7 @@ static ssize_t dw_wdt_write(struct file *filp, const char __user *buf,
}
dw_wdt_set_next_heartbeat();
+ dw_wdt_keepalive();
mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
return len;
@@ -348,8 +344,6 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
if (ret)
return ret;
- spin_lock_init(&dw_wdt.lock);
-
ret = misc_register(&dw_wdt_miscdev);
if (ret)
goto out_disable_clk;
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c
index 0deaa4f971f5f..0f73621827abf 100644
--- a/drivers/watchdog/imgpdc_wdt.c
+++ b/drivers/watchdog/imgpdc_wdt.c
@@ -9,6 +9,35 @@
*
* Based on drivers/watchdog/sunxi_wdt.c Copyright (c) 2013 Carlo Caione
* 2012 Henrik Nordstrom
+ *
+ * Notes
+ * -----
+ * The timeout value is rounded to the next power of two clock cycles.
+ * This is configured using the PDC_WDT_CONFIG register, according to this
+ * formula:
+ *
+ * timeout = 2^(delay + 1) clock cycles
+ *
+ * Where 'delay' is the value written in PDC_WDT_CONFIG register.
+ *
+ * Therefore, the hardware only allows to program watchdog timeouts, expressed
+ * as a power of two number of watchdog clock cycles. The current implementation
+ * guarantees that the actual watchdog timeout will be _at least_ the value
+ * programmed in the imgpdg_wdt driver.
+ *
+ * The following table shows how the user-configured timeout relates
+ * to the actual hardware timeout (watchdog clock @ 40000 Hz):
+ *
+ * input timeout | WD_DELAY | actual timeout
+ * -----------------------------------
+ * 10 | 18 | 13 seconds
+ * 20 | 19 | 26 seconds
+ * 30 | 20 | 52 seconds
+ * 60 | 21 | 104 seconds
+ *
+ * Albeit coarse, this granularity would suffice most watchdog uses.
+ * If the platform allows it, the user should be able to change the watchdog
+ * clock rate and achieve a finer timeout granularity.
*/
#include <linux/clk.h>
@@ -16,6 +45,7 @@
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/watchdog.h>
@@ -42,7 +72,7 @@
#define PDC_WDT_MIN_TIMEOUT 1
#define PDC_WDT_DEF_TIMEOUT 64
-static int heartbeat = PDC_WDT_DEF_TIMEOUT;
+static int heartbeat;
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds "
"(default=" __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
@@ -57,6 +87,7 @@ struct pdc_wdt_dev {
struct clk *wdt_clk;
struct clk *sys_clk;
void __iomem *base;
+ struct notifier_block restart_handler;
};
static int pdc_wdt_keepalive(struct watchdog_device *wdt_dev)
@@ -84,18 +115,24 @@ static int pdc_wdt_stop(struct watchdog_device *wdt_dev)
return 0;
}
+static void __pdc_wdt_set_timeout(struct pdc_wdt_dev *wdt)
+{
+ unsigned long clk_rate = clk_get_rate(wdt->wdt_clk);
+ unsigned int val;
+
+ val = readl(wdt->base + PDC_WDT_CONFIG) & ~PDC_WDT_CONFIG_DELAY_MASK;
+ val |= order_base_2(wdt->wdt_dev.timeout * clk_rate) - 1;
+ writel(val, wdt->base + PDC_WDT_CONFIG);
+}
+
static int pdc_wdt_set_timeout(struct watchdog_device *wdt_dev,
unsigned int new_timeout)
{
- unsigned int val;
struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev);
- unsigned long clk_rate = clk_get_rate(wdt->wdt_clk);
wdt->wdt_dev.timeout = new_timeout;
- val = readl(wdt->base + PDC_WDT_CONFIG) & ~PDC_WDT_CONFIG_DELAY_MASK;
- val |= order_base_2(new_timeout * clk_rate) - 1;
- writel(val, wdt->base + PDC_WDT_CONFIG);
+ __pdc_wdt_set_timeout(wdt);
return 0;
}
@@ -106,6 +143,8 @@ static int pdc_wdt_start(struct watchdog_device *wdt_dev)
unsigned int val;
struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev);
+ __pdc_wdt_set_timeout(wdt);
+
val = readl(wdt->base + PDC_WDT_CONFIG);
val |= PDC_WDT_CONFIG_ENABLE;
writel(val, wdt->base + PDC_WDT_CONFIG);
@@ -128,8 +167,21 @@ static const struct watchdog_ops pdc_wdt_ops = {
.set_timeout = pdc_wdt_set_timeout,
};
+static int pdc_wdt_restart(struct notifier_block *this, unsigned long mode,
+ void *cmd)
+{
+ struct pdc_wdt_dev *wdt = container_of(this, struct pdc_wdt_dev,
+ restart_handler);
+
+ /* Assert SOFT_RESET */
+ writel(0x1, wdt->base + PDC_WDT_SOFT_RESET);
+
+ return NOTIFY_OK;
+}
+
static int pdc_wdt_probe(struct platform_device *pdev)
{
+ u64 div;
int ret, val;
unsigned long clk_rate;
struct resource *res;
@@ -189,16 +241,15 @@ static int pdc_wdt_probe(struct platform_device *pdev)
pdc_wdt->wdt_dev.info = &pdc_wdt_info;
pdc_wdt->wdt_dev.ops = &pdc_wdt_ops;
- pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK;
+
+ div = 1ULL << (PDC_WDT_CONFIG_DELAY_MASK + 1);
+ do_div(div, clk_rate);
+ pdc_wdt->wdt_dev.max_timeout = div;
+ pdc_wdt->wdt_dev.timeout = PDC_WDT_DEF_TIMEOUT;
pdc_wdt->wdt_dev.parent = &pdev->dev;
watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
- ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev);
- if (ret < 0) {
- pdc_wdt->wdt_dev.timeout = pdc_wdt->wdt_dev.max_timeout;
- dev_warn(&pdev->dev,
- "Initial timeout out of range! setting max timeout\n");
- }
+ watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev);
pdc_wdt_stop(&pdc_wdt->wdt_dev);
@@ -238,6 +289,13 @@ static int pdc_wdt_probe(struct platform_device *pdev)
if (ret)
goto disable_wdt_clk;
+ pdc_wdt->restart_handler.notifier_call = pdc_wdt_restart;
+ pdc_wdt->restart_handler.priority = 128;
+ ret = register_restart_handler(&pdc_wdt->restart_handler);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to register restart handler: %d\n",
+ ret);
+
return 0;
disable_wdt_clk:
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 5e6d808d358a5..2acdd17025c40 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -166,6 +166,8 @@ static int imx2_wdt_set_timeout(struct watchdog_device *wdog,
{
struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+ wdog->timeout = new_timeout;
+
regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT,
WDOG_SEC_TO_COUNT(new_timeout));
return 0;
@@ -256,6 +258,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
wdog->ops = &imx2_wdt_ops;
wdog->min_timeout = 1;
wdog->max_timeout = IMX2_WDT_MAX_TIME;
+ wdog->parent = &pdev->dev;
clk_prepare_enable(wdev->clk);
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
index 08da3114accb5..b3a1130b8eebf 100644
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -214,7 +214,7 @@ static int max63xx_wdt_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_device_id max63xx_id_table[] = {
+static const struct platform_device_id max63xx_id_table[] = {
{ "max6369_wdt", (kernel_ulong_t)max6369_table, },
{ "max6370_wdt", (kernel_ulong_t)max6369_table, },
{ "max6371_wdt", (kernel_ulong_t)max6371_table, },
diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c
index 96dbba9805796..d193a5e79c381 100644
--- a/drivers/watchdog/mena21_wdt.c
+++ b/drivers/watchdog/mena21_wdt.c
@@ -208,14 +208,15 @@ static int a21_wdt_probe(struct platform_device *pdev)
else if (reset == 7)
a21_wdt.bootstatus |= WDIOF_EXTERN2;
+ drv->wdt = a21_wdt;
+ dev_set_drvdata(&pdev->dev, drv);
+
ret = watchdog_register_device(&a21_wdt);
if (ret) {
dev_err(&pdev->dev, "Cannot register watchdog device\n");
goto err_register_wd;
}
- dev_set_drvdata(&pdev->dev, drv);
-
dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n");
return 0;
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 1e6be9e405779..1a74bc7fb4586 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -53,7 +53,10 @@ static unsigned timer_margin;
module_param(timer_margin, uint, 0);
MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
+#define to_omap_wdt_dev(_wdog) container_of(_wdog, struct omap_wdt_dev, wdog)
+
struct omap_wdt_dev {
+ struct watchdog_device wdog;
void __iomem *base; /* physical */
struct device *dev;
bool omap_wdt_users;
@@ -123,7 +126,7 @@ static void omap_wdt_set_timer(struct omap_wdt_dev *wdev,
static int omap_wdt_start(struct watchdog_device *wdog)
{
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
void __iomem *base = wdev->base;
mutex_lock(&wdev->lock);
@@ -132,6 +135,13 @@ static int omap_wdt_start(struct watchdog_device *wdog)
pm_runtime_get_sync(wdev->dev);
+ /*
+ * Make sure the watchdog is disabled. This is unfortunately required
+ * because writing to various registers with the watchdog running has no
+ * effect.
+ */
+ omap_wdt_disable(wdev);
+
/* initialize prescaler */
while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x01)
cpu_relax();
@@ -151,7 +161,7 @@ static int omap_wdt_start(struct watchdog_device *wdog)
static int omap_wdt_stop(struct watchdog_device *wdog)
{
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
mutex_lock(&wdev->lock);
omap_wdt_disable(wdev);
@@ -163,7 +173,7 @@ static int omap_wdt_stop(struct watchdog_device *wdog)
static int omap_wdt_ping(struct watchdog_device *wdog)
{
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
mutex_lock(&wdev->lock);
omap_wdt_reload(wdev);
@@ -175,7 +185,7 @@ static int omap_wdt_ping(struct watchdog_device *wdog)
static int omap_wdt_set_timeout(struct watchdog_device *wdog,
unsigned int timeout)
{
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
mutex_lock(&wdev->lock);
omap_wdt_disable(wdev);
@@ -204,16 +214,10 @@ static const struct watchdog_ops omap_wdt_ops = {
static int omap_wdt_probe(struct platform_device *pdev)
{
struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev);
- struct watchdog_device *omap_wdt;
struct resource *res;
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;
-
wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
if (!wdev)
return -ENOMEM;
@@ -229,35 +233,30 @@ static int omap_wdt_probe(struct platform_device *pdev)
if (IS_ERR(wdev->base))
return PTR_ERR(wdev->base);
- 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;
+ wdev->wdog.info = &omap_wdt_info;
+ wdev->wdog.ops = &omap_wdt_ops;
+ wdev->wdog.min_timeout = TIMER_MARGIN_MIN;
+ wdev->wdog.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;
+ if (watchdog_init_timeout(&wdev->wdog, timer_margin, &pdev->dev) < 0)
+ wdev->wdog.timeout = TIMER_MARGIN_DEFAULT;
- watchdog_set_drvdata(omap_wdt, wdev);
- watchdog_set_nowayout(omap_wdt, nowayout);
+ watchdog_set_nowayout(&wdev->wdog, nowayout);
- platform_set_drvdata(pdev, omap_wdt);
+ platform_set_drvdata(pdev, wdev);
pm_runtime_enable(wdev->dev);
pm_runtime_get_sync(wdev->dev);
- 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;
+ if (pdata && pdata->read_reset_sources) {
+ u32 rs = pdata->read_reset_sources();
+ if (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT))
+ wdev->wdog.bootstatus = WDIOF_CARDRESET;
+ }
omap_wdt_disable(wdev);
- ret = watchdog_register_device(omap_wdt);
+ ret = watchdog_register_device(&wdev->wdog);
if (ret) {
pm_runtime_disable(wdev->dev);
return ret;
@@ -265,7 +264,7 @@ static int omap_wdt_probe(struct platform_device *pdev)
pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
readl_relaxed(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
- omap_wdt->timeout);
+ wdev->wdog.timeout);
pm_runtime_put_sync(wdev->dev);
@@ -274,8 +273,7 @@ static int omap_wdt_probe(struct platform_device *pdev)
static void omap_wdt_shutdown(struct platform_device *pdev)
{
- struct watchdog_device *wdog = platform_get_drvdata(pdev);
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
mutex_lock(&wdev->lock);
if (wdev->omap_wdt_users) {
@@ -287,11 +285,10 @@ static void omap_wdt_shutdown(struct platform_device *pdev)
static int omap_wdt_remove(struct platform_device *pdev)
{
- struct watchdog_device *wdog = platform_get_drvdata(pdev);
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
pm_runtime_disable(wdev->dev);
- watchdog_unregister_device(wdog);
+ watchdog_unregister_device(&wdev->wdog);
return 0;
}
@@ -306,8 +303,7 @@ static int omap_wdt_remove(struct platform_device *pdev)
static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct watchdog_device *wdog = platform_get_drvdata(pdev);
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
mutex_lock(&wdev->lock);
if (wdev->omap_wdt_users) {
@@ -321,8 +317,7 @@ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
static int omap_wdt_resume(struct platform_device *pdev)
{
- struct watchdog_device *wdog = platform_get_drvdata(pdev);
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
mutex_lock(&wdev->lock);
if (wdev->omap_wdt_users) {
diff --git a/drivers/watchdog/st_lpc_wdt.c b/drivers/watchdog/st_lpc_wdt.c
index f32be155212ad..6785afdc0fcaa 100644
--- a/drivers/watchdog/st_lpc_wdt.c
+++ b/drivers/watchdog/st_lpc_wdt.c
@@ -197,7 +197,7 @@ static int st_wdog_probe(struct platform_device *pdev)
return -EINVAL;
}
- /* LPC can either run in RTC or WDT mode */
+ /* LPC can either run as a Clocksource or in RTC or WDT mode */
if (mode != ST_LPC_MODE_WDT)
return -ENODEV;