diff options
| author | Jisheng Zhang <jszhang@marvell.com> | 2014-09-23 03:42:12 -0400 |
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2014-10-20 15:03:06 -0400 |
| commit | 31228f43ab528628c9b5f1351604361aa1d78533 (patch) | |
| tree | b3e2a9be36edb5b2fb5d585377706b1056642590 | |
| parent | 69a160a0543fd569661048a8692c10afcdb1914b (diff) | |
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>
| -rw-r--r-- | drivers/watchdog/dw_wdt.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 449c88523364..9e577a64ec9e 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | 21 | ||
| 22 | #include <linux/bitops.h> | 22 | #include <linux/bitops.h> |
| 23 | #include <linux/clk.h> | 23 | #include <linux/clk.h> |
| 24 | #include <linux/delay.h> | ||
| 24 | #include <linux/device.h> | 25 | #include <linux/device.h> |
| 25 | #include <linux/err.h> | 26 | #include <linux/err.h> |
| 26 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
| @@ -29,9 +30,11 @@ | |||
| 29 | #include <linux/miscdevice.h> | 30 | #include <linux/miscdevice.h> |
| 30 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 31 | #include <linux/moduleparam.h> | 32 | #include <linux/moduleparam.h> |
| 33 | #include <linux/notifier.h> | ||
| 32 | #include <linux/of.h> | 34 | #include <linux/of.h> |
| 33 | #include <linux/pm.h> | 35 | #include <linux/pm.h> |
| 34 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
| 37 | #include <linux/reboot.h> | ||
| 35 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
| 36 | #include <linux/timer.h> | 39 | #include <linux/timer.h> |
| 37 | #include <linux/uaccess.h> | 40 | #include <linux/uaccess.h> |
| @@ -63,6 +66,7 @@ static struct { | |||
| 63 | unsigned long next_heartbeat; | 66 | unsigned long next_heartbeat; |
| 64 | struct timer_list timer; | 67 | struct timer_list timer; |
| 65 | int expect_close; | 68 | int expect_close; |
| 69 | struct notifier_block restart_handler; | ||
| 66 | } dw_wdt; | 70 | } dw_wdt; |
| 67 | 71 | ||
| 68 | static inline int dw_wdt_is_enabled(void) | 72 | static inline int dw_wdt_is_enabled(void) |
| @@ -121,6 +125,26 @@ static void dw_wdt_keepalive(void) | |||
| 121 | WDOG_COUNTER_RESTART_REG_OFFSET); | 125 | WDOG_COUNTER_RESTART_REG_OFFSET); |
| 122 | } | 126 | } |
| 123 | 127 | ||
| 128 | static int dw_wdt_restart_handle(struct notifier_block *this, | ||
| 129 | unsigned long mode, void *cmd) | ||
| 130 | { | ||
| 131 | u32 val; | ||
| 132 | |||
| 133 | writel(0, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); | ||
| 134 | val = readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); | ||
| 135 | if (val & WDOG_CONTROL_REG_WDT_EN_MASK) | ||
| 136 | writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs + | ||
| 137 | WDOG_COUNTER_RESTART_REG_OFFSET); | ||
| 138 | else | ||
| 139 | writel(WDOG_CONTROL_REG_WDT_EN_MASK, | ||
| 140 | dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); | ||
| 141 | |||
| 142 | /* wait for reset to assert... */ | ||
| 143 | mdelay(500); | ||
| 144 | |||
| 145 | return NOTIFY_DONE; | ||
| 146 | } | ||
| 147 | |||
| 124 | static void dw_wdt_ping(unsigned long data) | 148 | static void dw_wdt_ping(unsigned long data) |
| 125 | { | 149 | { |
| 126 | if (time_before(jiffies, dw_wdt.next_heartbeat) || | 150 | if (time_before(jiffies, dw_wdt.next_heartbeat) || |
| @@ -316,6 +340,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) | |||
| 316 | if (ret) | 340 | if (ret) |
| 317 | goto out_disable_clk; | 341 | goto out_disable_clk; |
| 318 | 342 | ||
| 343 | dw_wdt.restart_handler.notifier_call = dw_wdt_restart_handle; | ||
| 344 | dw_wdt.restart_handler.priority = 128; | ||
| 345 | ret = register_restart_handler(&dw_wdt.restart_handler); | ||
| 346 | if (ret) | ||
| 347 | pr_warn("cannot register restart handler\n"); | ||
| 348 | |||
| 319 | dw_wdt_set_next_heartbeat(); | 349 | dw_wdt_set_next_heartbeat(); |
| 320 | setup_timer(&dw_wdt.timer, dw_wdt_ping, 0); | 350 | setup_timer(&dw_wdt.timer, dw_wdt_ping, 0); |
| 321 | mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); | 351 | mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); |
| @@ -330,6 +360,8 @@ out_disable_clk: | |||
| 330 | 360 | ||
| 331 | static int dw_wdt_drv_remove(struct platform_device *pdev) | 361 | static int dw_wdt_drv_remove(struct platform_device *pdev) |
| 332 | { | 362 | { |
| 363 | unregister_restart_handler(&dw_wdt.restart_handler); | ||
| 364 | |||
| 333 | misc_deregister(&dw_wdt_miscdev); | 365 | misc_deregister(&dw_wdt_miscdev); |
| 334 | 366 | ||
| 335 | clk_disable_unprepare(dw_wdt.clk); | 367 | clk_disable_unprepare(dw_wdt.clk); |
