diff options
| -rw-r--r-- | drivers/watchdog/s3c2410_wdt.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 015256e496ae..8532c3e2aea7 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
| @@ -41,6 +41,8 @@ | |||
| 41 | #include <linux/of.h> | 41 | #include <linux/of.h> |
| 42 | #include <linux/mfd/syscon.h> | 42 | #include <linux/mfd/syscon.h> |
| 43 | #include <linux/regmap.h> | 43 | #include <linux/regmap.h> |
| 44 | #include <linux/reboot.h> | ||
| 45 | #include <linux/delay.h> | ||
| 44 | 46 | ||
| 45 | #define S3C2410_WTCON 0x00 | 47 | #define S3C2410_WTCON 0x00 |
| 46 | #define S3C2410_WTDAT 0x04 | 48 | #define S3C2410_WTDAT 0x04 |
| @@ -128,6 +130,7 @@ struct s3c2410_wdt { | |||
| 128 | unsigned long wtdat_save; | 130 | unsigned long wtdat_save; |
| 129 | struct watchdog_device wdt_device; | 131 | struct watchdog_device wdt_device; |
| 130 | struct notifier_block freq_transition; | 132 | struct notifier_block freq_transition; |
| 133 | struct notifier_block restart_handler; | ||
| 131 | struct s3c2410_wdt_variant *drv_data; | 134 | struct s3c2410_wdt_variant *drv_data; |
| 132 | struct regmap *pmureg; | 135 | struct regmap *pmureg; |
| 133 | }; | 136 | }; |
| @@ -449,6 +452,31 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) | |||
| 449 | } | 452 | } |
| 450 | #endif | 453 | #endif |
| 451 | 454 | ||
| 455 | static int s3c2410wdt_restart(struct notifier_block *this, | ||
| 456 | unsigned long mode, void *cmd) | ||
| 457 | { | ||
| 458 | struct s3c2410_wdt *wdt = container_of(this, struct s3c2410_wdt, | ||
| 459 | restart_handler); | ||
| 460 | void __iomem *wdt_base = wdt->reg_base; | ||
| 461 | |||
| 462 | /* disable watchdog, to be safe */ | ||
| 463 | writel(0, wdt_base + S3C2410_WTCON); | ||
| 464 | |||
| 465 | /* put initial values into count and data */ | ||
| 466 | writel(0x80, wdt_base + S3C2410_WTCNT); | ||
| 467 | writel(0x80, wdt_base + S3C2410_WTDAT); | ||
| 468 | |||
| 469 | /* set the watchdog to go and reset... */ | ||
| 470 | writel(S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV16 | | ||
| 471 | S3C2410_WTCON_RSTEN | S3C2410_WTCON_PRESCALE(0x20), | ||
| 472 | wdt_base + S3C2410_WTCON); | ||
| 473 | |||
| 474 | /* wait for reset to assert... */ | ||
| 475 | mdelay(500); | ||
| 476 | |||
| 477 | return NOTIFY_DONE; | ||
| 478 | } | ||
| 479 | |||
| 452 | static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) | 480 | static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) |
| 453 | { | 481 | { |
| 454 | unsigned int rst_stat; | 482 | unsigned int rst_stat; |
| @@ -603,6 +631,12 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 603 | 631 | ||
| 604 | platform_set_drvdata(pdev, wdt); | 632 | platform_set_drvdata(pdev, wdt); |
| 605 | 633 | ||
| 634 | wdt->restart_handler.notifier_call = s3c2410wdt_restart; | ||
| 635 | wdt->restart_handler.priority = 128; | ||
| 636 | ret = register_restart_handler(&wdt->restart_handler); | ||
| 637 | if (ret) | ||
| 638 | pr_err("cannot register restart handler, %d\n", ret); | ||
| 639 | |||
| 606 | /* print out a statement of readiness */ | 640 | /* print out a statement of readiness */ |
| 607 | 641 | ||
| 608 | wtcon = readl(wdt->reg_base + S3C2410_WTCON); | 642 | wtcon = readl(wdt->reg_base + S3C2410_WTCON); |
| @@ -632,6 +666,8 @@ static int s3c2410wdt_remove(struct platform_device *dev) | |||
| 632 | int ret; | 666 | int ret; |
| 633 | struct s3c2410_wdt *wdt = platform_get_drvdata(dev); | 667 | struct s3c2410_wdt *wdt = platform_get_drvdata(dev); |
| 634 | 668 | ||
| 669 | unregister_restart_handler(&wdt->restart_handler); | ||
| 670 | |||
| 635 | ret = s3c2410wdt_mask_and_disable_reset(wdt, true); | 671 | ret = s3c2410wdt_mask_and_disable_reset(wdt, true); |
| 636 | if (ret < 0) | 672 | if (ret < 0) |
| 637 | return ret; | 673 | return ret; |
