Merge tag 'linux-watchdog-4.21-rc1' of git://www.linux-watchdog.org/linux-watchdog
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 1 Jan 2019 21:16:45 +0000 (13:16 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 1 Jan 2019 21:16:45 +0000 (13:16 -0800)
Pull watchdog updates from Wim Van Sebroeck:
 - add TQ-Systems TQMX86 watchdog driver
 - add Qualcomm PM8916 watchdog driver
 - w83627hf_wdt: add quirk for Inves system
 - renesas_wdt: several improvements and document r8a774c0 support
 - mena21_wdt, mtx-1: Convert to use GPIO descriptor
 - bcm281xx, ie6xx_wdt: convert to DEFINE_SHOW_ATTRIBUTE
 - documentation: add PM usage and kernel-api: don't reference removed functions
 - update bindings for MT7629 SoC
 - several small fixes

* tag 'linux-watchdog-4.21-rc1' of git://www.linux-watchdog.org/linux-watchdog: (22 commits)
  watchdog: tqmx86: Add watchdog driver for the IO controller
  dt-bindings: watchdog: renesas-wdt: Document r8a774c0 support
  watchdog: docs: kernel-api: don't reference removed functions
  watchdog: add documentation for PM usage
  watchdog: mtx-1: Convert to use GPIO descriptor
  watchdog: mena21_wdt: Convert to GPIO descriptors
  dt-bindings: watchdog: Add Qualcomm PM8916 watchdog
  watchdog: Add pm8916 watchdog driver
  dt-bindings: watchdog: update bindings for MT7629 SoC
  watchdog: renesas_wdt: don't keep timer value during suspend/resume
  watchdog: ie6xx_wdt: convert to DEFINE_SHOW_ATTRIBUTE
  watchdog: bcm281xx: convert to DEFINE_SHOW_ATTRIBUTE
  watchdog: asm9260_wdt: make array mode_name static, shrinks object size
  watchdog/hpwdt: Update driver version.
  watchdog/hpwdt: Do not claim unsupported hardware
  watchdog/hpwdt: Exclude via blacklist
  Watchdog: remove outdated comment
  watchdog: w83627hf_wdt: Add quirk for Inves system
  watchdog: cpwd: add of_node_put()
  watchdog: renesas_wdt: don't set divider while watchdog is running
  ...

20 files changed:
Documentation/devicetree/bindings/watchdog/mtk-wdt.txt
Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/renesas-wdt.txt
Documentation/watchdog/watchdog-kernel-api.txt
Documentation/watchdog/watchdog-pm.txt [new file with mode: 0644]
arch/mips/alchemy/board-mtx1.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/asm9260_wdt.c
drivers/watchdog/bcm_kona_wdt.c
drivers/watchdog/cpwd.c
drivers/watchdog/hpwdt.c
drivers/watchdog/ie6xx_wdt.c
drivers/watchdog/mena21_wdt.c
drivers/watchdog/mtx-1_wdt.c
drivers/watchdog/pm8916_wdt.c [new file with mode: 0644]
drivers/watchdog/renesas_wdt.c
drivers/watchdog/tqmx86_wdt.c [new file with mode: 0644]
drivers/watchdog/w83627hf_wdt.c
include/linux/watchdog.h

index 859dee167b9140970942fe08a5b1fca760f4f96f..8682d6a93e5b7ef74e358a8e118e4dcceab1f254 100644 (file)
@@ -8,6 +8,7 @@ Required properties:
        "mediatek,mt6797-wdt", "mediatek,mt6589-wdt": for MT6797
        "mediatek,mt7622-wdt", "mediatek,mt6589-wdt": for MT7622
        "mediatek,mt7623-wdt", "mediatek,mt6589-wdt": for MT7623
+       "mediatek,mt7629-wdt", "mediatek,mt6589-wdt": for MT7629
 
 - reg : Specifies base physical address and size of the registers.
 
diff --git a/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.txt b/Documentation/devicetree/bindings/watchdog/qcom,pm8916-wdt.txt
new file mode 100644 (file)
index 0000000..6fb984f
--- /dev/null
@@ -0,0 +1,28 @@
+QCOM PM8916 watchdog timer controller
+
+This pm8916 watchdog timer controller must be under pm8916-pon node.
+
+Required properties:
+- compatible: should be "qcom,pm8916-wdt"
+
+Optional properties :
+- interrupts : Watchdog pre-timeout (bark) interrupt.
+- timeout-sec : Watchdog timeout value in seconds.
+
+Example:
+
+       pm8916_0: pm8916@0 {
+               compatible = "qcom,pm8916", "qcom,spmi-pmic";
+               reg = <0x0 SPMI_USID>;
+
+               pon@800 {
+                       compatible = "qcom,pm8916-pon";
+                       reg = <0x800>;
+
+                       watchdog {
+                               compatible = "qcom,pm8916-wdt";
+                               interrupts = <0x0 0x8 6 IRQ_TYPE_EDGE_RISING>;
+                               timeout-sec = <10>;
+                       };
+               };
+       };
index a8ee29fd9ac811fac7550047d424c8191d3be6f0..ef2b97b72e082a0557a817b1d91a3978fd138b71 100644 (file)
@@ -9,6 +9,7 @@ Required properties:
                 - "renesas,r8a7744-wdt" (RZ/G1N)
                 - "renesas,r8a7745-wdt" (RZ/G1E)
                 - "renesas,r8a774a1-wdt" (RZ/G2M)
+                - "renesas,r8a774c0-wdt" (RZ/G2E)
                 - "renesas,r8a7790-wdt" (R-Car H2)
                 - "renesas,r8a7791-wdt" (R-Car M2-W)
                 - "renesas,r8a7792-wdt" (R-Car V2H)
index 9b93953f69cf866289fd8e49632860185bda1e6c..3a91ef5af04411ec6699653545c15bae1939b3c1 100644 (file)
@@ -128,8 +128,6 @@ struct watchdog_ops {
        int (*set_pretimeout)(struct watchdog_device *, unsigned int);
        unsigned int (*get_timeleft)(struct watchdog_device *);
        int (*restart)(struct watchdog_device *);
-       void (*ref)(struct watchdog_device *) __deprecated;
-       void (*unref)(struct watchdog_device *) __deprecated;
        long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
 };
 
@@ -218,8 +216,6 @@ they are supported. These optional routines/operations are:
   if a command is not supported. The parameters that are passed to the ioctl
   call are: watchdog_device, cmd and arg.
 
-The 'ref' and 'unref' operations are no longer used and deprecated.
-
 The status bits should (preferably) be set with the set_bit and clear_bit alike
 bit-operations. The status bits that are defined are:
 * WDOG_ACTIVE: this status bit indicates whether or not a watchdog timer device
diff --git a/Documentation/watchdog/watchdog-pm.txt b/Documentation/watchdog/watchdog-pm.txt
new file mode 100644 (file)
index 0000000..7a4dd46
--- /dev/null
@@ -0,0 +1,19 @@
+The Linux WatchDog Timer Power Management Guide
+===============================================
+Last reviewed: 17-Dec-2018
+
+Wolfram Sang <wsa+renesas@sang-engineering.com>
+
+Introduction
+------------
+This document states rules about watchdog devices and their power management
+handling to ensure a uniform behaviour for Linux systems.
+
+
+Ping on resume
+--------------
+On resume, a watchdog timer shall be reset to its selected value to give
+userspace enough time to resume. [1] [2]
+
+[1] https://patchwork.kernel.org/patch/10252209/
+[2] https://patchwork.kernel.org/patch/10711625/
index d625e6f99ae78eefa8c3d15e105134d13f6152c9..9d9d4ee316059b7028f25bfb79462127d50a6ecb 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/gpio.h>
+#include <linux/gpio/machine.h>
 #include <linux/gpio_keys.h>
 #include <linux/input.h>
 #include <linux/mtd/partitions.h>
@@ -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);
index 2d64333f4782b9c3a8fdb2734c035239ab5fe37c..57f017d74a976de975303c4a8b639c150fb6e084 100644 (file)
@@ -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
@@ -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
@@ -1308,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
index f69cdff5ad7fbaf0d666a2d4e057553f603c11d5..a0917ef28e07488abf768a481b3680cb8a9f1516 100644 (file)
@@ -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
@@ -129,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
index 2cf56b459d84c37411a9647d5fbf92927f5091a1..9768e44ffeb8a46d136e457bfc9e9e652540ee8d 100644 (file)
@@ -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);
index 1462be9e6fc54fa4519ea31a7825637e2d24e3a5..4249b47902bd5321bf7955b3f86bb773b8c2a305 100644 (file)
@@ -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);
index aee0b25cf10d9afd48604b943fa17d97a6fe6927..32156e199c5127d890d4b54151dbf405543c8bc1 100644 (file)
@@ -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.
index 93562304f7aa4f51441154640fa3031d89234fa2..ef30c7e9728de5e4aee04477debc6bf00559a752 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/watchdog.h>
 #include <asm/nmi.h>
 
