All of lore.kernel.org
 help / color / mirror / Atom feed
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


  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.