diff options
author | Michael Ellerman <mpe@ellerman.id.au> | 2015-06-05 17:47:32 +1000 |
---|---|---|
committer | Michael Ellerman <mpe@ellerman.id.au> | 2015-06-05 17:47:32 +1000 |
commit | 9d34ffda422ad2078205a03352cb1f97e5711742 (patch) | |
tree | 743241c614a0676c29d5e2b83903e14f735ee451 | |
parent | 76431b9d6aea112d85ab3d6cb6fbbd15b6a9d54f (diff) | |
parent | 32e263fc42c8e6ed1165710772afc678c8c248c4 (diff) | |
download | linux-next-9d34ffda422ad2078205a03352cb1f97e5711742.tar.gz |
Merge remote-tracking branch 'watchdog/master'
Conflicts:
drivers/watchdog/Kconfig
drivers/watchdog/st_lpc_wdt.c
-rw-r--r-- | Documentation/devicetree/bindings/watchdog/digicolor-wdt.txt | 25 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/watchdog/omap-wdt.txt | 9 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 16 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/at91sam9_wdt.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/digicolor_wdt.c | 205 | ||||
-rw-r--r-- | drivers/watchdog/dw_wdt.c | 8 | ||||
-rw-r--r-- | drivers/watchdog/imgpdc_wdt.c | 84 | ||||
-rw-r--r-- | drivers/watchdog/imx2_wdt.c | 3 | ||||
-rw-r--r-- | drivers/watchdog/max63xx_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/mena21_wdt.c | 5 | ||||
-rw-r--r-- | drivers/watchdog/omap_wdt.c | 73 | ||||
-rw-r--r-- | drivers/watchdog/st_lpc_wdt.c | 2 |
13 files changed, 366 insertions, 71 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/digicolor-wdt.txt b/Documentation/devicetree/bindings/watchdog/digicolor-wdt.txt new file mode 100644 index 0000000000000..a882967e17d4c --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/digicolor-wdt.txt @@ -0,0 +1,25 @@ +Conexant Digicolor SoCs Watchdog timer + +The watchdog functionality in Conexant Digicolor SoCs relies on the so called +"Agent Communication" block. This block includes the eight programmable system +timer counters. The first timer (called "Timer A") is the only one that can be +used as watchdog. + +Required properties: + +- compatible : Should be "cnxt,cx92755-wdt" +- reg : Specifies base physical address and size of the registers +- clocks : phandle; specifies the clock that drives the timer + +Optional properties: + +- timeout-sec : Contains the watchdog timeout in seconds + +Example: + + watchdog@f0000fc0 { + compatible = "cnxt,cx92755-wdt"; + reg = <0xf0000fc0 0x8>; + clocks = <&main_clk>; + timeout-sec = <15>; + }; diff --git a/Documentation/devicetree/bindings/watchdog/omap-wdt.txt b/Documentation/devicetree/bindings/watchdog/omap-wdt.txt index c227970671ea3..1fa20e453a2d0 100644 --- a/Documentation/devicetree/bindings/watchdog/omap-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/omap-wdt.txt @@ -1,10 +1,11 @@ TI Watchdog Timer (WDT) Controller for OMAP Required properties: -compatible: -- "ti,omap3-wdt" for OMAP3 -- "ti,omap4-wdt" for OMAP4 -- ti,hwmods: Name of the hwmod associated to the WDT +- compatible : "ti,omap3-wdt" for OMAP3 or "ti,omap4-wdt" for OMAP4 +- ti,hwmods : Name of the hwmod associated to the WDT + +Optional properties: +- timeout-sec : default watchdog timeout in seconds Examples: diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 262647bbc6144..8caff7d361c42 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -169,6 +169,7 @@ config AT91SAM9X_WATCHDOG config CADENCE_WATCHDOG tristate "Cadence Watchdog Timer" + depends on HAS_IOMEM select WATCHDOG_CORE help Say Y here if you want to include support for the watchdog @@ -408,7 +409,7 @@ config TS72XX_WATCHDOG config MAX63XX_WATCHDOG tristate "Max63xx watchdog" - depends on ARM && HAS_IOMEM + depends on HAS_IOMEM select WATCHDOG_CORE help Support for memory mapped max63{69,70,71,72,73,74} watchdog timer. @@ -475,6 +476,7 @@ config ST_LPC_WATCHDOG depends on ARCH_STI depends on OF select WATCHDOG_CORE + select MFD_ST_LPC help Say Y here to include STMicroelectronics Low Power Controller (LPC) based Watchdog timer support. @@ -526,6 +528,16 @@ config MEDIATEK_WATCHDOG To compile this driver as a module, choose M here: the module will be called mtk_wdt. +config DIGICOLOR_WATCHDOG + tristate "Conexant Digicolor SoCs watchdog support" + depends on ARCH_DIGICOLOR + select WATCHDOG_CORE + help + Say Y here to include support for the watchdog timer + in Conexant Digicolor SoCs. + To compile this driver as a module, choose M here: the + module will be called digicolor_wdt. + # AVR32 Architecture config AT32AP700X_WDT @@ -1355,7 +1367,7 @@ config BOOKE_WDT_DEFAULT_TIMEOUT config MEN_A21_WDT tristate "MEN A21 VME CPU Carrier Board Watchdog Timer" select WATCHDOG_CORE - depends on GPIOLIB + depends on GPIOLIB || COMPILE_TEST help Watchdog driver for MEN A21 VMEbus CPU Carrier Boards. diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index d98768c7d928c..4e26613a7f52b 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o +obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o # AVR32 Architecture obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index 1443b3c391de4..e4698f7c5f930 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -40,9 +40,9 @@ #define DRV_NAME "AT91SAM9 Watchdog" #define wdt_read(wdt, field) \ - __raw_readl((wdt)->base + (field)) + readl_relaxed((wdt)->base + (field)) #define wdt_write(wtd, field, val) \ - __raw_writel((val), (wdt)->base + (field)) + writel_relaxed((val), (wdt)->base + (field)) /* AT91SAM9 watchdog runs a 12bit counter @ 256Hz, * use this to convert a watchdog diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c new file mode 100644 index 0000000000000..31d8e4936611e --- /dev/null +++ b/drivers/watchdog/digicolor_wdt.c @@ -0,0 +1,205 @@ +/* + * Watchdog driver for Conexant Digicolor + * + * Copyright (C) 2015 Paradox Innovation Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <linux/watchdog.h> +#include <linux/reboot.h> +#include <linux/platform_device.h> +#include <linux/of_address.h> + +#define TIMER_A_CONTROL 0 +#define TIMER_A_COUNT 4 + +#define TIMER_A_ENABLE_COUNT BIT(0) +#define TIMER_A_ENABLE_WATCHDOG BIT(1) + +struct dc_wdt { + void __iomem *base; + struct clk *clk; + struct notifier_block restart_handler; + spinlock_t lock; +}; + +static unsigned timeout; +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds"); + +static void dc_wdt_set(struct dc_wdt *wdt, u32 ticks) +{ + unsigned long flags; + + spin_lock_irqsave(&wdt->lock, flags); + + writel_relaxed(0, wdt->base + TIMER_A_CONTROL); + writel_relaxed(ticks, wdt->base + TIMER_A_COUNT); + writel_relaxed(TIMER_A_ENABLE_COUNT | TIMER_A_ENABLE_WATCHDOG, + wdt->base + TIMER_A_CONTROL); + + spin_unlock_irqrestore(&wdt->lock, flags); +} + +static int dc_restart_handler(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + struct dc_wdt *wdt = container_of(this, struct dc_wdt, restart_handler); + + dc_wdt_set(wdt, 1); + /* wait for reset to assert... */ + mdelay(500); + + return NOTIFY_DONE; +} + +static int dc_wdt_start(struct watchdog_device *wdog) +{ + struct dc_wdt *wdt = watchdog_get_drvdata(wdog); + + dc_wdt_set(wdt, wdog->timeout * clk_get_rate(wdt->clk)); + + return 0; +} + +static int dc_wdt_stop(struct watchdog_device *wdog) +{ + struct dc_wdt *wdt = watchdog_get_drvdata(wdog); + + writel_relaxed(0, wdt->base + TIMER_A_CONTROL); + + return 0; +} + +static int dc_wdt_set_timeout(struct watchdog_device *wdog, unsigned int t) +{ + struct dc_wdt *wdt = watchdog_get_drvdata(wdog); + + dc_wdt_set(wdt, t * clk_get_rate(wdt->clk)); + wdog->timeout = t; + + return 0; +} + +static unsigned int dc_wdt_get_timeleft(struct watchdog_device *wdog) +{ + struct dc_wdt *wdt = watchdog_get_drvdata(wdog); + uint32_t count = readl_relaxed(wdt->base + TIMER_A_COUNT); + + return count / clk_get_rate(wdt->clk); +} + +static struct watchdog_ops dc_wdt_ops = { + .owner = THIS_MODULE, + .start = dc_wdt_start, + .stop = dc_wdt_stop, + .set_timeout = dc_wdt_set_timeout, + .get_timeleft = dc_wdt_get_timeleft, +}; + +static struct watchdog_info dc_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE + | WDIOF_KEEPALIVEPING, + .identity = "Conexant Digicolor Watchdog", +}; + +static struct watchdog_device dc_wdt_wdd = { + .info = &dc_wdt_info, + .ops = &dc_wdt_ops, + .min_timeout = 1, +}; + +static int dc_wdt_probe(struct platform_device *pdev) +{ + 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; + } + + wdt->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(wdt->clk)) { + ret = PTR_ERR(wdt->clk); + goto err_iounmap; + } + dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk); + dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout; + + spin_lock_init(&wdt->lock); + + watchdog_set_drvdata(&dc_wdt_wdd, wdt); + watchdog_init_timeout(&dc_wdt_wdd, timeout, dev); + ret = watchdog_register_device(&dc_wdt_wdd); + if (ret) { + dev_err(dev, "Failed to register watchdog device"); + goto err_iounmap; + } + + wdt->restart_handler.notifier_call = dc_restart_handler; + wdt->restart_handler.priority = 128; + ret = register_restart_handler(&wdt->restart_handler); + if (ret) + dev_warn(&pdev->dev, "cannot register restart handler\n"); + + 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); + + unregister_restart_handler(&wdt->restart_handler); + 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[] = { + { .compatible = "cnxt,cx92755-wdt", }, + {}, +}; +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, + }, +}; +module_platform_driver(dc_wdt_driver); + +MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); +MODULE_DESCRIPTION("Driver for Conexant Digicolor watchdog timer"); +MODULE_LICENSE("GPL"); diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index d0bb9499d12ca..6ea0634345e99 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c @@ -35,7 +35,6 @@ #include <linux/pm.h> #include <linux/platform_device.h> #include <linux/reboot.h> -#include <linux/spinlock.h> #include <linux/timer.h> #include <linux/uaccess.h> #include <linux/watchdog.h> @@ -61,7 +60,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " #define WDT_TIMEOUT (HZ / 2) static struct { - spinlock_t lock; void __iomem *regs; struct clk *clk; unsigned long in_use; @@ -177,7 +175,6 @@ static int dw_wdt_open(struct inode *inode, struct file *filp) /* Make sure we don't get unloaded. */ __module_get(THIS_MODULE); - spin_lock(&dw_wdt.lock); if (!dw_wdt_is_enabled()) { /* * The watchdog is not currently enabled. Set the timeout to @@ -190,8 +187,6 @@ static int dw_wdt_open(struct inode *inode, struct file *filp) dw_wdt_set_next_heartbeat(); - spin_unlock(&dw_wdt.lock); - return nonseekable_open(inode, filp); } @@ -220,6 +215,7 @@ static ssize_t dw_wdt_write(struct file *filp, const char __user *buf, } dw_wdt_set_next_heartbeat(); + dw_wdt_keepalive(); mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT); return len; @@ -348,8 +344,6 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) if (ret) return ret; - spin_lock_init(&dw_wdt.lock); - ret = misc_register(&dw_wdt_miscdev); if (ret) goto out_disable_clk; diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c index 0deaa4f971f5f..0f73621827abf 100644 --- a/drivers/watchdog/imgpdc_wdt.c +++ b/drivers/watchdog/imgpdc_wdt.c @@ -9,6 +9,35 @@ * * Based on drivers/watchdog/sunxi_wdt.c Copyright (c) 2013 Carlo Caione * 2012 Henrik Nordstrom + * + * Notes + * ----- + * The timeout value is rounded to the next power of two clock cycles. + * This is configured using the PDC_WDT_CONFIG register, according to this + * formula: + * + * timeout = 2^(delay + 1) clock cycles + * + * Where 'delay' is the value written in PDC_WDT_CONFIG register. + * + * Therefore, the hardware only allows to program watchdog timeouts, expressed + * as a power of two number of watchdog clock cycles. The current implementation + * guarantees that the actual watchdog timeout will be _at least_ the value + * programmed in the imgpdg_wdt driver. + * + * The following table shows how the user-configured timeout relates + * to the actual hardware timeout (watchdog clock @ 40000 Hz): + * + * input timeout | WD_DELAY | actual timeout + * ----------------------------------- + * 10 | 18 | 13 seconds + * 20 | 19 | 26 seconds + * 30 | 20 | 52 seconds + * 60 | 21 | 104 seconds + * + * Albeit coarse, this granularity would suffice most watchdog uses. + * If the platform allows it, the user should be able to change the watchdog + * clock rate and achieve a finer timeout granularity. */ #include <linux/clk.h> @@ -16,6 +45,7 @@ #include <linux/log2.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/reboot.h> #include <linux/slab.h> #include <linux/watchdog.h> @@ -42,7 +72,7 @@ #define PDC_WDT_MIN_TIMEOUT 1 #define PDC_WDT_DEF_TIMEOUT 64 -static int heartbeat = PDC_WDT_DEF_TIMEOUT; +static int heartbeat; module_param(heartbeat, int, 0); MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds " "(default=" __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")"); @@ -57,6 +87,7 @@ struct pdc_wdt_dev { struct clk *wdt_clk; struct clk *sys_clk; void __iomem *base; + struct notifier_block restart_handler; }; static int pdc_wdt_keepalive(struct watchdog_device *wdt_dev) @@ -84,18 +115,24 @@ static int pdc_wdt_stop(struct watchdog_device *wdt_dev) return 0; } +static void __pdc_wdt_set_timeout(struct pdc_wdt_dev *wdt) +{ + unsigned long clk_rate = clk_get_rate(wdt->wdt_clk); + unsigned int val; + + val = readl(wdt->base + PDC_WDT_CONFIG) & ~PDC_WDT_CONFIG_DELAY_MASK; + val |= order_base_2(wdt->wdt_dev.timeout * clk_rate) - 1; + writel(val, wdt->base + PDC_WDT_CONFIG); +} + static int pdc_wdt_set_timeout(struct watchdog_device *wdt_dev, unsigned int new_timeout) { - unsigned int val; struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev); - unsigned long clk_rate = clk_get_rate(wdt->wdt_clk); wdt->wdt_dev.timeout = new_timeout; - val = readl(wdt->base + PDC_WDT_CONFIG) & ~PDC_WDT_CONFIG_DELAY_MASK; - val |= order_base_2(new_timeout * clk_rate) - 1; - writel(val, wdt->base + PDC_WDT_CONFIG); + __pdc_wdt_set_timeout(wdt); return 0; } @@ -106,6 +143,8 @@ static int pdc_wdt_start(struct watchdog_device *wdt_dev) unsigned int val; struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev); + __pdc_wdt_set_timeout(wdt); + val = readl(wdt->base + PDC_WDT_CONFIG); val |= PDC_WDT_CONFIG_ENABLE; writel(val, wdt->base + PDC_WDT_CONFIG); @@ -128,8 +167,21 @@ static const struct watchdog_ops pdc_wdt_ops = { .set_timeout = pdc_wdt_set_timeout, }; +static int pdc_wdt_restart(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + struct pdc_wdt_dev *wdt = container_of(this, struct pdc_wdt_dev, + restart_handler); + + /* Assert SOFT_RESET */ + writel(0x1, wdt->base + PDC_WDT_SOFT_RESET); + + return NOTIFY_OK; +} + static int pdc_wdt_probe(struct platform_device *pdev) { + u64 div; int ret, val; unsigned long clk_rate; struct resource *res; @@ -189,16 +241,15 @@ static int pdc_wdt_probe(struct platform_device *pdev) pdc_wdt->wdt_dev.info = &pdc_wdt_info; pdc_wdt->wdt_dev.ops = &pdc_wdt_ops; - pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK; + + div = 1ULL << (PDC_WDT_CONFIG_DELAY_MASK + 1); + do_div(div, clk_rate); + pdc_wdt->wdt_dev.max_timeout = div; + pdc_wdt->wdt_dev.timeout = PDC_WDT_DEF_TIMEOUT; pdc_wdt->wdt_dev.parent = &pdev->dev; watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt); - ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev); - if (ret < 0) { - pdc_wdt->wdt_dev.timeout = pdc_wdt->wdt_dev.max_timeout; - dev_warn(&pdev->dev, - "Initial timeout out of range! setting max timeout\n"); - } + watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev); pdc_wdt_stop(&pdc_wdt->wdt_dev); @@ -238,6 +289,13 @@ static int pdc_wdt_probe(struct platform_device *pdev) if (ret) goto disable_wdt_clk; + pdc_wdt->restart_handler.notifier_call = pdc_wdt_restart; + pdc_wdt->restart_handler.priority = 128; + ret = register_restart_handler(&pdc_wdt->restart_handler); + if (ret) + dev_warn(&pdev->dev, "failed to register restart handler: %d\n", + ret); + return 0; disable_wdt_clk: diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 5e6d808d358a5..2acdd17025c40 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c @@ -166,6 +166,8 @@ static int imx2_wdt_set_timeout(struct watchdog_device *wdog, { struct imx2_wdt_device *wdev = watchdog_get_drvdata(wdog); + wdog->timeout = new_timeout; + regmap_update_bits(wdev->regmap, IMX2_WDT_WCR, IMX2_WDT_WCR_WT, WDOG_SEC_TO_COUNT(new_timeout)); return 0; @@ -256,6 +258,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) wdog->ops = &imx2_wdt_ops; wdog->min_timeout = 1; wdog->max_timeout = IMX2_WDT_MAX_TIME; + wdog->parent = &pdev->dev; clk_prepare_enable(wdev->clk); diff --git a/drivers/watchdog/max63xx_wdt.c b/drivers/watchdog/max63xx_wdt.c index 08da3114accb5..b3a1130b8eebf 100644 --- a/drivers/watchdog/max63xx_wdt.c +++ b/drivers/watchdog/max63xx_wdt.c @@ -214,7 +214,7 @@ static int max63xx_wdt_remove(struct platform_device *pdev) return 0; } -static struct platform_device_id max63xx_id_table[] = { +static const struct platform_device_id max63xx_id_table[] = { { "max6369_wdt", (kernel_ulong_t)max6369_table, }, { "max6370_wdt", (kernel_ulong_t)max6369_table, }, { "max6371_wdt", (kernel_ulong_t)max6371_table, }, diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c index 96dbba9805796..d193a5e79c381 100644 --- a/drivers/watchdog/mena21_wdt.c +++ b/drivers/watchdog/mena21_wdt.c @@ -208,14 +208,15 @@ static int a21_wdt_probe(struct platform_device *pdev) else if (reset == 7) a21_wdt.bootstatus |= WDIOF_EXTERN2; + drv->wdt = a21_wdt; + dev_set_drvdata(&pdev->dev, drv); + ret = watchdog_register_device(&a21_wdt); if (ret) { dev_err(&pdev->dev, "Cannot register watchdog device\n"); goto err_register_wd; } - dev_set_drvdata(&pdev->dev, drv); - dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n"); return 0; diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index 1e6be9e405779..1a74bc7fb4586 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -53,7 +53,10 @@ static unsigned timer_margin; module_param(timer_margin, uint, 0); MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)"); +#define to_omap_wdt_dev(_wdog) container_of(_wdog, struct omap_wdt_dev, wdog) + struct omap_wdt_dev { + struct watchdog_device wdog; void __iomem *base; /* physical */ struct device *dev; bool omap_wdt_users; @@ -123,7 +126,7 @@ static void omap_wdt_set_timer(struct omap_wdt_dev *wdev, static int omap_wdt_start(struct watchdog_device *wdog) { - struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); + struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog); void __iomem *base = wdev->base; mutex_lock(&wdev->lock); @@ -132,6 +135,13 @@ static int omap_wdt_start(struct watchdog_device *wdog) pm_runtime_get_sync(wdev->dev); + /* + * Make sure the watchdog is disabled. This is unfortunately required + * because writing to various registers with the watchdog running has no + * effect. + */ + omap_wdt_disable(wdev); + /* initialize prescaler */ while (readl_relaxed(base + OMAP_WATCHDOG_WPS) & 0x01) cpu_relax(); @@ -151,7 +161,7 @@ static int omap_wdt_start(struct watchdog_device *wdog) static int omap_wdt_stop(struct watchdog_device *wdog) { - struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); + struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog); mutex_lock(&wdev->lock); omap_wdt_disable(wdev); @@ -163,7 +173,7 @@ static int omap_wdt_stop(struct watchdog_device *wdog) static int omap_wdt_ping(struct watchdog_device *wdog) { - struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); + struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog); mutex_lock(&wdev->lock); omap_wdt_reload(wdev); @@ -175,7 +185,7 @@ static int omap_wdt_ping(struct watchdog_device *wdog) static int omap_wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout) { - struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); + struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog); mutex_lock(&wdev->lock); omap_wdt_disable(wdev); @@ -204,16 +214,10 @@ static const struct watchdog_ops omap_wdt_ops = { static int omap_wdt_probe(struct platform_device *pdev) { struct omap_wd_timer_platform_data *pdata = dev_get_platdata(&pdev->dev); - struct watchdog_device *omap_wdt; struct resource *res; struct omap_wdt_dev *wdev; - u32 rs; int ret; - omap_wdt = devm_kzalloc(&pdev->dev, sizeof(*omap_wdt), GFP_KERNEL); - if (!omap_wdt) - return -ENOMEM; - wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL); if (!wdev) return -ENOMEM; @@ -229,35 +233,30 @@ static int omap_wdt_probe(struct platform_device *pdev) if (IS_ERR(wdev->base)) return PTR_ERR(wdev->base); - omap_wdt->info = &omap_wdt_info; - omap_wdt->ops = &omap_wdt_ops; - omap_wdt->min_timeout = TIMER_MARGIN_MIN; - omap_wdt->max_timeout = TIMER_MARGIN_MAX; + wdev->wdog.info = &omap_wdt_info; + wdev->wdog.ops = &omap_wdt_ops; + wdev->wdog.min_timeout = TIMER_MARGIN_MIN; + wdev->wdog.max_timeout = TIMER_MARGIN_MAX; - if (timer_margin >= TIMER_MARGIN_MIN && - timer_margin <= TIMER_MARGIN_MAX) - omap_wdt->timeout = timer_margin; - else - omap_wdt->timeout = TIMER_MARGIN_DEFAULT; + if (watchdog_init_timeout(&wdev->wdog, timer_margin, &pdev->dev) < 0) + wdev->wdog.timeout = TIMER_MARGIN_DEFAULT; - watchdog_set_drvdata(omap_wdt, wdev); - watchdog_set_nowayout(omap_wdt, nowayout); + watchdog_set_nowayout(&wdev->wdog, nowayout); - platform_set_drvdata(pdev, omap_wdt); + platform_set_drvdata(pdev, wdev); pm_runtime_enable(wdev->dev); pm_runtime_get_sync(wdev->dev); - if (pdata && pdata->read_reset_sources) - rs = pdata->read_reset_sources(); - else - rs = 0; - omap_wdt->bootstatus = (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) ? - WDIOF_CARDRESET : 0; + if (pdata && pdata->read_reset_sources) { + u32 rs = pdata->read_reset_sources(); + if (rs & (1 << OMAP_MPU_WD_RST_SRC_ID_SHIFT)) + wdev->wdog.bootstatus = WDIOF_CARDRESET; + } omap_wdt_disable(wdev); - ret = watchdog_register_device(omap_wdt); + ret = watchdog_register_device(&wdev->wdog); if (ret) { pm_runtime_disable(wdev->dev); return ret; @@ -265,7 +264,7 @@ static int omap_wdt_probe(struct platform_device *pdev) pr_info("OMAP Watchdog Timer Rev 0x%02x: initial timeout %d sec\n", readl_relaxed(wdev->base + OMAP_WATCHDOG_REV) & 0xFF, - omap_wdt->timeout); + wdev->wdog.timeout); pm_runtime_put_sync(wdev->dev); @@ -274,8 +273,7 @@ static int omap_wdt_probe(struct platform_device *pdev) static void omap_wdt_shutdown(struct platform_device *pdev) { - struct watchdog_device *wdog = platform_get_drvdata(pdev); - struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); + struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); mutex_lock(&wdev->lock); if (wdev->omap_wdt_users) { @@ -287,11 +285,10 @@ static void omap_wdt_shutdown(struct platform_device *pdev) static int omap_wdt_remove(struct platform_device *pdev) { - struct watchdog_device *wdog = platform_get_drvdata(pdev); - struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); + struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); pm_runtime_disable(wdev->dev); - watchdog_unregister_device(wdog); + watchdog_unregister_device(&wdev->wdog); return 0; } @@ -306,8 +303,7 @@ static int omap_wdt_remove(struct platform_device *pdev) static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) { - struct watchdog_device *wdog = platform_get_drvdata(pdev); - struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); + struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); mutex_lock(&wdev->lock); if (wdev->omap_wdt_users) { @@ -321,8 +317,7 @@ static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state) static int omap_wdt_resume(struct platform_device *pdev) { - struct watchdog_device *wdog = platform_get_drvdata(pdev); - struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog); + struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); mutex_lock(&wdev->lock); if (wdev->omap_wdt_users) { diff --git a/drivers/watchdog/st_lpc_wdt.c b/drivers/watchdog/st_lpc_wdt.c index f32be155212ad..6785afdc0fcaa 100644 --- a/drivers/watchdog/st_lpc_wdt.c +++ b/drivers/watchdog/st_lpc_wdt.c @@ -197,7 +197,7 @@ static int st_wdog_probe(struct platform_device *pdev) return -EINVAL; } - /* LPC can either run in RTC or WDT mode */ + /* LPC can either run as a Clocksource or in RTC or WDT mode */ if (mode != ST_LPC_MODE_WDT) return -ENODEV; |