forked from Minki/linux
09fb6d010a
Introduce local variable 'struct device *dev' and use it instead of dereferencing it repeatedly. The conversion was done automatically with coccinelle using the following semantic patches. The semantic patches and the scripts used to generate this commit log are available at https://github.com/groeck/coccinelle-patches Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
127 lines
2.9 KiB
C
127 lines
2.9 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Watchdog driver for TQMx86 PLD.
|
|
*
|
|
* The watchdog supports power of 2 timeouts from 1 to 4096sec.
|
|
* Once started, it cannot be stopped.
|
|
*
|
|
* Based on the vendor code written by Vadim V.Vlasov
|
|
* <vvlasov@dev.rtsoft.ru>
|
|
*/
|
|
|
|
#include <linux/io.h>
|
|
#include <linux/log2.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/timer.h>
|
|
#include <linux/watchdog.h>
|
|
|
|
/* default timeout (secs) */
|
|
#define WDT_TIMEOUT 32
|
|
|
|
static unsigned int timeout;
|
|
module_param(timeout, uint, 0);
|
|
MODULE_PARM_DESC(timeout,
|
|
"Watchdog timeout in seconds. (1<=timeout<=4096, default="
|
|
__MODULE_STRING(WDT_TIMEOUT) ")");
|
|
struct tqmx86_wdt {
|
|
struct watchdog_device wdd;
|
|
void __iomem *io_base;
|
|
};
|
|
|
|
#define TQMX86_WDCFG 0x00 /* Watchdog Configuration Register */
|
|
#define TQMX86_WDCS 0x01 /* Watchdog Config/Status Register */
|
|
|
|
static int tqmx86_wdt_start(struct watchdog_device *wdd)
|
|
{
|
|
struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
|
|
|
|
iowrite8(0x81, priv->io_base + TQMX86_WDCS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tqmx86_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
|
|
{
|
|
struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd);
|
|
u8 val;
|
|
|
|
t = roundup_pow_of_two(t);
|
|
val = ilog2(t) | 0x90;
|
|
val += 3; /* values 0,1,2 correspond to 0.125,0.25,0.5s timeouts */
|
|
iowrite8(val, priv->io_base + TQMX86_WDCFG);
|
|
|
|
wdd->timeout = t;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct watchdog_info tqmx86_wdt_info = {
|
|
.options = WDIOF_SETTIMEOUT |
|
|
WDIOF_KEEPALIVEPING,
|
|
.identity = "TQMx86 Watchdog",
|
|
};
|
|
|
|
static struct watchdog_ops tqmx86_wdt_ops = {
|
|
.owner = THIS_MODULE,
|
|
.start = tqmx86_wdt_start,
|
|
.set_timeout = tqmx86_wdt_set_timeout,
|
|
};
|
|
|
|
static int tqmx86_wdt_probe(struct platform_device *pdev)
|
|
{
|
|
struct device *dev = &pdev->dev;
|
|
struct tqmx86_wdt *priv;
|
|
struct resource *res;
|
|
int err;
|
|
|
|
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
|
if (!priv)
|
|
return -ENOMEM;
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
|
|
if (!res)
|
|
return -ENODEV;
|
|
|
|
priv->io_base = devm_ioport_map(dev, res->start, resource_size(res));
|
|
if (!priv->io_base)
|
|
return -ENOMEM;
|
|
|
|
watchdog_set_drvdata(&priv->wdd, priv);
|
|
|
|
priv->wdd.parent = dev;
|
|
priv->wdd.info = &tqmx86_wdt_info;
|
|
priv->wdd.ops = &tqmx86_wdt_ops;
|
|
priv->wdd.min_timeout = 1;
|
|
priv->wdd.max_timeout = 4096;
|
|
priv->wdd.max_hw_heartbeat_ms = 4096*1000;
|
|
priv->wdd.timeout = WDT_TIMEOUT;
|
|
|
|
watchdog_init_timeout(&priv->wdd, timeout, dev);
|
|
watchdog_set_nowayout(&priv->wdd, WATCHDOG_NOWAYOUT);
|
|
|
|
tqmx86_wdt_set_timeout(&priv->wdd, priv->wdd.timeout);
|
|
|
|
err = devm_watchdog_register_device(dev, &priv->wdd);
|
|
if (err)
|
|
return err;
|
|
|
|
dev_info(dev, "TQMx86 watchdog\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver tqmx86_wdt_driver = {
|
|
.driver = {
|
|
.name = "tqmx86-wdt",
|
|
},
|
|
.probe = tqmx86_wdt_probe,
|
|
};
|
|
|
|
module_platform_driver(tqmx86_wdt_driver);
|
|
|
|
MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
|
|
MODULE_DESCRIPTION("TQMx86 Watchdog");
|
|
MODULE_ALIAS("platform:tqmx86-wdt");
|
|
MODULE_LICENSE("GPL");
|