Merge tag 'linux-watchdog-5.19-rc1' of git://www.linux-watchdog.org/linux-watchdog
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Jun 2022 21:05:16 +0000 (14:05 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 1 Jun 2022 21:05:16 +0000 (14:05 -0700)
Pull watchdog updates from Wim Van Sebroeck:

 - Add MediaTek MT8186 support

 - Add Mediatek MT7986 reset-controller support

 - Add i.MX93 support

 - Add watchdog driver for Sunplus SP7021

 - Add SC8180X and SC8280XP compatibles

 - Add Renesas RZ/N1 Watchdog driver and support for RZ/N1

 - rzg2l_wdt improvements and fixes

 - Several other improvements and fixes

* tag 'linux-watchdog-5.19-rc1' of git://www.linux-watchdog.org/linux-watchdog: (38 commits)
  watchdog: ts4800_wdt: Fix refcount leak in ts4800_wdt_probe
  dt-bindings: watchdog: renesas,wdt: R-Car V3U is R-Car Gen4
  watchdog: Add Renesas RZ/N1 Watchdog driver
  dt-bindings: watchdog: renesas,wdt: Add support for RZ/N1
  watchdog: wdat_wdt: Stop watchdog when uninstalling module
  watchdog: wdat_wdt: Stop watchdog when rebooting the system
  watchdog: wdat_wdt: Using the existing function to check parameter timeout
  dt-bindings: watchdog: da9062: add watchdog timeout mode
  dt-bindings: watchdog: renesas,wdt: Document RZ/G2UL SoC
  watchdog: iTCO_wdt: Using existing macro define covers more scenarios
  watchdog: rti-wdt: Fix pm_runtime_get_sync() error checking
  dt-bindings: watchdog: Add SC8180X and SC8280XP compatibles
  watchdog: rti_wdt: Fix calculation and evaluation of preset heartbeat
  dt-bindings: watchdog: uniphier: Use unevaluatedProperties
  watchdog: sp805: disable watchdog on remove
  watchdog: da9063: optionally disable watchdog during suspend
  dt-bindings: mfd: da9063: watchdog: add suspend disable option
  dt-bindings: watchdog: sunxi: clarify clock support
  dt-bindings: watchdog: sunxi: fix F1C100s compatible
  watchdog: Add watchdog driver for Sunplus SP7021
  ...

26 files changed:
Documentation/devicetree/bindings/mfd/da9063.txt
Documentation/devicetree/bindings/watchdog/da9062-wdt.txt
Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt [deleted file]
Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml
Documentation/devicetree/bindings/watchdog/mtk-wdt.txt
Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml
Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml
Documentation/devicetree/bindings/watchdog/socionext,uniphier-wdt.yaml
Documentation/devicetree/bindings/watchdog/sunplus,sp7021-wdt.yaml [new file with mode: 0644]
MAINTAINERS
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/bcm7038_wdt.c
drivers/watchdog/da9063_wdt.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/mtk_wdt.c
drivers/watchdog/rti_wdt.c
drivers/watchdog/rzg2l_wdt.c
drivers/watchdog/rzn1_wdt.c [new file with mode: 0644]
drivers/watchdog/sp805_wdt.c
drivers/watchdog/sunplus_wdt.c [new file with mode: 0644]
drivers/watchdog/ts4800_wdt.c
drivers/watchdog/wdat_wdt.c
include/dt-bindings/reset/mt7986-resets.h [new file with mode: 0644]
include/dt-bindings/reset/mt8186-resets.h [new file with mode: 0644]

index 91b79a21d4039228266db308dbd7fab5ea5d32b1..aa8b800cc4ad87e1e1982c8de1e60b4262fd8eb7 100644 (file)
@@ -64,10 +64,13 @@ Sub-nodes:
     and KEY_SLEEP.
 
 - watchdog : This node defines settings for the Watchdog timer associated
-  with the DA9063 and DA9063L. There are currently no entries in this
-  binding, however compatible = "dlg,da9063-watchdog" should be added
-  if a node is created.
+  with the DA9063 and DA9063L. The node should contain the compatible property
+  with the value "dlg,da9063-watchdog".
 
+  Optional watchdog properties:
+  - dlg,use-sw-pm: Add this property to disable the watchdog during suspend.
+  Only use this option if you can't use the watchdog automatic suspend
+  function during a suspend (see register CONTROL_B).
 
 Example:
 
index 950e4fba8dbc7c013a5aac5e4c58a4aab05829e4..354314d854ef784c93232864b604154514cffd61 100644 (file)
@@ -10,6 +10,12 @@ Optional properties:
 - dlg,use-sw-pm: Add this property to disable the watchdog during suspend.
        Only use this option if you can't use the watchdog automatic suspend
        function during a suspend (see register CONTROL_B).
+- dlg,wdt-sd: Set what happens on watchdog timeout. If this bit is set the
+       watchdog timeout triggers SHUTDOWN, if cleared the watchdog triggers
+       POWERDOWN. Can be 0 or 1. Only use this option if you want to change the
+       default chip's OTP setting for WATCHDOG_SD bit. If this property is NOT
+       set the WATCHDOG_SD bit and on timeout watchdog behavior will match the
+       chip's OTP settings.
 
 Example: DA9062
 
diff --git a/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt b/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt
deleted file mode 100644 (file)
index 9ecdb50..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-Faraday Technology FTWDT010 watchdog
-
-This is an IP part from Faraday Technology found in the Gemini
-SoCs and others.
-
-Required properties:
-- compatible : must be one of
-  "faraday,ftwdt010"
-  "cortina,gemini-watchdog", "faraday,ftwdt010"
-- reg : shall contain base register location and length
-- interrupts : shall contain the interrupt for the watchdog
-
-Optional properties:
-- timeout-sec : the default watchdog timeout in seconds.
-
-Example:
-
-watchdog@41000000 {
-       compatible = "faraday,ftwdt010";
-       reg = <0x41000000 0x1000>;
-       interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
-};
diff --git a/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml b/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml
new file mode 100644 (file)
index 0000000..ca9e1be
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/watchdog/faraday,ftwdt010.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Faraday Technology FTWDT010 watchdog
+
+maintainers:
+  - Linus Walleij <linus.walleij@linaro.org>
+  - Corentin Labbe <clabbe@baylibre.com>
+
+description: |
+  This is an IP part from Faraday Technology found in the Gemini
+  SoCs and others.
+
+allOf:
+  - $ref: "watchdog.yaml#"
+
+properties:
+  compatible:
+    oneOf:
+      - const: faraday,ftwdt010
+      - items:
+          - enum:
+              - cortina,gemini-watchdog
+              - moxa,moxart-watchdog
+          - const: faraday,ftwdt010
+
+  reg:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: PCLK
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    watchdog@41000000 {
+      compatible = "faraday,ftwdt010";
+      reg = <0x41000000 0x1000>;
+      interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
+      timeout-secs = <5>;
+    };
+  - |
+    watchdog: watchdog@98500000 {
+      compatible = "moxa,moxart-watchdog", "faraday,ftwdt010";
+      reg = <0x98500000 0x10>;
+      clocks = <&clk_apb>;
+      clock-names = "PCLK";
+    };
+...
index 4ca8a31359a55dfff5f883aa1d432c0eaaf07978..8562978aa0c8b3ec4b8e8da8a602961db72041b0 100644 (file)
@@ -19,6 +19,7 @@ properties:
       - items:
           - const: fsl,imx8ulp-wdt
           - const: fsl,imx7ulp-wdt
+      - const: fsl,imx93-wdt
 
   reg:
     maxItems: 1
index a97418c74f6bcb166fc1b55373eb7ee68c98c387..762c62e428ef269279c97c874f921399b218f8d9 100644 (file)
@@ -16,6 +16,7 @@ Required properties:
        "mediatek,mt7629-wdt", "mediatek,mt6589-wdt": for MT7629
        "mediatek,mt7986-wdt", "mediatek,mt6589-wdt": for MT7986
        "mediatek,mt8183-wdt": for MT8183
+       "mediatek,mt8186-wdt", "mediatek,mt6589-wdt": for MT8186
        "mediatek,mt8516-wdt", "mediatek,mt6589-wdt": for MT8516
        "mediatek,mt8192-wdt": for MT8192
        "mediatek,mt8195-wdt", "mediatek,mt6589-wdt": for MT8195
index 16c6f82a13ca2cf2e2275f44aee6baed337b3323..2bd6b4a5263726cf401debb6f105c48e385a0d6d 100644 (file)
@@ -14,22 +14,29 @@ allOf:
 
 properties:
   compatible:
-    enum:
-      - qcom,apss-wdt-qcs404
-      - qcom,apss-wdt-sc7180
-      - qcom,apss-wdt-sc7280
-      - qcom,apss-wdt-sdm845
-      - qcom,apss-wdt-sdx55
-      - qcom,apss-wdt-sm6350
-      - qcom,apss-wdt-sm8150
-      - qcom,apss-wdt-sm8250
-      - qcom,kpss-timer
-      - qcom,kpss-wdt
-      - qcom,kpss-wdt-apq8064
-      - qcom,kpss-wdt-ipq4019
-      - qcom,kpss-wdt-ipq8064
-      - qcom,kpss-wdt-msm8960
-      - qcom,scss-timer
+    oneOf:
+      - items:
+          - enum:
+              - qcom,apss-wdt-qcs404
+              - qcom,apss-wdt-sc7180
+              - qcom,apss-wdt-sc7280
+              - qcom,apss-wdt-sc8180x
+              - qcom,apss-wdt-sc8280xp
+              - qcom,apss-wdt-sdm845
+              - qcom,apss-wdt-sdx55
+              - qcom,apss-wdt-sm6350
+              - qcom,apss-wdt-sm8150
+              - qcom,apss-wdt-sm8250
+          - const: qcom,kpss-wdt
+      - items:
+          - enum:
+              - qcom,kpss-wdt
+              - qcom,kpss-timer
+              - qcom,kpss-wdt-apq8064
+              - qcom,kpss-wdt-ipq4019
+              - qcom,kpss-wdt-ipq8064
+              - qcom,kpss-wdt-msm8960
+              - qcom,scss-timer
 
   reg:
     maxItems: 1
index d060438e1402d502ab0cf068e2d33afe6584572a..a8d7dde5271b8f2fba4a159bb4db0f42756c1463 100644 (file)
@@ -21,8 +21,15 @@ properties:
 
       - items:
           - enum:
+              - renesas,r9a06g032-wdt    # RZ/N1D
+          - const: renesas,rzn1-wdt      # RZ/N1
+
+      - items:
+          - enum:
+              - renesas,r9a07g043-wdt    # RZ/G2UL
               - renesas,r9a07g044-wdt    # RZ/G2{L,LC}
-          - const: renesas,rzg2l-wdt     # RZ/G2L
+              - renesas,r9a07g054-wdt    # RZ/V2L
+          - const: renesas,rzg2l-wdt
 
       - items:
           - enum:
@@ -52,11 +59,11 @@ properties:
               - renesas,r8a77980-wdt     # R-Car V3H
               - renesas,r8a77990-wdt     # R-Car E3
               - renesas,r8a77995-wdt     # R-Car D3
-              - renesas,r8a779a0-wdt     # R-Car V3U
           - const: renesas,rcar-gen3-wdt # R-Car Gen3 and RZ/G2
 
       - items:
           - enum:
+              - renesas,r8a779a0-wdt     # R-Car V3U
               - renesas,r8a779f0-wdt     # R-Car S4-8
           - const: renesas,rcar-gen4-wdt # R-Car Gen4
 
@@ -94,6 +101,7 @@ allOf:
             contains:
               enum:
                 - renesas,rza-wdt
+                - renesas,rzn1-wdt
     then:
       required:
         - power-domains
index a059d16cb4f2e4739e64d98a705bd30d445f74f9..90698cfa8f9450bf302efb6badd6b3d4d343c1c3 100644 (file)
@@ -19,7 +19,7 @@ properties:
 required:
   - compatible
 
-additionalProperties: false
+unevaluatedProperties: false
 
 examples:
   - |
diff --git a/Documentation/devicetree/bindings/watchdog/sunplus,sp7021-wdt.yaml b/Documentation/devicetree/bindings/watchdog/sunplus,sp7021-wdt.yaml
new file mode 100644 (file)
index 0000000..d902710
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/watchdog/sunplus,sp7021-wdt.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus SoCs Watchdog
+
+maintainers:
+  - XianTao Hu <xt.hu@cqplus1.com>
+
+allOf:
+  - $ref: watchdog.yaml#
+
+properties:
+  compatible:
+    const: sunplus,sp7021-wdt
+
+  reg:
+    items:
+      - description: watchdog registers regions
+      - description: miscellaneous control registers regions
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    watchdog: watchdog@9c000630 {
+        compatible = "sunplus,sp7021-wdt";
+        reg = <0x9c000630 0x08>, <0x9c000274 0x04>;
+        clocks = <&clkc 0x24>;
+        resets = <&rstc 0x14>;
+    };
+...
index 3577be9c7089ccdc76a79264fb6d3f2d41bca35f..1ce27e0f826ed9efe34351f2edd52777efcc57a2 100644 (file)
@@ -19057,6 +19057,13 @@ S:     Maintained
 F:     Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
 F:     drivers/tty/serial/sunplus-uart.c
 
+SUNPLUS WATCHDOG DRIVER
+M:     Xiantao Hu <xt.hu@cqplus1.com>
+L:     linux-watchdog@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/watchdog/sunplus,sp7021-wdt.yaml
+F:     drivers/watchdog/sunplus_wdt.c
+
 SUPERH
 M:     Yoshinori Sato <ysato@users.sourceforge.jp>
 M:     Rich Felker <dalias@libc.org>
index c4e82a8d863f8dded3bb044df5ef007ac0132efe..001ae1be9b61c263fd0135ba173b8b0d61465494 100644 (file)
@@ -883,6 +883,14 @@ config RENESAS_RZAWDT
          This driver adds watchdog support for the integrated watchdogs in the
          Renesas RZ/A SoCs. These watchdogs can be used to reset a system.
 
+config RENESAS_RZN1WDT
+       tristate "Renesas RZ/N1 watchdog"
+       depends on ARCH_RENESAS || COMPILE_TEST
+       select WATCHDOG_CORE
+       help
+         This driver adds watchdog support for the integrated watchdogs in the
+         Renesas RZ/N1 SoCs. These watchdogs can be used to reset a system.
+
 config RENESAS_RZG2LWDT
        tristate "Renesas RZ/G2L WDT Watchdog"
        depends on ARCH_RENESAS || COMPILE_TEST
@@ -1011,6 +1019,17 @@ config APPLE_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called apple_wdt.
 
+config SUNPLUS_WATCHDOG
+       tristate "Sunplus watchdog support"
+       depends on ARCH_SUNPLUS || COMPILE_TEST
+       select WATCHDOG_CORE
+       help
+         Say Y here to include support for the watchdog timer
+         in Sunplus SoCs.
+
+         To compile this driver as a module, choose M here: the
+         module will be called sunplus_wdt.
+
 # X86 (i386 + ia64 + x86_64) Architecture
 
 config ACQUIRE_WDT
index f7da867e8782ed4b5439229e3fa21d68a891a2e0..5f88a6237f7c423fe37f25f7b472435c737d8992 100644 (file)
@@ -84,6 +84,7 @@ obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o
 obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
 obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o
 obj-$(CONFIG_RENESAS_RZAWDT) += rza_wdt.o
+obj-$(CONFIG_RENESAS_RZN1WDT) += rzn1_wdt.o
 obj-$(CONFIG_RENESAS_RZG2LWDT) += rzg2l_wdt.o
 obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o
 obj-$(CONFIG_STM32_WATCHDOG) += stm32_iwdg.o
@@ -95,6 +96,7 @@ obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
 obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
 obj-$(CONFIG_MSC313E_WATCHDOG) += msc313e_wdt.o
 obj-$(CONFIG_APPLE_WATCHDOG) += apple_wdt.o
+obj-$(CONFIG_SUNPLUS_WATCHDOG) += sunplus_wdt.o
 
 # X86 (i386 + ia64 + x86_64) Architecture
 obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
index 8656a137e9a4ada6f2363233d5f219d7335dccb0..1ffcf6aca6aeed28b1a9872b653a9a8efdfc9266 100644 (file)
@@ -218,6 +218,7 @@ static SIMPLE_DEV_PM_OPS(bcm7038_wdt_pm_ops, bcm7038_wdt_suspend,
                         bcm7038_wdt_resume);
 
 static const struct of_device_id bcm7038_wdt_match[] = {
+       { .compatible = "brcm,bcm6345-wdt" },
        { .compatible = "brcm,bcm7038-wdt" },
        {},
 };
index 9adad1862bbdb78378017f7afe488a087260fb10..09a4af4c58fc85f6d9cc858325a1b43bf18819fc 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/delay.h>
 #include <linux/mfd/da9063/registers.h>
 #include <linux/mfd/da9063/core.h>
+#include <linux/property.h>
 #include <linux/regmap.h>
 
 /*
@@ -26,6 +27,8 @@
  *   others: timeout = 2048 ms * 2^(TWDSCALE-1).
  */
 static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 };
