summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2019-12-10 05:41:45 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2019-12-10 05:41:45 +0100
commit28e374e062aede65b6bb6f341376f196e5ac4fc7 (patch)
tree603f97f7495cc6c234482424fcb4b39dc77369da
parent4b05f14d96afde2fb8e7e9a92893ca3c684870d0 (diff)
parentaade8d53cf6cccf7958d2c11e5791dfcd85a584f (diff)
downloadbarebox-28e374e062aede65b6bb6f341376f196e5ac4fc7.tar.gz
barebox-28e374e062aede65b6bb6f341376f196e5ac4fc7.tar.xz
Merge branch 'for-next/watchdog'
-rw-r--r--drivers/mfd/da9053.c1
-rw-r--r--drivers/mfd/da9063.c1
-rw-r--r--drivers/watchdog/f71808e_wdt.c7
-rw-r--r--drivers/watchdog/imxwd.c14
-rw-r--r--drivers/watchdog/stm32_iwdg.c1
-rw-r--r--drivers/watchdog/wd_core.c48
-rw-r--r--include/param.h24
-rw-r--r--include/watchdog.h27
-rw-r--r--lib/parameter.c22
9 files changed, 118 insertions, 27 deletions
diff --git a/drivers/mfd/da9053.c b/drivers/mfd/da9053.c
index 4c31beb267..1f32869038 100644
--- a/drivers/mfd/da9053.c
+++ b/drivers/mfd/da9053.c
@@ -271,7 +271,6 @@ static int da9053_probe(struct device_d *dev)
da9053->dev = dev;
da9053->client = to_i2c_client(dev);
da9053->wd.set_timeout = da9053_set_timeout;
- da9053->wd.priority = of_get_watchdog_priority(dev->device_node);
da9053->wd.hwdev = dev;
ret = da9053_enable_multiwrite(da9053);
diff --git a/drivers/mfd/da9063.c b/drivers/mfd/da9063.c
index 967ca9ac51..e48c38affa 100644
--- a/drivers/mfd/da9063.c
+++ b/drivers/mfd/da9063.c
@@ -377,7 +377,6 @@ static int da9063_probe(struct device_d *dev)
dev_data = ret < 0 ? NULL : dev_data_tmp;
priv = xzalloc(sizeof(struct da9063));
- priv->wd.priority = of_get_watchdog_priority(dev->device_node);
priv->wd.set_timeout = da9063_watchdog_set_timeout;
priv->wd.hwdev = dev;
priv->timeout = DA9063_INITIAL_TIMEOUT;
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c
index 4f881a1d02..5307ab0b3e 100644
--- a/drivers/watchdog/f71808e_wdt.c
+++ b/drivers/watchdog/f71808e_wdt.c
@@ -222,7 +222,7 @@ static int f71808e_wdt_init(struct f71808e_wdt *wd, struct device_d *dev)
{
struct watchdog *wdd = &wd->wdd;
const char * const *names = pulse_width_names;
- int wdt_conf;
+ unsigned long wdt_conf;
int ret;
superio_enter(wd->sioaddr);
@@ -262,6 +262,11 @@ static int f71808e_wdt_init(struct f71808e_wdt *wd, struct device_d *dev)
dev_info(dev, "reset reason: %s\n", reset_source_name());
+ if (test_bit(F71808FG_FLAG_WD_EN, &wdt_conf))
+ wdd->running = WDOG_HW_RUNNING;
+ else
+ wdd->running = WDOG_HW_NOT_RUNNING;
+
ret = watchdog_register(wdd);
if (ret)
return ret;
diff --git a/drivers/watchdog/imxwd.c b/drivers/watchdog/imxwd.c
index 77a3bd76ce..b2cfd1cd3a 100644
--- a/drivers/watchdog/imxwd.c
+++ b/drivers/watchdog/imxwd.c
@@ -28,6 +28,7 @@ struct imx_wd_ops {
int (*set_timeout)(struct imx_wd *, unsigned);
void (*soc_reset)(struct imx_wd *);
int (*init)(struct imx_wd *);
+ bool (*is_running)(struct imx_wd *);
unsigned int timeout_max;
};
@@ -111,6 +112,11 @@ static void imx1_soc_reset(struct imx_wd *priv)
writew(IMX1_WDOG_WCR_WDE, priv->base + IMX1_WDOG_WCR);
}
+static inline bool imx21_watchdog_is_running(struct imx_wd *priv)
+{
+ return imxwd_read(priv, IMX21_WDOG_WCR) & IMX21_WDOG_WCR_WDE;
+}
+
static int imx21_watchdog_set_timeout(struct imx_wd *priv, unsigned timeout)
{
u16 val;
@@ -243,6 +249,13 @@ static int imx_wd_probe(struct device_d *dev)
"fsl,ext-reset-output");
if (IS_ENABLED(CONFIG_WATCHDOG_IMX)) {
+ if (priv->ops->is_running) {
+ if (priv->ops->is_running(priv))
+ priv->wd.running = WDOG_HW_RUNNING;
+ else
+ priv->wd.running = WDOG_HW_NOT_RUNNING;
+ }
+
ret = watchdog_register(&priv->wd);
if (ret)
goto on_error;
@@ -277,6 +290,7 @@ static const struct imx_wd_ops imx21_wd_ops = {
.set_timeout = imx21_watchdog_set_timeout,
.soc_reset = imx21_soc_reset,
.init = imx21_wd_init,
+ .is_running = imx21_watchdog_is_running,
.timeout_max = 128,
};
diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c
index 808d7c8372..c7a5cb9caa 100644
--- a/drivers/watchdog/stm32_iwdg.c
+++ b/drivers/watchdog/stm32_iwdg.c
@@ -256,6 +256,7 @@ static int stm32_iwdg_probe(struct device_d *dev)
wdd->set_timeout = stm32_iwdg_set_timeout;
wdd->timeout_max = (RLR_MAX + 1) * data->max_prescaler * 1000;
wdd->timeout_max /= wd->rate * 1000;
+ wdd->running = WDOG_HW_RUNNING_UNSUPPORTED; /* ONF bit not present in IP */
ret = watchdog_register(wdd);
if (ret) {
diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c
index 8b13950238..b6e2a37b1f 100644
--- a/drivers/watchdog/wd_core.c
+++ b/drivers/watchdog/wd_core.c
@@ -37,6 +37,8 @@ static const char *watchdog_name(struct watchdog *wd)
*/
int watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
{
+ int ret;
+
if (!wd)
return -ENODEV;
@@ -45,7 +47,13 @@ int watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
pr_debug("setting timeout on %s to %ds\n", watchdog_name(wd), timeout);
- return wd->set_timeout(wd, timeout);
+ ret = wd->set_timeout(wd, timeout);
+ if (ret)
+ return ret;
+
+ wd->running = timeout ? WDOG_HW_RUNNING : WDOG_HW_NOT_RUNNING;
+
+ return 0;
}
EXPORT_SYMBOL(watchdog_set_timeout);
@@ -127,6 +135,23 @@ static int watchdog_register_dev(struct watchdog *wd, const char *name, int id)
return register_device(&wd->dev);
}
+/**
+ * dev_get_watchdog_priority() - get a device's desired watchdog priority
+ * @dev: The device, which device_node to read the property from
+ *
+ * return: The priority
+ */
+static unsigned int dev_get_watchdog_priority(struct device_d *dev)
+{
+ unsigned int priority = WATCHDOG_DEFAULT_PRIORITY;
+
+ if (dev)
+ of_property_read_u32(dev->device_node, "watchdog-priority",
+ &priority);
+
+ return priority;
+}
+
int watchdog_register(struct watchdog *wd)
{
struct param_d *p;
@@ -145,8 +170,12 @@ int watchdog_register(struct watchdog *wd)
if (ret)
return ret;
+ p = dev_add_param_tristate_ro(&wd->dev, "running", &wd->running);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
if (!wd->priority)
- wd->priority = WATCHDOG_DEFAULT_PRIORITY;
+ wd->priority = dev_get_watchdog_priority(wd->hwdev);
p = dev_add_param_uint32(&wd->dev, "priority",
watchdog_set_priority, NULL,
@@ -232,18 +261,3 @@ struct watchdog *watchdog_get_by_name(const char *name)
return NULL;
}
EXPORT_SYMBOL(watchdog_get_by_name);
-
-/**
- * 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;
-}
diff --git a/include/param.h b/include/param.h
index 4ac502e726..d75f50ea3e 100644
--- a/include/param.h
+++ b/include/param.h
@@ -63,6 +63,16 @@ struct param_d *dev_add_param_enum(struct device_d *dev, const char *name,
int (*get)(struct param_d *p, void *priv),
int *value, const char * const *names, int max, void *priv);
+enum param_tristate { PARAM_TRISTATE_UNKNOWN, PARAM_TRISTATE_TRUE, PARAM_TRISTATE_FALSE };
+
+struct param_d *dev_add_param_tristate(struct device_d *dev, const char *name,
+ int (*set)(struct param_d *p, void *priv),
+ int (*get)(struct param_d *p, void *priv),
+ int *value, void *priv);
+
+struct param_d *dev_add_param_tristate_ro(struct device_d *dev, const char *name,
+ int *value);
+
struct param_d *dev_add_param_bitmask(struct device_d *dev, const char *name,
int (*set)(struct param_d *p, void *priv),
int (*get)(struct param_d *p, void *priv),
@@ -144,6 +154,20 @@ static inline struct param_d *dev_add_param_bitmask(struct device_d *dev, const
return ERR_PTR(-ENOSYS);
}
+static inline struct param_d *dev_add_param_tristate(struct device_d *dev, const char *name,
+ int (*set)(struct param_d *p, void *priv),
+ int (*get)(struct param_d *p, void *priv),
+ int *value, void *priv)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
+static inline struct param_d *dev_add_param_tristate_ro(struct device_d *dev, const char *name,
+ int *value)
+{
+ return ERR_PTR(-ENOSYS);
+}
+
static inline struct param_d *dev_add_param_ip(struct device_d *dev, const char *name,
int (*set)(struct param_d *p, void *priv),
int (*get)(struct param_d *p, void *priv),
diff --git a/include/watchdog.h b/include/watchdog.h
index 184a218916..9741570ce2 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -15,6 +15,13 @@
#include <poller.h>
#include <driver.h>
+#include <param.h>
+
+enum wdog_hw_runnning {
+ WDOG_HW_RUNNING_UNSUPPORTED = PARAM_TRISTATE_UNKNOWN,
+ WDOG_HW_RUNNING = PARAM_TRISTATE_TRUE,
+ WDOG_HW_NOT_RUNNING = PARAM_TRISTATE_FALSE
+};
struct watchdog {
int (*set_timeout)(struct watchdog *, unsigned);
@@ -27,15 +34,27 @@ struct watchdog {
unsigned int poller_enable;
struct poller_async poller;
struct list_head list;
+ int running; /* enum wdog_hw_running */
};
+/*
+ * Use the following function to check whether or not the hardware watchdog
+ * is running
+ */
+static inline int watchdog_hw_running(struct watchdog *w)
+{
+ if (w->running == WDOG_HW_RUNNING_UNSUPPORTED)
+ return -ENOSYS;
+
+ return w->running == WDOG_HW_RUNNING;
+}
+
#ifdef CONFIG_WATCHDOG
int watchdog_register(struct watchdog *);
int watchdog_deregister(struct watchdog *);
struct watchdog *watchdog_get_default(void);
struct watchdog *watchdog_get_by_name(const char *name);
int watchdog_set_timeout(struct watchdog*, unsigned);
-unsigned int of_get_watchdog_priority(struct device_node *node);
#else
static inline int watchdog_register(struct watchdog *w)
{
@@ -61,12 +80,6 @@ static inline int watchdog_set_timeout(struct watchdog*w, unsigned t)
{
return 0;
}
-
-
-static inline unsigned int of_get_watchdog_priority(struct device_node *node)
-{
- return 0;
-}
#endif
#define WATCHDOG_DEFAULT_PRIORITY 100
diff --git a/lib/parameter.c b/lib/parameter.c
index fdbb2e71d1..22695634e5 100644
--- a/lib/parameter.c
+++ b/lib/parameter.c
@@ -588,6 +588,28 @@ struct param_d *dev_add_param_enum(struct device_d *dev, const char *name,
return &pe->param;
}
+static const char *const tristate_names[] = {
+ [PARAM_TRISTATE_UNKNOWN] = "unknown",
+ [PARAM_TRISTATE_TRUE] = "1",
+ [PARAM_TRISTATE_FALSE] = "0",
+};
+
+struct param_d *dev_add_param_tristate(struct device_d *dev, const char *name,
+ int (*set)(struct param_d *p, void *priv),
+ int (*get)(struct param_d *p, void *priv),
+ int *value, void *priv)
+{
+ return dev_add_param_enum(dev, name, set, get, value, tristate_names,
+ ARRAY_SIZE(tristate_names), priv);
+}
+
+struct param_d *dev_add_param_tristate_ro(struct device_d *dev, const char *name,
+ int *value)
+{
+ return dev_add_param_enum_ro(dev, name, value, tristate_names,
+ ARRAY_SIZE(tristate_names));
+}
+
struct param_bitmask {
struct param_d param;
unsigned long *value;