]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'watchdog-for-linus-v4.11' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 26 Feb 2017 21:19:17 +0000 (13:19 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 26 Feb 2017 21:19:17 +0000 (13:19 -0800)
Pull watchdog updates from Guenter Roeck:
 "Wim asked me to handle the watchdog pull request this time around.

  Key changes:

   - New drivers: Cortina Gemini, ZTE's zx2967 family, NIC7018

   - Convert to use device managed functions: ebc-c384_wdt, tegra_wdt,
     da9063_wdt, da9062_wdt, da9055_wdt, da9052_wdt, bcm2835_wdt,
     mena21_wdt, wm831x_wdt, digicolor_wdt, intel-mid_wdt, meson_wdt,
     sunxi_wdt, aspeed_wdt, coh901327_wdt, iTCO_wdt

   - Use watchdog core to install restart handler: tangox, dw_wdt,
     bcm2835_wdt, asm9260_wdt, bcm47xx_wdt

   - Convert ts72xx_wdt driver to watchdog core

   - Let core handle heartbeat in ep93xx_wdt driver

   - Enable COMPILE_TEST where possible

   - Various other improvements"

* tag 'watchdog-for-linus-v4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging: (54 commits)
  watchdog: s3c2410: Add prefix to local function
  watchdog: s3c2410: Select MFD_SYSCON on all Exynos platforms
  watchdog: s3c2410: Use dev_dbg instead of pr_info
  watchdog: s3c2410: Fix infinite interrupt in soft mode
  watchdog: s3c2410: Remove confusing CONFIG prefix from local defines
  watchdog: softdog: make pretimeout support a compile option
  watchdog: zx2967: add watchdog controller driver for ZTE's zx2967 family
  dt: bindings: add documentation for zx2967 family watchdog controller
  watchdog: sama5d4: Implement resume hook
  watchdog: sama5d4: Cache MR instead of a partial config
  watchdog: ts72xx_wdt: convert driver to watchdog core
  watchdog: ep93xx_wdt: cleanup and let the core handle the heartbeat
  watchdog: RDC321X_WDT always depends on PCI
  watchdog: add driver for Cortina Gemini watchdog
  watchdog: add DT bindings for Cortina Gemini
  watchdog: constify watchdog_ops structures
  watchdog: Introduce watchdog_stop_on_unregister helper
  watchdog: ebc-c384_wdt: Utilize devm_ functions in driver probe callback
  watchdog: tegra_wdt: Convert to use device managed functions
  watchdog: da9063_wdt: Convert to use device managed functions
  ...

57 files changed:
Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt [new file with mode: 0644]
Documentation/watchdog/watchdog-kernel-api.txt
Documentation/watchdog/watchdog-parameters.txt
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/asm9260_wdt.c
drivers/watchdog/aspeed_wdt.c
drivers/watchdog/atlas7_wdt.c
drivers/watchdog/bcm2835_wdt.c
drivers/watchdog/bcm47xx_wdt.c
drivers/watchdog/bcm7038_wdt.c
drivers/watchdog/bcm_kona_wdt.c
drivers/watchdog/booke_wdt.c
drivers/watchdog/cadence_wdt.c
drivers/watchdog/coh901327_wdt.c
drivers/watchdog/da9052_wdt.c
drivers/watchdog/da9055_wdt.c
drivers/watchdog/da9062_wdt.c
drivers/watchdog/da9063_wdt.c
drivers/watchdog/diag288_wdt.c
drivers/watchdog/digicolor_wdt.c
drivers/watchdog/dw_wdt.c
drivers/watchdog/ebc-c384_wdt.c
drivers/watchdog/ep93xx_wdt.c
drivers/watchdog/gemini_wdt.c [new file with mode: 0644]
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/imgpdc_wdt.c
drivers/watchdog/intel-mid_wdt.c
drivers/watchdog/kempld_wdt.c
drivers/watchdog/lantiq_wdt.c
drivers/watchdog/lpc18xx_wdt.c
drivers/watchdog/mena21_wdt.c
drivers/watchdog/meson_wdt.c
drivers/watchdog/mt7621_wdt.c
drivers/watchdog/nic7018_wdt.c [new file with mode: 0644]
drivers/watchdog/orion_wdt.c
drivers/watchdog/pika_wdt.c
drivers/watchdog/rn5t618_wdt.c
drivers/watchdog/rt2880_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sa1100_wdt.c
drivers/watchdog/sama5d4_wdt.c
drivers/watchdog/sbsa_gwdt.c
drivers/watchdog/sirfsoc_wdt.c
drivers/watchdog/softdog.c
drivers/watchdog/sun4v_wdt.c
drivers/watchdog/sunxi_wdt.c
drivers/watchdog/tangox_wdt.c
drivers/watchdog/tegra_wdt.c
drivers/watchdog/ts72xx_wdt.c
drivers/watchdog/w83627hf_wdt.c
drivers/watchdog/watchdog_dev.c
drivers/watchdog/wm831x_wdt.c
drivers/watchdog/zx2967_wdt.c [new file with mode: 0644]
include/linux/watchdog.h

diff --git a/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt b/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt
new file mode 100644 (file)
index 0000000..bc4b865
--- /dev/null
@@ -0,0 +1,17 @@
+Cortina Systems Gemini SoC Watchdog
+
+Required properties:
+- compatible : must be "cortina,gemini-watchdog"
+- reg : shall contain base register location and length
+- interrupts : shall contain the interrupt for the watchdog
+
+Optional properties:
+- timeout-sec : the default watchdog timeout in seconds.
+
+Example:
+
+watchdog@41000000 {
+       compatible = "cortina,gemini-watchdog";
+       reg = <0x41000000 0x1000>;
+       interrupts = <3 IRQ_TYPE_LEVEL_HIGH>;
+};
index 8f3d96af81d70303e5bb449ecc366a85846bdd00..1f6e101e299a217875ea75d5e423a898be32c33e 100644 (file)
@@ -6,10 +6,11 @@ occurred.
 
 Required properties:
 - compatible : should be one among the following
-       (a) "samsung,s3c2410-wdt" for Exynos4 and previous SoCs
-       (b) "samsung,exynos5250-wdt" for Exynos5250
-       (c) "samsung,exynos5420-wdt" for Exynos5420
-       (c) "samsung,exynos7-wdt" for Exynos7
+       - "samsung,s3c2410-wdt" for S3C2410
+       - "samsung,s3c6410-wdt" for S3C6410, S5PV210 and Exynos4
+       - "samsung,exynos5250-wdt" for Exynos5250
+       - "samsung,exynos5420-wdt" for Exynos5420
+       - "samsung,exynos7-wdt" for Exynos7
 
 - reg : base physical address of the controller and length of memory mapped
        region.
diff --git a/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt
new file mode 100644 (file)
index 0000000..06ce677
--- /dev/null
@@ -0,0 +1,32 @@
+ZTE zx2967 Watchdog timer
+
+Required properties:
+
+- compatible : should be one of the following.
+       * zte,zx296718-wdt
+- reg : Specifies base physical address and size of the registers.
+- clocks : Pairs of phandle and specifier referencing the controller's clocks.
+- resets : Reference to the reset controller controlling the watchdog
+           controller.
+
+Optional properties:
+
+- timeout-sec : Contains the watchdog timeout in seconds.
+- zte,wdt-reset-sysctrl : Directs how to reset system by the watchdog.
+       if we don't want to restart system when watchdog been triggered,
+       it's not required, vice versa.
+       It should include following fields.
+         * phandle of aon-sysctrl.
+         * offset of register that be written, should be 0xb0.
+         * configure value that be written to aon-sysctrl.
+         * bit mask, corresponding bits will be affected.
+
+Example:
+
+wdt: watchdog@1465000 {
+       compatible = "zte,zx296718-wdt";
+       reg = <0x1465000 0x1000>;
+       clocks = <&topcrm WDT_WCLK>;
+       resets = <&toprst 35>;
+       zte,wdt-reset-sysctrl = <&aon_sysctrl 0xb0 1 0x115>;
+};
index ea277478982f5aef1e122f33f55140e8c5010fc4..9b93953f69cf866289fd8e49632860185bda1e6c 100644 (file)
@@ -280,6 +280,12 @@ To disable the watchdog on reboot, the user must call the following helper:
 
 static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd);
 
+To disable the watchdog when unregistering the watchdog, the user must call
+the following helper. Note that this will only stop the watchdog if the
+nowayout flag is not set.
+
+static inline void watchdog_stop_on_unregister(struct watchdog_device *wdd);
+
 To change the priority of the restart handler the following helper should be
 used:
 
index e21850e270a0555417c0615f128da609e2e1e1ce..4f7d86dd0a5d88802d85bb68ccf1f93715003a42 100644 (file)
@@ -209,6 +209,11 @@ timeout: Initial watchdog timeout in seconds (0<timeout<516, default=60)
 nowayout: Watchdog cannot be stopped once started
        (default=kernel config parameter)
 -------------------------------------------------
+nic7018_wdt:
+timeout: Initial watchdog timeout in seconds (0<timeout<464, default=80)
+nowayout: Watchdog cannot be stopped once started
+       (default=kernel config parameter)
+-------------------------------------------------
 nuc900_wdt:
 heartbeat: Watchdog heartbeats in seconds.
        (default = 15)
index acb00b53a5207b46252e8f06c1860702f1ccfbe4..c831b7967bf95f46139b55792e6d249a5c5812b2 100644 (file)
@@ -71,9 +71,17 @@ config SOFT_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called softdog.
 
+config SOFT_WATCHDOG_PRETIMEOUT
+       bool "Software watchdog pretimeout governor support"
+       depends on SOFT_WATCHDOG && WATCHDOG_PRETIMEOUT_GOV
+       help
+         Enable this if you want to use pretimeout governors with the software
+         watchdog. Be aware that governors might affect the watchdog because it
+         is purely software, e.g. the panic governor will stall it!
+
 config DA9052_WATCHDOG
        tristate "Dialog DA9052 Watchdog"
-       depends on PMIC_DA9052
+       depends on PMIC_DA9052 || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Support for the watchdog in the DA9052 PMIC. Watchdog trigger
@@ -85,7 +93,7 @@ config DA9052_WATCHDOG
 
 config DA9055_WATCHDOG
        tristate "Dialog Semiconductor DA9055 Watchdog"
-       depends on MFD_DA9055
+       depends on MFD_DA9055 || COMPILE_TEST
        select WATCHDOG_CORE
        help
          If you say yes here you get support for watchdog on the Dialog
@@ -96,7 +104,7 @@ config DA9055_WATCHDOG
 
 config DA9063_WATCHDOG
        tristate "Dialog DA9063 Watchdog"
-       depends on MFD_DA9063
+       depends on MFD_DA9063 || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Support for the watchdog in the DA9063 PMIC.
@@ -105,7 +113,7 @@ config DA9063_WATCHDOG
 
 config DA9062_WATCHDOG
        tristate "Dialog DA9062/61 Watchdog"
-       depends on MFD_DA9062
+       depends on MFD_DA9062 || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Support for the watchdog in the DA9062 and DA9061 PMICs.
@@ -133,7 +141,7 @@ config GPIO_WATCHDOG_ARCH_INITCALL
 
 config MENF21BMC_WATCHDOG
        tristate "MEN 14F021P00 BMC Watchdog"
-       depends on MFD_MENF21BMC
+       depends on MFD_MENF21BMC || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here to include support for the MEN 14F021P00 BMC Watchdog.
@@ -168,7 +176,7 @@ config WDAT_WDT
 
 config WM831X_WATCHDOG
        tristate "WM831x watchdog"
-       depends on MFD_WM831X
+       depends on MFD_WM831X || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Support for the watchdog in the WM831x AudioPlus PMICs.  When
@@ -209,7 +217,7 @@ config ZIIRAVE_WATCHDOG
 
 config ARM_SP805_WATCHDOG
        tristate "ARM SP805 Watchdog"
-       depends on (ARM || ARM64) && ARM_AMBA
+       depends on (ARM || ARM64) && (ARM_AMBA || COMPILE_TEST)
        select WATCHDOG_CORE
        help
          ARM Primecell SP805 Watchdog timer. This will reboot your system when
@@ -237,7 +245,7 @@ config ARM_SBSA_WATCHDOG
 
 config ASM9260_WATCHDOG
        tristate "Alphascale ASM9260 watchdog"
-       depends on MACH_ASM9260
+       depends on MACH_ASM9260 || COMPILE_TEST
        depends on OF
        select WATCHDOG_CORE
        select RESET_CONTROLLER
@@ -247,14 +255,14 @@ config ASM9260_WATCHDOG
 
 config AT91RM9200_WATCHDOG
        tristate "AT91RM9200 watchdog"
-       depends on SOC_AT91RM9200 && MFD_SYSCON
+       depends on (SOC_AT91RM9200 && MFD_SYSCON) || COMPILE_TEST
        help
          Watchdog timer embedded into AT91RM9200 chips. This will reboot your
          system when the timeout is reached.
 
 config AT91SAM9X_WATCHDOG
        tristate "AT91SAM9X / AT91CAP9 watchdog"
-       depends on ARCH_AT91
+       depends on ARCH_AT91 || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will
@@ -262,7 +270,7 @@ config AT91SAM9X_WATCHDOG
 
 config SAMA5D4_WATCHDOG
        tristate "Atmel SAMA5D4 Watchdog Timer"
-       depends on ARCH_AT91
+       depends on ARCH_AT91 || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Atmel SAMA5D4 watchdog timer is embedded into SAMA5D4 chips.
@@ -293,7 +301,7 @@ config 21285_WATCHDOG
 
 config 977_WATCHDOG
        tristate "NetWinder WB83C977 watchdog"
-       depends on FOOTBRIDGE && ARCH_NETWINDER
+       depends on (FOOTBRIDGE && ARCH_NETWINDER) || (ARM && COMPILE_TEST)
        help
          Say Y here to include support for the WB977 watchdog included in
          NetWinder machines. Alternatively say M to compile the driver as
@@ -301,6 +309,17 @@ config 977_WATCHDOG
 
          Not sure? It's safe to say N.
 
+config GEMINI_WATCHDOG
+       tristate "Gemini watchdog"
+       depends on ARCH_GEMINI
+       select WATCHDOG_CORE
+       help
+         Say Y here if to include support for the watchdog timer
+         embedded in the Cortina Systems Gemini family of devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called gemini_wdt.
+
 config IXP4XX_WATCHDOG
        tristate "IXP4xx Watchdog"
        depends on ARCH_IXP4XX
@@ -333,9 +352,9 @@ config HAVE_S3C2410_WATCHDOG
 
 config S3C2410_WATCHDOG
        tristate "S3C2410 Watchdog"
-       depends on HAVE_S3C2410_WATCHDOG
+       depends on HAVE_S3C2410_WATCHDOG || COMPILE_TEST
        select WATCHDOG_CORE
-       select MFD_SYSCON if ARCH_EXYNOS5
+       select MFD_SYSCON if ARCH_EXYNOS
        help
          Watchdog timer block in the Samsung SoCs. This will reboot
          the system when the timer expires with the watchdog enabled.
@@ -372,7 +391,7 @@ config DW_WATCHDOG
 
 config EP93XX_WATCHDOG
        tristate "EP93xx Watchdog"
-       depends on ARCH_EP93XX
+       depends on ARCH_EP93XX || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here if to include support for the watchdog timer
@@ -383,7 +402,7 @@ config EP93XX_WATCHDOG
 
 config OMAP_WATCHDOG
        tristate "OMAP Watchdog"
-       depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS
+       depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog.  Say 'Y'
@@ -419,7 +438,7 @@ config IOP_WATCHDOG
 
 config DAVINCI_WATCHDOG
        tristate "DaVinci watchdog"
-       depends on ARCH_DAVINCI || ARCH_KEYSTONE
+       depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here if to include support for the watchdog timer
@@ -432,7 +451,7 @@ config DAVINCI_WATCHDOG
 
 config ORION_WATCHDOG
        tristate "Orion watchdog"
-       depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU
+       depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU || COMPILE_TEST
        depends on ARM
        select WATCHDOG_CORE
        help
@@ -443,7 +462,7 @@ config ORION_WATCHDOG
 
 config RN5T618_WATCHDOG
        tristate "Ricoh RN5T618 watchdog"
-       depends on MFD_RN5T618
+       depends on MFD_RN5T618 || COMPILE_TEST
        select WATCHDOG_CORE
        help
          If you say yes here you get support for watchdog on the Ricoh
@@ -454,7 +473,7 @@ config RN5T618_WATCHDOG
 
 config SUNXI_WATCHDOG
        tristate "Allwinner SoCs watchdog support"
-       depends on ARCH_SUNXI
+       depends on ARCH_SUNXI || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here to include support for the watchdog timer
@@ -464,7 +483,7 @@ config SUNXI_WATCHDOG
 
 config COH901327_WATCHDOG
        bool "ST-Ericsson COH 901 327 watchdog"
-       depends on ARCH_U300
+       depends on ARCH_U300 || (ARM && COMPILE_TEST)
        default y if MACH_U300
        select WATCHDOG_CORE
        help
@@ -483,7 +502,7 @@ config TWL4030_WATCHDOG
 
 config STMP3XXX_RTC_WATCHDOG
        tristate "Freescale STMP3XXX & i.MX23/28 watchdog"
-       depends on RTC_DRV_STMP
+       depends on RTC_DRV_STMP || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here to include support for the watchdog timer inside
@@ -493,7 +512,7 @@ config STMP3XXX_RTC_WATCHDOG
 
 config NUC900_WATCHDOG
        tristate "Nuvoton NUC900 watchdog"
-       depends on ARCH_W90X900
+       depends on ARCH_W90X900 || COMPILE_TEST
        help
          Say Y here if to include support for the watchdog timer
          for the Nuvoton NUC900 series SoCs.
@@ -513,7 +532,7 @@ config TS4800_WATCHDOG
 
 config TS72XX_WATCHDOG
        tristate "TS-72XX SBC Watchdog"
-       depends on MACH_TS72XX
+       depends on MACH_TS72XX || COMPILE_TEST
        help
          Technologic Systems TS-7200, TS-7250 and TS-7260 boards have
          watchdog timer implemented in a external CPLD chip. Say Y here
@@ -531,7 +550,7 @@ config MAX63XX_WATCHDOG
 
 config MAX77620_WATCHDOG
        tristate "Maxim Max77620 Watchdog Timer"
-       depends on MFD_MAX77620
+       depends on MFD_MAX77620 || COMPILE_TEST
        help
         This is the driver for the Max77620 watchdog timer.
         Say 'Y' here to enable the watchdog timer support for
@@ -540,7 +559,7 @@ config MAX77620_WATCHDOG
 
 config IMX2_WDT
        tristate "IMX2+ Watchdog"
-       depends on ARCH_MXC || ARCH_LAYERSCAPE
+       depends on ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST
        select REGMAP_MMIO
        select WATCHDOG_CORE
        help
@@ -554,7 +573,7 @@ config IMX2_WDT
 
 config UX500_WATCHDOG
        tristate "ST-Ericsson Ux500 watchdog"
-       depends on MFD_DB8500_PRCMU
+       depends on MFD_DB8500_PRCMU || (ARM && COMPILE_TEST)
        select WATCHDOG_CORE
        default y
        help
@@ -566,7 +585,7 @@ config UX500_WATCHDOG
 
 config RETU_WATCHDOG
        tristate "Retu watchdog"
