diff options
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/Kconfig | 15 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/adx_wdt.c | 355 | ||||
-rw-r--r-- | drivers/watchdog/bcm47xx_wdt.c | 27 | ||||
-rw-r--r-- | drivers/watchdog/coh901327_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/eurotechwdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/hpwdt.c | 34 | ||||
-rw-r--r-- | drivers/watchdog/iTCO_wdt.c | 19 | ||||
-rw-r--r-- | drivers/watchdog/lantiq_wdt.c | 8 | ||||
-rw-r--r-- | drivers/watchdog/mpcore_wdt.c | 3 | ||||
-rw-r--r-- | drivers/watchdog/octeon-wdt-main.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/s3c2410_wdt.c | 180 | ||||
-rw-r--r-- | drivers/watchdog/sb_wdog.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/sbc_epx_c3.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/sc520_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/smsc37b787_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/stmp3xxx_wdt.c | 1 | ||||
-rw-r--r-- | drivers/watchdog/w83627hf_wdt.c | 33 | ||||
-rw-r--r-- | drivers/watchdog/watchdog_dev.c | 14 | ||||
-rw-r--r-- | drivers/watchdog/wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/wdt_pci.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/wm831x_wdt.c | 318 |
22 files changed, 251 insertions, 777 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 86b0735e6aa0..79fd606b7cd5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -66,6 +66,7 @@ config SOFT_WATCHDOG | |||
66 | config WM831X_WATCHDOG | 66 | config WM831X_WATCHDOG |
67 | tristate "WM831x watchdog" | 67 | tristate "WM831x watchdog" |
68 | depends on MFD_WM831X | 68 | depends on MFD_WM831X |
69 | select WATCHDOG_CORE | ||
69 | help | 70 | help |
70 | Support for the watchdog in the WM831x AudioPlus PMICs. When | 71 | Support for the watchdog in the WM831x AudioPlus PMICs. When |
71 | the watchdog triggers the system will be reset. | 72 | the watchdog triggers the system will be reset. |
@@ -170,6 +171,7 @@ config HAVE_S3C2410_WATCHDOG | |||
170 | config S3C2410_WATCHDOG | 171 | config S3C2410_WATCHDOG |
171 | tristate "S3C2410 Watchdog" | 172 | tristate "S3C2410 Watchdog" |
172 | depends on ARCH_S3C2410 || HAVE_S3C2410_WATCHDOG | 173 | depends on ARCH_S3C2410 || HAVE_S3C2410_WATCHDOG |
174 | select WATCHDOG_CORE | ||
173 | help | 175 | help |
174 | Watchdog timer block in the Samsung SoCs. This will reboot | 176 | Watchdog timer block in the Samsung SoCs. This will reboot |
175 | the system when the timer expires with the watchdog enabled. | 177 | the system when the timer expires with the watchdog enabled. |
@@ -312,13 +314,6 @@ config NUC900_WATCHDOG | |||
312 | To compile this driver as a module, choose M here: the | 314 | To compile this driver as a module, choose M here: the |
313 | module will be called nuc900_wdt. | 315 | module will be called nuc900_wdt. |
314 | 316 | ||
315 | config ADX_WATCHDOG | ||
316 | tristate "Avionic Design Xanthos watchdog" | ||
317 | depends on ARCH_PXA_ADX | ||
318 | help | ||
319 | Say Y here if you want support for the watchdog timer on Avionic | ||
320 | Design Xanthos boards. | ||
321 | |||
322 | config TS72XX_WATCHDOG | 317 | config TS72XX_WATCHDOG |
323 | tristate "TS-72XX SBC Watchdog" | 318 | tristate "TS-72XX SBC Watchdog" |
324 | depends on MACH_TS72XX | 319 | depends on MACH_TS72XX |
@@ -726,7 +721,7 @@ config SBC8360_WDT | |||
726 | 721 | ||
727 | config SBC7240_WDT | 722 | config SBC7240_WDT |
728 | tristate "SBC Nano 7240 Watchdog Timer" | 723 | tristate "SBC Nano 7240 Watchdog Timer" |
729 | depends on X86_32 | 724 | depends on X86_32 && !UML |
730 | ---help--- | 725 | ---help--- |
731 | This is the driver for the hardware watchdog found on the IEI | 726 | This is the driver for the hardware watchdog found on the IEI |
732 | single board computers EPIC Nano 7240 (and likely others). This | 727 | single board computers EPIC Nano 7240 (and likely others). This |
@@ -1174,6 +1169,10 @@ config XEN_WDT | |||
1174 | by Xen 4.0 and newer. The watchdog timeout period is normally one | 1169 | by Xen 4.0 and newer. The watchdog timeout period is normally one |
1175 | minute but can be changed with a boot-time parameter. | 1170 | minute but can be changed with a boot-time parameter. |
1176 | 1171 | ||
1172 | config UML_WATCHDOG | ||
1173 | tristate "UML watchdog" | ||
1174 | depends on UML | ||
1175 | |||
1177 | # | 1176 | # |
1178 | # ISA-based Watchdog Cards | 1177 | # ISA-based Watchdog Cards |
1179 | # | 1178 | # |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 55bd5740e910..fe893e91935b 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
@@ -51,7 +51,6 @@ obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o | |||
51 | obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o | 51 | obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o |
52 | obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o | 52 | obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o |
53 | obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o | 53 | obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o |
54 | obj-$(CONFIG_ADX_WATCHDOG) += adx_wdt.o | ||
55 | obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o | 54 | obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o |
56 | obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o | 55 | obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o |
57 | 56 | ||
diff --git a/drivers/watchdog/adx_wdt.c b/drivers/watchdog/adx_wdt.c deleted file mode 100644 index af6e6b16475a..000000000000 --- a/drivers/watchdog/adx_wdt.c +++ /dev/null | |||
@@ -1,355 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008-2009 Avionic Design GmbH | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/fs.h> | ||
10 | #include <linux/gfp.h> | ||
11 | #include <linux/io.h> | ||
12 | #include <linux/miscdevice.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/uaccess.h> | ||
17 | #include <linux/watchdog.h> | ||
18 | |||
19 | #define WATCHDOG_NAME "adx-wdt" | ||
20 | |||
21 | /* register offsets */ | ||
22 | #define ADX_WDT_CONTROL 0x00 | ||
23 | #define ADX_WDT_CONTROL_ENABLE (1 << 0) | ||
24 | #define ADX_WDT_CONTROL_nRESET (1 << 1) | ||
25 | #define ADX_WDT_TIMEOUT 0x08 | ||
26 | |||
27 | static struct platform_device *adx_wdt_dev; | ||
28 | static unsigned long driver_open; | ||
29 | |||
30 | #define WDT_STATE_STOP 0 | ||
31 | #define WDT_STATE_START 1 | ||
32 | |||
33 | struct adx_wdt { | ||
34 | void __iomem *base; | ||
35 | unsigned long timeout; | ||
36 | unsigned int state; | ||
37 | unsigned int wake; | ||
38 | spinlock_t lock; | ||
39 | }; | ||
40 | |||
41 | static const struct watchdog_info adx_wdt_info = { | ||
42 | .identity = "Avionic Design Xanthos Watchdog", | ||
43 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | ||
44 | }; | ||
45 | |||
46 | static void adx_wdt_start_locked(struct adx_wdt *wdt) | ||
47 | { | ||
48 | u32 ctrl; | ||
49 | |||
50 | ctrl = readl(wdt->base + ADX_WDT_CONTROL); | ||
51 | ctrl |= ADX_WDT_CONTROL_ENABLE; | ||
52 | writel(ctrl, wdt->base + ADX_WDT_CONTROL); | ||
53 | wdt->state = WDT_STATE_START; | ||
54 | } | ||
55 | |||
56 | static void adx_wdt_start(struct adx_wdt *wdt) | ||
57 | { | ||
58 | unsigned long flags; | ||
59 | |||
60 | spin_lock_irqsave(&wdt->lock, flags); | ||
61 | adx_wdt_start_locked(wdt); | ||
62 | spin_unlock_irqrestore(&wdt->lock, flags); | ||
63 | } | ||
64 | |||
65 | static void adx_wdt_stop_locked(struct adx_wdt *wdt) | ||
66 | { | ||
67 | u32 ctrl; | ||
68 | |||
69 | ctrl = readl(wdt->base + ADX_WDT_CONTROL); | ||
70 | ctrl &= ~ADX_WDT_CONTROL_ENABLE; | ||
71 | writel(ctrl, wdt->base + ADX_WDT_CONTROL); | ||
72 | wdt->state = WDT_STATE_STOP; | ||
73 | } | ||
74 | |||
75 | static void adx_wdt_stop(struct adx_wdt *wdt) | ||
76 | { | ||
77 | unsigned long flags; | ||
78 | |||
79 | spin_lock_irqsave(&wdt->lock, flags); | ||
80 | adx_wdt_stop_locked(wdt); | ||
81 | spin_unlock_irqrestore(&wdt->lock, flags); | ||
82 | } | ||
83 | |||
84 | static void adx_wdt_set_timeout(struct adx_wdt *wdt, unsigned long seconds) | ||
85 | { | ||
86 | unsigned long timeout = seconds * 1000; | ||
87 | unsigned long flags; | ||
88 | unsigned int state; | ||
89 | |||
90 | spin_lock_irqsave(&wdt->lock, flags); | ||
91 | state = wdt->state; | ||
92 | adx_wdt_stop_locked(wdt); | ||
93 | writel(timeout, wdt->base + ADX_WDT_TIMEOUT); | ||
94 | |||
95 | if (state == WDT_STATE_START) | ||
96 | adx_wdt_start_locked(wdt); | ||
97 | |||
98 | wdt->timeout = timeout; | ||
99 | spin_unlock_irqrestore(&wdt->lock, flags); | ||
100 | } | ||
101 | |||
102 | static void adx_wdt_get_timeout(struct adx_wdt *wdt, unsigned long *seconds) | ||
103 | { | ||
104 | *seconds = wdt->timeout / 1000; | ||
105 | } | ||
106 | |||
107 | static void adx_wdt_keepalive(struct adx_wdt *wdt) | ||
108 | { | ||
109 | unsigned long flags; | ||
110 | |||
111 | spin_lock_irqsave(&wdt->lock, flags); | ||
112 | writel(wdt->timeout, wdt->base + ADX_WDT_TIMEOUT); | ||
113 | spin_unlock_irqrestore(&wdt->lock, flags); | ||
114 | } | ||
115 | |||
116 | static int adx_wdt_open(struct inode *inode, struct file *file) | ||
117 | { | ||
118 | struct adx_wdt *wdt = platform_get_drvdata(adx_wdt_dev); | ||
119 | |||
120 | if (test_and_set_bit(0, &driver_open)) | ||
121 | return -EBUSY; | ||
122 | |||
123 | file->private_data = wdt; | ||
124 | adx_wdt_set_timeout(wdt, 30); | ||
125 | adx_wdt_start(wdt); | ||
126 | |||
127 | return nonseekable_open(inode, file); | ||
128 | } | ||
129 | |||
130 | static int adx_wdt_release(struct inode *inode, struct file *file) | ||
131 | { | ||
132 | struct adx_wdt *wdt = file->private_data; | ||
133 | |||
134 | adx_wdt_stop(wdt); | ||
135 | clear_bit(0, &driver_open); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static long adx_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
141 | { | ||
142 | struct adx_wdt *wdt = file->private_data; | ||
143 | void __user *argp = (void __user *)arg; | ||
144 | unsigned long __user *p = argp; | ||
145 | unsigned long seconds = 0; | ||
146 | unsigned int options; | ||
147 | long ret = -EINVAL; | ||
148 | |||
149 | switch (cmd) { | ||
150 | case WDIOC_GETSUPPORT: | ||
151 | if (copy_to_user(argp, &adx_wdt_info, sizeof(adx_wdt_info))) | ||
152 | return -EFAULT; | ||
153 | else | ||
154 | return 0; | ||
155 | |||
156 | case WDIOC_GETSTATUS: | ||
157 | case WDIOC_GETBOOTSTATUS: | ||
158 | return put_user(0, p); | ||
159 | |||
160 | case WDIOC_KEEPALIVE: | ||
161 | adx_wdt_keepalive(wdt); | ||
162 | return 0; | ||
163 | |||
164 | case WDIOC_SETTIMEOUT: | ||
165 | if (get_user(seconds, p)) | ||
166 | return -EFAULT; | ||
167 | |||
168 | adx_wdt_set_timeout(wdt, seconds); | ||
169 | |||
170 | /* fallthrough */ | ||
171 | case WDIOC_GETTIMEOUT: | ||
172 | adx_wdt_get_timeout(wdt, &seconds); | ||
173 | return put_user(seconds, p); | ||
174 | |||
175 | case WDIOC_SETOPTIONS: | ||
176 | if (copy_from_user(&options, argp, sizeof(options))) | ||
177 | return -EFAULT; | ||
178 | |||
179 | if (options & WDIOS_DISABLECARD) { | ||
180 | adx_wdt_stop(wdt); | ||
181 | ret = 0; | ||
182 | } | ||
183 | |||
184 | if (options & WDIOS_ENABLECARD) { | ||
185 | adx_wdt_start(wdt); | ||
186 | ret = 0; | ||
187 | } | ||
188 | |||
189 | return ret; | ||
190 | |||
191 | default: | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | return -ENOTTY; | ||
196 | } | ||
197 | |||
198 | static ssize_t adx_wdt_write(struct file *file, const char __user *data, | ||
199 | size_t len, loff_t *ppos) | ||
200 | { | ||
201 | struct adx_wdt *wdt = file->private_data; | ||
202 | |||
203 | if (len) | ||
204 | adx_wdt_keepalive(wdt); | ||
205 | |||
206 | return len; | ||
207 | } | ||
208 | |||
209 | static const struct file_operations adx_wdt_fops = { | ||
210 | .owner = THIS_MODULE, | ||
211 | .llseek = no_llseek, | ||
212 | .open = adx_wdt_open, | ||
213 | .release = adx_wdt_release, | ||
214 | .unlocked_ioctl = adx_wdt_ioctl, | ||
215 | .write = adx_wdt_write, | ||
216 | }; | ||
217 | |||
218 | static struct miscdevice adx_wdt_miscdev = { | ||
219 | .minor = WATCHDOG_MINOR, | ||
220 | .name = "watchdog", | ||
221 | .fops = &adx_wdt_fops, | ||
222 | }; | ||
223 | |||
224 | static int __devinit adx_wdt_probe(struct platform_device *pdev) | ||
225 | { | ||
226 | struct resource *res; | ||
227 | struct adx_wdt *wdt; | ||
228 | int ret = 0; | ||
229 | u32 ctrl; | ||
230 | |||
231 | wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); | ||
232 | if (!wdt) { | ||
233 | dev_err(&pdev->dev, "cannot allocate WDT structure\n"); | ||
234 | return -ENOMEM; | ||
235 | } | ||
236 | |||
237 | spin_lock_init(&wdt->lock); | ||
238 | |||
239 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
240 | if (!res) { | ||
241 | dev_err(&pdev->dev, "cannot obtain I/O memory region\n"); | ||
242 | return -ENXIO; | ||
243 | } | ||
244 | |||
245 | res = devm_request_mem_region(&pdev->dev, res->start, | ||
246 | resource_size(res), res->name); | ||
247 | if (!res) { | ||
248 | dev_err(&pdev->dev, "cannot request I/O memory region\n"); | ||
249 | return -ENXIO; | ||
250 | } | ||
251 | |||
252 | wdt->base = devm_ioremap_nocache(&pdev->dev, res->start, | ||
253 | resource_size(res)); | ||
254 | if (!wdt->base) { | ||
255 | dev_err(&pdev->dev, "cannot remap I/O memory region\n"); | ||
256 | return -ENXIO; | ||
257 | } | ||
258 | |||
259 | /* disable watchdog and reboot on timeout */ | ||
260 | ctrl = readl(wdt->base + ADX_WDT_CONTROL); | ||
261 | ctrl &= ~ADX_WDT_CONTROL_ENABLE; | ||
262 | ctrl &= ~ADX_WDT_CONTROL_nRESET; | ||
263 | writel(ctrl, wdt->base + ADX_WDT_CONTROL); | ||
264 | |||
265 | platform_set_drvdata(pdev, wdt); | ||
266 | adx_wdt_dev = pdev; | ||
267 | |||
268 | ret = misc_register(&adx_wdt_miscdev); | ||
269 | if (ret) { | ||
270 | dev_err(&pdev->dev, "cannot register miscdev on minor %d " | ||
271 | "(err=%d)\n", WATCHDOG_MINOR, ret); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int __devexit adx_wdt_remove(struct platform_device *pdev) | ||
279 | { | ||
280 | struct adx_wdt *wdt = platform_get_drvdata(pdev); | ||
281 | |||
282 | misc_deregister(&adx_wdt_miscdev); | ||
283 | adx_wdt_stop(wdt); | ||
284 | platform_set_drvdata(pdev, NULL); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static void adx_wdt_shutdown(struct platform_device *pdev) | ||
290 | { | ||
291 | struct adx_wdt *wdt = platform_get_drvdata(pdev); | ||
292 | adx_wdt_stop(wdt); | ||
293 | } | ||
294 | |||
295 | #ifdef CONFIG_PM | ||
296 | static int adx_wdt_suspend(struct device *dev) | ||
297 | { | ||
298 | struct platform_device *pdev = to_platform_device(dev); | ||
299 | struct adx_wdt *wdt = platform_get_drvdata(pdev); | ||
300 | |||
301 | wdt->wake = (wdt->state == WDT_STATE_START) ? 1 : 0; | ||
302 | adx_wdt_stop(wdt); | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int adx_wdt_resume(struct device *dev) | ||
308 | { | ||
309 | struct platform_device *pdev = to_platform_device(dev); | ||
310 | struct adx_wdt *wdt = platform_get_drvdata(pdev); | ||
311 | |||
312 | if (wdt->wake) | ||
313 | adx_wdt_start(wdt); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static const struct dev_pm_ops adx_wdt_pm_ops = { | ||
319 | .suspend = adx_wdt_suspend, | ||
320 | .resume = adx_wdt_resume, | ||
321 | }; | ||
322 | |||
323 | # define ADX_WDT_PM_OPS (&adx_wdt_pm_ops) | ||
324 | #else | ||
325 | # define ADX_WDT_PM_OPS NULL | ||
326 | #endif | ||
327 | |||
328 | static struct platform_driver adx_wdt_driver = { | ||
329 | .probe = adx_wdt_probe, | ||
330 | .remove = __devexit_p(adx_wdt_remove), | ||
331 | .shutdown = adx_wdt_shutdown, | ||
332 | .driver = { | ||
333 | .name = WATCHDOG_NAME, | ||
334 | .owner = THIS_MODULE, | ||
335 | .pm = ADX_WDT_PM_OPS, | ||
336 | }, | ||
337 | }; | ||
338 | |||
339 | static int __init adx_wdt_init(void) | ||
340 | { | ||
341 | return platform_driver_register(&adx_wdt_driver); | ||
342 | } | ||
343 | |||
344 | static void __exit adx_wdt_exit(void) | ||
345 | { | ||
346 | platform_driver_unregister(&adx_wdt_driver); | ||
347 | } | ||
348 | |||
349 | module_init(adx_wdt_init); | ||
350 | module_exit(adx_wdt_exit); | ||
351 | |||
352 | MODULE_DESCRIPTION("Avionic Design Xanthos Watchdog Driver"); | ||
353 | MODULE_LICENSE("GPL v2"); | ||
354 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | ||
355 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index bd44417c84d4..5c5f4b14fd05 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c | |||
@@ -54,12 +54,35 @@ static atomic_t ticks; | |||
54 | static inline void bcm47xx_wdt_hw_start(void) | 54 | static inline void bcm47xx_wdt_hw_start(void) |
55 | { | 55 | { |
56 | /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */ | 56 | /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */ |
57 | ssb_watchdog_timer_set(&ssb_bcm47xx, 0xfffffff); | 57 | switch (bcm47xx_bus_type) { |
58 | #ifdef CONFIG_BCM47XX_SSB | ||
59 | case BCM47XX_BUS_TYPE_SSB: | ||
60 | ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff); | ||
61 | break; | ||
62 | #endif | ||
63 | #ifdef CONFIG_BCM47XX_BCMA | ||
64 | case BCM47XX_BUS_TYPE_BCMA: | ||
65 | bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, | ||
66 | 0xfffffff); | ||
67 | break; | ||
68 | #endif | ||
69 | } | ||
58 | } | 70 | } |
59 | 71 | ||
60 | static inline int bcm47xx_wdt_hw_stop(void) | 72 | static inline int bcm47xx_wdt_hw_stop(void) |
61 | { | 73 | { |
62 | return ssb_watchdog_timer_set(&ssb_bcm47xx, 0); | 74 | switch (bcm47xx_bus_type) { |
75 | #ifdef CONFIG_BCM47XX_SSB | ||
76 | case BCM47XX_BUS_TYPE_SSB: | ||
77 | return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0); | ||
78 | #endif | ||
79 | #ifdef CONFIG_BCM47XX_BCMA | ||
80 | case BCM47XX_BUS_TYPE_BCMA: | ||
81 | bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0); | ||
82 | return 0; | ||
83 | #endif | ||
84 | } | ||
85 | return -EINVAL; | ||
63 | } | 86 | } |
64 | 87 | ||
65 | static void bcm47xx_timer_tick(unsigned long unused) | 88 | static void bcm47xx_timer_tick(unsigned long unused) |
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index 9291506b8b23..03f449a430d2 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c | |||
@@ -429,7 +429,7 @@ static int __init coh901327_probe(struct platform_device *pdev) | |||
429 | writew(U300_WDOG_SR_RESET_STATUS_RESET, virtbase + U300_WDOG_SR); | 429 | writew(U300_WDOG_SR_RESET_STATUS_RESET, virtbase + U300_WDOG_SR); |
430 | 430 | ||
431 | irq = platform_get_irq(pdev, 0); | 431 | irq = platform_get_irq(pdev, 0); |
432 | if (request_irq(irq, coh901327_interrupt, IRQF_DISABLED, | 432 | if (request_irq(irq, coh901327_interrupt, 0, |
433 | DRV_NAME " Bark", pdev)) { | 433 | DRV_NAME " Bark", pdev)) { |
434 | ret = -EIO; | 434 | ret = -EIO; |
435 | goto out_no_irq; | 435 | goto out_no_irq; |
diff --git a/drivers/watchdog/eurotechwdt.c b/drivers/watchdog/eurotechwdt.c index f1d1da662fbe..41018d429abb 100644 --- a/drivers/watchdog/eurotechwdt.c +++ b/drivers/watchdog/eurotechwdt.c | |||
@@ -427,7 +427,7 @@ static int __init eurwdt_init(void) | |||
427 | { | 427 | { |
428 | int ret; | 428 | int ret; |
429 | 429 | ||
430 | ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL); | 430 | ret = request_irq(irq, eurwdt_interrupt, 0, "eurwdt", NULL); |
431 | if (ret) { | 431 | if (ret) { |
432 | printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); | 432 | printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); |
433 | goto out; | 433 | goto out; |
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 410fba45378d..3774c9b8dac9 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/notifier.h> | 35 | #include <linux/notifier.h> |
36 | #include <asm/cacheflush.h> | 36 | #include <asm/cacheflush.h> |
37 | #endif /* CONFIG_HPWDT_NMI_DECODING */ | 37 | #endif /* CONFIG_HPWDT_NMI_DECODING */ |
38 | #include <asm/nmi.h> | ||
38 | 39 | ||
39 | #define HPWDT_VERSION "1.3.0" | 40 | #define HPWDT_VERSION "1.3.0" |
40 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) | 41 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) |
@@ -477,15 +478,11 @@ static int hpwdt_time_left(void) | |||
477 | /* | 478 | /* |
478 | * NMI Handler | 479 | * NMI Handler |
479 | */ | 480 | */ |
480 | static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, | 481 | static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) |
481 | void *data) | ||
482 | { | 482 | { |
483 | unsigned long rom_pl; | 483 | unsigned long rom_pl; |
484 | static int die_nmi_called; | 484 | static int die_nmi_called; |
485 | 485 | ||
486 | if (ulReason != DIE_NMIUNKNOWN) | ||
487 | goto out; | ||
488 | |||
489 | if (!hpwdt_nmi_decoding) | 486 | if (!hpwdt_nmi_decoding) |
490 | goto out; | 487 | goto out; |
491 | 488 | ||
@@ -494,20 +491,21 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, | |||
494 | asminline_call(&cmn_regs, cru_rom_addr); | 491 | asminline_call(&cmn_regs, cru_rom_addr); |
495 | die_nmi_called = 1; | 492 | die_nmi_called = 1; |
496 | spin_unlock_irqrestore(&rom_lock, rom_pl); | 493 | spin_unlock_irqrestore(&rom_lock, rom_pl); |
494 | |||
495 | if (allow_kdump) | ||
496 | hpwdt_stop(); | ||
497 | |||
497 | if (!is_icru) { | 498 | if (!is_icru) { |
498 | if (cmn_regs.u1.ral == 0) { | 499 | if (cmn_regs.u1.ral == 0) { |
499 | printk(KERN_WARNING "hpwdt: An NMI occurred, " | 500 | panic("An NMI occurred, " |
500 | "but unable to determine source.\n"); | 501 | "but unable to determine source.\n"); |
501 | } | 502 | } |
502 | } | 503 | } |
503 | |||
504 | if (allow_kdump) | ||
505 | hpwdt_stop(); | ||
506 | panic("An NMI occurred, please see the Integrated " | 504 | panic("An NMI occurred, please see the Integrated " |
507 | "Management Log for details.\n"); | 505 | "Management Log for details.\n"); |
508 | 506 | ||
509 | out: | 507 | out: |
510 | return NOTIFY_OK; | 508 | return NMI_DONE; |
511 | } | 509 | } |
512 | #endif /* CONFIG_HPWDT_NMI_DECODING */ | 510 | #endif /* CONFIG_HPWDT_NMI_DECODING */ |
513 | 511 | ||
@@ -647,13 +645,6 @@ static struct miscdevice hpwdt_miscdev = { | |||
647 | .fops = &hpwdt_fops, | 645 | .fops = &hpwdt_fops, |
648 | }; | 646 | }; |
649 | 647 | ||
650 | #ifdef CONFIG_HPWDT_NMI_DECODING | ||
651 | static struct notifier_block die_notifier = { | ||
652 | .notifier_call = hpwdt_pretimeout, | ||
653 | .priority = 0, | ||
654 | }; | ||
655 | #endif /* CONFIG_HPWDT_NMI_DECODING */ | ||
656 | |||
657 | /* | 648 | /* |
658 | * Init & Exit | 649 | * Init & Exit |
659 | */ | 650 | */ |
@@ -739,10 +730,9 @@ static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) | |||
739 | * die notify list to handle a critical NMI. The default is to | 730 | * die notify list to handle a critical NMI. The default is to |
740 | * be last so other users of the NMI signal can function. | 731 | * be last so other users of the NMI signal can function. |
741 | */ | 732 | */ |
742 | if (priority) | 733 | retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, |
743 | die_notifier.priority = 0x7FFFFFFF; | 734 | (priority) ? NMI_FLAG_FIRST : 0, |
744 | 735 | "hpwdt"); | |
745 | retval = register_die_notifier(&die_notifier); | ||
746 | if (retval != 0) { | 736 | if (retval != 0) { |
747 | dev_warn(&dev->dev, | 737 | dev_warn(&dev->dev, |
748 | "Unable to register a die notifier (err=%d).\n", | 738 | "Unable to register a die notifier (err=%d).\n", |
@@ -762,7 +752,7 @@ static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) | |||
762 | 752 | ||
763 | static void hpwdt_exit_nmi_decoding(void) | 753 | static void hpwdt_exit_nmi_decoding(void) |
764 | { | 754 | { |
765 | unregister_die_notifier(&die_notifier); | 755 | unregister_nmi_handler(NMI_UNKNOWN, "hpwdt"); |
766 | if (cru_rom_addr) | 756 | if (cru_rom_addr) |
767 | iounmap(cru_rom_addr); | 757 | iounmap(cru_rom_addr); |
768 | } | 758 | } |
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 751a591684da..ba6ad662635a 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * intel TCO Watchdog Driver | 2 | * intel TCO Watchdog Driver |
3 | * | 3 | * |
4 | * (c) Copyright 2006-2010 Wim Van Sebroeck <wim@iguana.be>. | 4 | * (c) Copyright 2006-2011 Wim Van Sebroeck <wim@iguana.be>. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 7 | * modify it under the terms of the GNU General Public License |
@@ -44,7 +44,7 @@ | |||
44 | 44 | ||
45 | /* Module and version information */ | 45 | /* Module and version information */ |
46 | #define DRV_NAME "iTCO_wdt" | 46 | #define DRV_NAME "iTCO_wdt" |
47 | #define DRV_VERSION "1.06" | 47 | #define DRV_VERSION "1.07" |
48 | #define PFX DRV_NAME ": " | 48 | #define PFX DRV_NAME ": " |
49 | 49 | ||
50 | /* Includes */ | 50 | /* Includes */ |
@@ -384,6 +384,11 @@ MODULE_PARM_DESC(nowayout, | |||
384 | "Watchdog cannot be stopped once started (default=" | 384 | "Watchdog cannot be stopped once started (default=" |
385 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 385 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
386 | 386 | ||
387 | static int turn_SMI_watchdog_clear_off = 0; | ||
388 | module_param(turn_SMI_watchdog_clear_off, int, 0); | ||
389 | MODULE_PARM_DESC(turn_SMI_watchdog_clear_off, | ||
390 | "Turn off SMI clearing watchdog (default=0)"); | ||
391 | |||
387 | /* | 392 | /* |
388 | * Some TCO specific functions | 393 | * Some TCO specific functions |
389 | */ | 394 | */ |
@@ -808,10 +813,12 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, | |||
808 | ret = -EIO; | 813 | ret = -EIO; |
809 | goto out_unmap; | 814 | goto out_unmap; |
810 | } | 815 | } |
811 | /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ | 816 | if (turn_SMI_watchdog_clear_off) { |
812 | val32 = inl(SMI_EN); | 817 | /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ |
813 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ | 818 | val32 = inl(SMI_EN); |
814 | outl(val32, SMI_EN); | 819 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ |
820 | outl(val32, SMI_EN); | ||
821 | } | ||
815 | 822 | ||
816 | /* The TCO I/O registers reside in a 32-byte range pointed to | 823 | /* The TCO I/O registers reside in a 32-byte range pointed to |
817 | by the TCOBASE value */ | 824 | by the TCOBASE value */ |
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c index 7d82adac1cb2..102aed0efbf1 100644 --- a/drivers/watchdog/lantiq_wdt.c +++ b/drivers/watchdog/lantiq_wdt.c | |||
@@ -51,16 +51,16 @@ static int ltq_wdt_ok_to_close; | |||
51 | static void | 51 | static void |
52 | ltq_wdt_enable(void) | 52 | ltq_wdt_enable(void) |
53 | { | 53 | { |
54 | ltq_wdt_timeout = ltq_wdt_timeout * | 54 | unsigned long int timeout = ltq_wdt_timeout * |
55 | (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000; | 55 | (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000; |
56 | if (ltq_wdt_timeout > LTQ_MAX_TIMEOUT) | 56 | if (timeout > LTQ_MAX_TIMEOUT) |
57 | ltq_wdt_timeout = LTQ_MAX_TIMEOUT; | 57 | timeout = LTQ_MAX_TIMEOUT; |
58 | 58 | ||
59 | /* write the first password magic */ | 59 | /* write the first password magic */ |
60 | ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); | 60 | ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR); |
61 | /* write the second magic plus the configuration and new timeout */ | 61 | /* write the second magic plus the configuration and new timeout */ |
62 | ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV | | 62 | ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV | |
63 | LTQ_WDT_PW2 | ltq_wdt_timeout, ltq_wdt_membase + LTQ_WDT_CR); | 63 | LTQ_WDT_PW2 | timeout, ltq_wdt_membase + LTQ_WDT_CR); |
64 | } | 64 | } |
65 | 65 | ||
66 | static void | 66 | static void |
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c index 4dc31024d26c..82ccd36e2c90 100644 --- a/drivers/watchdog/mpcore_wdt.c +++ b/drivers/watchdog/mpcore_wdt.c | |||
@@ -367,8 +367,7 @@ static int __devinit mpcore_wdt_probe(struct platform_device *dev) | |||
367 | goto err_misc; | 367 | goto err_misc; |
368 | } | 368 | } |
369 | 369 | ||
370 | ret = request_irq(wdt->irq, mpcore_wdt_fire, IRQF_DISABLED, | 370 | ret = request_irq(wdt->irq, mpcore_wdt_fire, 0, "mpcore_wdt", wdt); |
371 | "mpcore_wdt", wdt); | ||
372 | if (ret) { | 371 | if (ret) { |
373 | dev_printk(KERN_ERR, wdt->dev, | 372 | dev_printk(KERN_ERR, wdt->dev, |
374 | "cannot register IRQ%d for watchdog\n", wdt->irq); | 373 | "cannot register IRQ%d for watchdog\n", wdt->irq); |
diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index 945ee8300306..7c0d8630e641 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c | |||
@@ -402,7 +402,7 @@ static void octeon_wdt_setup_interrupt(int cpu) | |||
402 | irq = OCTEON_IRQ_WDOG0 + core; | 402 | irq = OCTEON_IRQ_WDOG0 + core; |
403 | 403 | ||
404 | if (request_irq(irq, octeon_wdt_poke_irq, | 404 | if (request_irq(irq, octeon_wdt_poke_irq, |
405 | IRQF_DISABLED, "octeon_wdt", octeon_wdt_poke_irq)) | 405 | IRQF_NO_THREAD, "octeon_wdt", octeon_wdt_poke_irq)) |
406 | panic("octeon_wdt: Couldn't obtain irq %d", irq); | 406 | panic("octeon_wdt: Couldn't obtain irq %d", irq); |
407 | 407 | ||
408 | cpumask_set_cpu(cpu, &irq_enabled_cpus); | 408 | cpumask_set_cpu(cpu, &irq_enabled_cpus); |
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 30da88f47cd3..a79e3840782a 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
@@ -27,9 +27,8 @@ | |||
27 | #include <linux/moduleparam.h> | 27 | #include <linux/moduleparam.h> |
28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
29 | #include <linux/timer.h> | 29 | #include <linux/timer.h> |
30 | #include <linux/miscdevice.h> | 30 | #include <linux/miscdevice.h> /* for MODULE_ALIAS_MISCDEV */ |
31 | #include <linux/watchdog.h> | 31 | #include <linux/watchdog.h> |
32 | #include <linux/fs.h> | ||
33 | #include <linux/init.h> | 32 | #include <linux/init.h> |
34 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
35 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
@@ -38,6 +37,7 @@ | |||
38 | #include <linux/io.h> | 37 | #include <linux/io.h> |
39 | #include <linux/cpufreq.h> | 38 | #include <linux/cpufreq.h> |
40 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
40 | #include <linux/err.h> | ||
41 | 41 | ||
42 | #include <mach/map.h> | 42 | #include <mach/map.h> |
43 | 43 | ||
@@ -74,14 +74,12 @@ MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " | |||
74 | "0 to reboot (default 0)"); | 74 | "0 to reboot (default 0)"); |
75 | MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); | 75 | MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); |
76 | 76 | ||
77 | static unsigned long open_lock; | ||
78 | static struct device *wdt_dev; /* platform device attached to */ | 77 | static struct device *wdt_dev; /* platform device attached to */ |
79 | static struct resource *wdt_mem; | 78 | static struct resource *wdt_mem; |
80 | static struct resource *wdt_irq; | 79 | static struct resource *wdt_irq; |
81 | static struct clk *wdt_clock; | 80 | static struct clk *wdt_clock; |
82 | static void __iomem *wdt_base; | 81 | static void __iomem *wdt_base; |
83 | static unsigned int wdt_count; | 82 | static unsigned int wdt_count; |
84 | static char expect_close; | ||
85 | static DEFINE_SPINLOCK(wdt_lock); | 83 | static DEFINE_SPINLOCK(wdt_lock); |
86 | 84 | ||
87 | /* watchdog control routines */ | 85 | /* watchdog control routines */ |
@@ -93,11 +91,13 @@ static DEFINE_SPINLOCK(wdt_lock); | |||
93 | 91 | ||
94 | /* functions */ | 92 | /* functions */ |
95 | 93 | ||
96 | static void s3c2410wdt_keepalive(void) | 94 | static int s3c2410wdt_keepalive(struct watchdog_device *wdd) |
97 | { | 95 | { |
98 | spin_lock(&wdt_lock); | 96 | spin_lock(&wdt_lock); |
99 | writel(wdt_count, wdt_base + S3C2410_WTCNT); | 97 | writel(wdt_count, wdt_base + S3C2410_WTCNT); |
100 | spin_unlock(&wdt_lock); | 98 | spin_unlock(&wdt_lock); |
99 | |||
100 | return 0; | ||
101 | } | 101 | } |
102 | 102 | ||
103 | static void __s3c2410wdt_stop(void) | 103 | static void __s3c2410wdt_stop(void) |
@@ -109,14 +109,16 @@ static void __s3c2410wdt_stop(void) | |||
109 | writel(wtcon, wdt_base + S3C2410_WTCON); | 109 | writel(wtcon, wdt_base + S3C2410_WTCON); |
110 | } | 110 | } |
111 | 111 | ||
112 | static void s3c2410wdt_stop(void) | 112 | static int s3c2410wdt_stop(struct watchdog_device *wdd) |
113 | { | 113 | { |
114 | spin_lock(&wdt_lock); | 114 | spin_lock(&wdt_lock); |
115 | __s3c2410wdt_stop(); | 115 | __s3c2410wdt_stop(); |
116 | spin_unlock(&wdt_lock); | 116 | spin_unlock(&wdt_lock); |
117 | |||
118 | return 0; | ||
117 | } | 119 | } |
118 | 120 | ||
119 | static void s3c2410wdt_start(void) | 121 | static int s3c2410wdt_start(struct watchdog_device *wdd) |
120 | { | 122 | { |
121 | unsigned long wtcon; | 123 | unsigned long wtcon; |
122 | 124 | ||
@@ -142,6 +144,8 @@ static void s3c2410wdt_start(void) | |||
142 | writel(wdt_count, wdt_base + S3C2410_WTCNT); | 144 | writel(wdt_count, wdt_base + S3C2410_WTCNT); |
143 | writel(wtcon, wdt_base + S3C2410_WTCON); | 145 | writel(wtcon, wdt_base + S3C2410_WTCON); |
144 | spin_unlock(&wdt_lock); | 146 | spin_unlock(&wdt_lock); |
147 | |||
148 | return 0; | ||
145 | } | 149 | } |
146 | 150 | ||
147 | static inline int s3c2410wdt_is_running(void) | 151 | static inline int s3c2410wdt_is_running(void) |
@@ -149,7 +153,7 @@ static inline int s3c2410wdt_is_running(void) | |||
149 | return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; | 153 | return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; |
150 | } | 154 | } |
151 | 155 | ||
152 | static int s3c2410wdt_set_heartbeat(int timeout) | 156 | static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeout) |
153 | { | 157 | { |
154 | unsigned long freq = clk_get_rate(wdt_clock); | 158 | unsigned long freq = clk_get_rate(wdt_clock); |
155 | unsigned int count; | 159 | unsigned int count; |
@@ -182,8 +186,6 @@ static int s3c2410wdt_set_heartbeat(int timeout) | |||
182 | } | 186 | } |
183 | } | 187 | } |
184 | 188 | ||
185 | tmr_margin = timeout; | ||
186 | |||
187 | DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", | 189 | DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", |
188 | __func__, timeout, divisor, count, count/divisor); | 190 | __func__, timeout, divisor, count, count/divisor); |
189 | 191 | ||
@@ -201,70 +203,6 @@ static int s3c2410wdt_set_heartbeat(int timeout) | |||
201 | return 0; | 203 | return 0; |
202 | } | 204 | } |
203 | 205 | ||
204 | /* | ||
205 | * /dev/watchdog handling | ||
206 | */ | ||
207 | |||
208 | static int s3c2410wdt_open(struct inode *inode, struct file *file) | ||
209 | { | ||
210 | if (test_and_set_bit(0, &open_lock)) | ||
211 | return -EBUSY; | ||
212 | |||
213 | if (nowayout) | ||
214 | __module_get(THIS_MODULE); | ||
215 | |||
216 | expect_close = 0; | ||
217 | |||
218 | /* start the timer */ | ||
219 | s3c2410wdt_start(); | ||
220 | return nonseekable_open(inode, file); | ||
221 | } | ||
222 | |||
223 | static int s3c2410wdt_release(struct inode *inode, struct file *file) | ||
224 | { | ||
225 | /* | ||
226 | * Shut off the timer. | ||
227 | * Lock it in if it's a module and we set nowayout | ||
228 | */ | ||
229 | |||
230 | if (expect_close == 42) | ||
231 | s3c2410wdt_stop(); | ||
232 | else { | ||
233 | dev_err(wdt_dev, "Unexpected close, not stopping watchdog\n"); | ||
234 | s3c2410wdt_keepalive(); | ||
235 | } | ||
236 | expect_close = 0; | ||
237 | clear_bit(0, &open_lock); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static ssize_t s3c2410wdt_write(struct file *file, const char __user *data, | ||
242 | size_t len, loff_t *ppos) | ||
243 | { | ||
244 | /* | ||
245 | * Refresh the timer. | ||
246 | */ | ||
247 | if (len) { | ||
248 | if (!nowayout) { | ||
249 | size_t i; | ||
250 | |||
251 | /* In case it was set long ago */ | ||
252 | expect_close = 0; | ||
253 | |||
254 | for (i = 0; i != len; i++) { | ||
255 | char c; | ||
256 | |||
257 | if (get_user(c, data + i)) | ||
258 | return -EFAULT; | ||
259 | if (c == 'V') | ||
260 | expect_close = 42; | ||
261 | } | ||
262 | } | ||
263 | s3c2410wdt_keepalive(); | ||
264 | } | ||
265 | return len; | ||
266 | } | ||
267 | |||
268 | #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) | 206 | #define OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) |
269 | 207 | ||
270 | static const struct watchdog_info s3c2410_wdt_ident = { | 208 | static const struct watchdog_info s3c2410_wdt_ident = { |
@@ -273,53 +211,17 @@ static const struct watchdog_info s3c2410_wdt_ident = { | |||
273 | .identity = "S3C2410 Watchdog", | 211 | .identity = "S3C2410 Watchdog", |
274 | }; | 212 | }; |
275 | 213 | ||
276 | 214 | static struct watchdog_ops s3c2410wdt_ops = { | |
277 | static long s3c2410wdt_ioctl(struct file *file, unsigned int cmd, | 215 | .owner = THIS_MODULE, |
278 | unsigned long arg) | 216 | .start = s3c2410wdt_start, |
279 | { | 217 | .stop = s3c2410wdt_stop, |
280 | void __user *argp = (void __user *)arg; | 218 | .ping = s3c2410wdt_keepalive, |
281 | int __user *p = argp; | 219 | .set_timeout = s3c2410wdt_set_heartbeat, |
282 | int new_margin; | ||
283 | |||
284 | switch (cmd) { | ||
285 | case WDIOC_GETSUPPORT: | ||
286 | return copy_to_user(argp, &s3c2410_wdt_ident, | ||
287 | sizeof(s3c2410_wdt_ident)) ? -EFAULT : 0; | ||
288 | case WDIOC_GETSTATUS: | ||
289 | case WDIOC_GETBOOTSTATUS: | ||
290 | return put_user(0, p); | ||
291 | case WDIOC_KEEPALIVE: | ||
292 | s3c2410wdt_keepalive(); | ||
293 | return 0; | ||
294 | case WDIOC_SETTIMEOUT: | ||
295 | if (get_user(new_margin, p)) | ||
296 | return -EFAULT; | ||
297 | if (s3c2410wdt_set_heartbeat(new_margin)) | ||
298 | return -EINVAL; | ||
299 | s3c2410wdt_keepalive(); | ||
300 | return put_user(tmr_margin, p); | ||
301 | case WDIOC_GETTIMEOUT: | ||
302 | return put_user(tmr_margin, p); | ||
303 | default: | ||
304 | return -ENOTTY; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | /* kernel interface */ | ||
309 | |||
310 | static const struct file_operations s3c2410wdt_fops = { | ||
311 | .owner = THIS_MODULE, | ||
312 | .llseek = no_llseek, | ||
313 | .write = s3c2410wdt_write, | ||
314 | .unlocked_ioctl = s3c2410wdt_ioctl, | ||
315 | .open = s3c2410wdt_open, | ||
316 | .release = s3c2410wdt_release, | ||
317 | }; | 220 | }; |
318 | 221 | ||
319 | static struct miscdevice s3c2410wdt_miscdev = { | 222 | static struct watchdog_device s3c2410_wdd = { |
320 | .minor = WATCHDOG_MINOR, | 223 | .info = &s3c2410_wdt_ident, |
321 | .name = "watchdog", | 224 | .ops = &s3c2410wdt_ops, |
322 | .fops = &s3c2410wdt_fops, | ||
323 | }; | 225 | }; |
324 | 226 | ||
325 | /* interrupt handler code */ | 227 | /* interrupt handler code */ |
@@ -328,7 +230,7 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) | |||
328 | { | 230 | { |
329 | dev_info(wdt_dev, "watchdog timer expired (irq)\n"); | 231 | dev_info(wdt_dev, "watchdog timer expired (irq)\n"); |
330 | 232 | ||
331 | s3c2410wdt_keepalive(); | 233 | s3c2410wdt_keepalive(&s3c2410_wdd); |
332 | return IRQ_HANDLED; | 234 | return IRQ_HANDLED; |
333 | } | 235 | } |
334 | 236 | ||
@@ -349,14 +251,14 @@ static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, | |||
349 | * the watchdog is running. | 251 | * the watchdog is running. |
350 | */ | 252 | */ |
351 | 253 | ||
352 | s3c2410wdt_keepalive(); | 254 | s3c2410wdt_keepalive(&s3c2410_wdd); |
353 | } else if (val == CPUFREQ_POSTCHANGE) { | 255 | } else if (val == CPUFREQ_POSTCHANGE) { |
354 | s3c2410wdt_stop(); | 256 | s3c2410wdt_stop(&s3c2410_wdd); |
355 | 257 | ||
356 | ret = s3c2410wdt_set_heartbeat(tmr_margin); | 258 | ret = s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout); |
357 | 259 | ||
358 | if (ret >= 0) | 260 | if (ret >= 0) |
359 | s3c2410wdt_start(); | 261 | s3c2410wdt_start(&s3c2410_wdd); |
360 | else | 262 | else |
361 | goto err; | 263 | goto err; |
362 | } | 264 | } |
@@ -365,7 +267,8 @@ done: | |||
365 | return 0; | 267 | return 0; |
366 | 268 | ||
367 | err: | 269 | err: |
368 | dev_err(wdt_dev, "cannot set new value for timeout %d\n", tmr_margin); | 270 | dev_err(wdt_dev, "cannot set new value for timeout %d\n", |
271 | s3c2410_wdd.timeout); | ||
369 | return ret; | 272 | return ret; |
370 | } | 273 | } |
371 | 274 | ||
@@ -396,10 +299,6 @@ static inline void s3c2410wdt_cpufreq_deregister(void) | |||
396 | } | 299 | } |
397 | #endif | 300 | #endif |
398 | 301 | ||
399 | |||
400 | |||
401 | /* device interface */ | ||
402 | |||
403 | static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | 302 | static int __devinit s3c2410wdt_probe(struct platform_device *pdev) |
404 | { | 303 | { |
405 | struct device *dev; | 304 | struct device *dev; |
@@ -466,8 +365,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
466 | /* see if we can actually set the requested timer margin, and if | 365 | /* see if we can actually set the requested timer margin, and if |
467 | * not, try the default value */ | 366 | * not, try the default value */ |
468 | 367 | ||
469 | if (s3c2410wdt_set_heartbeat(tmr_margin)) { | 368 | if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, tmr_margin)) { |
470 | started = s3c2410wdt_set_heartbeat( | 369 | started = s3c2410wdt_set_heartbeat(&s3c2410_wdd, |
471 | CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); | 370 | CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); |
472 | 371 | ||
473 | if (started == 0) | 372 | if (started == 0) |
@@ -479,22 +378,21 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
479 | "cannot start\n"); | 378 | "cannot start\n"); |
480 | } | 379 | } |
481 | 380 | ||
482 | ret = misc_register(&s3c2410wdt_miscdev); | 381 | ret = watchdog_register_device(&s3c2410_wdd); |
483 | if (ret) { | 382 | if (ret) { |
484 | dev_err(dev, "cannot register miscdev on minor=%d (%d)\n", | 383 | dev_err(dev, "cannot register watchdog (%d)\n", ret); |
485 | WATCHDOG_MINOR, ret); | ||
486 | goto err_cpufreq; | 384 | goto err_cpufreq; |
487 | } | 385 | } |
488 | 386 | ||
489 | if (tmr_atboot && started == 0) { | 387 | if (tmr_atboot && started == 0) { |
490 | dev_info(dev, "starting watchdog timer\n"); | 388 | dev_info(dev, "starting watchdog timer\n"); |
491 | s3c2410wdt_start(); | 389 | s3c2410wdt_start(&s3c2410_wdd); |
492 | } else if (!tmr_atboot) { | 390 | } else if (!tmr_atboot) { |
493 | /* if we're not enabling the watchdog, then ensure it is | 391 | /* if we're not enabling the watchdog, then ensure it is |
494 | * disabled if it has been left running from the bootloader | 392 | * disabled if it has been left running from the bootloader |
495 | * or other source */ | 393 | * or other source */ |
496 | 394 | ||
497 | s3c2410wdt_stop(); | 395 | s3c2410wdt_stop(&s3c2410_wdd); |
498 | } | 396 | } |
499 | 397 | ||
500 | /* print out a statement of readiness */ | 398 | /* print out a statement of readiness */ |
@@ -503,8 +401,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
503 | 401 | ||
504 | dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n", | 402 | dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n", |
505 | (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in", | 403 | (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in", |
506 | (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis", | 404 | (wtcon & S3C2410_WTCON_RSTEN) ? "en" : "dis", |
507 | (wtcon & S3C2410_WTCON_INTEN) ? "" : "en"); | 405 | (wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis"); |
508 | 406 | ||
509 | return 0; | 407 | return 0; |
510 | 408 | ||
@@ -530,7 +428,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
530 | 428 | ||
531 | static int __devexit s3c2410wdt_remove(struct platform_device *dev) | 429 | static int __devexit s3c2410wdt_remove(struct platform_device *dev) |
532 | { | 430 | { |
533 | misc_deregister(&s3c2410wdt_miscdev); | 431 | watchdog_unregister_device(&s3c2410_wdd); |
534 | 432 | ||
535 | s3c2410wdt_cpufreq_deregister(); | 433 | s3c2410wdt_cpufreq_deregister(); |
536 | 434 | ||
@@ -550,7 +448,7 @@ static int __devexit s3c2410wdt_remove(struct platform_device *dev) | |||
550 | 448 | ||
551 | static void s3c2410wdt_shutdown(struct platform_device *dev) | 449 | static void s3c2410wdt_shutdown(struct platform_device *dev) |
552 | { | 450 | { |
553 | s3c2410wdt_stop(); | 451 | s3c2410wdt_stop(&s3c2410_wdd); |
554 | } | 452 | } |
555 | 453 | ||
556 | #ifdef CONFIG_PM | 454 | #ifdef CONFIG_PM |
@@ -565,7 +463,7 @@ static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state) | |||
565 | wtdat_save = readl(wdt_base + S3C2410_WTDAT); | 463 | wtdat_save = readl(wdt_base + S3C2410_WTDAT); |
566 | 464 | ||
567 | /* Note that WTCNT doesn't need to be saved. */ | 465 | /* Note that WTCNT doesn't need to be saved. */ |
568 | s3c2410wdt_stop(); | 466 | s3c2410wdt_stop(&s3c2410_wdd); |
569 | 467 | ||
570 | return 0; | 468 | return 0; |
571 | } | 469 | } |
diff --git a/drivers/watchdog/sb_wdog.c b/drivers/watchdog/sb_wdog.c index f31493e65b38..b01a30e5a663 100644 --- a/drivers/watchdog/sb_wdog.c +++ b/drivers/watchdog/sb_wdog.c | |||
@@ -300,7 +300,7 @@ static int __init sbwdog_init(void) | |||
300 | * get the resources | 300 | * get the resources |
301 | */ | 301 | */ |
302 | 302 | ||
303 | ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, | 303 | ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED, |
304 | ident.identity, (void *)user_dog); | 304 | ident.identity, (void *)user_dog); |
305 | if (ret) { | 305 | if (ret) { |
306 | printk(KERN_ERR "%s: failed to request irq 1 - %d\n", | 306 | printk(KERN_ERR "%s: failed to request irq 1 - %d\n", |
@@ -350,7 +350,7 @@ void platform_wd_setup(void) | |||
350 | { | 350 | { |
351 | int ret; | 351 | int ret; |
352 | 352 | ||
353 | ret = request_irq(1, sbwdog_interrupt, IRQF_DISABLED | IRQF_SHARED, | 353 | ret = request_irq(1, sbwdog_interrupt, IRQF_SHARED, |
354 | "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0)); | 354 | "Kernel Watchdog", IOADDR(A_SCD_WDOG_CFG_0)); |
355 | if (ret) { | 355 | if (ret) { |
356 | printk(KERN_CRIT | 356 | printk(KERN_CRIT |
diff --git a/drivers/watchdog/sbc_epx_c3.c b/drivers/watchdog/sbc_epx_c3.c index 3066a5127ca8..eaca366b7234 100644 --- a/drivers/watchdog/sbc_epx_c3.c +++ b/drivers/watchdog/sbc_epx_c3.c | |||
@@ -173,7 +173,7 @@ static struct notifier_block epx_c3_notifier = { | |||
173 | .notifier_call = epx_c3_notify_sys, | 173 | .notifier_call = epx_c3_notify_sys, |
174 | }; | 174 | }; |
175 | 175 | ||
176 | static const char banner[] __initdata = KERN_INFO PFX | 176 | static const char banner[] __initconst = KERN_INFO PFX |
177 | "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n"; | 177 | "Hardware Watchdog Timer for Winsystems EPX-C3 SBC: 0.1\n"; |
178 | 178 | ||
179 | static int __init watchdog_init(void) | 179 | static int __init watchdog_init(void) |
diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c index 52b63f2f0dac..b2840409ebc7 100644 --- a/drivers/watchdog/sc520_wdt.c +++ b/drivers/watchdog/sc520_wdt.c | |||
@@ -398,7 +398,7 @@ static int __init sc520_wdt_init(void) | |||
398 | WATCHDOG_TIMEOUT); | 398 | WATCHDOG_TIMEOUT); |
399 | } | 399 | } |
400 | 400 | ||
401 | wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2); | 401 | wdtmrctl = ioremap(MMCR_BASE + OFFS_WDTMRCTL, 2); |
402 | if (!wdtmrctl) { | 402 | if (!wdtmrctl) { |
403 | printk(KERN_ERR PFX "Unable to remap memory\n"); | 403 | printk(KERN_ERR PFX "Unable to remap memory\n"); |
404 | rc = -ENOMEM; | 404 | rc = -ENOMEM; |
diff --git a/drivers/watchdog/smsc37b787_wdt.c b/drivers/watchdog/smsc37b787_wdt.c index e97b0499bd0d..97b8184614ae 100644 --- a/drivers/watchdog/smsc37b787_wdt.c +++ b/drivers/watchdog/smsc37b787_wdt.c | |||
@@ -40,7 +40,7 @@ | |||
40 | * mknod /dev/watchdog c 10 130 | 40 | * mknod /dev/watchdog c 10 130 |
41 | * | 41 | * |
42 | * For an example userspace keep-alive daemon, see: | 42 | * For an example userspace keep-alive daemon, see: |
43 | * Documentation/watchdog/watchdog.txt | 43 | * Documentation/watchdog/wdt.txt |
44 | */ | 44 | */ |
45 | 45 | ||
46 | #include <linux/module.h> | 46 | #include <linux/module.h> |
diff --git a/drivers/watchdog/stmp3xxx_wdt.c b/drivers/watchdog/stmp3xxx_wdt.c index b3421fd2cda8..ac2346a452e5 100644 --- a/drivers/watchdog/stmp3xxx_wdt.c +++ b/drivers/watchdog/stmp3xxx_wdt.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
16 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
17 | #include <linux/module.h> | ||
17 | 18 | ||
18 | #include <mach/platform.h> | 19 | #include <mach/platform.h> |
19 | #include <mach/regs-rtc.h> | 20 | #include <mach/regs-rtc.h> |
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index e5c91d4404ed..dd5d67548758 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c | |||
@@ -142,7 +142,7 @@ static void w83627hf_init(void) | |||
142 | w83627hf_unselect_wd_register(); | 142 | w83627hf_unselect_wd_register(); |
143 | } | 143 | } |
144 | 144 | ||
145 | static void wdt_ctrl(int timeout) | 145 | static void wdt_set_time(int timeout) |
146 | { | 146 | { |
147 | spin_lock(&io_lock); | 147 | spin_lock(&io_lock); |
148 | 148 | ||
@@ -158,13 +158,13 @@ static void wdt_ctrl(int timeout) | |||
158 | 158 | ||
159 | static int wdt_ping(void) | 159 | static int wdt_ping(void) |
160 | { | 160 | { |
161 | wdt_ctrl(timeout); | 161 | wdt_set_time(timeout); |
162 | return 0; | 162 | return 0; |
163 | } | 163 | } |
164 | 164 | ||
165 | static int wdt_disable(void) | 165 | static int wdt_disable(void) |
166 | { | 166 | { |
167 | wdt_ctrl(0); | 167 | wdt_set_time(0); |
168 | return 0; | 168 | return 0; |
169 | } | 169 | } |
170 | 170 | ||
@@ -176,6 +176,24 @@ static int wdt_set_heartbeat(int t) | |||
176 | return 0; | 176 | return 0; |
177 | } | 177 | } |
178 | 178 | ||
179 | static int wdt_get_time(void) | ||
180 | { | ||
181 | int timeleft; | ||
182 | |||
183 | spin_lock(&io_lock); | ||
184 | |||
185 | w83627hf_select_wd_register(); | ||
186 | |||
187 | outb_p(0xF6, WDT_EFER); /* Select CRF6 */ | ||
188 | timeleft = inb_p(WDT_EFDR); /* Read Timeout counter to CRF6 */ | ||
189 | |||
190 | w83627hf_unselect_wd_register(); | ||
191 | |||
192 | spin_unlock(&io_lock); | ||
193 | |||
194 | return timeleft; | ||
195 | } | ||
196 | |||
179 | static ssize_t wdt_write(struct file *file, const char __user *buf, | 197 | static ssize_t wdt_write(struct file *file, const char __user *buf, |
180 | size_t count, loff_t *ppos) | 198 | size_t count, loff_t *ppos) |
181 | { | 199 | { |
@@ -202,7 +220,7 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
202 | { | 220 | { |
203 | void __user *argp = (void __user *)arg; | 221 | void __user *argp = (void __user *)arg; |
204 | int __user *p = argp; | 222 | int __user *p = argp; |
205 | int new_timeout; | 223 | int timeval; |
206 | static const struct watchdog_info ident = { | 224 | static const struct watchdog_info ident = { |
207 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | | 225 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
208 | WDIOF_MAGICCLOSE, | 226 | WDIOF_MAGICCLOSE, |
@@ -238,14 +256,17 @@ static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
238 | wdt_ping(); | 256 | wdt_ping(); |
239 | break; | 257 | break; |
240 | case WDIOC_SETTIMEOUT: | 258 | case WDIOC_SETTIMEOUT: |
241 | if (get_user(new_timeout, p)) | 259 | if (get_user(timeval, p)) |
242 | return -EFAULT; | 260 | return -EFAULT; |
243 | if (wdt_set_heartbeat(new_timeout)) | 261 | if (wdt_set_heartbeat(timeval)) |
244 | return -EINVAL; | 262 | return -EINVAL; |
245 | wdt_ping(); | 263 | wdt_ping(); |
246 | /* Fall */ | 264 | /* Fall */ |
247 | case WDIOC_GETTIMEOUT: | 265 | case WDIOC_GETTIMEOUT: |
248 | return put_user(timeout, p); | 266 | return put_user(timeout, p); |
267 | case WDIOC_GETTIMELEFT: | ||
268 | timeval = wdt_get_time(); | ||
269 | return put_user(timeval, p); | ||
249 | default: | 270 | default: |
250 | return -ENOTTY; | 271 | return -ENOTTY; |
251 | } | 272 | } |
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index d33520d0b4c9..1199da0f98cf 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c | |||
@@ -59,7 +59,7 @@ static struct watchdog_device *wdd; | |||
59 | 59 | ||
60 | static int watchdog_ping(struct watchdog_device *wddev) | 60 | static int watchdog_ping(struct watchdog_device *wddev) |
61 | { | 61 | { |
62 | if (test_bit(WDOG_ACTIVE, &wdd->status)) { | 62 | if (test_bit(WDOG_ACTIVE, &wddev->status)) { |
63 | if (wddev->ops->ping) | 63 | if (wddev->ops->ping) |
64 | return wddev->ops->ping(wddev); /* ping the watchdog */ | 64 | return wddev->ops->ping(wddev); /* ping the watchdog */ |
65 | else | 65 | else |
@@ -81,12 +81,12 @@ static int watchdog_start(struct watchdog_device *wddev) | |||
81 | { | 81 | { |
82 | int err; | 82 | int err; |
83 | 83 | ||
84 | if (!test_bit(WDOG_ACTIVE, &wdd->status)) { | 84 | if (!test_bit(WDOG_ACTIVE, &wddev->status)) { |
85 | err = wddev->ops->start(wddev); | 85 | err = wddev->ops->start(wddev); |
86 | if (err < 0) | 86 | if (err < 0) |
87 | return err; | 87 | return err; |
88 | 88 | ||
89 | set_bit(WDOG_ACTIVE, &wdd->status); | 89 | set_bit(WDOG_ACTIVE, &wddev->status); |
90 | } | 90 | } |
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
@@ -105,18 +105,18 @@ static int watchdog_stop(struct watchdog_device *wddev) | |||
105 | { | 105 | { |
106 | int err = -EBUSY; | 106 | int err = -EBUSY; |
107 | 107 | ||
108 | if (test_bit(WDOG_NO_WAY_OUT, &wdd->status)) { | 108 | if (test_bit(WDOG_NO_WAY_OUT, &wddev->status)) { |
109 | pr_info("%s: nowayout prevents watchdog to be stopped!\n", | 109 | pr_info("%s: nowayout prevents watchdog to be stopped!\n", |
110 | wdd->info->identity); | 110 | wddev->info->identity); |
111 | return err; | 111 | return err; |
112 | } | 112 | } |
113 | 113 | ||
114 | if (test_bit(WDOG_ACTIVE, &wdd->status)) { | 114 | if (test_bit(WDOG_ACTIVE, &wddev->status)) { |
115 | err = wddev->ops->stop(wddev); | 115 | err = wddev->ops->stop(wddev); |
116 | if (err < 0) | 116 | if (err < 0) |
117 | return err; | 117 | return err; |
118 | 118 | ||
119 | clear_bit(WDOG_ACTIVE, &wdd->status); | 119 | clear_bit(WDOG_ACTIVE, &wddev->status); |
120 | } | 120 | } |
121 | return 0; | 121 | return 0; |
122 | } | 122 | } |
diff --git a/drivers/watchdog/wdt.c b/drivers/watchdog/wdt.c index bb03e151a1d0..d2ef002be96b 100644 --- a/drivers/watchdog/wdt.c +++ b/drivers/watchdog/wdt.c | |||
@@ -612,7 +612,7 @@ static int __init wdt_init(void) | |||
612 | goto out; | 612 | goto out; |
613 | } | 613 | } |
614 | 614 | ||
615 | ret = request_irq(irq, wdt_interrupt, IRQF_DISABLED, "wdt501p", NULL); | 615 | ret = request_irq(irq, wdt_interrupt, 0, "wdt501p", NULL); |
616 | if (ret) { | 616 | if (ret) { |
617 | printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); | 617 | printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); |
618 | goto outreg; | 618 | goto outreg; |
diff --git a/drivers/watchdog/wdt_pci.c b/drivers/watchdog/wdt_pci.c index 172dad6c7693..e0fc3baa9197 100644 --- a/drivers/watchdog/wdt_pci.c +++ b/drivers/watchdog/wdt_pci.c | |||
@@ -643,7 +643,7 @@ static int __devinit wdtpci_init_one(struct pci_dev *dev, | |||
643 | irq = dev->irq; | 643 | irq = dev->irq; |
644 | io = pci_resource_start(dev, 2); | 644 | io = pci_resource_start(dev, 2); |
645 | 645 | ||
646 | if (request_irq(irq, wdtpci_interrupt, IRQF_DISABLED | IRQF_SHARED, | 646 | if (request_irq(irq, wdtpci_interrupt, IRQF_SHARED, |
647 | "wdt_pci", &wdtpci_miscdev)) { | 647 | "wdt_pci", &wdtpci_miscdev)) { |
648 | printk(KERN_ERR PFX "IRQ %d is not free\n", irq); | 648 | printk(KERN_ERR PFX "IRQ %d is not free\n", irq); |
649 | goto out_reg; | 649 | goto out_reg; |
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 871caea4e1c6..e789a47db41f 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c | |||
@@ -12,8 +12,7 @@ | |||
12 | #include <linux/moduleparam.h> | 12 | #include <linux/moduleparam.h> |
13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/fs.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/miscdevice.h> | ||
17 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
18 | #include <linux/watchdog.h> | 17 | #include <linux/watchdog.h> |
19 | #include <linux/uaccess.h> | 18 | #include <linux/uaccess.h> |
@@ -29,19 +28,19 @@ MODULE_PARM_DESC(nowayout, | |||
29 | "Watchdog cannot be stopped once started (default=" | 28 | "Watchdog cannot be stopped once started (default=" |
30 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 29 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
31 | 30 | ||
32 | static unsigned long wm831x_wdt_users; | 31 | struct wm831x_wdt_drvdata { |
33 | static struct miscdevice wm831x_wdt_miscdev; | 32 | struct watchdog_device wdt; |
34 | static int wm831x_wdt_expect_close; | 33 | struct wm831x *wm831x; |
35 | static DEFINE_MUTEX(wdt_mutex); | 34 | struct mutex lock; |
36 | static struct wm831x *wm831x; | 35 | int update_gpio; |
37 | static unsigned int update_gpio; | 36 | int update_state; |
38 | static unsigned int update_state; | 37 | }; |
39 | 38 | ||
40 | /* We can't use the sub-second values here but they're included | 39 | /* We can't use the sub-second values here but they're included |
41 | * for completeness. */ | 40 | * for completeness. */ |
42 | static struct { | 41 | static struct { |
43 | int time; /* Seconds */ | 42 | unsigned int time; /* Seconds */ |
44 | u16 val; /* WDOG_TO value */ | 43 | u16 val; /* WDOG_TO value */ |
45 | } wm831x_wdt_cfgs[] = { | 44 | } wm831x_wdt_cfgs[] = { |
46 | { 1, 2 }, | 45 | { 1, 2 }, |
47 | { 2, 3 }, | 46 | { 2, 3 }, |
@@ -52,32 +51,13 @@ static struct { | |||
52 | { 33, 7 }, /* Actually 32.768s so include both, others round down */ | 51 | { 33, 7 }, /* Actually 32.768s so include both, others round down */ |
53 | }; | 52 | }; |
54 | 53 | ||
55 | static int wm831x_wdt_set_timeout(struct wm831x *wm831x, u16 value) | 54 | static int wm831x_wdt_start(struct watchdog_device *wdt_dev) |
56 | { | ||
57 | int ret; | ||
58 | |||
59 | mutex_lock(&wdt_mutex); | ||
60 | |||
61 | ret = wm831x_reg_unlock(wm831x); | ||
62 | if (ret == 0) { | ||
63 | ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, | ||
64 | WM831X_WDOG_TO_MASK, value); | ||
65 | wm831x_reg_lock(wm831x); | ||
66 | } else { | ||
67 | dev_err(wm831x->dev, "Failed to unlock security key: %d\n", | ||
68 | ret); | ||
69 | } | ||
70 | |||
71 | mutex_unlock(&wdt_mutex); | ||
72 | |||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | static int wm831x_wdt_start(struct wm831x *wm831x) | ||
77 | { | 55 | { |
56 | struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); | ||
57 | struct wm831x *wm831x = driver_data->wm831x; | ||
78 | int ret; | 58 | int ret; |
79 | 59 | ||
80 | mutex_lock(&wdt_mutex); | 60 | mutex_lock(&driver_data->lock); |
81 | 61 | ||
82 | ret = wm831x_reg_unlock(wm831x); | 62 | ret = wm831x_reg_unlock(wm831x); |
83 | if (ret == 0) { | 63 | if (ret == 0) { |
@@ -89,16 +69,18 @@ static int wm831x_wdt_start(struct wm831x *wm831x) | |||
89 | ret); | 69 | ret); |
90 | } | 70 | } |
91 | 71 | ||
92 | mutex_unlock(&wdt_mutex); | 72 | mutex_unlock(&driver_data->lock); |
93 | 73 | ||
94 | return ret; | 74 | return ret; |
95 | } | 75 | } |
96 | 76 | ||
97 | static int wm831x_wdt_stop(struct wm831x *wm831x) | 77 | static int wm831x_wdt_stop(struct watchdog_device *wdt_dev) |
98 | { | 78 | { |
79 | struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); | ||
80 | struct wm831x *wm831x = driver_data->wm831x; | ||
99 | int ret; | 81 | int ret; |
100 | 82 | ||
101 | mutex_lock(&wdt_mutex); | 83 | mutex_lock(&driver_data->lock); |
102 | 84 | ||
103 | ret = wm831x_reg_unlock(wm831x); | 85 | ret = wm831x_reg_unlock(wm831x); |
104 | if (ret == 0) { | 86 | if (ret == 0) { |
@@ -110,26 +92,28 @@ static int wm831x_wdt_stop(struct wm831x *wm831x) | |||
110 | ret); | 92 | ret); |
111 | } | 93 | } |
112 | 94 | ||
113 | mutex_unlock(&wdt_mutex); | 95 | mutex_unlock(&driver_data->lock); |
114 | 96 | ||
115 | return ret; | 97 | return ret; |
116 | } | 98 | } |
117 | 99 | ||
118 | static int wm831x_wdt_kick(struct wm831x *wm831x) | 100 | static int wm831x_wdt_ping(struct watchdog_device *wdt_dev) |
119 | { | 101 | { |
102 | struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); | ||
103 | struct wm831x *wm831x = driver_data->wm831x; | ||
120 | int ret; | 104 | int ret; |
121 | u16 reg; | 105 | u16 reg; |
122 | 106 | ||
123 | mutex_lock(&wdt_mutex); | 107 | mutex_lock(&driver_data->lock); |
124 | 108 | ||
125 | if (update_gpio) { | 109 | if (driver_data->update_gpio) { |
126 | gpio_set_value_cansleep(update_gpio, update_state); | 110 | gpio_set_value_cansleep(driver_data->update_gpio, |
127 | update_state = !update_state; | 111 | driver_data->update_state); |
112 | driver_data->update_state = !driver_data->update_state; | ||
128 | ret = 0; | 113 | ret = 0; |
129 | goto out; | 114 | goto out; |
130 | } | 115 | } |
131 | 116 | ||
132 | |||
133 | reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); | 117 | reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); |
134 | 118 | ||
135 | if (!(reg & WM831X_WDOG_RST_SRC)) { | 119 | if (!(reg & WM831X_WDOG_RST_SRC)) { |
@@ -150,182 +134,59 @@ static int wm831x_wdt_kick(struct wm831x *wm831x) | |||
150 | } | 134 | } |
151 | 135 | ||
152 | out: | 136 | out: |
153 | mutex_unlock(&wdt_mutex); | 137 | mutex_unlock(&driver_data->lock); |
154 | 138 | ||
155 | return ret; | 139 | return ret; |
156 | } | 140 | } |
157 | 141 | ||
158 | static int wm831x_wdt_open(struct inode *inode, struct file *file) | 142 | static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev, |
143 | unsigned int timeout) | ||
159 | { | 144 | { |
160 | int ret; | 145 | struct wm831x_wdt_drvdata *driver_data = watchdog_get_drvdata(wdt_dev); |
161 | 146 | struct wm831x *wm831x = driver_data->wm831x; | |
162 | if (!wm831x) | 147 | int ret, i; |
163 | return -ENODEV; | ||
164 | |||
165 | if (test_and_set_bit(0, &wm831x_wdt_users)) | ||
166 | return -EBUSY; | ||
167 | 148 | ||
168 | ret = wm831x_wdt_start(wm831x); | 149 | for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) |
169 | if (ret != 0) | 150 | if (wm831x_wdt_cfgs[i].time == timeout) |
170 | return ret; | 151 | break; |
171 | 152 | if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) | |
172 | return nonseekable_open(inode, file); | 153 | return -EINVAL; |
173 | } | ||
174 | 154 | ||
175 | static int wm831x_wdt_release(struct inode *inode, struct file *file) | 155 | ret = wm831x_reg_unlock(wm831x); |
176 | { | 156 | if (ret == 0) { |
177 | if (wm831x_wdt_expect_close) | 157 | ret = wm831x_set_bits(wm831x, WM831X_WATCHDOG, |
178 | wm831x_wdt_stop(wm831x); | 158 | WM831X_WDOG_TO_MASK, |
179 | else { | 159 | wm831x_wdt_cfgs[i].val); |
180 | dev_warn(wm831x->dev, "Watchdog device closed uncleanly\n"); | 160 | wm831x_reg_lock(wm831x); |
181 | wm831x_wdt_kick(wm831x); | 161 | } else { |
162 | dev_err(wm831x->dev, "Failed to unlock security key: %d\n", | ||
163 | ret); | ||
182 | } | 164 | } |
183 | 165 | ||
184 | clear_bit(0, &wm831x_wdt_users); | 166 | return ret; |
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static ssize_t wm831x_wdt_write(struct file *file, | ||
190 | const char __user *data, size_t count, | ||
191 | loff_t *ppos) | ||
192 | { | ||
193 | size_t i; | ||
194 | |||
195 | if (count) { | ||
196 | wm831x_wdt_kick(wm831x); | ||
197 | |||
198 | if (!nowayout) { | ||
199 | /* In case it was set long ago */ | ||
200 | wm831x_wdt_expect_close = 0; | ||
201 | |||
202 | /* scan to see whether or not we got the magic | ||
203 | character */ | ||
204 | for (i = 0; i != count; i++) { | ||
205 | char c; | ||
206 | if (get_user(c, data + i)) | ||
207 | return -EFAULT; | ||
208 | if (c == 'V') | ||
209 | wm831x_wdt_expect_close = 42; | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | return count; | ||
214 | } | 167 | } |
215 | 168 | ||
216 | static const struct watchdog_info ident = { | 169 | static const struct watchdog_info wm831x_wdt_info = { |
217 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | 170 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, |
218 | .identity = "WM831x Watchdog", | 171 | .identity = "WM831x Watchdog", |
219 | }; | 172 | }; |
220 | 173 | ||
221 | static long wm831x_wdt_ioctl(struct file *file, unsigned int cmd, | 174 | static const struct watchdog_ops wm831x_wdt_ops = { |
222 | unsigned long arg) | ||
223 | { | ||
224 | int ret = -ENOTTY, time, i; | ||
225 | void __user *argp = (void __user *)arg; | ||
226 | int __user *p = argp; | ||
227 | u16 reg; | ||
228 | |||
229 | switch (cmd) { | ||
230 | case WDIOC_GETSUPPORT: | ||
231 | ret = copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; | ||
232 | break; | ||
233 | |||
234 | case WDIOC_GETSTATUS: | ||
235 | case WDIOC_GETBOOTSTATUS: | ||
236 | ret = put_user(0, p); | ||
237 | break; | ||
238 | |||
239 | case WDIOC_SETOPTIONS: | ||
240 | { | ||
241 | int options; | ||
242 | |||
243 | if (get_user(options, p)) | ||
244 | return -EFAULT; | ||
245 | |||
246 | ret = -EINVAL; | ||
247 | |||
248 | /* Setting both simultaneously means at least one must fail */ | ||
249 | if (options == WDIOS_DISABLECARD) | ||
250 | ret = wm831x_wdt_start(wm831x); | ||
251 | |||
252 | if (options == WDIOS_ENABLECARD) | ||
253 | ret = wm831x_wdt_stop(wm831x); | ||
254 | break; | ||
255 | } | ||
256 | |||
257 | case WDIOC_KEEPALIVE: | ||
258 | ret = wm831x_wdt_kick(wm831x); | ||
259 | break; | ||
260 | |||
261 | case WDIOC_SETTIMEOUT: | ||
262 | ret = get_user(time, p); | ||
263 | if (ret) | ||
264 | break; | ||
265 | |||
266 | if (time == 0) { | ||
267 | if (nowayout) | ||
268 | ret = -EINVAL; | ||
269 | else | ||
270 | wm831x_wdt_stop(wm831x); | ||
271 | break; | ||
272 | } | ||
273 | |||
274 | for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) | ||
275 | if (wm831x_wdt_cfgs[i].time == time) | ||
276 | break; | ||
277 | if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) | ||
278 | ret = -EINVAL; | ||
279 | else | ||
280 | ret = wm831x_wdt_set_timeout(wm831x, | ||
281 | wm831x_wdt_cfgs[i].val); | ||
282 | break; | ||
283 | |||
284 | case WDIOC_GETTIMEOUT: | ||
285 | reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); | ||
286 | reg &= WM831X_WDOG_TO_MASK; | ||
287 | for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) | ||
288 | if (wm831x_wdt_cfgs[i].val == reg) | ||
289 | break; | ||
290 | if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) { | ||
291 | dev_warn(wm831x->dev, | ||
292 | "Unknown watchdog configuration: %x\n", reg); | ||
293 | ret = -EINVAL; | ||
294 | } else | ||
295 | ret = put_user(wm831x_wdt_cfgs[i].time, p); | ||
296 | |||
297 | } | ||
298 | |||
299 | return ret; | ||
300 | } | ||
301 | |||
302 | static const struct file_operations wm831x_wdt_fops = { | ||
303 | .owner = THIS_MODULE, | 175 | .owner = THIS_MODULE, |
304 | .llseek = no_llseek, | 176 | .start = wm831x_wdt_start, |
305 | .write = wm831x_wdt_write, | 177 | .stop = wm831x_wdt_stop, |
306 | .unlocked_ioctl = wm831x_wdt_ioctl, | 178 | .ping = wm831x_wdt_ping, |
307 | .open = wm831x_wdt_open, | 179 | .set_timeout = wm831x_wdt_set_timeout, |
308 | .release = wm831x_wdt_release, | ||
309 | }; | ||
310 | |||
311 | static struct miscdevice wm831x_wdt_miscdev = { | ||
312 | .minor = WATCHDOG_MINOR, | ||
313 | .name = "watchdog", | ||
314 | .fops = &wm831x_wdt_fops, | ||
315 | }; | 180 | }; |
316 | 181 | ||
317 | static int __devinit wm831x_wdt_probe(struct platform_device *pdev) | 182 | static int __devinit wm831x_wdt_probe(struct platform_device *pdev) |
318 | { | 183 | { |
184 | struct wm831x *wm831x = dev_get_drvdata(pdev->dev.parent); | ||
319 | struct wm831x_pdata *chip_pdata; | 185 | struct wm831x_pdata *chip_pdata; |
320 | struct wm831x_watchdog_pdata *pdata; | 186 | struct wm831x_watchdog_pdata *pdata; |
321 | int reg, ret; | 187 | struct wm831x_wdt_drvdata *driver_data; |
322 | 188 | struct watchdog_device *wm831x_wdt; | |
323 | if (wm831x) { | 189 | int reg, ret, i; |
324 | dev_err(&pdev->dev, "wm831x watchdog already registered\n"); | ||
325 | return -EBUSY; | ||
326 | } | ||
327 | |||
328 | wm831x = dev_get_drvdata(pdev->dev.parent); | ||
329 | 190 | ||
330 | ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG); | 191 | ret = wm831x_reg_read(wm831x, WM831X_WATCHDOG); |
331 | if (ret < 0) { | 192 | if (ret < 0) { |
@@ -338,6 +199,36 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) | |||
338 | if (reg & WM831X_WDOG_DEBUG) | 199 | if (reg & WM831X_WDOG_DEBUG) |
339 | dev_warn(wm831x->dev, "Watchdog is paused\n"); | 200 | dev_warn(wm831x->dev, "Watchdog is paused\n"); |
340 | 201 | ||
202 | driver_data = kzalloc(sizeof(*driver_data), GFP_KERNEL); | ||
203 | if (!driver_data) { | ||
204 | dev_err(wm831x->dev, "Unable to alloacate watchdog device\n"); | ||
205 | ret = -ENOMEM; | ||
206 | goto err; | ||
207 | } | ||
208 | |||
209 | mutex_init(&driver_data->lock); | ||
210 | driver_data->wm831x = wm831x; | ||
211 | |||
212 | wm831x_wdt = &driver_data->wdt; | ||
213 | |||
214 | wm831x_wdt->info = &wm831x_wdt_info; | ||
215 | wm831x_wdt->ops = &wm831x_wdt_ops; | ||
216 | watchdog_set_drvdata(wm831x_wdt, driver_data); | ||
217 | |||
218 | if (nowayout) | ||
219 | wm831x_wdt->status |= WDOG_NO_WAY_OUT; | ||
220 | |||
221 | reg = wm831x_reg_read(wm831x, WM831X_WATCHDOG); | ||
222 | reg &= WM831X_WDOG_TO_MASK; | ||
223 | for (i = 0; i < ARRAY_SIZE(wm831x_wdt_cfgs); i++) | ||
224 | if (wm831x_wdt_cfgs[i].val == reg) | ||
225 | break; | ||
226 | if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) | ||
227 | dev_warn(wm831x->dev, | ||
228 | "Unknown watchdog timeout: %x\n", reg); | ||
229 | else | ||
230 | wm831x_wdt->timeout = wm831x_wdt_cfgs[i].time; | ||
231 | |||
341 | /* Apply any configuration */ | 232 | /* Apply any configuration */ |
342 | if (pdev->dev.parent->platform_data) { | 233 | if (pdev->dev.parent->platform_data) { |
343 | chip_pdata = pdev->dev.parent->platform_data; | 234 | chip_pdata = pdev->dev.parent->platform_data; |
@@ -361,7 +252,7 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) | |||
361 | dev_err(wm831x->dev, | 252 | dev_err(wm831x->dev, |
362 | "Failed to request update GPIO: %d\n", | 253 | "Failed to request update GPIO: %d\n", |
363 | ret); | 254 | ret); |
364 | goto err; | 255 | goto err_alloc; |
365 | } | 256 | } |
366 | 257 | ||
367 | ret = gpio_direction_output(pdata->update_gpio, 0); | 258 | ret = gpio_direction_output(pdata->update_gpio, 0); |
@@ -372,7 +263,7 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) | |||
372 | goto err_gpio; | 263 | goto err_gpio; |
373 | } | 264 | } |
374 | 265 | ||
375 | update_gpio = pdata->update_gpio; | 266 | driver_data->update_gpio = pdata->update_gpio; |
376 | 267 | ||
377 | /* Make sure the watchdog takes hardware updates */ | 268 | /* Make sure the watchdog takes hardware updates */ |
378 | reg |= WM831X_WDOG_RST_SRC; | 269 | reg |= WM831X_WDOG_RST_SRC; |
@@ -389,33 +280,34 @@ static int __devinit wm831x_wdt_probe(struct platform_device *pdev) | |||
389 | } | 280 | } |
390 | } | 281 | } |
391 | 282 | ||
392 | wm831x_wdt_miscdev.parent = &pdev->dev; | 283 | ret = watchdog_register_device(&driver_data->wdt); |
393 | |||
394 | ret = misc_register(&wm831x_wdt_miscdev); | ||
395 | if (ret != 0) { | 284 | if (ret != 0) { |
396 | dev_err(wm831x->dev, "Failed to register miscdev: %d\n", ret); | 285 | dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n", |
286 | ret); | ||
397 | goto err_gpio; | 287 | goto err_gpio; |
398 | } | 288 | } |
399 | 289 | ||
290 | dev_set_drvdata(&pdev->dev, driver_data); | ||
291 | |||
400 | return 0; | 292 | return 0; |
401 | 293 | ||
402 | err_gpio: | 294 | err_gpio: |
403 | if (update_gpio) { | 295 | if (driver_data->update_gpio) |
404 | gpio_free(update_gpio); | 296 | gpio_free(driver_data->update_gpio); |
405 | update_gpio = 0; | 297 | err_alloc: |
406 | } | 298 | kfree(driver_data); |
407 | err: | 299 | err: |
408 | return ret; | 300 | return ret; |
409 | } | 301 | } |
410 | 302 | ||
411 | static int __devexit wm831x_wdt_remove(struct platform_device *pdev) | 303 | static int __devexit wm831x_wdt_remove(struct platform_device *pdev) |
412 | { | 304 | { |
413 | if (update_gpio) { | 305 | struct wm831x_wdt_drvdata *driver_data = dev_get_drvdata(&pdev->dev); |
414 | gpio_free(update_gpio); | 306 | |
415 | update_gpio = 0; | 307 | watchdog_unregister_device(&driver_data->wdt); |
416 | } | ||
417 | 308 | ||
418 | misc_deregister(&wm831x_wdt_miscdev); | 309 | if (driver_data->update_gpio) |
310 | gpio_free(driver_data->update_gpio); | ||
419 | 311 | ||
420 | return 0; | 312 | return 0; |
421 | } | 313 | } |