aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaro Koskinen <aaro.koskinen@iki.fi>2012-12-27 15:58:29 -0500
committerWim Van Sebroeck <wim@iguana.be>2013-03-01 06:31:14 -0500
commit3d3a6d18abc66ba38e554fd5cb5991dfa805cd23 (patch)
tree588d6d86b6ce6aaed3198a482657398546d98ca3
parentd1ec74ab5a48d794c5e3671a895d49d162d0f916 (diff)
watchdog: introduce retu_wdt driver
Introduce Retu watchdog driver. Cc: linux-watchdog@vger.kernel.org Acked-by: Felipe Balbi <balbi@ti.com> Acked-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--drivers/watchdog/Kconfig12
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/retu_wdt.c178
3 files changed, 191 insertions, 0 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index bb74186d88f3..7f61687504b7 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -377,6 +377,18 @@ config UX500_WATCHDOG
377 To compile this driver as a module, choose M here: the 377 To compile this driver as a module, choose M here: the
378 module will be called ux500_wdt. 378 module will be called ux500_wdt.
379 379
380config RETU_WATCHDOG
381 tristate "Retu watchdog"
382 depends on MFD_RETU
383 select WATCHDOG_CORE
384 help
385 Retu watchdog driver for Nokia Internet Tablets (770, N800,
386 N810). At least on N800 the watchdog cannot be disabled, so
387 this driver is essential and you should enable it.
388
389 To compile this driver as a module, choose M here: the
390 module will be called retu_wdt.
391
380# AVR32 Architecture 392# AVR32 Architecture
381 393
382config AT32AP700X_WDT 394config AT32AP700X_WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index bec86ee6e9e3..f7a612c0a5b4 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
53obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o 53obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
54obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o 54obj-$(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
56 57
57# AVR32 Architecture 58# AVR32 Architecture
58obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o 59obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
diff --git a/drivers/watchdog/retu_wdt.c b/drivers/watchdog/retu_wdt.c
new file mode 100644
index 000000000000..f53615dc633d
--- /dev/null
+++ b/drivers/watchdog/retu_wdt.c
@@ -0,0 +1,178 @@
1/*
2 * Retu watchdog driver
3 *
4 * Copyright (C) 2004, 2005 Nokia Corporation
5 *
6 * Based on code written by Amit Kucheria and Michael Buesch.
7 * Rewritten by Aaro Koskinen.
8 *
9 * This file is subject to the terms and conditions of the GNU General
10 * Public License. See the file "COPYING" in the main directory of this
11 * archive for more details.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/init.h>
20#include <linux/slab.h>
21#include <linux/errno.h>
22#include <linux/device.h>
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/mfd/retu.h>
26#include <linux/watchdog.h>
27#include <linux/platform_device.h>
28
29/* Watchdog timer values in seconds */
30#define RETU_WDT_MAX_TIMER 63
31
32struct retu_wdt_dev {
33 struct retu_dev *rdev;
34 struct device *dev;
35 struct delayed_work ping_work;
36};
37
38/*
39 * Since Retu watchdog cannot be disabled in hardware, we must kick it
40 * with a timer until userspace watchdog software takes over. If
41 * CONFIG_WATCHDOG_NOWAYOUT is set, we never start the feeding.
42 */
43static void retu_wdt_ping_enable(struct retu_wdt_dev *wdev)
44{
45 retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER);
46 schedule_delayed_work(&wdev->ping_work,
47 round_jiffies_relative(RETU_WDT_MAX_TIMER * HZ / 2));
48}
49
50static void retu_wdt_ping_disable(struct retu_wdt_dev *wdev)
51{
52 retu_write(wdev->rdev, RETU_REG_WATCHDOG, RETU_WDT_MAX_TIMER);
53 cancel_delayed_work_sync(&wdev->ping_work);
54}
55
56static void retu_wdt_ping_work(struct work_struct *work)
57{
58 struct retu_wdt_dev *wdev = container_of(to_delayed_work(work),
59 struct retu_wdt_dev, ping_work);
60 retu_wdt_ping_enable(wdev);
61}
62
63static int retu_wdt_start(struct watchdog_device *wdog)
64{
65 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
66
67 retu_wdt_ping_disable(wdev);
68
69 return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
70}
71
72static int retu_wdt_stop(struct watchdog_device *wdog)
73{
74 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
75
76 retu_wdt_ping_enable(wdev);
77
78 return 0;
79}
80
81static int retu_wdt_ping(struct watchdog_device *wdog)
82{
83 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
84
85 return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
86}
87
88static int retu_wdt_set_timeout(struct watchdog_device *wdog,
89 unsigned int timeout)
90{
91 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
92
93 wdog->timeout = timeout;
94 return retu_write(wdev->rdev, RETU_REG_WATCHDOG, wdog->timeout);
95}
96
97static const struct watchdog_info retu_wdt_info = {
98 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
99 .identity = "Retu watchdog",
100};
101
102static const struct watchdog_ops retu_wdt_ops = {
103 .owner = THIS_MODULE,
104 .start = retu_wdt_start,
105 .stop = retu_wdt_stop,
106 .ping = retu_wdt_ping,
107 .set_timeout = retu_wdt_set_timeout,
108};
109
110static int retu_wdt_probe(struct platform_device *pdev)
111{
112 struct retu_dev *rdev = dev_get_drvdata(pdev->dev.parent);
113 bool nowayout = WATCHDOG_NOWAYOUT;
114 struct watchdog_device *retu_wdt;
115 struct retu_wdt_dev *wdev;
116 int ret;
117
118 retu_wdt = devm_kzalloc(&pdev->dev, sizeof(*retu_wdt), GFP_KERNEL);
119 if (!retu_wdt)
120 return -ENOMEM;
121
122 wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
123 if (!wdev)
124 return -ENOMEM;
125
126 retu_wdt->info = &retu_wdt_info;
127 retu_wdt->ops = &retu_wdt_ops;
128 retu_wdt->timeout = RETU_WDT_MAX_TIMER;
129 retu_wdt->min_timeout = 0;
130 retu_wdt->max_timeout = RETU_WDT_MAX_TIMER;
131
132 watchdog_set_drvdata(retu_wdt, wdev);
133 watchdog_set_nowayout(retu_wdt, nowayout);
134
135 wdev->rdev = rdev;
136 wdev->dev = &pdev->dev;
137
138 INIT_DELAYED_WORK(&wdev->ping_work, retu_wdt_ping_work);
139
140 ret = watchdog_register_device(retu_wdt);
141 if (ret < 0)
142 return ret;
143
144 if (nowayout)
145 retu_wdt_ping(retu_wdt);
146 else
147 retu_wdt_ping_enable(wdev);
148
149 platform_set_drvdata(pdev, retu_wdt);
150
151 return 0;
152}
153
154static int retu_wdt_remove(struct platform_device *pdev)
155{
156 struct watchdog_device *wdog = platform_get_drvdata(pdev);
157 struct retu_wdt_dev *wdev = watchdog_get_drvdata(wdog);
158
159 watchdog_unregister_device(wdog);
160 cancel_delayed_work_sync(&wdev->ping_work);
161
162 return 0;
163}
164
165static struct platform_driver retu_wdt_driver = {
166 .probe = retu_wdt_probe,
167 .remove = retu_wdt_remove,
168 .driver = {
169 .name = "retu-wdt",
170 },
171};
172module_platform_driver(retu_wdt_driver);
173
174MODULE_ALIAS("platform:retu-wdt");
175MODULE_DESCRIPTION("Retu watchdog");
176MODULE_AUTHOR("Amit Kucheria");
177MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>");
178MODULE_LICENSE("GPL");