diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-06-01 14:05:16 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-06-01 14:05:16 -0700 |
commit | 96752be4d7b443e6f1e322428d61f777d7d8bd4d (patch) | |
tree | d805495265e60273600b287c070aff21743c62d7 | |
parent | 176882156ae6d63a81fe7f01ea6fe65ab6b52105 (diff) | |
parent | 5d24df3d690809952528e7a19a43d84bc5b99d44 (diff) | |
download | linux-96752be4d7b443e6f1e322428d61f777d7d8bd4d.tar.bz2 |
Merge tag 'linux-watchdog-5.19-rc1' of git://www.linux-watchdog.org/linux-watchdog
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, 822 insertions, 100 deletions
diff --git a/Documentation/devicetree/bindings/mfd/da9063.txt b/Documentation/devicetree/bindings/mfd/da9063.txt index 91b79a21d403..aa8b800cc4ad 100644 --- a/Documentation/devicetree/bindings/mfd/da9063.txt +++ b/Documentation/devicetree/bindings/mfd/da9063.txt @@ -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: diff --git a/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt b/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt index 950e4fba8dbc..354314d854ef 100644 --- a/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/da9062-wdt.txt @@ -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 index 9ecdb502e605..000000000000 --- a/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.txt +++ /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 index 000000000000..ca9e1beff76b --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/faraday,ftwdt010.yaml @@ -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"; + }; +... diff --git a/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml b/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml index 4ca8a31359a5..8562978aa0c8 100644 --- a/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/fsl-imx7ulp-wdt.yaml @@ -19,6 +19,7 @@ properties: - items: - const: fsl,imx8ulp-wdt - const: fsl,imx7ulp-wdt + - const: fsl,imx93-wdt reg: maxItems: 1 diff --git a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt index a97418c74f6b..762c62e428ef 100644 --- a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt @@ -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 diff --git a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml index 16c6f82a13ca..2bd6b4a52637 100644 --- a/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/qcom-wdt.yaml @@ -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 diff --git a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml index d060438e1402..a8d7dde5271b 100644 --- a/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/renesas,wdt.yaml @@ -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 diff --git a/Documentation/devicetree/bindings/watchdog/socionext,uniphier-wdt.yaml b/Documentation/devicetree/bindings/watchdog/socionext,uniphier-wdt.yaml index a059d16cb4f2..90698cfa8f94 100644 --- a/Documentation/devicetree/bindings/watchdog/socionext,uniphier-wdt.yaml +++ b/Documentation/devicetree/bindings/watchdog/socionext,uniphier-wdt.yaml @@ -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 index 000000000000..d90271013191 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/sunplus,sp7021-wdt.yaml @@ -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>; + }; +... diff --git a/MAINTAINERS b/MAINTAINERS index 3577be9c7089..1ce27e0f826e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index c4e82a8d863f..001ae1be9b61 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -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 diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index f7da867e8782..5f88a6237f7c 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -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 diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c index 8656a137e9a4..1ffcf6aca6ae 100644 --- a/drivers/watchdog/bcm7038_wdt.c +++ b/drivers/watchdog/bcm7038_wdt.c @@ -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" }, {}, }; diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index 9adad1862bbd..09a4af4c58fc 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c @@ -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); diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 3f2f4343644f..34693f11385f 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -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, }, }; diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index 4577a76dd464..f0d4e3cc7459 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c @@ -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 */ } diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index db843f825860..053ef3bde12d 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -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); diff --git a/drivers/watchdog/rzg2l_wdt.c b/drivers/watchdog/rzg2l_wdt.c index 6b426df34fd6..6eea0ee4af49 100644 --- a/drivers/watchdog/rzg2l_wdt.c +++ b/drivers/watchdog/rzg2l_wdt.c @@ -21,8 +21,11 @@ #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 index 000000000000..55ab384b9965 --- /dev/null +++ b/drivers/watchdog/rzn1_wdt.c @@ -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"); diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index dbeb2146c968..f9479a3fe2a6 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -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 index 000000000000..e2d8c532bcb1 --- /dev/null +++ b/drivers/watchdog/sunplus_wdt.c @@ -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"); diff --git a/drivers/watchdog/ts4800_wdt.c b/drivers/watchdog/ts4800_wdt.c index c137ad2bd5c3..0ea554c7cda5 100644 --- a/drivers/watchdog/ts4800_wdt.c +++ b/drivers/watchdog/ts4800_wdt.c @@ -125,13 +125,16 @@ static int ts4800_wdt_probe(struct platform_device *pdev) ret = of_property_read_u32_index(np, "syscon", 1, ®); 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; diff --git a/drivers/watchdog/wdat_wdt.c b/drivers/watchdog/wdat_wdt.c index 195c8c004b69..e6f95e99156d 100644 --- a/drivers/watchdog/wdat_wdt.c +++ b/drivers/watchdog/wdat_wdt.c @@ -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 index 000000000000..af3d16c81192 --- /dev/null +++ b/include/dt-bindings/reset/mt7986-resets.h @@ -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 index 000000000000..5f850370c42c --- /dev/null +++ b/include/dt-bindings/reset/mt8186-resets.h @@ -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 */ |