// SPDX-License-Identifier: GPL-2.0 /* * Watchdog driver for IMX2 and later processors * * Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. <kernel@pengutronix.de> * Copyright (C) 2014 Freescale Semiconductor, Inc. * * some parts adapted by similar drivers from Darius Augulis and Vladimir * Zapolskiy, additional improvements by Wim Van Sebroeck. * * NOTE: MX1 has a slightly different Watchdog than MX2 and later: * * MX1: MX2+: * ---- ----- * Registers: 32-bit 16-bit * Stopable timer: Yes No * Need to enable clk: No Yes * Halt on suspend: Manual Can be automatic
*/
/* Use internal reset or external - not both */ if (wdev->ext_reset)
wcr_enable |= IMX2_WDT_WCR_SRS; /* do not assert int reset */ else
wcr_enable |= IMX2_WDT_WCR_WDA; /* do not assert ext-reset */
/* Assert SRS signal */
regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable); /* * Due to imx6q errata ERR004346 (WDOG: WDOG SRS bit requires to be * written twice), we add another two writes to ensure there must be at * least two writes happen in the same one 32kHz clock period. We save * the target check here, since the writes shouldn't be a huge burden * for other platforms.
*/
regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
regmap_write(wdev->regmap, IMX2_WDT_WCR, wcr_enable);
/* Suspend timer in low power mode, write once-only */
val |= IMX2_WDT_WCR_WDZST; /* Suspend timer in low power WAIT mode, write once-only */ if (wdev->sleep_wait)
val |= IMX2_WDT_WCR_WDW; /* Strip the old watchdog Time-Out value */
val &= ~IMX2_WDT_WCR_WT; /* Generate internal chip-level reset if WDOG times out */ if (!wdev->ext_reset)
val &= ~IMX2_WDT_WCR_WRE; /* Or if external-reset assert WDOG_B reset only on time-out */ else
val |= IMX2_WDT_WCR_WRE; /* Keep Watchdog Disabled */
val &= ~IMX2_WDT_WCR_WDE; /* Set the watchdog's Time-Out value */
val |= WDOG_SEC_TO_COUNT(wdog->timeout);
regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
/* enable the watchdog */
val |= IMX2_WDT_WCR_WDE;
regmap_write(wdev->regmap, IMX2_WDT_WCR, val);
}
if (of_property_read_bool(dev->of_node, "fsl,suspend-in-wait")) { if (!wdev->data->wdw_supported) {
dev_err(dev, "suspend-in-wait not supported\n"); return -EINVAL;
}
wdev->sleep_wait = true;
}
/* * The i.MX7D doesn't support low power mode, so we need to ping the watchdog * during suspend. Interaction with "fsl,suspend-in-wait" is unknown!
*/
wdev->no_ping = !of_device_is_compatible(dev->of_node, "fsl,imx7d-wdt");
platform_set_drvdata(pdev, wdog);
watchdog_set_drvdata(wdog, wdev);
watchdog_set_nowayout(wdog, nowayout);
watchdog_set_restart_priority(wdog, 128);
watchdog_init_timeout(wdog, timeout, dev); if (wdev->no_ping)
watchdog_stop_ping_on_suspend(wdog);
if (imx2_wdt_is_running(wdev)) {
imx2_wdt_set_timeout(wdog, wdog->timeout);
set_bit(WDOG_HW_RUNNING, &wdog->status);
}
/* * Disable the watchdog power down counter at boot. Otherwise the power * down counter will pull down the #WDOG interrupt line for one clock * cycle.
*/
regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
if (imx2_wdt_is_running(wdev)) { /* * We are running, configure max timeout before reboot * will take place.
*/
imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
imx2_wdt_ping(wdog);
dev_crit(&pdev->dev, "Device shutdown.\n");
}
}
/* Disable watchdog if it is active or non-active but still running */ staticint 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)) { /* * Don't update wdog->timeout, we'll restore the current value * during resume.
*/
__imx2_wdt_set_timeout(wdog, IMX2_WDT_MAX_TIME);
imx2_wdt_ping(wdog);
}
if (wdev->no_ping) {
clk_disable_unprepare(wdev->clk);
wdev->clk_is_on = false;
}
return 0;
}
/* Enable watchdog and configure it if necessary */ staticint imx2_wdt_resume(struct device *dev)
{ struct watchdog_device *wdog = dev_get_drvdata(dev); struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); int ret;
if (wdev->no_ping) {
ret = clk_prepare_enable(wdev->clk);
if (ret) return ret;
wdev->clk_is_on = true;
}
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);
} if (imx2_wdt_is_running(wdev)) {
imx2_wdt_set_timeout(wdog, wdog->timeout);
imx2_wdt_ping(wdog);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.