-       depends on MFD_RETU
+       depends on MFD_RETU || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Retu watchdog driver for Nokia Internet Tablets (770, N800,
@@ -578,7 +597,7 @@ config RETU_WATCHDOG
 
 config MOXART_WDT
        tristate "MOXART watchdog"
-       depends on ARCH_MOXART
+       depends on ARCH_MOXART || COMPILE_TEST
        help
          Say Y here to include Watchdog timer support for the watchdog
          existing on the MOXA ART SoC series platforms.
@@ -588,7 +607,7 @@ config MOXART_WDT
 
 config SIRFSOC_WATCHDOG
        tristate "SiRFSOC watchdog"
-       depends on ARCH_SIRF
+       depends on ARCH_SIRF || COMPILE_TEST
        select WATCHDOG_CORE
        default y
        help
@@ -597,7 +616,7 @@ config SIRFSOC_WATCHDOG
 
 config ST_LPC_WATCHDOG
        tristate "STMicroelectronics LPC Watchdog"
-       depends on ARCH_STI
+       depends on ARCH_STI || COMPILE_TEST
        depends on OF
        select WATCHDOG_CORE
        help
@@ -621,7 +640,7 @@ config TEGRA_WATCHDOG
 config QCOM_WDT
        tristate "QCOM watchdog"
        depends on HAS_IOMEM
-       depends on ARCH_QCOM
+       depends on ARCH_QCOM || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here to include Watchdog timer support for the watchdog found
@@ -633,7 +652,7 @@ config QCOM_WDT
 
 config MESON_GXBB_WATCHDOG
        tristate "Amlogic Meson GXBB SoCs watchdog support"
-       depends on ARCH_MESON
+       depends on ARCH_MESON || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here to include support for the watchdog timer
@@ -643,7 +662,7 @@ config MESON_GXBB_WATCHDOG
 
 config MESON_WATCHDOG
        tristate "Amlogic Meson SoCs watchdog support"
-       depends on ARCH_MESON
+       depends on ARCH_MESON || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here to include support for the watchdog timer
@@ -653,7 +672,7 @@ config MESON_WATCHDOG
 
 config MEDIATEK_WATCHDOG
        tristate "Mediatek SoCs watchdog support"
-       depends on ARCH_MEDIATEK
+       depends on ARCH_MEDIATEK || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here to include support for the watchdog timer
@@ -663,7 +682,7 @@ config MEDIATEK_WATCHDOG
 
 config DIGICOLOR_WATCHDOG
        tristate "Conexant Digicolor SoCs watchdog support"
-       depends on ARCH_DIGICOLOR
+       depends on ARCH_DIGICOLOR || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Say Y here to include support for the watchdog timer
@@ -685,7 +704,7 @@ config LPC18XX_WATCHDOG
 
 config ATLAS7_WATCHDOG
        tristate "CSRatlas7 watchdog"
-       depends on ARCH_ATLAS7
+       depends on ARCH_ATLAS7 || COMPILE_TEST
        help
          Say Y here to include Watchdog timer support for the watchdog
          existing on the CSRatlas7 series platforms.
@@ -714,11 +733,21 @@ config ASPEED_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called aspeed_wdt.
 
+config ZX2967_WATCHDOG
+       tristate "ZTE zx2967 SoCs watchdog support"
+       depends on ARCH_ZX
+       select WATCHDOG_CORE
+       help
+         Say Y here to include support for the watchdog timer
+         in ZTE zx2967 SoCs.
+         To compile this driver as a module, choose M here: the
+         module will be called zx2967_wdt.
+
 # AVR32 Architecture
 
 config AT32AP700X_WDT
        tristate "AT32AP700x watchdog"
-       depends on CPU_AT32AP700X
+       depends on CPU_AT32AP700X || COMPILE_TEST
        help
          Watchdog timer embedded into AT32AP700x devices. This will reboot
          your system when the timeout is reached.
@@ -822,7 +851,7 @@ config SP5100_TCO
 
 config GEODE_WDT
        tristate "AMD Geode CS5535/CS5536 Watchdog"
-       depends on CS5535_MFGPT
+       depends on CS5535_MFGPT || (X86 && COMPILE_TEST)
        help
          This driver enables a watchdog capability built into the
          CS5535/CS5536 companion chips for the AMD Geode GX and LX
@@ -835,7 +864,7 @@ config GEODE_WDT
 
 config SC520_WDT
        tristate "AMD Elan SC520 processor Watchdog"
-       depends on MELAN
+       depends on MELAN || COMPILE_TEST
        help
          This is the driver for the hardware watchdog built in to the
          AMD "Elan" SC520 microcomputer commonly used in embedded systems.
@@ -1034,7 +1063,7 @@ config HP_WATCHDOG
 
 config KEMPLD_WDT
        tristate "Kontron COM Watchdog Timer"
-       depends on MFD_KEMPLD
+       depends on MFD_KEMPLD || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Support for the PLD watchdog on some Kontron ETX and COMexpress
@@ -1108,7 +1137,8 @@ config NV_TCO
 
 config RDC321X_WDT
        tristate "RDC R-321x SoC watchdog"
-       depends on X86_RDC321X
+       depends on X86_RDC321X || COMPILE_TEST
+       depends on PCI
        help
          This is the driver for the built in hardware watchdog
          in the RDC R-321x SoC.
@@ -1326,6 +1356,16 @@ config NI903X_WDT
          To compile this driver as a module, choose M here: the module will be
          called ni903x_wdt.
 
+config NIC7018_WDT
+       tristate "NIC7018 Watchdog"
+       depends on X86 && ACPI
+       select WATCHDOG_CORE
+       ---help---
+         Support for National Instruments NIC7018 Watchdog.
+
+         To compile this driver as a module, choose M here: the module will be
+         called nic7018_wdt.
+
 # M32R Architecture
 
 # M68K Architecture
@@ -1343,14 +1383,14 @@ config M54xx_WATCHDOG
 
 config ATH79_WDT
        tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog"
-       depends on ATH79
+       depends on ATH79 || (ARM && COMPILE_TEST)
        help
          Hardware driver for the built-in watchdog timer on the Atheros
          AR71XX/AR724X/AR913X SoCs.
 
 config BCM47XX_WDT
        tristate "Broadcom BCM47xx Watchdog Timer"
-       depends on BCM47XX || ARCH_BCM_5301X
+       depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Hardware driver for the Broadcom BCM47xx Watchdog Timer.
@@ -1367,7 +1407,7 @@ config RC32434_WDT
 
 config INDYDOG
        tristate "Indy/I2 Hardware Watchdog"
-       depends on SGI_HAS_INDYDOG
+       depends on SGI_HAS_INDYDOG || (MIPS && COMPILE_TEST)
        help
          Hardware driver for the Indy's/I2's watchdog. This is a
          watchdog timer that will reboot the machine after a 60 second
@@ -1383,7 +1423,7 @@ config JZ4740_WDT
 
 config WDT_MTX1
        tristate "MTX-1 Hardware Watchdog"
-       depends on MIPS_MTX1
+       depends on MIPS_MTX1 || (MIPS && COMPILE_TEST)
        help
          Hardware driver for the MTX-1 boards. This is a watchdog timer that
          will reboot the machine after a 100 seconds timer expired.
@@ -1391,6 +1431,7 @@ config WDT_MTX1
 config PNX833X_WDT
        tristate "PNX833x Hardware Watchdog"
        depends on SOC_PNX8335
+       depends on BROKEN
        help
          Hardware driver for the PNX833x's watchdog. This is a
          watchdog timer that will reboot the machine after a programmable
@@ -1399,7 +1440,7 @@ config PNX833X_WDT
 
 config SIBYTE_WDOG
        tristate "Sibyte SoC hardware watchdog"
-       depends on CPU_SB1
+       depends on CPU_SB1 || (MIPS && COMPILE_TEST)
        help
          Watchdog driver for the built in watchdog hardware in Sibyte
          SoC processors.  There are apparently two watchdog timers
@@ -1412,13 +1453,13 @@ config SIBYTE_WDOG
 
 config AR7_WDT
        tristate "TI AR7 Watchdog Timer"
-       depends on AR7
+       depends on AR7 || (MIPS && COMPILE_TEST)
        help
          Hardware driver for the TI AR7 Watchdog Timer.
 
 config TXX9_WDT
        tristate "Toshiba TXx9 Watchdog Timer"
-       depends on CPU_TX39XX || CPU_TX49XX
+       depends on CPU_TX39XX || CPU_TX49XX || (MIPS && COMPILE_TEST)
        select WATCHDOG_CORE
        help
          Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs.
@@ -1454,7 +1495,7 @@ config BCM63XX_WDT
 
 config BCM2835_WDT
        tristate "Broadcom BCM2835 hardware watchdog"
-       depends on ARCH_BCM2835
+       depends on ARCH_BCM2835 || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Watchdog driver for the built in watchdog hardware in Broadcom
@@ -1465,7 +1506,7 @@ config BCM2835_WDT
 
 config BCM_KONA_WDT
        tristate "BCM Kona Watchdog"
-       depends on ARCH_BCM_MOBILE
+       depends on ARCH_BCM_MOBILE || COMPILE_TEST
        select WATCHDOG_CORE
        help
          Support for the watchdog timer on the following Broadcom BCM281xx
@@ -1477,7 +1518,7 @@ config BCM_KONA_WDT
 
 config BCM_KONA_WDT_DEBUG
        bool "DEBUGFS support for BCM Kona Watchdog"
-       depends on BCM_KONA_WDT
+       depends on BCM_KONA_WDT || COMPILE_TEST
        help
          If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides
          access to the driver's internal data structures as well as watchdog
@@ -1538,7 +1579,7 @@ config MT7621_WDT
 config PIC32_WDT
        tristate "Microchip PIC32 hardware watchdog"
        select WATCHDOG_CORE
-       depends on MACH_PIC32
+       depends on MACH_PIC32 || (MIPS && COMPILE_TEST)
        help
          Watchdog driver for the built in watchdog hardware in a PIC32.
 
@@ -1551,7 +1592,7 @@ config PIC32_WDT
 config PIC32_DMT
        tristate "Microchip PIC32 Deadman Timer"
        select WATCHDOG_CORE
-       depends on MACH_PIC32
+       depends on MACH_PIC32 || (MIPS && COMPILE_TEST)
        help
          Watchdog driver for PIC32 instruction fetch counting timer. This specific
          timer is typically be used in misson critical and safety critical
@@ -1573,7 +1614,7 @@ config GEF_WDT
 
 config MPC5200_WDT
        bool "MPC52xx Watchdog Timer"
-       depends on PPC_MPC52xx
+       depends on PPC_MPC52xx || COMPILE_TEST
        help
          Use General Purpose Timer (GPT) 0 on the MPC5200 as Watchdog.
 
@@ -1592,11 +1633,11 @@ config 8xxx_WDT
 
 config MV64X60_WDT
        tristate "MV64X60 (Marvell Discovery) Watchdog Timer"
-       depends on MV64X60
+       depends on MV64X60 || COMPILE_TEST
 
 config PIKA_WDT
        tristate "PIKA FPGA Watchdog"
-       depends on WARP
+       depends on WARP || (PPC64 && COMPILE_TEST)
        default y
        help
          This enables the watchdog in the PIKA FPGA. Currently used on
@@ -1646,7 +1687,7 @@ config MEN_A21_WDT
 
 config WATCHDOG_RTAS
        tristate "RTAS watchdog"
-       depends on PPC_RTAS
+       depends on PPC_RTAS || (PPC64 && COMPILE_TEST)
        help
          This driver adds watchdog support for the RTAS watchdog.
 
@@ -1674,7 +1715,7 @@ config DIAG288_WATCHDOG
 
 config SH_WDT
        tristate "SuperH Watchdog"
-       depends on SUPERH && (CPU_SH3 || CPU_SH4)
+       depends on SUPERH && (CPU_SH3 || CPU_SH4 || COMPILE_TEST)
        select WATCHDOG_CORE
        help
          This driver adds watchdog support for the integrated watchdog in the
@@ -1741,7 +1782,7 @@ config XEN_WDT
 
 config UML_WATCHDOG
        tristate "UML watchdog"
-       depends on UML
+       depends on UML || COMPILE_TEST
 
 #
 # ISA-based Watchdog Cards
index 0c3d35e3c3341541fc4140797653611a1bed88a8..a2126e2a99ae85205bb96c7981f44cb36fc97efd 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o
 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
 obj-$(CONFIG_977_WATCHDOG) += wdt977.o
+obj-$(CONFIG_GEMINI_WATCHDOG) += gemini_wdt.o
 obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o
 obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o
 obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
@@ -82,6 +83,7 @@ obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o
 obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o
 obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o
 obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o
+obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -139,6 +141,7 @@ obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o
 obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o
 obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o
 obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o
+obj-$(CONFIG_NIC7018_WDT) += nic7018_wdt.o
 
 # M32R Architecture
 
index d0b59ba0f661a0be2dbfce74cc35851d08463ed5..53da001f0838eeb09303bce1725d316068b369c1 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/reset.h>
 #include <linux/watchdog.h>
 
@@ -59,7 +58,6 @@ struct asm9260_wdt_priv {
        struct clk              *clk;
        struct clk              *clk_ahb;
        struct reset_control    *rst;
-       struct notifier_block   restart_handler;
 
        void __iomem            *iobase;
        int                     irq;
@@ -172,15 +170,14 @@ static irqreturn_t asm9260_wdt_irq(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
-static int asm9260_restart_handler(struct notifier_block *this,
-                                  unsigned long mode, void *cmd)
+static int asm9260_restart(struct watchdog_device *wdd, unsigned long action,
+                          void *data)
 {
-       struct asm9260_wdt_priv *priv =
-               container_of(this, struct asm9260_wdt_priv, restart_handler);
+       struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
        asm9260_wdt_sys_reset(priv);
 
-       return NOTIFY_DONE;
+       return 0;
 }
 
 static const struct watchdog_info asm9260_wdt_ident = {
@@ -189,13 +186,14 @@ static const struct watchdog_info asm9260_wdt_ident = {
        .identity         =     "Alphascale asm9260 Watchdog",
 };
 
-static struct watchdog_ops asm9260_wdt_ops = {
+static const struct watchdog_ops asm9260_wdt_ops = {
        .owner          = THIS_MODULE,
        .start          = asm9260_wdt_enable,
        .stop           = asm9260_wdt_disable,
        .get_timeleft   = asm9260_wdt_gettimeleft,
        .ping           = asm9260_wdt_feed,
        .set_timeout    = asm9260_wdt_settimeout,
+       .restart        = asm9260_restart,
 };
 
 static int asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv *priv)
@@ -335,18 +333,14 @@ static int asm9260_wdt_probe(struct platform_device *pdev)
                        dev_warn(&pdev->dev, "failed to request IRQ\n");
        }
 
+       watchdog_set_restart_priority(wdd, 128);
+
        ret = watchdog_register_device(wdd);
        if (ret)
                goto clk_off;
 
        platform_set_drvdata(pdev, priv);
 
-       priv->restart_handler.notifier_call = asm9260_restart_handler;
-       priv->restart_handler.priority = 128;
-       ret = register_restart_handler(&priv->restart_handler);
-       if (ret)
-               dev_warn(&pdev->dev, "cannot register restart handler\n");
-
        dev_info(&pdev->dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n",
                 wdd->timeout, mode_name[priv->mode]);
        return 0;
@@ -370,8 +364,6 @@ static int asm9260_wdt_remove(struct platform_device *pdev)
 
        asm9260_wdt_disable(&priv->wdd);
 
-       unregister_restart_handler(&priv->restart_handler);
-
        watchdog_unregister_device(&priv->wdd);
 
        clk_disable_unprepare(priv->clk);
index f5ad8023c2e6aeea92ddc245ebc2d034dd843ac6..1c652582de40036ed44d21d8c8d67bded52aa643 100644 (file)
@@ -136,15 +136,6 @@ static const struct watchdog_info aspeed_wdt_info = {
        .identity       = KBUILD_MODNAME,
 };
 
-static int aspeed_wdt_remove(struct platform_device *pdev)
-{
-       struct aspeed_wdt *wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&wdt->wdd);
-
-       return 0;
-}
-
 static int aspeed_wdt_probe(struct platform_device *pdev)
 {
        struct aspeed_wdt *wdt;
@@ -187,20 +178,17 @@ static int aspeed_wdt_probe(struct platform_device *pdev)
                set_bit(WDOG_HW_RUNNING, &wdt->wdd.status);
        }
 
-       ret = watchdog_register_device(&wdt->wdd);
+       ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);
        if (ret) {
                dev_err(&pdev->dev, "failed to register\n");
                return ret;
        }
 
-       platform_set_drvdata(pdev, wdt);
-
        return 0;
 }
 
 static struct platform_driver aspeed_watchdog_driver = {
        .probe = aspeed_wdt_probe,
-       .remove = aspeed_wdt_remove,
        .driver = {
                .name = KBUILD_MODNAME,
                .of_match_table = of_match_ptr(aspeed_wdt_of_table),
index ed80734befae16ea294b97fa6f1bfc5249a5d6bc..4abdcabd8219e61ddc8adbbba23ac804f2f54f2c 100644 (file)
@@ -105,7 +105,7 @@ static const struct watchdog_info atlas7_wdt_ident = {
        .identity = "atlas7 Watchdog",
 };
 
-static struct watchdog_ops atlas7_wdt_ops = {
+static const struct watchdog_ops atlas7_wdt_ops = {
        .owner = THIS_MODULE,
        .start = atlas7_wdt_enable,
        .stop = atlas7_wdt_disable,
index c32c45bd8b097889c8f322255fa63c8ed507d6ab..496f6c106bb134a8e0d99a7f7975fa36b67f53df 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/delay.h>
-#include <linux/reboot.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/io.h>
@@ -49,7 +48,6 @@
 struct bcm2835_wdt {
        void __iomem            *base;
        spinlock_t              lock;
-       struct notifier_block   restart_handler;
 };
 
 static unsigned int heartbeat;
@@ -99,11 +97,37 @@ static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog)
        return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET);
 }
 
+static void __bcm2835_restart(struct bcm2835_wdt *wdt)
+{
+       u32 val;
+
+       /* use a timeout of 10 ticks (~150us) */
+       writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
+       val = readl_relaxed(wdt->base + PM_RSTC);
+       val &= PM_RSTC_WRCFG_CLR;
+       val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
+       writel_relaxed(val, wdt->base + PM_RSTC);
+
+       /* No sleeping, possibly atomic. */
+       mdelay(1);
+}
+
+static int bcm2835_restart(struct watchdog_device *wdog,
+                          unsigned long action, void *data)
+{
+       struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog);
+
+       __bcm2835_restart(wdt);
+
+       return 0;
+}
+
 static const struct watchdog_ops bcm2835_wdt_ops = {
        .owner =        THIS_MODULE,
        .start =        bcm2835_wdt_start,
        .stop =         bcm2835_wdt_stop,
        .get_timeleft = bcm2835_wdt_get_timeleft,
+       .restart =      bcm2835_restart,
 };
 
 static const struct watchdog_info bcm2835_wdt_info = {
@@ -120,26 +144,6 @@ static struct watchdog_device bcm2835_wdt_wdd = {
        .timeout =      WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET),
 };
 
-static int
-bcm2835_restart(struct notifier_block *this, unsigned long mode, void *cmd)
-{
-       struct bcm2835_wdt *wdt = container_of(this, struct bcm2835_wdt,
-                                              restart_handler);
-       u32 val;
-
-       /* use a timeout of 10 ticks (~150us) */
-       writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG);
-       val = readl_relaxed(wdt->base + PM_RSTC);
-       val &= PM_RSTC_WRCFG_CLR;
-       val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET;
-       writel_relaxed(val, wdt->base + PM_RSTC);
-
-       /* No sleeping, possibly atomic. */
-       mdelay(1);
-
-       return 0;
-}
-
 /*
  * We can't really power off, but if we do the normal reset scheme, and
  * indicate to bootcode.bin not to reboot, then most of the chip will be
@@ -163,13 +167,13 @@ static void bcm2835_power_off(void)
        writel_relaxed(val, wdt->base + PM_RSTS);
 
        /* Continue with normal reset mechanism */
-       bcm2835_restart(&wdt->restart_handler, REBOOT_HARD, NULL);
+       __bcm2835_restart(wdt);
 }
 
 static int bcm2835_wdt_probe(struct platform_device *pdev)
 {
+       struct resource *res;
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
        struct bcm2835_wdt *wdt;
        int err;
 
@@ -180,16 +184,15 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
 
        spin_lock_init(&wdt->lock);
 
-       wdt->base = of_iomap(np, 0);
-       if (!wdt->base) {
-               dev_err(dev, "Failed to remap watchdog regs");
-               return -ENODEV;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdt->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(wdt->base))
+               return PTR_ERR(wdt->base);
 
        watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt);
        watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev);
        watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout);
-       bcm2835_wdt_wdd.parent = &pdev->dev;
+       bcm2835_wdt_wdd.parent = dev;
        if (bcm2835_wdt_is_running(wdt)) {
                /*
                 * The currently active timeout value (set by the
@@ -201,16 +204,16 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
                 */
                set_bit(WDOG_HW_RUNNING, &bcm2835_wdt_wdd.status);
        }
-       err = watchdog_register_device(&bcm2835_wdt_wdd);
+
+       watchdog_set_restart_priority(&bcm2835_wdt_wdd, 128);
+
+       watchdog_stop_on_reboot(&bcm2835_wdt_wdd);
+       err = devm_watchdog_register_device(dev, &bcm2835_wdt_wdd);
        if (err) {
                dev_err(dev, "Failed to register watchdog device");
-               iounmap(wdt->base);
                return err;
        }
 
-       wdt->restart_handler.notifier_call = bcm2835_restart;
-       wdt->restart_handler.priority = 128;
-       register_restart_handler(&wdt->restart_handler);
        if (pm_power_off == NULL)
                pm_power_off = bcm2835_power_off;
 
@@ -220,22 +223,12 @@ static int bcm2835_wdt_probe(struct platform_device *pdev)
 
 static int bcm2835_wdt_remove(struct platform_device *pdev)
 {
-       struct bcm2835_wdt *wdt = platform_get_drvdata(pdev);
-
-       unregister_restart_handler(&wdt->restart_handler);
        if (pm_power_off == bcm2835_power_off)
                pm_power_off = NULL;
-       watchdog_unregister_device(&bcm2835_wdt_wdd);
-       iounmap(wdt->base);
 
        return 0;
 }
 