+static bool use_sw_pm;
+
 #define DA9063_TWDSCALE_DISABLE                0
 #define DA9063_TWDSCALE_MIN            1
 #define DA9063_TWDSCALE_MAX            (ARRAY_SIZE(wdt_timeout) - 1)
@@ -218,6 +221,8 @@ static int da9063_wdt_probe(struct platform_device *pdev)
        if (!wdd)
                return -ENOMEM;
 
+       use_sw_pm = device_property_present(dev, "dlg,use-sw-pm");
+
        wdd->info = &da9063_watchdog_info;
        wdd->ops = &da9063_watchdog_ops;
        wdd->min_timeout = DA9063_WDT_MIN_TIMEOUT;
@@ -228,6 +233,7 @@ static int da9063_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_restart_priority(wdd, 128);
        watchdog_set_drvdata(wdd, da9063);
+       dev_set_drvdata(dev, wdd);
 
        wdd->timeout = DA9063_WDG_TIMEOUT;
 
@@ -249,10 +255,40 @@ static int da9063_wdt_probe(struct platform_device *pdev)
        return devm_watchdog_register_device(dev, wdd);
 }
 
+static int __maybe_unused da9063_wdt_suspend(struct device *dev)
+{
+       struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+       if (!use_sw_pm)
+               return 0;
+
+       if (watchdog_active(wdd))
+               return da9063_wdt_stop(wdd);
+
+       return 0;
+}
+
+static int __maybe_unused da9063_wdt_resume(struct device *dev)
+{
+       struct watchdog_device *wdd = dev_get_drvdata(dev);
+
+       if (!use_sw_pm)
+               return 0;
+
+       if (watchdog_active(wdd))
+               return da9063_wdt_start(wdd);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(da9063_wdt_pm_ops,
+                       da9063_wdt_suspend, da9063_wdt_resume);
+
 static struct platform_driver da9063_wdt_driver = {
        .probe = da9063_wdt_probe,
        .driver = {
                .name = DA9063_DRVNAME_WATCHDOG,
+               .pm = &da9063_wdt_pm_ops,
        },
 };
 module_platform_driver(da9063_wdt_driver);
index 3f2f4343644f562124bd353e3943968b602b5dcb..34693f11385f6c64178b548ef580d12f74b76dca 100644 (file)
@@ -596,7 +596,6 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
 /*
  * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so
  * the watchdog cannot be pinged while in that state.  In ACPI sleep states the
@@ -604,15 +603,15 @@ static int iTCO_wdt_probe(struct platform_device *pdev)
  */
 
 #ifdef CONFIG_ACPI
-static inline bool need_suspend(void)
+static inline bool __maybe_unused need_suspend(void)
 {
        return acpi_target_system_state() == ACPI_STATE_S0;
 }
 #else
-static inline bool need_suspend(void) { return true; }
+static inline bool __maybe_unused need_suspend(void) { return true; }
 #endif
 
-static int iTCO_wdt_suspend_noirq(struct device *dev)
+static int __maybe_unused iTCO_wdt_suspend_noirq(struct device *dev)
 {
        struct iTCO_wdt_private *p = dev_get_drvdata(dev);
        int ret = 0;
@@ -626,7 +625,7 @@ static int iTCO_wdt_suspend_noirq(struct device *dev)
        return ret;
 }
 
-static int iTCO_wdt_resume_noirq(struct device *dev)
+static int __maybe_unused iTCO_wdt_resume_noirq(struct device *dev)
 {
        struct iTCO_wdt_private *p = dev_get_drvdata(dev);
 
@@ -637,20 +636,15 @@ static int iTCO_wdt_resume_noirq(struct device *dev)
 }
 
 static const struct dev_pm_ops iTCO_wdt_pm = {
-       .suspend_noirq = iTCO_wdt_suspend_noirq,
-       .resume_noirq = iTCO_wdt_resume_noirq,
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(iTCO_wdt_suspend_noirq,
+                                     iTCO_wdt_resume_noirq)
 };
 
-#define ITCO_WDT_PM_OPS        (&iTCO_wdt_pm)
-#else
-#define ITCO_WDT_PM_OPS        NULL
-#endif /* CONFIG_PM_SLEEP */
-
 static struct platform_driver iTCO_wdt_driver = {
        .probe          = iTCO_wdt_probe,
        .driver         = {
                .name   = DRV_NAME,
-               .pm     = ITCO_WDT_PM_OPS,
+               .pm     = &iTCO_wdt_pm,
        },
 };
 
index 4577a76dd464fdea227ebaa7a6fea06d187fb920..f0d4e3cc74590c978f8f0d7c512440bf4f10121b 100644 (file)
@@ -10,7 +10,9 @@
  */
 
 #include <dt-bindings/reset/mt2712-resets.h>
+#include <dt-bindings/reset/mt7986-resets.h>
 #include <dt-bindings/reset/mt8183-resets.h>
+#include <dt-bindings/reset/mt8186-resets.h>
 #include <dt-bindings/reset/mt8192-resets.h>
 #include <dt-bindings/reset/mt8195-resets.h>
 #include <linux/delay.h>
@@ -76,10 +78,18 @@ static const struct mtk_wdt_data mt2712_data = {
        .toprgu_sw_rst_num = MT2712_TOPRGU_SW_RST_NUM,
 };
 
+static const struct mtk_wdt_data mt7986_data = {
+       .toprgu_sw_rst_num = MT7986_TOPRGU_SW_RST_NUM,
+};
+
 static const struct mtk_wdt_data mt8183_data = {
        .toprgu_sw_rst_num = MT8183_TOPRGU_SW_RST_NUM,
 };
 
+static const struct mtk_wdt_data mt8186_data = {
+       .toprgu_sw_rst_num = MT8186_TOPRGU_SW_RST_NUM,
+};
+
 static const struct mtk_wdt_data mt8192_data = {
        .toprgu_sw_rst_num = MT8192_TOPRGU_SW_RST_NUM,
 };
@@ -418,7 +428,9 @@ static int mtk_wdt_resume(struct device *dev)
 static const struct of_device_id mtk_wdt_dt_ids[] = {
        { .compatible = "mediatek,mt2712-wdt", .data = &mt2712_data },
        { .compatible = "mediatek,mt6589-wdt" },
+       { .compatible = "mediatek,mt7986-wdt", .data = &mt7986_data },
        { .compatible = "mediatek,mt8183-wdt", .data = &mt8183_data },
+       { .compatible = "mediatek,mt8186-wdt", .data = &mt8186_data },
        { .compatible = "mediatek,mt8192-wdt", .data = &mt8192_data },
        { .compatible = "mediatek,mt8195-wdt", .data = &mt8195_data },
        { /* sentinel */ }
index db843f82586026be10443dbc4f2b3feec2bae9b7..053ef3bde12d41bd873e432c2c0e1631c2bd064e 100644 (file)
@@ -226,7 +226,7 @@ static int rti_wdt_probe(struct platform_device *pdev)
 
        pm_runtime_enable(dev);
        ret = pm_runtime_get_sync(dev);
-       if (ret) {
+       if (ret < 0) {
                pm_runtime_put_noidle(dev);
                pm_runtime_disable(&pdev->dev);
                return dev_err_probe(dev, ret, "runtime pm failed\n");
@@ -253,6 +253,7 @@ static int rti_wdt_probe(struct platform_device *pdev)
        }
 
        if (readl(wdt->base + RTIDWDCTRL) == WDENABLE_KEY) {
+               int preset_heartbeat;
                u32 time_left_ms;
                u64 heartbeat_ms;
                u32 wsize;
@@ -263,11 +264,12 @@ static int rti_wdt_probe(struct platform_device *pdev)
                heartbeat_ms <<= WDT_PRELOAD_SHIFT;
                heartbeat_ms *= 1000;
                do_div(heartbeat_ms, wdt->freq);
-               if (heartbeat_ms != heartbeat * 1000)
+               preset_heartbeat = heartbeat_ms + 500;
+               preset_heartbeat /= 1000;
+               if (preset_heartbeat != heartbeat)
                        dev_warn(dev, "watchdog already running, ignoring heartbeat config!\n");
 
-               heartbeat = heartbeat_ms;
-               heartbeat /= 1000;
+               heartbeat = preset_heartbeat;
 
                wsize = readl(wdt->base + RTIWWDSIZECTRL);
                ret = rti_wdt_setup_hw_hb(wdd, wsize);
index 6b426df34fd6fd728639210b2b9a19639012b30a..6eea0ee4af49eae9b9a98c2c9a8878118bf89214 100644 (file)
 #define WDTSET         0x04
 #define WDTTIM         0x08
 #define WDTINT         0x0C
+#define PECR           0x10
+#define PEEN           0x14
 #define WDTCNT_WDTEN   BIT(0)
 #define WDTINT_INTDISP BIT(0)
+#define PEEN_FORCE     BIT(0)
 
 #define WDT_DEFAULT_TIMEOUT            60U
 
@@ -43,6 +46,8 @@ struct rzg2l_wdt_priv {
        struct reset_control *rstc;
        unsigned long osc_clk_rate;
        unsigned long delay;
+       struct clk *pclk;
+       struct clk *osc_clk;
 };
 
 static void rzg2l_wdt_wait_delay(struct rzg2l_wdt_priv *priv)
@@ -53,7 +58,7 @@ static void rzg2l_wdt_wait_delay(struct rzg2l_wdt_priv *priv)
 
 static u32 rzg2l_wdt_get_cycle_usec(unsigned long cycle, u32 wdttime)
 {
-       u64 timer_cycle_us = 1024 * 1024 * (wdttime + 1) * MICRO;
+       u64 timer_cycle_us = 1024 * 1024ULL * (wdttime + 1) * MICRO;
 
        return div64_ul(timer_cycle_us, cycle);
 }
@@ -86,7 +91,6 @@ static int rzg2l_wdt_start(struct watchdog_device *wdev)
 {
        struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
 
-       reset_control_deassert(priv->rstc);
        pm_runtime_get_sync(wdev->parent);
 
        /* Initialize time out */
@@ -106,7 +110,26 @@ static int rzg2l_wdt_stop(struct watchdog_device *wdev)
        struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
 
        pm_runtime_put(wdev->parent);
-       reset_control_assert(priv->rstc);
+       reset_control_reset(priv->rstc);
+
+       return 0;
+}
+
+static int rzg2l_wdt_set_timeout(struct watchdog_device *wdev, unsigned int timeout)
+{
+       struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
+
+       wdev->timeout = timeout;
+
+       /*
+        * If the watchdog is active, reset the module for updating the WDTSET
+        * register so that it is updated with new timeout values.
+        */
+       if (watchdog_active(wdev)) {
+               pm_runtime_put(wdev->parent);
+               reset_control_reset(priv->rstc);
+               rzg2l_wdt_start(wdev);
+       }
 
        return 0;
 }
@@ -116,15 +139,14 @@ static int rzg2l_wdt_restart(struct watchdog_device *wdev,
 {
        struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
 
-       /* Reset the module before we modify any register */
-       reset_control_reset(priv->rstc);
-       pm_runtime_get_sync(wdev->parent);
+       clk_prepare_enable(priv->pclk);
+       clk_prepare_enable(priv->osc_clk);
 
-       /* smallest counter value to reboot soon */
-       rzg2l_wdt_write(priv, WDTSET_COUNTER_VAL(1), WDTSET);
+       /* Generate Reset (WDTRSTB) Signal on parity error */
+       rzg2l_wdt_write(priv, 0, PECR);
 
-       /* Enable watchdog timer*/
-       rzg2l_wdt_write(priv, WDTCNT_WDTEN, WDTCNT);
+       /* Force parity error */
+       rzg2l_wdt_write(priv, PEEN_FORCE, PEEN);
 
        return 0;
 }
@@ -148,15 +170,15 @@ static const struct watchdog_ops rzg2l_wdt_ops = {
        .start = rzg2l_wdt_start,
        .stop = rzg2l_wdt_stop,
        .ping = rzg2l_wdt_ping,
+       .set_timeout = rzg2l_wdt_set_timeout,
        .restart = rzg2l_wdt_restart,
 };
 
-static void rzg2l_wdt_reset_assert_pm_disable_put(void *data)
+static void rzg2l_wdt_reset_assert_pm_disable(void *data)
 {
        struct watchdog_device *wdev = data;
        struct rzg2l_wdt_priv *priv = watchdog_get_drvdata(wdev);
 
-       pm_runtime_put(wdev->parent);
        pm_runtime_disable(wdev->parent);
        reset_control_assert(priv->rstc);
 }
@@ -166,7 +188,6 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct rzg2l_wdt_priv *priv;
        unsigned long pclk_rate;
-       struct clk *wdt_clk;
        int ret;
 
        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -178,22 +199,20 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
                return PTR_ERR(priv->base);
 
        /* Get watchdog main clock */
-       wdt_clk = clk_get(&pdev->dev, "oscclk");
-       if (IS_ERR(wdt_clk))
-               return dev_err_probe(&pdev->dev, PTR_ERR(wdt_clk), "no oscclk");
+       priv->osc_clk = devm_clk_get(&pdev->dev, "oscclk");
+       if (IS_ERR(priv->osc_clk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(priv->osc_clk), "no oscclk");
 
-       priv->osc_clk_rate = clk_get_rate(wdt_clk);
-       clk_put(wdt_clk);
+       priv->osc_clk_rate = clk_get_rate(priv->osc_clk);
        if (!priv->osc_clk_rate)
                return dev_err_probe(&pdev->dev, -EINVAL, "oscclk rate is 0");
 
        /* Get Peripheral clock */
-       wdt_clk = clk_get(&pdev->dev, "pclk");
-       if (IS_ERR(wdt_clk))
-               return dev_err_probe(&pdev->dev, PTR_ERR(wdt_clk), "no pclk");
+       priv->pclk = devm_clk_get(&pdev->dev, "pclk");
+       if (IS_ERR(priv->pclk))
+               return dev_err_probe(&pdev->dev, PTR_ERR(priv->pclk), "no pclk");
 
-       pclk_rate = clk_get_rate(wdt_clk);
-       clk_put(wdt_clk);
+       pclk_rate = clk_get_rate(priv->pclk);
        if (!pclk_rate)
                return dev_err_probe(&pdev->dev, -EINVAL, "pclk rate is 0");
 
@@ -204,13 +223,11 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
                return dev_err_probe(&pdev->dev, PTR_ERR(priv->rstc),
                                     "failed to get cpg reset");
 
-       reset_control_deassert(priv->rstc);
+       ret = reset_control_deassert(priv->rstc);
+       if (ret)
+               return dev_err_probe(dev, ret, "failed to deassert");
+
        pm_runtime_enable(&pdev->dev);
-       ret = pm_runtime_resume_and_get(&pdev->dev);
-       if (ret < 0) {
-               dev_err(dev, "pm_runtime_resume_and_get failed ret=%pe", ERR_PTR(ret));
-               goto out_pm_get;
-       }
 
        priv->wdev.info = &rzg2l_wdt_ident;
        priv->wdev.ops = &rzg2l_wdt_ops;
@@ -222,7 +239,7 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_drvdata(&priv->wdev, priv);
        ret = devm_add_action_or_reset(&pdev->dev,
-                                      rzg2l_wdt_reset_assert_pm_disable_put,
+                                      rzg2l_wdt_reset_assert_pm_disable,
                                       &priv->wdev);
        if (ret < 0)
                return ret;
@@ -235,12 +252,6 @@ static int rzg2l_wdt_probe(struct platform_device *pdev)
                dev_warn(dev, "Specified timeout invalid, using default");
 
        return devm_watchdog_register_device(&pdev->dev, &priv->wdev);
-
-out_pm_get:
-       pm_runtime_disable(dev);
-       reset_control_assert(priv->rstc);
-
-       return ret;
 }
 
 static const struct of_device_id rzg2l_wdt_ids[] = {
diff --git a/drivers/watchdog/rzn1_wdt.c b/drivers/watchdog/rzn1_wdt.c
new file mode 100644 (file)
index 0000000..55ab384
--- /dev/null
@@ -0,0 +1,203 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/N1 Watchdog timer.
+ * This is a 12-bit timer driver from a (62.5/16384) MHz clock. It can't even
+ * cope with 2 seconds.
+ *
+ * Copyright 2018 Renesas Electronics Europe Ltd.
+ *
+ * Derived from Ralink RT288x watchdog timer.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+
+#define DEFAULT_TIMEOUT                60
+
+#define RZN1_WDT_RETRIGGER                     0x0
+#define RZN1_WDT_RETRIGGER_RELOAD_VAL          0
+#define RZN1_WDT_RETRIGGER_RELOAD_VAL_MASK     0xfff
+#define RZN1_WDT_RETRIGGER_PRESCALE            BIT(12)
+#define RZN1_WDT_RETRIGGER_ENABLE              BIT(13)
+#define RZN1_WDT_RETRIGGER_WDSI                        (0x2 << 14)
+
+#define RZN1_WDT_PRESCALER                     16384
+#define RZN1_WDT_MAX                           4095
+
+struct rzn1_watchdog {
+       struct watchdog_device          wdtdev;
+       void __iomem                    *base;
+       unsigned long                   clk_rate_khz;
+};
+
+static inline uint32_t max_heart_beat_ms(unsigned long clk_rate_khz)
+{
+       return (RZN1_WDT_MAX * RZN1_WDT_PRESCALER) / clk_rate_khz;
+}
+
+static inline uint32_t compute_reload_value(uint32_t tick_ms,
+                                           unsigned long clk_rate_khz)
+{
+       return (tick_ms * clk_rate_khz) / RZN1_WDT_PRESCALER;
+}
+
+static int rzn1_wdt_ping(struct watchdog_device *w)
+{
+       struct rzn1_watchdog *wdt = watchdog_get_drvdata(w);
+
+       /* Any value retrigggers the watchdog */
+       writel(0, wdt->base + RZN1_WDT_RETRIGGER);
+
+       return 0;
+}
+
+static int rzn1_wdt_start(struct watchdog_device *w)
+{
+       struct rzn1_watchdog *wdt = watchdog_get_drvdata(w);
+       u32 val;
+
+       /*
+        * The hardware allows you to write to this reg only once.
+        * Since this includes the reload value, there is no way to change the
+        * timeout once started. Also note that the WDT clock is half the bus
+        * fabric clock rate, so if the bus fabric clock rate is changed after
+        * the WDT is started, the WDT interval will be wrong.
+        */
+       val = RZN1_WDT_RETRIGGER_WDSI;
+       val |= RZN1_WDT_RETRIGGER_ENABLE;
+       val |= RZN1_WDT_RETRIGGER_PRESCALE;
+       val |= compute_reload_value(w->max_hw_heartbeat_ms, wdt->clk_rate_khz);
+       writel(val, wdt->base + RZN1_WDT_RETRIGGER);
+
+       return 0;
+}
+
+static irqreturn_t rzn1_wdt_irq(int irq, void *_wdt)
+{
+       pr_crit("RZN1 Watchdog. Initiating system reboot\n");
+       emergency_restart();
+
+       return IRQ_HANDLED;
+}
+
+static struct watchdog_info rzn1_wdt_info = {
+       .identity = "RZ/N1 Watchdog",
+       .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+};
+
+static const struct watchdog_ops rzn1_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = rzn1_wdt_start,
+       .ping = rzn1_wdt_ping,
+};
+
+static void rzn1_wdt_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
+static int rzn1_wdt_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct rzn1_watchdog *wdt;
+       struct device_node *np = dev->of_node;
+       struct clk *clk;
+       unsigned long clk_rate;
+       int ret;
+       int irq;
+
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       wdt->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(wdt->base))
+               return PTR_ERR(wdt->base);
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
+
+       ret = devm_request_irq(dev, irq, rzn1_wdt_irq, 0,
+                              np->name, wdt);
+       if (ret) {
+               dev_err(dev, "failed to request irq %d\n", irq);
+               return ret;
+       }
+
+       clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(clk)) {
+               dev_err(dev, "failed to get the clock\n");
+               return PTR_ERR(clk);
+       }
+
+       ret = clk_prepare_enable(clk);
+       if (ret) {
+               dev_err(dev, "failed to prepare/enable the clock\n");
+               return ret;
+       }
+
+       ret = devm_add_action_or_reset(dev, rzn1_wdt_clk_disable_unprepare,
+                                      clk);
+       if (ret)
+               return ret;
+
+       clk_rate = clk_get_rate(clk);
+       if (!clk_rate) {
+               dev_err(dev, "failed to get the clock rate\n");
+               return -EINVAL;
+       }
+
+       wdt->clk_rate_khz = clk_rate / 1000;
+       wdt->wdtdev.info = &rzn1_wdt_info,
+       wdt->wdtdev.ops = &rzn1_wdt_ops,
+       wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS,
+       wdt->wdtdev.parent = dev;
+       /*
+        * The period of the watchdog cannot be changed once set
+        * and is limited to a very short period.
+        * Configure it for a 1s period once and for all, and
+        * rely on the heart-beat provided by the watchdog core
+        * to make this usable by the user-space.
+        */
+       wdt->wdtdev.max_hw_heartbeat_ms = max_heart_beat_ms(wdt->clk_rate_khz);
+       if (wdt->wdtdev.max_hw_heartbeat_ms > 1000)
+               wdt->wdtdev.max_hw_heartbeat_ms = 1000;
+
+       wdt->wdtdev.timeout = DEFAULT_TIMEOUT;
+       ret = watchdog_init_timeout(&wdt->wdtdev, 0, dev);
+       if (ret)
+               return ret;
+
+       watchdog_set_drvdata(&wdt->wdtdev, wdt);
+
+       return devm_watchdog_register_device(dev, &wdt->wdtdev);
+}
+
+
+static const struct of_device_id rzn1_wdt_match[] = {
+       { .compatible = "renesas,rzn1-wdt" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rzn1_wdt_match);
+
+static struct platform_driver rzn1_wdt_driver = {
+       .probe          = rzn1_wdt_probe,
+       .driver         = {
+               .name           = KBUILD_MODNAME,
+               .of_match_table = rzn1_wdt_match,
+       },
+};
+
+module_platform_driver(rzn1_wdt_driver);
+
+MODULE_DESCRIPTION("Renesas RZ/N1 hardware watchdog");
+MODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>");
+MODULE_LICENSE("GPL");
index dbeb2146c9681a45a32724453c90a4dc8a1f27b1..f9479a3fe2a69e3388d39f4035e4c3a3d9fd9bc6 100644 (file)
@@ -272,6 +272,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id)
        watchdog_set_nowayout(&wdt->wdd, nowayout);
        watchdog_set_drvdata(&wdt->wdd, wdt);
        watchdog_set_restart_priority(&wdt->wdd, 128);
+       watchdog_stop_on_unregister(&wdt->wdd);
 
        /*
         * If 'timeout-sec' devicetree property is specified, use that.
diff --git a/drivers/watchdog/sunplus_wdt.c b/drivers/watchdog/sunplus_wdt.c
new file mode 100644 (file)
index 0000000..e2d8c53
--- /dev/null
@@ -0,0 +1,220 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * sunplus Watchdog Driver
+ *
+ * Copyright (C) 2021 Sunplus Technology Co., Ltd.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/watchdog.h>
+
+#define WDT_CTRL               0x00
+#define WDT_CNT                        0x04
+
+#define WDT_STOP               0x3877
+#define WDT_RESUME             0x4A4B
+#define WDT_CLRIRQ             0x7482
+#define WDT_UNLOCK             0xAB00
+#define WDT_LOCK               0xAB01
+#define WDT_CONMAX             0xDEAF
+
+/* TIMEOUT_MAX = ffff0/90kHz =11.65, so longer than 11 seconds will time out. */
+#define SP_WDT_MAX_TIMEOUT     11U
+#define SP_WDT_DEFAULT_TIMEOUT 10
+
+#define STC_CLK                        90000
+
+#define DEVICE_NAME            "sunplus-wdt"
+
+static unsigned int timeout;
+module_param(timeout, int, 0);
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                       __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+struct sp_wdt_priv {
+       struct watchdog_device wdev;
+       void __iomem *base;
+       struct clk *clk;
+       struct reset_control *rstc;
+};
+
+static int sp_wdt_restart(struct watchdog_device *wdev,
+                         unsigned long action, void *data)
+{
+       struct sp_wdt_priv *priv = watchdog_get_drvdata(wdev);
+       void __iomem *base = priv->base;
+
+       writel(WDT_STOP, base + WDT_CTRL);
+       writel(WDT_UNLOCK, base + WDT_CTRL);
+       writel(0x0001, base + WDT_CNT);
+       writel(WDT_LOCK, base + WDT_CTRL);
+       writel(WDT_RESUME, base + WDT_CTRL);
+
+       return 0;
+}
+
+static int sp_wdt_ping(struct watchdog_device *wdev)
+{
+       struct sp_wdt_priv *priv = watchdog_get_drvdata(wdev);
+       void __iomem *base = priv->base;
+       u32 count;
+
+       if (wdev->timeout > SP_WDT_MAX_TIMEOUT) {
+               /* WDT_CONMAX sets the count to the maximum (down-counting). */
+               writel(WDT_CONMAX, base + WDT_CTRL);
+       } else {
+               writel(WDT_UNLOCK, base + WDT_CTRL);
+               /*
+                * Watchdog timer is a 20-bit down-counting based on STC_CLK.
+                * This register bits[16:0] is from bit[19:4] of the watchdog
+                * timer counter.
+                */
+               count = (wdev->timeout * STC_CLK) >> 4;
+               writel(count, base + WDT_CNT);
+               writel(WDT_LOCK, base + WDT_CTRL);
+       }
+
+       return 0;
+}
+
+static int sp_wdt_stop(struct watchdog_device *wdev)
+{
+       struct sp_wdt_priv *priv = watchdog_get_drvdata(wdev);
+       void __iomem *base = priv->base;
+
+       writel(WDT_STOP, base + WDT_CTRL);
+
+       return 0;
+}
+
+static int sp_wdt_start(struct watchdog_device *wdev)
+{
+       struct sp_wdt_priv *priv = watchdog_get_drvdata(wdev);
+       void __iomem *base = priv->base;
+
+       writel(WDT_RESUME, base + WDT_CTRL);
+
+       return 0;
+}
+
+static unsigned int sp_wdt_get_timeleft(struct watchdog_device *wdev)
+{
+       struct sp_wdt_priv *priv = watchdog_get_drvdata(wdev);
+       void __iomem *base = priv->base;
+       u32 val;
+
+       val = readl(base + WDT_CNT);
+       val &= 0xffff;
+       val = val << 4;
+
+       return val;
+}
+
+static const struct watchdog_info sp_wdt_info = {
+       .identity       = DEVICE_NAME,
+       .options        = WDIOF_SETTIMEOUT |
+                         WDIOF_MAGICCLOSE |
+                         WDIOF_KEEPALIVEPING,
+};
+
+static const struct watchdog_ops sp_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = sp_wdt_start,
+       .stop           = sp_wdt_stop,
+       .ping           = sp_wdt_ping,
+       .get_timeleft   = sp_wdt_get_timeleft,
+       .restart        = sp_wdt_restart,
+};
+
+static void sp_clk_disable_unprepare(void *data)
+{
+       clk_disable_unprepare(data);
+}
+
+static void sp_reset_control_assert(void *data)
+{
+       reset_control_assert(data);
+}
+
+static int sp_wdt_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct sp_wdt_priv *priv;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clk))
+               return dev_err_probe(dev, PTR_ERR(priv->clk), "Failed to get clock\n");
+
+       ret = clk_prepare_enable(priv->clk);
+       if (ret)
+               return dev_err_probe(dev, ret, "Failed to enable clock\n");
+
+       ret = devm_add_action_or_reset(dev, sp_clk_disable_unprepare, priv->clk);
+       if (ret)
+               return ret;
+
+       /* The timer and watchdog shared the STC reset */
+       priv->rstc = devm_reset_control_get_shared(dev, NULL);
+       if (IS_ERR(priv->rstc))
+               return dev_err_probe(dev, PTR_ERR(priv->rstc), "Failed to get reset\n");
+
+       reset_control_deassert(priv->rstc);
+
+       ret = devm_add_action_or_reset(dev, sp_reset_control_assert, priv->rstc);
+       if (ret)
+               return ret;
+
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       priv->wdev.info = &sp_wdt_info;
+       priv->wdev.ops = &sp_wdt_ops;
+       priv->wdev.timeout = SP_WDT_DEFAULT_TIMEOUT;
+       priv->wdev.max_hw_heartbeat_ms = SP_WDT_MAX_TIMEOUT * 1000;
+       priv->wdev.min_timeout = 1;
+       priv->wdev.parent = dev;
+
+       watchdog_set_drvdata(&priv->wdev, priv);
+       watchdog_init_timeout(&priv->wdev, timeout, dev);
+       watchdog_set_nowayout(&priv->wdev, nowayout);
+       watchdog_stop_on_reboot(&priv->wdev);
+       watchdog_set_restart_priority(&priv->wdev, 128);
+
+       return devm_watchdog_register_device(dev, &priv->wdev);
+}
+
+static const struct of_device_id sp_wdt_of_match[] = {
+       {.compatible = "sunplus,sp7021-wdt", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sp_wdt_of_match);
+
+static struct platform_driver sp_wdt_driver = {
+       .probe = sp_wdt_probe,
+       .driver = {
+                  .name = DEVICE_NAME,
+                  .of_match_table = sp_wdt_of_match,
+       },
+};
+
+module_platform_driver(sp_wdt_driver);
+
+MODULE_AUTHOR("Xiantao Hu <xt.hu@cqplus1.com>");
+MODULE_DESCRIPTION("Sunplus Watchdog Timer Driver");
+MODULE_LICENSE("GPL");
index c137ad2bd5c31616f4259a528bc713ec193ab616..0ea554c7cda579320e56e36ae27a21a5a13f2665 100644 (file)
@@ -125,13 +125,16 @@ static int ts4800_wdt_probe(struct platform_device *pdev)
        ret = of_property_read_u32_index(np, "syscon", 1, &reg);
        if (ret < 0) {
                dev_err(dev, "no offset in syscon\n");
+               of_node_put(syscon_np);
                return ret;
        }
 
        /* allocate memory for watchdog struct */
        wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
-       if (!wdt)
+       if (!wdt) {
+               of_node_put(syscon_np);
                return -ENOMEM;
+       }
 
        /* set regmap and offset to know where to write */
        wdt->feed_offset = reg;
index 195c8c004b69d70c213d4d3588ec4bacb8d5e8ce..e6f95e99156dbb1aecddc57e7e9a47b997d07cfe 100644 (file)
@@ -344,6 +344,7 @@ static int wdat_wdt_probe(struct platform_device *pdev)
        wdat->period = tbl->timer_period;
        wdat->wdd.min_hw_heartbeat_ms = wdat->period * tbl->min_count;
        wdat->wdd.max_hw_heartbeat_ms = wdat->period * tbl->max_count;
+       wdat->wdd.min_timeout = 1;
        wdat->stopped_in_sleep = tbl->flags & ACPI_WDAT_STOPPED;
        wdat->wdd.info = &wdat_wdt_info;
        wdat->wdd.ops = &wdat_wdt_ops;
@@ -450,8 +451,7 @@ static int wdat_wdt_probe(struct platform_device *pdev)
         * watchdog properly after it has opened the device. In some cases
         * the BIOS default is too short and causes immediate reboot.
         */
-       if (timeout * 1000 < wdat->wdd.min_hw_heartbeat_ms ||
-           timeout * 1000 > wdat->wdd.max_hw_heartbeat_ms) {
+       if (watchdog_timeout_invalid(&wdat->wdd, timeout)) {
                dev_warn(dev, "Invalid timeout %d given, using %d\n",
                         timeout, WDAT_DEFAULT_TIMEOUT);
                timeout = WDAT_DEFAULT_TIMEOUT;
@@ -462,6 +462,8 @@ static int wdat_wdt_probe(struct platform_device *pdev)
                return ret;
 
        watchdog_set_nowayout(&wdat->wdd, nowayout);
+       watchdog_stop_on_reboot(&wdat->wdd);
+       watchdog_stop_on_unregister(&wdat->wdd);
        return devm_watchdog_register_device(dev, &wdat->wdd);
 }
 
diff --git a/include/dt-bindings/reset/mt7986-resets.h b/include/dt-bindings/reset/mt7986-resets.h
new file mode 100644 (file)
index 0000000..af3d16c
--- /dev/null
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Sam Shih <sam.shih@mediatek.com>
+ */
+
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT7986
+#define _DT_BINDINGS_RESET_CONTROLLER_MT7986
+
+/* INFRACFG resets */
+#define MT7986_INFRACFG_PEXTP_MAC_SW_RST       6
+#define MT7986_INFRACFG_SSUSB_SW_RST           7
+#define MT7986_INFRACFG_EIP97_SW_RST           8
+#define MT7986_INFRACFG_AUDIO_SW_RST           13
+#define MT7986_INFRACFG_CQ_DMA_SW_RST          14
+
+#define MT7986_INFRACFG_TRNG_SW_RST            17
+#define MT7986_INFRACFG_AP_DMA_SW_RST          32
+#define MT7986_INFRACFG_I2C_SW_RST             33
+#define MT7986_INFRACFG_NFI_SW_RST             34
+#define MT7986_INFRACFG_SPI0_SW_RST            35
+#define MT7986_INFRACFG_SPI1_SW_RST            36
+#define MT7986_INFRACFG_UART0_SW_RST           37
+#define MT7986_INFRACFG_UART1_SW_RST           38
+#define MT7986_INFRACFG_UART2_SW_RST           39
+#define MT7986_INFRACFG_AUXADC_SW_RST          43
+
+#define MT7986_INFRACFG_APXGPT_SW_RST          66
+#define MT7986_INFRACFG_PWM_SW_RST             68
+
+#define MT7986_INFRACFG_SW_RST_NUM             69
+
+/* TOPRGU resets */
+#define MT7986_TOPRGU_APMIXEDSYS_SW_RST                0
+#define MT7986_TOPRGU_SGMII0_SW_RST            1
+#define MT7986_TOPRGU_SGMII1_SW_RST            2
+#define MT7986_TOPRGU_INFRA_SW_RST             3
+#define MT7986_TOPRGU_U2PHY_SW_RST             5
+#define MT7986_TOPRGU_PCIE_SW_RST              6
+#define MT7986_TOPRGU_SSUSB_SW_RST             7
+#define MT7986_TOPRGU_ETHDMA_SW_RST            20
+#define MT7986_TOPRGU_CONSYS_SW_RST            23
+
+#define MT7986_TOPRGU_SW_RST_NUM               24
+
+/* ETHSYS Subsystem resets */
+#define MT7986_ETHSYS_FE_SW_RST                        6
+#define MT7986_ETHSYS_PMTR_SW_RST              8
+#define MT7986_ETHSYS_GMAC_SW_RST              23
+#define MT7986_ETHSYS_PPE0_SW_RST              30
+#define MT7986_ETHSYS_PPE1_SW_RST              31
+
+#define MT7986_ETHSYS_SW_RST_NUM               32
+
+#endif  /* _DT_BINDINGS_RESET_CONTROLLER_MT7986 */
diff --git a/include/dt-bindings/reset/mt8186-resets.h b/include/dt-bindings/reset/mt8186-resets.h
new file mode 100644 (file)
index 0000000..5f85037
--- /dev/null
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
+/*
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Runyang Chen <runyang.chen@mediatek.com>
+ */
+
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_MT8186
+#define _DT_BINDINGS_RESET_CONTROLLER_MT8186
+
+#define MT8186_TOPRGU_INFRA_SW_RST                             0
+#define MT8186_TOPRGU_MM_SW_RST                                        1
+#define MT8186_TOPRGU_MFG_SW_RST                               2
+#define MT8186_TOPRGU_VENC_SW_RST                              3
+#define MT8186_TOPRGU_VDEC_SW_RST                              4
+#define MT8186_TOPRGU_IMG_SW_RST                               5
+#define MT8186_TOPRGU_DDR_SW_RST                               6
+#define MT8186_TOPRGU_INFRA_AO_SW_RST                          8
+#define MT8186_TOPRGU_CONNSYS_SW_RST                           9
+#define MT8186_TOPRGU_APMIXED_SW_RST                           10
+#define MT8186_TOPRGU_PWRAP_SW_RST                             11
+#define MT8186_TOPRGU_CONN_MCU_SW_RST                          12
+#define MT8186_TOPRGU_IPNNA_SW_RST                             13
+#define MT8186_TOPRGU_WPE_SW_RST                               14
+#define MT8186_TOPRGU_ADSP_SW_RST                              15
+#define MT8186_TOPRGU_AUDIO_SW_RST                             17
+#define MT8186_TOPRGU_CAM_MAIN_SW_RST                          18
+#define MT8186_TOPRGU_CAM_RAWA_SW_RST                          19
+#define MT8186_TOPRGU_CAM_RAWB_SW_RST                          20
+#define MT8186_TOPRGU_IPE_SW_RST                               21
+#define MT8186_TOPRGU_IMG2_SW_RST                              22
+#define MT8186_TOPRGU_SW_RST_NUM                               23
+
+/* MMSYS resets */
+#define MT8186_MMSYS_SW0_RST_B_DISP_DSI0                       19
+
+#endif  /* _DT_BINDINGS_RESET_CONTROLLER_MT8186 */