diff options
57 files changed, 1536 insertions, 1243 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt b/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt new file mode 100644 index 000000000000..bc4b865d178b --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/cortina,gemin-watchdog.txt | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | Cortina Systems Gemini SoC Watchdog | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible : must be "cortina,gemini-watchdog" | ||
| 5 | - reg : shall contain base register location and length | ||
| 6 | - interrupts : shall contain the interrupt for the watchdog | ||
| 7 | |||
| 8 | Optional properties: | ||
| 9 | - timeout-sec : the default watchdog timeout in seconds. | ||
| 10 | |||
| 11 | Example: | ||
| 12 | |||
| 13 | watchdog@41000000 { | ||
| 14 | compatible = "cortina,gemini-watchdog"; | ||
| 15 | reg = <0x41000000 0x1000>; | ||
| 16 | interrupts = <3 IRQ_TYPE_LEVEL_HIGH>; | ||
| 17 | }; | ||
diff --git a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt index 8f3d96af81d7..1f6e101e299a 100644 --- a/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/samsung-wdt.txt | |||
| @@ -6,10 +6,11 @@ occurred. | |||
| 6 | 6 | ||
| 7 | Required properties: | 7 | Required properties: |
| 8 | - compatible : should be one among the following | 8 | - compatible : should be one among the following |
| 9 | (a) "samsung,s3c2410-wdt" for Exynos4 and previous SoCs | 9 | - "samsung,s3c2410-wdt" for S3C2410 |
| 10 | (b) "samsung,exynos5250-wdt" for Exynos5250 | 10 | - "samsung,s3c6410-wdt" for S3C6410, S5PV210 and Exynos4 |
| 11 | (c) "samsung,exynos5420-wdt" for Exynos5420 | 11 | - "samsung,exynos5250-wdt" for Exynos5250 |
| 12 | (c) "samsung,exynos7-wdt" for Exynos7 | 12 | - "samsung,exynos5420-wdt" for Exynos5420 |
| 13 | - "samsung,exynos7-wdt" for Exynos7 | ||
| 13 | 14 | ||
| 14 | - reg : base physical address of the controller and length of memory mapped | 15 | - reg : base physical address of the controller and length of memory mapped |
| 15 | region. | 16 | 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 index 000000000000..06ce67766756 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/zte,zx2967-wdt.txt | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | ZTE zx2967 Watchdog timer | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - compatible : should be one of the following. | ||
| 6 | * zte,zx296718-wdt | ||
| 7 | - reg : Specifies base physical address and size of the registers. | ||
| 8 | - clocks : Pairs of phandle and specifier referencing the controller's clocks. | ||
| 9 | - resets : Reference to the reset controller controlling the watchdog | ||
| 10 | controller. | ||
| 11 | |||
| 12 | Optional properties: | ||
| 13 | |||
| 14 | - timeout-sec : Contains the watchdog timeout in seconds. | ||
| 15 | - zte,wdt-reset-sysctrl : Directs how to reset system by the watchdog. | ||
| 16 | if we don't want to restart system when watchdog been triggered, | ||
| 17 | it's not required, vice versa. | ||
| 18 | It should include following fields. | ||
| 19 | * phandle of aon-sysctrl. | ||
| 20 | * offset of register that be written, should be 0xb0. | ||
| 21 | * configure value that be written to aon-sysctrl. | ||
| 22 | * bit mask, corresponding bits will be affected. | ||
| 23 | |||
| 24 | Example: | ||
| 25 | |||
| 26 | wdt: watchdog@1465000 { | ||
| 27 | compatible = "zte,zx296718-wdt"; | ||
| 28 | reg = <0x1465000 0x1000>; | ||
| 29 | clocks = <&topcrm WDT_WCLK>; | ||
| 30 | resets = <&toprst 35>; | ||
| 31 | zte,wdt-reset-sysctrl = <&aon_sysctrl 0xb0 1 0x115>; | ||
| 32 | }; | ||
diff --git a/Documentation/watchdog/watchdog-kernel-api.txt b/Documentation/watchdog/watchdog-kernel-api.txt index ea277478982f..9b93953f69cf 100644 --- a/Documentation/watchdog/watchdog-kernel-api.txt +++ b/Documentation/watchdog/watchdog-kernel-api.txt | |||
| @@ -280,6 +280,12 @@ To disable the watchdog on reboot, the user must call the following helper: | |||
| 280 | 280 | ||
| 281 | static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd); | 281 | static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd); |
| 282 | 282 | ||
| 283 | To disable the watchdog when unregistering the watchdog, the user must call | ||
| 284 | the following helper. Note that this will only stop the watchdog if the | ||
| 285 | nowayout flag is not set. | ||
| 286 | |||
| 287 | static inline void watchdog_stop_on_unregister(struct watchdog_device *wdd); | ||
| 288 | |||
| 283 | To change the priority of the restart handler the following helper should be | 289 | To change the priority of the restart handler the following helper should be |
| 284 | used: | 290 | used: |
| 285 | 291 | ||
diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt index e21850e270a0..4f7d86dd0a5d 100644 --- a/Documentation/watchdog/watchdog-parameters.txt +++ b/Documentation/watchdog/watchdog-parameters.txt | |||
| @@ -209,6 +209,11 @@ timeout: Initial watchdog timeout in seconds (0<timeout<516, default=60) | |||
| 209 | nowayout: Watchdog cannot be stopped once started | 209 | nowayout: Watchdog cannot be stopped once started |
| 210 | (default=kernel config parameter) | 210 | (default=kernel config parameter) |
| 211 | ------------------------------------------------- | 211 | ------------------------------------------------- |
| 212 | nic7018_wdt: | ||
| 213 | timeout: Initial watchdog timeout in seconds (0<timeout<464, default=80) | ||
| 214 | nowayout: Watchdog cannot be stopped once started | ||
| 215 | (default=kernel config parameter) | ||
| 216 | ------------------------------------------------- | ||
| 212 | nuc900_wdt: | 217 | nuc900_wdt: |
| 213 | heartbeat: Watchdog heartbeats in seconds. | 218 | heartbeat: Watchdog heartbeats in seconds. |
| 214 | (default = 15) | 219 | (default = 15) |
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index acb00b53a520..c831b7967bf9 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
| @@ -71,9 +71,17 @@ config SOFT_WATCHDOG | |||
| 71 | To compile this driver as a module, choose M here: the | 71 | To compile this driver as a module, choose M here: the |
| 72 | module will be called softdog. | 72 | module will be called softdog. |
| 73 | 73 | ||
| 74 | config SOFT_WATCHDOG_PRETIMEOUT | ||
| 75 | bool "Software watchdog pretimeout governor support" | ||
| 76 | depends on SOFT_WATCHDOG && WATCHDOG_PRETIMEOUT_GOV | ||
| 77 | help | ||
| 78 | Enable this if you want to use pretimeout governors with the software | ||
| 79 | watchdog. Be aware that governors might affect the watchdog because it | ||
| 80 | is purely software, e.g. the panic governor will stall it! | ||
| 81 | |||
| 74 | config DA9052_WATCHDOG | 82 | config DA9052_WATCHDOG |
| 75 | tristate "Dialog DA9052 Watchdog" | 83 | tristate "Dialog DA9052 Watchdog" |
| 76 | depends on PMIC_DA9052 | 84 | depends on PMIC_DA9052 || COMPILE_TEST |
| 77 | select WATCHDOG_CORE | 85 | select WATCHDOG_CORE |
| 78 | help | 86 | help |
| 79 | Support for the watchdog in the DA9052 PMIC. Watchdog trigger | 87 | Support for the watchdog in the DA9052 PMIC. Watchdog trigger |
| @@ -85,7 +93,7 @@ config DA9052_WATCHDOG | |||
| 85 | 93 | ||
| 86 | config DA9055_WATCHDOG | 94 | config DA9055_WATCHDOG |
| 87 | tristate "Dialog Semiconductor DA9055 Watchdog" | 95 | tristate "Dialog Semiconductor DA9055 Watchdog" |
| 88 | depends on MFD_DA9055 | 96 | depends on MFD_DA9055 || COMPILE_TEST |
| 89 | select WATCHDOG_CORE | 97 | select WATCHDOG_CORE |
| 90 | help | 98 | help |
| 91 | If you say yes here you get support for watchdog on the Dialog | 99 | If you say yes here you get support for watchdog on the Dialog |
| @@ -96,7 +104,7 @@ config DA9055_WATCHDOG | |||
| 96 | 104 | ||
| 97 | config DA9063_WATCHDOG | 105 | config DA9063_WATCHDOG |
| 98 | tristate "Dialog DA9063 Watchdog" | 106 | tristate "Dialog DA9063 Watchdog" |
| 99 | depends on MFD_DA9063 | 107 | depends on MFD_DA9063 || COMPILE_TEST |
| 100 | select WATCHDOG_CORE | 108 | select WATCHDOG_CORE |
| 101 | help | 109 | help |
| 102 | Support for the watchdog in the DA9063 PMIC. | 110 | Support for the watchdog in the DA9063 PMIC. |
| @@ -105,7 +113,7 @@ config DA9063_WATCHDOG | |||
| 105 | 113 | ||
| 106 | config DA9062_WATCHDOG | 114 | config DA9062_WATCHDOG |
| 107 | tristate "Dialog DA9062/61 Watchdog" | 115 | tristate "Dialog DA9062/61 Watchdog" |
| 108 | depends on MFD_DA9062 | 116 | depends on MFD_DA9062 || COMPILE_TEST |
| 109 | select WATCHDOG_CORE | 117 | select WATCHDOG_CORE |
| 110 | help | 118 | help |
| 111 | Support for the watchdog in the DA9062 and DA9061 PMICs. | 119 | Support for the watchdog in the DA9062 and DA9061 PMICs. |
| @@ -133,7 +141,7 @@ config GPIO_WATCHDOG_ARCH_INITCALL | |||
| 133 | 141 | ||
| 134 | config MENF21BMC_WATCHDOG | 142 | config MENF21BMC_WATCHDOG |
| 135 | tristate "MEN 14F021P00 BMC Watchdog" | 143 | tristate "MEN 14F021P00 BMC Watchdog" |
| 136 | depends on MFD_MENF21BMC | 144 | depends on MFD_MENF21BMC || COMPILE_TEST |
| 137 | select WATCHDOG_CORE | 145 | select WATCHDOG_CORE |
| 138 | help | 146 | help |
| 139 | Say Y here to include support for the MEN 14F021P00 BMC Watchdog. | 147 | Say Y here to include support for the MEN 14F021P00 BMC Watchdog. |
| @@ -168,7 +176,7 @@ config WDAT_WDT | |||
| 168 | 176 | ||
| 169 | config WM831X_WATCHDOG | 177 | config WM831X_WATCHDOG |
| 170 | tristate "WM831x watchdog" | 178 | tristate "WM831x watchdog" |
| 171 | depends on MFD_WM831X | 179 | depends on MFD_WM831X || COMPILE_TEST |
| 172 | select WATCHDOG_CORE | 180 | select WATCHDOG_CORE |
| 173 | help | 181 | help |
| 174 | Support for the watchdog in the WM831x AudioPlus PMICs. When | 182 | Support for the watchdog in the WM831x AudioPlus PMICs. When |
| @@ -209,7 +217,7 @@ config ZIIRAVE_WATCHDOG | |||
| 209 | 217 | ||
| 210 | config ARM_SP805_WATCHDOG | 218 | config ARM_SP805_WATCHDOG |
| 211 | tristate "ARM SP805 Watchdog" | 219 | tristate "ARM SP805 Watchdog" |
| 212 | depends on (ARM || ARM64) && ARM_AMBA | 220 | depends on (ARM || ARM64) && (ARM_AMBA || COMPILE_TEST) |
| 213 | select WATCHDOG_CORE | 221 | select WATCHDOG_CORE |
| 214 | help | 222 | help |
| 215 | ARM Primecell SP805 Watchdog timer. This will reboot your system when | 223 | ARM Primecell SP805 Watchdog timer. This will reboot your system when |
| @@ -237,7 +245,7 @@ config ARM_SBSA_WATCHDOG | |||
| 237 | 245 | ||
| 238 | config ASM9260_WATCHDOG | 246 | config ASM9260_WATCHDOG |
| 239 | tristate "Alphascale ASM9260 watchdog" | 247 | tristate "Alphascale ASM9260 watchdog" |
| 240 | depends on MACH_ASM9260 | 248 | depends on MACH_ASM9260 || COMPILE_TEST |
| 241 | depends on OF | 249 | depends on OF |
| 242 | select WATCHDOG_CORE | 250 | select WATCHDOG_CORE |
| 243 | select RESET_CONTROLLER | 251 | select RESET_CONTROLLER |
| @@ -247,14 +255,14 @@ config ASM9260_WATCHDOG | |||
| 247 | 255 | ||
| 248 | config AT91RM9200_WATCHDOG | 256 | config AT91RM9200_WATCHDOG |
| 249 | tristate "AT91RM9200 watchdog" | 257 | tristate "AT91RM9200 watchdog" |
| 250 | depends on SOC_AT91RM9200 && MFD_SYSCON | 258 | depends on (SOC_AT91RM9200 && MFD_SYSCON) || COMPILE_TEST |
| 251 | help | 259 | help |
| 252 | Watchdog timer embedded into AT91RM9200 chips. This will reboot your | 260 | Watchdog timer embedded into AT91RM9200 chips. This will reboot your |
| 253 | system when the timeout is reached. | 261 | system when the timeout is reached. |
| 254 | 262 | ||
| 255 | config AT91SAM9X_WATCHDOG | 263 | config AT91SAM9X_WATCHDOG |
| 256 | tristate "AT91SAM9X / AT91CAP9 watchdog" | 264 | tristate "AT91SAM9X / AT91CAP9 watchdog" |
| 257 | depends on ARCH_AT91 | 265 | depends on ARCH_AT91 || COMPILE_TEST |
| 258 | select WATCHDOG_CORE | 266 | select WATCHDOG_CORE |
| 259 | help | 267 | help |
| 260 | Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will | 268 | Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will |
| @@ -262,7 +270,7 @@ config AT91SAM9X_WATCHDOG | |||
| 262 | 270 | ||
| 263 | config SAMA5D4_WATCHDOG | 271 | config SAMA5D4_WATCHDOG |
| 264 | tristate "Atmel SAMA5D4 Watchdog Timer" | 272 | tristate "Atmel SAMA5D4 Watchdog Timer" |
| 265 | depends on ARCH_AT91 | 273 | depends on ARCH_AT91 || COMPILE_TEST |
| 266 | select WATCHDOG_CORE | 274 | select WATCHDOG_CORE |
| 267 | help | 275 | help |
| 268 | Atmel SAMA5D4 watchdog timer is embedded into SAMA5D4 chips. | 276 | Atmel SAMA5D4 watchdog timer is embedded into SAMA5D4 chips. |
| @@ -293,7 +301,7 @@ config 21285_WATCHDOG | |||
| 293 | 301 | ||
| 294 | config 977_WATCHDOG | 302 | config 977_WATCHDOG |
| 295 | tristate "NetWinder WB83C977 watchdog" | 303 | tristate "NetWinder WB83C977 watchdog" |
| 296 | depends on FOOTBRIDGE && ARCH_NETWINDER | 304 | depends on (FOOTBRIDGE && ARCH_NETWINDER) || (ARM && COMPILE_TEST) |
| 297 | help | 305 | help |
| 298 | Say Y here to include support for the WB977 watchdog included in | 306 | Say Y here to include support for the WB977 watchdog included in |
| 299 | NetWinder machines. Alternatively say M to compile the driver as | 307 | NetWinder machines. Alternatively say M to compile the driver as |
| @@ -301,6 +309,17 @@ config 977_WATCHDOG | |||
| 301 | 309 | ||
| 302 | Not sure? It's safe to say N. | 310 | Not sure? It's safe to say N. |
| 303 | 311 | ||
| 312 | config GEMINI_WATCHDOG | ||
| 313 | tristate "Gemini watchdog" | ||
| 314 | depends on ARCH_GEMINI | ||
| 315 | select WATCHDOG_CORE | ||
| 316 | help | ||
| 317 | Say Y here if to include support for the watchdog timer | ||
| 318 | embedded in the Cortina Systems Gemini family of devices. | ||
| 319 | |||
| 320 | To compile this driver as a module, choose M here: the | ||
| 321 | module will be called gemini_wdt. | ||
| 322 | |||
| 304 | config IXP4XX_WATCHDOG | 323 | config IXP4XX_WATCHDOG |
| 305 | tristate "IXP4xx Watchdog" | 324 | tristate "IXP4xx Watchdog" |
| 306 | depends on ARCH_IXP4XX | 325 | depends on ARCH_IXP4XX |
| @@ -333,9 +352,9 @@ config HAVE_S3C2410_WATCHDOG | |||
| 333 | 352 | ||
| 334 | config S3C2410_WATCHDOG | 353 | config S3C2410_WATCHDOG |
| 335 | tristate "S3C2410 Watchdog" | 354 | tristate "S3C2410 Watchdog" |
| 336 | depends on HAVE_S3C2410_WATCHDOG | 355 | depends on HAVE_S3C2410_WATCHDOG || COMPILE_TEST |
| 337 | select WATCHDOG_CORE | 356 | select WATCHDOG_CORE |
| 338 | select MFD_SYSCON if ARCH_EXYNOS5 | 357 | select MFD_SYSCON if ARCH_EXYNOS |
| 339 | help | 358 | help |
| 340 | Watchdog timer block in the Samsung SoCs. This will reboot | 359 | Watchdog timer block in the Samsung SoCs. This will reboot |
| 341 | the system when the timer expires with the watchdog enabled. | 360 | the system when the timer expires with the watchdog enabled. |
| @@ -372,7 +391,7 @@ config DW_WATCHDOG | |||
| 372 | 391 | ||
| 373 | config EP93XX_WATCHDOG | 392 | config EP93XX_WATCHDOG |
| 374 | tristate "EP93xx Watchdog" | 393 | tristate "EP93xx Watchdog" |
| 375 | depends on ARCH_EP93XX | 394 | depends on ARCH_EP93XX || COMPILE_TEST |
| 376 | select WATCHDOG_CORE | 395 | select WATCHDOG_CORE |
| 377 | help | 396 | help |
| 378 | Say Y here if to include support for the watchdog timer | 397 | Say Y here if to include support for the watchdog timer |
| @@ -383,7 +402,7 @@ config EP93XX_WATCHDOG | |||
| 383 | 402 | ||
| 384 | config OMAP_WATCHDOG | 403 | config OMAP_WATCHDOG |
| 385 | tristate "OMAP Watchdog" | 404 | tristate "OMAP Watchdog" |
| 386 | depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS | 405 | depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || COMPILE_TEST |
| 387 | select WATCHDOG_CORE | 406 | select WATCHDOG_CORE |
| 388 | help | 407 | help |
| 389 | Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y' | 408 | Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y' |
| @@ -419,7 +438,7 @@ config IOP_WATCHDOG | |||
| 419 | 438 | ||
| 420 | config DAVINCI_WATCHDOG | 439 | config DAVINCI_WATCHDOG |
| 421 | tristate "DaVinci watchdog" | 440 | tristate "DaVinci watchdog" |
| 422 | depends on ARCH_DAVINCI || ARCH_KEYSTONE | 441 | depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST |
| 423 | select WATCHDOG_CORE | 442 | select WATCHDOG_CORE |
| 424 | help | 443 | help |
| 425 | Say Y here if to include support for the watchdog timer | 444 | Say Y here if to include support for the watchdog timer |
| @@ -432,7 +451,7 @@ config DAVINCI_WATCHDOG | |||
| 432 | 451 | ||
| 433 | config ORION_WATCHDOG | 452 | config ORION_WATCHDOG |
| 434 | tristate "Orion watchdog" | 453 | tristate "Orion watchdog" |
| 435 | depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU | 454 | depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU || COMPILE_TEST |
| 436 | depends on ARM | 455 | depends on ARM |
| 437 | select WATCHDOG_CORE | 456 | select WATCHDOG_CORE |
| 438 | help | 457 | help |
| @@ -443,7 +462,7 @@ config ORION_WATCHDOG | |||
| 443 | 462 | ||
| 444 | config RN5T618_WATCHDOG | 463 | config RN5T618_WATCHDOG |
| 445 | tristate "Ricoh RN5T618 watchdog" | 464 | tristate "Ricoh RN5T618 watchdog" |
| 446 | depends on MFD_RN5T618 | 465 | depends on MFD_RN5T618 || COMPILE_TEST |
| 447 | select WATCHDOG_CORE | 466 | select WATCHDOG_CORE |
| 448 | help | 467 | help |
| 449 | If you say yes here you get support for watchdog on the Ricoh | 468 | If you say yes here you get support for watchdog on the Ricoh |
| @@ -454,7 +473,7 @@ config RN5T618_WATCHDOG | |||
| 454 | 473 | ||
| 455 | config SUNXI_WATCHDOG | 474 | config SUNXI_WATCHDOG |
| 456 | tristate "Allwinner SoCs watchdog support" | 475 | tristate "Allwinner SoCs watchdog support" |
| 457 | depends on ARCH_SUNXI | 476 | depends on ARCH_SUNXI || COMPILE_TEST |
| 458 | select WATCHDOG_CORE | 477 | select WATCHDOG_CORE |
| 459 | help | 478 | help |
| 460 | Say Y here to include support for the watchdog timer | 479 | Say Y here to include support for the watchdog timer |
| @@ -464,7 +483,7 @@ config SUNXI_WATCHDOG | |||
| 464 | 483 | ||
| 465 | config COH901327_WATCHDOG | 484 | config COH901327_WATCHDOG |
| 466 | bool "ST-Ericsson COH 901 327 watchdog" | 485 | bool "ST-Ericsson COH 901 327 watchdog" |
| 467 | depends on ARCH_U300 | 486 | depends on ARCH_U300 || (ARM && COMPILE_TEST) |
| 468 | default y if MACH_U300 | 487 | default y if MACH_U300 |
| 469 | select WATCHDOG_CORE | 488 | select WATCHDOG_CORE |
| 470 | help | 489 | help |
| @@ -483,7 +502,7 @@ config TWL4030_WATCHDOG | |||
| 483 | 502 | ||
| 484 | config STMP3XXX_RTC_WATCHDOG | 503 | config STMP3XXX_RTC_WATCHDOG |
| 485 | tristate "Freescale STMP3XXX & i.MX23/28 watchdog" | 504 | tristate "Freescale STMP3XXX & i.MX23/28 watchdog" |
| 486 | depends on RTC_DRV_STMP | 505 | depends on RTC_DRV_STMP || COMPILE_TEST |
| 487 | select WATCHDOG_CORE | 506 | select WATCHDOG_CORE |
| 488 | help | 507 | help |
| 489 | Say Y here to include support for the watchdog timer inside | 508 | Say Y here to include support for the watchdog timer inside |
| @@ -493,7 +512,7 @@ config STMP3XXX_RTC_WATCHDOG | |||
| 493 | 512 | ||
| 494 | config NUC900_WATCHDOG | 513 | config NUC900_WATCHDOG |
| 495 | tristate "Nuvoton NUC900 watchdog" | 514 | tristate "Nuvoton NUC900 watchdog" |
| 496 | depends on ARCH_W90X900 | 515 | depends on ARCH_W90X900 || COMPILE_TEST |
| 497 | help | 516 | help |
| 498 | Say Y here if to include support for the watchdog timer | 517 | Say Y here if to include support for the watchdog timer |
| 499 | for the Nuvoton NUC900 series SoCs. | 518 | for the Nuvoton NUC900 series SoCs. |
| @@ -513,7 +532,7 @@ config TS4800_WATCHDOG | |||
| 513 | 532 | ||
| 514 | config TS72XX_WATCHDOG | 533 | config TS72XX_WATCHDOG |
| 515 | tristate "TS-72XX SBC Watchdog" | 534 | tristate "TS-72XX SBC Watchdog" |
| 516 | depends on MACH_TS72XX | 535 | depends on MACH_TS72XX || COMPILE_TEST |
| 517 | help | 536 | help |
| 518 | Technologic Systems TS-7200, TS-7250 and TS-7260 boards have | 537 | Technologic Systems TS-7200, TS-7250 and TS-7260 boards have |
| 519 | watchdog timer implemented in a external CPLD chip. Say Y here | 538 | watchdog timer implemented in a external CPLD chip. Say Y here |
| @@ -531,7 +550,7 @@ config MAX63XX_WATCHDOG | |||
| 531 | 550 | ||
| 532 | config MAX77620_WATCHDOG | 551 | config MAX77620_WATCHDOG |
| 533 | tristate "Maxim Max77620 Watchdog Timer" | 552 | tristate "Maxim Max77620 Watchdog Timer" |
| 534 | depends on MFD_MAX77620 | 553 | depends on MFD_MAX77620 || COMPILE_TEST |
| 535 | help | 554 | help |
| 536 | This is the driver for the Max77620 watchdog timer. | 555 | This is the driver for the Max77620 watchdog timer. |
| 537 | Say 'Y' here to enable the watchdog timer support for | 556 | Say 'Y' here to enable the watchdog timer support for |
| @@ -540,7 +559,7 @@ config MAX77620_WATCHDOG | |||
| 540 | 559 | ||
| 541 | config IMX2_WDT | 560 | config IMX2_WDT |
| 542 | tristate "IMX2+ Watchdog" | 561 | tristate "IMX2+ Watchdog" |
| 543 | depends on ARCH_MXC || ARCH_LAYERSCAPE | 562 | depends on ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST |
| 544 | select REGMAP_MMIO | 563 | select REGMAP_MMIO |
| 545 | select WATCHDOG_CORE | 564 | select WATCHDOG_CORE |
| 546 | help | 565 | help |
| @@ -554,7 +573,7 @@ config IMX2_WDT | |||
| 554 | 573 | ||
| 555 | config UX500_WATCHDOG | 574 | config UX500_WATCHDOG |
| 556 | tristate "ST-Ericsson Ux500 watchdog" | 575 | tristate "ST-Ericsson Ux500 watchdog" |
| 557 | depends on MFD_DB8500_PRCMU | 576 | depends on MFD_DB8500_PRCMU || (ARM && COMPILE_TEST) |
| 558 | select WATCHDOG_CORE | 577 | select WATCHDOG_CORE |
| 559 | default y | 578 | default y |
| 560 | help | 579 | help |
| @@ -566,7 +585,7 @@ config UX500_WATCHDOG | |||
| 566 | 585 | ||
| 567 | config RETU_WATCHDOG | 586 | config RETU_WATCHDOG |
| 568 | tristate "Retu watchdog" | 587 | tristate "Retu watchdog" |
| 569 | depends on MFD_RETU | 588 | depends on MFD_RETU || COMPILE_TEST |
| 570 | select WATCHDOG_CORE | 589 | select WATCHDOG_CORE |
| 571 | help | 590 | help |
| 572 | Retu watchdog driver for Nokia Internet Tablets (770, N800, | 591 | Retu watchdog driver for Nokia Internet Tablets (770, N800, |
| @@ -578,7 +597,7 @@ config RETU_WATCHDOG | |||
| 578 | 597 | ||
| 579 | config MOXART_WDT | 598 | config MOXART_WDT |
| 580 | tristate "MOXART watchdog" | 599 | tristate "MOXART watchdog" |
| 581 | depends on ARCH_MOXART | 600 | depends on ARCH_MOXART || COMPILE_TEST |
| 582 | help | 601 | help |
| 583 | Say Y here to include Watchdog timer support for the watchdog | 602 | Say Y here to include Watchdog timer support for the watchdog |
| 584 | existing on the MOXA ART SoC series platforms. | 603 | existing on the MOXA ART SoC series platforms. |
| @@ -588,7 +607,7 @@ config MOXART_WDT | |||
| 588 | 607 | ||
| 589 | config SIRFSOC_WATCHDOG | 608 | config SIRFSOC_WATCHDOG |
| 590 | tristate "SiRFSOC watchdog" | 609 | tristate "SiRFSOC watchdog" |
| 591 | depends on ARCH_SIRF | 610 | depends on ARCH_SIRF || COMPILE_TEST |
| 592 | select WATCHDOG_CORE | 611 | select WATCHDOG_CORE |
| 593 | default y | 612 | default y |
| 594 | help | 613 | help |
| @@ -597,7 +616,7 @@ config SIRFSOC_WATCHDOG | |||
| 597 | 616 | ||
| 598 | config ST_LPC_WATCHDOG | 617 | config ST_LPC_WATCHDOG |
| 599 | tristate "STMicroelectronics LPC Watchdog" | 618 | tristate "STMicroelectronics LPC Watchdog" |
| 600 | depends on ARCH_STI | 619 | depends on ARCH_STI || COMPILE_TEST |
| 601 | depends on OF | 620 | depends on OF |
| 602 | select WATCHDOG_CORE | 621 | select WATCHDOG_CORE |
| 603 | help | 622 | help |
| @@ -621,7 +640,7 @@ config TEGRA_WATCHDOG | |||
| 621 | config QCOM_WDT | 640 | config QCOM_WDT |
| 622 | tristate "QCOM watchdog" | 641 | tristate "QCOM watchdog" |
| 623 | depends on HAS_IOMEM | 642 | depends on HAS_IOMEM |
| 624 | depends on ARCH_QCOM | 643 | depends on ARCH_QCOM || COMPILE_TEST |
| 625 | select WATCHDOG_CORE | 644 | select WATCHDOG_CORE |
| 626 | help | 645 | help |
| 627 | Say Y here to include Watchdog timer support for the watchdog found | 646 | Say Y here to include Watchdog timer support for the watchdog found |
| @@ -633,7 +652,7 @@ config QCOM_WDT | |||
| 633 | 652 | ||
| 634 | config MESON_GXBB_WATCHDOG | 653 | config MESON_GXBB_WATCHDOG |
| 635 | tristate "Amlogic Meson GXBB SoCs watchdog support" | 654 | tristate "Amlogic Meson GXBB SoCs watchdog support" |
| 636 | depends on ARCH_MESON | 655 | depends on ARCH_MESON || COMPILE_TEST |
| 637 | select WATCHDOG_CORE | 656 | select WATCHDOG_CORE |
| 638 | help | 657 | help |
| 639 | Say Y here to include support for the watchdog timer | 658 | Say Y here to include support for the watchdog timer |
| @@ -643,7 +662,7 @@ config MESON_GXBB_WATCHDOG | |||
| 643 | 662 | ||
| 644 | config MESON_WATCHDOG | 663 | config MESON_WATCHDOG |
| 645 | tristate "Amlogic Meson SoCs watchdog support" | 664 | tristate "Amlogic Meson SoCs watchdog support" |
| 646 | depends on ARCH_MESON | 665 | depends on ARCH_MESON || COMPILE_TEST |
| 647 | select WATCHDOG_CORE | 666 | select WATCHDOG_CORE |
| 648 | help | 667 | help |
| 649 | Say Y here to include support for the watchdog timer | 668 | Say Y here to include support for the watchdog timer |
| @@ -653,7 +672,7 @@ config MESON_WATCHDOG | |||
| 653 | 672 | ||
| 654 | config MEDIATEK_WATCHDOG | 673 | config MEDIATEK_WATCHDOG |
| 655 | tristate "Mediatek SoCs watchdog support" | 674 | tristate "Mediatek SoCs watchdog support" |
| 656 | depends on ARCH_MEDIATEK | 675 | depends on ARCH_MEDIATEK || COMPILE_TEST |
| 657 | select WATCHDOG_CORE | 676 | select WATCHDOG_CORE |
| 658 | help | 677 | help |
| 659 | Say Y here to include support for the watchdog timer | 678 | Say Y here to include support for the watchdog timer |
| @@ -663,7 +682,7 @@ config MEDIATEK_WATCHDOG | |||
| 663 | 682 | ||
| 664 | config DIGICOLOR_WATCHDOG | 683 | config DIGICOLOR_WATCHDOG |
| 665 | tristate "Conexant Digicolor SoCs watchdog support" | 684 | tristate "Conexant Digicolor SoCs watchdog support" |
| 666 | depends on ARCH_DIGICOLOR | 685 | depends on ARCH_DIGICOLOR || COMPILE_TEST |
| 667 | select WATCHDOG_CORE | 686 | select WATCHDOG_CORE |
| 668 | help | 687 | help |
| 669 | Say Y here to include support for the watchdog timer | 688 | Say Y here to include support for the watchdog timer |
| @@ -685,7 +704,7 @@ config LPC18XX_WATCHDOG | |||
| 685 | 704 | ||
| 686 | config ATLAS7_WATCHDOG | 705 | config ATLAS7_WATCHDOG |
| 687 | tristate "CSRatlas7 watchdog" | 706 | tristate "CSRatlas7 watchdog" |
| 688 | depends on ARCH_ATLAS7 | 707 | depends on ARCH_ATLAS7 || COMPILE_TEST |
| 689 | help | 708 | help |
| 690 | Say Y here to include Watchdog timer support for the watchdog | 709 | Say Y here to include Watchdog timer support for the watchdog |
| 691 | existing on the CSRatlas7 series platforms. | 710 | existing on the CSRatlas7 series platforms. |
| @@ -714,11 +733,21 @@ config ASPEED_WATCHDOG | |||
| 714 | To compile this driver as a module, choose M here: the | 733 | To compile this driver as a module, choose M here: the |
| 715 | module will be called aspeed_wdt. | 734 | module will be called aspeed_wdt. |
| 716 | 735 | ||
| 736 | config ZX2967_WATCHDOG | ||
| 737 | tristate "ZTE zx2967 SoCs watchdog support" | ||
| 738 | depends on ARCH_ZX | ||
| 739 | select WATCHDOG_CORE | ||
| 740 | help | ||
| 741 | Say Y here to include support for the watchdog timer | ||
| 742 | in ZTE zx2967 SoCs. | ||
| 743 | To compile this driver as a module, choose M here: the | ||
| 744 | module will be called zx2967_wdt. | ||
| 745 | |||
| 717 | # AVR32 Architecture | 746 | # AVR32 Architecture |
| 718 | 747 | ||
| 719 | config AT32AP700X_WDT | 748 | config AT32AP700X_WDT |
| 720 | tristate "AT32AP700x watchdog" | 749 | tristate "AT32AP700x watchdog" |
| 721 | depends on CPU_AT32AP700X | 750 | depends on CPU_AT32AP700X || COMPILE_TEST |
| 722 | help | 751 | help |
| 723 | Watchdog timer embedded into AT32AP700x devices. This will reboot | 752 | Watchdog timer embedded into AT32AP700x devices. This will reboot |
| 724 | your system when the timeout is reached. | 753 | your system when the timeout is reached. |
| @@ -822,7 +851,7 @@ config SP5100_TCO | |||
| 822 | 851 | ||
| 823 | config GEODE_WDT | 852 | config GEODE_WDT |
| 824 | tristate "AMD Geode CS5535/CS5536 Watchdog" | 853 | tristate "AMD Geode CS5535/CS5536 Watchdog" |
| 825 | depends on CS5535_MFGPT | 854 | depends on CS5535_MFGPT || (X86 && COMPILE_TEST) |
| 826 | help | 855 | help |
| 827 | This driver enables a watchdog capability built into the | 856 | This driver enables a watchdog capability built into the |
| 828 | CS5535/CS5536 companion chips for the AMD Geode GX and LX | 857 | CS5535/CS5536 companion chips for the AMD Geode GX and LX |
| @@ -835,7 +864,7 @@ config GEODE_WDT | |||
| 835 | 864 | ||
| 836 | config SC520_WDT | 865 | config SC520_WDT |
| 837 | tristate "AMD Elan SC520 processor Watchdog" | 866 | tristate "AMD Elan SC520 processor Watchdog" |
| 838 | depends on MELAN | 867 | depends on MELAN || COMPILE_TEST |
| 839 | help | 868 | help |
| 840 | This is the driver for the hardware watchdog built in to the | 869 | This is the driver for the hardware watchdog built in to the |
| 841 | AMD "Elan" SC520 microcomputer commonly used in embedded systems. | 870 | AMD "Elan" SC520 microcomputer commonly used in embedded systems. |
| @@ -1034,7 +1063,7 @@ config HP_WATCHDOG | |||
| 1034 | 1063 | ||
| 1035 | config KEMPLD_WDT | 1064 | config KEMPLD_WDT |
| 1036 | tristate "Kontron COM Watchdog Timer" | 1065 | tristate "Kontron COM Watchdog Timer" |
| 1037 | depends on MFD_KEMPLD | 1066 | depends on MFD_KEMPLD || COMPILE_TEST |
| 1038 | select WATCHDOG_CORE | 1067 | select WATCHDOG_CORE |
| 1039 | help | 1068 | help |
| 1040 | Support for the PLD watchdog on some Kontron ETX and COMexpress | 1069 | Support for the PLD watchdog on some Kontron ETX and COMexpress |
| @@ -1108,7 +1137,8 @@ config NV_TCO | |||
| 1108 | 1137 | ||
| 1109 | config RDC321X_WDT | 1138 | config RDC321X_WDT |
| 1110 | tristate "RDC R-321x SoC watchdog" | 1139 | tristate "RDC R-321x SoC watchdog" |
| 1111 | depends on X86_RDC321X | 1140 | depends on X86_RDC321X || COMPILE_TEST |
| 1141 | depends on PCI | ||
| 1112 | help | 1142 | help |
| 1113 | This is the driver for the built in hardware watchdog | 1143 | This is the driver for the built in hardware watchdog |
| 1114 | in the RDC R-321x SoC. | 1144 | in the RDC R-321x SoC. |
| @@ -1326,6 +1356,16 @@ config NI903X_WDT | |||
| 1326 | To compile this driver as a module, choose M here: the module will be | 1356 | To compile this driver as a module, choose M here: the module will be |
| 1327 | called ni903x_wdt. | 1357 | called ni903x_wdt. |
| 1328 | 1358 | ||
| 1359 | config NIC7018_WDT | ||
| 1360 | tristate "NIC7018 Watchdog" | ||
| 1361 | depends on X86 && ACPI | ||
| 1362 | select WATCHDOG_CORE | ||
| 1363 | ---help--- | ||
| 1364 | Support for National Instruments NIC7018 Watchdog. | ||
| 1365 | |||
| 1366 | To compile this driver as a module, choose M here: the module will be | ||
| 1367 | called nic7018_wdt. | ||
| 1368 | |||
| 1329 | # M32R Architecture | 1369 | # M32R Architecture |
| 1330 | 1370 | ||
| 1331 | # M68K Architecture | 1371 | # M68K Architecture |
| @@ -1343,14 +1383,14 @@ config M54xx_WATCHDOG | |||
| 1343 | 1383 | ||
| 1344 | config ATH79_WDT | 1384 | config ATH79_WDT |
| 1345 | tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog" | 1385 | tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog" |
| 1346 | depends on ATH79 | 1386 | depends on ATH79 || (ARM && COMPILE_TEST) |
| 1347 | help | 1387 | help |
| 1348 | Hardware driver for the built-in watchdog timer on the Atheros | 1388 | Hardware driver for the built-in watchdog timer on the Atheros |
| 1349 | AR71XX/AR724X/AR913X SoCs. | 1389 | AR71XX/AR724X/AR913X SoCs. |
| 1350 | 1390 | ||
| 1351 | config BCM47XX_WDT | 1391 | config BCM47XX_WDT |
| 1352 | tristate "Broadcom BCM47xx Watchdog Timer" | 1392 | tristate "Broadcom BCM47xx Watchdog Timer" |
| 1353 | depends on BCM47XX || ARCH_BCM_5301X | 1393 | depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST |
| 1354 | select WATCHDOG_CORE | 1394 | select WATCHDOG_CORE |
| 1355 | help | 1395 | help |
| 1356 | Hardware driver for the Broadcom BCM47xx Watchdog Timer. | 1396 | Hardware driver for the Broadcom BCM47xx Watchdog Timer. |
| @@ -1367,7 +1407,7 @@ config RC32434_WDT | |||
| 1367 | 1407 | ||
| 1368 | config INDYDOG | 1408 | config INDYDOG |
| 1369 | tristate "Indy/I2 Hardware Watchdog" | 1409 | tristate "Indy/I2 Hardware Watchdog" |
| 1370 | depends on SGI_HAS_INDYDOG | 1410 | depends on SGI_HAS_INDYDOG || (MIPS && COMPILE_TEST) |
| 1371 | help | 1411 | help |
| 1372 | Hardware driver for the Indy's/I2's watchdog. This is a | 1412 | Hardware driver for the Indy's/I2's watchdog. This is a |
| 1373 | watchdog timer that will reboot the machine after a 60 second | 1413 | watchdog timer that will reboot the machine after a 60 second |
| @@ -1383,7 +1423,7 @@ config JZ4740_WDT | |||
| 1383 | 1423 | ||
| 1384 | config WDT_MTX1 | 1424 | config WDT_MTX1 |
| 1385 | tristate "MTX-1 Hardware Watchdog" | 1425 | tristate "MTX-1 Hardware Watchdog" |
| 1386 | depends on MIPS_MTX1 | 1426 | depends on MIPS_MTX1 || (MIPS && COMPILE_TEST) |
| 1387 | help | 1427 | help |
| 1388 | Hardware driver for the MTX-1 boards. This is a watchdog timer that | 1428 | Hardware driver for the MTX-1 boards. This is a watchdog timer that |
| 1389 | will reboot the machine after a 100 seconds timer expired. | 1429 | will reboot the machine after a 100 seconds timer expired. |
| @@ -1391,6 +1431,7 @@ config WDT_MTX1 | |||
| 1391 | config PNX833X_WDT | 1431 | config PNX833X_WDT |
| 1392 | tristate "PNX833x Hardware Watchdog" | 1432 | tristate "PNX833x Hardware Watchdog" |
| 1393 | depends on SOC_PNX8335 | 1433 | depends on SOC_PNX8335 |
| 1434 | depends on BROKEN | ||
| 1394 | help | 1435 | help |
| 1395 | Hardware driver for the PNX833x's watchdog. This is a | 1436 | Hardware driver for the PNX833x's watchdog. This is a |
| 1396 | watchdog timer that will reboot the machine after a programmable | 1437 | watchdog timer that will reboot the machine after a programmable |
| @@ -1399,7 +1440,7 @@ config PNX833X_WDT | |||
| 1399 | 1440 | ||
| 1400 | config SIBYTE_WDOG | 1441 | config SIBYTE_WDOG |
| 1401 | tristate "Sibyte SoC hardware watchdog" | 1442 | tristate "Sibyte SoC hardware watchdog" |
| 1402 | depends on CPU_SB1 | 1443 | depends on CPU_SB1 || (MIPS && COMPILE_TEST) |
| 1403 | help | 1444 | help |
| 1404 | Watchdog driver for the built in watchdog hardware in Sibyte | 1445 | Watchdog driver for the built in watchdog hardware in Sibyte |
| 1405 | SoC processors. There are apparently two watchdog timers | 1446 | SoC processors. There are apparently two watchdog timers |
| @@ -1412,13 +1453,13 @@ config SIBYTE_WDOG | |||
| 1412 | 1453 | ||
| 1413 | config AR7_WDT | 1454 | config AR7_WDT |
| 1414 | tristate "TI AR7 Watchdog Timer" | 1455 | tristate "TI AR7 Watchdog Timer" |
| 1415 | depends on AR7 | 1456 | depends on AR7 || (MIPS && COMPILE_TEST) |
| 1416 | help | 1457 | help |
| 1417 | Hardware driver for the TI AR7 Watchdog Timer. | 1458 | Hardware driver for the TI AR7 Watchdog Timer. |
| 1418 | 1459 | ||
| 1419 | config TXX9_WDT | 1460 | config TXX9_WDT |
| 1420 | tristate "Toshiba TXx9 Watchdog Timer" | 1461 | tristate "Toshiba TXx9 Watchdog Timer" |
| 1421 | depends on CPU_TX39XX || CPU_TX49XX | 1462 | depends on CPU_TX39XX || CPU_TX49XX || (MIPS && COMPILE_TEST) |
| 1422 | select WATCHDOG_CORE | 1463 | select WATCHDOG_CORE |
| 1423 | help | 1464 | help |
| 1424 | Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs. | 1465 | Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs. |
| @@ -1454,7 +1495,7 @@ config BCM63XX_WDT | |||
| 1454 | 1495 | ||
| 1455 | config BCM2835_WDT | 1496 | config BCM2835_WDT |
| 1456 | tristate "Broadcom BCM2835 hardware watchdog" | 1497 | tristate "Broadcom BCM2835 hardware watchdog" |
| 1457 | depends on ARCH_BCM2835 | 1498 | depends on ARCH_BCM2835 || COMPILE_TEST |
| 1458 | select WATCHDOG_CORE | 1499 | select WATCHDOG_CORE |
| 1459 | help | 1500 | help |
| 1460 | Watchdog driver for the built in watchdog hardware in Broadcom | 1501 | Watchdog driver for the built in watchdog hardware in Broadcom |
| @@ -1465,7 +1506,7 @@ config BCM2835_WDT | |||
| 1465 | 1506 | ||
| 1466 | config BCM_KONA_WDT | 1507 | config BCM_KONA_WDT |
| 1467 | tristate "BCM Kona Watchdog" | 1508 | tristate "BCM Kona Watchdog" |
| 1468 | depends on ARCH_BCM_MOBILE | 1509 | depends on ARCH_BCM_MOBILE || COMPILE_TEST |
| 1469 | select WATCHDOG_CORE | 1510 | select WATCHDOG_CORE |
| 1470 | help | 1511 | help |
| 1471 | Support for the watchdog timer on the following Broadcom BCM281xx | 1512 | Support for the watchdog timer on the following Broadcom BCM281xx |
| @@ -1477,7 +1518,7 @@ config BCM_KONA_WDT | |||
| 1477 | 1518 | ||
| 1478 | config BCM_KONA_WDT_DEBUG | 1519 | config BCM_KONA_WDT_DEBUG |
| 1479 | bool "DEBUGFS support for BCM Kona Watchdog" | 1520 | bool "DEBUGFS support for BCM Kona Watchdog" |
| 1480 | depends on BCM_KONA_WDT | 1521 | depends on BCM_KONA_WDT || COMPILE_TEST |
| 1481 | help | 1522 | help |
| 1482 | If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides | 1523 | If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides |
| 1483 | access to the driver's internal data structures as well as watchdog | 1524 | access to the driver's internal data structures as well as watchdog |
| @@ -1538,7 +1579,7 @@ config MT7621_WDT | |||
| 1538 | config PIC32_WDT | 1579 | config PIC32_WDT |
| 1539 | tristate "Microchip PIC32 hardware watchdog" | 1580 | tristate "Microchip PIC32 hardware watchdog" |
| 1540 | select WATCHDOG_CORE | 1581 | select WATCHDOG_CORE |
| 1541 | depends on MACH_PIC32 | 1582 | depends on MACH_PIC32 || (MIPS && COMPILE_TEST) |
| 1542 | help | 1583 | help |
| 1543 | Watchdog driver for the built in watchdog hardware in a PIC32. | 1584 | Watchdog driver for the built in watchdog hardware in a PIC32. |
| 1544 | 1585 | ||
| @@ -1551,7 +1592,7 @@ config PIC32_WDT | |||
| 1551 | config PIC32_DMT | 1592 | config PIC32_DMT |
| 1552 | tristate "Microchip PIC32 Deadman Timer" | 1593 | tristate "Microchip PIC32 Deadman Timer" |
| 1553 | select WATCHDOG_CORE | 1594 | select WATCHDOG_CORE |
| 1554 | depends on MACH_PIC32 | 1595 | depends on MACH_PIC32 || (MIPS && COMPILE_TEST) |
| 1555 | help | 1596 | help |
| 1556 | Watchdog driver for PIC32 instruction fetch counting timer. This specific | 1597 | Watchdog driver for PIC32 instruction fetch counting timer. This specific |
| 1557 | timer is typically be used in misson critical and safety critical | 1598 | timer is typically be used in misson critical and safety critical |
| @@ -1573,7 +1614,7 @@ config GEF_WDT | |||
| 1573 | 1614 | ||
| 1574 | config MPC5200_WDT | 1615 | config MPC5200_WDT |
| 1575 | bool "MPC52xx Watchdog Timer" | 1616 | bool "MPC52xx Watchdog Timer" |
| 1576 | depends on PPC_MPC52xx | 1617 | depends on PPC_MPC52xx || COMPILE_TEST |
| 1577 | help | 1618 | help |
| 1578 | Use General Purpose Timer (GPT) 0 on the MPC5200 as Watchdog. | 1619 | Use General Purpose Timer (GPT) 0 on the MPC5200 as Watchdog. |
| 1579 | 1620 | ||
| @@ -1592,11 +1633,11 @@ config 8xxx_WDT | |||
| 1592 | 1633 | ||
| 1593 | config MV64X60_WDT | 1634 | config MV64X60_WDT |
| 1594 | tristate "MV64X60 (Marvell Discovery) Watchdog Timer" | 1635 | tristate "MV64X60 (Marvell Discovery) Watchdog Timer" |
| 1595 | depends on MV64X60 | 1636 | depends on MV64X60 || COMPILE_TEST |
| 1596 | 1637 | ||
| 1597 | config PIKA_WDT | 1638 | config PIKA_WDT |
| 1598 | tristate "PIKA FPGA Watchdog" | 1639 | tristate "PIKA FPGA Watchdog" |
| 1599 | depends on WARP | 1640 | depends on WARP || (PPC64 && COMPILE_TEST) |
| 1600 | default y | 1641 | default y |
| 1601 | help | 1642 | help |
| 1602 | This enables the watchdog in the PIKA FPGA. Currently used on | 1643 | This enables the watchdog in the PIKA FPGA. Currently used on |
| @@ -1646,7 +1687,7 @@ config MEN_A21_WDT | |||
| 1646 | 1687 | ||
| 1647 | config WATCHDOG_RTAS | 1688 | config WATCHDOG_RTAS |
| 1648 | tristate "RTAS watchdog" | 1689 | tristate "RTAS watchdog" |
| 1649 | depends on PPC_RTAS | 1690 | depends on PPC_RTAS || (PPC64 && COMPILE_TEST) |
| 1650 | help | 1691 | help |
| 1651 | This driver adds watchdog support for the RTAS watchdog. | 1692 | This driver adds watchdog support for the RTAS watchdog. |
| 1652 | 1693 | ||
| @@ -1674,7 +1715,7 @@ config DIAG288_WATCHDOG | |||
| 1674 | 1715 | ||
| 1675 | config SH_WDT | 1716 | config SH_WDT |
| 1676 | tristate "SuperH Watchdog" | 1717 | tristate "SuperH Watchdog" |
| 1677 | depends on SUPERH && (CPU_SH3 || CPU_SH4) | 1718 | depends on SUPERH && (CPU_SH3 || CPU_SH4 || COMPILE_TEST) |
| 1678 | select WATCHDOG_CORE | 1719 | select WATCHDOG_CORE |
| 1679 | help | 1720 | help |
| 1680 | This driver adds watchdog support for the integrated watchdog in the | 1721 | This driver adds watchdog support for the integrated watchdog in the |
| @@ -1741,7 +1782,7 @@ config XEN_WDT | |||
| 1741 | 1782 | ||
| 1742 | config UML_WATCHDOG | 1783 | config UML_WATCHDOG |
| 1743 | tristate "UML watchdog" | 1784 | tristate "UML watchdog" |
| 1744 | depends on UML | 1785 | depends on UML || COMPILE_TEST |
| 1745 | 1786 | ||
| 1746 | # | 1787 | # |
| 1747 | # ISA-based Watchdog Cards | 1788 | # ISA-based Watchdog Cards |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 0c3d35e3c334..a2126e2a99ae 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
| @@ -45,6 +45,7 @@ obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o | |||
| 45 | obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o | 45 | obj-$(CONFIG_TWL4030_WATCHDOG) += twl4030_wdt.o |
| 46 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o | 46 | obj-$(CONFIG_21285_WATCHDOG) += wdt285.o |
| 47 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o | 47 | obj-$(CONFIG_977_WATCHDOG) += wdt977.o |
| 48 | obj-$(CONFIG_GEMINI_WATCHDOG) += gemini_wdt.o | ||
| 48 | obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o | 49 | obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o |
| 49 | obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o | 50 | obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o |
| 50 | obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o | 51 | obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o |
| @@ -82,6 +83,7 @@ obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o | |||
| 82 | obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o | 83 | obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o |
| 83 | obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o | 84 | obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o |
| 84 | obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o | 85 | obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o |
| 86 | obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o | ||
| 85 | 87 | ||
| 86 | # AVR32 Architecture | 88 | # AVR32 Architecture |
| 87 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o | 89 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o |
| @@ -139,6 +141,7 @@ obj-$(CONFIG_INTEL_SCU_WATCHDOG) += intel_scu_watchdog.o | |||
| 139 | obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o | 141 | obj-$(CONFIG_INTEL_MID_WATCHDOG) += intel-mid_wdt.o |
| 140 | obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o | 142 | obj-$(CONFIG_INTEL_MEI_WDT) += mei_wdt.o |
| 141 | obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o | 143 | obj-$(CONFIG_NI903X_WDT) += ni903x_wdt.o |
| 144 | obj-$(CONFIG_NIC7018_WDT) += nic7018_wdt.o | ||
| 142 | 145 | ||
| 143 | # M32R Architecture | 146 | # M32R Architecture |
| 144 | 147 | ||
diff --git a/drivers/watchdog/asm9260_wdt.c b/drivers/watchdog/asm9260_wdt.c index d0b59ba0f661..53da001f0838 100644 --- a/drivers/watchdog/asm9260_wdt.c +++ b/drivers/watchdog/asm9260_wdt.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 15 | #include <linux/of.h> | 15 | #include <linux/of.h> |
| 16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 17 | #include <linux/reboot.h> | ||
| 18 | #include <linux/reset.h> | 17 | #include <linux/reset.h> |
| 19 | #include <linux/watchdog.h> | 18 | #include <linux/watchdog.h> |
| 20 | 19 | ||
| @@ -59,7 +58,6 @@ struct asm9260_wdt_priv { | |||
| 59 | struct clk *clk; | 58 | struct clk *clk; |
| 60 | struct clk *clk_ahb; | 59 | struct clk *clk_ahb; |
| 61 | struct reset_control *rst; | 60 | struct reset_control *rst; |
| 62 | struct notifier_block restart_handler; | ||
| 63 | 61 | ||
| 64 | void __iomem *iobase; | 62 | void __iomem *iobase; |
| 65 | int irq; | 63 | int irq; |
| @@ -172,15 +170,14 @@ static irqreturn_t asm9260_wdt_irq(int irq, void *devid) | |||
| 172 | return IRQ_HANDLED; | 170 | return IRQ_HANDLED; |
| 173 | } | 171 | } |
| 174 | 172 | ||
| 175 | static int asm9260_restart_handler(struct notifier_block *this, | 173 | static int asm9260_restart(struct watchdog_device *wdd, unsigned long action, |
| 176 | unsigned long mode, void *cmd) | 174 | void *data) |
| 177 | { | 175 | { |
| 178 | struct asm9260_wdt_priv *priv = | 176 | struct asm9260_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 179 | container_of(this, struct asm9260_wdt_priv, restart_handler); | ||
| 180 | 177 | ||
| 181 | asm9260_wdt_sys_reset(priv); | 178 | asm9260_wdt_sys_reset(priv); |
| 182 | 179 | ||
| 183 | return NOTIFY_DONE; | 180 | return 0; |
| 184 | } | 181 | } |
| 185 | 182 | ||
| 186 | static const struct watchdog_info asm9260_wdt_ident = { | 183 | static const struct watchdog_info asm9260_wdt_ident = { |
| @@ -189,13 +186,14 @@ static const struct watchdog_info asm9260_wdt_ident = { | |||
| 189 | .identity = "Alphascale asm9260 Watchdog", | 186 | .identity = "Alphascale asm9260 Watchdog", |
| 190 | }; | 187 | }; |
| 191 | 188 | ||
| 192 | static struct watchdog_ops asm9260_wdt_ops = { | 189 | static const struct watchdog_ops asm9260_wdt_ops = { |
| 193 | .owner = THIS_MODULE, | 190 | .owner = THIS_MODULE, |
| 194 | .start = asm9260_wdt_enable, | 191 | .start = asm9260_wdt_enable, |
| 195 | .stop = asm9260_wdt_disable, | 192 | .stop = asm9260_wdt_disable, |
| 196 | .get_timeleft = asm9260_wdt_gettimeleft, | 193 | .get_timeleft = asm9260_wdt_gettimeleft, |
| 197 | .ping = asm9260_wdt_feed, | 194 | .ping = asm9260_wdt_feed, |
| 198 | .set_timeout = asm9260_wdt_settimeout, | 195 | .set_timeout = asm9260_wdt_settimeout, |
| 196 | .restart = asm9260_restart, | ||
| 199 | }; | 197 | }; |
| 200 | 198 | ||
| 201 | static int asm9260_wdt_get_dt_clks(struct asm9260_wdt_priv *priv) | 199 | 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) | |||
| 335 | dev_warn(&pdev->dev, "failed to request IRQ\n"); | 333 | dev_warn(&pdev->dev, "failed to request IRQ\n"); |
| 336 | } | 334 | } |
| 337 | 335 | ||
| 336 | watchdog_set_restart_priority(wdd, 128); | ||
| 337 | |||
| 338 | ret = watchdog_register_device(wdd); | 338 | ret = watchdog_register_device(wdd); |
| 339 | if (ret) | 339 | if (ret) |
| 340 | goto clk_off; | 340 | goto clk_off; |
| 341 | 341 | ||
| 342 | platform_set_drvdata(pdev, priv); | 342 | platform_set_drvdata(pdev, priv); |
| 343 | 343 | ||
| 344 | priv->restart_handler.notifier_call = asm9260_restart_handler; | ||
| 345 | priv->restart_handler.priority = 128; | ||
| 346 | ret = register_restart_handler(&priv->restart_handler); | ||
| 347 | if (ret) | ||
| 348 | dev_warn(&pdev->dev, "cannot register restart handler\n"); | ||
| 349 | |||
| 350 | dev_info(&pdev->dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n", | 344 | dev_info(&pdev->dev, "Watchdog enabled (timeout: %d sec, mode: %s)\n", |
| 351 | wdd->timeout, mode_name[priv->mode]); | 345 | wdd->timeout, mode_name[priv->mode]); |
| 352 | return 0; | 346 | return 0; |
| @@ -370,8 +364,6 @@ static int asm9260_wdt_remove(struct platform_device *pdev) | |||
| 370 | 364 | ||
| 371 | asm9260_wdt_disable(&priv->wdd); | 365 | asm9260_wdt_disable(&priv->wdd); |
| 372 | 366 | ||
| 373 | unregister_restart_handler(&priv->restart_handler); | ||
| 374 | |||
| 375 | watchdog_unregister_device(&priv->wdd); | 367 | watchdog_unregister_device(&priv->wdd); |
| 376 | 368 | ||
| 377 | clk_disable_unprepare(priv->clk); | 369 | clk_disable_unprepare(priv->clk); |
diff --git a/drivers/watchdog/aspeed_wdt.c b/drivers/watchdog/aspeed_wdt.c index f5ad8023c2e6..1c652582de40 100644 --- a/drivers/watchdog/aspeed_wdt.c +++ b/drivers/watchdog/aspeed_wdt.c | |||
| @@ -136,15 +136,6 @@ static const struct watchdog_info aspeed_wdt_info = { | |||
| 136 | .identity = KBUILD_MODNAME, | 136 | .identity = KBUILD_MODNAME, |
| 137 | }; | 137 | }; |
| 138 | 138 | ||
| 139 | static int aspeed_wdt_remove(struct platform_device *pdev) | ||
| 140 | { | ||
| 141 | struct aspeed_wdt *wdt = platform_get_drvdata(pdev); | ||
| 142 | |||
| 143 | watchdog_unregister_device(&wdt->wdd); | ||
| 144 | |||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | static int aspeed_wdt_probe(struct platform_device *pdev) | 139 | static int aspeed_wdt_probe(struct platform_device *pdev) |
| 149 | { | 140 | { |
| 150 | struct aspeed_wdt *wdt; | 141 | struct aspeed_wdt *wdt; |
| @@ -187,20 +178,17 @@ static int aspeed_wdt_probe(struct platform_device *pdev) | |||
| 187 | set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); | 178 | set_bit(WDOG_HW_RUNNING, &wdt->wdd.status); |
| 188 | } | 179 | } |
| 189 | 180 | ||
| 190 | ret = watchdog_register_device(&wdt->wdd); | 181 | ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd); |
| 191 | if (ret) { | 182 | if (ret) { |
| 192 | dev_err(&pdev->dev, "failed to register\n"); | 183 | dev_err(&pdev->dev, "failed to register\n"); |
| 193 | return ret; | 184 | return ret; |
| 194 | } | 185 | } |
| 195 | 186 | ||
| 196 | platform_set_drvdata(pdev, wdt); | ||
| 197 | |||
| 198 | return 0; | 187 | return 0; |
| 199 | } | 188 | } |
| 200 | 189 | ||
| 201 | static struct platform_driver aspeed_watchdog_driver = { | 190 | static struct platform_driver aspeed_watchdog_driver = { |
| 202 | .probe = aspeed_wdt_probe, | 191 | .probe = aspeed_wdt_probe, |
| 203 | .remove = aspeed_wdt_remove, | ||
| 204 | .driver = { | 192 | .driver = { |
| 205 | .name = KBUILD_MODNAME, | 193 | .name = KBUILD_MODNAME, |
| 206 | .of_match_table = of_match_ptr(aspeed_wdt_of_table), | 194 | .of_match_table = of_match_ptr(aspeed_wdt_of_table), |
diff --git a/drivers/watchdog/atlas7_wdt.c b/drivers/watchdog/atlas7_wdt.c index ed80734befae..4abdcabd8219 100644 --- a/drivers/watchdog/atlas7_wdt.c +++ b/drivers/watchdog/atlas7_wdt.c | |||
| @@ -105,7 +105,7 @@ static const struct watchdog_info atlas7_wdt_ident = { | |||
| 105 | .identity = "atlas7 Watchdog", | 105 | .identity = "atlas7 Watchdog", |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | static struct watchdog_ops atlas7_wdt_ops = { | 108 | static const struct watchdog_ops atlas7_wdt_ops = { |
| 109 | .owner = THIS_MODULE, | 109 | .owner = THIS_MODULE, |
| 110 | .start = atlas7_wdt_enable, | 110 | .start = atlas7_wdt_enable, |
| 111 | .stop = atlas7_wdt_disable, | 111 | .stop = atlas7_wdt_disable, |
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c index c32c45bd8b09..496f6c106bb1 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
| 17 | #include <linux/reboot.h> | ||
| 18 | #include <linux/types.h> | 17 | #include <linux/types.h> |
| 19 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 20 | #include <linux/io.h> | 19 | #include <linux/io.h> |
| @@ -49,7 +48,6 @@ | |||
| 49 | struct bcm2835_wdt { | 48 | struct bcm2835_wdt { |
| 50 | void __iomem *base; | 49 | void __iomem *base; |
| 51 | spinlock_t lock; | 50 | spinlock_t lock; |
| 52 | struct notifier_block restart_handler; | ||
| 53 | }; | 51 | }; |
| 54 | 52 | ||
| 55 | static unsigned int heartbeat; | 53 | static unsigned int heartbeat; |
| @@ -99,11 +97,37 @@ static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog) | |||
| 99 | return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET); | 97 | return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET); |
| 100 | } | 98 | } |
| 101 | 99 | ||
| 100 | static void __bcm2835_restart(struct bcm2835_wdt *wdt) | ||
| 101 | { | ||
| 102 | u32 val; | ||
| 103 | |||
| 104 | /* use a timeout of 10 ticks (~150us) */ | ||
| 105 | writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG); | ||
| 106 | val = readl_relaxed(wdt->base + PM_RSTC); | ||
| 107 | val &= PM_RSTC_WRCFG_CLR; | ||
| 108 | val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; | ||
| 109 | writel_relaxed(val, wdt->base + PM_RSTC); | ||
| 110 | |||
| 111 | /* No sleeping, possibly atomic. */ | ||
| 112 | mdelay(1); | ||
| 113 | } | ||
| 114 | |||
| 115 | static int bcm2835_restart(struct watchdog_device *wdog, | ||
| 116 | unsigned long action, void *data) | ||
| 117 | { | ||
| 118 | struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog); | ||
| 119 | |||
| 120 | __bcm2835_restart(wdt); | ||
| 121 | |||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 102 | static const struct watchdog_ops bcm2835_wdt_ops = { | 125 | static const struct watchdog_ops bcm2835_wdt_ops = { |
| 103 | .owner = THIS_MODULE, | 126 | .owner = THIS_MODULE, |
| 104 | .start = bcm2835_wdt_start, | 127 | .start = bcm2835_wdt_start, |
| 105 | .stop = bcm2835_wdt_stop, | 128 | .stop = bcm2835_wdt_stop, |
| 106 | .get_timeleft = bcm2835_wdt_get_timeleft, | 129 | .get_timeleft = bcm2835_wdt_get_timeleft, |
| 130 | .restart = bcm2835_restart, | ||
| 107 | }; | 131 | }; |
| 108 | 132 | ||
| 109 | static const struct watchdog_info bcm2835_wdt_info = { | 133 | static const struct watchdog_info bcm2835_wdt_info = { |
| @@ -120,26 +144,6 @@ static struct watchdog_device bcm2835_wdt_wdd = { | |||
| 120 | .timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET), | 144 | .timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET), |
| 121 | }; | 145 | }; |
| 122 | 146 | ||
| 123 | static int | ||
| 124 | bcm2835_restart(struct notifier_block *this, unsigned long mode, void *cmd) | ||
| 125 | { | ||
| 126 | struct bcm2835_wdt *wdt = container_of(this, struct bcm2835_wdt, | ||
| 127 | restart_handler); | ||
| 128 | u32 val; | ||
| 129 | |||
| 130 | /* use a timeout of 10 ticks (~150us) */ | ||
| 131 | writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG); | ||
| 132 | val = readl_relaxed(wdt->base + PM_RSTC); | ||
| 133 | val &= PM_RSTC_WRCFG_CLR; | ||
| 134 | val |= PM_PASSWORD | PM_RSTC_WRCFG_FULL_RESET; | ||
| 135 | writel_relaxed(val, wdt->base + PM_RSTC); | ||
| 136 | |||
| 137 | /* No sleeping, possibly atomic. */ | ||
| 138 | mdelay(1); | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* | 147 | /* |
| 144 | * We can't really power off, but if we do the normal reset scheme, and | 148 | * We can't really power off, but if we do the normal reset scheme, and |
| 145 | * indicate to bootcode.bin not to reboot, then most of the chip will be | 149 | * indicate to bootcode.bin not to reboot, then most of the chip will be |
| @@ -163,13 +167,13 @@ static void bcm2835_power_off(void) | |||
| 163 | writel_relaxed(val, wdt->base + PM_RSTS); | 167 | writel_relaxed(val, wdt->base + PM_RSTS); |
| 164 | 168 | ||
| 165 | /* Continue with normal reset mechanism */ | 169 | /* Continue with normal reset mechanism */ |
| 166 | bcm2835_restart(&wdt->restart_handler, REBOOT_HARD, NULL); | 170 | __bcm2835_restart(wdt); |
| 167 | } | 171 | } |
| 168 | 172 | ||
| 169 | static int bcm2835_wdt_probe(struct platform_device *pdev) | 173 | static int bcm2835_wdt_probe(struct platform_device *pdev) |
| 170 | { | 174 | { |
| 175 | struct resource *res; | ||
| 171 | struct device *dev = &pdev->dev; | 176 | struct device *dev = &pdev->dev; |
| 172 | struct device_node *np = dev->of_node; | ||
| 173 | struct bcm2835_wdt *wdt; | 177 | struct bcm2835_wdt *wdt; |
| 174 | int err; | 178 | int err; |
| 175 | 179 | ||
| @@ -180,16 +184,15 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) | |||
| 180 | 184 | ||
| 181 | spin_lock_init(&wdt->lock); | 185 | spin_lock_init(&wdt->lock); |
| 182 | 186 | ||
| 183 | wdt->base = of_iomap(np, 0); | 187 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 184 | if (!wdt->base) { | 188 | wdt->base = devm_ioremap_resource(dev, res); |
| 185 | dev_err(dev, "Failed to remap watchdog regs"); | 189 | if (IS_ERR(wdt->base)) |
| 186 | return -ENODEV; | 190 | return PTR_ERR(wdt->base); |
| 187 | } | ||
| 188 | 191 | ||
| 189 | watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt); | 192 | watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt); |
| 190 | watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev); | 193 | watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev); |
| 191 | watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout); | 194 | watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout); |
| 192 | bcm2835_wdt_wdd.parent = &pdev->dev; | 195 | bcm2835_wdt_wdd.parent = dev; |
| 193 | if (bcm2835_wdt_is_running(wdt)) { | 196 | if (bcm2835_wdt_is_running(wdt)) { |
| 194 | /* | 197 | /* |
| 195 | * The currently active timeout value (set by the | 198 | * The currently active timeout value (set by the |
| @@ -201,16 +204,16 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) | |||
| 201 | */ | 204 | */ |
| 202 | set_bit(WDOG_HW_RUNNING, &bcm2835_wdt_wdd.status); | 205 | set_bit(WDOG_HW_RUNNING, &bcm2835_wdt_wdd.status); |
| 203 | } | 206 | } |
| 204 | err = watchdog_register_device(&bcm2835_wdt_wdd); | 207 | |
| 208 | watchdog_set_restart_priority(&bcm2835_wdt_wdd, 128); | ||
| 209 | |||
| 210 | watchdog_stop_on_reboot(&bcm2835_wdt_wdd); | ||
| 211 | err = devm_watchdog_register_device(dev, &bcm2835_wdt_wdd); | ||
| 205 | if (err) { | 212 | if (err) { |
| 206 | dev_err(dev, "Failed to register watchdog device"); | 213 | dev_err(dev, "Failed to register watchdog device"); |
| 207 | iounmap(wdt->base); | ||
| 208 | return err; | 214 | return err; |
| 209 | } | 215 | } |
| 210 | 216 | ||
| 211 | wdt->restart_handler.notifier_call = bcm2835_restart; | ||
| 212 | wdt->restart_handler.priority = 128; | ||
| 213 | register_restart_handler(&wdt->restart_handler); | ||
| 214 | if (pm_power_off == NULL) | 217 | if (pm_power_off == NULL) |
| 215 | pm_power_off = bcm2835_power_off; | 218 | pm_power_off = bcm2835_power_off; |
| 216 | 219 | ||
| @@ -220,22 +223,12 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) | |||
| 220 | 223 | ||
| 221 | static int bcm2835_wdt_remove(struct platform_device *pdev) | 224 | static int bcm2835_wdt_remove(struct platform_device *pdev) |
| 222 | { | 225 | { |
| 223 | struct bcm2835_wdt *wdt = platform_get_drvdata(pdev); | ||
| 224 | |||
| 225 | unregister_restart_handler(&wdt->restart_handler); | ||
| 226 | if (pm_power_off == bcm2835_power_off) | 226 | if (pm_power_off == bcm2835_power_off) |
| 227 | pm_power_off = NULL; | 227 | pm_power_off = NULL; |
| 228 | watchdog_unregister_device(&bcm2835_wdt_wdd); | ||
| 229 | iounmap(wdt->base); | ||
| 230 | 228 | ||
| 231 | return 0; | 229 | return 0; |
| 232 | } | 230 | } |
| 233 | 231 | ||
| 234 | static void bcm2835_wdt_shutdown(struct platform_device *pdev) | ||
| 235 | { | ||
| 236 | bcm2835_wdt_stop(&bcm2835_wdt_wdd); | ||
| 237 | } | ||
| 238 | |||
| 239 | static const struct of_device_id bcm2835_wdt_of_match[] = { | 232 | static const struct of_device_id bcm2835_wdt_of_match[] = { |
| 240 | { .compatible = "brcm,bcm2835-pm-wdt", }, | 233 | { .compatible = "brcm,bcm2835-pm-wdt", }, |
| 241 | {}, | 234 | {}, |
| @@ -245,7 +238,6 @@ MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match); | |||
| 245 | static struct platform_driver bcm2835_wdt_driver = { | 238 | static struct platform_driver bcm2835_wdt_driver = { |
| 246 | .probe = bcm2835_wdt_probe, | 239 | .probe = bcm2835_wdt_probe, |
| 247 | .remove = bcm2835_wdt_remove, | 240 | .remove = bcm2835_wdt_remove, |
| 248 | .shutdown = bcm2835_wdt_shutdown, | ||
| 249 | .driver = { | 241 | .driver = { |
| 250 | .name = "bcm2835-wdt", | 242 | .name = "bcm2835-wdt", |
| 251 | .of_match_table = bcm2835_wdt_of_match, | 243 | .of_match_table = bcm2835_wdt_of_match, |
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index a1900b9ab6c4..35725e21b18a 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c | |||
| @@ -226,9 +226,6 @@ static int bcm47xx_wdt_remove(struct platform_device *pdev) | |||
| 226 | { | 226 | { |
| 227 | struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); | 227 | struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); |
| 228 | 228 | ||
| 229 | if (!wdt) | ||
| 230 | return -ENXIO; | ||
| 231 | |||
| 232 | watchdog_unregister_device(&wdt->wdd); | 229 | watchdog_unregister_device(&wdt->wdd); |
| 233 | 230 | ||
| 234 | return 0; | 231 | return 0; |
diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c index 4814c00b32f6..c1b8e534fb55 100644 --- a/drivers/watchdog/bcm7038_wdt.c +++ b/drivers/watchdog/bcm7038_wdt.c | |||
| @@ -101,7 +101,7 @@ static unsigned int bcm7038_wdt_get_timeleft(struct watchdog_device *wdog) | |||
| 101 | return time_left / wdt->rate; | 101 | return time_left / wdt->rate; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | static struct watchdog_info bcm7038_wdt_info = { | 104 | static const struct watchdog_info bcm7038_wdt_info = { |
| 105 | .identity = "Broadcom BCM7038 Watchdog Timer", | 105 | .identity = "Broadcom BCM7038 Watchdog Timer", |
| 106 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | | 106 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | |
| 107 | WDIOF_MAGICCLOSE | 107 | WDIOF_MAGICCLOSE |
diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c index e0c98423f2c9..6fce17d5b9f1 100644 --- a/drivers/watchdog/bcm_kona_wdt.c +++ b/drivers/watchdog/bcm_kona_wdt.c | |||
| @@ -266,7 +266,7 @@ static int bcm_kona_wdt_stop(struct watchdog_device *wdog) | |||
| 266 | SECWDOG_SRSTEN_MASK, 0); | 266 | SECWDOG_SRSTEN_MASK, 0); |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | static struct watchdog_ops bcm_kona_wdt_ops = { | 269 | static const struct watchdog_ops bcm_kona_wdt_ops = { |
| 270 | .owner = THIS_MODULE, | 270 | .owner = THIS_MODULE, |
| 271 | .start = bcm_kona_wdt_start, | 271 | .start = bcm_kona_wdt_start, |
| 272 | .stop = bcm_kona_wdt_stop, | 272 | .stop = bcm_kona_wdt_stop, |
| @@ -274,7 +274,7 @@ static struct watchdog_ops bcm_kona_wdt_ops = { | |||
| 274 | .get_timeleft = bcm_kona_wdt_get_timeleft, | 274 | .get_timeleft = bcm_kona_wdt_get_timeleft, |
| 275 | }; | 275 | }; |
| 276 | 276 | ||
| 277 | static struct watchdog_info bcm_kona_wdt_info = { | 277 | static const struct watchdog_info bcm_kona_wdt_info = { |
| 278 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | | 278 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | |
| 279 | WDIOF_KEEPALIVEPING, | 279 | WDIOF_KEEPALIVEPING, |
| 280 | .identity = "Broadcom Kona Watchdog Timer", | 280 | .identity = "Broadcom Kona Watchdog Timer", |
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index 04da4b66c75e..3ad1e44bef44 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c | |||
| @@ -192,12 +192,12 @@ static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev, | |||
| 192 | return 0; | 192 | return 0; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | static struct watchdog_info booke_wdt_info = { | 195 | static struct watchdog_info booke_wdt_info __ro_after_init = { |
| 196 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 196 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
| 197 | .identity = "PowerPC Book-E Watchdog", | 197 | .identity = "PowerPC Book-E Watchdog", |
| 198 | }; | 198 | }; |
| 199 | 199 | ||
| 200 | static struct watchdog_ops booke_wdt_ops = { | 200 | static const struct watchdog_ops booke_wdt_ops = { |
| 201 | .owner = THIS_MODULE, | 201 | .owner = THIS_MODULE, |
| 202 | .start = booke_wdt_start, | 202 | .start = booke_wdt_start, |
| 203 | .stop = booke_wdt_stop, | 203 | .stop = booke_wdt_stop, |
diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c index 98acef72334d..8d61e8bfe60b 100644 --- a/drivers/watchdog/cadence_wdt.c +++ b/drivers/watchdog/cadence_wdt.c | |||
| @@ -262,7 +262,7 @@ static irqreturn_t cdns_wdt_irq_handler(int irq, void *dev_id) | |||
| 262 | * Info structure used to indicate the features supported by the device | 262 | * Info structure used to indicate the features supported by the device |
| 263 | * to the upper layers. This is defined in watchdog.h header file. | 263 | * to the upper layers. This is defined in watchdog.h header file. |
| 264 | */ | 264 | */ |
| 265 | static struct watchdog_info cdns_wdt_info = { | 265 | static const struct watchdog_info cdns_wdt_info = { |
| 266 | .identity = "cdns_wdt watchdog", | 266 | .identity = "cdns_wdt watchdog", |
| 267 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | | 267 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | |
| 268 | WDIOF_MAGICCLOSE, | 268 | WDIOF_MAGICCLOSE, |
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index a099b77fc0b9..38dd60f0cfcc 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c | |||
| @@ -68,17 +68,10 @@ | |||
| 68 | 68 | ||
| 69 | /* Default timeout in seconds = 1 minute */ | 69 | /* Default timeout in seconds = 1 minute */ |
| 70 | static unsigned int margin = 60; | 70 | static unsigned int margin = 60; |
| 71 | static resource_size_t phybase; | ||
| 72 | static resource_size_t physize; | ||
| 73 | static int irq; | 71 | static int irq; |
| 74 | static void __iomem *virtbase; | 72 | static void __iomem *virtbase; |
| 75 | static struct device *parent; | 73 | static struct device *parent; |
| 76 | 74 | ||
| 77 | /* | ||
| 78 | * The watchdog block is of course always clocked, the | ||
| 79 | * clk_enable()/clk_disable() calls are mainly for performing reference | ||
| 80 | * counting higher up in the clock hierarchy. | ||
| 81 | */ | ||
| 82 | static struct clk *clk; | 75 | static struct clk *clk; |
| 83 | 76 | ||
| 84 | /* | 77 | /* |
| @@ -90,7 +83,6 @@ static void coh901327_enable(u16 timeout) | |||
| 90 | unsigned long freq; | 83 | unsigned long freq; |
| 91 | unsigned long delay_ns; | 84 | unsigned long delay_ns; |
| 92 | 85 | ||
| 93 | clk_enable(clk); | ||
| 94 | /* Restart timer if it is disabled */ | 86 | /* Restart timer if it is disabled */ |
| 95 | val = readw(virtbase + U300_WDOG_D2R); | 87 | val = readw(virtbase + U300_WDOG_D2R); |
| 96 | if (val == U300_WDOG_D2R_DISABLE_STATUS_DISABLED) | 88 | if (val == U300_WDOG_D2R_DISABLE_STATUS_DISABLED) |
| @@ -118,7 +110,6 @@ static void coh901327_enable(u16 timeout) | |||
| 118 | */ | 110 | */ |
| 119 | (void) readw(virtbase + U300_WDOG_CR); | 111 | (void) readw(virtbase + U300_WDOG_CR); |
| 120 | val = readw(virtbase + U300_WDOG_D2R); | 112 | val = readw(virtbase + U300_WDOG_D2R); |
| 121 | clk_disable(clk); | ||
| 122 | if (val != U300_WDOG_D2R_DISABLE_STATUS_ENABLED) | 113 | if (val != U300_WDOG_D2R_DISABLE_STATUS_ENABLED) |
| 123 | dev_err(parent, | 114 | dev_err(parent, |
| 124 | "%s(): watchdog not enabled! D2R value %04x\n", | 115 | "%s(): watchdog not enabled! D2R value %04x\n", |
| @@ -129,7 +120,6 @@ static void coh901327_disable(void) | |||
| 129 | { | 120 | { |
| 130 | u16 val; | 121 | u16 val; |
| 131 | 122 | ||
| 132 | clk_enable(clk); | ||
| 133 | /* Disable the watchdog interrupt if it is active */ | 123 | /* Disable the watchdog interrupt if it is active */ |
| 134 | writew(0x0000U, virtbase + U300_WDOG_IMR); | 124 | writew(0x0000U, virtbase + U300_WDOG_IMR); |
| 135 | /* If the watchdog is currently enabled, attempt to disable it */ | 125 | /* If the watchdog is currently enabled, attempt to disable it */ |
| @@ -144,7 +134,6 @@ static void coh901327_disable(void) | |||
| 144 | virtbase + U300_WDOG_D2R); | 134 | virtbase + U300_WDOG_D2R); |
| 145 | } | 135 | } |
| 146 | val = readw(virtbase + U300_WDOG_D2R); | 136 | val = readw(virtbase + U300_WDOG_D2R); |
| 147 | clk_disable(clk); | ||
| 148 | if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED) | 137 | if (val != U300_WDOG_D2R_DISABLE_STATUS_DISABLED) |
| 149 | dev_err(parent, | 138 | dev_err(parent, |
| 150 | "%s(): watchdog not disabled! D2R value %04x\n", | 139 | "%s(): watchdog not disabled! D2R value %04x\n", |
| @@ -165,11 +154,9 @@ static int coh901327_stop(struct watchdog_device *wdt_dev) | |||
| 165 | 154 | ||
| 166 | static int coh901327_ping(struct watchdog_device *wdd) | 155 | static int coh901327_ping(struct watchdog_device *wdd) |
| 167 | { | 156 | { |
| 168 | clk_enable(clk); | ||
| 169 | /* Feed the watchdog */ | 157 | /* Feed the watchdog */ |
| 170 | writew(U300_WDOG_FR_FEED_RESTART_TIMER, | 158 | writew(U300_WDOG_FR_FEED_RESTART_TIMER, |
| 171 | virtbase + U300_WDOG_FR); | 159 | virtbase + U300_WDOG_FR); |
| 172 | clk_disable(clk); | ||
| 173 | return 0; | 160 | return 0; |
| 174 | } | 161 | } |
| 175 | 162 | ||
| @@ -177,13 +164,11 @@ static int coh901327_settimeout(struct watchdog_device *wdt_dev, | |||
| 177 | unsigned int time) | 164 | unsigned int time) |
| 178 | { | 165 | { |
| 179 | wdt_dev->timeout = time; | 166 | wdt_dev->timeout = time; |
| 180 | clk_enable(clk); | ||
| 181 | /* Set new timeout value */ | 167 | /* Set new timeout value */ |
| 182 | writew(time * 100, virtbase + U300_WDOG_TR); | 168 | writew(time * 100, virtbase + U300_WDOG_TR); |
| 183 | /* Feed the dog */ | 169 | /* Feed the dog */ |
| 184 | writew(U300_WDOG_FR_FEED_RESTART_TIMER, | 170 | writew(U300_WDOG_FR_FEED_RESTART_TIMER, |
| 185 | virtbase + U300_WDOG_FR); | 171 | virtbase + U300_WDOG_FR); |
| 186 | clk_disable(clk); | ||
| 187 | return 0; | 172 | return 0; |
| 188 | } | 173 | } |
| 189 | 174 | ||
| @@ -191,13 +176,11 @@ static unsigned int coh901327_gettimeleft(struct watchdog_device *wdt_dev) | |||
| 191 | { | 176 | { |
| 192 | u16 val; | 177 | u16 val; |
| 193 | 178 | ||
| 194 | clk_enable(clk); | ||
| 195 | /* Read repeatedly until the value is stable! */ | 179 | /* Read repeatedly until the value is stable! */ |
| 196 | val = readw(virtbase + U300_WDOG_CR); | 180 | val = readw(virtbase + U300_WDOG_CR); |
| 197 | while (val & U300_WDOG_CR_VALID_IND) | 181 | while (val & U300_WDOG_CR_VALID_IND) |
| 198 | val = readw(virtbase + U300_WDOG_CR); | 182 | val = readw(virtbase + U300_WDOG_CR); |
| 199 | val &= U300_WDOG_CR_COUNT_VALUE_MASK; | 183 | val &= U300_WDOG_CR_COUNT_VALUE_MASK; |
| 200 | clk_disable(clk); | ||
| 201 | if (val != 0) | 184 | if (val != 0) |
| 202 | val /= 100; | 185 | val /= 100; |
| 203 | 186 | ||
| @@ -221,13 +204,11 @@ static irqreturn_t coh901327_interrupt(int irq, void *data) | |||
| 221 | * to prevent a watchdog reset by feeding the watchdog at this | 204 | * to prevent a watchdog reset by feeding the watchdog at this |
| 222 | * point. | 205 | * point. |
| 223 | */ | 206 | */ |
| 224 | clk_enable(clk); | ||
| 225 | val = readw(virtbase + U300_WDOG_IER); | 207 | val = readw(virtbase + U300_WDOG_IER); |
| 226 | if (val == U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND) | 208 | if (val == U300_WDOG_IER_WILL_BARK_IRQ_EVENT_IND) |
| 227 | writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE, | 209 | writew(U300_WDOG_IER_WILL_BARK_IRQ_ACK_ENABLE, |
| 228 | virtbase + U300_WDOG_IER); | 210 | virtbase + U300_WDOG_IER); |
| 229 | writew(0x0000U, virtbase + U300_WDOG_IMR); | 211 | writew(0x0000U, virtbase + U300_WDOG_IMR); |
| 230 | clk_disable(clk); | ||
| 231 | dev_crit(parent, "watchdog is barking!\n"); | 212 | dev_crit(parent, "watchdog is barking!\n"); |
| 232 | return IRQ_HANDLED; | 213 | return IRQ_HANDLED; |
| 233 | } | 214 | } |
| @@ -263,81 +244,63 @@ static int __exit coh901327_remove(struct platform_device *pdev) | |||
| 263 | watchdog_unregister_device(&coh901327_wdt); | 244 | watchdog_unregister_device(&coh901327_wdt); |
| 264 | coh901327_disable(); | 245 | coh901327_disable(); |
| 265 | free_irq(irq, pdev); | 246 | free_irq(irq, pdev); |
| 266 | clk_unprepare(clk); | 247 | clk_disable_unprepare(clk); |
| 267 | clk_put(clk); | 248 | clk_put(clk); |
| 268 | iounmap(virtbase); | ||
| 269 | release_mem_region(phybase, physize); | ||
| 270 | return 0; | 249 | return 0; |
| 271 | } | 250 | } |
| 272 | 251 | ||
| 273 | static int __init coh901327_probe(struct platform_device *pdev) | 252 | static int __init coh901327_probe(struct platform_device *pdev) |
| 274 | { | 253 | { |
| 254 | struct device *dev = &pdev->dev; | ||
| 275 | int ret; | 255 | int ret; |
| 276 | u16 val; | 256 | u16 val; |
| 277 | struct resource *res; | 257 | struct resource *res; |
| 278 | 258 | ||
| 279 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 259 | parent = dev; |
| 280 | if (!res) | ||
| 281 | return -ENOENT; | ||
| 282 | |||
| 283 | parent = &pdev->dev; | ||
| 284 | physize = resource_size(res); | ||
| 285 | phybase = res->start; | ||
| 286 | 260 | ||
| 287 | if (request_mem_region(phybase, physize, DRV_NAME) == NULL) { | 261 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 288 | ret = -EBUSY; | 262 | virtbase = devm_ioremap_resource(dev, res); |
| 289 | goto out; | 263 | if (IS_ERR(virtbase)) |
| 290 | } | 264 | return PTR_ERR(virtbase); |
| 291 | |||
| 292 | virtbase = ioremap(phybase, physize); | ||
| 293 | if (!virtbase) { | ||
| 294 | ret = -ENOMEM; | ||
| 295 | goto out_no_remap; | ||
| 296 | } | ||
| 297 | 265 | ||
| 298 | clk = clk_get(&pdev->dev, NULL); | 266 | clk = clk_get(dev, NULL); |
| 299 | if (IS_ERR(clk)) { | 267 | if (IS_ERR(clk)) { |
| 300 | ret = PTR_ERR(clk); | 268 | ret = PTR_ERR(clk); |
| 301 | dev_err(&pdev->dev, "could not get clock\n"); | 269 | dev_err(dev, "could not get clock\n"); |
| 302 | goto out_no_clk; | 270 | return ret; |
| 303 | } | 271 | } |
| 304 | ret = clk_prepare_enable(clk); | 272 | ret = clk_prepare_enable(clk); |
| 305 | if (ret) { | 273 | if (ret) { |
| 306 | dev_err(&pdev->dev, "could not prepare and enable clock\n"); | 274 | dev_err(dev, "could not prepare and enable clock\n"); |
| 307 | goto out_no_clk_enable; | 275 | goto out_no_clk_enable; |
| 308 | } | 276 | } |
| 309 | 277 | ||
| 310 | val = readw(virtbase + U300_WDOG_SR); | 278 | val = readw(virtbase + U300_WDOG_SR); |
| 311 | switch (val) { | 279 | switch (val) { |
| 312 | case U300_WDOG_SR_STATUS_TIMED_OUT: | 280 | case U300_WDOG_SR_STATUS_TIMED_OUT: |
| 313 | dev_info(&pdev->dev, | 281 | dev_info(dev, "watchdog timed out since last chip reset!\n"); |
| 314 | "watchdog timed out since last chip reset!\n"); | ||
| 315 | coh901327_wdt.bootstatus |= WDIOF_CARDRESET; | 282 | coh901327_wdt.bootstatus |= WDIOF_CARDRESET; |
| 316 | /* Status will be cleared below */ | 283 | /* Status will be cleared below */ |
| 317 | break; | 284 | break; |
| 318 | case U300_WDOG_SR_STATUS_NORMAL: | 285 | case U300_WDOG_SR_STATUS_NORMAL: |
| 319 | dev_info(&pdev->dev, | 286 | dev_info(dev, "in normal status, no timeouts have occurred.\n"); |
| 320 | "in normal status, no timeouts have occurred.\n"); | ||
| 321 | break; | 287 | break; |
| 322 | default: | 288 | default: |
| 323 | dev_info(&pdev->dev, | 289 | dev_info(dev, "contains an illegal status code (%08x)\n", val); |
| 324 | "contains an illegal status code (%08x)\n", val); | ||
| 325 | break; | 290 | break; |
| 326 | } | 291 | } |
| 327 | 292 | ||
| 328 | val = readw(virtbase + U300_WDOG_D2R); | 293 | val = readw(virtbase + U300_WDOG_D2R); |
| 329 | switch (val) { | 294 | switch (val) { |
| 330 | case U300_WDOG_D2R_DISABLE_STATUS_DISABLED: | 295 | case U300_WDOG_D2R_DISABLE_STATUS_DISABLED: |
| 331 | dev_info(&pdev->dev, "currently disabled.\n"); | 296 | dev_info(dev, "currently disabled.\n"); |
| 332 | break; | 297 | break; |
| 333 | case U300_WDOG_D2R_DISABLE_STATUS_ENABLED: | 298 | case U300_WDOG_D2R_DISABLE_STATUS_ENABLED: |
| 334 | dev_info(&pdev->dev, | 299 | dev_info(dev, "currently enabled! (disabling it now)\n"); |
| 335 | "currently enabled! (disabling it now)\n"); | ||
| 336 | coh901327_disable(); | 300 | coh901327_disable(); |
| 337 | break; | 301 | break; |
| 338 | default: | 302 | default: |
| 339 | dev_err(&pdev->dev, | 303 | dev_err(dev, "contains an illegal enable/disable code (%08x)\n", |
| 340 | "contains an illegal enable/disable code (%08x)\n", | ||
| 341 | val); | 304 | val); |
| 342 | break; | 305 | break; |
| 343 | } | 306 | } |
| @@ -352,20 +315,16 @@ static int __init coh901327_probe(struct platform_device *pdev) | |||
| 352 | goto out_no_irq; | 315 | goto out_no_irq; |
| 353 | } | 316 | } |
| 354 | 317 | ||
| 355 | clk_disable(clk); | 318 | ret = watchdog_init_timeout(&coh901327_wdt, margin, dev); |
| 356 | |||
| 357 | ret = watchdog_init_timeout(&coh901327_wdt, margin, &pdev->dev); | ||
| 358 | if (ret < 0) | 319 | if (ret < 0) |
| 359 | coh901327_wdt.timeout = 60; | 320 | coh901327_wdt.timeout = 60; |
| 360 | 321 | ||
| 361 | coh901327_wdt.parent = &pdev->dev; | 322 | coh901327_wdt.parent = dev; |
| 362 | ret = watchdog_register_device(&coh901327_wdt); | 323 | ret = watchdog_register_device(&coh901327_wdt); |
| 363 | if (ret == 0) | 324 | if (ret) |
| 364 | dev_info(&pdev->dev, | ||
| 365 | "initialized. timer margin=%d sec\n", margin); | ||
| 366 | else | ||
| 367 | goto out_no_wdog; | 325 | goto out_no_wdog; |
| 368 | 326 | ||
| 327 | dev_info(dev, "initialized. timer margin=%d sec\n", margin); | ||
| 369 | return 0; | 328 | return 0; |
| 370 | 329 | ||
| 371 | out_no_wdog: | 330 | out_no_wdog: |
| @@ -374,11 +333,6 @@ out_no_irq: | |||
| 374 | clk_disable_unprepare(clk); | 333 | clk_disable_unprepare(clk); |
| 375 | out_no_clk_enable: | 334 | out_no_clk_enable: |
| 376 | clk_put(clk); | 335 | clk_put(clk); |
| 377 | out_no_clk: | ||
| 378 | iounmap(virtbase); | ||
| 379 | out_no_remap: | ||
| 380 | release_mem_region(phybase, SZ_4K); | ||
| 381 | out: | ||
| 382 | return ret; | 336 | return ret; |
| 383 | } | 337 | } |
| 384 | 338 | ||
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c index 2fc19a32a320..d6d5006efa71 100644 --- a/drivers/watchdog/da9052_wdt.c +++ b/drivers/watchdog/da9052_wdt.c | |||
| @@ -128,19 +128,17 @@ static int da9052_wdt_ping(struct watchdog_device *wdt_dev) | |||
| 128 | ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG, | 128 | ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG, |
| 129 | DA9052_CONTROLD_WATCHDOG, 1 << 7); | 129 | DA9052_CONTROLD_WATCHDOG, 1 << 7); |
| 130 | if (ret < 0) | 130 | if (ret < 0) |
| 131 | goto err_strobe; | 131 | return ret; |
| 132 | 132 | ||
| 133 | /* | 133 | /* |
| 134 | * FIXME: Reset the watchdog core, in general PMIC | 134 | * FIXME: Reset the watchdog core, in general PMIC |
| 135 | * is supposed to do this | 135 | * is supposed to do this |
| 136 | */ | 136 | */ |
| 137 | ret = da9052_reg_update(da9052, DA9052_CONTROL_D_REG, | 137 | return da9052_reg_update(da9052, DA9052_CONTROL_D_REG, |
| 138 | DA9052_CONTROLD_WATCHDOG, 0 << 7); | 138 | DA9052_CONTROLD_WATCHDOG, 0 << 7); |
| 139 | err_strobe: | ||
| 140 | return ret; | ||
| 141 | } | 139 | } |
| 142 | 140 | ||
| 143 | static struct watchdog_info da9052_wdt_info = { | 141 | static const struct watchdog_info da9052_wdt_info = { |
| 144 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 142 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
| 145 | .identity = "DA9052 Watchdog", | 143 | .identity = "DA9052 Watchdog", |
| 146 | }; | 144 | }; |
| @@ -163,10 +161,8 @@ static int da9052_wdt_probe(struct platform_device *pdev) | |||
| 163 | 161 | ||
| 164 | driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data), | 162 | driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data), |
| 165 | GFP_KERNEL); | 163 | GFP_KERNEL); |
| 166 | if (!driver_data) { | 164 | if (!driver_data) |
| 167 | ret = -ENOMEM; | 165 | return -ENOMEM; |
| 168 | goto err; | ||
| 169 | } | ||
| 170 | driver_data->da9052 = da9052; | 166 | driver_data->da9052 = da9052; |
| 171 | 167 | ||
| 172 | da9052_wdt = &driver_data->wdt; | 168 | da9052_wdt = &driver_data->wdt; |
| @@ -182,33 +178,21 @@ static int da9052_wdt_probe(struct platform_device *pdev) | |||
| 182 | if (ret < 0) { | 178 | if (ret < 0) { |
| 183 | dev_err(&pdev->dev, "Failed to disable watchdog bits, %d\n", | 179 | dev_err(&pdev->dev, "Failed to disable watchdog bits, %d\n", |
| 184 | ret); | 180 | ret); |
| 185 | goto err; | 181 | return ret; |
| 186 | } | 182 | } |
| 187 | 183 | ||
| 188 | ret = watchdog_register_device(&driver_data->wdt); | 184 | ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt); |
| 189 | if (ret != 0) { | 185 | if (ret != 0) { |
| 190 | dev_err(da9052->dev, "watchdog_register_device() failed: %d\n", | 186 | dev_err(da9052->dev, "watchdog_register_device() failed: %d\n", |
| 191 | ret); | 187 | ret); |
| 192 | goto err; | 188 | return ret; |
| 193 | } | 189 | } |
| 194 | 190 | ||
| 195 | platform_set_drvdata(pdev, driver_data); | ||
| 196 | err: | ||
| 197 | return ret; | 191 | return ret; |
| 198 | } | 192 | } |
| 199 | 193 | ||
| 200 | static int da9052_wdt_remove(struct platform_device *pdev) | ||
| 201 | { | ||
| 202 | struct da9052_wdt_data *driver_data = platform_get_drvdata(pdev); | ||
| 203 | |||
| 204 | watchdog_unregister_device(&driver_data->wdt); | ||
| 205 | |||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | |||
| 209 | static struct platform_driver da9052_wdt_driver = { | 194 | static struct platform_driver da9052_wdt_driver = { |
| 210 | .probe = da9052_wdt_probe, | 195 | .probe = da9052_wdt_probe, |
| 211 | .remove = da9052_wdt_remove, | ||
| 212 | .driver = { | 196 | .driver = { |
| 213 | .name = "da9052-watchdog", | 197 | .name = "da9052-watchdog", |
| 214 | }, | 198 | }, |
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c index 8377c43f3f20..50bdd1022186 100644 --- a/drivers/watchdog/da9055_wdt.c +++ b/drivers/watchdog/da9055_wdt.c | |||
| @@ -108,7 +108,7 @@ static int da9055_wdt_stop(struct watchdog_device *wdt_dev) | |||
| 108 | return da9055_wdt_set_timeout(wdt_dev, 0); | 108 | return da9055_wdt_set_timeout(wdt_dev, 0); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | static struct watchdog_info da9055_wdt_info = { | 111 | static const struct watchdog_info da9055_wdt_info = { |
| 112 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 112 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
| 113 | .identity = "DA9055 Watchdog", | 113 | .identity = "DA9055 Watchdog", |
| 114 | }; | 114 | }; |
| @@ -147,32 +147,19 @@ static int da9055_wdt_probe(struct platform_device *pdev) | |||
| 147 | ret = da9055_wdt_stop(da9055_wdt); | 147 | ret = da9055_wdt_stop(da9055_wdt); |
| 148 | if (ret < 0) { | 148 | if (ret < 0) { |
| 149 | dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret); | 149 | dev_err(&pdev->dev, "Failed to stop watchdog, %d\n", ret); |
| 150 | goto err; | 150 | return ret; |
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | platform_set_drvdata(pdev, driver_data); | 153 | ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt); |
| 154 | |||
| 155 | ret = watchdog_register_device(&driver_data->wdt); | ||
| 156 | if (ret != 0) | 154 | if (ret != 0) |
| 157 | dev_err(da9055->dev, "watchdog_register_device() failed: %d\n", | 155 | dev_err(da9055->dev, "watchdog_register_device() failed: %d\n", |
| 158 | ret); | 156 | ret); |
| 159 | 157 | ||
| 160 | err: | ||
| 161 | return ret; | 158 | return ret; |
| 162 | } | 159 | } |
| 163 | 160 | ||
| 164 | static int da9055_wdt_remove(struct platform_device *pdev) | ||
| 165 | { | ||
| 166 | struct da9055_wdt_data *driver_data = platform_get_drvdata(pdev); | ||
| 167 | |||
| 168 | watchdog_unregister_device(&driver_data->wdt); | ||
| 169 | |||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | |||
| 173 | static struct platform_driver da9055_wdt_driver = { | 161 | static struct platform_driver da9055_wdt_driver = { |
| 174 | .probe = da9055_wdt_probe, | 162 | .probe = da9055_wdt_probe, |
| 175 | .remove = da9055_wdt_remove, | ||
| 176 | .driver = { | 163 | .driver = { |
| 177 | .name = "da9055-watchdog", | 164 | .name = "da9055-watchdog", |
| 178 | }, | 165 | }, |
diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index a02cee6820a1..9083d3d922b0 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c | |||
| @@ -220,9 +220,8 @@ static int da9062_wdt_probe(struct platform_device *pdev) | |||
| 220 | wdt->wdtdev.parent = &pdev->dev; | 220 | wdt->wdtdev.parent = &pdev->dev; |
| 221 | 221 | ||
| 222 | watchdog_set_drvdata(&wdt->wdtdev, wdt); | 222 | watchdog_set_drvdata(&wdt->wdtdev, wdt); |
| 223 | dev_set_drvdata(&pdev->dev, wdt); | ||
| 224 | 223 | ||
| 225 | ret = watchdog_register_device(&wdt->wdtdev); | 224 | ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev); |
| 226 | if (ret < 0) { | 225 | if (ret < 0) { |
| 227 | dev_err(wdt->hw->dev, | 226 | dev_err(wdt->hw->dev, |
| 228 | "watchdog registration failed (%d)\n", ret); | 227 | "watchdog registration failed (%d)\n", ret); |
| @@ -231,24 +230,11 @@ static int da9062_wdt_probe(struct platform_device *pdev) | |||
| 231 | 230 | ||
| 232 | da9062_set_window_start(wdt); | 231 | da9062_set_window_start(wdt); |
| 233 | 232 | ||
| 234 | ret = da9062_wdt_ping(&wdt->wdtdev); | 233 | return da9062_wdt_ping(&wdt->wdtdev); |
| 235 | if (ret < 0) | ||
| 236 | watchdog_unregister_device(&wdt->wdtdev); | ||
| 237 | |||
| 238 | return ret; | ||
| 239 | } | ||
| 240 | |||
| 241 | static int da9062_wdt_remove(struct platform_device *pdev) | ||
| 242 | { | ||
| 243 | struct da9062_watchdog *wdt = dev_get_drvdata(&pdev->dev); | ||
| 244 | |||
| 245 | watchdog_unregister_device(&wdt->wdtdev); | ||
| 246 | return 0; | ||
| 247 | } | 234 | } |
| 248 | 235 | ||
| 249 | static struct platform_driver da9062_wdt_driver = { | 236 | static struct platform_driver da9062_wdt_driver = { |
| 250 | .probe = da9062_wdt_probe, | 237 | .probe = da9062_wdt_probe, |
| 251 | .remove = da9062_wdt_remove, | ||
| 252 | .driver = { | 238 | .driver = { |
| 253 | .name = "da9062-watchdog", | 239 | .name = "da9062-watchdog", |
| 254 | .of_match_table = da9062_compatible_id_table, | 240 | .of_match_table = da9062_compatible_id_table, |
diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index 5d6b4e5f7989..4691c5509129 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c | |||
| @@ -151,7 +151,6 @@ static const struct watchdog_ops da9063_watchdog_ops = { | |||
| 151 | 151 | ||
| 152 | static int da9063_wdt_probe(struct platform_device *pdev) | 152 | static int da9063_wdt_probe(struct platform_device *pdev) |
| 153 | { | 153 | { |
| 154 | int ret; | ||
| 155 | struct da9063 *da9063; | 154 | struct da9063 *da9063; |
| 156 | struct da9063_watchdog *wdt; | 155 | struct da9063_watchdog *wdt; |
| 157 | 156 | ||
| @@ -181,27 +180,12 @@ static int da9063_wdt_probe(struct platform_device *pdev) | |||
| 181 | watchdog_set_restart_priority(&wdt->wdtdev, 128); | 180 | watchdog_set_restart_priority(&wdt->wdtdev, 128); |
| 182 | 181 | ||
| 183 | watchdog_set_drvdata(&wdt->wdtdev, wdt); | 182 | watchdog_set_drvdata(&wdt->wdtdev, wdt); |
| 184 | dev_set_drvdata(&pdev->dev, wdt); | ||
| 185 | |||
| 186 | ret = watchdog_register_device(&wdt->wdtdev); | ||
| 187 | if (ret) | ||
| 188 | return ret; | ||
| 189 | |||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | |||
| 193 | static int da9063_wdt_remove(struct platform_device *pdev) | ||
| 194 | { | ||
| 195 | struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev); | ||
| 196 | |||
| 197 | watchdog_unregister_device(&wdt->wdtdev); | ||
| 198 | 183 | ||
| 199 | return 0; | 184 | return devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev); |
| 200 | } | 185 | } |
| 201 | 186 | ||
| 202 | static struct platform_driver da9063_wdt_driver = { | 187 | static struct platform_driver da9063_wdt_driver = { |
| 203 | .probe = da9063_wdt_probe, | 188 | .probe = da9063_wdt_probe, |
| 204 | .remove = da9063_wdt_remove, | ||
| 205 | .driver = { | 189 | .driver = { |
| 206 | .name = DA9063_DRVNAME_WATCHDOG, | 190 | .name = DA9063_DRVNAME_WATCHDOG, |
| 207 | }, | 191 | }, |
diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c index 861d3d3133f8..6f591084bb7a 100644 --- a/drivers/watchdog/diag288_wdt.c +++ b/drivers/watchdog/diag288_wdt.c | |||
| @@ -205,7 +205,7 @@ static int wdt_set_timeout(struct watchdog_device * dev, unsigned int new_to) | |||
| 205 | return wdt_ping(dev); | 205 | return wdt_ping(dev); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | static struct watchdog_ops wdt_ops = { | 208 | static const struct watchdog_ops wdt_ops = { |
| 209 | .owner = THIS_MODULE, | 209 | .owner = THIS_MODULE, |
| 210 | .start = wdt_start, | 210 | .start = wdt_start, |
| 211 | .stop = wdt_stop, | 211 | .stop = wdt_stop, |
diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c index 77df772406b0..5e4ef93caa02 100644 --- a/drivers/watchdog/digicolor_wdt.c +++ b/drivers/watchdog/digicolor_wdt.c | |||
| @@ -96,7 +96,7 @@ static unsigned int dc_wdt_get_timeleft(struct watchdog_device *wdog) | |||
| 96 | return count / clk_get_rate(wdt->clk); | 96 | return count / clk_get_rate(wdt->clk); |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | static struct watchdog_ops dc_wdt_ops = { | 99 | static const struct watchdog_ops dc_wdt_ops = { |
| 100 | .owner = THIS_MODULE, | 100 | .owner = THIS_MODULE, |
| 101 | .start = dc_wdt_start, | 101 | .start = dc_wdt_start, |
| 102 | .stop = dc_wdt_stop, | 102 | .stop = dc_wdt_stop, |
| @@ -105,7 +105,7 @@ static struct watchdog_ops dc_wdt_ops = { | |||
| 105 | .restart = dc_wdt_restart, | 105 | .restart = dc_wdt_restart, |
| 106 | }; | 106 | }; |
| 107 | 107 | ||
| 108 | static struct watchdog_info dc_wdt_info = { | 108 | static const struct watchdog_info dc_wdt_info = { |
| 109 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | 109 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
| 110 | | WDIOF_KEEPALIVEPING, | 110 | | WDIOF_KEEPALIVEPING, |
| 111 | .identity = "Conexant Digicolor Watchdog", | 111 | .identity = "Conexant Digicolor Watchdog", |
| @@ -119,62 +119,40 @@ static struct watchdog_device dc_wdt_wdd = { | |||
| 119 | 119 | ||
| 120 | static int dc_wdt_probe(struct platform_device *pdev) | 120 | static int dc_wdt_probe(struct platform_device *pdev) |
| 121 | { | 121 | { |
| 122 | struct resource *res; | ||
| 122 | struct device *dev = &pdev->dev; | 123 | struct device *dev = &pdev->dev; |
| 123 | struct device_node *np = dev->of_node; | ||
| 124 | struct dc_wdt *wdt; | 124 | struct dc_wdt *wdt; |
| 125 | int ret; | 125 | int ret; |
| 126 | 126 | ||
| 127 | wdt = devm_kzalloc(dev, sizeof(struct dc_wdt), GFP_KERNEL); | 127 | wdt = devm_kzalloc(dev, sizeof(struct dc_wdt), GFP_KERNEL); |
| 128 | if (!wdt) | 128 | if (!wdt) |
| 129 | return -ENOMEM; | 129 | return -ENOMEM; |
| 130 | platform_set_drvdata(pdev, wdt); | ||
| 131 | 130 | ||
| 132 | wdt->base = of_iomap(np, 0); | 131 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 133 | if (!wdt->base) { | 132 | wdt->base = devm_ioremap_resource(dev, res); |
| 134 | dev_err(dev, "Failed to remap watchdog regs"); | 133 | if (IS_ERR(wdt->base)) |
| 135 | return -ENODEV; | 134 | return PTR_ERR(wdt->base); |
| 136 | } | ||
| 137 | 135 | ||
| 138 | wdt->clk = devm_clk_get(&pdev->dev, NULL); | 136 | wdt->clk = devm_clk_get(dev, NULL); |
| 139 | if (IS_ERR(wdt->clk)) { | 137 | if (IS_ERR(wdt->clk)) |
| 140 | ret = PTR_ERR(wdt->clk); | 138 | return PTR_ERR(wdt->clk); |
| 141 | goto err_iounmap; | ||
| 142 | } | ||
| 143 | dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk); | 139 | dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk); |
| 144 | dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout; | 140 | dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout; |
| 145 | dc_wdt_wdd.parent = &pdev->dev; | 141 | dc_wdt_wdd.parent = dev; |
| 146 | 142 | ||
| 147 | spin_lock_init(&wdt->lock); | 143 | spin_lock_init(&wdt->lock); |
| 148 | 144 | ||
| 149 | watchdog_set_drvdata(&dc_wdt_wdd, wdt); | 145 | watchdog_set_drvdata(&dc_wdt_wdd, wdt); |
| 150 | watchdog_set_restart_priority(&dc_wdt_wdd, 128); | 146 | watchdog_set_restart_priority(&dc_wdt_wdd, 128); |
| 151 | watchdog_init_timeout(&dc_wdt_wdd, timeout, dev); | 147 | watchdog_init_timeout(&dc_wdt_wdd, timeout, dev); |
| 152 | ret = watchdog_register_device(&dc_wdt_wdd); | 148 | watchdog_stop_on_reboot(&dc_wdt_wdd); |
| 149 | ret = devm_watchdog_register_device(dev, &dc_wdt_wdd); | ||
| 153 | if (ret) { | 150 | if (ret) { |
| 154 | dev_err(dev, "Failed to register watchdog device"); | 151 | dev_err(dev, "Failed to register watchdog device"); |
| 155 | goto err_iounmap; | 152 | return ret; |
| 156 | } | 153 | } |
| 157 | 154 | ||
| 158 | return 0; | 155 | return 0; |
| 159 | |||
| 160 | err_iounmap: | ||
| 161 | iounmap(wdt->base); | ||
| 162 | return ret; | ||
| 163 | } | ||
| 164 | |||
| 165 | static int dc_wdt_remove(struct platform_device *pdev) | ||
| 166 | { | ||
| 167 | struct dc_wdt *wdt = platform_get_drvdata(pdev); | ||
| 168 | |||
| 169 | watchdog_unregister_device(&dc_wdt_wdd); | ||
| 170 | iounmap(wdt->base); | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | static void dc_wdt_shutdown(struct platform_device *pdev) | ||
| 176 | { | ||
| 177 | dc_wdt_stop(&dc_wdt_wdd); | ||
| 178 | } | 156 | } |
| 179 | 157 | ||
| 180 | static const struct of_device_id dc_wdt_of_match[] = { | 158 | static const struct of_device_id dc_wdt_of_match[] = { |
| @@ -185,8 +163,6 @@ MODULE_DEVICE_TABLE(of, dc_wdt_of_match); | |||
| 185 | 163 | ||
| 186 | static struct platform_driver dc_wdt_driver = { | 164 | static struct platform_driver dc_wdt_driver = { |
| 187 | .probe = dc_wdt_probe, | 165 | .probe = dc_wdt_probe, |
| 188 | .remove = dc_wdt_remove, | ||
| 189 | .shutdown = dc_wdt_shutdown, | ||
| 190 | .driver = { | 166 | .driver = { |
| 191 | .name = "digicolor-wdt", | 167 | .name = "digicolor-wdt", |
| 192 | .of_match_table = dc_wdt_of_match, | 168 | .of_match_table = dc_wdt_of_match, |
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 3c6a3de13a1b..914da3a4d334 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c | |||
| @@ -26,11 +26,9 @@ | |||
| 26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
| 27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
| 28 | #include <linux/moduleparam.h> | 28 | #include <linux/moduleparam.h> |
| 29 | #include <linux/notifier.h> | ||
| 30 | #include <linux/of.h> | 29 | #include <linux/of.h> |
| 31 | #include <linux/pm.h> | 30 | #include <linux/pm.h> |
| 32 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
| 33 | #include <linux/reboot.h> | ||
| 34 | #include <linux/watchdog.h> | 32 | #include <linux/watchdog.h> |
| 35 | 33 | ||
| 36 | #define WDOG_CONTROL_REG_OFFSET 0x00 | 34 | #define WDOG_CONTROL_REG_OFFSET 0x00 |
| @@ -55,7 +53,6 @@ struct dw_wdt { | |||
| 55 | void __iomem *regs; | 53 | void __iomem *regs; |
| 56 | struct clk *clk; | 54 | struct clk *clk; |
| 57 | unsigned long rate; | 55 | unsigned long rate; |
| 58 | struct notifier_block restart_handler; | ||
| 59 | struct watchdog_device wdd; | 56 | struct watchdog_device wdd; |
| 60 | }; | 57 | }; |
| 61 | 58 | ||
| @@ -136,14 +133,12 @@ static int dw_wdt_start(struct watchdog_device *wdd) | |||
| 136 | return 0; | 133 | return 0; |
| 137 | } | 134 | } |
| 138 | 135 | ||
| 139 | static int dw_wdt_restart_handle(struct notifier_block *this, | 136 | static int dw_wdt_restart(struct watchdog_device *wdd, |
| 140 | unsigned long mode, void *cmd) | 137 | unsigned long action, void *data) |
| 141 | { | 138 | { |
| 142 | struct dw_wdt *dw_wdt; | 139 | struct dw_wdt *dw_wdt = to_dw_wdt(wdd); |
| 143 | u32 val; | 140 | u32 val; |
| 144 | 141 | ||
| 145 | dw_wdt = container_of(this, struct dw_wdt, restart_handler); | ||
| 146 | |||
| 147 | writel(0, dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); | 142 | writel(0, dw_wdt->regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); |
| 148 | val = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); | 143 | val = readl(dw_wdt->regs + WDOG_CONTROL_REG_OFFSET); |
| 149 | if (val & WDOG_CONTROL_REG_WDT_EN_MASK) | 144 | if (val & WDOG_CONTROL_REG_WDT_EN_MASK) |
| @@ -156,7 +151,7 @@ static int dw_wdt_restart_handle(struct notifier_block *this, | |||
| 156 | /* wait for reset to assert... */ | 151 | /* wait for reset to assert... */ |
| 157 | mdelay(500); | 152 | mdelay(500); |
| 158 | 153 | ||
| 159 | return NOTIFY_DONE; | 154 | return 0; |
| 160 | } | 155 | } |
| 161 | 156 | ||
| 162 | static unsigned int dw_wdt_get_timeleft(struct watchdog_device *wdd) | 157 | static unsigned int dw_wdt_get_timeleft(struct watchdog_device *wdd) |
| @@ -179,6 +174,7 @@ static const struct watchdog_ops dw_wdt_ops = { | |||
| 179 | .ping = dw_wdt_ping, | 174 | .ping = dw_wdt_ping, |
| 180 | .set_timeout = dw_wdt_set_timeout, | 175 | .set_timeout = dw_wdt_set_timeout, |
| 181 | .get_timeleft = dw_wdt_get_timeleft, | 176 | .get_timeleft = dw_wdt_get_timeleft, |
| 177 | .restart = dw_wdt_restart, | ||
| 182 | }; | 178 | }; |
| 183 | 179 | ||
| 184 | #ifdef CONFIG_PM_SLEEP | 180 | #ifdef CONFIG_PM_SLEEP |
| @@ -265,16 +261,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) | |||
| 265 | 261 | ||
| 266 | platform_set_drvdata(pdev, dw_wdt); | 262 | platform_set_drvdata(pdev, dw_wdt); |
| 267 | 263 | ||
| 264 | watchdog_set_restart_priority(wdd, 128); | ||
| 265 | |||
| 268 | ret = watchdog_register_device(wdd); | 266 | ret = watchdog_register_device(wdd); |
| 269 | if (ret) | 267 | if (ret) |
| 270 | goto out_disable_clk; | 268 | goto out_disable_clk; |
| 271 | 269 | ||
| 272 | dw_wdt->restart_handler.notifier_call = dw_wdt_restart_handle; | ||
| 273 | dw_wdt->restart_handler.priority = 128; | ||
| 274 | ret = register_restart_handler(&dw_wdt->restart_handler); | ||
| 275 | if (ret) | ||
| 276 | pr_warn("cannot register restart handler\n"); | ||
| 277 | |||
| 278 | return 0; | 270 | return 0; |
| 279 | 271 | ||
| 280 | out_disable_clk: | 272 | out_disable_clk: |
| @@ -286,7 +278,6 @@ static int dw_wdt_drv_remove(struct platform_device *pdev) | |||
| 286 | { | 278 | { |
| 287 | struct dw_wdt *dw_wdt = platform_get_drvdata(pdev); | 279 | struct dw_wdt *dw_wdt = platform_get_drvdata(pdev); |
| 288 | 280 | ||
| 289 | unregister_restart_handler(&dw_wdt->restart_handler); | ||
| 290 | watchdog_unregister_device(&dw_wdt->wdd); | 281 | watchdog_unregister_device(&dw_wdt->wdd); |
| 291 | clk_disable_unprepare(dw_wdt->clk); | 282 | clk_disable_unprepare(dw_wdt->clk); |
| 292 | 283 | ||
diff --git a/drivers/watchdog/ebc-c384_wdt.c b/drivers/watchdog/ebc-c384_wdt.c index 4b849b8e37c2..2170b275ea01 100644 --- a/drivers/watchdog/ebc-c384_wdt.c +++ b/drivers/watchdog/ebc-c384_wdt.c | |||
| @@ -121,18 +121,7 @@ static int ebc_c384_wdt_probe(struct device *dev, unsigned int id) | |||
| 121 | dev_warn(dev, "Invalid timeout (%u seconds), using default (%u seconds)\n", | 121 | dev_warn(dev, "Invalid timeout (%u seconds), using default (%u seconds)\n", |
| 122 | timeout, WATCHDOG_TIMEOUT); | 122 | timeout, WATCHDOG_TIMEOUT); |
| 123 | 123 | ||
| 124 | dev_set_drvdata(dev, wdd); | 124 | return devm_watchdog_register_device(dev, wdd); |
| 125 | |||
| 126 | return watchdog_register_device(wdd); | ||
| 127 | } | ||
| 128 | |||
| 129 | static int ebc_c384_wdt_remove(struct device *dev, unsigned int id) | ||
| 130 | { | ||
| 131 | struct watchdog_device *wdd = dev_get_drvdata(dev); | ||
| 132 | |||
| 133 | watchdog_unregister_device(wdd); | ||
| 134 | |||
| 135 | return 0; | ||
| 136 | } | 125 | } |
| 137 | 126 | ||
| 138 | static struct isa_driver ebc_c384_wdt_driver = { | 127 | static struct isa_driver ebc_c384_wdt_driver = { |
| @@ -140,7 +129,6 @@ static struct isa_driver ebc_c384_wdt_driver = { | |||
| 140 | .driver = { | 129 | .driver = { |
| 141 | .name = MODULE_NAME | 130 | .name = MODULE_NAME |
| 142 | }, | 131 | }, |
| 143 | .remove = ebc_c384_wdt_remove | ||
| 144 | }; | 132 | }; |
| 145 | 133 | ||
| 146 | static int __init ebc_c384_wdt_init(void) | 134 | static int __init ebc_c384_wdt_init(void) |
diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c index 0a4d7cc05d54..f9b14e6efd9a 100644 --- a/drivers/watchdog/ep93xx_wdt.c +++ b/drivers/watchdog/ep93xx_wdt.c | |||
| @@ -19,21 +19,13 @@ | |||
| 19 | * for us to rely on the user space daemon alone. So we ping the | 19 | * for us to rely on the user space daemon alone. So we ping the |
| 20 | * wdt each ~200msec and eventually stop doing it if the user space | 20 | * wdt each ~200msec and eventually stop doing it if the user space |
| 21 | * daemon dies. | 21 | * daemon dies. |
| 22 | * | ||
| 23 | * TODO: | ||
| 24 | * | ||
| 25 | * - Test last reset from watchdog status | ||
| 26 | * - Add a few missing ioctls | ||
| 27 | */ | 22 | */ |
| 28 | 23 | ||
| 29 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 30 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 31 | #include <linux/watchdog.h> | 26 | #include <linux/watchdog.h> |
| 32 | #include <linux/timer.h> | ||
| 33 | #include <linux/io.h> | 27 | #include <linux/io.h> |
| 34 | 28 | ||
| 35 | #define WDT_VERSION "0.4" | ||
| 36 | |||
| 37 | /* default timeout (secs) */ | 29 | /* default timeout (secs) */ |
| 38 | #define WDT_TIMEOUT 30 | 30 | #define WDT_TIMEOUT 30 |
| 39 | 31 | ||
| @@ -41,117 +33,101 @@ static bool nowayout = WATCHDOG_NOWAYOUT; | |||
| 41 | module_param(nowayout, bool, 0); | 33 | module_param(nowayout, bool, 0); |
| 42 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); | 34 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); |
| 43 | 35 | ||
| 44 | static unsigned int timeout = WDT_TIMEOUT; | 36 | static unsigned int timeout; |
| 45 | module_param(timeout, uint, 0); | 37 | module_param(timeout, uint, 0); |
| 46 | MODULE_PARM_DESC(timeout, | 38 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds."); |
| 47 | "Watchdog timeout in seconds. (1<=timeout<=3600, default=" | ||
| 48 | __MODULE_STRING(WDT_TIMEOUT) ")"); | ||
| 49 | |||
| 50 | static void __iomem *mmio_base; | ||
| 51 | static struct timer_list timer; | ||
| 52 | static unsigned long next_heartbeat; | ||
| 53 | 39 | ||
| 54 | #define EP93XX_WATCHDOG 0x00 | 40 | #define EP93XX_WATCHDOG 0x00 |
| 55 | #define EP93XX_WDSTATUS 0x04 | 41 | #define EP93XX_WDSTATUS 0x04 |
| 56 | 42 | ||
| 57 | /* reset the wdt every ~200ms - the heartbeat of the device is 0.250 seconds*/ | 43 | struct ep93xx_wdt_priv { |
| 58 | #define WDT_INTERVAL (HZ/5) | 44 | void __iomem *mmio; |
| 59 | 45 | struct watchdog_device wdd; | |
| 60 | static void ep93xx_wdt_timer_ping(unsigned long data) | 46 | }; |
| 61 | { | ||
| 62 | if (time_before(jiffies, next_heartbeat)) | ||
| 63 | writel(0x5555, mmio_base + EP93XX_WATCHDOG); | ||
| 64 | |||
| 65 | /* Re-set the timer interval */ | ||
| 66 | mod_timer(&timer, jiffies + WDT_INTERVAL); | ||
| 67 | } | ||
| 68 | 47 | ||
| 69 | static int ep93xx_wdt_start(struct watchdog_device *wdd) | 48 | static int ep93xx_wdt_start(struct watchdog_device *wdd) |
| 70 | { | 49 | { |
| 71 | next_heartbeat = jiffies + (timeout * HZ); | 50 | struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 72 | 51 | ||
| 73 | writel(0xaaaa, mmio_base + EP93XX_WATCHDOG); | 52 | writel(0xaaaa, priv->mmio + EP93XX_WATCHDOG); |
| 74 | mod_timer(&timer, jiffies + WDT_INTERVAL); | ||
| 75 | 53 | ||
| 76 | return 0; | 54 | return 0; |
| 77 | } | 55 | } |
| 78 | 56 | ||
| 79 | static int ep93xx_wdt_stop(struct watchdog_device *wdd) | 57 | static int ep93xx_wdt_stop(struct watchdog_device *wdd) |
| 80 | { | 58 | { |
| 81 | del_timer_sync(&timer); | 59 | struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 82 | writel(0xaa55, mmio_base + EP93XX_WATCHDOG); | 60 | |
| 61 | writel(0xaa55, priv->mmio + EP93XX_WATCHDOG); | ||
| 83 | 62 | ||
| 84 | return 0; | 63 | return 0; |
| 85 | } | 64 | } |
| 86 | 65 | ||
| 87 | static int ep93xx_wdt_keepalive(struct watchdog_device *wdd) | 66 | static int ep93xx_wdt_ping(struct watchdog_device *wdd) |
| 88 | { | 67 | { |
| 89 | /* user land ping */ | 68 | struct ep93xx_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 90 | next_heartbeat = jiffies + (timeout * HZ); | 69 | |
| 70 | writel(0x5555, priv->mmio + EP93XX_WATCHDOG); | ||
| 91 | 71 | ||
| 92 | return 0; | 72 | return 0; |
| 93 | } | 73 | } |
| 94 | 74 | ||
| 95 | static const struct watchdog_info ep93xx_wdt_ident = { | 75 | static const struct watchdog_info ep93xx_wdt_ident = { |
| 96 | .options = WDIOF_CARDRESET | | 76 | .options = WDIOF_CARDRESET | |
| 77 | WDIOF_SETTIMEOUT | | ||
| 97 | WDIOF_MAGICCLOSE | | 78 | WDIOF_MAGICCLOSE | |
| 98 | WDIOF_KEEPALIVEPING, | 79 | WDIOF_KEEPALIVEPING, |
| 99 | .identity = "EP93xx Watchdog", | 80 | .identity = "EP93xx Watchdog", |
| 100 | }; | 81 | }; |
| 101 | 82 | ||
| 102 | static struct watchdog_ops ep93xx_wdt_ops = { | 83 | static const struct watchdog_ops ep93xx_wdt_ops = { |
| 103 | .owner = THIS_MODULE, | 84 | .owner = THIS_MODULE, |
| 104 | .start = ep93xx_wdt_start, | 85 | .start = ep93xx_wdt_start, |
| 105 | .stop = ep93xx_wdt_stop, | 86 | .stop = ep93xx_wdt_stop, |
| 106 | .ping = ep93xx_wdt_keepalive, | 87 | .ping = ep93xx_wdt_ping, |
| 107 | }; | ||
| 108 | |||
| 109 | static struct watchdog_device ep93xx_wdt_wdd = { | ||
| 110 | .info = &ep93xx_wdt_ident, | ||
| 111 | .ops = &ep93xx_wdt_ops, | ||
| 112 | }; | 88 | }; |
| 113 | 89 | ||
| 114 | static int ep93xx_wdt_probe(struct platform_device *pdev) | 90 | static int ep93xx_wdt_probe(struct platform_device *pdev) |
| 115 | { | 91 | { |
| 92 | struct ep93xx_wdt_priv *priv; | ||
| 93 | struct watchdog_device *wdd; | ||
| 116 | struct resource *res; | 94 | struct resource *res; |
| 117 | unsigned long val; | 95 | unsigned long val; |
| 118 | int err; | 96 | int ret; |
| 97 | |||
| 98 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
| 99 | if (!priv) | ||
| 100 | return -ENOMEM; | ||
| 119 | 101 | ||
| 120 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 102 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 121 | mmio_base = devm_ioremap_resource(&pdev->dev, res); | 103 | priv->mmio = devm_ioremap_resource(&pdev->dev, res); |
| 122 | if (IS_ERR(mmio_base)) | 104 | if (IS_ERR(priv->mmio)) |
| 123 | return PTR_ERR(mmio_base); | 105 | return PTR_ERR(priv->mmio); |
| 124 | 106 | ||
| 125 | if (timeout < 1 || timeout > 3600) { | 107 | val = readl(priv->mmio + EP93XX_WATCHDOG); |
| 126 | timeout = WDT_TIMEOUT; | ||
| 127 | dev_warn(&pdev->dev, | ||
| 128 | "timeout value must be 1<=x<=3600, using %d\n", | ||
| 129 | timeout); | ||
| 130 | } | ||
| 131 | 108 | ||
| 132 | val = readl(mmio_base + EP93XX_WATCHDOG); | 109 | wdd = &priv->wdd; |
| 133 | ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0; | 110 | wdd->bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0; |
| 134 | ep93xx_wdt_wdd.timeout = timeout; | 111 | wdd->info = &ep93xx_wdt_ident; |
| 135 | ep93xx_wdt_wdd.parent = &pdev->dev; | 112 | wdd->ops = &ep93xx_wdt_ops; |
| 113 | wdd->min_timeout = 1; | ||
| 114 | wdd->max_hw_heartbeat_ms = 200; | ||
| 115 | wdd->parent = &pdev->dev; | ||
| 136 | 116 | ||
| 137 | watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout); | 117 | watchdog_set_nowayout(wdd, nowayout); |
| 138 | 118 | ||
| 139 | setup_timer(&timer, ep93xx_wdt_timer_ping, 1); | 119 | wdd->timeout = WDT_TIMEOUT; |
| 120 | watchdog_init_timeout(wdd, timeout, &pdev->dev); | ||
| 140 | 121 | ||
| 141 | err = watchdog_register_device(&ep93xx_wdt_wdd); | 122 | watchdog_set_drvdata(wdd, priv); |
| 142 | if (err) | ||
| 143 | return err; | ||
| 144 | 123 | ||
| 145 | dev_info(&pdev->dev, | 124 | ret = devm_watchdog_register_device(&pdev->dev, wdd); |
| 146 | "EP93XX watchdog, driver version " WDT_VERSION "%s\n", | 125 | if (ret) |
| 147 | (val & 0x08) ? " (nCS1 disable detected)" : ""); | 126 | return ret; |
| 148 | 127 | ||
| 149 | return 0; | 128 | dev_info(&pdev->dev, "EP93XX watchdog driver %s\n", |
| 150 | } | 129 | (val & 0x08) ? " (nCS1 disable detected)" : ""); |
| 151 | 130 | ||
| 152 | static int ep93xx_wdt_remove(struct platform_device *pdev) | ||
| 153 | { | ||
| 154 | watchdog_unregister_device(&ep93xx_wdt_wdd); | ||
| 155 | return 0; | 131 | return 0; |
| 156 | } | 132 | } |
| 157 | 133 | ||
| @@ -160,7 +136,6 @@ static struct platform_driver ep93xx_wdt_driver = { | |||
| 160 | .name = "ep93xx-wdt", | 136 | .name = "ep93xx-wdt", |
| 161 | }, | 137 | }, |
| 162 | .probe = ep93xx_wdt_probe, | 138 | .probe = ep93xx_wdt_probe, |
| 163 | .remove = ep93xx_wdt_remove, | ||
| 164 | }; | 139 | }; |
| 165 | 140 | ||
| 166 | module_platform_driver(ep93xx_wdt_driver); | 141 | module_platform_driver(ep93xx_wdt_driver); |
| @@ -170,4 +145,3 @@ MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | |||
| 170 | MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); | 145 | MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); |
| 171 | MODULE_DESCRIPTION("EP93xx Watchdog"); | 146 | MODULE_DESCRIPTION("EP93xx Watchdog"); |
| 172 | MODULE_LICENSE("GPL"); | 147 | MODULE_LICENSE("GPL"); |
| 173 | MODULE_VERSION(WDT_VERSION); | ||
diff --git a/drivers/watchdog/gemini_wdt.c b/drivers/watchdog/gemini_wdt.c new file mode 100644 index 000000000000..8155aa619e4c --- /dev/null +++ b/drivers/watchdog/gemini_wdt.c | |||
| @@ -0,0 +1,229 @@ | |||
| 1 | /* | ||
| 2 | * Watchdog driver for Cortina Systems Gemini SoC | ||
| 3 | * | ||
| 4 | * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> | ||
| 5 | * | ||
| 6 | * Inspired by the out-of-tree drivers from OpenWRT: | ||
| 7 | * Copyright (C) 2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/bitops.h> | ||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/interrupt.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/of_device.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/watchdog.h> | ||
| 24 | |||
| 25 | #define GEMINI_WDCOUNTER 0x0 | ||
| 26 | #define GEMINI_WDLOAD 0x4 | ||
| 27 | #define GEMINI_WDRESTART 0x8 | ||
| 28 | #define GEMINI_WDCR 0xC | ||
| 29 | |||
| 30 | #define WDRESTART_MAGIC 0x5AB9 | ||
| 31 | |||
| 32 | #define WDCR_CLOCK_5MHZ BIT(4) | ||
| 33 | #define WDCR_SYS_RST BIT(1) | ||
| 34 | #define WDCR_ENABLE BIT(0) | ||
| 35 | |||
| 36 | #define WDT_CLOCK 5000000 /* 5 MHz */ | ||
| 37 | |||
| 38 | struct gemini_wdt { | ||
| 39 | struct watchdog_device wdd; | ||
| 40 | struct device *dev; | ||
| 41 | void __iomem *base; | ||
| 42 | }; | ||
| 43 | |||
| 44 | static inline | ||
| 45 | struct gemini_wdt *to_gemini_wdt(struct watchdog_device *wdd) | ||
| 46 | { | ||
| 47 | return container_of(wdd, struct gemini_wdt, wdd); | ||
| 48 | } | ||
| 49 | |||
| 50 | static int gemini_wdt_start(struct watchdog_device *wdd) | ||
| 51 | { | ||
| 52 | struct gemini_wdt *gwdt = to_gemini_wdt(wdd); | ||
| 53 | |||
| 54 | writel(wdd->timeout * WDT_CLOCK, gwdt->base + GEMINI_WDLOAD); | ||
| 55 | writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART); | ||
| 56 | /* set clock before enabling */ | ||
| 57 | writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST, | ||
| 58 | gwdt->base + GEMINI_WDCR); | ||
| 59 | writel(WDCR_CLOCK_5MHZ | WDCR_SYS_RST | WDCR_ENABLE, | ||
| 60 | gwdt->base + GEMINI_WDCR); | ||
| 61 | |||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | static int gemini_wdt_stop(struct watchdog_device *wdd) | ||
| 66 | { | ||
| 67 | struct gemini_wdt *gwdt = to_gemini_wdt(wdd); | ||
| 68 | |||
| 69 | writel(0, gwdt->base + GEMINI_WDCR); | ||
| 70 | |||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | static int gemini_wdt_ping(struct watchdog_device *wdd) | ||
| 75 | { | ||
| 76 | struct gemini_wdt *gwdt = to_gemini_wdt(wdd); | ||
| 77 | |||
| 78 | writel(WDRESTART_MAGIC, gwdt->base + GEMINI_WDRESTART); | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static int gemini_wdt_set_timeout(struct watchdog_device *wdd, | ||
| 84 | unsigned int timeout) | ||
| 85 | { | ||
| 86 | wdd->timeout = timeout; | ||
| 87 | if (watchdog_active(wdd)) | ||
| 88 | gemini_wdt_start(wdd); | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | static irqreturn_t gemini_wdt_interrupt(int irq, void *data) | ||
| 94 | { | ||
| 95 | struct gemini_wdt *gwdt = data; | ||
| 96 | |||
| 97 | watchdog_notify_pretimeout(&gwdt->wdd); | ||
| 98 | |||
| 99 | return IRQ_HANDLED; | ||
| 100 | } | ||
| 101 | |||
| 102 | static const struct watchdog_ops gemini_wdt_ops = { | ||
| 103 | .start = gemini_wdt_start, | ||
| 104 | .stop = gemini_wdt_stop, | ||
| 105 | .ping = gemini_wdt_ping, | ||
| 106 | .set_timeout = gemini_wdt_set_timeout, | ||
| 107 | .owner = THIS_MODULE, | ||
| 108 | }; | ||
| 109 | |||
| 110 | static const struct watchdog_info gemini_wdt_info = { | ||
| 111 | .options = WDIOF_KEEPALIVEPING | ||
| 112 | | WDIOF_MAGICCLOSE | ||
| 113 | | WDIOF_SETTIMEOUT, | ||
| 114 | .identity = KBUILD_MODNAME, | ||
| 115 | }; | ||
| 116 | |||
| 117 | |||
| 118 | static int gemini_wdt_probe(struct platform_device *pdev) | ||
| 119 | { | ||
| 120 | struct device *dev = &pdev->dev; | ||
| 121 | struct resource *res; | ||
| 122 | struct gemini_wdt *gwdt; | ||
| 123 | unsigned int reg; | ||
| 124 | int irq; | ||
| 125 | int ret; | ||
| 126 | |||
| 127 | gwdt = devm_kzalloc(dev, sizeof(*gwdt), GFP_KERNEL); | ||
| 128 | if (!gwdt) | ||
| 129 | return -ENOMEM; | ||
| 130 | |||
| 131 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 132 | gwdt->base = devm_ioremap_resource(dev, res); | ||
| 133 | if (IS_ERR(gwdt->base)) | ||
| 134 | return PTR_ERR(gwdt->base); | ||
| 135 | |||
| 136 | irq = platform_get_irq(pdev, 0); | ||
| 137 | if (!irq) | ||
| 138 | return -EINVAL; | ||
| 139 | |||
| 140 | gwdt->dev = dev; | ||
| 141 | gwdt->wdd.info = &gemini_wdt_info; | ||
| 142 | gwdt->wdd.ops = &gemini_wdt_ops; | ||
| 143 | gwdt->wdd.min_timeout = 1; | ||
| 144 | gwdt->wdd.max_timeout = 0xFFFFFFFF / WDT_CLOCK; | ||
| 145 | gwdt->wdd.parent = dev; | ||
| 146 | |||
| 147 | /* | ||
| 148 | * If 'timeout-sec' unspecified in devicetree, assume a 13 second | ||
| 149 | * default. | ||
| 150 | */ | ||
| 151 | gwdt->wdd.timeout = 13U; | ||
| 152 | watchdog_init_timeout(&gwdt->wdd, 0, dev); | ||
| 153 | |||
| 154 | reg = readw(gwdt->base + GEMINI_WDCR); | ||
| 155 | if (reg & WDCR_ENABLE) { | ||
| 156 | /* Watchdog was enabled by the bootloader, disable it. */ | ||
| 157 | reg &= ~WDCR_ENABLE; | ||
| 158 | writel(reg, gwdt->base + GEMINI_WDCR); | ||
| 159 | } | ||
| 160 | |||
| 161 | ret = devm_request_irq(dev, irq, gemini_wdt_interrupt, 0, | ||
| 162 | "watchdog bark", gwdt); | ||
| 163 | if (ret) | ||
| 164 | return ret; | ||
| 165 | |||
| 166 | ret = devm_watchdog_register_device(dev, &gwdt->wdd); | ||
| 167 | if (ret) { | ||
| 168 | dev_err(&pdev->dev, "failed to register watchdog\n"); | ||
| 169 | return ret; | ||
| 170 | } | ||
| 171 | |||
| 172 | /* Set up platform driver data */ | ||
| 173 | platform_set_drvdata(pdev, gwdt); | ||
| 174 | dev_info(dev, "Gemini watchdog driver enabled\n"); | ||
| 175 | |||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | static int __maybe_unused gemini_wdt_suspend(struct device *dev) | ||
| 180 | { | ||
| 181 | struct gemini_wdt *gwdt = dev_get_drvdata(dev); | ||
| 182 | unsigned int reg; | ||
| 183 | |||
| 184 | reg = readw(gwdt->base + GEMINI_WDCR); | ||
| 185 | reg &= ~WDCR_ENABLE; | ||
| 186 | writel(reg, gwdt->base + GEMINI_WDCR); | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int __maybe_unused gemini_wdt_resume(struct device *dev) | ||
| 192 | { | ||
| 193 | struct gemini_wdt *gwdt = dev_get_drvdata(dev); | ||
| 194 | unsigned int reg; | ||
| 195 | |||
| 196 | if (watchdog_active(&gwdt->wdd)) { | ||
| 197 | reg = readw(gwdt->base + GEMINI_WDCR); | ||
| 198 | reg |= WDCR_ENABLE; | ||
| 199 | writel(reg, gwdt->base + GEMINI_WDCR); | ||
| 200 | } | ||
| 201 | |||
| 202 | return 0; | ||
| 203 | } | ||
| 204 | |||
| 205 | static const struct dev_pm_ops gemini_wdt_dev_pm_ops = { | ||
| 206 | SET_SYSTEM_SLEEP_PM_OPS(gemini_wdt_suspend, | ||
| 207 | gemini_wdt_resume) | ||
| 208 | }; | ||
| 209 | |||
| 210 | #ifdef CONFIG_OF | ||
| 211 | static const struct of_device_id gemini_wdt_match[] = { | ||
| 212 | { .compatible = "cortina,gemini-watchdog" }, | ||
| 213 | {}, | ||
| 214 | }; | ||
| 215 | MODULE_DEVICE_TABLE(of, gemini_wdt_match); | ||
| 216 | #endif | ||
| 217 | |||
| 218 | static struct platform_driver gemini_wdt_driver = { | ||
| 219 | .probe = gemini_wdt_probe, | ||
| 220 | .driver = { | ||
| 221 | .name = "gemini-wdt", | ||
| 222 | .of_match_table = of_match_ptr(gemini_wdt_match), | ||
| 223 | .pm = &gemini_wdt_dev_pm_ops, | ||
| 224 | }, | ||
| 225 | }; | ||
| 226 | module_platform_driver(gemini_wdt_driver); | ||
| 227 | MODULE_AUTHOR("Linus Walleij"); | ||
| 228 | MODULE_DESCRIPTION("Watchdog driver for Gemini"); | ||
| 229 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 06fcb6c8c917..3d0abc0d59b4 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c | |||
| @@ -72,22 +72,24 @@ | |||
| 72 | 72 | ||
| 73 | /* Address definitions for the TCO */ | 73 | /* Address definitions for the TCO */ |
| 74 | /* TCO base address */ | 74 | /* TCO base address */ |
| 75 | #define TCOBASE (iTCO_wdt_private.tco_res->start) | 75 | #define TCOBASE(p) ((p)->tco_res->start) |
| 76 | /* SMI Control and Enable Register */ | 76 | /* SMI Control and Enable Register */ |
| 77 | #define SMI_EN (iTCO_wdt_private.smi_res->start) | 77 | #define SMI_EN(p) ((p)->smi_res->start) |
| 78 | 78 | ||
| 79 | #define TCO_RLD (TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */ | 79 | #define TCO_RLD(p) (TCOBASE(p) + 0x00) /* TCO Timer Reload/Curr. Value */ |
| 80 | #define TCOv1_TMR (TCOBASE + 0x01) /* TCOv1 Timer Initial Value */ | 80 | #define TCOv1_TMR(p) (TCOBASE(p) + 0x01) /* TCOv1 Timer Initial Value*/ |
| 81 | #define TCO_DAT_IN (TCOBASE + 0x02) /* TCO Data In Register */ | 81 | #define TCO_DAT_IN(p) (TCOBASE(p) + 0x02) /* TCO Data In Register */ |
| 82 | #define TCO_DAT_OUT (TCOBASE + 0x03) /* TCO Data Out Register */ | 82 | #define TCO_DAT_OUT(p) (TCOBASE(p) + 0x03) /* TCO Data Out Register */ |
| 83 | #define TCO1_STS (TCOBASE + 0x04) /* TCO1 Status Register */ | 83 | #define TCO1_STS(p) (TCOBASE(p) + 0x04) /* TCO1 Status Register */ |
| 84 | #define TCO2_STS (TCOBASE + 0x06) /* TCO2 Status Register */ | 84 | #define TCO2_STS(p) (TCOBASE(p) + 0x06) /* TCO2 Status Register */ |
| 85 | #define TCO1_CNT (TCOBASE + 0x08) /* TCO1 Control Register */ | 85 | #define TCO1_CNT(p) (TCOBASE(p) + 0x08) /* TCO1 Control Register */ |
| 86 | #define TCO2_CNT (TCOBASE + 0x0a) /* TCO2 Control Register */ | 86 | #define TCO2_CNT(p) (TCOBASE(p) + 0x0a) /* TCO2 Control Register */ |
| 87 | #define TCOv2_TMR (TCOBASE + 0x12) /* TCOv2 Timer Initial Value */ | 87 | #define TCOv2_TMR(p) (TCOBASE(p) + 0x12) /* TCOv2 Timer Initial Value*/ |
| 88 | 88 | ||
| 89 | /* internal variables */ | 89 | /* internal variables */ |
| 90 | static struct { /* this is private data for the iTCO_wdt device */ | 90 | struct iTCO_wdt_private { |
| 91 | struct watchdog_device wddev; | ||
| 92 | |||
| 91 | /* TCO version/generation */ | 93 | /* TCO version/generation */ |
| 92 | unsigned int iTCO_version; | 94 | unsigned int iTCO_version; |
| 93 | struct resource *tco_res; | 95 | struct resource *tco_res; |
| @@ -100,12 +102,11 @@ static struct { /* this is private data for the iTCO_wdt device */ | |||
| 100 | unsigned long __iomem *gcs_pmc; | 102 | unsigned long __iomem *gcs_pmc; |
| 101 | /* the lock for io operations */ | 103 | /* the lock for io operations */ |
| 102 | spinlock_t io_lock; | 104 | spinlock_t io_lock; |
| 103 | struct platform_device *dev; | ||
| 104 | /* the PCI-device */ | 105 | /* the PCI-device */ |
| 105 | struct pci_dev *pdev; | 106 | struct pci_dev *pci_dev; |
| 106 | /* whether or not the watchdog has been suspended */ | 107 | /* whether or not the watchdog has been suspended */ |
| 107 | bool suspended; | 108 | bool suspended; |
| 108 | } iTCO_wdt_private; | 109 | }; |
| 109 | 110 | ||
| 110 | /* module parameters */ | 111 | /* module parameters */ |
| 111 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default heartbeat */ | 112 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default heartbeat */ |
| @@ -135,21 +136,23 @@ MODULE_PARM_DESC(turn_SMI_watchdog_clear_off, | |||
| 135 | * every 0.6 seconds. v3's internal timer is stored as seconds (some | 136 | * every 0.6 seconds. v3's internal timer is stored as seconds (some |
| 136 | * datasheets incorrectly state 0.6 seconds). | 137 | * datasheets incorrectly state 0.6 seconds). |
| 137 | */ | 138 | */ |
| 138 | static inline unsigned int seconds_to_ticks(int secs) | 139 | static inline unsigned int seconds_to_ticks(struct iTCO_wdt_private *p, |
| 140 | int secs) | ||
| 139 | { | 141 | { |
| 140 | return iTCO_wdt_private.iTCO_version == 3 ? secs : (secs * 10) / 6; | 142 | return p->iTCO_version == 3 ? secs : (secs * 10) / 6; |
| 141 | } | 143 | } |
| 142 | 144 | ||
| 143 | static inline unsigned int ticks_to_seconds(int ticks) | 145 | static inline unsigned int ticks_to_seconds(struct iTCO_wdt_private *p, |
| 146 | int ticks) | ||
| 144 | { | 147 | { |
| 145 | return iTCO_wdt_private.iTCO_version == 3 ? ticks : (ticks * 6) / 10; | 148 | return p->iTCO_version == 3 ? ticks : (ticks * 6) / 10; |
| 146 | } | 149 | } |
| 147 | 150 | ||
| 148 | static inline u32 no_reboot_bit(void) | 151 | static inline u32 no_reboot_bit(struct iTCO_wdt_private *p) |
| 149 | { | 152 | { |
| 150 | u32 enable_bit; | 153 | u32 enable_bit; |
| 151 | 154 | ||
| 152 | switch (iTCO_wdt_private.iTCO_version) { | 155 | switch (p->iTCO_version) { |
| 153 | case 5: | 156 | case 5: |
| 154 | case 3: | 157 | case 3: |
| 155 | enable_bit = 0x00000010; | 158 | enable_bit = 0x00000010; |
| @@ -167,40 +170,40 @@ static inline u32 no_reboot_bit(void) | |||
| 167 | return enable_bit; | 170 | return enable_bit; |
| 168 | } | 171 | } |
| 169 | 172 | ||
| 170 | static void iTCO_wdt_set_NO_REBOOT_bit(void) | 173 | static void iTCO_wdt_set_NO_REBOOT_bit(struct iTCO_wdt_private *p) |
| 171 | { | 174 | { |
| 172 | u32 val32; | 175 | u32 val32; |
| 173 | 176 | ||
| 174 | /* Set the NO_REBOOT bit: this disables reboots */ | 177 | /* Set the NO_REBOOT bit: this disables reboots */ |
| 175 | if (iTCO_wdt_private.iTCO_version >= 2) { | 178 | if (p->iTCO_version >= 2) { |
| 176 | val32 = readl(iTCO_wdt_private.gcs_pmc); | 179 | val32 = readl(p->gcs_pmc); |
| 177 | val32 |= no_reboot_bit(); | 180 | val32 |= no_reboot_bit(p); |
| 178 | writel(val32, iTCO_wdt_private.gcs_pmc); | 181 | writel(val32, p->gcs_pmc); |
| 179 | } else if (iTCO_wdt_private.iTCO_version == 1) { | 182 | } else if (p->iTCO_version == 1) { |
| 180 | pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); | 183 | pci_read_config_dword(p->pci_dev, 0xd4, &val32); |
| 181 | val32 |= no_reboot_bit(); | 184 | val32 |= no_reboot_bit(p); |
| 182 | pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); | 185 | pci_write_config_dword(p->pci_dev, 0xd4, val32); |
| 183 | } | 186 | } |
| 184 | } | 187 | } |
| 185 | 188 | ||
| 186 | static int iTCO_wdt_unset_NO_REBOOT_bit(void) | 189 | static int iTCO_wdt_unset_NO_REBOOT_bit(struct iTCO_wdt_private *p) |
| 187 | { | 190 | { |
| 188 | u32 enable_bit = no_reboot_bit(); | 191 | u32 enable_bit = no_reboot_bit(p); |
| 189 | u32 val32 = 0; | 192 | u32 val32 = 0; |
| 190 | 193 | ||
| 191 | /* Unset the NO_REBOOT bit: this enables reboots */ | 194 | /* Unset the NO_REBOOT bit: this enables reboots */ |
| 192 | if (iTCO_wdt_private.iTCO_version >= 2) { | 195 | if (p->iTCO_version >= 2) { |
| 193 | val32 = readl(iTCO_wdt_private.gcs_pmc); | 196 | val32 = readl(p->gcs_pmc); |
| 194 | val32 &= ~enable_bit; | 197 | val32 &= ~enable_bit; |
| 195 | writel(val32, iTCO_wdt_private.gcs_pmc); | 198 | writel(val32, p->gcs_pmc); |
| 196 | 199 | ||
| 197 | val32 = readl(iTCO_wdt_private.gcs_pmc); | 200 | val32 = readl(p->gcs_pmc); |
| 198 | } else if (iTCO_wdt_private.iTCO_version == 1) { | 201 | } else if (p->iTCO_version == 1) { |
| 199 | pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); | 202 | pci_read_config_dword(p->pci_dev, 0xd4, &val32); |
| 200 | val32 &= ~enable_bit; | 203 | val32 &= ~enable_bit; |
| 201 | pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32); | 204 | pci_write_config_dword(p->pci_dev, 0xd4, val32); |
| 202 | 205 | ||
| 203 | pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32); | 206 | pci_read_config_dword(p->pci_dev, 0xd4, &val32); |
| 204 | } | 207 | } |
| 205 | 208 | ||
| 206 | if (val32 & enable_bit) | 209 | if (val32 & enable_bit) |
| @@ -211,32 +214,33 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void) | |||
| 211 | 214 | ||
| 212 | static int iTCO_wdt_start(struct watchdog_device *wd_dev) | 215 | static int iTCO_wdt_start(struct watchdog_device *wd_dev) |
| 213 | { | 216 | { |
| 217 | struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); | ||
| 214 | unsigned int val; | 218 | unsigned int val; |
| 215 | 219 | ||
| 216 | spin_lock(&iTCO_wdt_private.io_lock); | 220 | spin_lock(&p->io_lock); |
| 217 | 221 | ||
| 218 | iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, wd_dev->timeout); | 222 | iTCO_vendor_pre_start(p->smi_res, wd_dev->timeout); |
| 219 | 223 | ||
| 220 | /* disable chipset's NO_REBOOT bit */ | 224 | /* disable chipset's NO_REBOOT bit */ |
| 221 | if (iTCO_wdt_unset_NO_REBOOT_bit()) { | 225 | if (iTCO_wdt_unset_NO_REBOOT_bit(p)) { |
| 222 | spin_unlock(&iTCO_wdt_private.io_lock); | 226 | spin_unlock(&p->io_lock); |
| 223 | pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n"); | 227 | pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n"); |
| 224 | return -EIO; | 228 | return -EIO; |
| 225 | } | 229 | } |
| 226 | 230 | ||
| 227 | /* Force the timer to its reload value by writing to the TCO_RLD | 231 | /* Force the timer to its reload value by writing to the TCO_RLD |
| 228 | register */ | 232 | register */ |
| 229 | if (iTCO_wdt_private.iTCO_version >= 2) | 233 | if (p->iTCO_version >= 2) |
| 230 | outw(0x01, TCO_RLD); | 234 | outw(0x01, TCO_RLD(p)); |
| 231 | else if (iTCO_wdt_private.iTCO_version == 1) | 235 | else if (p->iTCO_version == 1) |
| 232 | outb(0x01, TCO_RLD); | 236 | outb(0x01, TCO_RLD(p)); |
| 233 | 237 | ||
| 234 | /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ | 238 | /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ |
| 235 | val = inw(TCO1_CNT); | 239 | val = inw(TCO1_CNT(p)); |
| 236 | val &= 0xf7ff; | 240 | val &= 0xf7ff; |
| 237 | outw(val, TCO1_CNT); | 241 | outw(val, TCO1_CNT(p)); |
| 238 | val = inw(TCO1_CNT); | 242 | val = inw(TCO1_CNT(p)); |
| 239 | spin_unlock(&iTCO_wdt_private.io_lock); | 243 | spin_unlock(&p->io_lock); |
| 240 | 244 | ||
| 241 | if (val & 0x0800) | 245 | if (val & 0x0800) |
| 242 | return -1; | 246 | return -1; |
| @@ -245,22 +249,23 @@ static int iTCO_wdt_start(struct watchdog_device *wd_dev) | |||
| 245 | 249 | ||
| 246 | static int iTCO_wdt_stop(struct watchdog_device *wd_dev) | 250 | static int iTCO_wdt_stop(struct watchdog_device *wd_dev) |
| 247 | { | 251 | { |
| 252 | struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); | ||
| 248 | unsigned int val; | 253 | unsigned int val; |
| 249 | 254 | ||
| 250 | spin_lock(&iTCO_wdt_private.io_lock); | 255 | spin_lock(&p->io_lock); |
| 251 | 256 | ||
| 252 | iTCO_vendor_pre_stop(iTCO_wdt_private.smi_res); | 257 | iTCO_vendor_pre_stop(p->smi_res); |
| 253 | 258 | ||
| 254 | /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ | 259 | /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ |
| 255 | val = inw(TCO1_CNT); | 260 | val = inw(TCO1_CNT(p)); |
| 256 | val |= 0x0800; | 261 | val |= 0x0800; |
| 257 | outw(val, TCO1_CNT); | 262 | outw(val, TCO1_CNT(p)); |
| 258 | val = inw(TCO1_CNT); | 263 | val = inw(TCO1_CNT(p)); |
| 259 | 264 | ||
| 260 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | 265 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ |
| 261 | iTCO_wdt_set_NO_REBOOT_bit(); | 266 | iTCO_wdt_set_NO_REBOOT_bit(p); |
| 262 | 267 | ||
| 263 | spin_unlock(&iTCO_wdt_private.io_lock); | 268 | spin_unlock(&p->io_lock); |
| 264 | 269 | ||
| 265 | if ((val & 0x0800) == 0) | 270 | if ((val & 0x0800) == 0) |
| 266 | return -1; | 271 | return -1; |
| @@ -269,67 +274,70 @@ static int iTCO_wdt_stop(struct watchdog_device *wd_dev) | |||
| 269 | 274 | ||
| 270 | static int iTCO_wdt_ping(struct watchdog_device *wd_dev) | 275 | static int iTCO_wdt_ping(struct watchdog_device *wd_dev) |
| 271 | { | 276 | { |
| 272 | spin_lock(&iTCO_wdt_private.io_lock); | 277 | struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); |
| 273 | 278 | ||
| 274 | iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, wd_dev->timeout); | 279 | spin_lock(&p->io_lock); |
| 280 | |||
| 281 | iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout); | ||
| 275 | 282 | ||
| 276 | /* Reload the timer by writing to the TCO Timer Counter register */ | 283 | /* Reload the timer by writing to the TCO Timer Counter register */ |
| 277 | if (iTCO_wdt_private.iTCO_version >= 2) { | 284 | if (p->iTCO_version >= 2) { |
| 278 | outw(0x01, TCO_RLD); | 285 | outw(0x01, TCO_RLD(p)); |
| 279 | } else if (iTCO_wdt_private.iTCO_version == 1) { | 286 | } else if (p->iTCO_version == 1) { |
| 280 | /* Reset the timeout status bit so that the timer | 287 | /* Reset the timeout status bit so that the timer |
| 281 | * needs to count down twice again before rebooting */ | 288 | * needs to count down twice again before rebooting */ |
| 282 | outw(0x0008, TCO1_STS); /* write 1 to clear bit */ | 289 | outw(0x0008, TCO1_STS(p)); /* write 1 to clear bit */ |
| 283 | 290 | ||
| 284 | outb(0x01, TCO_RLD); | 291 | outb(0x01, TCO_RLD(p)); |
| 285 | } | 292 | } |
| 286 | 293 | ||
| 287 | spin_unlock(&iTCO_wdt_private.io_lock); | 294 | spin_unlock(&p->io_lock); |
| 288 | return 0; | 295 | return 0; |
| 289 | } | 296 | } |
| 290 | 297 | ||
| 291 | static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t) | 298 | static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t) |
| 292 | { | 299 | { |
| 300 | struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); | ||
| 293 | unsigned int val16; | 301 | unsigned int val16; |
| 294 | unsigned char val8; | 302 | unsigned char val8; |
| 295 | unsigned int tmrval; | 303 | unsigned int tmrval; |
| 296 | 304 | ||
| 297 | tmrval = seconds_to_ticks(t); | 305 | tmrval = seconds_to_ticks(p, t); |
| 298 | 306 | ||
| 299 | /* For TCO v1 the timer counts down twice before rebooting */ | 307 | /* For TCO v1 the timer counts down twice before rebooting */ |
| 300 | if (iTCO_wdt_private.iTCO_version == 1) | 308 | if (p->iTCO_version == 1) |
| 301 | tmrval /= 2; | 309 | tmrval /= 2; |
| 302 | 310 | ||
| 303 | /* from the specs: */ | 311 | /* from the specs: */ |
| 304 | /* "Values of 0h-3h are ignored and should not be attempted" */ | 312 | /* "Values of 0h-3h are ignored and should not be attempted" */ |
| 305 | if (tmrval < 0x04) | 313 | if (tmrval < 0x04) |
| 306 | return -EINVAL; | 314 | return -EINVAL; |
| 307 | if (((iTCO_wdt_private.iTCO_version >= 2) && (tmrval > 0x3ff)) || | 315 | if ((p->iTCO_version >= 2 && tmrval > 0x3ff) || |
| 308 | ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f))) | 316 | (p->iTCO_version == 1 && tmrval > 0x03f)) |
| 309 | return -EINVAL; | 317 | return -EINVAL; |
| 310 | 318 | ||
| 311 | iTCO_vendor_pre_set_heartbeat(tmrval); | 319 | iTCO_vendor_pre_set_heartbeat(tmrval); |
| 312 | 320 | ||
| 313 | /* Write new heartbeat to watchdog */ | 321 | /* Write new heartbeat to watchdog */ |
| 314 | if (iTCO_wdt_private.iTCO_version >= 2) { | 322 | if (p->iTCO_version >= 2) { |
| 315 | spin_lock(&iTCO_wdt_private.io_lock); | 323 | spin_lock(&p->io_lock); |
| 316 | val16 = inw(TCOv2_TMR); | 324 | val16 = inw(TCOv2_TMR(p)); |
| 317 | val16 &= 0xfc00; | 325 | val16 &= 0xfc00; |
| 318 | val16 |= tmrval; | 326 | val16 |= tmrval; |
| 319 | outw(val16, TCOv2_TMR); | 327 | outw(val16, TCOv2_TMR(p)); |
| 320 | val16 = inw(TCOv2_TMR); | 328 | val16 = inw(TCOv2_TMR(p)); |
| 321 | spin_unlock(&iTCO_wdt_private.io_lock); | 329 | spin_unlock(&p->io_lock); |
| 322 | 330 | ||
| 323 | if ((val16 & 0x3ff) != tmrval) | 331 | if ((val16 & 0x3ff) != tmrval) |
| 324 | return -EINVAL; | 332 | return -EINVAL; |
| 325 | } else if (iTCO_wdt_private.iTCO_version == 1) { | 333 | } else if (p->iTCO_version == 1) { |
| 326 | spin_lock(&iTCO_wdt_private.io_lock); | 334 | spin_lock(&p->io_lock); |
| 327 | val8 = inb(TCOv1_TMR); | 335 | val8 = inb(TCOv1_TMR(p)); |
| 328 | val8 &= 0xc0; | 336 | val8 &= 0xc0; |
| 329 | val8 |= (tmrval & 0xff); | 337 | val8 |= (tmrval & 0xff); |
| 330 | outb(val8, TCOv1_TMR); | 338 | outb(val8, TCOv1_TMR(p)); |
| 331 | val8 = inb(TCOv1_TMR); | 339 | val8 = inb(TCOv1_TMR(p)); |
| 332 | spin_unlock(&iTCO_wdt_private.io_lock); | 340 | spin_unlock(&p->io_lock); |
| 333 | 341 | ||
| 334 | if ((val8 & 0x3f) != tmrval) | 342 | if ((val8 & 0x3f) != tmrval) |
| 335 | return -EINVAL; | 343 | return -EINVAL; |
| @@ -341,27 +349,28 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t) | |||
| 341 | 349 | ||
| 342 | static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev) | 350 | static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev) |
| 343 | { | 351 | { |
| 352 | struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); | ||
| 344 | unsigned int val16; | 353 | unsigned int val16; |
| 345 | unsigned char val8; | 354 | unsigned char val8; |
| 346 | unsigned int time_left = 0; | 355 | unsigned int time_left = 0; |
| 347 | 356 | ||
| 348 | /* read the TCO Timer */ | 357 | /* read the TCO Timer */ |
| 349 | if (iTCO_wdt_private.iTCO_version >= 2) { | 358 | if (p->iTCO_version >= 2) { |
| 350 | spin_lock(&iTCO_wdt_private.io_lock); | 359 | spin_lock(&p->io_lock); |
| 351 | val16 = inw(TCO_RLD); | 360 | val16 = inw(TCO_RLD(p)); |
| 352 | val16 &= 0x3ff; | 361 | val16 &= 0x3ff; |
| 353 | spin_unlock(&iTCO_wdt_private.io_lock); | 362 | spin_unlock(&p->io_lock); |
| 354 | 363 | ||
| 355 | time_left = ticks_to_seconds(val16); | 364 | time_left = ticks_to_seconds(p, val16); |
| 356 | } else if (iTCO_wdt_private.iTCO_version == 1) { | 365 | } else if (p->iTCO_version == 1) { |
| 357 | spin_lock(&iTCO_wdt_private.io_lock); | 366 | spin_lock(&p->io_lock); |
| 358 | val8 = inb(TCO_RLD); | 367 | val8 = inb(TCO_RLD(p)); |
| 359 | val8 &= 0x3f; | 368 | val8 &= 0x3f; |
| 360 | if (!(inw(TCO1_STS) & 0x0008)) | 369 | if (!(inw(TCO1_STS(p)) & 0x0008)) |
| 361 | val8 += (inb(TCOv1_TMR) & 0x3f); | 370 | val8 += (inb(TCOv1_TMR(p)) & 0x3f); |
| 362 | spin_unlock(&iTCO_wdt_private.io_lock); | 371 | spin_unlock(&p->io_lock); |
| 363 | 372 | ||
| 364 | time_left = ticks_to_seconds(val8); | 373 | time_left = ticks_to_seconds(p, val8); |
| 365 | } | 374 | } |
| 366 | return time_left; | 375 | return time_left; |
| 367 | } | 376 | } |
| @@ -387,209 +396,152 @@ static const struct watchdog_ops iTCO_wdt_ops = { | |||
| 387 | .get_timeleft = iTCO_wdt_get_timeleft, | 396 | .get_timeleft = iTCO_wdt_get_timeleft, |
| 388 | }; | 397 | }; |
| 389 | 398 | ||
| 390 | static struct watchdog_device iTCO_wdt_watchdog_dev = { | ||
| 391 | .info = &ident, | ||
| 392 | .ops = &iTCO_wdt_ops, | ||
| 393 | }; | ||
| 394 | |||
| 395 | /* | 399 | /* |
| 396 | * Init & exit routines | 400 | * Init & exit routines |
| 397 | */ | 401 | */ |
| 398 | 402 | ||
| 399 | static void iTCO_wdt_cleanup(void) | 403 | static int iTCO_wdt_probe(struct platform_device *pdev) |
| 400 | { | ||
| 401 | /* Stop the timer before we leave */ | ||
| 402 | if (!nowayout) | ||
| 403 | iTCO_wdt_stop(&iTCO_wdt_watchdog_dev); | ||
| 404 | |||
| 405 | /* Deregister */ | ||
| 406 | watchdog_unregister_device(&iTCO_wdt_watchdog_dev); | ||
| 407 | |||
| 408 | /* release resources */ | ||
| 409 | release_region(iTCO_wdt_private.tco_res->start, | ||
| 410 | resource_size(iTCO_wdt_private.tco_res)); | ||
| 411 | release_region(iTCO_wdt_private.smi_res->start, | ||
| 412 | resource_size(iTCO_wdt_private.smi_res)); | ||
| 413 | if (iTCO_wdt_private.iTCO_version >= 2) { | ||
| 414 | iounmap(iTCO_wdt_private.gcs_pmc); | ||
| 415 | release_mem_region(iTCO_wdt_private.gcs_pmc_res->start, | ||
| 416 | resource_size(iTCO_wdt_private.gcs_pmc_res)); | ||
| 417 | } | ||
| 418 | |||
| 419 | iTCO_wdt_private.tco_res = NULL; | ||
| 420 | iTCO_wdt_private.smi_res = NULL; | ||
| 421 | iTCO_wdt_private.gcs_pmc_res = NULL; | ||
| 422 | iTCO_wdt_private.gcs_pmc = NULL; | ||
| 423 | } | ||
| 424 | |||
| 425 | static int iTCO_wdt_probe(struct platform_device *dev) | ||
| 426 | { | 404 | { |
| 427 | int ret = -ENODEV; | 405 | struct device *dev = &pdev->dev; |
| 406 | struct itco_wdt_platform_data *pdata = dev_get_platdata(dev); | ||
| 407 | struct iTCO_wdt_private *p; | ||
| 428 | unsigned long val32; | 408 | unsigned long val32; |
| 429 | struct itco_wdt_platform_data *pdata = dev_get_platdata(&dev->dev); | 409 | int ret; |
| 430 | 410 | ||
| 431 | if (!pdata) | 411 | if (!pdata) |
| 432 | goto out; | 412 | return -ENODEV; |
| 413 | |||
| 414 | p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); | ||
| 415 | if (!p) | ||
| 416 | return -ENOMEM; | ||
| 433 | 417 | ||
| 434 | spin_lock_init(&iTCO_wdt_private.io_lock); | 418 | spin_lock_init(&p->io_lock); |
| 435 | 419 | ||
| 436 | iTCO_wdt_private.tco_res = | 420 | p->tco_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_TCO); |
| 437 | platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_TCO); | 421 | if (!p->tco_res) |
| 438 | if (!iTCO_wdt_private.tco_res) | 422 | return -ENODEV; |
| 439 | goto out; | ||
| 440 | 423 | ||
| 441 | iTCO_wdt_private.smi_res = | 424 | p->smi_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_SMI); |
| 442 | platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_SMI); | 425 | if (!p->smi_res) |
| 443 | if (!iTCO_wdt_private.smi_res) | 426 | return -ENODEV; |
| 444 | goto out; | ||
| 445 | 427 | ||
| 446 | iTCO_wdt_private.iTCO_version = pdata->version; | 428 | p->iTCO_version = pdata->version; |
| 447 | iTCO_wdt_private.dev = dev; | 429 | p->pci_dev = to_pci_dev(dev->parent); |
| 448 | iTCO_wdt_private.pdev = to_pci_dev(dev->dev.parent); | ||
| 449 | 430 | ||
| 450 | /* | 431 | /* |
| 451 | * Get the Memory-Mapped GCS or PMC register, we need it for the | 432 | * Get the Memory-Mapped GCS or PMC register, we need it for the |
| 452 | * NO_REBOOT flag (TCO v2 and v3). | 433 | * NO_REBOOT flag (TCO v2 and v3). |
| 453 | */ | 434 | */ |
| 454 | if (iTCO_wdt_private.iTCO_version >= 2) { | 435 | if (p->iTCO_version >= 2) { |
| 455 | iTCO_wdt_private.gcs_pmc_res = platform_get_resource(dev, | 436 | p->gcs_pmc_res = platform_get_resource(pdev, |
| 456 | IORESOURCE_MEM, | 437 | IORESOURCE_MEM, |
| 457 | ICH_RES_MEM_GCS_PMC); | 438 | ICH_RES_MEM_GCS_PMC); |
| 458 | 439 | p->gcs_pmc = devm_ioremap_resource(dev, p->gcs_pmc_res); | |
| 459 | if (!iTCO_wdt_private.gcs_pmc_res) | 440 | if (IS_ERR(p->gcs_pmc)) |
| 460 | goto out; | 441 | return PTR_ERR(p->gcs_pmc); |
| 461 | |||
| 462 | if (!request_mem_region(iTCO_wdt_private.gcs_pmc_res->start, | ||
| 463 | resource_size(iTCO_wdt_private.gcs_pmc_res), dev->name)) { | ||
| 464 | ret = -EBUSY; | ||
| 465 | goto out; | ||
| 466 | } | ||
| 467 | iTCO_wdt_private.gcs_pmc = ioremap(iTCO_wdt_private.gcs_pmc_res->start, | ||
| 468 | resource_size(iTCO_wdt_private.gcs_pmc_res)); | ||
| 469 | if (!iTCO_wdt_private.gcs_pmc) { | ||
| 470 | ret = -EIO; | ||
| 471 | goto unreg_gcs_pmc; | ||
| 472 | } | ||
| 473 | } | 442 | } |
| 474 | 443 | ||
| 475 | /* Check chipset's NO_REBOOT bit */ | 444 | /* Check chipset's NO_REBOOT bit */ |
| 476 | if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { | 445 | if (iTCO_wdt_unset_NO_REBOOT_bit(p) && |
| 446 | iTCO_vendor_check_noreboot_on()) { | ||
| 477 | pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n"); | 447 | pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n"); |
| 478 | ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ | 448 | return -ENODEV; /* Cannot reset NO_REBOOT bit */ |
| 479 | goto unmap_gcs_pmc; | ||
| 480 | } | 449 | } |
| 481 | 450 | ||
| 482 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ | 451 | /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ |
| 483 | iTCO_wdt_set_NO_REBOOT_bit(); | 452 | iTCO_wdt_set_NO_REBOOT_bit(p); |
| 484 | 453 | ||
| 485 | /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ | 454 | /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ |
| 486 | if (!request_region(iTCO_wdt_private.smi_res->start, | 455 | if (!devm_request_region(dev, p->smi_res->start, |
| 487 | resource_size(iTCO_wdt_private.smi_res), dev->name)) { | 456 | resource_size(p->smi_res), |
| 457 | pdev->name)) { | ||
| 488 | pr_err("I/O address 0x%04llx already in use, device disabled\n", | 458 | pr_err("I/O address 0x%04llx already in use, device disabled\n", |
| 489 | (u64)SMI_EN); | 459 | (u64)SMI_EN(p)); |
| 490 | ret = -EBUSY; | 460 | return -EBUSY; |
| 491 | goto unmap_gcs_pmc; | ||
| 492 | } | 461 | } |
| 493 | if (turn_SMI_watchdog_clear_off >= iTCO_wdt_private.iTCO_version) { | 462 | if (turn_SMI_watchdog_clear_off >= p->iTCO_version) { |
| 494 | /* | 463 | /* |
| 495 | * Bit 13: TCO_EN -> 0 | 464 | * Bit 13: TCO_EN -> 0 |
| 496 | * Disables TCO logic generating an SMI# | 465 | * Disables TCO logic generating an SMI# |
| 497 | */ | 466 | */ |
| 498 | val32 = inl(SMI_EN); | 467 | val32 = inl(SMI_EN(p)); |
| 499 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ | 468 | val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ |
| 500 | outl(val32, SMI_EN); | 469 | outl(val32, SMI_EN(p)); |
| 501 | } | 470 | } |
| 502 | 471 | ||
| 503 | if (!request_region(iTCO_wdt_private.tco_res->start, | 472 | if (!devm_request_region(dev, p->tco_res->start, |
| 504 | resource_size(iTCO_wdt_private.tco_res), dev->name)) { | 473 | resource_size(p->tco_res), |
| 474 | pdev->name)) { | ||
| 505 | pr_err("I/O address 0x%04llx already in use, device disabled\n", | 475 | pr_err("I/O address 0x%04llx already in use, device disabled\n", |
| 506 | (u64)TCOBASE); | 476 | (u64)TCOBASE(p)); |
| 507 | ret = -EBUSY; | 477 | return -EBUSY; |
| 508 | goto unreg_smi; | ||
| 509 | } | 478 | } |
| 510 | 479 | ||
| 511 | pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n", | 480 | pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n", |
| 512 | pdata->name, pdata->version, (u64)TCOBASE); | 481 | pdata->name, pdata->version, (u64)TCOBASE(p)); |
| 513 | 482 | ||
| 514 | /* Clear out the (probably old) status */ | 483 | /* Clear out the (probably old) status */ |
| 515 | switch (iTCO_wdt_private.iTCO_version) { | 484 | switch (p->iTCO_version) { |
| 516 | case 5: | 485 | case 5: |
| 517 | case 4: | 486 | case 4: |
| 518 | outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */ | 487 | outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */ |
| 519 | outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */ | 488 | outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */ |
| 520 | break; | 489 | break; |
| 521 | case 3: | 490 | case 3: |
| 522 | outl(0x20008, TCO1_STS); | 491 | outl(0x20008, TCO1_STS(p)); |
| 523 | break; | 492 | break; |
| 524 | case 2: | 493 | case 2: |
| 525 | case 1: | 494 | case 1: |
| 526 | default: | 495 | default: |
| 527 | outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */ | 496 | outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */ |
| 528 | outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */ | 497 | outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */ |
| 529 | outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */ | 498 | outw(0x0004, TCO2_STS(p)); /* Clear BOOT_STS bit */ |
| 530 | break; | 499 | break; |
| 531 | } | 500 | } |
| 532 | 501 | ||
| 533 | iTCO_wdt_watchdog_dev.bootstatus = 0; | 502 | p->wddev.info = &ident, |
| 534 | iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT; | 503 | p->wddev.ops = &iTCO_wdt_ops, |
| 535 | watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout); | 504 | p->wddev.bootstatus = 0; |
| 536 | iTCO_wdt_watchdog_dev.parent = &dev->dev; | 505 | p->wddev.timeout = WATCHDOG_TIMEOUT; |
| 506 | watchdog_set_nowayout(&p->wddev, nowayout); | ||
| 507 | p->wddev.parent = dev; | ||
| 508 | |||
| 509 | watchdog_set_drvdata(&p->wddev, p); | ||
| 510 | platform_set_drvdata(pdev, p); | ||
| 537 | 511 | ||
| 538 | /* Make sure the watchdog is not running */ | 512 | /* Make sure the watchdog is not running */ |
| 539 | iTCO_wdt_stop(&iTCO_wdt_watchdog_dev); | 513 | iTCO_wdt_stop(&p->wddev); |
| 540 | 514 | ||
| 541 | /* Check that the heartbeat value is within it's range; | 515 | /* Check that the heartbeat value is within it's range; |
| 542 | if not reset to the default */ | 516 | if not reset to the default */ |
| 543 | if (iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, heartbeat)) { | 517 | if (iTCO_wdt_set_timeout(&p->wddev, heartbeat)) { |
| 544 | iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, WATCHDOG_TIMEOUT); | 518 | iTCO_wdt_set_timeout(&p->wddev, WATCHDOG_TIMEOUT); |
| 545 | pr_info("timeout value out of range, using %d\n", | 519 | pr_info("timeout value out of range, using %d\n", |
| 546 | WATCHDOG_TIMEOUT); | 520 | WATCHDOG_TIMEOUT); |
| 547 | } | 521 | } |
| 548 | 522 | ||
| 549 | ret = watchdog_register_device(&iTCO_wdt_watchdog_dev); | 523 | watchdog_stop_on_reboot(&p->wddev); |
| 524 | ret = devm_watchdog_register_device(dev, &p->wddev); | ||
| 550 | if (ret != 0) { | 525 | if (ret != 0) { |
| 551 | pr_err("cannot register watchdog device (err=%d)\n", ret); | 526 | pr_err("cannot register watchdog device (err=%d)\n", ret); |
| 552 | goto unreg_tco; | 527 | return ret; |
| 553 | } | 528 | } |
| 554 | 529 | ||
| 555 | pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n", | 530 | pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n", |
| 556 | heartbeat, nowayout); | 531 | heartbeat, nowayout); |
| 557 | 532 | ||
| 558 | return 0; | 533 | return 0; |
| 559 | |||
| 560 | unreg_tco: | ||
| 561 | release_region(iTCO_wdt_private.tco_res->start, | ||
| 562 | resource_size(iTCO_wdt_private.tco_res)); | ||
| 563 | unreg_smi: | ||
| 564 | release_region(iTCO_wdt_private.smi_res->start, | ||
| 565 | resource_size(iTCO_wdt_private.smi_res)); | ||
| 566 | unmap_gcs_pmc: | ||
| 567 | if (iTCO_wdt_private.iTCO_version >= 2) | ||
| 568 | iounmap(iTCO_wdt_private.gcs_pmc); | ||
| 569 | unreg_gcs_pmc: | ||
| 570 | if (iTCO_wdt_private.iTCO_version >= 2) | ||
| 571 | release_mem_region(iTCO_wdt_private.gcs_pmc_res->start, | ||
| 572 | resource_size(iTCO_wdt_private.gcs_pmc_res)); | ||
| 573 | out: | ||
| 574 | iTCO_wdt_private.tco_res = NULL; | ||
| 575 | iTCO_wdt_private.smi_res = NULL; | ||
| 576 | iTCO_wdt_private.gcs_pmc_res = NULL; | ||
| 577 | iTCO_wdt_private.gcs_pmc = NULL; | ||
| 578 | |||
| 579 | return ret; | ||
| 580 | } | 534 | } |
| 581 | 535 | ||
| 582 | static int iTCO_wdt_remove(struct platform_device *dev) | 536 | static int iTCO_wdt_remove(struct platform_device *pdev) |
| 583 | { | 537 | { |
| 584 | if (iTCO_wdt_private.tco_res || iTCO_wdt_private.smi_res) | 538 | struct iTCO_wdt_private *p = platform_get_drvdata(pdev); |
| 585 | iTCO_wdt_cleanup(); | ||
| 586 | 539 | ||
| 587 | return 0; | 540 | /* Stop the timer before we leave */ |
| 588 | } | 541 | if (!nowayout) |
| 542 | iTCO_wdt_stop(&p->wddev); | ||
| 589 | 543 | ||
| 590 | static void iTCO_wdt_shutdown(struct platform_device *dev) | 544 | return 0; |
| 591 | { | ||
| 592 | iTCO_wdt_stop(NULL); | ||
| 593 | } | 545 | } |
| 594 | 546 | ||
| 595 | #ifdef CONFIG_PM_SLEEP | 547 | #ifdef CONFIG_PM_SLEEP |
| @@ -610,21 +562,24 @@ static inline bool need_suspend(void) { return true; } | |||
| 610 | 562 | ||
| 611 | static int iTCO_wdt_suspend_noirq(struct device *dev) | 563 | static int iTCO_wdt_suspend_noirq(struct device *dev) |
| 612 | { | 564 | { |
| 565 | struct iTCO_wdt_private *p = dev_get_drvdata(dev); | ||
| 613 | int ret = 0; | 566 | int ret = 0; |
| 614 | 567 | ||
| 615 | iTCO_wdt_private.suspended = false; | 568 | p->suspended = false; |
| 616 | if (watchdog_active(&iTCO_wdt_watchdog_dev) && need_suspend()) { | 569 | if (watchdog_active(&p->wddev) && need_suspend()) { |
| 617 | ret = iTCO_wdt_stop(&iTCO_wdt_watchdog_dev); | 570 | ret = iTCO_wdt_stop(&p->wddev); |
| 618 | if (!ret) | 571 | if (!ret) |
| 619 | iTCO_wdt_private.suspended = true; | 572 | p->suspended = true; |
| 620 | } | 573 | } |
| 621 | return ret; | 574 | return ret; |
| 622 | } | 575 | } |
| 623 | 576 | ||
| 624 | static int iTCO_wdt_resume_noirq(struct device *dev) | 577 | static int iTCO_wdt_resume_noirq(struct device *dev) |
| 625 | { | 578 | { |
| 626 | if (iTCO_wdt_private.suspended) | 579 | struct iTCO_wdt_private *p = dev_get_drvdata(dev); |
| 627 | iTCO_wdt_start(&iTCO_wdt_watchdog_dev); | 580 | |
| 581 | if (p->suspended) | ||
| 582 | iTCO_wdt_start(&p->wddev); | ||
| 628 | 583 | ||
| 629 | return 0; | 584 | return 0; |
| 630 | } | 585 | } |
| @@ -642,7 +597,6 @@ static const struct dev_pm_ops iTCO_wdt_pm = { | |||
| 642 | static struct platform_driver iTCO_wdt_driver = { | 597 | static struct platform_driver iTCO_wdt_driver = { |
| 643 | .probe = iTCO_wdt_probe, | 598 | .probe = iTCO_wdt_probe, |
| 644 | .remove = iTCO_wdt_remove, | 599 | .remove = iTCO_wdt_remove, |
| 645 | .shutdown = iTCO_wdt_shutdown, | ||
| 646 | .driver = { | 600 | .driver = { |
| 647 | .name = DRV_NAME, | 601 | .name = DRV_NAME, |
| 648 | .pm = ITCO_WDT_PM_OPS, | 602 | .pm = ITCO_WDT_PM_OPS, |
| @@ -651,15 +605,9 @@ static struct platform_driver iTCO_wdt_driver = { | |||
| 651 | 605 | ||
| 652 | static int __init iTCO_wdt_init_module(void) | 606 | static int __init iTCO_wdt_init_module(void) |
| 653 | { | 607 | { |
| 654 | int err; | ||
| 655 | |||
| 656 | pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION); | 608 | pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION); |
| 657 | 609 | ||
| 658 | err = platform_driver_register(&iTCO_wdt_driver); | 610 | return platform_driver_register(&iTCO_wdt_driver); |
| 659 | if (err) | ||
| 660 | return err; | ||
| 661 | |||
| 662 | return 0; | ||
| 663 | } | 611 | } |
| 664 | 612 | ||
| 665 | static void __exit iTCO_wdt_cleanup_module(void) | 613 | static void __exit iTCO_wdt_cleanup_module(void) |
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c index 516fbef00856..6ed39dee995f 100644 --- a/drivers/watchdog/imgpdc_wdt.c +++ b/drivers/watchdog/imgpdc_wdt.c | |||
| @@ -161,7 +161,7 @@ static int pdc_wdt_restart(struct watchdog_device *wdt_dev, | |||
| 161 | return 0; | 161 | return 0; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static struct watchdog_info pdc_wdt_info = { | 164 | static const struct watchdog_info pdc_wdt_info = { |
| 165 | .identity = "IMG PDC Watchdog", | 165 | .identity = "IMG PDC Watchdog", |
| 166 | .options = WDIOF_SETTIMEOUT | | 166 | .options = WDIOF_SETTIMEOUT | |
| 167 | WDIOF_KEEPALIVEPING | | 167 | WDIOF_KEEPALIVEPING | |
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index a4b729259b12..45e4d02221b5 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c | |||
| @@ -137,7 +137,6 @@ static int mid_wdt_probe(struct platform_device *pdev) | |||
| 137 | wdt_dev->parent = &pdev->dev; | 137 | wdt_dev->parent = &pdev->dev; |
| 138 | 138 | ||
| 139 | watchdog_set_drvdata(wdt_dev, &pdev->dev); | 139 | watchdog_set_drvdata(wdt_dev, &pdev->dev); |
| 140 | platform_set_drvdata(pdev, wdt_dev); | ||
| 141 | 140 | ||
| 142 | ret = devm_request_irq(&pdev->dev, pdata->irq, mid_wdt_irq, | 141 | ret = devm_request_irq(&pdev->dev, pdata->irq, mid_wdt_irq, |
| 143 | IRQF_SHARED | IRQF_NO_SUSPEND, "watchdog", | 142 | IRQF_SHARED | IRQF_NO_SUSPEND, "watchdog", |
| @@ -151,7 +150,7 @@ static int mid_wdt_probe(struct platform_device *pdev) | |||
| 151 | /* Make sure the watchdog is not running */ | 150 | /* Make sure the watchdog is not running */ |
| 152 | wdt_stop(wdt_dev); | 151 | wdt_stop(wdt_dev); |
| 153 | 152 | ||
| 154 | ret = watchdog_register_device(wdt_dev); | 153 | ret = devm_watchdog_register_device(&pdev->dev, wdt_dev); |
| 155 | if (ret) { | 154 | if (ret) { |
| 156 | dev_err(&pdev->dev, "error registering watchdog device\n"); | 155 | dev_err(&pdev->dev, "error registering watchdog device\n"); |
| 157 | return ret; | 156 | return ret; |
| @@ -162,16 +161,8 @@ static int mid_wdt_probe(struct platform_device *pdev) | |||
| 162 | return 0; | 161 | return 0; |
| 163 | } | 162 | } |
| 164 | 163 | ||
| 165 | static int mid_wdt_remove(struct platform_device *pdev) | ||
| 166 | { | ||
| 167 | struct watchdog_device *wd = platform_get_drvdata(pdev); | ||
| 168 | watchdog_unregister_device(wd); | ||
| 169 | return 0; | ||
| 170 | } | ||
| 171 | |||
| 172 | static struct platform_driver mid_wdt_driver = { | 164 | static struct platform_driver mid_wdt_driver = { |
| 173 | .probe = mid_wdt_probe, | 165 | .probe = mid_wdt_probe, |
| 174 | .remove = mid_wdt_remove, | ||
| 175 | .driver = { | 166 | .driver = { |
| 176 | .name = "intel_mid_wdt", | 167 | .name = "intel_mid_wdt", |
| 177 | }, | 168 | }, |
diff --git a/drivers/watchdog/kempld_wdt.c b/drivers/watchdog/kempld_wdt.c index 8e302d0e346c..73c46b3a09ab 100644 --- a/drivers/watchdog/kempld_wdt.c +++ b/drivers/watchdog/kempld_wdt.c | |||
| @@ -422,7 +422,7 @@ static int kempld_wdt_probe_stages(struct watchdog_device *wdd) | |||
| 422 | return 0; | 422 | return 0; |
| 423 | } | 423 | } |
| 424 | 424 | ||
| 425 | static struct watchdog_info kempld_wdt_info = { | 425 | static const struct watchdog_info kempld_wdt_info = { |
| 426 | .identity = "KEMPLD Watchdog", | 426 | .identity = "KEMPLD Watchdog", |
| 427 | .options = WDIOF_SETTIMEOUT | | 427 | .options = WDIOF_SETTIMEOUT | |
| 428 | WDIOF_KEEPALIVEPING | | 428 | WDIOF_KEEPALIVEPING | |
diff --git a/drivers/watchdog/lantiq_wdt.c b/drivers/watchdog/lantiq_wdt.c index 582f2fa1b8d9..e0823677d8c1 100644 --- a/drivers/watchdog/lantiq_wdt.c +++ b/drivers/watchdog/lantiq_wdt.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * under the terms of the GNU General Public License version 2 as published | 3 | * under the terms of the GNU General Public License version 2 as published |
| 4 | * by the Free Software Foundation. | 4 | * by the Free Software Foundation. |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2010 John Crispin <blogic@openwrt.org> | 6 | * Copyright (C) 2010 John Crispin <john@phrozen.org> |
| 7 | * Based on EP93xx wdt driver | 7 | * Based on EP93xx wdt driver |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| @@ -240,6 +240,6 @@ module_platform_driver(ltq_wdt_driver); | |||
| 240 | 240 | ||
| 241 | module_param(nowayout, bool, 0); | 241 | module_param(nowayout, bool, 0); |
| 242 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); | 242 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started"); |
| 243 | MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); | 243 | MODULE_AUTHOR("John Crispin <john@phrozen.org>"); |
| 244 | MODULE_DESCRIPTION("Lantiq SoC Watchdog"); | 244 | MODULE_DESCRIPTION("Lantiq SoC Watchdog"); |
| 245 | MODULE_LICENSE("GPL"); | 245 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c index fd171e6caa16..3b8bb59adf02 100644 --- a/drivers/watchdog/lpc18xx_wdt.c +++ b/drivers/watchdog/lpc18xx_wdt.c | |||
| @@ -181,7 +181,7 @@ static int lpc18xx_wdt_restart(struct watchdog_device *wdt_dev, | |||
| 181 | return 0; | 181 | return 0; |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | static struct watchdog_info lpc18xx_wdt_info = { | 184 | static const struct watchdog_info lpc18xx_wdt_info = { |
| 185 | .identity = "NXP LPC18xx Watchdog", | 185 | .identity = "NXP LPC18xx Watchdog", |
| 186 | .options = WDIOF_SETTIMEOUT | | 186 | .options = WDIOF_SETTIMEOUT | |
| 187 | WDIOF_KEEPALIVEPING | | 187 | WDIOF_KEEPALIVEPING | |
diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c index af6a7c489f08..045201a6fdb3 100644 --- a/drivers/watchdog/mena21_wdt.c +++ b/drivers/watchdog/mena21_wdt.c | |||
| @@ -212,34 +212,15 @@ static int a21_wdt_probe(struct platform_device *pdev) | |||
| 212 | drv->wdt = a21_wdt; | 212 | drv->wdt = a21_wdt; |
| 213 | dev_set_drvdata(&pdev->dev, drv); | 213 | dev_set_drvdata(&pdev->dev, drv); |
| 214 | 214 | ||
| 215 | ret = watchdog_register_device(&a21_wdt); | 215 | ret = devm_watchdog_register_device(&pdev->dev, &a21_wdt); |
| 216 | if (ret) { | 216 | if (ret) { |
| 217 | dev_err(&pdev->dev, "Cannot register watchdog device\n"); | 217 | dev_err(&pdev->dev, "Cannot register watchdog device\n"); |
| 218 | goto err_register_wd; | 218 | return ret; |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n"); | 221 | dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n"); |
| 222 | 222 | ||
| 223 | return 0; | 223 | return 0; |
| 224 | |||
| 225 | err_register_wd: | ||
| 226 | mutex_destroy(&drv->lock); | ||
| 227 | |||
| 228 | return ret; | ||
| 229 | } | ||
| 230 | |||
| 231 | static int a21_wdt_remove(struct platform_device *pdev) | ||
| 232 | { | ||
| 233 | struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev); | ||
| 234 | |||
| 235 | dev_warn(&pdev->dev, | ||
| 236 | "Unregistering A21 watchdog driver, board may reboot\n"); | ||
| 237 | |||
| 238 | watchdog_unregister_device(&drv->wdt); | ||
| 239 | |||
| 240 | mutex_destroy(&drv->lock); | ||
| 241 | |||
| 242 | return 0; | ||
| 243 | } | 224 | } |
| 244 | 225 | ||
| 245 | static void a21_wdt_shutdown(struct platform_device *pdev) | 226 | static void a21_wdt_shutdown(struct platform_device *pdev) |
| @@ -257,7 +238,6 @@ MODULE_DEVICE_TABLE(of, a21_wdt_ids); | |||
| 257 | 238 | ||
| 258 | static struct platform_driver a21_wdt_driver = { | 239 | static struct platform_driver a21_wdt_driver = { |
| 259 | .probe = a21_wdt_probe, | 240 | .probe = a21_wdt_probe, |
| 260 | .remove = a21_wdt_remove, | ||
| 261 | .shutdown = a21_wdt_shutdown, | 241 | .shutdown = a21_wdt_shutdown, |
| 262 | .driver = { | 242 | .driver = { |
| 263 | .name = "a21-watchdog", | 243 | .name = "a21-watchdog", |
diff --git a/drivers/watchdog/meson_wdt.c b/drivers/watchdog/meson_wdt.c index 56ea1caf71c3..491b9bf13d84 100644 --- a/drivers/watchdog/meson_wdt.c +++ b/drivers/watchdog/meson_wdt.c | |||
| @@ -201,38 +201,19 @@ static int meson_wdt_probe(struct platform_device *pdev) | |||
| 201 | 201 | ||
| 202 | meson_wdt_stop(&meson_wdt->wdt_dev); | 202 | meson_wdt_stop(&meson_wdt->wdt_dev); |
| 203 | 203 | ||
| 204 | err = watchdog_register_device(&meson_wdt->wdt_dev); | 204 | watchdog_stop_on_reboot(&meson_wdt->wdt_dev); |
| 205 | err = devm_watchdog_register_device(&pdev->dev, &meson_wdt->wdt_dev); | ||
| 205 | if (err) | 206 | if (err) |
| 206 | return err; | 207 | return err; |
| 207 | 208 | ||
| 208 | platform_set_drvdata(pdev, meson_wdt); | ||
| 209 | |||
| 210 | dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", | 209 | dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)", |
| 211 | meson_wdt->wdt_dev.timeout, nowayout); | 210 | meson_wdt->wdt_dev.timeout, nowayout); |
| 212 | 211 | ||
| 213 | return 0; | 212 | return 0; |
| 214 | } | 213 | } |
| 215 | 214 | ||
| 216 | static int meson_wdt_remove(struct platform_device *pdev) | ||
| 217 | { | ||
| 218 | struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev); | ||
| 219 | |||
| 220 | watchdog_unregister_device(&meson_wdt->wdt_dev); | ||
| 221 | |||
| 222 | return 0; | ||
| 223 | } | ||
| 224 | |||
| 225 | static void meson_wdt_shutdown(struct platform_device *pdev) | ||
| 226 | { | ||
| 227 | struct meson_wdt_dev *meson_wdt = platform_get_drvdata(pdev); | ||
| 228 | |||
| 229 | meson_wdt_stop(&meson_wdt->wdt_dev); | ||
| 230 | } | ||
| 231 | |||
| 232 | static struct platform_driver meson_wdt_driver = { | 215 | static struct platform_driver meson_wdt_driver = { |
| 233 | .probe = meson_wdt_probe, | 216 | .probe = meson_wdt_probe, |
| 234 | .remove = meson_wdt_remove, | ||
| 235 | .shutdown = meson_wdt_shutdown, | ||
| 236 | .driver = { | 217 | .driver = { |
| 237 | .name = DRV_NAME, | 218 | .name = DRV_NAME, |
| 238 | .of_match_table = meson_wdt_dt_ids, | 219 | .of_match_table = meson_wdt_dt_ids, |
diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c index d5735c12067d..48a06067075d 100644 --- a/drivers/watchdog/mt7621_wdt.c +++ b/drivers/watchdog/mt7621_wdt.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Ralink MT7621/MT7628 built-in hardware watchdog timer | 2 | * Ralink MT7621/MT7628 built-in hardware watchdog timer |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2014 John Crispin <blogic@openwrt.org> | 4 | * Copyright (C) 2014 John Crispin <john@phrozen.org> |
| 5 | * | 5 | * |
| 6 | * This driver was based on: drivers/watchdog/rt2880_wdt.c | 6 | * This driver was based on: drivers/watchdog/rt2880_wdt.c |
| 7 | * | 7 | * |
| @@ -110,7 +110,7 @@ static struct watchdog_info mt7621_wdt_info = { | |||
| 110 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | 110 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, |
| 111 | }; | 111 | }; |
| 112 | 112 | ||
| 113 | static struct watchdog_ops mt7621_wdt_ops = { | 113 | static const struct watchdog_ops mt7621_wdt_ops = { |
| 114 | .owner = THIS_MODULE, | 114 | .owner = THIS_MODULE, |
| 115 | .start = mt7621_wdt_start, | 115 | .start = mt7621_wdt_start, |
| 116 | .stop = mt7621_wdt_stop, | 116 | .stop = mt7621_wdt_stop, |
| @@ -181,5 +181,5 @@ static struct platform_driver mt7621_wdt_driver = { | |||
| 181 | module_platform_driver(mt7621_wdt_driver); | 181 | module_platform_driver(mt7621_wdt_driver); |
| 182 | 182 | ||
| 183 | MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver"); | 183 | MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver"); |
| 184 | MODULE_AUTHOR("John Crispin <blogic@openwrt.org"); | 184 | MODULE_AUTHOR("John Crispin <john@phrozen.org"); |
| 185 | MODULE_LICENSE("GPL v2"); | 185 | MODULE_LICENSE("GPL v2"); |
diff --git a/drivers/watchdog/nic7018_wdt.c b/drivers/watchdog/nic7018_wdt.c new file mode 100644 index 000000000000..dcd265685837 --- /dev/null +++ b/drivers/watchdog/nic7018_wdt.c | |||
| @@ -0,0 +1,265 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2016 National Instruments Corp. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/acpi.h> | ||
| 16 | #include <linux/bitops.h> | ||
| 17 | #include <linux/device.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/watchdog.h> | ||
| 22 | |||
| 23 | #define LOCK 0xA5 | ||
| 24 | #define UNLOCK 0x5A | ||
| 25 | |||
| 26 | #define WDT_CTRL_RESET_EN BIT(7) | ||
| 27 | #define WDT_RELOAD_PORT_EN BIT(7) | ||
| 28 | |||
| 29 | #define WDT_CTRL 1 | ||
| 30 | #define WDT_RELOAD_CTRL 2 | ||
| 31 | #define WDT_PRESET_PRESCALE 4 | ||
| 32 | #define WDT_REG_LOCK 5 | ||
| 33 | #define WDT_COUNT 6 | ||
| 34 | #define WDT_RELOAD_PORT 7 | ||
| 35 | |||
| 36 | #define WDT_MIN_TIMEOUT 1 | ||
| 37 | #define WDT_MAX_TIMEOUT 464 | ||
| 38 | #define WDT_DEFAULT_TIMEOUT 80 | ||
| 39 | |||
| 40 | #define WDT_MAX_COUNTER 15 | ||
| 41 | |||
| 42 | static unsigned int timeout; | ||
| 43 | module_param(timeout, uint, 0); | ||
| 44 | MODULE_PARM_DESC(timeout, | ||
| 45 | "Watchdog timeout in seconds. (default=" | ||
| 46 | __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")"); | ||
| 47 | |||
| 48 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
| 49 | module_param(nowayout, bool, 0); | ||
| 50 | MODULE_PARM_DESC(nowayout, | ||
| 51 | "Watchdog cannot be stopped once started. (default=" | ||
| 52 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 53 | |||
| 54 | struct nic7018_wdt { | ||
| 55 | u16 io_base; | ||
| 56 | u32 period; | ||
| 57 | struct watchdog_device wdd; | ||
| 58 | }; | ||
| 59 | |||
| 60 | struct nic7018_config { | ||
| 61 | u32 period; | ||
| 62 | u8 divider; | ||
| 63 | }; | ||
| 64 | |||
| 65 | static const struct nic7018_config nic7018_configs[] = { | ||
| 66 | { 2, 4 }, | ||
| 67 | { 32, 5 }, | ||
| 68 | }; | ||
| 69 | |||
| 70 | static inline u32 nic7018_timeout(u32 period, u8 counter) | ||
| 71 | { | ||
| 72 | return period * counter - period / 2; | ||
| 73 | } | ||
| 74 | |||
| 75 | static const struct nic7018_config *nic7018_get_config(u32 timeout, | ||
| 76 | u8 *counter) | ||
| 77 | { | ||
| 78 | const struct nic7018_config *config; | ||
| 79 | u8 count; | ||
| 80 | |||
| 81 | if (timeout < 30 && timeout != 16) { | ||
| 82 | config = &nic7018_configs[0]; | ||
| 83 | count = timeout / 2 + 1; | ||
| 84 | } else { | ||
| 85 | config = &nic7018_configs[1]; | ||
| 86 | count = DIV_ROUND_UP(timeout + 16, 32); | ||
| 87 | |||
| 88 | if (count > WDT_MAX_COUNTER) | ||
| 89 | count = WDT_MAX_COUNTER; | ||
| 90 | } | ||
| 91 | *counter = count; | ||
| 92 | return config; | ||
| 93 | } | ||
| 94 | |||
| 95 | static int nic7018_set_timeout(struct watchdog_device *wdd, | ||
| 96 | unsigned int timeout) | ||
| 97 | { | ||
| 98 | struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 99 | const struct nic7018_config *config; | ||
| 100 | u8 counter; | ||
| 101 | |||
| 102 | config = nic7018_get_config(timeout, &counter); | ||
| 103 | |||
| 104 | outb(counter << 4 | config->divider, | ||
| 105 | wdt->io_base + WDT_PRESET_PRESCALE); | ||
| 106 | |||
| 107 | wdd->timeout = nic7018_timeout(config->period, counter); | ||
| 108 | wdt->period = config->period; | ||
| 109 | |||
| 110 | return 0; | ||
| 111 | } | ||
| 112 | |||
| 113 | static int nic7018_start(struct watchdog_device *wdd) | ||
| 114 | { | ||
| 115 | struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 116 | u8 control; | ||
| 117 | |||
| 118 | nic7018_set_timeout(wdd, wdd->timeout); | ||
| 119 | |||
| 120 | control = inb(wdt->io_base + WDT_RELOAD_CTRL); | ||
| 121 | outb(control | WDT_RELOAD_PORT_EN, wdt->io_base + WDT_RELOAD_CTRL); | ||
| 122 | |||
| 123 | outb(1, wdt->io_base + WDT_RELOAD_PORT); | ||
| 124 | |||
| 125 | control = inb(wdt->io_base + WDT_CTRL); | ||
| 126 | outb(control | WDT_CTRL_RESET_EN, wdt->io_base + WDT_CTRL); | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int nic7018_stop(struct watchdog_device *wdd) | ||
| 132 | { | ||
| 133 | struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 134 | |||
| 135 | outb(0, wdt->io_base + WDT_CTRL); | ||
| 136 | outb(0, wdt->io_base + WDT_RELOAD_CTRL); | ||
| 137 | outb(0xF0, wdt->io_base + WDT_PRESET_PRESCALE); | ||
| 138 | |||
| 139 | return 0; | ||
| 140 | } | ||
| 141 | |||
| 142 | static int nic7018_ping(struct watchdog_device *wdd) | ||
| 143 | { | ||
| 144 | struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 145 | |||
| 146 | outb(1, wdt->io_base + WDT_RELOAD_PORT); | ||
| 147 | |||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static unsigned int nic7018_get_timeleft(struct watchdog_device *wdd) | ||
| 152 | { | ||
| 153 | struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 154 | u8 count; | ||
| 155 | |||
| 156 | count = inb(wdt->io_base + WDT_COUNT) & 0xF; | ||
| 157 | if (!count) | ||
| 158 | return 0; | ||
| 159 | |||
| 160 | return nic7018_timeout(wdt->period, count); | ||
| 161 | } | ||
| 162 | |||
| 163 | static const struct watchdog_info nic7018_wdd_info = { | ||
| 164 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | ||
| 165 | .identity = "NIC7018 Watchdog", | ||
| 166 | }; | ||
| 167 | |||
| 168 | static const struct watchdog_ops nic7018_wdd_ops = { | ||
| 169 | .owner = THIS_MODULE, | ||
| 170 | .start = nic7018_start, | ||
| 171 | .stop = nic7018_stop, | ||
| 172 | .ping = nic7018_ping, | ||
| 173 | .set_timeout = nic7018_set_timeout, | ||
| 174 | .get_timeleft = nic7018_get_timeleft, | ||
| 175 | }; | ||
| 176 | |||
| 177 | static int nic7018_probe(struct platform_device *pdev) | ||
| 178 | { | ||
| 179 | struct device *dev = &pdev->dev; | ||
| 180 | struct watchdog_device *wdd; | ||
| 181 | struct nic7018_wdt *wdt; | ||
| 182 | struct resource *io_rc; | ||
| 183 | int ret; | ||
| 184 | |||
| 185 | wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); | ||
| 186 | if (!wdt) | ||
| 187 | return -ENOMEM; | ||
| 188 | |||
| 189 | platform_set_drvdata(pdev, wdt); | ||
| 190 | |||
| 191 | io_rc = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
| 192 | if (!io_rc) { | ||
| 193 | dev_err(dev, "missing IO resources\n"); | ||
| 194 | return -EINVAL; | ||
| 195 | } | ||
| 196 | |||
| 197 | if (!devm_request_region(dev, io_rc->start, resource_size(io_rc), | ||
| 198 | KBUILD_MODNAME)) { | ||
| 199 | dev_err(dev, "failed to get IO region\n"); | ||
| 200 | return -EBUSY; | ||
| 201 | } | ||
| 202 | |||
| 203 | wdt->io_base = io_rc->start; | ||
| 204 | wdd = &wdt->wdd; | ||
| 205 | wdd->info = &nic7018_wdd_info; | ||
| 206 | wdd->ops = &nic7018_wdd_ops; | ||
| 207 | wdd->min_timeout = WDT_MIN_TIMEOUT; | ||
| 208 | wdd->max_timeout = WDT_MAX_TIMEOUT; | ||
| 209 | wdd->timeout = WDT_DEFAULT_TIMEOUT; | ||
| 210 | wdd->parent = dev; | ||
| 211 | |||
| 212 | watchdog_set_drvdata(wdd, wdt); | ||
| 213 | watchdog_set_nowayout(wdd, nowayout); | ||
| 214 | |||
| 215 | ret = watchdog_init_timeout(wdd, timeout, dev); | ||
| 216 | if (ret) | ||
| 217 | dev_warn(dev, "unable to set timeout value, using default\n"); | ||
| 218 | |||
| 219 | /* Unlock WDT register */ | ||
| 220 | outb(UNLOCK, wdt->io_base + WDT_REG_LOCK); | ||
| 221 | |||
| 222 | ret = watchdog_register_device(wdd); | ||
| 223 | if (ret) { | ||
| 224 | outb(LOCK, wdt->io_base + WDT_REG_LOCK); | ||
| 225 | dev_err(dev, "failed to register watchdog\n"); | ||
| 226 | return ret; | ||
| 227 | } | ||
| 228 | |||
| 229 | dev_dbg(dev, "io_base=0x%04X, timeout=%d, nowayout=%d\n", | ||
| 230 | wdt->io_base, timeout, nowayout); | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | static int nic7018_remove(struct platform_device *pdev) | ||
| 235 | { | ||
| 236 | struct nic7018_wdt *wdt = platform_get_drvdata(pdev); | ||
| 237 | |||
| 238 | watchdog_unregister_device(&wdt->wdd); | ||
| 239 | |||
| 240 | /* Lock WDT register */ | ||
| 241 | outb(LOCK, wdt->io_base + WDT_REG_LOCK); | ||
| 242 | |||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | static const struct acpi_device_id nic7018_device_ids[] = { | ||
| 247 | {"NIC7018", 0}, | ||
| 248 | {"", 0}, | ||
| 249 | }; | ||
| 250 | MODULE_DEVICE_TABLE(acpi, nic7018_device_ids); | ||
| 251 | |||
| 252 | static struct platform_driver watchdog_driver = { | ||
| 253 | .probe = nic7018_probe, | ||
| 254 | .remove = nic7018_remove, | ||
| 255 | .driver = { | ||
| 256 | .name = KBUILD_MODNAME, | ||
| 257 | .acpi_match_table = ACPI_PTR(nic7018_device_ids), | ||
| 258 | }, | ||
| 259 | }; | ||
| 260 | |||
| 261 | module_platform_driver(watchdog_driver); | ||
| 262 | |||
| 263 | MODULE_DESCRIPTION("National Instruments NIC7018 Watchdog driver"); | ||
| 264 | MODULE_AUTHOR("Hui Chun Ong <hui.chun.ong@ni.com>"); | ||
| 265 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index c6b8f4a43bde..39be4dd8035e 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c | |||
| @@ -395,7 +395,7 @@ static void __iomem *orion_wdt_ioremap_rstout(struct platform_device *pdev, | |||
| 395 | 395 | ||
| 396 | rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET; | 396 | rstout = internal_regs + ORION_RSTOUT_MASK_OFFSET; |
| 397 | 397 | ||
| 398 | WARN(1, FW_BUG "falling back to harcoded RSTOUT reg %pa\n", &rstout); | 398 | WARN(1, FW_BUG "falling back to hardcoded RSTOUT reg %pa\n", &rstout); |
| 399 | return devm_ioremap(&pdev->dev, rstout, 0x4); | 399 | return devm_ioremap(&pdev->dev, rstout, 0x4); |
| 400 | } | 400 | } |
| 401 | 401 | ||
diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c index 0cdfee266690..e35cf5e87907 100644 --- a/drivers/watchdog/pika_wdt.c +++ b/drivers/watchdog/pika_wdt.c | |||
| @@ -54,7 +54,7 @@ static struct { | |||
| 54 | struct timer_list timer; /* The timer that pings the watchdog */ | 54 | struct timer_list timer; /* The timer that pings the watchdog */ |
| 55 | } pikawdt_private; | 55 | } pikawdt_private; |
| 56 | 56 | ||
| 57 | static struct watchdog_info ident = { | 57 | static struct watchdog_info ident __ro_after_init = { |
| 58 | .identity = DRV_NAME, | 58 | .identity = DRV_NAME, |
| 59 | .options = WDIOF_CARDRESET | | 59 | .options = WDIOF_CARDRESET | |
| 60 | WDIOF_SETTIMEOUT | | 60 | WDIOF_SETTIMEOUT | |
diff --git a/drivers/watchdog/rn5t618_wdt.c b/drivers/watchdog/rn5t618_wdt.c index 0805ee2acd7a..e60f55702ab7 100644 --- a/drivers/watchdog/rn5t618_wdt.c +++ b/drivers/watchdog/rn5t618_wdt.c | |||
| @@ -130,7 +130,7 @@ static int rn5t618_wdt_ping(struct watchdog_device *wdt_dev) | |||
| 130 | RN5T618_PWRIRQ_IR_WDOG, 0); | 130 | RN5T618_PWRIRQ_IR_WDOG, 0); |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | static struct watchdog_info rn5t618_wdt_info = { | 133 | static const struct watchdog_info rn5t618_wdt_info = { |
| 134 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | | 134 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | |
| 135 | WDIOF_KEEPALIVEPING, | 135 | WDIOF_KEEPALIVEPING, |
| 136 | .identity = DRIVER_NAME, | 136 | .identity = DRIVER_NAME, |
diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index 14b4fd428fff..05524baf7dcc 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | * Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer | 2 | * Ralink RT288x/RT3xxx/MT76xx built-in hardware watchdog timer |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> | 4 | * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> |
| 5 | * Copyright (C) 2013 John Crispin <blogic@openwrt.org> | 5 | * Copyright (C) 2013 John Crispin <john@phrozen.org> |
| 6 | * | 6 | * |
| 7 | * This driver was based on: drivers/watchdog/softdog.c | 7 | * This driver was based on: drivers/watchdog/softdog.c |
| 8 | * | 8 | * |
| @@ -124,7 +124,7 @@ static struct watchdog_info rt288x_wdt_info = { | |||
| 124 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | 124 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, |
| 125 | }; | 125 | }; |
| 126 | 126 | ||
| 127 | static struct watchdog_ops rt288x_wdt_ops = { | 127 | static const struct watchdog_ops rt288x_wdt_ops = { |
| 128 | .owner = THIS_MODULE, | 128 | .owner = THIS_MODULE, |
| 129 | .start = rt288x_wdt_start, | 129 | .start = rt288x_wdt_start, |
| 130 | .stop = rt288x_wdt_stop, | 130 | .stop = rt288x_wdt_stop, |
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 59e95762a6de..6ed97596ca80 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
| @@ -23,8 +23,6 @@ | |||
| 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 27 | |||
| 28 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 29 | #include <linux/moduleparam.h> | 27 | #include <linux/moduleparam.h> |
| 30 | #include <linux/types.h> | 28 | #include <linux/types.h> |
| @@ -46,6 +44,7 @@ | |||
| 46 | #define S3C2410_WTCON 0x00 | 44 | #define S3C2410_WTCON 0x00 |
| 47 | #define S3C2410_WTDAT 0x04 | 45 | #define S3C2410_WTDAT 0x04 |
| 48 | #define S3C2410_WTCNT 0x08 | 46 | #define S3C2410_WTCNT 0x08 |
| 47 | #define S3C2410_WTCLRINT 0x0c | ||
| 49 | 48 | ||
| 50 | #define S3C2410_WTCNT_MAXCNT 0xffff | 49 | #define S3C2410_WTCNT_MAXCNT 0xffff |
| 51 | 50 | ||
| @@ -64,14 +63,15 @@ | |||
| 64 | #define S3C2410_WTCON_PRESCALE_MASK (0xff << 8) | 63 | #define S3C2410_WTCON_PRESCALE_MASK (0xff << 8) |
| 65 | #define S3C2410_WTCON_PRESCALE_MAX 0xff | 64 | #define S3C2410_WTCON_PRESCALE_MAX 0xff |
| 66 | 65 | ||
| 67 | #define CONFIG_S3C2410_WATCHDOG_ATBOOT (0) | 66 | #define S3C2410_WATCHDOG_ATBOOT (0) |
| 68 | #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15) | 67 | #define S3C2410_WATCHDOG_DEFAULT_TIME (15) |
| 69 | 68 | ||
| 70 | #define EXYNOS5_RST_STAT_REG_OFFSET 0x0404 | 69 | #define EXYNOS5_RST_STAT_REG_OFFSET 0x0404 |
| 71 | #define EXYNOS5_WDT_DISABLE_REG_OFFSET 0x0408 | 70 | #define EXYNOS5_WDT_DISABLE_REG_OFFSET 0x0408 |
| 72 | #define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c | 71 | #define EXYNOS5_WDT_MASK_RESET_REG_OFFSET 0x040c |
| 73 | #define QUIRK_HAS_PMU_CONFIG (1 << 0) | 72 | #define QUIRK_HAS_PMU_CONFIG (1 << 0) |
| 74 | #define QUIRK_HAS_RST_STAT (1 << 1) | 73 | #define QUIRK_HAS_RST_STAT (1 << 1) |
| 74 | #define QUIRK_HAS_WTCLRINT_REG (1 << 2) | ||
| 75 | 75 | ||
| 76 | /* These quirks require that we have a PMU register map */ | 76 | /* These quirks require that we have a PMU register map */ |
| 77 | #define QUIRKS_HAVE_PMUREG (QUIRK_HAS_PMU_CONFIG | \ | 77 | #define QUIRKS_HAVE_PMUREG (QUIRK_HAS_PMU_CONFIG | \ |
| @@ -79,26 +79,23 @@ | |||
| 79 | 79 | ||
| 80 | static bool nowayout = WATCHDOG_NOWAYOUT; | 80 | static bool nowayout = WATCHDOG_NOWAYOUT; |
| 81 | static int tmr_margin; | 81 | static int tmr_margin; |
| 82 | static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT; | 82 | static int tmr_atboot = S3C2410_WATCHDOG_ATBOOT; |
| 83 | static int soft_noboot; | 83 | static int soft_noboot; |
| 84 | static int debug; | ||
| 85 | 84 | ||
| 86 | module_param(tmr_margin, int, 0); | 85 | module_param(tmr_margin, int, 0); |
| 87 | module_param(tmr_atboot, int, 0); | 86 | module_param(tmr_atboot, int, 0); |
| 88 | module_param(nowayout, bool, 0); | 87 | module_param(nowayout, bool, 0); |
| 89 | module_param(soft_noboot, int, 0); | 88 | module_param(soft_noboot, int, 0); |
| 90 | module_param(debug, int, 0); | ||
| 91 | 89 | ||
| 92 | MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default=" | 90 | MODULE_PARM_DESC(tmr_margin, "Watchdog tmr_margin in seconds. (default=" |
| 93 | __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME) ")"); | 91 | __MODULE_STRING(S3C2410_WATCHDOG_DEFAULT_TIME) ")"); |
| 94 | MODULE_PARM_DESC(tmr_atboot, | 92 | MODULE_PARM_DESC(tmr_atboot, |
| 95 | "Watchdog is started at boot time if set to 1, default=" | 93 | "Watchdog is started at boot time if set to 1, default=" |
| 96 | __MODULE_STRING(CONFIG_S3C2410_WATCHDOG_ATBOOT)); | 94 | __MODULE_STRING(S3C2410_WATCHDOG_ATBOOT)); |
| 97 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 95 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
| 98 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 96 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
| 99 | MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " | 97 | MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " |
| 100 | "0 to reboot (default 0)"); | 98 | "0 to reboot (default 0)"); |
| 101 | MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)"); | ||
| 102 | 99 | ||
| 103 | /** | 100 | /** |
| 104 | * struct s3c2410_wdt_variant - Per-variant config data | 101 | * struct s3c2410_wdt_variant - Per-variant config data |
| @@ -143,13 +140,18 @@ static const struct s3c2410_wdt_variant drv_data_s3c2410 = { | |||
| 143 | }; | 140 | }; |
| 144 | 141 | ||
| 145 | #ifdef CONFIG_OF | 142 | #ifdef CONFIG_OF |
| 143 | static const struct s3c2410_wdt_variant drv_data_s3c6410 = { | ||
| 144 | .quirks = QUIRK_HAS_WTCLRINT_REG, | ||
| 145 | }; | ||
| 146 | |||
| 146 | static const struct s3c2410_wdt_variant drv_data_exynos5250 = { | 147 | static const struct s3c2410_wdt_variant drv_data_exynos5250 = { |
| 147 | .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, | 148 | .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, |
| 148 | .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, | 149 | .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, |
| 149 | .mask_bit = 20, | 150 | .mask_bit = 20, |
| 150 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, | 151 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, |
| 151 | .rst_stat_bit = 20, | 152 | .rst_stat_bit = 20, |
| 152 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, | 153 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \ |
| 154 | | QUIRK_HAS_WTCLRINT_REG, | ||
| 153 | }; | 155 | }; |
| 154 | 156 | ||
| 155 | static const struct s3c2410_wdt_variant drv_data_exynos5420 = { | 157 | static const struct s3c2410_wdt_variant drv_data_exynos5420 = { |
| @@ -158,7 +160,8 @@ static const struct s3c2410_wdt_variant drv_data_exynos5420 = { | |||
| 158 | .mask_bit = 0, | 160 | .mask_bit = 0, |
| 159 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, | 161 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, |
| 160 | .rst_stat_bit = 9, | 162 | .rst_stat_bit = 9, |
| 161 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, | 163 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \ |
| 164 | | QUIRK_HAS_WTCLRINT_REG, | ||
| 162 | }; | 165 | }; |
| 163 | 166 | ||
| 164 | static const struct s3c2410_wdt_variant drv_data_exynos7 = { | 167 | static const struct s3c2410_wdt_variant drv_data_exynos7 = { |
| @@ -167,12 +170,15 @@ static const struct s3c2410_wdt_variant drv_data_exynos7 = { | |||
| 167 | .mask_bit = 23, | 170 | .mask_bit = 23, |
| 168 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, | 171 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, |
| 169 | .rst_stat_bit = 23, /* A57 WDTRESET */ | 172 | .rst_stat_bit = 23, /* A57 WDTRESET */ |
| 170 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, | 173 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT \ |
| 174 | | QUIRK_HAS_WTCLRINT_REG, | ||
| 171 | }; | 175 | }; |
| 172 | 176 | ||
| 173 | static const struct of_device_id s3c2410_wdt_match[] = { | 177 | static const struct of_device_id s3c2410_wdt_match[] = { |
| 174 | { .compatible = "samsung,s3c2410-wdt", | 178 | { .compatible = "samsung,s3c2410-wdt", |
| 175 | .data = &drv_data_s3c2410 }, | 179 | .data = &drv_data_s3c2410 }, |
| 180 | { .compatible = "samsung,s3c6410-wdt", | ||
| 181 | .data = &drv_data_s3c6410 }, | ||
| 176 | { .compatible = "samsung,exynos5250-wdt", | 182 | { .compatible = "samsung,exynos5250-wdt", |
| 177 | .data = &drv_data_exynos5250 }, | 183 | .data = &drv_data_exynos5250 }, |
| 178 | { .compatible = "samsung,exynos5420-wdt", | 184 | { .compatible = "samsung,exynos5420-wdt", |
| @@ -193,14 +199,6 @@ static const struct platform_device_id s3c2410_wdt_ids[] = { | |||
| 193 | }; | 199 | }; |
| 194 | MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids); | 200 | MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids); |
| 195 | 201 | ||
| 196 | /* watchdog control routines */ | ||
| 197 | |||
| 198 | #define DBG(fmt, ...) \ | ||
| 199 | do { \ | ||
| 200 | if (debug) \ | ||
| 201 | pr_info(fmt, ##__VA_ARGS__); \ | ||
| 202 | } while (0) | ||
| 203 | |||
| 204 | /* functions */ | 202 | /* functions */ |
| 205 | 203 | ||
| 206 | static inline unsigned int s3c2410wdt_max_timeout(struct clk *clock) | 204 | static inline unsigned int s3c2410wdt_max_timeout(struct clk *clock) |
| @@ -296,8 +294,8 @@ static int s3c2410wdt_start(struct watchdog_device *wdd) | |||
| 296 | wtcon |= S3C2410_WTCON_RSTEN; | 294 | wtcon |= S3C2410_WTCON_RSTEN; |
| 297 | } | 295 | } |
| 298 | 296 | ||
| 299 | DBG("%s: count=0x%08x, wtcon=%08lx\n", | 297 | dev_dbg(wdt->dev, "Starting watchdog: count=0x%08x, wtcon=%08lx\n", |
| 300 | __func__, wdt->count, wtcon); | 298 | wdt->count, wtcon); |
| 301 | 299 | ||
| 302 | writel(wdt->count, wdt->reg_base + S3C2410_WTDAT); | 300 | writel(wdt->count, wdt->reg_base + S3C2410_WTDAT); |
| 303 | writel(wdt->count, wdt->reg_base + S3C2410_WTCNT); | 301 | writel(wdt->count, wdt->reg_base + S3C2410_WTCNT); |
| @@ -326,8 +324,8 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou | |||
| 326 | freq = DIV_ROUND_UP(freq, 128); | 324 | freq = DIV_ROUND_UP(freq, 128); |
| 327 | count = timeout * freq; | 325 | count = timeout * freq; |
| 328 | 326 | ||
| 329 | DBG("%s: count=%d, timeout=%d, freq=%lu\n", | 327 | dev_dbg(wdt->dev, "Heartbeat: count=%d, timeout=%d, freq=%lu\n", |
| 330 | __func__, count, timeout, freq); | 328 | count, timeout, freq); |
| 331 | 329 | ||
| 332 | /* if the count is bigger than the watchdog register, | 330 | /* if the count is bigger than the watchdog register, |
| 333 | then work out what we need to do (and if) we can | 331 | 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 | |||
| 343 | } | 341 | } |
| 344 | } | 342 | } |
| 345 | 343 | ||
| 346 | DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n", | 344 | dev_dbg(wdt->dev, "Heartbeat: timeout=%d, divisor=%d, count=%d (%08x)\n", |
| 347 | __func__, timeout, divisor, count, DIV_ROUND_UP(count, divisor)); | 345 | timeout, divisor, count, DIV_ROUND_UP(count, divisor)); |
| 348 | 346 | ||
| 349 | count = DIV_ROUND_UP(count, divisor); | 347 | count = DIV_ROUND_UP(count, divisor); |
| 350 | wdt->count = count; | 348 | wdt->count = count; |
| @@ -394,7 +392,7 @@ static const struct watchdog_info s3c2410_wdt_ident = { | |||
| 394 | .identity = "S3C2410 Watchdog", | 392 | .identity = "S3C2410 Watchdog", |
| 395 | }; | 393 | }; |
| 396 | 394 | ||
| 397 | static struct watchdog_ops s3c2410wdt_ops = { | 395 | static const struct watchdog_ops s3c2410wdt_ops = { |
| 398 | .owner = THIS_MODULE, | 396 | .owner = THIS_MODULE, |
| 399 | .start = s3c2410wdt_start, | 397 | .start = s3c2410wdt_start, |
| 400 | .stop = s3c2410wdt_stop, | 398 | .stop = s3c2410wdt_stop, |
| @@ -406,7 +404,7 @@ static struct watchdog_ops s3c2410wdt_ops = { | |||
| 406 | static struct watchdog_device s3c2410_wdd = { | 404 | static struct watchdog_device s3c2410_wdd = { |
| 407 | .info = &s3c2410_wdt_ident, | 405 | .info = &s3c2410_wdt_ident, |
| 408 | .ops = &s3c2410wdt_ops, | 406 | .ops = &s3c2410wdt_ops, |
| 409 | .timeout = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME, | 407 | .timeout = S3C2410_WATCHDOG_DEFAULT_TIME, |
| 410 | }; | 408 | }; |
| 411 | 409 | ||
| 412 | /* interrupt handler code */ | 410 | /* interrupt handler code */ |
| @@ -418,6 +416,10 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) | |||
| 418 | dev_info(wdt->dev, "watchdog timer expired (irq)\n"); | 416 | dev_info(wdt->dev, "watchdog timer expired (irq)\n"); |
| 419 | 417 | ||
| 420 | s3c2410wdt_keepalive(&wdt->wdt_device); | 418 | s3c2410wdt_keepalive(&wdt->wdt_device); |
| 419 | |||
| 420 | if (wdt->drv_data->quirks & QUIRK_HAS_WTCLRINT_REG) | ||
| 421 | writel(0x1, wdt->reg_base + S3C2410_WTCLRINT); | ||
| 422 | |||
| 421 | return IRQ_HANDLED; | 423 | return IRQ_HANDLED; |
| 422 | } | 424 | } |
| 423 | 425 | ||
| @@ -505,9 +507,8 @@ static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) | |||
| 505 | return 0; | 507 | return 0; |
| 506 | } | 508 | } |
| 507 | 509 | ||
| 508 | /* s3c2410_get_wdt_driver_data */ | ||
| 509 | static inline struct s3c2410_wdt_variant * | 510 | static inline struct s3c2410_wdt_variant * |
| 510 | get_wdt_drv_data(struct platform_device *pdev) | 511 | s3c2410_get_wdt_drv_data(struct platform_device *pdev) |
| 511 | { | 512 | { |
| 512 | if (pdev->dev.of_node) { | 513 | if (pdev->dev.of_node) { |
| 513 | const struct of_device_id *match; | 514 | const struct of_device_id *match; |
| @@ -529,8 +530,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 529 | int started = 0; | 530 | int started = 0; |
| 530 | int ret; | 531 | int ret; |
| 531 | 532 | ||
| 532 | DBG("%s: probe=%p\n", __func__, pdev); | ||
| 533 | |||
| 534 | dev = &pdev->dev; | 533 | dev = &pdev->dev; |
| 535 | 534 | ||
| 536 | wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); | 535 | wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); |
| @@ -541,7 +540,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 541 | spin_lock_init(&wdt->lock); | 540 | spin_lock_init(&wdt->lock); |
| 542 | wdt->wdt_device = s3c2410_wdd; | 541 | wdt->wdt_device = s3c2410_wdd; |
| 543 | 542 | ||
| 544 | wdt->drv_data = get_wdt_drv_data(pdev); | 543 | wdt->drv_data = s3c2410_get_wdt_drv_data(pdev); |
| 545 | if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) { | 544 | if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) { |
| 546 | wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, | 545 | wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node, |
| 547 | "samsung,syscon-phandle"); | 546 | "samsung,syscon-phandle"); |
| @@ -566,8 +565,6 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 566 | goto err; | 565 | goto err; |
| 567 | } | 566 | } |
| 568 | 567 | ||
| 569 | DBG("probe: mapped reg_base=%p\n", wdt->reg_base); | ||
| 570 | |||
| 571 | wdt->clock = devm_clk_get(dev, "watchdog"); | 568 | wdt->clock = devm_clk_get(dev, "watchdog"); |
| 572 | if (IS_ERR(wdt->clock)) { | 569 | if (IS_ERR(wdt->clock)) { |
| 573 | dev_err(dev, "failed to find watchdog clock source\n"); | 570 | dev_err(dev, "failed to find watchdog clock source\n"); |
| @@ -600,12 +597,12 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 600 | wdt->wdt_device.timeout); | 597 | wdt->wdt_device.timeout); |
| 601 | if (ret) { | 598 | if (ret) { |
| 602 | started = s3c2410wdt_set_heartbeat(&wdt->wdt_device, | 599 | started = s3c2410wdt_set_heartbeat(&wdt->wdt_device, |
| 603 | CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); | 600 | S3C2410_WATCHDOG_DEFAULT_TIME); |
| 604 | 601 | ||
| 605 | if (started == 0) | 602 | if (started == 0) |
| 606 | dev_info(dev, | 603 | dev_info(dev, |
| 607 | "tmr_margin value out of range, default %d used\n", | 604 | "tmr_margin value out of range, default %d used\n", |
| 608 | CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME); | 605 | S3C2410_WATCHDOG_DEFAULT_TIME); |
| 609 | else | 606 | else |
| 610 | dev_info(dev, "default timer value is out of range, " | 607 | dev_info(dev, "default timer value is out of range, " |
| 611 | "cannot start\n"); | 608 | "cannot start\n"); |
diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c index 8965e3f536c3..d3be4f831db5 100644 --- a/drivers/watchdog/sa1100_wdt.c +++ b/drivers/watchdog/sa1100_wdt.c | |||
| @@ -188,12 +188,14 @@ static int __init sa1100dog_init(void) | |||
| 188 | pre_margin = oscr_freq * margin; | 188 | pre_margin = oscr_freq * margin; |
| 189 | 189 | ||
| 190 | ret = misc_register(&sa1100dog_miscdev); | 190 | ret = misc_register(&sa1100dog_miscdev); |
| 191 | if (ret == 0) | 191 | if (ret == 0) { |
| 192 | pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", | 192 | pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", |
| 193 | margin); | 193 | margin); |
| 194 | return ret; | 194 | return 0; |
| 195 | err: | 195 | } |
| 196 | |||
| 196 | clk_disable_unprepare(clk); | 197 | clk_disable_unprepare(clk); |
| 198 | err: | ||
| 197 | clk_put(clk); | 199 | clk_put(clk); |
| 198 | return ret; | 200 | return ret; |
| 199 | } | 201 | } |
diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c index a49634cdc1cc..f709962018ac 100644 --- a/drivers/watchdog/sama5d4_wdt.c +++ b/drivers/watchdog/sama5d4_wdt.c | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | struct sama5d4_wdt { | 28 | struct sama5d4_wdt { |
| 29 | struct watchdog_device wdd; | 29 | struct watchdog_device wdd; |
| 30 | void __iomem *reg_base; | 30 | void __iomem *reg_base; |
| 31 | u32 config; | 31 | u32 mr; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | static int wdt_timeout = WDT_DEFAULT_TIMEOUT; | 34 | static int wdt_timeout = WDT_DEFAULT_TIMEOUT; |
| @@ -53,11 +53,9 @@ MODULE_PARM_DESC(nowayout, | |||
| 53 | static int sama5d4_wdt_start(struct watchdog_device *wdd) | 53 | static int sama5d4_wdt_start(struct watchdog_device *wdd) |
| 54 | { | 54 | { |
| 55 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); | 55 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); |
| 56 | u32 reg; | ||
| 57 | 56 | ||
| 58 | reg = wdt_read(wdt, AT91_WDT_MR); | 57 | wdt->mr &= ~AT91_WDT_WDDIS; |
| 59 | reg &= ~AT91_WDT_WDDIS; | 58 | wdt_write(wdt, AT91_WDT_MR, wdt->mr); |
| 60 | wdt_write(wdt, AT91_WDT_MR, reg); | ||
| 61 | 59 | ||
| 62 | return 0; | 60 | return 0; |
| 63 | } | 61 | } |
| @@ -65,11 +63,9 @@ static int sama5d4_wdt_start(struct watchdog_device *wdd) | |||
| 65 | static int sama5d4_wdt_stop(struct watchdog_device *wdd) | 63 | static int sama5d4_wdt_stop(struct watchdog_device *wdd) |
| 66 | { | 64 | { |
| 67 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); | 65 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); |
| 68 | u32 reg; | ||
| 69 | 66 | ||
| 70 | reg = wdt_read(wdt, AT91_WDT_MR); | 67 | wdt->mr |= AT91_WDT_WDDIS; |
| 71 | reg |= AT91_WDT_WDDIS; | 68 | wdt_write(wdt, AT91_WDT_MR, wdt->mr); |
| 72 | wdt_write(wdt, AT91_WDT_MR, reg); | ||
| 73 | 69 | ||
| 74 | return 0; | 70 | return 0; |
| 75 | } | 71 | } |
| @@ -88,14 +84,12 @@ static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd, | |||
| 88 | { | 84 | { |
| 89 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); | 85 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); |
| 90 | u32 value = WDT_SEC2TICKS(timeout); | 86 | u32 value = WDT_SEC2TICKS(timeout); |
| 91 | u32 reg; | ||
| 92 | 87 | ||
| 93 | reg = wdt_read(wdt, AT91_WDT_MR); | 88 | wdt->mr &= ~AT91_WDT_WDV; |
| 94 | reg &= ~AT91_WDT_WDV; | 89 | wdt->mr &= ~AT91_WDT_WDD; |
| 95 | reg &= ~AT91_WDT_WDD; | 90 | wdt->mr |= AT91_WDT_SET_WDV(value); |
| 96 | reg |= AT91_WDT_SET_WDV(value); | 91 | wdt->mr |= AT91_WDT_SET_WDD(value); |
| 97 | reg |= AT91_WDT_SET_WDD(value); | 92 | wdt_write(wdt, AT91_WDT_MR, wdt->mr); |
| 98 | wdt_write(wdt, AT91_WDT_MR, reg); | ||
| 99 | 93 | ||
| 100 | wdd->timeout = timeout; | 94 | wdd->timeout = timeout; |
| 101 | 95 | ||
| @@ -107,7 +101,7 @@ static const struct watchdog_info sama5d4_wdt_info = { | |||
| 107 | .identity = "Atmel SAMA5D4 Watchdog", | 101 | .identity = "Atmel SAMA5D4 Watchdog", |
| 108 | }; | 102 | }; |
| 109 | 103 | ||
| 110 | static struct watchdog_ops sama5d4_wdt_ops = { | 104 | static const struct watchdog_ops sama5d4_wdt_ops = { |
| 111 | .owner = THIS_MODULE, | 105 | .owner = THIS_MODULE, |
| 112 | .start = sama5d4_wdt_start, | 106 | .start = sama5d4_wdt_start, |
| 113 | .stop = sama5d4_wdt_stop, | 107 | .stop = sama5d4_wdt_stop, |
| @@ -132,19 +126,19 @@ static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt) | |||
| 132 | { | 126 | { |
| 133 | const char *tmp; | 127 | const char *tmp; |
| 134 | 128 | ||
| 135 | wdt->config = AT91_WDT_WDDIS; | 129 | wdt->mr = AT91_WDT_WDDIS; |
| 136 | 130 | ||
| 137 | if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && | 131 | if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && |
| 138 | !strcmp(tmp, "software")) | 132 | !strcmp(tmp, "software")) |
| 139 | wdt->config |= AT91_WDT_WDFIEN; | 133 | wdt->mr |= AT91_WDT_WDFIEN; |
| 140 | else | 134 | else |
| 141 | wdt->config |= AT91_WDT_WDRSTEN; | 135 | wdt->mr |= AT91_WDT_WDRSTEN; |
| 142 | 136 | ||
| 143 | if (of_property_read_bool(np, "atmel,idle-halt")) | 137 | if (of_property_read_bool(np, "atmel,idle-halt")) |
| 144 | wdt->config |= AT91_WDT_WDIDLEHLT; | 138 | wdt->mr |= AT91_WDT_WDIDLEHLT; |
| 145 | 139 | ||
| 146 | if (of_property_read_bool(np, "atmel,dbg-halt")) | 140 | if (of_property_read_bool(np, "atmel,dbg-halt")) |
| 147 | wdt->config |= AT91_WDT_WDDBGHLT; | 141 | wdt->mr |= AT91_WDT_WDDBGHLT; |
| 148 | 142 | ||
| 149 | return 0; | 143 | return 0; |
| 150 | } | 144 | } |
| @@ -163,11 +157,10 @@ static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) | |||
| 163 | reg &= ~AT91_WDT_WDDIS; | 157 | reg &= ~AT91_WDT_WDDIS; |
| 164 | wdt_write(wdt, AT91_WDT_MR, reg); | 158 | wdt_write(wdt, AT91_WDT_MR, reg); |
| 165 | 159 | ||
| 166 | reg = wdt->config; | 160 | wdt->mr |= AT91_WDT_SET_WDD(value); |
| 167 | reg |= AT91_WDT_SET_WDD(value); | 161 | wdt->mr |= AT91_WDT_SET_WDV(value); |
| 168 | reg |= AT91_WDT_SET_WDV(value); | ||
| 169 | 162 | ||
| 170 | wdt_write(wdt, AT91_WDT_MR, reg); | 163 | wdt_write(wdt, AT91_WDT_MR, wdt->mr); |
| 171 | 164 | ||
| 172 | return 0; | 165 | return 0; |
| 173 | } | 166 | } |
| @@ -211,7 +204,7 @@ static int sama5d4_wdt_probe(struct platform_device *pdev) | |||
| 211 | return ret; | 204 | return ret; |
| 212 | } | 205 | } |
| 213 | 206 | ||
| 214 | if ((wdt->config & AT91_WDT_WDFIEN) && irq) { | 207 | if ((wdt->mr & AT91_WDT_WDFIEN) && irq) { |
| 215 | ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler, | 208 | ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler, |
| 216 | IRQF_SHARED | IRQF_IRQPOLL | | 209 | IRQF_SHARED | IRQF_IRQPOLL | |
| 217 | IRQF_NO_SUSPEND, pdev->name, pdev); | 210 | IRQF_NO_SUSPEND, pdev->name, pdev); |
| @@ -265,11 +258,28 @@ static const struct of_device_id sama5d4_wdt_of_match[] = { | |||
| 265 | }; | 258 | }; |
| 266 | MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match); | 259 | MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match); |
| 267 | 260 | ||
| 261 | #ifdef CONFIG_PM_SLEEP | ||
| 262 | static int sama5d4_wdt_resume(struct device *dev) | ||
| 263 | { | ||
| 264 | struct sama5d4_wdt *wdt = dev_get_drvdata(dev); | ||
| 265 | |||
| 266 | wdt_write(wdt, AT91_WDT_MR, wdt->mr & ~AT91_WDT_WDDIS); | ||
| 267 | if (wdt->mr & AT91_WDT_WDDIS) | ||
| 268 | wdt_write(wdt, AT91_WDT_MR, wdt->mr); | ||
| 269 | |||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | #endif | ||
| 273 | |||
| 274 | static SIMPLE_DEV_PM_OPS(sama5d4_wdt_pm_ops, NULL, | ||
| 275 | sama5d4_wdt_resume); | ||
| 276 | |||
| 268 | static struct platform_driver sama5d4_wdt_driver = { | 277 | static struct platform_driver sama5d4_wdt_driver = { |
| 269 | .probe = sama5d4_wdt_probe, | 278 | .probe = sama5d4_wdt_probe, |
| 270 | .remove = sama5d4_wdt_remove, | 279 | .remove = sama5d4_wdt_remove, |
| 271 | .driver = { | 280 | .driver = { |
| 272 | .name = "sama5d4_wdt", | 281 | .name = "sama5d4_wdt", |
| 282 | .pm = &sama5d4_wdt_pm_ops, | ||
| 273 | .of_match_table = sama5d4_wdt_of_match, | 283 | .of_match_table = sama5d4_wdt_of_match, |
| 274 | } | 284 | } |
| 275 | }; | 285 | }; |
diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index ce0c38bd0f00..316c2eb122d2 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c | |||
| @@ -207,7 +207,7 @@ static irqreturn_t sbsa_gwdt_interrupt(int irq, void *dev_id) | |||
| 207 | return IRQ_HANDLED; | 207 | return IRQ_HANDLED; |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | static struct watchdog_info sbsa_gwdt_info = { | 210 | static const struct watchdog_info sbsa_gwdt_info = { |
| 211 | .identity = WATCHDOG_NAME, | 211 | .identity = WATCHDOG_NAME, |
| 212 | .options = WDIOF_SETTIMEOUT | | 212 | .options = WDIOF_SETTIMEOUT | |
| 213 | WDIOF_KEEPALIVEPING | | 213 | WDIOF_KEEPALIVEPING | |
| @@ -215,7 +215,7 @@ static struct watchdog_info sbsa_gwdt_info = { | |||
| 215 | WDIOF_CARDRESET, | 215 | WDIOF_CARDRESET, |
| 216 | }; | 216 | }; |
| 217 | 217 | ||
| 218 | static struct watchdog_ops sbsa_gwdt_ops = { | 218 | static const struct watchdog_ops sbsa_gwdt_ops = { |
| 219 | .owner = THIS_MODULE, | 219 | .owner = THIS_MODULE, |
| 220 | .start = sbsa_gwdt_start, | 220 | .start = sbsa_gwdt_start, |
| 221 | .stop = sbsa_gwdt_stop, | 221 | .stop = sbsa_gwdt_stop, |
diff --git a/drivers/watchdog/sirfsoc_wdt.c b/drivers/watchdog/sirfsoc_wdt.c index 3050a0031479..4eea351e09b0 100644 --- a/drivers/watchdog/sirfsoc_wdt.c +++ b/drivers/watchdog/sirfsoc_wdt.c | |||
| @@ -127,7 +127,7 @@ static const struct watchdog_info sirfsoc_wdt_ident = { | |||
| 127 | .identity = "SiRFSOC Watchdog", | 127 | .identity = "SiRFSOC Watchdog", |
| 128 | }; | 128 | }; |
| 129 | 129 | ||
| 130 | static struct watchdog_ops sirfsoc_wdt_ops = { | 130 | static const struct watchdog_ops sirfsoc_wdt_ops = { |
| 131 | .owner = THIS_MODULE, | 131 | .owner = THIS_MODULE, |
| 132 | .start = sirfsoc_wdt_enable, | 132 | .start = sirfsoc_wdt_enable, |
| 133 | .stop = sirfsoc_wdt_disable, | 133 | .stop = sirfsoc_wdt_disable, |
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c index c7bdc986dca1..7983029852ab 100644 --- a/drivers/watchdog/softdog.c +++ b/drivers/watchdog/softdog.c | |||
| @@ -87,11 +87,13 @@ static int softdog_ping(struct watchdog_device *w) | |||
| 87 | if (!mod_timer(&softdog_ticktock, jiffies + (w->timeout * HZ))) | 87 | if (!mod_timer(&softdog_ticktock, jiffies + (w->timeout * HZ))) |
| 88 | __module_get(THIS_MODULE); | 88 | __module_get(THIS_MODULE); |
| 89 | 89 | ||
| 90 | if (w->pretimeout) | 90 | if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT)) { |
| 91 | mod_timer(&softdog_preticktock, jiffies + | 91 | if (w->pretimeout) |
| 92 | (w->timeout - w->pretimeout) * HZ); | 92 | mod_timer(&softdog_preticktock, jiffies + |
| 93 | else | 93 | (w->timeout - w->pretimeout) * HZ); |
| 94 | del_timer(&softdog_preticktock); | 94 | else |
| 95 | del_timer(&softdog_preticktock); | ||
| 96 | } | ||
| 95 | 97 | ||
| 96 | return 0; | 98 | return 0; |
| 97 | } | 99 | } |
| @@ -101,15 +103,15 @@ static int softdog_stop(struct watchdog_device *w) | |||
| 101 | if (del_timer(&softdog_ticktock)) | 103 | if (del_timer(&softdog_ticktock)) |
| 102 | module_put(THIS_MODULE); | 104 | module_put(THIS_MODULE); |
| 103 | 105 | ||
| 104 | del_timer(&softdog_preticktock); | 106 | if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT)) |
| 107 | del_timer(&softdog_preticktock); | ||
| 105 | 108 | ||
| 106 | return 0; | 109 | return 0; |
| 107 | } | 110 | } |
| 108 | 111 | ||
| 109 | static struct watchdog_info softdog_info = { | 112 | static struct watchdog_info softdog_info = { |
| 110 | .identity = "Software Watchdog", | 113 | .identity = "Software Watchdog", |
| 111 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE | | 114 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, |
| 112 | WDIOF_PRETIMEOUT, | ||
| 113 | }; | 115 | }; |
| 114 | 116 | ||
| 115 | static const struct watchdog_ops softdog_ops = { | 117 | static const struct watchdog_ops softdog_ops = { |
| @@ -134,6 +136,9 @@ static int __init softdog_init(void) | |||
| 134 | watchdog_set_nowayout(&softdog_dev, nowayout); | 136 | watchdog_set_nowayout(&softdog_dev, nowayout); |
| 135 | watchdog_stop_on_reboot(&softdog_dev); | 137 | watchdog_stop_on_reboot(&softdog_dev); |
| 136 | 138 | ||
| 139 | if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT)) | ||
| 140 | softdog_info.options |= WDIOF_PRETIMEOUT; | ||
| 141 | |||
| 137 | ret = watchdog_register_device(&softdog_dev); | 142 | ret = watchdog_register_device(&softdog_dev); |
| 138 | if (ret) | 143 | if (ret) |
| 139 | return ret; | 144 | return ret; |
diff --git a/drivers/watchdog/sun4v_wdt.c b/drivers/watchdog/sun4v_wdt.c index 1467fe50a76f..00907973608c 100644 --- a/drivers/watchdog/sun4v_wdt.c +++ b/drivers/watchdog/sun4v_wdt.c | |||
| @@ -77,7 +77,7 @@ static const struct watchdog_info sun4v_wdt_ident = { | |||
| 77 | .firmware_version = 0, | 77 | .firmware_version = 0, |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | static struct watchdog_ops sun4v_wdt_ops = { | 80 | static const struct watchdog_ops sun4v_wdt_ops = { |
| 81 | .owner = THIS_MODULE, | 81 | .owner = THIS_MODULE, |
| 82 | .start = sun4v_wdt_ping, | 82 | .start = sun4v_wdt_ping, |
| 83 | .stop = sun4v_wdt_stop, | 83 | .stop = sun4v_wdt_stop, |
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c index 953bb7b7446f..9728fa32c357 100644 --- a/drivers/watchdog/sunxi_wdt.c +++ b/drivers/watchdog/sunxi_wdt.c | |||
| @@ -242,8 +242,6 @@ static int sunxi_wdt_probe(struct platform_device *pdev) | |||
| 242 | if (!sunxi_wdt) | 242 | if (!sunxi_wdt) |
| 243 | return -EINVAL; | 243 | return -EINVAL; |
| 244 | 244 | ||
| 245 | platform_set_drvdata(pdev, sunxi_wdt); | ||
| 246 | |||
| 247 | device = of_match_device(sunxi_wdt_dt_ids, &pdev->dev); | 245 | device = of_match_device(sunxi_wdt_dt_ids, &pdev->dev); |
| 248 | if (!device) | 246 | if (!device) |
| 249 | return -ENODEV; | 247 | return -ENODEV; |
| @@ -270,7 +268,8 @@ static int sunxi_wdt_probe(struct platform_device *pdev) | |||
| 270 | 268 | ||
| 271 | sunxi_wdt_stop(&sunxi_wdt->wdt_dev); | 269 | sunxi_wdt_stop(&sunxi_wdt->wdt_dev); |
| 272 | 270 | ||
| 273 | err = watchdog_register_device(&sunxi_wdt->wdt_dev); | 271 | watchdog_stop_on_reboot(&sunxi_wdt->wdt_dev); |
| 272 | err = devm_watchdog_register_device(&pdev->dev, &sunxi_wdt->wdt_dev); | ||
| 274 | if (unlikely(err)) | 273 | if (unlikely(err)) |
| 275 | return err; | 274 | return err; |
| 276 | 275 | ||
| @@ -280,27 +279,8 @@ static int sunxi_wdt_probe(struct platform_device *pdev) | |||
| 280 | return 0; | 279 | return 0; |
| 281 | } | 280 | } |
| 282 | 281 | ||
| 283 | static int sunxi_wdt_remove(struct platform_device *pdev) | ||
| 284 | { | ||
| 285 | struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev); | ||
| 286 | |||
| 287 | watchdog_unregister_device(&sunxi_wdt->wdt_dev); | ||
| 288 | watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL); | ||
| 289 | |||
| 290 | return 0; | ||
| 291 | } | ||
| 292 | |||
| 293 | static void sunxi_wdt_shutdown(struct platform_device *pdev) | ||
| 294 | { | ||
| 295 | struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev); | ||
| 296 | |||
| 297 | sunxi_wdt_stop(&sunxi_wdt->wdt_dev); | ||
| 298 | } | ||
| 299 | |||
| 300 | static struct platform_driver sunxi_wdt_driver = { | 282 | static struct platform_driver sunxi_wdt_driver = { |
| 301 | .probe = sunxi_wdt_probe, | 283 | .probe = sunxi_wdt_probe, |
| 302 | .remove = sunxi_wdt_remove, | ||
| 303 | .shutdown = sunxi_wdt_shutdown, | ||
| 304 | .driver = { | 284 | .driver = { |
| 305 | .name = DRV_NAME, | 285 | .name = DRV_NAME, |
| 306 | .of_match_table = sunxi_wdt_dt_ids, | 286 | .of_match_table = sunxi_wdt_dt_ids, |
diff --git a/drivers/watchdog/tangox_wdt.c b/drivers/watchdog/tangox_wdt.c index 202c4b9cc921..d5fcce062920 100644 --- a/drivers/watchdog/tangox_wdt.c +++ b/drivers/watchdog/tangox_wdt.c | |||
| @@ -15,9 +15,7 @@ | |||
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/moduleparam.h> | 17 | #include <linux/moduleparam.h> |
| 18 | #include <linux/notifier.h> | ||
| 19 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
| 20 | #include <linux/reboot.h> | ||
| 21 | #include <linux/watchdog.h> | 19 | #include <linux/watchdog.h> |
| 22 | 20 | ||
| 23 | #define DEFAULT_TIMEOUT 30 | 21 | #define DEFAULT_TIMEOUT 30 |
| @@ -47,7 +45,6 @@ struct tangox_wdt_device { | |||
| 47 | void __iomem *base; | 45 | void __iomem *base; |
| 48 | unsigned long clk_rate; | 46 | unsigned long clk_rate; |
| 49 | struct clk *clk; | 47 | struct clk *clk; |
| 50 | struct notifier_block restart; | ||
| 51 | }; | 48 | }; |
| 52 | 49 | ||
| 53 | static int tangox_wdt_set_timeout(struct watchdog_device *wdt, | 50 | static int tangox_wdt_set_timeout(struct watchdog_device *wdt, |
| @@ -96,24 +93,24 @@ static const struct watchdog_info tangox_wdt_info = { | |||
| 96 | .identity = "tangox watchdog", | 93 | .identity = "tangox watchdog", |
| 97 | }; | 94 | }; |
| 98 | 95 | ||
| 96 | static int tangox_wdt_restart(struct watchdog_device *wdt, | ||
| 97 | unsigned long action, void *data) | ||
| 98 | { | ||
| 99 | struct tangox_wdt_device *dev = watchdog_get_drvdata(wdt); | ||
| 100 | |||
| 101 | writel(1, dev->base + WD_COUNTER); | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 99 | static const struct watchdog_ops tangox_wdt_ops = { | 106 | static const struct watchdog_ops tangox_wdt_ops = { |
| 100 | .start = tangox_wdt_start, | 107 | .start = tangox_wdt_start, |
| 101 | .stop = tangox_wdt_stop, | 108 | .stop = tangox_wdt_stop, |
| 102 | .set_timeout = tangox_wdt_set_timeout, | 109 | .set_timeout = tangox_wdt_set_timeout, |
| 103 | .get_timeleft = tangox_wdt_get_timeleft, | 110 | .get_timeleft = tangox_wdt_get_timeleft, |
| 111 | .restart = tangox_wdt_restart, | ||
| 104 | }; | 112 | }; |
| 105 | 113 | ||
| 106 | static int tangox_wdt_restart(struct notifier_block *nb, unsigned long action, | ||
| 107 | void *data) | ||
| 108 | { | ||
| 109 | struct tangox_wdt_device *dev = | ||
| 110 | container_of(nb, struct tangox_wdt_device, restart); | ||
| 111 | |||
| 112 | writel(1, dev->base + WD_COUNTER); | ||
| 113 | |||
| 114 | return NOTIFY_DONE; | ||
| 115 | } | ||
| 116 | |||
| 117 | static int tangox_wdt_probe(struct platform_device *pdev) | 114 | static int tangox_wdt_probe(struct platform_device *pdev) |
| 118 | { | 115 | { |
| 119 | struct tangox_wdt_device *dev; | 116 | struct tangox_wdt_device *dev; |
| @@ -174,18 +171,14 @@ static int tangox_wdt_probe(struct platform_device *pdev) | |||
| 174 | tangox_wdt_start(&dev->wdt); | 171 | tangox_wdt_start(&dev->wdt); |
| 175 | } | 172 | } |
| 176 | 173 | ||
| 174 | watchdog_set_restart_priority(&dev->wdt, 128); | ||
| 175 | |||
| 177 | err = watchdog_register_device(&dev->wdt); | 176 | err = watchdog_register_device(&dev->wdt); |
| 178 | if (err) | 177 | if (err) |
| 179 | goto err; | 178 | goto err; |
| 180 | 179 | ||
| 181 | platform_set_drvdata(pdev, dev); | 180 | platform_set_drvdata(pdev, dev); |
| 182 | 181 | ||
| 183 | dev->restart.notifier_call = tangox_wdt_restart; | ||
| 184 | dev->restart.priority = 128; | ||
| 185 | err = register_restart_handler(&dev->restart); | ||
| 186 | if (err) | ||
| 187 | dev_warn(&pdev->dev, "failed to register restart handler\n"); | ||
| 188 | |||
| 189 | dev_info(&pdev->dev, "SMP86xx/SMP87xx watchdog registered\n"); | 182 | dev_info(&pdev->dev, "SMP86xx/SMP87xx watchdog registered\n"); |
| 190 | 183 | ||
| 191 | return 0; | 184 | return 0; |
| @@ -202,7 +195,6 @@ static int tangox_wdt_remove(struct platform_device *pdev) | |||
| 202 | tangox_wdt_stop(&dev->wdt); | 195 | tangox_wdt_stop(&dev->wdt); |
| 203 | clk_disable_unprepare(dev->clk); | 196 | clk_disable_unprepare(dev->clk); |
| 204 | 197 | ||
| 205 | unregister_restart_handler(&dev->restart); | ||
| 206 | watchdog_unregister_device(&dev->wdt); | 198 | watchdog_unregister_device(&dev->wdt); |
| 207 | 199 | ||
| 208 | return 0; | 200 | return 0; |
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index 2d53c3f9394f..9403c08816e3 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c | |||
| @@ -226,7 +226,7 @@ static int tegra_wdt_probe(struct platform_device *pdev) | |||
| 226 | 226 | ||
| 227 | watchdog_set_nowayout(wdd, nowayout); | 227 | watchdog_set_nowayout(wdd, nowayout); |
| 228 | 228 | ||
| 229 | ret = watchdog_register_device(wdd); | 229 | ret = devm_watchdog_register_device(&pdev->dev, wdd); |
| 230 | if (ret) { | 230 | if (ret) { |
| 231 | dev_err(&pdev->dev, | 231 | dev_err(&pdev->dev, |
| 232 | "failed to register watchdog device\n"); | 232 | "failed to register watchdog device\n"); |
| @@ -248,8 +248,6 @@ static int tegra_wdt_remove(struct platform_device *pdev) | |||
| 248 | 248 | ||
| 249 | tegra_wdt_stop(&wdt->wdd); | 249 | tegra_wdt_stop(&wdt->wdd); |
| 250 | 250 | ||
| 251 | watchdog_unregister_device(&wdt->wdd); | ||
| 252 | |||
| 253 | dev_info(&pdev->dev, "removed wdt\n"); | 251 | dev_info(&pdev->dev, "removed wdt\n"); |
| 254 | 252 | ||
| 255 | return 0; | 253 | return 0; |
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c index 4b541934b6c5..17c25daebcce 100644 --- a/drivers/watchdog/ts72xx_wdt.c +++ b/drivers/watchdog/ts72xx_wdt.c | |||
| @@ -13,428 +13,159 @@ | |||
| 13 | * warranty of any kind, whether express or implied. | 13 | * warranty of any kind, whether express or implied. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/fs.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/moduleparam.h> | ||
| 20 | #include <linux/miscdevice.h> | ||
| 21 | #include <linux/mutex.h> | ||
| 22 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 23 | #include <linux/slab.h> | 17 | #include <linux/module.h> |
| 24 | #include <linux/watchdog.h> | 18 | #include <linux/watchdog.h> |
| 25 | #include <linux/uaccess.h> | 19 | #include <linux/io.h> |
| 26 | 20 | ||
| 27 | #define TS72XX_WDT_FEED_VAL 0x05 | 21 | #define TS72XX_WDT_DEFAULT_TIMEOUT 30 |
| 28 | #define TS72XX_WDT_DEFAULT_TIMEOUT 8 | ||
| 29 | 22 | ||
| 30 | static int timeout = TS72XX_WDT_DEFAULT_TIMEOUT; | 23 | static int timeout; |
| 31 | module_param(timeout, int, 0); | 24 | module_param(timeout, int, 0); |
| 32 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. " | 25 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds."); |
| 33 | "(1 <= timeout <= 8, default=" | ||
| 34 | __MODULE_STRING(TS72XX_WDT_DEFAULT_TIMEOUT) | ||
| 35 | ")"); | ||
| 36 | 26 | ||
| 37 | static bool nowayout = WATCHDOG_NOWAYOUT; | 27 | static bool nowayout = WATCHDOG_NOWAYOUT; |
| 38 | module_param(nowayout, bool, 0); | 28 | module_param(nowayout, bool, 0); |
| 39 | MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); | 29 | MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); |
| 40 | 30 | ||
| 41 | /** | 31 | /* priv->control_reg */ |
| 42 | * struct ts72xx_wdt - watchdog control structure | 32 | #define TS72XX_WDT_CTRL_DISABLE 0x00 |
| 43 | * @lock: lock that protects this structure | 33 | #define TS72XX_WDT_CTRL_250MS 0x01 |
| 44 | * @regval: watchdog timeout value suitable for control register | 34 | #define TS72XX_WDT_CTRL_500MS 0x02 |
| 45 | * @flags: flags controlling watchdog device state | 35 | #define TS72XX_WDT_CTRL_1SEC 0x03 |
| 46 | * @control_reg: watchdog control register | 36 | #define TS72XX_WDT_CTRL_RESERVED 0x04 |
| 47 | * @feed_reg: watchdog feed register | 37 | #define TS72XX_WDT_CTRL_2SEC 0x05 |
| 48 | * @pdev: back pointer to platform dev | 38 | #define TS72XX_WDT_CTRL_4SEC 0x06 |
| 49 | */ | 39 | #define TS72XX_WDT_CTRL_8SEC 0x07 |
| 50 | struct ts72xx_wdt { | 40 | |
| 51 | struct mutex lock; | 41 | /* priv->feed_reg */ |
| 52 | int regval; | 42 | #define TS72XX_WDT_FEED_VAL 0x05 |
| 53 | |||
| 54 | #define TS72XX_WDT_BUSY_FLAG 1 | ||
| 55 | #define TS72XX_WDT_EXPECT_CLOSE_FLAG 2 | ||
| 56 | int flags; | ||
| 57 | 43 | ||
| 44 | struct ts72xx_wdt_priv { | ||
| 58 | void __iomem *control_reg; | 45 | void __iomem *control_reg; |
| 59 | void __iomem *feed_reg; | 46 | void __iomem *feed_reg; |
| 60 | 47 | struct watchdog_device wdd; | |
| 61 | struct platform_device *pdev; | 48 | unsigned char regval; |
| 62 | }; | 49 | }; |
| 63 | 50 | ||
| 64 | static struct platform_device *ts72xx_wdt_pdev; | 51 | static int ts72xx_wdt_start(struct watchdog_device *wdd) |
| 65 | |||
| 66 | /* | ||
| 67 | * TS-72xx Watchdog supports following timeouts (value written | ||
| 68 | * to control register): | ||
| 69 | * value description | ||
| 70 | * ------------------------- | ||
| 71 | * 0x00 watchdog disabled | ||
| 72 | * 0x01 250ms | ||
| 73 | * 0x02 500ms | ||
| 74 | * 0x03 1s | ||
| 75 | * 0x04 reserved | ||
| 76 | * 0x05 2s | ||
| 77 | * 0x06 4s | ||
| 78 | * 0x07 8s | ||
| 79 | * | ||
| 80 | * Timeouts below 1s are not very usable so we don't | ||
| 81 | * allow them at all. | ||
| 82 | * | ||
| 83 | * We provide two functions that convert between these: | ||
| 84 | * timeout_to_regval() and regval_to_timeout(). | ||
| 85 | */ | ||
| 86 | static const struct { | ||
| 87 | int timeout; | ||
| 88 | int regval; | ||
| 89 | } ts72xx_wdt_map[] = { | ||
| 90 | { 1, 3 }, | ||
| 91 | { 2, 5 }, | ||
| 92 | { 4, 6 }, | ||
| 93 | { 8, 7 }, | ||
| 94 | }; | ||
| 95 | |||
| 96 | /** | ||
| 97 | * timeout_to_regval() - converts given timeout to control register value | ||
| 98 | * @new_timeout: timeout in seconds to be converted | ||
| 99 | * | ||
| 100 | * Function converts given @new_timeout into valid value that can | ||
| 101 | * be programmed into watchdog control register. When conversion is | ||
| 102 | * not possible, function returns %-EINVAL. | ||
| 103 | */ | ||
| 104 | static int timeout_to_regval(int new_timeout) | ||
| 105 | { | ||
| 106 | int i; | ||
| 107 | |||
| 108 | /* first limit it to 1 - 8 seconds */ | ||
| 109 | new_timeout = clamp_val(new_timeout, 1, 8); | ||
| 110 | |||
| 111 | for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) { | ||
| 112 | if (ts72xx_wdt_map[i].timeout >= new_timeout) | ||
| 113 | return ts72xx_wdt_map[i].regval; | ||
| 114 | } | ||
| 115 | |||
| 116 | return -EINVAL; | ||
| 117 | } | ||
| 118 | |||
| 119 | /** | ||
| 120 | * regval_to_timeout() - converts control register value to timeout | ||
| 121 | * @regval: control register value to be converted | ||
| 122 | * | ||
| 123 | * Function converts given @regval to timeout in seconds (1, 2, 4 or 8). | ||
| 124 | * If @regval cannot be converted, function returns %-EINVAL. | ||
| 125 | */ | ||
| 126 | static int regval_to_timeout(int regval) | ||
| 127 | { | 52 | { |
| 128 | int i; | 53 | struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 129 | 54 | ||
| 130 | for (i = 0; i < ARRAY_SIZE(ts72xx_wdt_map); i++) { | 55 | writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg); |
| 131 | if (ts72xx_wdt_map[i].regval == regval) | 56 | writeb(priv->regval, priv->control_reg); |
| 132 | return ts72xx_wdt_map[i].timeout; | ||
| 133 | } | ||
| 134 | 57 | ||
| 135 | return -EINVAL; | 58 | return 0; |
| 136 | } | 59 | } |
| 137 | 60 | ||
| 138 | /** | 61 | static int ts72xx_wdt_stop(struct watchdog_device *wdd) |
| 139 | * ts72xx_wdt_kick() - kick the watchdog | ||
| 140 | * @wdt: watchdog to be kicked | ||
| 141 | * | ||
| 142 | * Called with @wdt->lock held. | ||
| 143 | */ | ||
| 144 | static inline void ts72xx_wdt_kick(struct ts72xx_wdt *wdt) | ||
| 145 | { | 62 | { |
| 146 | __raw_writeb(TS72XX_WDT_FEED_VAL, wdt->feed_reg); | 63 | struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 147 | } | ||
| 148 | 64 | ||
| 149 | /** | 65 | writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg); |
| 150 | * ts72xx_wdt_start() - starts the watchdog timer | 66 | writeb(TS72XX_WDT_CTRL_DISABLE, priv->control_reg); |
| 151 | * @wdt: watchdog to be started | ||
| 152 | * | ||
| 153 | * This function programs timeout to watchdog timer | ||
| 154 | * and starts it. | ||
| 155 | * | ||
| 156 | * Called with @wdt->lock held. | ||
| 157 | */ | ||
| 158 | static void ts72xx_wdt_start(struct ts72xx_wdt *wdt) | ||
| 159 | { | ||
| 160 | /* | ||
| 161 | * To program the wdt, it first must be "fed" and | ||
| 162 | * only after that (within 30 usecs) the configuration | ||
| 163 | * can be changed. | ||
| 164 | */ | ||
| 165 | ts72xx_wdt_kick(wdt); | ||
| 166 | __raw_writeb((u8)wdt->regval, wdt->control_reg); | ||
| 167 | } | ||
| 168 | 67 | ||
| 169 | /** | 68 | return 0; |
| 170 | * ts72xx_wdt_stop() - stops the watchdog timer | ||
| 171 | * @wdt: watchdog to be stopped | ||
| 172 | * | ||
| 173 | * Called with @wdt->lock held. | ||
| 174 | */ | ||
| 175 | static void ts72xx_wdt_stop(struct ts72xx_wdt *wdt) | ||
| 176 | { | ||
| 177 | ts72xx_wdt_kick(wdt); | ||
| 178 | __raw_writeb(0, wdt->control_reg); | ||
| 179 | } | 69 | } |
| 180 | 70 | ||
| 181 | static int ts72xx_wdt_open(struct inode *inode, struct file *file) | 71 | static int ts72xx_wdt_ping(struct watchdog_device *wdd) |
| 182 | { | 72 | { |
| 183 | struct ts72xx_wdt *wdt = platform_get_drvdata(ts72xx_wdt_pdev); | 73 | struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 184 | int regval; | ||
| 185 | |||
| 186 | /* | ||
| 187 | * Try to convert default timeout to valid register | ||
| 188 | * value first. | ||
| 189 | */ | ||
| 190 | regval = timeout_to_regval(timeout); | ||
| 191 | if (regval < 0) { | ||
| 192 | dev_err(&wdt->pdev->dev, | ||
| 193 | "failed to convert timeout (%d) to register value\n", | ||
| 194 | timeout); | ||
| 195 | return regval; | ||
| 196 | } | ||
| 197 | |||
| 198 | if (mutex_lock_interruptible(&wdt->lock)) | ||
| 199 | return -ERESTARTSYS; | ||
| 200 | 74 | ||
| 201 | if ((wdt->flags & TS72XX_WDT_BUSY_FLAG) != 0) { | 75 | writeb(TS72XX_WDT_FEED_VAL, priv->feed_reg); |
| 202 | mutex_unlock(&wdt->lock); | ||
| 203 | return -EBUSY; | ||
| 204 | } | ||
| 205 | |||
| 206 | wdt->flags = TS72XX_WDT_BUSY_FLAG; | ||
| 207 | wdt->regval = regval; | ||
| 208 | file->private_data = wdt; | ||
| 209 | |||
| 210 | ts72xx_wdt_start(wdt); | ||
| 211 | 76 | ||
| 212 | mutex_unlock(&wdt->lock); | 77 | return 0; |
| 213 | return nonseekable_open(inode, file); | ||
| 214 | } | 78 | } |
| 215 | 79 | ||
| 216 | static int ts72xx_wdt_release(struct inode *inode, struct file *file) | 80 | static int ts72xx_wdt_settimeout(struct watchdog_device *wdd, unsigned int to) |
| 217 | { | 81 | { |
| 218 | struct ts72xx_wdt *wdt = file->private_data; | 82 | struct ts72xx_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 219 | 83 | ||
| 220 | if (mutex_lock_interruptible(&wdt->lock)) | 84 | if (to == 1) { |
| 221 | return -ERESTARTSYS; | 85 | priv->regval = TS72XX_WDT_CTRL_1SEC; |
| 222 | 86 | } else if (to == 2) { | |
| 223 | if ((wdt->flags & TS72XX_WDT_EXPECT_CLOSE_FLAG) != 0) { | 87 | priv->regval = TS72XX_WDT_CTRL_2SEC; |
| 224 | ts72xx_wdt_stop(wdt); | 88 | } else if (to <= 4) { |
| 89 | priv->regval = TS72XX_WDT_CTRL_4SEC; | ||
| 90 | to = 4; | ||
| 225 | } else { | 91 | } else { |
| 226 | dev_warn(&wdt->pdev->dev, | 92 | priv->regval = TS72XX_WDT_CTRL_8SEC; |
| 227 | "TS-72XX WDT device closed unexpectly. " | 93 | if (to <= 8) |
| 228 | "Watchdog timer will not stop!\n"); | 94 | to = 8; |
| 229 | /* | ||
| 230 | * Kick it one more time, to give userland some time | ||
| 231 | * to recover (for example, respawning the kicker | ||
| 232 | * daemon). | ||
| 233 | */ | ||
| 234 | ts72xx_wdt_kick(wdt); | ||
| 235 | } | 95 | } |
| 236 | 96 | ||
| 237 | wdt->flags = 0; | 97 | wdd->timeout = to; |
| 238 | 98 | ||
| 239 | mutex_unlock(&wdt->lock); | 99 | if (watchdog_active(wdd)) { |
| 240 | return 0; | 100 | ts72xx_wdt_stop(wdd); |
| 241 | } | 101 | ts72xx_wdt_start(wdd); |
| 242 | |||
| 243 | static ssize_t ts72xx_wdt_write(struct file *file, | ||
| 244 | const char __user *data, | ||
| 245 | size_t len, | ||
| 246 | loff_t *ppos) | ||
| 247 | { | ||
| 248 | struct ts72xx_wdt *wdt = file->private_data; | ||
| 249 | |||
| 250 | if (!len) | ||
| 251 | return 0; | ||
| 252 | |||
| 253 | if (mutex_lock_interruptible(&wdt->lock)) | ||
| 254 | return -ERESTARTSYS; | ||
| 255 | |||
| 256 | ts72xx_wdt_kick(wdt); | ||
| 257 | |||
| 258 | /* | ||
| 259 | * Support for magic character closing. User process | ||
| 260 | * writes 'V' into the device, just before it is closed. | ||
| 261 | * This means that we know that the wdt timer can be | ||
| 262 | * stopped after user closes the device. | ||
| 263 | */ | ||
| 264 | if (!nowayout) { | ||
| 265 | int i; | ||
| 266 | |||
| 267 | for (i = 0; i < len; i++) { | ||
| 268 | char c; | ||
| 269 | |||
| 270 | /* In case it was set long ago */ | ||
| 271 | wdt->flags &= ~TS72XX_WDT_EXPECT_CLOSE_FLAG; | ||
| 272 | |||
| 273 | if (get_user(c, data + i)) { | ||
| 274 | mutex_unlock(&wdt->lock); | ||
| 275 | return -EFAULT; | ||
| 276 | } | ||
| 277 | if (c == 'V') { | ||
| 278 | wdt->flags |= TS72XX_WDT_EXPECT_CLOSE_FLAG; | ||
| 279 | break; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | } | 102 | } |
| 283 | 103 | ||
| 284 | mutex_unlock(&wdt->lock); | 104 | return 0; |
| 285 | return len; | ||
| 286 | } | 105 | } |
| 287 | 106 | ||
| 288 | static const struct watchdog_info winfo = { | 107 | static const struct watchdog_info ts72xx_wdt_ident = { |
| 289 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | | 108 | .options = WDIOF_KEEPALIVEPING | |
| 109 | WDIOF_SETTIMEOUT | | ||
| 290 | WDIOF_MAGICCLOSE, | 110 | WDIOF_MAGICCLOSE, |
| 291 | .firmware_version = 1, | 111 | .firmware_version = 1, |
| 292 | .identity = "TS-72XX WDT", | 112 | .identity = "TS-72XX WDT", |
| 293 | }; | 113 | }; |
| 294 | 114 | ||
| 295 | static long ts72xx_wdt_ioctl(struct file *file, unsigned int cmd, | 115 | static struct watchdog_ops ts72xx_wdt_ops = { |
| 296 | unsigned long arg) | ||
| 297 | { | ||
| 298 | struct ts72xx_wdt *wdt = file->private_data; | ||
| 299 | void __user *argp = (void __user *)arg; | ||
| 300 | int __user *p = (int __user *)argp; | ||
| 301 | int error = 0; | ||
| 302 | |||
| 303 | if (mutex_lock_interruptible(&wdt->lock)) | ||
| 304 | return -ERESTARTSYS; | ||
| 305 | |||
| 306 | switch (cmd) { | ||
| 307 | case WDIOC_GETSUPPORT: | ||
| 308 | if (copy_to_user(argp, &winfo, sizeof(winfo))) | ||
| 309 | error = -EFAULT; | ||
| 310 | break; | ||
| 311 | |||
| 312 | case WDIOC_GETSTATUS: | ||
| 313 | case WDIOC_GETBOOTSTATUS: | ||
| 314 | error = put_user(0, p); | ||
| 315 | break; | ||
| 316 | |||
| 317 | case WDIOC_KEEPALIVE: | ||
| 318 | ts72xx_wdt_kick(wdt); | ||
| 319 | break; | ||
| 320 | |||
| 321 | case WDIOC_SETOPTIONS: { | ||
| 322 | int options; | ||
| 323 | |||
| 324 | error = get_user(options, p); | ||
| 325 | if (error) | ||
| 326 | break; | ||
| 327 | |||
| 328 | error = -EINVAL; | ||
| 329 | |||
| 330 | if ((options & WDIOS_DISABLECARD) != 0) { | ||
| 331 | ts72xx_wdt_stop(wdt); | ||
| 332 | error = 0; | ||
| 333 | } | ||
| 334 | if ((options & WDIOS_ENABLECARD) != 0) { | ||
| 335 | ts72xx_wdt_start(wdt); | ||
| 336 | error = 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | break; | ||
| 340 | } | ||
| 341 | |||
| 342 | case WDIOC_SETTIMEOUT: { | ||
| 343 | int new_timeout; | ||
| 344 | int regval; | ||
| 345 | |||
| 346 | error = get_user(new_timeout, p); | ||
| 347 | if (error) | ||
| 348 | break; | ||
| 349 | |||
| 350 | regval = timeout_to_regval(new_timeout); | ||
| 351 | if (regval < 0) { | ||
| 352 | error = regval; | ||
| 353 | break; | ||
| 354 | } | ||
| 355 | ts72xx_wdt_stop(wdt); | ||
| 356 | wdt->regval = regval; | ||
| 357 | ts72xx_wdt_start(wdt); | ||
| 358 | |||
| 359 | /*FALLTHROUGH*/ | ||
| 360 | } | ||
| 361 | |||
| 362 | case WDIOC_GETTIMEOUT: | ||
| 363 | error = put_user(regval_to_timeout(wdt->regval), p); | ||
| 364 | break; | ||
| 365 | |||
| 366 | default: | ||
| 367 | error = -ENOTTY; | ||
| 368 | break; | ||
| 369 | } | ||
| 370 | |||
| 371 | mutex_unlock(&wdt->lock); | ||
| 372 | return error; | ||
| 373 | } | ||
| 374 | |||
| 375 | static const struct file_operations ts72xx_wdt_fops = { | ||
| 376 | .owner = THIS_MODULE, | 116 | .owner = THIS_MODULE, |
| 377 | .llseek = no_llseek, | 117 | .start = ts72xx_wdt_start, |
| 378 | .open = ts72xx_wdt_open, | 118 | .stop = ts72xx_wdt_stop, |
| 379 | .release = ts72xx_wdt_release, | 119 | .ping = ts72xx_wdt_ping, |
| 380 | .write = ts72xx_wdt_write, | 120 | .set_timeout = ts72xx_wdt_settimeout, |
| 381 | .unlocked_ioctl = ts72xx_wdt_ioctl, | ||
| 382 | }; | ||
| 383 | |||
| 384 | static struct miscdevice ts72xx_wdt_miscdev = { | ||
| 385 | .minor = WATCHDOG_MINOR, | ||
| 386 | .name = "watchdog", | ||
| 387 | .fops = &ts72xx_wdt_fops, | ||
| 388 | }; | 121 | }; |
| 389 | 122 | ||
| 390 | static int ts72xx_wdt_probe(struct platform_device *pdev) | 123 | static int ts72xx_wdt_probe(struct platform_device *pdev) |
| 391 | { | 124 | { |
| 392 | struct ts72xx_wdt *wdt; | 125 | struct ts72xx_wdt_priv *priv; |
| 393 | struct resource *r1, *r2; | 126 | struct watchdog_device *wdd; |
| 394 | int error = 0; | 127 | struct resource *res; |
| 128 | int ret; | ||
| 395 | 129 | ||
| 396 | wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL); | 130 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); |
| 397 | if (!wdt) | 131 | if (!priv) |
| 398 | return -ENOMEM; | 132 | return -ENOMEM; |
| 399 | 133 | ||
| 400 | r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 134 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 401 | wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1); | 135 | priv->control_reg = devm_ioremap_resource(&pdev->dev, res); |
| 402 | if (IS_ERR(wdt->control_reg)) | 136 | if (IS_ERR(priv->control_reg)) |
| 403 | return PTR_ERR(wdt->control_reg); | 137 | return PTR_ERR(priv->control_reg); |
| 404 | 138 | ||
| 405 | r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 139 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| 406 | wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2); | 140 | priv->feed_reg = devm_ioremap_resource(&pdev->dev, res); |
| 407 | if (IS_ERR(wdt->feed_reg)) | 141 | if (IS_ERR(priv->feed_reg)) |
| 408 | return PTR_ERR(wdt->feed_reg); | 142 | return PTR_ERR(priv->feed_reg); |
| 409 | 143 | ||
| 410 | platform_set_drvdata(pdev, wdt); | 144 | wdd = &priv->wdd; |
| 411 | ts72xx_wdt_pdev = pdev; | 145 | wdd->info = &ts72xx_wdt_ident; |
| 412 | wdt->pdev = pdev; | 146 | wdd->ops = &ts72xx_wdt_ops; |
| 413 | mutex_init(&wdt->lock); | 147 | wdd->min_timeout = 1; |
| 148 | wdd->max_hw_heartbeat_ms = 8000; | ||
| 149 | wdd->parent = &pdev->dev; | ||
| 414 | 150 | ||
| 415 | /* make sure that the watchdog is disabled */ | 151 | watchdog_set_nowayout(wdd, nowayout); |
| 416 | ts72xx_wdt_stop(wdt); | ||
| 417 | 152 | ||
| 418 | error = misc_register(&ts72xx_wdt_miscdev); | 153 | wdd->timeout = TS72XX_WDT_DEFAULT_TIMEOUT; |
| 419 | if (error) { | 154 | watchdog_init_timeout(wdd, timeout, &pdev->dev); |
| 420 | dev_err(&pdev->dev, "failed to register miscdev\n"); | ||
| 421 | return error; | ||
| 422 | } | ||
| 423 | 155 | ||
| 424 | dev_info(&pdev->dev, "TS-72xx Watchdog driver\n"); | 156 | watchdog_set_drvdata(wdd, priv); |
| 425 | 157 | ||
| 426 | return 0; | 158 | ret = devm_watchdog_register_device(&pdev->dev, wdd); |
| 427 | } | 159 | if (ret) |
| 160 | return ret; | ||
| 161 | |||
| 162 | dev_info(&pdev->dev, "TS-72xx Watchdog driver\n"); | ||
| 428 | 163 | ||
| 429 | static int ts72xx_wdt_remove(struct platform_device *pdev) | ||
| 430 | { | ||
| 431 | misc_deregister(&ts72xx_wdt_miscdev); | ||
| 432 | return 0; | 164 | return 0; |
| 433 | } | 165 | } |
| 434 | 166 | ||
| 435 | static struct platform_driver ts72xx_wdt_driver = { | 167 | static struct platform_driver ts72xx_wdt_driver = { |
| 436 | .probe = ts72xx_wdt_probe, | 168 | .probe = ts72xx_wdt_probe, |
| 437 | .remove = ts72xx_wdt_remove, | ||
| 438 | .driver = { | 169 | .driver = { |
| 439 | .name = "ts72xx-wdt", | 170 | .name = "ts72xx-wdt", |
| 440 | }, | 171 | }, |
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index ef2ecaf53a14..98fd186c6878 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c | |||
| @@ -297,7 +297,7 @@ static unsigned int wdt_get_time(struct watchdog_device *wdog) | |||
| 297 | * Kernel Interfaces | 297 | * Kernel Interfaces |
| 298 | */ | 298 | */ |
| 299 | 299 | ||
| 300 | static struct watchdog_info wdt_info = { | 300 | static const struct watchdog_info wdt_info = { |
| 301 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | 301 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, |
| 302 | .identity = "W83627HF Watchdog", | 302 | .identity = "W83627HF Watchdog", |
| 303 | }; | 303 | }; |
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 32930a073a12..d5d2bbd8f428 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c | |||
| @@ -987,6 +987,11 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd) | |||
| 987 | wdd->wd_data = NULL; | 987 | wdd->wd_data = NULL; |
| 988 | mutex_unlock(&wd_data->lock); | 988 | mutex_unlock(&wd_data->lock); |
| 989 | 989 | ||
| 990 | if (watchdog_active(wdd) && | ||
| 991 | test_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status)) { | ||
| 992 | watchdog_stop(wdd); | ||
| 993 | } | ||
| 994 | |||
| 990 | cancel_delayed_work_sync(&wd_data->work); | 995 | cancel_delayed_work_sync(&wd_data->work); |
| 991 | 996 | ||
| 992 | kref_put(&wd_data->kref, watchdog_core_data_release); | 997 | kref_put(&wd_data->kref, watchdog_core_data_release); |
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 8d1184aee932..1ddc1f742cd4 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c | |||
| @@ -194,7 +194,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev) | |||
| 194 | if (ret < 0) { | 194 | if (ret < 0) { |
| 195 | dev_err(wm831x->dev, "Failed to read watchdog status: %d\n", | 195 | dev_err(wm831x->dev, "Failed to read watchdog status: %d\n", |
| 196 | ret); | 196 | ret); |
| 197 | goto err; | 197 | return ret; |
| 198 | } | 198 | } |
| 199 | reg = ret; | 199 | reg = ret; |
| 200 | 200 | ||
| @@ -203,10 +203,8 @@ static int wm831x_wdt_probe(struct platform_device *pdev) | |||
| 203 | 203 | ||
| 204 | driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data), | 204 | driver_data = devm_kzalloc(&pdev->dev, sizeof(*driver_data), |
| 205 | GFP_KERNEL); | 205 | GFP_KERNEL); |
| 206 | if (!driver_data) { | 206 | if (!driver_data) |
| 207 | ret = -ENOMEM; | 207 | return -ENOMEM; |
| 208 | goto err; | ||
| 209 | } | ||
| 210 | 208 | ||
| 211 | mutex_init(&driver_data->lock); | 209 | mutex_init(&driver_data->lock); |
| 212 | driver_data->wm831x = wm831x; | 210 | driver_data->wm831x = wm831x; |
| @@ -253,7 +251,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev) | |||
| 253 | dev_err(wm831x->dev, | 251 | dev_err(wm831x->dev, |
| 254 | "Failed to request update GPIO: %d\n", | 252 | "Failed to request update GPIO: %d\n", |
| 255 | ret); | 253 | ret); |
| 256 | goto err; | 254 | return ret; |
| 257 | } | 255 | } |
| 258 | 256 | ||
| 259 | driver_data->update_gpio = pdata->update_gpio; | 257 | driver_data->update_gpio = pdata->update_gpio; |
| @@ -269,37 +267,22 @@ static int wm831x_wdt_probe(struct platform_device *pdev) | |||
| 269 | } else { | 267 | } else { |
| 270 | dev_err(wm831x->dev, | 268 | dev_err(wm831x->dev, |
| 271 | "Failed to unlock security key: %d\n", ret); | 269 | "Failed to unlock security key: %d\n", ret); |
| 272 | goto err; | 270 | return ret; |
| 273 | } | 271 | } |
| 274 | } | 272 | } |
| 275 | 273 | ||
| 276 | ret = watchdog_register_device(&driver_data->wdt); | 274 | ret = devm_watchdog_register_device(&pdev->dev, &driver_data->wdt); |
| 277 | if (ret != 0) { | 275 | if (ret != 0) { |
| 278 | dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n", | 276 | dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n", |
| 279 | ret); | 277 | ret); |
| 280 | goto err; | 278 | return ret; |
| 281 | } | 279 | } |
| 282 | 280 | ||
| 283 | platform_set_drvdata(pdev, driver_data); | ||
| 284 | |||
| 285 | return 0; | ||
| 286 | |||
| 287 | err: | ||
| 288 | return ret; | ||
| 289 | } | ||
| 290 | |||
| 291 | static int wm831x_wdt_remove(struct platform_device *pdev) | ||
| 292 | { | ||
| 293 | struct wm831x_wdt_drvdata *driver_data = platform_get_drvdata(pdev); | ||
| 294 | |||
| 295 | watchdog_unregister_device(&driver_data->wdt); | ||
| 296 | |||
| 297 | return 0; | 281 | return 0; |
| 298 | } | 282 | } |
| 299 | 283 | ||
| 300 | static struct platform_driver wm831x_wdt_driver = { | 284 | static struct platform_driver wm831x_wdt_driver = { |
| 301 | .probe = wm831x_wdt_probe, | 285 | .probe = wm831x_wdt_probe, |
| 302 | .remove = wm831x_wdt_remove, | ||
| 303 | .driver = { | 286 | .driver = { |
| 304 | .name = "wm831x-watchdog", | 287 | .name = "wm831x-watchdog", |
| 305 | }, | 288 | }, |
diff --git a/drivers/watchdog/zx2967_wdt.c b/drivers/watchdog/zx2967_wdt.c new file mode 100644 index 000000000000..e290d5a13a6d --- /dev/null +++ b/drivers/watchdog/zx2967_wdt.c | |||
| @@ -0,0 +1,291 @@ | |||
| 1 | /* | ||
| 2 | * watchdog driver for ZTE's zx2967 family | ||
| 3 | * | ||
| 4 | * Copyright (C) 2017 ZTE Ltd. | ||
| 5 | * | ||
| 6 | * Author: Baoyou Xie <baoyou.xie@linaro.org> | ||
| 7 | * | ||
| 8 | * License terms: GNU General Public License (GPL) version 2 | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/clk.h> | ||
| 12 | #include <linux/io.h> | ||
| 13 | #include <linux/mfd/syscon.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/of_address.h> | ||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/regmap.h> | ||
| 18 | #include <linux/reset.h> | ||
| 19 | #include <linux/watchdog.h> | ||
| 20 | |||
| 21 | #define ZX2967_WDT_CFG_REG 0x4 | ||
| 22 | #define ZX2967_WDT_LOAD_REG 0x8 | ||
| 23 | #define ZX2967_WDT_REFRESH_REG 0x18 | ||
| 24 | #define ZX2967_WDT_START_REG 0x1c | ||
| 25 | |||
| 26 | #define ZX2967_WDT_REFRESH_MASK GENMASK(5, 0) | ||
| 27 | |||
| 28 | #define ZX2967_WDT_CFG_DIV(n) ((((n) & 0xff) - 1) << 8) | ||
| 29 | #define ZX2967_WDT_START_EN 0x1 | ||
| 30 | |||
| 31 | /* | ||
| 32 | * Hardware magic number. | ||
| 33 | * When watchdog reg is written, the lowest 16 bits are valid, but | ||
| 34 | * the highest 16 bits should be always this number. | ||
| 35 | */ | ||
| 36 | #define ZX2967_WDT_WRITEKEY (0x1234 << 16) | ||
| 37 | #define ZX2967_WDT_VAL_MASK GENMASK(15, 0) | ||
| 38 | |||
| 39 | #define ZX2967_WDT_DIV_DEFAULT 16 | ||
| 40 | #define ZX2967_WDT_DEFAULT_TIMEOUT 32 | ||
| 41 | #define ZX2967_WDT_MIN_TIMEOUT 1 | ||
| 42 | #define ZX2967_WDT_MAX_TIMEOUT 524 | ||
| 43 | #define ZX2967_WDT_MAX_COUNT 0xffff | ||
| 44 | |||
| 45 | #define ZX2967_WDT_CLK_FREQ 0x8000 | ||
| 46 | |||
| 47 | #define ZX2967_WDT_FLAG_REBOOT_MON BIT(0) | ||
| 48 | |||
| 49 | struct zx2967_wdt { | ||
| 50 | struct watchdog_device wdt_device; | ||
| 51 | void __iomem *reg_base; | ||
| 52 | struct clk *clock; | ||
| 53 | }; | ||
| 54 | |||
| 55 | static inline u32 zx2967_wdt_readl(struct zx2967_wdt *wdt, u16 reg) | ||
| 56 | { | ||
| 57 | return readl_relaxed(wdt->reg_base + reg); | ||
| 58 | } | ||
| 59 | |||
| 60 | static inline void zx2967_wdt_writel(struct zx2967_wdt *wdt, u16 reg, u32 val) | ||
| 61 | { | ||
| 62 | writel_relaxed(val | ZX2967_WDT_WRITEKEY, wdt->reg_base + reg); | ||
| 63 | } | ||
| 64 | |||
| 65 | static void zx2967_wdt_refresh(struct zx2967_wdt *wdt) | ||
| 66 | { | ||
| 67 | u32 val; | ||
| 68 | |||
| 69 | val = zx2967_wdt_readl(wdt, ZX2967_WDT_REFRESH_REG); | ||
| 70 | /* | ||
| 71 | * Bit 4-5, 1 and 2: refresh config info | ||
| 72 | * Bit 2-3, 1 and 2: refresh counter | ||
| 73 | * Bit 0-1, 1 and 2: refresh int-value | ||
| 74 | * we shift each group value between 1 and 2 to refresh all data. | ||
| 75 | */ | ||
| 76 | val ^= ZX2967_WDT_REFRESH_MASK; | ||
| 77 | zx2967_wdt_writel(wdt, ZX2967_WDT_REFRESH_REG, | ||
| 78 | val & ZX2967_WDT_VAL_MASK); | ||
| 79 | } | ||
| 80 | |||
| 81 | static int | ||
| 82 | zx2967_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout) | ||
| 83 | { | ||
| 84 | struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 85 | unsigned int divisor = ZX2967_WDT_DIV_DEFAULT; | ||
| 86 | u32 count; | ||
| 87 | |||
| 88 | count = timeout * ZX2967_WDT_CLK_FREQ; | ||
| 89 | if (count > divisor * ZX2967_WDT_MAX_COUNT) | ||
| 90 | divisor = DIV_ROUND_UP(count, ZX2967_WDT_MAX_COUNT); | ||
| 91 | count = DIV_ROUND_UP(count, divisor); | ||
| 92 | zx2967_wdt_writel(wdt, ZX2967_WDT_CFG_REG, | ||
| 93 | ZX2967_WDT_CFG_DIV(divisor) & ZX2967_WDT_VAL_MASK); | ||
| 94 | zx2967_wdt_writel(wdt, ZX2967_WDT_LOAD_REG, | ||
| 95 | count & ZX2967_WDT_VAL_MASK); | ||
| 96 | zx2967_wdt_refresh(wdt); | ||
| 97 | wdd->timeout = (count * divisor) / ZX2967_WDT_CLK_FREQ; | ||
| 98 | |||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static void __zx2967_wdt_start(struct zx2967_wdt *wdt) | ||
| 103 | { | ||
| 104 | u32 val; | ||
| 105 | |||
| 106 | val = zx2967_wdt_readl(wdt, ZX2967_WDT_START_REG); | ||
| 107 | val |= ZX2967_WDT_START_EN; | ||
| 108 | zx2967_wdt_writel(wdt, ZX2967_WDT_START_REG, | ||
| 109 | val & ZX2967_WDT_VAL_MASK); | ||
| 110 | } | ||
| 111 | |||
| 112 | static void __zx2967_wdt_stop(struct zx2967_wdt *wdt) | ||
| 113 | { | ||
| 114 | u32 val; | ||
| 115 | |||
| 116 | val = zx2967_wdt_readl(wdt, ZX2967_WDT_START_REG); | ||
| 117 | val &= ~ZX2967_WDT_START_EN; | ||
| 118 | zx2967_wdt_writel(wdt, ZX2967_WDT_START_REG, | ||
| 119 | val & ZX2967_WDT_VAL_MASK); | ||
| 120 | } | ||
| 121 | |||
| 122 | static int zx2967_wdt_start(struct watchdog_device *wdd) | ||
| 123 | { | ||
| 124 | struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 125 | |||
| 126 | zx2967_wdt_set_timeout(wdd, wdd->timeout); | ||
| 127 | __zx2967_wdt_start(wdt); | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int zx2967_wdt_stop(struct watchdog_device *wdd) | ||
| 133 | { | ||
| 134 | struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 135 | |||
| 136 | __zx2967_wdt_stop(wdt); | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | static int zx2967_wdt_keepalive(struct watchdog_device *wdd) | ||
| 142 | { | ||
| 143 | struct zx2967_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 144 | |||
| 145 | zx2967_wdt_refresh(wdt); | ||
| 146 | |||
| 147 | return 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | #define ZX2967_WDT_OPTIONS \ | ||
| 151 | (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE) | ||
| 152 | static const struct watchdog_info zx2967_wdt_ident = { | ||
| 153 | .options = ZX2967_WDT_OPTIONS, | ||
| 154 | .identity = "zx2967 watchdog", | ||
| 155 | }; | ||
| 156 | |||
| 157 | static struct watchdog_ops zx2967_wdt_ops = { | ||
| 158 | .owner = THIS_MODULE, | ||
| 159 | .start = zx2967_wdt_start, | ||
| 160 | .stop = zx2967_wdt_stop, | ||
| 161 | .ping = zx2967_wdt_keepalive, | ||
| 162 | .set_timeout = zx2967_wdt_set_timeout, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static void zx2967_wdt_reset_sysctrl(struct device *dev) | ||
| 166 | { | ||
| 167 | int ret; | ||
| 168 | void __iomem *regmap; | ||
| 169 | unsigned int offset, mask, config; | ||
| 170 | struct of_phandle_args out_args; | ||
| 171 | |||
| 172 | ret = of_parse_phandle_with_fixed_args(dev->of_node, | ||
| 173 | "zte,wdt-reset-sysctrl", 3, 0, &out_args); | ||
| 174 | if (ret) | ||
| 175 | return; | ||
| 176 | |||
| 177 | offset = out_args.args[0]; | ||
| 178 | config = out_args.args[1]; | ||
| 179 | mask = out_args.args[2]; | ||
| 180 | |||
| 181 | regmap = syscon_node_to_regmap(out_args.np); | ||
| 182 | if (IS_ERR(regmap)) { | ||
| 183 | of_node_put(out_args.np); | ||
| 184 | return; | ||
| 185 | } | ||
| 186 | |||
| 187 | regmap_update_bits(regmap, offset, mask, config); | ||
| 188 | of_node_put(out_args.np); | ||
| 189 | } | ||
| 190 | |||
| 191 | static int zx2967_wdt_probe(struct platform_device *pdev) | ||
| 192 | { | ||
| 193 | struct device *dev = &pdev->dev; | ||
| 194 | struct zx2967_wdt *wdt; | ||
| 195 | struct resource *base; | ||
| 196 | int ret; | ||
| 197 | struct reset_control *rstc; | ||
| 198 | |||
| 199 | wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); | ||
| 200 | if (!wdt) | ||
| 201 | return -ENOMEM; | ||
| 202 | |||
| 203 | platform_set_drvdata(pdev, wdt); | ||
| 204 | |||
| 205 | wdt->wdt_device.info = &zx2967_wdt_ident; | ||
| 206 | wdt->wdt_device.ops = &zx2967_wdt_ops; | ||
| 207 | wdt->wdt_device.timeout = ZX2967_WDT_DEFAULT_TIMEOUT; | ||
| 208 | wdt->wdt_device.max_timeout = ZX2967_WDT_MAX_TIMEOUT; | ||
| 209 | wdt->wdt_device.min_timeout = ZX2967_WDT_MIN_TIMEOUT; | ||
| 210 | wdt->wdt_device.parent = &pdev->dev; | ||
| 211 | |||
| 212 | base = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 213 | wdt->reg_base = devm_ioremap_resource(dev, base); | ||
| 214 | if (IS_ERR(wdt->reg_base)) { | ||
| 215 | dev_err(dev, "ioremap failed\n"); | ||
| 216 | return PTR_ERR(wdt->reg_base); | ||
| 217 | } | ||
| 218 | |||
| 219 | zx2967_wdt_reset_sysctrl(dev); | ||
| 220 | |||
| 221 | wdt->clock = devm_clk_get(dev, NULL); | ||
| 222 | if (IS_ERR(wdt->clock)) { | ||
| 223 | dev_err(dev, "failed to find watchdog clock source\n"); | ||
| 224 | return PTR_ERR(wdt->clock); | ||
| 225 | } | ||
| 226 | |||
| 227 | ret = clk_prepare_enable(wdt->clock); | ||
| 228 | if (ret < 0) { | ||
| 229 | dev_err(dev, "failed to enable clock\n"); | ||
| 230 | return ret; | ||
| 231 | } | ||
| 232 | clk_set_rate(wdt->clock, ZX2967_WDT_CLK_FREQ); | ||
| 233 | |||
| 234 | rstc = devm_reset_control_get(dev, NULL); | ||
| 235 | if (IS_ERR(rstc)) { | ||
| 236 | dev_err(dev, "failed to get rstc"); | ||
| 237 | ret = PTR_ERR(rstc); | ||
| 238 | goto err; | ||
| 239 | } | ||
| 240 | |||
| 241 | reset_control_assert(rstc); | ||
| 242 | reset_control_deassert(rstc); | ||
| 243 | |||
| 244 | watchdog_set_drvdata(&wdt->wdt_device, wdt); | ||
| 245 | watchdog_init_timeout(&wdt->wdt_device, | ||
| 246 | ZX2967_WDT_DEFAULT_TIMEOUT, dev); | ||
| 247 | watchdog_set_nowayout(&wdt->wdt_device, WATCHDOG_NOWAYOUT); | ||
| 248 | |||
| 249 | ret = watchdog_register_device(&wdt->wdt_device); | ||
| 250 | if (ret) | ||
| 251 | goto err; | ||
| 252 | |||
| 253 | dev_info(dev, "watchdog enabled (timeout=%d sec, nowayout=%d)", | ||
| 254 | wdt->wdt_device.timeout, WATCHDOG_NOWAYOUT); | ||
| 255 | |||
| 256 | return 0; | ||
| 257 | |||
| 258 | err: | ||
| 259 | clk_disable_unprepare(wdt->clock); | ||
| 260 | return ret; | ||
| 261 | } | ||
| 262 | |||
| 263 | static int zx2967_wdt_remove(struct platform_device *pdev) | ||
| 264 | { | ||
| 265 | struct zx2967_wdt *wdt = platform_get_drvdata(pdev); | ||
| 266 | |||
| 267 | watchdog_unregister_device(&wdt->wdt_device); | ||
| 268 | clk_disable_unprepare(wdt->clock); | ||
| 269 | |||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | static const struct of_device_id zx2967_wdt_match[] = { | ||
| 274 | { .compatible = "zte,zx296718-wdt", }, | ||
| 275 | {} | ||
| 276 | }; | ||
| 277 | MODULE_DEVICE_TABLE(of, zx2967_wdt_match); | ||
| 278 | |||
| 279 | static struct platform_driver zx2967_wdt_driver = { | ||
| 280 | .probe = zx2967_wdt_probe, | ||
| 281 | .remove = zx2967_wdt_remove, | ||
| 282 | .driver = { | ||
| 283 | .name = "zx2967-wdt", | ||
| 284 | .of_match_table = of_match_ptr(zx2967_wdt_match), | ||
| 285 | }, | ||
| 286 | }; | ||
| 287 | module_platform_driver(zx2967_wdt_driver); | ||
| 288 | |||
| 289 | MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>"); | ||
| 290 | MODULE_DESCRIPTION("ZTE zx2967 Watchdog Device Driver"); | ||
| 291 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index 35a4d8185b51..a786e5e8973b 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h | |||
| @@ -117,6 +117,7 @@ struct watchdog_device { | |||
| 117 | #define WDOG_NO_WAY_OUT 1 /* Is 'nowayout' feature set ? */ | 117 | #define WDOG_NO_WAY_OUT 1 /* Is 'nowayout' feature set ? */ |
| 118 | #define WDOG_STOP_ON_REBOOT 2 /* Should be stopped on reboot */ | 118 | #define WDOG_STOP_ON_REBOOT 2 /* Should be stopped on reboot */ |
| 119 | #define WDOG_HW_RUNNING 3 /* True if HW watchdog running */ | 119 | #define WDOG_HW_RUNNING 3 /* True if HW watchdog running */ |
| 120 | #define WDOG_STOP_ON_UNREGISTER 4 /* Should be stopped on unregister */ | ||
| 120 | struct list_head deferred; | 121 | struct list_head deferred; |
| 121 | }; | 122 | }; |
| 122 | 123 | ||
| @@ -151,6 +152,12 @@ static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd) | |||
| 151 | set_bit(WDOG_STOP_ON_REBOOT, &wdd->status); | 152 | set_bit(WDOG_STOP_ON_REBOOT, &wdd->status); |
| 152 | } | 153 | } |
| 153 | 154 | ||
| 155 | /* Use the following function to stop the watchdog when unregistering it */ | ||
| 156 | static inline void watchdog_stop_on_unregister(struct watchdog_device *wdd) | ||
| 157 | { | ||
| 158 | set_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status); | ||
| 159 | } | ||
| 160 | |||
| 154 | /* Use the following function to check if a timeout value is invalid */ | 161 | /* Use the following function to check if a timeout value is invalid */ |
| 155 | static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t) | 162 | static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t) |
| 156 | { | 163 | { |
