]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/watchdog/pnx4008_wdt.c
Merge tag 'sound-fix-4.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[karo-tx-linux.git] / drivers / watchdog / pnx4008_wdt.c
index 313cd1c6fda0efcfa03897f1d23fc18b138e3779..0529aed158a4f22f56088599c71475b587e6d6f7 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
 #include <mach/hardware.h>
 
 /* WatchDog Timer - Chapter 23 Page 207 */
@@ -124,6 +126,41 @@ static int pnx4008_wdt_set_timeout(struct watchdog_device *wdd,
        return 0;
 }
 
+static int pnx4008_restart_handler(struct watchdog_device *wdd,
+                                  unsigned long mode, void *cmd)
+{
+       const char *boot_cmd = cmd;
+
+       /*
+        * Verify if a "cmd" passed from the userspace program rebooting
+        * the system; if available, handle it.
+        * - For details, see the 'reboot' syscall in kernel/reboot.c
+        * - If the received "cmd" is not supported, use the default mode.
+        */
+       if (boot_cmd) {
+               if (boot_cmd[0] == 'h')
+                       mode = REBOOT_HARD;
+               else if (boot_cmd[0] == 's')
+                       mode = REBOOT_SOFT;
+       }
+
+       if (mode == REBOOT_SOFT) {
+               /* Force match output active */
+               writel(EXT_MATCH0, WDTIM_EMR(wdt_base));
+               /* Internal reset on match output (RESOUT_N not asserted) */
+               writel(M_RES1, WDTIM_MCTRL(wdt_base));
+       } else {
+               /* Instant assert of RESETOUT_N with pulse length 1mS */
+               writel(13000, WDTIM_PULSE(wdt_base));
+               writel(M_RES2 | RESFRC1 | RESFRC2, WDTIM_MCTRL(wdt_base));
+       }
+
+       /* Wait for watchdog to reset system */
+       mdelay(1000);
+
+       return NOTIFY_DONE;
+}
+
 static const struct watchdog_info pnx4008_wdt_ident = {
        .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
            WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
@@ -135,6 +172,7 @@ static const struct watchdog_ops pnx4008_wdt_ops = {
        .start = pnx4008_wdt_start,
        .stop = pnx4008_wdt_stop,
        .set_timeout = pnx4008_wdt_set_timeout,
+       .restart = pnx4008_restart_handler,
 };
 
 static struct watchdog_device pnx4008_wdd = {
@@ -169,6 +207,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
                        WDIOF_CARDRESET : 0;
        pnx4008_wdd.parent = &pdev->dev;
        watchdog_set_nowayout(&pnx4008_wdd, nowayout);
+       watchdog_set_restart_priority(&pnx4008_wdd, 128);
 
        pnx4008_wdt_stop(&pnx4008_wdd); /* disable for now */
 
@@ -178,8 +217,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
                goto disable_clk;
        }
 
-       dev_info(&pdev->dev, "PNX4008 Watchdog Timer: heartbeat %d sec\n",
-                pnx4008_wdd.timeout);
+       dev_info(&pdev->dev, "heartbeat %d sec\n", pnx4008_wdd.timeout);
 
        return 0;