Commit 31228f43 authored by Jisheng Zhang's avatar Jisheng Zhang Committed by Wim Van Sebroeck

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: default avatarJisheng Zhang <jszhang@marvell.com>
Reviewed-by: default avatarGuenter Roeck <linux@roeck-us.net>
Signed-off-by: default avatarWim Van Sebroeck <wim@iguana.be>
parent 69a160a0
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/fs.h> #include <linux/fs.h>
...@@ -29,9 +30,11 @@ ...@@ -29,9 +30,11 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/notifier.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -63,6 +66,7 @@ static struct { ...@@ -63,6 +66,7 @@ static struct {
unsigned long next_heartbeat; unsigned long next_heartbeat;
struct timer_list timer; struct timer_list timer;
int expect_close; int expect_close;
struct notifier_block restart_handler;
} dw_wdt; } dw_wdt;
static inline int dw_wdt_is_enabled(void) static inline int dw_wdt_is_enabled(void)
...@@ -121,6 +125,26 @@ static void dw_wdt_keepalive(void) ...@@ -121,6 +125,26 @@ static void dw_wdt_keepalive(void)
WDOG_COUNTER_RESTART_REG_OFFSET); WDOG_COUNTER_RESTART_REG_OFFSET);
} }
static int dw_wdt_restart_handle(struct notifier_block *this,
unsigned long mode, void *cmd)
{
u32 val;
writel(0, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
val = readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
if (val & WDOG_CONTROL_REG_WDT_EN_MASK)
writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
WDOG_COUNTER_RESTART_REG_OFFSET);
else
writel(WDOG_CONTROL_REG_WDT_EN_MASK,
dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
/* wait for reset to assert... */
mdelay(500);
return NOTIFY_DONE;
}
static void dw_wdt_ping(unsigned long data) static void dw_wdt_ping(unsigned long data)
{ {
if (time_before(jiffies, dw_wdt.next_heartbeat) || if (time_before(jiffies, dw_wdt.next_heartbeat) ||
...@@ -316,6 +340,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) ...@@ -316,6 +340,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
if (ret) if (ret)
goto out_disable_clk; goto out_disable_clk;
dw_wdt.restart_handler.notifier_call = dw_wdt_restart_handle;
dw_wdt.restart_handler.priority = 128;
ret = register_restart_handler(&dw_wdt.restart_handler);
if (ret)
pr_warn("cannot register restart handler\n");
dw_wdt_set_next_heartbeat(); dw_wdt_set_next_heartbeat();
setup_timer(&dw_wdt.timer, dw_wdt_ping, 0); setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
...@@ -330,6 +360,8 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) ...@@ -330,6 +360,8 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
static int dw_wdt_drv_remove(struct platform_device *pdev) static int dw_wdt_drv_remove(struct platform_device *pdev)
{ {
unregister_restart_handler(&dw_wdt.restart_handler);
misc_deregister(&dw_wdt_miscdev); misc_deregister(&dw_wdt_miscdev);
clk_disable_unprepare(dw_wdt.clk); clk_disable_unprepare(dw_wdt.clk);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment