From f8cde726739c60109cc4a30b6b5475b5bd5e1d97 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Mon, 5 Nov 2018 10:53:47 +0000 Subject: watchdog: renesas_wdt: Fix typos Do not use "," but ";" to separate instructions. Signed-off-by: Fabrizio Castro Reviewed-by: Guenter Roeck Reviewed-by: Simon Horman Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/renesas_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c index 0d74c3e48979..b570962e84f3 100644 --- a/drivers/watchdog/renesas_wdt.c +++ b/drivers/watchdog/renesas_wdt.c @@ -220,8 +220,8 @@ static int rwdt_probe(struct platform_device *pdev) goto out_pm_disable; } - priv->wdev.info = &rwdt_ident, - priv->wdev.ops = &rwdt_ops, + priv->wdev.info = &rwdt_ident; + priv->wdev.ops = &rwdt_ops; priv->wdev.parent = &pdev->dev; priv->wdev.min_timeout = 1; priv->wdev.max_timeout = DIV_BY_CLKS_PER_SEC(priv, 65536); -- cgit v1.2.3 From 7db706a2184d37ca52a4f5315556ed4adac86e82 Mon Sep 17 00:00:00 2001 From: Tomer Maimon Date: Mon, 5 Nov 2018 18:11:52 +0200 Subject: watchdog: npcm: Modify npcm watchdog kconfig arch parameter Modify Nuvoton watchdog Kconfig default supported architecture name to ARCH_NPCM7XX because ARCH_NPCM750 architecture name is not supported. Signed-off-by: Tomer Maimon Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 2d64333f4782..746759ec8960 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -538,7 +538,7 @@ config COH901327_WATCHDOG config NPCM7XX_WATCHDOG bool "Nuvoton NPCM750 watchdog" depends on ARCH_NPCM || COMPILE_TEST - default y if ARCH_NPCM750 + default y if ARCH_NPCM7XX select WATCHDOG_CORE help Say Y here to include Watchdog timer support for the -- cgit v1.2.3 From e990e12741877e9bfac402ca468f4007a75f6e2a Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 7 Nov 2018 20:46:02 +0100 Subject: watchdog: renesas_wdt: don't set divider while watchdog is running The datasheet says we must stop the timer before changing the clock divider. This can happen when the restart handler is called while the watchdog is running. Signed-off-by: Wolfram Sang Reviewed-by: Fabrizio Castro Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/renesas_wdt.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c index b570962e84f3..c450e23e24a8 100644 --- a/drivers/watchdog/renesas_wdt.c +++ b/drivers/watchdog/renesas_wdt.c @@ -74,12 +74,17 @@ static int rwdt_init_timeout(struct watchdog_device *wdev) static int rwdt_start(struct watchdog_device *wdev) { struct rwdt_priv *priv = watchdog_get_drvdata(wdev); + u8 val; pm_runtime_get_sync(wdev->parent); - rwdt_write(priv, 0, RWTCSRB); - rwdt_write(priv, priv->cks, RWTCSRA); + /* Stop the timer before we modify any register */ + val = readb_relaxed(priv->base + RWTCSRA) & ~RWTCSRA_TME; + rwdt_write(priv, val, RWTCSRA); + rwdt_init_timeout(wdev); + rwdt_write(priv, priv->cks, RWTCSRA); + rwdt_write(priv, 0, RWTCSRB); while (readb_relaxed(priv->base + RWTCSRA) & RWTCSRA_WRFLG) cpu_relax(); -- cgit v1.2.3 From 06f8f2ca0585ea0c8df7e6c65659b1f679b4254b Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 20 Nov 2018 09:54:45 -0500 Subject: watchdog: cpwd: add of_node_put() use of_node_put() to release the refcount. Signed-off-by: Yangtao Li Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/cpwd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index aee0b25cf10d..32156e199c51 100644 --- a/drivers/watchdog/cpwd.c +++ b/drivers/watchdog/cpwd.c @@ -570,6 +570,8 @@ static int cpwd_probe(struct platform_device *op) if (str_prop) p->timeout = simple_strtoul(str_prop, NULL, 10); + of_node_put(options); + /* CP1400s seem to have broken PLD implementations-- the * interrupt_mask register cannot be written, so no timer * interrupts can be masked within the PLD. -- cgit v1.2.3 From 31eb42bd9353c807522697ddc2a6ab14b4924fa5 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 19 Nov 2018 09:17:38 +0100 Subject: watchdog: w83627hf_wdt: Add quirk for Inves system On some systems, the NCT6791D comes with a companion chip and the watchdog function is in this companion chip. We must use a different unlocking sequence to access the companion chip. Use DMI strings to identify such system and adjust the unlocking sequence automatically. Signed-off-by: Jean Delvare Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/w83627hf_wdt.c | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 4b9365d4de7a..3a49ba9ea608 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c @@ -38,6 +38,7 @@ #include #include #include +#include #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ @@ -46,6 +47,8 @@ static int wdt_io; static int cr_wdt_timeout; /* WDT timeout register */ static int cr_wdt_control; /* WDT control register */ static int cr_wdt_csr; /* WDT control & status register */ +static int wdt_cfg_enter = 0x87;/* key to unlock configuration space */ +static int wdt_cfg_leave = 0xAA;/* key to lock configuration space */ enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, @@ -130,8 +133,8 @@ static int superio_enter(void) if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME)) return -EBUSY; - outb_p(0x87, WDT_EFER); /* Enter extended function mode */ - outb_p(0x87, WDT_EFER); /* Again according to manual */ + outb_p(wdt_cfg_enter, WDT_EFER); /* Enter extended function mode */ + outb_p(wdt_cfg_enter, WDT_EFER); /* Again according to manual */ return 0; } @@ -143,7 +146,7 @@ static void superio_select(int ld) static void superio_exit(void) { - outb_p(0xAA, WDT_EFER); /* Leave extended function mode */ + outb_p(wdt_cfg_leave, WDT_EFER); /* Leave extended function mode */ release_region(wdt_io, 2); } @@ -430,6 +433,32 @@ static int wdt_find(int addr) return ret; } +/* + * On some systems, the NCT6791D comes with a companion chip and the + * watchdog function is in this companion chip. We must use a different + * unlocking sequence to access the companion chip. + */ +static int __init wdt_use_alt_key(const struct dmi_system_id *d) +{ + wdt_cfg_enter = 0x88; + wdt_cfg_leave = 0xBB; + + return 0; +} + +static const struct dmi_system_id wdt_dmi_table[] __initconst = { + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "INVES"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CTS"), + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "INVES"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "SHARKBAY"), + }, + .callback = wdt_use_alt_key, + }, + {} +}; + static int __init wdt_init(void) { int ret; @@ -459,6 +488,9 @@ static int __init wdt_init(void) "NCT6102", }; + /* Apply system-specific quirks */ + dmi_check_system(wdt_dmi_table); + wdt_io = 0x2e; chip = wdt_find(0x2e); if (chip < 0) { -- cgit v1.2.3 From 94d6b80c45d3f436d993aa026aa080866cb4b87e Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Wed, 5 Dec 2018 17:42:21 -0700 Subject: watchdog/hpwdt: Exclude via blacklist Instead of having explicit if statments excluding devices, use a pci_device_id table of devices to blacklist. Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 93562304f7aa..eecd014ccd5b 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -50,6 +50,10 @@ static const struct pci_device_id hpwdt_devices[] = { }; MODULE_DEVICE_TABLE(pci, hpwdt_devices); +static const struct pci_device_id hpwdt_blacklist[] = { + { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP, 0x1979) }, /* auxilary iLO */ + {0}, /* terminate list */ +}; /* * Watchdog operations @@ -274,12 +278,10 @@ static int hpwdt_init_one(struct pci_dev *dev, return -ENODEV; } - /* - * Ignore all auxilary iLO devices with the following PCI ID - */ - if (dev->subsystem_vendor == PCI_VENDOR_ID_HP && - dev->subsystem_device == 0x1979) + if (pci_match_id(hpwdt_blacklist, dev)) { + dev_dbg(&dev->dev, "Not supported on this device\n"); return -ENODEV; + } if (pci_enable_device(dev)) { dev_warn(&dev->dev, -- cgit v1.2.3 From de2cb0cc300ea9bdb7dee476d24c2b20d469c3f2 Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Wed, 5 Dec 2018 17:42:22 -0700 Subject: watchdog/hpwdt: Do not claim unsupported hardware Do not claim when SSID 0x0289 as the watchdog features are not enabled/validated by the firmware. Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index eecd014ccd5b..c8e805589351 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -52,6 +52,7 @@ MODULE_DEVICE_TABLE(pci, hpwdt_devices); static const struct pci_device_id hpwdt_blacklist[] = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP, 0x1979) }, /* auxilary iLO */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP_3PAR, 0x0289) }, /* CL */ {0}, /* terminate list */ }; -- cgit v1.2.3 From 437a3f8ea493ba9b80c9bb983e15f4297fc653de Mon Sep 17 00:00:00 2001 From: Jerry Hoemann Date: Wed, 5 Dec 2018 17:42:23 -0700 Subject: watchdog/hpwdt: Update driver version. Bump version number to reflect recent minor changes. Signed-off-by: Jerry Hoemann Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index c8e805589351..ef30c7e9728d 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -26,7 +26,7 @@ #include #include -#define HPWDT_VERSION "2.0.1" +#define HPWDT_VERSION "2.0.2" #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) -- cgit v1.2.3 From b1bbb0cb2c0ee6dccaf341f99dad9bdff5882acd Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 29 Nov 2018 23:25:00 +0000 Subject: watchdog: asm9260_wdt: make array mode_name static, shrinks object size Don't populate the const array mode_name on the stack but instead make it static. Makes the object code smaller by 41 bytes: Before: text data bss dec hex filename 7699 1872 0 9571 2563 drivers/watchdog/asm9260_wdt.o After: text data bss dec hex filename 7594 1936 0 9530 253a drivers/watchdog/asm9260_wdt.o (gcc version 8.2.0 x86_64) Signed-off-by: Colin Ian King Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/asm9260_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/asm9260_wdt.c b/drivers/watchdog/asm9260_wdt.c index 2cf56b459d84..9768e44ffeb8 100644 --- a/drivers/watchdog/asm9260_wdt.c +++ b/drivers/watchdog/asm9260_wdt.c @@ -278,7 +278,7 @@ static int asm9260_wdt_probe(struct platform_device *pdev) struct watchdog_device *wdd; struct resource *res; int ret; - const char * const mode_name[] = { "hw", "sw", "debug", }; + static const char * const mode_name[] = { "hw", "sw", "debug", }; priv = devm_kzalloc(&pdev->dev, sizeof(struct asm9260_wdt_priv), GFP_KERNEL); -- cgit v1.2.3 From 57808f448b3d2214df4cfa5ab046e09da2908cde Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 1 Dec 2018 09:51:39 -0500 Subject: watchdog: bcm281xx: convert to DEFINE_SHOW_ATTRIBUTE Use DEFINE_SHOW_ATTRIBUTE macro to simplify the code. Signed-off-by: Yangtao Li Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/bcm_kona_wdt.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c index 1462be9e6fc5..4249b47902bd 100644 --- a/drivers/watchdog/bcm_kona_wdt.c +++ b/drivers/watchdog/bcm_kona_wdt.c @@ -90,7 +90,7 @@ static int secure_register_read(struct bcm_kona_wdt *wdt, uint32_t offset) #ifdef CONFIG_BCM_KONA_WDT_DEBUG -static int bcm_kona_wdt_dbg_show(struct seq_file *s, void *data) +static int bcm_kona_show(struct seq_file *s, void *data) { int ctl_val, cur_val; unsigned long flags; @@ -130,17 +130,7 @@ static int bcm_kona_wdt_dbg_show(struct seq_file *s, void *data) return 0; } -static int bcm_kona_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, bcm_kona_wdt_dbg_show, inode->i_private); -} - -static const struct file_operations bcm_kona_dbg_operations = { - .open = bcm_kona_dbg_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(bcm_kona); static void bcm_kona_wdt_debug_init(struct platform_device *pdev) { @@ -157,7 +147,7 @@ static void bcm_kona_wdt_debug_init(struct platform_device *pdev) return; if (debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt, - &bcm_kona_dbg_operations)) + &bcm_kona_fops)) wdt->debugfs = dir; else debugfs_remove_recursive(dir); -- cgit v1.2.3 From 248e655b45ed2ce98aee9de439616fdd2b78b0f5 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 1 Dec 2018 09:51:40 -0500 Subject: watchdog: ie6xx_wdt: convert to DEFINE_SHOW_ATTRIBUTE Use DEFINE_SHOW_ATTRIBUTE macro to simplify the code. Signed-off-by: Yangtao Li Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/ie6xx_wdt.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/ie6xx_wdt.c b/drivers/watchdog/ie6xx_wdt.c index 78c2541f5d52..8de9fb1ed371 100644 --- a/drivers/watchdog/ie6xx_wdt.c +++ b/drivers/watchdog/ie6xx_wdt.c @@ -193,7 +193,7 @@ static struct watchdog_device ie6xx_wdt_dev = { #ifdef CONFIG_DEBUG_FS -static int ie6xx_wdt_dbg_show(struct seq_file *s, void *unused) +static int ie6xx_wdt_show(struct seq_file *s, void *unused) { seq_printf(s, "PV1 = 0x%08x\n", inl(ie6xx_wdt_data.sch_wdtba + PV1)); @@ -212,23 +212,13 @@ static int ie6xx_wdt_dbg_show(struct seq_file *s, void *unused) return 0; } -static int ie6xx_wdt_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, ie6xx_wdt_dbg_show, NULL); -} - -static const struct file_operations ie6xx_wdt_dbg_operations = { - .open = ie6xx_wdt_dbg_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(ie6xx_wdt); static void ie6xx_wdt_debugfs_init(void) { /* /sys/kernel/debug/ie6xx_wdt */ ie6xx_wdt_data.debugfs = debugfs_create_file("ie6xx_wdt", - S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_dbg_operations); + S_IFREG | S_IRUGO, NULL, NULL, &ie6xx_wdt_fops); } static void ie6xx_wdt_debugfs_exit(void) -- cgit v1.2.3 From 9077123c68074619177c9a8d3adce2527bd94179 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 4 Dec 2018 13:01:46 +0100 Subject: watchdog: renesas_wdt: don't keep timer value during suspend/resume After discussing this mail thread [1] again, we concluded that giving userspace enough time to prepare is our favourite option. So, do not keep the time value when suspended but reset it when resuming. [1] https://patchwork.kernel.org/patch/10252209/ Signed-off-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Reviewed-by: Guenter Roeck Reviewed-by: Fabrizio Castro Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/renesas_wdt.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/renesas_wdt.c b/drivers/watchdog/renesas_wdt.c index c450e23e24a8..622ede529912 100644 --- a/drivers/watchdog/renesas_wdt.c +++ b/drivers/watchdog/renesas_wdt.c @@ -48,7 +48,6 @@ struct rwdt_priv { void __iomem *base; struct watchdog_device wdev; unsigned long clk_rate; - u16 time_left; u8 cks; }; @@ -268,10 +267,9 @@ static int __maybe_unused rwdt_suspend(struct device *dev) { struct rwdt_priv *priv = dev_get_drvdata(dev); - if (watchdog_active(&priv->wdev)) { - priv->time_left = readw(priv->base + RWTCNT); + if (watchdog_active(&priv->wdev)) rwdt_stop(&priv->wdev); - } + return 0; } @@ -279,10 +277,9 @@ static int __maybe_unused rwdt_resume(struct device *dev) { struct rwdt_priv *priv = dev_get_drvdata(dev); - if (watchdog_active(&priv->wdev)) { + if (watchdog_active(&priv->wdev)) rwdt_start(&priv->wdev); - rwdt_write(priv, priv->time_left, RWTCNT); - } + return 0; } -- cgit v1.2.3 From 969c0acc039f77c6b9d000ccb8b9d3afca4d3667 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Fri, 23 Nov 2018 09:44:36 +0100 Subject: watchdog: Add pm8916 watchdog driver The PM816 module is a versatile PMIC with many diverse functions integrated, including, a watchdog. This watchdog is subcomponent of the PON (Power On) peripheral, in the same way as pwrkey/resin buttons. It works with two timers (2-stages), the first one generates an IRQ to the main SoC (APQ8016/MSM8916), the second one performs the reset. This driver expects the following device hierarchy: [pm8916]->[pm8916-pon]->[pm8916-wdt] It uses the pm8916 regmap to access PM8916 registers. Signed-off-by: Loic Poulain Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 8 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/pm8916_wdt.c | 211 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 drivers/watchdog/pm8916_wdt.c (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 746759ec8960..6dcd5603a3e4 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -847,6 +847,14 @@ config SPRD_WATCHDOG Say Y here to include watchdog timer supported by Spreadtrum system. +config PM8916_WATCHDOG + tristate "QCOM PM8916 pmic watchdog" + depends on OF && MFD_SPMI_PMIC + select WATCHDOG_CORE + help + Say Y here to include support watchdog timer embedded into the + pm8916 module. + # X86 (i386 + ia64 + x86_64) Architecture config ACQUIRE_WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index f69cdff5ad7f..cc90e723135e 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -92,6 +92,7 @@ obj-$(CONFIG_STM32_WATCHDOG) += stm32_iwdg.o obj-$(CONFIG_UNIPHIER_WATCHDOG) += uniphier_wdt.o obj-$(CONFIG_RTD119X_WATCHDOG) += rtd119x_wdt.o obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o +obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o # X86 (i386 + ia64 + x86_64) Architecture obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o diff --git a/drivers/watchdog/pm8916_wdt.c b/drivers/watchdog/pm8916_wdt.c new file mode 100644 index 000000000000..7f10041fcf5b --- /dev/null +++ b/drivers/watchdog/pm8916_wdt.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PON_INT_RT_STS 0x10 +#define PMIC_WD_BARK_STS_BIT BIT(6) + +#define PON_PMIC_WD_RESET_S1_TIMER 0x54 +#define PON_PMIC_WD_RESET_S2_TIMER 0x55 + +#define PON_PMIC_WD_RESET_S2_CTL 0x56 +#define RESET_TYPE_WARM 0x01 +#define RESET_TYPE_SHUTDOWN 0x04 +#define RESET_TYPE_HARD 0x07 + +#define PON_PMIC_WD_RESET_S2_CTL2 0x57 +#define S2_RESET_EN_BIT BIT(7) + +#define PON_PMIC_WD_RESET_PET 0x58 +#define WATCHDOG_PET_BIT BIT(0) + +#define PM8916_WDT_DEFAULT_TIMEOUT 32 +#define PM8916_WDT_MIN_TIMEOUT 1 +#define PM8916_WDT_MAX_TIMEOUT 127 + +struct pm8916_wdt { + struct regmap *regmap; + struct watchdog_device wdev; + u32 baseaddr; +}; + +static int pm8916_wdt_start(struct watchdog_device *wdev) +{ + struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev); + + return regmap_update_bits(wdt->regmap, + wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL2, + S2_RESET_EN_BIT, S2_RESET_EN_BIT); +} + +static int pm8916_wdt_stop(struct watchdog_device *wdev) +{ + struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev); + + return regmap_update_bits(wdt->regmap, + wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL2, + S2_RESET_EN_BIT, 0); +} + +static int pm8916_wdt_ping(struct watchdog_device *wdev) +{ + struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev); + + return regmap_update_bits(wdt->regmap, + wdt->baseaddr + PON_PMIC_WD_RESET_PET, + WATCHDOG_PET_BIT, WATCHDOG_PET_BIT); +} + +static int pm8916_wdt_configure_timers(struct watchdog_device *wdev) +{ + struct pm8916_wdt *wdt = watchdog_get_drvdata(wdev); + int err; + + err = regmap_write(wdt->regmap, + wdt->baseaddr + PON_PMIC_WD_RESET_S1_TIMER, + wdev->timeout - wdev->pretimeout); + if (err) + return err; + + return regmap_write(wdt->regmap, + wdt->baseaddr + PON_PMIC_WD_RESET_S2_TIMER, + wdev->pretimeout); +} + +static int pm8916_wdt_set_timeout(struct watchdog_device *wdev, + unsigned int timeout) +{ + wdev->timeout = timeout; + + return pm8916_wdt_configure_timers(wdev); +} + +static int pm8916_wdt_set_pretimeout(struct watchdog_device *wdev, + unsigned int pretimeout) +{ + wdev->pretimeout = pretimeout; + + return pm8916_wdt_configure_timers(wdev); +} + +static irqreturn_t pm8916_wdt_isr(int irq, void *arg) +{ + struct pm8916_wdt *wdt = arg; + int err, sts; + + err = regmap_read(wdt->regmap, wdt->baseaddr + PON_INT_RT_STS, &sts); + if (err) + return IRQ_HANDLED; + + if (sts & PMIC_WD_BARK_STS_BIT) + watchdog_notify_pretimeout(&wdt->wdev); + + return IRQ_HANDLED; +} + +static const struct watchdog_info pm8916_wdt_ident = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, + .identity = "QCOM PM8916 PON WDT", +}; + +static const struct watchdog_info pm8916_wdt_pt_ident = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | + WDIOF_PRETIMEOUT, + .identity = "QCOM PM8916 PON WDT", +}; + +static const struct watchdog_ops pm8916_wdt_ops = { + .owner = THIS_MODULE, + .start = pm8916_wdt_start, + .stop = pm8916_wdt_stop, + .ping = pm8916_wdt_ping, + .set_timeout = pm8916_wdt_set_timeout, + .set_pretimeout = pm8916_wdt_set_pretimeout, +}; + +static int pm8916_wdt_probe(struct platform_device *pdev) +{ + struct pm8916_wdt *wdt; + struct device *parent; + int err, irq; + + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + parent = pdev->dev.parent; + + /* + * The pm8916-pon-wdt is a child of the pon device, which is a child + * of the pm8916 mfd device. We want access to the pm8916 registers. + * Retrieve regmap from pm8916 (parent->parent) and base address + * from pm8916-pon (pon). + */ + wdt->regmap = dev_get_regmap(parent->parent, NULL); + if (!wdt->regmap) { + dev_err(&pdev->dev, "failed to locate regmap\n"); + return -ENODEV; + } + + err = device_property_read_u32(parent, "reg", &wdt->baseaddr); + if (err) { + dev_err(&pdev->dev, "failed to get pm8916-pon address\n"); + return err; + } + + irq = platform_get_irq(pdev, 0); + if (irq > 0) { + if (devm_request_irq(&pdev->dev, irq, pm8916_wdt_isr, 0, + "pm8916_wdt", wdt)) + irq = 0; + } + + /* Configure watchdog to hard-reset mode */ + err = regmap_write(wdt->regmap, + wdt->baseaddr + PON_PMIC_WD_RESET_S2_CTL, + RESET_TYPE_HARD); + if (err) { + dev_err(&pdev->dev, "failed configure watchdog\n"); + return err; + } + + wdt->wdev.info = (irq > 0) ? &pm8916_wdt_pt_ident : &pm8916_wdt_ident, + wdt->wdev.ops = &pm8916_wdt_ops, + wdt->wdev.parent = &pdev->dev; + wdt->wdev.min_timeout = PM8916_WDT_MIN_TIMEOUT; + wdt->wdev.max_timeout = PM8916_WDT_MAX_TIMEOUT; + wdt->wdev.timeout = PM8916_WDT_DEFAULT_TIMEOUT; + wdt->wdev.pretimeout = 0; + watchdog_set_drvdata(&wdt->wdev, wdt); + + watchdog_init_timeout(&wdt->wdev, 0, &pdev->dev); + pm8916_wdt_configure_timers(&wdt->wdev); + + return devm_watchdog_register_device(&pdev->dev, &wdt->wdev); +} + +static const struct of_device_id pm8916_wdt_id_table[] = { + { .compatible = "qcom,pm8916-wdt" }, + { } +}; +MODULE_DEVICE_TABLE(of, pm8916_wdt_id_table); + +static struct platform_driver pm8916_wdt_driver = { + .probe = pm8916_wdt_probe, + .driver = { + .name = "pm8916-wdt", + .of_match_table = of_match_ptr(pm8916_wdt_id_table), + }, +}; +module_platform_driver(pm8916_wdt_driver); + +MODULE_AUTHOR("Loic Poulain "); +MODULE_DESCRIPTION("Qualcomm pm8916 watchdog driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 22ec9bb1cbcd613c73476ccd8f6a5e8c77793f66 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 2 Dec 2018 12:04:10 +0100 Subject: watchdog: mena21_wdt: Convert to GPIO descriptors This drops the old OF API use to look up global GPIO numbers and replace it with the GPIO descriptor API. Cc: Johannes Thumshirn Cc: Johannes Thumshirn Cc: Johannes Thumshirn Signed-off-by: Linus Walleij Acked-by: Johannes Thumshirn Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mena21_wdt.c | 73 +++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 37 deletions(-) (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c index 0be7f50e8ff9..6db69883ece6 100644 --- a/drivers/watchdog/mena21_wdt.c +++ b/drivers/watchdog/mena21_wdt.c @@ -13,10 +13,10 @@ #include #include #include -#include -#include +#include #include #include +#include #define NUM_GPIOS 6 @@ -31,7 +31,7 @@ enum a21_wdt_gpios { struct a21_wdt_drv { struct watchdog_device wdt; - unsigned gpios[NUM_GPIOS]; + struct gpio_desc *gpios[NUM_GPIOS]; }; static bool nowayout = WATCHDOG_NOWAYOUT; @@ -43,9 +43,9 @@ static unsigned int a21_wdt_get_bootstatus(struct a21_wdt_drv *drv) { int reset = 0; - reset |= gpio_get_value(drv->gpios[GPIO_WD_RST0]) ? (1 << 0) : 0; - reset |= gpio_get_value(drv->gpios[GPIO_WD_RST1]) ? (1 << 1) : 0; - reset |= gpio_get_value(drv->gpios[GPIO_WD_RST2]) ? (1 << 2) : 0; + reset |= gpiod_get_value(drv->gpios[GPIO_WD_RST0]) ? (1 << 0) : 0; + reset |= gpiod_get_value(drv->gpios[GPIO_WD_RST1]) ? (1 << 1) : 0; + reset |= gpiod_get_value(drv->gpios[GPIO_WD_RST2]) ? (1 << 2) : 0; return reset; } @@ -54,7 +54,7 @@ static int a21_wdt_start(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); - gpio_set_value(drv->gpios[GPIO_WD_ENAB], 1); + gpiod_set_value(drv->gpios[GPIO_WD_ENAB], 1); return 0; } @@ -63,7 +63,7 @@ static int a21_wdt_stop(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); - gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0); + gpiod_set_value(drv->gpios[GPIO_WD_ENAB], 0); return 0; } @@ -72,9 +72,9 @@ static int a21_wdt_ping(struct watchdog_device *wdt) { struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); - gpio_set_value(drv->gpios[GPIO_WD_TRIG], 0); + gpiod_set_value(drv->gpios[GPIO_WD_TRIG], 0); ndelay(10); - gpio_set_value(drv->gpios[GPIO_WD_TRIG], 1); + gpiod_set_value(drv->gpios[GPIO_WD_TRIG], 1); return 0; } @@ -96,9 +96,9 @@ static int a21_wdt_set_timeout(struct watchdog_device *wdt, } if (timeout == 1) - gpio_set_value(drv->gpios[GPIO_WD_FAST], 1); + gpiod_set_value(drv->gpios[GPIO_WD_FAST], 1); else - gpio_set_value(drv->gpios[GPIO_WD_FAST], 0); + gpiod_set_value(drv->gpios[GPIO_WD_FAST], 0); wdt->timeout = timeout; @@ -127,7 +127,6 @@ static struct watchdog_device a21_wdt = { static int a21_wdt_probe(struct platform_device *pdev) { - struct device_node *node; struct a21_wdt_drv *drv; unsigned int reset = 0; int num_gpios; @@ -138,40 +137,40 @@ static int a21_wdt_probe(struct platform_device *pdev) if (!drv) return -ENOMEM; - /* Fill GPIO pin array */ - node = pdev->dev.of_node; - - num_gpios = of_gpio_count(node); + num_gpios = gpiod_count(&pdev->dev, NULL); if (num_gpios != NUM_GPIOS) { dev_err(&pdev->dev, "gpios DT property wrong, got %d want %d", num_gpios, NUM_GPIOS); return -ENODEV; } - for (i = 0; i < num_gpios; i++) { - int val; - - val = of_get_gpio(node, i); - if (val < 0) - return val; - - drv->gpios[i] = val; - } - /* Request the used GPIOs */ for (i = 0; i < num_gpios; i++) { - ret = devm_gpio_request(&pdev->dev, drv->gpios[i], - "MEN A21 Watchdog"); - if (ret) - return ret; + enum gpiod_flags gflags; if (i < GPIO_WD_RST0) - ret = gpio_direction_output(drv->gpios[i], - gpio_get_value(drv->gpios[i])); - else /* GPIO_WD_RST[0..2] are inputs */ - ret = gpio_direction_input(drv->gpios[i]); - if (ret) + gflags = GPIOD_ASIS; + else + gflags = GPIOD_IN; + drv->gpios[i] = devm_gpiod_get_index(&pdev->dev, NULL, i, + gflags); + if (IS_ERR(drv->gpios[i])) { + ret = PTR_ERR(drv->gpios[i]); return ret; + } + + gpiod_set_consumer_name(drv->gpios[i], "MEN A21 Watchdog"); + + /* + * Retrieve the initial value from the GPIOs that should be + * output, then set up the line as output with that value. + */ + if (i < GPIO_WD_RST0) { + int val; + + val = gpiod_get_value(drv->gpios[i]); + gpiod_direction_output(drv->gpios[i], val); + } } watchdog_init_timeout(&a21_wdt, 30, &pdev->dev); @@ -207,7 +206,7 @@ static void a21_wdt_shutdown(struct platform_device *pdev) { struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev); - gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0); + gpiod_set_value(drv->gpios[GPIO_WD_ENAB], 0); } static const struct of_device_id a21_wdt_ids[] = { -- cgit v1.2.3 From d2b911db8b73bc6bfa163515b4ff142fb0dda66d Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 22 Dec 2018 11:12:31 +0100 Subject: watchdog: mtx-1: Convert to use GPIO descriptor This converts the MTX-1 driver to grab a GPIO descriptor associated with the device instead of using a resource with a global GPIO number. Augment the driver and the boardfile. Cc: Ralf Baechle Cc: Paul Burton Cc: James Hogan Cc: linux-mips@linux-mips.org Cc: Florian Fainelli Reviewed-by: Florian Fainelli Signed-off-by: Linus Walleij Acked-by: Paul Burton Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- arch/mips/alchemy/board-mtx1.c | 18 +++++++++--------- drivers/watchdog/mtx-1_wdt.c | 19 +++++++++---------- 2 files changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers/watchdog') diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c index d625e6f99ae7..9d9d4ee31605 100644 --- a/arch/mips/alchemy/board-mtx1.c +++ b/arch/mips/alchemy/board-mtx1.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -130,20 +131,18 @@ static struct platform_device mtx1_button = { } }; -static struct resource mtx1_wdt_res[] = { - [0] = { - .start = 215, - .end = 215, - .name = "mtx1-wdt-gpio", - .flags = IORESOURCE_IRQ, - } +static struct gpiod_lookup_table mtx1_wdt_gpio_table = { + .dev_id = "mtx1-wdt.0", + .table = { + /* Global number 215 is offset 15 on Alchemy GPIO 2 */ + GPIO_LOOKUP("alchemy-gpio2", 15, NULL, GPIO_ACTIVE_HIGH), + { }, + }, }; static struct platform_device mtx1_wdt = { .name = "mtx1-wdt", .id = 0, - .num_resources = ARRAY_SIZE(mtx1_wdt_res), - .resource = mtx1_wdt_res, }; static const struct gpio_led default_leds[] = { @@ -310,6 +309,7 @@ static int __init mtx1_register_devices(void) } gpio_direction_input(mtx1_gpio_button[0].gpio); out: + gpiod_add_lookup_table(&mtx1_wdt_gpio_table); return platform_add_devices(mtx1_devs, ARRAY_SIZE(mtx1_devs)); } arch_initcall(mtx1_register_devices); diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index 1fa7d2b32494..e028e0a2eca0 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include @@ -55,7 +55,7 @@ static struct { int queue; int default_ticks; unsigned long inuse; - unsigned gpio; + struct gpio_desc *gpiod; unsigned int gstate; } mtx1_wdt_device; @@ -67,7 +67,7 @@ static void mtx1_wdt_trigger(struct timer_list *unused) /* toggle wdt gpio */ mtx1_wdt_device.gstate = !mtx1_wdt_device.gstate; - gpio_set_value(mtx1_wdt_device.gpio, mtx1_wdt_device.gstate); + gpiod_set_value(mtx1_wdt_device.gpiod, mtx1_wdt_device.gstate); if (mtx1_wdt_device.queue && ticks) mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); @@ -90,7 +90,7 @@ static void mtx1_wdt_start(void) if (!mtx1_wdt_device.queue) { mtx1_wdt_device.queue = 1; mtx1_wdt_device.gstate = 1; - gpio_set_value(mtx1_wdt_device.gpio, 1); + gpiod_set_value(mtx1_wdt_device.gpiod, 1); mod_timer(&mtx1_wdt_device.timer, jiffies + MTX1_WDT_INTERVAL); } mtx1_wdt_device.running++; @@ -105,7 +105,7 @@ static int mtx1_wdt_stop(void) if (mtx1_wdt_device.queue) { mtx1_wdt_device.queue = 0; mtx1_wdt_device.gstate = 0; - gpio_set_value(mtx1_wdt_device.gpio, 0); + gpiod_set_value(mtx1_wdt_device.gpiod, 0); } ticks = mtx1_wdt_device.default_ticks; spin_unlock_irqrestore(&mtx1_wdt_device.lock, flags); @@ -198,12 +198,11 @@ static int mtx1_wdt_probe(struct platform_device *pdev) { int ret; - mtx1_wdt_device.gpio = pdev->resource[0].start; - ret = devm_gpio_request_one(&pdev->dev, mtx1_wdt_device.gpio, - GPIOF_OUT_INIT_HIGH, "mtx1-wdt"); - if (ret < 0) { + mtx1_wdt_device.gpiod = devm_gpiod_get(&pdev->dev, + NULL, GPIOD_OUT_HIGH); + if (IS_ERR(mtx1_wdt_device.gpiod)) { dev_err(&pdev->dev, "failed to request gpio"); - return ret; + return PTR_ERR(mtx1_wdt_device.gpiod); } spin_lock_init(&mtx1_wdt_device.lock); -- cgit v1.2.3 From e3c21e088f8936a004a3d9f2f4e14b3f2bdd6ea9 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Wed, 19 Dec 2018 16:18:20 +0100 Subject: watchdog: tqmx86: Add watchdog driver for the IO controller Some TQ-Systems ComExpress modules have an IO controller with a watchdog timer. Signed-off-by: Andrew Lunn Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 12 ++++ drivers/watchdog/Makefile | 1 + drivers/watchdog/tqmx86_wdt.c | 126 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 drivers/watchdog/tqmx86_wdt.c (limited to 'drivers/watchdog') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 6dcd5603a3e4..57f017d74a97 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1316,6 +1316,18 @@ config SMSC37B787_WDT Most people will say N. +config TQMX86_WDT + tristate "TQ-Systems TQMX86 Watchdog Timer" + depends on X86 + help + This is the driver for the hardware watchdog timer in the TQMX86 IO + controller found on some of their ComExpress Modules. + + To compile this driver as a module, choose M here; the module + will be called tqmx86_wdt. + + Most people will say N. + config VIA_WDT tristate "VIA Watchdog Timer" depends on X86 && PCI diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index cc90e723135e..a0917ef28e07 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -130,6 +130,7 @@ obj-$(CONFIG_SBC7240_WDT) += sbc7240_wdt.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o obj-$(CONFIG_SMSC_SCH311X_WDT) += sch311x_wdt.o obj-$(CONFIG_SMSC37B787_WDT) += smsc37b787_wdt.o +obj-$(CONFIG_TQMX86_WDT) += tqmx86_wdt.o obj-$(CONFIG_VIA_WDT) += via_wdt.o obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o diff --git a/drivers/watchdog/tqmx86_wdt.c b/drivers/watchdog/tqmx86_wdt.c new file mode 100644 index 000000000000..0d3a0fbbd7a5 --- /dev/null +++ b/drivers/watchdog/tqmx86_wdt.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for TQMx86 PLD. + * + * The watchdog supports power of 2 timeouts from 1 to 4096sec. + * Once started, it cannot be stopped. + * + * Based on the vendor code written by Vadim V.Vlasov + * + */ + +#include +#include +#include +#include +#include +#include + +/* default timeout (secs) */ +#define WDT_TIMEOUT 32 + +static unsigned int timeout; +module_param(timeout, uint, 0); +MODULE_PARM_DESC(timeout, + "Watchdog timeout in seconds. (1<=timeout<=4096, default=" + __MODULE_STRING(WDT_TIMEOUT) ")"); +struct tqmx86_wdt { + struct watchdog_device wdd; + void __iomem *io_base; +}; + +#define TQMX86_WDCFG 0x00 /* Watchdog Configuration Register */ +#define TQMX86_WDCS 0x01 /* Watchdog Config/Status Register */ + +static int tqmx86_wdt_start(struct watchdog_device *wdd) +{ + struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd); + + iowrite8(0x81, priv->io_base + TQMX86_WDCS); + + return 0; +} + +static int tqmx86_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) +{ + struct tqmx86_wdt *priv = watchdog_get_drvdata(wdd); + u8 val; + + t = roundup_pow_of_two(t); + val = ilog2(t) | 0x90; + val += 3; /* values 0,1,2 correspond to 0.125,0.25,0.5s timeouts */ + iowrite8(val, priv->io_base + TQMX86_WDCFG); + + wdd->timeout = t; + + return 0; +} + +static const struct watchdog_info tqmx86_wdt_info = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING, + .identity = "TQMx86 Watchdog", +}; + +static struct watchdog_ops tqmx86_wdt_ops = { + .owner = THIS_MODULE, + .start = tqmx86_wdt_start, + .set_timeout = tqmx86_wdt_set_timeout, +}; + +static int tqmx86_wdt_probe(struct platform_device *pdev) +{ + struct tqmx86_wdt *priv; + struct resource *res; + int err; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + + priv->io_base = devm_ioport_map(&pdev->dev, res->start, + resource_size(res)); + if (IS_ERR(priv->io_base)) + return PTR_ERR(priv->io_base); + + watchdog_set_drvdata(&priv->wdd, priv); + + priv->wdd.parent = &pdev->dev; + priv->wdd.info = &tqmx86_wdt_info; + priv->wdd.ops = &tqmx86_wdt_ops; + priv->wdd.min_timeout = 1; + priv->wdd.max_timeout = 4096; + priv->wdd.max_hw_heartbeat_ms = 4096*1000; + priv->wdd.timeout = WDT_TIMEOUT; + + watchdog_init_timeout(&priv->wdd, timeout, &pdev->dev); + watchdog_set_nowayout(&priv->wdd, WATCHDOG_NOWAYOUT); + + tqmx86_wdt_set_timeout(&priv->wdd, priv->wdd.timeout); + + err = devm_watchdog_register_device(&pdev->dev, &priv->wdd); + if (err) + return err; + + dev_info(&pdev->dev, "TQMx86 watchdog\n"); + + return 0; +} + +static struct platform_driver tqmx86_wdt_driver = { + .driver = { + .name = "tqmx86-wdt", + }, + .probe = tqmx86_wdt_probe, +}; + +module_platform_driver(tqmx86_wdt_driver); + +MODULE_AUTHOR("Andrew Lunn "); +MODULE_DESCRIPTION("TQMx86 Watchdog"); +MODULE_ALIAS("platform:tqmx86-wdt"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3