aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorJisheng Zhang <jszhang@marvell.com>2014-09-23 03:42:12 -0400
committerWim Van Sebroeck <wim@iguana.be>2014-10-20 15:03:06 -0400
commit31228f43ab528628c9b5f1351604361aa1d78533 (patch)
treeb3e2a9be36edb5b2fb5d585377706b1056642590 /drivers/watchdog
parent69a160a0543fd569661048a8692c10afcdb1914b (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.c32
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
68static inline int dw_wdt_is_enabled(void) 72static 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
128static 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
124static void dw_wdt_ping(unsigned long data) 148static 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
331static int dw_wdt_drv_remove(struct platform_device *pdev) 361static 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);