aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Lunn <andrew@lunn.ch>2018-12-19 10:18:20 -0500
committerWim Van Sebroeck <wim@linux-watchdog.org>2018-12-24 07:15:07 -0500
commite3c21e088f8936a004a3d9f2f4e14b3f2bdd6ea9 (patch)
treeda813b49c8ec459e5ab62e645322aee76824c213
parent6797f292e4f59211c1763de87a69c9a55fd9caef (diff)
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: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
-rw-r--r--drivers/watchdog/Kconfig12
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/tqmx86_wdt.c126
3 files changed, 139 insertions, 0 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 6dcd5603a3e4..57f017d74a97 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1316,6 +1316,18 @@ config SMSC37B787_WDT
1316 1316
1317 Most people will say N. 1317 Most people will say N.
1318 1318
1319config TQMX86_WDT
1320 tristate "TQ-Systems TQMX86 Watchdog Timer"
1321 depends on X86
1322 help
1323 This is the driver for the hardware watchdog timer in the TQMX86 IO
1324 controller found on some of their ComExpress Modules.
1325
1326 To compile this driver as a module, choose M here; the module
1327 will be called tqmx86_wdt.
1328
1329 Most people will say N.
1330
1319config VIA_WDT 1331config VIA_WDT
1320 tristate "VIA Watchdog Timer" 1332 tristate "VIA Watchdog Timer"
1321 depends on X86 && PCI 1333 depends on X86 && PCI
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index cc90e723135e..a0917ef28e07 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -130,6 +130,7 @@ obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o
130obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o 130obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o
131obj-$(CONFIG_SMSC_SCH311X_WDT) += sch311x_wdt.o 131obj-$(CONFIG_SMSC_SCH311X_WDT) += sch311x_wdt.o
132obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o 132obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o
133obj-$(CONFIG_TQMX86_WDT) += tqmx86_wdt.o
133obj-$(CONFIG_VIA_WDT) += via_wdt.o 134obj-$(CONFIG_VIA_WDT) += via_wdt.o
134obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o 135obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o
135obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o 136obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o
diff --git a/drivers/watchdog/tqmx86_wdt.c b/drivers/watchdog/tqmx86_wdt.c
new file mode 100644
index 000000000000..0d3a0fbbd7a5
--- /dev/null
+++ b/drivers/watchdog/tqmx86_wdt.c
@@ -0,0 +1,126 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Watchdog driver for TQMx86 PLD.
4 *
5 * The watchdog supports power of 2 timeouts from 1 to 4096sec.
6 * Once started, it cannot be stopped.
7 *
8 * Based on the vendor code written by Vadim V.Vlasov
9 * <vvlasov@dev.rtsoft.ru>
10 */
11
12#include <linux/io.h>
13#include <linux/log2.h>
14#include <linux/module.h>
15#include <linux/platform_device.h>
16#include <linux/timer.h>
17#include <linux/watchdog.h>
18
19/* default timeout (secs) */
20#define WDT_TIMEOUT 32
21
22static unsigned int timeout;
23module_param(timeout, uint, 0);
24MODULE_PARM_DESC(timeout,
25 "Watchdog timeout in seconds. (1<=timeout<=4096, default="
26 __MODULE_STRING(WDT_TIMEOUT) ")");
27struct tqmx86_wdt {
28 struct watchdog_device wdd;
29 void __iomem *io_base;
30};
31
32#define TQMX86_WDCFG 0x00 /* Watchdog Configuration Register */
33#define TQMX86_WDCS 0x01 /* Watchdog Config/Status Register */
34
35static int tqmx86_wdt_start(struct watchdog_device *wdd)
36{
37 struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
38
39 iowrite8(0x81, priv->io_base + TQMX86_WDCS);
40
41 return 0;
42}
43
44static int tqmx86_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
45{
46 struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
47 u8 val;
48
49 t = roundup_pow_of_two(t);
50 val = ilog2(t) | 0x90;
51 val += 3; /* values 0,1,2 correspond to 0.125,0.25,0.5s timeouts */
52 iowrite8(val, priv->io_base + TQMX86_WDCFG);
53
54 wdd->timeout = t;
55
56 return 0;
57}
58
59static const struct watchdog_info tqmx86_wdt_info = {
60 .options = WDIOF_SETTIMEOUT |
61 WDIOF_KEEPALIVEPING,
62 .identity = "TQMx86 Watchdog",
63};
64
65static struct watchdog_ops tqmx86_wdt_ops = {
66 .owner = THIS_MODULE,
67 .start = tqmx86_wdt_start,
68 .set_timeout = tqmx86_wdt_set_timeout,
69};
70
71static int tqmx86_wdt_probe(struct platform_device *pdev)
72{
73 struct tqmx86_wdt *priv;
74 struct resource *res;
75 int err;
76
77 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
78 if (!priv)
79 return -ENOMEM;
80
81 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
82 if (IS_ERR(res))
83 return PTR_ERR(res);
84
85 priv->io_base = devm_ioport_map(&pdev->dev, res->start,
86 resource_size(res));
87 if (IS_ERR(priv->io_base))
88 return PTR_ERR(priv->io_base);
89
90 watchdog_set_drvdata(&priv->wdd, priv);
91
92 priv->wdd.parent = &pdev->dev;
93 priv->wdd.info = &tqmx86_wdt_info;
94 priv->wdd.ops = &tqmx86_wdt_ops;
95 priv->wdd.min_timeout = 1;
96 priv->wdd.max_timeout = 4096;
97 priv->wdd.max_hw_heartbeat_ms = 4096*1000;
98 priv->wdd.timeout = WDT_TIMEOUT;
99
100 watchdog_init_timeout(&priv->wdd, timeout, &pdev->dev);
101 watchdog_set_nowayout(&priv->wdd, WATCHDOG_NOWAYOUT);
102
103 tqmx86_wdt_set_timeout(&priv->wdd, priv->wdd.timeout);
104
105 err = devm_watchdog_register_device(&pdev->dev, &priv->wdd);
106 if (err)
107 return err;
108
109 dev_info(&pdev->dev, "TQMx86 watchdog\n");
110
111 return 0;
112}
113
114static struct platform_driver tqmx86_wdt_driver = {
115 .driver = {
116 .name = "tqmx86-wdt",
117 },
118 .probe = tqmx86_wdt_probe,
119};
120
121module_platform_driver(tqmx86_wdt_driver);
122
123MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
124MODULE_DESCRIPTION("TQMx86 Watchdog");
125MODULE_ALIAS("platform:tqmx86-wdt");
126MODULE_LICENSE("GPL");