From 4fa5daa9c618e3411a351c326c34916b65ee7ae6 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Wed, 4 Dec 2013 21:39:29 +0200 Subject: watchdog: davinci: add "timeout-sec" property Since Davinci WDT has been switched to use WDT core, it became able to support timeout-sec property, so add it to it's binding description. Signed-off-by: Ivan Khoronzhuk Acked-by: Santosh Shilimkar Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- Documentation/devicetree/bindings/watchdog/davinci-wdt.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt index 75558ccd9a05..e450134650bb 100644 --- a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt @@ -4,9 +4,13 @@ Required properties: - compatible : Should be "ti,davinci-wdt" - reg : Should contain WDT registers location and length +Optional properties: +- timeout-sec : Contains the watchdog timeout in seconds + Examples: wdt: wdt@2320000 { compatible = "ti,davinci-wdt"; reg = <0x02320000 0x80>; + timeout-sec = <30>; }; -- cgit v1.2.3 From 8832b20093434514fda5e8a0c885270eda4fbf40 Mon Sep 17 00:00:00 2001 From: Ivan Khoronzhuk Date: Wed, 4 Dec 2013 21:39:30 +0200 Subject: watchdog: davinci: reuse driver for keystone arch The keystone arch uses the same IP watchdog, so add "ti,keystone-wdt" compatible and correct identity. The Keystone arch is using clocks in DT and source clock for watchdog has to be specified, so add this to binding. Signed-off-by: Ivan Khoronzhuk Acked-by: Santosh Shilimkar Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- Documentation/devicetree/bindings/watchdog/davinci-wdt.txt | 12 ++++++++++-- drivers/watchdog/Kconfig | 4 ++-- drivers/watchdog/davinci_wdt.c | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt index e450134650bb..e60b9a13bdcb 100644 --- a/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/davinci-wdt.txt @@ -1,11 +1,18 @@ -DaVinci Watchdog Timer (WDT) Controller +Texas Instruments DaVinci/Keystone Watchdog Timer (WDT) Controller Required properties: -- compatible : Should be "ti,davinci-wdt" +- compatible : Should be "ti,davinci-wdt", "ti,keystone-wdt" - reg : Should contain WDT registers location and length Optional properties: - timeout-sec : Contains the watchdog timeout in seconds +- clocks : the clock feeding the watchdog timer. + Needed if platform uses clocks. + See clock-bindings.txt + +Documentation: +Davinci DM646x - http://www.ti.com/lit/ug/spruer5b/spruer5b.pdf +Keystone - http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf Examples: @@ -13,4 +20,5 @@ wdt: wdt@2320000 { compatible = "ti,davinci-wdt"; reg = <0x02320000 0x80>; timeout-sec = <30>; + clocks = <&clkwdtimer0>; }; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b69a0f763a6d..af8f7c75e03c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -270,11 +270,11 @@ config IOP_WATCHDOG config DAVINCI_WATCHDOG tristate "DaVinci watchdog" - depends on ARCH_DAVINCI + depends on ARCH_DAVINCI || ARCH_KEYSTONE select WATCHDOG_CORE help Say Y here if to include support for the watchdog timer - in the DaVinci DM644x/DM646x processors. + in the DaVinci DM644x/DM646x or Keystone processors. To compile this driver as a module, choose M here: the module will be called davinci_wdt. diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index dbe28343e749..b1bae03742a9 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -143,7 +143,7 @@ static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd) static const struct watchdog_info davinci_wdt_info = { .options = WDIOF_KEEPALIVEPING, - .identity = "DaVinci Watchdog", + .identity = "DaVinci/Keystone Watchdog", }; static const struct watchdog_ops davinci_wdt_ops = { -- cgit v1.2.3 From 25134eafb05eef6dd4b6caee3a711b63ee0c3737 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 30 Nov 2013 11:54:32 +0400 Subject: watchdog: GPIO-controlled watchdog This patch adds a watchdog driver for devices controlled through GPIO, (Analog Devices ADM706, Maxim MAX823, National NE555 etc). Signed-off-by: Alexander Shiyan Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../devicetree/bindings/watchdog/gpio-wdt.txt | 23 ++ drivers/watchdog/Kconfig | 8 + drivers/watchdog/Makefile | 1 + drivers/watchdog/gpio_wdt.c | 254 +++++++++++++++++++++ 4 files changed, 286 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/gpio-wdt.txt create mode 100644 drivers/watchdog/gpio_wdt.c (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt new file mode 100644 index 000000000000..37afec194949 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt @@ -0,0 +1,23 @@ +* GPIO-controlled Watchdog + +Required Properties: +- compatible: Should contain "linux,wdt-gpio". +- gpios: From common gpio binding; gpio connection to WDT reset pin. +- hw_algo: The algorithm used by the driver. Should be one of the + following values: + - toggle: Either a high-to-low or a low-to-high transition clears + the WDT counter. The watchdog timer is disabled when GPIO is + left floating or connected to a three-state buffer. + - level: Low or high level starts counting WDT timeout, + the opposite level disables the WDT. Active level is determined + by the GPIO flags. +- hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds). + +Example: + watchdog: watchdog { + /* ADM706 */ + compatible = "linux,wdt-gpio"; + gpios = <&gpio3 9 GPIO_ACTIVE_LOW>; + hw_algo = "toggle"; + hw_margin_ms = <1600>; + }; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index af8f7c75e03c..7a2fedab0fb5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -87,6 +87,14 @@ config DA9055_WATCHDOG This driver can also be built as a module. If so, the module will be called da9055_wdt. +config GPIO_WATCHDOG + tristate "Watchdog device controlled through GPIO-line" + depends on OF_GPIO + select WATCHDOG_CORE + help + If you say yes here you get support for watchdog device + controlled through GPIO-line. + config WM831X_WATCHDOG tristate "WM831x watchdog" depends on MFD_WM831X diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index af2251682214..985a66cda76f 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -172,6 +172,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o # Architecture Independent obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o +obj-$(CONFIG_GPIO_WATCHDOG) += gpio_wdt.o obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c new file mode 100644 index 000000000000..220a9e07cfd5 --- /dev/null +++ b/drivers/watchdog/gpio_wdt.c @@ -0,0 +1,254 @@ +/* + * Driver for watchdog device controlled through GPIO-line + * + * Author: 2013, Alexander Shiyan + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define SOFT_TIMEOUT_MIN 1 +#define SOFT_TIMEOUT_DEF 60 +#define SOFT_TIMEOUT_MAX 0xffff + +enum { + HW_ALGO_TOGGLE, + HW_ALGO_LEVEL, +}; + +struct gpio_wdt_priv { + int gpio; + bool active_low; + bool state; + unsigned int hw_algo; + unsigned int hw_margin; + unsigned long last_jiffies; + struct notifier_block notifier; + struct timer_list timer; + struct watchdog_device wdd; +}; + +static void gpio_wdt_disable(struct gpio_wdt_priv *priv) +{ + gpio_set_value_cansleep(priv->gpio, !priv->active_low); + + /* Put GPIO back to tristate */ + if (priv->hw_algo == HW_ALGO_TOGGLE) + gpio_direction_input(priv->gpio); +} + +static int gpio_wdt_start(struct watchdog_device *wdd) +{ + 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); + + return 0; +} + +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); + + return 0; +} + +static int gpio_wdt_ping(struct watchdog_device *wdd) +{ + struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); + + priv->last_jiffies = jiffies; + + return 0; +} + +static int gpio_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) +{ + wdd->timeout = t; + + return gpio_wdt_ping(wdd); +} + +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))) { + dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); + return; + } + + /* Restart timer */ + mod_timer(&priv->timer, jiffies + priv->hw_margin); + + switch (priv->hw_algo) { + case HW_ALGO_TOGGLE: + /* Toggle output pin */ + priv->state = !priv->state; + gpio_set_value_cansleep(priv->gpio, priv->state); + break; + case HW_ALGO_LEVEL: + /* Pulse */ + gpio_set_value_cansleep(priv->gpio, !priv->active_low); + udelay(1); + gpio_set_value_cansleep(priv->gpio, priv->active_low); + break; + } +} + +static int gpio_wdt_notify_sys(struct notifier_block *nb, unsigned long code, + void *unused) +{ + struct gpio_wdt_priv *priv = container_of(nb, struct gpio_wdt_priv, + notifier); + + mod_timer(&priv->timer, 0); + + switch (code) { + case SYS_HALT: + case SYS_POWER_OFF: + gpio_wdt_disable(priv); + break; + default: + break; + } + + return NOTIFY_DONE; +} + +static const struct watchdog_info gpio_wdt_ident = { + .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | + WDIOF_SETTIMEOUT, + .identity = "GPIO Watchdog", +}; + +static const struct watchdog_ops gpio_wdt_ops = { + .owner = THIS_MODULE, + .start = gpio_wdt_start, + .stop = gpio_wdt_stop, + .ping = gpio_wdt_ping, + .set_timeout = gpio_wdt_set_timeout, +}; + +static int gpio_wdt_probe(struct platform_device *pdev) +{ + struct gpio_wdt_priv *priv; + enum of_gpio_flags flags; + unsigned int hw_margin; + unsigned long f = 0; + const char *algo; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags); + if (!gpio_is_valid(priv->gpio)) + return priv->gpio; + + priv->active_low = flags & OF_GPIO_ACTIVE_LOW; + + ret = of_property_read_string(pdev->dev.of_node, "hw_algo", &algo); + if (ret) + return ret; + if (!strncmp(algo, "toggle", 6)) { + priv->hw_algo = HW_ALGO_TOGGLE; + f = GPIOF_IN; + } else if (!strncmp(algo, "level", 5)) { + priv->hw_algo = HW_ALGO_LEVEL; + f = priv->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; + } else { + return -EINVAL; + } + + ret = devm_gpio_request_one(&pdev->dev, priv->gpio, f, + dev_name(&pdev->dev)); + if (ret) + return ret; + + ret = of_property_read_u32(pdev->dev.of_node, + "hw_margin_ms", &hw_margin); + if (ret) + return ret; + /* Disallow values lower than 2 and higher than 65535 ms */ + if (hw_margin < 2 || hw_margin > 65535) + return -EINVAL; + + /* Use safe value (1/2 of real timeout) */ + priv->hw_margin = msecs_to_jiffies(hw_margin / 2); + + watchdog_set_drvdata(&priv->wdd, priv); + + priv->wdd.info = &gpio_wdt_ident; + priv->wdd.ops = &gpio_wdt_ops; + priv->wdd.min_timeout = SOFT_TIMEOUT_MIN; + priv->wdd.max_timeout = SOFT_TIMEOUT_MAX; + + if (watchdog_init_timeout(&priv->wdd, 0, &pdev->dev) < 0) + priv->wdd.timeout = SOFT_TIMEOUT_DEF; + + setup_timer(&priv->timer, gpio_wdt_hwping, (unsigned long)&priv->wdd); + + ret = watchdog_register_device(&priv->wdd); + if (ret) + return ret; + + priv->notifier.notifier_call = gpio_wdt_notify_sys; + ret = register_reboot_notifier(&priv->notifier); + if (ret) + watchdog_unregister_device(&priv->wdd); + + return ret; +} + +static int gpio_wdt_remove(struct platform_device *pdev) +{ + struct gpio_wdt_priv *priv = platform_get_drvdata(pdev); + + del_timer_sync(&priv->timer); + unregister_reboot_notifier(&priv->notifier); + watchdog_unregister_device(&priv->wdd); + + return 0; +} + +static const struct of_device_id gpio_wdt_dt_ids[] = { + { .compatible = "linux,wdt-gpio", }, + { } +}; +MODULE_DEVICE_TABLE(of, gpio_wdt_dt_ids); + +static struct platform_driver gpio_wdt_driver = { + .driver = { + .name = "gpio-wdt", + .owner = THIS_MODULE, + .of_match_table = gpio_wdt_dt_ids, + }, + .probe = gpio_wdt_probe, + .remove = gpio_wdt_remove, +}; +module_platform_driver(gpio_wdt_driver); + +MODULE_AUTHOR("Alexander Shiyan "); +MODULE_DESCRIPTION("GPIO Watchdog"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4f1f653a68d67ca5732fdd7ee4deb290a3ea5149 Mon Sep 17 00:00:00 2001 From: Leela Krishna Amudala Date: Fri, 6 Dec 2013 11:17:47 +0530 Subject: watchdog: s3c2410_wdt: use syscon regmap interface to configure pmu register Add device tree support for exynos5250 and 5420 SoCs and use syscon regmap interface to configure AUTOMATIC_WDT_RESET_DISABLE and MASK_WDT_RESET_REQUEST registers of PMU to mask/unmask enable/disable of watchdog in probe and s2r scenarios. Signed-off-by: Leela Krishna Amudala Signed-off-by: Doug Anderson Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../devicetree/bindings/watchdog/samsung-wdt.txt | 21 ++- drivers/watchdog/Kconfig | 1 + drivers/watchdog/s3c2410_wdt.c | 154 +++++++++++++++++++-- 3 files changed, 166 insertions(+), 10 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt index 2aa486cc1ff6..cfff37511aac 100644 --- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt @@ -5,10 +5,29 @@ after a preset amount of time during which the WDT reset event has not occurred. Required properties: -- compatible : should be "samsung,s3c2410-wdt" +- 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 + - reg : base physical address of the controller and length of memory mapped region. - interrupts : interrupt number to the cpu. +- samsung,syscon-phandle : reference to syscon node (This property required only + in case of compatible being "samsung,exynos5250-wdt" or "samsung,exynos5420-wdt". + In case of Exynos5250 and 5420 this property points to syscon node holding the PMU + base address) Optional properties: - timeout-sec : contains the watchdog timeout in seconds. + +Example: + +watchdog@101D0000 { + compatible = "samsung,exynos5250-wdt"; + reg = <0x101D0000 0x100>; + interrupts = <0 42 0>; + clocks = <&clock 336>; + clock-names = "watchdog"; + samsung,syscon-phandle = <&pmu_syscon>; +}; diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 7a2fedab0fb5..c11a3387335d 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -196,6 +196,7 @@ config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" depends on HAVE_S3C2410_WATCHDOG select WATCHDOG_CORE + select MFD_SYSCON if ARCH_EXYNOS5 help Watchdog timer block in the Samsung SoCs. This will reboot the system when the timer expires with the watchdog enabled. diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 8beaa1799df6..64f5470a6a0e 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #define S3C2410_WTCON 0x00 #define S3C2410_WTDAT 0x04 @@ -60,6 +62,10 @@ #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) +#define EXYNOS5_WDT_DISABLE_REG_OFFSET 0x0408 +#define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c +#define QUIRK_HAS_PMU_CONFIG (1 << 0) + static bool nowayout = WATCHDOG_NOWAYOUT; static int tmr_margin; static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; @@ -83,6 +89,25 @@ 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 + * + * @disable_reg: Offset in pmureg for the register that disables the watchdog + * timer reset functionality. + * @mask_reset_reg: Offset in pmureg for the register that masks the watchdog + * timer reset functionality. + * @mask_bit: Bit number for the watchdog timer in the disable register and the + * mask reset register. + * @quirks: A bitfield of quirks. + */ + +struct s3c2410_wdt_variant { + int disable_reg; + int mask_reset_reg; + int mask_bit; + u32 quirks; +}; + struct s3c2410_wdt { struct device *dev; struct clk *clock; @@ -93,7 +118,49 @@ struct s3c2410_wdt { unsigned long wtdat_save; struct watchdog_device wdt_device; struct notifier_block freq_transition; + struct s3c2410_wdt_variant *drv_data; + struct regmap *pmureg; +}; + +static const struct s3c2410_wdt_variant drv_data_s3c2410 = { + .quirks = 0 +}; + +#ifdef CONFIG_OF +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, + .quirks = QUIRK_HAS_PMU_CONFIG +}; + +static const struct s3c2410_wdt_variant drv_data_exynos5420 = { + .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, + .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, + .mask_bit = 0, + .quirks = QUIRK_HAS_PMU_CONFIG +}; + +static const struct of_device_id s3c2410_wdt_match[] = { + { .compatible = "samsung,s3c2410-wdt", + .data = &drv_data_s3c2410 }, + { .compatible = "samsung,exynos5250-wdt", + .data = &drv_data_exynos5250 }, + { .compatible = "samsung,exynos5420-wdt", + .data = &drv_data_exynos5420 }, + {}, }; +MODULE_DEVICE_TABLE(of, s3c2410_wdt_match); +#endif + +static const struct platform_device_id s3c2410_wdt_ids[] = { + { + .name = "s3c2410-wdt", + .driver_data = (unsigned long)&drv_data_s3c2410, + }, + {} +}; +MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids); /* watchdog control routines */ @@ -110,6 +177,35 @@ static inline struct s3c2410_wdt *freq_to_wdt(struct notifier_block *nb) return container_of(nb, struct s3c2410_wdt, freq_transition); } +static int s3c2410wdt_mask_and_disable_reset(struct s3c2410_wdt *wdt, bool mask) +{ + int ret; + u32 mask_val = 1 << wdt->drv_data->mask_bit; + u32 val = 0; + + /* No need to do anything if no PMU CONFIG needed */ + if (!(wdt->drv_data->quirks & QUIRK_HAS_PMU_CONFIG)) + return 0; + + if (mask) + val = mask_val; + + ret = regmap_update_bits(wdt->pmureg, + wdt->drv_data->disable_reg, + mask_val, val); + if (ret < 0) + goto error; + + ret = regmap_update_bits(wdt->pmureg, + wdt->drv_data->mask_reset_reg, + mask_val, val); + error: + if (ret < 0) + dev_err(wdt->dev, "failed to update reg(%d)\n", ret); + + return ret; +} + static int s3c2410wdt_keepalive(struct watchdog_device *wdd) { struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); @@ -328,6 +424,20 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt) } #endif +/* s3c2410_get_wdt_driver_data */ +static inline struct s3c2410_wdt_variant * +get_wdt_drv_data(struct platform_device *pdev) +{ + if (pdev->dev.of_node) { + const struct of_device_id *match; + match = of_match_node(s3c2410_wdt_match, pdev->dev.of_node); + return (struct s3c2410_wdt_variant *)match->data; + } else { + return (struct s3c2410_wdt_variant *) + platform_get_device_id(pdev)->driver_data; + } +} + static int s3c2410wdt_probe(struct platform_device *pdev) { struct device *dev; @@ -350,6 +460,16 @@ 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); + if (wdt->drv_data->quirks & QUIRK_HAS_PMU_CONFIG) { + wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, + "samsung,syscon-phandle"); + if (IS_ERR(wdt->pmureg)) { + dev_err(dev, "syscon regmap lookup failed.\n"); + return PTR_ERR(wdt->pmureg); + } + } + wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (wdt_irq == NULL) { dev_err(dev, "no irq resource specified\n"); @@ -418,6 +538,10 @@ static int s3c2410wdt_probe(struct platform_device *pdev) goto err_cpufreq; } + ret = s3c2410wdt_mask_and_disable_reset(wdt, false); + if (ret < 0) + goto err_unregister; + if (tmr_atboot && started == 0) { dev_info(dev, "starting watchdog timer\n"); s3c2410wdt_start(&wdt->wdt_device); @@ -442,6 +566,9 @@ static int s3c2410wdt_probe(struct platform_device *pdev) return 0; + err_unregister: + watchdog_unregister_device(&wdt->wdt_device); + err_cpufreq: s3c2410wdt_cpufreq_deregister(wdt); @@ -455,8 +582,13 @@ static int s3c2410wdt_probe(struct platform_device *pdev) static int s3c2410wdt_remove(struct platform_device *dev) { + int ret; struct s3c2410_wdt *wdt = platform_get_drvdata(dev); + ret = s3c2410wdt_mask_and_disable_reset(wdt, true); + if (ret < 0) + return ret; + watchdog_unregister_device(&wdt->wdt_device); s3c2410wdt_cpufreq_deregister(wdt); @@ -471,6 +603,8 @@ static void s3c2410wdt_shutdown(struct platform_device *dev) { struct s3c2410_wdt *wdt = platform_get_drvdata(dev); + s3c2410wdt_mask_and_disable_reset(wdt, true); + s3c2410wdt_stop(&wdt->wdt_device); } @@ -478,12 +612,17 @@ static void s3c2410wdt_shutdown(struct platform_device *dev) static int s3c2410wdt_suspend(struct device *dev) { + int ret; struct s3c2410_wdt *wdt = dev_get_drvdata(dev); /* Save watchdog state, and turn it off. */ wdt->wtcon_save = readl(wdt->reg_base + S3C2410_WTCON); wdt->wtdat_save = readl(wdt->reg_base + S3C2410_WTDAT); + ret = s3c2410wdt_mask_and_disable_reset(wdt, true); + if (ret < 0) + return ret; + /* Note that WTCNT doesn't need to be saved. */ s3c2410wdt_stop(&wdt->wdt_device); @@ -492,6 +631,7 @@ static int s3c2410wdt_suspend(struct device *dev) static int s3c2410wdt_resume(struct device *dev) { + int ret; struct s3c2410_wdt *wdt = dev_get_drvdata(dev); /* Restore watchdog state. */ @@ -499,6 +639,10 @@ static int s3c2410wdt_resume(struct device *dev) writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTCNT);/* Reset count */ writel(wdt->wtcon_save, wdt->reg_base + S3C2410_WTCON); + ret = s3c2410wdt_mask_and_disable_reset(wdt, false); + if (ret < 0) + return ret; + dev_info(dev, "watchdog %sabled\n", (wdt->wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); @@ -509,18 +653,11 @@ static int s3c2410wdt_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend, s3c2410wdt_resume); -#ifdef CONFIG_OF -static const struct of_device_id s3c2410_wdt_match[] = { - { .compatible = "samsung,s3c2410-wdt" }, - {}, -}; -MODULE_DEVICE_TABLE(of, s3c2410_wdt_match); -#endif - static struct platform_driver s3c2410wdt_driver = { .probe = s3c2410wdt_probe, .remove = s3c2410wdt_remove, .shutdown = s3c2410wdt_shutdown, + .id_table = s3c2410_wdt_ids, .driver = { .owner = THIS_MODULE, .name = "s3c2410-wdt", @@ -535,4 +672,3 @@ MODULE_AUTHOR("Ben Dooks , " "Dimitry Andric "); MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c2410-wdt"); -- cgit v1.2.3 From 6914c5873c227f0eb03e3860a1cf95a930a06f31 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Fri, 4 Oct 2013 09:24:13 +0200 Subject: watchdog: at91sam9_wdt: update device tree doc Add new at91sam9 watchdog properties to the documentation. Signed-off-by: Boris BREZILLON Acked-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../devicetree/bindings/watchdog/atmel-wdt.txt | 30 ++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt index fcdd48f7dcff..f90e294d7631 100644 --- a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt @@ -9,11 +9,37 @@ Required properties: Optional properties: - timeout-sec: contains the watchdog timeout in seconds. +- interrupts : Should contain WDT interrupt. +- atmel,max-heartbeat-sec : Should contain the maximum heartbeat value in + seconds. This value should be less or equal to 16. It is used to + compute the WDV field. +- atmel,min-heartbeat-sec : Should contain the minimum heartbeat value in + seconds. This value must be smaller than the max-heartbeat-sec value. + It is used to compute the WDD field. +- atmel,watchdog-type : Should be "hardware" or "software". Hardware watchdog + use the at91 watchdog reset. Software watchdog use the watchdog + interrupt to trigger a software reset. +- atmel,reset-type : Should be "proc" or "all". + "all" : assert peripherals and processor reset signals + "proc" : assert the processor reset signal + This is valid only when using "hardware" watchdog. +- atmel,disable : Should be present if you want to disable the watchdog. +- atmel,idle-halt : Should be present if you want to stop the watchdog when + entering idle state. +- atmel,dbg-halt : Should be present if you want to stop the watchdog when + entering debug state. Example: - watchdog@fffffd40 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; - timeout-sec = <10>; + interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + timeout-sec = <15>; + atmel,watchdog-type = "hardware"; + atmel,reset-type = "all"; + atmel,dbg-halt; + atmel,idle-halt; + atmel,max-heartbeat-sec = <16>; + atmel,min-heartbeat-sec = <0>; + status = "okay"; }; -- cgit v1.2.3