diff options
53 files changed, 916 insertions, 135 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt new file mode 100644 index 000000000000..f7cc7c060910 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | * Atmel SAMA5D4 Watchdog Timer (WDT) Controller | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: "atmel,sama5d4-wdt" | ||
| 5 | - reg: base physical address and length of memory mapped region. | ||
| 6 | |||
| 7 | Optional properties: | ||
| 8 | - timeout-sec: watchdog timeout value (in seconds). | ||
| 9 | - interrupts: interrupt number to the CPU. | ||
| 10 | - atmel,watchdog-type: should be "hardware" or "software". | ||
| 11 | "hardware": enable watchdog fault reset. A watchdog fault triggers | ||
| 12 | watchdog reset. | ||
| 13 | "software": enable watchdog fault interrupt. A watchdog fault asserts | ||
| 14 | watchdog interrupt. | ||
| 15 | - atmel,idle-halt: present if you want to stop the watchdog when the CPU is | ||
| 16 | in idle state. | ||
| 17 | CAUTION: This property should be used with care, it actually makes the | ||
| 18 | watchdog not counting when the CPU is in idle state, therefore the | ||
| 19 | watchdog reset time depends on mean CPU usage and will not reset at all | ||
| 20 | if the CPU stop working while it is in idle state, which is probably | ||
| 21 | not what you want. | ||
| 22 | - atmel,dbg-halt: present if you want to stop the watchdog when the CPU is | ||
| 23 | in debug state. | ||
| 24 | |||
| 25 | Example: | ||
| 26 | watchdog@fc068640 { | ||
| 27 | compatible = "atmel,sama5d4-wdt"; | ||
| 28 | reg = <0xfc068640 0x10>; | ||
| 29 | interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>; | ||
| 30 | timeout-sec = <10>; | ||
| 31 | atmel,watchdog-type = "hardware"; | ||
| 32 | atmel,dbg-halt; | ||
| 33 | atmel,idle-halt; | ||
| 34 | status = "okay"; | ||
| 35 | }; | ||
diff --git a/Documentation/devicetree/bindings/watchdog/lpc18xx-wdt.txt b/Documentation/devicetree/bindings/watchdog/lpc18xx-wdt.txt new file mode 100644 index 000000000000..09f6b24969e0 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/lpc18xx-wdt.txt | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | * NXP LPC18xx Watchdog Timer (WDT) | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be "nxp,lpc1850-wwdt" | ||
| 5 | - reg: Should contain WDT registers location and length | ||
| 6 | - clocks: Must contain an entry for each entry in clock-names. | ||
| 7 | - clock-names: Should contain "wdtclk" and "reg"; the watchdog counter | ||
| 8 | clock and register interface clock respectively. | ||
| 9 | - interrupts: Should contain WDT interrupt | ||
| 10 | |||
| 11 | Examples: | ||
| 12 | |||
| 13 | watchdog@40080000 { | ||
| 14 | compatible = "nxp,lpc1850-wwdt"; | ||
| 15 | reg = <0x40080000 0x24>; | ||
| 16 | clocks = <&cgu BASE_SAFE_CLK>, <&ccu1 CLK_CPU_WWDT>; | ||
| 17 | clock-names = "wdtclk", "reg"; | ||
| 18 | interrupts = <49>; | ||
| 19 | }; | ||
diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c index 3da822967ee0..fcdde8fc98be 100644 --- a/Documentation/watchdog/src/watchdog-test.c +++ b/Documentation/watchdog/src/watchdog-test.c | |||
| @@ -41,6 +41,7 @@ static void term(int sig) | |||
| 41 | int main(int argc, char *argv[]) | 41 | int main(int argc, char *argv[]) |
| 42 | { | 42 | { |
| 43 | int flags; | 43 | int flags; |
| 44 | unsigned int ping_rate = 1; | ||
| 44 | 45 | ||
| 45 | fd = open("/dev/watchdog", O_WRONLY); | 46 | fd = open("/dev/watchdog", O_WRONLY); |
| 46 | 47 | ||
| @@ -63,22 +64,33 @@ int main(int argc, char *argv[]) | |||
| 63 | fprintf(stderr, "Watchdog card enabled.\n"); | 64 | fprintf(stderr, "Watchdog card enabled.\n"); |
| 64 | fflush(stderr); | 65 | fflush(stderr); |
| 65 | goto end; | 66 | goto end; |
| 67 | } else if (!strncasecmp(argv[1], "-t", 2) && argv[2]) { | ||
| 68 | flags = atoi(argv[2]); | ||
| 69 | ioctl(fd, WDIOC_SETTIMEOUT, &flags); | ||
| 70 | fprintf(stderr, "Watchdog timeout set to %u seconds.\n", flags); | ||
| 71 | fflush(stderr); | ||
| 72 | goto end; | ||
| 73 | } else if (!strncasecmp(argv[1], "-p", 2) && argv[2]) { | ||
| 74 | ping_rate = strtoul(argv[2], NULL, 0); | ||
| 75 | fprintf(stderr, "Watchdog ping rate set to %u seconds.\n", ping_rate); | ||
| 76 | fflush(stderr); | ||
| 66 | } else { | 77 | } else { |
| 67 | fprintf(stderr, "-d to disable, -e to enable.\n"); | 78 | fprintf(stderr, "-d to disable, -e to enable, -t <n> to set " \ |
| 79 | "the timeout,\n-p <n> to set the ping rate, and \n"); | ||
| 68 | fprintf(stderr, "run by itself to tick the card.\n"); | 80 | fprintf(stderr, "run by itself to tick the card.\n"); |
| 69 | fflush(stderr); | 81 | fflush(stderr); |
| 70 | goto end; | 82 | goto end; |
| 71 | } | 83 | } |
| 72 | } else { | ||
| 73 | fprintf(stderr, "Watchdog Ticking Away!\n"); | ||
| 74 | fflush(stderr); | ||
| 75 | } | 84 | } |
| 76 | 85 | ||
| 86 | fprintf(stderr, "Watchdog Ticking Away!\n"); | ||
| 87 | fflush(stderr); | ||
| 88 | |||
| 77 | signal(SIGINT, term); | 89 | signal(SIGINT, term); |
| 78 | 90 | ||
| 79 | while(1) { | 91 | while(1) { |
| 80 | keep_alive(); | 92 | keep_alive(); |
| 81 | sleep(1); | 93 | sleep(ping_rate); |
| 82 | } | 94 | } |
| 83 | end: | 95 | end: |
| 84 | close(fd); | 96 | close(fd); |
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index 2bc0f5089f82..b346638833b0 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c | |||
| @@ -364,6 +364,7 @@ int mei_watchdog_register(struct mei_device *dev) | |||
| 364 | 364 | ||
| 365 | int ret; | 365 | int ret; |
| 366 | 366 | ||
| 367 | amt_wd_dev.parent = dev->dev; | ||
| 367 | /* unlock to perserve correct locking order */ | 368 | /* unlock to perserve correct locking order */ |
| 368 | mutex_unlock(&dev->device_lock); | 369 | mutex_unlock(&dev->device_lock); |
| 369 | ret = watchdog_register_device(&amt_wd_dev); | 370 | ret = watchdog_register_device(&amt_wd_dev); |
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 55c4b5b0a317..c68edc16aa54 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
| @@ -188,6 +188,15 @@ config AT91SAM9X_WATCHDOG | |||
| 188 | Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will | 188 | Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will |
| 189 | reboot your system when the timeout is reached. | 189 | reboot your system when the timeout is reached. |
| 190 | 190 | ||
| 191 | config SAMA5D4_WATCHDOG | ||
| 192 | tristate "Atmel SAMA5D4 Watchdog Timer" | ||
| 193 | depends on ARCH_AT91 | ||
| 194 | select WATCHDOG_CORE | ||
| 195 | help | ||
| 196 | Atmel SAMA5D4 watchdog timer is embedded into SAMA5D4 chips. | ||
| 197 | Its Watchdog Timer Mode Register can be written more than once. | ||
| 198 | This will reboot your system when the timeout is reached. | ||
| 199 | |||
| 191 | config CADENCE_WATCHDOG | 200 | config CADENCE_WATCHDOG |
| 192 | tristate "Cadence Watchdog Timer" | 201 | tristate "Cadence Watchdog Timer" |
| 193 | depends on HAS_IOMEM | 202 | depends on HAS_IOMEM |
| @@ -558,6 +567,17 @@ config DIGICOLOR_WATCHDOG | |||
| 558 | To compile this driver as a module, choose M here: the | 567 | To compile this driver as a module, choose M here: the |
| 559 | module will be called digicolor_wdt. | 568 | module will be called digicolor_wdt. |
| 560 | 569 | ||
| 570 | config LPC18XX_WATCHDOG | ||
| 571 | tristate "LPC18xx/43xx Watchdog" | ||
| 572 | depends on ARCH_LPC18XX || COMPILE_TEST | ||
| 573 | select WATCHDOG_CORE | ||
| 574 | help | ||
| 575 | Say Y here if to include support for the watchdog timer | ||
| 576 | in NXP LPC SoCs family, which includes LPC18xx/LPC43xx | ||
| 577 | processors. | ||
| 578 | To compile this driver as a module, choose M here: the | ||
| 579 | module will be called lpc18xx_wdt. | ||
| 580 | |||
| 561 | # AVR32 Architecture | 581 | # AVR32 Architecture |
| 562 | 582 | ||
| 563 | config AT32AP700X_WDT | 583 | config AT32AP700X_WDT |
| @@ -1334,7 +1354,7 @@ config MPC5200_WDT | |||
| 1334 | 1354 | ||
| 1335 | config 8xxx_WDT | 1355 | config 8xxx_WDT |
| 1336 | tristate "MPC8xxx Platform Watchdog Timer" | 1356 | tristate "MPC8xxx Platform Watchdog Timer" |
| 1337 | depends on PPC_8xx || PPC_83xx || PPC_86xx | 1357 | depends on PPC_8xx || PPC_83xx || PPC_86xx || PPC_MPC512x |
| 1338 | select WATCHDOG_CORE | 1358 | select WATCHDOG_CORE |
| 1339 | help | 1359 | help |
| 1340 | This driver is for a SoC level watchdog that exists on some | 1360 | This driver is for a SoC level watchdog that exists on some |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 59ea9a1b8e76..0c616e3f67bb 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
| @@ -41,6 +41,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o | |||
| 41 | obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o | 41 | obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o |
| 42 | obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o | 42 | obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o |
| 43 | obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o | 43 | obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o |
| 44 | obj-$(CONFIG_SAMA5D4_WATCHDOG) += sama5d4_wdt.o | ||
| 44 | obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o | 45 | obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o |
| 45 | obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o | 46 | obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o |
| 46 | obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o | 47 | obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o |
| @@ -66,6 +67,7 @@ obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o | |||
| 66 | obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o | 67 | obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o |
| 67 | obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o | 68 | obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o |
| 68 | obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o | 69 | obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o |
| 70 | obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o | ||
| 69 | 71 | ||
| 70 | # AVR32 Architecture | 72 | # AVR32 Architecture |
| 71 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o | 73 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o |
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index 9ba1153465ae..e12a797cb820 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c | |||
| @@ -244,7 +244,7 @@ static int at91wdt_probe(struct platform_device *pdev) | |||
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | regmap_st = syscon_node_to_regmap(parent->of_node); | 246 | regmap_st = syscon_node_to_regmap(parent->of_node); |
| 247 | if (!regmap_st) | 247 | if (IS_ERR(regmap_st)) |
| 248 | return -ENODEV; | 248 | return -ENODEV; |
| 249 | 249 | ||
| 250 | res = misc_register(&at91wdt_miscdev); | 250 | res = misc_register(&at91wdt_miscdev); |
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index e4698f7c5f93..7e6acaf3ece4 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 19 | 19 | ||
| 20 | #include <linux/clk.h> | ||
| 20 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
| 21 | #include <linux/init.h> | 22 | #include <linux/init.h> |
| 22 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
| @@ -90,6 +91,7 @@ struct at91wdt { | |||
| 90 | unsigned long heartbeat; /* WDT heartbeat in jiffies */ | 91 | unsigned long heartbeat; /* WDT heartbeat in jiffies */ |
| 91 | bool nowayout; | 92 | bool nowayout; |
| 92 | unsigned int irq; | 93 | unsigned int irq; |
| 94 | struct clk *sclk; | ||
| 93 | }; | 95 | }; |
| 94 | 96 | ||
| 95 | /* ......................................................................... */ | 97 | /* ......................................................................... */ |
| @@ -352,15 +354,25 @@ static int __init at91wdt_probe(struct platform_device *pdev) | |||
| 352 | if (IS_ERR(wdt->base)) | 354 | if (IS_ERR(wdt->base)) |
| 353 | return PTR_ERR(wdt->base); | 355 | return PTR_ERR(wdt->base); |
| 354 | 356 | ||
| 357 | wdt->sclk = devm_clk_get(&pdev->dev, NULL); | ||
| 358 | if (IS_ERR(wdt->sclk)) | ||
| 359 | return PTR_ERR(wdt->sclk); | ||
| 360 | |||
| 361 | err = clk_prepare_enable(wdt->sclk); | ||
| 362 | if (err) { | ||
| 363 | dev_err(&pdev->dev, "Could not enable slow clock\n"); | ||
| 364 | return err; | ||
| 365 | } | ||
| 366 | |||
| 355 | if (pdev->dev.of_node) { | 367 | if (pdev->dev.of_node) { |
| 356 | err = of_at91wdt_init(pdev->dev.of_node, wdt); | 368 | err = of_at91wdt_init(pdev->dev.of_node, wdt); |
| 357 | if (err) | 369 | if (err) |
| 358 | return err; | 370 | goto err_clk; |
| 359 | } | 371 | } |
| 360 | 372 | ||
| 361 | err = at91_wdt_init(pdev, wdt); | 373 | err = at91_wdt_init(pdev, wdt); |
| 362 | if (err) | 374 | if (err) |
| 363 | return err; | 375 | goto err_clk; |
| 364 | 376 | ||
| 365 | platform_set_drvdata(pdev, wdt); | 377 | platform_set_drvdata(pdev, wdt); |
| 366 | 378 | ||
| @@ -368,6 +380,11 @@ static int __init at91wdt_probe(struct platform_device *pdev) | |||
| 368 | wdt->wdd.timeout, wdt->nowayout); | 380 | wdt->wdd.timeout, wdt->nowayout); |
| 369 | 381 | ||
| 370 | return 0; | 382 | return 0; |
| 383 | |||
| 384 | err_clk: | ||
| 385 | clk_disable_unprepare(wdt->sclk); | ||
| 386 | |||
| 387 | return err; | ||
| 371 | } | 388 | } |
| 372 | 389 | ||
| 373 | static int __exit at91wdt_remove(struct platform_device *pdev) | 390 | static int __exit at91wdt_remove(struct platform_device *pdev) |
| @@ -377,6 +394,7 @@ static int __exit at91wdt_remove(struct platform_device *pdev) | |||
| 377 | 394 | ||
| 378 | pr_warn("I quit now, hardware will probably reboot!\n"); | 395 | pr_warn("I quit now, hardware will probably reboot!\n"); |
| 379 | del_timer(&wdt->timer); | 396 | del_timer(&wdt->timer); |
| 397 | clk_disable_unprepare(wdt->sclk); | ||
| 380 | 398 | ||
| 381 | return 0; | 399 | return 0; |
| 382 | } | 400 | } |
diff --git a/drivers/watchdog/at91sam9_wdt.h b/drivers/watchdog/at91sam9_wdt.h index c6fbb2e6c41b..b79a83b467ce 100644 --- a/drivers/watchdog/at91sam9_wdt.h +++ b/drivers/watchdog/at91sam9_wdt.h | |||
| @@ -22,11 +22,13 @@ | |||
| 22 | 22 | ||
| 23 | #define AT91_WDT_MR 0x04 /* Watchdog Mode Register */ | 23 | #define AT91_WDT_MR 0x04 /* Watchdog Mode Register */ |
| 24 | #define AT91_WDT_WDV (0xfff << 0) /* Counter Value */ | 24 | #define AT91_WDT_WDV (0xfff << 0) /* Counter Value */ |
| 25 | #define AT91_WDT_SET_WDV(x) ((x) & AT91_WDT_WDV) | ||
| 25 | #define AT91_WDT_WDFIEN (1 << 12) /* Fault Interrupt Enable */ | 26 | #define AT91_WDT_WDFIEN (1 << 12) /* Fault Interrupt Enable */ |
| 26 | #define AT91_WDT_WDRSTEN (1 << 13) /* Reset Processor */ | 27 | #define AT91_WDT_WDRSTEN (1 << 13) /* Reset Processor */ |
| 27 | #define AT91_WDT_WDRPROC (1 << 14) /* Timer Restart */ | 28 | #define AT91_WDT_WDRPROC (1 << 14) /* Timer Restart */ |
| 28 | #define AT91_WDT_WDDIS (1 << 15) /* Watchdog Disable */ | 29 | #define AT91_WDT_WDDIS (1 << 15) /* Watchdog Disable */ |
| 29 | #define AT91_WDT_WDD (0xfff << 16) /* Delta Value */ | 30 | #define AT91_WDT_WDD (0xfff << 16) /* Delta Value */ |
| 31 | #define AT91_WDT_SET_WDD(x) (((x) << 16) & AT91_WDT_WDD) | ||
| 30 | #define AT91_WDT_WDDBGHLT (1 << 28) /* Debug Halt */ | 32 | #define AT91_WDT_WDDBGHLT (1 << 28) /* Debug Halt */ |
| 31 | #define AT91_WDT_WDIDLEHLT (1 << 29) /* Idle Halt */ | 33 | #define AT91_WDT_WDIDLEHLT (1 << 29) /* Idle Halt */ |
| 32 | 34 | ||
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c index 7116968dee12..66c3e656a616 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c | |||
| @@ -182,6 +182,7 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) | |||
| 182 | watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt); | 182 | watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt); |
| 183 | watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev); | 183 | watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev); |
| 184 | watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout); | 184 | watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout); |
| 185 | bcm2835_wdt_wdd.parent = &pdev->dev; | ||
| 185 | err = watchdog_register_device(&bcm2835_wdt_wdd); | 186 | err = watchdog_register_device(&bcm2835_wdt_wdd); |
| 186 | if (err) { | 187 | if (err) { |
| 187 | dev_err(dev, "Failed to register watchdog device"); | 188 | dev_err(dev, "Failed to register watchdog device"); |
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index b28a072abf78..4064a43f1360 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c | |||
| @@ -209,6 +209,7 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev) | |||
| 209 | 209 | ||
| 210 | wdt->wdd.info = &bcm47xx_wdt_info; | 210 | wdt->wdd.info = &bcm47xx_wdt_info; |
| 211 | wdt->wdd.timeout = WDT_DEFAULT_TIME; | 211 | wdt->wdd.timeout = WDT_DEFAULT_TIME; |
| 212 | wdt->wdd.parent = &pdev->dev; | ||
| 212 | ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout); | 213 | ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout); |
| 213 | if (ret) | 214 | if (ret) |
| 214 | goto err_timer; | 215 | goto err_timer; |
diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c index 22d8ae65772a..e0c98423f2c9 100644 --- a/drivers/watchdog/bcm_kona_wdt.c +++ b/drivers/watchdog/bcm_kona_wdt.c | |||
| @@ -319,6 +319,7 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev) | |||
| 319 | spin_lock_init(&wdt->lock); | 319 | spin_lock_init(&wdt->lock); |
| 320 | platform_set_drvdata(pdev, wdt); | 320 | platform_set_drvdata(pdev, wdt); |
| 321 | watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt); | 321 | watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt); |
| 322 | bcm_kona_wdt_wdd.parent = &pdev->dev; | ||
| 322 | 323 | ||
| 323 | ret = bcm_kona_wdt_set_timeout_reg(&bcm_kona_wdt_wdd, 0); | 324 | ret = bcm_kona_wdt_set_timeout_reg(&bcm_kona_wdt_wdd, 0); |
| 324 | if (ret) { | 325 | if (ret) { |
diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index e96b09b135c8..04da4b66c75e 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c | |||
| @@ -186,8 +186,6 @@ static int booke_wdt_stop(struct watchdog_device *wdog) | |||
| 186 | static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev, | 186 | static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev, |
| 187 | unsigned int timeout) | 187 | unsigned int timeout) |
| 188 | { | 188 | { |
| 189 | if (timeout > MAX_WDT_TIMEOUT) | ||
| 190 | return -EINVAL; | ||
| 191 | wdt_dev->timeout = timeout; | 189 | wdt_dev->timeout = timeout; |
| 192 | booke_wdt_set(wdt_dev); | 190 | booke_wdt_set(wdt_dev); |
| 193 | 191 | ||
| @@ -211,7 +209,6 @@ static struct watchdog_device booke_wdt_dev = { | |||
| 211 | .info = &booke_wdt_info, | 209 | .info = &booke_wdt_info, |
| 212 | .ops = &booke_wdt_ops, | 210 | .ops = &booke_wdt_ops, |
| 213 | .min_timeout = 1, | 211 | .min_timeout = 1, |
| 214 | .max_timeout = 0xFFFF | ||
| 215 | }; | 212 | }; |
| 216 | 213 | ||
| 217 | static void __exit booke_wdt_exit(void) | 214 | static void __exit booke_wdt_exit(void) |
| @@ -229,6 +226,7 @@ static int __init booke_wdt_init(void) | |||
| 229 | booke_wdt_set_timeout(&booke_wdt_dev, | 226 | booke_wdt_set_timeout(&booke_wdt_dev, |
| 230 | period_to_sec(booke_wdt_period)); | 227 | period_to_sec(booke_wdt_period)); |
| 231 | watchdog_set_nowayout(&booke_wdt_dev, nowayout); | 228 | watchdog_set_nowayout(&booke_wdt_dev, nowayout); |
| 229 | booke_wdt_dev.max_timeout = MAX_WDT_TIMEOUT; | ||
| 232 | if (booke_wdt_enabled) | 230 | if (booke_wdt_enabled) |
| 233 | booke_wdt_start(&booke_wdt_dev); | 231 | booke_wdt_start(&booke_wdt_dev); |
| 234 | 232 | ||
diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index ce12f437f195..a099b77fc0b9 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c | |||
| @@ -358,6 +358,7 @@ static int __init coh901327_probe(struct platform_device *pdev) | |||
| 358 | if (ret < 0) | 358 | if (ret < 0) |
| 359 | coh901327_wdt.timeout = 60; | 359 | coh901327_wdt.timeout = 60; |
| 360 | 360 | ||
| 361 | coh901327_wdt.parent = &pdev->dev; | ||
| 361 | ret = watchdog_register_device(&coh901327_wdt); | 362 | ret = watchdog_register_device(&coh901327_wdt); |
| 362 | if (ret == 0) | 363 | if (ret == 0) |
| 363 | dev_info(&pdev->dev, | 364 | dev_info(&pdev->dev, |
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c index 2e9589652e1e..67e67977bd29 100644 --- a/drivers/watchdog/da9052_wdt.c +++ b/drivers/watchdog/da9052_wdt.c | |||
| @@ -195,6 +195,7 @@ static int da9052_wdt_probe(struct platform_device *pdev) | |||
| 195 | da9052_wdt->timeout = DA9052_DEF_TIMEOUT; | 195 | da9052_wdt->timeout = DA9052_DEF_TIMEOUT; |
| 196 | da9052_wdt->info = &da9052_wdt_info; | 196 | da9052_wdt->info = &da9052_wdt_info; |
| 197 | da9052_wdt->ops = &da9052_wdt_ops; | 197 | da9052_wdt->ops = &da9052_wdt_ops; |
| 198 | da9052_wdt->parent = &pdev->dev; | ||
| 198 | watchdog_set_drvdata(da9052_wdt, driver_data); | 199 | watchdog_set_drvdata(da9052_wdt, driver_data); |
| 199 | 200 | ||
| 200 | kref_init(&driver_data->kref); | 201 | kref_init(&driver_data->kref); |
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c index 495089d8dbfe..04d1430d93d2 100644 --- a/drivers/watchdog/da9055_wdt.c +++ b/drivers/watchdog/da9055_wdt.c | |||
| @@ -161,6 +161,7 @@ static int da9055_wdt_probe(struct platform_device *pdev) | |||
| 161 | da9055_wdt->timeout = DA9055_DEF_TIMEOUT; | 161 | da9055_wdt->timeout = DA9055_DEF_TIMEOUT; |
| 162 | da9055_wdt->info = &da9055_wdt_info; | 162 | da9055_wdt->info = &da9055_wdt_info; |
| 163 | da9055_wdt->ops = &da9055_wdt_ops; | 163 | da9055_wdt->ops = &da9055_wdt_ops; |
| 164 | da9055_wdt->parent = &pdev->dev; | ||
| 164 | watchdog_set_nowayout(da9055_wdt, nowayout); | 165 | watchdog_set_nowayout(da9055_wdt, nowayout); |
| 165 | watchdog_set_drvdata(da9055_wdt, driver_data); | 166 | watchdog_set_drvdata(da9055_wdt, driver_data); |
| 166 | 167 | ||
diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index b3a870ce85be..7386111220d5 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c | |||
| @@ -210,6 +210,7 @@ static int da9062_wdt_probe(struct platform_device *pdev) | |||
| 210 | wdt->wdtdev.max_timeout = DA9062_WDT_MAX_TIMEOUT; | 210 | wdt->wdtdev.max_timeout = DA9062_WDT_MAX_TIMEOUT; |
| 211 | wdt->wdtdev.timeout = DA9062_WDG_DEFAULT_TIMEOUT; | 211 | wdt->wdtdev.timeout = DA9062_WDG_DEFAULT_TIMEOUT; |
| 212 | wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS; | 212 | wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS; |
| 213 | wdt->wdtdev.parent = &pdev->dev; | ||
| 213 | 214 | ||
| 214 | watchdog_set_drvdata(&wdt->wdtdev, wdt); | 215 | watchdog_set_drvdata(&wdt->wdtdev, wdt); |
| 215 | dev_set_drvdata(&pdev->dev, wdt); | 216 | dev_set_drvdata(&pdev->dev, wdt); |
diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index e2fe2ebdebd4..6bf130bd863d 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c | |||
| @@ -175,6 +175,7 @@ static int da9063_wdt_probe(struct platform_device *pdev) | |||
| 175 | wdt->wdtdev.min_timeout = DA9063_WDT_MIN_TIMEOUT; | 175 | wdt->wdtdev.min_timeout = DA9063_WDT_MIN_TIMEOUT; |
| 176 | wdt->wdtdev.max_timeout = DA9063_WDT_MAX_TIMEOUT; | 176 | wdt->wdtdev.max_timeout = DA9063_WDT_MAX_TIMEOUT; |
| 177 | wdt->wdtdev.timeout = DA9063_WDG_TIMEOUT; | 177 | wdt->wdtdev.timeout = DA9063_WDG_TIMEOUT; |
| 178 | wdt->wdtdev.parent = &pdev->dev; | ||
| 178 | 179 | ||
| 179 | wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS; | 180 | wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS; |
| 180 | 181 | ||
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index cfdf8a408aea..17454ca653f4 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c | |||
| @@ -179,6 +179,7 @@ static int davinci_wdt_probe(struct platform_device *pdev) | |||
| 179 | wdd->min_timeout = 1; | 179 | wdd->min_timeout = 1; |
| 180 | wdd->max_timeout = MAX_HEARTBEAT; | 180 | wdd->max_timeout = MAX_HEARTBEAT; |
| 181 | wdd->timeout = DEFAULT_HEARTBEAT; | 181 | wdd->timeout = DEFAULT_HEARTBEAT; |
| 182 | wdd->parent = &pdev->dev; | ||
| 182 | 183 | ||
| 183 | watchdog_init_timeout(wdd, heartbeat, dev); | 184 | watchdog_init_timeout(wdd, heartbeat, dev); |
| 184 | 185 | ||
diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c index 31d8e4936611..50abe1bf62a5 100644 --- a/drivers/watchdog/digicolor_wdt.c +++ b/drivers/watchdog/digicolor_wdt.c | |||
| @@ -143,6 +143,7 @@ static int dc_wdt_probe(struct platform_device *pdev) | |||
| 143 | } | 143 | } |
| 144 | dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk); | 144 | dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk); |
| 145 | dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout; | 145 | dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout; |
| 146 | dc_wdt_wdd.parent = &pdev->dev; | ||
| 146 | 147 | ||
| 147 | spin_lock_init(&wdt->lock); | 148 | spin_lock_init(&wdt->lock); |
| 148 | 149 | ||
diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c index 7a2cc7191c58..0a4d7cc05d54 100644 --- a/drivers/watchdog/ep93xx_wdt.c +++ b/drivers/watchdog/ep93xx_wdt.c | |||
| @@ -132,6 +132,7 @@ static int ep93xx_wdt_probe(struct platform_device *pdev) | |||
| 132 | val = readl(mmio_base + EP93XX_WATCHDOG); | 132 | val = readl(mmio_base + EP93XX_WATCHDOG); |
| 133 | ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0; | 133 | ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0; |
| 134 | ep93xx_wdt_wdd.timeout = timeout; | 134 | ep93xx_wdt_wdd.timeout = timeout; |
| 135 | ep93xx_wdt_wdd.parent = &pdev->dev; | ||
| 135 | 136 | ||
| 136 | watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout); | 137 | watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout); |
| 137 | 138 | ||
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c index 1687cc2d7122..90d59d3f38a3 100644 --- a/drivers/watchdog/gpio_wdt.c +++ b/drivers/watchdog/gpio_wdt.c | |||
| @@ -50,12 +50,41 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv) | |||
| 50 | gpio_direction_input(priv->gpio); | 50 | gpio_direction_input(priv->gpio); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | static void gpio_wdt_hwping(unsigned long data) | ||
| 54 | { | ||
| 55 | struct watchdog_device *wdd = (struct watchdog_device *)data; | ||
| 56 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||
| 57 | |||
| 58 | if (priv->armed && time_after(jiffies, priv->last_jiffies + | ||
| 59 | msecs_to_jiffies(wdd->timeout * 1000))) { | ||
| 60 | dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); | ||
| 61 | return; | ||
| 62 | } | ||
| 63 | |||
| 64 | /* Restart timer */ | ||
| 65 | mod_timer(&priv->timer, jiffies + priv->hw_margin); | ||
| 66 | |||
| 67 | switch (priv->hw_algo) { | ||
| 68 | case HW_ALGO_TOGGLE: | ||
| 69 | /* Toggle output pin */ | ||
| 70 | priv->state = !priv->state; | ||
| 71 | gpio_set_value_cansleep(priv->gpio, priv->state); | ||
| 72 | break; | ||
| 73 | case HW_ALGO_LEVEL: | ||
| 74 | /* Pulse */ | ||
| 75 | gpio_set_value_cansleep(priv->gpio, !priv->active_low); | ||
| 76 | udelay(1); | ||
| 77 | gpio_set_value_cansleep(priv->gpio, priv->active_low); | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 53 | static void gpio_wdt_start_impl(struct gpio_wdt_priv *priv) | 82 | static void gpio_wdt_start_impl(struct gpio_wdt_priv *priv) |
| 54 | { | 83 | { |
| 55 | priv->state = priv->active_low; | 84 | priv->state = priv->active_low; |
| 56 | gpio_direction_output(priv->gpio, priv->state); | 85 | gpio_direction_output(priv->gpio, priv->state); |
| 57 | priv->last_jiffies = jiffies; | 86 | priv->last_jiffies = jiffies; |
| 58 | mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin); | 87 | gpio_wdt_hwping((unsigned long)&priv->wdd); |
| 59 | } | 88 | } |
| 60 | 89 | ||
| 61 | static int gpio_wdt_start(struct watchdog_device *wdd) | 90 | static int gpio_wdt_start(struct watchdog_device *wdd) |
| @@ -97,35 +126,6 @@ static int gpio_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) | |||
| 97 | return gpio_wdt_ping(wdd); | 126 | return gpio_wdt_ping(wdd); |
| 98 | } | 127 | } |
| 99 | 128 | ||
| 100 | static void gpio_wdt_hwping(unsigned long data) | ||
| 101 | { | ||
| 102 | struct watchdog_device *wdd = (struct watchdog_device *)data; | ||
| 103 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||
| 104 | |||
| 105 | if (priv->armed && time_after(jiffies, priv->last_jiffies + | ||
| 106 | msecs_to_jiffies(wdd->timeout * 1000))) { | ||
| 107 | dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); | ||
| 108 | return; | ||
| 109 | } | ||
| 110 | |||
| 111 | /* Restart timer */ | ||
| 112 | mod_timer(&priv->timer, jiffies + priv->hw_margin); | ||
| 113 | |||
| 114 | switch (priv->hw_algo) { | ||
| 115 | case HW_ALGO_TOGGLE: | ||
| 116 | /* Toggle output pin */ | ||
| 117 | priv->state = !priv->state; | ||
| 118 | gpio_set_value_cansleep(priv->gpio, priv->state); | ||
| 119 | break; | ||
| 120 | case HW_ALGO_LEVEL: | ||
| 121 | /* Pulse */ | ||
| 122 | gpio_set_value_cansleep(priv->gpio, !priv->active_low); | ||
| 123 | udelay(1); | ||
| 124 | gpio_set_value_cansleep(priv->gpio, priv->active_low); | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | static int gpio_wdt_notify_sys(struct notifier_block *nb, unsigned long code, | 129 | static int gpio_wdt_notify_sys(struct notifier_block *nb, unsigned long code, |
| 130 | void *unused) | 130 | void *unused) |
| 131 | { | 131 | { |
| @@ -182,10 +182,10 @@ static int gpio_wdt_probe(struct platform_device *pdev) | |||
| 182 | ret = of_property_read_string(pdev->dev.of_node, "hw_algo", &algo); | 182 | ret = of_property_read_string(pdev->dev.of_node, "hw_algo", &algo); |
| 183 | if (ret) | 183 | if (ret) |
| 184 | return ret; | 184 | return ret; |
| 185 | if (!strncmp(algo, "toggle", 6)) { | 185 | if (!strcmp(algo, "toggle")) { |
| 186 | priv->hw_algo = HW_ALGO_TOGGLE; | 186 | priv->hw_algo = HW_ALGO_TOGGLE; |
| 187 | f = GPIOF_IN; | 187 | f = GPIOF_IN; |
| 188 | } else if (!strncmp(algo, "level", 5)) { | 188 | } else if (!strcmp(algo, "level")) { |
| 189 | priv->hw_algo = HW_ALGO_LEVEL; | 189 | priv->hw_algo = HW_ALGO_LEVEL; |
| 190 | f = priv->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; | 190 | f = priv->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; |
| 191 | } else { | 191 | } else { |
| @@ -217,6 +217,7 @@ static int gpio_wdt_probe(struct platform_device *pdev) | |||
| 217 | priv->wdd.ops = &gpio_wdt_ops; | 217 | priv->wdd.ops = &gpio_wdt_ops; |
| 218 | priv->wdd.min_timeout = SOFT_TIMEOUT_MIN; | 218 | priv->wdd.min_timeout = SOFT_TIMEOUT_MIN; |
| 219 | priv->wdd.max_timeout = SOFT_TIMEOUT_MAX; | 219 | priv->wdd.max_timeout = SOFT_TIMEOUT_MAX; |
| 220 | priv->wdd.parent = &pdev->dev; | ||
| 220 | 221 | ||
| 221 | if (watchdog_init_timeout(&priv->wdd, 0, &pdev->dev) < 0) | 222 | if (watchdog_init_timeout(&priv->wdd, 0, &pdev->dev) < 0) |
| 222 | priv->wdd.timeout = SOFT_TIMEOUT_DEF; | 223 | priv->wdd.timeout = SOFT_TIMEOUT_DEF; |
diff --git a/drivers/watchdog/ie6xx_wdt.c b/drivers/watchdog/ie6xx_wdt.c index 9bc39ae51624..78c2541f5d52 100644 --- a/drivers/watchdog/ie6xx_wdt.c +++ b/drivers/watchdog/ie6xx_wdt.c | |||
| @@ -267,6 +267,7 @@ static int ie6xx_wdt_probe(struct platform_device *pdev) | |||
| 267 | 267 | ||
| 268 | ie6xx_wdt_dev.timeout = timeout; | 268 | ie6xx_wdt_dev.timeout = timeout; |
| 269 | watchdog_set_nowayout(&ie6xx_wdt_dev, nowayout); | 269 | watchdog_set_nowayout(&ie6xx_wdt_dev, nowayout); |
| 270 | ie6xx_wdt_dev.parent = &pdev->dev; | ||
| 270 | 271 | ||
| 271 | spin_lock_init(&ie6xx_wdt_data.unlock_sequence); | 272 | spin_lock_init(&ie6xx_wdt_data.unlock_sequence); |
| 272 | 273 | ||
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c index 0f73621827ab..15ab07230960 100644 --- a/drivers/watchdog/imgpdc_wdt.c +++ b/drivers/watchdog/imgpdc_wdt.c | |||
| @@ -316,6 +316,7 @@ static int pdc_wdt_remove(struct platform_device *pdev) | |||
| 316 | { | 316 | { |
| 317 | struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev); | 317 | struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev); |
| 318 | 318 | ||
| 319 | unregister_restart_handler(&pdc_wdt->restart_handler); | ||
| 319 | pdc_wdt_stop(&pdc_wdt->wdt_dev); | 320 | pdc_wdt_stop(&pdc_wdt->wdt_dev); |
| 320 | watchdog_unregister_device(&pdc_wdt->wdt_dev); | 321 | watchdog_unregister_device(&pdc_wdt->wdt_dev); |
| 321 | clk_disable_unprepare(pdc_wdt->wdt_clk); | 322 | clk_disable_unprepare(pdc_wdt->wdt_clk); |
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index 84f6701c391f..0a436b5d1e84 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c | |||
| @@ -137,6 +137,7 @@ static int mid_wdt_probe(struct platform_device *pdev) | |||
| 137 | wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN; | 137 | wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN; |
| 138 | wdt_dev->max_timeout = MID_WDT_TIMEOUT_MAX; | 138 | wdt_dev->max_timeout = MID_WDT_TIMEOUT_MAX; |
| 139 | wdt_dev->timeout = MID_WDT_DEFAULT_TIMEOUT; | 139 | wdt_dev->timeout = MID_WDT_DEFAULT_TIMEOUT; |
| 140 | wdt_dev->parent = &pdev->dev; | ||
| 140 | 141 | ||
| 141 | watchdog_set_drvdata(wdt_dev, &pdev->dev); | 142 | watchdog_set_drvdata(wdt_dev, &pdev->dev); |
| 142 | platform_set_drvdata(pdev, wdt_dev); | 143 | platform_set_drvdata(pdev, wdt_dev); |
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c index 4c2cc09c0c57..6a7d5c365438 100644 --- a/drivers/watchdog/jz4740_wdt.c +++ b/drivers/watchdog/jz4740_wdt.c | |||
| @@ -174,6 +174,7 @@ static int jz4740_wdt_probe(struct platform_device *pdev) | |||
| 174 | jz4740_wdt->timeout = heartbeat; | 174 | jz4740_wdt->timeout = heartbeat; |
| 175 | jz4740_wdt->min_timeout = 1; | 175 | jz4740_wdt->min_timeout = 1; |
| 176 | jz4740_wdt->max_timeout = MAX_HEARTBEAT; | 176 | jz4740_wdt->max_timeout = MAX_HEARTBEAT; |
| 177 | jz4740_wdt->parent = &pdev->dev; | ||
| 177 | watchdog_set_nowayout(jz4740_wdt, nowayout); | 178 | watchdog_set_nowayout(jz4740_wdt, nowayout); |
| 178 | watchdog_set_drvdata(jz4740_wdt, drvdata); | 179 | watchdog_set_drvdata(jz4740_wdt, drvdata); |
| 179 | 180 | ||
diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c new file mode 100644 index 000000000000..ab7b8b185d99 --- /dev/null +++ b/drivers/watchdog/lpc18xx_wdt.c | |||
| @@ -0,0 +1,340 @@ | |||
| 1 | /* | ||
| 2 | * NXP LPC18xx Watchdog Timer (WDT) | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License version 2 as published by | ||
| 8 | * the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * Notes | ||
| 11 | * ----- | ||
| 12 | * The Watchdog consists of a fixed divide-by-4 clock pre-scaler and a 24-bit | ||
| 13 | * counter which decrements on every clock cycle. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/clk.h> | ||
| 17 | #include <linux/io.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/of.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/reboot.h> | ||
| 22 | #include <linux/watchdog.h> | ||
| 23 | |||
| 24 | /* Registers */ | ||
| 25 | #define LPC18XX_WDT_MOD 0x00 | ||
| 26 | #define LPC18XX_WDT_MOD_WDEN BIT(0) | ||
| 27 | #define LPC18XX_WDT_MOD_WDRESET BIT(1) | ||
| 28 | |||
| 29 | #define LPC18XX_WDT_TC 0x04 | ||
| 30 | #define LPC18XX_WDT_TC_MIN 0xff | ||
| 31 | #define LPC18XX_WDT_TC_MAX 0xffffff | ||
| 32 | |||
| 33 | #define LPC18XX_WDT_FEED 0x08 | ||
| 34 | #define LPC18XX_WDT_FEED_MAGIC1 0xaa | ||
| 35 | #define LPC18XX_WDT_FEED_MAGIC2 0x55 | ||
| 36 | |||
| 37 | #define LPC18XX_WDT_TV 0x0c | ||
| 38 | |||
| 39 | /* Clock pre-scaler */ | ||
| 40 | #define LPC18XX_WDT_CLK_DIV 4 | ||
| 41 | |||
| 42 | /* Timeout values in seconds */ | ||
| 43 | #define LPC18XX_WDT_DEF_TIMEOUT 30U | ||
| 44 | |||
| 45 | static int heartbeat; | ||
| 46 | module_param(heartbeat, int, 0); | ||
| 47 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds (default=" | ||
| 48 | __MODULE_STRING(LPC18XX_WDT_DEF_TIMEOUT) ")"); | ||
| 49 | |||
| 50 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
| 51 | module_param(nowayout, bool, 0); | ||
| 52 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | ||
| 53 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 54 | |||
| 55 | struct lpc18xx_wdt_dev { | ||
| 56 | struct watchdog_device wdt_dev; | ||
| 57 | struct clk *reg_clk; | ||
| 58 | struct clk *wdt_clk; | ||
| 59 | unsigned long clk_rate; | ||
| 60 | void __iomem *base; | ||
| 61 | struct timer_list timer; | ||
| 62 | struct notifier_block restart_handler; | ||
| 63 | spinlock_t lock; | ||
| 64 | }; | ||
| 65 | |||
| 66 | static int lpc18xx_wdt_feed(struct watchdog_device *wdt_dev) | ||
| 67 | { | ||
| 68 | struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); | ||
| 69 | unsigned long flags; | ||
| 70 | |||
| 71 | /* | ||
| 72 | * An abort condition will occur if an interrupt happens during the feed | ||
| 73 | * sequence. | ||
| 74 | */ | ||
| 75 | spin_lock_irqsave(&lpc18xx_wdt->lock, flags); | ||
| 76 | writel(LPC18XX_WDT_FEED_MAGIC1, lpc18xx_wdt->base + LPC18XX_WDT_FEED); | ||
| 77 | writel(LPC18XX_WDT_FEED_MAGIC2, lpc18xx_wdt->base + LPC18XX_WDT_FEED); | ||
| 78 | spin_unlock_irqrestore(&lpc18xx_wdt->lock, flags); | ||
| 79 | |||
| 80 | return 0; | ||
| 81 | } | ||
| 82 | |||
| 83 | static void lpc18xx_wdt_timer_feed(unsigned long data) | ||
| 84 | { | ||
| 85 | struct watchdog_device *wdt_dev = (struct watchdog_device *)data; | ||
| 86 | struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); | ||
| 87 | |||
| 88 | lpc18xx_wdt_feed(wdt_dev); | ||
| 89 | |||
| 90 | /* Use safe value (1/2 of real timeout) */ | ||
| 91 | mod_timer(&lpc18xx_wdt->timer, jiffies + | ||
| 92 | msecs_to_jiffies((wdt_dev->timeout * MSEC_PER_SEC) / 2)); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* | ||
| 96 | * Since LPC18xx Watchdog cannot be disabled in hardware, we must keep feeding | ||
| 97 | * it with a timer until userspace watchdog software takes over. | ||
| 98 | */ | ||
| 99 | static int lpc18xx_wdt_stop(struct watchdog_device *wdt_dev) | ||
| 100 | { | ||
| 101 | lpc18xx_wdt_timer_feed((unsigned long)wdt_dev); | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | static void __lpc18xx_wdt_set_timeout(struct lpc18xx_wdt_dev *lpc18xx_wdt) | ||
| 107 | { | ||
| 108 | unsigned int val; | ||
| 109 | |||
| 110 | val = DIV_ROUND_UP(lpc18xx_wdt->wdt_dev.timeout * lpc18xx_wdt->clk_rate, | ||
| 111 | LPC18XX_WDT_CLK_DIV); | ||
| 112 | writel(val, lpc18xx_wdt->base + LPC18XX_WDT_TC); | ||
| 113 | } | ||
| 114 | |||
| 115 | static int lpc18xx_wdt_set_timeout(struct watchdog_device *wdt_dev, | ||
| 116 | unsigned int new_timeout) | ||
| 117 | { | ||
| 118 | struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); | ||
| 119 | |||
| 120 | lpc18xx_wdt->wdt_dev.timeout = new_timeout; | ||
| 121 | __lpc18xx_wdt_set_timeout(lpc18xx_wdt); | ||
| 122 | |||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | static unsigned int lpc18xx_wdt_get_timeleft(struct watchdog_device *wdt_dev) | ||
| 127 | { | ||
| 128 | struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); | ||
| 129 | unsigned int val; | ||
| 130 | |||
| 131 | val = readl(lpc18xx_wdt->base + LPC18XX_WDT_TV); | ||
| 132 | return (val * LPC18XX_WDT_CLK_DIV) / lpc18xx_wdt->clk_rate; | ||
| 133 | } | ||
| 134 | |||
| 135 | static int lpc18xx_wdt_start(struct watchdog_device *wdt_dev) | ||
| 136 | { | ||
| 137 | struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); | ||
| 138 | unsigned int val; | ||
| 139 | |||
| 140 | if (timer_pending(&lpc18xx_wdt->timer)) | ||
| 141 | del_timer(&lpc18xx_wdt->timer); | ||
| 142 | |||
| 143 | val = readl(lpc18xx_wdt->base + LPC18XX_WDT_MOD); | ||
| 144 | val |= LPC18XX_WDT_MOD_WDEN; | ||
| 145 | val |= LPC18XX_WDT_MOD_WDRESET; | ||
| 146 | writel(val, lpc18xx_wdt->base + LPC18XX_WDT_MOD); | ||
| 147 | |||
| 148 | /* | ||
| 149 | * Setting the WDEN bit in the WDMOD register is not sufficient to | ||
| 150 | * enable the Watchdog. A valid feed sequence must be completed after | ||
| 151 | * setting WDEN before the Watchdog is capable of generating a reset. | ||
| 152 | */ | ||
| 153 | lpc18xx_wdt_feed(wdt_dev); | ||
| 154 | |||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | static struct watchdog_info lpc18xx_wdt_info = { | ||
| 159 | .identity = "NXP LPC18xx Watchdog", | ||
| 160 | .options = WDIOF_SETTIMEOUT | | ||
| 161 | WDIOF_KEEPALIVEPING | | ||
| 162 | WDIOF_MAGICCLOSE, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static const struct watchdog_ops lpc18xx_wdt_ops = { | ||
| 166 | .owner = THIS_MODULE, | ||
| 167 | .start = lpc18xx_wdt_start, | ||
| 168 | .stop = lpc18xx_wdt_stop, | ||
| 169 | .ping = lpc18xx_wdt_feed, | ||
| 170 | .set_timeout = lpc18xx_wdt_set_timeout, | ||
| 171 | .get_timeleft = lpc18xx_wdt_get_timeleft, | ||
| 172 | }; | ||
| 173 | |||
| 174 | static int lpc18xx_wdt_restart(struct notifier_block *this, unsigned long mode, | ||
| 175 | void *cmd) | ||
| 176 | { | ||
| 177 | struct lpc18xx_wdt_dev *lpc18xx_wdt = container_of(this, | ||
| 178 | struct lpc18xx_wdt_dev, restart_handler); | ||
| 179 | unsigned long flags; | ||
| 180 | int val; | ||
| 181 | |||
| 182 | /* | ||
| 183 | * Incorrect feed sequence causes immediate watchdog reset if enabled. | ||
| 184 | */ | ||
| 185 | spin_lock_irqsave(&lpc18xx_wdt->lock, flags); | ||
| 186 | |||
| 187 | val = readl(lpc18xx_wdt->base + LPC18XX_WDT_MOD); | ||
| 188 | val |= LPC18XX_WDT_MOD_WDEN; | ||
| 189 | val |= LPC18XX_WDT_MOD_WDRESET; | ||
| 190 | writel(val, lpc18xx_wdt->base + LPC18XX_WDT_MOD); | ||
| 191 | |||
| 192 | writel(LPC18XX_WDT_FEED_MAGIC1, lpc18xx_wdt->base + LPC18XX_WDT_FEED); | ||
| 193 | writel(LPC18XX_WDT_FEED_MAGIC2, lpc18xx_wdt->base + LPC18XX_WDT_FEED); | ||
| 194 | |||
| 195 | writel(LPC18XX_WDT_FEED_MAGIC1, lpc18xx_wdt->base + LPC18XX_WDT_FEED); | ||
| 196 | writel(LPC18XX_WDT_FEED_MAGIC1, lpc18xx_wdt->base + LPC18XX_WDT_FEED); | ||
| 197 | |||
| 198 | spin_unlock_irqrestore(&lpc18xx_wdt->lock, flags); | ||
| 199 | |||
| 200 | return NOTIFY_OK; | ||
| 201 | } | ||
| 202 | |||
| 203 | static int lpc18xx_wdt_probe(struct platform_device *pdev) | ||
| 204 | { | ||
| 205 | struct lpc18xx_wdt_dev *lpc18xx_wdt; | ||
| 206 | struct device *dev = &pdev->dev; | ||
| 207 | struct resource *res; | ||
| 208 | int ret; | ||
| 209 | |||
| 210 | lpc18xx_wdt = devm_kzalloc(dev, sizeof(*lpc18xx_wdt), GFP_KERNEL); | ||
| 211 | if (!lpc18xx_wdt) | ||
| 212 | return -ENOMEM; | ||
| 213 | |||
| 214 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 215 | lpc18xx_wdt->base = devm_ioremap_resource(dev, res); | ||
| 216 | if (IS_ERR(lpc18xx_wdt->base)) | ||
| 217 | return PTR_ERR(lpc18xx_wdt->base); | ||
| 218 | |||
| 219 | lpc18xx_wdt->reg_clk = devm_clk_get(dev, "reg"); | ||
| 220 | if (IS_ERR(lpc18xx_wdt->reg_clk)) { | ||
| 221 | dev_err(dev, "failed to get the reg clock\n"); | ||
| 222 | return PTR_ERR(lpc18xx_wdt->reg_clk); | ||
| 223 | } | ||
| 224 | |||
| 225 | lpc18xx_wdt->wdt_clk = devm_clk_get(dev, "wdtclk"); | ||
| 226 | if (IS_ERR(lpc18xx_wdt->wdt_clk)) { | ||
| 227 | dev_err(dev, "failed to get the wdt clock\n"); | ||
| 228 | return PTR_ERR(lpc18xx_wdt->wdt_clk); | ||
| 229 | } | ||
| 230 | |||
| 231 | ret = clk_prepare_enable(lpc18xx_wdt->reg_clk); | ||
| 232 | if (ret) { | ||
| 233 | dev_err(dev, "could not prepare or enable sys clock\n"); | ||
| 234 | return ret; | ||
| 235 | } | ||
| 236 | |||
| 237 | ret = clk_prepare_enable(lpc18xx_wdt->wdt_clk); | ||
| 238 | if (ret) { | ||
| 239 | dev_err(dev, "could not prepare or enable wdt clock\n"); | ||
| 240 | goto disable_reg_clk; | ||
| 241 | } | ||
| 242 | |||
| 243 | /* We use the clock rate to calculate timeouts */ | ||
| 244 | lpc18xx_wdt->clk_rate = clk_get_rate(lpc18xx_wdt->wdt_clk); | ||
| 245 | if (lpc18xx_wdt->clk_rate == 0) { | ||
| 246 | dev_err(dev, "failed to get clock rate\n"); | ||
| 247 | ret = -EINVAL; | ||
| 248 | goto disable_wdt_clk; | ||
| 249 | } | ||
| 250 | |||
| 251 | lpc18xx_wdt->wdt_dev.info = &lpc18xx_wdt_info; | ||
| 252 | lpc18xx_wdt->wdt_dev.ops = &lpc18xx_wdt_ops; | ||
| 253 | |||
| 254 | lpc18xx_wdt->wdt_dev.min_timeout = DIV_ROUND_UP(LPC18XX_WDT_TC_MIN * | ||
| 255 | LPC18XX_WDT_CLK_DIV, lpc18xx_wdt->clk_rate); | ||
| 256 | |||
| 257 | lpc18xx_wdt->wdt_dev.max_timeout = (LPC18XX_WDT_TC_MAX * | ||
| 258 | LPC18XX_WDT_CLK_DIV) / lpc18xx_wdt->clk_rate; | ||
| 259 | |||
| 260 | lpc18xx_wdt->wdt_dev.timeout = min(lpc18xx_wdt->wdt_dev.max_timeout, | ||
| 261 | LPC18XX_WDT_DEF_TIMEOUT); | ||
| 262 | |||
| 263 | spin_lock_init(&lpc18xx_wdt->lock); | ||
| 264 | |||
| 265 | lpc18xx_wdt->wdt_dev.parent = dev; | ||
| 266 | watchdog_set_drvdata(&lpc18xx_wdt->wdt_dev, lpc18xx_wdt); | ||
| 267 | |||
| 268 | ret = watchdog_init_timeout(&lpc18xx_wdt->wdt_dev, heartbeat, dev); | ||
| 269 | |||
| 270 | __lpc18xx_wdt_set_timeout(lpc18xx_wdt); | ||
| 271 | |||
| 272 | setup_timer(&lpc18xx_wdt->timer, lpc18xx_wdt_timer_feed, | ||
| 273 | (unsigned long)&lpc18xx_wdt->wdt_dev); | ||
| 274 | |||
| 275 | watchdog_set_nowayout(&lpc18xx_wdt->wdt_dev, nowayout); | ||
| 276 | |||
| 277 | platform_set_drvdata(pdev, lpc18xx_wdt); | ||
| 278 | |||
| 279 | ret = watchdog_register_device(&lpc18xx_wdt->wdt_dev); | ||
| 280 | if (ret) | ||
| 281 | goto disable_wdt_clk; | ||
| 282 | |||
| 283 | lpc18xx_wdt->restart_handler.notifier_call = lpc18xx_wdt_restart; | ||
| 284 | lpc18xx_wdt->restart_handler.priority = 128; | ||
| 285 | ret = register_restart_handler(&lpc18xx_wdt->restart_handler); | ||
| 286 | if (ret) | ||
| 287 | dev_warn(dev, "failed to register restart handler: %d\n", ret); | ||
| 288 | |||
| 289 | return 0; | ||
| 290 | |||
| 291 | disable_wdt_clk: | ||
| 292 | clk_disable_unprepare(lpc18xx_wdt->wdt_clk); | ||
| 293 | disable_reg_clk: | ||
| 294 | clk_disable_unprepare(lpc18xx_wdt->reg_clk); | ||
| 295 | return ret; | ||
| 296 | } | ||
| 297 | |||
| 298 | static void lpc18xx_wdt_shutdown(struct platform_device *pdev) | ||
| 299 | { | ||
| 300 | struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev); | ||
| 301 | |||
| 302 | lpc18xx_wdt_stop(&lpc18xx_wdt->wdt_dev); | ||
| 303 | } | ||
| 304 | |||
| 305 | static int lpc18xx_wdt_remove(struct platform_device *pdev) | ||
| 306 | { | ||
| 307 | struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev); | ||
| 308 | |||
| 309 | unregister_restart_handler(&lpc18xx_wdt->restart_handler); | ||
| 310 | |||
| 311 | dev_warn(&pdev->dev, "I quit now, hardware will probably reboot!\n"); | ||
| 312 | del_timer(&lpc18xx_wdt->timer); | ||
| 313 | |||
| 314 | watchdog_unregister_device(&lpc18xx_wdt->wdt_dev); | ||
| 315 | clk_disable_unprepare(lpc18xx_wdt->wdt_clk); | ||
| 316 | clk_disable_unprepare(lpc18xx_wdt->reg_clk); | ||
| 317 | |||
| 318 | return 0; | ||
| 319 | } | ||
| 320 | |||
| 321 | static const struct of_device_id lpc18xx_wdt_match[] = { | ||
| 322 | { .compatible = "nxp,lpc1850-wwdt" }, | ||
| 323 | {} | ||
| 324 | }; | ||
| 325 | MODULE_DEVICE_TABLE(of, lpc18xx_wdt_match); | ||
| 326 | |||
| 327 | static struct platform_driver lpc18xx_wdt_driver = { | ||
| 328 | .driver = { | ||
| 329 | .name = "lpc18xx-wdt", | ||
| 330 | .of_match_table = lpc18xx_wdt_match, | ||
| 331 | }, | ||
| 332 | .probe = lpc18xx_wdt_probe, | ||
| 333 | .remove = lpc18xx_wdt_remove, | ||
| 334 | .shutdown = lpc18xx_wdt_shutdown, | ||
| 335 | }; | ||
| 336 | module_platform_driver(lpc18xx_wdt_driver); | ||
| 337 | |||
| 338 | MODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>"); | ||
| 339 | MODULE_DESCRIPTION("NXP LPC18xx Watchdog Timer Driver"); | ||
| 340 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c index d193a5e79c38..69013007dc47 100644 --- a/drivers/watchdog/mena21_wdt.c +++ b/drivers/watchdog/mena21_wdt.c | |||
| @@ -197,6 +197,7 @@ static int a21_wdt_probe(struct platform_device *pdev) | |||
| 197 | watchdog_init_timeout(&a21_wdt, 30, &pdev->dev); | 197 | watchdog_init_timeout(&a21_wdt, 30, &pdev->dev); |
| 198 | watchdog_set_nowayout(&a21_wdt, nowayout); | 198 | watchdog_set_nowayout(&a21_wdt, nowayout); |
| 199 | watchdog_set_drvdata(&a21_wdt, drv); | 199 | watchdog_set_drvdata(&a21_wdt, drv); |
| 200 | a21_wdt.parent = &pdev->dev; | ||
| 200 | 201 | ||
| 201 | reset = a21_wdt_get_bootstatus(drv); | 202 | reset = a21_wdt_get_bootstatus(drv); |
| 202 | if (reset == 2) | 203 | if (reset == 2) |
diff --git a/drivers/watchdog/menf21bmc_wdt.c b/drivers/watchdog/menf21bmc_wdt.c index 59f0913c7341..3aefddebb386 100644 --- a/drivers/watchdog/menf21bmc_wdt.c +++ b/drivers/watchdog/menf21bmc_wdt.c | |||
| @@ -130,6 +130,7 @@ static int menf21bmc_wdt_probe(struct platform_device *pdev) | |||
| 130 | drv_data->wdt.info = &menf21bmc_wdt_info; | 130 | drv_data->wdt.info = &menf21bmc_wdt_info; |
| 131 | drv_data->wdt.min_timeout = BMC_WD_TIMEOUT_MIN; | 131 | drv_data->wdt.min_timeout = BMC_WD_TIMEOUT_MIN; |
| 132 | drv_data->wdt.max_timeout = BMC_WD_TIMEOUT_MAX; | 132 | drv_data->wdt.max_timeout = BMC_WD_TIMEOUT_MAX; |
| 133 | drv_data->wdt.parent = &pdev->dev; | ||
| 133 | drv_data->i2c_client = i2c_client; | 134 | drv_data->i2c_client = i2c_client; |
| 134 | 135 | ||
| 135 | /* | 136 | /* |
diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 689381a24887..5f2273aac37d 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c | |||
| @@ -50,8 +50,12 @@ struct mpc8xxx_wdt_type { | |||
| 50 | bool hw_enabled; | 50 | bool hw_enabled; |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | static struct mpc8xxx_wdt __iomem *wd_base; | 53 | struct mpc8xxx_wdt_ddata { |
| 54 | static int mpc8xxx_wdt_init_late(void); | 54 | struct mpc8xxx_wdt __iomem *base; |
| 55 | struct watchdog_device wdd; | ||
| 56 | struct timer_list timer; | ||
| 57 | spinlock_t lock; | ||
| 58 | }; | ||
| 55 | 59 | ||
| 56 | static u16 timeout = 0xffff; | 60 | static u16 timeout = 0xffff; |
| 57 | module_param(timeout, ushort, 0); | 61 | module_param(timeout, ushort, 0); |
| @@ -68,65 +72,59 @@ module_param(nowayout, bool, 0); | |||
| 68 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " | 72 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " |
| 69 | "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 73 | "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
| 70 | 74 | ||
| 71 | /* | 75 | static void mpc8xxx_wdt_keepalive(struct mpc8xxx_wdt_ddata *ddata) |
| 72 | * We always prescale, but if someone really doesn't want to they can set this | ||
| 73 | * to 0 | ||
| 74 | */ | ||
| 75 | static int prescale = 1; | ||
| 76 | |||
| 77 | static DEFINE_SPINLOCK(wdt_spinlock); | ||
| 78 | |||
| 79 | static void mpc8xxx_wdt_keepalive(void) | ||
| 80 | { | 76 | { |
| 81 | /* Ping the WDT */ | 77 | /* Ping the WDT */ |
| 82 | spin_lock(&wdt_spinlock); | 78 | spin_lock(&ddata->lock); |
| 83 | out_be16(&wd_base->swsrr, 0x556c); | 79 | out_be16(&ddata->base->swsrr, 0x556c); |
| 84 | out_be16(&wd_base->swsrr, 0xaa39); | 80 | out_be16(&ddata->base->swsrr, 0xaa39); |
| 85 | spin_unlock(&wdt_spinlock); | 81 | spin_unlock(&ddata->lock); |
| 86 | } | 82 | } |
| 87 | 83 | ||
| 88 | static struct watchdog_device mpc8xxx_wdt_dev; | ||
| 89 | static void mpc8xxx_wdt_timer_ping(unsigned long arg); | ||
| 90 | static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, | ||
| 91 | (unsigned long)&mpc8xxx_wdt_dev); | ||
| 92 | |||
| 93 | static void mpc8xxx_wdt_timer_ping(unsigned long arg) | 84 | static void mpc8xxx_wdt_timer_ping(unsigned long arg) |
| 94 | { | 85 | { |
| 95 | struct watchdog_device *w = (struct watchdog_device *)arg; | 86 | struct mpc8xxx_wdt_ddata *ddata = (void *)arg; |
| 96 | 87 | ||
| 97 | mpc8xxx_wdt_keepalive(); | 88 | mpc8xxx_wdt_keepalive(ddata); |
| 98 | /* We're pinging it twice faster than needed, just to be sure. */ | 89 | /* We're pinging it twice faster than needed, just to be sure. */ |
| 99 | mod_timer(&wdt_timer, jiffies + HZ * w->timeout / 2); | 90 | mod_timer(&ddata->timer, jiffies + HZ * ddata->wdd.timeout / 2); |
| 100 | } | 91 | } |
| 101 | 92 | ||
| 102 | static int mpc8xxx_wdt_start(struct watchdog_device *w) | 93 | static int mpc8xxx_wdt_start(struct watchdog_device *w) |
| 103 | { | 94 | { |
| 104 | u32 tmp = SWCRR_SWEN; | 95 | struct mpc8xxx_wdt_ddata *ddata = |
| 96 | container_of(w, struct mpc8xxx_wdt_ddata, wdd); | ||
| 97 | |||
| 98 | u32 tmp = SWCRR_SWEN | SWCRR_SWPR; | ||
| 105 | 99 | ||
| 106 | /* Good, fire up the show */ | 100 | /* Good, fire up the show */ |
| 107 | if (prescale) | ||
| 108 | tmp |= SWCRR_SWPR; | ||
| 109 | if (reset) | 101 | if (reset) |
| 110 | tmp |= SWCRR_SWRI; | 102 | tmp |= SWCRR_SWRI; |
| 111 | 103 | ||
| 112 | tmp |= timeout << 16; | 104 | tmp |= timeout << 16; |
| 113 | 105 | ||
| 114 | out_be32(&wd_base->swcrr, tmp); | 106 | out_be32(&ddata->base->swcrr, tmp); |
| 115 | 107 | ||
| 116 | del_timer_sync(&wdt_timer); | 108 | del_timer_sync(&ddata->timer); |
| 117 | 109 | ||
| 118 | return 0; | 110 | return 0; |
| 119 | } | 111 | } |
| 120 | 112 | ||
| 121 | static int mpc8xxx_wdt_ping(struct watchdog_device *w) | 113 | static int mpc8xxx_wdt_ping(struct watchdog_device *w) |
| 122 | { | 114 | { |
| 123 | mpc8xxx_wdt_keepalive(); | 115 | struct mpc8xxx_wdt_ddata *ddata = |
| 116 | container_of(w, struct mpc8xxx_wdt_ddata, wdd); | ||
| 117 | |||
| 118 | mpc8xxx_wdt_keepalive(ddata); | ||
| 124 | return 0; | 119 | return 0; |
| 125 | } | 120 | } |
| 126 | 121 | ||
| 127 | static int mpc8xxx_wdt_stop(struct watchdog_device *w) | 122 | static int mpc8xxx_wdt_stop(struct watchdog_device *w) |
| 128 | { | 123 | { |
| 129 | mod_timer(&wdt_timer, jiffies); | 124 | struct mpc8xxx_wdt_ddata *ddata = |
| 125 | container_of(w, struct mpc8xxx_wdt_ddata, wdd); | ||
| 126 | |||
| 127 | mod_timer(&ddata->timer, jiffies); | ||
| 130 | return 0; | 128 | return 0; |
| 131 | } | 129 | } |
| 132 | 130 | ||
| @@ -143,53 +141,57 @@ static struct watchdog_ops mpc8xxx_wdt_ops = { | |||
| 143 | .stop = mpc8xxx_wdt_stop, | 141 | .stop = mpc8xxx_wdt_stop, |
| 144 | }; | 142 | }; |
| 145 | 143 | ||
| 146 | static struct watchdog_device mpc8xxx_wdt_dev = { | ||
| 147 | .info = &mpc8xxx_wdt_info, | ||
| 148 | .ops = &mpc8xxx_wdt_ops, | ||
| 149 | }; | ||
| 150 | |||
| 151 | static const struct of_device_id mpc8xxx_wdt_match[]; | ||
| 152 | static int mpc8xxx_wdt_probe(struct platform_device *ofdev) | 144 | static int mpc8xxx_wdt_probe(struct platform_device *ofdev) |
| 153 | { | 145 | { |
| 154 | int ret; | 146 | int ret; |
| 155 | const struct of_device_id *match; | 147 | struct resource *res; |
| 156 | struct device_node *np = ofdev->dev.of_node; | ||
| 157 | const struct mpc8xxx_wdt_type *wdt_type; | 148 | const struct mpc8xxx_wdt_type *wdt_type; |
| 149 | struct mpc8xxx_wdt_ddata *ddata; | ||
| 158 | u32 freq = fsl_get_sys_freq(); | 150 | u32 freq = fsl_get_sys_freq(); |
| 159 | bool enabled; | 151 | bool enabled; |
| 160 | unsigned int timeout_sec; | 152 | unsigned int timeout_sec; |
| 161 | 153 | ||
| 162 | match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev); | 154 | wdt_type = of_device_get_match_data(&ofdev->dev); |
| 163 | if (!match) | 155 | if (!wdt_type) |
| 164 | return -EINVAL; | 156 | return -EINVAL; |
| 165 | wdt_type = match->data; | ||
| 166 | 157 | ||
| 167 | if (!freq || freq == -1) | 158 | if (!freq || freq == -1) |
| 168 | return -EINVAL; | 159 | return -EINVAL; |
| 169 | 160 | ||
| 170 | wd_base = of_iomap(np, 0); | 161 | ddata = devm_kzalloc(&ofdev->dev, sizeof(*ddata), GFP_KERNEL); |
| 171 | if (!wd_base) | 162 | if (!ddata) |
| 172 | return -ENOMEM; | 163 | return -ENOMEM; |
| 173 | 164 | ||
| 174 | enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN; | 165 | res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); |
| 166 | ddata->base = devm_ioremap_resource(&ofdev->dev, res); | ||
| 167 | if (IS_ERR(ddata->base)) | ||
| 168 | return PTR_ERR(ddata->base); | ||
| 169 | |||
| 170 | enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN; | ||
| 175 | if (!enabled && wdt_type->hw_enabled) { | 171 | if (!enabled && wdt_type->hw_enabled) { |
| 176 | pr_info("could not be enabled in software\n"); | 172 | pr_info("could not be enabled in software\n"); |
| 177 | ret = -ENOSYS; | 173 | return -ENODEV; |
| 178 | goto err_unmap; | ||
| 179 | } | 174 | } |
| 180 | 175 | ||
| 176 | spin_lock_init(&ddata->lock); | ||
| 177 | setup_timer(&ddata->timer, mpc8xxx_wdt_timer_ping, | ||
| 178 | (unsigned long)ddata); | ||
| 179 | |||
| 180 | ddata->wdd.info = &mpc8xxx_wdt_info, | ||
| 181 | ddata->wdd.ops = &mpc8xxx_wdt_ops, | ||
| 182 | |||
| 181 | /* Calculate the timeout in seconds */ | 183 | /* Calculate the timeout in seconds */ |
| 182 | if (prescale) | 184 | timeout_sec = (timeout * wdt_type->prescaler) / freq; |
| 183 | timeout_sec = (timeout * wdt_type->prescaler) / freq; | 185 | |
| 184 | else | 186 | ddata->wdd.timeout = timeout_sec; |
| 185 | timeout_sec = timeout / freq; | 187 | |
| 186 | 188 | watchdog_set_nowayout(&ddata->wdd, nowayout); | |
| 187 | mpc8xxx_wdt_dev.timeout = timeout_sec; | 189 | |
| 188 | #ifdef MODULE | 190 | ret = watchdog_register_device(&ddata->wdd); |
| 189 | ret = mpc8xxx_wdt_init_late(); | 191 | if (ret) { |
| 190 | if (ret) | 192 | pr_err("cannot register watchdog device (err=%d)\n", ret); |
| 191 | goto err_unmap; | 193 | return ret; |
| 192 | #endif | 194 | } |
| 193 | 195 | ||
| 194 | pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n", | 196 | pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n", |
| 195 | reset ? "reset" : "interrupt", timeout, timeout_sec); | 197 | reset ? "reset" : "interrupt", timeout, timeout_sec); |
| @@ -200,21 +202,20 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) | |||
| 200 | * userspace handles it. | 202 | * userspace handles it. |
| 201 | */ | 203 | */ |
| 202 | if (enabled) | 204 | if (enabled) |
| 203 | mod_timer(&wdt_timer, jiffies); | 205 | mod_timer(&ddata->timer, jiffies); |
| 206 | |||
| 207 | platform_set_drvdata(ofdev, ddata); | ||
| 204 | return 0; | 208 | return 0; |
| 205 | err_unmap: | ||
| 206 | iounmap(wd_base); | ||
| 207 | wd_base = NULL; | ||
| 208 | return ret; | ||
| 209 | } | 209 | } |
| 210 | 210 | ||
| 211 | static int mpc8xxx_wdt_remove(struct platform_device *ofdev) | 211 | static int mpc8xxx_wdt_remove(struct platform_device *ofdev) |
| 212 | { | 212 | { |
| 213 | struct mpc8xxx_wdt_ddata *ddata = platform_get_drvdata(ofdev); | ||
| 214 | |||
| 213 | pr_crit("Watchdog removed, expect the %s soon!\n", | 215 | pr_crit("Watchdog removed, expect the %s soon!\n", |
| 214 | reset ? "reset" : "machine check exception"); | 216 | reset ? "reset" : "machine check exception"); |
| 215 | del_timer_sync(&wdt_timer); | 217 | del_timer_sync(&ddata->timer); |
| 216 | watchdog_unregister_device(&mpc8xxx_wdt_dev); | 218 | watchdog_unregister_device(&ddata->wdd); |
| 217 | iounmap(wd_base); | ||
| 218 | 219 | ||
| 219 | return 0; | 220 | return 0; |
| 220 | } | 221 | } |
| @@ -253,31 +254,6 @@ static struct platform_driver mpc8xxx_wdt_driver = { | |||
| 253 | }, | 254 | }, |
| 254 | }; | 255 | }; |
| 255 | 256 | ||
| 256 | /* | ||
| 257 | * We do wdt initialization in two steps: arch_initcall probes the wdt | ||
| 258 | * very early to start pinging the watchdog (misc devices are not yet | ||
| 259 | * available), and later module_init() just registers the misc device. | ||
| 260 | */ | ||
| 261 | static int mpc8xxx_wdt_init_late(void) | ||
| 262 | { | ||
| 263 | int ret; | ||
| 264 | |||
| 265 | if (!wd_base) | ||
| 266 | return -ENODEV; | ||
| 267 | |||
| 268 | watchdog_set_nowayout(&mpc8xxx_wdt_dev, nowayout); | ||
| 269 | |||
| 270 | ret = watchdog_register_device(&mpc8xxx_wdt_dev); | ||
| 271 | if (ret) { | ||
| 272 | pr_err("cannot register watchdog device (err=%d)\n", ret); | ||
| 273 | return ret; | ||
| 274 | } | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | #ifndef MODULE | ||
| 278 | module_init(mpc8xxx_wdt_init_late); | ||
| 279 | #endif | ||
| 280 | |||
| 281 | static int __init mpc8xxx_wdt_init(void) | 257 | static int __init mpc8xxx_wdt_init(void) |
| 282 | { | 258 | { |
| 283 | return platform_driver_register(&mpc8xxx_wdt_driver); | 259 | return platform_driver_register(&mpc8xxx_wdt_driver); |
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index 938b987de551..6ad9df948711 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c | |||
| @@ -210,6 +210,14 @@ static int mtk_wdt_probe(struct platform_device *pdev) | |||
| 210 | return 0; | 210 | return 0; |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | static void mtk_wdt_shutdown(struct platform_device *pdev) | ||
| 214 | { | ||
| 215 | struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); | ||
| 216 | |||
| 217 | if (watchdog_active(&mtk_wdt->wdt_dev)) | ||
| 218 | mtk_wdt_stop(&mtk_wdt->wdt_dev); | ||
| 219 | } | ||
| 220 | |||
| 213 | static int mtk_wdt_remove(struct platform_device *pdev) | 221 | static int mtk_wdt_remove(struct platform_device *pdev) |
| 214 | { | 222 | { |
| 215 | struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); | 223 | struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); |
| @@ -221,17 +229,48 @@ static int mtk_wdt_remove(struct platform_device *pdev) | |||
| 221 | return 0; | 229 | return 0; |
| 222 | } | 230 | } |
| 223 | 231 | ||
| 232 | #ifdef CONFIG_PM_SLEEP | ||
| 233 | static int mtk_wdt_suspend(struct device *dev) | ||
| 234 | { | ||
| 235 | struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev); | ||
| 236 | |||
| 237 | if (watchdog_active(&mtk_wdt->wdt_dev)) | ||
| 238 | mtk_wdt_stop(&mtk_wdt->wdt_dev); | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static int mtk_wdt_resume(struct device *dev) | ||
| 244 | { | ||
| 245 | struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev); | ||
| 246 | |||
| 247 | if (watchdog_active(&mtk_wdt->wdt_dev)) { | ||
| 248 | mtk_wdt_start(&mtk_wdt->wdt_dev); | ||
| 249 | mtk_wdt_ping(&mtk_wdt->wdt_dev); | ||
| 250 | } | ||
| 251 | |||
| 252 | return 0; | ||
| 253 | } | ||
| 254 | #endif | ||
| 255 | |||
| 224 | static const struct of_device_id mtk_wdt_dt_ids[] = { | 256 | static const struct of_device_id mtk_wdt_dt_ids[] = { |
| 225 | { .compatible = "mediatek,mt6589-wdt" }, | 257 | { .compatible = "mediatek,mt6589-wdt" }, |
| 226 | { /* sentinel */ } | 258 | { /* sentinel */ } |
| 227 | }; | 259 | }; |
| 228 | MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids); | 260 | MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids); |
| 229 | 261 | ||
| 262 | static const struct dev_pm_ops mtk_wdt_pm_ops = { | ||
| 263 | SET_SYSTEM_SLEEP_PM_OPS(mtk_wdt_suspend, | ||
| 264 | mtk_wdt_resume) | ||
| 265 | }; | ||
| 266 | |||
| 230 | static struct platform_driver mtk_wdt_driver = { | 267 | static struct platform_driver mtk_wdt_driver = { |
| 231 | .probe = mtk_wdt_probe, | 268 | .probe = mtk_wdt_probe, |
| 232 | .remove = mtk_wdt_remove, | 269 | .remove = mtk_wdt_remove, |
| 270 | .shutdown = mtk_wdt_shutdown, | ||
| 233 | .driver = { | 271 | .driver = { |
| 234 | .name = DRV_NAME, | 272 | .name = DRV_NAME, |
| 273 | .pm = &mtk_wdt_pm_ops, | ||
| 235 | .of_match_table = mtk_wdt_dt_ids, | 274 | .of_match_table = mtk_wdt_dt_ids, |
| 236 | }, | 275 | }, |
| 237 | }; | 276 | }; |
diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c index c028454be66c..bd917bb757b8 100644 --- a/drivers/watchdog/nv_tco.c +++ b/drivers/watchdog/nv_tco.c | |||
| @@ -294,6 +294,8 @@ static const struct pci_device_id tco_pci_tbl[] = { | |||
| 294 | PCI_ANY_ID, PCI_ANY_ID, }, | 294 | PCI_ANY_ID, PCI_ANY_ID, }, |
| 295 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, | 295 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, |
| 296 | PCI_ANY_ID, PCI_ANY_ID, }, | 296 | PCI_ANY_ID, PCI_ANY_ID, }, |
| 297 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS, | ||
| 298 | PCI_ANY_ID, PCI_ANY_ID, }, | ||
| 297 | { 0, }, /* End of list */ | 299 | { 0, }, /* End of list */ |
| 298 | }; | 300 | }; |
| 299 | MODULE_DEVICE_TABLE(pci, tco_pci_tbl); | 301 | MODULE_DEVICE_TABLE(pci, tco_pci_tbl); |
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index de911c7e477c..d96bee017fd3 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c | |||
| @@ -253,6 +253,7 @@ static int omap_wdt_probe(struct platform_device *pdev) | |||
| 253 | wdev->wdog.ops = &omap_wdt_ops; | 253 | wdev->wdog.ops = &omap_wdt_ops; |
| 254 | wdev->wdog.min_timeout = TIMER_MARGIN_MIN; | 254 | wdev->wdog.min_timeout = TIMER_MARGIN_MIN; |
| 255 | wdev->wdog.max_timeout = TIMER_MARGIN_MAX; | 255 | wdev->wdog.max_timeout = TIMER_MARGIN_MAX; |
| 256 | wdev->wdog.parent = &pdev->dev; | ||
| 256 | 257 | ||
| 257 | if (watchdog_init_timeout(&wdev->wdog, timer_margin, &pdev->dev) < 0) | 258 | if (watchdog_init_timeout(&wdev->wdog, timer_margin, &pdev->dev) < 0) |
| 258 | wdev->wdog.timeout = TIMER_MARGIN_DEFAULT; | 259 | wdev->wdog.timeout = TIMER_MARGIN_DEFAULT; |
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index ef0c628d5037..c6b8f4a43bde 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c | |||
| @@ -567,6 +567,7 @@ static int orion_wdt_probe(struct platform_device *pdev) | |||
| 567 | 567 | ||
| 568 | dev->wdt.timeout = wdt_max_duration; | 568 | dev->wdt.timeout = wdt_max_duration; |
| 569 | dev->wdt.max_timeout = wdt_max_duration; | 569 | dev->wdt.max_timeout = wdt_max_duration; |
| 570 | dev->wdt.parent = &pdev->dev; | ||
| 570 | watchdog_init_timeout(&dev->wdt, heartbeat, &pdev->dev); | 571 | watchdog_init_timeout(&dev->wdt, heartbeat, &pdev->dev); |
| 571 | 572 | ||
| 572 | platform_set_drvdata(pdev, &dev->wdt); | 573 | platform_set_drvdata(pdev, &dev->wdt); |
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index b9c6049c3e78..4224b3ec83a5 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c | |||
| @@ -167,6 +167,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev) | |||
| 167 | 167 | ||
| 168 | pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ? | 168 | pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ? |
| 169 | WDIOF_CARDRESET : 0; | 169 | WDIOF_CARDRESET : 0; |
| 170 | pnx4008_wdd.parent = &pdev->dev; | ||
| 170 | watchdog_set_nowayout(&pnx4008_wdd, nowayout); | 171 | watchdog_set_nowayout(&pnx4008_wdd, nowayout); |
| 171 | 172 | ||
| 172 | pnx4008_wdt_stop(&pnx4008_wdd); /* disable for now */ | 173 | pnx4008_wdt_stop(&pnx4008_wdd); /* disable for now */ |
diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index aa03ca8f2d9b..773dcfaee7b2 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c | |||
| @@ -171,6 +171,7 @@ static int qcom_wdt_probe(struct platform_device *pdev) | |||
| 171 | wdt->wdd.ops = &qcom_wdt_ops; | 171 | wdt->wdd.ops = &qcom_wdt_ops; |
| 172 | wdt->wdd.min_timeout = 1; | 172 | wdt->wdd.min_timeout = 1; |
| 173 | wdt->wdd.max_timeout = 0x10000000U / wdt->rate; | 173 | wdt->wdd.max_timeout = 0x10000000U / wdt->rate; |
| 174 | wdt->wdd.parent = &pdev->dev; | ||
| 174 | 175 | ||
| 175 | /* | 176 | /* |
| 176 | * If 'timeout-sec' unspecified in devicetree, assume a 30 second | 177 | * If 'timeout-sec' unspecified in devicetree, assume a 30 second |
diff --git a/drivers/watchdog/retu_wdt.c b/drivers/watchdog/retu_wdt.c index b7c68e275aeb..39cd51df2ffc 100644 --- a/drivers/watchdog/retu_wdt.c +++ b/drivers/watchdog/retu_wdt.c | |||
| @@ -127,6 +127,7 @@ static int retu_wdt_probe(struct platform_device *pdev) | |||
| 127 | retu_wdt->timeout = RETU_WDT_MAX_TIMER; | 127 | retu_wdt->timeout = RETU_WDT_MAX_TIMER; |
| 128 | retu_wdt->min_timeout = 0; | 128 | retu_wdt->min_timeout = 0; |
| 129 | retu_wdt->max_timeout = RETU_WDT_MAX_TIMER; | 129 | retu_wdt->max_timeout = RETU_WDT_MAX_TIMER; |
| 130 | retu_wdt->parent = &pdev->dev; | ||
| 130 | 131 | ||
| 131 | watchdog_set_drvdata(retu_wdt, wdev); | 132 | watchdog_set_drvdata(retu_wdt, wdev); |
| 132 | watchdog_set_nowayout(retu_wdt, nowayout); | 133 | watchdog_set_nowayout(retu_wdt, nowayout); |
diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index a6f7e2e29beb..1967919ae743 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c | |||
| @@ -161,6 +161,7 @@ static int rt288x_wdt_probe(struct platform_device *pdev) | |||
| 161 | rt288x_wdt_dev.dev = &pdev->dev; | 161 | rt288x_wdt_dev.dev = &pdev->dev; |
| 162 | rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); | 162 | rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); |
| 163 | rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); | 163 | rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); |
| 164 | rt288x_wdt_dev.parent = &pdev->dev; | ||
| 164 | 165 | ||
| 165 | watchdog_init_timeout(&rt288x_wdt_dev, rt288x_wdt_dev.max_timeout, | 166 | watchdog_init_timeout(&rt288x_wdt_dev, rt288x_wdt_dev.max_timeout, |
| 166 | &pdev->dev); | 167 | &pdev->dev); |
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index e89ae027c91d..d781000c7825 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
| @@ -607,6 +607,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 607 | watchdog_set_nowayout(&wdt->wdt_device, nowayout); | 607 | watchdog_set_nowayout(&wdt->wdt_device, nowayout); |
| 608 | 608 | ||
| 609 | wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt); | 609 | wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt); |
| 610 | wdt->wdt_device.parent = &pdev->dev; | ||
| 610 | 611 | ||
| 611 | ret = watchdog_register_device(&wdt->wdt_device); | 612 | ret = watchdog_register_device(&wdt->wdt_device); |
| 612 | if (ret) { | 613 | if (ret) { |
diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c new file mode 100644 index 000000000000..a49634cdc1cc --- /dev/null +++ b/drivers/watchdog/sama5d4_wdt.c | |||
| @@ -0,0 +1,280 @@ | |||
| 1 | /* | ||
| 2 | * Driver for Atmel SAMA5D4 Watchdog Timer | ||
| 3 | * | ||
| 4 | * Copyright (C) 2015 Atmel Corporation | ||
| 5 | * | ||
| 6 | * Licensed under GPLv2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/interrupt.h> | ||
| 10 | #include <linux/io.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/of.h> | ||
| 14 | #include <linux/of_irq.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/reboot.h> | ||
| 17 | #include <linux/watchdog.h> | ||
| 18 | |||
| 19 | #include "at91sam9_wdt.h" | ||
| 20 | |||
| 21 | /* minimum and maximum watchdog timeout, in seconds */ | ||
| 22 | #define MIN_WDT_TIMEOUT 1 | ||
| 23 | #define MAX_WDT_TIMEOUT 16 | ||
| 24 | #define WDT_DEFAULT_TIMEOUT MAX_WDT_TIMEOUT | ||
| 25 | |||
| 26 | #define WDT_SEC2TICKS(s) ((s) ? (((s) << 8) - 1) : 0) | ||
| 27 | |||
| 28 | struct sama5d4_wdt { | ||
| 29 | struct watchdog_device wdd; | ||
| 30 | void __iomem *reg_base; | ||
| 31 | u32 config; | ||
| 32 | }; | ||
| 33 | |||
| 34 | static int wdt_timeout = WDT_DEFAULT_TIMEOUT; | ||
| 35 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
| 36 | |||
| 37 | module_param(wdt_timeout, int, 0); | ||
| 38 | MODULE_PARM_DESC(wdt_timeout, | ||
| 39 | "Watchdog timeout in seconds. (default = " | ||
| 40 | __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")"); | ||
| 41 | |||
| 42 | module_param(nowayout, bool, 0); | ||
| 43 | MODULE_PARM_DESC(nowayout, | ||
| 44 | "Watchdog cannot be stopped once started (default=" | ||
| 45 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 46 | |||
| 47 | #define wdt_read(wdt, field) \ | ||
| 48 | readl_relaxed((wdt)->reg_base + (field)) | ||
| 49 | |||
| 50 | #define wdt_write(wtd, field, val) \ | ||
| 51 | writel_relaxed((val), (wdt)->reg_base + (field)) | ||
| 52 | |||
| 53 | static int sama5d4_wdt_start(struct watchdog_device *wdd) | ||
| 54 | { | ||
| 55 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 56 | u32 reg; | ||
| 57 | |||
| 58 | reg = wdt_read(wdt, AT91_WDT_MR); | ||
| 59 | reg &= ~AT91_WDT_WDDIS; | ||
| 60 | wdt_write(wdt, AT91_WDT_MR, reg); | ||
| 61 | |||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | static int sama5d4_wdt_stop(struct watchdog_device *wdd) | ||
| 66 | { | ||
| 67 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 68 | u32 reg; | ||
| 69 | |||
| 70 | reg = wdt_read(wdt, AT91_WDT_MR); | ||
| 71 | reg |= AT91_WDT_WDDIS; | ||
| 72 | wdt_write(wdt, AT91_WDT_MR, reg); | ||
| 73 | |||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | static int sama5d4_wdt_ping(struct watchdog_device *wdd) | ||
| 78 | { | ||
| 79 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 80 | |||
| 81 | wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); | ||
| 82 | |||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd, | ||
| 87 | unsigned int timeout) | ||
| 88 | { | ||
| 89 | struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); | ||
| 90 | u32 value = WDT_SEC2TICKS(timeout); | ||
| 91 | u32 reg; | ||
| 92 | |||
| 93 | reg = wdt_read(wdt, AT91_WDT_MR); | ||
| 94 | reg &= ~AT91_WDT_WDV; | ||
| 95 | reg &= ~AT91_WDT_WDD; | ||
| 96 | reg |= AT91_WDT_SET_WDV(value); | ||
| 97 | reg |= AT91_WDT_SET_WDD(value); | ||
| 98 | wdt_write(wdt, AT91_WDT_MR, reg); | ||
| 99 | |||
| 100 | wdd->timeout = timeout; | ||
| 101 | |||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | static const struct watchdog_info sama5d4_wdt_info = { | ||
| 106 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, | ||
| 107 | .identity = "Atmel SAMA5D4 Watchdog", | ||
| 108 | }; | ||
| 109 | |||
| 110 | static struct watchdog_ops sama5d4_wdt_ops = { | ||
| 111 | .owner = THIS_MODULE, | ||
| 112 | .start = sama5d4_wdt_start, | ||
| 113 | .stop = sama5d4_wdt_stop, | ||
| 114 | .ping = sama5d4_wdt_ping, | ||
| 115 | .set_timeout = sama5d4_wdt_set_timeout, | ||
| 116 | }; | ||
| 117 | |||
| 118 | static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id) | ||
| 119 | { | ||
| 120 | struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id); | ||
| 121 | |||
| 122 | if (wdt_read(wdt, AT91_WDT_SR)) { | ||
| 123 | pr_crit("Atmel Watchdog Software Reset\n"); | ||
| 124 | emergency_restart(); | ||
| 125 | pr_crit("Reboot didn't succeed\n"); | ||
| 126 | } | ||
| 127 | |||
| 128 | return IRQ_HANDLED; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt) | ||
| 132 | { | ||
| 133 | const char *tmp; | ||
| 134 | |||
| 135 | wdt->config = AT91_WDT_WDDIS; | ||
| 136 | |||
| 137 | if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && | ||
| 138 | !strcmp(tmp, "software")) | ||
| 139 | wdt->config |= AT91_WDT_WDFIEN; | ||
| 140 | else | ||
| 141 | wdt->config |= AT91_WDT_WDRSTEN; | ||
| 142 | |||
| 143 | if (of_property_read_bool(np, "atmel,idle-halt")) | ||
| 144 | wdt->config |= AT91_WDT_WDIDLEHLT; | ||
| 145 | |||
| 146 | if (of_property_read_bool(np, "atmel,dbg-halt")) | ||
| 147 | wdt->config |= AT91_WDT_WDDBGHLT; | ||
| 148 | |||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) | ||
| 153 | { | ||
| 154 | struct watchdog_device *wdd = &wdt->wdd; | ||
| 155 | u32 value = WDT_SEC2TICKS(wdd->timeout); | ||
| 156 | u32 reg; | ||
| 157 | |||
| 158 | /* | ||
| 159 | * Because the fields WDV and WDD must not be modified when the WDDIS | ||
| 160 | * bit is set, so clear the WDDIS bit before writing the WDT_MR. | ||
| 161 | */ | ||
| 162 | reg = wdt_read(wdt, AT91_WDT_MR); | ||
| 163 | reg &= ~AT91_WDT_WDDIS; | ||
| 164 | wdt_write(wdt, AT91_WDT_MR, reg); | ||
| 165 | |||
| 166 | reg = wdt->config; | ||
| 167 | reg |= AT91_WDT_SET_WDD(value); | ||
| 168 | reg |= AT91_WDT_SET_WDV(value); | ||
| 169 | |||
| 170 | wdt_write(wdt, AT91_WDT_MR, reg); | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | static int sama5d4_wdt_probe(struct platform_device *pdev) | ||
| 176 | { | ||
| 177 | struct watchdog_device *wdd; | ||
| 178 | struct sama5d4_wdt *wdt; | ||
| 179 | struct resource *res; | ||
| 180 | void __iomem *regs; | ||
| 181 | u32 irq = 0; | ||
| 182 | int ret; | ||
| 183 | |||
| 184 | wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); | ||
| 185 | if (!wdt) | ||
| 186 | return -ENOMEM; | ||
| 187 | |||
| 188 | wdd = &wdt->wdd; | ||
| 189 | wdd->timeout = wdt_timeout; | ||
| 190 | wdd->info = &sama5d4_wdt_info; | ||
| 191 | wdd->ops = &sama5d4_wdt_ops; | ||
| 192 | wdd->min_timeout = MIN_WDT_TIMEOUT; | ||
| 193 | wdd->max_timeout = MAX_WDT_TIMEOUT; | ||
| 194 | |||
| 195 | watchdog_set_drvdata(wdd, wdt); | ||
| 196 | |||
| 197 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 198 | regs = devm_ioremap_resource(&pdev->dev, res); | ||
| 199 | if (IS_ERR(regs)) | ||
| 200 | return PTR_ERR(regs); | ||
| 201 | |||
| 202 | wdt->reg_base = regs; | ||
| 203 | |||
| 204 | if (pdev->dev.of_node) { | ||
| 205 | irq = irq_of_parse_and_map(pdev->dev.of_node, 0); | ||
| 206 | if (!irq) | ||
| 207 | dev_warn(&pdev->dev, "failed to get IRQ from DT\n"); | ||
| 208 | |||
| 209 | ret = of_sama5d4_wdt_init(pdev->dev.of_node, wdt); | ||
| 210 | if (ret) | ||
| 211 | return ret; | ||
| 212 | } | ||
| 213 | |||
| 214 | if ((wdt->config & AT91_WDT_WDFIEN) && irq) { | ||
| 215 | ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler, | ||
| 216 | IRQF_SHARED | IRQF_IRQPOLL | | ||
| 217 | IRQF_NO_SUSPEND, pdev->name, pdev); | ||
| 218 | if (ret) { | ||
| 219 | dev_err(&pdev->dev, | ||
| 220 | "cannot register interrupt handler\n"); | ||
| 221 | return ret; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | ret = watchdog_init_timeout(wdd, wdt_timeout, &pdev->dev); | ||
| 226 | if (ret) { | ||
| 227 | dev_err(&pdev->dev, "unable to set timeout value\n"); | ||
| 228 | return ret; | ||
| 229 | } | ||
| 230 | |||
| 231 | ret = sama5d4_wdt_init(wdt); | ||
| 232 | if (ret) | ||
| 233 | return ret; | ||
| 234 | |||
| 235 | watchdog_set_nowayout(wdd, nowayout); | ||
| 236 | |||
| 237 | ret = watchdog_register_device(wdd); | ||
| 238 | if (ret) { | ||
| 239 | dev_err(&pdev->dev, "failed to register watchdog device\n"); | ||
| 240 | return ret; | ||
| 241 | } | ||
| 242 | |||
| 243 | platform_set_drvdata(pdev, wdt); | ||
| 244 | |||
| 245 | dev_info(&pdev->dev, "initialized (timeout = %d sec, nowayout = %d)\n", | ||
| 246 | wdt_timeout, nowayout); | ||
| 247 | |||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | static int sama5d4_wdt_remove(struct platform_device *pdev) | ||
| 252 | { | ||
| 253 | struct sama5d4_wdt *wdt = platform_get_drvdata(pdev); | ||
| 254 | |||
| 255 | sama5d4_wdt_stop(&wdt->wdd); | ||
| 256 | |||
| 257 | watchdog_unregister_device(&wdt->wdd); | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | static const struct of_device_id sama5d4_wdt_of_match[] = { | ||
| 263 | { .compatible = "atmel,sama5d4-wdt", }, | ||
| 264 | { } | ||
| 265 | }; | ||
| 266 | MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match); | ||
| 267 | |||
| 268 | static struct platform_driver sama5d4_wdt_driver = { | ||
| 269 | .probe = sama5d4_wdt_probe, | ||
| 270 | .remove = sama5d4_wdt_remove, | ||
| 271 | .driver = { | ||
| 272 | .name = "sama5d4_wdt", | ||
| 273 | .of_match_table = sama5d4_wdt_of_match, | ||
| 274 | } | ||
| 275 | }; | ||
| 276 | module_platform_driver(sama5d4_wdt_driver); | ||
| 277 | |||
| 278 | MODULE_AUTHOR("Atmel Corporation"); | ||
| 279 | MODULE_DESCRIPTION("Atmel SAMA5D4 Watchdog Timer driver"); | ||
| 280 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index 567458b137a6..f90812170657 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c | |||
| @@ -252,6 +252,7 @@ static int sh_wdt_probe(struct platform_device *pdev) | |||
| 252 | 252 | ||
| 253 | watchdog_set_nowayout(&sh_wdt_dev, nowayout); | 253 | watchdog_set_nowayout(&sh_wdt_dev, nowayout); |
| 254 | watchdog_set_drvdata(&sh_wdt_dev, wdt); | 254 | watchdog_set_drvdata(&sh_wdt_dev, wdt); |
| 255 | sh_wdt_dev.parent = &pdev->dev; | ||
| 255 | 256 | ||
| 256 | spin_lock_init(&wdt->lock); | 257 | spin_lock_init(&wdt->lock); |
| 257 | 258 | ||
diff --git a/drivers/watchdog/sirfsoc_wdt.c b/drivers/watchdog/sirfsoc_wdt.c index 42fa5c0c518a..d0578ab2e636 100644 --- a/drivers/watchdog/sirfsoc_wdt.c +++ b/drivers/watchdog/sirfsoc_wdt.c | |||
| @@ -154,6 +154,7 @@ static int sirfsoc_wdt_probe(struct platform_device *pdev) | |||
| 154 | 154 | ||
| 155 | watchdog_init_timeout(&sirfsoc_wdd, timeout, &pdev->dev); | 155 | watchdog_init_timeout(&sirfsoc_wdd, timeout, &pdev->dev); |
| 156 | watchdog_set_nowayout(&sirfsoc_wdd, nowayout); | 156 | watchdog_set_nowayout(&sirfsoc_wdd, nowayout); |
| 157 | sirfsoc_wdd.parent = &pdev->dev; | ||
| 157 | 158 | ||
| 158 | ret = watchdog_register_device(&sirfsoc_wdd); | 159 | ret = watchdog_register_device(&sirfsoc_wdd); |
| 159 | if (ret) | 160 | if (ret) |
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index 4e7fec36f5c3..01d816251302 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c | |||
| @@ -226,6 +226,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) | |||
| 226 | wdt->adev = adev; | 226 | wdt->adev = adev; |
| 227 | wdt->wdd.info = &wdt_info; | 227 | wdt->wdd.info = &wdt_info; |
| 228 | wdt->wdd.ops = &wdt_ops; | 228 | wdt->wdd.ops = &wdt_ops; |
| 229 | wdt->wdd.parent = &adev->dev; | ||
| 229 | 230 | ||
| 230 | spin_lock_init(&wdt->lock); | 231 | spin_lock_init(&wdt->lock); |
| 231 | watchdog_set_nowayout(&wdt->wdd, nowayout); | 232 | watchdog_set_nowayout(&wdt->wdd, nowayout); |
diff --git a/drivers/watchdog/st_lpc_wdt.c b/drivers/watchdog/st_lpc_wdt.c index 6785afdc0fca..14e9badf2bfa 100644 --- a/drivers/watchdog/st_lpc_wdt.c +++ b/drivers/watchdog/st_lpc_wdt.c | |||
| @@ -241,6 +241,7 @@ static int st_wdog_probe(struct platform_device *pdev) | |||
| 241 | return -EINVAL; | 241 | return -EINVAL; |
| 242 | } | 242 | } |
| 243 | st_wdog_dev.max_timeout = 0xFFFFFFFF / st_wdog->clkrate; | 243 | st_wdog_dev.max_timeout = 0xFFFFFFFF / st_wdog->clkrate; |
| 244 | st_wdog_dev.parent = &pdev->dev; | ||
| 244 | 245 | ||
| 245 | ret = clk_prepare_enable(clk); | 246 | ret = clk_prepare_enable(clk); |
| 246 | if (ret) { | 247 | if (ret) { |
diff --git a/drivers/watchdog/stmp3xxx_rtc_wdt.c b/drivers/watchdog/stmp3xxx_rtc_wdt.c index e7f0d5b60d3d..3ee6128a540e 100644 --- a/drivers/watchdog/stmp3xxx_rtc_wdt.c +++ b/drivers/watchdog/stmp3xxx_rtc_wdt.c | |||
| @@ -76,6 +76,7 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev) | |||
| 76 | watchdog_set_drvdata(&stmp3xxx_wdd, &pdev->dev); | 76 | watchdog_set_drvdata(&stmp3xxx_wdd, &pdev->dev); |
| 77 | 77 | ||
| 78 | stmp3xxx_wdd.timeout = clamp_t(unsigned, heartbeat, 1, STMP3XXX_MAX_TIMEOUT); | 78 | stmp3xxx_wdd.timeout = clamp_t(unsigned, heartbeat, 1, STMP3XXX_MAX_TIMEOUT); |
| 79 | stmp3xxx_wdd.parent = &pdev->dev; | ||
| 79 | 80 | ||
| 80 | ret = watchdog_register_device(&stmp3xxx_wdd); | 81 | ret = watchdog_register_device(&stmp3xxx_wdd); |
| 81 | if (ret < 0) { | 82 | if (ret < 0) { |
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c index a29afb37c48c..47bd8a14d01f 100644 --- a/drivers/watchdog/sunxi_wdt.c +++ b/drivers/watchdog/sunxi_wdt.c | |||
| @@ -184,7 +184,7 @@ static int sunxi_wdt_start(struct watchdog_device *wdt_dev) | |||
| 184 | /* Set system reset function */ | 184 | /* Set system reset function */ |
| 185 | reg = readl(wdt_base + regs->wdt_cfg); | 185 | reg = readl(wdt_base + regs->wdt_cfg); |
| 186 | reg &= ~(regs->wdt_reset_mask); | 186 | reg &= ~(regs->wdt_reset_mask); |
| 187 | reg |= ~(regs->wdt_reset_val); | 187 | reg |= regs->wdt_reset_val; |
| 188 | writel(reg, wdt_base + regs->wdt_cfg); | 188 | writel(reg, wdt_base + regs->wdt_cfg); |
| 189 | 189 | ||
| 190 | /* Enable watchdog */ | 190 | /* Enable watchdog */ |
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index 30451ea46902..7f97cdd53f29 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c | |||
| @@ -218,6 +218,7 @@ static int tegra_wdt_probe(struct platform_device *pdev) | |||
| 218 | wdd->ops = &tegra_wdt_ops; | 218 | wdd->ops = &tegra_wdt_ops; |
| 219 | wdd->min_timeout = MIN_WDT_TIMEOUT; | 219 | wdd->min_timeout = MIN_WDT_TIMEOUT; |
| 220 | wdd->max_timeout = MAX_WDT_TIMEOUT; | 220 | wdd->max_timeout = MAX_WDT_TIMEOUT; |
| 221 | wdd->parent = &pdev->dev; | ||
| 221 | 222 | ||
| 222 | watchdog_set_drvdata(wdd, wdt); | 223 | watchdog_set_drvdata(wdd, wdt); |
| 223 | 224 | ||
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index 2c1db6fa9a27..9bf3cc0f3961 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c | |||
| @@ -83,6 +83,7 @@ static int twl4030_wdt_probe(struct platform_device *pdev) | |||
| 83 | wdt->timeout = 30; | 83 | wdt->timeout = 30; |
| 84 | wdt->min_timeout = 1; | 84 | wdt->min_timeout = 1; |
| 85 | wdt->max_timeout = 30; | 85 | wdt->max_timeout = 30; |
| 86 | wdt->parent = &pdev->dev; | ||
| 86 | 87 | ||
| 87 | watchdog_set_nowayout(wdt, nowayout); | 88 | watchdog_set_nowayout(wdt, nowayout); |
| 88 | platform_set_drvdata(pdev, wdt); | 89 | platform_set_drvdata(pdev, wdt); |
diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index 7f615933d31a..c2da880292bc 100644 --- a/drivers/watchdog/txx9wdt.c +++ b/drivers/watchdog/txx9wdt.c | |||
| @@ -131,6 +131,7 @@ static int __init txx9wdt_probe(struct platform_device *dev) | |||
| 131 | txx9wdt.timeout = timeout; | 131 | txx9wdt.timeout = timeout; |
| 132 | txx9wdt.min_timeout = 1; | 132 | txx9wdt.min_timeout = 1; |
| 133 | txx9wdt.max_timeout = WD_MAX_TIMEOUT; | 133 | txx9wdt.max_timeout = WD_MAX_TIMEOUT; |
| 134 | txx9wdt.parent = &dev->dev; | ||
| 134 | watchdog_set_nowayout(&txx9wdt, nowayout); | 135 | watchdog_set_nowayout(&txx9wdt, nowayout); |
| 135 | 136 | ||
| 136 | ret = watchdog_register_device(&txx9wdt); | 137 | ret = watchdog_register_device(&txx9wdt); |
diff --git a/drivers/watchdog/ux500_wdt.c b/drivers/watchdog/ux500_wdt.c index 9de09ab00838..37c084353cce 100644 --- a/drivers/watchdog/ux500_wdt.c +++ b/drivers/watchdog/ux500_wdt.c | |||
| @@ -96,6 +96,7 @@ static int ux500_wdt_probe(struct platform_device *pdev) | |||
| 96 | ux500_wdt.max_timeout = WATCHDOG_MAX28; | 96 | ux500_wdt.max_timeout = WATCHDOG_MAX28; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | ux500_wdt.parent = &pdev->dev; | ||
| 99 | watchdog_set_nowayout(&ux500_wdt, nowayout); | 100 | watchdog_set_nowayout(&ux500_wdt, nowayout); |
| 100 | 101 | ||
| 101 | /* disable auto off on sleep */ | 102 | /* disable auto off on sleep */ |
diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c index 56369c4f1961..5f9cbc37520d 100644 --- a/drivers/watchdog/via_wdt.c +++ b/drivers/watchdog/via_wdt.c | |||
| @@ -206,6 +206,7 @@ static int wdt_probe(struct pci_dev *pdev, | |||
| 206 | timeout = WDT_TIMEOUT; | 206 | timeout = WDT_TIMEOUT; |
| 207 | 207 | ||
| 208 | wdt_dev.timeout = timeout; | 208 | wdt_dev.timeout = timeout; |
| 209 | wdt_dev.parent = &pdev->dev; | ||
| 209 | watchdog_set_nowayout(&wdt_dev, nowayout); | 210 | watchdog_set_nowayout(&wdt_dev, nowayout); |
| 210 | if (readl(wdt_mem) & VIA_WDT_FIRED) | 211 | if (readl(wdt_mem) & VIA_WDT_FIRED) |
| 211 | wdt_dev.bootstatus |= WDIOF_CARDRESET; | 212 | wdt_dev.bootstatus |= WDIOF_CARDRESET; |
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 2fa17e746ff6..8d1184aee932 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c | |||
| @@ -215,6 +215,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev) | |||
| 215 | 215 | ||
| 216 | wm831x_wdt->info = &wm831x_wdt_info; | 216 | wm831x_wdt->info = &wm831x_wdt_info; |
| 217 | wm831x_wdt->ops = &wm831x_wdt_ops; | 217 | wm831x_wdt->ops = &wm831x_wdt_ops; |
| 218 | wm831x_wdt->parent = &pdev->dev; | ||
| 218 | watchdog_set_nowayout(wm831x_wdt, nowayout); | 219 | watchdog_set_nowayout(wm831x_wdt, nowayout); |
| 219 | watchdog_set_drvdata(wm831x_wdt, driver_data); | 220 | watchdog_set_drvdata(wm831x_wdt, driver_data); |
| 220 | 221 | ||
diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c index 34d272ada23d..4ab4b8347d45 100644 --- a/drivers/watchdog/wm8350_wdt.c +++ b/drivers/watchdog/wm8350_wdt.c | |||
| @@ -151,6 +151,7 @@ static int wm8350_wdt_probe(struct platform_device *pdev) | |||
| 151 | 151 | ||
| 152 | watchdog_set_nowayout(&wm8350_wdt, nowayout); | 152 | watchdog_set_nowayout(&wm8350_wdt, nowayout); |
| 153 | watchdog_set_drvdata(&wm8350_wdt, wm8350); | 153 | watchdog_set_drvdata(&wm8350_wdt, wm8350); |
| 154 | wm8350_wdt.parent = &pdev->dev; | ||
| 154 | 155 | ||
| 155 | /* Default to 4s timeout */ | 156 | /* Default to 4s timeout */ |
| 156 | wm8350_wdt_set_timeout(&wm8350_wdt, 4); | 157 | wm8350_wdt_set_timeout(&wm8350_wdt, 4); |
