aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-12-21 20:10:29 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-21 20:10:29 -0500
commit4fe19a136a8871e5fc6e44d72979f18a4968c2ab (patch)
tree785366514a250acd3f38f91686f2c886dc34cfb9 /drivers
parent769cb858c23ba7379ea27208624b444cd7b61af2 (diff)
parentd692170037c0338b31dac5ac4722c1360a4b5257 (diff)
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck: "This includes some fixes and code improvements (like clk_prepare_enable and clk_disable_unprepare), conversion from the omap_wdt and twl4030_wdt drivers to the watchdog framework, addition of the SB8x0 chipset support and the DA9055 Watchdog driver and some OF support for the davinci_wdt driver." * git://www.linux-watchdog.org/linux-watchdog: (22 commits) watchdog: mei: avoid oops in watchdog unregister code path watchdog: Orion: Fix possible null-deference in orion_wdt_probe watchdog: sp5100_tco: Add SB8x0 chipset support watchdog: davinci_wdt: add OF support watchdog: da9052: Fix invalid free of devm_ allocated data watchdog: twl4030_wdt: Change TWL4030_MODULE_PM_RECEIVER to TWL_MODULE_PM_RECEIVER watchdog: remove depends on CONFIG_EXPERIMENTAL watchdog: Convert dev_printk(KERN_<LEVEL> to dev_<level>( watchdog: DA9055 Watchdog driver watchdog: omap_wdt: eliminate goto watchdog: omap_wdt: delete redundant platform_set_drvdata() calls watchdog: omap_wdt: convert to devm_ functions watchdog: omap_wdt: convert to new watchdog core watchdog: WatchDog Timer Driver Core: fix comment watchdog: s3c2410_wdt: use clk_prepare_enable and clk_disable_unprepare watchdog: imx2_wdt: Select the driver via ARCH_MXC watchdog: cpu5wdt.c: add missing del_timer call watchdog: hpwdt.c: Increase version string watchdog: Convert twl4030_wdt to watchdog core davinci_wdt: preparation for switch to common clock framework ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/misc/mei/wd.c2
-rw-r--r--drivers/watchdog/Kconfig18
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/ath79_wdt.c13
-rw-r--r--drivers/watchdog/cpu5wdt.c1
-rw-r--r--drivers/watchdog/da9052_wdt.c4
-rw-r--r--drivers/watchdog/da9055_wdt.c216
-rw-r--r--drivers/watchdog/davinci_wdt.c11
-rw-r--r--drivers/watchdog/hpwdt.c2
-rw-r--r--drivers/watchdog/mpcore_wdt.c19
-rw-r--r--drivers/watchdog/omap_wdt.c311
-rw-r--r--drivers/watchdog/orion_wdt.c2
-rw-r--r--drivers/watchdog/s3c2410_wdt.c6
-rw-r--r--drivers/watchdog/sp5100_tco.c321
-rw-r--r--drivers/watchdog/sp5100_tco.h46
-rw-r--r--drivers/watchdog/sp805_wdt.c11
-rw-r--r--drivers/watchdog/twl4030_wdt.c185
17 files changed, 725 insertions, 444 deletions
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index 636409f9667f..9299a8c29a6f 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -370,7 +370,7 @@ void mei_watchdog_register(struct mei_device *dev)
370 370
371void mei_watchdog_unregister(struct mei_device *dev) 371void mei_watchdog_unregister(struct mei_device *dev)
372{ 372{
373 if (test_bit(WDOG_UNREGISTERED, &amt_wd_dev.status)) 373 if (watchdog_get_drvdata(&amt_wd_dev) == NULL)
374 return; 374 return;
375 375
376 watchdog_set_drvdata(&amt_wd_dev, NULL); 376 watchdog_set_drvdata(&amt_wd_dev, NULL);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index ad1bb9382a96..7f809fd4a57f 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -76,6 +76,16 @@ config DA9052_WATCHDOG
76 Alternatively say M to compile the driver as a module, 76 Alternatively say M to compile the driver as a module,
77 which will be called da9052_wdt. 77 which will be called da9052_wdt.
78 78
79config DA9055_WATCHDOG
80 tristate "Dialog Semiconductor DA9055 Watchdog"
81 depends on MFD_DA9055
82 help
83 If you say yes here you get support for watchdog on the Dialog
84 Semiconductor DA9055 PMIC.
85
86 This driver can also be built as a module. If so, the module
87 will be called da9055_wdt.
88
79config WM831X_WATCHDOG 89config WM831X_WATCHDOG
80 tristate "WM831x watchdog" 90 tristate "WM831x watchdog"
81 depends on MFD_WM831X 91 depends on MFD_WM831X
@@ -232,6 +242,7 @@ config EP93XX_WATCHDOG
232config OMAP_WATCHDOG 242config OMAP_WATCHDOG
233 tristate "OMAP Watchdog" 243 tristate "OMAP Watchdog"
234 depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS 244 depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
245 select WATCHDOG_CORE
235 help 246 help
236 Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y' 247 Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y'
237 here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer. 248 here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer.
@@ -300,6 +311,7 @@ config COH901327_WATCHDOG
300config TWL4030_WATCHDOG 311config TWL4030_WATCHDOG
301 tristate "TWL4030 Watchdog" 312 tristate "TWL4030 Watchdog"
302 depends on TWL4030_CORE 313 depends on TWL4030_CORE
314 select WATCHDOG_CORE
303 help 315 help
304 Support for TI TWL4030 watchdog. Say 'Y' here to enable the 316 Support for TI TWL4030 watchdog. Say 'Y' here to enable the
305 watchdog timer support for TWL4030 chips. 317 watchdog timer support for TWL4030 chips.
@@ -342,7 +354,7 @@ config MAX63XX_WATCHDOG
342 354
343config IMX2_WDT 355config IMX2_WDT
344 tristate "IMX2+ Watchdog" 356 tristate "IMX2+ Watchdog"
345 depends on IMX_HAVE_PLATFORM_IMX2_WDT 357 depends on ARCH_MXC
346 help 358 help
347 This is the driver for the hardware watchdog 359 This is the driver for the hardware watchdog
348 on the Freescale IMX2 and later processors. 360 on the Freescale IMX2 and later processors.
@@ -431,7 +443,7 @@ config ALIM7101_WDT
431 443
432config F71808E_WDT 444config F71808E_WDT
433 tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog" 445 tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog"
434 depends on X86 && EXPERIMENTAL 446 depends on X86
435 help 447 help
436 This is the driver for the hardware watchdog on the Fintek 448 This is the driver for the hardware watchdog on the Fintek
437 F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers. 449 F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers.
@@ -622,7 +634,7 @@ config IT8712F_WDT
622 634
623config IT87_WDT 635config IT87_WDT
624 tristate "IT87 Watchdog Timer" 636 tristate "IT87 Watchdog Timer"
625 depends on X86 && EXPERIMENTAL 637 depends on X86
626 ---help--- 638 ---help---
627 This is the driver for the hardware watchdog on the ITE IT8702, 639 This is the driver for the hardware watchdog on the ITE IT8702,
628 IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728 640 IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 572b39bed06a..97bbdb3a4648 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -164,6 +164,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o
164 164
165# Architecture Independent 165# Architecture Independent
166obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o 166obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
167obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
167obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o 168obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
168obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o 169obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
169obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o 170obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index 7c8ede7816b1..38a999e60c0d 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -284,6 +284,7 @@ static void ath97_wdt_shutdown(struct platform_device *pdev)
284} 284}
285 285
286static struct platform_driver ath79_wdt_driver = { 286static struct platform_driver ath79_wdt_driver = {
287 .probe = ath79_wdt_probe,
287 .remove = ath79_wdt_remove, 288 .remove = ath79_wdt_remove,
288 .shutdown = ath97_wdt_shutdown, 289 .shutdown = ath97_wdt_shutdown,
289 .driver = { 290 .driver = {
@@ -292,17 +293,7 @@ static struct platform_driver ath79_wdt_driver = {
292 }, 293 },
293}; 294};
294 295
295static int __init ath79_wdt_init(void) 296module_platform_driver(ath79_wdt_driver);
296{
297 return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe);
298}
299module_init(ath79_wdt_init);
300
301static void __exit ath79_wdt_exit(void)
302{
303 platform_driver_unregister(&ath79_wdt_driver);
304}
305module_exit(ath79_wdt_exit);
306 297
307MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver"); 298MODULE_DESCRIPTION("Atheros AR71XX/AR724X/AR913X hardware watchdog driver");
308MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org"); 299MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org");
diff --git a/drivers/watchdog/cpu5wdt.c b/drivers/watchdog/cpu5wdt.c
index cd87758abac3..f270bb7bc456 100644
--- a/drivers/watchdog/cpu5wdt.c
+++ b/drivers/watchdog/cpu5wdt.c
@@ -266,6 +266,7 @@ static void cpu5wdt_exit(void)
266 if (cpu5wdt_device.queue) { 266 if (cpu5wdt_device.queue) {
267 cpu5wdt_device.queue = 0; 267 cpu5wdt_device.queue = 0;
268 wait_for_completion(&cpu5wdt_device.stop); 268 wait_for_completion(&cpu5wdt_device.stop);
269 del_timer(&cpu5wdt_device.timer);
269 } 270 }
270 271
271 misc_deregister(&cpu5wdt_misc); 272 misc_deregister(&cpu5wdt_misc);
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c
index 8be70d8f2680..367445009c64 100644
--- a/drivers/watchdog/da9052_wdt.c
+++ b/drivers/watchdog/da9052_wdt.c
@@ -53,10 +53,6 @@ static const struct {
53 53
54static void da9052_wdt_release_resources(struct kref *r) 54static void da9052_wdt_release_resources(struct kref *r)
55{ 55{
56 struct da9052_wdt_data *driver_data =
57 container_of(r, struct da9052_wdt_data, kref);
58
59 kfree(driver_data);
60} 56}
61 57
62static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev, 58static int da9052_wdt_set_timeout(struct watchdog_device *wdt_dev,
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c
new file mode 100644
index 000000000000..709ea1aefebb
--- /dev/null
+++ b/drivers/watchdog/da9055_wdt.c
@@ -0,0 +1,216 @@
1/*
2 * System monitoring driver for DA9055 PMICs.
3 *
4 * Copyright(c) 2012 Dialog Semiconductor Ltd.
5 *
6 * Author: David Dajun Chen <dchen@diasemi.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 */
14
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/slab.h>
19#include <linux/platform_device.h>
20#include <linux/watchdog.h>
21#include <linux/delay.h>
22
23#include <linux/mfd/da9055/core.h>
24#include <linux/mfd/da9055/reg.h>
25
26static bool nowayout = WATCHDOG_NOWAYOUT;
27module_param(nowayout, bool, 0);
28MODULE_PARM_DESC(nowayout,
29 "Watchdog cannot be stopped once started (default="
30 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
31
32#define DA9055_DEF_TIMEOUT 4
33#define DA9055_TWDMIN 256
34
35struct da9055_wdt_data {
36 struct watchdog_device wdt;
37 struct da9055 *da9055;
38 struct kref kref;
39};
40
41static const struct {
42 u8 reg_val;
43 int user_time; /* In seconds */
44} da9055_wdt_maps[] = {
45 { 0, 0 },
46 { 1, 2 },
47 { 2, 4 },
48 { 3, 8 },
49 { 4, 16 },
50 { 5, 32 },
51 { 5, 33 }, /* Actual time 32.768s so included both 32s and 33s */
52 { 6, 65 },
53 { 6, 66 }, /* Actual time 65.536s so include both, 65s and 66s */
54 { 7, 131 },
55};
56
57static int da9055_wdt_set_timeout(struct watchdog_device *wdt_dev,
58 unsigned int timeout)
59{
60 struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
61 struct da9055 *da9055 = driver_data->da9055;
62 int ret, i;
63
64 for (i = 0; i < ARRAY_SIZE(da9055_wdt_maps); i++)
65 if (da9055_wdt_maps[i].user_time == timeout)
66 break;
67
68 if (i == ARRAY_SIZE(da9055_wdt_maps))
69 ret = -EINVAL;
70 else
71 ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
72 DA9055_TWDSCALE_MASK,
73 da9055_wdt_maps[i].reg_val <<
74 DA9055_TWDSCALE_SHIFT);
75 if (ret < 0)
76 dev_err(da9055->dev,
77 "Failed to update timescale bit, %d\n", ret);
78
79 wdt_dev->timeout = timeout;
80
81 return ret;
82}
83
84static int da9055_wdt_ping(struct watchdog_device *wdt_dev)
85{
86 struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
87 struct da9055 *da9055 = driver_data->da9055;
88 int ret;
89
90 /*
91 * We have a minimum time for watchdog window called TWDMIN. A write
92 * to the watchdog before this elapsed time will cause an error.
93 */
94 mdelay(DA9055_TWDMIN);
95
96 /* Reset the watchdog timer */
97 ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_E,
98 DA9055_WATCHDOG_MASK, 1);
99
100 return ret;
101}
102
103static void da9055_wdt_release_resources(struct kref *r)
104{
105 struct da9055_wdt_data *driver_data =
106 container_of(r, struct da9055_wdt_data, kref);
107
108 kfree(driver_data);
109}
110
111static void da9055_wdt_ref(struct watchdog_device *wdt_dev)
112{
113 struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
114
115 kref_get(&driver_data->kref);
116}
117
118static void da9055_wdt_unref(struct watchdog_device *wdt_dev)
119{
120 struct da9055_wdt_data *driver_data = watchdog_get_drvdata(wdt_dev);
121
122 kref_put(&driver_data->kref, da9055_wdt_release_resources);
123}
124
125static int da9055_wdt_start(struct watchdog_device *wdt_dev)
126{
127 return da9055_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
128}
129
130static int da9055_wdt_stop(struct watchdog_device *wdt_dev)
131{
132 return da9055_wdt_set_timeout(wdt_dev, 0);
133}
134
135static struct watchdog_info da9055_wdt_info = {
136 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
137 .identity = "DA9055 Watchdog",
138};
139
140static const struct watchdog_ops da9055_wdt_ops = {
141 .owner = THIS_MODULE,
142 .start = da9055_wdt_start,
143 .stop = da9055_wdt_stop,
144 .ping = da9055_wdt_ping,
145 .set_timeout = da9055_wdt_set_timeout,
146 .ref = da9055_wdt_ref,
147 .unref = da9055_wdt_unref,
148};
149
150static int da9055_wdt_probe(struct platform_device *pdev)
151{
152 struct da9055 *da9055 = dev_get_drvdata(pdev->dev.parent);
153 struct da9055_wdt_data *driver_data;
154 struct watchdog_device *da9055_wdt;
155 int ret;
156
157 driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
158 GFP_KERNEL);
159 if (!driver_data) {
160 dev_err(da9055->dev, "Failed to allocate watchdog device\n");
161 return -ENOMEM;
162 }
163
164 driver_data->da9055 = da9055;
165
166 da9055_wdt = &driver_data->wdt;
167
168 da9055_wdt->timeout = DA9055_DEF_TIMEOUT;
169 da9055_wdt->info = &da9055_wdt_info;
170 da9055_wdt->ops = &da9055_wdt_ops;
171 watchdog_set_nowayout(da9055_wdt, nowayout);
172 watchdog_set_drvdata(da9055_wdt, driver_data);
173
174 kref_init(&driver_data->kref);
175
176 ret = da9055_wdt_stop(da9055_wdt);
177 if (ret < 0) {
178 dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
179 goto err;
180 }
181
182 dev_set_drvdata(&pdev->dev, driver_data);
183
184 ret = watchdog_register_device(&driver_data->wdt);
185 if (ret != 0)
186 dev_err(da9055->dev, "watchdog_register_device() failed: %d\n",
187 ret);
188
189err:
190 return ret;
191}
192
193static int da9055_wdt_remove(struct platform_device *pdev)
194{
195 struct da9055_wdt_data *driver_data = dev_get_drvdata(&pdev->dev);
196
197 watchdog_unregister_device(&driver_data->wdt);
198 kref_put(&driver_data->kref, da9055_wdt_release_resources);
199
200 return 0;
201}
202
203static struct platform_driver da9055_wdt_driver = {
204 .probe = da9055_wdt_probe,
205 .remove = da9055_wdt_remove,
206 .driver = {
207 .name = "da9055-watchdog",
208 },
209};
210
211module_platform_driver(da9055_wdt_driver);
212
213MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
214MODULE_DESCRIPTION("DA9055 watchdog");
215MODULE_LICENSE("GPL");
216MODULE_ALIAS("platform:da9055-watchdog");
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index 8791879e5181..e8e87246ea6d 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -208,7 +208,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
208 if (WARN_ON(IS_ERR(wdt_clk))) 208 if (WARN_ON(IS_ERR(wdt_clk)))
209 return PTR_ERR(wdt_clk); 209 return PTR_ERR(wdt_clk);
210 210
211 clk_enable(wdt_clk); 211 clk_prepare_enable(wdt_clk);
212 212
213 if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT) 213 if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
214 heartbeat = DEFAULT_HEARTBEAT; 214 heartbeat = DEFAULT_HEARTBEAT;
@@ -256,16 +256,23 @@ static int davinci_wdt_remove(struct platform_device *pdev)
256 wdt_mem = NULL; 256 wdt_mem = NULL;
257 } 257 }
258 258
259 clk_disable(wdt_clk); 259 clk_disable_unprepare(wdt_clk);
260 clk_put(wdt_clk); 260 clk_put(wdt_clk);
261 261
262 return 0; 262 return 0;
263} 263}
264 264
265static const struct of_device_id davinci_wdt_of_match[] = {
266 { .compatible = "ti,davinci-wdt", },
267 {},
268};
269MODULE_DEVICE_TABLE(of, davinci_wdt_of_match);
270
265static struct platform_driver platform_wdt_driver = { 271static struct platform_driver platform_wdt_driver = {
266 .driver = { 272 .driver = {
267 .name = "watchdog", 273 .name = "watchdog",
268 .owner = THIS_MODULE, 274 .owner = THIS_MODULE,
275 .of_match_table = davinci_wdt_of_match,
269 }, 276 },
270 .probe = davinci_wdt_probe, 277 .probe = davinci_wdt_probe,
271 .remove = davinci_wdt_remove, 278 .remove = davinci_wdt_remove,
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 8717255ec7be..11796b9b864e 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -39,7 +39,7 @@
39#endif /* CONFIG_HPWDT_NMI_DECODING */ 39#endif /* CONFIG_HPWDT_NMI_DECODING */
40#include <asm/nmi.h> 40#include <asm/nmi.h>
41 41
42#define HPWDT_VERSION "1.3.0" 42#define HPWDT_VERSION "1.3.1"
43#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) 43#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
44#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) 44#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
45#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) 45#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c
index a84eb551ea27..233cfadcb21f 100644
--- a/drivers/watchdog/mpcore_wdt.c
+++ b/drivers/watchdog/mpcore_wdt.c
@@ -80,8 +80,7 @@ static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
80 80
81 /* Check it really was our interrupt */ 81 /* Check it really was our interrupt */
82 if (readl(wdt->base + TWD_WDOG_INTSTAT)) { 82 if (readl(wdt->base + TWD_WDOG_INTSTAT)) {
83 dev_printk(KERN_CRIT, wdt->dev, 83 dev_crit(wdt->dev, "Triggered - Reboot ignored\n");
84 "Triggered - Reboot ignored.\n");
85 /* Clear the interrupt on the watchdog */ 84 /* Clear the interrupt on the watchdog */
86 writel(1, wdt->base + TWD_WDOG_INTSTAT); 85 writel(1, wdt->base + TWD_WDOG_INTSTAT);
87 return IRQ_HANDLED; 86 return IRQ_HANDLED;
@@ -123,7 +122,7 @@ static void mpcore_wdt_stop(struct mpcore_wdt *wdt)
123 122
124static void mpcore_wdt_start(struct mpcore_wdt *wdt) 123static void mpcore_wdt_start(struct mpcore_wdt *wdt)
125{ 124{
126 dev_printk(KERN_INFO, wdt->dev, "enabling watchdog.\n"); 125 dev_info(wdt->dev, "enabling watchdog\n");
127 126
128 /* This loads the count register but does NOT start the count yet */ 127 /* This loads the count register but does NOT start the count yet */
129 mpcore_wdt_keepalive(wdt); 128 mpcore_wdt_keepalive(wdt);
@@ -180,8 +179,8 @@ static int mpcore_wdt_release(struct inode *inode, struct file *file)
180 if (wdt->expect_close == 42) 179 if (wdt->expect_close == 42)
181 mpcore_wdt_stop(wdt); 180 mpcore_wdt_stop(wdt);
182 else { 181 else {
183 dev_printk(KERN_CRIT, wdt->dev, 182 dev_crit(wdt->dev,
184 "unexpected close, not stopping watchdog!\n"); 183 "unexpected close, not stopping watchdog!\n");
185 mpcore_wdt_keepalive(wdt); 184 mpcore_wdt_keepalive(wdt);
186 } 185 }
187 clear_bit(0, &wdt->timer_alive); 186 clear_bit(0, &wdt->timer_alive);
@@ -351,9 +350,9 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
351 ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0, 350 ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0,
352 "mpcore_wdt", wdt); 351 "mpcore_wdt", wdt);
353 if (ret) { 352 if (ret) {
354 dev_printk(KERN_ERR, wdt->dev, 353 dev_err(wdt->dev,
355 "cannot register IRQ%d for watchdog\n", 354 "cannot register IRQ%d for watchdog\n",
356 wdt->irq); 355 wdt->irq);
357 return ret; 356 return ret;
358 } 357 }
359 } 358 }
@@ -365,9 +364,9 @@ static int mpcore_wdt_probe(struct platform_device *pdev)
365 mpcore_wdt_miscdev.parent = &pdev->dev; 364 mpcore_wdt_miscdev.parent = &pdev->dev;
366 ret = misc_register(&mpcore_wdt_miscdev); 365 ret = misc_register(&mpcore_wdt_miscdev);
367 if (ret) { 366 if (ret) {
368 dev_printk(KERN_ERR, wdt->dev, 367 dev_err(wdt->dev,
369 "cannot register miscdev on minor=%d (err=%d)\n", 368 "cannot register miscdev on minor=%d (err=%d)\n",
370 WATCHDOG_MINOR, ret); 369 WATCHDOG_MINOR, ret);
371 return ret; 370 return ret;
372 } 371 }
373 372
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 3e3ebbc83faf..34ed61ea02b4 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -31,42 +31,34 @@
31#include <linux/module.h> 31#include <linux/module.h>
32#include <linux/types.h> 32#include <linux/types.h>
33#include <linux/kernel.h> 33#include <linux/kernel.h>
34#include <linux/fs.h>
35#include <linux/mm.h> 34#include <linux/mm.h>
36#include <linux/miscdevice.h>
37#include <linux/watchdog.h> 35#include <linux/watchdog.h>
38#include <linux/reboot.h> 36#include <linux/reboot.h>
39#include <linux/init.h> 37#include <linux/init.h>
40#include <linux/err.h> 38#include <linux/err.h>
41#include <linux/platform_device.h> 39#include <linux/platform_device.h>
42#include <linux/moduleparam.h> 40#include <linux/moduleparam.h>
43#include <linux/bitops.h>
44#include <linux/io.h> 41#include <linux/io.h>
45#include <linux/uaccess.h>
46#include <linux/slab.h> 42#include <linux/slab.h>
47#include <linux/pm_runtime.h> 43#include <linux/pm_runtime.h>
48#include <linux/platform_data/omap-wd-timer.h> 44#include <linux/platform_data/omap-wd-timer.h>
49 45
50#include "omap_wdt.h" 46#include "omap_wdt.h"
51 47
52static struct platform_device *omap_wdt_dev;
53
54static unsigned timer_margin; 48static unsigned timer_margin;
55module_param(timer_margin, uint, 0); 49module_param(timer_margin, uint, 0);
56MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); 50MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
57 51
58static unsigned int wdt_trgr_pattern = 0x1234;
59static DEFINE_SPINLOCK(wdt_lock);
60
61struct omap_wdt_dev { 52struct omap_wdt_dev {
62 void __iomem *base; /* physical */ 53 void __iomem *base; /* physical */
63 struct device *dev; 54 struct device *dev;
64 int omap_wdt_users; 55 bool omap_wdt_users;
65 struct resource *mem; 56 struct resource *mem;
66 struct miscdevice omap_wdt_miscdev; 57 int wdt_trgr_pattern;
58 struct mutex lock; /* to avoid races with PM */
67}; 59};
68 60
69static void omap_wdt_ping(struct omap_wdt_dev *wdev) 61static void omap_wdt_reload(struct omap_wdt_dev *wdev)
70{ 62{
71 void __iomem *base = wdev->base; 63 void __iomem *base = wdev->base;
72 64
@@ -74,8 +66,8 @@ static void omap_wdt_ping(struct omap_wdt_dev *wdev)
74 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) 66 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
75 cpu_relax(); 67 cpu_relax();
76 68
77 wdt_trgr_pattern = ~wdt_trgr_pattern; 69 wdev->wdt_trgr_pattern = ~wdev->wdt_trgr_pattern;
78 __raw_writel(wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR)); 70 __raw_writel(wdev->wdt_trgr_pattern, (base + OMAP_WATCHDOG_TGR));
79 71
80 /* wait for posted write to complete */ 72 /* wait for posted write to complete */
81 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08) 73 while ((__raw_readl(base + OMAP_WATCHDOG_WPS)) & 0x08)
@@ -111,18 +103,10 @@ static void omap_wdt_disable(struct omap_wdt_dev *wdev)
111 cpu_relax(); 103 cpu_relax();
112} 104}
113 105
114static void omap_wdt_adjust_timeout(unsigned new_timeout) 106static void omap_wdt_set_timer(struct omap_wdt_dev *wdev,
115{ 107 unsigned int timeout)
116 if (new_timeout < TIMER_MARGIN_MIN)
117 new_timeout = TIMER_MARGIN_DEFAULT;
118 if (new_timeout > TIMER_MARGIN_MAX)
119 new_timeout = TIMER_MARGIN_MAX;
120 timer_margin = new_timeout;
121}
122
123static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
124{ 108{
125 u32 pre_margin = GET_WLDR_VAL(timer_margin); 109 u32 pre_margin = GET_WLDR_VAL(timeout);
126 void __iomem *base = wdev->base; 110 void __iomem *base = wdev->base;
127 111
128 /* just count up at 32 KHz */ 112 /* just count up at 32 KHz */
@@ -134,16 +118,14 @@ static void omap_wdt_set_timeout(struct omap_wdt_dev *wdev)
134 cpu_relax(); 118 cpu_relax();
135} 119}
136 120
137/* 121static int omap_wdt_start(struct watchdog_device *wdog)
138 * Allow only one task to hold it open
139 */
140static int omap_wdt_open(struct inode *inode, struct file *file)
141{ 122{
142 struct omap_wdt_dev *wdev = platform_get_drvdata(omap_wdt_dev); 123 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
143 void __iomem *base = wdev->base; 124 void __iomem *base = wdev->base;
144 125
145 if (test_and_set_bit(1, (unsigned long *)&(wdev->omap_wdt_users))) 126 mutex_lock(&wdev->lock);
146 return -EBUSY; 127
128 wdev->omap_wdt_users = true;
147 129
148 pm_runtime_get_sync(wdev->dev); 130 pm_runtime_get_sync(wdev->dev);
149 131
@@ -155,223 +137,169 @@ static int omap_wdt_open(struct inode *inode, struct file *file)
155 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01) 137 while (__raw_readl(base + OMAP_WATCHDOG_WPS) & 0x01)
156 cpu_relax(); 138 cpu_relax();
157 139
158 file->private_data = (void *) wdev; 140 omap_wdt_set_timer(wdev, wdog->timeout);
159 141 omap_wdt_reload(wdev); /* trigger loading of new timeout value */
160 omap_wdt_set_timeout(wdev);
161 omap_wdt_ping(wdev); /* trigger loading of new timeout value */
162 omap_wdt_enable(wdev); 142 omap_wdt_enable(wdev);
163 143
164 return nonseekable_open(inode, file); 144 mutex_unlock(&wdev->lock);
145
146 return 0;
165} 147}
166 148
167static int omap_wdt_release(struct inode *inode, struct file *file) 149static int omap_wdt_stop(struct watchdog_device *wdog)
168{ 150{
169 struct omap_wdt_dev *wdev = file->private_data; 151 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
170 152
171 /* 153 mutex_lock(&wdev->lock);
172 * Shut off the timer unless NOWAYOUT is defined.
173 */
174#ifndef CONFIG_WATCHDOG_NOWAYOUT
175 omap_wdt_disable(wdev); 154 omap_wdt_disable(wdev);
176
177 pm_runtime_put_sync(wdev->dev); 155 pm_runtime_put_sync(wdev->dev);
178#else 156 wdev->omap_wdt_users = false;
179 pr_crit("Unexpected close, not stopping!\n"); 157 mutex_unlock(&wdev->lock);
180#endif
181 wdev->omap_wdt_users = 0;
182
183 return 0; 158 return 0;
184} 159}
185 160
186static ssize_t omap_wdt_write(struct file *file, const char __user *data, 161static int omap_wdt_ping(struct watchdog_device *wdog)
187 size_t len, loff_t *ppos)
188{ 162{
189 struct omap_wdt_dev *wdev = file->private_data; 163 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
190 164
191 /* Refresh LOAD_TIME. */ 165 mutex_lock(&wdev->lock);
192 if (len) { 166 omap_wdt_reload(wdev);
193 spin_lock(&wdt_lock); 167 mutex_unlock(&wdev->lock);
194 omap_wdt_ping(wdev); 168
195 spin_unlock(&wdt_lock); 169 return 0;
196 }
197 return len;
198} 170}
199 171
200static long omap_wdt_ioctl(struct file *file, unsigned int cmd, 172static int omap_wdt_set_timeout(struct watchdog_device *wdog,
201 unsigned long arg) 173 unsigned int timeout)
202{ 174{
203 struct omap_wd_timer_platform_data *pdata; 175 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
204 struct omap_wdt_dev *wdev;
205 u32 rs;
206 int new_margin, bs;
207 static const struct watchdog_info ident = {
208 .identity = "OMAP Watchdog",
209 .options = WDIOF_SETTIMEOUT,
210 .firmware_version = 0,
211 };
212
213 wdev = file->private_data;
214 pdata = wdev->dev->platform_data;
215
216 switch (cmd) {
217 case WDIOC_GETSUPPORT:
218 return copy_to_user((struct watchdog_info __user *)arg, &ident,
219 sizeof(ident));
220 case WDIOC_GETSTATUS:
221 return put_user(0, (int __user *)arg);
222 case WDIOC_GETBOOTSTATUS:
223 if (!pdata || !pdata->read_reset_sources)
224 return put_user(0, (int __user *)arg);
225 rs = pdata->read_reset_sources();
226 bs = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
227 WDIOF_CARDRESET : 0;
228 return put_user(bs, (int __user *)arg);
229 case WDIOC_KEEPALIVE:
230 spin_lock(&wdt_lock);
231 omap_wdt_ping(wdev);
232 spin_unlock(&wdt_lock);
233 return 0;
234 case WDIOC_SETTIMEOUT:
235 if (get_user(new_margin, (int __user *)arg))
236 return -EFAULT;
237 omap_wdt_adjust_timeout(new_margin);
238
239 spin_lock(&wdt_lock);
240 omap_wdt_disable(wdev);
241 omap_wdt_set_timeout(wdev);
242 omap_wdt_enable(wdev);
243 176
244 omap_wdt_ping(wdev); 177 mutex_lock(&wdev->lock);
245 spin_unlock(&wdt_lock); 178 omap_wdt_disable(wdev);
246 /* Fall */ 179 omap_wdt_set_timer(wdev, timeout);
247 case WDIOC_GETTIMEOUT: 180 omap_wdt_enable(wdev);
248 return put_user(timer_margin, (int __user *)arg); 181 omap_wdt_reload(wdev);
249 default: 182 wdog->timeout = timeout;
250 return -ENOTTY; 183 mutex_unlock(&wdev->lock);
251 } 184
185 return 0;
252} 186}
253 187
254static const struct file_operations omap_wdt_fops = { 188static const struct watchdog_info omap_wdt_info = {
255 .owner = THIS_MODULE, 189 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
256 .write = omap_wdt_write, 190 .identity = "OMAP Watchdog",
257 .unlocked_ioctl = omap_wdt_ioctl, 191};
258 .open = omap_wdt_open, 192
259 .release = omap_wdt_release, 193static const struct watchdog_ops omap_wdt_ops = {
260 .llseek = no_llseek, 194 .owner = THIS_MODULE,
195 .start = omap_wdt_start,
196 .stop = omap_wdt_stop,
197 .ping = omap_wdt_ping,
198 .set_timeout = omap_wdt_set_timeout,
261}; 199};
262 200
263static int omap_wdt_probe(struct platform_device *pdev) 201static int omap_wdt_probe(struct platform_device *pdev)
264{ 202{
203 struct omap_wd_timer_platform_data *pdata = pdev->dev.platform_data;
204 bool nowayout = WATCHDOG_NOWAYOUT;
205 struct watchdog_device *omap_wdt;
265 struct resource *res, *mem; 206 struct resource *res, *mem;
266 struct omap_wdt_dev *wdev; 207 struct omap_wdt_dev *wdev;
208 u32 rs;
267 int ret; 209 int ret;
268 210
211 omap_wdt = devm_kzalloc(&pdev->dev, sizeof(*omap_wdt), GFP_KERNEL);
212 if (!omap_wdt)
213 return -ENOMEM;
214
269 /* reserve static register mappings */ 215 /* reserve static register mappings */
270 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 216 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
271 if (!res) { 217 if (!res)
272 ret = -ENOENT; 218 return -ENOENT;
273 goto err_get_resource;
274 }
275 219
276 if (omap_wdt_dev) { 220 mem = devm_request_mem_region(&pdev->dev, res->start,
277 ret = -EBUSY; 221 resource_size(res), pdev->name);
278 goto err_busy; 222 if (!mem)
279 } 223 return -EBUSY;
280 224
281 mem = request_mem_region(res->start, resource_size(res), pdev->name); 225 wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
282 if (!mem) { 226 if (!wdev)
283 ret = -EBUSY; 227 return -ENOMEM;
284 goto err_busy;
285 }
286 228
287 wdev = kzalloc(sizeof(struct omap_wdt_dev), GFP_KERNEL); 229 wdev->omap_wdt_users = false;
288 if (!wdev) { 230 wdev->mem = mem;
289 ret = -ENOMEM; 231 wdev->dev = &pdev->dev;
290 goto err_kzalloc; 232 wdev->wdt_trgr_pattern = 0x1234;
291 } 233 mutex_init(&wdev->lock);
292 234
293 wdev->omap_wdt_users = 0; 235 wdev->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
294 wdev->mem = mem; 236 if (!wdev->base)
295 wdev->dev = &pdev->dev; 237 return -ENOMEM;
296 238
297 wdev->base = ioremap(res->start, resource_size(res)); 239 omap_wdt->info = &omap_wdt_info;
298 if (!wdev->base) { 240 omap_wdt->ops = &omap_wdt_ops;
299 ret = -ENOMEM; 241 omap_wdt->min_timeout = TIMER_MARGIN_MIN;
300 goto err_ioremap; 242 omap_wdt->max_timeout = TIMER_MARGIN_MAX;
301 } 243
244 if (timer_margin >= TIMER_MARGIN_MIN &&
245 timer_margin <= TIMER_MARGIN_MAX)
246 omap_wdt->timeout = timer_margin;
247 else
248 omap_wdt->timeout = TIMER_MARGIN_DEFAULT;
302 249
303 platform_set_drvdata(pdev, wdev); 250 watchdog_set_drvdata(omap_wdt, wdev);
251 watchdog_set_nowayout(omap_wdt, nowayout);
252
253 platform_set_drvdata(pdev, omap_wdt);
304 254
305 pm_runtime_enable(wdev->dev); 255 pm_runtime_enable(wdev->dev);
306 pm_runtime_get_sync(wdev->dev); 256 pm_runtime_get_sync(wdev->dev);
307 257
308 omap_wdt_disable(wdev); 258 if (pdata && pdata->read_reset_sources)
309 omap_wdt_adjust_timeout(timer_margin); 259 rs = pdata->read_reset_sources();
260 else
261 rs = 0;
262 omap_wdt->bootstatus = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ?
263 WDIOF_CARDRESET : 0;
310 264
311 wdev->omap_wdt_miscdev.parent = &pdev->dev; 265 omap_wdt_disable(wdev);
312 wdev->omap_wdt_miscdev.minor = WATCHDOG_MINOR;
313 wdev->omap_wdt_miscdev.name = "watchdog";
314 wdev->omap_wdt_miscdev.fops = &omap_wdt_fops;
315 266
316 ret = misc_register(&(wdev->omap_wdt_miscdev)); 267 ret = watchdog_register_device(omap_wdt);
317 if (ret) 268 if (ret) {
318 goto err_misc; 269 pm_runtime_disable(wdev->dev);
270 return ret;
271 }
319 272
320 pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", 273 pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n",
321 __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, 274 __raw_readl(wdev->base + OMAP_WATCHDOG_REV) & 0xFF,
322 timer_margin); 275 omap_wdt->timeout);
323 276
324 pm_runtime_put_sync(wdev->dev); 277 pm_runtime_put_sync(wdev->dev);
325 278
326 omap_wdt_dev = pdev;
327
328 return 0; 279 return 0;
329
330err_misc:
331 pm_runtime_disable(wdev->dev);
332 platform_set_drvdata(pdev, NULL);
333 iounmap(wdev->base);
334
335err_ioremap:
336 wdev->base = NULL;
337 kfree(wdev);
338
339err_kzalloc:
340 release_mem_region(res->start, resource_size(res));
341
342err_busy:
343err_get_resource:
344
345 return ret;
346} 280}
347 281
348static void omap_wdt_shutdown(struct platform_device *pdev) 282static void omap_wdt_shutdown(struct platform_device *pdev)
349{ 283{
350 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 284 struct watchdog_device *wdog = platform_get_drvdata(pdev);
285 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
351 286
287 mutex_lock(&wdev->lock);
352 if (wdev->omap_wdt_users) { 288 if (wdev->omap_wdt_users) {
353 omap_wdt_disable(wdev); 289 omap_wdt_disable(wdev);
354 pm_runtime_put_sync(wdev->dev); 290 pm_runtime_put_sync(wdev->dev);
355 } 291 }
292 mutex_unlock(&wdev->lock);
356} 293}
357 294
358static int omap_wdt_remove(struct platform_device *pdev) 295static int omap_wdt_remove(struct platform_device *pdev)
359{ 296{
360 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 297 struct watchdog_device *wdog = platform_get_drvdata(pdev);
298 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
361 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 299 struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
362 300
363 pm_runtime_disable(wdev->dev); 301 pm_runtime_disable(wdev->dev);
364 if (!res) 302 watchdog_unregister_device(wdog);
365 return -ENOENT;
366
367 misc_deregister(&(wdev->omap_wdt_miscdev));
368 release_mem_region(res->start, resource_size(res));
369 platform_set_drvdata(pdev, NULL);
370
371 iounmap(wdev->base);
372
373 kfree(wdev);
374 omap_wdt_dev = NULL;
375 303
376 return 0; 304 return 0;
377} 305}
@@ -386,25 +314,31 @@ static int omap_wdt_remove(struct platform_device *pdev)
386 314
387static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) 315static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
388{ 316{
389 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 317 struct watchdog_device *wdog = platform_get_drvdata(pdev);
318 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
390 319
320 mutex_lock(&wdev->lock);
391 if (wdev->omap_wdt_users) { 321 if (wdev->omap_wdt_users) {
392 omap_wdt_disable(wdev); 322 omap_wdt_disable(wdev);
393 pm_runtime_put_sync(wdev->dev); 323 pm_runtime_put_sync(wdev->dev);
394 } 324 }
325 mutex_unlock(&wdev->lock);
395 326
396 return 0; 327 return 0;
397} 328}
398 329
399static int omap_wdt_resume(struct platform_device *pdev) 330static int omap_wdt_resume(struct platform_device *pdev)
400{ 331{
401 struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); 332 struct watchdog_device *wdog = platform_get_drvdata(pdev);
333 struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
402 334
335 mutex_lock(&wdev->lock);
403 if (wdev->omap_wdt_users) { 336 if (wdev->omap_wdt_users) {
404 pm_runtime_get_sync(wdev->dev); 337 pm_runtime_get_sync(wdev->dev);
405 omap_wdt_enable(wdev); 338 omap_wdt_enable(wdev);
406 omap_wdt_ping(wdev); 339 omap_wdt_reload(wdev);
407 } 340 }
341 mutex_unlock(&wdev->lock);
408 342
409 return 0; 343 return 0;
410} 344}
@@ -437,5 +371,4 @@ module_platform_driver(omap_wdt_driver);
437 371
438MODULE_AUTHOR("George G. Davis"); 372MODULE_AUTHOR("George G. Davis");
439MODULE_LICENSE("GPL"); 373MODULE_LICENSE("GPL");
440MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
441MODULE_ALIAS("platform:omap_wdt"); 374MODULE_ALIAS("platform:omap_wdt");
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 0478b001b1ef..7c18b3bffcf7 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -156,6 +156,8 @@ static int orion_wdt_probe(struct platform_device *pdev)
156 wdt_tclk = clk_get_rate(clk); 156 wdt_tclk = clk_get_rate(clk);
157 157
158 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 158 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
159 if (!res)
160 return -ENODEV;
159 wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res)); 161 wdt_reg = devm_ioremap(&pdev->dev, res->start, resource_size(res));
160 if (!wdt_reg) 162 if (!wdt_reg)
161 return -ENOMEM; 163 return -ENOMEM;
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index b0dab10fc6a5..27bcd4e2c4a4 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -354,7 +354,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
354 goto err_map; 354 goto err_map;
355 } 355 }
356 356
357 clk_enable(wdt_clock); 357 clk_prepare_enable(wdt_clock);
358 358
359 ret = s3c2410wdt_cpufreq_register(); 359 ret = s3c2410wdt_cpufreq_register();
360 if (ret < 0) { 360 if (ret < 0) {
@@ -421,7 +421,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
421 s3c2410wdt_cpufreq_deregister(); 421 s3c2410wdt_cpufreq_deregister();
422 422
423 err_clk: 423 err_clk:
424 clk_disable(wdt_clock); 424 clk_disable_unprepare(wdt_clock);
425 clk_put(wdt_clock); 425 clk_put(wdt_clock);
426 wdt_clock = NULL; 426 wdt_clock = NULL;
427 427
@@ -445,7 +445,7 @@ static int s3c2410wdt_remove(struct platform_device *dev)
445 445
446 s3c2410wdt_cpufreq_deregister(); 446 s3c2410wdt_cpufreq_deregister();
447 447
448 clk_disable(wdt_clock); 448 clk_disable_unprepare(wdt_clock);
449 clk_put(wdt_clock); 449 clk_put(wdt_clock);
450 wdt_clock = NULL; 450 wdt_clock = NULL;
451 451
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c
index b3876812ff07..2b0e000d4377 100644
--- a/drivers/watchdog/sp5100_tco.c
+++ b/drivers/watchdog/sp5100_tco.c
@@ -13,7 +13,9 @@
13 * as published by the Free Software Foundation; either version 13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version. 14 * 2 of the License, or (at your option) any later version.
15 * 15 *
16 * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide" 16 * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide",
17 * AMD Publication 45482 "AMD SB800-Series Southbridges Register
18 * Reference Guide"
17 */ 19 */
18 20
19/* 21/*
@@ -38,18 +40,24 @@
38#include "sp5100_tco.h" 40#include "sp5100_tco.h"
39 41
40/* Module and version information */ 42/* Module and version information */
41#define TCO_VERSION "0.01" 43#define TCO_VERSION "0.03"
42#define TCO_MODULE_NAME "SP5100 TCO timer" 44#define TCO_MODULE_NAME "SP5100 TCO timer"
43#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION 45#define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION
44 46
45/* internal variables */ 47/* internal variables */
46static u32 tcobase_phys; 48static u32 tcobase_phys;
49static u32 resbase_phys;
50static u32 tco_wdt_fired;
47static void __iomem *tcobase; 51static void __iomem *tcobase;
48static unsigned int pm_iobase; 52static unsigned int pm_iobase;
49static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ 53static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */
50static unsigned long timer_alive; 54static unsigned long timer_alive;
51static char tco_expect_close; 55static char tco_expect_close;
52static struct pci_dev *sp5100_tco_pci; 56static struct pci_dev *sp5100_tco_pci;
57static struct resource wdt_res = {
58 .name = "Watchdog Timer",
59 .flags = IORESOURCE_MEM,
60};
53 61
54/* the watchdog platform device */ 62/* the watchdog platform device */
55static struct platform_device *sp5100_tco_platform_device; 63static struct platform_device *sp5100_tco_platform_device;
@@ -64,9 +72,15 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
64 72
65static bool nowayout = WATCHDOG_NOWAYOUT; 73static bool nowayout = WATCHDOG_NOWAYOUT;
66module_param(nowayout, bool, 0); 74module_param(nowayout, bool, 0);
67MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started" 75MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started."
68 " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 76 " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
69 77
78static unsigned int force_addr;
79module_param(force_addr, uint, 0);
80MODULE_PARM_DESC(force_addr, "Force the use of specified MMIO address."
81 " ONLY USE THIS PARAMETER IF YOU REALLY KNOW"
82 " WHAT YOU ARE DOING (default=none)");
83
70/* 84/*
71 * Some TCO specific functions 85 * Some TCO specific functions
72 */ 86 */
@@ -122,6 +136,79 @@ static int tco_timer_set_heartbeat(int t)
122 return 0; 136 return 0;
123} 137}
124 138
139static void tco_timer_enable(void)
140{
141 int val;
142
143 if (sp5100_tco_pci->revision >= 0x40) {
144 /* For SB800 or later */
145 /* Set the Watchdog timer resolution to 1 sec */
146 outb(SB800_PM_WATCHDOG_CONFIG, SB800_IO_PM_INDEX_REG);
147 val = inb(SB800_IO_PM_DATA_REG);
148 val |= SB800_PM_WATCHDOG_SECOND_RES;
149 outb(val, SB800_IO_PM_DATA_REG);
150
151 /* Enable watchdog decode bit and watchdog timer */
152 outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG);
153 val = inb(SB800_IO_PM_DATA_REG);
154 val |= SB800_PCI_WATCHDOG_DECODE_EN;
155 val &= ~SB800_PM_WATCHDOG_DISABLE;
156 outb(val, SB800_IO_PM_DATA_REG);
157 } else {
158 /* For SP5100 or SB7x0 */
159 /* Enable watchdog decode bit */
160 pci_read_config_dword(sp5100_tco_pci,
161 SP5100_PCI_WATCHDOG_MISC_REG,
162 &val);
163
164 val |= SP5100_PCI_WATCHDOG_DECODE_EN;
165
166 pci_write_config_dword(sp5100_tco_pci,
167 SP5100_PCI_WATCHDOG_MISC_REG,
168 val);
169
170 /* Enable Watchdog timer and set the resolution to 1 sec */
171 outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
172 val = inb(SP5100_IO_PM_DATA_REG);
173 val |= SP5100_PM_WATCHDOG_SECOND_RES;
174 val &= ~SP5100_PM_WATCHDOG_DISABLE;
175 outb(val, SP5100_IO_PM_DATA_REG);
176 }
177}
178
179static void tco_timer_disable(void)
180{
181 int val;
182
183 if (sp5100_tco_pci->revision >= 0x40) {
184 /* For SB800 or later */
185 /* Enable watchdog decode bit and Disable watchdog timer */
186 outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG);
187 val = inb(SB800_IO_PM_DATA_REG);
188 val |= SB800_PCI_WATCHDOG_DECODE_EN;
189 val |= SB800_PM_WATCHDOG_DISABLE;
190 outb(val, SB800_IO_PM_DATA_REG);
191 } else {
192 /* For SP5100 or SB7x0 */
193 /* Enable watchdog decode bit */
194 pci_read_config_dword(sp5100_tco_pci,
195 SP5100_PCI_WATCHDOG_MISC_REG,
196 &val);
197
198 val |= SP5100_PCI_WATCHDOG_DECODE_EN;
199
200 pci_write_config_dword(sp5100_tco_pci,
201 SP5100_PCI_WATCHDOG_MISC_REG,
202 val);
203
204 /* Disable Watchdog timer */
205 outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
206 val = inb(SP5100_IO_PM_DATA_REG);
207 val |= SP5100_PM_WATCHDOG_DISABLE;
208 outb(val, SP5100_IO_PM_DATA_REG);
209 }
210}
211
125/* 212/*
126 * /dev/watchdog handling 213 * /dev/watchdog handling
127 */ 214 */
@@ -270,11 +357,12 @@ MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl);
270/* 357/*
271 * Init & exit routines 358 * Init & exit routines
272 */ 359 */
273
274static unsigned char sp5100_tco_setupdevice(void) 360static unsigned char sp5100_tco_setupdevice(void)
275{ 361{
276 struct pci_dev *dev = NULL; 362 struct pci_dev *dev = NULL;
363 const char *dev_name = NULL;
277 u32 val; 364 u32 val;
365 u32 index_reg, data_reg, base_addr;
278 366
279 /* Match the PCI device */ 367 /* Match the PCI device */
280 for_each_pci_dev(dev) { 368 for_each_pci_dev(dev) {
@@ -287,29 +375,160 @@ static unsigned char sp5100_tco_setupdevice(void)
287 if (!sp5100_tco_pci) 375 if (!sp5100_tco_pci)
288 return 0; 376 return 0;
289 377
378 pr_info("PCI Revision ID: 0x%x\n", sp5100_tco_pci->revision);
379
380 /*
381 * Determine type of southbridge chipset.
382 */
383 if (sp5100_tco_pci->revision >= 0x40) {
384 dev_name = SB800_DEVNAME;
385 index_reg = SB800_IO_PM_INDEX_REG;
386 data_reg = SB800_IO_PM_DATA_REG;
387 base_addr = SB800_PM_WATCHDOG_BASE;
388 } else {
389 dev_name = SP5100_DEVNAME;
390 index_reg = SP5100_IO_PM_INDEX_REG;
391 data_reg = SP5100_IO_PM_DATA_REG;
392 base_addr = SP5100_PM_WATCHDOG_BASE;
393 }
394
290 /* Request the IO ports used by this driver */ 395 /* Request the IO ports used by this driver */
291 pm_iobase = SP5100_IO_PM_INDEX_REG; 396 pm_iobase = SP5100_IO_PM_INDEX_REG;
292 if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) { 397 if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, dev_name)) {
293 pr_err("I/O address 0x%04x already in use\n", pm_iobase); 398 pr_err("I/O address 0x%04x already in use\n", pm_iobase);
294 goto exit; 399 goto exit;
295 } 400 }
296 401
297 /* Find the watchdog base address. */ 402 /*
298 outb(SP5100_PM_WATCHDOG_BASE3, SP5100_IO_PM_INDEX_REG); 403 * First, Find the watchdog timer MMIO address from indirect I/O.
299 val = inb(SP5100_IO_PM_DATA_REG); 404 */
300 outb(SP5100_PM_WATCHDOG_BASE2, SP5100_IO_PM_INDEX_REG); 405 outb(base_addr+3, index_reg);
301 val = val << 8 | inb(SP5100_IO_PM_DATA_REG); 406 val = inb(data_reg);
302 outb(SP5100_PM_WATCHDOG_BASE1, SP5100_IO_PM_INDEX_REG); 407 outb(base_addr+2, index_reg);
303 val = val << 8 | inb(SP5100_IO_PM_DATA_REG); 408 val = val << 8 | inb(data_reg);
304 outb(SP5100_PM_WATCHDOG_BASE0, SP5100_IO_PM_INDEX_REG); 409 outb(base_addr+1, index_reg);
305 /* Low three bits of BASE0 are reserved. */ 410 val = val << 8 | inb(data_reg);
306 val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); 411 outb(base_addr+0, index_reg);
412 /* Low three bits of BASE are reserved */
413 val = val << 8 | (inb(data_reg) & 0xf8);
414
415 pr_debug("Got 0x%04x from indirect I/O\n", val);
416
417 /* Check MMIO address conflict */
418 if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
419 dev_name))
420 goto setup_wdt;
421 else
422 pr_debug("MMIO address 0x%04x already in use\n", val);
423
424 /*
425 * Secondly, Find the watchdog timer MMIO address
426 * from SBResource_MMIO register.
427 */
428 if (sp5100_tco_pci->revision >= 0x40) {
429 /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */
430 outb(SB800_PM_ACPI_MMIO_EN+3, SB800_IO_PM_INDEX_REG);
431 val = inb(SB800_IO_PM_DATA_REG);
432 outb(SB800_PM_ACPI_MMIO_EN+2, SB800_IO_PM_INDEX_REG);
433 val = val << 8 | inb(SB800_IO_PM_DATA_REG);
434 outb(SB800_PM_ACPI_MMIO_EN+1, SB800_IO_PM_INDEX_REG);
435 val = val << 8 | inb(SB800_IO_PM_DATA_REG);
436 outb(SB800_PM_ACPI_MMIO_EN+0, SB800_IO_PM_INDEX_REG);
437 val = val << 8 | inb(SB800_IO_PM_DATA_REG);
438 } else {
439 /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */
440 pci_read_config_dword(sp5100_tco_pci,
441 SP5100_SB_RESOURCE_MMIO_BASE, &val);
442 }
443
444 /* The SBResource_MMIO is enabled and mapped memory space? */
445 if ((val & (SB800_ACPI_MMIO_DECODE_EN | SB800_ACPI_MMIO_SEL)) ==
446 SB800_ACPI_MMIO_DECODE_EN) {
447 /* Clear unnecessary the low twelve bits */
448 val &= ~0xFFF;
449 /* Add the Watchdog Timer offset to base address. */
450 val += SB800_PM_WDT_MMIO_OFFSET;
451 /* Check MMIO address conflict */
452 if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
453 dev_name)) {
454 pr_debug("Got 0x%04x from SBResource_MMIO register\n",
455 val);
456 goto setup_wdt;
457 } else
458 pr_debug("MMIO address 0x%04x already in use\n", val);
459 } else
460 pr_debug("SBResource_MMIO is disabled(0x%04x)\n", val);
461
462 /*
463 * Lastly re-programming the watchdog timer MMIO address,
464 * This method is a last resort...
465 *
466 * Before re-programming, to ensure that the watchdog timer
467 * is disabled, disable the watchdog timer.
468 */
469 tco_timer_disable();
470
471 if (force_addr) {
472 /*
473 * Force the use of watchdog timer MMIO address, and aligned to
474 * 8byte boundary.
475 */
476 force_addr &= ~0x7;
477 val = force_addr;
478
479 pr_info("Force the use of 0x%04x as MMIO address\n", val);
480 } else {
481 /*
482 * Get empty slot into the resource tree for watchdog timer.
483 */
484 if (allocate_resource(&iomem_resource,
485 &wdt_res,
486 SP5100_WDT_MEM_MAP_SIZE,
487 0xf0000000,
488 0xfffffff8,
489 0x8,
490 NULL,
491 NULL)) {
492 pr_err("MMIO allocation failed\n");
493 goto unreg_region;
494 }
495
496 val = resbase_phys = wdt_res.start;
497 pr_debug("Got 0x%04x from resource tree\n", val);
498 }
499
500 /* Restore to the low three bits, if chipset is SB8x0(or later) */
501 if (sp5100_tco_pci->revision >= 0x40) {
502 u8 reserved_bit;
503 reserved_bit = inb(base_addr) & 0x7;
504 val |= (u32)reserved_bit;
505 }
506
507 /* Re-programming the watchdog timer base address */
508 outb(base_addr+0, index_reg);
509 /* Low three bits of BASE are reserved */
510 outb((val >> 0) & 0xf8, data_reg);
511 outb(base_addr+1, index_reg);
512 outb((val >> 8) & 0xff, data_reg);
513 outb(base_addr+2, index_reg);
514 outb((val >> 16) & 0xff, data_reg);
515 outb(base_addr+3, index_reg);
516 outb((val >> 24) & 0xff, data_reg);
517
518 /*
519 * Clear unnecessary the low three bits,
520 * if chipset is SB8x0(or later)
521 */
522 if (sp5100_tco_pci->revision >= 0x40)
523 val &= ~0x7;
307 524
308 if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, 525 if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE,
309 "SP5100 TCO")) { 526 dev_name)) {
310 pr_err("mmio address 0x%04x already in use\n", val); 527 pr_err("MMIO address 0x%04x already in use\n", val);
311 goto unreg_region; 528 goto unreg_resource;
312 } 529 }
530
531setup_wdt:
313 tcobase_phys = val; 532 tcobase_phys = val;
314 533
315 tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); 534 tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE);
@@ -318,26 +537,18 @@ static unsigned char sp5100_tco_setupdevice(void)
318 goto unreg_mem_region; 537 goto unreg_mem_region;
319 } 538 }
320 539
321 /* Enable watchdog decode bit */ 540 pr_info("Using 0x%04x for watchdog MMIO address\n", val);
322 pci_read_config_dword(sp5100_tco_pci,
323 SP5100_PCI_WATCHDOG_MISC_REG,
324 &val);
325
326 val |= SP5100_PCI_WATCHDOG_DECODE_EN;
327 541
328 pci_write_config_dword(sp5100_tco_pci, 542 /* Setup the watchdog timer */
329 SP5100_PCI_WATCHDOG_MISC_REG, 543 tco_timer_enable();
330 val);
331 544
332 /* Enable Watchdog timer and set the resolution to 1 sec. */ 545 /* Check that the watchdog action is set to reset the system */
333 outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG);
334 val = inb(SP5100_IO_PM_DATA_REG);
335 val |= SP5100_PM_WATCHDOG_SECOND_RES;
336 val &= ~SP5100_PM_WATCHDOG_DISABLE;
337 outb(val, SP5100_IO_PM_DATA_REG);
338
339 /* Check that the watchdog action is set to reset the system. */
340 val = readl(SP5100_WDT_CONTROL(tcobase)); 546 val = readl(SP5100_WDT_CONTROL(tcobase));
547 /*
548 * Save WatchDogFired status, because WatchDogFired flag is
549 * cleared here.
550 */
551 tco_wdt_fired = val & SP5100_PM_WATCHDOG_FIRED;
341 val &= ~SP5100_PM_WATCHDOG_ACTION_RESET; 552 val &= ~SP5100_PM_WATCHDOG_ACTION_RESET;
342 writel(val, SP5100_WDT_CONTROL(tcobase)); 553 writel(val, SP5100_WDT_CONTROL(tcobase));
343 554
@@ -355,6 +566,9 @@ static unsigned char sp5100_tco_setupdevice(void)
355 566
356unreg_mem_region: 567unreg_mem_region:
357 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 568 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
569unreg_resource:
570 if (resbase_phys)
571 release_resource(&wdt_res);
358unreg_region: 572unreg_region:
359 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 573 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
360exit: 574exit:
@@ -364,23 +578,18 @@ exit:
364static int sp5100_tco_init(struct platform_device *dev) 578static int sp5100_tco_init(struct platform_device *dev)
365{ 579{
366 int ret; 580 int ret;
367 u32 val; 581 char addr_str[16];
368 582
369 /* Check whether or not the hardware watchdog is there. If found, then 583 /*
584 * Check whether or not the hardware watchdog is there. If found, then
370 * set it up. 585 * set it up.
371 */ 586 */
372 if (!sp5100_tco_setupdevice()) 587 if (!sp5100_tco_setupdevice())
373 return -ENODEV; 588 return -ENODEV;
374 589
375 /* Check to see if last reboot was due to watchdog timeout */ 590 /* Check to see if last reboot was due to watchdog timeout */
376 pr_info("Watchdog reboot %sdetected\n", 591 pr_info("Last reboot was %striggered by watchdog.\n",
377 readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ? 592 tco_wdt_fired ? "" : "not ");
378 "" : "not ");
379
380 /* Clear out the old status */
381 val = readl(SP5100_WDT_CONTROL(tcobase));
382 val &= ~SP5100_PM_WATCHDOG_FIRED;
383 writel(val, SP5100_WDT_CONTROL(tcobase));
384 593
385 /* 594 /*
386 * Check that the heartbeat value is within it's range. 595 * Check that the heartbeat value is within it's range.
@@ -400,14 +609,24 @@ static int sp5100_tco_init(struct platform_device *dev)
400 609
401 clear_bit(0, &timer_alive); 610 clear_bit(0, &timer_alive);
402 611
403 pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n", 612 /* Show module parameters */
404 tcobase, heartbeat, nowayout); 613 if (force_addr == tcobase_phys)
614 /* The force_addr is vaild */
615 sprintf(addr_str, "0x%04x", force_addr);
616 else
617 strcpy(addr_str, "none");
618
619 pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d, "
620 "force_addr=%s)\n",
621 tcobase, heartbeat, nowayout, addr_str);
405 622
406 return 0; 623 return 0;
407 624
408exit: 625exit:
409 iounmap(tcobase); 626 iounmap(tcobase);
410 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 627 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
628 if (resbase_phys)
629 release_resource(&wdt_res);
411 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 630 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
412 return ret; 631 return ret;
413} 632}
@@ -422,6 +641,8 @@ static void sp5100_tco_cleanup(void)
422 misc_deregister(&sp5100_tco_miscdev); 641 misc_deregister(&sp5100_tco_miscdev);
423 iounmap(tcobase); 642 iounmap(tcobase);
424 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); 643 release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE);
644 if (resbase_phys)
645 release_resource(&wdt_res);
425 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); 646 release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE);
426} 647}
427 648
@@ -451,7 +672,7 @@ static int __init sp5100_tco_init_module(void)
451{ 672{
452 int err; 673 int err;
453 674
454 pr_info("SP5100 TCO WatchDog Timer Driver v%s\n", TCO_VERSION); 675 pr_info("SP5100/SB800 TCO WatchDog Timer Driver v%s\n", TCO_VERSION);
455 676
456 err = platform_driver_register(&sp5100_tco_driver); 677 err = platform_driver_register(&sp5100_tco_driver);
457 if (err) 678 if (err)
@@ -475,13 +696,13 @@ static void __exit sp5100_tco_cleanup_module(void)
475{ 696{
476 platform_device_unregister(sp5100_tco_platform_device); 697 platform_device_unregister(sp5100_tco_platform_device);
477 platform_driver_unregister(&sp5100_tco_driver); 698 platform_driver_unregister(&sp5100_tco_driver);
478 pr_info("SP5100 TCO Watchdog Module Unloaded\n"); 699 pr_info("SP5100/SB800 TCO Watchdog Module Unloaded\n");
479} 700}
480 701
481module_init(sp5100_tco_init_module); 702module_init(sp5100_tco_init_module);
482module_exit(sp5100_tco_cleanup_module); 703module_exit(sp5100_tco_cleanup_module);
483 704
484MODULE_AUTHOR("Priyanka Gupta"); 705MODULE_AUTHOR("Priyanka Gupta");
485MODULE_DESCRIPTION("TCO timer driver for SP5100 chipset"); 706MODULE_DESCRIPTION("TCO timer driver for SP5100/SB800 chipset");
486MODULE_LICENSE("GPL"); 707MODULE_LICENSE("GPL");
487MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 708MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/watchdog/sp5100_tco.h b/drivers/watchdog/sp5100_tco.h
index a5a16cc90a34..71594a0c14b7 100644
--- a/drivers/watchdog/sp5100_tco.h
+++ b/drivers/watchdog/sp5100_tco.h
@@ -9,33 +9,57 @@
9/* 9/*
10 * Some address definitions for the Watchdog 10 * Some address definitions for the Watchdog
11 */ 11 */
12
13#define SP5100_WDT_MEM_MAP_SIZE 0x08 12#define SP5100_WDT_MEM_MAP_SIZE 0x08
14#define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */ 13#define SP5100_WDT_CONTROL(base) ((base) + 0x00) /* Watchdog Control */
15#define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */ 14#define SP5100_WDT_COUNT(base) ((base) + 0x04) /* Watchdog Count */
16 15
17#define SP5100_WDT_START_STOP_BIT 1 16#define SP5100_WDT_START_STOP_BIT (1 << 0)
18#define SP5100_WDT_TRIGGER_BIT (1 << 7) 17#define SP5100_WDT_TRIGGER_BIT (1 << 7)
19 18
20#define SP5100_PCI_WATCHDOG_MISC_REG 0x41
21#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3)
22
23#define SP5100_PM_IOPORTS_SIZE 0x02 19#define SP5100_PM_IOPORTS_SIZE 0x02
24 20
25/* These two IO registers are hardcoded and there doesn't seem to be a way to 21/*
22 * These two IO registers are hardcoded and there doesn't seem to be a way to
26 * read them from a register. 23 * read them from a register.
27 */ 24 */
25
26/* For SP5100/SB7x0 chipset */
28#define SP5100_IO_PM_INDEX_REG 0xCD6 27#define SP5100_IO_PM_INDEX_REG 0xCD6
29#define SP5100_IO_PM_DATA_REG 0xCD7 28#define SP5100_IO_PM_DATA_REG 0xCD7
30 29
30#define SP5100_SB_RESOURCE_MMIO_BASE 0x9C
31
31#define SP5100_PM_WATCHDOG_CONTROL 0x69 32#define SP5100_PM_WATCHDOG_CONTROL 0x69
32#define SP5100_PM_WATCHDOG_BASE0 0x6C 33#define SP5100_PM_WATCHDOG_BASE 0x6C
33#define SP5100_PM_WATCHDOG_BASE1 0x6D
34#define SP5100_PM_WATCHDOG_BASE2 0x6E
35#define SP5100_PM_WATCHDOG_BASE3 0x6F
36 34
37#define SP5100_PM_WATCHDOG_FIRED (1 << 1) 35#define SP5100_PM_WATCHDOG_FIRED (1 << 1)
38#define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2) 36#define SP5100_PM_WATCHDOG_ACTION_RESET (1 << 2)
39 37
40#define SP5100_PM_WATCHDOG_DISABLE 1 38#define SP5100_PCI_WATCHDOG_MISC_REG 0x41
39#define SP5100_PCI_WATCHDOG_DECODE_EN (1 << 3)
40
41#define SP5100_PM_WATCHDOG_DISABLE (1 << 0)
41#define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1) 42#define SP5100_PM_WATCHDOG_SECOND_RES (3 << 1)
43
44#define SP5100_DEVNAME "SP5100 TCO"
45
46
47/* For SB8x0(or later) chipset */
48#define SB800_IO_PM_INDEX_REG 0xCD6
49#define SB800_IO_PM_DATA_REG 0xCD7
50
51#define SB800_PM_ACPI_MMIO_EN 0x24
52#define SB800_PM_WATCHDOG_CONTROL 0x48
53#define SB800_PM_WATCHDOG_BASE 0x48
54#define SB800_PM_WATCHDOG_CONFIG 0x4C
55
56#define SB800_PCI_WATCHDOG_DECODE_EN (1 << 0)
57#define SB800_PM_WATCHDOG_DISABLE (1 << 2)
58#define SB800_PM_WATCHDOG_SECOND_RES (3 << 0)
59#define SB800_ACPI_MMIO_DECODE_EN (1 << 0)
60#define SB800_ACPI_MMIO_SEL (1 << 2)
61
62
63#define SB800_PM_WDT_MMIO_OFFSET 0xB00
64
65#define SB800_DEVNAME "SB800 TCO"
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c
index 76c73cbf0040..8872642505c0 100644
--- a/drivers/watchdog/sp805_wdt.c
+++ b/drivers/watchdog/sp805_wdt.c
@@ -130,16 +130,10 @@ static int wdt_config(struct watchdog_device *wdd, bool ping)
130 int ret; 130 int ret;
131 131
132 if (!ping) { 132 if (!ping) {
133 ret = clk_prepare(wdt->clk);
134 if (ret) {
135 dev_err(&wdt->adev->dev, "clock prepare fail");
136 return ret;
137 }
138 133
139 ret = clk_enable(wdt->clk); 134 ret = clk_prepare_enable(wdt->clk);
140 if (ret) { 135 if (ret) {
141 dev_err(&wdt->adev->dev, "clock enable fail"); 136 dev_err(&wdt->adev->dev, "clock enable fail");
142 clk_unprepare(wdt->clk);
143 return ret; 137 return ret;
144 } 138 }
145 } 139 }
@@ -190,8 +184,7 @@ static int wdt_disable(struct watchdog_device *wdd)
190 readl_relaxed(wdt->base + WDTLOCK); 184 readl_relaxed(wdt->base + WDTLOCK);
191 spin_unlock(&wdt->lock); 185 spin_unlock(&wdt->lock);
192 186
193 clk_disable(wdt->clk); 187 clk_disable_unprepare(wdt->clk);
194 clk_unprepare(wdt->clk);
195 188
196 return 0; 189 return 0;
197} 190}
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c
index 9f54b1da7185..81918cf8993b 100644
--- a/drivers/watchdog/twl4030_wdt.c
+++ b/drivers/watchdog/twl4030_wdt.c
@@ -22,26 +22,12 @@
22#include <linux/types.h> 22#include <linux/types.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/fs.h>
26#include <linux/watchdog.h> 25#include <linux/watchdog.h>
27#include <linux/platform_device.h> 26#include <linux/platform_device.h>
28#include <linux/miscdevice.h>
29#include <linux/uaccess.h>
30#include <linux/i2c/twl.h> 27#include <linux/i2c/twl.h>
31 28
32#define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3 29#define TWL4030_WATCHDOG_CFG_REG_OFFS 0x3
33 30
34#define TWL4030_WDT_STATE_OPEN 0x1
35#define TWL4030_WDT_STATE_ACTIVE 0x8
36
37static struct platform_device *twl4030_wdt_dev;
38
39struct twl4030_wdt {
40 struct miscdevice miscdev;
41 int timer_margin;
42 unsigned long state;
43};
44
45static bool nowayout = WATCHDOG_NOWAYOUT; 31static bool nowayout = WATCHDOG_NOWAYOUT;
46module_param(nowayout, bool, 0); 32module_param(nowayout, bool, 0);
47MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " 33MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
@@ -49,175 +35,75 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
49 35
50static int twl4030_wdt_write(unsigned char val) 36static int twl4030_wdt_write(unsigned char val)
51{ 37{
52 return twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, val, 38 return twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, val,
53 TWL4030_WATCHDOG_CFG_REG_OFFS); 39 TWL4030_WATCHDOG_CFG_REG_OFFS);
54} 40}
55 41
56static int twl4030_wdt_enable(struct twl4030_wdt *wdt) 42static int twl4030_wdt_start(struct watchdog_device *wdt)
57{ 43{
58 return twl4030_wdt_write(wdt->timer_margin + 1); 44 return twl4030_wdt_write(wdt->timeout + 1);
59} 45}
60 46
61static int twl4030_wdt_disable(struct twl4030_wdt *wdt) 47static int twl4030_wdt_stop(struct watchdog_device *wdt)
62{ 48{
63 return twl4030_wdt_write(0); 49 return twl4030_wdt_write(0);
64} 50}
65 51
66static int twl4030_wdt_set_timeout(struct twl4030_wdt *wdt, int timeout) 52static int twl4030_wdt_set_timeout(struct watchdog_device *wdt,
67{ 53 unsigned int timeout)
68 if (timeout < 0 || timeout > 30) {
69 dev_warn(wdt->miscdev.parent,
70 "Timeout can only be in the range [0-30] seconds");
71 return -EINVAL;
72 }
73 wdt->timer_margin = timeout;
74 return twl4030_wdt_enable(wdt);
75}
76
77static ssize_t twl4030_wdt_write_fop(struct file *file,
78 const char __user *data, size_t len, loff_t *ppos)
79{ 54{
80 struct twl4030_wdt *wdt = file->private_data; 55 wdt->timeout = timeout;
81
82 if (len)
83 twl4030_wdt_enable(wdt);
84
85 return len;
86}
87
88static long twl4030_wdt_ioctl(struct file *file,
89 unsigned int cmd, unsigned long arg)
90{
91 void __user *argp = (void __user *)arg;
92 int __user *p = argp;
93 int new_margin;
94 struct twl4030_wdt *wdt = file->private_data;
95
96 static const struct watchdog_info twl4030_wd_ident = {
97 .identity = "TWL4030 Watchdog",
98 .options = WDIOF_SETTIMEOUT,
99 .firmware_version = 0,
100 };
101
102 switch (cmd) {
103 case WDIOC_GETSUPPORT:
104 return copy_to_user(argp, &twl4030_wd_ident,
105 sizeof(twl4030_wd_ident)) ? -EFAULT : 0;
106
107 case WDIOC_GETSTATUS:
108 case WDIOC_GETBOOTSTATUS:
109 return put_user(0, p);
110
111 case WDIOC_KEEPALIVE:
112 twl4030_wdt_enable(wdt);
113 break;
114
115 case WDIOC_SETTIMEOUT:
116 if (get_user(new_margin, p))
117 return -EFAULT;
118 if (twl4030_wdt_set_timeout(wdt, new_margin))
119 return -EINVAL;
120 return put_user(wdt->timer_margin, p);
121
122 case WDIOC_GETTIMEOUT:
123 return put_user(wdt->timer_margin, p);
124
125 default:
126 return -ENOTTY;
127 }
128
129 return 0; 56 return 0;
130} 57}
131 58
132static int twl4030_wdt_open(struct inode *inode, struct file *file) 59static const struct watchdog_info twl4030_wdt_info = {
133{ 60 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
134 struct twl4030_wdt *wdt = platform_get_drvdata(twl4030_wdt_dev); 61 .identity = "TWL4030 Watchdog",
135 62};
136 /* /dev/watchdog can only be opened once */
137 if (test_and_set_bit(0, &wdt->state))
138 return -EBUSY;
139
140 wdt->state |= TWL4030_WDT_STATE_ACTIVE;
141 file->private_data = (void *) wdt;
142
143 twl4030_wdt_enable(wdt);
144 return nonseekable_open(inode, file);
145}
146
147static int twl4030_wdt_release(struct inode *inode, struct file *file)
148{
149 struct twl4030_wdt *wdt = file->private_data;
150 if (nowayout) {
151 dev_alert(wdt->miscdev.parent,
152 "Unexpected close, watchdog still running!\n");
153 twl4030_wdt_enable(wdt);
154 } else {
155 if (twl4030_wdt_disable(wdt))
156 return -EFAULT;
157 wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
158 }
159
160 clear_bit(0, &wdt->state);
161 return 0;
162}
163 63
164static const struct file_operations twl4030_wdt_fops = { 64static const struct watchdog_ops twl4030_wdt_ops = {
165 .owner = THIS_MODULE, 65 .owner = THIS_MODULE,
166 .llseek = no_llseek, 66 .start = twl4030_wdt_start,
167 .open = twl4030_wdt_open, 67 .stop = twl4030_wdt_stop,
168 .release = twl4030_wdt_release, 68 .set_timeout = twl4030_wdt_set_timeout,
169 .unlocked_ioctl = twl4030_wdt_ioctl,
170 .write = twl4030_wdt_write_fop,
171}; 69};
172 70
173static int twl4030_wdt_probe(struct platform_device *pdev) 71static int twl4030_wdt_probe(struct platform_device *pdev)
174{ 72{
175 int ret = 0; 73 int ret = 0;
176 struct twl4030_wdt *wdt; 74 struct watchdog_device *wdt;
177 75
178 wdt = kzalloc(sizeof(struct twl4030_wdt), GFP_KERNEL); 76 wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
179 if (!wdt) 77 if (!wdt)
180 return -ENOMEM; 78 return -ENOMEM;
181 79
182 wdt->state = 0; 80 wdt->info = &twl4030_wdt_info;
183 wdt->timer_margin = 30; 81 wdt->ops = &twl4030_wdt_ops;
184 wdt->miscdev.parent = &pdev->dev; 82 wdt->status = 0;
185 wdt->miscdev.fops = &twl4030_wdt_fops; 83 wdt->timeout = 30;
186 wdt->miscdev.minor = WATCHDOG_MINOR; 84 wdt->min_timeout = 1;
187 wdt->miscdev.name = "watchdog"; 85 wdt->max_timeout = 30;
188 86
87 watchdog_set_nowayout(wdt, nowayout);
189 platform_set_drvdata(pdev, wdt); 88 platform_set_drvdata(pdev, wdt);
190 89
191 twl4030_wdt_dev = pdev; 90 twl4030_wdt_stop(wdt);
192 91
193 twl4030_wdt_disable(wdt); 92 ret = watchdog_register_device(wdt);
194
195 ret = misc_register(&wdt->miscdev);
196 if (ret) { 93 if (ret) {
197 dev_err(wdt->miscdev.parent,
198 "Failed to register misc device\n");
199 platform_set_drvdata(pdev, NULL); 94 platform_set_drvdata(pdev, NULL);
200 kfree(wdt);
201 twl4030_wdt_dev = NULL;
202 return ret; 95 return ret;
203 } 96 }
97
204 return 0; 98 return 0;
205} 99}
206 100
207static int twl4030_wdt_remove(struct platform_device *pdev) 101static int twl4030_wdt_remove(struct platform_device *pdev)
208{ 102{
209 struct twl4030_wdt *wdt = platform_get_drvdata(pdev); 103 struct watchdog_device *wdt = platform_get_drvdata(pdev);
210
211 if (wdt->state & TWL4030_WDT_STATE_ACTIVE)
212 if (twl4030_wdt_disable(wdt))
213 return -EFAULT;
214
215 wdt->state &= ~TWL4030_WDT_STATE_ACTIVE;
216 misc_deregister(&wdt->miscdev);
217 104
105 watchdog_unregister_device(wdt);
218 platform_set_drvdata(pdev, NULL); 106 platform_set_drvdata(pdev, NULL);
219 kfree(wdt);
220 twl4030_wdt_dev = NULL;
221 107
222 return 0; 108 return 0;
223} 109}
@@ -225,18 +111,18 @@ static int twl4030_wdt_remove(struct platform_device *pdev)
225#ifdef CONFIG_PM 111#ifdef CONFIG_PM
226static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state) 112static int twl4030_wdt_suspend(struct platform_device *pdev, pm_message_t state)
227{ 113{
228 struct twl4030_wdt *wdt = platform_get_drvdata(pdev); 114 struct watchdog_device *wdt = platform_get_drvdata(pdev);
229 if (wdt->state & TWL4030_WDT_STATE_ACTIVE) 115 if (watchdog_active(wdt))
230 return twl4030_wdt_disable(wdt); 116 return twl4030_wdt_stop(wdt);
231 117
232 return 0; 118 return 0;
233} 119}
234 120
235static int twl4030_wdt_resume(struct platform_device *pdev) 121static int twl4030_wdt_resume(struct platform_device *pdev)
236{ 122{
237 struct twl4030_wdt *wdt = platform_get_drvdata(pdev); 123 struct watchdog_device *wdt = platform_get_drvdata(pdev);
238 if (wdt->state & TWL4030_WDT_STATE_ACTIVE) 124 if (watchdog_active(wdt))
239 return twl4030_wdt_enable(wdt); 125 return twl4030_wdt_start(wdt);
240 126
241 return 0; 127 return 0;
242} 128}
@@ -260,6 +146,5 @@ module_platform_driver(twl4030_wdt_driver);
260 146
261MODULE_AUTHOR("Nokia Corporation"); 147MODULE_AUTHOR("Nokia Corporation");
262MODULE_LICENSE("GPL"); 148MODULE_LICENSE("GPL");
263MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
264MODULE_ALIAS("platform:twl4030_wdt"); 149MODULE_ALIAS("platform:twl4030_wdt");
265 150