diff options
author | Wolfram Sang <w.sang@pengutronix.de> | 2011-09-26 09:40:14 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2011-11-05 16:25:20 -0400 |
commit | 25dc46e3837cd01dc1742eefb73d064f6336850f (patch) | |
tree | 8986b563b9385060f4134fe8ac19bb9d0719fe54 /drivers | |
parent | 74cd4c67392c1cee0499ba0977ec843252c7af28 (diff) |
watchdog: s3c2410: convert to use the watchdog framework
Make this driver a user of the watchdog framework and remove now
centrally handled parts. Tested on a mini2440.
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Acked-by: Kukjin Kim <kgene.kim@samsung.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/watchdog/Kconfig | 1 | ||||
-rw-r--r-- | drivers/watchdog/s3c2410_wdt.c | 176 |
2 files changed, 38 insertions, 139 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 64c6752ea2c6..40a36c50a5f4 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -170,6 +170,7 @@ config HAVE_S3C2410_WATCHDOG | |||
170 | config S3C2410_WATCHDOG | 170 | config S3C2410_WATCHDOG |
171 | tristate "S3C2410 Watchdog" | 171 | tristate "S3C2410 Watchdog" |
172 | depends on ARCH_S3C2410 || HAVE_S3C2410_WATCHDOG | 172 | depends on ARCH_S3C2410 || HAVE_S3C2410_WATCHDOG |
173 | select WATCHDOG_CORE | ||
173 | help | 174 | help |
174 | Watchdog timer block in the Samsung SoCs. This will reboot | 175 | Watchdog timer block in the Samsung SoCs. This will reboot |
175 | the system when the timer expires with the watchdog enabled. | 176 | the system when the timer expires with the watchdog enabled. |
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 30da88f47cd3..5de7e4fa5b8a 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 */ |
@@ -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 | } |