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>
This commit is contained in:
Jisheng Zhang 2014-09-23 15:42:12 +08:00 committed by Wim Van Sebroeck
parent 69a160a054
commit 31228f43ab

View File

@ -21,6 +21,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/fs.h>
@ -29,9 +30,11 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/uaccess.h>
@ -63,6 +66,7 @@ static struct {
unsigned long next_heartbeat;
struct timer_list timer;
int expect_close;
struct notifier_block restart_handler;
} dw_wdt;
static inline int dw_wdt_is_enabled(void)
@ -121,6 +125,26 @@ static void dw_wdt_keepalive(void)
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)
{
if (time_before(jiffies, dw_wdt.next_heartbeat) ||
@ -316,6 +340,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
if (ret)
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();
setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
@ -330,6 +360,8 @@ out_disable_clk:
static int dw_wdt_drv_remove(struct platform_device *pdev)
{
unregister_restart_handler(&dw_wdt.restart_handler);
misc_deregister(&dw_wdt_miscdev);
clk_disable_unprepare(dw_wdt.clk);