diff options
-rw-r--r-- | drivers/watchdog/sunxi_wdt.c | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c index 693b9d2c6e39..60deb9d304c0 100644 --- a/drivers/watchdog/sunxi_wdt.c +++ b/drivers/watchdog/sunxi_wdt.c @@ -14,6 +14,7 @@ */ #include <linux/clk.h> +#include <linux/delay.h> #include <linux/err.h> #include <linux/init.h> #include <linux/io.h> @@ -22,9 +23,12 @@ #include <linux/moduleparam.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/reboot.h> #include <linux/types.h> #include <linux/watchdog.h> +#include <asm/system_misc.h> + #define WDT_MAX_TIMEOUT 16 #define WDT_MIN_TIMEOUT 1 #define WDT_MODE_TIMEOUT(n) ((n) << 3) @@ -70,6 +74,26 @@ static const int wdt_timeout_map[] = { [16] = 0xB, /* 16s */ }; +static void __iomem *reboot_wdt_base; + +static void sun4i_wdt_restart(enum reboot_mode mode, const char *cmd) +{ + /* Enable timer and set reset bit in the watchdog */ + writel(WDT_MODE_EN | WDT_MODE_RST_EN, reboot_wdt_base + WDT_MODE); + + /* + * Restart the watchdog. The default (and lowest) interval + * value for the watchdog is 0.5s. + */ + writel(WDT_CTRL_RELOAD, reboot_wdt_base + WDT_CTRL); + + while (1) { + mdelay(5); + writel(WDT_MODE_EN | WDT_MODE_RST_EN, + reboot_wdt_base + WDT_MODE); + } +} + static int sunxi_wdt_ping(struct watchdog_device *wdt_dev) { struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev); @@ -181,6 +205,9 @@ static int sunxi_wdt_probe(struct platform_device *pdev) if (unlikely(err)) return err; + reboot_wdt_base = sunxi_wdt->wdt_base; + arm_pm_restart = sun4i_wdt_restart; + dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", sunxi_wdt->wdt_dev.timeout, nowayout); @@ -191,6 +218,8 @@ static int sunxi_wdt_remove(struct platform_device *pdev) { struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev); + arm_pm_restart = NULL; + watchdog_unregister_device(&sunxi_wdt->wdt_dev); watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL); |