forked from Minki/linux
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:
parent
69a160a054
commit
31228f43ab
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user