-static void bcm2835_wdt_shutdown(struct platform_device *pdev)
-{
-       bcm2835_wdt_stop(&bcm2835_wdt_wdd);
-}
-
 static const struct of_device_id bcm2835_wdt_of_match[] = {
        { .compatible = "brcm,bcm2835-pm-wdt", },
        {},
@@ -245,7 +238,6 @@ MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match);
 static struct platform_driver bcm2835_wdt_driver = {
        .probe          = bcm2835_wdt_probe,
        .remove         = bcm2835_wdt_remove,
-       .shutdown       = bcm2835_wdt_shutdown,
        .driver = {
                .name =         "bcm2835-wdt",
                .of_match_table = bcm2835_wdt_of_match,
index a1900b9ab6c4e651b799f39b6c0f80ae62657d05..35725e21b18a609d267b5dfd49ce4dcc803133af 100644 (file)
@@ -226,9 +226,6 @@ static int bcm47xx_wdt_remove(struct platform_device *pdev)
 {
        struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
 
-       if (!wdt)
-               return -ENXIO;
-
        watchdog_unregister_device(&wdt->wdd);
 
        return 0;
index 4814c00b32f6de8c47b6c112988ce3837ffe7f81..c1b8e534fb5585ad52c2b4d9693981d33b448dff 100644 (file)
@@ -101,7 +101,7 @@ static unsigned int bcm7038_wdt_get_timeleft(struct watchdog_device *wdog)
        return time_left / wdt->rate;
 }
 
-static struct watchdog_info bcm7038_wdt_info = {
+static const struct watchdog_info bcm7038_wdt_info = {
        .identity       = "Broadcom BCM7038 Watchdog Timer",
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
                                WDIOF_MAGICCLOSE
index e0c98423f2c9d0c2203a14933a0061f3026b224e..6fce17d5b9f1a27f94e711d0e69d9844c920a91d 100644 (file)
@@ -266,7 +266,7 @@ static int bcm_kona_wdt_stop(struct watchdog_device *wdog)
                                            SECWDOG_SRSTEN_MASK, 0);
 }
 
-static struct watchdog_ops bcm_kona_wdt_ops = {
+static const struct watchdog_ops bcm_kona_wdt_ops = {
        .owner =        THIS_MODULE,
        .start =        bcm_kona_wdt_start,
        .stop =         bcm_kona_wdt_stop,
@@ -274,7 +274,7 @@ static struct watchdog_ops bcm_kona_wdt_ops = {
        .get_timeleft = bcm_kona_wdt_get_timeleft,
 };
 
-static struct watchdog_info bcm_kona_wdt_info = {
+static const struct watchdog_info bcm_kona_wdt_info = {
        .options =      WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
                        WDIOF_KEEPALIVEPING,
        .identity =     "Broadcom Kona Watchdog Timer",
index 04da4b66c75e361d191a0c0faac4fd4010d9d26a..3ad1e44bef44b16cf653eaeac430ee8316916f68 100644 (file)
@@ -192,12 +192,12 @@ static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev,
        return 0;
 }
 
-static struct watchdog_info booke_wdt_info = {
+static struct watchdog_info booke_wdt_info __ro_after_init = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
        .identity = "PowerPC Book-E Watchdog",
 };
 
-static struct watchdog_ops booke_wdt_ops = {
+static const struct watchdog_ops booke_wdt_ops = {
        .owner = THIS_MODULE,
        .start = booke_wdt_start,
        .stop = booke_wdt_stop,
index 98acef72334d7760296ab98ef30fa1d417a6ad83..8d61e8bfe60b1a418eab489e966652840dedccff 100644 (file)
@@ -262,7 +262,7 @@ static irqreturn_t cdns_wdt_irq_handler(int irq, void *dev_id)
  * Info structure used to indicate the features supported by the device
  * to the upper layers. This is defined in watchdog.h header file.
  */
-static struct watchdog_info cdns_wdt_info = {
+static const struct watchdog_info cdns_wdt_info = {
        .identity       = "cdns_wdt watchdog",
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
                          WDIOF_MAGICCLOSE,
index a099b77fc0b91a076302f6657aaf87d4be9ed159..38dd60f0cfcc636d0b5df5197c06ffcb9f09adbf 100644 (file)
 
 /* Default timeout in seconds = 1 minute */
 static unsigned int margin = 60;
-static resource_size_t phybase;
-static resource_size_t physize;
 static int irq;
 static void __iomem *virtbase;
 static struct device *parent;
 
-/*
- * The watchdog block is of course always clocked, the
- * clk_enable()/clk_disable() calls are mainly for performing reference
- * counting higher up in the clock hierarchy.
- */
 static struct clk *clk;
 
 /*
@@ -90,7 +83,6 @@ static void coh901327_enable(u16 timeout)
        unsigned long freq;
        unsigned long delay_ns;
 
-       clk_enable(clk);
        /* Restart timer if it is disabled */
        val = readw(virtbase + U300_WDOG_D2R);
        if (val == U300_WDOG_D2R_DISABLE_STATUS_DISABLED)
@@ -118,7 +110,6 @@ static void coh901327_enable(u16 timeout)
         */
        (void) readw(virtbase + U300_WDOG_CR);
        val = readw(virtbase + U300_WDOG_D2R);
-       clk_disable(clk);
        if (val != U300_WDOG_D2R_DISABLE_STATUS_ENABLED)
                dev_err(parent,
                        "%s(): watchdog not enabled! D2R value %04x\n",
@@ -129,7 +120,6 @@ static void coh901327_disable(void)
 {
        u16 val;
 
-       clk_enable(clk);
        /* Disable the watchdog interrupt if it is active */
        writew(0x0000U, virtbase + U300_WDOG_IMR);
        /* If the watchdog is currently enabled, attempt to disable it */
@@ -144,7 +134,6 @@ static void coh901327_disable(void)
                       virtbase + U300_WDOG_D2R);
        }
        val = readw(virtbase + U300_WDOG_D2R);
-       clk_disable(clk);
        if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED)
                dev_err(parent,
                        "%s(): watchdog not disabled! D2R value %04x\n",
@@ -165,11 +154,9 @@ static int coh901327_stop(struct watchdog_device *wdt_dev)
 
 static int coh901327_ping(struct watchdog_device *wdd)
 {
-       clk_enable(clk);
        /* Feed the watchdog */
        writew(U300_WDOG_FR_FEED_RESTART_TIMER,
               virtbase + U300_WDOG_FR);
-       clk_disable(clk);
        return 0;
 }
 
@@ -177,13 +164,11 @@ static int coh901327_settimeout(struct watchdog_device *wdt_dev,
                                unsigned int time)
 {
        wdt_dev->timeout = time;
-       clk_enable(clk);
        /* Set new timeout value */
        writew(time * 100, virtbase + U300_WDOG_TR);
        /* Feed the dog */
        writew(U300_WDOG_FR_FEED_RESTART_TIMER,
               virtbase + U300_WDOG_FR);
-       clk_disable(clk);
        return 0;
 }
 
@@ -191,13 +176,11 @@ static unsigned int coh901327_gettimeleft(struct watchdog_device *wdt_dev)
 {
        u16 val;
 
-       clk_enable(clk);
        /* Read repeatedly until the value is stable! */
        val = readw(virtbase + U300_WDOG_CR);
        while (val & U300_WDOG_CR_VALID_IND)
                val = readw(virtbase + U300_WDOG_CR);
        val &= U300_WDOG_CR_COUNT_VALUE_MASK;
-       clk_disable(clk);
        if (val != 0)
                val /= 100;
 
@@ -221,13 +204,11 @@ static irqreturn_t coh901327_interrupt(int irq, void *data)
         * to prevent a watchdog reset by feeding the watchdog at this
         * point.
         */
-       clk_enable(clk);
        val = readw(virtbase + U300_WDOG_IER);
        if (val == U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND)
                writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE,
                       virtbase + U300_WDOG_IER);
        writew(0x0000U, virtbase + U300_WDOG_IMR);
-       clk_disable(clk);
        dev_crit(parent, "watchdog is barking!\n");
        return IRQ_HANDLED;
 }
@@ -263,81 +244,63 @@ static int __exit coh901327_remove(struct platform_device *pdev)
        watchdog_unregister_device(&coh901327_wdt);
        coh901327_disable();
        free_irq(irq, pdev);
-       clk_unprepare(clk);
+       clk_disable_unprepare(clk);
        clk_put(clk);
-       iounmap(virtbase);
-       release_mem_region(phybase, physize);
        return 0;
 }
 
 static int __init coh901327_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        int ret;
        u16 val;
        struct resource *res;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENOENT;
-
-       parent = &pdev->dev;
-       physize = resource_size(res);
-       phybase = res->start;
+       parent = dev;
 
-       if (request_mem_region(phybase, physize, DRV_NAME) == NULL) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       virtbase = ioremap(phybase, physize);
-       if (!virtbase) {
-               ret = -ENOMEM;
-               goto out_no_remap;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       virtbase = devm_ioremap_resource(dev, res);
+       if (IS_ERR(virtbase))
+               return PTR_ERR(virtbase);
 
-       clk = clk_get(&pdev->dev, NULL);
+       clk = clk_get(dev, NULL);
        if (IS_ERR(clk)) {
                ret = PTR_ERR(clk);
-               dev_err(&pdev->dev, "could not get clock\n");
-               goto out_no_clk;
+               dev_err(dev, "could not get clock\n");
+               return ret;
        }
        ret = clk_prepare_enable(clk);
        if (ret) {
-               dev_err(&pdev->dev, "could not prepare and enable clock\n");
+               dev_err(dev, "could not prepare and enable clock\n");
                goto out_no_clk_enable;
        }
 
        val = readw(virtbase + U300_WDOG_SR);
        switch (val) {
        case U300_WDOG_SR_STATUS_TIMED_OUT:
-               dev_info(&pdev->dev,
-                       "watchdog timed out since last chip reset!\n");
+               dev_info(dev, "watchdog timed out since last chip reset!\n");
                coh901327_wdt.bootstatus |= WDIOF_CARDRESET;
                /* Status will be cleared below */
                break;
        case U300_WDOG_SR_STATUS_NORMAL:
-               dev_info(&pdev->dev,
-                       "in normal status, no timeouts have occurred.\n");
+               dev_info(dev, "in normal status, no timeouts have occurred.\n");
                break;
        default:
-               dev_info(&pdev->dev,
-                       "contains an illegal status code (%08x)\n", val);
+               dev_info(dev, "contains an illegal status code (%08x)\n", val);
                break;
        }
 
        val = readw(virtbase + U300_WDOG_D2R);
        switch (val) {
        case U300_WDOG_D2R_DISABLE_STATUS_DISABLED:
-               dev_info(&pdev->dev, "currently disabled.\n");
+               dev_info(dev, "currently disabled.\n");
                break;
        case U300_WDOG_D2R_DISABLE_STATUS_ENABLED:
-               dev_info(&pdev->dev,
-                        "currently enabled! (disabling it now)\n");
+               dev_info(dev, "currently enabled! (disabling it now)\n");
                coh901327_disable();
                break;
        default:
-               dev_err(&pdev->dev,
-                       "contains an illegal enable/disable code (%08x)\n",
+               dev_err(dev, "contains an illegal enable/disable code (%08x)\n",
                        val);
                break;
        }
@@ -352,20 +315,16 @@ static int __init coh901327_probe(struct platform_device *pdev)
                goto out_no_irq;
        }
 
-       clk_disable(clk);
-
-       ret = watchdog_init_timeout(&coh901327_wdt, margin, &pdev->dev);
+       ret = watchdog_init_timeout(&coh901327_wdt, margin, dev);
        if (ret < 0)
                coh901327_wdt.timeout = 60;
 
-       coh901327_wdt.parent = &pdev->dev;
+       coh901327_wdt.parent = dev;
        ret = watchdog_register_device(&coh901327_wdt);
-       if (ret == 0)
-               dev_info(&pdev->dev,
-                        "initialized. timer margin=%d sec\n", margin);
-       else
+       if (ret)
                goto out_no_wdog;
 
+       dev_info(dev, "initialized. timer margin=%d sec\n", margin);
        return 0;
 
 out_no_wdog:
@@ -374,11 +333,6 @@ out_no_irq:
        clk_disable_unprepare(clk);
 out_no_clk_enable:
        clk_put(clk);
-out_no_clk:
-       iounmap(virtbase);
-out_no_remap:
-       release_mem_region(phybase, SZ_4K);
-out:
        return ret;
 }
 
index 2fc19a32a320bfcd49113c30e441bb837054d588..d6d5006efa717df162a4746341467d96a677f412 100644 (file)
@@ -128,19 +128,17 @@ static int da9052_wdt_ping(struct watchdog_device *wdt_dev)
        ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
                                DA9052_CONTROLD_WATCHDOG, 1 << 7);
        if (ret < 0)
-               goto err_strobe;
+               return ret;
 
        /*
         * FIXME: Reset the watchdog core, in general PMIC
         * is supposed to do this
         */
-       ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
-                               DA9052_CONTROLD_WATCHDOG, 0 << 7);
-err_strobe:
-       return ret;
+       return da9052_reg_update(da9052, DA9052_CONTROL_D_REG,
+                                DA9052_CONTROLD_WATCHDOG, 0 << 7);
 }
 
-static struct watchdog_info da9052_wdt_info = {
+static const struct watchdog_info da9052_wdt_info = {
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
        .identity       = "DA9052 Watchdog",
 };
@@ -163,10 +161,8 @@ static int da9052_wdt_probe(struct platform_device *pdev)
 
        driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
                                   GFP_KERNEL);
-       if (!driver_data) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (!driver_data)
+               return -ENOMEM;
        driver_data->da9052 = da9052;
 
        da9052_wdt = &driver_data->wdt;
@@ -182,33 +178,21 @@ static int da9052_wdt_probe(struct platform_device *pdev)
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to disable watchdog bits, %d\n",
                        ret);
-               goto err;
+               return ret;
        }
 
-       ret = watchdog_register_device(&driver_data->wdt);
+       ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt);
        if (ret != 0) {
                dev_err(da9052->dev, "watchdog_register_device() failed: %d\n",
                        ret);
-               goto err;
+               return ret;
        }
 
-       platform_set_drvdata(pdev, driver_data);
-err:
        return ret;
 }
 
-static int da9052_wdt_remove(struct platform_device *pdev)
-{
-       struct da9052_wdt_data *driver_data = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&driver_data->wdt);
-
-       return 0;
-}
-
 static struct platform_driver da9052_wdt_driver = {
        .probe = da9052_wdt_probe,
-       .remove = da9052_wdt_remove,
        .driver = {
                .name   = "da9052-watchdog",
        },
index 8377c43f3f20ff0c7537642b05ac580badffdd71..50bdd10221864994a771b868acd98c07fc398528 100644 (file)
@@ -108,7 +108,7 @@ static int da9055_wdt_stop(struct watchdog_device *wdt_dev)
        return da9055_wdt_set_timeout(wdt_dev, 0);
 }
 
-static struct watchdog_info da9055_wdt_info = {
+static const struct watchdog_info da9055_wdt_info = {
        .options        = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
        .identity       = "DA9055 Watchdog",
 };
@@ -147,32 +147,19 @@ static int da9055_wdt_probe(struct platform_device *pdev)
        ret = da9055_wdt_stop(da9055_wdt);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret);
-               goto err;
+               return ret;
        }
 
-       platform_set_drvdata(pdev, driver_data);
-
-       ret = watchdog_register_device(&driver_data->wdt);
+       ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt);
        if (ret != 0)
                dev_err(da9055->dev, "watchdog_register_device() failed: %d\n",
                        ret);
 
-err:
        return ret;
 }
 
