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/watchdog | |
| 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/watchdog')
| -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 64c6752ea2c..40a36c50a5f 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 30da88f47cd..5de7e4fa5b8 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 | } |
