Skip to content

Commit e42c73f

Browse files
andrejpicejWim Van Sebroeck
authored andcommitted
watchdog: imx2_wdg: suspend watchdog in WAIT mode
Putting device into the "Suspend-To-Idle" mode causes watchdog to trigger and resets the board after set watchdog timeout period elapses. Introduce new device-tree property "fsl,suspend-in-wait" which suspends watchdog in WAIT mode. This is done by setting WDW bit in WCR (Watchdog Control Register). Watchdog operation is restored after exiting WAIT mode as expected. WAIT mode corresponds with Linux's "Suspend-To-Idle". Signed-off-by: Andrej Picej <[email protected]> Reviewed-by: Fabio Estevam <[email protected]> Reviewed-by: Guenter Roeck <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Guenter Roeck <[email protected]> Signed-off-by: Wim Van Sebroeck <[email protected]>
1 parent 7d06c07 commit e42c73f

File tree

1 file changed

+52
-3
lines changed

1 file changed

+52
-3
lines changed

drivers/watchdog/imx2_wdt.c

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/module.h>
2828
#include <linux/moduleparam.h>
2929
#include <linux/of_address.h>
30+
#include <linux/of_device.h>
3031
#include <linux/platform_device.h>
3132
#include <linux/regmap.h>
3233
#include <linux/watchdog.h>
@@ -35,6 +36,7 @@
3536

3637
#define IMX2_WDT_WCR 0x00 /* Control Register */
3738
#define IMX2_WDT_WCR_WT (0xFF << 8) /* -> Watchdog Timeout Field */
39+
#define IMX2_WDT_WCR_WDW BIT(7) /* -> Watchdog disable for WAIT */
3840
#define IMX2_WDT_WCR_WDA BIT(5) /* -> External Reset WDOG_B */
3941
#define IMX2_WDT_WCR_SRS BIT(4) /* -> Software Reset Signal */
4042
#define IMX2_WDT_WCR_WRE BIT(3) /* -> WDOG Reset Enable */
@@ -60,13 +62,19 @@
6062

6163
#define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
6264

65+
struct imx2_wdt_data {
66+
bool wdw_supported;
67+
};
68+
6369
struct imx2_wdt_device {
6470
struct clk *clk;
6571
struct regmap *regmap;
6672
struct watchdog_device wdog;
73+
const struct imx2_wdt_data *data;
6774
bool ext_reset;
6875
bool clk_is_on;
6976
bool no_ping;
77+
bool sleep_wait;
7078
};
7179

7280
static bool nowayout = WATCHDOG_NOWAYOUT;
@@ -129,6 +137,9 @@ static inline void imx2_wdt_setup(struct watchdog_device *wdog)
129137

130138
/* Suspend timer in low power mode, write once-only */
131139
val |= IMX2_WDT_WCR_WDZST;
140+
/* Suspend timer in low power WAIT mode, write once-only */
141+
if (wdev->sleep_wait)
142+
val |= IMX2_WDT_WCR_WDW;
132143
/* Strip the old watchdog Time-Out value */
133144
val &= ~IMX2_WDT_WCR_WT;
134145
/* Generate internal chip-level reset if WDOG times out */
@@ -292,6 +303,8 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
292303
wdog->max_hw_heartbeat_ms = IMX2_WDT_MAX_TIME * 1000;
293304
wdog->parent = dev;
294305

306+
wdev->data = of_device_get_match_data(dev);
307+
295308
ret = platform_get_irq(pdev, 0);
296309
if (ret > 0)
297310
if (!devm_request_irq(dev, ret, imx2_wdt_isr, 0,
@@ -313,9 +326,18 @@ static int __init imx2_wdt_probe(struct platform_device *pdev)
313326

314327
wdev->ext_reset = of_property_read_bool(dev->of_node,
315328
"fsl,ext-reset-output");
329+
330+
if (of_property_read_bool(dev->of_node, "fsl,suspend-in-wait")) {
331+
if (!wdev->data->wdw_supported) {
332+
dev_err(dev, "suspend-in-wait not supported\n");
333+
return -EINVAL;
334+
}
335+
wdev->sleep_wait = true;
336+
}
337+
316338
/*
317339
* The i.MX7D doesn't support low power mode, so we need to ping the watchdog
318-
* during suspend.
340+
* during suspend. Interaction with "fsl,suspend-in-wait" is unknown!
319341
*/
320342
wdev->no_ping = !of_device_is_compatible(dev->of_node, "fsl,imx7d-wdt");
321343
platform_set_drvdata(pdev, wdog);
@@ -417,9 +439,36 @@ static int __maybe_unused imx2_wdt_resume(struct device *dev)
417439
static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
418440
imx2_wdt_resume);
419441

442+
struct imx2_wdt_data imx_wdt = {
443+
.wdw_supported = true,
444+
};
445+
446+
struct imx2_wdt_data imx_wdt_legacy = {
447+
.wdw_supported = false,
448+
};
449+
420450
static const struct of_device_id imx2_wdt_dt_ids[] = {
421-
{ .compatible = "fsl,imx21-wdt", },
422-
{ .compatible = "fsl,imx7d-wdt", },
451+
{ .compatible = "fsl,imx21-wdt", .data = &imx_wdt_legacy },
452+
{ .compatible = "fsl,imx25-wdt", .data = &imx_wdt },
453+
{ .compatible = "fsl,imx27-wdt", .data = &imx_wdt_legacy },
454+
{ .compatible = "fsl,imx31-wdt", .data = &imx_wdt_legacy },
455+
{ .compatible = "fsl,imx35-wdt", .data = &imx_wdt },
456+
{ .compatible = "fsl,imx50-wdt", .data = &imx_wdt },
457+
{ .compatible = "fsl,imx51-wdt", .data = &imx_wdt },
458+
{ .compatible = "fsl,imx53-wdt", .data = &imx_wdt },
459+
{ .compatible = "fsl,imx6q-wdt", .data = &imx_wdt },
460+
{ .compatible = "fsl,imx6sl-wdt", .data = &imx_wdt },
461+
{ .compatible = "fsl,imx6sll-wdt", .data = &imx_wdt },
462+
{ .compatible = "fsl,imx6sx-wdt", .data = &imx_wdt },
463+
{ .compatible = "fsl,imx6ul-wdt", .data = &imx_wdt },
464+
{ .compatible = "fsl,imx7d-wdt", .data = &imx_wdt },
465+
{ .compatible = "fsl,imx8mm-wdt", .data = &imx_wdt },
466+
{ .compatible = "fsl,imx8mn-wdt", .data = &imx_wdt },
467+
{ .compatible = "fsl,imx8mp-wdt", .data = &imx_wdt },
468+
{ .compatible = "fsl,imx8mq-wdt", .data = &imx_wdt },
469+
{ .compatible = "fsl,ls1012a-wdt", .data = &imx_wdt_legacy },
470+
{ .compatible = "fsl,ls1043a-wdt", .data = &imx_wdt_legacy },
471+
{ .compatible = "fsl,vf610-wdt", .data = &imx_wdt },
423472
{ /* sentinel */ }
424473
};
425474
MODULE_DEVICE_TABLE(of, imx2_wdt_dt_ids);

0 commit comments

Comments
 (0)