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; |