Root/target/linux/lantiq/patches-2.6.32/0013-MIPS-Lantiq-Add-watchdog-support.patch

1From 3466449c8f455da0cb646231602e6af16190f592 Mon Sep 17 00:00:00 2001
2From: John Crispin <blogic@openwrt.org>
3Date: Thu, 5 May 2011 23:00:23 +0200
4Subject: [PATCH 13/13] MIPS: Lantiq: Add watchdog support
5
6This patch adds the driver for the watchdog found inside the Lantiq SoC family.
7
8Signed-off-by: John Crispin <blogic@openwrt.org>
9Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
10Cc: Wim Van Sebroeck <wim@iguana.be>
11Cc: linux-mips@linux-mips.org
12Cc: linux-watchdog@vger.kernel.org
13Patchwork: https://patchwork.linux-mips.org/patch/2327/
14Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
15---
16 drivers/watchdog/Kconfig | 6 +
17 drivers/watchdog/Makefile | 1 +
18 drivers/watchdog/lantiq_wdt.c | 261 +++++++++++++++++++++++++++++++++++++++++
19 3 files changed, 268 insertions(+), 0 deletions(-)
20 create mode 100644 drivers/watchdog/lantiq_wdt.c
21
22--- a/drivers/watchdog/Kconfig
23+++ b/drivers/watchdog/Kconfig
24@@ -850,6 +850,12 @@
25     help
26       Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
27 
28+config LANTIQ_WDT
29+ tristate "Lantiq SoC watchdog"
30+ depends on LANTIQ
31+ help
32+ Hardware driver for the Lantiq SoC Watchdog Timer.
33+
34 # PARISC Architecture
35 
36 # POWERPC Architecture
37--- a/drivers/watchdog/Makefile
38+++ b/drivers/watchdog/Makefile
39@@ -113,6 +113,7 @@
40 obj-$(CONFIG_SIBYTE_WDOG) += sb_wdog.o
41 obj-$(CONFIG_AR7_WDT) += ar7_wdt.o
42 obj-$(CONFIG_TXX9_WDT) += txx9wdt.o
43+obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
44 
45 # PARISC Architecture
46 
47--- /dev/null
48+++ b/drivers/watchdog/lantiq_wdt.c
49@@ -0,0 +1,261 @@
50+/*
51+ * This program is free software; you can redistribute it and/or modify it
52+ * under the terms of the GNU General Public License version 2 as published
53+ * by the Free Software Foundation.
54+ *
55+ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
56+ * Based on EP93xx wdt driver
57+ */
58+
59+#include <linux/module.h>
60+#include <linux/fs.h>
61+#include <linux/miscdevice.h>
62+#include <linux/watchdog.h>
63+#include <linux/platform_device.h>
64+#include <linux/uaccess.h>
65+#include <linux/clk.h>
66+#include <linux/io.h>
67+
68+#include <lantiq.h>
69+
70+/* Section 3.4 of the datasheet
71+ * The password sequence protects the WDT control register from unintended
72+ * write actions, which might cause malfunction of the WDT.
73+ *
74+ * essentially the following two magic passwords need to be written to allow
75+ * IO access to the WDT core
76+ */
77+#define LTQ_WDT_PW1 0x00BE0000
78+#define LTQ_WDT_PW2 0x00DC0000
79+
80+#define LTQ_WDT_CR 0x0 /* watchdog control register */
81+#define LTQ_WDT_SR 0x8 /* watchdog status register */
82+
83+#define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */
84+#define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */
85+#define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */
86+ /* divider to 0x40000 */
87+#define LTQ_WDT_DIVIDER 0x40000
88+#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */
89+
90+static int nowayout = WATCHDOG_NOWAYOUT;
91+
92+static void __iomem *ltq_wdt_membase;
93+static unsigned long ltq_io_region_clk_rate;
94+
95+static unsigned long ltq_wdt_bootstatus;
96+static unsigned long ltq_wdt_in_use;
97+static int ltq_wdt_timeout = 30;
98+static int ltq_wdt_ok_to_close;
99+
100+static void
101+ltq_wdt_enable(void)
102+{
103+ ltq_wdt_timeout = ltq_wdt_timeout *
104+ (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
105+ if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT)
106+ ltq_wdt_timeout = LTQ_MAX_TIMEOUT;
107+
108+ /* write the first password magic */
109+ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
110+ /* write the second magic plus the configuration and new timeout */
111+ ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
112+ LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR);
113+}
114+
115+static void
116+ltq_wdt_disable(void)
117+{
118+ /* write the first password magic */
119+ ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
120+ /* write the second password magic with no config
121+ * this turns the watchdog off
122+ */
123+ ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR);
124+}
125+
126+static ssize_t
127+ltq_wdt_write(struct file *file, const char __user *data,
128+ size_t len, loff_t *ppos)
129+{
130+ if (len) {
131+ if (!nowayout) {
132+ size_t i;
133+
134+ ltq_wdt_ok_to_close = 0;
135+ for (i = 0; i != len; i++) {
136+ char c;
137+
138+ if (get_user(c, data + i))
139+ return -EFAULT;
140+ if (c == 'V')
141+ ltq_wdt_ok_to_close = 1;
142+ else
143+ ltq_wdt_ok_to_close = 0;
144+ }
145+ }
146+ ltq_wdt_enable();
147+ }
148+
149+ return len;
150+}
151+
152+static struct watchdog_info ident = {
153+ .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
154+ WDIOF_CARDRESET,
155+ .identity = "ltq_wdt",
156+};
157+
158+static long
159+ltq_wdt_ioctl(struct file *file,
160+ unsigned int cmd, unsigned long arg)
161+{
162+ int ret = -ENOTTY;
163+
164+ switch (cmd) {
165+ case WDIOC_GETSUPPORT:
166+ ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
167+ sizeof(ident)) ? -EFAULT : 0;
168+ break;
169+
170+ case WDIOC_GETBOOTSTATUS:
171+ ret = put_user(ltq_wdt_bootstatus, (int __user *)arg);
172+ break;
173+
174+ case WDIOC_GETSTATUS:
175+ ret = put_user(0, (int __user *)arg);
176+ break;
177+
178+ case WDIOC_SETTIMEOUT:
179+ ret = get_user(ltq_wdt_timeout, (int __user *)arg);
180+ if (!ret)
181+ ltq_wdt_enable();
182+ /* intentional drop through */
183+ case WDIOC_GETTIMEOUT:
184+ ret = put_user(ltq_wdt_timeout, (int __user *)arg);
185+ break;
186+
187+ case WDIOC_KEEPALIVE:
188+ ltq_wdt_enable();
189+ ret = 0;
190+ break;
191+ }
192+ return ret;
193+}
194+
195+static int
196+ltq_wdt_open(struct inode *inode, struct file *file)
197+{
198+ if (test_and_set_bit(0, &ltq_wdt_in_use))
199+ return -EBUSY;
200+ ltq_wdt_in_use = 1;
201+ ltq_wdt_enable();
202+
203+ return nonseekable_open(inode, file);
204+}
205+
206+static int
207+ltq_wdt_release(struct inode *inode, struct file *file)
208+{
209+ if (ltq_wdt_ok_to_close)
210+ ltq_wdt_disable();
211+ else
212+ pr_err("ltq_wdt: watchdog closed without warning\n");
213+ ltq_wdt_ok_to_close = 0;
214+ clear_bit(0, &ltq_wdt_in_use);
215+
216+ return 0;
217+}
218+
219+static const struct file_operations ltq_wdt_fops = {
220+ .owner = THIS_MODULE,
221+ .write = ltq_wdt_write,
222+ .unlocked_ioctl = ltq_wdt_ioctl,
223+ .open = ltq_wdt_open,
224+ .release = ltq_wdt_release,
225+ .llseek = no_llseek,
226+};
227+
228+static struct miscdevice ltq_wdt_miscdev = {
229+ .minor = WATCHDOG_MINOR,
230+ .name = "watchdog",
231+ .fops = &ltq_wdt_fops,
232+};
233+
234+static int __init
235+ltq_wdt_probe(struct platform_device *pdev)
236+{
237+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
238+ struct clk *clk;
239+
240+ if (!res) {
241+ dev_err(&pdev->dev, "cannot obtain I/O memory region");
242+ return -ENOENT;
243+ }
244+ res = devm_request_mem_region(&pdev->dev, res->start,
245+ resource_size(res), dev_name(&pdev->dev));
246+ if (!res) {
247+ dev_err(&pdev->dev, "cannot request I/O memory region");
248+ return -EBUSY;
249+ }
250+ ltq_wdt_membase = devm_ioremap_nocache(&pdev->dev, res->start,
251+ resource_size(res));
252+ if (!ltq_wdt_membase) {
253+ dev_err(&pdev->dev, "cannot remap I/O memory region\n");
254+ return -ENOMEM;
255+ }
256+
257+ /* we do not need to enable the clock as it is always running */
258+ clk = clk_get(&pdev->dev, "io");
259+ WARN_ON(!clk);
260+ ltq_io_region_clk_rate = clk_get_rate(clk);
261+ clk_put(clk);
262+
263+ if (ltq_reset_cause() == LTQ_RST_CAUSE_WDTRST)
264+ ltq_wdt_bootstatus = WDIOF_CARDRESET;
265+
266+ return misc_register(&ltq_wdt_miscdev);
267+}
268+
269+static int __devexit
270+ltq_wdt_remove(struct platform_device *pdev)
271+{
272+ misc_deregister(&ltq_wdt_miscdev);
273+
274+ if (ltq_wdt_membase)
275+ iounmap(ltq_wdt_membase);
276+
277+ return 0;
278+}
279+
280+
281+static struct platform_driver ltq_wdt_driver = {
282+ .remove = __devexit_p(ltq_wdt_remove),
283+ .driver = {
284+ .name = "ltq_wdt",
285+ .owner = THIS_MODULE,
286+ },
287+};
288+
289+static int __init
290+init_ltq_wdt(void)
291+{
292+ return platform_driver_probe(&ltq_wdt_driver, ltq_wdt_probe);
293+}
294+
295+static void __exit
296+exit_ltq_wdt(void)
297+{
298+ return platform_driver_unregister(&ltq_wdt_driver);
299+}
300+
301+module_init(init_ltq_wdt);
302+module_exit(exit_ltq_wdt);
303+
304+module_param(nowayout, int, 0);
305+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
306+
307+MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
308+MODULE_DESCRIPTION("Lantiq SoC Watchdog");
309+MODULE_LICENSE("GPL");
310+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
311

Archive Download this file



interactive