aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/s3c2410_wdt.c
diff options
context:
space:
mode:
authorWolfram Sang <w.sang@pengutronix.de>2011-09-26 09:40:14 -0400
committerWim Van Sebroeck <wim@iguana.be>2011-11-05 16:25:20 -0400
commit25dc46e3837cd01dc1742eefb73d064f6336850f (patch)
tree8986b563b9385060f4134fe8ac19bb9d0719fe54 /drivers/watchdog/s3c2410_wdt.c
parent74cd4c67392c1cee0499ba0977ec843252c7af28 (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/watchdog/s3c2410_wdt.c')
-rw-r--r--drivers/watchdog/s3c2410_wdt.c176
1 files changed, 37 insertions, 139 deletions
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)");
75MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); 75MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");
76 76
77static unsigned long open_lock;
78static struct device *wdt_dev; /* platform device attached to */ 77static struct device *wdt_dev; /* platform device attached to */
79static struct resource *wdt_mem; 78static struct resource *wdt_mem;
80static struct resource *wdt_irq; 79static struct resource *wdt_irq;
81static struct clk *wdt_clock; 80static struct clk *wdt_clock;
82static void __iomem *wdt_base; 81static void __iomem *wdt_base;
83static unsigned int wdt_count; 82static unsigned int wdt_count;
84static char expect_close;
85static DEFINE_SPINLOCK(wdt_lock); 83static 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
96static void s3c2410wdt_keepalive(void) 94static 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
103static void __s3c2410wdt_stop(void) 103static 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
112static void s3c2410wdt_stop(void) 112static 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
119static void s3c2410wdt_start(void) 121static 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
147static inline int s3c2410wdt_is_running(void) 151static 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
152static int s3c2410wdt_set_heartbeat(int timeout) 156static 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
208static 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
223static 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
241static 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
270static const struct watchdog_info s3c2410_wdt_ident = { 208static 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 214static struct watchdog_ops s3c2410wdt_ops = {
277static 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
310static 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
319static struct miscdevice s3c2410wdt_miscdev = { 222static 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
403static int __devinit s3c2410wdt_probe(struct platform_device *pdev) 302static 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
531static int __devexit s3c2410wdt_remove(struct platform_device *dev) 429static 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
551static void s3c2410wdt_shutdown(struct platform_device *dev) 449static 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}