summaryrefslogtreecommitdiff
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorXiubo Li <Li.Xiubo@freescale.com>2014-09-15 07:49:42 (GMT)
committerMatthew Weigel <Matthew.Weigel@freescale.com>2014-12-11 18:38:04 (GMT)
commit95eb68d11a583748ff4b8d695f4bee5d1e00fc24 (patch)
tree8bf186c9a32bcc90b1b2b2619981a57f73e8cc8d /drivers/watchdog
parent493dcca333efb0c3f2b9444055a7614bd8319861 (diff)
downloadlinux-fsl-qoriq-95eb68d11a583748ff4b8d695f4bee5d1e00fc24.tar.xz
watchdog: imx2_wdt: Add power management support.
Add power management operations(suspend and resume) as part of dev_pm_ops for IMX2 watchdog driver. If PM will be supported, please make sure that the wdev->clk could disable the watchdog's counter input clock source or can mask watchdog's reset request to the core. If watchdog is still used by consumers and resumes from deep sleep state, we need to restart the watchdog again without enabling the timer. If watchdog been has started --> stopped by the consumers and resumes from non-deep sleep state, then start the timer again. If watchdog has been started --> stopped by the consumers and resumes from deep sleep state, will do nothing. The watchdog will be restarted by consumers next time to be used. Signed-off-by: Xiubo Li <Li.Xiubo@freescale.com> This patch has been sent out to community under discussing. The mails URL: https://lkml.org/lkml/2014/9/23/410 Change-Id: I507825f3e063e7f8b67496d9cb4894b607eb2535 Reviewed-on: http://git.am.freescale.net:8181/21409 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Zhengxiong Jin <Jason.Jin@freescale.com>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/imx2_wdt.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 68c3d37..729b09f 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -295,6 +295,65 @@ static void imx2_wdt_shutdown(struct platform_device *pdev)
}
}
+#ifdef CONFIG_PM_SLEEP
+/* Disable watchdog if it is active or non-active but still running */
+static int imx2_wdt_suspend(struct device *dev)
+{
+ struct watchdog_device *wdog = dev_get_drvdata(dev);
+ struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+
+ /* The watchdog IP block is running */
+ if (imx2_wdt_is_running(wdev)) {
+ imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
+ imx2_wdt_ping(wdog);
+
+ /* The watchdog is not active */
+ if (!watchdog_active(wdog))
+ del_timer_sync(&wdev->timer);
+ }
+
+ clk_disable_unprepare(wdev->clk);
+
+ return 0;
+}
+
+/* Enable watchdog and configure it if necessary */
+static int imx2_wdt_resume(struct device *dev)
+{
+ struct watchdog_device *wdog = dev_get_drvdata(dev);
+ struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog);
+
+ clk_prepare_enable(wdev->clk);
+
+ if (watchdog_active(wdog) && !imx2_wdt_is_running(wdev)) {
+ /*
+ * If the watchdog is still active and resumes
+ * from deep sleep state, need to restart the
+ * watchdog again.
+ */
+ imx2_wdt_setup(wdog);
+ imx2_wdt_set_timeout(wdog, wdog->timeout);
+ imx2_wdt_ping(wdog);
+ } else if (imx2_wdt_is_running(wdev)) {
+ /* Resuming from non-deep sleep state. */
+ imx2_wdt_set_timeout(wdog, wdog->timeout);
+ imx2_wdt_ping(wdog);
+ /*
+ * But the watchdog is not active, then start
+ * the timer again.
+ */
+ if (!watchdog_active(wdog))
+ mod_timer(&wdev->timer,
+ jiffies + wdog->timeout * HZ / 2);
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
+ imx2_wdt_resume);
+
static const struct of_device_id imx2_wdt_dt_ids[] = {
{ .compatible = "fsl,imx21-wdt", },
{ /* sentinel */ }
@@ -307,6 +366,7 @@ static struct platform_driver imx2_wdt_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
+ .pm = &imx2_wdt_pm_ops,
.of_match_table = imx2_wdt_dt_ids,
},
};