-static int da9055_wdt_remove(struct platform_device *pdev)
-{
-       struct da9055_wdt_data *driver_data = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&driver_data->wdt);
-
-       return 0;
-}
-
 static struct platform_driver da9055_wdt_driver = {
        .probe = da9055_wdt_probe,
-       .remove = da9055_wdt_remove,
        .driver = {
                .name   = "da9055-watchdog",
        },
index a02cee6820a1593ede5ff6969c48451aa2727e8d..9083d3d922b0b4304a3623b307c3b6a66e99f2ef 100644 (file)
@@ -220,9 +220,8 @@ static int da9062_wdt_probe(struct platform_device *pdev)
        wdt->wdtdev.parent = &pdev->dev;
 
        watchdog_set_drvdata(&wdt->wdtdev, wdt);
-       dev_set_drvdata(&pdev->dev, wdt);
 
-       ret = watchdog_register_device(&wdt->wdtdev);
+       ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev);
        if (ret < 0) {
                dev_err(wdt->hw->dev,
                        "watchdog registration failed (%d)\n", ret);
@@ -231,24 +230,11 @@ static int da9062_wdt_probe(struct platform_device *pdev)
 
        da9062_set_window_start(wdt);
 
-       ret = da9062_wdt_ping(&wdt->wdtdev);
-       if (ret < 0)
-               watchdog_unregister_device(&wdt->wdtdev);
-
-       return ret;
-}
-
-static int da9062_wdt_remove(struct platform_device *pdev)
-{
-       struct da9062_watchdog *wdt = dev_get_drvdata(&pdev->dev);
-
-       watchdog_unregister_device(&wdt->wdtdev);
-       return 0;
+       return da9062_wdt_ping(&wdt->wdtdev);
 }
 
 static struct platform_driver da9062_wdt_driver = {
        .probe = da9062_wdt_probe,
-       .remove = da9062_wdt_remove,
        .driver = {
                .name = "da9062-watchdog",
                .of_match_table = da9062_compatible_id_table,
index 5d6b4e5f7989ccc4d63a88e8b366f9b6d48b63bb..4691c5509129ec51f3df37e63b3af584a833929d 100644 (file)
@@ -151,7 +151,6 @@ static const struct watchdog_ops da9063_watchdog_ops = {
 
 static int da9063_wdt_probe(struct platform_device *pdev)
 {
-       int ret;
        struct da9063 *da9063;
        struct da9063_watchdog *wdt;
 
@@ -181,27 +180,12 @@ static int da9063_wdt_probe(struct platform_device *pdev)
        watchdog_set_restart_priority(&wdt->wdtdev, 128);
 
        watchdog_set_drvdata(&wdt->wdtdev, wdt);
-       dev_set_drvdata(&pdev->dev, wdt);
-
-       ret = watchdog_register_device(&wdt->wdtdev);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
-static int da9063_wdt_remove(struct platform_device *pdev)
-{
-       struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev);
-
-       watchdog_unregister_device(&wdt->wdtdev);
 
-       return 0;
+       return devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev);
 }
 
 static struct platform_driver da9063_wdt_driver = {
        .probe = da9063_wdt_probe,
-       .remove = da9063_wdt_remove,
        .driver = {
                .name = DA9063_DRVNAME_WATCHDOG,
        },
index 861d3d3133f8cac99ed2c07188ffb68947304e08..6f591084bb7af2fb64510171a8ba872c919f53b1 100644 (file)
@@ -205,7 +205,7 @@ static int wdt_set_timeout(struct watchdog_device * dev, unsigned int new_to)
        return wdt_ping(dev);
 }
 
-static struct watchdog_ops wdt_ops = {
+static const struct watchdog_ops wdt_ops = {
        .owner = THIS_MODULE,
        .start = wdt_start,
        .stop = wdt_stop,
index 77df772406b084b93104f13221bdc248d7317bef..5e4ef93caa02b603998a2ab4b5f71cbf5c2ca4df 100644 (file)
@@ -96,7 +96,7 @@ static unsigned int dc_wdt_get_timeleft(struct watchdog_device *wdog)
        return count / clk_get_rate(wdt->clk);
 }
 
-static struct watchdog_ops dc_wdt_ops = {
+static const struct watchdog_ops dc_wdt_ops = {
        .owner          = THIS_MODULE,
        .start          = dc_wdt_start,
        .stop           = dc_wdt_stop,
@@ -105,7 +105,7 @@ static struct watchdog_ops dc_wdt_ops = {
        .restart        = dc_wdt_restart,
 };
 
-static struct watchdog_info dc_wdt_info = {
+static const struct watchdog_info dc_wdt_info = {
        .options        = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE
                        | WDIOF_KEEPALIVEPING,
        .identity       = "Conexant Digicolor Watchdog",
@@ -119,62 +119,40 @@ static struct watchdog_device dc_wdt_wdd = {
 
 static int dc_wdt_probe(struct platform_device *pdev)
 {
+       struct resource *res;
        struct device *dev = &pdev->dev;
-       struct device_node *np = dev->of_node;
        struct dc_wdt *wdt;
        int ret;
 
        wdt = devm_kzalloc(dev, sizeof(struct dc_wdt), GFP_KERNEL);
        if (!wdt)
                return -ENOMEM;
-       platform_set_drvdata(pdev, wdt);
 
-       wdt->base = of_iomap(np, 0);
-       if (!wdt->base) {
-               dev_err(dev, "Failed to remap watchdog regs");
-               return -ENODEV;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdt->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(wdt->base))
+               return PTR_ERR(wdt->base);
 
-       wdt->clk = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(wdt->clk)) {
-               ret = PTR_ERR(wdt->clk);
-               goto err_iounmap;
-       }
+       wdt->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(wdt->clk))
+               return PTR_ERR(wdt->clk);
        dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk);
        dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout;
-       dc_wdt_wdd.parent = &pdev->dev;
+       dc_wdt_wdd.parent = dev;
 
        spin_lock_init(&wdt->lock);
 
        watchdog_set_drvdata(&dc_wdt_wdd, wdt);
        watchdog_set_restart_priority(&dc_wdt_wdd, 128);
        watchdog_init_timeout(&dc_wdt_wdd, timeout, dev);
-       ret = watchdog_register_device(&dc_wdt_wdd);
+       watchdog_stop_on_reboot(&dc_wdt_wdd);
+       ret = devm_watchdog_register_device(dev, &dc_wdt_wdd);
        if (ret) {
                dev_err(dev, "Failed to register watchdog device");
-               goto err_iounmap;
+               return ret;
        }
 
        return 0;
-
-err_iounmap:
-       iounmap(wdt->base);
-       return ret;
-}
-
-static int dc_wdt_remove(struct platform_device *pdev)
-{
-       struct dc_wdt *wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&dc_wdt_wdd);
-       iounmap(wdt->base);
-
-       return 0;
-}
-
-static void dc_wdt_shutdown(struct platform_device *pdev)
-{
-       dc_wdt_stop(&dc_wdt_wdd);
 }
 
 static const struct of_device_id dc_wdt_of_match[] = {
@@ -185,8 +163,6 @@ MODULE_DEVICE_TABLE(of, dc_wdt_of_match);
 
 static struct platform_driver dc_wdt_driver = {
        .probe          = dc_wdt_probe,
-       .remove         = dc_wdt_remove,
-       .shutdown       = dc_wdt_shutdown,
        .driver = {
                .name =         "digicolor-wdt",
                .of_match_table = dc_wdt_of_match,
index 3c6a3de13a1bc1cf06c3cc2a85f9489227952c4f..914da3a4d3341514c4d27560f39cd27624afb9c6 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/notifier.h>
 #include <linux/of.h>
 #include <linux/pm.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/watchdog.h>
 
 #define WDOG_CONTROL_REG_OFFSET                    0x00
@@ -55,7 +53,6 @@ struct dw_wdt {
        void __iomem            *regs;
        struct clk              *clk;
        unsigned long           rate;
-       struct notifier_block   restart_handler;
        struct watchdog_device  wdd;
 };
 
@@ -136,14 +133,12 @@ static int dw_wdt_start(struct watchdog_device *wdd)
        return 0;
 }
 
-static int dw_wdt_restart_handle(struct notifier_block *this,
-                                unsigned long mode, void *cmd)
+static int dw_wdt_restart(struct watchdog_device *wdd,
+                         unsigned long action, void *data)
 {
-       struct dw_wdt *dw_wdt;
+       struct dw_wdt *dw_wdt = to_dw_wdt(wdd);
        u32 val;
 
-       dw_wdt = container_of(this, struct dw_wdt, restart_handler);
-
        writel(0, dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
        val = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET);
        if (val & WDOG_CONTROL_REG_WDT_EN_MASK)
@@ -156,7 +151,7 @@ static int dw_wdt_restart_handle(struct notifier_block *this,
        /* wait for reset to assert... */
        mdelay(500);
 
-       return NOTIFY_DONE;
+       return 0;
 }
 
 static unsigned int dw_wdt_get_timeleft(struct watchdog_device *wdd)
@@ -179,6 +174,7 @@ static const struct watchdog_ops dw_wdt_ops = {
        .ping           = dw_wdt_ping,
        .set_timeout    = dw_wdt_set_timeout,
        .get_timeleft   = dw_wdt_get_timeleft,
+       .restart        = dw_wdt_restart,
 };
 
 #ifdef CONFIG_PM_SLEEP
@@ -265,16 +261,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, dw_wdt);
 
+       watchdog_set_restart_priority(wdd, 128);
+
        ret = watchdog_register_device(wdd);
        if (ret)
                goto out_disable_clk;
 
-       dw_wdt->restart_handler.notifier_call = dw_wdt_restart_handle;
-       dw_wdt->restart_handler.priority = 128;
-       ret = register_restart_handler(&dw_wdt->restart_handler);
-       if (ret)
-               pr_warn("cannot register restart handler\n");
-
        return 0;
 
 out_disable_clk:
@@ -286,7 +278,6 @@ static int dw_wdt_drv_remove(struct platform_device *pdev)
 {
        struct dw_wdt *dw_wdt = platform_get_drvdata(pdev);
 
-       unregister_restart_handler(&dw_wdt->restart_handler);
        watchdog_unregister_device(&dw_wdt->wdd);
        clk_disable_unprepare(dw_wdt->clk);
 
index 4b849b8e37c2621ab6be50b1b4a0b2f6c81f9297..2170b275ea017ab2c0fcf35294111b2cf58da8ca 100644 (file)
@@ -121,18 +121,7 @@ static int ebc_c384_wdt_probe(struct device *dev, unsigned int id)
                dev_warn(dev, "Invalid timeout (%u seconds), using default (%u seconds)\n",
                        timeout, WATCHDOG_TIMEOUT);
 
-       dev_set_drvdata(dev, wdd);
-
-       return watchdog_register_device(wdd);
-}
-
-static int ebc_c384_wdt_remove(struct device *dev, unsigned int id)
-{
-       struct watchdog_device *wdd = dev_get_drvdata(dev);
-
-       watchdog_unregister_device(wdd);
-
-       return 0;
+       return devm_watchdog_register_device(dev, wdd);
 }
 
 static struct isa_driver ebc_c384_wdt_driver = {
@@ -140,7 +129,6 @@ static struct isa_driver ebc_c384_wdt_driver = {
        .driver = {
                .name = MODULE_NAME
        },
-       .remove = ebc_c384_wdt_remove
 };
 
 static int __init ebc_c384_wdt_init(void)
index 0a4d7cc05d5439346ae0b77633089a08ea0464d6..f9b14e6efd9ac226f56ca232812e61276266e090 100644 (file)
  * for us to rely on the user space daemon alone. So we ping the
  * wdt each ~200msec and eventually stop doing it if the user space
  * daemon dies.
- *
- * TODO:
- *
- *     - Test last reset from watchdog status
- *     - Add a few missing ioctls
  */
 
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/watchdog.h>
-#include <linux/timer.h>
 #include <linux/io.h>
 
-#define WDT_VERSION    "0.4"
-
 /* default timeout (secs) */
 #define WDT_TIMEOUT 30
 
@@ -41,117 +33,101 @@ static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
 
-static unsigned int timeout = WDT_TIMEOUT;
+static unsigned int timeout;
 module_param(timeout, uint, 0);
-MODULE_PARM_DESC(timeout,
-       "Watchdog timeout in seconds. (1<=timeout<=3600, default="
-                               __MODULE_STRING(WDT_TIMEOUT) ")");
-
-static void __iomem *mmio_base;
-static struct timer_list timer;
-static unsigned long next_heartbeat;
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds.");
 
 #define EP93XX_WATCHDOG                0x00
 #define EP93XX_WDSTATUS                0x04
 
-/* reset the wdt every ~200ms - the heartbeat of the device is 0.250 seconds*/
-#define WDT_INTERVAL (HZ/5)
-
-static void ep93xx_wdt_timer_ping(unsigned long data)
-{
-       if (time_before(jiffies, next_heartbeat))
-               writel(0x5555, mmio_base + EP93XX_WATCHDOG);
-
-       /* Re-set the timer interval */
-       mod_timer(&timer, jiffies + WDT_INTERVAL);
-}
+struct ep93xx_wdt_priv {
+       void __iomem *mmio;
+       struct watchdog_device wdd;
+};
 
 static int ep93xx_wdt_start(struct watchdog_device *wdd)
 {
-       next_heartbeat = jiffies + (timeout * HZ);
+       struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-       writel(0xaaaa, mmio_base + EP93XX_WATCHDOG);
-       mod_timer(&timer, jiffies + WDT_INTERVAL);
+       writel(0xaaaa, priv->mmio + EP93XX_WATCHDOG);
 
        return 0;
 }
 
 static int ep93xx_wdt_stop(struct watchdog_device *wdd)
 {
-       del_timer_sync(&timer);
-       writel(0xaa55, mmio_base + EP93XX_WATCHDOG);
+       struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+       writel(0xaa55, priv->mmio + EP93XX_WATCHDOG);
 
        return 0;
 }
 
-static int ep93xx_wdt_keepalive(struct watchdog_device *wdd)
+static int ep93xx_wdt_ping(struct watchdog_device *wdd)
 {
-       /* user land ping */
-       next_heartbeat = jiffies + (timeout * HZ);
+       struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+       writel(0x5555, priv->mmio + EP93XX_WATCHDOG);
 
        return 0;
 }
 
 static const struct watchdog_info ep93xx_wdt_ident = {
        .options        = WDIOF_CARDRESET |
+                         WDIOF_SETTIMEOUT |
                          WDIOF_MAGICCLOSE |
                          WDIOF_KEEPALIVEPING,
        .identity       = "EP93xx Watchdog",
 };
 
-static struct watchdog_ops ep93xx_wdt_ops = {
+static const struct watchdog_ops ep93xx_wdt_ops = {
        .owner          = THIS_MODULE,
        .start          = ep93xx_wdt_start,
        .stop           = ep93xx_wdt_stop,
-       .ping           = ep93xx_wdt_keepalive,
-};
-
-static struct watchdog_device ep93xx_wdt_wdd = {
-       .info           = &ep93xx_wdt_ident,
-       .ops            = &ep93xx_wdt_ops,
+       .ping           = ep93xx_wdt_ping,
 };
 
 static int ep93xx_wdt_probe(struct platform_device *pdev)
 {
+       struct ep93xx_wdt_priv *priv;
+       struct watchdog_device *wdd;
        struct resource *res;
        unsigned long val;
-       int err;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       mmio_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(mmio_base))
-               return PTR_ERR(mmio_base);
+       priv->mmio = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->mmio))
+               return PTR_ERR(priv->mmio);
 
-       if (timeout < 1 || timeout > 3600) {
-               timeout = WDT_TIMEOUT;
-               dev_warn(&pdev->dev,
-                       "timeout value must be 1<=x<=3600, using %d\n",
-                       timeout);
-       }
+       val = readl(priv->mmio + EP93XX_WATCHDOG);
 
-       val = readl(mmio_base + EP93XX_WATCHDOG);
-       ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0;
-       ep93xx_wdt_wdd.timeout = timeout;
-       ep93xx_wdt_wdd.parent = &pdev->dev;
+       wdd = &priv->wdd;
+       wdd->bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0;
+       wdd->info = &ep93xx_wdt_ident;
+       wdd->ops = &ep93xx_wdt_ops;
+       wdd->min_timeout = 1;
+       wdd->max_hw_heartbeat_ms = 200;
+       wdd->parent = &pdev->dev;
 
-       watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout);
+       watchdog_set_nowayout(wdd, nowayout);
 
-       setup_timer(&timer, ep93xx_wdt_timer_ping, 1);
+       wdd->timeout = WDT_TIMEOUT;
+       watchdog_init_timeout(wdd, timeout, &pdev->dev);
 
-       err = watchdog_register_device(&ep93xx_wdt_wdd);
-       if (err)
-               return err;
+       watchdog_set_drvdata(wdd, priv);
 
-       dev_info(&pdev->dev,
-               "EP93XX watchdog, driver version " WDT_VERSION "%s\n",
-               (val & 0x08) ? " (nCS1 disable detected)" : "");
+       ret = devm_watchdog_register_device(&pdev->dev, wdd);
+       if (ret)
+               return ret;
 
-       return 0;
-}
+       dev_info(&pdev->dev, "EP93XX watchdog driver %s\n",
+               (val & 0x08) ? " (nCS1 disable detected)" : "");
 
-static int ep93xx_wdt_remove(struct platform_device *pdev)
-{
-       watchdog_unregister_device(&ep93xx_wdt_wdd);
        return 0;
 }
 
@@ -160,7 +136,6 @@ static struct platform_driver ep93xx_wdt_driver = {
                .name   = "ep93xx-wdt",
        },
        .probe          = ep93xx_wdt_probe,
-       .remove         = ep93xx_wdt_remove,
 };
 
 module_platform_driver(ep93xx_wdt_driver);
@@ -170,4 +145,3 @@ MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
 MODULE_DESCRIPTION("EP93xx Watchdog");
 MODULE_LICENSE("GPL");
-MODULE_VERSION(WDT_VERSION);
diff --git a/drivers/watchdog/gemini_wdt.c b/drivers/watchdog/gemini_wdt.c
new file mode 100644 (file)
index 0000000..8155aa6
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Watchdog driver for Cortina Systems Gemini SoC
+ *
+ * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
+ *
+ * Inspired by the out-of-tree drivers from OpenWRT:
+ * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/watchdog.h>
+
+#define GEMINI_WDCOUNTER       0x0
+#define GEMINI_WDLOAD          0x4
+#define GEMINI_WDRESTART       0x8
+#define GEMINI_WDCR            0xC
+
+#define WDRESTART_MAGIC                0x5AB9
+
+#define WDCR_CLOCK_5MHZ                BIT(4)
+#define WDCR_SYS_RST           BIT(1)
+#define WDCR_ENABLE            BIT(0)
+
+#define WDT_CLOCK              5000000         /* 5 MHz */
+
+struct gemini_wdt {
+       struct watchdog_device  wdd;
+       struct device           *dev;
+       void __iomem            *base;
+};
+
+static inline
+struct gemini_wdt *to_gemini_wdt(struct watchdog_device *wdd)
+{
+       return container_of(wdd, struct gemini_wdt, wdd);
+}
+
+static int gemini_wdt_start(struct watchdog_device *wdd)
+{
+       struct gemini_wdt *gwdt = to_gemini_wdt(wdd);
+
+       writel(wdd->timeout * WDT_CLOCK, gwdt->base + GEMINI_WDLOAD);
+       writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART);
+       /* set clock before enabling */
+       writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST,
+                       gwdt->base + GEMINI_WDCR);
+       writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE,
+                       gwdt->base + GEMINI_WDCR);
+
+       return 0;
+}
+
+static int gemini_wdt_stop(struct watchdog_device *wdd)
+{
+       struct gemini_wdt *gwdt = to_gemini_wdt(wdd);
+
+       writel(0, gwdt->base + GEMINI_WDCR);
+
+       return 0;
+}
+
+static int gemini_wdt_ping(struct watchdog_device *wdd)
+{
+       struct gemini_wdt *gwdt = to_gemini_wdt(wdd);
+
+       writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART);
+
+       return 0;
+}
+
+static int gemini_wdt_set_timeout(struct watchdog_device *wdd,
+                                 unsigned int timeout)
+{
+       wdd->timeout = timeout;
+       if (watchdog_active(wdd))
+               gemini_wdt_start(wdd);
+
+       return 0;
+}
+
+static irqreturn_t gemini_wdt_interrupt(int irq, void *data)
+{
+       struct gemini_wdt *gwdt = data;
+
+       watchdog_notify_pretimeout(&gwdt->wdd);
+
+       return IRQ_HANDLED;
+}
+
+static const struct watchdog_ops gemini_wdt_ops = {
+       .start          = gemini_wdt_start,
+       .stop           = gemini_wdt_stop,
+       .ping           = gemini_wdt_ping,
+       .set_timeout    = gemini_wdt_set_timeout,
+       .owner          = THIS_MODULE,
+};
+
+static const struct watchdog_info gemini_wdt_info = {
+       .options        = WDIOF_KEEPALIVEPING
+                       | WDIOF_MAGICCLOSE
+                       | WDIOF_SETTIMEOUT,
+       .identity       = KBUILD_MODNAME,
+};
+
+
+static int gemini_wdt_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       struct gemini_wdt *gwdt;
+       unsigned int reg;
+       int irq;
+       int ret;
+
+       gwdt = devm_kzalloc(dev, sizeof(*gwdt), GFP_KERNEL);
+       if (!gwdt)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       gwdt->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(gwdt->base))
+               return PTR_ERR(gwdt->base);
+
+       irq = platform_get_irq(pdev, 0);
+       if (!irq)
+               return -EINVAL;
+
+       gwdt->dev = dev;
+       gwdt->wdd.info = &gemini_wdt_info;
+       gwdt->wdd.ops = &gemini_wdt_ops;
+       gwdt->wdd.min_timeout = 1;
+       gwdt->wdd.max_timeout = 0xFFFFFFFF / WDT_CLOCK;
+       gwdt->wdd.parent = dev;
+
+       /*
+        * If 'timeout-sec' unspecified in devicetree, assume a 13 second
+        * default.
+        */
+       gwdt->wdd.timeout = 13U;
+       watchdog_init_timeout(&gwdt->wdd, 0, dev);
+
+       reg = readw(gwdt->base + GEMINI_WDCR);
+       if (reg & WDCR_ENABLE) {
+               /* Watchdog was enabled by the bootloader, disable it. */
+               reg &= ~WDCR_ENABLE;
+               writel(reg, gwdt->base + GEMINI_WDCR);
+       }
+
+       ret = devm_request_irq(dev, irq, gemini_wdt_interrupt, 0,
+                              "watchdog bark", gwdt);
+       if (ret)
+               return ret;
+
+       ret = devm_watchdog_register_device(dev, &gwdt->wdd);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to register watchdog\n");
+               return ret;
+       }
+
+       /* Set up platform driver data */
+       platform_set_drvdata(pdev, gwdt);
+       dev_info(dev, "Gemini watchdog driver enabled\n");
+
+       return 0;
+}
+
+static int __maybe_unused gemini_wdt_suspend(struct device *dev)
+{
+       struct gemini_wdt *gwdt = dev_get_drvdata(dev);
+       unsigned int reg;
+
+       reg = readw(gwdt->base + GEMINI_WDCR);
+       reg &= ~WDCR_ENABLE;
+       writel(reg, gwdt->base + GEMINI_WDCR);
+
+       return 0;
+}
+
+static int __maybe_unused gemini_wdt_resume(struct device *dev)
+{
+       struct gemini_wdt *gwdt = dev_get_drvdata(dev);
+       unsigned int reg;
+
+       if (watchdog_active(&gwdt->wdd)) {
+               reg = readw(gwdt->base + GEMINI_WDCR);
+               reg |= WDCR_ENABLE;
+               writel(reg, gwdt->base + GEMINI_WDCR);
+       }
+
+       return 0;
+}
+
+static const struct dev_pm_ops gemini_wdt_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(gemini_wdt_suspend,
+                               gemini_wdt_resume)
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id gemini_wdt_match[] = {
+       { .compatible = "cortina,gemini-watchdog" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, gemini_wdt_match);
+#endif
+
+static struct platform_driver gemini_wdt_driver = {
+       .probe          = gemini_wdt_probe,
+       .driver         = {
+               .name   = "gemini-wdt",
+               .of_match_table = of_match_ptr(gemini_wdt_match),
+               .pm = &gemini_wdt_dev_pm_ops,
+       },
+};
+module_platform_driver(gemini_wdt_driver);
+MODULE_AUTHOR("Linus Walleij");
+MODULE_DESCRIPTION("Watchdog driver for Gemini");
+MODULE_LICENSE("GPL");
index 06fcb6c8c9172379dd320aaaed10f368cdced739..3d0abc0d59b4f176d62ce30ebc236471cde051d2 100644 (file)
 
 /* Address definitions for the TCO */
 /* TCO base address */
-#define TCOBASE                (iTCO_wdt_private.tco_res->start)
+#define TCOBASE(p)     ((p)->tco_res->start)
 /* SMI Control and Enable Register */
-#define SMI_EN         (iTCO_wdt_private.smi_res->start)
-
-#define TCO_RLD                (TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */
-#define TCOv1_TMR      (TCOBASE + 0x01) /* TCOv1 Timer Initial Value   */
-#define TCO_DAT_IN     (TCOBASE + 0x02) /* TCO Data In Register        */
-#define TCO_DAT_OUT    (TCOBASE + 0x03) /* TCO Data Out Register       */
-#define TCO1_STS       (TCOBASE + 0x04) /* TCO1 Status Register        */
-#define TCO2_STS       (TCOBASE + 0x06) /* TCO2 Status Register        */
-#define TCO1_CNT       (TCOBASE + 0x08) /* TCO1 Control Register       */
-#define TCO2_CNT       (TCOBASE + 0x0a) /* TCO2 Control Register       */
-#define TCOv2_TMR      (TCOBASE + 0x12) /* TCOv2 Timer Initial Value   */
+#define SMI_EN(p)      ((p)->smi_res->start)
+
+#define TCO_RLD(p)     (TCOBASE(p) + 0x00) /* TCO Timer Reload/Curr. Value */
+#define TCOv1_TMR(p)   (TCOBASE(p) + 0x01) /* TCOv1 Timer Initial Value*/
+#define TCO_DAT_IN(p)  (TCOBASE(p) + 0x02) /* TCO Data In Register     */
+#define TCO_DAT_OUT(p) (TCOBASE(p) + 0x03) /* TCO Data Out Register    */
+#define TCO1_STS(p)    (TCOBASE(p) + 0x04) /* TCO1 Status Register     */
+#define TCO2_STS(p)    (TCOBASE(p) + 0x06) /* TCO2 Status Register     */
+#define TCO1_CNT(p)    (TCOBASE(p) + 0x08) /* TCO1 Control Register    */
+#define TCO2_CNT(p)    (TCOBASE(p) + 0x0a) /* TCO2 Control Register    */
+#define TCOv2_TMR(p)   (TCOBASE(p) + 0x12) /* TCOv2 Timer Initial Value*/
 
 /* internal variables */
-static struct {                /* this is private data for the iTCO_wdt device */
+struct iTCO_wdt_private {
+       struct watchdog_device wddev;
+
        /* TCO version/generation */
        unsigned int iTCO_version;
        struct resource *tco_res;
@@ -100,12 +102,11 @@ static struct {           /* this is private data for the iTCO_wdt device */
        unsigned long __iomem *gcs_pmc;
        /* the lock for io operations */
        spinlock_t io_lock;
-       struct platform_device *dev;
        /* the PCI-device */
-       struct pci_dev *pdev;
+       struct pci_dev *pci_dev;
        /* whether or not the watchdog has been suspended */
        bool suspended;
-} iTCO_wdt_private;
+};
 
 /* module parameters */
 #define WATCHDOG_TIMEOUT 30    /* 30 sec default heartbeat */
@@ -135,21 +136,23 @@ MODULE_PARM_DESC(turn_SMI_watchdog_clear_off,
  * every 0.6 seconds.  v3's internal timer is stored as seconds (some
  * datasheets incorrectly state 0.6 seconds).
  */
-static inline unsigned int seconds_to_ticks(int secs)
+static inline unsigned int seconds_to_ticks(struct iTCO_wdt_private *p,
+                                           int secs)
 {
-       return iTCO_wdt_private.iTCO_version == 3 ? secs : (secs * 10) / 6;
+       return p->iTCO_version == 3 ? secs : (secs * 10) / 6;
 }
 
-static inline unsigned int ticks_to_seconds(int ticks)
+static inline unsigned int ticks_to_seconds(struct iTCO_wdt_private *p,
+                                           int ticks)
 {
-       return iTCO_wdt_private.iTCO_version == 3 ? ticks : (ticks * 6) / 10;
+       return p->iTCO_version == 3 ? ticks : (ticks * 6) / 10;
 }
 
-static inline u32 no_reboot_bit(void)
+static inline u32 no_reboot_bit(struct iTCO_wdt_private *p)
 {
        u32 enable_bit;
 
-       switch (iTCO_wdt_private.iTCO_version) {
+       switch (p->iTCO_version) {
        case 5:
        case 3:
                enable_bit = 0x00000010;
@@ -167,40 +170,40 @@ static inline u32 no_reboot_bit(void)
        return enable_bit;
 }
 
-static void iTCO_wdt_set_NO_REBOOT_bit(void)
+static void iTCO_wdt_set_NO_REBOOT_bit(struct iTCO_wdt_private *p)
 {
        u32 val32;
 
        /* Set the NO_REBOOT bit: this disables reboots */
-       if (iTCO_wdt_private.iTCO_version >= 2) {
-               val32 = readl(iTCO_wdt_private.gcs_pmc);
-               val32 |= no_reboot_bit();
-               writel(val32, iTCO_wdt_private.gcs_pmc);
-       } else if (iTCO_wdt_private.iTCO_version == 1) {
-               pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
-               val32 |= no_reboot_bit();
-               pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
+       if (p->iTCO_version >= 2) {
+               val32 = readl(p->gcs_pmc);
+               val32 |= no_reboot_bit(p);
+               writel(val32, p->gcs_pmc);
+       } else if (p->iTCO_version == 1) {
+               pci_read_config_dword(p->pci_dev, 0xd4, &val32);
+               val32 |= no_reboot_bit(p);
+               pci_write_config_dword(p->pci_dev, 0xd4, val32);
        }
 }
 
-static int iTCO_wdt_unset_NO_REBOOT_bit(void)
+static int iTCO_wdt_unset_NO_REBOOT_bit(struct iTCO_wdt_private *p)
 {
-       u32 enable_bit = no_reboot_bit();
+       u32 enable_bit = no_reboot_bit(p);
        u32 val32 = 0;
 
        /* Unset the NO_REBOOT bit: this enables reboots */
-       if (iTCO_wdt_private.iTCO_version >= 2) {
-               val32 = readl(iTCO_wdt_private.gcs_pmc);
+       if (p->iTCO_version >= 2) {
+               val32 = readl(p->gcs_pmc);
                val32 &= ~enable_bit;
-               writel(val32, iTCO_wdt_private.gcs_pmc);
+               writel(val32, p->gcs_pmc);
 
-               val32 = readl(iTCO_wdt_private.gcs_pmc);
-       } else if (iTCO_wdt_private.iTCO_version == 1) {
-               pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+               val32 = readl(p->gcs_pmc);
+       } else if (p->iTCO_version == 1) {
+               pci_read_config_dword(p->pci_dev, 0xd4, &val32);
                val32 &= ~enable_bit;
-               pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
+               pci_write_config_dword(p->pci_dev, 0xd4, val32);
 
-               pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+               pci_read_config_dword(p->pci_dev, 0xd4, &val32);
        }
 
        if (val32 & enable_bit)
@@ -211,32 +214,33 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void)
 
 static int iTCO_wdt_start(struct watchdog_device *wd_dev)
 {
+       struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
        unsigned int val;
 
-       spin_lock(&iTCO_wdt_private.io_lock);
+       spin_lock(&p->io_lock);
 
-       iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, wd_dev->timeout);
+       iTCO_vendor_pre_start(p->smi_res, wd_dev->timeout);
 
        /* disable chipset's NO_REBOOT bit */
-       if (iTCO_wdt_unset_NO_REBOOT_bit()) {
-               spin_unlock(&iTCO_wdt_private.io_lock);
+       if (iTCO_wdt_unset_NO_REBOOT_bit(p)) {
+               spin_unlock(&p->io_lock);
                pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n");
                return -EIO;
        }
 
        /* Force the timer to its reload value by writing to the TCO_RLD
           register */
-       if (iTCO_wdt_private.iTCO_version >= 2)
-               outw(0x01, TCO_RLD);
-       else if (iTCO_wdt_private.iTCO_version == 1)
-               outb(0x01, TCO_RLD);
+       if (p->iTCO_version >= 2)
+               outw(0x01, TCO_RLD(p));
+       else if (p->iTCO_version == 1)
+               outb(0x01, TCO_RLD(p));
 
        /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
-       val = inw(TCO1_CNT);
+       val = inw(TCO1_CNT(p));
        val &= 0xf7ff;
-       outw(val, TCO1_CNT);
-       val = inw(TCO1_CNT);
-       spin_unlock(&iTCO_wdt_private.io_lock);
+       outw(val, TCO1_CNT(p));
+       val = inw(TCO1_CNT(p));
+       spin_unlock(&p->io_lock);
 
        if (val & 0x0800)
                return -1;
@@ -245,22 +249,23 @@ static int iTCO_wdt_start(struct watchdog_device *wd_dev)
 
 static int iTCO_wdt_stop(struct watchdog_device *wd_dev)
 {
+       struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
        unsigned int val;
 
-       spin_lock(&iTCO_wdt_private.io_lock);
+       spin_lock(&p->io_lock);
 
-       iTCO_vendor_pre_stop(iTCO_wdt_private.smi_res);
+       iTCO_vendor_pre_stop(p->smi_res);
 
        /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
-       val = inw(TCO1_CNT);
+       val = inw(TCO1_CNT(p));
        val |= 0x0800;
-       outw(val, TCO1_CNT);
-       val = inw(TCO1_CNT);
+       outw(val, TCO1_CNT(p));
+       val = inw(TCO1_CNT(p));
 
        /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
-       iTCO_wdt_set_NO_REBOOT_bit();
+       iTCO_wdt_set_NO_REBOOT_bit(p);
 
-       spin_unlock(&iTCO_wdt_private.io_lock);
+       spin_unlock(&p->io_lock);
 
        if ((val & 0x0800) == 0)
                return -1;
@@ -269,67 +274,70 @@ static int iTCO_wdt_stop(struct watchdog_device *wd_dev)
 
 static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
 {
-       spin_lock(&iTCO_wdt_private.io_lock);
+       struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
 
-       iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, wd_dev->timeout);
+       spin_lock(&p->io_lock);
+
+       iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout);
 
        /* Reload the timer by writing to the TCO Timer Counter register */
-       if (iTCO_wdt_private.iTCO_version >= 2) {
-               outw(0x01, TCO_RLD);
-       } else if (iTCO_wdt_private.iTCO_version == 1) {
+       if (p->iTCO_version >= 2) {
+               outw(0x01, TCO_RLD(p));
+       } else if (p->iTCO_version == 1) {
                /* Reset the timeout status bit so that the timer
                 * needs to count down twice again before rebooting */
-               outw(0x0008, TCO1_STS); /* write 1 to clear bit */
+               outw(0x0008, TCO1_STS(p));      /* write 1 to clear bit */
 
-               outb(0x01, TCO_RLD);
+               outb(0x01, TCO_RLD(p));
        }
 
-       spin_unlock(&iTCO_wdt_private.io_lock);
+       spin_unlock(&p->io_lock);
        return 0;
 }
 
 static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
 {
+       struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
        unsigned int val16;
        unsigned char val8;
        unsigned int tmrval;
 
-       tmrval = seconds_to_ticks(t);
+       tmrval = seconds_to_ticks(p, t);
 
        /* For TCO v1 the timer counts down twice before rebooting */
-       if (iTCO_wdt_private.iTCO_version == 1)
+       if (p->iTCO_version == 1)
                tmrval /= 2;
 
        /* from the specs: */
        /* "Values of 0h-3h are ignored and should not be attempted" */
        if (tmrval < 0x04)
                return -EINVAL;
-       if (((iTCO_wdt_private.iTCO_version >= 2) && (tmrval > 0x3ff)) ||
-           ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
+       if ((p->iTCO_version >= 2 && tmrval > 0x3ff) ||
+           (p->iTCO_version == 1 && tmrval > 0x03f))
                return -EINVAL;
 
        iTCO_vendor_pre_set_heartbeat(tmrval);
 
        /* Write new heartbeat to watchdog */
-       if (iTCO_wdt_private.iTCO_version >= 2) {
-               spin_lock(&iTCO_wdt_private.io_lock);
-               val16 = inw(TCOv2_TMR);
+       if (p->iTCO_version >= 2) {
+               spin_lock(&p->io_lock);
+               val16 = inw(TCOv2_TMR(p));
                val16 &= 0xfc00;
                val16 |= tmrval;
-               outw(val16, TCOv2_TMR);
-               val16 = inw(TCOv2_TMR);
-               spin_unlock(&iTCO_wdt_private.io_lock);
+               outw(val16, TCOv2_TMR(p));
+               val16 = inw(TCOv2_TMR(p));
+               spin_unlock(&p->io_lock);
 
                if ((val16 & 0x3ff) != tmrval)
                        return -EINVAL;
-       } else if (iTCO_wdt_private.iTCO_version == 1) {
-               spin_lock(&iTCO_wdt_private.io_lock);
-               val8 = inb(TCOv1_TMR);
+       } else if (p->iTCO_version == 1) {
+               spin_lock(&p->io_lock);
+               val8 = inb(TCOv1_TMR(p));
                val8 &= 0xc0;
                val8 |= (tmrval & 0xff);
-               outb(val8, TCOv1_TMR);
-               val8 = inb(TCOv1_TMR);
-               spin_unlock(&iTCO_wdt_private.io_lock);
+               outb(val8, TCOv1_TMR(p));
+               val8 = inb(TCOv1_TMR(p));
+               spin_unlock(&p->io_lock);
 
                if ((val8 & 0x3f) != tmrval)
                        return -EINVAL;
@@ -341,27 +349,28 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
 
 static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
 {
+       struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev);
        unsigned int val16;
        unsigned char val8;
        unsigned int time_left = 0;
 
        /* read the TCO Timer */
-       if (iTCO_wdt_private.iTCO_version >= 2) {
-               spin_lock(&iTCO_wdt_private.io_lock);
-               val16 = inw(TCO_RLD);
+       if (p->iTCO_version >= 2) {
+               spin_lock(&p->io_lock);
+               val16 = inw(TCO_RLD(p));
                val16 &= 0x3ff;
-               spin_unlock(&iTCO_wdt_private.io_lock);
+               spin_unlock(&p->io_lock);
 
-               time_left = ticks_to_seconds(val16);
-       } else if (iTCO_wdt_private.iTCO_version == 1) {
-               spin_lock(&iTCO_wdt_private.io_lock);
-               val8 = inb(TCO_RLD);
+               time_left = ticks_to_seconds(p, val16);
+       } else if (p->iTCO_version == 1) {
+               spin_lock(&p->io_lock);
+               val8 = inb(TCO_RLD(p));
                val8 &= 0x3f;
-               if (!(inw(TCO1_STS) & 0x0008))
-                       val8 += (inb(TCOv1_TMR) & 0x3f);
-               spin_unlock(&iTCO_wdt_private.io_lock);
+               if (!(inw(TCO1_STS(p)) & 0x0008))
+                       val8 += (inb(TCOv1_TMR(p)) & 0x3f);
+               spin_unlock(&p->io_lock);
 
-               time_left = ticks_to_seconds(val8);
+               time_left = ticks_to_seconds(p, val8);
        }
        return time_left;
 }
@@ -387,209 +396,152 @@ static const struct watchdog_ops iTCO_wdt_ops = {
        .get_timeleft =         iTCO_wdt_get_timeleft,
 };
 
-static struct watchdog_device iTCO_wdt_watchdog_dev = {
-       .info =         &ident,
-       .ops =          &iTCO_wdt_ops,
-};
-
 /*
  *     Init & exit routines
  */
 
-static void iTCO_wdt_cleanup(void)
-{
-       /* Stop the timer before we leave */
-       if (!nowayout)
-               iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
-
-       /* Deregister */
-       watchdog_unregister_device(&iTCO_wdt_watchdog_dev);
-
-       /* release resources */
-       release_region(iTCO_wdt_private.tco_res->start,
-                       resource_size(iTCO_wdt_private.tco_res));
-       release_region(iTCO_wdt_private.smi_res->start,
-                       resource_size(iTCO_wdt_private.smi_res));
-       if (iTCO_wdt_private.iTCO_version >= 2) {
-               iounmap(iTCO_wdt_private.gcs_pmc);
-               release_mem_region(iTCO_wdt_private.gcs_pmc_res->start,
-                               resource_size(iTCO_wdt_private.gcs_pmc_res));
-       }
-
-       iTCO_wdt_private.tco_res = NULL;
-       iTCO_wdt_private.smi_res = NULL;
-       iTCO_wdt_private.gcs_pmc_res = NULL;
-       iTCO_wdt_private.gcs_pmc = NULL;
-}
-
-static int iTCO_wdt_probe(struct platform_device *dev)
+static int iTCO_wdt_probe(struct platform_device *pdev)
 {
-       int ret = -ENODEV;
+       struct device *dev = &pdev->dev;
+       struct itco_wdt_platform_data *pdata = dev_get_platdata(dev);
+       struct iTCO_wdt_private *p;
        unsigned long val32;
-       struct itco_wdt_platform_data *pdata = dev_get_platdata(&dev->dev);
+       int ret;
 
        if (!pdata)
-               goto out;
+               return -ENODEV;
+
+       p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
 
-       spin_lock_init(&iTCO_wdt_private.io_lock);
+       spin_lock_init(&p->io_lock);
 
-       iTCO_wdt_private.tco_res =
-               platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_TCO);
-       if (!iTCO_wdt_private.tco_res)
-               goto out;
+       p->tco_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_TCO);
+       if (!p->tco_res)
+               return -ENODEV;
 
-       iTCO_wdt_private.smi_res =
-               platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_SMI);
-       if (!iTCO_wdt_private.smi_res)
-               goto out;
+       p->smi_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_SMI);
+       if (!p->smi_res)
+               return -ENODEV;
 
-       iTCO_wdt_private.iTCO_version = pdata->version;
-       iTCO_wdt_private.dev = dev;
-       iTCO_wdt_private.pdev = to_pci_dev(dev->dev.parent);
+       p->iTCO_version = pdata->version;
+       p->pci_dev = to_pci_dev(dev->parent);
 
        /*
         * Get the Memory-Mapped GCS or PMC register, we need it for the
         * NO_REBOOT flag (TCO v2 and v3).
         */
-       if (iTCO_wdt_private.iTCO_version >= 2) {
-               iTCO_wdt_private.gcs_pmc_res = platform_get_resource(dev,
-                                                       IORESOURCE_MEM,
-                                                       ICH_RES_MEM_GCS_PMC);
-
-               if (!iTCO_wdt_private.gcs_pmc_res)
-                       goto out;
-
-               if (!request_mem_region(iTCO_wdt_private.gcs_pmc_res->start,
-                       resource_size(iTCO_wdt_private.gcs_pmc_res), dev->name)) {
-                       ret = -EBUSY;
-                       goto out;
-               }
-               iTCO_wdt_private.gcs_pmc = ioremap(iTCO_wdt_private.gcs_pmc_res->start,
-                       resource_size(iTCO_wdt_private.gcs_pmc_res));
-               if (!iTCO_wdt_private.gcs_pmc) {
-                       ret = -EIO;
-                       goto unreg_gcs_pmc;
-               }
+       if (p->iTCO_version >= 2) {
+               p->gcs_pmc_res = platform_get_resource(pdev,
+                                                      IORESOURCE_MEM,
+                                                      ICH_RES_MEM_GCS_PMC);
+               p->gcs_pmc = devm_ioremap_resource(dev, p->gcs_pmc_res);
+               if (IS_ERR(p->gcs_pmc))
+                       return PTR_ERR(p->gcs_pmc);
        }
 
        /* Check chipset's NO_REBOOT bit */
-       if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
+       if (iTCO_wdt_unset_NO_REBOOT_bit(p) &&
+           iTCO_vendor_check_noreboot_on()) {
                pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n");
-               ret = -ENODEV;  /* Cannot reset NO_REBOOT bit */
-               goto unmap_gcs_pmc;
+               return -ENODEV; /* Cannot reset NO_REBOOT bit */
        }
 
        /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
-       iTCO_wdt_set_NO_REBOOT_bit();
+       iTCO_wdt_set_NO_REBOOT_bit(p);
 
        /* The TCO logic uses the TCO_EN bit in the SMI_EN register */
-       if (!request_region(iTCO_wdt_private.smi_res->start,
-                       resource_size(iTCO_wdt_private.smi_res), dev->name)) {
+       if (!devm_request_region(dev, p->smi_res->start,
+                                resource_size(p->smi_res),
+                                pdev->name)) {
                pr_err("I/O address 0x%04llx already in use, device disabled\n",
-                      (u64)SMI_EN);
-               ret = -EBUSY;
-               goto unmap_gcs_pmc;
+                      (u64)SMI_EN(p));
+               return -EBUSY;
        }
-       if (turn_SMI_watchdog_clear_off >= iTCO_wdt_private.iTCO_version) {
+       if (turn_SMI_watchdog_clear_off >= p->iTCO_version) {
                /*
                 * Bit 13: TCO_EN -> 0
                 * Disables TCO logic generating an SMI#
                 */
-               val32 = inl(SMI_EN);
+               val32 = inl(SMI_EN(p));
                val32 &= 0xffffdfff;    /* Turn off SMI clearing watchdog */
-               outl(val32, SMI_EN);
+               outl(val32, SMI_EN(p));
        }
 
-       if (!request_region(iTCO_wdt_private.tco_res->start,
-                       resource_size(iTCO_wdt_private.tco_res), dev->name)) {
+       if (!devm_request_region(dev, p->tco_res->start,
+                                resource_size(p->tco_res),
+                                pdev->name)) {
                pr_err("I/O address 0x%04llx already in use, device disabled\n",
-                      (u64)TCOBASE);
-               ret = -EBUSY;
-               goto unreg_smi;
+                      (u64)TCOBASE(p));
+               return -EBUSY;
        }
 
        pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n",
-               pdata->name, pdata->version, (u64)TCOBASE);
+               pdata->name, pdata->version, (u64)TCOBASE(p));
 
        /* Clear out the (probably old) status */
-       switch (iTCO_wdt_private.iTCO_version) {
+       switch (p->iTCO_version) {
        case 5:
        case 4:
-               outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
-               outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
+               outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */
+               outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */
                break;
        case 3:
-               outl(0x20008, TCO1_STS);
+               outl(0x20008, TCO1_STS(p));
                break;
        case 2:
        case 1:
        default:
-               outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
-               outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
-               outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */
+               outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */
+               outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */
+               outw(0x0004, TCO2_STS(p)); /* Clear BOOT_STS bit */
                break;
        }
 
-       iTCO_wdt_watchdog_dev.bootstatus = 0;
-       iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT;
-       watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout);
-       iTCO_wdt_watchdog_dev.parent = &dev->dev;
+       p->wddev.info = &ident,
+       p->wddev.ops = &iTCO_wdt_ops,
+       p->wddev.bootstatus = 0;
+       p->wddev.timeout = WATCHDOG_TIMEOUT;
+       watchdog_set_nowayout(&p->wddev, nowayout);
+       p->wddev.parent = dev;
+
+       watchdog_set_drvdata(&p->wddev, p);
+       platform_set_drvdata(pdev, p);
 
        /* Make sure the watchdog is not running */
-       iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
+       iTCO_wdt_stop(&p->wddev);
 
        /* Check that the heartbeat value is within it's range;
           if not reset to the default */
-       if (iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, heartbeat)) {
-               iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, WATCHDOG_TIMEOUT);
+       if (iTCO_wdt_set_timeout(&p->wddev, heartbeat)) {
+               iTCO_wdt_set_timeout(&p->wddev, WATCHDOG_TIMEOUT);
                pr_info("timeout value out of range, using %d\n",
                        WATCHDOG_TIMEOUT);
        }
 
-       ret = watchdog_register_device(&iTCO_wdt_watchdog_dev);
+       watchdog_stop_on_reboot(&p->wddev);
+       ret = devm_watchdog_register_device(dev, &p->wddev);
        if (ret != 0) {
                pr_err("cannot register watchdog device (err=%d)\n", ret);
-               goto unreg_tco;
+               return ret;
        }
 
        pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
                heartbeat, nowayout);
 
        return 0;
-
-unreg_tco:
-       release_region(iTCO_wdt_private.tco_res->start,
-                       resource_size(iTCO_wdt_private.tco_res));
-unreg_smi:
-       release_region(iTCO_wdt_private.smi_res->start,
-                       resource_size(iTCO_wdt_private.smi_res));
-unmap_gcs_pmc:
-       if (iTCO_wdt_private.iTCO_version >= 2)
-               iounmap(iTCO_wdt_private.gcs_pmc);
-unreg_gcs_pmc:
-       if (iTCO_wdt_private.iTCO_version >= 2)
-               release_mem_region(iTCO_wdt_private.gcs_pmc_res->start,
-                               resource_size(iTCO_wdt_private.gcs_pmc_res));
-out:
-       iTCO_wdt_private.tco_res = NULL;
-       iTCO_wdt_private.smi_res = NULL;
-       iTCO_wdt_private.gcs_pmc_res = NULL;
-       iTCO_wdt_private.gcs_pmc = NULL;
-
-       return ret;
 }
 
-static int iTCO_wdt_remove(struct platform_device *dev)
+static int iTCO_wdt_remove(struct platform_device *pdev)
 {
-       if (iTCO_wdt_private.tco_res || iTCO_wdt_private.smi_res)
-               iTCO_wdt_cleanup();
+       struct iTCO_wdt_private *p = platform_get_drvdata(pdev);
 
-       return 0;
-}
+       /* Stop the timer before we leave */
+       if (!nowayout)
+               iTCO_wdt_stop(&p->wddev);
 
-static void iTCO_wdt_shutdown(struct platform_device *dev)
-{
-       iTCO_wdt_stop(NULL);
+       return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
@@ -610,21 +562,24 @@ static inline bool need_suspend(void) { return true; }
 
 static int iTCO_wdt_suspend_noirq(struct device *dev)
 {
+       struct iTCO_wdt_private *p = dev_get_drvdata(dev);
        int ret = 0;
 
-       iTCO_wdt_private.suspended = false;
-       if (watchdog_active(&iTCO_wdt_watchdog_dev) && need_suspend()) {
-               ret = iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
+       p->suspended = false;
+       if (watchdog_active(&p->wddev) && need_suspend()) {
+               ret = iTCO_wdt_stop(&p->wddev);
                if (!ret)
-                       iTCO_wdt_private.suspended = true;
+                       p->suspended = true;
        }
        return ret;
 }
 
 static int iTCO_wdt_resume_noirq(struct device *dev)
 {
-       if (iTCO_wdt_private.suspended)
-               iTCO_wdt_start(&iTCO_wdt_watchdog_dev);
+       struct iTCO_wdt_private *p = dev_get_drvdata(dev);
+
+       if (p->suspended)
+               iTCO_wdt_start(&p->wddev);
 
        return 0;
 }
@@ -642,7 +597,6 @@ static const struct dev_pm_ops iTCO_wdt_pm = {
 static struct platform_driver iTCO_wdt_driver = {
        .probe          = iTCO_wdt_probe,
        .remove         = iTCO_wdt_remove,
-       .shutdown       = iTCO_wdt_shutdown,
        .driver         = {
                .name   = DRV_NAME,
                .pm     = ITCO_WDT_PM_OPS,
@@ -651,15 +605,9 @@ static struct platform_driver iTCO_wdt_driver = {
 
 static int __init iTCO_wdt_init_module(void)
 {
-       int err;
-
        pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION);
 
-       err = platform_driver_register(&iTCO_wdt_driver);
-       if (err)
-               return err;
-
-       return 0;
+       return platform_driver_register(&iTCO_wdt_driver);
 }
 
 static void __exit iTCO_wdt_cleanup_module(void)
index 516fbef00856edeceb59fba31968c1c2328bd24e..6ed39dee995f4f713845ce4bd60ac44d6e9d64fd 100644 (file)
@@ -161,7 +161,7 @@ static int pdc_wdt_restart(struct watchdog_device *wdt_dev,
        return 0;
 }
 
-static struct watchdog_info pdc_wdt_info = {
+static const struct watchdog_info pdc_wdt_info = {
        .identity       = "IMG PDC Watchdog",
        .options        = WDIOF_SETTIMEOUT |
                          WDIOF_KEEPALIVEPING |
index a4b729259b122fe4c18a9f4fcd6080446e635c34..45e4d02221b5849e1a3f61fa83d85b16bb8382d6 100644 (file)
@@ -137,7 +137,6 @@ static int mid_wdt_probe(struct platform_device *pdev)
        wdt_dev->parent = &pdev->dev;
 
        watchdog_set_drvdata(wdt_dev, &pdev->dev);
-       platform_set_drvdata(pdev, wdt_dev);
 
        ret = devm_request_irq(&pdev->dev, pdata->irq, mid_wdt_irq,
                               IRQF_SHARED | IRQF_NO_SUSPEND, "watchdog",
@@ -151,7 +150,7 @@ static int mid_wdt_probe(struct platform_device *pdev)
        /* Make sure the watchdog is not running */
        wdt_stop(wdt_dev);
 
-       ret = watchdog_register_device(wdt_dev);
+       ret = devm_watchdog_register_device(&pdev->dev, wdt_dev);
        if (ret) {
                dev_err(&pdev->dev, "error registering watchdog device\n");
                return ret;
@@ -162,16 +161,8 @@ static int mid_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int mid_wdt_remove(struct platform_device *pdev)
-{
-       struct watchdog_device *wd = platform_get_drvdata(pdev);
-       watchdog_unregister_device(wd);
-       return 0;
-}
-
 static struct platform_driver mid_wdt_driver = {
        .probe          = mid_wdt_probe,
-       .remove         = mid_wdt_remove,
        .driver         = {
                .name   = "intel_mid_wdt",
        },
index 8e302d0e346c9b6a617fd0c1f3a64c65f0a084df..73c46b3a09ab3ec80db0bfb7577fe289fc811b51 100644 (file)
@@ -422,7 +422,7 @@ static int kempld_wdt_probe_stages(struct watchdog_device *wdd)
        return 0;
 }
 
-static struct watchdog_info kempld_wdt_info = {
+static const struct watchdog_info kempld_wdt_info = {
        .identity       = "KEMPLD Watchdog",
        .options        = WDIOF_SETTIMEOUT |
                        WDIOF_KEEPALIVEPING |
index 582f2fa1b8d91709dde248463f20edabb5850461..e0823677d8c17a1b4733d1c111c3415f01b0ca72 100644 (file)
@@ -3,7 +3,7 @@
  *  under the terms of the GNU General Public License version 2 as published
  *  by the Free Software Foundation.
  *
- *  Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2010 John Crispin <john@phrozen.org>
  *  Based on EP93xx wdt driver
  */
 
@@ -240,6 +240,6 @@ module_platform_driver(ltq_wdt_driver);
 
 module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
-MODULE_AUTHOR("John Crispin <blogic@openwrt.org>");
+MODULE_AUTHOR("John Crispin <john@phrozen.org>");
 MODULE_DESCRIPTION("Lantiq SoC Watchdog");
 MODULE_LICENSE("GPL");
index fd171e6caa167457777ced3220d6bd277f0dde34..3b8bb59adf027bddf5fde1013c3621f4b480e9a3 100644 (file)
@@ -181,7 +181,7 @@ static int lpc18xx_wdt_restart(struct watchdog_device *wdt_dev,
        return 0;
 }
 
-static struct watchdog_info lpc18xx_wdt_info = {
+static const struct watchdog_info lpc18xx_wdt_info = {
        .identity       = "NXP LPC18xx Watchdog",
        .options        = WDIOF_SETTIMEOUT |
                          WDIOF_KEEPALIVEPING |
index af6a7c489f085aaa31e2d1361f059145f2116ba7..045201a6fdb38dfa8bc3bc75978455da2e8101a9 100644 (file)
@@ -212,33 +212,14 @@ static int a21_wdt_probe(struct platform_device *pdev)
        drv->wdt = a21_wdt;
        dev_set_drvdata(&pdev->dev, drv);
 
-       ret = watchdog_register_device(&a21_wdt);
+       ret = devm_watchdog_register_device(&pdev->dev, &a21_wdt);
        if (ret) {
                dev_err(&pdev->dev, "Cannot register watchdog device\n");
-               goto err_register_wd;
+               return ret;
        }
 
        dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n");
 
-       return 0;
-
-err_register_wd:
-       mutex_destroy(&drv->lock);
-
-       return ret;
-}
-
-static int a21_wdt_remove(struct platform_device *pdev)
-{
-       struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev);
-
-       dev_warn(&pdev->dev,
-               "Unregistering A21 watchdog driver, board may reboot\n");
-
-       watchdog_unregister_device(&drv->wdt);
-
-       mutex_destroy(&drv->lock);
-
        return 0;
 }
 
@@ -257,7 +238,6 @@ MODULE_DEVICE_TABLE(of, a21_wdt_ids);
 
 static struct platform_driver a21_wdt_driver = {
        .probe = a21_wdt_probe,
-       .remove = a21_wdt_remove,
        .shutdown = a21_wdt_shutdown,
        .driver = {
                .name = "a21-watchdog",
index 56ea1caf71c35d3bfde164dacdb8775f4fba98bb..491b9bf13d849d2f2bc578538e113073b757f70f 100644 (file)
@@ -201,38 +201,19 @@ static int meson_wdt_probe(struct platform_device *pdev)
 
        meson_wdt_stop(&meson_wdt->wdt_dev);
 
-       err = watchdog_register_device(&meson_wdt->wdt_dev);
+       watchdog_stop_on_reboot(&meson_wdt->wdt_dev);
+       err = devm_watchdog_register_device(&pdev->dev, &meson_wdt->wdt_dev);
        if (err)
                return err;
 
-       platform_set_drvdata(pdev, meson_wdt);
-
        dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
                 meson_wdt->wdt_dev.timeout, nowayout);
 
        return 0;
 }
 
-static int meson_wdt_remove(struct platform_device *pdev)
-{
-       struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&meson_wdt->wdt_dev);
-
-       return 0;
-}
-
-static void meson_wdt_shutdown(struct platform_device *pdev)
-{
-       struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev);
-
-       meson_wdt_stop(&meson_wdt->wdt_dev);
-}
-
 static struct platform_driver meson_wdt_driver = {
        .probe          = meson_wdt_probe,
-       .remove         = meson_wdt_remove,
-       .shutdown       = meson_wdt_shutdown,
        .driver         = {
                .name           = DRV_NAME,
                .of_match_table = meson_wdt_dt_ids,
index d5735c12067d609465c556e17422e86b08ffe140..48a06067075d56c2f90358527cdd351575992ea1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Ralink MT7621/MT7628 built-in hardware watchdog timer
  *
- * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2014 John Crispin <john@phrozen.org>
  *
  * This driver was based on: drivers/watchdog/rt2880_wdt.c
  *
@@ -110,7 +110,7 @@ static struct watchdog_info mt7621_wdt_info = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 };
 
-static struct watchdog_ops mt7621_wdt_ops = {
+static const struct watchdog_ops mt7621_wdt_ops = {
        .owner = THIS_MODULE,
        .start = mt7621_wdt_start,
        .stop = mt7621_wdt_stop,
@@ -181,5 +181,5 @@ static struct platform_driver mt7621_wdt_driver = {
 module_platform_driver(mt7621_wdt_driver);
 
 MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver");
-MODULE_AUTHOR("John Crispin <blogic@openwrt.org");
+MODULE_AUTHOR("John Crispin <john@phrozen.org");
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/watchdog/nic7018_wdt.c b/drivers/watchdog/nic7018_wdt.c
new file mode 100644 (file)
index 0000000..dcd2656
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2016 National Instruments Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/acpi.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+#define LOCK                   0xA5
+#define UNLOCK                 0x5A
+
+#define WDT_CTRL_RESET_EN      BIT(7)
+#define WDT_RELOAD_PORT_EN     BIT(7)
+
+#define WDT_CTRL               1
+#define WDT_RELOAD_CTRL                2
+#define WDT_PRESET_PRESCALE    4
+#define WDT_REG_LOCK           5
+#define WDT_COUNT              6
+#define WDT_RELOAD_PORT                7
+
+#define WDT_MIN_TIMEOUT                1
+#define WDT_MAX_TIMEOUT                464
+#define WDT_DEFAULT_TIMEOUT    80
+
+#define WDT_MAX_COUNTER                15
+
+static unsigned int timeout;
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout,
+                "Watchdog timeout in seconds. (default="
+                __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout,
+                "Watchdog cannot be stopped once started. (default="
+                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+struct nic7018_wdt {
+       u16 io_base;
+       u32 period;
+       struct watchdog_device wdd;
+};
+
+struct nic7018_config {
+       u32 period;
+       u8 divider;
+};
+
+static const struct nic7018_config nic7018_configs[] = {
+       {  2, 4 },
+       { 32, 5 },
+};
+
+static inline u32 nic7018_timeout(u32 period, u8 counter)
+{
+       return period * counter - period / 2;
+}
+
+static const struct nic7018_config *nic7018_get_config(u32 timeout,
+                                                      u8 *counter)
+{
+       const struct nic7018_config *config;
+       u8 count;
+
+       if (timeout < 30 && timeout != 16) {
+               config = &nic7018_configs[0];
+               count = timeout / 2 + 1;
+       } else {
+               config = &nic7018_configs[1];
+               count = DIV_ROUND_UP(timeout + 16, 32);
+
+               if (count > WDT_MAX_COUNTER)
+                       count = WDT_MAX_COUNTER;
+       }
+       *counter = count;
+       return config;
+}
+
+static int nic7018_set_timeout(struct watchdog_device *wdd,
+                              unsigned int timeout)
+{
+       struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd);
+       const struct nic7018_config *config;
+       u8 counter;
+
+       config = nic7018_get_config(timeout, &counter);
+
+       outb(counter << 4 | config->divider,
+            wdt->io_base + WDT_PRESET_PRESCALE);
+
+       wdd->timeout = nic7018_timeout(config->period, counter);
+       wdt->period = config->period;
+
+       return 0;
+}
+
+static int nic7018_start(struct watchdog_device *wdd)
+{
+       struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd);
+       u8 control;
+
+       nic7018_set_timeout(wdd, wdd->timeout);
+
+       control = inb(wdt->io_base + WDT_RELOAD_CTRL);
+       outb(control | WDT_RELOAD_PORT_EN, wdt->io_base + WDT_RELOAD_CTRL);
+
+       outb(1, wdt->io_base + WDT_RELOAD_PORT);
+
+       control = inb(wdt->io_base + WDT_CTRL);
+       outb(control | WDT_CTRL_RESET_EN, wdt->io_base + WDT_CTRL);
+
+       return 0;
+}
+
+static int nic7018_stop(struct watchdog_device *wdd)
+{
+       struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       outb(0, wdt->io_base + WDT_CTRL);
+       outb(0, wdt->io_base + WDT_RELOAD_CTRL);
+       outb(0xF0, wdt->io_base + WDT_PRESET_PRESCALE);
+
+       return 0;
+}
+
+static int nic7018_ping(struct watchdog_device *wdd)
+{
+       struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       outb(1, wdt->io_base + WDT_RELOAD_PORT);
+
+       return 0;
+}
+
+static unsigned int nic7018_get_timeleft(struct watchdog_device *wdd)
+{
+       struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd);
+       u8 count;
+
+       count = inb(wdt->io_base + WDT_COUNT) & 0xF;
+       if (!count)
+               return 0;
+
+       return nic7018_timeout(wdt->period, count);
+}
+
+static const struct watchdog_info nic7018_wdd_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+       .identity = "NIC7018 Watchdog",
+};
+
+static const struct watchdog_ops nic7018_wdd_ops = {
+       .owner = THIS_MODULE,
+       .start = nic7018_start,
+       .stop = nic7018_stop,
+       .ping = nic7018_ping,
+       .set_timeout = nic7018_set_timeout,
+       .get_timeleft = nic7018_get_timeleft,
+};
+
+static int nic7018_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct watchdog_device *wdd;
+       struct nic7018_wdt *wdt;
+       struct resource *io_rc;
+       int ret;
+
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, wdt);
+
+       io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       if (!io_rc) {
+               dev_err(dev, "missing IO resources\n");
+               return -EINVAL;
+       }
+
+       if (!devm_request_region(dev, io_rc->start, resource_size(io_rc),
+                                KBUILD_MODNAME)) {
+               dev_err(dev, "failed to get IO region\n");
+               return -EBUSY;
+       }
+
+       wdt->io_base = io_rc->start;
+       wdd = &wdt->wdd;
+       wdd->info = &nic7018_wdd_info;
+       wdd->ops = &nic7018_wdd_ops;
+       wdd->min_timeout = WDT_MIN_TIMEOUT;
+       wdd->max_timeout = WDT_MAX_TIMEOUT;
+       wdd->timeout = WDT_DEFAULT_TIMEOUT;
+       wdd->parent = dev;
+
+       watchdog_set_drvdata(wdd, wdt);
+       watchdog_set_nowayout(wdd, nowayout);
+
+       ret = watchdog_init_timeout(wdd, timeout, dev);
+       if (ret)
+               dev_warn(dev, "unable to set timeout value, using default\n");
+
+       /* Unlock WDT register */
+       outb(UNLOCK, wdt->io_base + WDT_REG_LOCK);
+
+       ret = watchdog_register_device(wdd);
+       if (ret) {
+               outb(LOCK, wdt->io_base + WDT_REG_LOCK);
+               dev_err(dev, "failed to register watchdog\n");
+               return ret;
+       }
+
+       dev_dbg(dev, "io_base=0x%04X, timeout=%d, nowayout=%d\n",
+               wdt->io_base, timeout, nowayout);
+       return 0;
+}
+
+static int nic7018_remove(struct platform_device *pdev)
+{
+       struct nic7018_wdt *wdt = platform_get_drvdata(pdev);
+
+       watchdog_unregister_device(&wdt->wdd);
+
+       /* Lock WDT register */
+       outb(LOCK, wdt->io_base + WDT_REG_LOCK);
+
+       return 0;
+}
+
+static const struct acpi_device_id nic7018_device_ids[] = {
+       {"NIC7018", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, nic7018_device_ids);
+
+static struct platform_driver watchdog_driver = {
+       .probe = nic7018_probe,
+       .remove = nic7018_remove,
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .acpi_match_table = ACPI_PTR(nic7018_device_ids),
+       },
+};
+
+module_platform_driver(watchdog_driver);
+
+MODULE_DESCRIPTION("National Instruments NIC7018 Watchdog driver");
+MODULE_AUTHOR("Hui Chun Ong <hui.chun.ong@ni.com>");
+MODULE_LICENSE("GPL");
index c6b8f4a43bdeff2df7faa71f6356819f8129c326..39be4dd8035ed0952af5dc6f81c6db888e1506ac 100644 (file)
@@ -395,7 +395,7 @@ static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev,
 
        rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET;
 
-       WARN(1, FW_BUG "falling back to harcoded RSTOUT reg %pa\n", &rstout);
+       WARN(1, FW_BUG "falling back to hardcoded RSTOUT reg %pa\n", &rstout);
        return devm_ioremap(&pdev->dev, rstout, 0x4);
 }
 
index 0cdfee266690b70fccc93eee4573f0b0cb65766a..e35cf5e87907c3f98520ab0440d6088e6976f803 100644 (file)
@@ -54,7 +54,7 @@ static struct {
        struct timer_list timer;        /* The timer that pings the watchdog */
 } pikawdt_private;
 
-static struct watchdog_info ident = {
+static struct watchdog_info ident __ro_after_init = {
        .identity       = DRV_NAME,
        .options        = WDIOF_CARDRESET |
                          WDIOF_SETTIMEOUT |
index 0805ee2acd7a94bb913472f5bd33bea5d95bc0c8..e60f55702ab79d111078dae1b253799dfdc4684d 100644 (file)
@@ -130,7 +130,7 @@ static int rn5t618_wdt_ping(struct watchdog_device *wdt_dev)
                                  RN5T618_PWRIRQ_IR_WDOG, 0);
 }
 
-static struct watchdog_info rn5t618_wdt_info = {
+static const struct watchdog_info rn5t618_wdt_info = {
        .options        = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
                          WDIOF_KEEPALIVEPING,
        .identity       = DRIVER_NAME,
index 14b4fd428fffbbfaf539eb0ab06273858d15ed93..05524baf7dccba28fa84360a909bea22127f0ddc 100644 (file)
@@ -2,7 +2,7 @@
  * Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer
  *
  * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org>
- * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2013 John Crispin <john@phrozen.org>
  *
  * This driver was based on: drivers/watchdog/softdog.c
  *
@@ -124,7 +124,7 @@ static struct watchdog_info rt288x_wdt_info = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 };
 
-static struct watchdog_ops rt288x_wdt_ops = {
+static const struct watchdog_ops rt288x_wdt_ops = {
        .owner = THIS_MODULE,
        .start = rt288x_wdt_start,
        .stop = rt288x_wdt_stop,
index 59e95762a6de776ba9a6bcc793138eccb8396675..6ed97596ca80685519ec327d4d6a847824788546 100644 (file)
@@ -23,8 +23,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/types.h>
@@ -46,6 +44,7 @@
 #define S3C2410_WTCON          0x00
 #define S3C2410_WTDAT          0x04
 #define S3C2410_WTCNT          0x08
+#define S3C2410_WTCLRINT       0x0c
 
 #define S3C2410_WTCNT_MAXCNT   0xffff
 
 #define S3C2410_WTCON_PRESCALE_MASK    (0xff << 8)
 #define S3C2410_WTCON_PRESCALE_MAX     0xff
 
-#define CONFIG_S3C2410_WATCHDOG_ATBOOT         (0)
-#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME   (15)
+#define S3C2410_WATCHDOG_ATBOOT                (0)
+#define S3C2410_WATCHDOG_DEFAULT_TIME  (15)
 
 #define EXYNOS5_RST_STAT_REG_OFFSET            0x0404
 #define EXYNOS5_WDT_DISABLE_REG_OFFSET         0x0408
 #define EXYNOS5_WDT_MASK_RESET_REG_OFFSET      0x040c
 #define QUIRK_HAS_PMU_CONFIG                   (1 << 0)
 #define QUIRK_HAS_RST_STAT                     (1 << 1)
+#define QUIRK_HAS_WTCLRINT_REG                 (1 << 2)
 
 /* These quirks require that we have a PMU register map */
 #define QUIRKS_HAVE_PMUREG                     (QUIRK_HAS_PMU_CONFIG | \
 
 static bool nowayout   = WATCHDOG_NOWAYOUT;
 static int tmr_margin;
-static int tmr_atboot  = CONFIG_S3C2410_WATCHDOG_ATBOOT;
+static int tmr_atboot  = S3C2410_WATCHDOG_ATBOOT;
 static int soft_noboot;
-static int debug;
 
 module_param(tmr_margin,  int, 0);
 module_param(tmr_atboot,  int, 0);
 module_param(nowayout,   bool, 0);
 module_param(soft_noboot, int, 0);
-module_param(debug,      int, 0);
 
 MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default="
-               __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")");
+               __MODULE_STRING(S3C2410_WATCHDOG_DEFAULT_TIME) ")");
 MODULE_PARM_DESC(tmr_atboot,
                "Watchdog is started at boot time if set to 1, default="
-                       __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT));
+                       __MODULE_STRING(S3C2410_WATCHDOG_ATBOOT));
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
                        __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
                        "0 to reboot (default 0)");
-MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");
 
 /**
  * struct s3c2410_wdt_variant - Per-variant config data
@@ -143,13 +140,18 @@ static const struct s3c2410_wdt_variant drv_data_s3c2410 = {
 };
 
 #ifdef CONFIG_OF
+static const struct s3c2410_wdt_variant drv_data_s3c6410 = {
+       .quirks = QUIRK_HAS_WTCLRINT_REG,
+};
+
 static const struct s3c2410_wdt_variant drv_data_exynos5250  = {
        .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
        .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
        .mask_bit = 20,
        .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
        .rst_stat_bit = 20,
-       .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
+       .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \
+                 | QUIRK_HAS_WTCLRINT_REG,
 };
 
 static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
@@ -158,7 +160,8 @@ static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
        .mask_bit = 0,
        .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
        .rst_stat_bit = 9,
-       .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
+       .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \
+                 | QUIRK_HAS_WTCLRINT_REG,
 };
 
 static const struct s3c2410_wdt_variant drv_data_exynos7 = {
@@ -167,12 +170,15 @@ static const struct s3c2410_wdt_variant drv_data_exynos7 = {
        .mask_bit = 23,
        .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
        .rst_stat_bit = 23,     /* A57 WDTRESET */
-       .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
+       .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \
+                 | QUIRK_HAS_WTCLRINT_REG,
 };
 
 static const struct of_device_id s3c2410_wdt_match[] = {
        { .compatible = "samsung,s3c2410-wdt",
          .data = &drv_data_s3c2410 },
+       { .compatible = "samsung,s3c6410-wdt",
+         .data = &drv_data_s3c6410 },
        { .compatible = "samsung,exynos5250-wdt",
          .data = &drv_data_exynos5250 },
        { .compatible = "samsung,exynos5420-wdt",
@@ -193,14 +199,6 @@ static const struct platform_device_id s3c2410_wdt_ids[] = {
 };
 MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids);
 
-/* watchdog control routines */
-
-#define DBG(fmt, ...)                                  \
-do {                                                   \
-       if (debug)                                      \
-               pr_info(fmt, ##__VA_ARGS__);            \
-} while (0)
-
 /* functions */
 
 static inline unsigned int s3c2410wdt_max_timeout(struct clk *clock)
@@ -296,8 +294,8 @@ static int s3c2410wdt_start(struct watchdog_device *wdd)
                wtcon |= S3C2410_WTCON_RSTEN;
        }
 
-       DBG("%s: count=0x%08x, wtcon=%08lx\n",
-           __func__, wdt->count, wtcon);
+       dev_dbg(wdt->dev, "Starting watchdog: count=0x%08x, wtcon=%08lx\n",
+               wdt->count, wtcon);
 
        writel(wdt->count, wdt->reg_base + S3C2410_WTDAT);
        writel(wdt->count, wdt->reg_base + S3C2410_WTCNT);
@@ -326,8 +324,8 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
        freq = DIV_ROUND_UP(freq, 128);
        count = timeout * freq;
 
-       DBG("%s: count=%d, timeout=%d, freq=%lu\n",
-           __func__, count, timeout, freq);
+       dev_dbg(wdt->dev, "Heartbeat: count=%d, timeout=%d, freq=%lu\n",
+               count, timeout, freq);
 
        /* if the count is bigger than the watchdog register,
           then work out what we need to do (and if) we can
@@ -343,8 +341,8 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
                }
        }
 
-       DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",
-           __func__, timeout, divisor, count, DIV_ROUND_UP(count, divisor));
+       dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%d (%08x)\n",
+               timeout, divisor, count, DIV_ROUND_UP(count, divisor));
 
        count = DIV_ROUND_UP(count, divisor);
        wdt->count = count;
@@ -394,7 +392,7 @@ static const struct watchdog_info s3c2410_wdt_ident = {
        .identity         =     "S3C2410 Watchdog",
 };
 
-static struct watchdog_ops s3c2410wdt_ops = {
+static const struct watchdog_ops s3c2410wdt_ops = {
        .owner = THIS_MODULE,
        .start = s3c2410wdt_start,
        .stop = s3c2410wdt_stop,
@@ -406,7 +404,7 @@ static struct watchdog_ops s3c2410wdt_ops = {
 static struct watchdog_device s3c2410_wdd = {
        .info = &s3c2410_wdt_ident,
        .ops = &s3c2410wdt_ops,
-       .timeout = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME,
+       .timeout = S3C2410_WATCHDOG_DEFAULT_TIME,
 };
 
 /* interrupt handler code */
@@ -418,6 +416,10 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
        dev_info(wdt->dev, "watchdog timer expired (irq)\n");
 
        s3c2410wdt_keepalive(&wdt->wdt_device);
+
+       if (wdt->drv_data->quirks & QUIRK_HAS_WTCLRINT_REG)
+               writel(0x1, wdt->reg_base + S3C2410_WTCLRINT);
+
        return IRQ_HANDLED;
 }
 
@@ -505,9 +507,8 @@ static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt)
        return 0;
 }
 
-/* s3c2410_get_wdt_driver_data */
 static inline struct s3c2410_wdt_variant *
-get_wdt_drv_data(struct platform_device *pdev)
+s3c2410_get_wdt_drv_data(struct platform_device *pdev)
 {
        if (pdev->dev.of_node) {
                const struct of_device_id *match;
@@ -529,8 +530,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        int started = 0;
        int ret;
 
-       DBG("%s: probe=%p\n", __func__, pdev);
-
        dev = &pdev->dev;
 
        wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
@@ -541,7 +540,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        spin_lock_init(&wdt->lock);
        wdt->wdt_device = s3c2410_wdd;
 
-       wdt->drv_data = get_wdt_drv_data(pdev);
+       wdt->drv_data = s3c2410_get_wdt_drv_data(pdev);
        if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) {
                wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
                                                "samsung,syscon-phandle");
@@ -566,8 +565,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
                goto err;
        }
 
-       DBG("probe: mapped reg_base=%p\n", wdt->reg_base);
-
        wdt->clock = devm_clk_get(dev, "watchdog");
        if (IS_ERR(wdt->clock)) {
                dev_err(dev, "failed to find watchdog clock source\n");
@@ -600,12 +597,12 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
                                        wdt->wdt_device.timeout);
        if (ret) {
                started = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
-                                       CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
+                                       S3C2410_WATCHDOG_DEFAULT_TIME);
 
                if (started == 0)
                        dev_info(dev,
                           "tmr_margin value out of range, default %d used\n",
-                              CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
+                              S3C2410_WATCHDOG_DEFAULT_TIME);
                else
                        dev_info(dev, "default timer value is out of range, "
                                                        "cannot start\n");
index 8965e3f536c3572516053c522eb1d4208309988a..d3be4f831db58a22cee4e868920923ad3bc5612d 100644 (file)
@@ -188,12 +188,14 @@ static int __init sa1100dog_init(void)
        pre_margin = oscr_freq * margin;
 
        ret = misc_register(&sa1100dog_miscdev);
-       if (ret == 0)
+       if (ret == 0) {
                pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n",
                        margin);
-       return ret;
-err:
+               return 0;
+       }
+
        clk_disable_unprepare(clk);
+err:
        clk_put(clk);
        return ret;
 }
index a49634cdc1ccbc987576bae3480f6669db3c0cde..f709962018ac260107dd2c419c1fbcdfafd4599b 100644 (file)
@@ -28,7 +28,7 @@
 struct sama5d4_wdt {
        struct watchdog_device  wdd;
        void __iomem            *reg_base;
-       u32     config;
+       u32                     mr;
 };
 
 static int wdt_timeout = WDT_DEFAULT_TIMEOUT;
@@ -53,11 +53,9 @@ MODULE_PARM_DESC(nowayout,
 static int sama5d4_wdt_start(struct watchdog_device *wdd)
 {
        struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
-       u32 reg;
 
-       reg = wdt_read(wdt, AT91_WDT_MR);
-       reg &= ~AT91_WDT_WDDIS;
-       wdt_write(wdt, AT91_WDT_MR, reg);
+       wdt->mr &= ~AT91_WDT_WDDIS;
+       wdt_write(wdt, AT91_WDT_MR, wdt->mr);
 
        return 0;
 }
@@ -65,11 +63,9 @@ static int sama5d4_wdt_start(struct watchdog_device *wdd)
 static int sama5d4_wdt_stop(struct watchdog_device *wdd)
 {
        struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
-       u32 reg;
 
-       reg = wdt_read(wdt, AT91_WDT_MR);
-       reg |= AT91_WDT_WDDIS;
-       wdt_write(wdt, AT91_WDT_MR, reg);
+       wdt->mr |= AT91_WDT_WDDIS;
+       wdt_write(wdt, AT91_WDT_MR, wdt->mr);
 
        return 0;
 }
@@ -88,14 +84,12 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd,
 {
        struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd);
        u32 value = WDT_SEC2TICKS(timeout);
-       u32 reg;
 
-       reg = wdt_read(wdt, AT91_WDT_MR);
-       reg &= ~AT91_WDT_WDV;
-       reg &= ~AT91_WDT_WDD;
-       reg |= AT91_WDT_SET_WDV(value);
-       reg |= AT91_WDT_SET_WDD(value);
-       wdt_write(wdt, AT91_WDT_MR, reg);
+       wdt->mr &= ~AT91_WDT_WDV;
+       wdt->mr &= ~AT91_WDT_WDD;
+       wdt->mr |= AT91_WDT_SET_WDV(value);
+       wdt->mr |= AT91_WDT_SET_WDD(value);
+       wdt_write(wdt, AT91_WDT_MR, wdt->mr);
 
        wdd->timeout = timeout;
 
@@ -107,7 +101,7 @@ static const struct watchdog_info sama5d4_wdt_info = {
        .identity = "Atmel SAMA5D4 Watchdog",
 };
 
-static struct watchdog_ops sama5d4_wdt_ops = {
+static const struct watchdog_ops sama5d4_wdt_ops = {
        .owner = THIS_MODULE,
        .start = sama5d4_wdt_start,
        .stop = sama5d4_wdt_stop,
@@ -132,19 +126,19 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt)
 {
        const char *tmp;
 
-       wdt->config = AT91_WDT_WDDIS;
+       wdt->mr = AT91_WDT_WDDIS;
 
        if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) &&
            !strcmp(tmp, "software"))
-               wdt->config |= AT91_WDT_WDFIEN;
+               wdt->mr |= AT91_WDT_WDFIEN;
        else
-               wdt->config |= AT91_WDT_WDRSTEN;
+               wdt->mr |= AT91_WDT_WDRSTEN;
 
        if (of_property_read_bool(np, "atmel,idle-halt"))
-               wdt->config |= AT91_WDT_WDIDLEHLT;
+               wdt->mr |= AT91_WDT_WDIDLEHLT;
 
        if (of_property_read_bool(np, "atmel,dbg-halt"))
-               wdt->config |= AT91_WDT_WDDBGHLT;
+               wdt->mr |= AT91_WDT_WDDBGHLT;
 
        return 0;
 }
@@ -163,11 +157,10 @@ static int sama5d4_wdt_init(struct sama5d4_wdt *wdt)
        reg &= ~AT91_WDT_WDDIS;
        wdt_write(wdt, AT91_WDT_MR, reg);
 
-       reg = wdt->config;
-       reg |= AT91_WDT_SET_WDD(value);
-       reg |= AT91_WDT_SET_WDV(value);
+       wdt->mr |= AT91_WDT_SET_WDD(value);
+       wdt->mr |= AT91_WDT_SET_WDV(value);
 
-       wdt_write(wdt, AT91_WDT_MR, reg);
+       wdt_write(wdt, AT91_WDT_MR, wdt->mr);
 
        return 0;
 }
@@ -211,7 +204,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev)
                        return ret;
        }
 
-       if ((wdt->config & AT91_WDT_WDFIEN) && irq) {
+       if ((wdt->mr & AT91_WDT_WDFIEN) && irq) {
                ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler,
                                       IRQF_SHARED | IRQF_IRQPOLL |
                                       IRQF_NO_SUSPEND, pdev->name, pdev);
@@ -265,11 +258,28 @@ static const struct of_device_id sama5d4_wdt_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match);
 
+#ifdef CONFIG_PM_SLEEP
+static int sama5d4_wdt_resume(struct device *dev)
+{
+       struct sama5d4_wdt *wdt = dev_get_drvdata(dev);
+
+       wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS);
+       if (wdt->mr & AT91_WDT_WDDIS)
+               wdt_write(wdt, AT91_WDT_MR, wdt->mr);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(sama5d4_wdt_pm_ops, NULL,
+                        sama5d4_wdt_resume);
+
 static struct platform_driver sama5d4_wdt_driver = {
        .probe          = sama5d4_wdt_probe,
        .remove         = sama5d4_wdt_remove,
        .driver         = {
                .name   = "sama5d4_wdt",
+               .pm     = &sama5d4_wdt_pm_ops,
                .of_match_table = sama5d4_wdt_of_match,
        }
 };
index ce0c38bd0f0078eb32826b9377724432530efcf3..316c2eb122d23d335d738947a63fc2f9db2e4f1b 100644 (file)
@@ -207,7 +207,7 @@ static irqreturn_t sbsa_gwdt_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-static struct watchdog_info sbsa_gwdt_info = {
+static const struct watchdog_info sbsa_gwdt_info = {
        .identity       = WATCHDOG_NAME,
        .options        = WDIOF_SETTIMEOUT |
                          WDIOF_KEEPALIVEPING |
@@ -215,7 +215,7 @@ static struct watchdog_info sbsa_gwdt_info = {
                          WDIOF_CARDRESET,
 };
 
-static struct watchdog_ops sbsa_gwdt_ops = {
+static const struct watchdog_ops sbsa_gwdt_ops = {
        .owner          = THIS_MODULE,
        .start          = sbsa_gwdt_start,
        .stop           = sbsa_gwdt_stop,
index 3050a0031479f4737a3358d9152d973ad347fff1..4eea351e09b0d205d20e771e2349abc04d6310f8 100644 (file)
@@ -127,7 +127,7 @@ static const struct watchdog_info sirfsoc_wdt_ident = {
        .identity         =     "SiRFSOC Watchdog",
 };
 
-static struct watchdog_ops sirfsoc_wdt_ops = {
+static const struct watchdog_ops sirfsoc_wdt_ops = {
        .owner = THIS_MODULE,
        .start = sirfsoc_wdt_enable,
        .stop = sirfsoc_wdt_disable,
index c7bdc986dca1c249c2b61ad902504cdd1df4fb2d..7983029852ab0dc7e688b0766337fd0bb9da8c54 100644 (file)
@@ -87,11 +87,13 @@ static int softdog_ping(struct watchdog_device *w)
        if (!mod_timer(&softdog_ticktock, jiffies + (w->timeout * HZ)))
                __module_get(THIS_MODULE);
 
-       if (w->pretimeout)
-               mod_timer(&softdog_preticktock, jiffies +
-                         (w->timeout - w->pretimeout) * HZ);
-       else
-               del_timer(&softdog_preticktock);
+       if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT)) {
+               if (w->pretimeout)
+                       mod_timer(&softdog_preticktock, jiffies +
+                                 (w->timeout - w->pretimeout) * HZ);
+               else
+                       del_timer(&softdog_preticktock);
+       }
 
        return 0;
 }
@@ -101,15 +103,15 @@ static int softdog_stop(struct watchdog_device *w)
        if (del_timer(&softdog_ticktock))
                module_put(THIS_MODULE);
 
-       del_timer(&softdog_preticktock);
+       if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT))
+               del_timer(&softdog_preticktock);
 
        return 0;
 }
 
 static struct watchdog_info softdog_info = {
        .identity = "Software Watchdog",
-       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE |
-                  WDIOF_PRETIMEOUT,
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 };
 
 static const struct watchdog_ops softdog_ops = {
@@ -134,6 +136,9 @@ static int __init softdog_init(void)
        watchdog_set_nowayout(&softdog_dev, nowayout);
        watchdog_stop_on_reboot(&softdog_dev);
 
+       if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT))
+               softdog_info.options |= WDIOF_PRETIMEOUT;
+
        ret = watchdog_register_device(&softdog_dev);
        if (ret)
                return ret;
