0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include <linux/platform_device.h>
0025 #include <linux/module.h>
0026 #include <linux/watchdog.h>
0027 #include <linux/io.h>
0028
0029
0030 #define WDT_TIMEOUT 30
0031
0032 static bool nowayout = WATCHDOG_NOWAYOUT;
0033 module_param(nowayout, bool, 0);
0034 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
0035
0036 static unsigned int timeout;
0037 module_param(timeout, uint, 0);
0038 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds.");
0039
0040 #define EP93XX_WATCHDOG 0x00
0041 #define EP93XX_WDSTATUS 0x04
0042
0043 struct ep93xx_wdt_priv {
0044 void __iomem *mmio;
0045 struct watchdog_device wdd;
0046 };
0047
0048 static int ep93xx_wdt_start(struct watchdog_device *wdd)
0049 {
0050 struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
0051
0052 writel(0xaaaa, priv->mmio + EP93XX_WATCHDOG);
0053
0054 return 0;
0055 }
0056
0057 static int ep93xx_wdt_stop(struct watchdog_device *wdd)
0058 {
0059 struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
0060
0061 writel(0xaa55, priv->mmio + EP93XX_WATCHDOG);
0062
0063 return 0;
0064 }
0065
0066 static int ep93xx_wdt_ping(struct watchdog_device *wdd)
0067 {
0068 struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
0069
0070 writel(0x5555, priv->mmio + EP93XX_WATCHDOG);
0071
0072 return 0;
0073 }
0074
0075 static const struct watchdog_info ep93xx_wdt_ident = {
0076 .options = WDIOF_CARDRESET |
0077 WDIOF_SETTIMEOUT |
0078 WDIOF_MAGICCLOSE |
0079 WDIOF_KEEPALIVEPING,
0080 .identity = "EP93xx Watchdog",
0081 };
0082
0083 static const struct watchdog_ops ep93xx_wdt_ops = {
0084 .owner = THIS_MODULE,
0085 .start = ep93xx_wdt_start,
0086 .stop = ep93xx_wdt_stop,
0087 .ping = ep93xx_wdt_ping,
0088 };
0089
0090 static int ep93xx_wdt_probe(struct platform_device *pdev)
0091 {
0092 struct device *dev = &pdev->dev;
0093 struct ep93xx_wdt_priv *priv;
0094 struct watchdog_device *wdd;
0095 unsigned long val;
0096 int ret;
0097
0098 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0099 if (!priv)
0100 return -ENOMEM;
0101
0102 priv->mmio = devm_platform_ioremap_resource(pdev, 0);
0103 if (IS_ERR(priv->mmio))
0104 return PTR_ERR(priv->mmio);
0105
0106 val = readl(priv->mmio + EP93XX_WATCHDOG);
0107
0108 wdd = &priv->wdd;
0109 wdd->bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0;
0110 wdd->info = &ep93xx_wdt_ident;
0111 wdd->ops = &ep93xx_wdt_ops;
0112 wdd->min_timeout = 1;
0113 wdd->max_hw_heartbeat_ms = 200;
0114 wdd->parent = dev;
0115
0116 watchdog_set_nowayout(wdd, nowayout);
0117
0118 wdd->timeout = WDT_TIMEOUT;
0119 watchdog_init_timeout(wdd, timeout, dev);
0120
0121 watchdog_set_drvdata(wdd, priv);
0122
0123 ret = devm_watchdog_register_device(dev, wdd);
0124 if (ret)
0125 return ret;
0126
0127 dev_info(dev, "EP93XX watchdog driver %s\n",
0128 (val & 0x08) ? " (nCS1 disable detected)" : "");
0129
0130 return 0;
0131 }
0132
0133 static struct platform_driver ep93xx_wdt_driver = {
0134 .driver = {
0135 .name = "ep93xx-wdt",
0136 },
0137 .probe = ep93xx_wdt_probe,
0138 };
0139
0140 module_platform_driver(ep93xx_wdt_driver);
0141
0142 MODULE_AUTHOR("Ray Lehtiniemi <rayl@mail.com>");
0143 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
0144 MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
0145 MODULE_DESCRIPTION("EP93xx Watchdog");
0146 MODULE_LICENSE("GPL");