0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/watchdog.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/stmp3xxx_rtc_wdt.h>
0014 #include <linux/notifier.h>
0015 #include <linux/reboot.h>
0016
0017 #define WDOG_TICK_RATE 1000
0018 #define STMP3XXX_DEFAULT_TIMEOUT 19
0019 #define STMP3XXX_MAX_TIMEOUT (UINT_MAX / WDOG_TICK_RATE)
0020
0021 static int heartbeat = STMP3XXX_DEFAULT_TIMEOUT;
0022 module_param(heartbeat, uint, 0);
0023 MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat period in seconds from 1 to "
0024 __MODULE_STRING(STMP3XXX_MAX_TIMEOUT) ", default "
0025 __MODULE_STRING(STMP3XXX_DEFAULT_TIMEOUT));
0026
0027 static int wdt_start(struct watchdog_device *wdd)
0028 {
0029 struct device *dev = watchdog_get_drvdata(wdd);
0030 struct stmp3xxx_wdt_pdata *pdata = dev_get_platdata(dev);
0031
0032 pdata->wdt_set_timeout(dev->parent, wdd->timeout * WDOG_TICK_RATE);
0033 return 0;
0034 }
0035
0036 static int wdt_stop(struct watchdog_device *wdd)
0037 {
0038 struct device *dev = watchdog_get_drvdata(wdd);
0039 struct stmp3xxx_wdt_pdata *pdata = dev_get_platdata(dev);
0040
0041 pdata->wdt_set_timeout(dev->parent, 0);
0042 return 0;
0043 }
0044
0045 static int wdt_set_timeout(struct watchdog_device *wdd, unsigned new_timeout)
0046 {
0047 wdd->timeout = new_timeout;
0048 return wdt_start(wdd);
0049 }
0050
0051 static const struct watchdog_info stmp3xxx_wdt_ident = {
0052 .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
0053 .identity = "STMP3XXX RTC Watchdog",
0054 };
0055
0056 static const struct watchdog_ops stmp3xxx_wdt_ops = {
0057 .owner = THIS_MODULE,
0058 .start = wdt_start,
0059 .stop = wdt_stop,
0060 .set_timeout = wdt_set_timeout,
0061 };
0062
0063 static struct watchdog_device stmp3xxx_wdd = {
0064 .info = &stmp3xxx_wdt_ident,
0065 .ops = &stmp3xxx_wdt_ops,
0066 .min_timeout = 1,
0067 .max_timeout = STMP3XXX_MAX_TIMEOUT,
0068 .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
0069 };
0070
0071 static int wdt_notify_sys(struct notifier_block *nb, unsigned long code,
0072 void *unused)
0073 {
0074 switch (code) {
0075 case SYS_DOWN:
0076 break;
0077 case SYS_HALT:
0078 case SYS_POWER_OFF:
0079 wdt_stop(&stmp3xxx_wdd);
0080 break;
0081 }
0082
0083 return NOTIFY_DONE;
0084 }
0085
0086 static struct notifier_block wdt_notifier = {
0087 .notifier_call = wdt_notify_sys,
0088 };
0089
0090 static int stmp3xxx_wdt_probe(struct platform_device *pdev)
0091 {
0092 struct device *dev = &pdev->dev;
0093 int ret;
0094
0095 watchdog_set_drvdata(&stmp3xxx_wdd, dev);
0096
0097 stmp3xxx_wdd.timeout = clamp_t(unsigned, heartbeat, 1, STMP3XXX_MAX_TIMEOUT);
0098 stmp3xxx_wdd.parent = dev;
0099
0100 ret = devm_watchdog_register_device(dev, &stmp3xxx_wdd);
0101 if (ret < 0)
0102 return ret;
0103
0104 if (register_reboot_notifier(&wdt_notifier))
0105 dev_warn(dev, "cannot register reboot notifier\n");
0106
0107 dev_info(dev, "initialized watchdog with heartbeat %ds\n",
0108 stmp3xxx_wdd.timeout);
0109 return 0;
0110 }
0111
0112 static int stmp3xxx_wdt_remove(struct platform_device *pdev)
0113 {
0114 unregister_reboot_notifier(&wdt_notifier);
0115 return 0;
0116 }
0117
0118 static int __maybe_unused stmp3xxx_wdt_suspend(struct device *dev)
0119 {
0120 struct watchdog_device *wdd = &stmp3xxx_wdd;
0121
0122 if (watchdog_active(wdd))
0123 return wdt_stop(wdd);
0124
0125 return 0;
0126 }
0127
0128 static int __maybe_unused stmp3xxx_wdt_resume(struct device *dev)
0129 {
0130 struct watchdog_device *wdd = &stmp3xxx_wdd;
0131
0132 if (watchdog_active(wdd))
0133 return wdt_start(wdd);
0134
0135 return 0;
0136 }
0137
0138 static SIMPLE_DEV_PM_OPS(stmp3xxx_wdt_pm_ops,
0139 stmp3xxx_wdt_suspend, stmp3xxx_wdt_resume);
0140
0141 static struct platform_driver stmp3xxx_wdt_driver = {
0142 .driver = {
0143 .name = "stmp3xxx_rtc_wdt",
0144 .pm = &stmp3xxx_wdt_pm_ops,
0145 },
0146 .probe = stmp3xxx_wdt_probe,
0147 .remove = stmp3xxx_wdt_remove,
0148 };
0149 module_platform_driver(stmp3xxx_wdt_driver);
0150
0151 MODULE_DESCRIPTION("STMP3XXX RTC Watchdog Driver");
0152 MODULE_LICENSE("GPL v2");
0153 MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");