summaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/davinci_wdt.c1
-rw-r--r--drivers/watchdog/im28wd.c1
-rw-r--r--drivers/watchdog/imxwd.c35
-rw-r--r--drivers/watchdog/jz4740.c37
-rw-r--r--drivers/watchdog/wd_core.c70
5 files changed, 91 insertions, 53 deletions
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index ecf6e89b47..dfabee230c 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -147,6 +147,7 @@ static int davinci_wdt_probe(struct device_d *dev)
clk_enable(davinci_wdt->clk);
davinci_wdt->wd.set_timeout = davinci_wdt_set_timeout;
+ davinci_wdt->wd.dev = dev;
ret = watchdog_register(&davinci_wdt->wd);
if (ret < 0)
diff --git a/drivers/watchdog/im28wd.c b/drivers/watchdog/im28wd.c
index a9093a7b51..3510776a3a 100644
--- a/drivers/watchdog/im28wd.c
+++ b/drivers/watchdog/im28wd.c
@@ -197,6 +197,7 @@ static int imx28_wd_probe(struct device_d *dev)
if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);
priv->wd.set_timeout = imx28_watchdog_set_timeout;
+ priv->wd.dev = dev;
if (!(readl(priv->regs + MXS_RTC_STAT) & MXS_RTC_STAT_WD_PRESENT)) {
rc = -ENODEV;
diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c
index 5ffbac7cdd..dd11a62613 100644
--- a/drivers/watchdog/imxwd.c
+++ b/drivers/watchdog/imxwd.c
@@ -18,6 +18,7 @@
#include <of.h>
#include <errno.h>
#include <malloc.h>
+#include <restart.h>
#include <watchdog.h>
#include <reset_source.h>
@@ -33,6 +34,7 @@ struct imx_wd {
void __iomem *base;
struct device_d *dev;
const struct imx_wd_ops *ops;
+ struct restart_handler restart;
};
#define to_imx_wd(h) container_of(h, struct imx_wd, wd)
@@ -121,12 +123,11 @@ static int imx_watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
return priv->ops->set_timeout(priv, timeout);
}
-static struct imx_wd *reset_wd;
-
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn imxwd_force_soc_reset(struct restart_handler *rst)
{
- if (reset_wd)
- reset_wd->ops->set_timeout(reset_wd, -1);
+ struct imx_wd *priv = container_of(rst, struct imx_wd, restart);
+
+ priv->ops->set_timeout(priv, -1);
mdelay(1000);
@@ -185,11 +186,9 @@ static int imx_wd_probe(struct device_d *dev)
}
priv->ops = ops;
priv->wd.set_timeout = imx_watchdog_set_timeout;
+ priv->wd.dev = dev;
priv->dev = dev;
- if (!reset_wd)
- reset_wd = priv;
-
if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) {
ret = watchdog_register(&priv->wd);
if (ret)
@@ -206,28 +205,21 @@ static int imx_wd_probe(struct device_d *dev)
dev->priv = priv;
+ priv->restart.name = "imxwd";
+ priv->restart.restart = imxwd_force_soc_reset;
+
+ restart_handler_register(&priv->restart);
+
return 0;
error_unregister:
if (IS_ENABLED(CONFIG_WATCHDOG_IMX))
watchdog_deregister(&priv->wd);
on_error:
- if (reset_wd && reset_wd != priv)
- free(priv);
+ free(priv);
return ret;
}
-static void imx_wd_remove(struct device_d *dev)
-{
- struct imx_wd *priv = dev->priv;
-
- if (IS_ENABLED(CONFIG_WATCHDOG_IMX))
- watchdog_deregister(&priv->wd);
-
- if (reset_wd && reset_wd != priv)
- free(priv);
-}
-
static const struct imx_wd_ops imx21_wd_ops = {
.set_timeout = imx21_watchdog_set_timeout,
.init = imx21_wd_init,
@@ -264,7 +256,6 @@ static struct platform_device_id imx_wdt_ids[] = {
static struct driver_d imx_wd_driver = {
.name = "imx-watchdog",
.probe = imx_wd_probe,
- .remove = imx_wd_remove,
.of_compatible = DRV_OF_COMPAT(imx_wdt_dt_ids),
.id_table = imx_wdt_ids,
};
diff --git a/drivers/watchdog/jz4740.c b/drivers/watchdog/jz4740.c
index 8ac51e060a..3d45b46ee2 100644
--- a/drivers/watchdog/jz4740.c
+++ b/drivers/watchdog/jz4740.c
@@ -16,6 +16,7 @@
#include <common.h>
#include <init.h>
+#include <restart.h>
#include <io.h>
#define JZ_REG_WDT_TIMER_DATA 0x0
@@ -39,33 +40,30 @@
#define JZ_EXTAL 24000000
struct jz4740_wdt_drvdata {
+ struct restart_handler restart;
void __iomem *base;
};
-static struct jz4740_wdt_drvdata *reset_wd;
-
-void __noreturn reset_cpu(unsigned long addr)
+static void __noreturn jz4740_reset_soc(struct restart_handler *rst)
{
- if (reset_wd) {
- void __iomem *base = reset_wd->base;
+ struct jz4740_wdt_drvdata *priv =
+ container_of(rst, struct jz4740_wdt_drvdata, restart);
+ void __iomem *base = priv->base;
- writew(JZ_WDT_CLOCK_DIV_4 | JZ_WDT_CLOCK_EXT,
- base + JZ_REG_WDT_TIMER_CONTROL);
- writew(0, base + JZ_REG_WDT_TIMER_COUNTER);
+ writew(JZ_WDT_CLOCK_DIV_4 | JZ_WDT_CLOCK_EXT,
+ base + JZ_REG_WDT_TIMER_CONTROL);
+ writew(0, base + JZ_REG_WDT_TIMER_COUNTER);
- /* reset after 4ms */
- writew(JZ_EXTAL / 1000, base + JZ_REG_WDT_TIMER_DATA);
+ /* reset after 4ms */
+ writew(JZ_EXTAL / 1000, base + JZ_REG_WDT_TIMER_DATA);
- /* start wdt */
- writeb(0x1, base + JZ_REG_WDT_COUNTER_ENABLE);
+ /* start wdt */
+ writeb(0x1, base + JZ_REG_WDT_COUNTER_ENABLE);
- mdelay(1000);
- } else
- pr_err("%s: can't reset cpu\n", __func__);
+ mdelay(1000);
hang();
}
-EXPORT_SYMBOL(reset_cpu);
static int jz4740_wdt_probe(struct device_d *dev)
{
@@ -78,11 +76,12 @@ static int jz4740_wdt_probe(struct device_d *dev)
return -ENODEV;
}
- if (!reset_wd)
- reset_wd = priv;
-
dev->priv = priv;
+ priv->restart.name = "jz4740-wdt";
+ priv->restart.restart = jz4740_reset_soc;
+ restart_handler_register(&priv->restart);
+
return 0;
}
diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c
index 3d0cfc635d..3a3f519648 100644
--- a/drivers/watchdog/wd_core.c
+++ b/drivers/watchdog/wd_core.c
@@ -11,6 +11,7 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) "watchdog: " fmt
#include <common.h>
#include <command.h>
@@ -18,40 +19,85 @@
#include <linux/ctype.h>
#include <watchdog.h>
-/*
- * Note: this simple framework supports one watchdog only.
- */
-static struct watchdog *watchdog;
+static LIST_HEAD(watchdog_list);
+
+static const char *watchdog_name(struct watchdog *wd)
+{
+ if (wd->dev)
+ return dev_name(wd->dev);
+ if (wd->name)
+ return wd->name;
+
+ return "unknown";
+}
int watchdog_register(struct watchdog *wd)
{
- if (watchdog != NULL)
- return -EBUSY;
+ if (!wd->priority)
+ wd->priority = WATCHDOG_DEFAULT_PRIORITY;
+
+ list_add_tail(&wd->list, &watchdog_list);
+
+ pr_debug("registering watchdog %s with priority %d\n", watchdog_name(wd),
+ wd->priority);
- watchdog = wd;
return 0;
}
EXPORT_SYMBOL(watchdog_register);
int watchdog_deregister(struct watchdog *wd)
{
- if (watchdog == NULL || wd != watchdog)
- return -ENODEV;
+ list_del(&wd->list);
- watchdog = NULL;
return 0;
}
EXPORT_SYMBOL(watchdog_deregister);
+static struct watchdog *watchdog_get_default(void)
+{
+ struct watchdog *tmp, *wd = NULL;
+ int priority = 0;
+
+ list_for_each_entry(tmp, &watchdog_list, list) {
+ if (tmp->priority > priority) {
+ priority = tmp->priority;
+ wd = tmp;
+ }
+ }
+
+ return wd;
+}
+
/*
* start, stop or retrigger the watchdog
* timeout in [seconds]. timeout of '0' will disable the watchdog (if possible)
*/
int watchdog_set_timeout(unsigned timeout)
{
- if (watchdog == NULL)
+ struct watchdog *wd;
+
+ wd = watchdog_get_default();
+
+ if (!wd)
return -ENODEV;
- return watchdog->set_timeout(watchdog, timeout);
+ pr_debug("setting timeout on %s to %ds\n", watchdog_name(wd), timeout);
+
+ return wd->set_timeout(wd, timeout);
}
EXPORT_SYMBOL(watchdog_set_timeout);
+
+/**
+ * of_get_watchdog_priority() - get the desired watchdog priority from device tree
+ * @node: The device_node to read the property from
+ *
+ * return: The priority
+ */
+unsigned int of_get_watchdog_priority(struct device_node *node)
+{
+ unsigned int priority = WATCHDOG_DEFAULT_PRIORITY;
+
+ of_property_read_u32(node, "watchdog-priority", &priority);
+
+ return priority;
+}