Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+32 −0
Original line number Diff line number Diff line
@@ -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 @@ static int dw_wdt_drv_probe(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);

	clk_disable_unprepare(dw_wdt.clk);