index 1467fe50a76fad5399d3eb25babc4cdaed1d0049..00907973608c6ff7ef8a571c36f64af30945f3d9 100644 (file)
@@ -77,7 +77,7 @@ static const struct watchdog_info sun4v_wdt_ident = {
        .firmware_version = 0,
 };
 
-static struct watchdog_ops sun4v_wdt_ops = {
+static const struct watchdog_ops sun4v_wdt_ops = {
        .owner =        THIS_MODULE,
        .start =        sun4v_wdt_ping,
        .stop =         sun4v_wdt_stop,
index 953bb7b7446f95367d39923a6c6a11a186a9052a..9728fa32c357b88f5cab03300c96aeaf9f6f1968 100644 (file)
@@ -242,8 +242,6 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
        if (!sunxi_wdt)
                return -EINVAL;
 
-       platform_set_drvdata(pdev, sunxi_wdt);
-
        device = of_match_device(sunxi_wdt_dt_ids, &pdev->dev);
        if (!device)
                return -ENODEV;
@@ -270,7 +268,8 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
 
        sunxi_wdt_stop(&sunxi_wdt->wdt_dev);
 
-       err = watchdog_register_device(&sunxi_wdt->wdt_dev);
+       watchdog_stop_on_reboot(&sunxi_wdt->wdt_dev);
+       err = devm_watchdog_register_device(&pdev->dev, &sunxi_wdt->wdt_dev);
        if (unlikely(err))
                return err;
 
@@ -280,27 +279,8 @@ static int sunxi_wdt_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int sunxi_wdt_remove(struct platform_device *pdev)
-{
-       struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&sunxi_wdt->wdt_dev);
-       watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL);
-
-       return 0;
-}
-
-static void sunxi_wdt_shutdown(struct platform_device *pdev)
-{
-       struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
-
-       sunxi_wdt_stop(&sunxi_wdt->wdt_dev);
-}
-
 static struct platform_driver sunxi_wdt_driver = {
        .probe          = sunxi_wdt_probe,
-       .remove         = sunxi_wdt_remove,
-       .shutdown       = sunxi_wdt_shutdown,
        .driver         = {
                .name           = DRV_NAME,
                .of_match_table = sunxi_wdt_dt_ids,
index 202c4b9cc9212b779c9bc2145bbb9bac503c6cf6..d5fcce062920e0d1739e85b2956bd9d30b436daa 100644 (file)
@@ -15,9 +15,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/notifier.h>
 #include <linux/platform_device.h>
-#include <linux/reboot.h>
 #include <linux/watchdog.h>
 
 #define DEFAULT_TIMEOUT 30
@@ -47,7 +45,6 @@ struct tangox_wdt_device {
        void __iomem *base;
        unsigned long clk_rate;
        struct clk *clk;
-       struct notifier_block restart;
 };
 
 static int tangox_wdt_set_timeout(struct watchdog_device *wdt,
@@ -96,24 +93,24 @@ static const struct watchdog_info tangox_wdt_info = {
        .identity = "tangox watchdog",
 };
 
+static int tangox_wdt_restart(struct watchdog_device *wdt,
+                             unsigned long action, void *data)
+{
+       struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt);
+
+       writel(1, dev->base + WD_COUNTER);
+
+       return 0;
+}
+
 static const struct watchdog_ops tangox_wdt_ops = {
        .start          = tangox_wdt_start,
        .stop           = tangox_wdt_stop,
        .set_timeout    = tangox_wdt_set_timeout,
        .get_timeleft   = tangox_wdt_get_timeleft,
+       .restart        = tangox_wdt_restart,
 };
 
-static int tangox_wdt_restart(struct notifier_block *nb, unsigned long action,
-                             void *data)
-{
-       struct tangox_wdt_device *dev =
-               container_of(nb, struct tangox_wdt_device, restart);
-
-       writel(1, dev->base + WD_COUNTER);
-
-       return NOTIFY_DONE;
-}
-
 static int tangox_wdt_probe(struct platform_device *pdev)
 {
        struct tangox_wdt_device *dev;
@@ -174,18 +171,14 @@ static int tangox_wdt_probe(struct platform_device *pdev)
                tangox_wdt_start(&dev->wdt);
        }
 
+       watchdog_set_restart_priority(&dev->wdt, 128);
+
        err = watchdog_register_device(&dev->wdt);
        if (err)
                goto err;
 
        platform_set_drvdata(pdev, dev);
 
-       dev->restart.notifier_call = tangox_wdt_restart;
-       dev->restart.priority = 128;
-       err = register_restart_handler(&dev->restart);
-       if (err)
-               dev_warn(&pdev->dev, "failed to register restart handler\n");
-
        dev_info(&pdev->dev, "SMP86xx/SMP87xx watchdog registered\n");
 
        return 0;
@@ -202,7 +195,6 @@ static int tangox_wdt_remove(struct platform_device *pdev)
        tangox_wdt_stop(&dev->wdt);
        clk_disable_unprepare(dev->clk);
 
-       unregister_restart_handler(&dev->restart);
        watchdog_unregister_device(&dev->wdt);
 
        return 0;
index 2d53c3f9394f2a39bf78175bf4c229c7f3bbab90..9403c08816e35f47e7338938674414953f184f20 100644 (file)
@@ -226,7 +226,7 @@ static int tegra_wdt_probe(struct platform_device *pdev)
 
        watchdog_set_nowayout(wdd, nowayout);
 
-       ret = watchdog_register_device(wdd);
+       ret = devm_watchdog_register_device(&pdev->dev, wdd);
        if (ret) {
                dev_err(&pdev->dev,
                        "failed to register watchdog device\n");
@@ -248,8 +248,6 @@ static int tegra_wdt_remove(struct platform_device *pdev)
 
        tegra_wdt_stop(&wdt->wdd);
 
-       watchdog_unregister_device(&wdt->wdd);
-
        dev_info(&pdev->dev, "removed wdt\n");
 
        return 0;
index 4b541934b6c59e6702345e14ea90360ff67a694e..17c25daebcceb6678467890593a0023b7167f82b 100644 (file)
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/fs.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/miscdevice.h>
-#include <linux/mutex.h>
 #include <linux/platform_device.h>
-#include <linux/slab.h>
+#include <linux/module.h>
 #include <linux/watchdog.h>
-#include <linux/uaccess.h>
+#include <linux/io.h>
 
-#define TS72XX_WDT_FEED_VAL            0x05
-#define TS72XX_WDT_DEFAULT_TIMEOUT     8
+#define TS72XX_WDT_DEFAULT_TIMEOUT     30
 
-static int timeout = TS72XX_WDT_DEFAULT_TIMEOUT;
+static int timeout;
 module_param(timeout, int, 0);
-MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. "
-                         "(1 <= timeout <= 8, default="
-                         __MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT)
-                         ")");
+MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds.");
 
 static bool nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
 
-/**
- * struct ts72xx_wdt - watchdog control structure
- * @lock: lock that protects this structure
- * @regval: watchdog timeout value suitable for control register
- * @flags: flags controlling watchdog device state
- * @control_reg: watchdog control register
- * @feed_reg: watchdog feed register
- * @pdev: back pointer to platform dev
- */
-struct ts72xx_wdt {
-       struct mutex    lock;
-       int             regval;
-
-#define TS72XX_WDT_BUSY_FLAG           1
-#define TS72XX_WDT_EXPECT_CLOSE_FLAG   2
-       int             flags;
+/* priv->control_reg */
+#define TS72XX_WDT_CTRL_DISABLE                0x00
+#define TS72XX_WDT_CTRL_250MS          0x01
+#define TS72XX_WDT_CTRL_500MS          0x02
+#define TS72XX_WDT_CTRL_1SEC           0x03
+#define TS72XX_WDT_CTRL_RESERVED       0x04
+#define TS72XX_WDT_CTRL_2SEC           0x05
+#define TS72XX_WDT_CTRL_4SEC           0x06
+#define TS72XX_WDT_CTRL_8SEC           0x07
+
+/* priv->feed_reg */
+#define TS72XX_WDT_FEED_VAL            0x05
 
+struct ts72xx_wdt_priv {
        void __iomem    *control_reg;
        void __iomem    *feed_reg;
-
-       struct platform_device *pdev;
+       struct watchdog_device wdd;
+       unsigned char regval;
 };
 
-static struct platform_device *ts72xx_wdt_pdev;
-
-/*
- * TS-72xx Watchdog supports following timeouts (value written
- * to control register):
- *     value   description
- *     -------------------------
- *     0x00    watchdog disabled
- *     0x01    250ms
- *     0x02    500ms
- *     0x03    1s
- *     0x04    reserved
- *     0x05    2s
- *     0x06    4s
- *     0x07    8s
- *
- * Timeouts below 1s are not very usable so we don't
- * allow them at all.
- *
- * We provide two functions that convert between these:
- * timeout_to_regval() and regval_to_timeout().
- */
-static const struct {
-       int     timeout;
-       int     regval;
-} ts72xx_wdt_map[] = {
-       { 1, 3 },
-       { 2, 5 },
-       { 4, 6 },
-       { 8, 7 },
-};
-
-/**
- * timeout_to_regval() - converts given timeout to control register value
- * @new_timeout: timeout in seconds to be converted
- *
- * Function converts given @new_timeout into valid value that can
- * be programmed into watchdog control register. When conversion is
- * not possible, function returns %-EINVAL.
- */
-static int timeout_to_regval(int new_timeout)
-{
-       int i;
-
-       /* first limit it to 1 - 8 seconds */
-       new_timeout = clamp_val(new_timeout, 1, 8);
-
-       for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) {
-               if (ts72xx_wdt_map[i].timeout >= new_timeout)
-                       return ts72xx_wdt_map[i].regval;
-       }
-
-       return -EINVAL;
-}
-
-/**
- * regval_to_timeout() - converts control register value to timeout
- * @regval: control register value to be converted
- *
- * Function converts given @regval to timeout in seconds (1, 2, 4 or 8).
- * If @regval cannot be converted, function returns %-EINVAL.
- */
-static int regval_to_timeout(int regval)
+static int ts72xx_wdt_start(struct watchdog_device *wdd)
 {
-       int i;
+       struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-       for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) {
-               if (ts72xx_wdt_map[i].regval == regval)
-                       return ts72xx_wdt_map[i].timeout;
-       }
+       writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg);
+       writeb(priv->regval, priv->control_reg);
 
-       return -EINVAL;
+       return 0;
 }
 
-/**
- * ts72xx_wdt_kick() - kick the watchdog
- * @wdt: watchdog to be kicked
- *
- * Called with @wdt->lock held.
- */
-static inline void ts72xx_wdt_kick(struct ts72xx_wdt *wdt)
+static int ts72xx_wdt_stop(struct watchdog_device *wdd)
 {
-       __raw_writeb(TS72XX_WDT_FEED_VAL, wdt->feed_reg);
-}
+       struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-/**
- * ts72xx_wdt_start() - starts the watchdog timer
- * @wdt: watchdog to be started
- *
- * This function programs timeout to watchdog timer
- * and starts it.
- *
- * Called with @wdt->lock held.
- */
-static void ts72xx_wdt_start(struct ts72xx_wdt *wdt)
-{
-       /*
-        * To program the wdt, it first must be "fed" and
-        * only after that (within 30 usecs) the configuration
-        * can be changed.
-        */
-       ts72xx_wdt_kick(wdt);
-       __raw_writeb((u8)wdt->regval, wdt->control_reg);
-}
+       writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg);
+       writeb(TS72XX_WDT_CTRL_DISABLE, priv->control_reg);
 
-/**
- * ts72xx_wdt_stop() - stops the watchdog timer
- * @wdt: watchdog to be stopped
- *
- * Called with @wdt->lock held.
- */
-static void ts72xx_wdt_stop(struct ts72xx_wdt *wdt)
-{
-       ts72xx_wdt_kick(wdt);
-       __raw_writeb(0, wdt->control_reg);
+       return 0;
 }
 
-static int ts72xx_wdt_open(struct inode *inode, struct file *file)
+static int ts72xx_wdt_ping(struct watchdog_device *wdd)
 {
-       struct ts72xx_wdt *wdt = platform_get_drvdata(ts72xx_wdt_pdev);
-       int regval;
-
-       /*
-        * Try to convert default timeout to valid register
-        * value first.
-        */
-       regval = timeout_to_regval(timeout);
-       if (regval < 0) {
-               dev_err(&wdt->pdev->dev,
-                       "failed to convert timeout (%d) to register value\n",
-                       timeout);
-               return regval;
-       }
-
-       if (mutex_lock_interruptible(&wdt->lock))
-               return -ERESTARTSYS;
+       struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
 
-       if ((wdt->flags & TS72XX_WDT_BUSY_FLAG) != 0) {
-               mutex_unlock(&wdt->lock);
-               return -EBUSY;
-       }
-
-       wdt->flags = TS72XX_WDT_BUSY_FLAG;
-       wdt->regval = regval;
-       file->private_data = wdt;
-
-       ts72xx_wdt_start(wdt);
+       writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg);
 
-       mutex_unlock(&wdt->lock);
-       return nonseekable_open(inode, file);
+       return 0;
 }
 
-static int ts72xx_wdt_release(struct inode *inode, struct file *file)
+static int ts72xx_wdt_settimeout(struct watchdog_device *wdd, unsigned int to)
 {
-       struct ts72xx_wdt *wdt = file->private_data;
-
-       if (mutex_lock_interruptible(&wdt->lock))
-               return -ERESTARTSYS;
-
-       if ((wdt->flags & TS72XX_WDT_EXPECT_CLOSE_FLAG) != 0) {
-               ts72xx_wdt_stop(wdt);
+       struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+       if (to == 1) {
+               priv->regval = TS72XX_WDT_CTRL_1SEC;
+       } else if (to == 2) {
+               priv->regval = TS72XX_WDT_CTRL_2SEC;
+       } else if (to <= 4) {
+               priv->regval = TS72XX_WDT_CTRL_4SEC;
+               to = 4;
        } else {
-               dev_warn(&wdt->pdev->dev,
-                        "TS-72XX WDT device closed unexpectly. "
-                        "Watchdog timer will not stop!\n");
-               /*
-                * Kick it one more time, to give userland some time
-                * to recover (for example, respawning the kicker
-                * daemon).
-                */
-               ts72xx_wdt_kick(wdt);
+               priv->regval = TS72XX_WDT_CTRL_8SEC;
+               if (to <= 8)
+                       to = 8;
        }
 
-       wdt->flags = 0;
+       wdd->timeout = to;
 
-       mutex_unlock(&wdt->lock);
-       return 0;
-}
-
-static ssize_t ts72xx_wdt_write(struct file *file,
-                               const char __user *data,
-                               size_t len,
-                               loff_t *ppos)
-{
-       struct ts72xx_wdt *wdt = file->private_data;
-
-       if (!len)
-               return 0;
-
-       if (mutex_lock_interruptible(&wdt->lock))
-               return -ERESTARTSYS;
-
-       ts72xx_wdt_kick(wdt);
-
-       /*
-        * Support for magic character closing. User process
-        * writes 'V' into the device, just before it is closed.
-        * This means that we know that the wdt timer can be
-        * stopped after user closes the device.
-        */
-       if (!nowayout) {
-               int i;
-
-               for (i = 0; i < len; i++) {
-                       char c;
-
-                       /* In case it was set long ago */
-                       wdt->flags &= ~TS72XX_WDT_EXPECT_CLOSE_FLAG;
-
-                       if (get_user(c, data + i)) {
-                               mutex_unlock(&wdt->lock);
-                               return -EFAULT;
-                       }
-                       if (c == 'V') {
-                               wdt->flags |= TS72XX_WDT_EXPECT_CLOSE_FLAG;
-                               break;
-                       }
-               }
+       if (watchdog_active(wdd)) {
+               ts72xx_wdt_stop(wdd);
+               ts72xx_wdt_start(wdd);
        }
 
-       mutex_unlock(&wdt->lock);
-       return len;
+       return 0;
 }
 
-static const struct watchdog_info winfo = {
-       .options                = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+static const struct watchdog_info ts72xx_wdt_ident = {
+       .options                = WDIOF_KEEPALIVEPING |
+                                 WDIOF_SETTIMEOUT |
                                  WDIOF_MAGICCLOSE,
        .firmware_version       = 1,
        .identity               = "TS-72XX WDT",
 };
 
-static long ts72xx_wdt_ioctl(struct file *file, unsigned int cmd,
-                            unsigned long arg)
-{
-       struct ts72xx_wdt *wdt = file->private_data;
-       void __user *argp = (void __user *)arg;
-       int __user *p = (int __user *)argp;
-       int error = 0;
-
-       if (mutex_lock_interruptible(&wdt->lock))
-               return -ERESTARTSYS;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               if (copy_to_user(argp, &winfo, sizeof(winfo)))
-                       error = -EFAULT;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               error = put_user(0, p);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               ts72xx_wdt_kick(wdt);
-               break;
-
-       case WDIOC_SETOPTIONS: {
-               int options;
-
-               error = get_user(options, p);
-               if (error)
-                       break;
-
-               error = -EINVAL;
-
-               if ((options & WDIOS_DISABLECARD) != 0) {
-                       ts72xx_wdt_stop(wdt);
-                       error = 0;
-               }
-               if ((options & WDIOS_ENABLECARD) != 0) {
-                       ts72xx_wdt_start(wdt);
-                       error = 0;
-               }
-
-               break;
-       }
-
-       case WDIOC_SETTIMEOUT: {
-               int new_timeout;
-               int regval;
-
-               error = get_user(new_timeout, p);
-               if (error)
-                       break;
-
-               regval = timeout_to_regval(new_timeout);
-               if (regval < 0) {
-                       error = regval;
-                       break;
-               }
-               ts72xx_wdt_stop(wdt);
-               wdt->regval = regval;
-               ts72xx_wdt_start(wdt);
-
-               /*FALLTHROUGH*/
-       }
-
-       case WDIOC_GETTIMEOUT:
-               error = put_user(regval_to_timeout(wdt->regval), p);
-               break;
-
-       default:
-               error = -ENOTTY;
-               break;
-       }
-
-       mutex_unlock(&wdt->lock);
-       return error;
-}
-
-static const struct file_operations ts72xx_wdt_fops = {
+static struct watchdog_ops ts72xx_wdt_ops = {
        .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .open           = ts72xx_wdt_open,
-       .release        = ts72xx_wdt_release,
-       .write          = ts72xx_wdt_write,
-       .unlocked_ioctl = ts72xx_wdt_ioctl,
-};
-
-static struct miscdevice ts72xx_wdt_miscdev = {
-       .minor          = WATCHDOG_MINOR,
-       .name           = "watchdog",
-       .fops           = &ts72xx_wdt_fops,
+       .start          = ts72xx_wdt_start,
+       .stop           = ts72xx_wdt_stop,
+       .ping           = ts72xx_wdt_ping,
+       .set_timeout    = ts72xx_wdt_settimeout,
 };
 
 static int ts72xx_wdt_probe(struct platform_device *pdev)
 {
-       struct ts72xx_wdt *wdt;
-       struct resource *r1, *r2;
-       int error = 0;
+       struct ts72xx_wdt_priv *priv;
+       struct watchdog_device *wdd;
+       struct resource *res;
+       int ret;
 
-       wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL);
-       if (!wdt)
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
                return -ENOMEM;
 
-       r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1);
-       if (IS_ERR(wdt->control_reg))
-               return PTR_ERR(wdt->control_reg);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       priv->control_reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->control_reg))
+               return PTR_ERR(priv->control_reg);
 
