aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas Jensen <jonas.jensen@gmail.com>2013-08-02 10:40:45 -0400
committerWim Van Sebroeck <wim@iguana.be>2013-11-17 13:34:49 -0500
commite14538e0db8d880291064348bda7d52ec8322675 (patch)
treee670e629231e771a1f3a03134c42794c42a69969
parentb3970bdebbb2901becca7cb82e44b5c5976f0fae (diff)
watchdog: Add MOXA ART watchdog driver
This patch adds a watchdog driver for the main hardware watchdog timer found on MOXA ART SoCs. The MOXA ART SoC provides one writable timer register, restarting the hardware once it reaches zero. The register is auto decremented every APB clock cycle. Signed-off-by: Jonas Jensen <jonas.jensen@gmail.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--Documentation/devicetree/bindings/watchdog/moxa,moxart-watchdog.txt15
-rw-r--r--drivers/watchdog/Kconfig10
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/moxart_wdt.c165
4 files changed, 191 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/moxa,moxart-watchdog.txt b/Documentation/devicetree/bindings/watchdog/moxa,moxart-watchdog.txt
new file mode 100644
index 000000000000..1169857d1d12
--- /dev/null
+++ b/Documentation/devicetree/bindings/watchdog/moxa,moxart-watchdog.txt
@@ -0,0 +1,15 @@
1MOXA ART Watchdog timer
2
3Required properties:
4
5- compatible : Must be "moxa,moxart-watchdog"
6- reg : Should contain registers location and length
7- clocks : Should contain phandle for the clock that drives the counter
8
9Example:
10
11 watchdog: watchdog@98500000 {
12 compatible = "moxa,moxart-watchdog";
13 reg = <0x98500000 0x10>;
14 clocks = <&coreclk>;
15 };
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 6df632e0bb55..7fc6e101923a 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -392,6 +392,16 @@ config RETU_WATCHDOG
392 To compile this driver as a module, choose M here: the 392 To compile this driver as a module, choose M here: the
393 module will be called retu_wdt. 393 module will be called retu_wdt.
394 394
395config MOXART_WDT
396 tristate "MOXART watchdog"
397 depends on ARCH_MOXART
398 help
399 Say Y here to include Watchdog timer support for the watchdog
400 existing on the MOXA ART SoC series platforms.
401
402 To compile this driver as a module, choose M here: the
403 module will be called moxart_wdt.
404
395# AVR32 Architecture 405# AVR32 Architecture
396 406
397config AT32AP700X_WDT 407config AT32AP700X_WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 8c7b8bcbbdc5..40c36ccdd0d4 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
55obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o 55obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
56obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o 56obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
57obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o 57obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
58obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o
58 59
59# AVR32 Architecture 60# AVR32 Architecture
60obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o 61obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/moxart_wdt.c b/drivers/watchdog/moxart_wdt.c
new file mode 100644
index 000000000000..4166e4d116a8
--- /dev/null
+++ b/drivers/watchdog/moxart_wdt.c
@@ -0,0 +1,165 @@
1/*
2 * MOXA ART SoCs watchdog driver.
3 *
4 * Copyright (C) 2013 Jonas Jensen
5 *
6 * Jonas Jensen <jonas.jensen@gmail.com>
7 *
8 * This file is licensed under the terms of the GNU General Public
9 * License version 2. This program is licensed "as is" without any
10 * warranty of any kind, whether express or implied.
11 */
12
13#include <linux/clk.h>
14#include <linux/io.h>
15#include <linux/module.h>
16#include <linux/err.h>
17#include <linux/kernel.h>
18#include <linux/platform_device.h>
19#include <linux/watchdog.h>
20#include <linux/moduleparam.h>
21
22#define REG_COUNT 0x4
23#define REG_MODE 0x8
24#define REG_ENABLE 0xC
25
26struct moxart_wdt_dev {
27 struct watchdog_device dev;
28 void __iomem *base;
29 unsigned int clock_frequency;
30};
31
32static int heartbeat;
33
34static int moxart_wdt_stop(struct watchdog_device *wdt_dev)
35{
36 struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev);
37
38 writel(0, moxart_wdt->base + REG_ENABLE);
39
40 return 0;
41}
42
43static int moxart_wdt_start(struct watchdog_device *wdt_dev)
44{
45 struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev);
46
47 writel(moxart_wdt->clock_frequency * wdt_dev->timeout,
48 moxart_wdt->base + REG_COUNT);
49 writel(0x5ab9, moxart_wdt->base + REG_MODE);
50 writel(0x03, moxart_wdt->base + REG_ENABLE);
51
52 return 0;
53}
54
55static int moxart_wdt_set_timeout(struct watchdog_device *wdt_dev,
56 unsigned int timeout)
57{
58 wdt_dev->timeout = timeout;
59
60 return 0;
61}
62
63static const struct watchdog_info moxart_wdt_info = {
64 .identity = "moxart-wdt",
65 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
66 WDIOF_MAGICCLOSE,
67};
68
69static const struct watchdog_ops moxart_wdt_ops = {
70 .owner = THIS_MODULE,
71 .start = moxart_wdt_start,
72 .stop = moxart_wdt_stop,
73 .set_timeout = moxart_wdt_set_timeout,
74};
75
76static int moxart_wdt_probe(struct platform_device *pdev)
77{
78 struct moxart_wdt_dev *moxart_wdt;
79 struct device *dev = &pdev->dev;
80 struct device_node *node = dev->of_node;
81 struct resource *res;
82 struct clk *clk;
83 int err;
84 unsigned int max_timeout;
85 bool nowayout = WATCHDOG_NOWAYOUT;
86
87 moxart_wdt = devm_kzalloc(dev, sizeof(*moxart_wdt), GFP_KERNEL);
88 if (!moxart_wdt)
89 return -ENOMEM;
90
91 platform_set_drvdata(pdev, moxart_wdt);
92
93 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
94 moxart_wdt->base = devm_ioremap_resource(dev, res);
95 if (IS_ERR(moxart_wdt->base))
96 return PTR_ERR(moxart_wdt->base);
97
98 clk = of_clk_get(node, 0);
99 if (IS_ERR(clk)) {
100 pr_err("%s: of_clk_get failed\n", __func__);
101 return PTR_ERR(clk);
102 }
103
104 moxart_wdt->clock_frequency = clk_get_rate(clk);
105 if (moxart_wdt->clock_frequency == 0) {
106 pr_err("%s: incorrect clock frequency\n", __func__);
107 return -EINVAL;
108 }
109
110 max_timeout = UINT_MAX / moxart_wdt->clock_frequency;
111
112 moxart_wdt->dev.info = &moxart_wdt_info;
113 moxart_wdt->dev.ops = &moxart_wdt_ops;
114 moxart_wdt->dev.timeout = max_timeout;
115 moxart_wdt->dev.min_timeout = 1;
116 moxart_wdt->dev.max_timeout = max_timeout;
117 moxart_wdt->dev.parent = dev;
118
119 watchdog_init_timeout(&moxart_wdt->dev, heartbeat, dev);
120 watchdog_set_nowayout(&moxart_wdt->dev, nowayout);
121
122 watchdog_set_drvdata(&moxart_wdt->dev, moxart_wdt);
123
124 err = watchdog_register_device(&moxart_wdt->dev);
125 if (err)
126 return err;
127
128 dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n",
129 moxart_wdt->dev.timeout, nowayout);
130
131 return 0;
132}
133
134static int moxart_wdt_remove(struct platform_device *pdev)
135{
136 struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev);
137
138 moxart_wdt_stop(&moxart_wdt->dev);
139 watchdog_unregister_device(&moxart_wdt->dev);
140
141 return 0;
142}
143
144static const struct of_device_id moxart_watchdog_match[] = {
145 { .compatible = "moxa,moxart-watchdog" },
146 { },
147};
148
149static struct platform_driver moxart_wdt_driver = {
150 .probe = moxart_wdt_probe,
151 .remove = moxart_wdt_remove,
152 .driver = {
153 .name = "moxart-watchdog",
154 .owner = THIS_MODULE,
155 .of_match_table = moxart_watchdog_match,
156 },
157};
158module_platform_driver(moxart_wdt_driver);
159
160module_param(heartbeat, int, 0);
161MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds");
162
163MODULE_DESCRIPTION("MOXART watchdog driver");
164MODULE_LICENSE("GPL");
165MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");