-#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)
@@ -50,6 +50,11 @@ 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 */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_HP, 0x3306, PCI_VENDOR_ID_HP_3PAR, 0x0289) },  /* CL */
+       {0},                    /* terminate list */
+};
 
 /*
  *     Watchdog operations
@@ -274,12 +279,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,
index 78c2541f5d52d31af60e239dafd417b2cabd4cc8..8de9fb1ed37109615ae14251fe9bd4026e07b919 100644 (file)
@@ -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)
index 0be7f50e8ff940d441feac339f8f106d805c91a3..6db69883ece69540839ec6da3ec5a88939019df8 100644 (file)
 #include <linux/platform_device.h>
 #include <linux/watchdog.h>
 #include <linux/uaccess.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/delay.h>
 #include <linux/bitops.h>
+#include <linux/of.h>
 
 #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[] = {
index 1fa7d2b32494c2eca854830f8c33c155ba95b290..e028e0a2eca0a6dd8a2e13b6c30d6dcefef518c6 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/uaccess.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 
 #include <asm/mach-au1x00/au1000.h>
 
@@ -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);
diff --git a/drivers/watchdog/pm8916_wdt.c b/drivers/watchdog/pm8916_wdt.c
new file mode 100644 (file)
index 0000000..7f10041
--- /dev/null
@@ -0,0 +1,211 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/watchdog.h>
+
+#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 <loic.poulain@linaro.org>");
+MODULE_DESCRIPTION("Qualcomm pm8916 watchdog driver");
+MODULE_LICENSE("GPL v2");
index 0d74c3e48979709c84a8b39823b5633ab7acae33..622ede529912f47011c42c8e30cf508fcc5a502d 100644 (file)
@@ -48,7 +48,6 @@ struct rwdt_priv {
        void __iomem *base;
        struct watchdog_device wdev;
        unsigned long clk_rate;
-       u16 time_left;
        u8 cks;
 };
 
@@ -74,12 +73,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();
@@ -220,8 +224,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);
@@ -263,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;
 }
 
@@ -274,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;
 }
 
diff --git a/drivers/watchdog/tqmx86_wdt.c b/drivers/watchdog/tqmx86_wdt.c
new file mode 100644 (file)
index 0000000..0d3a0fb
--- /dev/null
@@ -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
+ * <vvlasov@dev.rtsoft.ru>
+ */
+
+#include <linux/io.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/timer.h>
+#include <linux/watchdog.h>
+
+/* 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 <andrew@lunn.ch>");
+MODULE_DESCRIPTION("TQMx86 Watchdog");
+MODULE_ALIAS("platform:tqmx86-wdt");
+MODULE_LICENSE("GPL");
index 4b9365d4de7a9759c0ad741812b397d3aaf2d961..3a49ba9ea608388d5b77a39ddc98b6a780b473da 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/ioport.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/dmi.h>
 
 #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) {
index 44985c4a1e86214dca6579b42bda3c6d666bcdc9..417d9f37077a802d142f4826e1863b987e067a0f 100644 (file)
@@ -90,9 +90,6 @@ struct watchdog_ops {
  *
  * The driver-data field may not be accessed directly. It must be accessed
  * via the watchdog_set_drvdata and watchdog_get_drvdata helpers.
- *
- * The lock field is for watchdog core internal use only and should not be
- * touched.
  */
 struct watchdog_device {
        int id;