From: advantech.susiteam@gmail.com
To: advantech.susiteam@gmail.com
Cc: wenkai.chung@advantech.com.tw, Susi.Driver@advantech.com,
Wim Van Sebroeck <wim@linux-watchdog.org>,
Guenter Roeck <linux@roeck-us.net>,
linux-kernel@vger.kernel.org, linux-watchdog@vger.kernel.org
Subject: [PATCH 4/5] watchdog: eiois200_wdt: Enhanced watchdog functionality and pretimeout
Date: Thu, 5 Oct 2023 16:51:22 +0800 [thread overview]
Message-ID: <9dc5114ec819588c5ba957bd9e365329533ac191.1696495372.git.advantech.susiteam@gmail.com> (raw)
In-Reply-To: <cover.1696495372.git.advantech.susiteam@gmail.com>
From: Wenkai <advantech.susiteam@gmail.com>
This patch extends the Advantech EIO-IS200 Watchdog Driver to provide
advanced watchdog functionality, including pretimeout support. It allows
the user to specify a timeout or pre-timeout trigger event, let the
event pin output level switches from high to low. The event pin which
can be one of the following:
- PWRBTN (Power button)
- SCI (ACPI System Control Interrupt)
- IRQ
- GPIO
If the pretimeout is specified, when the pretimeout time expires, it
triggers the associated pin. If the timeout expires, it triggers a reset.
If the pretimeout is not specified, the timeout expiration triggers the
associated pin or the reset pin.
This addition to basic watchdog functionality. It ensures proper
integration with the watchdog framework and provides a flexible watchdog
solution for Advantech EIO-IS200-based systems.
Signed-off-by: Wenkai <advantech.susiteam@gmail.com>
---
drivers/watchdog/eiois200_wdt.c | 159 ++++++++++++++++++++++++++++++--
1 file changed, 152 insertions(+), 7 deletions(-)
diff --git a/drivers/watchdog/eiois200_wdt.c b/drivers/watchdog/eiois200_wdt.c
index 569e619448e5..85179806ab7e 100644
--- a/drivers/watchdog/eiois200_wdt.c
+++ b/drivers/watchdog/eiois200_wdt.c
@@ -18,13 +18,21 @@
/* Support Flags */
#define SUPPORT_AVAILABLE BIT(0)
+#define SUPPORT_PWRBTN BIT(3)
+#define SUPPORT_IRQ BIT(4)
+#define SUPPORT_SCI BIT(5)
+#define SUPPORT_PIN BIT(6)
#define SUPPORT_RESET BIT(7)
/* PMC registers */
#define REG_STATUS 0x00
#define REG_CONTROL 0x02
#define REG_EVENT 0x10
+#define REG_PWR_EVENT_TIME 0x12
+#define REG_IRQ_EVENT_TIME 0x13
#define REG_RESET_EVENT_TIME 0x14
+#define REG_PIN_EVENT_TIME 0x15
+#define REG_SCI_EVENT_TIME 0x16
#define REG_IRQ_NUMBER 0x17
/* PMC command and control */
@@ -50,20 +58,53 @@
#define PMC_WRITE(cmd, data) pmc(CMD_WDT_WRITE, cmd, data)
#define PMC_READ(cmd, data) pmc(CMD_WDT_READ, cmd, data)
+/* Mapping event type to supported bit */
+#define EVENT_BIT(type) BIT(type + 2)
+
+enum event_type {
+ EVENT_NONE,
+ EVENT_PWRBTN,
+ EVENT_IRQ,
+ EVENT_SCI,
+ EVENT_PIN
+};
+
static struct _wdt {
+ u32 event_type;
u32 support;
long last_time;
struct regmap *iomap;
struct device *dev;
} wdt;
+static char * const type_strs[] = {
+ "NONE",
+ "PWRBTN",
+ "IRQ",
+ "SCI",
+ "PIN",
+};
+
+static u32 type_regs[] = {
+ REG_RESET_EVENT_TIME,
+ REG_PWR_EVENT_TIME,
+ REG_IRQ_EVENT_TIME,
+ REG_SCI_EVENT_TIME,
+ REG_PIN_EVENT_TIME,
+};
+
/* Pointer to the eiois200_core device structure */
static struct eiois200_dev *eiois200_dev;
+/* Specify the pin triggered on pretimeout or timeout */
+static char *event_type = "NONE";
+module_param(event_type, charp, 0);
+MODULE_PARM_DESC(event_type,
+ "Watchdog timeout event type (RESET, PWRBTN, SCI, IRQ, GPIO)");
static struct watchdog_info wdinfo = {
.identity = KBUILD_MODNAME,
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
- WDIOF_MAGICCLOSE,
+ WDIOF_PRETIMEOUT | WDIOF_MAGICCLOSE,
};
static struct watchdog_device wddev = {
@@ -76,8 +117,42 @@ static int wdt_set_timeout(struct watchdog_device *dev,
unsigned int _timeout)
{
dev->timeout = _timeout;
- dev_dbg(wdt.dev, "Set timeout: %d\n", _timeout);
+ dev_info(wdt.dev, "Set timeout: %d\n", _timeout);
+
+ return 0;
+}
+
+static int wdt_set_pretimeout(struct watchdog_device *dev,
+ unsigned int _pretimeout)
+{
+ dev->pretimeout = _pretimeout;
+
+ dev_info(wdt.dev, "Set pretimeout: %d\n", _pretimeout);
+
+ return 0;
+}
+
+static int wdt_get_type(void)
+{
+ int i;
+
+ for (i = 1; i < ARRAY_SIZE(type_strs); i++)
+ if (strcasecmp(event_type, type_strs[i]) == 0) {
+ if ((wdt.support & EVENT_BIT(i)) == 0) {
+ dev_err(wdt.dev,
+ "This board doesn't support %s trigger type\n",
+ event_type);
+ return -EINVAL;
+ }
+
+ dev_info(wdt.dev, "Trigger type is %d:%s\n",
+ i, type_strs[i]);
+ wdt.event_type = i;
+
+ return 0;
+ }
+ dev_info(wdt.dev, "Event type: %s\n", type_strs[wdt.event_type]);
return 0;
}
@@ -116,33 +191,98 @@ static int set_time(u8 ctl, u32 time)
static int wdt_set_config(void)
{
- int ret;
+ int ret, type;
+ u32 event_time = 0;
u32 reset_time = 0;
+ /* event_type should never out of range */
+ if (wdt.event_type > EVENT_PIN)
+ return -EFAULT;
+
+ /* Calculate event time and reset time */
+ if (wddev.pretimeout && wddev.timeout) {
+ if (wddev.timeout < wddev.pretimeout)
+ return -EINVAL;
+
reset_time = wddev.timeout;
+ event_time = wddev.timeout - wddev.pretimeout;
+ } else if (wddev.timeout) {
+ reset_time = wdt.event_type ? 0 : wddev.timeout;
+ event_time = wdt.event_type ? wddev.timeout : 0;
+ }
+
+ /* Set reset time */
ret = set_time(REG_RESET_EVENT_TIME, reset_time);
if (ret)
return ret;
- dev_info(wdt.dev, "Config wdt reset time %d\n", reset_time);
+ /* Set every other times */
+ for (type = 1; type < ARRAY_SIZE(type_regs); type++) {
+ ret = set_time(type_regs[type],
+ wdt.event_type == type ? event_time : 0);
+ if (ret)
+ return ret;
+ }
+
+ dev_dbg(wdt.dev, "Config wdt reset time %d\n", reset_time);
+ dev_dbg(wdt.dev, "Config wdt event time %d\n", event_time);
+ dev_dbg(wdt.dev, "Config wdt event type %s\n",
+ type_strs[wdt.event_type]);
return ret;
}
static int wdt_get_config(void)
{
- int ret;
- u32 reset_time;
+ int ret, type;
+ u32 event_time, reset_time;
/* Get Reset Time */
ret = get_time(REG_RESET_EVENT_TIME, &reset_time);
if (ret)
return ret;
- dev_info(wdt.dev, "Timeout H/W default timeout: %d secs\n", reset_time);
+ dev_dbg(wdt.dev, "Timeout H/W default timeout: %d secs\n", reset_time);
+
+ /* Get every other times **/
+ for (type = 1; type < ARRAY_SIZE(type_regs); type++) {
+ if ((wdt.support & EVENT_BIT(type)) == 0)
+ continue;
+
+ ret = get_time(type_regs[type], &event_time);
+ if (ret)
+ return ret;
+
+ if (event_time == 0)
+ continue;
+
+ if (reset_time) {
+ if (reset_time < event_time)
+ continue;
+
wddev.timeout = reset_time;
+ wddev.pretimeout = reset_time - event_time;
+
+ dev_dbg(wdt.dev, "Pretimeout H/W enabled with event %s of %d secs\n",
+ type_strs[type], wddev.pretimeout);
+ } else {
+ wddev.timeout = event_time;
+ wddev.pretimeout = 0;
+ }
+
+ wdt.event_type = type;
+
+ dev_dbg(wdt.dev, "Timeout H/W enabled of %d secs\n",
+ wddev.timeout);
+ return 0;
+ }
+
+ wdt.event_type = EVENT_NONE;
+ wddev.pretimeout = reset_time ? 0 : WATCHDOG_PRETIMEOUT;
+ wddev.timeout = reset_time ? reset_time : WATCHDOG_TIMEOUT;
+ dev_dbg(wdt.dev, "Pretimeout H/W disabled");
return 0;
}
@@ -218,6 +358,7 @@ static int wdt_support(void)
return 0;
}
+
static int wdt_init(struct device *dev)
{
int ret = 0;
@@ -230,6 +371,9 @@ static int wdt_init(struct device *dev)
if (ret)
return ret;
+ ret = wdt_get_type();
+ if (ret)
+ return ret;
return ret;
}
@@ -240,6 +384,7 @@ static const struct watchdog_ops wdt_ops = {
.ping = wdt_ping,
.set_timeout = wdt_set_timeout,
.get_timeleft = wdt_get_timeleft,
+ .set_pretimeout = wdt_set_pretimeout,
};
static int wdt_probe(struct platform_device *pdev)
--
2.34.1
next prev parent reply other threads:[~2023-10-05 14:38 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-10-05 8:51 [PATCH 0/5] watchdog: eiois200_wdt: Add EIO-IS200 Watchdog Driver advantech.susiteam
2023-10-05 8:51 ` [PATCH 1/5] watchdog: eiois200_wdt: Constructing Advantech EIO-IS200 watchdog driver advantech.susiteam
2023-10-05 23:33 ` kernel test robot
2023-10-05 8:51 ` [PATCH 2/5] watchdog: eiois200_wdt: Add PMC support with eiois200_core advantech.susiteam
2023-10-05 8:51 ` [PATCH 3/5] watchdog: eiois200_wdt: Implement basic watchdog functionalities advantech.susiteam
2023-10-05 8:51 ` advantech.susiteam [this message]
2023-10-05 8:51 ` [PATCH 5/5] watchdog: eiois200_wdt: Enhanced IRQ trigger behavior advantech.susiteam
2023-10-06 3:02 ` [PATCH 0/5] watchdog: eiois200_wdt: Add EIO-IS200 Watchdog Driver Guenter Roeck
2023-10-06 9:27 ` Wenkai
2023-10-06 14:16 ` Guenter Roeck
2023-10-11 4:08 ` Wenkai
2023-10-11 15:05 ` Guenter Roeck
2023-10-12 7:56 ` Wenkai
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9dc5114ec819588c5ba957bd9e365329533ac191.1696495372.git.advantech.susiteam@gmail.com \
--to=advantech.susiteam@gmail.com \
--cc=Susi.Driver@advantech.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-watchdog@vger.kernel.org \
--cc=linux@roeck-us.net \
--cc=wenkai.chung@advantech.com.tw \
--cc=wim@linux-watchdog.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.