1 // SPDX-License-Identifier: GPL-2.0
3 * Watchdog driver for the RTC based watchdog in STMP3xxx and i.MX23/28
5 * Author: Wolfram Sang <kernel@pengutronix.de>
7 * Copyright (C) 2011-12 Wolfram Sang, Pengutronix
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/watchdog.h>
12 #include <linux/platform_device.h>
13 #include <linux/stmp3xxx_rtc_wdt.h>
14 #include <linux/notifier.h>
15 #include <linux/reboot.h>
17 #define WDOG_TICK_RATE 1000 /* 1 kHz clock */
18 #define STMP3XXX_DEFAULT_TIMEOUT 19
19 #define STMP3XXX_MAX_TIMEOUT (UINT_MAX / WDOG_TICK_RATE)
21 static int heartbeat
= STMP3XXX_DEFAULT_TIMEOUT
;
22 module_param(heartbeat
, uint
, 0);
23 MODULE_PARM_DESC(heartbeat
, "Watchdog heartbeat period in seconds from 1 to "
24 __MODULE_STRING(STMP3XXX_MAX_TIMEOUT
) ", default "
25 __MODULE_STRING(STMP3XXX_DEFAULT_TIMEOUT
));
27 static int wdt_start(struct watchdog_device
*wdd
)
29 struct device
*dev
= watchdog_get_drvdata(wdd
);
30 struct stmp3xxx_wdt_pdata
*pdata
= dev_get_platdata(dev
);
32 pdata
->wdt_set_timeout(dev
->parent
, wdd
->timeout
* WDOG_TICK_RATE
);
36 static int wdt_stop(struct watchdog_device
*wdd
)
38 struct device
*dev
= watchdog_get_drvdata(wdd
);
39 struct stmp3xxx_wdt_pdata
*pdata
= dev_get_platdata(dev
);
41 pdata
->wdt_set_timeout(dev
->parent
, 0);
45 static int wdt_set_timeout(struct watchdog_device
*wdd
, unsigned new_timeout
)
47 wdd
->timeout
= new_timeout
;
48 return wdt_start(wdd
);
51 static const struct watchdog_info stmp3xxx_wdt_ident
= {
52 .options
= WDIOF_MAGICCLOSE
| WDIOF_SETTIMEOUT
| WDIOF_KEEPALIVEPING
,
53 .identity
= "STMP3XXX RTC Watchdog",
56 static const struct watchdog_ops stmp3xxx_wdt_ops
= {
60 .set_timeout
= wdt_set_timeout
,
63 static struct watchdog_device stmp3xxx_wdd
= {
64 .info
= &stmp3xxx_wdt_ident
,
65 .ops
= &stmp3xxx_wdt_ops
,
67 .max_timeout
= STMP3XXX_MAX_TIMEOUT
,
68 .status
= WATCHDOG_NOWAYOUT_INIT_STATUS
,
71 static int wdt_notify_sys(struct notifier_block
*nb
, unsigned long code
,
75 case SYS_DOWN
: /* keep enabled, system might crash while going down */
77 case SYS_HALT
: /* allow the system to actually halt */
79 wdt_stop(&stmp3xxx_wdd
);
86 static struct notifier_block wdt_notifier
= {
87 .notifier_call
= wdt_notify_sys
,
90 static int stmp3xxx_wdt_probe(struct platform_device
*pdev
)
92 struct device
*dev
= &pdev
->dev
;
95 watchdog_set_drvdata(&stmp3xxx_wdd
, dev
);
97 stmp3xxx_wdd
.timeout
= clamp_t(unsigned, heartbeat
, 1, STMP3XXX_MAX_TIMEOUT
);
98 stmp3xxx_wdd
.parent
= dev
;
100 ret
= devm_watchdog_register_device(dev
, &stmp3xxx_wdd
);
104 if (register_reboot_notifier(&wdt_notifier
))
105 dev_warn(dev
, "cannot register reboot notifier\n");
107 dev_info(dev
, "initialized watchdog with heartbeat %ds\n",
108 stmp3xxx_wdd
.timeout
);
112 static int stmp3xxx_wdt_remove(struct platform_device
*pdev
)
114 unregister_reboot_notifier(&wdt_notifier
);
118 static int __maybe_unused
stmp3xxx_wdt_suspend(struct device
*dev
)
120 struct watchdog_device
*wdd
= &stmp3xxx_wdd
;
122 if (watchdog_active(wdd
))
123 return wdt_stop(wdd
);
128 static int __maybe_unused
stmp3xxx_wdt_resume(struct device
*dev
)
130 struct watchdog_device
*wdd
= &stmp3xxx_wdd
;
132 if (watchdog_active(wdd
))
133 return wdt_start(wdd
);
138 static SIMPLE_DEV_PM_OPS(stmp3xxx_wdt_pm_ops
,
139 stmp3xxx_wdt_suspend
, stmp3xxx_wdt_resume
);
141 static struct platform_driver stmp3xxx_wdt_driver
= {
143 .name
= "stmp3xxx_rtc_wdt",
144 .pm
= &stmp3xxx_wdt_pm_ops
,
146 .probe
= stmp3xxx_wdt_probe
,
147 .remove
= stmp3xxx_wdt_remove
,
149 module_platform_driver(stmp3xxx_wdt_driver
);
151 MODULE_DESCRIPTION("STMP3XXX RTC Watchdog Driver");
152 MODULE_LICENSE("GPL v2");
153 MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");