0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/io.h>
0013 #include <linux/log2.h>
0014 #include <linux/module.h>
0015 #include <linux/platform_device.h>
0016 #include <linux/timer.h>
0017 #include <linux/watchdog.h>
0018
0019
0020 #define WDT_TIMEOUT 32
0021
0022 static unsigned int timeout;
0023 module_param(timeout, uint, 0);
0024 MODULE_PARM_DESC(timeout,
0025 "Watchdog timeout in seconds. (1<=timeout<=4096, default="
0026 __MODULE_STRING(WDT_TIMEOUT) ")");
0027 struct tqmx86_wdt {
0028 struct watchdog_device wdd;
0029 void __iomem *io_base;
0030 };
0031
0032 #define TQMX86_WDCFG 0x00
0033 #define TQMX86_WDCS 0x01
0034
0035 static int tqmx86_wdt_start(struct watchdog_device *wdd)
0036 {
0037 struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
0038
0039 iowrite8(0x81, priv->io_base + TQMX86_WDCS);
0040
0041 return 0;
0042 }
0043
0044 static int tqmx86_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
0045 {
0046 struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
0047 u8 val;
0048
0049 t = roundup_pow_of_two(t);
0050 val = ilog2(t) | 0x90;
0051 val += 3;
0052 iowrite8(val, priv->io_base + TQMX86_WDCFG);
0053
0054 wdd->timeout = t;
0055
0056 return 0;
0057 }
0058
0059 static const struct watchdog_info tqmx86_wdt_info = {
0060 .options = WDIOF_SETTIMEOUT |
0061 WDIOF_KEEPALIVEPING,
0062 .identity = "TQMx86 Watchdog",
0063 };
0064
0065 static const struct watchdog_ops tqmx86_wdt_ops = {
0066 .owner = THIS_MODULE,
0067 .start = tqmx86_wdt_start,
0068 .set_timeout = tqmx86_wdt_set_timeout,
0069 };
0070
0071 static int tqmx86_wdt_probe(struct platform_device *pdev)
0072 {
0073 struct device *dev = &pdev->dev;
0074 struct tqmx86_wdt *priv;
0075 struct resource *res;
0076 int err;
0077
0078 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0079 if (!priv)
0080 return -ENOMEM;
0081
0082 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
0083 if (!res)
0084 return -ENODEV;
0085
0086 priv->io_base = devm_ioport_map(dev, res->start, resource_size(res));
0087 if (!priv->io_base)
0088 return -ENOMEM;
0089
0090 watchdog_set_drvdata(&priv->wdd, priv);
0091
0092 priv->wdd.parent = dev;
0093 priv->wdd.info = &tqmx86_wdt_info;
0094 priv->wdd.ops = &tqmx86_wdt_ops;
0095 priv->wdd.min_timeout = 1;
0096 priv->wdd.max_timeout = 4096;
0097 priv->wdd.max_hw_heartbeat_ms = 4096*1000;
0098 priv->wdd.timeout = WDT_TIMEOUT;
0099
0100 watchdog_init_timeout(&priv->wdd, timeout, dev);
0101 watchdog_set_nowayout(&priv->wdd, WATCHDOG_NOWAYOUT);
0102
0103 tqmx86_wdt_set_timeout(&priv->wdd, priv->wdd.timeout);
0104
0105 err = devm_watchdog_register_device(dev, &priv->wdd);
0106 if (err)
0107 return err;
0108
0109 dev_info(dev, "TQMx86 watchdog\n");
0110
0111 return 0;
0112 }
0113
0114 static struct platform_driver tqmx86_wdt_driver = {
0115 .driver = {
0116 .name = "tqmx86-wdt",
0117 },
0118 .probe = tqmx86_wdt_probe,
0119 };
0120
0121 module_platform_driver(tqmx86_wdt_driver);
0122
0123 MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
0124 MODULE_DESCRIPTION("TQMx86 Watchdog");
0125 MODULE_ALIAS("platform:tqmx86-wdt");
0126 MODULE_LICENSE("GPL");