-       r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2);
-       if (IS_ERR(wdt->feed_reg))
-               return PTR_ERR(wdt->feed_reg);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       priv->feed_reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->feed_reg))
+               return PTR_ERR(priv->feed_reg);
 
-       platform_set_drvdata(pdev, wdt);
-       ts72xx_wdt_pdev = pdev;
-       wdt->pdev = pdev;
-       mutex_init(&wdt->lock);
+       wdd = &priv->wdd;
+       wdd->info = &ts72xx_wdt_ident;
+       wdd->ops = &ts72xx_wdt_ops;
+       wdd->min_timeout = 1;
+       wdd->max_hw_heartbeat_ms = 8000;
+       wdd->parent = &pdev->dev;
 
-       /* make sure that the watchdog is disabled */
-       ts72xx_wdt_stop(wdt);
+       watchdog_set_nowayout(wdd, nowayout);
 
-       error = misc_register(&ts72xx_wdt_miscdev);
-       if (error) {
-               dev_err(&pdev->dev, "failed to register miscdev\n");
-               return error;
-       }
+       wdd->timeout = TS72XX_WDT_DEFAULT_TIMEOUT;
+       watchdog_init_timeout(wdd, timeout, &pdev->dev);
 
-       dev_info(&pdev->dev, "TS-72xx Watchdog driver\n");
+       watchdog_set_drvdata(wdd, priv);
 
-       return 0;
-}
+       ret = devm_watchdog_register_device(&pdev->dev, wdd);
+       if (ret)
+               return ret;
+
+       dev_info(&pdev->dev, "TS-72xx Watchdog driver\n");
 
-static int ts72xx_wdt_remove(struct platform_device *pdev)
-{
-       misc_deregister(&ts72xx_wdt_miscdev);
        return 0;
 }
 
 static struct platform_driver ts72xx_wdt_driver = {
        .probe          = ts72xx_wdt_probe,
-       .remove         = ts72xx_wdt_remove,
        .driver         = {
                .name   = "ts72xx-wdt",
        },
index ef2ecaf53a147e54ca96c862b43e4c87e59903b6..98fd186c6878833c830b7a45779789912c0c7973 100644 (file)
@@ -297,7 +297,7 @@ static unsigned int wdt_get_time(struct watchdog_device *wdog)
  *     Kernel Interfaces
  */
 
-static struct watchdog_info wdt_info = {
+static const struct watchdog_info wdt_info = {
        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
        .identity = "W83627HF Watchdog",
 };
index 32930a073a12744b6d6cf1bcc0b154effea431ab..d5d2bbd8f428565357bb6e2f44be6adc9fa84701 100644 (file)
@@ -987,6 +987,11 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
        wdd->wd_data = NULL;
        mutex_unlock(&wd_data->lock);
 
+       if (watchdog_active(wdd) &&
+           test_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status)) {
+               watchdog_stop(wdd);
+       }
+
        cancel_delayed_work_sync(&wd_data->work);
 
        kref_put(&wd_data->kref, watchdog_core_data_release);
index 8d1184aee932e064240eba56195b812e32229f6e..1ddc1f742cd4fff66f2e3dd96f60de2fc2b24606 100644 (file)
@@ -194,7 +194,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
        if (ret < 0) {
                dev_err(wm831x->dev, "Failed to read watchdog status: %d\n",
                        ret);
-               goto err;
+               return ret;
        }
        reg = ret;
 
@@ -203,10 +203,8 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
 
        driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data),
                                   GFP_KERNEL);
-       if (!driver_data) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (!driver_data)
+               return -ENOMEM;
 
        mutex_init(&driver_data->lock);
        driver_data->wm831x = wm831x;
@@ -253,7 +251,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
                                dev_err(wm831x->dev,
                                        "Failed to request update GPIO: %d\n",
                                        ret);
-                               goto err;
+                               return ret;
                        }
 
                        driver_data->update_gpio = pdata->update_gpio;
@@ -269,37 +267,22 @@ static int wm831x_wdt_probe(struct platform_device *pdev)
                } else {
                        dev_err(wm831x->dev,
                                "Failed to unlock security key: %d\n", ret);
-                       goto err;
+                       return ret;
                }
        }
 
-       ret = watchdog_register_device(&driver_data->wdt);
+       ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt);
        if (ret != 0) {
                dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n",
                        ret);
-               goto err;
+               return ret;
        }
 
-       platform_set_drvdata(pdev, driver_data);
-
-       return 0;
-
-err:
-       return ret;
-}
-
-static int wm831x_wdt_remove(struct platform_device *pdev)
-{
-       struct wm831x_wdt_drvdata *driver_data = platform_get_drvdata(pdev);
-
-       watchdog_unregister_device(&driver_data->wdt);
-
        return 0;
 }
 
 static struct platform_driver wm831x_wdt_driver = {
        .probe = wm831x_wdt_probe,
-       .remove = wm831x_wdt_remove,
        .driver = {
                .name = "wm831x-watchdog",
        },
diff --git a/drivers/watchdog/zx2967_wdt.c b/drivers/watchdog/zx2967_wdt.c
new file mode 100644 (file)
index 0000000..e290d5a
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * watchdog driver for ZTE's zx2967 family
+ *
+ * Copyright (C) 2017 ZTE Ltd.
+ *
+ * Author: Baoyou Xie <baoyou.xie@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/watchdog.h>
+
+#define ZX2967_WDT_CFG_REG                     0x4
+#define ZX2967_WDT_LOAD_REG                    0x8
+#define ZX2967_WDT_REFRESH_REG                 0x18
+#define ZX2967_WDT_START_REG                   0x1c
+
+#define ZX2967_WDT_REFRESH_MASK                        GENMASK(5, 0)
+
+#define ZX2967_WDT_CFG_DIV(n)                  ((((n) & 0xff) - 1) << 8)
+#define ZX2967_WDT_START_EN                    0x1
+
+/*
+ * Hardware magic number.
+ * When watchdog reg is written, the lowest 16 bits are valid, but
+ * the highest 16 bits should be always this number.
+ */
+#define ZX2967_WDT_WRITEKEY                    (0x1234 << 16)
+#define ZX2967_WDT_VAL_MASK                    GENMASK(15, 0)
+
+#define ZX2967_WDT_DIV_DEFAULT                 16
+#define ZX2967_WDT_DEFAULT_TIMEOUT             32
+#define ZX2967_WDT_MIN_TIMEOUT                 1
+#define ZX2967_WDT_MAX_TIMEOUT                 524
+#define ZX2967_WDT_MAX_COUNT                   0xffff
+
+#define ZX2967_WDT_CLK_FREQ                    0x8000
+
+#define ZX2967_WDT_FLAG_REBOOT_MON             BIT(0)
+
+struct zx2967_wdt {
+       struct watchdog_device  wdt_device;
+       void __iomem            *reg_base;
+       struct clk              *clock;
+};
+
+static inline u32 zx2967_wdt_readl(struct zx2967_wdt *wdt, u16 reg)
+{
+       return readl_relaxed(wdt->reg_base + reg);
+}
+
+static inline void zx2967_wdt_writel(struct zx2967_wdt *wdt, u16 reg, u32 val)
+{
+       writel_relaxed(val | ZX2967_WDT_WRITEKEY, wdt->reg_base + reg);
+}
+
+static void zx2967_wdt_refresh(struct zx2967_wdt *wdt)
+{
+       u32 val;
+
+       val = zx2967_wdt_readl(wdt, ZX2967_WDT_REFRESH_REG);
+       /*
+        * Bit 4-5, 1 and 2: refresh config info
+        * Bit 2-3, 1 and 2: refresh counter
+        * Bit 0-1, 1 and 2: refresh int-value
+        * we shift each group value between 1 and 2 to refresh all data.
+        */
+       val ^= ZX2967_WDT_REFRESH_MASK;
+       zx2967_wdt_writel(wdt, ZX2967_WDT_REFRESH_REG,
+                         val & ZX2967_WDT_VAL_MASK);
+}
+
+static int
+zx2967_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
+{
+       struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd);
+       unsigned int divisor = ZX2967_WDT_DIV_DEFAULT;
+       u32 count;
+
+       count = timeout * ZX2967_WDT_CLK_FREQ;
+       if (count > divisor * ZX2967_WDT_MAX_COUNT)
+               divisor = DIV_ROUND_UP(count, ZX2967_WDT_MAX_COUNT);
+       count = DIV_ROUND_UP(count, divisor);
+       zx2967_wdt_writel(wdt, ZX2967_WDT_CFG_REG,
+                       ZX2967_WDT_CFG_DIV(divisor) & ZX2967_WDT_VAL_MASK);
+       zx2967_wdt_writel(wdt, ZX2967_WDT_LOAD_REG,
+                       count & ZX2967_WDT_VAL_MASK);
+       zx2967_wdt_refresh(wdt);
+       wdd->timeout =  (count * divisor) / ZX2967_WDT_CLK_FREQ;
+
+       return 0;
+}
+
+static void __zx2967_wdt_start(struct zx2967_wdt *wdt)
+{
+       u32 val;
+
+       val = zx2967_wdt_readl(wdt, ZX2967_WDT_START_REG);
+       val |= ZX2967_WDT_START_EN;
+       zx2967_wdt_writel(wdt, ZX2967_WDT_START_REG,
+                       val & ZX2967_WDT_VAL_MASK);
+}
+
+static void __zx2967_wdt_stop(struct zx2967_wdt *wdt)
+{
+       u32 val;
+
+       val = zx2967_wdt_readl(wdt, ZX2967_WDT_START_REG);
+       val &= ~ZX2967_WDT_START_EN;
+       zx2967_wdt_writel(wdt, ZX2967_WDT_START_REG,
+                       val & ZX2967_WDT_VAL_MASK);
+}
+
+static int zx2967_wdt_start(struct watchdog_device *wdd)
+{
+       struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       zx2967_wdt_set_timeout(wdd, wdd->timeout);
+       __zx2967_wdt_start(wdt);
+
+       return 0;
+}
+
+static int zx2967_wdt_stop(struct watchdog_device *wdd)
+{
+       struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       __zx2967_wdt_stop(wdt);
+
+       return 0;
+}
+
+static int zx2967_wdt_keepalive(struct watchdog_device *wdd)
+{
+       struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       zx2967_wdt_refresh(wdt);
+
+       return 0;
+}
+
+#define ZX2967_WDT_OPTIONS \
+       (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE)
+static const struct watchdog_info zx2967_wdt_ident = {
+       .options          =     ZX2967_WDT_OPTIONS,
+       .identity         =     "zx2967 watchdog",
+};
+
+static struct watchdog_ops zx2967_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = zx2967_wdt_start,
+       .stop = zx2967_wdt_stop,
+       .ping = zx2967_wdt_keepalive,
+       .set_timeout = zx2967_wdt_set_timeout,
+};
+
+static void zx2967_wdt_reset_sysctrl(struct device *dev)
+{
+       int ret;
+       void __iomem *regmap;
+       unsigned int offset, mask, config;
+       struct of_phandle_args out_args;
+
+       ret = of_parse_phandle_with_fixed_args(dev->of_node,
+                       "zte,wdt-reset-sysctrl", 3, 0, &out_args);
+       if (ret)
+               return;
+
+       offset = out_args.args[0];
+       config = out_args.args[1];
+       mask = out_args.args[2];
+
+       regmap = syscon_node_to_regmap(out_args.np);
+       if (IS_ERR(regmap)) {
+               of_node_put(out_args.np);
+               return;
+       }
+
+       regmap_update_bits(regmap, offset, mask, config);
+       of_node_put(out_args.np);
+}
+
+static int zx2967_wdt_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct zx2967_wdt *wdt;
+       struct resource *base;
+       int ret;
+       struct reset_control *rstc;
+
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, wdt);
+
+       wdt->wdt_device.info = &zx2967_wdt_ident;
+       wdt->wdt_device.ops = &zx2967_wdt_ops;
+       wdt->wdt_device.timeout = ZX2967_WDT_DEFAULT_TIMEOUT;
+       wdt->wdt_device.max_timeout = ZX2967_WDT_MAX_TIMEOUT;
+       wdt->wdt_device.min_timeout = ZX2967_WDT_MIN_TIMEOUT;
+       wdt->wdt_device.parent = &pdev->dev;
+
+       base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdt->reg_base = devm_ioremap_resource(dev, base);
+       if (IS_ERR(wdt->reg_base)) {
+               dev_err(dev, "ioremap failed\n");
+               return PTR_ERR(wdt->reg_base);
+       }
+
+       zx2967_wdt_reset_sysctrl(dev);
+
+       wdt->clock = devm_clk_get(dev, NULL);
+       if (IS_ERR(wdt->clock)) {
+               dev_err(dev, "failed to find watchdog clock source\n");
+               return PTR_ERR(wdt->clock);
+       }
+
+       ret = clk_prepare_enable(wdt->clock);
+       if (ret < 0) {
+               dev_err(dev, "failed to enable clock\n");
+               return ret;
+       }
+       clk_set_rate(wdt->clock, ZX2967_WDT_CLK_FREQ);
+
+       rstc = devm_reset_control_get(dev, NULL);
+       if (IS_ERR(rstc)) {
+               dev_err(dev, "failed to get rstc");
+               ret = PTR_ERR(rstc);
+               goto err;
+       }
+
+       reset_control_assert(rstc);
+       reset_control_deassert(rstc);
+
+       watchdog_set_drvdata(&wdt->wdt_device, wdt);
+       watchdog_init_timeout(&wdt->wdt_device,
+                       ZX2967_WDT_DEFAULT_TIMEOUT, dev);
+       watchdog_set_nowayout(&wdt->wdt_device, WATCHDOG_NOWAYOUT);
+
+       ret = watchdog_register_device(&wdt->wdt_device);
+       if (ret)
+               goto err;
+
+       dev_info(dev, "watchdog enabled (timeout=%d sec, nowayout=%d)",
+                wdt->wdt_device.timeout, WATCHDOG_NOWAYOUT);
+
+       return 0;
+
+err:
+       clk_disable_unprepare(wdt->clock);
+       return ret;
+}
+
+static int zx2967_wdt_remove(struct platform_device *pdev)
+{
+       struct zx2967_wdt *wdt = platform_get_drvdata(pdev);
+
+       watchdog_unregister_device(&wdt->wdt_device);
+       clk_disable_unprepare(wdt->clock);
+
+       return 0;
+}
+
+static const struct of_device_id zx2967_wdt_match[] = {
+       { .compatible = "zte,zx296718-wdt", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, zx2967_wdt_match);
+
+static struct platform_driver zx2967_wdt_driver = {
+       .probe          = zx2967_wdt_probe,
+       .remove         = zx2967_wdt_remove,
+       .driver         = {
+               .name   = "zx2967-wdt",
+               .of_match_table = of_match_ptr(zx2967_wdt_match),
+       },
+};
+module_platform_driver(zx2967_wdt_driver);
+
+MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
+MODULE_DESCRIPTION("ZTE zx2967 Watchdog Device Driver");
+MODULE_LICENSE("GPL v2");
index 35a4d8185b51cd83492743c043aea3ffa1eca9f9..a786e5e8973bff15e47c91b5ba8abbcf7e1bf4c8 100644 (file)
@@ -117,6 +117,7 @@ struct watchdog_device {
 #define WDOG_NO_WAY_OUT                1       /* Is 'nowayout' feature set ? */
 #define WDOG_STOP_ON_REBOOT    2       /* Should be stopped on reboot */
 #define WDOG_HW_RUNNING                3       /* True if HW watchdog running */
+#define WDOG_STOP_ON_UNREGISTER        4       /* Should be stopped on unregister */
        struct list_head deferred;
 };
 
@@ -151,6 +152,12 @@ static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd)
        set_bit(WDOG_STOP_ON_REBOOT, &wdd->status);
 }
 
+/* Use the following function to stop the watchdog when unregistering it */
+static inline void watchdog_stop_on_unregister(struct watchdog_device *wdd)
+{
+       set_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status);
+}
+
 /* Use the following function to check if a timeout value is invalid */
 static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t)
 {