Commit 78b421b6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'linux-watchdog-6.4-rc1' of git://www.linux-watchdog.org/linux-watchdog

Pull watchdog updates from Wim Van Sebroeck:

 - Add watchdog driver for StarFive JH7100 and JH7110 Soc

 - Add Rockchip RK3588 devices

 - Add Qualcom IPQ5332 APSS, QCM2290 KPSS and SM6115 SoC devices

 - Add Mediatke MT8365 and MT6735 devices

 - Watchdog-core: Always set WDOG_HW_RUNNING when starting watchdog

 - Convert watchdog platform drivers to return void on the remove
   callback

 - Convert to devm_clk_get_enabled() helpers

 - ... and other small fixes and improvements

* tag 'linux-watchdog-6.4-rc1' of git://www.linux-watchdog.org/linux-watchdog: (72 commits)
  watchdog: dw_wdt: Simplify clk management
  watchdog: dw_wdt: Fix the error handling path of dw_wdt_drv_probe()
  watchdog: starfive: Fix the warning of starfive_wdt_match
  watchdog: starfive: Fix the probe return error if PM and early_enable are both disabled
  MAINTAINERS: Add fragment for Xilinx watchdog driver
  watchdog: menz069_wdt: fix timeout setting
  watchdog: menz069_wdt: fix watchdog initialisation
  dt-bindings: watchdog: alphascale-asm9260: convert to DT schema
  watchdog: loongson1_wdt: Implement restart handler
  dt-bindings: watchdog: Document Qualcomm SM6115 watchdog
  dt-bindings: watchdog: realtek,otto-wdt: simplify requiring interrupt-names
  dt-bindings: watchdog: toshiba,visconti-wdt: simplify with unevaluatedProperties
  dt-bindings: watchdog: fsl-imx7ulp-wdt: simplify with unevaluatedProperties
  dt-bindings: watchdog: arm,sp805: drop unneeded minItems
  dt-bindings: watchdog: drop duplicated GPIO watchdog bindings
  dt-bindings: reset: Add binding for MediaTek MT6735 TOPRGU/WDT
  drivers: watchdog: Add StarFive Watchdog driver
  dt-bindings: watchdog: Add watchdog for StarFive JH7100 and JH7110
  dt-bindings: watchdog: indentation, quotes and white-space cleanup
  watchdog: ebc-c384_wdt: Mark status as orphaned
  ...
parents 3c4aa443 10f67d1f
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/watchdog/alphascale,asm9260-wdt.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Alphascale asm9260 Watchdog timer
allOf:
- $ref: watchdog.yaml#
maintainers:
- Oleksij Rempel <linux@rempel-privat.de>
properties:
compatible:
const: alphascale,asm9260-wdt
reg:
maxItems: 1
clocks:
items:
- description: source clock, used for tick counter
- description: ahb gate
clock-names:
items:
- const: mod
- const: ahb
interrupts:
maxItems: 1
resets:
maxItems: 1
reset-names:
items:
- const: wdt_rst
alphascale,mode:
description: |
Specifies the reset mode of operation. If set to sw, then reset is handled
via interrupt request, if set to debug, then it does nothing and logs.
$ref: /schemas/types.yaml#/definitions/string
enum: [hw, sw, debug]
default: hw
required:
- compatible
- reg
- clocks
- clock-names
- interrupts
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/alphascale,asm9260.h>
watchdog0: watchdog@80048000 {
compatible = "alphascale,asm9260-wdt";
reg = <0x80048000 0x10>;
clocks = <&acc CLKID_SYS_WDT>, <&acc CLKID_AHB_WDT>;
clock-names = "mod", "ahb";
interrupts = <55>;
timeout-sec = <30>;
alphascale,mode = "hw";
};
Alphascale asm9260 Watchdog timer
Required properties:
- compatible : should be "alphascale,asm9260-wdt".
- reg : Specifies base physical address and size of the registers.
- clocks : the clocks feeding the watchdog timer. See clock-bindings.txt
- clock-names : should be set to
"mod" - source for tick counter.
"ahb" - ahb gate.
- resets : phandle pointing to the system reset controller with
line index for the watchdog.
- reset-names : should be set to "wdt_rst".
Optional properties:
- timeout-sec : shall contain the default watchdog timeout in seconds,
if unset, the default timeout is 30 seconds.
- alphascale,mode : three modes are supported
"hw" - hw reset (default).
"sw" - sw reset.
"debug" - no action is taken.
Example:
watchdog0: watchdog@80048000 {
compatible = "alphascale,asm9260-wdt";
reg = <0x80048000 0x10>;
clocks = <&acc CLKID_SYS_WDT>, <&acc CLKID_AHB_WDT>;
clock-names = "mod", "ahb";
interrupts = <55>;
resets = <&rst WDT_RESET>;
reset-names = "wdt_rst";
timeout-sec = <30>;
alphascale,mode = "hw";
};
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
# Copyright 2019 BayLibre, SAS # Copyright 2019 BayLibre, SAS
%YAML 1.2 %YAML 1.2
--- ---
$id: "http://devicetree.org/schemas/watchdog/amlogic,meson-gxbb-wdt.yaml#" $id: http://devicetree.org/schemas/watchdog/amlogic,meson-gxbb-wdt.yaml#
$schema: "http://devicetree.org/meta-schemas/core.yaml#" $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Meson GXBB SoCs Watchdog timer title: Meson GXBB SoCs Watchdog timer
...@@ -36,7 +36,7 @@ unevaluatedProperties: false ...@@ -36,7 +36,7 @@ unevaluatedProperties: false
examples: examples:
- | - |
watchdog@98d0 { watchdog@98d0 {
compatible = "amlogic,meson-gxbb-wdt"; compatible = "amlogic,meson-gxbb-wdt";
reg = <0x98d0 0x10>; reg = <0x98d0 0x10>;
clocks = <&xtal>; clocks = <&xtal>;
}; };
...@@ -40,7 +40,6 @@ unevaluatedProperties: false ...@@ -40,7 +40,6 @@ unevaluatedProperties: false
examples: examples:
- | - |
watchdog@2a440000 { watchdog@2a440000 {
compatible = "arm,sbsa-gwdt"; compatible = "arm,sbsa-gwdt";
reg = <0x2a440000 0x1000>, reg = <0x2a440000 0x1000>,
......
...@@ -43,7 +43,6 @@ properties: ...@@ -43,7 +43,6 @@ properties:
Clocks driving the watchdog timer hardware. The first clock is used Clocks driving the watchdog timer hardware. The first clock is used
for the actual watchdog counter. The second clock drives the register for the actual watchdog counter. The second clock drives the register
interface. interface.
minItems: 2
maxItems: 2 maxItems: 2
clock-names: clock-names:
......
...@@ -44,7 +44,7 @@ examples: ...@@ -44,7 +44,7 @@ examples:
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/arm-gic.h>
watchdog@2c000620 { watchdog@2c000620 {
compatible = "arm,arm11mp-twd-wdt"; compatible = "arm,arm11mp-twd-wdt";
reg = <0x2c000620 0x20>; reg = <0x2c000620 0x20>;
interrupts = <GIC_PPI 14 0xf01>; interrupts = <GIC_PPI 14 0xf01>;
}; };
...@@ -16,6 +16,7 @@ properties: ...@@ -16,6 +16,7 @@ properties:
compatible: compatible:
enum: enum:
- arm,smc-wdt - arm,smc-wdt
arm,smc-id: arm,smc-id:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
description: | description: |
...@@ -30,9 +31,9 @@ unevaluatedProperties: false ...@@ -30,9 +31,9 @@ unevaluatedProperties: false
examples: examples:
- | - |
watchdog { watchdog {
compatible = "arm,smc-wdt"; compatible = "arm,smc-wdt";
arm,smc-id = <0x82003D06>; arm,smc-id = <0x82003D06>;
timeout-sec = <15>; timeout-sec = <15>;
}; };
... ...
...@@ -65,13 +65,13 @@ examples: ...@@ -65,13 +65,13 @@ examples:
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
watchdog@fc068640 { watchdog@fc068640 {
compatible = "atmel,sama5d4-wdt"; compatible = "atmel,sama5d4-wdt";
reg = <0xfc068640 0x10>; reg = <0xfc068640 0x10>;
interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>; interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>;
timeout-sec = <10>; timeout-sec = <10>;
atmel,watchdog-type = "hardware"; atmel,watchdog-type = "hardware";
atmel,dbg-halt; atmel,dbg-halt;
atmel,idle-halt; atmel,idle-halt;
}; };
... ...
...@@ -37,7 +37,7 @@ required: ...@@ -37,7 +37,7 @@ required:
examples: examples:
- | - |
watchdog@f040a7e8 { watchdog@f040a7e8 {
compatible = "brcm,bcm7038-wdt"; compatible = "brcm,bcm7038-wdt";
reg = <0xf040a7e8 0x16>; reg = <0xf040a7e8 0x16>;
clocks = <&upg_fixed>; clocks = <&upg_fixed>;
}; };
...@@ -52,16 +52,16 @@ examples: ...@@ -52,16 +52,16 @@ examples:
- | - |
#include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/irq.h>
watchdog@41000000 { watchdog@41000000 {
compatible = "faraday,ftwdt010"; compatible = "faraday,ftwdt010";
reg = <0x41000000 0x1000>; reg = <0x41000000 0x1000>;
interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
timeout-sec = <5>; timeout-sec = <5>;
}; };
- | - |
watchdog: watchdog@98500000 { watchdog: watchdog@98500000 {
compatible = "moxa,moxart-watchdog", "faraday,ftwdt010"; compatible = "moxa,moxart-watchdog", "faraday,ftwdt010";
reg = <0x98500000 0x10>; reg = <0x98500000 0x10>;
clocks = <&clk_apb>; clocks = <&clk_apb>;
clock-names = "PCLK"; clock-names = "PCLK";
}; };
... ...
...@@ -30,15 +30,13 @@ properties: ...@@ -30,15 +30,13 @@ properties:
clocks: clocks:
maxItems: 1 maxItems: 1
timeout-sec: true
required: required:
- compatible - compatible
- interrupts - interrupts
- reg - reg
- clocks - clocks
additionalProperties: false unevaluatedProperties: false
examples: examples:
- | - |
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/watchdog/gpio-wdt.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: GPIO controlled watchdog
maintainers:
- Robert Marko <robert.marko@sartura.hr>
properties:
compatible:
const: linux,wdt-gpio
gpios:
maxItems: 1
description: GPIO connected to the WDT reset pin
hw_algo:
$ref: /schemas/types.yaml#/definitions/string
description: Algorithm used by the driver
oneOf:
- description:
Either a high-to-low or a low-to-high transition clears the WDT counter.
The watchdog timer is disabled when GPIO is left floating or connected
to a three-state buffer.
const: toggle
- description:
Low or high level starts counting WDT timeout, the opposite level
disables the WDT.
Active level is determined by the GPIO flags.
const: level
hw_margin_ms:
$ref: /schemas/types.yaml#/definitions/uint32
description: Maximum time to reset watchdog circuit (in milliseconds)
minimum: 2
maximum: 65535
always-running:
type: boolean
description:
If the watchdog timer cannot be disabled, add this flag to have the driver
keep toggling the signal without a client.
It will only cease to toggle the signal when the device is open and the
timeout elapsed.
required:
- compatible
- gpios
- hw_algo
- hw_margin_ms
unevaluatedProperties: false
...@@ -8,6 +8,7 @@ title: GPIO-controlled Watchdog ...@@ -8,6 +8,7 @@ title: GPIO-controlled Watchdog
maintainers: maintainers:
- Guenter Roeck <linux@roeck-us.net> - Guenter Roeck <linux@roeck-us.net>
- Robert Marko <robert.marko@sartura.hr>
properties: properties:
compatible: compatible:
...@@ -19,11 +20,23 @@ properties: ...@@ -19,11 +20,23 @@ properties:
hw_algo: hw_algo:
description: The algorithm used by the driver. description: The algorithm used by the driver.
enum: [ level, toggle ] oneOf:
- description:
Either a high-to-low or a low-to-high transition clears the WDT counter.
The watchdog timer is disabled when GPIO is left floating or connected
to a three-state buffer.
const: toggle
- description:
Low or high level starts counting WDT timeout, the opposite level
disables the WDT.
Active level is determined by the GPIO flags.
const: level
hw_margin_ms: hw_margin_ms:
description: Maximum time to reset watchdog circuit (milliseconds). description: Maximum time to reset watchdog circuit (milliseconds).
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
minimum: 2
maximum: 65535
always-running: always-running:
type: boolean type: boolean
...@@ -42,7 +55,7 @@ required: ...@@ -42,7 +55,7 @@ required:
allOf: allOf:
- $ref: watchdog.yaml# - $ref: watchdog.yaml#
additionalProperties: false unevaluatedProperties: false
examples: examples:
- | - |
......
...@@ -34,7 +34,7 @@ additionalProperties: false ...@@ -34,7 +34,7 @@ additionalProperties: false
examples: examples:
- | - |
watchdog@100 { watchdog@100 {
compatible = "mediatek,mt7621-wdt"; compatible = "mediatek,mt7621-wdt";
reg = <0x100 0x100>; reg = <0x100 0x100>;
mediatek,sysctl = <&sysc>; mediatek,sysctl = <&sysc>;
}; };
...@@ -22,6 +22,7 @@ properties: ...@@ -22,6 +22,7 @@ properties:
- enum: - enum:
- mediatek,mt2712-wdt - mediatek,mt2712-wdt
- mediatek,mt6589-wdt - mediatek,mt6589-wdt
- mediatek,mt6735-wdt
- mediatek,mt6795-wdt - mediatek,mt6795-wdt
- mediatek,mt7986-wdt - mediatek,mt7986-wdt
- mediatek,mt8183-wdt - mediatek,mt8183-wdt
...@@ -38,6 +39,7 @@ properties: ...@@ -38,6 +39,7 @@ properties:
- mediatek,mt7623-wdt - mediatek,mt7623-wdt
- mediatek,mt7629-wdt - mediatek,mt7629-wdt
- mediatek,mt8173-wdt - mediatek,mt8173-wdt
- mediatek,mt8365-wdt
- mediatek,mt8516-wdt - mediatek,mt8516-wdt
- const: mediatek,mt6589-wdt - const: mediatek,mt6589-wdt
......
...@@ -18,7 +18,10 @@ properties: ...@@ -18,7 +18,10 @@ properties:
- items: - items:
- enum: - enum:
- qcom,kpss-wdt-ipq4019 - qcom,kpss-wdt-ipq4019
- qcom,apss-wdt-ipq5332
- qcom,apss-wdt-ipq9574
- qcom,apss-wdt-msm8994 - qcom,apss-wdt-msm8994
- qcom,apss-wdt-qcm2290
- qcom,apss-wdt-qcs404 - qcom,apss-wdt-qcs404
- qcom,apss-wdt-sa8775p - qcom,apss-wdt-sa8775p
- qcom,apss-wdt-sc7180 - qcom,apss-wdt-sc7180
...@@ -28,6 +31,7 @@ properties: ...@@ -28,6 +31,7 @@ properties:
- qcom,apss-wdt-sdm845 - qcom,apss-wdt-sdm845
- qcom,apss-wdt-sdx55 - qcom,apss-wdt-sdx55
- qcom,apss-wdt-sdx65 - qcom,apss-wdt-sdx65
- qcom,apss-wdt-sm6115
- qcom,apss-wdt-sm6350 - qcom,apss-wdt-sm6350
- qcom,apss-wdt-sm8150 - qcom,apss-wdt-sm8150
- qcom,apss-wdt-sm8250 - qcom,apss-wdt-sm8250
...@@ -113,26 +117,26 @@ examples: ...@@ -113,26 +117,26 @@ examples:
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/arm-gic.h>
watchdog@17c10000 { watchdog@17c10000 {
compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt"; compatible = "qcom,apss-wdt-sm8150", "qcom,kpss-wdt";
reg = <0x17c10000 0x1000>; reg = <0x17c10000 0x1000>;
clocks = <&sleep_clk>; clocks = <&sleep_clk>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
timeout-sec = <10>; timeout-sec = <10>;
}; };
- | - |
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/arm-gic.h>
watchdog@200a000 { watchdog@200a000 {
compatible = "qcom,kpss-wdt-ipq8064", "qcom,kpss-timer", "qcom,msm-timer"; compatible = "qcom,kpss-wdt-ipq8064", "qcom,kpss-timer", "qcom,msm-timer";
interrupts = <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>, interrupts = <GIC_PPI 1 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
<GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>, <GIC_PPI 2 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
<GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>, <GIC_PPI 3 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
<GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>, <GIC_PPI 4 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>,
<GIC_PPI 5 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>; <GIC_PPI 5 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_EDGE_RISING)>;
reg = <0x0200a000 0x100>; reg = <0x0200a000 0x100>;
clock-frequency = <25000000>; clock-frequency = <25000000>;
clocks = <&sleep_clk>; clocks = <&sleep_clk>;
clock-names = "sleep"; clock-names = "sleep";
cpu-offset = <0x80000>; cpu-offset = <0x80000>;
}; };
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/watchdog/ralink,rt2880-wdt.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ralink Watchdog Timers
maintainers:
- Sergio Paracuellos <sergio.paracuellos@gmail.com>
allOf:
- $ref: watchdog.yaml#
properties:
compatible:
const: ralink,rt2880-wdt
reg:
maxItems: 1
clocks:
maxItems: 1
resets:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
watchdog@100 {
compatible = "ralink,rt2880-wdt";
reg = <0x120 0x10>;
clocks = <&clkref>;
resets = <&rstctrl 8>;
interrupt-parent = <&intc>;
interrupts = <1>;
};
...@@ -67,12 +67,10 @@ required: ...@@ -67,12 +67,10 @@ required:
- reg - reg
- clocks - clocks
- interrupts - interrupts
- interrupt-names
unevaluatedProperties: false unevaluatedProperties: false
dependencies:
interrupts: [ interrupt-names ]
examples: examples:
- | - |
watchdog: watchdog@3150 { watchdog: watchdog@3150 {
......
...@@ -177,11 +177,11 @@ examples: ...@@ -177,11 +177,11 @@ examples:
#include <dt-bindings/power/r8a7795-sysc.h> #include <dt-bindings/power/r8a7795-sysc.h>
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/arm-gic.h>
wdt0: watchdog@e6020000 { wdt0: watchdog@e6020000 {
compatible = "renesas,r8a7795-wdt", "renesas,rcar-gen3-wdt"; compatible = "renesas,r8a7795-wdt", "renesas,rcar-gen3-wdt";
reg = <0xe6020000 0x0c>; reg = <0xe6020000 0x0c>;
interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cpg CPG_MOD 402>; clocks = <&cpg CPG_MOD 402>;
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>; power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
resets = <&cpg 402>; resets = <&cpg 402>;
timeout-sec = <60>; timeout-sec = <60>;
}; };
Ralink Watchdog Timers
Required properties:
- compatible: must be "ralink,rt2880-wdt"
- reg: physical base address of the controller and length of the register range
Optional properties:
- interrupts: Specify the INTC interrupt number
Example:
watchdog@120 {
compatible = "ralink,rt2880-wdt";
reg = <0x120 0x10>;
interrupt-parent = <&intc>;
interrupts = <1>;
};
...@@ -83,25 +83,25 @@ required: ...@@ -83,25 +83,25 @@ required:
examples: examples:
- | - |
watchdog@ffd02000 { watchdog@ffd02000 {
compatible = "snps,dw-wdt"; compatible = "snps,dw-wdt";
reg = <0xffd02000 0x1000>; reg = <0xffd02000 0x1000>;
interrupts = <0 171 4>; interrupts = <0 171 4>;
clocks = <&per_base_clk>; clocks = <&per_base_clk>;
resets = <&wdt_rst>; resets = <&wdt_rst>;
}; };
- | - |
watchdog@ffd02000 { watchdog@ffd02000 {
compatible = "snps,dw-wdt"; compatible = "snps,dw-wdt";
reg = <0xffd02000 0x1000>; reg = <0xffd02000 0x1000>;
interrupts = <0 171 4>; interrupts = <0 171 4>;
clocks = <&per_base_clk>; clocks = <&per_base_clk>;
clock-names = "tclk"; clock-names = "tclk";
snps,watchdog-tops = <0x000000FF 0x000001FF 0x000003FF snps,watchdog-tops = <0x000000FF 0x000001FF 0x000003FF
0x000007FF 0x0000FFFF 0x0001FFFF 0x000007FF 0x0000FFFF 0x0001FFFF
0x0003FFFF 0x0007FFFF 0x000FFFFF 0x0003FFFF 0x0007FFFF 0x000FFFFF
0x001FFFFF 0x003FFFFF 0x007FFFFF 0x001FFFFF 0x003FFFFF 0x007FFFFF
0x00FFFFFF 0x01FFFFFF 0x03FFFFFF 0x00FFFFFF 0x01FFFFFF 0x03FFFFFF
0x07FFFFFF>; 0x07FFFFFF>;
}; };
... ...
...@@ -48,11 +48,11 @@ examples: ...@@ -48,11 +48,11 @@ examples:
- | - |
#include <dt-bindings/clock/stm32mp1-clks.h> #include <dt-bindings/clock/stm32mp1-clks.h>
watchdog@5a002000 { watchdog@5a002000 {
compatible = "st,stm32mp1-iwdg"; compatible = "st,stm32mp1-iwdg";
reg = <0x5a002000 0x400>; reg = <0x5a002000 0x400>;
clocks = <&rcc IWDG2>, <&rcc CK_LSI>; clocks = <&rcc IWDG2>, <&rcc CK_LSI>;
clock-names = "pclk", "lsi"; clock-names = "pclk", "lsi";
timeout-sec = <32>; timeout-sec = <32>;
}; };
... ...
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/watchdog/starfive,jh7100-wdt.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: StarFive Watchdog for JH7100 and JH7110 SoC
maintainers:
- Xingyu Wu <xingyu.wu@starfivetech.com>
- Samin Guo <samin.guo@starfivetech.com>
description:
The JH7100 and JH7110 watchdog both are 32 bit counters. JH7100 watchdog
has only one timeout phase and reboots. And JH7110 watchdog has two
timeout phases. At the first phase, the signal of watchdog interrupt
output(WDOGINT) will rise when counter is 0. The counter will reload
the timeout value. And then, if counter decreases to 0 again and WDOGINT
isn't cleared, the watchdog will reset the system unless the watchdog
reset is disabled.
allOf:
- $ref: watchdog.yaml#
properties:
compatible:
enum:
- starfive,jh7100-wdt
- starfive,jh7110-wdt
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
items:
- description: APB clock
- description: Core clock
clock-names:
items:
- const: apb
- const: core
resets:
items:
- description: APB reset
- description: Core reset
required:
- compatible
- reg
- clocks
- clock-names
- resets
unevaluatedProperties: false
examples:
- |
watchdog@12480000 {
compatible = "starfive,jh7100-wdt";
reg = <0x12480000 0x10000>;
clocks = <&clk 171>,
<&clk 172>;
clock-names = "apb", "core";
resets = <&rst 99>,
<&rst 100>;
};
...@@ -24,14 +24,12 @@ properties: ...@@ -24,14 +24,12 @@ properties:
clocks: clocks:
maxItems: 1 maxItems: 1
timeout-sec: true
required: required:
- compatible - compatible
- reg - reg
- clocks - clocks
additionalProperties: false unevaluatedProperties: false
examples: examples:
- | - |
......
...@@ -58,11 +58,11 @@ unevaluatedProperties: false ...@@ -58,11 +58,11 @@ unevaluatedProperties: false
examples: examples:
- | - |
watchdog@40100000 { watchdog@40100000 {
compatible = "xlnx,xps-timebase-wdt-1.00.a"; compatible = "xlnx,xps-timebase-wdt-1.00.a";
reg = <0x40100000 0x1000>; reg = <0x40100000 0x1000>;
clock-frequency = <50000000>; clock-frequency = <50000000>;
clocks = <&clkc 15>; clocks = <&clkc 15>;
xlnx,wdt-enable-once = <0x0>; xlnx,wdt-enable-once = <0x0>;
xlnx,wdt-interval = <0x1b>; xlnx,wdt-interval = <0x1b>;
}; };
... ...
...@@ -20136,6 +20136,13 @@ S: Supported ...@@ -20136,6 +20136,13 @@ S: Supported
F: Documentation/devicetree/bindings/rng/starfive* F: Documentation/devicetree/bindings/rng/starfive*
F: drivers/char/hw_random/jh7110-trng.c F: drivers/char/hw_random/jh7110-trng.c
STARFIVE WATCHDOG DRIVER
M: Xingyu Wu <xingyu.wu@starfivetech.com>
M: Samin Guo <samin.guo@starfivetech.com>
S: Supported
F: Documentation/devicetree/bindings/watchdog/starfive*
F: drivers/watchdog/starfive-wdt.c
STATIC BRANCH/CALL STATIC BRANCH/CALL
M: Peter Zijlstra <peterz@infradead.org> M: Peter Zijlstra <peterz@infradead.org>
M: Josh Poimboeuf <jpoimboe@kernel.org> M: Josh Poimboeuf <jpoimboe@kernel.org>
...@@ -22706,9 +22713,8 @@ S: Maintained ...@@ -22706,9 +22713,8 @@ S: Maintained
F: drivers/media/rc/winbond-cir.c F: drivers/media/rc/winbond-cir.c
WINSYSTEMS EBC-C384 WATCHDOG DRIVER WINSYSTEMS EBC-C384 WATCHDOG DRIVER
M: William Breathitt Gray <william.gray@linaro.org>
L: linux-watchdog@vger.kernel.org L: linux-watchdog@vger.kernel.org
S: Maintained S: Orphan
F: drivers/watchdog/ebc-c384_wdt.c F: drivers/watchdog/ebc-c384_wdt.c
WINSYSTEMS WS16C48 GPIO DRIVER WINSYSTEMS WS16C48 GPIO DRIVER
...@@ -23169,6 +23175,14 @@ F: Documentation/devicetree/bindings/media/xilinx/ ...@@ -23169,6 +23175,14 @@ F: Documentation/devicetree/bindings/media/xilinx/
F: drivers/media/platform/xilinx/ F: drivers/media/platform/xilinx/
F: include/uapi/linux/xilinx-v4l2-controls.h F: include/uapi/linux/xilinx-v4l2-controls.h
XILINX WATCHDOG DRIVER
M: Srinivas Neeli <srinivas.neeli@amd.com>
R: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
R: Michal Simek <michal.simek@amd.com>
S: Maintained
F: Documentation/devicetree/bindings/watchdog/xlnx,xps-timebase-wdt.yaml
F: drivers/watchdog/of_xilinx_wdt.c
XILINX XDMA DRIVER XILINX XDMA DRIVER
M: Lizhi Hou <lizhi.hou@amd.com> M: Lizhi Hou <lizhi.hou@amd.com>
M: Brian Xu <brian.xu@amd.com> M: Brian Xu <brian.xu@amd.com>
......
...@@ -1999,6 +1999,17 @@ config WATCHDOG_RTAS ...@@ -1999,6 +1999,17 @@ config WATCHDOG_RTAS
To compile this driver as a module, choose M here. The module To compile this driver as a module, choose M here. The module
will be called wdrtas. will be called wdrtas.
# RISC-V Architecture
config STARFIVE_WATCHDOG
tristate "StarFive Watchdog support"
depends on ARCH_STARFIVE || COMPILE_TEST
select WATCHDOG_CORE
default ARCH_STARFIVE
help
Say Y here to support the watchdog of StarFive JH7100 and JH7110
SoC. This driver can also be built as a module if choose M.
# S390 Architecture # S390 Architecture
config DIAG288_WATCHDOG config DIAG288_WATCHDOG
......
...@@ -192,6 +192,9 @@ obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt.o ...@@ -192,6 +192,9 @@ obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt.o
obj-$(CONFIG_PSERIES_WDT) += pseries-wdt.o obj-$(CONFIG_PSERIES_WDT) += pseries-wdt.o
obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
# RISC-V Architecture
obj-$(CONFIG_STARFIVE_WATCHDOG) += starfive-wdt.o
# S390 Architecture # S390 Architecture
obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o
......
...@@ -271,14 +271,12 @@ static int __init acq_probe(struct platform_device *dev) ...@@ -271,14 +271,12 @@ static int __init acq_probe(struct platform_device *dev)
return ret; return ret;
} }
static int acq_remove(struct platform_device *dev) static void acq_remove(struct platform_device *dev)
{ {
misc_deregister(&acq_miscdev); misc_deregister(&acq_miscdev);
release_region(wdt_start, 1); release_region(wdt_start, 1);
if (wdt_stop != wdt_start) if (wdt_stop != wdt_start)
release_region(wdt_stop, 1); release_region(wdt_stop, 1);
return 0;
} }
static void acq_shutdown(struct platform_device *dev) static void acq_shutdown(struct platform_device *dev)
...@@ -288,7 +286,7 @@ static void acq_shutdown(struct platform_device *dev) ...@@ -288,7 +286,7 @@ static void acq_shutdown(struct platform_device *dev)
} }
static struct platform_driver acquirewdt_driver = { static struct platform_driver acquirewdt_driver = {
.remove = acq_remove, .remove_new = acq_remove,
.shutdown = acq_shutdown, .shutdown = acq_shutdown,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
......
...@@ -279,14 +279,12 @@ static int __init advwdt_probe(struct platform_device *dev) ...@@ -279,14 +279,12 @@ static int __init advwdt_probe(struct platform_device *dev)
goto out; goto out;
} }
static int advwdt_remove(struct platform_device *dev) static void advwdt_remove(struct platform_device *dev)
{ {
misc_deregister(&advwdt_miscdev); misc_deregister(&advwdt_miscdev);
release_region(wdt_start, 1); release_region(wdt_start, 1);
if (wdt_stop != wdt_start) if (wdt_stop != wdt_start)
release_region(wdt_stop, 1); release_region(wdt_stop, 1);
return 0;
} }
static void advwdt_shutdown(struct platform_device *dev) static void advwdt_shutdown(struct platform_device *dev)
...@@ -296,7 +294,7 @@ static void advwdt_shutdown(struct platform_device *dev) ...@@ -296,7 +294,7 @@ static void advwdt_shutdown(struct platform_device *dev)
} }
static struct platform_driver advwdt_driver = { static struct platform_driver advwdt_driver = {
.remove = advwdt_remove, .remove_new = advwdt_remove,
.shutdown = advwdt_shutdown, .shutdown = advwdt_shutdown,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
......
...@@ -290,12 +290,11 @@ static int ar7_wdt_probe(struct platform_device *pdev) ...@@ -290,12 +290,11 @@ static int ar7_wdt_probe(struct platform_device *pdev)
return rc; return rc;
} }
static int ar7_wdt_remove(struct platform_device *pdev) static void ar7_wdt_remove(struct platform_device *pdev)
{ {
misc_deregister(&ar7_wdt_miscdev); misc_deregister(&ar7_wdt_miscdev);
clk_put(vbus_clk); clk_put(vbus_clk);
vbus_clk = NULL; vbus_clk = NULL;
return 0;
} }
static void ar7_wdt_shutdown(struct platform_device *pdev) static void ar7_wdt_shutdown(struct platform_device *pdev)
...@@ -306,7 +305,7 @@ static void ar7_wdt_shutdown(struct platform_device *pdev) ...@@ -306,7 +305,7 @@ static void ar7_wdt_shutdown(struct platform_device *pdev)
static struct platform_driver ar7_wdt_driver = { static struct platform_driver ar7_wdt_driver = {
.probe = ar7_wdt_probe, .probe = ar7_wdt_probe,
.remove = ar7_wdt_remove, .remove_new = ar7_wdt_remove,
.shutdown = ar7_wdt_shutdown, .shutdown = ar7_wdt_shutdown,
.driver = { .driver = {
.name = "ar7_wdt", .name = "ar7_wdt",
......
...@@ -465,7 +465,7 @@ static struct platform_driver aspeed_watchdog_driver = { ...@@ -465,7 +465,7 @@ static struct platform_driver aspeed_watchdog_driver = {
.probe = aspeed_wdt_probe, .probe = aspeed_wdt_probe,
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.of_match_table = of_match_ptr(aspeed_wdt_of_table), .of_match_table = aspeed_wdt_of_table,
}, },
}; };
......
...@@ -258,7 +258,7 @@ static int at91wdt_probe(struct platform_device *pdev) ...@@ -258,7 +258,7 @@ static int at91wdt_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int at91wdt_remove(struct platform_device *pdev) static void at91wdt_remove(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
int res; int res;
...@@ -269,8 +269,6 @@ static int at91wdt_remove(struct platform_device *pdev) ...@@ -269,8 +269,6 @@ static int at91wdt_remove(struct platform_device *pdev)
misc_deregister(&at91wdt_miscdev); misc_deregister(&at91wdt_miscdev);
at91wdt_miscdev.parent = NULL; at91wdt_miscdev.parent = NULL;
return 0;
} }
static void at91wdt_shutdown(struct platform_device *pdev) static void at91wdt_shutdown(struct platform_device *pdev)
...@@ -299,7 +297,7 @@ MODULE_DEVICE_TABLE(of, at91_wdt_dt_ids); ...@@ -299,7 +297,7 @@ MODULE_DEVICE_TABLE(of, at91_wdt_dt_ids);
static struct platform_driver at91wdt_driver = { static struct platform_driver at91wdt_driver = {
.probe = at91wdt_probe, .probe = at91wdt_probe,
.remove = at91wdt_remove, .remove_new = at91wdt_remove,
.shutdown = at91wdt_shutdown, .shutdown = at91wdt_shutdown,
.suspend = pm_ptr(at91wdt_suspend), .suspend = pm_ptr(at91wdt_suspend),
.resume = pm_ptr(at91wdt_resume), .resume = pm_ptr(at91wdt_resume),
......
...@@ -296,11 +296,10 @@ static int ath79_wdt_probe(struct platform_device *pdev) ...@@ -296,11 +296,10 @@ static int ath79_wdt_probe(struct platform_device *pdev)
return err; return err;
} }
static int ath79_wdt_remove(struct platform_device *pdev) static void ath79_wdt_remove(struct platform_device *pdev)
{ {
misc_deregister(&ath79_wdt_miscdev); misc_deregister(&ath79_wdt_miscdev);
clk_disable_unprepare(wdt_clk); clk_disable_unprepare(wdt_clk);
return 0;
} }
static void ath79_wdt_shutdown(struct platform_device *pdev) static void ath79_wdt_shutdown(struct platform_device *pdev)
...@@ -318,7 +317,7 @@ MODULE_DEVICE_TABLE(of, ath79_wdt_match); ...@@ -318,7 +317,7 @@ MODULE_DEVICE_TABLE(of, ath79_wdt_match);
static struct platform_driver ath79_wdt_driver = { static struct platform_driver ath79_wdt_driver = {
.probe = ath79_wdt_probe, .probe = ath79_wdt_probe,
.remove = ath79_wdt_remove, .remove_new = ath79_wdt_remove,
.shutdown = ath79_wdt_shutdown, .shutdown = ath79_wdt_shutdown,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
......
...@@ -218,17 +218,15 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) ...@@ -218,17 +218,15 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int bcm2835_wdt_remove(struct platform_device *pdev) static void bcm2835_wdt_remove(struct platform_device *pdev)
{ {
if (pm_power_off == bcm2835_power_off) if (pm_power_off == bcm2835_power_off)
pm_power_off = NULL; pm_power_off = NULL;
return 0;
} }
static struct platform_driver bcm2835_wdt_driver = { static struct platform_driver bcm2835_wdt_driver = {
.probe = bcm2835_wdt_probe, .probe = bcm2835_wdt_probe,
.remove = bcm2835_wdt_remove, .remove_new = bcm2835_wdt_remove,
.driver = { .driver = {
.name = "bcm2835-wdt", .name = "bcm2835-wdt",
}, },
......
...@@ -202,7 +202,7 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev) ...@@ -202,7 +202,7 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev)
watchdog_set_restart_priority(&wdt->wdd, 64); watchdog_set_restart_priority(&wdt->wdd, 64);
watchdog_stop_on_reboot(&wdt->wdd); watchdog_stop_on_reboot(&wdt->wdd);
ret = watchdog_register_device(&wdt->wdd); ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);
if (ret) if (ret)
goto err_timer; goto err_timer;
...@@ -218,21 +218,11 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev) ...@@ -218,21 +218,11 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int bcm47xx_wdt_remove(struct platform_device *pdev)
{
struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
watchdog_unregister_device(&wdt->wdd);
return 0;
}
static struct platform_driver bcm47xx_wdt_driver = { static struct platform_driver bcm47xx_wdt_driver = {
.driver = { .driver = {
.name = "bcm47xx-wdt", .name = "bcm47xx-wdt",
}, },
.probe = bcm47xx_wdt_probe, .probe = bcm47xx_wdt_probe,
.remove = bcm47xx_wdt_remove,
}; };
module_platform_driver(bcm47xx_wdt_driver); module_platform_driver(bcm47xx_wdt_driver);
......
...@@ -310,12 +310,10 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev) ...@@ -310,12 +310,10 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int bcm_kona_wdt_remove(struct platform_device *pdev) static void bcm_kona_wdt_remove(struct platform_device *pdev)
{ {
bcm_kona_wdt_debug_exit(pdev); bcm_kona_wdt_debug_exit(pdev);
dev_dbg(&pdev->dev, "Watchdog driver disabled"); dev_dbg(&pdev->dev, "Watchdog driver disabled");
return 0;
} }
static const struct of_device_id bcm_kona_wdt_of_match[] = { static const struct of_device_id bcm_kona_wdt_of_match[] = {
...@@ -330,7 +328,7 @@ static struct platform_driver bcm_kona_wdt_driver = { ...@@ -330,7 +328,7 @@ static struct platform_driver bcm_kona_wdt_driver = {
.of_match_table = bcm_kona_wdt_of_match, .of_match_table = bcm_kona_wdt_of_match,
}, },
.probe = bcm_kona_wdt_probe, .probe = bcm_kona_wdt_probe,
.remove = bcm_kona_wdt_remove, .remove_new = bcm_kona_wdt_remove,
}; };
module_platform_driver(bcm_kona_wdt_driver); module_platform_driver(bcm_kona_wdt_driver);
......
...@@ -614,7 +614,7 @@ static int cpwd_probe(struct platform_device *op) ...@@ -614,7 +614,7 @@ static int cpwd_probe(struct platform_device *op)
return err; return err;
} }
static int cpwd_remove(struct platform_device *op) static void cpwd_remove(struct platform_device *op)
{ {
struct cpwd *p = platform_get_drvdata(op); struct cpwd *p = platform_get_drvdata(op);
int i; int i;
...@@ -638,8 +638,6 @@ static int cpwd_remove(struct platform_device *op) ...@@ -638,8 +638,6 @@ static int cpwd_remove(struct platform_device *op)
of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
cpwd_device = NULL; cpwd_device = NULL;
return 0;
} }
static const struct of_device_id cpwd_match[] = { static const struct of_device_id cpwd_match[] = {
...@@ -656,7 +654,7 @@ static struct platform_driver cpwd_driver = { ...@@ -656,7 +654,7 @@ static struct platform_driver cpwd_driver = {
.of_match_table = cpwd_match, .of_match_table = cpwd_match,
}, },
.probe = cpwd_probe, .probe = cpwd_probe,
.remove = cpwd_remove, .remove_new = cpwd_remove,
}; };
module_platform_driver(cpwd_driver); module_platform_driver(cpwd_driver);
...@@ -566,22 +566,16 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) ...@@ -566,22 +566,16 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
* to the common timer/bus clocks configuration, in which the very * to the common timer/bus clocks configuration, in which the very
* first found clock supply both timer and APB signals. * first found clock supply both timer and APB signals.
*/ */
dw_wdt->clk = devm_clk_get(dev, "tclk"); dw_wdt->clk = devm_clk_get_enabled(dev, "tclk");
if (IS_ERR(dw_wdt->clk)) { if (IS_ERR(dw_wdt->clk)) {
dw_wdt->clk = devm_clk_get(dev, NULL); dw_wdt->clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(dw_wdt->clk)) if (IS_ERR(dw_wdt->clk))
return PTR_ERR(dw_wdt->clk); return PTR_ERR(dw_wdt->clk);
} }
ret = clk_prepare_enable(dw_wdt->clk);
if (ret)
return ret;
dw_wdt->rate = clk_get_rate(dw_wdt->clk); dw_wdt->rate = clk_get_rate(dw_wdt->clk);
if (dw_wdt->rate == 0) { if (dw_wdt->rate == 0)
ret = -EINVAL; return -EINVAL;
goto out_disable_clk;
}
/* /*
* Request APB clock if device is configured with async clocks mode. * Request APB clock if device is configured with async clocks mode.
...@@ -590,21 +584,13 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) ...@@ -590,21 +584,13 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
* so the pclk phandle reference is left optional. If it couldn't be * so the pclk phandle reference is left optional. If it couldn't be
* found we consider the device configured in synchronous clocks mode. * found we consider the device configured in synchronous clocks mode.
*/ */
dw_wdt->pclk = devm_clk_get_optional(dev, "pclk"); dw_wdt->pclk = devm_clk_get_optional_enabled(dev, "pclk");
if (IS_ERR(dw_wdt->pclk)) { if (IS_ERR(dw_wdt->pclk))
ret = PTR_ERR(dw_wdt->pclk); return PTR_ERR(dw_wdt->pclk);
goto out_disable_clk;
}
ret = clk_prepare_enable(dw_wdt->pclk);
if (ret)
goto out_disable_clk;
dw_wdt->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); dw_wdt->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
if (IS_ERR(dw_wdt->rst)) { if (IS_ERR(dw_wdt->rst))
ret = PTR_ERR(dw_wdt->rst); return PTR_ERR(dw_wdt->rst);
goto out_disable_pclk;
}
/* Enable normal reset without pre-timeout by default. */ /* Enable normal reset without pre-timeout by default. */
dw_wdt_update_mode(dw_wdt, DW_WDT_RMOD_RESET); dw_wdt_update_mode(dw_wdt, DW_WDT_RMOD_RESET);
...@@ -621,12 +607,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) ...@@ -621,12 +607,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
IRQF_SHARED | IRQF_TRIGGER_RISING, IRQF_SHARED | IRQF_TRIGGER_RISING,
pdev->name, dw_wdt); pdev->name, dw_wdt);
if (ret) if (ret)
goto out_disable_pclk; return ret;
dw_wdt->wdd.info = &dw_wdt_pt_ident; dw_wdt->wdd.info = &dw_wdt_pt_ident;
} else { } else {
if (ret == -EPROBE_DEFER) if (ret == -EPROBE_DEFER)
goto out_disable_pclk; return ret;
dw_wdt->wdd.info = &dw_wdt_ident; dw_wdt->wdd.info = &dw_wdt_ident;
} }
...@@ -635,7 +621,7 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) ...@@ -635,7 +621,7 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
ret = dw_wdt_init_timeouts(dw_wdt, dev); ret = dw_wdt_init_timeouts(dw_wdt, dev);
if (ret) if (ret)
goto out_disable_clk; goto out_assert_rst;
wdd = &dw_wdt->wdd; wdd = &dw_wdt->wdd;
wdd->ops = &dw_wdt_ops; wdd->ops = &dw_wdt_ops;
...@@ -667,21 +653,18 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) ...@@ -667,21 +653,18 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
ret = watchdog_register_device(wdd); ret = watchdog_register_device(wdd);
if (ret) if (ret)
goto out_disable_pclk; goto out_assert_rst;
dw_wdt_dbgfs_init(dw_wdt); dw_wdt_dbgfs_init(dw_wdt);
return 0; return 0;
out_disable_pclk: out_assert_rst:
clk_disable_unprepare(dw_wdt->pclk); reset_control_assert(dw_wdt->rst);
out_disable_clk:
clk_disable_unprepare(dw_wdt->clk);
return ret; return ret;
} }
static int dw_wdt_drv_remove(struct platform_device *pdev) static void dw_wdt_drv_remove(struct platform_device *pdev)
{ {
struct dw_wdt *dw_wdt = platform_get_drvdata(pdev); struct dw_wdt *dw_wdt = platform_get_drvdata(pdev);
...@@ -689,10 +672,6 @@ static int dw_wdt_drv_remove(struct platform_device *pdev) ...@@ -689,10 +672,6 @@ static int dw_wdt_drv_remove(struct platform_device *pdev)
watchdog_unregister_device(&dw_wdt->wdd); watchdog_unregister_device(&dw_wdt->wdd);
reset_control_assert(dw_wdt->rst); reset_control_assert(dw_wdt->rst);
clk_disable_unprepare(dw_wdt->pclk);
clk_disable_unprepare(dw_wdt->clk);
return 0;
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF
...@@ -705,7 +684,7 @@ MODULE_DEVICE_TABLE(of, dw_wdt_of_match); ...@@ -705,7 +684,7 @@ MODULE_DEVICE_TABLE(of, dw_wdt_of_match);
static struct platform_driver dw_wdt_driver = { static struct platform_driver dw_wdt_driver = {
.probe = dw_wdt_drv_probe, .probe = dw_wdt_drv_probe,
.remove = dw_wdt_drv_remove, .remove_new = dw_wdt_drv_remove,
.driver = { .driver = {
.name = "dw_wdt", .name = "dw_wdt",
.of_match_table = of_match_ptr(dw_wdt_of_match), .of_match_table = of_match_ptr(dw_wdt_of_match),
......
...@@ -283,15 +283,13 @@ static int gef_wdt_probe(struct platform_device *dev) ...@@ -283,15 +283,13 @@ static int gef_wdt_probe(struct platform_device *dev)
return misc_register(&gef_wdt_miscdev); return misc_register(&gef_wdt_miscdev);
} }
static int gef_wdt_remove(struct platform_device *dev) static void gef_wdt_remove(struct platform_device *dev)
{ {
misc_deregister(&gef_wdt_miscdev); misc_deregister(&gef_wdt_miscdev);
gef_wdt_handler_disable(); gef_wdt_handler_disable();
iounmap(gef_wdt_regs); iounmap(gef_wdt_regs);
return 0;
} }
static const struct of_device_id gef_wdt_ids[] = { static const struct of_device_id gef_wdt_ids[] = {
...@@ -308,7 +306,7 @@ static struct platform_driver gef_wdt_driver = { ...@@ -308,7 +306,7 @@ static struct platform_driver gef_wdt_driver = {
.of_match_table = gef_wdt_ids, .of_match_table = gef_wdt_ids,
}, },
.probe = gef_wdt_probe, .probe = gef_wdt_probe,
.remove = gef_wdt_remove, .remove_new = gef_wdt_remove,
}; };
static int __init gef_wdt_init(void) static int __init gef_wdt_init(void)
......
...@@ -238,10 +238,9 @@ static int __init geodewdt_probe(struct platform_device *dev) ...@@ -238,10 +238,9 @@ static int __init geodewdt_probe(struct platform_device *dev)
return ret; return ret;
} }
static int geodewdt_remove(struct platform_device *dev) static void geodewdt_remove(struct platform_device *dev)
{ {
misc_deregister(&geodewdt_miscdev); misc_deregister(&geodewdt_miscdev);
return 0;
} }
static void geodewdt_shutdown(struct platform_device *dev) static void geodewdt_shutdown(struct platform_device *dev)
...@@ -250,7 +249,7 @@ static void geodewdt_shutdown(struct platform_device *dev) ...@@ -250,7 +249,7 @@ static void geodewdt_shutdown(struct platform_device *dev)
} }
static struct platform_driver geodewdt_driver = { static struct platform_driver geodewdt_driver = {
.remove = geodewdt_remove, .remove_new = geodewdt_remove,
.shutdown = geodewdt_shutdown, .shutdown = geodewdt_shutdown,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
......
...@@ -316,14 +316,13 @@ static int __init ibwdt_probe(struct platform_device *dev) ...@@ -316,14 +316,13 @@ static int __init ibwdt_probe(struct platform_device *dev)
return res; return res;
} }
static int ibwdt_remove(struct platform_device *dev) static void ibwdt_remove(struct platform_device *dev)
{ {
misc_deregister(&ibwdt_miscdev); misc_deregister(&ibwdt_miscdev);
release_region(WDT_START, 1); release_region(WDT_START, 1);
#if WDT_START != WDT_STOP #if WDT_START != WDT_STOP
release_region(WDT_STOP, 1); release_region(WDT_STOP, 1);
#endif #endif
return 0;
} }
static void ibwdt_shutdown(struct platform_device *dev) static void ibwdt_shutdown(struct platform_device *dev)
...@@ -333,7 +332,7 @@ static void ibwdt_shutdown(struct platform_device *dev) ...@@ -333,7 +332,7 @@ static void ibwdt_shutdown(struct platform_device *dev)
} }
static struct platform_driver ibwdt_driver = { static struct platform_driver ibwdt_driver = {
.remove = ibwdt_remove, .remove_new = ibwdt_remove,
.shutdown = ibwdt_shutdown, .shutdown = ibwdt_shutdown,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
......
...@@ -266,7 +266,7 @@ static int ie6xx_wdt_probe(struct platform_device *pdev) ...@@ -266,7 +266,7 @@ static int ie6xx_wdt_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int ie6xx_wdt_remove(struct platform_device *pdev) static void ie6xx_wdt_remove(struct platform_device *pdev)
{ {
struct resource *res; struct resource *res;
...@@ -276,13 +276,11 @@ static int ie6xx_wdt_remove(struct platform_device *pdev) ...@@ -276,13 +276,11 @@ static int ie6xx_wdt_remove(struct platform_device *pdev)
ie6xx_wdt_debugfs_exit(); ie6xx_wdt_debugfs_exit();
release_region(res->start, resource_size(res)); release_region(res->start, resource_size(res));
ie6xx_wdt_data.sch_wdtba = 0; ie6xx_wdt_data.sch_wdtba = 0;
return 0;
} }
static struct platform_driver ie6xx_wdt_driver = { static struct platform_driver ie6xx_wdt_driver = {
.probe = ie6xx_wdt_probe, .probe = ie6xx_wdt_probe,
.remove = ie6xx_wdt_remove, .remove_new = ie6xx_wdt_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
}, },
......
...@@ -439,11 +439,11 @@ static int __maybe_unused imx2_wdt_resume(struct device *dev) ...@@ -439,11 +439,11 @@ static int __maybe_unused imx2_wdt_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend, static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
imx2_wdt_resume); imx2_wdt_resume);
struct imx2_wdt_data imx_wdt = { static struct imx2_wdt_data imx_wdt = {
.wdw_supported = true, .wdw_supported = true,
}; };
struct imx2_wdt_data imx_wdt_legacy = { static struct imx2_wdt_data imx_wdt_legacy = {
.wdw_supported = false, .wdw_supported = false,
}; };
......
...@@ -112,12 +112,6 @@ static const struct watchdog_info ixp4xx_wdt_info = { ...@@ -112,12 +112,6 @@ static const struct watchdog_info ixp4xx_wdt_info = {
.identity = KBUILD_MODNAME, .identity = KBUILD_MODNAME,
}; };
/* Devres-handled clock disablement */
static void ixp4xx_clock_action(void *d)
{
clk_disable_unprepare(d);
}
static int ixp4xx_wdt_probe(struct platform_device *pdev) static int ixp4xx_wdt_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -139,16 +133,10 @@ static int ixp4xx_wdt_probe(struct platform_device *pdev) ...@@ -139,16 +133,10 @@ static int ixp4xx_wdt_probe(struct platform_device *pdev)
* Retrieve rate from a fixed clock from the device tree if * Retrieve rate from a fixed clock from the device tree if
* the parent has that, else use the default clock rate. * the parent has that, else use the default clock rate.
*/ */
clk = devm_clk_get(dev->parent, NULL); clk = devm_clk_get_enabled(dev->parent, NULL);
if (!IS_ERR(clk)) { if (!IS_ERR(clk))
ret = clk_prepare_enable(clk);
if (ret)
return ret;
ret = devm_add_action_or_reset(dev, ixp4xx_clock_action, clk);
if (ret)
return ret;
iwdt->rate = clk_get_rate(clk); iwdt->rate = clk_get_rate(clk);
}
if (!iwdt->rate) if (!iwdt->rate)
iwdt->rate = IXP4XX_TIMER_FREQ; iwdt->rate = IXP4XX_TIMER_FREQ;
......
...@@ -7,7 +7,11 @@ ...@@ -7,7 +7,11 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <loongson1.h>
/* Loongson 1 Watchdog Register Definitions */
#define WDT_EN 0x0
#define WDT_TIMER 0x4
#define WDT_SET 0x8
#define DEFAULT_HEARTBEAT 30 #define DEFAULT_HEARTBEAT 30
...@@ -66,6 +70,18 @@ static int ls1x_wdt_stop(struct watchdog_device *wdt_dev) ...@@ -66,6 +70,18 @@ static int ls1x_wdt_stop(struct watchdog_device *wdt_dev)
return 0; return 0;
} }
static int ls1x_wdt_restart(struct watchdog_device *wdt_dev,
unsigned long action, void *data)
{
struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev);
writel(0x1, drvdata->base + WDT_EN);
writel(0x1, drvdata->base + WDT_TIMER);
writel(0x1, drvdata->base + WDT_SET);
return 0;
}
static const struct watchdog_info ls1x_wdt_info = { static const struct watchdog_info ls1x_wdt_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
.identity = "Loongson1 Watchdog", .identity = "Loongson1 Watchdog",
...@@ -77,13 +93,9 @@ static const struct watchdog_ops ls1x_wdt_ops = { ...@@ -77,13 +93,9 @@ static const struct watchdog_ops ls1x_wdt_ops = {
.stop = ls1x_wdt_stop, .stop = ls1x_wdt_stop,
.ping = ls1x_wdt_ping, .ping = ls1x_wdt_ping,
.set_timeout = ls1x_wdt_set_timeout, .set_timeout = ls1x_wdt_set_timeout,
.restart = ls1x_wdt_restart,
}; };
static void ls1x_clk_disable_unprepare(void *data)
{
clk_disable_unprepare(data);
}
static int ls1x_wdt_probe(struct platform_device *pdev) static int ls1x_wdt_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -100,20 +112,10 @@ static int ls1x_wdt_probe(struct platform_device *pdev) ...@@ -100,20 +112,10 @@ static int ls1x_wdt_probe(struct platform_device *pdev)
if (IS_ERR(drvdata->base)) if (IS_ERR(drvdata->base))
return PTR_ERR(drvdata->base); return PTR_ERR(drvdata->base);
drvdata->clk = devm_clk_get(dev, pdev->name); drvdata->clk = devm_clk_get_enabled(dev, pdev->name);
if (IS_ERR(drvdata->clk)) if (IS_ERR(drvdata->clk))
return PTR_ERR(drvdata->clk); return PTR_ERR(drvdata->clk);
err = clk_prepare_enable(drvdata->clk);
if (err) {
dev_err(dev, "clk enable failed\n");
return err;
}
err = devm_add_action_or_reset(dev, ls1x_clk_disable_unprepare,
drvdata->clk);
if (err)
return err;
clk_rate = clk_get_rate(drvdata->clk); clk_rate = clk_get_rate(drvdata->clk);
if (!clk_rate) if (!clk_rate)
return -EINVAL; return -EINVAL;
......
...@@ -261,14 +261,12 @@ static int lpc18xx_wdt_probe(struct platform_device *pdev) ...@@ -261,14 +261,12 @@ static int lpc18xx_wdt_probe(struct platform_device *pdev)
return devm_watchdog_register_device(dev, &lpc18xx_wdt->wdt_dev); return devm_watchdog_register_device(dev, &lpc18xx_wdt->wdt_dev);
} }
static int lpc18xx_wdt_remove(struct platform_device *pdev) static void lpc18xx_wdt_remove(struct platform_device *pdev)
{ {
struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev); struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev);
dev_warn(&pdev->dev, "I quit now, hardware will probably reboot!\n"); dev_warn(&pdev->dev, "I quit now, hardware will probably reboot!\n");
del_timer_sync(&lpc18xx_wdt->timer); del_timer_sync(&lpc18xx_wdt->timer);
return 0;
} }
static const struct of_device_id lpc18xx_wdt_match[] = { static const struct of_device_id lpc18xx_wdt_match[] = {
...@@ -283,7 +281,7 @@ static struct platform_driver lpc18xx_wdt_driver = { ...@@ -283,7 +281,7 @@ static struct platform_driver lpc18xx_wdt_driver = {
.of_match_table = lpc18xx_wdt_match, .of_match_table = lpc18xx_wdt_match,
}, },
.probe = lpc18xx_wdt_probe, .probe = lpc18xx_wdt_probe,
.remove = lpc18xx_wdt_remove, .remove_new = lpc18xx_wdt_remove,
}; };
module_platform_driver(lpc18xx_wdt_driver); module_platform_driver(lpc18xx_wdt_driver);
......
...@@ -77,7 +77,7 @@ static int men_z069_wdt_set_timeout(struct watchdog_device *wdt, ...@@ -77,7 +77,7 @@ static int men_z069_wdt_set_timeout(struct watchdog_device *wdt,
wdt->timeout = timeout; wdt->timeout = timeout;
val = timeout * MEN_Z069_TIMER_FREQ; val = timeout * MEN_Z069_TIMER_FREQ;
reg = readw(drv->base + MEN_Z069_WVR); reg = readw(drv->base + MEN_Z069_WTR);
ena = reg & MEN_Z069_WTR_WDEN; ena = reg & MEN_Z069_WTR_WDEN;
reg = ena | val; reg = ena | val;
writew(reg, drv->base + MEN_Z069_WTR); writew(reg, drv->base + MEN_Z069_WTR);
...@@ -98,14 +98,6 @@ static const struct watchdog_ops men_z069_ops = { ...@@ -98,14 +98,6 @@ static const struct watchdog_ops men_z069_ops = {
.set_timeout = men_z069_wdt_set_timeout, .set_timeout = men_z069_wdt_set_timeout,
}; };
static struct watchdog_device men_z069_wdt = {
.info = &men_z069_info,
.ops = &men_z069_ops,
.timeout = MEN_Z069_DEFAULT_TIMEOUT,
.min_timeout = 1,
.max_timeout = MEN_Z069_WDT_COUNTER_MAX / MEN_Z069_TIMER_FREQ,
};
static int men_z069_probe(struct mcb_device *dev, static int men_z069_probe(struct mcb_device *dev,
const struct mcb_device_id *id) const struct mcb_device_id *id)
{ {
...@@ -125,15 +117,19 @@ static int men_z069_probe(struct mcb_device *dev, ...@@ -125,15 +117,19 @@ static int men_z069_probe(struct mcb_device *dev,
goto release_mem; goto release_mem;
drv->mem = mem; drv->mem = mem;
drv->wdt.info = &men_z069_info;
drv->wdt.ops = &men_z069_ops;
drv->wdt.timeout = MEN_Z069_DEFAULT_TIMEOUT;
drv->wdt.min_timeout = 1;
drv->wdt.max_timeout = MEN_Z069_WDT_COUNTER_MAX / MEN_Z069_TIMER_FREQ;
drv->wdt = men_z069_wdt;
watchdog_init_timeout(&drv->wdt, 0, &dev->dev); watchdog_init_timeout(&drv->wdt, 0, &dev->dev);
watchdog_set_nowayout(&drv->wdt, nowayout); watchdog_set_nowayout(&drv->wdt, nowayout);
watchdog_set_drvdata(&drv->wdt, drv); watchdog_set_drvdata(&drv->wdt, drv);
drv->wdt.parent = &dev->dev; drv->wdt.parent = &dev->dev;
mcb_set_drvdata(dev, drv); mcb_set_drvdata(dev, drv);
return watchdog_register_device(&men_z069_wdt); return watchdog_register_device(&drv->wdt);
release_mem: release_mem:
mcb_release_mem(mem); mcb_release_mem(mem);
......
...@@ -221,7 +221,7 @@ static int mtx1_wdt_probe(struct platform_device *pdev) ...@@ -221,7 +221,7 @@ static int mtx1_wdt_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int mtx1_wdt_remove(struct platform_device *pdev) static void mtx1_wdt_remove(struct platform_device *pdev)
{ {
/* FIXME: do we need to lock this test ? */ /* FIXME: do we need to lock this test ? */
if (mtx1_wdt_device.queue) { if (mtx1_wdt_device.queue) {
...@@ -230,12 +230,11 @@ static int mtx1_wdt_remove(struct platform_device *pdev) ...@@ -230,12 +230,11 @@ static int mtx1_wdt_remove(struct platform_device *pdev)
} }
misc_deregister(&mtx1_wdt_misc); misc_deregister(&mtx1_wdt_misc);
return 0;
} }
static struct platform_driver mtx1_wdt_driver = { static struct platform_driver mtx1_wdt_driver = {
.probe = mtx1_wdt_probe, .probe = mtx1_wdt_probe,
.remove = mtx1_wdt_remove, .remove_new = mtx1_wdt_remove,
.driver.name = "mtx1-wdt", .driver.name = "mtx1-wdt",
.driver.owner = THIS_MODULE, .driver.owner = THIS_MODULE,
}; };
......
...@@ -218,7 +218,7 @@ static int nic7018_probe(struct platform_device *pdev) ...@@ -218,7 +218,7 @@ static int nic7018_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int nic7018_remove(struct platform_device *pdev) static void nic7018_remove(struct platform_device *pdev)
{ {
struct nic7018_wdt *wdt = platform_get_drvdata(pdev); struct nic7018_wdt *wdt = platform_get_drvdata(pdev);
...@@ -226,8 +226,6 @@ static int nic7018_remove(struct platform_device *pdev) ...@@ -226,8 +226,6 @@ static int nic7018_remove(struct platform_device *pdev)
/* Lock WDT register */ /* Lock WDT register */
outb(LOCK, wdt->io_base + WDT_REG_LOCK); outb(LOCK, wdt->io_base + WDT_REG_LOCK);
return 0;
} }
static const struct acpi_device_id nic7018_device_ids[] = { static const struct acpi_device_id nic7018_device_ids[] = {
...@@ -238,7 +236,7 @@ MODULE_DEVICE_TABLE(acpi, nic7018_device_ids); ...@@ -238,7 +236,7 @@ MODULE_DEVICE_TABLE(acpi, nic7018_device_ids);
static struct platform_driver watchdog_driver = { static struct platform_driver watchdog_driver = {
.probe = nic7018_probe, .probe = nic7018_probe,
.remove = nic7018_remove, .remove_new = nic7018_remove,
.driver = { .driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.acpi_match_table = ACPI_PTR(nic7018_device_ids), .acpi_match_table = ACPI_PTR(nic7018_device_ids),
......
...@@ -446,12 +446,10 @@ static void nv_tco_cleanup(void) ...@@ -446,12 +446,10 @@ static void nv_tco_cleanup(void)
release_region(tcobase, 0x10); release_region(tcobase, 0x10);
} }
static int nv_tco_remove(struct platform_device *dev) static void nv_tco_remove(struct platform_device *dev)
{ {
if (tcobase) if (tcobase)
nv_tco_cleanup(); nv_tco_cleanup();
return 0;
} }
static void nv_tco_shutdown(struct platform_device *dev) static void nv_tco_shutdown(struct platform_device *dev)
...@@ -469,7 +467,7 @@ static void nv_tco_shutdown(struct platform_device *dev) ...@@ -469,7 +467,7 @@ static void nv_tco_shutdown(struct platform_device *dev)
static struct platform_driver nv_tco_driver = { static struct platform_driver nv_tco_driver = {
.probe = nv_tco_init, .probe = nv_tco_init,
.remove = nv_tco_remove, .remove_new = nv_tco_remove,
.shutdown = nv_tco_shutdown, .shutdown = nv_tco_shutdown,
.driver = { .driver = {
.name = TCO_MODULE_NAME, .name = TCO_MODULE_NAME,
......
...@@ -306,14 +306,12 @@ static void omap_wdt_shutdown(struct platform_device *pdev) ...@@ -306,14 +306,12 @@ static void omap_wdt_shutdown(struct platform_device *pdev)
mutex_unlock(&wdev->lock); mutex_unlock(&wdev->lock);
} }
static int omap_wdt_remove(struct platform_device *pdev) static void omap_wdt_remove(struct platform_device *pdev)
{ {
struct omap_wdt_dev *wdev = platform_get_drvdata(pdev); struct omap_wdt_dev *wdev = platform_get_drvdata(pdev);
pm_runtime_disable(wdev->dev); pm_runtime_disable(wdev->dev);
watchdog_unregister_device(&wdev->wdog); watchdog_unregister_device(&wdev->wdog);
return 0;
} }
/* REVISIT ... not clear this is the best way to handle system suspend; and /* REVISIT ... not clear this is the best way to handle system suspend; and
...@@ -359,7 +357,7 @@ MODULE_DEVICE_TABLE(of, omap_wdt_of_match); ...@@ -359,7 +357,7 @@ MODULE_DEVICE_TABLE(of, omap_wdt_of_match);
static struct platform_driver omap_wdt_driver = { static struct platform_driver omap_wdt_driver = {
.probe = omap_wdt_probe, .probe = omap_wdt_probe,
.remove = omap_wdt_remove, .remove_new = omap_wdt_remove,
.shutdown = omap_wdt_shutdown, .shutdown = omap_wdt_shutdown,
.suspend = pm_ptr(omap_wdt_suspend), .suspend = pm_ptr(omap_wdt_suspend),
.resume = pm_ptr(omap_wdt_resume), .resume = pm_ptr(omap_wdt_resume),
......
...@@ -649,7 +649,7 @@ static int orion_wdt_probe(struct platform_device *pdev) ...@@ -649,7 +649,7 @@ static int orion_wdt_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int orion_wdt_remove(struct platform_device *pdev) static void orion_wdt_remove(struct platform_device *pdev)
{ {
struct watchdog_device *wdt_dev = platform_get_drvdata(pdev); struct watchdog_device *wdt_dev = platform_get_drvdata(pdev);
struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev); struct orion_watchdog *dev = watchdog_get_drvdata(wdt_dev);
...@@ -657,7 +657,6 @@ static int orion_wdt_remove(struct platform_device *pdev) ...@@ -657,7 +657,6 @@ static int orion_wdt_remove(struct platform_device *pdev)
watchdog_unregister_device(wdt_dev); watchdog_unregister_device(wdt_dev);
clk_disable_unprepare(dev->clk); clk_disable_unprepare(dev->clk);
clk_put(dev->clk); clk_put(dev->clk);
return 0;
} }
static void orion_wdt_shutdown(struct platform_device *pdev) static void orion_wdt_shutdown(struct platform_device *pdev)
...@@ -668,7 +667,7 @@ static void orion_wdt_shutdown(struct platform_device *pdev) ...@@ -668,7 +667,7 @@ static void orion_wdt_shutdown(struct platform_device *pdev)
static struct platform_driver orion_wdt_driver = { static struct platform_driver orion_wdt_driver = {
.probe = orion_wdt_probe, .probe = orion_wdt_probe,
.remove = orion_wdt_remove, .remove_new = orion_wdt_remove,
.shutdown = orion_wdt_shutdown, .shutdown = orion_wdt_shutdown,
.driver = { .driver = {
.name = "orion_wdt", .name = "orion_wdt",
......
...@@ -298,10 +298,9 @@ static int rc32434_wdt_probe(struct platform_device *pdev) ...@@ -298,10 +298,9 @@ static int rc32434_wdt_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int rc32434_wdt_remove(struct platform_device *pdev) static void rc32434_wdt_remove(struct platform_device *pdev)
{ {
misc_deregister(&rc32434_wdt_miscdev); misc_deregister(&rc32434_wdt_miscdev);
return 0;
} }
static void rc32434_wdt_shutdown(struct platform_device *pdev) static void rc32434_wdt_shutdown(struct platform_device *pdev)
...@@ -311,7 +310,7 @@ static void rc32434_wdt_shutdown(struct platform_device *pdev) ...@@ -311,7 +310,7 @@ static void rc32434_wdt_shutdown(struct platform_device *pdev)
static struct platform_driver rc32434_wdt_driver = { static struct platform_driver rc32434_wdt_driver = {
.probe = rc32434_wdt_probe, .probe = rc32434_wdt_probe,
.remove = rc32434_wdt_remove, .remove_new = rc32434_wdt_remove,
.shutdown = rc32434_wdt_shutdown, .shutdown = rc32434_wdt_shutdown,
.driver = { .driver = {
.name = "rc32434_wdt", .name = "rc32434_wdt",
......
...@@ -257,7 +257,7 @@ static int rdc321x_wdt_probe(struct platform_device *pdev) ...@@ -257,7 +257,7 @@ static int rdc321x_wdt_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int rdc321x_wdt_remove(struct platform_device *pdev) static void rdc321x_wdt_remove(struct platform_device *pdev)
{ {
if (rdc321x_wdt_device.queue) { if (rdc321x_wdt_device.queue) {
rdc321x_wdt_device.queue = 0; rdc321x_wdt_device.queue = 0;
...@@ -265,13 +265,11 @@ static int rdc321x_wdt_remove(struct platform_device *pdev) ...@@ -265,13 +265,11 @@ static int rdc321x_wdt_remove(struct platform_device *pdev)
} }
misc_deregister(&rdc321x_wdt_misc); misc_deregister(&rdc321x_wdt_misc);
return 0;
} }
static struct platform_driver rdc321x_wdt_driver = { static struct platform_driver rdc321x_wdt_driver = {
.probe = rdc321x_wdt_probe, .probe = rdc321x_wdt_probe,
.remove = rdc321x_wdt_remove, .remove_new = rdc321x_wdt_remove,
.driver = { .driver = {
.name = "rdc321x-wdt", .name = "rdc321x-wdt",
}, },
......
...@@ -292,14 +292,12 @@ static int rwdt_probe(struct platform_device *pdev) ...@@ -292,14 +292,12 @@ static int rwdt_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int rwdt_remove(struct platform_device *pdev) static void rwdt_remove(struct platform_device *pdev)
{ {
struct rwdt_priv *priv = platform_get_drvdata(pdev); struct rwdt_priv *priv = platform_get_drvdata(pdev);
watchdog_unregister_device(&priv->wdev); watchdog_unregister_device(&priv->wdev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return 0;
} }
static int __maybe_unused rwdt_suspend(struct device *dev) static int __maybe_unused rwdt_suspend(struct device *dev)
...@@ -339,7 +337,7 @@ static struct platform_driver rwdt_driver = { ...@@ -339,7 +337,7 @@ static struct platform_driver rwdt_driver = {
.pm = &rwdt_pm_ops, .pm = &rwdt_pm_ops,
}, },
.probe = rwdt_probe, .probe = rwdt_probe,
.remove = rwdt_remove, .remove_new = rwdt_remove,
}; };
module_platform_driver(rwdt_driver); module_platform_driver(rwdt_driver);
......
...@@ -217,14 +217,12 @@ static int riowd_probe(struct platform_device *op) ...@@ -217,14 +217,12 @@ static int riowd_probe(struct platform_device *op)
return err; return err;
} }
static int riowd_remove(struct platform_device *op) static void riowd_remove(struct platform_device *op)
{ {
struct riowd *p = platform_get_drvdata(op); struct riowd *p = platform_get_drvdata(op);
misc_deregister(&riowd_miscdev); misc_deregister(&riowd_miscdev);
of_iounmap(&op->resource[0], p->regs, 2); of_iounmap(&op->resource[0], p->regs, 2);
return 0;
} }
static const struct of_device_id riowd_match[] = { static const struct of_device_id riowd_match[] = {
...@@ -241,7 +239,7 @@ static struct platform_driver riowd_driver = { ...@@ -241,7 +239,7 @@ static struct platform_driver riowd_driver = {
.of_match_table = riowd_match, .of_match_table = riowd_match,
}, },
.probe = riowd_probe, .probe = riowd_probe,
.remove = riowd_remove, .remove_new = riowd_remove,
}; };
module_platform_driver(riowd_driver); module_platform_driver(riowd_driver);
...@@ -178,21 +178,11 @@ static int rn5t618_wdt_probe(struct platform_device *pdev) ...@@ -178,21 +178,11 @@ static int rn5t618_wdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, wdt); platform_set_drvdata(pdev, wdt);
return watchdog_register_device(&wdt->wdt_dev); return devm_watchdog_register_device(dev, &wdt->wdt_dev);
}
static int rn5t618_wdt_remove(struct platform_device *pdev)
{
struct rn5t618_wdt *wdt = platform_get_drvdata(pdev);
watchdog_unregister_device(&wdt->wdt_dev);
return 0;
} }
static struct platform_driver rn5t618_wdt_driver = { static struct platform_driver rn5t618_wdt_driver = {
.probe = rn5t618_wdt_probe, .probe = rn5t618_wdt_probe,
.remove = rn5t618_wdt_remove,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
}, },
......
...@@ -40,10 +40,13 @@ ...@@ -40,10 +40,13 @@
#define TMR1CTL_PRESCALE_MASK 0xf #define TMR1CTL_PRESCALE_MASK 0xf
#define TMR1CTL_PRESCALE_65536 0xf #define TMR1CTL_PRESCALE_65536 0xf
static struct clk *rt288x_wdt_clk; struct rt2880_wdt_data {
static unsigned long rt288x_wdt_freq; void __iomem *base;
static void __iomem *rt288x_wdt_base; unsigned long freq;
static struct reset_control *rt288x_wdt_reset; struct clk *clk;
struct reset_control *rst;
struct watchdog_device wdt;
};
static bool nowayout = WATCHDOG_NOWAYOUT; static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0); module_param(nowayout, bool, 0);
...@@ -51,52 +54,56 @@ MODULE_PARM_DESC(nowayout, ...@@ -51,52 +54,56 @@ MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default=" "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
static inline void rt_wdt_w32(unsigned reg, u32 val) static inline void rt_wdt_w32(void __iomem *base, unsigned int reg, u32 val)
{ {
iowrite32(val, rt288x_wdt_base + reg); iowrite32(val, base + reg);
} }
static inline u32 rt_wdt_r32(unsigned reg) static inline u32 rt_wdt_r32(void __iomem *base, unsigned int reg)
{ {
return ioread32(rt288x_wdt_base + reg); return ioread32(base + reg);
} }
static int rt288x_wdt_ping(struct watchdog_device *w) static int rt288x_wdt_ping(struct watchdog_device *w)
{ {
rt_wdt_w32(TIMER_REG_TMR1LOAD, w->timeout * rt288x_wdt_freq); struct rt2880_wdt_data *drvdata = watchdog_get_drvdata(w);
rt_wdt_w32(drvdata->base, TIMER_REG_TMR1LOAD, w->timeout * drvdata->freq);
return 0; return 0;
} }
static int rt288x_wdt_start(struct watchdog_device *w) static int rt288x_wdt_start(struct watchdog_device *w)
{ {
struct rt2880_wdt_data *drvdata = watchdog_get_drvdata(w);
u32 t; u32 t;
t = rt_wdt_r32(TIMER_REG_TMR1CTL); t = rt_wdt_r32(drvdata->base, TIMER_REG_TMR1CTL);
t &= ~(TMR1CTL_MODE_MASK << TMR1CTL_MODE_SHIFT | t &= ~(TMR1CTL_MODE_MASK << TMR1CTL_MODE_SHIFT |
TMR1CTL_PRESCALE_MASK); TMR1CTL_PRESCALE_MASK);
t |= (TMR1CTL_MODE_WDT << TMR1CTL_MODE_SHIFT | t |= (TMR1CTL_MODE_WDT << TMR1CTL_MODE_SHIFT |
TMR1CTL_PRESCALE_65536); TMR1CTL_PRESCALE_65536);
rt_wdt_w32(TIMER_REG_TMR1CTL, t); rt_wdt_w32(drvdata->base, TIMER_REG_TMR1CTL, t);
rt288x_wdt_ping(w); rt288x_wdt_ping(w);
t = rt_wdt_r32(TIMER_REG_TMR1CTL); t = rt_wdt_r32(drvdata->base, TIMER_REG_TMR1CTL);
t |= TMR1CTL_ENABLE; t |= TMR1CTL_ENABLE;
rt_wdt_w32(TIMER_REG_TMR1CTL, t); rt_wdt_w32(drvdata->base, TIMER_REG_TMR1CTL, t);
return 0; return 0;
} }
static int rt288x_wdt_stop(struct watchdog_device *w) static int rt288x_wdt_stop(struct watchdog_device *w)
{ {
struct rt2880_wdt_data *drvdata = watchdog_get_drvdata(w);
u32 t; u32 t;
rt288x_wdt_ping(w); rt288x_wdt_ping(w);
t = rt_wdt_r32(TIMER_REG_TMR1CTL); t = rt_wdt_r32(drvdata->base, TIMER_REG_TMR1CTL);
t &= ~TMR1CTL_ENABLE; t &= ~TMR1CTL_ENABLE;
rt_wdt_w32(TIMER_REG_TMR1CTL, t); rt_wdt_w32(drvdata->base, TIMER_REG_TMR1CTL, t);
return 0; return 0;
} }
...@@ -130,41 +137,45 @@ static const struct watchdog_ops rt288x_wdt_ops = { ...@@ -130,41 +137,45 @@ static const struct watchdog_ops rt288x_wdt_ops = {
.set_timeout = rt288x_wdt_set_timeout, .set_timeout = rt288x_wdt_set_timeout,
}; };
static struct watchdog_device rt288x_wdt_dev = {
.info = &rt288x_wdt_info,
.ops = &rt288x_wdt_ops,
.min_timeout = 1,
};
static int rt288x_wdt_probe(struct platform_device *pdev) static int rt288x_wdt_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct watchdog_device *wdt;
struct rt2880_wdt_data *drvdata;
int ret; int ret;
rt288x_wdt_base = devm_platform_ioremap_resource(pdev, 0); drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
if (IS_ERR(rt288x_wdt_base)) if (!drvdata)
return PTR_ERR(rt288x_wdt_base); return -ENOMEM;
drvdata->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(drvdata->base))
return PTR_ERR(drvdata->base);
rt288x_wdt_clk = devm_clk_get(dev, NULL); drvdata->clk = devm_clk_get(dev, NULL);
if (IS_ERR(rt288x_wdt_clk)) if (IS_ERR(drvdata->clk))
return PTR_ERR(rt288x_wdt_clk); return PTR_ERR(drvdata->clk);
rt288x_wdt_reset = devm_reset_control_get_exclusive(dev, NULL); drvdata->rst = devm_reset_control_get_exclusive(dev, NULL);
if (!IS_ERR(rt288x_wdt_reset)) if (!IS_ERR(drvdata->rst))
reset_control_deassert(rt288x_wdt_reset); reset_control_deassert(drvdata->rst);
rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE; drvdata->freq = clk_get_rate(drvdata->clk) / RALINK_WDT_PRESCALE;
rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); wdt = &drvdata->wdt;
rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); wdt->info = &rt288x_wdt_info;
rt288x_wdt_dev.parent = dev; wdt->ops = &rt288x_wdt_ops;
wdt->min_timeout = 1;
wdt->max_timeout = (0xfffful / drvdata->freq);
wdt->parent = dev;
wdt->bootstatus = rt288x_wdt_bootcause();
watchdog_init_timeout(&rt288x_wdt_dev, rt288x_wdt_dev.max_timeout, watchdog_init_timeout(wdt, wdt->max_timeout, dev);
dev); watchdog_set_nowayout(wdt, nowayout);
watchdog_set_nowayout(&rt288x_wdt_dev, nowayout); watchdog_set_drvdata(wdt, drvdata);
watchdog_stop_on_reboot(&rt288x_wdt_dev); watchdog_stop_on_reboot(wdt);
ret = devm_watchdog_register_device(dev, &rt288x_wdt_dev); ret = devm_watchdog_register_device(dev, &drvdata->wdt);
if (!ret) if (!ret)
dev_info(dev, "Initialized\n"); dev_info(dev, "Initialized\n");
......
...@@ -304,15 +304,13 @@ static int rti_wdt_probe(struct platform_device *pdev) ...@@ -304,15 +304,13 @@ static int rti_wdt_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int rti_wdt_remove(struct platform_device *pdev) static void rti_wdt_remove(struct platform_device *pdev)
{ {
struct rti_wdt_device *wdt = platform_get_drvdata(pdev); struct rti_wdt_device *wdt = platform_get_drvdata(pdev);
watchdog_unregister_device(&wdt->wdd); watchdog_unregister_device(&wdt->wdd);
pm_runtime_put(&pdev->dev); pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return 0;
} }
static const struct of_device_id rti_wdt_of_match[] = { static const struct of_device_id rti_wdt_of_match[] = {
...@@ -327,7 +325,7 @@ static struct platform_driver rti_wdt_driver = { ...@@ -327,7 +325,7 @@ static struct platform_driver rti_wdt_driver = {
.of_match_table = rti_wdt_of_match, .of_match_table = rti_wdt_of_match,
}, },
.probe = rti_wdt_probe, .probe = rti_wdt_probe,
.remove = rti_wdt_remove, .remove_new = rti_wdt_remove,
}; };
module_platform_driver(rti_wdt_driver); module_platform_driver(rti_wdt_driver);
......
...@@ -308,11 +308,6 @@ static inline unsigned int s3c2410wdt_max_timeout(struct s3c2410_wdt *wdt) ...@@ -308,11 +308,6 @@ static inline unsigned int s3c2410wdt_max_timeout(struct s3c2410_wdt *wdt)
/ S3C2410_WTCON_MAXDIV); / S3C2410_WTCON_MAXDIV);
} }
static inline struct s3c2410_wdt *freq_to_wdt(struct notifier_block *nb)
{
return container_of(nb, struct s3c2410_wdt, freq_transition);
}
static int s3c2410wdt_disable_wdt_reset(struct s3c2410_wdt *wdt, bool mask) static int s3c2410wdt_disable_wdt_reset(struct s3c2410_wdt *wdt, bool mask)
{ {
const u32 mask_val = BIT(wdt->drv_data->mask_bit); const u32 mask_val = BIT(wdt->drv_data->mask_bit);
...@@ -443,11 +438,6 @@ static int s3c2410wdt_start(struct watchdog_device *wdd) ...@@ -443,11 +438,6 @@ static int s3c2410wdt_start(struct watchdog_device *wdd)
return 0; return 0;
} }
static inline int s3c2410wdt_is_running(struct s3c2410_wdt *wdt)
{
return readl(wdt->reg_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
}
static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd,
unsigned int timeout) unsigned int timeout)
{ {
...@@ -579,8 +569,8 @@ static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) ...@@ -579,8 +569,8 @@ static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt)
return 0; return 0;
} }
static inline const struct s3c2410_wdt_variant * static inline int
s3c2410_get_wdt_drv_data(struct platform_device *pdev) s3c2410_get_wdt_drv_data(struct platform_device *pdev, struct s3c2410_wdt *wdt)
{ {
const struct s3c2410_wdt_variant *variant; const struct s3c2410_wdt_variant *variant;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -601,26 +591,30 @@ s3c2410_get_wdt_drv_data(struct platform_device *pdev) ...@@ -601,26 +591,30 @@ s3c2410_get_wdt_drv_data(struct platform_device *pdev)
err = of_property_read_u32(dev->of_node, err = of_property_read_u32(dev->of_node,
"samsung,cluster-index", &index); "samsung,cluster-index", &index);
if (err) { if (err)
dev_err(dev, "failed to get cluster index\n"); return dev_err_probe(dev, -EINVAL, "failed to get cluster index\n");
return NULL;
}
switch (index) { switch (index) {
case 0: case 0:
return variant; break;
case 1: case 1:
return (variant == &drv_data_exynos850_cl0) ? variant = (variant == &drv_data_exynos850_cl0) ?
&drv_data_exynos850_cl1 : &drv_data_exynos850_cl1 :
&drv_data_exynosautov9_cl1; &drv_data_exynosautov9_cl1;
break;
default: default:
dev_err(dev, "wrong cluster index: %u\n", index); return dev_err_probe(dev, -EINVAL, "wrong cluster index: %u\n", index);
return NULL;
} }
} }
#endif #endif
return variant; wdt->drv_data = variant;
return 0;
}
static void s3c2410wdt_wdt_disable_action(void *data)
{
s3c2410wdt_enable(data, false);
} }
static int s3c2410wdt_probe(struct platform_device *pdev) static int s3c2410wdt_probe(struct platform_device *pdev)
...@@ -639,17 +633,16 @@ static int s3c2410wdt_probe(struct platform_device *pdev) ...@@ -639,17 +633,16 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
spin_lock_init(&wdt->lock); spin_lock_init(&wdt->lock);
wdt->wdt_device = s3c2410_wdd; wdt->wdt_device = s3c2410_wdd;
wdt->drv_data = s3c2410_get_wdt_drv_data(pdev); ret = s3c2410_get_wdt_drv_data(pdev, wdt);
if (!wdt->drv_data) if (ret)
return -EINVAL; return ret;
if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) { if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) {
wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
"samsung,syscon-phandle"); "samsung,syscon-phandle");
if (IS_ERR(wdt->pmureg)) { if (IS_ERR(wdt->pmureg))
dev_err(dev, "syscon regmap lookup failed.\n"); return dev_err_probe(dev, PTR_ERR(wdt->pmureg),
return PTR_ERR(wdt->pmureg); "syscon regmap lookup failed.\n");
}
} }
wdt_irq = platform_get_irq(pdev, 0); wdt_irq = platform_get_irq(pdev, 0);
...@@ -661,35 +654,17 @@ static int s3c2410wdt_probe(struct platform_device *pdev) ...@@ -661,35 +654,17 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
if (IS_ERR(wdt->reg_base)) if (IS_ERR(wdt->reg_base))
return PTR_ERR(wdt->reg_base); return PTR_ERR(wdt->reg_base);
wdt->bus_clk = devm_clk_get(dev, "watchdog"); wdt->bus_clk = devm_clk_get_enabled(dev, "watchdog");
if (IS_ERR(wdt->bus_clk)) { if (IS_ERR(wdt->bus_clk))
dev_err(dev, "failed to find bus clock\n"); return dev_err_probe(dev, PTR_ERR(wdt->bus_clk), "failed to get bus clock\n");
return PTR_ERR(wdt->bus_clk);
}
ret = clk_prepare_enable(wdt->bus_clk);
if (ret < 0) {
dev_err(dev, "failed to enable bus clock\n");
return ret;
}
/* /*
* "watchdog_src" clock is optional; if it's not present -- just skip it * "watchdog_src" clock is optional; if it's not present -- just skip it
* and use "watchdog" clock as both bus and source clock. * and use "watchdog" clock as both bus and source clock.
*/ */
wdt->src_clk = devm_clk_get_optional(dev, "watchdog_src"); wdt->src_clk = devm_clk_get_optional_enabled(dev, "watchdog_src");
if (IS_ERR(wdt->src_clk)) { if (IS_ERR(wdt->src_clk))
dev_err_probe(dev, PTR_ERR(wdt->src_clk), return dev_err_probe(dev, PTR_ERR(wdt->src_clk), "failed to get source clock\n");
"failed to get source clock\n");
ret = PTR_ERR(wdt->src_clk);
goto err_bus_clk;
}
ret = clk_prepare_enable(wdt->src_clk);
if (ret) {
dev_err(dev, "failed to enable source clock\n");
goto err_bus_clk;
}
wdt->wdt_device.min_timeout = 1; wdt->wdt_device.min_timeout = 1;
wdt->wdt_device.max_timeout = s3c2410wdt_max_timeout(wdt); wdt->wdt_device.max_timeout = s3c2410wdt_max_timeout(wdt);
...@@ -705,21 +680,17 @@ static int s3c2410wdt_probe(struct platform_device *pdev) ...@@ -705,21 +680,17 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
if (ret) { if (ret) {
ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device, ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
S3C2410_WATCHDOG_DEFAULT_TIME); S3C2410_WATCHDOG_DEFAULT_TIME);
if (ret == 0) { if (ret == 0)
dev_warn(dev, "tmr_margin value out of range, default %d used\n", dev_warn(dev, "tmr_margin value out of range, default %d used\n",
S3C2410_WATCHDOG_DEFAULT_TIME); S3C2410_WATCHDOG_DEFAULT_TIME);
} else { else
dev_err(dev, "failed to use default timeout\n"); return dev_err_probe(dev, ret, "failed to use default timeout\n");
goto err_src_clk;
}
} }
ret = devm_request_irq(dev, wdt_irq, s3c2410wdt_irq, 0, ret = devm_request_irq(dev, wdt_irq, s3c2410wdt_irq, 0,
pdev->name, pdev); pdev->name, pdev);
if (ret != 0) { if (ret != 0)
dev_err(dev, "failed to install irq (%d)\n", ret); return dev_err_probe(dev, ret, "failed to install irq (%d)\n", ret);
goto err_src_clk;
}
watchdog_set_nowayout(&wdt->wdt_device, nowayout); watchdog_set_nowayout(&wdt->wdt_device, nowayout);
watchdog_set_restart_priority(&wdt->wdt_device, 128); watchdog_set_restart_priority(&wdt->wdt_device, 128);
...@@ -742,13 +713,17 @@ static int s3c2410wdt_probe(struct platform_device *pdev) ...@@ -742,13 +713,17 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
s3c2410wdt_stop(&wdt->wdt_device); s3c2410wdt_stop(&wdt->wdt_device);
} }
ret = watchdog_register_device(&wdt->wdt_device); ret = devm_watchdog_register_device(dev, &wdt->wdt_device);
if (ret) if (ret)
goto err_src_clk; return ret;
ret = s3c2410wdt_enable(wdt, true); ret = s3c2410wdt_enable(wdt, true);
if (ret < 0) if (ret < 0)
goto err_unregister; return ret;
ret = devm_add_action_or_reset(dev, s3c2410wdt_wdt_disable_action, wdt);
if (ret)
return ret;
platform_set_drvdata(pdev, wdt); platform_set_drvdata(pdev, wdt);
...@@ -762,34 +737,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev) ...@@ -762,34 +737,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
(wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis"); (wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis");
return 0; return 0;
err_unregister:
watchdog_unregister_device(&wdt->wdt_device);
err_src_clk:
clk_disable_unprepare(wdt->src_clk);
err_bus_clk:
clk_disable_unprepare(wdt->bus_clk);
return ret;
}
static int s3c2410wdt_remove(struct platform_device *dev)
{
int ret;
struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
ret = s3c2410wdt_enable(wdt, false);
if (ret < 0)
return ret;
watchdog_unregister_device(&wdt->wdt_device);
clk_disable_unprepare(wdt->src_clk);
clk_disable_unprepare(wdt->bus_clk);
return 0;
} }
static void s3c2410wdt_shutdown(struct platform_device *dev) static void s3c2410wdt_shutdown(struct platform_device *dev)
...@@ -844,7 +791,6 @@ static DEFINE_SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, ...@@ -844,7 +791,6 @@ static DEFINE_SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops,
static struct platform_driver s3c2410wdt_driver = { static struct platform_driver s3c2410wdt_driver = {
.probe = s3c2410wdt_probe, .probe = s3c2410wdt_probe,
.remove = s3c2410wdt_remove,
.shutdown = s3c2410wdt_shutdown, .shutdown = s3c2410wdt_shutdown,
.id_table = s3c2410_wdt_ids, .id_table = s3c2410_wdt_ids,
.driver = { .driver = {
......
...@@ -229,19 +229,17 @@ static int sa1100dog_probe(struct platform_device *pdev) ...@@ -229,19 +229,17 @@ static int sa1100dog_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int sa1100dog_remove(struct platform_device *pdev) static void sa1100dog_remove(struct platform_device *pdev)
{ {
misc_deregister(&sa1100dog_miscdev); misc_deregister(&sa1100dog_miscdev);
clk_disable_unprepare(clk); clk_disable_unprepare(clk);
clk_put(clk); clk_put(clk);
return 0;
} }
static struct platform_driver sa1100dog_driver = { static struct platform_driver sa1100dog_driver = {
.driver.name = "sa1100_wdt", .driver.name = "sa1100_wdt",
.probe = sa1100dog_probe, .probe = sa1100dog_probe,
.remove = sa1100dog_remove, .remove_new = sa1100dog_remove,
}; };
module_platform_driver(sa1100dog_driver); module_platform_driver(sa1100dog_driver);
......
...@@ -361,7 +361,7 @@ static int __maybe_unused sbsa_gwdt_suspend(struct device *dev) ...@@ -361,7 +361,7 @@ static int __maybe_unused sbsa_gwdt_suspend(struct device *dev)
{ {
struct sbsa_gwdt *gwdt = dev_get_drvdata(dev); struct sbsa_gwdt *gwdt = dev_get_drvdata(dev);
if (watchdog_active(&gwdt->wdd)) if (watchdog_hw_running(&gwdt->wdd))
sbsa_gwdt_stop(&gwdt->wdd); sbsa_gwdt_stop(&gwdt->wdd);
return 0; return 0;
...@@ -372,7 +372,7 @@ static int __maybe_unused sbsa_gwdt_resume(struct device *dev) ...@@ -372,7 +372,7 @@ static int __maybe_unused sbsa_gwdt_resume(struct device *dev)
{ {
struct sbsa_gwdt *gwdt = dev_get_drvdata(dev); struct sbsa_gwdt *gwdt = dev_get_drvdata(dev);
if (watchdog_active(&gwdt->wdd)) if (watchdog_hw_running(&gwdt->wdd))
sbsa_gwdt_start(&gwdt->wdd); sbsa_gwdt_start(&gwdt->wdd);
return 0; return 0;
......
...@@ -425,7 +425,7 @@ static int sch311x_wdt_probe(struct platform_device *pdev) ...@@ -425,7 +425,7 @@ static int sch311x_wdt_probe(struct platform_device *pdev)
return err; return err;
} }
static int sch311x_wdt_remove(struct platform_device *pdev) static void sch311x_wdt_remove(struct platform_device *pdev)
{ {
/* Stop the timer before we leave */ /* Stop the timer before we leave */
if (!nowayout) if (!nowayout)
...@@ -436,7 +436,6 @@ static int sch311x_wdt_remove(struct platform_device *pdev) ...@@ -436,7 +436,6 @@ static int sch311x_wdt_remove(struct platform_device *pdev)
release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4); release_region(sch311x_wdt_data.runtime_reg + WDT_TIME_OUT, 4);
release_region(sch311x_wdt_data.runtime_reg + GP60, 1); release_region(sch311x_wdt_data.runtime_reg + GP60, 1);
sch311x_wdt_data.runtime_reg = 0; sch311x_wdt_data.runtime_reg = 0;
return 0;
} }
static void sch311x_wdt_shutdown(struct platform_device *dev) static void sch311x_wdt_shutdown(struct platform_device *dev)
...@@ -447,7 +446,7 @@ static void sch311x_wdt_shutdown(struct platform_device *dev) ...@@ -447,7 +446,7 @@ static void sch311x_wdt_shutdown(struct platform_device *dev)
static struct platform_driver sch311x_wdt_driver = { static struct platform_driver sch311x_wdt_driver = {
.probe = sch311x_wdt_probe, .probe = sch311x_wdt_probe,
.remove = sch311x_wdt_remove, .remove_new = sch311x_wdt_remove,
.shutdown = sch311x_wdt_shutdown, .shutdown = sch311x_wdt_shutdown,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
......
...@@ -279,13 +279,11 @@ static int sh_wdt_probe(struct platform_device *pdev) ...@@ -279,13 +279,11 @@ static int sh_wdt_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int sh_wdt_remove(struct platform_device *pdev) static void sh_wdt_remove(struct platform_device *pdev)
{ {
watchdog_unregister_device(&sh_wdt_dev); watchdog_unregister_device(&sh_wdt_dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
return 0;
} }
static void sh_wdt_shutdown(struct platform_device *pdev) static void sh_wdt_shutdown(struct platform_device *pdev)
...@@ -299,7 +297,7 @@ static struct platform_driver sh_wdt_driver = { ...@@ -299,7 +297,7 @@ static struct platform_driver sh_wdt_driver = {
}, },
.probe = sh_wdt_probe, .probe = sh_wdt_probe,
.remove = sh_wdt_remove, .remove_new = sh_wdt_remove,
.shutdown = sh_wdt_shutdown, .shutdown = sh_wdt_shutdown,
}; };
......
...@@ -115,6 +115,10 @@ static int tco_timer_start(struct watchdog_device *wdd) ...@@ -115,6 +115,10 @@ static int tco_timer_start(struct watchdog_device *wdd)
val |= SP5100_WDT_START_STOP_BIT; val |= SP5100_WDT_START_STOP_BIT;
writel(val, SP5100_WDT_CONTROL(tco->tcobase)); writel(val, SP5100_WDT_CONTROL(tco->tcobase));
/* This must be a distinct write. */
val |= SP5100_WDT_TRIGGER_BIT;
writel(val, SP5100_WDT_CONTROL(tco->tcobase));
return 0; return 0;
} }
......
...@@ -239,13 +239,11 @@ static int st_wdog_probe(struct platform_device *pdev) ...@@ -239,13 +239,11 @@ static int st_wdog_probe(struct platform_device *pdev)
return ret; return ret;
} }
static int st_wdog_remove(struct platform_device *pdev) static void st_wdog_remove(struct platform_device *pdev)
{ {
struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev); struct st_wdog *st_wdog = watchdog_get_drvdata(&st_wdog_dev);
st_wdog_setup(st_wdog, false); st_wdog_setup(st_wdog, false);
return 0;
} }
static int st_wdog_suspend(struct device *dev) static int st_wdog_suspend(struct device *dev)
...@@ -295,7 +293,7 @@ static struct platform_driver st_wdog_driver = { ...@@ -295,7 +293,7 @@ static struct platform_driver st_wdog_driver = {
.of_match_table = st_wdog_match, .of_match_table = st_wdog_match,
}, },
.probe = st_wdog_probe, .probe = st_wdog_probe,
.remove = st_wdog_remove, .remove_new = st_wdog_remove,
}; };
module_platform_driver(st_wdog_driver); module_platform_driver(st_wdog_driver);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Starfive Watchdog driver
*
* Copyright (C) 2022 StarFive Technology Co., Ltd.
*/
#include <linux/clk.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/watchdog.h>
/* JH7100 Watchdog register define */
#define STARFIVE_WDT_JH7100_INTSTAUS 0x000
#define STARFIVE_WDT_JH7100_CONTROL 0x104
#define STARFIVE_WDT_JH7100_LOAD 0x108
#define STARFIVE_WDT_JH7100_EN 0x110
#define STARFIVE_WDT_JH7100_RELOAD 0x114 /* Write 0 or 1 to reload preset value */
#define STARFIVE_WDT_JH7100_VALUE 0x118
#define STARFIVE_WDT_JH7100_INTCLR 0x120 /*
* [0]: Write 1 to clear interrupt
* [1]: 1 mean clearing and 0 mean complete
* [31:2]: reserved.
*/
#define STARFIVE_WDT_JH7100_LOCK 0x13c /* write 0x378f0765 to unlock */
/* JH7110 Watchdog register define */
#define STARFIVE_WDT_JH7110_LOAD 0x000
#define STARFIVE_WDT_JH7110_VALUE 0x004
#define STARFIVE_WDT_JH7110_CONTROL 0x008 /*
* [0]: reset enable;
* [1]: interrupt enable && watchdog enable
* [31:2]: reserved.
*/
#define STARFIVE_WDT_JH7110_INTCLR 0x00c /* clear intterupt and reload the counter */
#define STARFIVE_WDT_JH7110_IMS 0x014
#define STARFIVE_WDT_JH7110_LOCK 0xc00 /* write 0x1ACCE551 to unlock */
/* WDOGCONTROL */
#define STARFIVE_WDT_ENABLE 0x1
#define STARFIVE_WDT_EN_SHIFT 0
#define STARFIVE_WDT_RESET_EN 0x1
#define STARFIVE_WDT_JH7100_RST_EN_SHIFT 0
#define STARFIVE_WDT_JH7110_RST_EN_SHIFT 1
/* WDOGLOCK */
#define STARFIVE_WDT_JH7100_UNLOCK_KEY 0x378f0765
#define STARFIVE_WDT_JH7110_UNLOCK_KEY 0x1acce551
/* WDOGINTCLR */
#define STARFIVE_WDT_INTCLR 0x1
#define STARFIVE_WDT_JH7100_INTCLR_AVA_SHIFT 1 /* Watchdog can clear interrupt when 0 */
#define STARFIVE_WDT_MAXCNT 0xffffffff
#define STARFIVE_WDT_DEFAULT_TIME (15)
#define STARFIVE_WDT_DELAY_US 0
#define STARFIVE_WDT_TIMEOUT_US 10000
/* module parameter */
#define STARFIVE_WDT_EARLY_ENA 0
static bool nowayout = WATCHDOG_NOWAYOUT;
static int heartbeat;
static bool early_enable = STARFIVE_WDT_EARLY_ENA;
module_param(heartbeat, int, 0);
module_param(early_enable, bool, 0);
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default="
__MODULE_STRING(STARFIVE_WDT_DEFAULT_TIME) ")");
MODULE_PARM_DESC(early_enable,
"Watchdog is started at boot time if set to 1, default="
__MODULE_STRING(STARFIVE_WDT_EARLY_ENA));
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
struct starfive_wdt_variant {
unsigned int control; /* Watchdog Control Resgister for reset enable */
unsigned int load; /* Watchdog Load register */
unsigned int reload; /* Watchdog Reload Control register */
unsigned int enable; /* Watchdog Enable Register */
unsigned int value; /* Watchdog Counter Value Register */
unsigned int int_clr; /* Watchdog Interrupt Clear Register */
unsigned int unlock; /* Watchdog Lock Register */
unsigned int int_status; /* Watchdog Interrupt Status Register */
u32 unlock_key;
char enrst_shift;
char en_shift;
bool intclr_check; /* whether need to check it before clearing interrupt */
char intclr_ava_shift;
bool double_timeout; /* The watchdog need twice timeout to reboot */
};
struct starfive_wdt {
struct watchdog_device wdd;
spinlock_t lock; /* spinlock for register handling */
void __iomem *base;
struct clk *core_clk;
struct clk *apb_clk;
const struct starfive_wdt_variant *variant;
unsigned long freq;
u32 count; /* count of timeout */
u32 reload; /* restore the count */
};
/* Register layout and configuration for the JH7100 */
static const struct starfive_wdt_variant starfive_wdt_jh7100_variant = {
.control = STARFIVE_WDT_JH7100_CONTROL,
.load = STARFIVE_WDT_JH7100_LOAD,
.reload = STARFIVE_WDT_JH7100_RELOAD,
.enable = STARFIVE_WDT_JH7100_EN,
.value = STARFIVE_WDT_JH7100_VALUE,
.int_clr = STARFIVE_WDT_JH7100_INTCLR,
.unlock = STARFIVE_WDT_JH7100_LOCK,
.unlock_key = STARFIVE_WDT_JH7100_UNLOCK_KEY,
.int_status = STARFIVE_WDT_JH7100_INTSTAUS,
.enrst_shift = STARFIVE_WDT_JH7100_RST_EN_SHIFT,
.en_shift = STARFIVE_WDT_EN_SHIFT,
.intclr_check = true,
.intclr_ava_shift = STARFIVE_WDT_JH7100_INTCLR_AVA_SHIFT,
.double_timeout = false,
};
/* Register layout and configuration for the JH7110 */
static const struct starfive_wdt_variant starfive_wdt_jh7110_variant = {
.control = STARFIVE_WDT_JH7110_CONTROL,
.load = STARFIVE_WDT_JH7110_LOAD,
.enable = STARFIVE_WDT_JH7110_CONTROL,
.value = STARFIVE_WDT_JH7110_VALUE,
.int_clr = STARFIVE_WDT_JH7110_INTCLR,
.unlock = STARFIVE_WDT_JH7110_LOCK,
.unlock_key = STARFIVE_WDT_JH7110_UNLOCK_KEY,
.int_status = STARFIVE_WDT_JH7110_IMS,
.enrst_shift = STARFIVE_WDT_JH7110_RST_EN_SHIFT,
.en_shift = STARFIVE_WDT_EN_SHIFT,
.intclr_check = false,
.double_timeout = true,
};
static int starfive_wdt_enable_clock(struct starfive_wdt *wdt)
{
int ret;
ret = clk_prepare_enable(wdt->apb_clk);
if (ret)
return dev_err_probe(wdt->wdd.parent, ret, "failed to enable apb clock\n");
ret = clk_prepare_enable(wdt->core_clk);
if (ret)
return dev_err_probe(wdt->wdd.parent, ret, "failed to enable core clock\n");
return 0;
}
static void starfive_wdt_disable_clock(struct starfive_wdt *wdt)
{
clk_disable_unprepare(wdt->core_clk);
clk_disable_unprepare(wdt->apb_clk);
}
static inline int starfive_wdt_get_clock(struct starfive_wdt *wdt)
{
struct device *dev = wdt->wdd.parent;
wdt->apb_clk = devm_clk_get(dev, "apb");
if (IS_ERR(wdt->apb_clk))
return dev_err_probe(dev, PTR_ERR(wdt->apb_clk), "failed to get apb clock\n");
wdt->core_clk = devm_clk_get(dev, "core");
if (IS_ERR(wdt->core_clk))
return dev_err_probe(dev, PTR_ERR(wdt->core_clk), "failed to get core clock\n");
return 0;
}
static inline int starfive_wdt_reset_init(struct device *dev)
{
struct reset_control *rsts;
int ret;
rsts = devm_reset_control_array_get_exclusive(dev);
if (IS_ERR(rsts))
return dev_err_probe(dev, PTR_ERR(rsts), "failed to get resets\n");
ret = reset_control_deassert(rsts);
if (ret)
return dev_err_probe(dev, ret, "failed to deassert resets\n");
return 0;
}
static u32 starfive_wdt_ticks_to_sec(struct starfive_wdt *wdt, u32 ticks)
{
return DIV_ROUND_CLOSEST(ticks, wdt->freq);
}
/* Write unlock-key to unlock. Write other value to lock. */
static void starfive_wdt_unlock(struct starfive_wdt *wdt)
{
spin_lock(&wdt->lock);
writel(wdt->variant->unlock_key, wdt->base + wdt->variant->unlock);
}
static void starfive_wdt_lock(struct starfive_wdt *wdt)
{
writel(~wdt->variant->unlock_key, wdt->base + wdt->variant->unlock);
spin_unlock(&wdt->lock);
}
/* enable watchdog interrupt to reset/reboot */
static void starfive_wdt_enable_reset(struct starfive_wdt *wdt)
{
u32 val;
val = readl(wdt->base + wdt->variant->control);
val |= STARFIVE_WDT_RESET_EN << wdt->variant->enrst_shift;
writel(val, wdt->base + wdt->variant->control);
}
/* interrupt status whether has been raised from the counter */
static bool starfive_wdt_raise_irq_status(struct starfive_wdt *wdt)
{
return !!readl(wdt->base + wdt->variant->int_status);
}
/* waiting interrupt can be free to clear */
static int starfive_wdt_wait_int_free(struct starfive_wdt *wdt)
{
u32 value;
return readl_poll_timeout_atomic(wdt->base + wdt->variant->int_clr, value,
!(value & BIT(wdt->variant->intclr_ava_shift)),
STARFIVE_WDT_DELAY_US, STARFIVE_WDT_TIMEOUT_US);
}
/* clear interrupt signal before initialization or reload */
static int starfive_wdt_int_clr(struct starfive_wdt *wdt)
{
int ret;
if (wdt->variant->intclr_check) {
ret = starfive_wdt_wait_int_free(wdt);
if (ret)
return dev_err_probe(wdt->wdd.parent, ret,
"watchdog is not ready to clear interrupt.\n");
}
writel(STARFIVE_WDT_INTCLR, wdt->base + wdt->variant->int_clr);
return 0;
}
static inline void starfive_wdt_set_count(struct starfive_wdt *wdt, u32 val)
{
writel(val, wdt->base + wdt->variant->load);
}
static inline u32 starfive_wdt_get_count(struct starfive_wdt *wdt)
{
return readl(wdt->base + wdt->variant->value);
}
/* enable watchdog */
static inline void starfive_wdt_enable(struct starfive_wdt *wdt)
{
u32 val;
val = readl(wdt->base + wdt->variant->enable);
val |= STARFIVE_WDT_ENABLE << wdt->variant->en_shift;
writel(val, wdt->base + wdt->variant->enable);
}
/* disable watchdog */
static inline void starfive_wdt_disable(struct starfive_wdt *wdt)
{
u32 val;
val = readl(wdt->base + wdt->variant->enable);
val &= ~(STARFIVE_WDT_ENABLE << wdt->variant->en_shift);
writel(val, wdt->base + wdt->variant->enable);
}
static inline void starfive_wdt_set_reload_count(struct starfive_wdt *wdt, u32 count)
{
starfive_wdt_set_count(wdt, count);
/* 7100 need set any value to reload register and could reload value to counter */
if (wdt->variant->reload)
writel(0x1, wdt->base + wdt->variant->reload);
}
static unsigned int starfive_wdt_max_timeout(struct starfive_wdt *wdt)
{
if (wdt->variant->double_timeout)
return DIV_ROUND_UP(STARFIVE_WDT_MAXCNT, (wdt->freq / 2)) - 1;
return DIV_ROUND_UP(STARFIVE_WDT_MAXCNT, wdt->freq) - 1;
}
static unsigned int starfive_wdt_get_timeleft(struct watchdog_device *wdd)
{
struct starfive_wdt *wdt = watchdog_get_drvdata(wdd);
u32 count;
/*
* If the watchdog takes twice timeout and set half count value,
* timeleft value should add the count value before first timeout.
*/
count = starfive_wdt_get_count(wdt);
if (wdt->variant->double_timeout && !starfive_wdt_raise_irq_status(wdt))
count += wdt->count;
return starfive_wdt_ticks_to_sec(wdt, count);
}
static int starfive_wdt_keepalive(struct watchdog_device *wdd)
{
struct starfive_wdt *wdt = watchdog_get_drvdata(wdd);
int ret;
starfive_wdt_unlock(wdt);
ret = starfive_wdt_int_clr(wdt);
if (ret)
goto exit;
starfive_wdt_set_reload_count(wdt, wdt->count);
exit:
/* exit with releasing spinlock and locking registers */
starfive_wdt_lock(wdt);
return ret;
}
static int starfive_wdt_start(struct starfive_wdt *wdt)
{
int ret;
starfive_wdt_unlock(wdt);
/* disable watchdog, to be safe */
starfive_wdt_disable(wdt);
starfive_wdt_enable_reset(wdt);
ret = starfive_wdt_int_clr(wdt);
if (ret)
goto exit;
starfive_wdt_set_count(wdt, wdt->count);
starfive_wdt_enable(wdt);
exit:
starfive_wdt_lock(wdt);
return ret;
}
static void starfive_wdt_stop(struct starfive_wdt *wdt)
{
starfive_wdt_unlock(wdt);
starfive_wdt_disable(wdt);
starfive_wdt_lock(wdt);
}
static int starfive_wdt_pm_start(struct watchdog_device *wdd)
{
struct starfive_wdt *wdt = watchdog_get_drvdata(wdd);
int ret = pm_runtime_get_sync(wdd->parent);
if (ret < 0)
return ret;
return starfive_wdt_start(wdt);
}
static int starfive_wdt_pm_stop(struct watchdog_device *wdd)
{
struct starfive_wdt *wdt = watchdog_get_drvdata(wdd);
starfive_wdt_stop(wdt);
return pm_runtime_put_sync(wdd->parent);
}
static int starfive_wdt_set_timeout(struct watchdog_device *wdd,
unsigned int timeout)
{
struct starfive_wdt *wdt = watchdog_get_drvdata(wdd);
unsigned long count = timeout * wdt->freq;
/* some watchdogs take two timeouts to reset */
if (wdt->variant->double_timeout)
count /= 2;
wdt->count = count;
wdd->timeout = timeout;
starfive_wdt_unlock(wdt);
starfive_wdt_disable(wdt);
starfive_wdt_set_reload_count(wdt, wdt->count);
starfive_wdt_enable(wdt);
starfive_wdt_lock(wdt);
return 0;
}
#define STARFIVE_WDT_OPTIONS (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
static const struct watchdog_info starfive_wdt_info = {
.options = STARFIVE_WDT_OPTIONS,
.identity = "StarFive Watchdog",
};
static const struct watchdog_ops starfive_wdt_ops = {
.owner = THIS_MODULE,
.start = starfive_wdt_pm_start,
.stop = starfive_wdt_pm_stop,
.ping = starfive_wdt_keepalive,
.set_timeout = starfive_wdt_set_timeout,
.get_timeleft = starfive_wdt_get_timeleft,
};
static int starfive_wdt_probe(struct platform_device *pdev)
{
struct starfive_wdt *wdt;
int ret;
wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
if (!wdt)
return -ENOMEM;
wdt->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(wdt->base))
return dev_err_probe(&pdev->dev, PTR_ERR(wdt->base), "error mapping registers\n");
wdt->wdd.parent = &pdev->dev;
ret = starfive_wdt_get_clock(wdt);
if (ret)
return ret;
platform_set_drvdata(pdev, wdt);
pm_runtime_enable(&pdev->dev);
if (pm_runtime_enabled(&pdev->dev)) {
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0)
return ret;
} else {
/* runtime PM is disabled but clocks need to be enabled */
ret = starfive_wdt_enable_clock(wdt);
if (ret)
return ret;
}
ret = starfive_wdt_reset_init(&pdev->dev);
if (ret)
goto err_exit;
watchdog_set_drvdata(&wdt->wdd, wdt);
wdt->wdd.info = &starfive_wdt_info;
wdt->wdd.ops = &starfive_wdt_ops;
wdt->variant = of_device_get_match_data(&pdev->dev);
spin_lock_init(&wdt->lock);
wdt->freq = clk_get_rate(wdt->core_clk);
if (!wdt->freq) {
dev_err(&pdev->dev, "get clock rate failed.\n");
ret = -EINVAL;
goto err_exit;
}
wdt->wdd.min_timeout = 1;
wdt->wdd.max_timeout = starfive_wdt_max_timeout(wdt);
wdt->wdd.timeout = STARFIVE_WDT_DEFAULT_TIME;
watchdog_init_timeout(&wdt->wdd, heartbeat, &pdev->dev);
starfive_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
watchdog_set_nowayout(&wdt->wdd, nowayout);
watchdog_stop_on_reboot(&wdt->wdd);
watchdog_stop_on_unregister(&wdt->wdd);
if (early_enable) {
ret = starfive_wdt_start(wdt);
if (ret)
goto err_exit;
set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
} else {
starfive_wdt_stop(wdt);
}
ret = watchdog_register_device(&wdt->wdd);
if (ret)
goto err_exit;
if (!early_enable)
pm_runtime_put_sync(&pdev->dev);
return 0;
err_exit:
starfive_wdt_disable_clock(wdt);
pm_runtime_disable(&pdev->dev);
return ret;
}
static int starfive_wdt_remove(struct platform_device *pdev)
{
struct starfive_wdt *wdt = platform_get_drvdata(pdev);
starfive_wdt_stop(wdt);
watchdog_unregister_device(&wdt->wdd);
if (pm_runtime_enabled(&pdev->dev))
pm_runtime_disable(&pdev->dev);
else
/* disable clock without PM */
starfive_wdt_disable_clock(wdt);
return 0;
}
static void starfive_wdt_shutdown(struct platform_device *pdev)
{
struct starfive_wdt *wdt = platform_get_drvdata(pdev);
starfive_wdt_pm_stop(&wdt->wdd);
}
#ifdef CONFIG_PM_SLEEP
static int starfive_wdt_suspend(struct device *dev)
{
struct starfive_wdt *wdt = dev_get_drvdata(dev);
/* Save watchdog state, and turn it off. */
wdt->reload = starfive_wdt_get_count(wdt);
/* Note that WTCNT doesn't need to be saved. */
starfive_wdt_stop(wdt);
return pm_runtime_force_suspend(dev);
}
static int starfive_wdt_resume(struct device *dev)
{
struct starfive_wdt *wdt = dev_get_drvdata(dev);
int ret;
ret = pm_runtime_force_resume(dev);
if (ret)
return ret;
starfive_wdt_unlock(wdt);
/* Restore watchdog state. */
starfive_wdt_set_reload_count(wdt, wdt->reload);
starfive_wdt_lock(wdt);
return starfive_wdt_start(wdt);
}
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM
static int starfive_wdt_runtime_suspend(struct device *dev)
{
struct starfive_wdt *wdt = dev_get_drvdata(dev);
starfive_wdt_disable_clock(wdt);
return 0;
}
static int starfive_wdt_runtime_resume(struct device *dev)
{
struct starfive_wdt *wdt = dev_get_drvdata(dev);
return starfive_wdt_enable_clock(wdt);
}
#endif /* CONFIG_PM */
static const struct dev_pm_ops starfive_wdt_pm_ops = {
SET_RUNTIME_PM_OPS(starfive_wdt_runtime_suspend, starfive_wdt_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(starfive_wdt_suspend, starfive_wdt_resume)
};
static const struct of_device_id starfive_wdt_match[] = {
{ .compatible = "starfive,jh7100-wdt", .data = &starfive_wdt_jh7100_variant },
{ .compatible = "starfive,jh7110-wdt", .data = &starfive_wdt_jh7110_variant },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, starfive_wdt_match);
static struct platform_driver starfive_wdt_driver = {
.probe = starfive_wdt_probe,
.remove = starfive_wdt_remove,
.shutdown = starfive_wdt_shutdown,
.driver = {
.name = "starfive-wdt",
.pm = &starfive_wdt_pm_ops,
.of_match_table = starfive_wdt_match,
},
};
module_platform_driver(starfive_wdt_driver);
MODULE_AUTHOR("Xingyu Wu <xingyu.wu@starfivetech.com>");
MODULE_AUTHOR("Samin Guo <samin.guo@starfivetech.com>");
MODULE_DESCRIPTION("StarFive Watchdog Device Driver");
MODULE_LICENSE("GPL");
...@@ -109,10 +109,9 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev) ...@@ -109,10 +109,9 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int stmp3xxx_wdt_remove(struct platform_device *pdev) static void stmp3xxx_wdt_remove(struct platform_device *pdev)
{ {
unregister_reboot_notifier(&wdt_notifier); unregister_reboot_notifier(&wdt_notifier);
return 0;
} }
static int __maybe_unused stmp3xxx_wdt_suspend(struct device *dev) static int __maybe_unused stmp3xxx_wdt_suspend(struct device *dev)
...@@ -144,7 +143,7 @@ static struct platform_driver stmp3xxx_wdt_driver = { ...@@ -144,7 +143,7 @@ static struct platform_driver stmp3xxx_wdt_driver = {
.pm = &stmp3xxx_wdt_pm_ops, .pm = &stmp3xxx_wdt_pm_ops,
}, },
.probe = stmp3xxx_wdt_probe, .probe = stmp3xxx_wdt_probe,
.remove = stmp3xxx_wdt_remove, .remove_new = stmp3xxx_wdt_remove,
}; };
module_platform_driver(stmp3xxx_wdt_driver); module_platform_driver(stmp3xxx_wdt_driver);
......
...@@ -162,7 +162,7 @@ static int watchdog_reboot_notifier(struct notifier_block *nb, ...@@ -162,7 +162,7 @@ static int watchdog_reboot_notifier(struct notifier_block *nb,
wdd = container_of(nb, struct watchdog_device, reboot_nb); wdd = container_of(nb, struct watchdog_device, reboot_nb);
if (code == SYS_DOWN || code == SYS_HALT) { if (code == SYS_DOWN || code == SYS_HALT) {
if (watchdog_active(wdd) || watchdog_hw_running(wdd)) { if (watchdog_hw_running(wdd)) {
int ret; int ret;
ret = wdd->ops->stop(wdd); ret = wdd->ops->stop(wdd);
......
...@@ -192,7 +192,7 @@ static int watchdog_ping(struct watchdog_device *wdd) ...@@ -192,7 +192,7 @@ static int watchdog_ping(struct watchdog_device *wdd)
{ {
struct watchdog_core_data *wd_data = wdd->wd_data; struct watchdog_core_data *wd_data = wdd->wd_data;
if (!watchdog_active(wdd) && !watchdog_hw_running(wdd)) if (!watchdog_hw_running(wdd))
return 0; return 0;
set_bit(_WDOG_KEEPALIVE, &wd_data->status); set_bit(_WDOG_KEEPALIVE, &wd_data->status);
...@@ -268,6 +268,7 @@ static int watchdog_start(struct watchdog_device *wdd) ...@@ -268,6 +268,7 @@ static int watchdog_start(struct watchdog_device *wdd)
trace_watchdog_start(wdd, err); trace_watchdog_start(wdd, err);
if (err == 0) { if (err == 0) {
set_bit(WDOG_ACTIVE, &wdd->status); set_bit(WDOG_ACTIVE, &wdd->status);
set_bit(WDOG_HW_RUNNING, &wdd->status);
wd_data->last_keepalive = started_at; wd_data->last_keepalive = started_at;
wd_data->last_hw_keepalive = started_at; wd_data->last_hw_keepalive = started_at;
watchdog_update_worker(wdd); watchdog_update_worker(wdd);
......
...@@ -207,10 +207,9 @@ void watchdog_unregister_pretimeout(struct watchdog_device *wdd) ...@@ -207,10 +207,9 @@ void watchdog_unregister_pretimeout(struct watchdog_device *wdd)
list_for_each_entry_safe(p, t, &pretimeout_list, entry) { list_for_each_entry_safe(p, t, &pretimeout_list, entry) {
if (p->wdd == wdd) { if (p->wdd == wdd) {
list_del(&p->entry); list_del(&p->entry);
kfree(p);
break; break;
} }
} }
spin_unlock_irq(&pretimeout_lock); spin_unlock_irq(&pretimeout_lock);
kfree(p);
} }
...@@ -153,18 +153,11 @@ static int wm8350_wdt_probe(struct platform_device *pdev) ...@@ -153,18 +153,11 @@ static int wm8350_wdt_probe(struct platform_device *pdev)
/* Default to 4s timeout */ /* Default to 4s timeout */
wm8350_wdt_set_timeout(&wm8350_wdt, 4); wm8350_wdt_set_timeout(&wm8350_wdt, 4);
return watchdog_register_device(&wm8350_wdt); return devm_watchdog_register_device(&pdev->dev, &wm8350_wdt);
}
static int wm8350_wdt_remove(struct platform_device *pdev)
{
watchdog_unregister_device(&wm8350_wdt);
return 0;
} }
static struct platform_driver wm8350_wdt_driver = { static struct platform_driver wm8350_wdt_driver = {
.probe = wm8350_wdt_probe, .probe = wm8350_wdt_probe,
.remove = wm8350_wdt_remove,
.driver = { .driver = {
.name = "wm8350-wdt", .name = "wm8350-wdt",
}, },
......
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
#ifndef _DT_BINDINGS_RESET_MEDIATEK_MT6735_WDT_H_
#define _DT_BINDINGS_RESET_MEDIATEK_MT6735_WDT_H_
#define MT6735_TOPRGU_MM_RST 1
#define MT6735_TOPRGU_MFG_RST 2
#define MT6735_TOPRGU_VENC_RST 3
#define MT6735_TOPRGU_VDEC_RST 4
#define MT6735_TOPRGU_IMG_RST 5
#define MT6735_TOPRGU_MD_RST 7
#define MT6735_TOPRGU_CONN_RST 9
#define MT6735_TOPRGU_C2K_SW_RST 14
#define MT6735_TOPRGU_C2K_RST 15
#define MT6735_TOPRGU_RST_NUM 9
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment