Commit e3c21e08 authored by Andrew Lunn's avatar Andrew Lunn Committed by Wim Van Sebroeck

watchdog: tqmx86: Add watchdog driver for the IO controller

Some TQ-Systems ComExpress modules have an IO controller with a
watchdog timer.
Signed-off-by: default avatarAndrew Lunn <andrew@lunn.ch>
Reviewed-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarWim Van Sebroeck <wim@linux-watchdog.org>
parent 6797f292
...@@ -1316,6 +1316,18 @@ config SMSC37B787_WDT ...@@ -1316,6 +1316,18 @@ config SMSC37B787_WDT
Most people will say N. Most people will say N.
config TQMX86_WDT
tristate "TQ-Systems TQMX86 Watchdog Timer"
depends on X86
help
This is the driver for the hardware watchdog timer in the TQMX86 IO
controller found on some of their ComExpress Modules.
To compile this driver as a module, choose M here; the module
will be called tqmx86_wdt.
Most people will say N.
config VIA_WDT config VIA_WDT
tristate "VIA Watchdog Timer" tristate "VIA Watchdog Timer"
depends on X86 && PCI depends on X86 && PCI
......
...@@ -130,6 +130,7 @@ obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o ...@@ -130,6 +130,7 @@ obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o
obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
obj-$(CONFIG_SMSC_SCH311X_WDT) += sch311x_wdt.o obj-$(CONFIG_SMSC_SCH311X_WDT) += sch311x_wdt.o
obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
obj-$(CONFIG_TQMX86_WDT) += tqmx86_wdt.o
obj-$(CONFIG_VIA_WDT) += via_wdt.o obj-$(CONFIG_VIA_WDT) += via_wdt.o
obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
......
// SPDX-License-Identifier: GPL-2.0+
/*
* Watchdog driver for TQMx86 PLD.
*
* The watchdog supports power of 2 timeouts from 1 to 4096sec.
* Once started, it cannot be stopped.
*
* Based on the vendor code written by Vadim V.Vlasov
* <vvlasov@dev.rtsoft.ru>
*/
#include <linux/io.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/timer.h>
#include <linux/watchdog.h>
/* default timeout (secs) */
#define WDT_TIMEOUT 32
static unsigned int timeout;
module_param(timeout, uint, 0);
MODULE_PARM_DESC(timeout,
"Watchdog timeout in seconds. (1<=timeout<=4096, default="
__MODULE_STRING(WDT_TIMEOUT) ")");
struct tqmx86_wdt {
struct watchdog_device wdd;
void __iomem *io_base;
};
#define TQMX86_WDCFG 0x00 /* Watchdog Configuration Register */
#define TQMX86_WDCS 0x01 /* Watchdog Config/Status Register */
static int tqmx86_wdt_start(struct watchdog_device *wdd)
{
struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
iowrite8(0x81, priv->io_base + TQMX86_WDCS);
return 0;
}
static int tqmx86_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
{
struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
u8 val;
t = roundup_pow_of_two(t);
val = ilog2(t) | 0x90;
val += 3; /* values 0,1,2 correspond to 0.125,0.25,0.5s timeouts */
iowrite8(val, priv->io_base + TQMX86_WDCFG);
wdd->timeout = t;
return 0;
}
static const struct watchdog_info tqmx86_wdt_info = {
.options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING,
.identity = "TQMx86 Watchdog",
};
static struct watchdog_ops tqmx86_wdt_ops = {
.owner = THIS_MODULE,
.start = tqmx86_wdt_start,
.set_timeout = tqmx86_wdt_set_timeout,
};
static int tqmx86_wdt_probe(struct platform_device *pdev)
{
struct tqmx86_wdt *priv;
struct resource *res;
int err;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (IS_ERR(res))
return PTR_ERR(res);
priv->io_base = devm_ioport_map(&pdev->dev, res->start,
resource_size(res));
if (IS_ERR(priv->io_base))
return PTR_ERR(priv->io_base);
watchdog_set_drvdata(&priv->wdd, priv);
priv->wdd.parent = &pdev->dev;
priv->wdd.info = &tqmx86_wdt_info;
priv->wdd.ops = &tqmx86_wdt_ops;
priv->wdd.min_timeout = 1;
priv->wdd.max_timeout = 4096;
priv->wdd.max_hw_heartbeat_ms = 4096*1000;
priv->wdd.timeout = WDT_TIMEOUT;
watchdog_init_timeout(&priv->wdd, timeout, &pdev->dev);
watchdog_set_nowayout(&priv->wdd, WATCHDOG_NOWAYOUT);
tqmx86_wdt_set_timeout(&priv->wdd, priv->wdd.timeout);
err = devm_watchdog_register_device(&pdev->dev, &priv->wdd);
if (err)
return err;
dev_info(&pdev->dev, "TQMx86 watchdog\n");
return 0;
}
static struct platform_driver tqmx86_wdt_driver = {
.driver = {
.name = "tqmx86-wdt",
},
.probe = tqmx86_wdt_probe,
};
module_platform_driver(tqmx86_wdt_driver);
MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
MODULE_DESCRIPTION("TQMx86 Watchdog");
MODULE_ALIAS("platform:tqmx86-wdt");
MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment