Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Pull watchdog updates from Wim Van Sebroeck:
 "This adds the following new drivers:

   - ImgTec PDC Watchdog Timer Driver,
   - Mediatek SoC integrated watchdog

  Add support for BCM5301X, IT8783, NCT6791 and NCT6792 WDT's

  Add bcm47xx_wdt and da9063 restart handlers and contains overall
  improvements and fixes"

* git://www.linux-watchdog.org/linux-watchdog:
  watchdog: bcm47xx_wdt.c: allow enabling on BCM5301X arch
  watchdog: jz4740: Add DT support
  dt: watchdog: Add DT binding documentation for jz4740 watchdog timer
  watchdog: dw_wdt: Try to get a 30 second watchdog by default
  watchdog: dw_wdt: pat the watchdog before enabling it
  watchdog: w83627hf_wdt: Add support for NCT6791 and NCT6792
  watchdog: bcm47xx_wdt.c: add restart handler support
  watchdog: gpio_wdt: Add "always_running" feature to GPIO watchdog
  watchdog: da9063: Add restart handler support
  ARM: mediatek: dts: Add bindings for watchdog
  watchdog: Add driver for Mediatek watchdog
  watchdog: Fix omap watchdogs to enable the magic close bit
  watchdog: rt2880_wdt: minor clean up
  watchdog: hpwdt: Fix initialization message in hpwdt.c
  watchdog: it87_wdt: add IT8783 ID
  watchdog: imx2: Constify struct regmap_config and watchdog_ops
  DT: watchdog: Add ImgTec PDC Watchdog Timer binding documentation
  watchdog: ImgTec PDC Watchdog Timer Driver
  • Loading branch information
torvalds committed Feb 18, 2015
2 parents a5ac1fb + 9461343 commit 928fce2
Show file tree
Hide file tree
Showing 22 changed files with 758 additions and 32 deletions.
5 changes: 5 additions & 0 deletions Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ Required Properties:
by the GPIO flags.
- hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds).

Optional Properties:
- always-running: If the watchdog timer cannot be disabled, add this flag to
have the driver keep toggling the signal without a client. It will only cease
to toggle the signal when the device is open and the timeout elapsed.

Example:
watchdog: watchdog {
/* ADM706 */
Expand Down
19 changes: 19 additions & 0 deletions Documentation/devicetree/bindings/watchdog/imgpdc-wdt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
*ImgTec PowerDown Controller (PDC) Watchdog Timer (WDT)

Required properties:
- compatible : Should be "img,pdc-wdt"
- reg : Should contain WDT registers location and length
- clocks: Must contain an entry for each entry in clock-names.
- clock-names: Should contain "wdt" and "sys"; the watchdog counter
clock and register interface clock respectively.
- interrupts : Should contain WDT interrupt

Examples:

watchdog@18102100 {
compatible = "img,pdc-wdt";
reg = <0x18102100 0x100>;
clocks = <&pdc_wdt_clk>, <&sys_clk>;
clock-names = "wdt", "sys";
interrupts = <0 52 IRQ_TYPE_LEVEL_HIGH>;
};
12 changes: 12 additions & 0 deletions Documentation/devicetree/bindings/watchdog/ingenic,jz4740-wdt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Ingenic Watchdog Timer (WDT) Controller for JZ4740

Required properties:
compatible: "ingenic,jz4740-watchdog"
reg: Register address and length for watchdog registers

Example:

watchdog: jz4740-watchdog@0x10002000 {
compatible = "ingenic,jz4740-watchdog";
reg = <0x10002000 0x100>;
};
13 changes: 13 additions & 0 deletions Documentation/devicetree/bindings/watchdog/mtk-wdt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Mediatek SoCs Watchdog timer

Required properties:

- compatible : should be "mediatek,mt6589-wdt"
- reg : Specifies base physical address and size of the registers.

Example:

wdt: watchdog@010000000 {
compatible = "mediatek,mt6589-wdt";
reg = <0x10000000 0x18>;
};
25 changes: 24 additions & 1 deletion drivers/watchdog/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,16 @@ config MESON_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called meson_wdt.

config MEDIATEK_WATCHDOG
tristate "Mediatek SoCs watchdog support"
depends on ARCH_MEDIATEK
select WATCHDOG_CORE
help
Say Y here to include support for the watchdog timer
in Mediatek SoCs.
To compile this driver as a module, choose M here: the
module will be called mtk_wdt.

# AVR32 Architecture

config AT32AP700X_WDT
Expand Down Expand Up @@ -1005,6 +1015,8 @@ config W83627HF_WDT
NCT6775
NCT6776
NCT6779
NCT6791
NCT6792

This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain
Expand Down Expand Up @@ -1101,7 +1113,7 @@ config ATH79_WDT

config BCM47XX_WDT
tristate "Broadcom BCM47xx Watchdog Timer"
depends on BCM47XX
depends on BCM47XX || ARCH_BCM_5301X
select WATCHDOG_CORE
help
Hardware driver for the Broadcom BCM47xx Watchdog Timer.
Expand Down Expand Up @@ -1235,6 +1247,17 @@ config BCM_KONA_WDT_DEBUG

If in doubt, say 'N'.

config IMGPDC_WDT
tristate "Imagination Technologies PDC Watchdog Timer"
depends on HAS_IOMEM
depends on METAG || MIPS || COMPILE_TEST
help
Driver for Imagination Technologies PowerDown Controller
Watchdog Timer.

To compile this driver as a loadable module, choose M here.
The module will be called imgpdc_wdt.

config LANTIQ_WDT
tristate "Lantiq SoC watchdog"
depends on LANTIQ
Expand Down
2 changes: 2 additions & 0 deletions drivers/watchdog/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ obj-$(CONFIG_QCOM_WDT) += qcom-wdt.o
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

# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
Expand Down Expand Up @@ -142,6 +143,7 @@ obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o
obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o

# PARISC Architecture

Expand Down
21 changes: 20 additions & 1 deletion drivers/watchdog/bcm47xx_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,17 @@ static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
return NOTIFY_DONE;
}

static int bcm47xx_wdt_restart(struct notifier_block *this, unsigned long mode,
void *cmd)
{
struct bcm47xx_wdt *wdt;

wdt = container_of(this, struct bcm47xx_wdt, restart_handler);
wdt->timer_set(wdt, 1);

return NOTIFY_DONE;
}

static struct watchdog_ops bcm47xx_wdt_soft_ops = {
.owner = THIS_MODULE,
.start = bcm47xx_wdt_soft_start,
Expand Down Expand Up @@ -209,15 +220,23 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev)
if (ret)
goto err_timer;

ret = watchdog_register_device(&wdt->wdd);
wdt->restart_handler.notifier_call = &bcm47xx_wdt_restart;
wdt->restart_handler.priority = 64;
ret = register_restart_handler(&wdt->restart_handler);
if (ret)
goto err_notifier;

ret = watchdog_register_device(&wdt->wdd);
if (ret)
goto err_handler;

dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n",
timeout, nowayout ? ", nowayout" : "",
soft ? ", Software Timer" : "");
return 0;

err_handler:
unregister_restart_handler(&wdt->restart_handler);
err_notifier:
unregister_reboot_notifier(&wdt->notifier);
err_timer:
Expand Down
32 changes: 31 additions & 1 deletion drivers/watchdog/da9063_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/mfd/da9063/registers.h>
#include <linux/mfd/da9063/core.h>
#include <linux/reboot.h>
#include <linux/regmap.h>

/*
Expand All @@ -38,6 +39,7 @@ static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 };
struct da9063_watchdog {
struct da9063 *da9063;
struct watchdog_device wdtdev;
struct notifier_block restart_handler;
};

static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs)
Expand Down Expand Up @@ -119,6 +121,23 @@ static int da9063_wdt_set_timeout(struct watchdog_device *wdd,
return ret;
}

static int da9063_wdt_restart_handler(struct notifier_block *this,
unsigned long mode, void *cmd)
{
struct da9063_watchdog *wdt = container_of(this,
struct da9063_watchdog,
restart_handler);
int ret;

ret = regmap_write(wdt->da9063->regmap, DA9063_REG_CONTROL_F,
DA9063_SHUTDOWN);
if (ret)
dev_alert(wdt->da9063->dev, "Failed to shutdown (err = %d)\n",
ret);

return NOTIFY_DONE;
}

static const struct watchdog_info da9063_watchdog_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "DA9063 Watchdog",
Expand Down Expand Up @@ -163,14 +182,25 @@ static int da9063_wdt_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, wdt);

ret = watchdog_register_device(&wdt->wdtdev);
if (ret)
return ret;

return ret;
wdt->restart_handler.notifier_call = da9063_wdt_restart_handler;
wdt->restart_handler.priority = 128;
ret = register_restart_handler(&wdt->restart_handler);
if (ret)
dev_err(wdt->da9063->dev,
"Failed to register restart handler (err = %d)\n", ret);

return 0;
}

static int da9063_wdt_remove(struct platform_device *pdev)
{
struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev);

unregister_restart_handler(&wdt->restart_handler);

watchdog_unregister_device(&wdt->wdtdev);

return 0;
Expand Down
32 changes: 23 additions & 9 deletions drivers/watchdog/dw_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@
/* The maximum TOP (timeout period) value that can be set in the watchdog. */
#define DW_WDT_MAX_TOP 15

#define DW_WDT_DEFAULT_SECONDS 30

static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
Expand Down Expand Up @@ -96,6 +98,12 @@ static inline void dw_wdt_set_next_heartbeat(void)
dw_wdt.next_heartbeat = jiffies + dw_wdt_get_top() * HZ;
}

static void dw_wdt_keepalive(void)
{
writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
WDOG_COUNTER_RESTART_REG_OFFSET);
}

static int dw_wdt_set_top(unsigned top_s)
{
int i, top_val = DW_WDT_MAX_TOP;
Expand All @@ -110,21 +118,27 @@ static int dw_wdt_set_top(unsigned top_s)
break;
}

/* Set the new value in the watchdog. */
/*
* Set the new value in the watchdog. Some versions of dw_wdt
* have have TOPINIT in the TIMEOUT_RANGE register (as per
* CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1). On those we
* effectively get a pat of the watchdog right here.
*/
writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT,
dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);

/*
* Add an explicit pat to handle versions of the watchdog that
* don't have TOPINIT. This won't hurt on versions that have
* it.
*/
dw_wdt_keepalive();

dw_wdt_set_next_heartbeat();

return dw_wdt_top_in_seconds(top_val);
}

static void dw_wdt_keepalive(void)
{
writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
WDOG_COUNTER_RESTART_REG_OFFSET);
}

static int dw_wdt_restart_handle(struct notifier_block *this,
unsigned long mode, void *cmd)
{
Expand Down Expand Up @@ -167,9 +181,9 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
if (!dw_wdt_is_enabled()) {
/*
* The watchdog is not currently enabled. Set the timeout to
* the maximum and then start it.
* something reasonable and then start it.
*/
dw_wdt_set_top(DW_WDT_MAX_TOP);
dw_wdt_set_top(DW_WDT_DEFAULT_SECONDS);
writel(WDOG_CONTROL_REG_WDT_EN_MASK,
dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
}
Expand Down
37 changes: 29 additions & 8 deletions drivers/watchdog/gpio_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ struct gpio_wdt_priv {
int gpio;
bool active_low;
bool state;
bool always_running;
bool armed;
unsigned int hw_algo;
unsigned int hw_margin;
unsigned long last_jiffies;
Expand All @@ -48,14 +50,20 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
gpio_direction_input(priv->gpio);
}

static int gpio_wdt_start(struct watchdog_device *wdd)
static void gpio_wdt_start_impl(struct gpio_wdt_priv *priv)
{
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);

priv->state = priv->active_low;
gpio_direction_output(priv->gpio, priv->state);
priv->last_jiffies = jiffies;
mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin);
}

static int gpio_wdt_start(struct watchdog_device *wdd)
{
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);

gpio_wdt_start_impl(priv);
priv->armed = true;

return 0;
}
Expand All @@ -64,8 +72,11 @@ static int gpio_wdt_stop(struct watchdog_device *wdd)
{
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);

mod_timer(&priv->timer, 0);
gpio_wdt_disable(priv);
priv->armed = false;
if (!priv->always_running) {
mod_timer(&priv->timer, 0);
gpio_wdt_disable(priv);
}

return 0;
}
Expand All @@ -91,8 +102,8 @@ static void gpio_wdt_hwping(unsigned long data)
struct watchdog_device *wdd = (struct watchdog_device *)data;
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);

if (time_after(jiffies, priv->last_jiffies +
msecs_to_jiffies(wdd->timeout * 1000))) {
if (priv->armed && time_after(jiffies, priv->last_jiffies +
msecs_to_jiffies(wdd->timeout * 1000))) {
dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n");
return;
}
Expand Down Expand Up @@ -197,6 +208,9 @@ static int gpio_wdt_probe(struct platform_device *pdev)
/* Use safe value (1/2 of real timeout) */
priv->hw_margin = msecs_to_jiffies(hw_margin / 2);

priv->always_running = of_property_read_bool(pdev->dev.of_node,
"always-running");

watchdog_set_drvdata(&priv->wdd, priv);

priv->wdd.info = &gpio_wdt_ident;
Expand All @@ -216,8 +230,15 @@ static int gpio_wdt_probe(struct platform_device *pdev)
priv->notifier.notifier_call = gpio_wdt_notify_sys;
ret = register_reboot_notifier(&priv->notifier);
if (ret)
watchdog_unregister_device(&priv->wdd);
goto error_unregister;

if (priv->always_running)
gpio_wdt_start_impl(priv);

return 0;

error_unregister:
watchdog_unregister_device(&priv->wdd);
return ret;
}

Expand Down
Loading

0 comments on commit 928fce2

Please sign in to comment.