// SPDX-License-Identifier: GPL-2.0-only /* * Imagination Technologies PowerDown Controller Watchdog Timer. * * Copyright (c) 2014 Imagination Technologies Ltd. * * Based on drivers/watchdog/sunxi_wdt.c Copyright (c) 2013 Carlo Caione * 2012 Henrik Nordstrom * * Notes * ----- * The timeout value is rounded to the next power of two clock cycles. * This is configured using the PDC_WDT_CONFIG register, according to this * formula: * * timeout = 2^(delay + 1) clock cycles * * Where 'delay' is the value written in PDC_WDT_CONFIG register. * * Therefore, the hardware only allows to program watchdog timeouts, expressed * as a power of two number of watchdog clock cycles. The current implementation * guarantees that the actual watchdog timeout will be _at least_ the value * programmed in the imgpdg_wdt driver. * * The following table shows how the user-configured timeout relates * to the actual hardware timeout (watchdog clock @ 40000 Hz): * * input timeout | WD_DELAY | actual timeout * ----------------------------------- * 10 | 18 | 13 seconds * 20 | 19 | 26 seconds * 30 | 20 | 52 seconds * 60 | 21 | 104 seconds * * Albeit coarse, this granularity would suffice most watchdog uses. * If the platform allows it, the user should be able to change the watchdog * clock rate and achieve a finer timeout granularity.
*/
pdc_wdt = devm_kzalloc(dev, sizeof(*pdc_wdt), GFP_KERNEL); if (!pdc_wdt) return -ENOMEM;
pdc_wdt->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(pdc_wdt->base)) return PTR_ERR(pdc_wdt->base);
pdc_wdt->sys_clk = devm_clk_get_enabled(dev, "sys"); if (IS_ERR(pdc_wdt->sys_clk)) {
dev_err(dev, "failed to get the sys clock\n"); return PTR_ERR(pdc_wdt->sys_clk);
}
pdc_wdt->wdt_clk = devm_clk_get_enabled(dev, "wdt"); if (IS_ERR(pdc_wdt->wdt_clk)) {
dev_err(dev, "failed to get the wdt clock\n"); return PTR_ERR(pdc_wdt->wdt_clk);
}
/* We use the clock rate to calculate the max timeout */
clk_rate = clk_get_rate(pdc_wdt->wdt_clk); if (clk_rate == 0) {
dev_err(dev, "failed to get clock rate\n"); return -EINVAL;
}
/* Find what caused the last reset */
val = readl(pdc_wdt->base + PDC_WDT_TICKLE1);
val = (val & PDC_WDT_TICKLE_STATUS_MASK) >> PDC_WDT_TICKLE_STATUS_SHIFT; switch (val) { case PDC_WDT_TICKLE_STATUS_TICKLE: case PDC_WDT_TICKLE_STATUS_TIMEOUT:
pdc_wdt->wdt_dev.bootstatus |= WDIOF_CARDRESET;
dev_info(dev, "watchdog module last reset due to timeout\n"); break; case PDC_WDT_TICKLE_STATUS_HRESET:
dev_info(dev, "watchdog module last reset due to hard reset\n"); break; case PDC_WDT_TICKLE_STATUS_SRESET:
dev_info(dev, "watchdog module last reset due to soft reset\n"); break; case PDC_WDT_TICKLE_STATUS_USER:
dev_info(dev, "watchdog module last reset due to user reset\n"); break; default:
dev_info(dev, "contains an illegal status code (%08x)\n", val); break;
}
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.