summaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/max63xx_wdt.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-07-01 19:33:16 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2015-07-01 19:33:16 -0700
commit93899e39e86bfc021a190a9c26e8e516561f2756 (patch)
treec01fe48641d2a81acfa083748ef267a9607e84af /drivers/watchdog/max63xx_wdt.c
parent5f1201d515819e7cfaaac3f0a30ff7b556261386 (diff)
parentb2102eb36e7909c779e46f66595fda75aa219f4c (diff)
downloadlinux-93899e39e86bfc021a190a9c26e8e516561f2756.tar.bz2
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck: "This contains: - new driver for ST's LPC Watchdog - new driver for Conexant Digicolor CX92755 SoC - new driver for DA9062 watchdog - Addition of the watchdog registration deferral mechanism - several improvements on omap_wdt - several improvements and reboot-support for imgpdc_wdt - max63xx_wdt improvements - imx2_wdt improvements - dw_wdt improvements - and other small improvements and fixes" * git://www.linux-watchdog.org/linux-watchdog: (37 commits) watchdog: omap_wdt: early_enable module parameter watchdog: gpio_wdt: Add option for early registration watchdog: watchdog_core: Add watchdog registration deferral mechanism watchdog: max63xx: dynamically allocate device watchdog: imx2_wdt: Disable previously acquired clock on error path watchdog: imx2_wdt: Check for clk_prepare_enable() error watchdog: hpwdt: Add support for WDIOC_SETOPTIONS watchdog: docs: omap_wdt also understands nowayout watchdog: omap_wdt: implement get_timeleft watchdog: da9062: DA9062 watchdog driver watchdog: imx2_wdt: set watchdog parent device watchdog: mena21_wdt: Fix possible NULL pointer dereference watchdog: dw_wdt: keepalive the watchdog at write time watchdog: dw_wdt: No need for a spinlock watchdog: imx2_wdt: also set wdog->timeout to new_timeout watchdog: Allow compile test of GPIO consumers if !GPIOLIB watchdog: cadence: Add dependency on HAS_IOMEM watchdog: max63xx_wdt: Constify platform_device_id watchdog: MAX63XX_WATCHDOG does not depend on ARM watchdog: imgpdc: Add some documentation about the timeout ...
Diffstat (limited to 'drivers/watchdog/max63xx_wdt.c')
-rw-r--r--drivers/watchdog/max63xx_wdt.c172
1 files changed, 105 insertions, 67 deletions
diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c
index 08da3114accb..f36ca4be0720 100644
--- a/drivers/watchdog/max63xx_wdt.c
+++ b/drivers/watchdog/max63xx_wdt.c
@@ -39,10 +39,22 @@ static bool nowayout = WATCHDOG_NOWAYOUT;
#define MAX6369_WDSET (7 << 0)
#define MAX6369_WDI (1 << 3)
-static DEFINE_SPINLOCK(io_lock);
+#define MAX6369_WDSET_DISABLED 3
static int nodelay;
-static void __iomem *wdt_base;
+
+struct max63xx_wdt {
+ struct watchdog_device wdd;
+ const struct max63xx_timeout *timeout;
+
+ /* memory mapping */
+ void __iomem *base;
+ spinlock_t lock;
+
+ /* WDI and WSET bits write access routines */
+ void (*ping)(struct max63xx_wdt *wdt);
+ void (*set)(struct max63xx_wdt *wdt, u8 set);
+};
/*
* The timeout values used are actually the absolute minimum the chip
@@ -59,25 +71,25 @@ static void __iomem *wdt_base;
/* Timeouts in second */
struct max63xx_timeout {
- u8 wdset;
- u8 tdelay;
- u8 twd;
+ const u8 wdset;
+ const u8 tdelay;
+ const u8 twd;
};
-static struct max63xx_timeout max6369_table[] = {
+static const struct max63xx_timeout max6369_table[] = {
{ 5, 1, 1 },
{ 6, 10, 10 },
{ 7, 60, 60 },
{ },
};
-static struct max63xx_timeout max6371_table[] = {
+static const struct max63xx_timeout max6371_table[] = {
{ 6, 60, 3 },
{ 7, 60, 60 },
{ },
};
-static struct max63xx_timeout max6373_table[] = {
+static const struct max63xx_timeout max6373_table[] = {
{ 2, 60, 1 },
{ 5, 0, 1 },
{ 1, 3, 3 },
@@ -86,8 +98,6 @@ static struct max63xx_timeout max6373_table[] = {
{ },
};
-static struct max63xx_timeout *current_timeout;
-
static struct max63xx_timeout *
max63xx_select_timeout(struct max63xx_timeout *table, int value)
{
@@ -108,59 +118,32 @@ max63xx_select_timeout(struct max63xx_timeout *table, int value)
static int max63xx_wdt_ping(struct watchdog_device *wdd)
{
- u8 val;
-
- spin_lock(&io_lock);
+ struct max63xx_wdt *wdt = watchdog_get_drvdata(wdd);
- val = __raw_readb(wdt_base);
-
- __raw_writeb(val | MAX6369_WDI, wdt_base);
- __raw_writeb(val & ~MAX6369_WDI, wdt_base);
-
- spin_unlock(&io_lock);
+ wdt->ping(wdt);
return 0;
}
static int max63xx_wdt_start(struct watchdog_device *wdd)
{
- struct max63xx_timeout *entry = watchdog_get_drvdata(wdd);
- u8 val;
+ struct max63xx_wdt *wdt = watchdog_get_drvdata(wdd);
- spin_lock(&io_lock);
-
- val = __raw_readb(wdt_base);
- val &= ~MAX6369_WDSET;
- val |= entry->wdset;
- __raw_writeb(val, wdt_base);
-
- spin_unlock(&io_lock);
+ wdt->set(wdt, wdt->timeout->wdset);
/* check for a edge triggered startup */
- if (entry->tdelay == 0)
- max63xx_wdt_ping(wdd);
+ if (wdt->timeout->tdelay == 0)
+ wdt->ping(wdt);
return 0;
}
static int max63xx_wdt_stop(struct watchdog_device *wdd)
{
- u8 val;
+ struct max63xx_wdt *wdt = watchdog_get_drvdata(wdd);
- spin_lock(&io_lock);
-
- val = __raw_readb(wdt_base);
- val &= ~MAX6369_WDSET;
- val |= 3;
- __raw_writeb(val, wdt_base);
-
- spin_unlock(&io_lock);
+ wdt->set(wdt, MAX6369_WDSET_DISABLED);
return 0;
}
-static const struct watchdog_info max63xx_wdt_info = {
- .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
- .identity = "max63xx Watchdog",
-};
-
static const struct watchdog_ops max63xx_wdt_ops = {
.owner = THIS_MODULE,
.start = max63xx_wdt_start,
@@ -168,53 +151,108 @@ static const struct watchdog_ops max63xx_wdt_ops = {
.ping = max63xx_wdt_ping,
};
-static struct watchdog_device max63xx_wdt_dev = {
- .info = &max63xx_wdt_info,
- .ops = &max63xx_wdt_ops,
+static const struct watchdog_info max63xx_wdt_info = {
+ .options = WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+ .identity = "max63xx Watchdog",
};
+static void max63xx_mmap_ping(struct max63xx_wdt *wdt)
+{
+ u8 val;
+
+ spin_lock(&wdt->lock);
+
+ val = __raw_readb(wdt->base);
+
+ __raw_writeb(val | MAX6369_WDI, wdt->base);
+ __raw_writeb(val & ~MAX6369_WDI, wdt->base);
+
+ spin_unlock(&wdt->lock);
+}
+
+static void max63xx_mmap_set(struct max63xx_wdt *wdt, u8 set)
+{
+ u8 val;
+
+ spin_lock(&wdt->lock);
+
+ val = __raw_readb(wdt->base);
+ val &= ~MAX6369_WDSET;
+ val |= set & MAX6369_WDSET;
+ __raw_writeb(val, wdt->base);
+
+ spin_unlock(&wdt->lock);
+}
+
+static int max63xx_mmap_init(struct platform_device *p, struct max63xx_wdt *wdt)
+{
+ struct resource *mem = platform_get_resource(p, IORESOURCE_MEM, 0);
+
+ wdt->base = devm_ioremap_resource(&p->dev, mem);
+ if (IS_ERR(wdt->base))
+ return PTR_ERR(wdt->base);
+
+ spin_lock_init(&wdt->lock);
+
+ wdt->ping = max63xx_mmap_ping;
+ wdt->set = max63xx_mmap_set;
+ return 0;
+}
+
static int max63xx_wdt_probe(struct platform_device *pdev)
{
- struct resource *wdt_mem;
+ struct max63xx_wdt *wdt;
struct max63xx_timeout *table;
+ int err;
+
+ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+ if (!wdt)
+ return -ENOMEM;
table = (struct max63xx_timeout *)pdev->id_entry->driver_data;
if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
heartbeat = DEFAULT_HEARTBEAT;
- dev_info(&pdev->dev, "requesting %ds heartbeat\n", heartbeat);
- current_timeout = max63xx_select_timeout(table, heartbeat);
-
- if (!current_timeout) {
- dev_err(&pdev->dev, "unable to satisfy heartbeat request\n");
+ wdt->timeout = max63xx_select_timeout(table, heartbeat);
+ if (!wdt->timeout) {
+ dev_err(&pdev->dev, "unable to satisfy %ds heartbeat request\n",
+ heartbeat);
return -EINVAL;
}
- dev_info(&pdev->dev, "using %ds heartbeat with %ds initial delay\n",
- current_timeout->twd, current_timeout->tdelay);
+ err = max63xx_mmap_init(pdev, wdt);
+ if (err)
+ return err;
+
+ platform_set_drvdata(pdev, &wdt->wdd);
+ watchdog_set_drvdata(&wdt->wdd, wdt);
- heartbeat = current_timeout->twd;
+ wdt->wdd.parent = &pdev->dev;
+ wdt->wdd.timeout = wdt->timeout->twd;
+ wdt->wdd.info = &max63xx_wdt_info;
+ wdt->wdd.ops = &max63xx_wdt_ops;
- wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- wdt_base = devm_ioremap_resource(&pdev->dev, wdt_mem);
- if (IS_ERR(wdt_base))
- return PTR_ERR(wdt_base);
+ watchdog_set_nowayout(&wdt->wdd, nowayout);
- max63xx_wdt_dev.timeout = heartbeat;
- watchdog_set_nowayout(&max63xx_wdt_dev, nowayout);
- watchdog_set_drvdata(&max63xx_wdt_dev, current_timeout);
+ err = watchdog_register_device(&wdt->wdd);
+ if (err)
+ return err;
- return watchdog_register_device(&max63xx_wdt_dev);
+ dev_info(&pdev->dev, "using %ds heartbeat with %ds initial delay\n",
+ wdt->timeout->twd, wdt->timeout->tdelay);
+ return 0;
}
static int max63xx_wdt_remove(struct platform_device *pdev)
{
- watchdog_unregister_device(&max63xx_wdt_dev);
+ struct watchdog_device *wdd = platform_get_drvdata(pdev);
+
+ watchdog_unregister_device(wdd);
return 0;
}
-static struct platform_device_id max63xx_id_table[] = {
+static const struct platform_device_id max63xx_id_table[] = {
{ "max6369_wdt", (kernel_ulong_t)max6369_table, },
{ "max6370_wdt", (kernel_ulong_t)max6369_table, },
{ "max6371_wdt", (kernel_ulong_t)max6371_table, },