diff options
author | Jisheng Zhang <jszhang@marvell.com> | 2014-09-23 03:42:12 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2014-10-20 15:03:06 -0400 |
commit | 31228f43ab528628c9b5f1351604361aa1d78533 (patch) | |
tree | b3e2a9be36edb5b2fb5d585377706b1056642590 /drivers/watchdog | |
parent | 69a160a0543fd569661048a8692c10afcdb1914b (diff) |
watchdog: dw_wdt: add restart handler support
The kernel core now provides an API to trigger a system restart.
Register with it to support restarting the system via. watchdog.
Signed-off-by: Jisheng Zhang <jszhang@marvell.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-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); |