From f3519a662f5f8abf6411a238b1af08a0101878c7 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Tue, 20 Dec 2016 19:56:59 +0100 Subject: watchdog: update my email address This patch updates my email address as I no longer have access to the old one. Signed-off-by: John Crispin Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/lantiq_wdt.c | 4 ++-- drivers/watchdog/mt7621_wdt.c | 4 ++-- drivers/watchdog/rt2880_wdt.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c index 582f2fa1b8d9..e0823677d8c1 100644 --- a/drivers/watchdog/lantiq_wdt.c +++ b/drivers/watchdog/lantiq_wdt.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright (C) 2010 John Crispin + * Copyright (C) 2010 John Crispin * Based on EP93xx wdt driver */ @@ -240,6 +240,6 @@ module_platform_driver(ltq_wdt_driver); module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); -MODULE_AUTHOR("John Crispin "); +MODULE_AUTHOR("John Crispin "); MODULE_DESCRIPTION("Lantiq SoC Watchdog"); MODULE_LICENSE("GPL"); diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c index d5735c12067d..2fb5a3085521 100644 --- a/drivers/watchdog/mt7621_wdt.c +++ b/drivers/watchdog/mt7621_wdt.c @@ -1,7 +1,7 @@ /* * Ralink MT7621/MT7628 built-in hardware watchdog timer * - * Copyright (C) 2014 John Crispin + * Copyright (C) 2014 John Crispin * * This driver was based on: drivers/watchdog/rt2880_wdt.c * @@ -181,5 +181,5 @@ static struct platform_driver mt7621_wdt_driver = { module_platform_driver(mt7621_wdt_driver); MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver"); -MODULE_AUTHOR("John Crispin - * Copyright (C) 2013 John Crispin + * Copyright (C) 2013 John Crispin * * This driver was based on: drivers/watchdog/softdog.c * -- cgit v1.2.3 From 027d89d96b6833f37091d858b9dcf92cd9b19aa7 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 21 Dec 2016 03:18:16 +0200 Subject: watchdog: sa11x0/pxa: fix error path of driver initialization The change corrects release of captured resources on error path, namely the clock is disabled and put if misc device registration fails and not enabled clock is not disabled now. Fixes: 6924089c488e ("watchdog: sa11x0/pxa: get rid of get_clock_tick_rate") Signed-off-by: Vladimir Zapolskiy Acked-by: Robert Jarzmik Reviewed-by: Guenter Roeck Acked-by: Russell King Signed-off-by: Guenter Roeck --- drivers/watchdog/sa1100_wdt.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c index 8965e3f536c3..d3be4f831db5 100644 --- a/drivers/watchdog/sa1100_wdt.c +++ b/drivers/watchdog/sa1100_wdt.c @@ -188,12 +188,14 @@ static int __init sa1100dog_init(void) pre_margin = oscr_freq * margin; ret = misc_register(&sa1100dog_miscdev); - if (ret == 0) + if (ret == 0) { pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", margin); - return ret; -err: + return 0; + } + clk_disable_unprepare(clk); +err: clk_put(clk); return ret; } -- cgit v1.2.3 From 8d97005e01445921b429e92d7c425a86f76050ab Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 24 Dec 2016 21:37:32 +0530 Subject: watchdog: booke_wdt: add __ro_after_init to booke_wdt_info The object booke_wdt_info of watchdog_info structure is not modified after getting initialized by booke_wdt_init. Apart from getting referenced in init it is also stored in the info field of watchdog_device structure which is of type const struct watchdog_info *info. So, it becomes read only after init and therefore add __ro_after_init to it's declaration. Signed-off-by: Bhumika Goyal Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/booke_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index 04da4b66c75e..ae034bb1e551 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -192,7 +192,7 @@ static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev, return 0; } -static struct watchdog_info booke_wdt_info = { +static struct watchdog_info booke_wdt_info __ro_after_init = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .identity = "PowerPC Book-E Watchdog", }; -- cgit v1.2.3 From cb5f9d406d50fc01c6564956ed9317614e665208 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sun, 25 Dec 2016 13:30:24 +0530 Subject: watchdog: pika_wdt: add __ro_after_init to ident The object ident of type watchdog_info structure is not modified after getting initialized by pikawdt_init. Apart from getting referenced in init it is also passed as an argument to the function copy_to_user but this argument is of type const void *. Therefore add __ro_after_init to its declaration. Signed-off-by: Bhumika Goyal Signed-off-by: Guenter Roeck --- drivers/watchdog/pika_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c index 0cdfee266690..e35cf5e87907 100644 --- a/drivers/watchdog/pika_wdt.c +++ b/drivers/watchdog/pika_wdt.c @@ -54,7 +54,7 @@ static struct { struct timer_list timer; /* The timer that pings the watchdog */ } pikawdt_private; -static struct watchdog_info ident = { +static struct watchdog_info ident __ro_after_init = { .identity = DRV_NAME, .options = WDIOF_CARDRESET | WDIOF_SETTIMEOUT | -- cgit v1.2.3 From 6c368932f0d885e54b8af06d699b6d559e86f0cd Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 26 Dec 2016 22:35:11 +0530 Subject: watchdog: constify watchdog_info structures Declare watchdog_info structures as const as they are only stored in the info field of watchdog_device structures. This field is of type const struct watchdog_info *, so watchdog_info structures having this property can be declared const too. Done using Coccinelle: @r1 disable optional_qualifier@ identifier i; position p; @@ static struct watchdog_info i@p={...}; @ok@ identifier r1.i; position p; struct watchdog_device obj; @@ obj.info=&i@p; @bad@ position p!={r1.p,ok.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct watchdog_info i; Signed-off-by: Bhumika Goyal Acked-by: Florian Fainelli Acked-by: Baruch Siach Reviewed-by: Guenter Roeck Acked-by: Adam Thomson Signed-off-by: Guenter Roeck --- drivers/watchdog/bcm7038_wdt.c | 2 +- drivers/watchdog/bcm_kona_wdt.c | 2 +- drivers/watchdog/cadence_wdt.c | 2 +- drivers/watchdog/da9052_wdt.c | 2 +- drivers/watchdog/da9055_wdt.c | 2 +- drivers/watchdog/digicolor_wdt.c | 2 +- drivers/watchdog/imgpdc_wdt.c | 2 +- drivers/watchdog/kempld_wdt.c | 2 +- drivers/watchdog/lpc18xx_wdt.c | 2 +- drivers/watchdog/rn5t618_wdt.c | 2 +- drivers/watchdog/sbsa_gwdt.c | 2 +- drivers/watchdog/w83627hf_wdt.c | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c index 4814c00b32f6..c1b8e534fb55 100644 --- a/drivers/watchdog/bcm7038_wdt.c +++ b/drivers/watchdog/bcm7038_wdt.c @@ -101,7 +101,7 @@ static unsigned int bcm7038_wdt_get_timeleft(struct watchdog_device *wdog) return time_left / wdt->rate; } -static struct watchdog_info bcm7038_wdt_info = { +static const struct watchdog_info bcm7038_wdt_info = { .identity = "Broadcom BCM7038 Watchdog Timer", .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c index e0c98423f2c9..76b00805cd87 100644 --- a/drivers/watchdog/bcm_kona_wdt.c +++ b/drivers/watchdog/bcm_kona_wdt.c @@ -274,7 +274,7 @@ static struct watchdog_ops bcm_kona_wdt_ops = { .get_timeleft = bcm_kona_wdt_get_timeleft, }; -static struct watchdog_info bcm_kona_wdt_info = { +static const struct watchdog_info bcm_kona_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, .identity = "Broadcom Kona Watchdog Timer", diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c index 98acef72334d..8d61e8bfe60b 100644 --- a/drivers/watchdog/cadence_wdt.c +++ b/drivers/watchdog/cadence_wdt.c @@ -262,7 +262,7 @@ static irqreturn_t cdns_wdt_irq_handler(int irq, void *dev_id) * Info structure used to indicate the features supported by the device * to the upper layers. This is defined in watchdog.h header file. */ -static struct watchdog_info cdns_wdt_info = { +static const struct watchdog_info cdns_wdt_info = { .identity = "cdns_wdt watchdog", .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c index 2fc19a32a320..d86a57e3d17d 100644 --- a/drivers/watchdog/da9052_wdt.c +++ b/drivers/watchdog/da9052_wdt.c @@ -140,7 +140,7 @@ err_strobe: return ret; } -static struct watchdog_info da9052_wdt_info = { +static const struct watchdog_info da9052_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .identity = "DA9052 Watchdog", }; diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c index 8377c43f3f20..4f30818cf93f 100644 --- a/drivers/watchdog/da9055_wdt.c +++ b/drivers/watchdog/da9055_wdt.c @@ -108,7 +108,7 @@ static int da9055_wdt_stop(struct watchdog_device *wdt_dev) return da9055_wdt_set_timeout(wdt_dev, 0); } -static struct watchdog_info da9055_wdt_info = { +static const struct watchdog_info da9055_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .identity = "DA9055 Watchdog", }; diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c index 77df772406b0..dfe72944822d 100644 --- a/drivers/watchdog/digicolor_wdt.c +++ b/drivers/watchdog/digicolor_wdt.c @@ -105,7 +105,7 @@ static struct watchdog_ops dc_wdt_ops = { .restart = dc_wdt_restart, }; -static struct watchdog_info dc_wdt_info = { +static const struct watchdog_info dc_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, .identity = "Conexant Digicolor Watchdog", diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c index 516fbef00856..6ed39dee995f 100644 --- a/drivers/watchdog/imgpdc_wdt.c +++ b/drivers/watchdog/imgpdc_wdt.c @@ -161,7 +161,7 @@ static int pdc_wdt_restart(struct watchdog_device *wdt_dev, return 0; } -static struct watchdog_info pdc_wdt_info = { +static const struct watchdog_info pdc_wdt_info = { .identity = "IMG PDC Watchdog", .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | diff --git a/drivers/watchdog/kempld_wdt.c b/drivers/watchdog/kempld_wdt.c index 8e302d0e346c..73c46b3a09ab 100644 --- a/drivers/watchdog/kempld_wdt.c +++ b/drivers/watchdog/kempld_wdt.c @@ -422,7 +422,7 @@ static int kempld_wdt_probe_stages(struct watchdog_device *wdd) return 0; } -static struct watchdog_info kempld_wdt_info = { +static const struct watchdog_info kempld_wdt_info = { .identity = "KEMPLD Watchdog", .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c index fd171e6caa16..3b8bb59adf02 100644 --- a/drivers/watchdog/lpc18xx_wdt.c +++ b/drivers/watchdog/lpc18xx_wdt.c @@ -181,7 +181,7 @@ static int lpc18xx_wdt_restart(struct watchdog_device *wdt_dev, return 0; } -static struct watchdog_info lpc18xx_wdt_info = { +static const struct watchdog_info lpc18xx_wdt_info = { .identity = "NXP LPC18xx Watchdog", .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | diff --git a/drivers/watchdog/rn5t618_wdt.c b/drivers/watchdog/rn5t618_wdt.c index 0805ee2acd7a..e60f55702ab7 100644 --- a/drivers/watchdog/rn5t618_wdt.c +++ b/drivers/watchdog/rn5t618_wdt.c @@ -130,7 +130,7 @@ static int rn5t618_wdt_ping(struct watchdog_device *wdt_dev) RN5T618_PWRIRQ_IR_WDOG, 0); } -static struct watchdog_info rn5t618_wdt_info = { +static const struct watchdog_info rn5t618_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, .identity = DRIVER_NAME, diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index ce0c38bd0f00..e9966bc8c23e 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -207,7 +207,7 @@ static irqreturn_t sbsa_gwdt_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static struct watchdog_info sbsa_gwdt_info = { +static const struct watchdog_info sbsa_gwdt_info = { .identity = WATCHDOG_NAME, .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index ef2ecaf53a14..98fd186c6878 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -297,7 +297,7 @@ static unsigned int wdt_get_time(struct watchdog_device *wdog) * Kernel Interfaces */ -static struct watchdog_info wdt_info = { +static const struct watchdog_info wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .identity = "W83627HF Watchdog", }; -- cgit v1.2.3 From 98078ca34a0a71d012e88d6d0a7de18d11c44f96 Mon Sep 17 00:00:00 2001 From: Hui Chun Ong Date: Wed, 28 Dec 2016 15:51:40 +0800 Subject: watchdog: nic7018_wdt: Add NIC7018 watchdog driver Add support for the watchdog timer on PXI Embedded Controller. Signed-off-by: Hui Chun Ong Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- Documentation/watchdog/watchdog-parameters.txt | 5 + drivers/watchdog/Kconfig | 10 + drivers/watchdog/Makefile | 1 + drivers/watchdog/nic7018_wdt.c | 265 +++++++++++++++++++++++++ 4 files changed, 281 insertions(+) create mode 100644 drivers/watchdog/nic7018_wdt.c diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt index e21850e270a0..4f7d86dd0a5d 100644 --- a/Documentation/watchdog/watchdog-parameters.txt +++ b/Documentation/watchdog/watchdog-parameters.txt @@ -209,6 +209,11 @@ timeout: Initial watchdog timeout in seconds (0 +#include +#include +#include +#include +#include +#include + +#define LOCK 0xA5 +#define UNLOCK 0x5A + +#define WDT_CTRL_RESET_EN BIT(7) +#define WDT_RELOAD_PORT_EN BIT(7) + +#define WDT_CTRL 1 +#define WDT_RELOAD_CTRL 2 +#define WDT_PRESET_PRESCALE 4 +#define WDT_REG_LOCK 5 +#define WDT_COUNT 6 +#define WDT_RELOAD_PORT 7 + +#define WDT_MIN_TIMEOUT 1 +#define WDT_MAX_TIMEOUT 464 +#define WDT_DEFAULT_TIMEOUT 80 + +#define WDT_MAX_COUNTER 15 + +static unsigned int timeout; +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, + "Watchdog timeout in seconds. (default=" + __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")"); + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started. (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +struct nic7018_wdt { + u16 io_base; + u32 period; + struct watchdog_device wdd; +}; + +struct nic7018_config { + u32 period; + u8 divider; +}; + +static const struct nic7018_config nic7018_configs[] = { + { 2, 4 }, + { 32, 5 }, +}; + +static inline u32 nic7018_timeout(u32 period, u8 counter) +{ + return period * counter - period / 2; +} + +static const struct nic7018_config *nic7018_get_config(u32 timeout, + u8 *counter) +{ + const struct nic7018_config *config; + u8 count; + + if (timeout < 30 && timeout != 16) { + config = &nic7018_configs[0]; + count = timeout / 2 + 1; + } else { + config = &nic7018_configs[1]; + count = DIV_ROUND_UP(timeout + 16, 32); + + if (count > WDT_MAX_COUNTER) + count = WDT_MAX_COUNTER; + } + *counter = count; + return config; +} + +static int nic7018_set_timeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); + const struct nic7018_config *config; + u8 counter; + + config = nic7018_get_config(timeout, &counter); + + outb(counter << 4 | config->divider, + wdt->io_base + WDT_PRESET_PRESCALE); + + wdd->timeout = nic7018_timeout(config->period, counter); + wdt->period = config->period; + + return 0; +} + +static int nic7018_start(struct watchdog_device *wdd) +{ + struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); + u8 control; + + nic7018_set_timeout(wdd, wdd->timeout); + + control = inb(wdt->io_base + WDT_RELOAD_CTRL); + outb(control | WDT_RELOAD_PORT_EN, wdt->io_base + WDT_RELOAD_CTRL); + + outb(1, wdt->io_base + WDT_RELOAD_PORT); + + control = inb(wdt->io_base + WDT_CTRL); + outb(control | WDT_CTRL_RESET_EN, wdt->io_base + WDT_CTRL); + + return 0; +} + +static int nic7018_stop(struct watchdog_device *wdd) +{ + struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); + + outb(0, wdt->io_base + WDT_CTRL); + outb(0, wdt->io_base + WDT_RELOAD_CTRL); + outb(0xF0, wdt->io_base + WDT_PRESET_PRESCALE); + + return 0; +} + +static int nic7018_ping(struct watchdog_device *wdd) +{ + struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); + + outb(1, wdt->io_base + WDT_RELOAD_PORT); + + return 0; +} + +static unsigned int nic7018_get_timeleft(struct watchdog_device *wdd) +{ + struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); + u8 count; + + count = inb(wdt->io_base + WDT_COUNT) & 0xF; + if (!count) + return 0; + + return nic7018_timeout(wdt->period, count); +} + +static const struct watchdog_info nic7018_wdd_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, + .identity = "NIC7018 Watchdog", +}; + +static const struct watchdog_ops nic7018_wdd_ops = { + .owner = THIS_MODULE, + .start = nic7018_start, + .stop = nic7018_stop, + .ping = nic7018_ping, + .set_timeout = nic7018_set_timeout, + .get_timeleft = nic7018_get_timeleft, +}; + +static int nic7018_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct watchdog_device *wdd; + struct nic7018_wdt *wdt; + struct resource *io_rc; + int ret; + + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + platform_set_drvdata(pdev, wdt); + + io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!io_rc) { + dev_err(dev, "missing IO resources\n"); + return -EINVAL; + } + + if (!devm_request_region(dev, io_rc->start, resource_size(io_rc), + KBUILD_MODNAME)) { + dev_err(dev, "failed to get IO region\n"); + return -EBUSY; + } + + wdt->io_base = io_rc->start; + wdd = &wdt->wdd; + wdd->info = &nic7018_wdd_info; + wdd->ops = &nic7018_wdd_ops; + wdd->min_timeout = WDT_MIN_TIMEOUT; + wdd->max_timeout = WDT_MAX_TIMEOUT; + wdd->timeout = WDT_DEFAULT_TIMEOUT; + wdd->parent = dev; + + watchdog_set_drvdata(wdd, wdt); + watchdog_set_nowayout(wdd, nowayout); + + ret = watchdog_init_timeout(wdd, timeout, dev); + if (ret) + dev_warn(dev, "unable to set timeout value, using default\n"); + + /* Unlock WDT register */ + outb(UNLOCK, wdt->io_base + WDT_REG_LOCK); + + ret = watchdog_register_device(wdd); + if (ret) { + outb(LOCK, wdt->io_base + WDT_REG_LOCK); + dev_err(dev, "failed to register watchdog\n"); + return ret; + } + + dev_dbg(dev, "io_base=0x%04X, timeout=%d, nowayout=%d\n", + wdt->io_base, timeout, nowayout); + return 0; +} + +static int nic7018_remove(struct platform_device *pdev) +{ + struct nic7018_wdt *wdt = platform_get_drvdata(pdev); + + watchdog_unregister_device(&wdt->wdd); + + /* Lock WDT register */ + outb(LOCK, wdt->io_base + WDT_REG_LOCK); + + return 0; +} + +static const struct acpi_device_id nic7018_device_ids[] = { + {"NIC7018", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, nic7018_device_ids); + +static struct platform_driver watchdog_driver = { + .probe = nic7018_probe, + .remove = nic7018_remove, + .driver = { + .name = KBUILD_MODNAME, + .acpi_match_table = ACPI_PTR(nic7018_device_ids), + }, +}; + +module_platform_driver(watchdog_driver); + +MODULE_DESCRIPTION("National Instruments NIC7018 Watchdog driver"); +MODULE_AUTHOR("Hui Chun Ong "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e628a0c1fdcdcde69037822feb27d81d02e7658c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 29 Dec 2016 08:34:50 -0800 Subject: watchdog: pnx833x_wdt: Mark as broken pnx833x_wdt does not compile if enabled. Bit operations expect an unsigned long as argument. If that is fixed, the build still fails because put_user, get_user, and copy_to_user are undefined. Mark it as broken. Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index e20eb42864ef..8c8b6f6e78c6 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1401,6 +1401,7 @@ config WDT_MTX1 config PNX833X_WDT tristate "PNX833x Hardware Watchdog" depends on SOC_PNX8335 + depends on BROKEN help Hardware driver for the PNX833x's watchdog. This is a watchdog timer that will reboot the machine after a programmable -- cgit v1.2.3 From da2a68b3eb47b9fb071def3f374258b2ce454096 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 29 Dec 2016 07:20:23 -0800 Subject: watchdog: Enable COMPILE_TEST where possible Building all watchdog drivers is all but impossible since many depend on platforms which are not enabled by test builds. Add dependency on COMPILE_TEST where possible to improve the situation. Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 118 +++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 8c8b6f6e78c6..f7cb150d43d6 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -73,7 +73,7 @@ config SOFT_WATCHDOG config DA9052_WATCHDOG tristate "Dialog DA9052 Watchdog" - depends on PMIC_DA9052 + depends on PMIC_DA9052 || COMPILE_TEST select WATCHDOG_CORE help Support for the watchdog in the DA9052 PMIC. Watchdog trigger @@ -85,7 +85,7 @@ config DA9052_WATCHDOG config DA9055_WATCHDOG tristate "Dialog Semiconductor DA9055 Watchdog" - depends on MFD_DA9055 + depends on MFD_DA9055 || COMPILE_TEST select WATCHDOG_CORE help If you say yes here you get support for watchdog on the Dialog @@ -96,7 +96,7 @@ config DA9055_WATCHDOG config DA9063_WATCHDOG tristate "Dialog DA9063 Watchdog" - depends on MFD_DA9063 + depends on MFD_DA9063 || COMPILE_TEST select WATCHDOG_CORE help Support for the watchdog in the DA9063 PMIC. @@ -105,7 +105,7 @@ config DA9063_WATCHDOG config DA9062_WATCHDOG tristate "Dialog DA9062/61 Watchdog" - depends on MFD_DA9062 + depends on MFD_DA9062 || COMPILE_TEST select WATCHDOG_CORE help Support for the watchdog in the DA9062 and DA9061 PMICs. @@ -133,7 +133,7 @@ config GPIO_WATCHDOG_ARCH_INITCALL config MENF21BMC_WATCHDOG tristate "MEN 14F021P00 BMC Watchdog" - depends on MFD_MENF21BMC + depends on MFD_MENF21BMC || COMPILE_TEST select WATCHDOG_CORE help Say Y here to include support for the MEN 14F021P00 BMC Watchdog. @@ -168,7 +168,7 @@ config WDAT_WDT config WM831X_WATCHDOG tristate "WM831x watchdog" - depends on MFD_WM831X + depends on MFD_WM831X || COMPILE_TEST select WATCHDOG_CORE help Support for the watchdog in the WM831x AudioPlus PMICs. When @@ -209,7 +209,7 @@ config ZIIRAVE_WATCHDOG config ARM_SP805_WATCHDOG tristate "ARM SP805 Watchdog" - depends on (ARM || ARM64) && ARM_AMBA + depends on (ARM || ARM64) && (ARM_AMBA || COMPILE_TEST) select WATCHDOG_CORE help ARM Primecell SP805 Watchdog timer. This will reboot your system when @@ -237,7 +237,7 @@ config ARM_SBSA_WATCHDOG config ASM9260_WATCHDOG tristate "Alphascale ASM9260 watchdog" - depends on MACH_ASM9260 + depends on MACH_ASM9260 || COMPILE_TEST depends on OF select WATCHDOG_CORE select RESET_CONTROLLER @@ -247,14 +247,14 @@ config ASM9260_WATCHDOG config AT91RM9200_WATCHDOG tristate "AT91RM9200 watchdog" - depends on SOC_AT91RM9200 && MFD_SYSCON + depends on (SOC_AT91RM9200 && MFD_SYSCON) || COMPILE_TEST help Watchdog timer embedded into AT91RM9200 chips. This will reboot your system when the timeout is reached. config AT91SAM9X_WATCHDOG tristate "AT91SAM9X / AT91CAP9 watchdog" - depends on ARCH_AT91 + depends on ARCH_AT91 || COMPILE_TEST select WATCHDOG_CORE help Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will @@ -262,7 +262,7 @@ config AT91SAM9X_WATCHDOG config SAMA5D4_WATCHDOG tristate "Atmel SAMA5D4 Watchdog Timer" - depends on ARCH_AT91 + depends on ARCH_AT91 || COMPILE_TEST select WATCHDOG_CORE help Atmel SAMA5D4 watchdog timer is embedded into SAMA5D4 chips. @@ -293,7 +293,7 @@ config 21285_WATCHDOG config 977_WATCHDOG tristate "NetWinder WB83C977 watchdog" - depends on FOOTBRIDGE && ARCH_NETWINDER + depends on (FOOTBRIDGE && ARCH_NETWINDER) || (ARM && COMPILE_TEST) help Say Y here to include support for the WB977 watchdog included in NetWinder machines. Alternatively say M to compile the driver as @@ -333,7 +333,7 @@ config HAVE_S3C2410_WATCHDOG config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" - depends on HAVE_S3C2410_WATCHDOG + depends on HAVE_S3C2410_WATCHDOG || COMPILE_TEST select WATCHDOG_CORE select MFD_SYSCON if ARCH_EXYNOS5 help @@ -372,7 +372,7 @@ config DW_WATCHDOG config EP93XX_WATCHDOG tristate "EP93xx Watchdog" - depends on ARCH_EP93XX + depends on ARCH_EP93XX || COMPILE_TEST select WATCHDOG_CORE help Say Y here if to include support for the watchdog timer @@ -383,7 +383,7 @@ config EP93XX_WATCHDOG config OMAP_WATCHDOG tristate "OMAP Watchdog" - depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS + depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || COMPILE_TEST select WATCHDOG_CORE help Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y' @@ -419,7 +419,7 @@ config IOP_WATCHDOG config DAVINCI_WATCHDOG tristate "DaVinci watchdog" - depends on ARCH_DAVINCI || ARCH_KEYSTONE + depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST select WATCHDOG_CORE help Say Y here if to include support for the watchdog timer @@ -432,7 +432,7 @@ config DAVINCI_WATCHDOG config ORION_WATCHDOG tristate "Orion watchdog" - depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU + depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU || COMPILE_TEST depends on ARM select WATCHDOG_CORE help @@ -443,7 +443,7 @@ config ORION_WATCHDOG config RN5T618_WATCHDOG tristate "Ricoh RN5T618 watchdog" - depends on MFD_RN5T618 + depends on MFD_RN5T618 || COMPILE_TEST select WATCHDOG_CORE help If you say yes here you get support for watchdog on the Ricoh @@ -454,7 +454,7 @@ config RN5T618_WATCHDOG config SUNXI_WATCHDOG tristate "Allwinner SoCs watchdog support" - depends on ARCH_SUNXI + depends on ARCH_SUNXI || COMPILE_TEST select WATCHDOG_CORE help Say Y here to include support for the watchdog timer @@ -464,7 +464,7 @@ config SUNXI_WATCHDOG config COH901327_WATCHDOG bool "ST-Ericsson COH 901 327 watchdog" - depends on ARCH_U300 + depends on ARCH_U300 || (ARM && COMPILE_TEST) default y if MACH_U300 select WATCHDOG_CORE help @@ -483,7 +483,7 @@ config TWL4030_WATCHDOG config STMP3XXX_RTC_WATCHDOG tristate "Freescale STMP3XXX & i.MX23/28 watchdog" - depends on RTC_DRV_STMP + depends on RTC_DRV_STMP || COMPILE_TEST select WATCHDOG_CORE help Say Y here to include support for the watchdog timer inside @@ -493,7 +493,7 @@ config STMP3XXX_RTC_WATCHDOG config NUC900_WATCHDOG tristate "Nuvoton NUC900 watchdog" - depends on ARCH_W90X900 + depends on ARCH_W90X900 || COMPILE_TEST help Say Y here if to include support for the watchdog timer for the Nuvoton NUC900 series SoCs. @@ -513,7 +513,7 @@ config TS4800_WATCHDOG config TS72XX_WATCHDOG tristate "TS-72XX SBC Watchdog" - depends on MACH_TS72XX + depends on MACH_TS72XX || COMPILE_TEST help Technologic Systems TS-7200, TS-7250 and TS-7260 boards have watchdog timer implemented in a external CPLD chip. Say Y here @@ -531,7 +531,7 @@ config MAX63XX_WATCHDOG config MAX77620_WATCHDOG tristate "Maxim Max77620 Watchdog Timer" - depends on MFD_MAX77620 + depends on MFD_MAX77620 || COMPILE_TEST help This is the driver for the Max77620 watchdog timer. Say 'Y' here to enable the watchdog timer support for @@ -540,7 +540,7 @@ config MAX77620_WATCHDOG config IMX2_WDT tristate "IMX2+ Watchdog" - depends on ARCH_MXC || ARCH_LAYERSCAPE + depends on ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST select REGMAP_MMIO select WATCHDOG_CORE help @@ -554,7 +554,7 @@ config IMX2_WDT config UX500_WATCHDOG tristate "ST-Ericsson Ux500 watchdog" - depends on MFD_DB8500_PRCMU + depends on MFD_DB8500_PRCMU || (ARM && COMPILE_TEST) select WATCHDOG_CORE default y help @@ -566,7 +566,7 @@ config UX500_WATCHDOG config RETU_WATCHDOG tristate "Retu watchdog" - depends on MFD_RETU + depends on MFD_RETU || COMPILE_TEST select WATCHDOG_CORE help Retu watchdog driver for Nokia Internet Tablets (770, N800, @@ -578,7 +578,7 @@ config RETU_WATCHDOG config MOXART_WDT tristate "MOXART watchdog" - depends on ARCH_MOXART + depends on ARCH_MOXART || COMPILE_TEST help Say Y here to include Watchdog timer support for the watchdog existing on the MOXA ART SoC series platforms. @@ -588,7 +588,7 @@ config MOXART_WDT config SIRFSOC_WATCHDOG tristate "SiRFSOC watchdog" - depends on ARCH_SIRF + depends on ARCH_SIRF || COMPILE_TEST select WATCHDOG_CORE default y help @@ -597,7 +597,7 @@ config SIRFSOC_WATCHDOG config ST_LPC_WATCHDOG tristate "STMicroelectronics LPC Watchdog" - depends on ARCH_STI + depends on ARCH_STI || COMPILE_TEST depends on OF select WATCHDOG_CORE help @@ -621,7 +621,7 @@ config TEGRA_WATCHDOG config QCOM_WDT tristate "QCOM watchdog" depends on HAS_IOMEM - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST select WATCHDOG_CORE help Say Y here to include Watchdog timer support for the watchdog found @@ -633,7 +633,7 @@ config QCOM_WDT config MESON_GXBB_WATCHDOG tristate "Amlogic Meson GXBB SoCs watchdog support" - depends on ARCH_MESON + depends on ARCH_MESON || COMPILE_TEST select WATCHDOG_CORE help Say Y here to include support for the watchdog timer @@ -643,7 +643,7 @@ config MESON_GXBB_WATCHDOG config MESON_WATCHDOG tristate "Amlogic Meson SoCs watchdog support" - depends on ARCH_MESON + depends on ARCH_MESON || COMPILE_TEST select WATCHDOG_CORE help Say Y here to include support for the watchdog timer @@ -653,7 +653,7 @@ config MESON_WATCHDOG config MEDIATEK_WATCHDOG tristate "Mediatek SoCs watchdog support" - depends on ARCH_MEDIATEK + depends on ARCH_MEDIATEK || COMPILE_TEST select WATCHDOG_CORE help Say Y here to include support for the watchdog timer @@ -663,7 +663,7 @@ config MEDIATEK_WATCHDOG config DIGICOLOR_WATCHDOG tristate "Conexant Digicolor SoCs watchdog support" - depends on ARCH_DIGICOLOR + depends on ARCH_DIGICOLOR || COMPILE_TEST select WATCHDOG_CORE help Say Y here to include support for the watchdog timer @@ -685,7 +685,7 @@ config LPC18XX_WATCHDOG config ATLAS7_WATCHDOG tristate "CSRatlas7 watchdog" - depends on ARCH_ATLAS7 + depends on ARCH_ATLAS7 || COMPILE_TEST help Say Y here to include Watchdog timer support for the watchdog existing on the CSRatlas7 series platforms. @@ -718,7 +718,7 @@ config ASPEED_WATCHDOG config AT32AP700X_WDT tristate "AT32AP700x watchdog" - depends on CPU_AT32AP700X + depends on CPU_AT32AP700X || COMPILE_TEST help Watchdog timer embedded into AT32AP700x devices. This will reboot your system when the timeout is reached. @@ -822,7 +822,7 @@ config SP5100_TCO config GEODE_WDT tristate "AMD Geode CS5535/CS5536 Watchdog" - depends on CS5535_MFGPT + depends on CS5535_MFGPT || (X86 && COMPILE_TEST) help This driver enables a watchdog capability built into the CS5535/CS5536 companion chips for the AMD Geode GX and LX @@ -835,7 +835,7 @@ config GEODE_WDT config SC520_WDT tristate "AMD Elan SC520 processor Watchdog" - depends on MELAN + depends on MELAN || COMPILE_TEST help This is the driver for the hardware watchdog built in to the AMD "Elan" SC520 microcomputer commonly used in embedded systems. @@ -1034,7 +1034,7 @@ config HP_WATCHDOG config KEMPLD_WDT tristate "Kontron COM Watchdog Timer" - depends on MFD_KEMPLD + depends on MFD_KEMPLD || COMPILE_TEST select WATCHDOG_CORE help Support for the PLD watchdog on some Kontron ETX and COMexpress @@ -1108,7 +1108,7 @@ config NV_TCO config RDC321X_WDT tristate "RDC R-321x SoC watchdog" - depends on X86_RDC321X + depends on X86_RDC321X || COMPILE_TEST help This is the driver for the built in hardware watchdog in the RDC R-321x SoC. @@ -1353,14 +1353,14 @@ config M54xx_WATCHDOG config ATH79_WDT tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog" - depends on ATH79 + depends on ATH79 || (ARM && COMPILE_TEST) help Hardware driver for the built-in watchdog timer on the Atheros AR71XX/AR724X/AR913X SoCs. config BCM47XX_WDT tristate "Broadcom BCM47xx Watchdog Timer" - depends on BCM47XX || ARCH_BCM_5301X + depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST select WATCHDOG_CORE help Hardware driver for the Broadcom BCM47xx Watchdog Timer. @@ -1377,7 +1377,7 @@ config RC32434_WDT config INDYDOG tristate "Indy/I2 Hardware Watchdog" - depends on SGI_HAS_INDYDOG + depends on SGI_HAS_INDYDOG || (MIPS && COMPILE_TEST) help Hardware driver for the Indy's/I2's watchdog. This is a watchdog timer that will reboot the machine after a 60 second @@ -1393,7 +1393,7 @@ config JZ4740_WDT config WDT_MTX1 tristate "MTX-1 Hardware Watchdog" - depends on MIPS_MTX1 + depends on MIPS_MTX1 || (MIPS && COMPILE_TEST) help Hardware driver for the MTX-1 boards. This is a watchdog timer that will reboot the machine after a 100 seconds timer expired. @@ -1410,7 +1410,7 @@ config PNX833X_WDT config SIBYTE_WDOG tristate "Sibyte SoC hardware watchdog" - depends on CPU_SB1 + depends on CPU_SB1 || (MIPS && COMPILE_TEST) help Watchdog driver for the built in watchdog hardware in Sibyte SoC processors. There are apparently two watchdog timers @@ -1423,13 +1423,13 @@ config SIBYTE_WDOG config AR7_WDT tristate "TI AR7 Watchdog Timer" - depends on AR7 + depends on AR7 || (MIPS && COMPILE_TEST) help Hardware driver for the TI AR7 Watchdog Timer. config TXX9_WDT tristate "Toshiba TXx9 Watchdog Timer" - depends on CPU_TX39XX || CPU_TX49XX + depends on CPU_TX39XX || CPU_TX49XX || (MIPS && COMPILE_TEST) select WATCHDOG_CORE help Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs. @@ -1465,7 +1465,7 @@ config BCM63XX_WDT config BCM2835_WDT tristate "Broadcom BCM2835 hardware watchdog" - depends on ARCH_BCM2835 + depends on ARCH_BCM2835 || COMPILE_TEST select WATCHDOG_CORE help Watchdog driver for the built in watchdog hardware in Broadcom @@ -1476,7 +1476,7 @@ config BCM2835_WDT config BCM_KONA_WDT tristate "BCM Kona Watchdog" - depends on ARCH_BCM_MOBILE + depends on ARCH_BCM_MOBILE || COMPILE_TEST select WATCHDOG_CORE help Support for the watchdog timer on the following Broadcom BCM281xx @@ -1488,7 +1488,7 @@ config BCM_KONA_WDT config BCM_KONA_WDT_DEBUG bool "DEBUGFS support for BCM Kona Watchdog" - depends on BCM_KONA_WDT + depends on BCM_KONA_WDT || COMPILE_TEST help If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides access to the driver's internal data structures as well as watchdog @@ -1549,7 +1549,7 @@ config MT7621_WDT config PIC32_WDT tristate "Microchip PIC32 hardware watchdog" select WATCHDOG_CORE - depends on MACH_PIC32 + depends on MACH_PIC32 || (MIPS && COMPILE_TEST) help Watchdog driver for the built in watchdog hardware in a PIC32. @@ -1562,7 +1562,7 @@ config PIC32_WDT config PIC32_DMT tristate "Microchip PIC32 Deadman Timer" select WATCHDOG_CORE - depends on MACH_PIC32 + depends on MACH_PIC32 || (MIPS && COMPILE_TEST) help Watchdog driver for PIC32 instruction fetch counting timer. This specific timer is typically be used in misson critical and safety critical @@ -1584,7 +1584,7 @@ config GEF_WDT config MPC5200_WDT bool "MPC52xx Watchdog Timer" - depends on PPC_MPC52xx + depends on PPC_MPC52xx || COMPILE_TEST help Use General Purpose Timer (GPT) 0 on the MPC5200 as Watchdog. @@ -1603,11 +1603,11 @@ config 8xxx_WDT config MV64X60_WDT tristate "MV64X60 (Marvell Discovery) Watchdog Timer" - depends on MV64X60 + depends on MV64X60 || COMPILE_TEST config PIKA_WDT tristate "PIKA FPGA Watchdog" - depends on WARP + depends on WARP || (PPC64 && COMPILE_TEST) default y help This enables the watchdog in the PIKA FPGA. Currently used on @@ -1657,7 +1657,7 @@ config MEN_A21_WDT config WATCHDOG_RTAS tristate "RTAS watchdog" - depends on PPC_RTAS + depends on PPC_RTAS || (PPC64 && COMPILE_TEST) help This driver adds watchdog support for the RTAS watchdog. @@ -1685,7 +1685,7 @@ config DIAG288_WATCHDOG config SH_WDT tristate "SuperH Watchdog" - depends on SUPERH && (CPU_SH3 || CPU_SH4) + depends on SUPERH && (CPU_SH3 || CPU_SH4 || COMPILE_TEST) select WATCHDOG_CORE help This driver adds watchdog support for the integrated watchdog in the @@ -1752,7 +1752,7 @@ config XEN_WDT config UML_WATCHDOG tristate "UML watchdog" - depends on UML + depends on UML || COMPILE_TEST # # ISA-based Watchdog Cards -- cgit v1.2.3 From 9bf2dfb0e4bce68d9c0b0109e150f6b099276957 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 29 Dec 2016 21:49:18 +0000 Subject: watchdog: orion: fix spelling mistake: "harcoded" -> "hardcoded" Trivial fix to spelling mistake in WARN message Signed-off-by: Colin Ian King Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/orion_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index c6b8f4a43bde..39be4dd8035e 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -395,7 +395,7 @@ static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev, rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET; - WARN(1, FW_BUG "falling back to harcoded RSTOUT reg %pa\n", &rstout); + WARN(1, FW_BUG "falling back to hardcoded RSTOUT reg %pa\n", &rstout); return devm_ioremap(&pdev->dev, rstout, 0x4); } -- cgit v1.2.3 From ce1b95ca23c1265d63746e72f37ea8e546687361 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 1 Jan 2017 11:11:39 -0800 Subject: watchdog: iTCO_wdt: Use allocated data structures Allocate private data and the watchdog device to avoid having to clear it on remove and to enable subsequent simplifications. Reviewed-by: Andy Shevchenko Mika Westerberg Signed-off-by: Guenter Roeck --- drivers/watchdog/iTCO_wdt.c | 402 ++++++++++++++++++++++---------------------- 1 file changed, 205 insertions(+), 197 deletions(-) diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 06fcb6c8c917..a35a9164ccd0 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -72,22 +72,24 @@ /* Address definitions for the TCO */ /* TCO base address */ -#define TCOBASE (iTCO_wdt_private.tco_res->start) +#define TCOBASE(p) ((p)->tco_res->start) /* SMI Control and Enable Register */ -#define SMI_EN (iTCO_wdt_private.smi_res->start) - -#define TCO_RLD (TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */ -#define TCOv1_TMR (TCOBASE + 0x01) /* TCOv1 Timer Initial Value */ -#define TCO_DAT_IN (TCOBASE + 0x02) /* TCO Data In Register */ -#define TCO_DAT_OUT (TCOBASE + 0x03) /* TCO Data Out Register */ -#define TCO1_STS (TCOBASE + 0x04) /* TCO1 Status Register */ -#define TCO2_STS (TCOBASE + 0x06) /* TCO2 Status Register */ -#define TCO1_CNT (TCOBASE + 0x08) /* TCO1 Control Register */ -#define TCO2_CNT (TCOBASE + 0x0a) /* TCO2 Control Register */ -#define TCOv2_TMR (TCOBASE + 0x12) /* TCOv2 Timer Initial Value */ +#define SMI_EN(p) ((p)->smi_res->start) + +#define TCO_RLD(p) (TCOBASE(p) + 0x00) /* TCO Timer Reload/Curr. Value */ +#define TCOv1_TMR(p) (TCOBASE(p) + 0x01) /* TCOv1 Timer Initial Value*/ +#define TCO_DAT_IN(p) (TCOBASE(p) + 0x02) /* TCO Data In Register */ +#define TCO_DAT_OUT(p) (TCOBASE(p) + 0x03) /* TCO Data Out Register */ +#define TCO1_STS(p) (TCOBASE(p) + 0x04) /* TCO1 Status Register */ +#define TCO2_STS(p) (TCOBASE(p) + 0x06) /* TCO2 Status Register */ +#define TCO1_CNT(p) (TCOBASE(p) + 0x08) /* TCO1 Control Register */ +#define TCO2_CNT(p) (TCOBASE(p) + 0x0a) /* TCO2 Control Register */ +#define TCOv2_TMR(p) (TCOBASE(p) + 0x12) /* TCOv2 Timer Initial Value*/ /* internal variables */ -static struct { /* this is private data for the iTCO_wdt device */ +struct iTCO_wdt_private { + struct watchdog_device wddev; + /* TCO version/generation */ unsigned int iTCO_version; struct resource *tco_res; @@ -105,7 +107,7 @@ static struct { /* this is private data for the iTCO_wdt device */ struct pci_dev *pdev; /* whether or not the watchdog has been suspended */ bool suspended; -} iTCO_wdt_private; +}; /* module parameters */ #define WATCHDOG_TIMEOUT 30 /* 30 sec default heartbeat */ @@ -135,21 +137,23 @@ MODULE_PARM_DESC(turn_SMI_watchdog_clear_off, * every 0.6 seconds. v3's internal timer is stored as seconds (some * datasheets incorrectly state 0.6 seconds). */ -static inline unsigned int seconds_to_ticks(int secs) +static inline unsigned int seconds_to_ticks(struct iTCO_wdt_private *p, + int secs) { - return iTCO_wdt_private.iTCO_version == 3 ? secs : (secs * 10) / 6; + return p->iTCO_version == 3 ? secs : (secs * 10) / 6; } -static inline unsigned int ticks_to_seconds(int ticks) +static inline unsigned int ticks_to_seconds(struct iTCO_wdt_private *p, + int ticks) { - return iTCO_wdt_private.iTCO_version == 3 ? ticks : (ticks * 6) / 10; + return p->iTCO_version == 3 ? ticks : (ticks * 6) / 10; } -static inline u32 no_reboot_bit(void) +static inline u32 no_reboot_bit(struct iTCO_wdt_private *p) { u32 enable_bit; - switch (iTCO_wdt_private.iTCO_version) { + switch (p->iTCO_version) { case 5: case 3: enable_bit = 0x00000010; @@ -167,40 +171,40 @@ static inline u32 no_reboot_bit(void) return enable_bit; } -static void iTCO_wdt_set_NO_REBOOT_bit(void) +static void iTCO_wdt_set_NO_REBOOT_bit(struct iTCO_wdt_private *p) { u32 val32; /* Set the NO_REBOOT bit: this disables reboots */ - if (iTCO_wdt_private.iTCO_version >= 2) { - val32 = readl(iTCO_wdt_private.gcs_pmc); - val32 |= no_reboot_bit(); - writel(val32, iTCO_wdt_private.gcs_pmc); - } else if (iTCO_wdt_private.iTCO_version == 1) { - pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); - val32 |= no_reboot_bit(); - pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); + if (p->iTCO_version >= 2) { + val32 = readl(p->gcs_pmc); + val32 |= no_reboot_bit(p); + writel(val32, p->gcs_pmc); + } else if (p->iTCO_version == 1) { + pci_read_config_dword(p->pdev, 0xd4, &val32); + val32 |= no_reboot_bit(p); + pci_write_config_dword(p->pdev, 0xd4, val32); } } -static int iTCO_wdt_unset_NO_REBOOT_bit(void) +static int iTCO_wdt_unset_NO_REBOOT_bit(struct iTCO_wdt_private *p) { - u32 enable_bit = no_reboot_bit(); + u32 enable_bit = no_reboot_bit(p); u32 val32 = 0; /* Unset the NO_REBOOT bit: this enables reboots */ - if (iTCO_wdt_private.iTCO_version >= 2) { - val32 = readl(iTCO_wdt_private.gcs_pmc); + if (p->iTCO_version >= 2) { + val32 = readl(p->gcs_pmc); val32 &= ~enable_bit; - writel(val32, iTCO_wdt_private.gcs_pmc); + writel(val32, p->gcs_pmc); - val32 = readl(iTCO_wdt_private.gcs_pmc); - } else if (iTCO_wdt_private.iTCO_version == 1) { - pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); + val32 = readl(p->gcs_pmc); + } else if (p->iTCO_version == 1) { + pci_read_config_dword(p->pdev, 0xd4, &val32); val32 &= ~enable_bit; - pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); + pci_write_config_dword(p->pdev, 0xd4, val32); - pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); + pci_read_config_dword(p->pdev, 0xd4, &val32); } if (val32 & enable_bit) @@ -211,32 +215,33 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void) static int iTCO_wdt_start(struct watchdog_device *wd_dev) { + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); unsigned int val; - spin_lock(&iTCO_wdt_private.io_lock); + spin_lock(&p->io_lock); - iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, wd_dev->timeout); + iTCO_vendor_pre_start(p->smi_res, wd_dev->timeout); /* disable chipset's NO_REBOOT bit */ - if (iTCO_wdt_unset_NO_REBOOT_bit()) { - spin_unlock(&iTCO_wdt_private.io_lock); + if (iTCO_wdt_unset_NO_REBOOT_bit(p)) { + spin_unlock(&p->io_lock); pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n"); return -EIO; } /* Force the timer to its reload value by writing to the TCO_RLD register */ - if (iTCO_wdt_private.iTCO_version >= 2) - outw(0x01, TCO_RLD); - else if (iTCO_wdt_private.iTCO_version == 1) - outb(0x01, TCO_RLD); + if (p->iTCO_version >= 2) + outw(0x01, TCO_RLD(p)); + else if (p->iTCO_version == 1) + outb(0x01, TCO_RLD(p)); /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ - val = inw(TCO1_CNT); + val = inw(TCO1_CNT(p)); val &= 0xf7ff; - outw(val, TCO1_CNT); - val = inw(TCO1_CNT); - spin_unlock(&iTCO_wdt_private.io_lock); + outw(val, TCO1_CNT(p)); + val = inw(TCO1_CNT(p)); + spin_unlock(&p->io_lock); if (val & 0x0800) return -1; @@ -245,22 +250,23 @@ static int iTCO_wdt_start(struct watchdog_device *wd_dev) static int iTCO_wdt_stop(struct watchdog_device *wd_dev) { + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); unsigned int val; - spin_lock(&iTCO_wdt_private.io_lock); + spin_lock(&p->io_lock); - iTCO_vendor_pre_stop(iTCO_wdt_private.smi_res); + iTCO_vendor_pre_stop(p->smi_res); /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ - val = inw(TCO1_CNT); + val = inw(TCO1_CNT(p)); val |= 0x0800; - outw(val, TCO1_CNT); - val = inw(TCO1_CNT); + outw(val, TCO1_CNT(p)); + val = inw(TCO1_CNT(p)); /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - iTCO_wdt_set_NO_REBOOT_bit(); + iTCO_wdt_set_NO_REBOOT_bit(p); - spin_unlock(&iTCO_wdt_private.io_lock); + spin_unlock(&p->io_lock); if ((val & 0x0800) == 0) return -1; @@ -269,67 +275,70 @@ static int iTCO_wdt_stop(struct watchdog_device *wd_dev) static int iTCO_wdt_ping(struct watchdog_device *wd_dev) { - spin_lock(&iTCO_wdt_private.io_lock); + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); - iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, wd_dev->timeout); + spin_lock(&p->io_lock); + + iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout); /* Reload the timer by writing to the TCO Timer Counter register */ - if (iTCO_wdt_private.iTCO_version >= 2) { - outw(0x01, TCO_RLD); - } else if (iTCO_wdt_private.iTCO_version == 1) { + if (p->iTCO_version >= 2) { + outw(0x01, TCO_RLD(p)); + } else if (p->iTCO_version == 1) { /* Reset the timeout status bit so that the timer * needs to count down twice again before rebooting */ - outw(0x0008, TCO1_STS); /* write 1 to clear bit */ + outw(0x0008, TCO1_STS(p)); /* write 1 to clear bit */ - outb(0x01, TCO_RLD); + outb(0x01, TCO_RLD(p)); } - spin_unlock(&iTCO_wdt_private.io_lock); + spin_unlock(&p->io_lock); return 0; } static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t) { + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); unsigned int val16; unsigned char val8; unsigned int tmrval; - tmrval = seconds_to_ticks(t); + tmrval = seconds_to_ticks(p, t); /* For TCO v1 the timer counts down twice before rebooting */ - if (iTCO_wdt_private.iTCO_version == 1) + if (p->iTCO_version == 1) tmrval /= 2; /* from the specs: */ /* "Values of 0h-3h are ignored and should not be attempted" */ if (tmrval < 0x04) return -EINVAL; - if (((iTCO_wdt_private.iTCO_version >= 2) && (tmrval > 0x3ff)) || - ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) + if ((p->iTCO_version >= 2 && tmrval > 0x3ff) || + (p->iTCO_version == 1 && tmrval > 0x03f)) return -EINVAL; iTCO_vendor_pre_set_heartbeat(tmrval); /* Write new heartbeat to watchdog */ - if (iTCO_wdt_private.iTCO_version >= 2) { - spin_lock(&iTCO_wdt_private.io_lock); - val16 = inw(TCOv2_TMR); + if (p->iTCO_version >= 2) { + spin_lock(&p->io_lock); + val16 = inw(TCOv2_TMR(p)); val16 &= 0xfc00; val16 |= tmrval; - outw(val16, TCOv2_TMR); - val16 = inw(TCOv2_TMR); - spin_unlock(&iTCO_wdt_private.io_lock); + outw(val16, TCOv2_TMR(p)); + val16 = inw(TCOv2_TMR(p)); + spin_unlock(&p->io_lock); if ((val16 & 0x3ff) != tmrval) return -EINVAL; - } else if (iTCO_wdt_private.iTCO_version == 1) { - spin_lock(&iTCO_wdt_private.io_lock); - val8 = inb(TCOv1_TMR); + } else if (p->iTCO_version == 1) { + spin_lock(&p->io_lock); + val8 = inb(TCOv1_TMR(p)); val8 &= 0xc0; val8 |= (tmrval & 0xff); - outb(val8, TCOv1_TMR); - val8 = inb(TCOv1_TMR); - spin_unlock(&iTCO_wdt_private.io_lock); + outb(val8, TCOv1_TMR(p)); + val8 = inb(TCOv1_TMR(p)); + spin_unlock(&p->io_lock); if ((val8 & 0x3f) != tmrval) return -EINVAL; @@ -341,27 +350,28 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t) static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev) { + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); unsigned int val16; unsigned char val8; unsigned int time_left = 0; /* read the TCO Timer */ - if (iTCO_wdt_private.iTCO_version >= 2) { - spin_lock(&iTCO_wdt_private.io_lock); - val16 = inw(TCO_RLD); + if (p->iTCO_version >= 2) { + spin_lock(&p->io_lock); + val16 = inw(TCO_RLD(p)); val16 &= 0x3ff; - spin_unlock(&iTCO_wdt_private.io_lock); + spin_unlock(&p->io_lock); - time_left = ticks_to_seconds(val16); - } else if (iTCO_wdt_private.iTCO_version == 1) { - spin_lock(&iTCO_wdt_private.io_lock); - val8 = inb(TCO_RLD); + time_left = ticks_to_seconds(p, val16); + } else if (p->iTCO_version == 1) { + spin_lock(&p->io_lock); + val8 = inb(TCO_RLD(p)); val8 &= 0x3f; - if (!(inw(TCO1_STS) & 0x0008)) - val8 += (inb(TCOv1_TMR) & 0x3f); - spin_unlock(&iTCO_wdt_private.io_lock); + if (!(inw(TCO1_STS(p)) & 0x0008)) + val8 += (inb(TCOv1_TMR(p)) & 0x3f); + spin_unlock(&p->io_lock); - time_left = ticks_to_seconds(val8); + time_left = ticks_to_seconds(p, val8); } return time_left; } @@ -387,166 +397,165 @@ static const struct watchdog_ops iTCO_wdt_ops = { .get_timeleft = iTCO_wdt_get_timeleft, }; -static struct watchdog_device iTCO_wdt_watchdog_dev = { - .info = &ident, - .ops = &iTCO_wdt_ops, -}; - /* * Init & exit routines */ -static void iTCO_wdt_cleanup(void) +static void iTCO_wdt_cleanup(struct iTCO_wdt_private *p) { /* Stop the timer before we leave */ if (!nowayout) - iTCO_wdt_stop(&iTCO_wdt_watchdog_dev); + iTCO_wdt_stop(&p->wddev); /* Deregister */ - watchdog_unregister_device(&iTCO_wdt_watchdog_dev); + watchdog_unregister_device(&p->wddev); /* release resources */ - release_region(iTCO_wdt_private.tco_res->start, - resource_size(iTCO_wdt_private.tco_res)); - release_region(iTCO_wdt_private.smi_res->start, - resource_size(iTCO_wdt_private.smi_res)); - if (iTCO_wdt_private.iTCO_version >= 2) { - iounmap(iTCO_wdt_private.gcs_pmc); - release_mem_region(iTCO_wdt_private.gcs_pmc_res->start, - resource_size(iTCO_wdt_private.gcs_pmc_res)); + release_region(p->tco_res->start, + resource_size(p->tco_res)); + release_region(p->smi_res->start, + resource_size(p->smi_res)); + if (p->iTCO_version >= 2) { + iounmap(p->gcs_pmc); + release_mem_region(p->gcs_pmc_res->start, + resource_size(p->gcs_pmc_res)); } - - iTCO_wdt_private.tco_res = NULL; - iTCO_wdt_private.smi_res = NULL; - iTCO_wdt_private.gcs_pmc_res = NULL; - iTCO_wdt_private.gcs_pmc = NULL; } static int iTCO_wdt_probe(struct platform_device *dev) { - int ret = -ENODEV; - unsigned long val32; struct itco_wdt_platform_data *pdata = dev_get_platdata(&dev->dev); + struct iTCO_wdt_private *p; + unsigned long val32; + int ret; if (!pdata) - goto out; + return -ENODEV; - spin_lock_init(&iTCO_wdt_private.io_lock); + p = devm_kzalloc(&dev->dev, sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; - iTCO_wdt_private.tco_res = - platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_TCO); - if (!iTCO_wdt_private.tco_res) - goto out; + spin_lock_init(&p->io_lock); - iTCO_wdt_private.smi_res = - platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_SMI); - if (!iTCO_wdt_private.smi_res) - goto out; + p->tco_res = platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_TCO); + if (!p->tco_res) + return -ENODEV; - iTCO_wdt_private.iTCO_version = pdata->version; - iTCO_wdt_private.dev = dev; - iTCO_wdt_private.pdev = to_pci_dev(dev->dev.parent); + p->smi_res = platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_SMI); + if (!p->smi_res) + return -ENODEV; + + p->iTCO_version = pdata->version; + p->dev = dev; + p->pdev = to_pci_dev(dev->dev.parent); /* * Get the Memory-Mapped GCS or PMC register, we need it for the * NO_REBOOT flag (TCO v2 and v3). */ - if (iTCO_wdt_private.iTCO_version >= 2) { - iTCO_wdt_private.gcs_pmc_res = platform_get_resource(dev, - IORESOURCE_MEM, - ICH_RES_MEM_GCS_PMC); - - if (!iTCO_wdt_private.gcs_pmc_res) - goto out; - - if (!request_mem_region(iTCO_wdt_private.gcs_pmc_res->start, - resource_size(iTCO_wdt_private.gcs_pmc_res), dev->name)) { - ret = -EBUSY; - goto out; - } - iTCO_wdt_private.gcs_pmc = ioremap(iTCO_wdt_private.gcs_pmc_res->start, - resource_size(iTCO_wdt_private.gcs_pmc_res)); - if (!iTCO_wdt_private.gcs_pmc) { + if (p->iTCO_version >= 2) { + p->gcs_pmc_res = platform_get_resource(dev, + IORESOURCE_MEM, + ICH_RES_MEM_GCS_PMC); + + if (!p->gcs_pmc_res) + return -ENODEV; + + if (!request_mem_region(p->gcs_pmc_res->start, + resource_size(p->gcs_pmc_res), + dev->name)) + return -EBUSY; + + p->gcs_pmc = ioremap(p->gcs_pmc_res->start, + resource_size(p->gcs_pmc_res)); + if (!p->gcs_pmc) { ret = -EIO; goto unreg_gcs_pmc; } } /* Check chipset's NO_REBOOT bit */ - if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { + if (iTCO_wdt_unset_NO_REBOOT_bit(p) && + iTCO_vendor_check_noreboot_on()) { pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n"); ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ goto unmap_gcs_pmc; } /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ - iTCO_wdt_set_NO_REBOOT_bit(); + iTCO_wdt_set_NO_REBOOT_bit(p); /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ - if (!request_region(iTCO_wdt_private.smi_res->start, - resource_size(iTCO_wdt_private.smi_res), dev->name)) { + if (!request_region(p->smi_res->start, + resource_size(p->smi_res), dev->name)) { pr_err("I/O address 0x%04llx already in use, device disabled\n", - (u64)SMI_EN); + (u64)SMI_EN(p)); ret = -EBUSY; goto unmap_gcs_pmc; } - if (turn_SMI_watchdog_clear_off >= iTCO_wdt_private.iTCO_version) { + if (turn_SMI_watchdog_clear_off >= p->iTCO_version) { /* * Bit 13: TCO_EN -> 0 * Disables TCO logic generating an SMI# */ - val32 = inl(SMI_EN); + val32 = inl(SMI_EN(p)); val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ - outl(val32, SMI_EN); + outl(val32, SMI_EN(p)); } - if (!request_region(iTCO_wdt_private.tco_res->start, - resource_size(iTCO_wdt_private.tco_res), dev->name)) { + if (!request_region(p->tco_res->start, + resource_size(p->tco_res), dev->name)) { pr_err("I/O address 0x%04llx already in use, device disabled\n", - (u64)TCOBASE); + (u64)TCOBASE(p)); ret = -EBUSY; goto unreg_smi; } pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n", - pdata->name, pdata->version, (u64)TCOBASE); + pdata->name, pdata->version, (u64)TCOBASE(p)); /* Clear out the (probably old) status */ - switch (iTCO_wdt_private.iTCO_version) { + switch (p->iTCO_version) { case 5: case 4: - outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */ - outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */ + outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */ + outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */ break; case 3: - outl(0x20008, TCO1_STS); + outl(0x20008, TCO1_STS(p)); break; case 2: case 1: default: - outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */ - outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */ - outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */ + outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */ + outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */ + outw(0x0004, TCO2_STS(p)); /* Clear BOOT_STS bit */ break; } - iTCO_wdt_watchdog_dev.bootstatus = 0; - iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT; - watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout); - iTCO_wdt_watchdog_dev.parent = &dev->dev; + p->wddev.info = &ident, + p->wddev.ops = &iTCO_wdt_ops, + p->wddev.bootstatus = 0; + p->wddev.timeout = WATCHDOG_TIMEOUT; + watchdog_set_nowayout(&p->wddev, nowayout); + p->wddev.parent = &dev->dev; + + watchdog_set_drvdata(&p->wddev, p); + platform_set_drvdata(dev, p); /* Make sure the watchdog is not running */ - iTCO_wdt_stop(&iTCO_wdt_watchdog_dev); + iTCO_wdt_stop(&p->wddev); /* Check that the heartbeat value is within it's range; if not reset to the default */ - if (iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, heartbeat)) { - iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, WATCHDOG_TIMEOUT); + if (iTCO_wdt_set_timeout(&p->wddev, heartbeat)) { + iTCO_wdt_set_timeout(&p->wddev, WATCHDOG_TIMEOUT); pr_info("timeout value out of range, using %d\n", WATCHDOG_TIMEOUT); } - ret = watchdog_register_device(&iTCO_wdt_watchdog_dev); + ret = watchdog_register_device(&p->wddev); if (ret != 0) { pr_err("cannot register watchdog device (err=%d)\n", ret); goto unreg_tco; @@ -558,38 +567,34 @@ static int iTCO_wdt_probe(struct platform_device *dev) return 0; unreg_tco: - release_region(iTCO_wdt_private.tco_res->start, - resource_size(iTCO_wdt_private.tco_res)); + release_region(p->tco_res->start, resource_size(p->tco_res)); unreg_smi: - release_region(iTCO_wdt_private.smi_res->start, - resource_size(iTCO_wdt_private.smi_res)); + release_region(p->smi_res->start, resource_size(p->smi_res)); unmap_gcs_pmc: - if (iTCO_wdt_private.iTCO_version >= 2) - iounmap(iTCO_wdt_private.gcs_pmc); + if (p->iTCO_version >= 2) + iounmap(p->gcs_pmc); unreg_gcs_pmc: - if (iTCO_wdt_private.iTCO_version >= 2) - release_mem_region(iTCO_wdt_private.gcs_pmc_res->start, - resource_size(iTCO_wdt_private.gcs_pmc_res)); -out: - iTCO_wdt_private.tco_res = NULL; - iTCO_wdt_private.smi_res = NULL; - iTCO_wdt_private.gcs_pmc_res = NULL; - iTCO_wdt_private.gcs_pmc = NULL; - + if (p->iTCO_version >= 2) + release_mem_region(p->gcs_pmc_res->start, + resource_size(p->gcs_pmc_res)); return ret; } static int iTCO_wdt_remove(struct platform_device *dev) { - if (iTCO_wdt_private.tco_res || iTCO_wdt_private.smi_res) - iTCO_wdt_cleanup(); + struct iTCO_wdt_private *p = platform_get_drvdata(dev); + + if (p->tco_res || p->smi_res) + iTCO_wdt_cleanup(p); return 0; } static void iTCO_wdt_shutdown(struct platform_device *dev) { - iTCO_wdt_stop(NULL); + struct iTCO_wdt_private *p = platform_get_drvdata(dev); + + iTCO_wdt_stop(&p->wddev); } #ifdef CONFIG_PM_SLEEP @@ -610,21 +615,24 @@ static inline bool need_suspend(void) { return true; } static int iTCO_wdt_suspend_noirq(struct device *dev) { + struct iTCO_wdt_private *p = dev_get_drvdata(dev); int ret = 0; - iTCO_wdt_private.suspended = false; - if (watchdog_active(&iTCO_wdt_watchdog_dev) && need_suspend()) { - ret = iTCO_wdt_stop(&iTCO_wdt_watchdog_dev); + p->suspended = false; + if (watchdog_active(&p->wddev) && need_suspend()) { + ret = iTCO_wdt_stop(&p->wddev); if (!ret) - iTCO_wdt_private.suspended = true; + p->suspended = true; } return ret; } static int iTCO_wdt_resume_noirq(struct device *dev) { - if (iTCO_wdt_private.suspended) - iTCO_wdt_start(&iTCO_wdt_watchdog_dev); + struct iTCO_wdt_private *p = dev_get_drvdata(dev); + + if (p->suspended) + iTCO_wdt_start(&p->wddev); return 0; } -- cgit v1.2.3 From c7bbcc87ac98c340cb6e68c70ea4b600734a04d2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 1 Jan 2017 10:39:09 -0800 Subject: watchdog: iTCO_wdt: Use device managed resources Using device managed resources simplifies error handling and cleanup, and to reduce the likelyhood of errors. Reviewed-by: Andy Shevchenko Mika Westerberg Signed-off-by: Guenter Roeck --- drivers/watchdog/iTCO_wdt.c | 80 ++++++++++----------------------------------- 1 file changed, 17 insertions(+), 63 deletions(-) diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index a35a9164ccd0..eed1dee6de19 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -401,27 +401,6 @@ static const struct watchdog_ops iTCO_wdt_ops = { * Init & exit routines */ -static void iTCO_wdt_cleanup(struct iTCO_wdt_private *p) -{ - /* Stop the timer before we leave */ - if (!nowayout) - iTCO_wdt_stop(&p->wddev); - - /* Deregister */ - watchdog_unregister_device(&p->wddev); - - /* release resources */ - release_region(p->tco_res->start, - resource_size(p->tco_res)); - release_region(p->smi_res->start, - resource_size(p->smi_res)); - if (p->iTCO_version >= 2) { - iounmap(p->gcs_pmc); - release_mem_region(p->gcs_pmc_res->start, - resource_size(p->gcs_pmc_res)); - } -} - static int iTCO_wdt_probe(struct platform_device *dev) { struct itco_wdt_platform_data *pdata = dev_get_platdata(&dev->dev); @@ -458,41 +437,28 @@ static int iTCO_wdt_probe(struct platform_device *dev) p->gcs_pmc_res = platform_get_resource(dev, IORESOURCE_MEM, ICH_RES_MEM_GCS_PMC); - - if (!p->gcs_pmc_res) - return -ENODEV; - - if (!request_mem_region(p->gcs_pmc_res->start, - resource_size(p->gcs_pmc_res), - dev->name)) - return -EBUSY; - - p->gcs_pmc = ioremap(p->gcs_pmc_res->start, - resource_size(p->gcs_pmc_res)); - if (!p->gcs_pmc) { - ret = -EIO; - goto unreg_gcs_pmc; - } + p->gcs_pmc = devm_ioremap_resource(&dev->dev, p->gcs_pmc_res); + if (IS_ERR(p->gcs_pmc)) + return PTR_ERR(p->gcs_pmc); } /* Check chipset's NO_REBOOT bit */ if (iTCO_wdt_unset_NO_REBOOT_bit(p) && iTCO_vendor_check_noreboot_on()) { pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n"); - ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ - goto unmap_gcs_pmc; + return -ENODEV; /* Cannot reset NO_REBOOT bit */ } /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ iTCO_wdt_set_NO_REBOOT_bit(p); /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ - if (!request_region(p->smi_res->start, - resource_size(p->smi_res), dev->name)) { + if (!devm_request_region(&dev->dev, p->smi_res->start, + resource_size(p->smi_res), + dev->name)) { pr_err("I/O address 0x%04llx already in use, device disabled\n", (u64)SMI_EN(p)); - ret = -EBUSY; - goto unmap_gcs_pmc; + return -EBUSY; } if (turn_SMI_watchdog_clear_off >= p->iTCO_version) { /* @@ -504,12 +470,12 @@ static int iTCO_wdt_probe(struct platform_device *dev) outl(val32, SMI_EN(p)); } - if (!request_region(p->tco_res->start, - resource_size(p->tco_res), dev->name)) { + if (!devm_request_region(&dev->dev, p->tco_res->start, + resource_size(p->tco_res), + dev->name)) { pr_err("I/O address 0x%04llx already in use, device disabled\n", (u64)TCOBASE(p)); - ret = -EBUSY; - goto unreg_smi; + return -EBUSY; } pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n", @@ -555,37 +521,25 @@ static int iTCO_wdt_probe(struct platform_device *dev) WATCHDOG_TIMEOUT); } - ret = watchdog_register_device(&p->wddev); + ret = devm_watchdog_register_device(&dev->dev, &p->wddev); if (ret != 0) { pr_err("cannot register watchdog device (err=%d)\n", ret); - goto unreg_tco; + return ret; } pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n", heartbeat, nowayout); return 0; - -unreg_tco: - release_region(p->tco_res->start, resource_size(p->tco_res)); -unreg_smi: - release_region(p->smi_res->start, resource_size(p->smi_res)); -unmap_gcs_pmc: - if (p->iTCO_version >= 2) - iounmap(p->gcs_pmc); -unreg_gcs_pmc: - if (p->iTCO_version >= 2) - release_mem_region(p->gcs_pmc_res->start, - resource_size(p->gcs_pmc_res)); - return ret; } static int iTCO_wdt_remove(struct platform_device *dev) { struct iTCO_wdt_private *p = platform_get_drvdata(dev); - if (p->tco_res || p->smi_res) - iTCO_wdt_cleanup(p); + /* Stop the timer before we leave */ + if (!nowayout) + iTCO_wdt_stop(&p->wddev); return 0; } -- cgit v1.2.3 From 78e45696d55c0754384f81e628b57b4e865a2478 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Mon, 2 Jan 2017 09:27:36 -0800 Subject: watchdog: iTCO_wdt: Use pdev for platform device and pci_dev for pci device Use pdev for struct platform_device, pci_dev for struct pci_dev, and dev for struct device variables to improve consistency. Remove 'struct platform_device *dev;' from struct iTCO_wdt_private since it was unused. Reviewed-by: Andy Shevchenko Mika Westerberg Signed-off-by: Guenter Roeck --- drivers/watchdog/iTCO_wdt.c | 53 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index eed1dee6de19..9b60f4201c26 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -102,9 +102,8 @@ struct iTCO_wdt_private { unsigned long __iomem *gcs_pmc; /* the lock for io operations */ spinlock_t io_lock; - struct platform_device *dev; /* the PCI-device */ - struct pci_dev *pdev; + struct pci_dev *pci_dev; /* whether or not the watchdog has been suspended */ bool suspended; }; @@ -181,9 +180,9 @@ static void iTCO_wdt_set_NO_REBOOT_bit(struct iTCO_wdt_private *p) val32 |= no_reboot_bit(p); writel(val32, p->gcs_pmc); } else if (p->iTCO_version == 1) { - pci_read_config_dword(p->pdev, 0xd4, &val32); + pci_read_config_dword(p->pci_dev, 0xd4, &val32); val32 |= no_reboot_bit(p); - pci_write_config_dword(p->pdev, 0xd4, val32); + pci_write_config_dword(p->pci_dev, 0xd4, val32); } } @@ -200,11 +199,11 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(struct iTCO_wdt_private *p) val32 = readl(p->gcs_pmc); } else if (p->iTCO_version == 1) { - pci_read_config_dword(p->pdev, 0xd4, &val32); + pci_read_config_dword(p->pci_dev, 0xd4, &val32); val32 &= ~enable_bit; - pci_write_config_dword(p->pdev, 0xd4, val32); + pci_write_config_dword(p->pci_dev, 0xd4, val32); - pci_read_config_dword(p->pdev, 0xd4, &val32); + pci_read_config_dword(p->pci_dev, 0xd4, &val32); } if (val32 & enable_bit) @@ -401,9 +400,10 @@ static const struct watchdog_ops iTCO_wdt_ops = { * Init & exit routines */ -static int iTCO_wdt_probe(struct platform_device *dev) +static int iTCO_wdt_probe(struct platform_device *pdev) { - struct itco_wdt_platform_data *pdata = dev_get_platdata(&dev->dev); + struct device *dev = &pdev->dev; + struct itco_wdt_platform_data *pdata = dev_get_platdata(dev); struct iTCO_wdt_private *p; unsigned long val32; int ret; @@ -411,33 +411,32 @@ static int iTCO_wdt_probe(struct platform_device *dev) if (!pdata) return -ENODEV; - p = devm_kzalloc(&dev->dev, sizeof(*p), GFP_KERNEL); + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); if (!p) return -ENOMEM; spin_lock_init(&p->io_lock); - p->tco_res = platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_TCO); + p->tco_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_TCO); if (!p->tco_res) return -ENODEV; - p->smi_res = platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_SMI); + p->smi_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_SMI); if (!p->smi_res) return -ENODEV; p->iTCO_version = pdata->version; - p->dev = dev; - p->pdev = to_pci_dev(dev->dev.parent); + p->pci_dev = to_pci_dev(dev->parent); /* * Get the Memory-Mapped GCS or PMC register, we need it for the * NO_REBOOT flag (TCO v2 and v3). */ if (p->iTCO_version >= 2) { - p->gcs_pmc_res = platform_get_resource(dev, + p->gcs_pmc_res = platform_get_resource(pdev, IORESOURCE_MEM, ICH_RES_MEM_GCS_PMC); - p->gcs_pmc = devm_ioremap_resource(&dev->dev, p->gcs_pmc_res); + p->gcs_pmc = devm_ioremap_resource(dev, p->gcs_pmc_res); if (IS_ERR(p->gcs_pmc)) return PTR_ERR(p->gcs_pmc); } @@ -453,9 +452,9 @@ static int iTCO_wdt_probe(struct platform_device *dev) iTCO_wdt_set_NO_REBOOT_bit(p); /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ - if (!devm_request_region(&dev->dev, p->smi_res->start, + if (!devm_request_region(dev, p->smi_res->start, resource_size(p->smi_res), - dev->name)) { + pdev->name)) { pr_err("I/O address 0x%04llx already in use, device disabled\n", (u64)SMI_EN(p)); return -EBUSY; @@ -470,9 +469,9 @@ static int iTCO_wdt_probe(struct platform_device *dev) outl(val32, SMI_EN(p)); } - if (!devm_request_region(&dev->dev, p->tco_res->start, + if (!devm_request_region(dev, p->tco_res->start, resource_size(p->tco_res), - dev->name)) { + pdev->name)) { pr_err("I/O address 0x%04llx already in use, device disabled\n", (u64)TCOBASE(p)); return -EBUSY; @@ -505,10 +504,10 @@ static int iTCO_wdt_probe(struct platform_device *dev) p->wddev.bootstatus = 0; p->wddev.timeout = WATCHDOG_TIMEOUT; watchdog_set_nowayout(&p->wddev, nowayout); - p->wddev.parent = &dev->dev; + p->wddev.parent = dev; watchdog_set_drvdata(&p->wddev, p); - platform_set_drvdata(dev, p); + platform_set_drvdata(pdev, p); /* Make sure the watchdog is not running */ iTCO_wdt_stop(&p->wddev); @@ -521,7 +520,7 @@ static int iTCO_wdt_probe(struct platform_device *dev) WATCHDOG_TIMEOUT); } - ret = devm_watchdog_register_device(&dev->dev, &p->wddev); + ret = devm_watchdog_register_device(dev, &p->wddev); if (ret != 0) { pr_err("cannot register watchdog device (err=%d)\n", ret); return ret; @@ -533,9 +532,9 @@ static int iTCO_wdt_probe(struct platform_device *dev) return 0; } -static int iTCO_wdt_remove(struct platform_device *dev) +static int iTCO_wdt_remove(struct platform_device *pdev) { - struct iTCO_wdt_private *p = platform_get_drvdata(dev); + struct iTCO_wdt_private *p = platform_get_drvdata(pdev); /* Stop the timer before we leave */ if (!nowayout) @@ -544,9 +543,9 @@ static int iTCO_wdt_remove(struct platform_device *dev) return 0; } -static void iTCO_wdt_shutdown(struct platform_device *dev) +static void iTCO_wdt_shutdown(struct platform_device *pdev) { - struct iTCO_wdt_private *p = platform_get_drvdata(dev); + struct iTCO_wdt_private *p = platform_get_drvdata(pdev); iTCO_wdt_stop(&p->wddev); } -- cgit v1.2.3 From 9616bd2a66000a30ff912ac3b1e02391dc2d0c89 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 3 Jan 2017 02:43:32 -0800 Subject: watchdog: iTCO_wdt: Simplify module init function The 'ret' variable in iTCO_wdt_init_module() does not add any value; drop it. Reviewed-by: Andy Shevchenko Mika Westerberg Signed-off-by: Guenter Roeck --- drivers/watchdog/iTCO_wdt.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 9b60f4201c26..d8bb7bf5e669 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -612,15 +612,9 @@ static struct platform_driver iTCO_wdt_driver = { static int __init iTCO_wdt_init_module(void) { - int err; - pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION); - err = platform_driver_register(&iTCO_wdt_driver); - if (err) - return err; - - return 0; + return platform_driver_register(&iTCO_wdt_driver); } static void __exit iTCO_wdt_cleanup_module(void) -- cgit v1.2.3 From 3b72c41f13e64e4799cb0978d46eb06575456f26 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 6 Jan 2017 06:35:16 -0800 Subject: watchdog: bcm47xx_wdt: Don't validate platform data on remove Platform data was already validated in the probe function. If it was NULL, the remove function will never be called. Remove the unnecessary check. Signed-off-by: Guenter Roeck --- drivers/watchdog/bcm47xx_wdt.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index a1900b9ab6c4..35725e21b18a 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c @@ -226,9 +226,6 @@ static int bcm47xx_wdt_remove(struct platform_device *pdev) { struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); - if (!wdt) - return -ENXIO; - watchdog_unregister_device(&wdt->wdd); return 0; -- cgit v1.2.3 From 55dbe8f325a2e935c7913d538f9b39acff0f3bfc Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 4 Jan 2017 12:24:52 -0800 Subject: watchdog: asm9260_wdt: Use watchdog core to install restart handler Use the infrastructure provided by the watchdog core to install the restart handler. Signed-off-by: Guenter Roeck --- drivers/watchdog/asm9260_wdt.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/watchdog/asm9260_wdt.c b/drivers/watchdog/asm9260_wdt.c index d0b59ba0f661..028feb6f6e53 100644 --- a/drivers/watchdog/asm9260_wdt.c +++ b/drivers/watchdog/asm9260_wdt.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -59,7 +58,6 @@ struct asm9260_wdt_priv { struct clk *clk; struct clk *clk_ahb; struct reset_control *rst; - struct notifier_block restart_handler; void __iomem *iobase; int irq; @@ -172,15 +170,14 @@ static irqreturn_t asm9260_wdt_irq(int irq, void *devid) return IRQ_HANDLED; } -static int asm9260_restart_handler(struct notifier_block *this, - unsigned long mode, void *cmd) +static int asm9260_restart(struct watchdog_device *wdd, unsigned long action, + void *data) { - struct asm9260_wdt_priv *priv = - container_of(this, struct asm9260_wdt_priv, restart_handler); + struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd); asm9260_wdt_sys_reset(priv); - return NOTIFY_DONE; + return 0; } static const struct watchdog_info asm9260_wdt_ident = { @@ -196,6 +193,7 @@ static struct watchdog_ops asm9260_wdt_ops = { .get_timeleft = asm9260_wdt_gettimeleft, .ping = asm9260_wdt_feed, .set_timeout = asm9260_wdt_settimeout, + .restart = asm9260_restart, }; static int asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv *priv) @@ -335,18 +333,14 @@ static int asm9260_wdt_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to request IRQ\n"); } + watchdog_set_restart_priority(wdd, 128); + ret = watchdog_register_device(wdd); if (ret) goto clk_off; platform_set_drvdata(pdev, priv); - priv->restart_handler.notifier_call = asm9260_restart_handler; - priv->restart_handler.priority = 128; - ret = register_restart_handler(&priv->restart_handler); - if (ret) - dev_warn(&pdev->dev, "cannot register restart handler\n"); - dev_info(&pdev->dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n", wdd->timeout, mode_name[priv->mode]); return 0; @@ -370,8 +364,6 @@ static int asm9260_wdt_remove(struct platform_device *pdev) asm9260_wdt_disable(&priv->wdd); - unregister_restart_handler(&priv->restart_handler); - watchdog_unregister_device(&priv->wdd); clk_disable_unprepare(priv->clk); -- cgit v1.2.3 From 71e9b2f0bf2abab805b23b126747979dda589a7c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 4 Jan 2017 12:26:45 -0800 Subject: watchdog: bcm2835_wdt: Use watchdog core to install restart handler Use the infrastructure provided by the watchdog core to install the restart handler. Acked-by: Eric Anholt Signed-off-by: Guenter Roeck --- drivers/watchdog/bcm2835_wdt.c | 57 ++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c index c32c45bd8b09..4e0adb6c88f0 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include @@ -49,7 +48,6 @@ struct bcm2835_wdt { void __iomem *base; spinlock_t lock; - struct notifier_block restart_handler; }; static unsigned int heartbeat; @@ -99,11 +97,37 @@ static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog) return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET); } +static void __bcm2835_restart(struct bcm2835_wdt *wdt) +{ + u32 val; + + /* use a timeout of 10 ticks (~150us) */ + writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG); + val = readl_relaxed(wdt->base + PM_RSTC); + val &= PM_RSTC_WRCFG_CLR; + val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; + writel_relaxed(val, wdt->base + PM_RSTC); + + /* No sleeping, possibly atomic. */ + mdelay(1); +} + +static int bcm2835_restart(struct watchdog_device *wdog, + unsigned long action, void *data) +{ + struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog); + + __bcm2835_restart(wdt); + + return 0; +} + static const struct watchdog_ops bcm2835_wdt_ops = { .owner = THIS_MODULE, .start = bcm2835_wdt_start, .stop = bcm2835_wdt_stop, .get_timeleft = bcm2835_wdt_get_timeleft, + .restart = bcm2835_restart, }; static const struct watchdog_info bcm2835_wdt_info = { @@ -120,26 +144,6 @@ static struct watchdog_device bcm2835_wdt_wdd = { .timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET), }; -static int -bcm2835_restart(struct notifier_block *this, unsigned long mode, void *cmd) -{ - struct bcm2835_wdt *wdt = container_of(this, struct bcm2835_wdt, - restart_handler); - u32 val; - - /* use a timeout of 10 ticks (~150us) */ - writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG); - val = readl_relaxed(wdt->base + PM_RSTC); - val &= PM_RSTC_WRCFG_CLR; - val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; - writel_relaxed(val, wdt->base + PM_RSTC); - - /* No sleeping, possibly atomic. */ - mdelay(1); - - return 0; -} - /* * We can't really power off, but if we do the normal reset scheme, and * indicate to bootcode.bin not to reboot, then most of the chip will be @@ -163,7 +167,7 @@ static void bcm2835_power_off(void) writel_relaxed(val, wdt->base + PM_RSTS); /* Continue with normal reset mechanism */ - bcm2835_restart(&wdt->restart_handler, REBOOT_HARD, NULL); + __bcm2835_restart(wdt); } static int bcm2835_wdt_probe(struct platform_device *pdev) @@ -201,6 +205,9 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) */ set_bit(WDOG_HW_RUNNING, &bcm2835_wdt_wdd.status); } + + watchdog_set_restart_priority(&bcm2835_wdt_wdd, 128); + err = watchdog_register_device(&bcm2835_wdt_wdd); if (err) { dev_err(dev, "Failed to register watchdog device"); @@ -208,9 +215,6 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) return err; } - wdt->restart_handler.notifier_call = bcm2835_restart; - wdt->restart_handler.priority = 128; - register_restart_handler(&wdt->restart_handler); if (pm_power_off == NULL) pm_power_off = bcm2835_power_off; @@ -222,7 +226,6 @@ static int bcm2835_wdt_remove(struct platform_device *pdev) { struct bcm2835_wdt *wdt = platform_get_drvdata(pdev); - unregister_restart_handler(&wdt->restart_handler); if (pm_power_off == bcm2835_power_off) pm_power_off = NULL; watchdog_unregister_device(&bcm2835_wdt_wdd); -- cgit v1.2.3 From a70dcc016fedfc214fb0d4cb59cd01d0117c8345 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 4 Jan 2017 12:27:21 -0800 Subject: watchdog: dw_wdt: Use watchdog core to install restart handler Use the infrastructure provided by the watchdog core to install the restart handler. Signed-off-by: Guenter Roeck --- drivers/watchdog/dw_wdt.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 3c6a3de13a1b..914da3a4d334 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c @@ -26,11 +26,9 @@ #include #include #include -#include #include #include #include -#include #include #define WDOG_CONTROL_REG_OFFSET 0x00 @@ -55,7 +53,6 @@ struct dw_wdt { void __iomem *regs; struct clk *clk; unsigned long rate; - struct notifier_block restart_handler; struct watchdog_device wdd; }; @@ -136,14 +133,12 @@ static int dw_wdt_start(struct watchdog_device *wdd) return 0; } -static int dw_wdt_restart_handle(struct notifier_block *this, - unsigned long mode, void *cmd) +static int dw_wdt_restart(struct watchdog_device *wdd, + unsigned long action, void *data) { - struct dw_wdt *dw_wdt; + struct dw_wdt *dw_wdt = to_dw_wdt(wdd); u32 val; - dw_wdt = container_of(this, struct dw_wdt, restart_handler); - writel(0, dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); val = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); if (val & WDOG_CONTROL_REG_WDT_EN_MASK) @@ -156,7 +151,7 @@ static int dw_wdt_restart_handle(struct notifier_block *this, /* wait for reset to assert... */ mdelay(500); - return NOTIFY_DONE; + return 0; } static unsigned int dw_wdt_get_timeleft(struct watchdog_device *wdd) @@ -179,6 +174,7 @@ static const struct watchdog_ops dw_wdt_ops = { .ping = dw_wdt_ping, .set_timeout = dw_wdt_set_timeout, .get_timeleft = dw_wdt_get_timeleft, + .restart = dw_wdt_restart, }; #ifdef CONFIG_PM_SLEEP @@ -265,16 +261,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dw_wdt); + watchdog_set_restart_priority(wdd, 128); + ret = watchdog_register_device(wdd); if (ret) goto out_disable_clk; - dw_wdt->restart_handler.notifier_call = dw_wdt_restart_handle; - dw_wdt->restart_handler.priority = 128; - ret = register_restart_handler(&dw_wdt->restart_handler); - if (ret) - pr_warn("cannot register restart handler\n"); - return 0; out_disable_clk: @@ -286,7 +278,6 @@ static int dw_wdt_drv_remove(struct platform_device *pdev) { struct dw_wdt *dw_wdt = platform_get_drvdata(pdev); - unregister_restart_handler(&dw_wdt->restart_handler); watchdog_unregister_device(&dw_wdt->wdd); clk_disable_unprepare(dw_wdt->clk); -- cgit v1.2.3 From 0397c5db1d3174a553da674bb779007cc62cc241 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 4 Jan 2017 12:28:01 -0800 Subject: watchdog: tangox: Use watchdog core to install restart handler Use the infrastructure provided by the watchdog core to install the restart handler. Signed-off-by: Guenter Roeck --- drivers/watchdog/tangox_wdt.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/drivers/watchdog/tangox_wdt.c b/drivers/watchdog/tangox_wdt.c index 202c4b9cc921..d5fcce062920 100644 --- a/drivers/watchdog/tangox_wdt.c +++ b/drivers/watchdog/tangox_wdt.c @@ -15,9 +15,7 @@ #include #include #include -#include #include -#include #include #define DEFAULT_TIMEOUT 30 @@ -47,7 +45,6 @@ struct tangox_wdt_device { void __iomem *base; unsigned long clk_rate; struct clk *clk; - struct notifier_block restart; }; static int tangox_wdt_set_timeout(struct watchdog_device *wdt, @@ -96,24 +93,24 @@ static const struct watchdog_info tangox_wdt_info = { .identity = "tangox watchdog", }; +static int tangox_wdt_restart(struct watchdog_device *wdt, + unsigned long action, void *data) +{ + struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt); + + writel(1, dev->base + WD_COUNTER); + + return 0; +} + static const struct watchdog_ops tangox_wdt_ops = { .start = tangox_wdt_start, .stop = tangox_wdt_stop, .set_timeout = tangox_wdt_set_timeout, .get_timeleft = tangox_wdt_get_timeleft, + .restart = tangox_wdt_restart, }; -static int tangox_wdt_restart(struct notifier_block *nb, unsigned long action, - void *data) -{ - struct tangox_wdt_device *dev = - container_of(nb, struct tangox_wdt_device, restart); - - writel(1, dev->base + WD_COUNTER); - - return NOTIFY_DONE; -} - static int tangox_wdt_probe(struct platform_device *pdev) { struct tangox_wdt_device *dev; @@ -174,18 +171,14 @@ static int tangox_wdt_probe(struct platform_device *pdev) tangox_wdt_start(&dev->wdt); } + watchdog_set_restart_priority(&dev->wdt, 128); + err = watchdog_register_device(&dev->wdt); if (err) goto err; platform_set_drvdata(pdev, dev); - dev->restart.notifier_call = tangox_wdt_restart; - dev->restart.priority = 128; - err = register_restart_handler(&dev->restart); - if (err) - dev_warn(&pdev->dev, "failed to register restart handler\n"); - dev_info(&pdev->dev, "SMP86xx/SMP87xx watchdog registered\n"); return 0; @@ -202,7 +195,6 @@ static int tangox_wdt_remove(struct platform_device *pdev) tangox_wdt_stop(&dev->wdt); clk_disable_unprepare(dev->clk); - unregister_restart_handler(&dev->restart); watchdog_unregister_device(&dev->wdt); return 0; -- cgit v1.2.3 From 01372ae13ba6a4792de2f4bd474f1374b5404448 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 3 Jan 2017 03:22:09 -0800 Subject: watchdog: coh901327_wdt: Simplify error handling in probe function Checking if there is no error followed by a goto if there is one is confusing. Reverse the logic. Reviewed-by: Linus Walleij Signed-off-by: Guenter Roeck --- drivers/watchdog/coh901327_wdt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index a099b77fc0b9..dc97b2fd6c49 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c @@ -360,12 +360,10 @@ static int __init coh901327_probe(struct platform_device *pdev) coh901327_wdt.parent = &pdev->dev; ret = watchdog_register_device(&coh901327_wdt); - if (ret == 0) - dev_info(&pdev->dev, - "initialized. timer margin=%d sec\n", margin); - else + if (ret) goto out_no_wdog; + dev_info(&pdev->dev, "initialized. timer margin=%d sec\n", margin); return 0; out_no_wdog: -- cgit v1.2.3 From 14da8d427eb8ea10d8fb78a1264583bb9b279231 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 3 Jan 2017 03:03:27 -0800 Subject: watchdog: coh901327_wdt: Keep clock enabled after loading driver Enabling the clock before accessing chip registers and disabling it afterwards does not really make sense and only adds complexity to the driver. In addition to that, a comment int the driver suggests that it does not serve a useful purpose either. "The watchdog block is of course always clocked, the clk_enable()/clk_disable() calls are mainly for performing reference counting higher up in the clock hierarchy." Just keep the clock enabled instead. Reviewed-by: Linus Walleij Signed-off-by: Guenter Roeck --- drivers/watchdog/coh901327_wdt.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index dc97b2fd6c49..1385a920df4f 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c @@ -74,11 +74,6 @@ static int irq; static void __iomem *virtbase; static struct device *parent; -/* - * The watchdog block is of course always clocked, the - * clk_enable()/clk_disable() calls are mainly for performing reference - * counting higher up in the clock hierarchy. - */ static struct clk *clk; /* @@ -90,7 +85,6 @@ static void coh901327_enable(u16 timeout) unsigned long freq; unsigned long delay_ns; - clk_enable(clk); /* Restart timer if it is disabled */ val = readw(virtbase + U300_WDOG_D2R); if (val == U300_WDOG_D2R_DISABLE_STATUS_DISABLED) @@ -118,7 +112,6 @@ static void coh901327_enable(u16 timeout) */ (void) readw(virtbase + U300_WDOG_CR); val = readw(virtbase + U300_WDOG_D2R); - clk_disable(clk); if (val != U300_WDOG_D2R_DISABLE_STATUS_ENABLED) dev_err(parent, "%s(): watchdog not enabled! D2R value %04x\n", @@ -129,7 +122,6 @@ static void coh901327_disable(void) { u16 val; - clk_enable(clk); /* Disable the watchdog interrupt if it is active */ writew(0x0000U, virtbase + U300_WDOG_IMR); /* If the watchdog is currently enabled, attempt to disable it */ @@ -144,7 +136,6 @@ static void coh901327_disable(void) virtbase + U300_WDOG_D2R); } val = readw(virtbase + U300_WDOG_D2R); - clk_disable(clk); if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED) dev_err(parent, "%s(): watchdog not disabled! D2R value %04x\n", @@ -165,11 +156,9 @@ static int coh901327_stop(struct watchdog_device *wdt_dev) static int coh901327_ping(struct watchdog_device *wdd) { - clk_enable(clk); /* Feed the watchdog */ writew(U300_WDOG_FR_FEED_RESTART_TIMER, virtbase + U300_WDOG_FR); - clk_disable(clk); return 0; } @@ -177,13 +166,11 @@ static int coh901327_settimeout(struct watchdog_device *wdt_dev, unsigned int time) { wdt_dev->timeout = time; - clk_enable(clk); /* Set new timeout value */ writew(time * 100, virtbase + U300_WDOG_TR); /* Feed the dog */ writew(U300_WDOG_FR_FEED_RESTART_TIMER, virtbase + U300_WDOG_FR); - clk_disable(clk); return 0; } @@ -191,13 +178,11 @@ static unsigned int coh901327_gettimeleft(struct watchdog_device *wdt_dev) { u16 val; - clk_enable(clk); /* Read repeatedly until the value is stable! */ val = readw(virtbase + U300_WDOG_CR); while (val & U300_WDOG_CR_VALID_IND) val = readw(virtbase + U300_WDOG_CR); val &= U300_WDOG_CR_COUNT_VALUE_MASK; - clk_disable(clk); if (val != 0) val /= 100; @@ -221,13 +206,11 @@ static irqreturn_t coh901327_interrupt(int irq, void *data) * to prevent a watchdog reset by feeding the watchdog at this * point. */ - clk_enable(clk); val = readw(virtbase + U300_WDOG_IER); if (val == U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND) writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE, virtbase + U300_WDOG_IER); writew(0x0000U, virtbase + U300_WDOG_IMR); - clk_disable(clk); dev_crit(parent, "watchdog is barking!\n"); return IRQ_HANDLED; } @@ -263,7 +246,7 @@ static int __exit coh901327_remove(struct platform_device *pdev) watchdog_unregister_device(&coh901327_wdt); coh901327_disable(); free_irq(irq, pdev); - clk_unprepare(clk); + clk_disable_unprepare(clk); clk_put(clk); iounmap(virtbase); release_mem_region(phybase, physize); @@ -352,8 +335,6 @@ static int __init coh901327_probe(struct platform_device *pdev) goto out_no_irq; } - clk_disable(clk); - ret = watchdog_init_timeout(&coh901327_wdt, margin, &pdev->dev); if (ret < 0) coh901327_wdt.timeout = 60; -- cgit v1.2.3 From 30c65b22f04262206e1ea00a87469233930066c2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 3 Jan 2017 03:10:30 -0800 Subject: watchdog: coh901327_wdt: Use devm_ioremap_resource to map resources Map resources using devm_ioremap_resource() to simplify error handling. Reviewed-by: Linus Walleij Signed-off-by: Guenter Roeck --- drivers/watchdog/coh901327_wdt.c | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index 1385a920df4f..986222efe174 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c @@ -68,8 +68,6 @@ /* Default timeout in seconds = 1 minute */ static unsigned int margin = 60; -static resource_size_t phybase; -static resource_size_t physize; static int irq; static void __iomem *virtbase; static struct device *parent; @@ -248,8 +246,6 @@ static int __exit coh901327_remove(struct platform_device *pdev) free_irq(irq, pdev); clk_disable_unprepare(clk); clk_put(clk); - iounmap(virtbase); - release_mem_region(phybase, physize); return 0; } @@ -259,30 +255,18 @@ static int __init coh901327_probe(struct platform_device *pdev) u16 val; struct resource *res; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENOENT; - parent = &pdev->dev; - physize = resource_size(res); - phybase = res->start; - - if (request_mem_region(phybase, physize, DRV_NAME) == NULL) { - ret = -EBUSY; - goto out; - } - virtbase = ioremap(phybase, physize); - if (!virtbase) { - ret = -ENOMEM; - goto out_no_remap; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + virtbase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(virtbase)) + return PTR_ERR(virtbase); clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { ret = PTR_ERR(clk); dev_err(&pdev->dev, "could not get clock\n"); - goto out_no_clk; + return ret; } ret = clk_prepare_enable(clk); if (ret) { @@ -353,11 +337,6 @@ out_no_irq: clk_disable_unprepare(clk); out_no_clk_enable: clk_put(clk); -out_no_clk: - iounmap(virtbase); -out_no_remap: - release_mem_region(phybase, SZ_4K); -out: return ret; } -- cgit v1.2.3 From 9e14375880c4a64e190b296023f52e987cb9d33e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 3 Jan 2017 19:21:37 -0800 Subject: watchdog: coh901327_wdt: Use dev variable instead of pdev->dev Use a local dev variable instead of dereferencing pdev->dev several times in the probe function to make the code easier to read. Reviewed-by: Linus Walleij Signed-off-by: Guenter Roeck --- drivers/watchdog/coh901327_wdt.c | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index 986222efe174..38dd60f0cfcc 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c @@ -251,60 +251,56 @@ static int __exit coh901327_remove(struct platform_device *pdev) static int __init coh901327_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; int ret; u16 val; struct resource *res; - parent = &pdev->dev; + parent = dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - virtbase = devm_ioremap_resource(&pdev->dev, res); + virtbase = devm_ioremap_resource(dev, res); if (IS_ERR(virtbase)) return PTR_ERR(virtbase); - clk = clk_get(&pdev->dev, NULL); + clk = clk_get(dev, NULL); if (IS_ERR(clk)) { ret = PTR_ERR(clk); - dev_err(&pdev->dev, "could not get clock\n"); + dev_err(dev, "could not get clock\n"); return ret; } ret = clk_prepare_enable(clk); if (ret) { - dev_err(&pdev->dev, "could not prepare and enable clock\n"); + dev_err(dev, "could not prepare and enable clock\n"); goto out_no_clk_enable; } val = readw(virtbase + U300_WDOG_SR); switch (val) { case U300_WDOG_SR_STATUS_TIMED_OUT: - dev_info(&pdev->dev, - "watchdog timed out since last chip reset!\n"); + dev_info(dev, "watchdog timed out since last chip reset!\n"); coh901327_wdt.bootstatus |= WDIOF_CARDRESET; /* Status will be cleared below */ break; case U300_WDOG_SR_STATUS_NORMAL: - dev_info(&pdev->dev, - "in normal status, no timeouts have occurred.\n"); + dev_info(dev, "in normal status, no timeouts have occurred.\n"); break; default: - dev_info(&pdev->dev, - "contains an illegal status code (%08x)\n", val); + dev_info(dev, "contains an illegal status code (%08x)\n", val); break; } val = readw(virtbase + U300_WDOG_D2R); switch (val) { case U300_WDOG_D2R_DISABLE_STATUS_DISABLED: - dev_info(&pdev->dev, "currently disabled.\n"); + dev_info(dev, "currently disabled.\n"); break; case U300_WDOG_D2R_DISABLE_STATUS_ENABLED: - dev_info(&pdev->dev, - "currently enabled! (disabling it now)\n"); + dev_info(dev, "currently enabled! (disabling it now)\n"); coh901327_disable(); break; default: - dev_err(&pdev->dev, - "contains an illegal enable/disable code (%08x)\n", + dev_err(dev, "contains an illegal enable/disable code (%08x)\n", val); break; } @@ -319,16 +315,16 @@ static int __init coh901327_probe(struct platform_device *pdev) goto out_no_irq; } - ret = watchdog_init_timeout(&coh901327_wdt, margin, &pdev->dev); + ret = watchdog_init_timeout(&coh901327_wdt, margin, dev); if (ret < 0) coh901327_wdt.timeout = 60; - coh901327_wdt.parent = &pdev->dev; + coh901327_wdt.parent = dev; ret = watchdog_register_device(&coh901327_wdt); if (ret) goto out_no_wdog; - dev_info(&pdev->dev, "initialized. timer margin=%d sec\n", margin); + dev_info(dev, "initialized. timer margin=%d sec\n", margin); return 0; out_no_wdog: -- cgit v1.2.3 From 7db1634d62d4b521c97ca3439221ee870bcc38f2 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:44 -0800 Subject: watchdog: aspeed_wdt: Convert to use device managed functions Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. 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 - Drop assignments to otherwise unused variables - Drop remove function - Drop platform_set_drvdata() - Use devm_watchdog_register_driver() to register watchdog device Acked-by: Joel Stanley Signed-off-by: Guenter Roeck --- drivers/watchdog/aspeed_wdt.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index f5ad8023c2e6..1c652582de40 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c @@ -136,15 +136,6 @@ static const struct watchdog_info aspeed_wdt_info = { .identity = KBUILD_MODNAME, }; -static int aspeed_wdt_remove(struct platform_device *pdev) -{ - struct aspeed_wdt *wdt = platform_get_drvdata(pdev); - - watchdog_unregister_device(&wdt->wdd); - - return 0; -} - static int aspeed_wdt_probe(struct platform_device *pdev) { struct aspeed_wdt *wdt; @@ -187,20 +178,17 @@ static int aspeed_wdt_probe(struct platform_device *pdev) set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); } - ret = watchdog_register_device(&wdt->wdd); + ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd); if (ret) { dev_err(&pdev->dev, "failed to register\n"); return ret; } - platform_set_drvdata(pdev, wdt); - return 0; } static struct platform_driver aspeed_watchdog_driver = { .probe = aspeed_wdt_probe, - .remove = aspeed_wdt_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(aspeed_wdt_of_table), -- cgit v1.2.3 From 42f82693776cb013baa94c818828f9859cc344a0 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:59 -0800 Subject: watchdog: sunxi_wdt: Convert to use device managed functions and other improvements Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. Other improvements as listed below. 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 - Drop assignments to otherwise unused variables - Drop remove function - Drop platform_set_drvdata() - Use devm_watchdog_register_driver() to register watchdog device - Replace shutdown function with call to watchdog_stop_on_reboot() Cc: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Guenter Roeck --- drivers/watchdog/sunxi_wdt.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c index 953bb7b7446f..9728fa32c357 100644 --- a/drivers/watchdog/sunxi_wdt.c +++ b/drivers/watchdog/sunxi_wdt.c @@ -242,8 +242,6 @@ static int sunxi_wdt_probe(struct platform_device *pdev) if (!sunxi_wdt) return -EINVAL; - platform_set_drvdata(pdev, sunxi_wdt); - device = of_match_device(sunxi_wdt_dt_ids, &pdev->dev); if (!device) return -ENODEV; @@ -270,7 +268,8 @@ static int sunxi_wdt_probe(struct platform_device *pdev) sunxi_wdt_stop(&sunxi_wdt->wdt_dev); - err = watchdog_register_device(&sunxi_wdt->wdt_dev); + watchdog_stop_on_reboot(&sunxi_wdt->wdt_dev); + err = devm_watchdog_register_device(&pdev->dev, &sunxi_wdt->wdt_dev); if (unlikely(err)) return err; @@ -280,27 +279,8 @@ static int sunxi_wdt_probe(struct platform_device *pdev) return 0; } -static int sunxi_wdt_remove(struct platform_device *pdev) -{ - struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev); - - watchdog_unregister_device(&sunxi_wdt->wdt_dev); - watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL); - - return 0; -} - -static void sunxi_wdt_shutdown(struct platform_device *pdev) -{ - struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev); - - sunxi_wdt_stop(&sunxi_wdt->wdt_dev); -} - static struct platform_driver sunxi_wdt_driver = { .probe = sunxi_wdt_probe, - .remove = sunxi_wdt_remove, - .shutdown = sunxi_wdt_shutdown, .driver = { .name = DRV_NAME, .of_match_table = sunxi_wdt_dt_ids, -- cgit v1.2.3 From c8841a606740867d7283b37dd948ece281add3d6 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:53 -0800 Subject: watchdog: meson_wdt: Convert to use device managed functions and other improvements Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. Other improvements as listed below. 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 - Drop assignments to otherwise unused variables - Drop remove function - Drop platform_set_drvdata() - Use devm_watchdog_register_driver() to register watchdog device - Replace shutdown function with call to watchdog_stop_on_reboot() Cc: Carlo Caione Acked-by: Kevin Hilman Signed-off-by: Guenter Roeck --- drivers/watchdog/meson_wdt.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/drivers/watchdog/meson_wdt.c b/drivers/watchdog/meson_wdt.c index 56ea1caf71c3..491b9bf13d84 100644 --- a/drivers/watchdog/meson_wdt.c +++ b/drivers/watchdog/meson_wdt.c @@ -201,38 +201,19 @@ static int meson_wdt_probe(struct platform_device *pdev) meson_wdt_stop(&meson_wdt->wdt_dev); - err = watchdog_register_device(&meson_wdt->wdt_dev); + watchdog_stop_on_reboot(&meson_wdt->wdt_dev); + err = devm_watchdog_register_device(&pdev->dev, &meson_wdt->wdt_dev); if (err) return err; - platform_set_drvdata(pdev, meson_wdt); - dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", meson_wdt->wdt_dev.timeout, nowayout); return 0; } -static int meson_wdt_remove(struct platform_device *pdev) -{ - struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev); - - watchdog_unregister_device(&meson_wdt->wdt_dev); - - return 0; -} - -static void meson_wdt_shutdown(struct platform_device *pdev) -{ - struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev); - - meson_wdt_stop(&meson_wdt->wdt_dev); -} - static struct platform_driver meson_wdt_driver = { .probe = meson_wdt_probe, - .remove = meson_wdt_remove, - .shutdown = meson_wdt_shutdown, .driver = { .name = DRV_NAME, .of_match_table = meson_wdt_dt_ids, -- cgit v1.2.3 From 396164b7407b7419a459c1905e9c8a91cb3c307f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:50 -0800 Subject: watchdog: intel-mid_wdt: Convert to use device managed functions Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. 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 - Drop assignments to otherwise unused variables - Drop remove function - Drop platform_set_drvdata() - Use devm_watchdog_register_driver() to register watchdog device Reviewed-by: Andy Shevchenko Signed-off-by: Guenter Roeck --- drivers/watchdog/intel-mid_wdt.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index a4b729259b12..45e4d02221b5 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c @@ -137,7 +137,6 @@ static int mid_wdt_probe(struct platform_device *pdev) wdt_dev->parent = &pdev->dev; watchdog_set_drvdata(wdt_dev, &pdev->dev); - platform_set_drvdata(pdev, wdt_dev); ret = devm_request_irq(&pdev->dev, pdata->irq, mid_wdt_irq, IRQF_SHARED | IRQF_NO_SUSPEND, "watchdog", @@ -151,7 +150,7 @@ static int mid_wdt_probe(struct platform_device *pdev) /* Make sure the watchdog is not running */ wdt_stop(wdt_dev); - ret = watchdog_register_device(wdt_dev); + ret = devm_watchdog_register_device(&pdev->dev, wdt_dev); if (ret) { dev_err(&pdev->dev, "error registering watchdog device\n"); return ret; @@ -162,16 +161,8 @@ static int mid_wdt_probe(struct platform_device *pdev) return 0; } -static int mid_wdt_remove(struct platform_device *pdev) -{ - struct watchdog_device *wd = platform_get_drvdata(pdev); - watchdog_unregister_device(wd); - return 0; -} - static struct platform_driver mid_wdt_driver = { .probe = mid_wdt_probe, - .remove = mid_wdt_remove, .driver = { .name = "intel_mid_wdt", }, -- cgit v1.2.3 From d3d77b5abc175684a3c42a240ee49931ca51d10d Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:49 -0800 Subject: watchdog: iTCO_wdt: Replace shutdown function with call to watchdog_stop_on_reboot The shutdown function calls the stop function. Call watchdog_stop_on_reboot() from probe instead. 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 - Replace shutdown function with call to watchdog_stop_on_reboot() Reviewed-by: Andy Shevchenko Signed-off-by: Guenter Roeck --- drivers/watchdog/iTCO_wdt.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index d8bb7bf5e669..3d0abc0d59b4 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -520,6 +520,7 @@ static int iTCO_wdt_probe(struct platform_device *pdev) WATCHDOG_TIMEOUT); } + watchdog_stop_on_reboot(&p->wddev); ret = devm_watchdog_register_device(dev, &p->wddev); if (ret != 0) { pr_err("cannot register watchdog device (err=%d)\n", ret); @@ -543,13 +544,6 @@ static int iTCO_wdt_remove(struct platform_device *pdev) return 0; } -static void iTCO_wdt_shutdown(struct platform_device *pdev) -{ - struct iTCO_wdt_private *p = platform_get_drvdata(pdev); - - iTCO_wdt_stop(&p->wddev); -} - #ifdef CONFIG_PM_SLEEP /* * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so @@ -603,7 +597,6 @@ static const struct dev_pm_ops iTCO_wdt_pm = { static struct platform_driver iTCO_wdt_driver = { .probe = iTCO_wdt_probe, .remove = iTCO_wdt_remove, - .shutdown = iTCO_wdt_shutdown, .driver = { .name = DRV_NAME, .pm = ITCO_WDT_PM_OPS, -- cgit v1.2.3 From dd36f6ce680d55fcafa62b35e589549cd53199b1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:48 -0800 Subject: watchdog: digicolor_wdt: Convert to use device managed functions and other improvements Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. Other improvements as listed below. 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 - Replace 'goto l; ... l: return e;' with 'return e;' - Replace 'val = e; return val;' with 'return e;' - Drop assignments to otherwise unused variables - Replace 'if (e) { return expr; }' with 'if (e) return expr;' - Drop remove function - Replace of_iomap() with platform_get_resource() followed by devm_ioremap_resource() - Drop platform_set_drvdata() - Replace &pdev->dev with dev if 'struct device *dev' is a declared variable - Use devm_watchdog_register_driver() to register watchdog device - Replace shutdown function with call to watchdog_stop_on_reboot() Acked-by: Baruch Siach Tested-by: Baruch Siach Signed-off-by: Guenter Roeck --- drivers/watchdog/digicolor_wdt.c | 48 ++++++++++------------------------------ 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c index dfe72944822d..870694d9ebc7 100644 --- a/drivers/watchdog/digicolor_wdt.c +++ b/drivers/watchdog/digicolor_wdt.c @@ -119,62 +119,40 @@ static struct watchdog_device dc_wdt_wdd = { static int dc_wdt_probe(struct platform_device *pdev) { + struct resource *res; struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; struct dc_wdt *wdt; int ret; wdt = devm_kzalloc(dev, sizeof(struct dc_wdt), GFP_KERNEL); if (!wdt) return -ENOMEM; - platform_set_drvdata(pdev, wdt); - wdt->base = of_iomap(np, 0); - if (!wdt->base) { - dev_err(dev, "Failed to remap watchdog regs"); - return -ENODEV; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + wdt->base = devm_ioremap_resource(dev, res); + if (IS_ERR(wdt->base)) + return PTR_ERR(wdt->base); - wdt->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(wdt->clk)) { - ret = PTR_ERR(wdt->clk); - goto err_iounmap; - } + wdt->clk = devm_clk_get(dev, NULL); + if (IS_ERR(wdt->clk)) + return PTR_ERR(wdt->clk); dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk); dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout; - dc_wdt_wdd.parent = &pdev->dev; + dc_wdt_wdd.parent = dev; spin_lock_init(&wdt->lock); watchdog_set_drvdata(&dc_wdt_wdd, wdt); watchdog_set_restart_priority(&dc_wdt_wdd, 128); watchdog_init_timeout(&dc_wdt_wdd, timeout, dev); - ret = watchdog_register_device(&dc_wdt_wdd); + watchdog_stop_on_reboot(&dc_wdt_wdd); + ret = devm_watchdog_register_device(dev, &dc_wdt_wdd); if (ret) { dev_err(dev, "Failed to register watchdog device"); - goto err_iounmap; + return ret; } return 0; - -err_iounmap: - iounmap(wdt->base); - return ret; -} - -static int dc_wdt_remove(struct platform_device *pdev) -{ - struct dc_wdt *wdt = platform_get_drvdata(pdev); - - watchdog_unregister_device(&dc_wdt_wdd); - iounmap(wdt->base); - - return 0; -} - -static void dc_wdt_shutdown(struct platform_device *pdev) -{ - dc_wdt_stop(&dc_wdt_wdd); } static const struct of_device_id dc_wdt_of_match[] = { @@ -185,8 +163,6 @@ MODULE_DEVICE_TABLE(of, dc_wdt_of_match); static struct platform_driver dc_wdt_driver = { .probe = dc_wdt_probe, - .remove = dc_wdt_remove, - .shutdown = dc_wdt_shutdown, .driver = { .name = "digicolor-wdt", .of_match_table = dc_wdt_of_match, -- cgit v1.2.3 From 30cba9a109feb0dbb262d575ae33be8c16d7d26f Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:22:01 -0800 Subject: watchdog: wm831x_wdt: Convert to use device managed functions Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. 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 - Replace 'goto l; ... l: return e;' with 'return e;' - Replace 'val = e; return val;' with 'return e;' - Drop assignments to otherwise unused variables - Replace 'if (e) { return expr; }' with 'if (e) return expr;' - Drop remove function - Drop platform_set_drvdata() - Use devm_watchdog_register_driver() to register watchdog device Acked-by: Charles Keepax Signed-off-by: Guenter Roeck --- drivers/watchdog/wm831x_wdt.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 8d1184aee932..1ddc1f742cd4 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c @@ -194,7 +194,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev) if (ret < 0) { dev_err(wm831x->dev, "Failed to read watchdog status: %d\n", ret); - goto err; + return ret; } reg = ret; @@ -203,10 +203,8 @@ static int wm831x_wdt_probe(struct platform_device *pdev) driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data), GFP_KERNEL); - if (!driver_data) { - ret = -ENOMEM; - goto err; - } + if (!driver_data) + return -ENOMEM; mutex_init(&driver_data->lock); driver_data->wm831x = wm831x; @@ -253,7 +251,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev) dev_err(wm831x->dev, "Failed to request update GPIO: %d\n", ret); - goto err; + return ret; } driver_data->update_gpio = pdata->update_gpio; @@ -269,37 +267,22 @@ static int wm831x_wdt_probe(struct platform_device *pdev) } else { dev_err(wm831x->dev, "Failed to unlock security key: %d\n", ret); - goto err; + return ret; } } - ret = watchdog_register_device(&driver_data->wdt); + ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt); if (ret != 0) { dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n", ret); - goto err; + return ret; } - platform_set_drvdata(pdev, driver_data); - - return 0; - -err: - return ret; -} - -static int wm831x_wdt_remove(struct platform_device *pdev) -{ - struct wm831x_wdt_drvdata *driver_data = platform_get_drvdata(pdev); - - watchdog_unregister_device(&driver_data->wdt); - return 0; } static struct platform_driver wm831x_wdt_driver = { .probe = wm831x_wdt_probe, - .remove = wm831x_wdt_remove, .driver = { .name = "wm831x-watchdog", }, -- cgit v1.2.3 From cb5c14ea573b625053487f9dfde395ac0e8bc11b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:52 -0800 Subject: watchdog: mena21_wdt: Convert to use device managed functions and other improvements Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. Other improvements as listed below. 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 - Replace 'goto l; ... l: return e;' with 'return e;' - Drop assignments to otherwise unused variables - Drop remove function - Drop unnecessary mutex_destroy() on allocated data - Use devm_watchdog_register_driver() to register watchdog device Acked-by: Johannes Thumshirn Signed-off-by: Guenter Roeck --- drivers/watchdog/mena21_wdt.c | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c index af6a7c489f08..045201a6fdb3 100644 --- a/drivers/watchdog/mena21_wdt.c +++ b/drivers/watchdog/mena21_wdt.c @@ -212,33 +212,14 @@ static int a21_wdt_probe(struct platform_device *pdev) drv->wdt = a21_wdt; dev_set_drvdata(&pdev->dev, drv); - ret = watchdog_register_device(&a21_wdt); + ret = devm_watchdog_register_device(&pdev->dev, &a21_wdt); if (ret) { dev_err(&pdev->dev, "Cannot register watchdog device\n"); - goto err_register_wd; + return ret; } dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n"); - return 0; - -err_register_wd: - mutex_destroy(&drv->lock); - - return ret; -} - -static int a21_wdt_remove(struct platform_device *pdev) -{ - struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev); - - dev_warn(&pdev->dev, - "Unregistering A21 watchdog driver, board may reboot\n"); - - watchdog_unregister_device(&drv->wdt); - - mutex_destroy(&drv->lock); - return 0; } @@ -257,7 +238,6 @@ MODULE_DEVICE_TABLE(of, a21_wdt_ids); static struct platform_driver a21_wdt_driver = { .probe = a21_wdt_probe, - .remove = a21_wdt_remove, .shutdown = a21_wdt_shutdown, .driver = { .name = "a21-watchdog", -- cgit v1.2.3 From 5f5aa6f10a11450fb326430bbbb67abf160edb95 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:45 -0800 Subject: watchdog: bcm2835_wdt: Convert to use device managed functions and other improvements Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. Other improvements as listed below. 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 - Drop assignments to otherwise unused variables - Replace of_iomap() with platform_get_resource() followed by devm_ioremap_resource() - Replace &pdev->dev with dev if 'struct device *dev' is a declared variable - Use devm_watchdog_register_driver() to register watchdog device - Replace shutdown function with call to watchdog_stop_on_reboot() Cc: Stephen Warren Cc: Lee Jones Cc: Florian Fainelli Cc: Ray Jui Cc: Scott Branden Acked-by: Eric Anholt Signed-off-by: Guenter Roeck --- drivers/watchdog/bcm2835_wdt.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c index 4e0adb6c88f0..496f6c106bb1 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c @@ -172,8 +172,8 @@ static void bcm2835_power_off(void) static int bcm2835_wdt_probe(struct platform_device *pdev) { + struct resource *res; struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; struct bcm2835_wdt *wdt; int err; @@ -184,16 +184,15 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) spin_lock_init(&wdt->lock); - wdt->base = of_iomap(np, 0); - if (!wdt->base) { - dev_err(dev, "Failed to remap watchdog regs"); - return -ENODEV; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + wdt->base = devm_ioremap_resource(dev, res); + if (IS_ERR(wdt->base)) + return PTR_ERR(wdt->base); watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt); watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev); watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout); - bcm2835_wdt_wdd.parent = &pdev->dev; + bcm2835_wdt_wdd.parent = dev; if (bcm2835_wdt_is_running(wdt)) { /* * The currently active timeout value (set by the @@ -208,10 +207,10 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) watchdog_set_restart_priority(&bcm2835_wdt_wdd, 128); - err = watchdog_register_device(&bcm2835_wdt_wdd); + watchdog_stop_on_reboot(&bcm2835_wdt_wdd); + err = devm_watchdog_register_device(dev, &bcm2835_wdt_wdd); if (err) { dev_err(dev, "Failed to register watchdog device"); - iounmap(wdt->base); return err; } @@ -224,21 +223,12 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) static int bcm2835_wdt_remove(struct platform_device *pdev) { - struct bcm2835_wdt *wdt = platform_get_drvdata(pdev); - if (pm_power_off == bcm2835_power_off) pm_power_off = NULL; - watchdog_unregister_device(&bcm2835_wdt_wdd); - iounmap(wdt->base); return 0; } -static void bcm2835_wdt_shutdown(struct platform_device *pdev) -{ - bcm2835_wdt_stop(&bcm2835_wdt_wdd); -} - static const struct of_device_id bcm2835_wdt_of_match[] = { { .compatible = "brcm,bcm2835-pm-wdt", }, {}, @@ -248,7 +238,6 @@ MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match); static struct platform_driver bcm2835_wdt_driver = { .probe = bcm2835_wdt_probe, .remove = bcm2835_wdt_remove, - .shutdown = bcm2835_wdt_shutdown, .driver = { .name = "bcm2835-wdt", .of_match_table = bcm2835_wdt_of_match, -- cgit v1.2.3 From 189c049a01c2de60e5b88cf73326b9ba3811a16b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:47 -0800 Subject: watchdog: da9052_wdt: Convert to use device managed functions Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. 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 - Replace 'goto l; ... l: return e;' with 'return e;' - Replace 'val = e; return val;' with 'return e;' - Drop assignments to otherwise unused variables - Replace 'if (e) { return expr; }' with 'if (e) return expr;' - Drop remove function - Drop platform_set_drvdata() - Use devm_watchdog_register_driver() to register watchdog device Acked-by: Adam Thomson Signed-off-by: Guenter Roeck --- drivers/watchdog/da9052_wdt.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c index d86a57e3d17d..d6d5006efa71 100644 --- a/drivers/watchdog/da9052_wdt.c +++ b/drivers/watchdog/da9052_wdt.c @@ -128,16 +128,14 @@ static int da9052_wdt_ping(struct watchdog_device *wdt_dev) ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG, DA9052_CONTROLD_WATCHDOG, 1 << 7); if (ret < 0) - goto err_strobe; + return ret; /* * FIXME: Reset the watchdog core, in general PMIC * is supposed to do this */ - ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG, - DA9052_CONTROLD_WATCHDOG, 0 << 7); -err_strobe: - return ret; + return da9052_reg_update(da9052, DA9052_CONTROL_D_REG, + DA9052_CONTROLD_WATCHDOG, 0 << 7); } static const struct watchdog_info da9052_wdt_info = { @@ -163,10 +161,8 @@ static int da9052_wdt_probe(struct platform_device *pdev) driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data), GFP_KERNEL); - if (!driver_data) { - ret = -ENOMEM; - goto err; - } + if (!driver_data) + return -ENOMEM; driver_data->da9052 = da9052; da9052_wdt = &driver_data->wdt; @@ -182,33 +178,21 @@ static int da9052_wdt_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Failed to disable watchdog bits, %d\n", ret); - goto err; + return ret; } - ret = watchdog_register_device(&driver_data->wdt); + ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt); if (ret != 0) { dev_err(da9052->dev, "watchdog_register_device() failed: %d\n", ret); - goto err; + return ret; } - platform_set_drvdata(pdev, driver_data); -err: return ret; } -static int da9052_wdt_remove(struct platform_device *pdev) -{ - struct da9052_wdt_data *driver_data = platform_get_drvdata(pdev); - - watchdog_unregister_device(&driver_data->wdt); - - return 0; -} - static struct platform_driver da9052_wdt_driver = { .probe = da9052_wdt_probe, - .remove = da9052_wdt_remove, .driver = { .name = "da9052-watchdog", }, -- cgit v1.2.3 From 89f944c0f9abce176cf442894d29a7ab25f81c76 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:47 -0800 Subject: watchdog: da9055_wdt: Convert to use device managed functions Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. 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 - Replace 'goto l; ... l: return e;' with 'return e;' - Drop assignments to otherwise unused variables - Drop remove function - Drop platform_set_drvdata() - Use devm_watchdog_register_driver() to register watchdog device Acked-by: Adam Thomson Signed-off-by: Guenter Roeck --- drivers/watchdog/da9055_wdt.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c index 4f30818cf93f..50bdd1022186 100644 --- a/drivers/watchdog/da9055_wdt.c +++ b/drivers/watchdog/da9055_wdt.c @@ -147,32 +147,19 @@ static int da9055_wdt_probe(struct platform_device *pdev) ret = da9055_wdt_stop(da9055_wdt); if (ret < 0) { dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret); - goto err; + return ret; } - platform_set_drvdata(pdev, driver_data); - - ret = watchdog_register_device(&driver_data->wdt); + ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt); if (ret != 0) dev_err(da9055->dev, "watchdog_register_device() failed: %d\n", ret); -err: return ret; } -static int da9055_wdt_remove(struct platform_device *pdev) -{ - struct da9055_wdt_data *driver_data = platform_get_drvdata(pdev); - - watchdog_unregister_device(&driver_data->wdt); - - return 0; -} - static struct platform_driver da9055_wdt_driver = { .probe = da9055_wdt_probe, - .remove = da9055_wdt_remove, .driver = { .name = "da9055-watchdog", }, -- cgit v1.2.3 From 528eff34dda07e98c7aeb2266d2bdb9c54439333 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:47 -0800 Subject: watchdog: da9062_wdt: Convert to use device managed functions Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. 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 - Replace 'val = e; return val;' with 'return e;' - Drop assignments to otherwise unused variables - Drop remove function - Drop dev_set_drvdata() - Use devm_watchdog_register_driver() to register watchdog device Acked-by: Adam Thomson Signed-off-by: Guenter Roeck --- drivers/watchdog/da9062_wdt.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index a02cee6820a1..9083d3d922b0 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c @@ -220,9 +220,8 @@ static int da9062_wdt_probe(struct platform_device *pdev) wdt->wdtdev.parent = &pdev->dev; watchdog_set_drvdata(&wdt->wdtdev, wdt); - dev_set_drvdata(&pdev->dev, wdt); - ret = watchdog_register_device(&wdt->wdtdev); + ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev); if (ret < 0) { dev_err(wdt->hw->dev, "watchdog registration failed (%d)\n", ret); @@ -231,24 +230,11 @@ static int da9062_wdt_probe(struct platform_device *pdev) da9062_set_window_start(wdt); - ret = da9062_wdt_ping(&wdt->wdtdev); - if (ret < 0) - watchdog_unregister_device(&wdt->wdtdev); - - return ret; -} - -static int da9062_wdt_remove(struct platform_device *pdev) -{ - struct da9062_watchdog *wdt = dev_get_drvdata(&pdev->dev); - - watchdog_unregister_device(&wdt->wdtdev); - return 0; + return da9062_wdt_ping(&wdt->wdtdev); } static struct platform_driver da9062_wdt_driver = { .probe = da9062_wdt_probe, - .remove = da9062_wdt_remove, .driver = { .name = "da9062-watchdog", .of_match_table = da9062_compatible_id_table, -- cgit v1.2.3 From 64b849e28b8be15a5bb855890fd9ddb8be162db6 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 15:21:47 -0800 Subject: watchdog: da9063_wdt: Convert to use device managed functions Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. 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 - Replace 'val = e; return val;' with 'return e;' - Replace 'if (e) return e; return 0;' with 'return e;' - Drop assignments to otherwise unused variables - Drop unused variables - Drop remove function - Drop dev_set_drvdata() - Use devm_watchdog_register_driver() to register watchdog device Acked-by: Adam Thomson Signed-off-by: Guenter Roeck --- drivers/watchdog/da9063_wdt.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index 5d6b4e5f7989..4691c5509129 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c @@ -151,7 +151,6 @@ static const struct watchdog_ops da9063_watchdog_ops = { static int da9063_wdt_probe(struct platform_device *pdev) { - int ret; struct da9063 *da9063; struct da9063_watchdog *wdt; @@ -181,27 +180,12 @@ static int da9063_wdt_probe(struct platform_device *pdev) watchdog_set_restart_priority(&wdt->wdtdev, 128); watchdog_set_drvdata(&wdt->wdtdev, wdt); - dev_set_drvdata(&pdev->dev, wdt); - - ret = watchdog_register_device(&wdt->wdtdev); - if (ret) - return ret; - - return 0; -} - -static int da9063_wdt_remove(struct platform_device *pdev) -{ - struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev); - - watchdog_unregister_device(&wdt->wdtdev); - return 0; + return devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev); } static struct platform_driver da9063_wdt_driver = { .probe = da9063_wdt_probe, - .remove = da9063_wdt_remove, .driver = { .name = DA9063_DRVNAME_WATCHDOG, }, -- cgit v1.2.3 From 4b448c96a7f0fd092a4113cab9248ddb7bf21c17 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 10 Jan 2017 18:09:11 -0800 Subject: watchdog: tegra_wdt: Convert to use device managed functions Use device managed functions to simplify error handling, reduce source code size, improve readability, and reduce the likelyhood of bugs. 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 - Use devm_watchdog_register_driver() to register watchdog device Cc: Stephen Warren Cc: Thierry Reding Cc: Alexandre Courbot Signed-off-by: Guenter Roeck Acked-by: Thierry Reding Signed-off-by: Guenter Roeck --- drivers/watchdog/tegra_wdt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index 2d53c3f9394f..9403c08816e3 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c @@ -226,7 +226,7 @@ static int tegra_wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(wdd, nowayout); - ret = watchdog_register_device(wdd); + ret = devm_watchdog_register_device(&pdev->dev, wdd); if (ret) { dev_err(&pdev->dev, "failed to register watchdog device\n"); @@ -248,8 +248,6 @@ static int tegra_wdt_remove(struct platform_device *pdev) tegra_wdt_stop(&wdt->wdd); - watchdog_unregister_device(&wdt->wdd); - dev_info(&pdev->dev, "removed wdt\n"); return 0; -- cgit v1.2.3 From 540aea3dbffc6a75d0b3b77db1cde36a065a6ab5 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 24 Jan 2017 17:02:33 -0500 Subject: watchdog: ebc-c384_wdt: Utilize devm_ functions in driver probe callback The devm_ resource manager functions allow memory to be automatically released when a device is unbound. This patch takes advantage of the resource manager functions and replaces the watchdog_register_device call with the devm_watchdog_register_device call. In addition, the ebc_c384_wdt_remove function has been removed as no longer necessary due to the use of the relevant devm_ resource manager functions. Signed-off-by: William Breathitt Gray Signed-off-by: Guenter Roeck --- drivers/watchdog/ebc-c384_wdt.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/watchdog/ebc-c384_wdt.c b/drivers/watchdog/ebc-c384_wdt.c index 4b849b8e37c2..2170b275ea01 100644 --- a/drivers/watchdog/ebc-c384_wdt.c +++ b/drivers/watchdog/ebc-c384_wdt.c @@ -121,18 +121,7 @@ static int ebc_c384_wdt_probe(struct device *dev, unsigned int id) dev_warn(dev, "Invalid timeout (%u seconds), using default (%u seconds)\n", timeout, WATCHDOG_TIMEOUT); - dev_set_drvdata(dev, wdd); - - return watchdog_register_device(wdd); -} - -static int ebc_c384_wdt_remove(struct device *dev, unsigned int id) -{ - struct watchdog_device *wdd = dev_get_drvdata(dev); - - watchdog_unregister_device(wdd); - - return 0; + return devm_watchdog_register_device(dev, wdd); } static struct isa_driver ebc_c384_wdt_driver = { @@ -140,7 +129,6 @@ static struct isa_driver ebc_c384_wdt_driver = { .driver = { .name = MODULE_NAME }, - .remove = ebc_c384_wdt_remove }; static int __init ebc_c384_wdt_init(void) -- cgit v1.2.3 From bb292ac1c6028344013309a309b44dc691581825 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 25 Jan 2017 14:21:10 -0800 Subject: watchdog: Introduce watchdog_stop_on_unregister helper Many watchdog drivers explicitly stop the watchdog when unregistering it. While it is unclear if this is actually needed (the whatdog should not be running at that time if it can be stopped), introduce a helper to explicitly stop the watchdog in the watchdog core when unregistering it. This helps reducing driver code size while retaining functionality. Signed-off-by: Guenter Roeck --- Documentation/watchdog/watchdog-kernel-api.txt | 6 ++++++ drivers/watchdog/watchdog_dev.c | 5 +++++ include/linux/watchdog.h | 7 +++++++ 3 files changed, 18 insertions(+) diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt index ea277478982f..9b93953f69cf 100644 --- a/Documentation/watchdog/watchdog-kernel-api.txt +++ b/Documentation/watchdog/watchdog-kernel-api.txt @@ -280,6 +280,12 @@ To disable the watchdog on reboot, the user must call the following helper: static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd); +To disable the watchdog when unregistering the watchdog, the user must call +the following helper. Note that this will only stop the watchdog if the +nowayout flag is not set. + +static inline void watchdog_stop_on_unregister(struct watchdog_device *wdd); + To change the priority of the restart handler the following helper should be used: diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 32930a073a12..d5d2bbd8f428 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -987,6 +987,11 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd) wdd->wd_data = NULL; mutex_unlock(&wd_data->lock); + if (watchdog_active(wdd) && + test_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status)) { + watchdog_stop(wdd); + } + cancel_delayed_work_sync(&wd_data->work); kref_put(&wd_data->kref, watchdog_core_data_release); diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index 35a4d8185b51..a786e5e8973b 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h @@ -117,6 +117,7 @@ struct watchdog_device { #define WDOG_NO_WAY_OUT 1 /* Is 'nowayout' feature set ? */ #define WDOG_STOP_ON_REBOOT 2 /* Should be stopped on reboot */ #define WDOG_HW_RUNNING 3 /* True if HW watchdog running */ +#define WDOG_STOP_ON_UNREGISTER 4 /* Should be stopped on unregister */ struct list_head deferred; }; @@ -151,6 +152,12 @@ static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd) set_bit(WDOG_STOP_ON_REBOOT, &wdd->status); } +/* Use the following function to stop the watchdog when unregistering it */ +static inline void watchdog_stop_on_unregister(struct watchdog_device *wdd) +{ + set_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status); +} + /* Use the following function to check if a timeout value is invalid */ static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t) { -- cgit v1.2.3 From b893e344bfbd01a3df5df32ecb9f7bf8f1271d46 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 28 Jan 2017 13:11:17 +0530 Subject: watchdog: constify watchdog_ops structures Declare watchdog_ops structures as const as they are only stored in the ops field of a watchdog_device structure. This field is of type const, so watchdog_ops structures having this property can be made const too. Done using Coccinelle: @r disable optional_qualifier@ identifier x; position p; @@ static struct watchdog_ops x@p={...}; @ok@ struct watchdog_device w; identifier r.x; position p; @@ w.ops=&x@p; @bad@ position p != {r.p,ok.p}; identifier r.x; @@ x@p @depends on !bad disable optional_qualifier@ identifier r.x; @@ +const struct watchdog_ops x; File size details before and after patching. First line of every .o file shows the file size before patching and second line shows the size after patching. text data bss dec hex filename 1340 544 0 1884 75c drivers/watchdog/bcm_kona_wdt.o 1436 440 0 1876 754 drivers/watchdog/bcm_kona_wdt.o 1176 544 4 1724 6bc drivers/watchdog/digicolor_wdt.o 1272 440 4 1716 6b4 drivers/watchdog/digicolor_wdt.o 925 580 89 1594 63a drivers/watchdog/ep93xx_wdt.o 1021 476 89 1586 632 drivers/watchdog/ep93xx_wdt.o 4932 288 17 5237 1475 drivers/watchdog/s3c2410_wdt.o 5028 192 17 5237 1475 drivers/watchdog/s3c2410_wdt.o 1977 292 1 2270 8de drivers/watchdog/sama5d4_wdt.o 2073 196 1 2270 8de drivers/watchdog/sama5d4_wdt.o 1375 484 1 1860 744 drivers/watchdog/sirfsoc_wdt.o 1471 380 1 1852 73c drivers/watchdog/sirfsoc_wdt.o Size remains the same for the files drivers/watchdog/diag288_wdt.o drivers/watchdog/asm9260_wdt.o and drivers/watchdog/atlas7_wdt.o The following .o files did not compile: drivers/watchdog/sun4v_wdt.o, drivers/watchdog/sbsa_gwdt.o, drivers/watchdog/rt2880_wdt.o, drivers/watchdog/booke_wdt.o drivers/watchdog/mt7621_wdt.o Signed-off-by: Bhumika Goyal Signed-off-by: Guenter Roeck --- drivers/watchdog/asm9260_wdt.c | 2 +- drivers/watchdog/atlas7_wdt.c | 2 +- drivers/watchdog/bcm_kona_wdt.c | 2 +- drivers/watchdog/booke_wdt.c | 2 +- drivers/watchdog/diag288_wdt.c | 2 +- drivers/watchdog/digicolor_wdt.c | 2 +- drivers/watchdog/ep93xx_wdt.c | 2 +- drivers/watchdog/mt7621_wdt.c | 2 +- drivers/watchdog/rt2880_wdt.c | 2 +- drivers/watchdog/s3c2410_wdt.c | 2 +- drivers/watchdog/sama5d4_wdt.c | 2 +- drivers/watchdog/sbsa_gwdt.c | 2 +- drivers/watchdog/sirfsoc_wdt.c | 2 +- drivers/watchdog/sun4v_wdt.c | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/watchdog/asm9260_wdt.c b/drivers/watchdog/asm9260_wdt.c index 028feb6f6e53..53da001f0838 100644 --- a/drivers/watchdog/asm9260_wdt.c +++ b/drivers/watchdog/asm9260_wdt.c @@ -186,7 +186,7 @@ static const struct watchdog_info asm9260_wdt_ident = { .identity = "Alphascale asm9260 Watchdog", }; -static struct watchdog_ops asm9260_wdt_ops = { +static const struct watchdog_ops asm9260_wdt_ops = { .owner = THIS_MODULE, .start = asm9260_wdt_enable, .stop = asm9260_wdt_disable, diff --git a/drivers/watchdog/atlas7_wdt.c b/drivers/watchdog/atlas7_wdt.c index ed80734befae..4abdcabd8219 100644 --- a/drivers/watchdog/atlas7_wdt.c +++ b/drivers/watchdog/atlas7_wdt.c @@ -105,7 +105,7 @@ static const struct watchdog_info atlas7_wdt_ident = { .identity = "atlas7 Watchdog", }; -static struct watchdog_ops atlas7_wdt_ops = { +static const struct watchdog_ops atlas7_wdt_ops = { .owner = THIS_MODULE, .start = atlas7_wdt_enable, .stop = atlas7_wdt_disable, diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c index 76b00805cd87..6fce17d5b9f1 100644 --- a/drivers/watchdog/bcm_kona_wdt.c +++ b/drivers/watchdog/bcm_kona_wdt.c @@ -266,7 +266,7 @@ static int bcm_kona_wdt_stop(struct watchdog_device *wdog) SECWDOG_SRSTEN_MASK, 0); } -static struct watchdog_ops bcm_kona_wdt_ops = { +static const struct watchdog_ops bcm_kona_wdt_ops = { .owner = THIS_MODULE, .start = bcm_kona_wdt_start, .stop = bcm_kona_wdt_stop, diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index ae034bb1e551..3ad1e44bef44 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -197,7 +197,7 @@ static struct watchdog_info booke_wdt_info __ro_after_init = { .identity = "PowerPC Book-E Watchdog", }; -static struct watchdog_ops booke_wdt_ops = { +static const struct watchdog_ops booke_wdt_ops = { .owner = THIS_MODULE, .start = booke_wdt_start, .stop = booke_wdt_stop, diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c index 861d3d3133f8..6f591084bb7a 100644 --- a/drivers/watchdog/diag288_wdt.c +++ b/drivers/watchdog/diag288_wdt.c @@ -205,7 +205,7 @@ static int wdt_set_timeout(struct watchdog_device * dev, unsigned int new_to) return wdt_ping(dev); } -static struct watchdog_ops wdt_ops = { +static const struct watchdog_ops wdt_ops = { .owner = THIS_MODULE, .start = wdt_start, .stop = wdt_stop, diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c index 870694d9ebc7..5e4ef93caa02 100644 --- a/drivers/watchdog/digicolor_wdt.c +++ b/drivers/watchdog/digicolor_wdt.c @@ -96,7 +96,7 @@ static unsigned int dc_wdt_get_timeleft(struct watchdog_device *wdog) return count / clk_get_rate(wdt->clk); } -static struct watchdog_ops dc_wdt_ops = { +static const struct watchdog_ops dc_wdt_ops = { .owner = THIS_MODULE, .start = dc_wdt_start, .stop = dc_wdt_stop, diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c index 0a4d7cc05d54..8a6e1a7c63ae 100644 --- a/drivers/watchdog/ep93xx_wdt.c +++ b/drivers/watchdog/ep93xx_wdt.c @@ -99,7 +99,7 @@ static const struct watchdog_info ep93xx_wdt_ident = { .identity = "EP93xx Watchdog", }; -static struct watchdog_ops ep93xx_wdt_ops = { +static const struct watchdog_ops ep93xx_wdt_ops = { .owner = THIS_MODULE, .start = ep93xx_wdt_start, .stop = ep93xx_wdt_stop, diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c index 2fb5a3085521..48a06067075d 100644 --- a/drivers/watchdog/mt7621_wdt.c +++ b/drivers/watchdog/mt7621_wdt.c @@ -110,7 +110,7 @@ static struct watchdog_info mt7621_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, }; -static struct watchdog_ops mt7621_wdt_ops = { +static const struct watchdog_ops mt7621_wdt_ops = { .owner = THIS_MODULE, .start = mt7621_wdt_start, .stop = mt7621_wdt_stop, diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index 4c471fe7b854..05524baf7dcc 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c @@ -124,7 +124,7 @@ static struct watchdog_info rt288x_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, }; -static struct watchdog_ops rt288x_wdt_ops = { +static const struct watchdog_ops rt288x_wdt_ops = { .owner = THIS_MODULE, .start = rt288x_wdt_start, .stop = rt288x_wdt_stop, diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 59e95762a6de..d48ba2590641 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -394,7 +394,7 @@ static const struct watchdog_info s3c2410_wdt_ident = { .identity = "S3C2410 Watchdog", }; -static struct watchdog_ops s3c2410wdt_ops = { +static const struct watchdog_ops s3c2410wdt_ops = { .owner = THIS_MODULE, .start = s3c2410wdt_start, .stop = s3c2410wdt_stop, diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c index a49634cdc1cc..dc4c76b660da 100644 --- a/drivers/watchdog/sama5d4_wdt.c +++ b/drivers/watchdog/sama5d4_wdt.c @@ -107,7 +107,7 @@ static const struct watchdog_info sama5d4_wdt_info = { .identity = "Atmel SAMA5D4 Watchdog", }; -static struct watchdog_ops sama5d4_wdt_ops = { +static const struct watchdog_ops sama5d4_wdt_ops = { .owner = THIS_MODULE, .start = sama5d4_wdt_start, .stop = sama5d4_wdt_stop, diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index e9966bc8c23e..316c2eb122d2 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -215,7 +215,7 @@ static const struct watchdog_info sbsa_gwdt_info = { WDIOF_CARDRESET, }; -static struct watchdog_ops sbsa_gwdt_ops = { +static const struct watchdog_ops sbsa_gwdt_ops = { .owner = THIS_MODULE, .start = sbsa_gwdt_start, .stop = sbsa_gwdt_stop, diff --git a/drivers/watchdog/sirfsoc_wdt.c b/drivers/watchdog/sirfsoc_wdt.c index 3050a0031479..4eea351e09b0 100644 --- a/drivers/watchdog/sirfsoc_wdt.c +++ b/drivers/watchdog/sirfsoc_wdt.c @@ -127,7 +127,7 @@ static const struct watchdog_info sirfsoc_wdt_ident = { .identity = "SiRFSOC Watchdog", }; -static struct watchdog_ops sirfsoc_wdt_ops = { +static const struct watchdog_ops sirfsoc_wdt_ops = { .owner = THIS_MODULE, .start = sirfsoc_wdt_enable, .stop = sirfsoc_wdt_disable, diff --git a/drivers/watchdog/sun4v_wdt.c b/drivers/watchdog/sun4v_wdt.c index 1467fe50a76f..00907973608c 100644 --- a/drivers/watchdog/sun4v_wdt.c +++ b/drivers/watchdog/sun4v_wdt.c @@ -77,7 +77,7 @@ static const struct watchdog_info sun4v_wdt_ident = { .firmware_version = 0, }; -static struct watchdog_ops sun4v_wdt_ops = { +static const struct watchdog_ops sun4v_wdt_ops = { .owner = THIS_MODULE, .start = sun4v_wdt_ping, .stop = sun4v_wdt_stop, -- cgit v1.2.3 From 428a66554a1d475896e47a23f1d2c99b58fa7105 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 28 Jan 2017 23:59:05 +0100 Subject: watchdog: add DT bindings for Cortina Gemini This adds DT bindings for the Cortina systems Gemini SoC watchdog timer. Cc: devicetree@vger.kernel.org Signed-off-by: Linus Walleij Signed-off-by: Guenter Roeck --- .../bindings/watchdog/cortina,gemin-watchdog.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt diff --git a/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt b/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt new file mode 100644 index 000000000000..bc4b865d178b --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt @@ -0,0 +1,17 @@ +Cortina Systems Gemini SoC Watchdog + +Required properties: +- compatible : must be "cortina,gemini-watchdog" +- reg : shall contain base register location and length +- interrupts : shall contain the interrupt for the watchdog + +Optional properties: +- timeout-sec : the default watchdog timeout in seconds. + +Example: + +watchdog@41000000 { + compatible = "cortina,gemini-watchdog"; + reg = <0x41000000 0x1000>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; +}; -- cgit v1.2.3 From eca10ae6000d45ee3fec65f0abf7e07abfc66abb Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 28 Jan 2017 23:59:37 +0100 Subject: watchdog: add driver for Cortina Gemini watchdog This add support for the Cortina systems Gemini (SL3516) SoC watchdog. I have tried to use all the right new kernel interfaces and tested with busybox' "watchdog" command both to kick and get timeouts and reboots. Signed-off-by: Linus Walleij Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 11 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/gemini_wdt.c | 229 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 241 insertions(+) create mode 100644 drivers/watchdog/gemini_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index f7cb150d43d6..ba116f8bf3ee 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -301,6 +301,17 @@ config 977_WATCHDOG Not sure? It's safe to say N. +config GEMINI_WATCHDOG + tristate "Gemini watchdog" + depends on ARCH_GEMINI + select WATCHDOG_CORE + help + Say Y here if to include support for the watchdog timer + embedded in the Cortina Systems Gemini family of devices. + + To compile this driver as a module, choose M here: the + module will be called gemini_wdt. + config IXP4XX_WATCHDOG tristate "IXP4xx Watchdog" depends on ARCH_IXP4XX diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 3af35889a609..21b6bf9bff68 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -45,6 +45,7 @@ obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o +obj-$(CONFIG_GEMINI_WATCHDOG) += gemini_wdt.o obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o diff --git a/drivers/watchdog/gemini_wdt.c b/drivers/watchdog/gemini_wdt.c new file mode 100644 index 000000000000..8155aa619e4c --- /dev/null +++ b/drivers/watchdog/gemini_wdt.c @@ -0,0 +1,229 @@ +/* + * Watchdog driver for Cortina Systems Gemini SoC + * + * Copyright (C) 2017 Linus Walleij + * + * Inspired by the out-of-tree drivers from OpenWRT: + * Copyright (C) 2009 Paulius Zaleckas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GEMINI_WDCOUNTER 0x0 +#define GEMINI_WDLOAD 0x4 +#define GEMINI_WDRESTART 0x8 +#define GEMINI_WDCR 0xC + +#define WDRESTART_MAGIC 0x5AB9 + +#define WDCR_CLOCK_5MHZ BIT(4) +#define WDCR_SYS_RST BIT(1) +#define WDCR_ENABLE BIT(0) + +#define WDT_CLOCK 5000000 /* 5 MHz */ + +struct gemini_wdt { + struct watchdog_device wdd; + struct device *dev; + void __iomem *base; +}; + +static inline +struct gemini_wdt *to_gemini_wdt(struct watchdog_device *wdd) +{ + return container_of(wdd, struct gemini_wdt, wdd); +} + +static int gemini_wdt_start(struct watchdog_device *wdd) +{ + struct gemini_wdt *gwdt = to_gemini_wdt(wdd); + + writel(wdd->timeout * WDT_CLOCK, gwdt->base + GEMINI_WDLOAD); + writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART); + /* set clock before enabling */ + writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST, + gwdt->base + GEMINI_WDCR); + writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE, + gwdt->base + GEMINI_WDCR); + + return 0; +} + +static int gemini_wdt_stop(struct watchdog_device *wdd) +{ + struct gemini_wdt *gwdt = to_gemini_wdt(wdd); + + writel(0, gwdt->base + GEMINI_WDCR); + + return 0; +} + +static int gemini_wdt_ping(struct watchdog_device *wdd) +{ + struct gemini_wdt *gwdt = to_gemini_wdt(wdd); + + writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART); + + return 0; +} + +static int gemini_wdt_set_timeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + wdd->timeout = timeout; + if (watchdog_active(wdd)) + gemini_wdt_start(wdd); + + return 0; +} + +static irqreturn_t gemini_wdt_interrupt(int irq, void *data) +{ + struct gemini_wdt *gwdt = data; + + watchdog_notify_pretimeout(&gwdt->wdd); + + return IRQ_HANDLED; +} + +static const struct watchdog_ops gemini_wdt_ops = { + .start = gemini_wdt_start, + .stop = gemini_wdt_stop, + .ping = gemini_wdt_ping, + .set_timeout = gemini_wdt_set_timeout, + .owner = THIS_MODULE, +}; + +static const struct watchdog_info gemini_wdt_info = { + .options = WDIOF_KEEPALIVEPING + | WDIOF_MAGICCLOSE + | WDIOF_SETTIMEOUT, + .identity = KBUILD_MODNAME, +}; + + +static int gemini_wdt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + struct gemini_wdt *gwdt; + unsigned int reg; + int irq; + int ret; + + gwdt = devm_kzalloc(dev, sizeof(*gwdt), GFP_KERNEL); + if (!gwdt) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gwdt->base = devm_ioremap_resource(dev, res); + if (IS_ERR(gwdt->base)) + return PTR_ERR(gwdt->base); + + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + + gwdt->dev = dev; + gwdt->wdd.info = &gemini_wdt_info; + gwdt->wdd.ops = &gemini_wdt_ops; + gwdt->wdd.min_timeout = 1; + gwdt->wdd.max_timeout = 0xFFFFFFFF / WDT_CLOCK; + gwdt->wdd.parent = dev; + + /* + * If 'timeout-sec' unspecified in devicetree, assume a 13 second + * default. + */ + gwdt->wdd.timeout = 13U; + watchdog_init_timeout(&gwdt->wdd, 0, dev); + + reg = readw(gwdt->base + GEMINI_WDCR); + if (reg & WDCR_ENABLE) { + /* Watchdog was enabled by the bootloader, disable it. */ + reg &= ~WDCR_ENABLE; + writel(reg, gwdt->base + GEMINI_WDCR); + } + + ret = devm_request_irq(dev, irq, gemini_wdt_interrupt, 0, + "watchdog bark", gwdt); + if (ret) + return ret; + + ret = devm_watchdog_register_device(dev, &gwdt->wdd); + if (ret) { + dev_err(&pdev->dev, "failed to register watchdog\n"); + return ret; + } + + /* Set up platform driver data */ + platform_set_drvdata(pdev, gwdt); + dev_info(dev, "Gemini watchdog driver enabled\n"); + + return 0; +} + +static int __maybe_unused gemini_wdt_suspend(struct device *dev) +{ + struct gemini_wdt *gwdt = dev_get_drvdata(dev); + unsigned int reg; + + reg = readw(gwdt->base + GEMINI_WDCR); + reg &= ~WDCR_ENABLE; + writel(reg, gwdt->base + GEMINI_WDCR); + + return 0; +} + +static int __maybe_unused gemini_wdt_resume(struct device *dev) +{ + struct gemini_wdt *gwdt = dev_get_drvdata(dev); + unsigned int reg; + + if (watchdog_active(&gwdt->wdd)) { + reg = readw(gwdt->base + GEMINI_WDCR); + reg |= WDCR_ENABLE; + writel(reg, gwdt->base + GEMINI_WDCR); + } + + return 0; +} + +static const struct dev_pm_ops gemini_wdt_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(gemini_wdt_suspend, + gemini_wdt_resume) +}; + +#ifdef CONFIG_OF +static const struct of_device_id gemini_wdt_match[] = { + { .compatible = "cortina,gemini-watchdog" }, + {}, +}; +MODULE_DEVICE_TABLE(of, gemini_wdt_match); +#endif + +static struct platform_driver gemini_wdt_driver = { + .probe = gemini_wdt_probe, + .driver = { + .name = "gemini-wdt", + .of_match_table = of_match_ptr(gemini_wdt_match), + .pm = &gemini_wdt_dev_pm_ops, + }, +}; +module_platform_driver(gemini_wdt_driver); +MODULE_AUTHOR("Linus Walleij"); +MODULE_DESCRIPTION("Watchdog driver for Gemini"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 8751f90c819c156befc630d467adbc003bd59d87 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sun, 29 Jan 2017 11:12:08 -0800 Subject: watchdog: RDC321X_WDT always depends on PCI Without this dependency, platforms not supporting PCI (such as m68k) report the following build warning when building allmodconfig or allyesconfig. drivers/watchdog/rdc321x_wdt.c: In function 'rdc321x_wdt_ioctl': ./arch/m68k/include/asm/uaccess_mm.h:61:1: warning: 'value' may be used uninitialized in this function Fixes: f4c3de659054 ("watchdog: Enable COMPILE_TEST where possible") Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index ba116f8bf3ee..89b50f6d258f 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1120,6 +1120,7 @@ config NV_TCO config RDC321X_WDT tristate "RDC R-321x SoC watchdog" depends on X86_RDC321X || COMPILE_TEST + depends on PCI help This is the driver for the built in hardware watchdog in the RDC R-321x SoC. -- cgit v1.2.3 From 917003610d178b8bc3cbc63ee9fd203a7b01c444 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 31 Jan 2017 09:33:29 -0700 Subject: watchdog: ep93xx_wdt: cleanup and let the core handle the heartbeat Cleanup this driver and remove the 200ms heartbeat timer. The core now has the ability to handle the heartbeat. Signed-off-by: H Hartley Sweeten [groeck: Dropped 0-initialization of static variable] Signed-off-by: Guenter Roeck --- drivers/watchdog/ep93xx_wdt.c | 114 ++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 70 deletions(-) diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c index 8a6e1a7c63ae..f9b14e6efd9a 100644 --- a/drivers/watchdog/ep93xx_wdt.c +++ b/drivers/watchdog/ep93xx_wdt.c @@ -19,21 +19,13 @@ * for us to rely on the user space daemon alone. So we ping the * wdt each ~200msec and eventually stop doing it if the user space * daemon dies. - * - * TODO: - * - * - Test last reset from watchdog status - * - Add a few missing ioctls */ #include #include #include -#include #include -#define WDT_VERSION "0.4" - /* default timeout (secs) */ #define WDT_TIMEOUT 30 @@ -41,59 +33,48 @@ static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); -static unsigned int timeout = WDT_TIMEOUT; +static unsigned int timeout; module_param(timeout, uint, 0); -MODULE_PARM_DESC(timeout, - "Watchdog timeout in seconds. (1<=timeout<=3600, default=" - __MODULE_STRING(WDT_TIMEOUT) ")"); - -static void __iomem *mmio_base; -static struct timer_list timer; -static unsigned long next_heartbeat; +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds."); #define EP93XX_WATCHDOG 0x00 #define EP93XX_WDSTATUS 0x04 -/* reset the wdt every ~200ms - the heartbeat of the device is 0.250 seconds*/ -#define WDT_INTERVAL (HZ/5) - -static void ep93xx_wdt_timer_ping(unsigned long data) -{ - if (time_before(jiffies, next_heartbeat)) - writel(0x5555, mmio_base + EP93XX_WATCHDOG); - - /* Re-set the timer interval */ - mod_timer(&timer, jiffies + WDT_INTERVAL); -} +struct ep93xx_wdt_priv { + void __iomem *mmio; + struct watchdog_device wdd; +}; static int ep93xx_wdt_start(struct watchdog_device *wdd) { - next_heartbeat = jiffies + (timeout * HZ); + struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd); - writel(0xaaaa, mmio_base + EP93XX_WATCHDOG); - mod_timer(&timer, jiffies + WDT_INTERVAL); + writel(0xaaaa, priv->mmio + EP93XX_WATCHDOG); return 0; } static int ep93xx_wdt_stop(struct watchdog_device *wdd) { - del_timer_sync(&timer); - writel(0xaa55, mmio_base + EP93XX_WATCHDOG); + struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd); + + writel(0xaa55, priv->mmio + EP93XX_WATCHDOG); return 0; } -static int ep93xx_wdt_keepalive(struct watchdog_device *wdd) +static int ep93xx_wdt_ping(struct watchdog_device *wdd) { - /* user land ping */ - next_heartbeat = jiffies + (timeout * HZ); + struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd); + + writel(0x5555, priv->mmio + EP93XX_WATCHDOG); return 0; } static const struct watchdog_info ep93xx_wdt_ident = { .options = WDIOF_CARDRESET | + WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, .identity = "EP93xx Watchdog", @@ -103,55 +84,50 @@ static const struct watchdog_ops ep93xx_wdt_ops = { .owner = THIS_MODULE, .start = ep93xx_wdt_start, .stop = ep93xx_wdt_stop, - .ping = ep93xx_wdt_keepalive, -}; - -static struct watchdog_device ep93xx_wdt_wdd = { - .info = &ep93xx_wdt_ident, - .ops = &ep93xx_wdt_ops, + .ping = ep93xx_wdt_ping, }; static int ep93xx_wdt_probe(struct platform_device *pdev) { + struct ep93xx_wdt_priv *priv; + struct watchdog_device *wdd; struct resource *res; unsigned long val; - int err; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mmio_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(mmio_base)) - return PTR_ERR(mmio_base); + priv->mmio = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->mmio)) + return PTR_ERR(priv->mmio); - if (timeout < 1 || timeout > 3600) { - timeout = WDT_TIMEOUT; - dev_warn(&pdev->dev, - "timeout value must be 1<=x<=3600, using %d\n", - timeout); - } + val = readl(priv->mmio + EP93XX_WATCHDOG); - val = readl(mmio_base + EP93XX_WATCHDOG); - ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0; - ep93xx_wdt_wdd.timeout = timeout; - ep93xx_wdt_wdd.parent = &pdev->dev; + wdd = &priv->wdd; + wdd->bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0; + wdd->info = &ep93xx_wdt_ident; + wdd->ops = &ep93xx_wdt_ops; + wdd->min_timeout = 1; + wdd->max_hw_heartbeat_ms = 200; + wdd->parent = &pdev->dev; - watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout); + watchdog_set_nowayout(wdd, nowayout); - setup_timer(&timer, ep93xx_wdt_timer_ping, 1); + wdd->timeout = WDT_TIMEOUT; + watchdog_init_timeout(wdd, timeout, &pdev->dev); - err = watchdog_register_device(&ep93xx_wdt_wdd); - if (err) - return err; + watchdog_set_drvdata(wdd, priv); - dev_info(&pdev->dev, - "EP93XX watchdog, driver version " WDT_VERSION "%s\n", - (val & 0x08) ? " (nCS1 disable detected)" : ""); + ret = devm_watchdog_register_device(&pdev->dev, wdd); + if (ret) + return ret; - return 0; -} + dev_info(&pdev->dev, "EP93XX watchdog driver %s\n", + (val & 0x08) ? " (nCS1 disable detected)" : ""); -static int ep93xx_wdt_remove(struct platform_device *pdev) -{ - watchdog_unregister_device(&ep93xx_wdt_wdd); return 0; } @@ -160,7 +136,6 @@ static struct platform_driver ep93xx_wdt_driver = { .name = "ep93xx-wdt", }, .probe = ep93xx_wdt_probe, - .remove = ep93xx_wdt_remove, }; module_platform_driver(ep93xx_wdt_driver); @@ -170,4 +145,3 @@ MODULE_AUTHOR("Alessandro Zummo "); MODULE_AUTHOR("H Hartley Sweeten "); MODULE_DESCRIPTION("EP93xx Watchdog"); MODULE_LICENSE("GPL"); -MODULE_VERSION(WDT_VERSION); -- cgit v1.2.3 From 8f8dc7bf3e0ab14d1ce1964dbe66ff8acf8779c6 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Tue, 31 Jan 2017 09:33:30 -0700 Subject: watchdog: ts72xx_wdt: convert driver to watchdog core Cleanup this driver and convert it to use the watchdog framework API. Signed-off-by: H Hartley Sweeten Cc: Mika Westerberg [groeck: Dropped initialization of static variable] Signed-off-by: Guenter Roeck --- drivers/watchdog/ts72xx_wdt.c | 447 +++++++++--------------------------------- 1 file changed, 89 insertions(+), 358 deletions(-) diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c index 4b541934b6c5..17c25daebcce 100644 --- a/drivers/watchdog/ts72xx_wdt.c +++ b/drivers/watchdog/ts72xx_wdt.c @@ -13,428 +13,159 @@ * warranty of any kind, whether express or implied. */ -#include -#include -#include -#include -#include -#include #include -#include +#include #include -#include +#include -#define TS72XX_WDT_FEED_VAL 0x05 -#define TS72XX_WDT_DEFAULT_TIMEOUT 8 +#define TS72XX_WDT_DEFAULT_TIMEOUT 30 -static int timeout = TS72XX_WDT_DEFAULT_TIMEOUT; +static int timeout; module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. " - "(1 <= timeout <= 8, default=" - __MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT) - ")"); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds."); static bool nowayout = WATCHDOG_NOWAYOUT; module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); -/** - * struct ts72xx_wdt - watchdog control structure - * @lock: lock that protects this structure - * @regval: watchdog timeout value suitable for control register - * @flags: flags controlling watchdog device state - * @control_reg: watchdog control register - * @feed_reg: watchdog feed register - * @pdev: back pointer to platform dev - */ -struct ts72xx_wdt { - struct mutex lock; - int regval; - -#define TS72XX_WDT_BUSY_FLAG 1 -#define TS72XX_WDT_EXPECT_CLOSE_FLAG 2 - int flags; +/* priv->control_reg */ +#define TS72XX_WDT_CTRL_DISABLE 0x00 +#define TS72XX_WDT_CTRL_250MS 0x01 +#define TS72XX_WDT_CTRL_500MS 0x02 +#define TS72XX_WDT_CTRL_1SEC 0x03 +#define TS72XX_WDT_CTRL_RESERVED 0x04 +#define TS72XX_WDT_CTRL_2SEC 0x05 +#define TS72XX_WDT_CTRL_4SEC 0x06 +#define TS72XX_WDT_CTRL_8SEC 0x07 + +/* priv->feed_reg */ +#define TS72XX_WDT_FEED_VAL 0x05 +struct ts72xx_wdt_priv { void __iomem *control_reg; void __iomem *feed_reg; - - struct platform_device *pdev; + struct watchdog_device wdd; + unsigned char regval; }; -static struct platform_device *ts72xx_wdt_pdev; - -/* - * TS-72xx Watchdog supports following timeouts (value written - * to control register): - * value description - * ------------------------- - * 0x00 watchdog disabled - * 0x01 250ms - * 0x02 500ms - * 0x03 1s - * 0x04 reserved - * 0x05 2s - * 0x06 4s - * 0x07 8s - * - * Timeouts below 1s are not very usable so we don't - * allow them at all. - * - * We provide two functions that convert between these: - * timeout_to_regval() and regval_to_timeout(). - */ -static const struct { - int timeout; - int regval; -} ts72xx_wdt_map[] = { - { 1, 3 }, - { 2, 5 }, - { 4, 6 }, - { 8, 7 }, -}; - -/** - * timeout_to_regval() - converts given timeout to control register value - * @new_timeout: timeout in seconds to be converted - * - * Function converts given @new_timeout into valid value that can - * be programmed into watchdog control register. When conversion is - * not possible, function returns %-EINVAL. - */ -static int timeout_to_regval(int new_timeout) -{ - int i; - - /* first limit it to 1 - 8 seconds */ - new_timeout = clamp_val(new_timeout, 1, 8); - - for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) { - if (ts72xx_wdt_map[i].timeout >= new_timeout) - return ts72xx_wdt_map[i].regval; - } - - return -EINVAL; -} - -/** - * regval_to_timeout() - converts control register value to timeout - * @regval: control register value to be converted - * - * Function converts given @regval to timeout in seconds (1, 2, 4 or 8). - * If @regval cannot be converted, function returns %-EINVAL. - */ -static int regval_to_timeout(int regval) +static int ts72xx_wdt_start(struct watchdog_device *wdd) { - int i; + struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); - for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) { - if (ts72xx_wdt_map[i].regval == regval) - return ts72xx_wdt_map[i].timeout; - } + writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg); + writeb(priv->regval, priv->control_reg); - return -EINVAL; + return 0; } -/** - * ts72xx_wdt_kick() - kick the watchdog - * @wdt: watchdog to be kicked - * - * Called with @wdt->lock held. - */ -static inline void ts72xx_wdt_kick(struct ts72xx_wdt *wdt) +static int ts72xx_wdt_stop(struct watchdog_device *wdd) { - __raw_writeb(TS72XX_WDT_FEED_VAL, wdt->feed_reg); -} + struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); -/** - * ts72xx_wdt_start() - starts the watchdog timer - * @wdt: watchdog to be started - * - * This function programs timeout to watchdog timer - * and starts it. - * - * Called with @wdt->lock held. - */ -static void ts72xx_wdt_start(struct ts72xx_wdt *wdt) -{ - /* - * To program the wdt, it first must be "fed" and - * only after that (within 30 usecs) the configuration - * can be changed. - */ - ts72xx_wdt_kick(wdt); - __raw_writeb((u8)wdt->regval, wdt->control_reg); -} + writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg); + writeb(TS72XX_WDT_CTRL_DISABLE, priv->control_reg); -/** - * ts72xx_wdt_stop() - stops the watchdog timer - * @wdt: watchdog to be stopped - * - * Called with @wdt->lock held. - */ -static void ts72xx_wdt_stop(struct ts72xx_wdt *wdt) -{ - ts72xx_wdt_kick(wdt); - __raw_writeb(0, wdt->control_reg); + return 0; } -static int ts72xx_wdt_open(struct inode *inode, struct file *file) +static int ts72xx_wdt_ping(struct watchdog_device *wdd) { - struct ts72xx_wdt *wdt = platform_get_drvdata(ts72xx_wdt_pdev); - int regval; - - /* - * Try to convert default timeout to valid register - * value first. - */ - regval = timeout_to_regval(timeout); - if (regval < 0) { - dev_err(&wdt->pdev->dev, - "failed to convert timeout (%d) to register value\n", - timeout); - return regval; - } - - if (mutex_lock_interruptible(&wdt->lock)) - return -ERESTARTSYS; + struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); - if ((wdt->flags & TS72XX_WDT_BUSY_FLAG) != 0) { - mutex_unlock(&wdt->lock); - return -EBUSY; - } - - wdt->flags = TS72XX_WDT_BUSY_FLAG; - wdt->regval = regval; - file->private_data = wdt; - - ts72xx_wdt_start(wdt); + writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg); - mutex_unlock(&wdt->lock); - return nonseekable_open(inode, file); + return 0; } -static int ts72xx_wdt_release(struct inode *inode, struct file *file) +static int ts72xx_wdt_settimeout(struct watchdog_device *wdd, unsigned int to) { - struct ts72xx_wdt *wdt = file->private_data; - - if (mutex_lock_interruptible(&wdt->lock)) - return -ERESTARTSYS; - - if ((wdt->flags & TS72XX_WDT_EXPECT_CLOSE_FLAG) != 0) { - ts72xx_wdt_stop(wdt); + struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); + + if (to == 1) { + priv->regval = TS72XX_WDT_CTRL_1SEC; + } else if (to == 2) { + priv->regval = TS72XX_WDT_CTRL_2SEC; + } else if (to <= 4) { + priv->regval = TS72XX_WDT_CTRL_4SEC; + to = 4; } else { - dev_warn(&wdt->pdev->dev, - "TS-72XX WDT device closed unexpectly. " - "Watchdog timer will not stop!\n"); - /* - * Kick it one more time, to give userland some time - * to recover (for example, respawning the kicker - * daemon). - */ - ts72xx_wdt_kick(wdt); + priv->regval = TS72XX_WDT_CTRL_8SEC; + if (to <= 8) + to = 8; } - wdt->flags = 0; + wdd->timeout = to; - mutex_unlock(&wdt->lock); - return 0; -} - -static ssize_t ts72xx_wdt_write(struct file *file, - const char __user *data, - size_t len, - loff_t *ppos) -{ - struct ts72xx_wdt *wdt = file->private_data; - - if (!len) - return 0; - - if (mutex_lock_interruptible(&wdt->lock)) - return -ERESTARTSYS; - - ts72xx_wdt_kick(wdt); - - /* - * Support for magic character closing. User process - * writes 'V' into the device, just before it is closed. - * This means that we know that the wdt timer can be - * stopped after user closes the device. - */ - if (!nowayout) { - int i; - - for (i = 0; i < len; i++) { - char c; - - /* In case it was set long ago */ - wdt->flags &= ~TS72XX_WDT_EXPECT_CLOSE_FLAG; - - if (get_user(c, data + i)) { - mutex_unlock(&wdt->lock); - return -EFAULT; - } - if (c == 'V') { - wdt->flags |= TS72XX_WDT_EXPECT_CLOSE_FLAG; - break; - } - } + if (watchdog_active(wdd)) { + ts72xx_wdt_stop(wdd); + ts72xx_wdt_start(wdd); } - mutex_unlock(&wdt->lock); - return len; + return 0; } -static const struct watchdog_info winfo = { - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | +static const struct watchdog_info ts72xx_wdt_ident = { + .options = WDIOF_KEEPALIVEPING | + WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, .firmware_version = 1, .identity = "TS-72XX WDT", }; -static long ts72xx_wdt_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct ts72xx_wdt *wdt = file->private_data; - void __user *argp = (void __user *)arg; - int __user *p = (int __user *)argp; - int error = 0; - - if (mutex_lock_interruptible(&wdt->lock)) - return -ERESTARTSYS; - - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user(argp, &winfo, sizeof(winfo))) - error = -EFAULT; - break; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - error = put_user(0, p); - break; - - case WDIOC_KEEPALIVE: - ts72xx_wdt_kick(wdt); - break; - - case WDIOC_SETOPTIONS: { - int options; - - error = get_user(options, p); - if (error) - break; - - error = -EINVAL; - - if ((options & WDIOS_DISABLECARD) != 0) { - ts72xx_wdt_stop(wdt); - error = 0; - } - if ((options & WDIOS_ENABLECARD) != 0) { - ts72xx_wdt_start(wdt); - error = 0; - } - - break; - } - - case WDIOC_SETTIMEOUT: { - int new_timeout; - int regval; - - error = get_user(new_timeout, p); - if (error) - break; - - regval = timeout_to_regval(new_timeout); - if (regval < 0) { - error = regval; - break; - } - ts72xx_wdt_stop(wdt); - wdt->regval = regval; - ts72xx_wdt_start(wdt); - - /*FALLTHROUGH*/ - } - - case WDIOC_GETTIMEOUT: - error = put_user(regval_to_timeout(wdt->regval), p); - break; - - default: - error = -ENOTTY; - break; - } - - mutex_unlock(&wdt->lock); - return error; -} - -static const struct file_operations ts72xx_wdt_fops = { +static struct watchdog_ops ts72xx_wdt_ops = { .owner = THIS_MODULE, - .llseek = no_llseek, - .open = ts72xx_wdt_open, - .release = ts72xx_wdt_release, - .write = ts72xx_wdt_write, - .unlocked_ioctl = ts72xx_wdt_ioctl, -}; - -static struct miscdevice ts72xx_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &ts72xx_wdt_fops, + .start = ts72xx_wdt_start, + .stop = ts72xx_wdt_stop, + .ping = ts72xx_wdt_ping, + .set_timeout = ts72xx_wdt_settimeout, }; static int ts72xx_wdt_probe(struct platform_device *pdev) { - struct ts72xx_wdt *wdt; - struct resource *r1, *r2; - int error = 0; + struct ts72xx_wdt_priv *priv; + struct watchdog_device *wdd; + struct resource *res; + int ret; - wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL); - if (!wdt) + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1); - if (IS_ERR(wdt->control_reg)) - return PTR_ERR(wdt->control_reg); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->control_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->control_reg)) + return PTR_ERR(priv->control_reg); - r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2); - if (IS_ERR(wdt->feed_reg)) - return PTR_ERR(wdt->feed_reg); + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + priv->feed_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->feed_reg)) + return PTR_ERR(priv->feed_reg); - platform_set_drvdata(pdev, wdt); - ts72xx_wdt_pdev = pdev; - wdt->pdev = pdev; - mutex_init(&wdt->lock); + wdd = &priv->wdd; + wdd->info = &ts72xx_wdt_ident; + wdd->ops = &ts72xx_wdt_ops; + wdd->min_timeout = 1; + wdd->max_hw_heartbeat_ms = 8000; + wdd->parent = &pdev->dev; - /* make sure that the watchdog is disabled */ - ts72xx_wdt_stop(wdt); + watchdog_set_nowayout(wdd, nowayout); - error = misc_register(&ts72xx_wdt_miscdev); - if (error) { - dev_err(&pdev->dev, "failed to register miscdev\n"); - return error; - } + wdd->timeout = TS72XX_WDT_DEFAULT_TIMEOUT; + watchdog_init_timeout(wdd, timeout, &pdev->dev); - dev_info(&pdev->dev, "TS-72xx Watchdog driver\n"); + watchdog_set_drvdata(wdd, priv); - return 0; -} + ret = devm_watchdog_register_device(&pdev->dev, wdd); + if (ret) + return ret; + + dev_info(&pdev->dev, "TS-72xx Watchdog driver\n"); -static int ts72xx_wdt_remove(struct platform_device *pdev) -{ - misc_deregister(&ts72xx_wdt_miscdev); return 0; } static struct platform_driver ts72xx_wdt_driver = { .probe = ts72xx_wdt_probe, - .remove = ts72xx_wdt_remove, .driver = { .name = "ts72xx-wdt", }, -- cgit v1.2.3 From 722ce6356ddfdcb75ab9379f426a89691b0234de Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 30 Jan 2017 18:18:47 +0100 Subject: watchdog: sama5d4: Cache MR instead of a partial config .config is used to cache a part of WDT_MR at probe time and is not used afterwards. Instead of doing that, actually cache MR and avoid reading it every time it is modified. Signed-off-by: Alexandre Belloni Signed-off-by: Guenter Roeck --- drivers/watchdog/sama5d4_wdt.c | 45 ++++++++++++++++++------------------------ 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c index dc4c76b660da..3230a842d015 100644 --- a/drivers/watchdog/sama5d4_wdt.c +++ b/drivers/watchdog/sama5d4_wdt.c @@ -28,7 +28,7 @@ struct sama5d4_wdt { struct watchdog_device wdd; void __iomem *reg_base; - u32 config; + u32 mr; }; static int wdt_timeout = WDT_DEFAULT_TIMEOUT; @@ -53,11 +53,9 @@ MODULE_PARM_DESC(nowayout, static int sama5d4_wdt_start(struct watchdog_device *wdd) { struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); - u32 reg; - reg = wdt_read(wdt, AT91_WDT_MR); - reg &= ~AT91_WDT_WDDIS; - wdt_write(wdt, AT91_WDT_MR, reg); + wdt->mr &= ~AT91_WDT_WDDIS; + wdt_write(wdt, AT91_WDT_MR, wdt->mr); return 0; } @@ -65,11 +63,9 @@ static int sama5d4_wdt_start(struct watchdog_device *wdd) static int sama5d4_wdt_stop(struct watchdog_device *wdd) { struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); - u32 reg; - reg = wdt_read(wdt, AT91_WDT_MR); - reg |= AT91_WDT_WDDIS; - wdt_write(wdt, AT91_WDT_MR, reg); + wdt->mr |= AT91_WDT_WDDIS; + wdt_write(wdt, AT91_WDT_MR, wdt->mr); return 0; } @@ -88,14 +84,12 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd, { struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); u32 value = WDT_SEC2TICKS(timeout); - u32 reg; - reg = wdt_read(wdt, AT91_WDT_MR); - reg &= ~AT91_WDT_WDV; - reg &= ~AT91_WDT_WDD; - reg |= AT91_WDT_SET_WDV(value); - reg |= AT91_WDT_SET_WDD(value); - wdt_write(wdt, AT91_WDT_MR, reg); + wdt->mr &= ~AT91_WDT_WDV; + wdt->mr &= ~AT91_WDT_WDD; + wdt->mr |= AT91_WDT_SET_WDV(value); + wdt->mr |= AT91_WDT_SET_WDD(value); + wdt_write(wdt, AT91_WDT_MR, wdt->mr); wdd->timeout = timeout; @@ -132,19 +126,19 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt) { const char *tmp; - wdt->config = AT91_WDT_WDDIS; + wdt->mr = AT91_WDT_WDDIS; if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && !strcmp(tmp, "software")) - wdt->config |= AT91_WDT_WDFIEN; + wdt->mr |= AT91_WDT_WDFIEN; else - wdt->config |= AT91_WDT_WDRSTEN; + wdt->mr |= AT91_WDT_WDRSTEN; if (of_property_read_bool(np, "atmel,idle-halt")) - wdt->config |= AT91_WDT_WDIDLEHLT; + wdt->mr |= AT91_WDT_WDIDLEHLT; if (of_property_read_bool(np, "atmel,dbg-halt")) - wdt->config |= AT91_WDT_WDDBGHLT; + wdt->mr |= AT91_WDT_WDDBGHLT; return 0; } @@ -163,11 +157,10 @@ static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) reg &= ~AT91_WDT_WDDIS; wdt_write(wdt, AT91_WDT_MR, reg); - reg = wdt->config; - reg |= AT91_WDT_SET_WDD(value); - reg |= AT91_WDT_SET_WDV(value); + wdt->mr |= AT91_WDT_SET_WDD(value); + wdt->mr |= AT91_WDT_SET_WDV(value); - wdt_write(wdt, AT91_WDT_MR, reg); + wdt_write(wdt, AT91_WDT_MR, wdt->mr); return 0; } @@ -211,7 +204,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev) return ret; } - if ((wdt->config & AT91_WDT_WDFIEN) && irq) { + if ((wdt->mr & AT91_WDT_WDFIEN) && irq) { ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler, IRQF_SHARED | IRQF_IRQPOLL | IRQF_NO_SUSPEND, pdev->name, pdev); -- cgit v1.2.3 From f201353273b6dec71940df01ea6eeb528d907941 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 30 Jan 2017 18:18:48 +0100 Subject: watchdog: sama5d4: Implement resume hook When resuming for the deepest state on sama5d2, it is necessary to restore MR as the registers are lost. Signed-off-by: Alexandre Belloni Signed-off-by: Guenter Roeck --- drivers/watchdog/sama5d4_wdt.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c index 3230a842d015..f709962018ac 100644 --- a/drivers/watchdog/sama5d4_wdt.c +++ b/drivers/watchdog/sama5d4_wdt.c @@ -258,11 +258,28 @@ static const struct of_device_id sama5d4_wdt_of_match[] = { }; MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match); +#ifdef CONFIG_PM_SLEEP +static int sama5d4_wdt_resume(struct device *dev) +{ + struct sama5d4_wdt *wdt = dev_get_drvdata(dev); + + wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS); + if (wdt->mr & AT91_WDT_WDDIS) + wdt_write(wdt, AT91_WDT_MR, wdt->mr); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(sama5d4_wdt_pm_ops, NULL, + sama5d4_wdt_resume); + static struct platform_driver sama5d4_wdt_driver = { .probe = sama5d4_wdt_probe, .remove = sama5d4_wdt_remove, .driver = { .name = "sama5d4_wdt", + .pm = &sama5d4_wdt_pm_ops, .of_match_table = sama5d4_wdt_of_match, } }; -- cgit v1.2.3 From df823c19e5245148b0557577000fb73274af3656 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Sat, 4 Feb 2017 09:34:13 +0800 Subject: dt: bindings: add documentation for zx2967 family watchdog controller This patch adds dt-binding documentation for zx2967 family watchdog controller. Signed-off-by: Baoyou Xie Acked-by: Rob Herring Signed-off-by: Guenter Roeck --- .../bindings/watchdog/zte,zx2967-wdt.txt | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt diff --git a/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt new file mode 100644 index 000000000000..06ce67766756 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt @@ -0,0 +1,32 @@ +ZTE zx2967 Watchdog timer + +Required properties: + +- compatible : should be one of the following. + * zte,zx296718-wdt +- reg : Specifies base physical address and size of the registers. +- clocks : Pairs of phandle and specifier referencing the controller's clocks. +- resets : Reference to the reset controller controlling the watchdog + controller. + +Optional properties: + +- timeout-sec : Contains the watchdog timeout in seconds. +- zte,wdt-reset-sysctrl : Directs how to reset system by the watchdog. + if we don't want to restart system when watchdog been triggered, + it's not required, vice versa. + It should include following fields. + * phandle of aon-sysctrl. + * offset of register that be written, should be 0xb0. + * configure value that be written to aon-sysctrl. + * bit mask, corresponding bits will be affected. + +Example: + +wdt: watchdog@1465000 { + compatible = "zte,zx296718-wdt"; + reg = <0x1465000 0x1000>; + clocks = <&topcrm WDT_WCLK>; + resets = <&toprst 35>; + zte,wdt-reset-sysctrl = <&aon_sysctrl 0xb0 1 0x115>; +}; -- cgit v1.2.3 From 8ce6796dabb9f1f55b07cd032449a24b625f761e Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Sat, 4 Feb 2017 09:34:15 +0800 Subject: watchdog: zx2967: add watchdog controller driver for ZTE's zx2967 family This patch adds watchdog controller driver for ZTE's zx2967 family. Signed-off-by: Baoyou Xie Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 10 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/zx2967_wdt.c | 291 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 302 insertions(+) create mode 100644 drivers/watchdog/zx2967_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 89b50f6d258f..2d006d8cfb15 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -725,6 +725,16 @@ config ASPEED_WATCHDOG To compile this driver as a module, choose M here: the module will be called aspeed_wdt. +config ZX2967_WATCHDOG + tristate "ZTE zx2967 SoCs watchdog support" + depends on ARCH_ZX + select WATCHDOG_CORE + help + Say Y here to include support for the watchdog timer + in ZTE zx2967 SoCs. + To compile this driver as a module, choose M here: the + module will be called zx2967_wdt. + # AVR32 Architecture config AT32AP700X_WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 21b6bf9bff68..a2126e2a99ae 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -83,6 +83,7 @@ obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o +obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o # AVR32 Architecture obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o diff --git a/drivers/watchdog/zx2967_wdt.c b/drivers/watchdog/zx2967_wdt.c new file mode 100644 index 000000000000..e290d5a13a6d --- /dev/null +++ b/drivers/watchdog/zx2967_wdt.c @@ -0,0 +1,291 @@ +/* + * watchdog driver for ZTE's zx2967 family + * + * Copyright (C) 2017 ZTE Ltd. + * + * Author: Baoyou Xie + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ZX2967_WDT_CFG_REG 0x4 +#define ZX2967_WDT_LOAD_REG 0x8 +#define ZX2967_WDT_REFRESH_REG 0x18 +#define ZX2967_WDT_START_REG 0x1c + +#define ZX2967_WDT_REFRESH_MASK GENMASK(5, 0) + +#define ZX2967_WDT_CFG_DIV(n) ((((n) & 0xff) - 1) << 8) +#define ZX2967_WDT_START_EN 0x1 + +/* + * Hardware magic number. + * When watchdog reg is written, the lowest 16 bits are valid, but + * the highest 16 bits should be always this number. + */ +#define ZX2967_WDT_WRITEKEY (0x1234 << 16) +#define ZX2967_WDT_VAL_MASK GENMASK(15, 0) + +#define ZX2967_WDT_DIV_DEFAULT 16 +#define ZX2967_WDT_DEFAULT_TIMEOUT 32 +#define ZX2967_WDT_MIN_TIMEOUT 1 +#define ZX2967_WDT_MAX_TIMEOUT 524 +#define ZX2967_WDT_MAX_COUNT 0xffff + +#define ZX2967_WDT_CLK_FREQ 0x8000 + +#define ZX2967_WDT_FLAG_REBOOT_MON BIT(0) + +struct zx2967_wdt { + struct watchdog_device wdt_device; + void __iomem *reg_base; + struct clk *clock; +}; + +static inline u32 zx2967_wdt_readl(struct zx2967_wdt *wdt, u16 reg) +{ + return readl_relaxed(wdt->reg_base + reg); +} + +static inline void zx2967_wdt_writel(struct zx2967_wdt *wdt, u16 reg, u32 val) +{ + writel_relaxed(val | ZX2967_WDT_WRITEKEY, wdt->reg_base + reg); +} + +static void zx2967_wdt_refresh(struct zx2967_wdt *wdt) +{ + u32 val; + + val = zx2967_wdt_readl(wdt, ZX2967_WDT_REFRESH_REG); + /* + * Bit 4-5, 1 and 2: refresh config info + * Bit 2-3, 1 and 2: refresh counter + * Bit 0-1, 1 and 2: refresh int-value + * we shift each group value between 1 and 2 to refresh all data. + */ + val ^= ZX2967_WDT_REFRESH_MASK; + zx2967_wdt_writel(wdt, ZX2967_WDT_REFRESH_REG, + val & ZX2967_WDT_VAL_MASK); +} + +static int +zx2967_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout) +{ + struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd); + unsigned int divisor = ZX2967_WDT_DIV_DEFAULT; + u32 count; + + count = timeout * ZX2967_WDT_CLK_FREQ; + if (count > divisor * ZX2967_WDT_MAX_COUNT) + divisor = DIV_ROUND_UP(count, ZX2967_WDT_MAX_COUNT); + count = DIV_ROUND_UP(count, divisor); + zx2967_wdt_writel(wdt, ZX2967_WDT_CFG_REG, + ZX2967_WDT_CFG_DIV(divisor) & ZX2967_WDT_VAL_MASK); + zx2967_wdt_writel(wdt, ZX2967_WDT_LOAD_REG, + count & ZX2967_WDT_VAL_MASK); + zx2967_wdt_refresh(wdt); + wdd->timeout = (count * divisor) / ZX2967_WDT_CLK_FREQ; + + return 0; +} + +static void __zx2967_wdt_start(struct zx2967_wdt *wdt) +{ + u32 val; + + val = zx2967_wdt_readl(wdt, ZX2967_WDT_START_REG); + val |= ZX2967_WDT_START_EN; + zx2967_wdt_writel(wdt, ZX2967_WDT_START_REG, + val & ZX2967_WDT_VAL_MASK); +} + +static void __zx2967_wdt_stop(struct zx2967_wdt *wdt) +{ + u32 val; + + val = zx2967_wdt_readl(wdt, ZX2967_WDT_START_REG); + val &= ~ZX2967_WDT_START_EN; + zx2967_wdt_writel(wdt, ZX2967_WDT_START_REG, + val & ZX2967_WDT_VAL_MASK); +} + +static int zx2967_wdt_start(struct watchdog_device *wdd) +{ + struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd); + + zx2967_wdt_set_timeout(wdd, wdd->timeout); + __zx2967_wdt_start(wdt); + + return 0; +} + +static int zx2967_wdt_stop(struct watchdog_device *wdd) +{ + struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd); + + __zx2967_wdt_stop(wdt); + + return 0; +} + +static int zx2967_wdt_keepalive(struct watchdog_device *wdd) +{ + struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd); + + zx2967_wdt_refresh(wdt); + + return 0; +} + +#define ZX2967_WDT_OPTIONS \ + (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) +static const struct watchdog_info zx2967_wdt_ident = { + .options = ZX2967_WDT_OPTIONS, + .identity = "zx2967 watchdog", +}; + +static struct watchdog_ops zx2967_wdt_ops = { + .owner = THIS_MODULE, + .start = zx2967_wdt_start, + .stop = zx2967_wdt_stop, + .ping = zx2967_wdt_keepalive, + .set_timeout = zx2967_wdt_set_timeout, +}; + +static void zx2967_wdt_reset_sysctrl(struct device *dev) +{ + int ret; + void __iomem *regmap; + unsigned int offset, mask, config; + struct of_phandle_args out_args; + + ret = of_parse_phandle_with_fixed_args(dev->of_node, + "zte,wdt-reset-sysctrl", 3, 0, &out_args); + if (ret) + return; + + offset = out_args.args[0]; + config = out_args.args[1]; + mask = out_args.args[2]; + + regmap = syscon_node_to_regmap(out_args.np); + if (IS_ERR(regmap)) { + of_node_put(out_args.np); + return; + } + + regmap_update_bits(regmap, offset, mask, config); + of_node_put(out_args.np); +} + +static int zx2967_wdt_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct zx2967_wdt *wdt; + struct resource *base; + int ret; + struct reset_control *rstc; + + wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + platform_set_drvdata(pdev, wdt); + + wdt->wdt_device.info = &zx2967_wdt_ident; + wdt->wdt_device.ops = &zx2967_wdt_ops; + wdt->wdt_device.timeout = ZX2967_WDT_DEFAULT_TIMEOUT; + wdt->wdt_device.max_timeout = ZX2967_WDT_MAX_TIMEOUT; + wdt->wdt_device.min_timeout = ZX2967_WDT_MIN_TIMEOUT; + wdt->wdt_device.parent = &pdev->dev; + + base = platform_get_resource(pdev, IORESOURCE_MEM, 0); + wdt->reg_base = devm_ioremap_resource(dev, base); + if (IS_ERR(wdt->reg_base)) { + dev_err(dev, "ioremap failed\n"); + return PTR_ERR(wdt->reg_base); + } + + zx2967_wdt_reset_sysctrl(dev); + + wdt->clock = devm_clk_get(dev, NULL); + if (IS_ERR(wdt->clock)) { + dev_err(dev, "failed to find watchdog clock source\n"); + return PTR_ERR(wdt->clock); + } + + ret = clk_prepare_enable(wdt->clock); + if (ret < 0) { + dev_err(dev, "failed to enable clock\n"); + return ret; + } + clk_set_rate(wdt->clock, ZX2967_WDT_CLK_FREQ); + + rstc = devm_reset_control_get(dev, NULL); + if (IS_ERR(rstc)) { + dev_err(dev, "failed to get rstc"); + ret = PTR_ERR(rstc); + goto err; + } + + reset_control_assert(rstc); + reset_control_deassert(rstc); + + watchdog_set_drvdata(&wdt->wdt_device, wdt); + watchdog_init_timeout(&wdt->wdt_device, + ZX2967_WDT_DEFAULT_TIMEOUT, dev); + watchdog_set_nowayout(&wdt->wdt_device, WATCHDOG_NOWAYOUT); + + ret = watchdog_register_device(&wdt->wdt_device); + if (ret) + goto err; + + dev_info(dev, "watchdog enabled (timeout=%d sec, nowayout=%d)", + wdt->wdt_device.timeout, WATCHDOG_NOWAYOUT); + + return 0; + +err: + clk_disable_unprepare(wdt->clock); + return ret; +} + +static int zx2967_wdt_remove(struct platform_device *pdev) +{ + struct zx2967_wdt *wdt = platform_get_drvdata(pdev); + + watchdog_unregister_device(&wdt->wdt_device); + clk_disable_unprepare(wdt->clock); + + return 0; +} + +static const struct of_device_id zx2967_wdt_match[] = { + { .compatible = "zte,zx296718-wdt", }, + {} +}; +MODULE_DEVICE_TABLE(of, zx2967_wdt_match); + +static struct platform_driver zx2967_wdt_driver = { + .probe = zx2967_wdt_probe, + .remove = zx2967_wdt_remove, + .driver = { + .name = "zx2967-wdt", + .of_match_table = of_match_ptr(zx2967_wdt_match), + }, +}; +module_platform_driver(zx2967_wdt_driver); + +MODULE_AUTHOR("Baoyou Xie "); +MODULE_DESCRIPTION("ZTE zx2967 Watchdog Device Driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 4cbc69023a2129c271ed67da555d62eca42469d2 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 7 Feb 2017 15:03:29 +0100 Subject: watchdog: softdog: make pretimeout support a compile option It occurred to me that the panic pretimeout governor will stall the softdog, because it is purely software which simply breaks when the kernel panics. Testing governors with the softdog on the other hand is really useful, so make this feature a compile time option which nees to be enabled explicitly. This also removes the overhead if pretimeout support is not used because it will now be compiled away (saving ~10% on ARM32). Signed-off-by: Wolfram Sang Reviewed-by: Vladimir Zapolskiy Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 8 ++++++++ drivers/watchdog/softdog.c | 21 +++++++++++++-------- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 2d006d8cfb15..1a4d6ca8028d 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -71,6 +71,14 @@ config SOFT_WATCHDOG To compile this driver as a module, choose M here: the module will be called softdog. +config SOFT_WATCHDOG_PRETIMEOUT + bool "Software watchdog pretimeout governor support" + depends on SOFT_WATCHDOG && WATCHDOG_PRETIMEOUT_GOV + help + Enable this if you want to use pretimeout governors with the software + watchdog. Be aware that governors might affect the watchdog because it + is purely software, e.g. the panic governor will stall it! + config DA9052_WATCHDOG tristate "Dialog DA9052 Watchdog" depends on PMIC_DA9052 || COMPILE_TEST diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c index c7bdc986dca1..7983029852ab 100644 --- a/drivers/watchdog/softdog.c +++ b/drivers/watchdog/softdog.c @@ -87,11 +87,13 @@ static int softdog_ping(struct watchdog_device *w) if (!mod_timer(&softdog_ticktock, jiffies + (w->timeout * HZ))) __module_get(THIS_MODULE); - if (w->pretimeout) - mod_timer(&softdog_preticktock, jiffies + - (w->timeout - w->pretimeout) * HZ); - else - del_timer(&softdog_preticktock); + if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT)) { + if (w->pretimeout) + mod_timer(&softdog_preticktock, jiffies + + (w->timeout - w->pretimeout) * HZ); + else + del_timer(&softdog_preticktock); + } return 0; } @@ -101,15 +103,15 @@ static int softdog_stop(struct watchdog_device *w) if (del_timer(&softdog_ticktock)) module_put(THIS_MODULE); - del_timer(&softdog_preticktock); + if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT)) + del_timer(&softdog_preticktock); return 0; } static struct watchdog_info softdog_info = { .identity = "Software Watchdog", - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | - WDIOF_PRETIMEOUT, + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, }; static const struct watchdog_ops softdog_ops = { @@ -134,6 +136,9 @@ static int __init softdog_init(void) watchdog_set_nowayout(&softdog_dev, nowayout); watchdog_stop_on_reboot(&softdog_dev); + if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT)) + softdog_info.options |= WDIOF_PRETIMEOUT; + ret = watchdog_register_device(&softdog_dev); if (ret) return ret; -- cgit v1.2.3 From 4f21195d42ef930f20e1753532709bb294aa73ac Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Feb 2017 17:11:15 +0200 Subject: watchdog: s3c2410: Remove confusing CONFIG prefix from local defines The CONFIG prefix from defines in the s3c2410_wdt.c might suggest that these constants come from Kconfig. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/s3c2410_wdt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index d48ba2590641..b305b8717d9f 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -64,8 +64,8 @@ #define S3C2410_WTCON_PRESCALE_MASK (0xff << 8) #define S3C2410_WTCON_PRESCALE_MAX 0xff -#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) -#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) +#define S3C2410_WATCHDOG_ATBOOT (0) +#define S3C2410_WATCHDOG_DEFAULT_TIME (15) #define EXYNOS5_RST_STAT_REG_OFFSET 0x0404 #define EXYNOS5_WDT_DISABLE_REG_OFFSET 0x0408 @@ -79,7 +79,7 @@ static bool nowayout = WATCHDOG_NOWAYOUT; static int tmr_margin; -static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; +static int tmr_atboot = S3C2410_WATCHDOG_ATBOOT; static int soft_noboot; static int debug; @@ -90,10 +90,10 @@ module_param(soft_noboot, int, 0); module_param(debug, int, 0); MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default=" - __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")"); + __MODULE_STRING(S3C2410_WATCHDOG_DEFAULT_TIME) ")"); MODULE_PARM_DESC(tmr_atboot, "Watchdog is started at boot time if set to 1, default=" - __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT)); + __MODULE_STRING(S3C2410_WATCHDOG_ATBOOT)); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " @@ -406,7 +406,7 @@ static const struct watchdog_ops s3c2410wdt_ops = { static struct watchdog_device s3c2410_wdd = { .info = &s3c2410_wdt_ident, .ops = &s3c2410wdt_ops, - .timeout = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME, + .timeout = S3C2410_WATCHDOG_DEFAULT_TIME, }; /* interrupt handler code */ @@ -600,12 +600,12 @@ static int s3c2410wdt_probe(struct platform_device *pdev) wdt->wdt_device.timeout); if (ret) { started = s3c2410wdt_set_heartbeat(&wdt->wdt_device, - CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); + S3C2410_WATCHDOG_DEFAULT_TIME); if (started == 0) dev_info(dev, "tmr_margin value out of range, default %d used\n", - CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); + S3C2410_WATCHDOG_DEFAULT_TIME); else dev_info(dev, "default timer value is out of range, " "cannot start\n"); -- cgit v1.2.3 From 0b445549ea6f91ffea78a976fe89b932db6e077a Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Feb 2017 17:11:16 +0200 Subject: watchdog: s3c2410: Fix infinite interrupt in soft mode In soft (no-reboot) mode, the driver self-pings watchdog upon expiration of an interrupt. However the interrupt itself was not cleared thus on first hit, the system enters infinite interrupt handling loop. On Odroid U3 (Exynos4412), when booted with s3c2410_wdt.soft_noboot=1 argument the console is flooded: # killall -9 watchdog [ 60.523760] s3c2410-wdt 10060000.watchdog: watchdog timer expired (irq) [ 60.536744] s3c2410-wdt 10060000.watchdog: watchdog timer expired (irq) Fix this by writing something to the WTCLRINT register to clear the interrupt. The register WTCLRINT however appeared in S3C6410 so a new watchdog quirk and flavor are needed. Signed-off-by: Krzysztof Kozlowski Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- .../devicetree/bindings/watchdog/samsung-wdt.txt | 9 +++++---- drivers/watchdog/s3c2410_wdt.c | 21 ++++++++++++++++++--- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt index 8f3d96af81d7..1f6e101e299a 100644 --- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt @@ -6,10 +6,11 @@ occurred. Required properties: - compatible : should be one among the following - (a) "samsung,s3c2410-wdt" for Exynos4 and previous SoCs - (b) "samsung,exynos5250-wdt" for Exynos5250 - (c) "samsung,exynos5420-wdt" for Exynos5420 - (c) "samsung,exynos7-wdt" for Exynos7 + - "samsung,s3c2410-wdt" for S3C2410 + - "samsung,s3c6410-wdt" for S3C6410, S5PV210 and Exynos4 + - "samsung,exynos5250-wdt" for Exynos5250 + - "samsung,exynos5420-wdt" for Exynos5420 + - "samsung,exynos7-wdt" for Exynos7 - reg : base physical address of the controller and length of memory mapped region. diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index b305b8717d9f..558789b8805f 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -46,6 +46,7 @@ #define S3C2410_WTCON 0x00 #define S3C2410_WTDAT 0x04 #define S3C2410_WTCNT 0x08 +#define S3C2410_WTCLRINT 0x0c #define S3C2410_WTCNT_MAXCNT 0xffff @@ -72,6 +73,7 @@ #define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c #define QUIRK_HAS_PMU_CONFIG (1 << 0) #define QUIRK_HAS_RST_STAT (1 << 1) +#define QUIRK_HAS_WTCLRINT_REG (1 << 2) /* These quirks require that we have a PMU register map */ #define QUIRKS_HAVE_PMUREG (QUIRK_HAS_PMU_CONFIG | \ @@ -143,13 +145,18 @@ static const struct s3c2410_wdt_variant drv_data_s3c2410 = { }; #ifdef CONFIG_OF +static const struct s3c2410_wdt_variant drv_data_s3c6410 = { + .quirks = QUIRK_HAS_WTCLRINT_REG, +}; + static const struct s3c2410_wdt_variant drv_data_exynos5250 = { .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, .mask_bit = 20, .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, .rst_stat_bit = 20, - .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, + .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \ + | QUIRK_HAS_WTCLRINT_REG, }; static const struct s3c2410_wdt_variant drv_data_exynos5420 = { @@ -158,7 +165,8 @@ static const struct s3c2410_wdt_variant drv_data_exynos5420 = { .mask_bit = 0, .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, .rst_stat_bit = 9, - .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, + .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \ + | QUIRK_HAS_WTCLRINT_REG, }; static const struct s3c2410_wdt_variant drv_data_exynos7 = { @@ -167,12 +175,15 @@ static const struct s3c2410_wdt_variant drv_data_exynos7 = { .mask_bit = 23, .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, .rst_stat_bit = 23, /* A57 WDTRESET */ - .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, + .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \ + | QUIRK_HAS_WTCLRINT_REG, }; static const struct of_device_id s3c2410_wdt_match[] = { { .compatible = "samsung,s3c2410-wdt", .data = &drv_data_s3c2410 }, + { .compatible = "samsung,s3c6410-wdt", + .data = &drv_data_s3c6410 }, { .compatible = "samsung,exynos5250-wdt", .data = &drv_data_exynos5250 }, { .compatible = "samsung,exynos5420-wdt", @@ -418,6 +429,10 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) dev_info(wdt->dev, "watchdog timer expired (irq)\n"); s3c2410wdt_keepalive(&wdt->wdt_device); + + if (wdt->drv_data->quirks & QUIRK_HAS_WTCLRINT_REG) + writel(0x1, wdt->reg_base + S3C2410_WTCLRINT); + return IRQ_HANDLED; } -- cgit v1.2.3 From 456f53d652411594249efc3fcea01842177c9a6f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Feb 2017 23:07:40 +0200 Subject: watchdog: s3c2410: Use dev_dbg instead of pr_info Replace the 'debug' module parameter and pr_info() with proper device dynamic debug calls because this is the preferred and flexible way of enabling debugging printks. Also remove some obvious debug printks. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Guenter Roeck --- drivers/watchdog/s3c2410_wdt.c | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 558789b8805f..7e504ec1a3c3 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -23,8 +23,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -83,13 +81,11 @@ static bool nowayout = WATCHDOG_NOWAYOUT; static int tmr_margin; static int tmr_atboot = S3C2410_WATCHDOG_ATBOOT; static int soft_noboot; -static int debug; module_param(tmr_margin, int, 0); module_param(tmr_atboot, int, 0); module_param(nowayout, bool, 0); module_param(soft_noboot, int, 0); -module_param(debug, int, 0); MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default=" __MODULE_STRING(S3C2410_WATCHDOG_DEFAULT_TIME) ")"); @@ -100,7 +96,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " "0 to reboot (default 0)"); -MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); /** * struct s3c2410_wdt_variant - Per-variant config data @@ -204,14 +199,6 @@ static const struct platform_device_id s3c2410_wdt_ids[] = { }; MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids); -/* watchdog control routines */ - -#define DBG(fmt, ...) \ -do { \ - if (debug) \ - pr_info(fmt, ##__VA_ARGS__); \ -} while (0) - /* functions */ static inline unsigned int s3c2410wdt_max_timeout(struct clk *clock) @@ -307,8 +294,8 @@ static int s3c2410wdt_start(struct watchdog_device *wdd) wtcon |= S3C2410_WTCON_RSTEN; } - DBG("%s: count=0x%08x, wtcon=%08lx\n", - __func__, wdt->count, wtcon); + dev_dbg(wdt->dev, "Starting watchdog: count=0x%08x, wtcon=%08lx\n", + wdt->count, wtcon); writel(wdt->count, wdt->reg_base + S3C2410_WTDAT); writel(wdt->count, wdt->reg_base + S3C2410_WTCNT); @@ -337,8 +324,8 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou freq = DIV_ROUND_UP(freq, 128); count = timeout * freq; - DBG("%s: count=%d, timeout=%d, freq=%lu\n", - __func__, count, timeout, freq); + dev_dbg(wdt->dev, "Heartbeat: count=%d, timeout=%d, freq=%lu\n", + count, timeout, freq); /* if the count is bigger than the watchdog register, then work out what we need to do (and if) we can @@ -354,8 +341,8 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou } } - DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", - __func__, timeout, divisor, count, DIV_ROUND_UP(count, divisor)); + dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%d (%08x)\n", + timeout, divisor, count, DIV_ROUND_UP(count, divisor)); count = DIV_ROUND_UP(count, divisor); wdt->count = count; @@ -544,8 +531,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev) int started = 0; int ret; - DBG("%s: probe=%p\n", __func__, pdev); - dev = &pdev->dev; wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); @@ -581,8 +566,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev) goto err; } - DBG("probe: mapped reg_base=%p\n", wdt->reg_base); - wdt->clock = devm_clk_get(dev, "watchdog"); if (IS_ERR(wdt->clock)) { dev_err(dev, "failed to find watchdog clock source\n"); -- cgit v1.2.3 From 53eac48d5c97e8a926e26ae4205ac890721ef260 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Feb 2017 23:07:41 +0200 Subject: watchdog: s3c2410: Select MFD_SYSCON on all Exynos platforms Syscon is used not only on Exynos5 SoCs but also on Exynos3250, Exynos4412 and ARMv8 versions (Exynos5433, Exynos7). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 1a4d6ca8028d..c831b7967bf9 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -354,7 +354,7 @@ config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" depends on HAVE_S3C2410_WATCHDOG || COMPILE_TEST select WATCHDOG_CORE - select MFD_SYSCON if ARCH_EXYNOS5 + select MFD_SYSCON if ARCH_EXYNOS help Watchdog timer block in the Samsung SoCs. This will reboot the system when the timer expires with the watchdog enabled. -- cgit v1.2.3 From e3a60ead2c9b813db832a35e50ebbc6b552a35e3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 24 Feb 2017 23:07:43 +0200 Subject: watchdog: s3c2410: Add prefix to local function Functions marked static inline might not be inlined so a driver-specific prefix for function name helps when looking through call backtrace. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Guenter Roeck --- drivers/watchdog/s3c2410_wdt.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 7e504ec1a3c3..6ed97596ca80 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -507,9 +507,8 @@ static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) return 0; } -/* s3c2410_get_wdt_driver_data */ static inline struct s3c2410_wdt_variant * -get_wdt_drv_data(struct platform_device *pdev) +s3c2410_get_wdt_drv_data(struct platform_device *pdev) { if (pdev->dev.of_node) { const struct of_device_id *match; @@ -541,7 +540,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) spin_lock_init(&wdt->lock); wdt->wdt_device = s3c2410_wdd; - wdt->drv_data = get_wdt_drv_data(pdev); + wdt->drv_data = s3c2410_get_wdt_drv_data(pdev); if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) { wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, "samsung,syscon-phandle"); -- cgit v1.2.3