diff options
| -rw-r--r-- | drivers/watchdog/dw_wdt.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 449c88523364..9e577a64ec9e 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/bitops.h> | 22 | #include <linux/bitops.h> |
| 23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
| 24 | #include <linux/delay.h> | ||
| 24 | #include <linux/device.h> | 25 | #include <linux/device.h> |
| 25 | #include <linux/err.h> | 26 | #include <linux/err.h> |
| 26 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
| @@ -29,9 +30,11 @@ | |||
| 29 | #include <linux/miscdevice.h> | 30 | #include <linux/miscdevice.h> |
| 30 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 31 | #include <linux/moduleparam.h> | 32 | #include <linux/moduleparam.h> |
| 33 | #include <linux/notifier.h> | ||
| 32 | #include <linux/of.h> | 34 | #include <linux/of.h> |
| 33 | #include <linux/pm.h> | 35 | #include <linux/pm.h> |
| 34 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
| 37 | #include <linux/reboot.h> | ||
| 35 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
| 36 | #include <linux/timer.h> | 39 | #include <linux/timer.h> |
| 37 | #include <linux/uaccess.h> | 40 | #include <linux/uaccess.h> |
| @@ -63,6 +66,7 @@ static struct { | |||
| 63 | unsigned long next_heartbeat; | 66 | unsigned long next_heartbeat; |
| 64 | struct timer_list timer; | 67 | struct timer_list timer; |
| 65 | int expect_close; | 68 | int expect_close; |
| 69 | struct notifier_block restart_handler; | ||
| 66 | } dw_wdt; | 70 | } dw_wdt; |
| 67 | 71 | ||
| 68 | static inline int dw_wdt_is_enabled(void) | 72 | static inline int dw_wdt_is_enabled(void) |
| @@ -121,6 +125,26 @@ static void dw_wdt_keepalive(void) | |||
| 121 | WDOG_COUNTER_RESTART_REG_OFFSET); | 125 | WDOG_COUNTER_RESTART_REG_OFFSET); |
| 122 | } | 126 | } |
| 123 | 127 | ||
| 128 | static int dw_wdt_restart_handle(struct notifier_block *this, | ||
| 129 | unsigned long mode, void *cmd) | ||
| 130 | { | ||
| 131 | u32 val; | ||
| 132 | |||
| 133 | writel(0, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); | ||
| 134 | val = readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); | ||
| 135 | if (val & WDOG_CONTROL_REG_WDT_EN_MASK) | ||
| 136 | writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs + | ||
| 137 | WDOG_COUNTER_RESTART_REG_OFFSET); | ||
| 138 | else | ||
| 139 | writel(WDOG_CONTROL_REG_WDT_EN_MASK, | ||
| 140 | dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); | ||
| 141 | |||
| 142 | /* wait for reset to assert... */ | ||
| 143 | mdelay(500); | ||
| 144 | |||
| 145 | return NOTIFY_DONE; | ||
| 146 | } | ||
| 147 | |||
| 124 | static void dw_wdt_ping(unsigned long data) | 148 | static void dw_wdt_ping(unsigned long data) |
| 125 | { | 149 | { |
| 126 | if (time_before(jiffies, dw_wdt.next_heartbeat) || | 150 | if (time_before(jiffies, dw_wdt.next_heartbeat) || |
| @@ -316,6 +340,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) | |||
| 316 | if (ret) | 340 | if (ret) |
| 317 | goto out_disable_clk; | 341 | goto out_disable_clk; |
| 318 | 342 | ||
| 343 | dw_wdt.restart_handler.notifier_call = dw_wdt_restart_handle; | ||
| 344 | dw_wdt.restart_handler.priority = 128; | ||
| 345 | ret = register_restart_handler(&dw_wdt.restart_handler); | ||
| 346 | if (ret) | ||
| 347 | pr_warn("cannot register restart handler\n"); | ||
| 348 | |||
| 319 | dw_wdt_set_next_heartbeat(); | 349 | dw_wdt_set_next_heartbeat(); |
| 320 | setup_timer(&dw_wdt.timer, dw_wdt_ping, 0); | 350 | setup_timer(&dw_wdt.timer, dw_wdt_ping, 0); |
| 321 | mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); | 351 | mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); |
| @@ -330,6 +360,8 @@ out_disable_clk: | |||
| 330 | 360 | ||
| 331 | static int dw_wdt_drv_remove(struct platform_device *pdev) | 361 | static int dw_wdt_drv_remove(struct platform_device *pdev) |
| 332 | { | 362 | { |
| 363 | unregister_restart_handler(&dw_wdt.restart_handler); | ||
| 364 | |||
| 333 | misc_deregister(&dw_wdt_miscdev); | 365 | misc_deregister(&dw_wdt_miscdev); |
| 334 | 366 | ||
| 335 | clk_disable_unprepare(dw_wdt.clk); | 367 | clk_disable_unprepare(dw_wdt.clk); |
