diff options
39 files changed, 629 insertions, 740 deletions
diff --git a/Documentation/devicetree/bindings/gpio/men-a021-wdt.txt b/Documentation/devicetree/bindings/gpio/men-a021-wdt.txt new file mode 100644 index 000000000000..370dee3226d9 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/men-a021-wdt.txt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | Bindings for MEN A21 Watchdog device connected to GPIO lines | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: "men,a021-wdt" | ||
| 5 | - gpios: Specifies the pins that control the Watchdog, order: | ||
| 6 | 1: Watchdog enable | ||
| 7 | 2: Watchdog fast-mode | ||
| 8 | 3: Watchdog trigger | ||
| 9 | 4: Watchdog reset cause bit 0 | ||
| 10 | 5: Watchdog reset cause bit 1 | ||
| 11 | 6: Watchdog reset cause bit 2 | ||
| 12 | |||
| 13 | Optional properties: | ||
| 14 | - None | ||
| 15 | |||
| 16 | Example: | ||
| 17 | watchdog { | ||
| 18 | compatible ="men,a021-wdt"; | ||
| 19 | gpios = <&gpio3 9 1 /* WD_EN */ | ||
| 20 | &gpio3 10 1 /* WD_FAST */ | ||
| 21 | &gpio3 11 1 /* WD_TRIG */ | ||
| 22 | &gpio3 6 1 /* RST_CAUSE[0] */ | ||
| 23 | &gpio3 7 1 /* RST_CAUSE[1] */ | ||
| 24 | &gpio3 8 1>; /* RST_CAUSE[2] */ | ||
| 25 | }; | ||
diff --git a/Documentation/devicetree/bindings/watchdog/brcm,bcm2835-pm-wdog.txt b/Documentation/devicetree/bindings/watchdog/brcm,bcm2835-pm-wdog.txt index d209366b4a69..f801d71de1cd 100644 --- a/Documentation/devicetree/bindings/watchdog/brcm,bcm2835-pm-wdog.txt +++ b/Documentation/devicetree/bindings/watchdog/brcm,bcm2835-pm-wdog.txt | |||
| @@ -5,9 +5,14 @@ Required properties: | |||
| 5 | - compatible : should be "brcm,bcm2835-pm-wdt" | 5 | - compatible : should be "brcm,bcm2835-pm-wdt" |
| 6 | - reg : Specifies base physical address and size of the registers. | 6 | - reg : Specifies base physical address and size of the registers. |
| 7 | 7 | ||
| 8 | Optional properties: | ||
| 9 | |||
| 10 | - timeout-sec : Contains the watchdog timeout in seconds | ||
| 11 | |||
| 8 | Example: | 12 | Example: |
| 9 | 13 | ||
| 10 | watchdog { | 14 | watchdog { |
| 11 | compatible = "brcm,bcm2835-pm-wdt"; | 15 | compatible = "brcm,bcm2835-pm-wdt"; |
| 12 | reg = <0x7e100000 0x28>; | 16 | reg = <0x7e100000 0x28>; |
| 17 | timeout-sec = <10>; | ||
| 13 | }; | 18 | }; |
diff --git a/Documentation/watchdog/watchdog-parameters.txt b/Documentation/watchdog/watchdog-parameters.txt index 04fddbacdbde..f9492fed4104 100644 --- a/Documentation/watchdog/watchdog-parameters.txt +++ b/Documentation/watchdog/watchdog-parameters.txt | |||
| @@ -194,14 +194,6 @@ reset: Watchdog Interrupt/Reset Mode. 0 = interrupt, 1 = reset | |||
| 194 | nowayout: Watchdog cannot be stopped once started | 194 | nowayout: Watchdog cannot be stopped once started |
| 195 | (default=kernel config parameter) | 195 | (default=kernel config parameter) |
| 196 | ------------------------------------------------- | 196 | ------------------------------------------------- |
| 197 | mpcore_wdt: | ||
| 198 | mpcore_margin: MPcore timer margin in seconds. | ||
| 199 | (0 < mpcore_margin < 65536, default=60) | ||
| 200 | nowayout: Watchdog cannot be stopped once started | ||
| 201 | (default=kernel config parameter) | ||
| 202 | mpcore_noboot: MPcore watchdog action, set to 1 to ignore reboots, | ||
| 203 | 0 to reboot (default=0 | ||
| 204 | ------------------------------------------------- | ||
| 205 | mv64x60_wdt: | 197 | mv64x60_wdt: |
| 206 | nowayout: Watchdog cannot be stopped once started | 198 | nowayout: Watchdog cannot be stopped once started |
| 207 | (default=kernel config parameter) | 199 | (default=kernel config parameter) |
diff --git a/MAINTAINERS b/MAINTAINERS index 705681e5a6bb..4d43db629689 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -5387,6 +5387,12 @@ F: drivers/mtd/ | |||
| 5387 | F: include/linux/mtd/ | 5387 | F: include/linux/mtd/ |
| 5388 | F: include/uapi/mtd/ | 5388 | F: include/uapi/mtd/ |
| 5389 | 5389 | ||
| 5390 | MEN A21 WATCHDOG DRIVER | ||
| 5391 | M: Johannes Thumshirn <johannes.thumshirn@men.de> | ||
| 5392 | L: linux-watchdog@vger.kernel.org | ||
| 5393 | S: Supported | ||
| 5394 | F: drivers/watchdog/mena21_wdt.c | ||
| 5395 | |||
| 5390 | METAG ARCHITECTURE | 5396 | METAG ARCHITECTURE |
| 5391 | M: James Hogan <james.hogan@imgtec.com> | 5397 | M: James Hogan <james.hogan@imgtec.com> |
| 5392 | S: Supported | 5398 | S: Supported |
diff --git a/arch/arm/configs/spear13xx_defconfig b/arch/arm/configs/spear13xx_defconfig index 1fdb82694ca2..82eaa552ed14 100644 --- a/arch/arm/configs/spear13xx_defconfig +++ b/arch/arm/configs/spear13xx_defconfig | |||
| @@ -61,7 +61,6 @@ CONFIG_GPIO_SYSFS=y | |||
| 61 | CONFIG_GPIO_PL061=y | 61 | CONFIG_GPIO_PL061=y |
| 62 | # CONFIG_HWMON is not set | 62 | # CONFIG_HWMON is not set |
| 63 | CONFIG_WATCHDOG=y | 63 | CONFIG_WATCHDOG=y |
| 64 | CONFIG_MPCORE_WATCHDOG=y | ||
| 65 | # CONFIG_HID_SUPPORT is not set | 64 | # CONFIG_HID_SUPPORT is not set |
| 66 | CONFIG_USB=y | 65 | CONFIG_USB=y |
| 67 | # CONFIG_USB_DEVICE_CLASS is not set | 66 | # CONFIG_USB_DEVICE_CLASS is not set |
diff --git a/arch/arm/mach-dove/include/mach/bridge-regs.h b/arch/arm/mach-dove/include/mach/bridge-regs.h index 99f259e8cf33..5362df3df89f 100644 --- a/arch/arm/mach-dove/include/mach/bridge-regs.h +++ b/arch/arm/mach-dove/include/mach/bridge-regs.h | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) | 26 | #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) |
| 27 | #define SOFT_RESET 0x00000001 | 27 | #define SOFT_RESET 0x00000001 |
| 28 | 28 | ||
| 29 | #define BRIDGE_CAUSE (BRIDGE_VIRT_BASE + 0x0110) | ||
| 29 | #define BRIDGE_INT_TIMER1_CLR (~0x0004) | 30 | #define BRIDGE_INT_TIMER1_CLR (~0x0004) |
| 30 | 31 | ||
| 31 | #define IRQ_VIRT_BASE (BRIDGE_VIRT_BASE + 0x0200) | 32 | #define IRQ_VIRT_BASE (BRIDGE_VIRT_BASE + 0x0200) |
diff --git a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h index d4cbe5e81bb4..91242c944d7a 100644 --- a/arch/arm/mach-kirkwood/include/mach/bridge-regs.h +++ b/arch/arm/mach-kirkwood/include/mach/bridge-regs.h | |||
| @@ -21,14 +21,12 @@ | |||
| 21 | #define CPU_RESET 0x00000002 | 21 | #define CPU_RESET 0x00000002 |
| 22 | 22 | ||
| 23 | #define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) | 23 | #define RSTOUTn_MASK (BRIDGE_VIRT_BASE + 0x0108) |
| 24 | #define WDT_RESET_OUT_EN 0x00000002 | ||
| 25 | #define SOFT_RESET_OUT_EN 0x00000004 | 24 | #define SOFT_RESET_OUT_EN 0x00000004 |
| 26 | 25 | ||
| 27 | #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) | 26 | #define SYSTEM_SOFT_RESET (BRIDGE_VIRT_BASE + 0x010c) |
| 28 | #define SOFT_RESET 0x00000001 | 27 | #define SOFT_RESET 0x00000001 |
| 29 | 28 | ||
| 30 | #define BRIDGE_CAUSE (BRIDGE_VIRT_BASE + 0x0110) | 29 | #define BRIDGE_CAUSE (BRIDGE_VIRT_BASE + 0x0110) |
| 31 | #define WDT_INT_REQ 0x0008 | ||
| 32 | 30 | ||
| 33 | #define BRIDGE_INT_TIMER1_CLR (~0x0004) | 31 | #define BRIDGE_INT_TIMER1_CLR (~0x0004) |
| 34 | 32 | ||
diff --git a/arch/arm/mach-orion5x/include/mach/bridge-regs.h b/arch/arm/mach-orion5x/include/mach/bridge-regs.h index 461fd69a10ae..f727d03f1688 100644 --- a/arch/arm/mach-orion5x/include/mach/bridge-regs.h +++ b/arch/arm/mach-orion5x/include/mach/bridge-regs.h | |||
| @@ -18,7 +18,6 @@ | |||
| 18 | #define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104) | 18 | #define CPU_CTRL (ORION5X_BRIDGE_VIRT_BASE + 0x104) |
| 19 | 19 | ||
| 20 | #define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE + 0x108) | 20 | #define RSTOUTn_MASK (ORION5X_BRIDGE_VIRT_BASE + 0x108) |
| 21 | #define WDT_RESET_OUT_EN 0x0002 | ||
| 22 | 21 | ||
| 23 | #define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE + 0x10c) | 22 | #define CPU_SOFT_RESET (ORION5X_BRIDGE_VIRT_BASE + 0x10c) |
| 24 | 23 | ||
| @@ -26,8 +25,6 @@ | |||
| 26 | 25 | ||
| 27 | #define POWER_MNG_CTRL_REG (ORION5X_BRIDGE_VIRT_BASE + 0x11C) | 26 | #define POWER_MNG_CTRL_REG (ORION5X_BRIDGE_VIRT_BASE + 0x11C) |
| 28 | 27 | ||
| 29 | #define WDT_INT_REQ 0x0008 | ||
| 30 | |||
| 31 | #define BRIDGE_INT_TIMER1_CLR (~0x0004) | 28 | #define BRIDGE_INT_TIMER1_CLR (~0x0004) |
| 32 | 29 | ||
| 33 | #define MAIN_IRQ_CAUSE (ORION5X_BRIDGE_VIRT_BASE + 0x200) | 30 | #define MAIN_IRQ_CAUSE (ORION5X_BRIDGE_VIRT_BASE + 0x200) |
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 7460d349df59..8519bc696a6f 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
| @@ -221,15 +221,6 @@ config DW_WATCHDOG | |||
| 221 | To compile this driver as a module, choose M here: the | 221 | To compile this driver as a module, choose M here: the |
| 222 | module will be called dw_wdt. | 222 | module will be called dw_wdt. |
| 223 | 223 | ||
| 224 | config MPCORE_WATCHDOG | ||
| 225 | tristate "MPcore watchdog" | ||
| 226 | depends on HAVE_ARM_TWD | ||
| 227 | help | ||
| 228 | Watchdog timer embedded into the MPcore system. | ||
| 229 | |||
| 230 | To compile this driver as a module, choose M here: the | ||
| 231 | module will be called mpcore_wdt. | ||
| 232 | |||
| 233 | config EP93XX_WATCHDOG | 224 | config EP93XX_WATCHDOG |
| 234 | tristate "EP93xx Watchdog" | 225 | tristate "EP93xx Watchdog" |
| 235 | depends on ARCH_EP93XX | 226 | depends on ARCH_EP93XX |
| @@ -291,7 +282,7 @@ config DAVINCI_WATCHDOG | |||
| 291 | 282 | ||
| 292 | config ORION_WATCHDOG | 283 | config ORION_WATCHDOG |
| 293 | tristate "Orion watchdog" | 284 | tristate "Orion watchdog" |
| 294 | depends on ARCH_ORION5X || ARCH_KIRKWOOD | 285 | depends on ARCH_ORION5X || ARCH_KIRKWOOD || ARCH_DOVE |
| 295 | select WATCHDOG_CORE | 286 | select WATCHDOG_CORE |
| 296 | help | 287 | help |
| 297 | Say Y here if to include support for the watchdog timer | 288 | Say Y here if to include support for the watchdog timer |
| @@ -1109,6 +1100,17 @@ config BCM63XX_WDT | |||
| 1109 | To compile this driver as a loadable module, choose M here. | 1100 | To compile this driver as a loadable module, choose M here. |
| 1110 | The module will be called bcm63xx_wdt. | 1101 | The module will be called bcm63xx_wdt. |
| 1111 | 1102 | ||
| 1103 | config BCM2835_WDT | ||
| 1104 | tristate "Broadcom BCM2835 hardware watchdog" | ||
| 1105 | depends on ARCH_BCM2835 | ||
| 1106 | select WATCHDOG_CORE | ||
| 1107 | help | ||
| 1108 | Watchdog driver for the built in watchdog hardware in Broadcom | ||
| 1109 | BCM2835 SoC. | ||
| 1110 | |||
| 1111 | To compile this driver as a loadable module, choose M here. | ||
| 1112 | The module will be called bcm2835_wdt. | ||
| 1113 | |||
| 1112 | config LANTIQ_WDT | 1114 | config LANTIQ_WDT |
| 1113 | tristate "Lantiq SoC watchdog" | 1115 | tristate "Lantiq SoC watchdog" |
| 1114 | depends on LANTIQ | 1116 | depends on LANTIQ |
| @@ -1183,6 +1185,18 @@ config BOOKE_WDT_DEFAULT_TIMEOUT | |||
| 1183 | 1185 | ||
| 1184 | The value can be overridden by the wdt_period command-line parameter. | 1186 | The value can be overridden by the wdt_period command-line parameter. |
| 1185 | 1187 | ||
| 1188 | config MEN_A21_WDT | ||
| 1189 | tristate "MEN A21 VME CPU Carrier Board Watchdog Timer" | ||
| 1190 | select WATCHDOG_CORE | ||
| 1191 | depends on GPIOLIB | ||
| 1192 | help | ||
| 1193 | Watchdog driver for MEN A21 VMEbus CPU Carrier Boards. | ||
| 1194 | |||
| 1195 | The driver can also be built as a module. If so, the module will be | ||
| 1196 | called mena21_wdt. | ||
| 1197 | |||
| 1198 | If unsure select N here. | ||
| 1199 | |||
| 1186 | # PPC64 Architecture | 1200 | # PPC64 Architecture |
| 1187 | 1201 | ||
| 1188 | config WATCHDOG_RTAS | 1202 | config WATCHDOG_RTAS |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index ec268995b261..2f26a0b47ddc 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
| @@ -41,7 +41,6 @@ obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o | |||
| 41 | obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o | 41 | obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o |
| 42 | obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o | 42 | obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o |
| 43 | obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o | 43 | obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o |
| 44 | obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o | ||
| 45 | obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o | 44 | obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o |
| 46 | obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o | 45 | obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o |
| 47 | obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o | 46 | obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o |
| @@ -54,6 +53,7 @@ obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o | |||
| 54 | obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o | 53 | obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o |
| 55 | obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o | 54 | obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o |
| 56 | obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o | 55 | obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o |
| 56 | obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o | ||
| 57 | 57 | ||
| 58 | # AVR32 Architecture | 58 | # AVR32 Architecture |
| 59 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o | 59 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o |
| @@ -144,6 +144,7 @@ obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o | |||
| 144 | obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o | 144 | obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o |
| 145 | obj-$(CONFIG_PIKA_WDT) += pika_wdt.o | 145 | obj-$(CONFIG_PIKA_WDT) += pika_wdt.o |
| 146 | obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o | 146 | obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o |
| 147 | obj-$(CONFIG_MEN_A21_WDT) += mena21_wdt.o | ||
| 147 | 148 | ||
| 148 | # PPC64 Architecture | 149 | # PPC64 Architecture |
| 149 | obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o | 150 | obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o |
diff --git a/drivers/watchdog/at32ap700x_wdt.c b/drivers/watchdog/at32ap700x_wdt.c index 7a715e3e6828..b178e717ef09 100644 --- a/drivers/watchdog/at32ap700x_wdt.c +++ b/drivers/watchdog/at32ap700x_wdt.c | |||
| @@ -321,13 +321,14 @@ static int __init at32_wdt_probe(struct platform_device *pdev) | |||
| 321 | return -ENXIO; | 321 | return -ENXIO; |
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | wdt = kzalloc(sizeof(struct wdt_at32ap700x), GFP_KERNEL); | 324 | wdt = devm_kzalloc(&pdev->dev, sizeof(struct wdt_at32ap700x), |
| 325 | GFP_KERNEL); | ||
| 325 | if (!wdt) { | 326 | if (!wdt) { |
| 326 | dev_dbg(&pdev->dev, "no memory for wdt structure\n"); | 327 | dev_dbg(&pdev->dev, "no memory for wdt structure\n"); |
| 327 | return -ENOMEM; | 328 | return -ENOMEM; |
| 328 | } | 329 | } |
| 329 | 330 | ||
| 330 | wdt->regs = ioremap(regs->start, resource_size(regs)); | 331 | wdt->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs)); |
| 331 | if (!wdt->regs) { | 332 | if (!wdt->regs) { |
| 332 | ret = -ENOMEM; | 333 | ret = -ENOMEM; |
| 333 | dev_dbg(&pdev->dev, "could not map I/O memory\n"); | 334 | dev_dbg(&pdev->dev, "could not map I/O memory\n"); |
| @@ -342,7 +343,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev) | |||
| 342 | dev_info(&pdev->dev, "CPU must be reset with external " | 343 | dev_info(&pdev->dev, "CPU must be reset with external " |
| 343 | "reset or POR due to silicon errata.\n"); | 344 | "reset or POR due to silicon errata.\n"); |
| 344 | ret = -EIO; | 345 | ret = -EIO; |
| 345 | goto err_iounmap; | 346 | goto err_free; |
| 346 | } else { | 347 | } else { |
| 347 | wdt->users = 0; | 348 | wdt->users = 0; |
| 348 | } | 349 | } |
| @@ -364,7 +365,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev) | |||
| 364 | ret = misc_register(&wdt->miscdev); | 365 | ret = misc_register(&wdt->miscdev); |
| 365 | if (ret) { | 366 | if (ret) { |
| 366 | dev_dbg(&pdev->dev, "failed to register wdt miscdev\n"); | 367 | dev_dbg(&pdev->dev, "failed to register wdt miscdev\n"); |
| 367 | goto err_register; | 368 | goto err_free; |
| 368 | } | 369 | } |
| 369 | 370 | ||
| 370 | dev_info(&pdev->dev, | 371 | dev_info(&pdev->dev, |
| @@ -373,12 +374,7 @@ static int __init at32_wdt_probe(struct platform_device *pdev) | |||
| 373 | 374 | ||
| 374 | return 0; | 375 | return 0; |
| 375 | 376 | ||
| 376 | err_register: | ||
| 377 | platform_set_drvdata(pdev, NULL); | ||
| 378 | err_iounmap: | ||
| 379 | iounmap(wdt->regs); | ||
| 380 | err_free: | 377 | err_free: |
| 381 | kfree(wdt); | ||
| 382 | wdt = NULL; | 378 | wdt = NULL; |
| 383 | return ret; | 379 | return ret; |
| 384 | } | 380 | } |
| @@ -391,10 +387,7 @@ static int __exit at32_wdt_remove(struct platform_device *pdev) | |||
| 391 | at32_wdt_stop(); | 387 | at32_wdt_stop(); |
| 392 | 388 | ||
| 393 | misc_deregister(&wdt->miscdev); | 389 | misc_deregister(&wdt->miscdev); |
| 394 | iounmap(wdt->regs); | ||
| 395 | kfree(wdt); | ||
| 396 | wdt = NULL; | 390 | wdt = NULL; |
| 397 | platform_set_drvdata(pdev, NULL); | ||
| 398 | } | 391 | } |
| 399 | return 0; | 392 | return 0; |
| 400 | } | 393 | } |
diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c new file mode 100644 index 000000000000..61566fc47f84 --- /dev/null +++ b/drivers/watchdog/bcm2835_wdt.c | |||
| @@ -0,0 +1,189 @@ | |||
| 1 | /* | ||
| 2 | * Watchdog driver for Broadcom BCM2835 | ||
| 3 | * | ||
| 4 | * "bcm2708_wdog" driver written by Luke Diamand that was obtained from | ||
| 5 | * branch "rpi-3.6.y" of git://github.com/raspberrypi/linux.git was used | ||
| 6 | * as a hardware reference for the Broadcom BCM2835 watchdog timer. | ||
| 7 | * | ||
| 8 | * Copyright (C) 2013 Lubomir Rintel <lkundrak@v3.sk> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify it | ||
| 11 | * under the terms of the GNU General Public License as published by the | ||
| 12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 13 | * option) any later version. | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/types.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/watchdog.h> | ||
| 20 | #include <linux/platform_device.h> | ||
| 21 | #include <linux/of_address.h> | ||
| 22 | #include <linux/miscdevice.h> | ||
| 23 | |||
| 24 | #define PM_RSTC 0x1c | ||
| 25 | #define PM_WDOG 0x24 | ||
| 26 | |||
| 27 | #define PM_PASSWORD 0x5a000000 | ||
| 28 | |||
| 29 | #define PM_WDOG_TIME_SET 0x000fffff | ||
| 30 | #define PM_RSTC_WRCFG_CLR 0xffffffcf | ||
| 31 | #define PM_RSTC_WRCFG_SET 0x00000030 | ||
| 32 | #define PM_RSTC_WRCFG_FULL_RESET 0x00000020 | ||
| 33 | #define PM_RSTC_RESET 0x00000102 | ||
| 34 | |||
| 35 | #define SECS_TO_WDOG_TICKS(x) ((x) << 16) | ||
| 36 | #define WDOG_TICKS_TO_SECS(x) ((x) >> 16) | ||
| 37 | |||
| 38 | struct bcm2835_wdt { | ||
| 39 | void __iomem *base; | ||
| 40 | spinlock_t lock; | ||
| 41 | }; | ||
| 42 | |||
| 43 | static unsigned int heartbeat; | ||
| 44 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
| 45 | |||
| 46 | static int bcm2835_wdt_start(struct watchdog_device *wdog) | ||
| 47 | { | ||
| 48 | struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog); | ||
| 49 | uint32_t cur; | ||
| 50 | unsigned long flags; | ||
| 51 | |||
| 52 | spin_lock_irqsave(&wdt->lock, flags); | ||
| 53 | |||
| 54 | writel_relaxed(PM_PASSWORD | (SECS_TO_WDOG_TICKS(wdog->timeout) & | ||
| 55 | PM_WDOG_TIME_SET), wdt->base + PM_WDOG); | ||
| 56 | cur = readl_relaxed(wdt->base + PM_RSTC); | ||
| 57 | writel_relaxed(PM_PASSWORD | (cur & PM_RSTC_WRCFG_CLR) | | ||
| 58 | PM_RSTC_WRCFG_FULL_RESET, wdt->base + PM_RSTC); | ||
| 59 | |||
| 60 | spin_unlock_irqrestore(&wdt->lock, flags); | ||
| 61 | |||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | static int bcm2835_wdt_stop(struct watchdog_device *wdog) | ||
| 66 | { | ||
| 67 | struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog); | ||
| 68 | |||
| 69 | writel_relaxed(PM_PASSWORD | PM_RSTC_RESET, wdt->base + PM_RSTC); | ||
| 70 | dev_info(wdog->dev, "Watchdog timer stopped"); | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | static int bcm2835_wdt_set_timeout(struct watchdog_device *wdog, unsigned int t) | ||
| 75 | { | ||
| 76 | wdog->timeout = t; | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog) | ||
| 81 | { | ||
| 82 | struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog); | ||
| 83 | |||
| 84 | uint32_t ret = readl_relaxed(wdt->base + PM_WDOG); | ||
| 85 | return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET); | ||
| 86 | } | ||
| 87 | |||
| 88 | static struct watchdog_ops bcm2835_wdt_ops = { | ||
| 89 | .owner = THIS_MODULE, | ||
| 90 | .start = bcm2835_wdt_start, | ||
| 91 | .stop = bcm2835_wdt_stop, | ||
| 92 | .set_timeout = bcm2835_wdt_set_timeout, | ||
| 93 | .get_timeleft = bcm2835_wdt_get_timeleft, | ||
| 94 | }; | ||
| 95 | |||
| 96 | static struct watchdog_info bcm2835_wdt_info = { | ||
| 97 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | | ||
| 98 | WDIOF_KEEPALIVEPING, | ||
| 99 | .identity = "Broadcom BCM2835 Watchdog timer", | ||
| 100 | }; | ||
| 101 | |||
| 102 | static struct watchdog_device bcm2835_wdt_wdd = { | ||
| 103 | .info = &bcm2835_wdt_info, | ||
| 104 | .ops = &bcm2835_wdt_ops, | ||
| 105 | .min_timeout = 1, | ||
| 106 | .max_timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET), | ||
| 107 | .timeout = WDOG_TICKS_TO_SECS(PM_WDOG_TIME_SET), | ||
| 108 | }; | ||
| 109 | |||
| 110 | static int bcm2835_wdt_probe(struct platform_device *pdev) | ||
| 111 | { | ||
| 112 | struct device *dev = &pdev->dev; | ||
| 113 | struct device_node *np = dev->of_node; | ||
| 114 | struct bcm2835_wdt *wdt; | ||
| 115 | int err; | ||
| 116 | |||
| 117 | wdt = devm_kzalloc(dev, sizeof(struct bcm2835_wdt), GFP_KERNEL); | ||
| 118 | if (!wdt) { | ||
| 119 | dev_err(dev, "Failed to allocate memory for watchdog device"); | ||
| 120 | return -ENOMEM; | ||
| 121 | } | ||
| 122 | platform_set_drvdata(pdev, wdt); | ||
| 123 | |||
| 124 | spin_lock_init(&wdt->lock); | ||
| 125 | |||
| 126 | wdt->base = of_iomap(np, 0); | ||
| 127 | if (!wdt->base) { | ||
| 128 | dev_err(dev, "Failed to remap watchdog regs"); | ||
| 129 | return -ENODEV; | ||
| 130 | } | ||
| 131 | |||
| 132 | watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt); | ||
| 133 | watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev); | ||
| 134 | watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout); | ||
| 135 | err = watchdog_register_device(&bcm2835_wdt_wdd); | ||
| 136 | if (err) { | ||
| 137 | dev_err(dev, "Failed to register watchdog device"); | ||
| 138 | iounmap(wdt->base); | ||
| 139 | return err; | ||
| 140 | } | ||
| 141 | |||
| 142 | dev_info(dev, "Broadcom BCM2835 watchdog timer"); | ||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | |||
| 146 | static int bcm2835_wdt_remove(struct platform_device *pdev) | ||
| 147 | { | ||
| 148 | struct bcm2835_wdt *wdt = platform_get_drvdata(pdev); | ||
| 149 | |||
| 150 | watchdog_unregister_device(&bcm2835_wdt_wdd); | ||
| 151 | iounmap(wdt->base); | ||
| 152 | |||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static void bcm2835_wdt_shutdown(struct platform_device *pdev) | ||
| 157 | { | ||
| 158 | bcm2835_wdt_stop(&bcm2835_wdt_wdd); | ||
| 159 | } | ||
| 160 | |||
| 161 | static const struct of_device_id bcm2835_wdt_of_match[] = { | ||
| 162 | { .compatible = "brcm,bcm2835-pm-wdt", }, | ||
| 163 | {}, | ||
| 164 | }; | ||
| 165 | MODULE_DEVICE_TABLE(of, bcm2835_wdt_of_match); | ||
| 166 | |||
| 167 | static struct platform_driver bcm2835_wdt_driver = { | ||
| 168 | .probe = bcm2835_wdt_probe, | ||
| 169 | .remove = bcm2835_wdt_remove, | ||
| 170 | .shutdown = bcm2835_wdt_shutdown, | ||
| 171 | .driver = { | ||
| 172 | .name = "bcm2835-wdt", | ||
| 173 | .owner = THIS_MODULE, | ||
| 174 | .of_match_table = bcm2835_wdt_of_match, | ||
| 175 | }, | ||
| 176 | }; | ||
| 177 | module_platform_driver(bcm2835_wdt_driver); | ||
| 178 | |||
| 179 | module_param(heartbeat, uint, 0); | ||
| 180 | MODULE_PARM_DESC(heartbeat, "Initial watchdog heartbeat in seconds"); | ||
| 181 | |||
| 182 | module_param(nowayout, bool, 0); | ||
| 183 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | ||
| 184 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 185 | |||
| 186 | MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); | ||
| 187 | MODULE_DESCRIPTION("Driver for Broadcom BCM2835 watchdog timer"); | ||
| 188 | MODULE_LICENSE("GPL"); | ||
| 189 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/watchdog/bcm63xx_wdt.c b/drivers/watchdog/bcm63xx_wdt.c index b2b80d4ac818..a14a58d9d110 100644 --- a/drivers/watchdog/bcm63xx_wdt.c +++ b/drivers/watchdog/bcm63xx_wdt.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
| 17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
| 18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
| 19 | #include <linux/io.h> | ||
| 19 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 20 | #include <linux/miscdevice.h> | 21 | #include <linux/miscdevice.h> |
| 21 | #include <linux/module.h> | 22 | #include <linux/module.h> |
| @@ -249,7 +250,8 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev) | |||
| 249 | return -ENODEV; | 250 | return -ENODEV; |
| 250 | } | 251 | } |
| 251 | 252 | ||
| 252 | bcm63xx_wdt_device.regs = ioremap_nocache(r->start, resource_size(r)); | 253 | bcm63xx_wdt_device.regs = devm_ioremap_nocache(&pdev->dev, r->start, |
| 254 | resource_size(r)); | ||
| 253 | if (!bcm63xx_wdt_device.regs) { | 255 | if (!bcm63xx_wdt_device.regs) { |
| 254 | dev_err(&pdev->dev, "failed to remap I/O resources\n"); | 256 | dev_err(&pdev->dev, "failed to remap I/O resources\n"); |
| 255 | return -ENXIO; | 257 | return -ENXIO; |
| @@ -258,7 +260,7 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev) | |||
| 258 | ret = bcm63xx_timer_register(TIMER_WDT_ID, bcm63xx_wdt_isr, NULL); | 260 | ret = bcm63xx_timer_register(TIMER_WDT_ID, bcm63xx_wdt_isr, NULL); |
| 259 | if (ret < 0) { | 261 | if (ret < 0) { |
| 260 | dev_err(&pdev->dev, "failed to register wdt timer isr\n"); | 262 | dev_err(&pdev->dev, "failed to register wdt timer isr\n"); |
| 261 | goto unmap; | 263 | return ret; |
| 262 | } | 264 | } |
| 263 | 265 | ||
| 264 | if (bcm63xx_wdt_settimeout(wdt_time)) { | 266 | if (bcm63xx_wdt_settimeout(wdt_time)) { |
| @@ -281,8 +283,6 @@ static int bcm63xx_wdt_probe(struct platform_device *pdev) | |||
| 281 | 283 | ||
| 282 | unregister_timer: | 284 | unregister_timer: |
| 283 | bcm63xx_timer_unregister(TIMER_WDT_ID); | 285 | bcm63xx_timer_unregister(TIMER_WDT_ID); |
| 284 | unmap: | ||
| 285 | iounmap(bcm63xx_wdt_device.regs); | ||
| 286 | return ret; | 286 | return ret; |
| 287 | } | 287 | } |
| 288 | 288 | ||
| @@ -293,7 +293,6 @@ static int bcm63xx_wdt_remove(struct platform_device *pdev) | |||
| 293 | 293 | ||
| 294 | misc_deregister(&bcm63xx_wdt_miscdev); | 294 | misc_deregister(&bcm63xx_wdt_miscdev); |
| 295 | bcm63xx_timer_unregister(TIMER_WDT_ID); | 295 | bcm63xx_timer_unregister(TIMER_WDT_ID); |
| 296 | iounmap(bcm63xx_wdt_device.regs); | ||
| 297 | return 0; | 296 | return 0; |
| 298 | } | 297 | } |
| 299 | 298 | ||
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index 70387582843f..213225edd059 100644 --- a/drivers/watchdog/cpwd.c +++ b/drivers/watchdog/cpwd.c | |||
| @@ -621,7 +621,7 @@ static int cpwd_probe(struct platform_device *op) | |||
| 621 | WD_BADMODEL); | 621 | WD_BADMODEL); |
| 622 | } | 622 | } |
| 623 | 623 | ||
| 624 | dev_set_drvdata(&op->dev, p); | 624 | platform_set_drvdata(op, p); |
| 625 | cpwd_device = p; | 625 | cpwd_device = p; |
| 626 | err = 0; | 626 | err = 0; |
| 627 | 627 | ||
| @@ -642,7 +642,7 @@ out_free: | |||
| 642 | 642 | ||
| 643 | static int cpwd_remove(struct platform_device *op) | 643 | static int cpwd_remove(struct platform_device *op) |
| 644 | { | 644 | { |
| 645 | struct cpwd *p = dev_get_drvdata(&op->dev); | 645 | struct cpwd *p = platform_get_drvdata(op); |
| 646 | int i; | 646 | int i; |
| 647 | 647 | ||
| 648 | for (i = 0; i < WD_NUMDEVS; i++) { | 648 | for (i = 0; i < WD_NUMDEVS; i++) { |
diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c index 367445009c64..f09c54e9686f 100644 --- a/drivers/watchdog/da9052_wdt.c +++ b/drivers/watchdog/da9052_wdt.c | |||
| @@ -215,14 +215,14 @@ static int da9052_wdt_probe(struct platform_device *pdev) | |||
| 215 | goto err; | 215 | goto err; |
| 216 | } | 216 | } |
| 217 | 217 | ||
| 218 | dev_set_drvdata(&pdev->dev, driver_data); | 218 | platform_set_drvdata(pdev, driver_data); |
| 219 | err: | 219 | err: |
| 220 | return ret; | 220 | return ret; |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | static int da9052_wdt_remove(struct platform_device *pdev) | 223 | static int da9052_wdt_remove(struct platform_device *pdev) |
| 224 | { | 224 | { |
| 225 | struct da9052_wdt_data *driver_data = dev_get_drvdata(&pdev->dev); | 225 | struct da9052_wdt_data *driver_data = platform_get_drvdata(pdev); |
| 226 | 226 | ||
| 227 | watchdog_unregister_device(&driver_data->wdt); | 227 | watchdog_unregister_device(&driver_data->wdt); |
| 228 | kref_put(&driver_data->kref, da9052_wdt_release_resources); | 228 | kref_put(&driver_data->kref, da9052_wdt_release_resources); |
diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c index f5ad10546fc9..575f37a965a4 100644 --- a/drivers/watchdog/da9055_wdt.c +++ b/drivers/watchdog/da9055_wdt.c | |||
| @@ -174,7 +174,7 @@ static int da9055_wdt_probe(struct platform_device *pdev) | |||
| 174 | goto err; | 174 | goto err; |
| 175 | } | 175 | } |
| 176 | 176 | ||
| 177 | dev_set_drvdata(&pdev->dev, driver_data); | 177 | platform_set_drvdata(pdev, driver_data); |
| 178 | 178 | ||
| 179 | ret = watchdog_register_device(&driver_data->wdt); | 179 | ret = watchdog_register_device(&driver_data->wdt); |
| 180 | if (ret != 0) | 180 | if (ret != 0) |
| @@ -187,7 +187,7 @@ err: | |||
| 187 | 187 | ||
| 188 | static int da9055_wdt_remove(struct platform_device *pdev) | 188 | static int da9055_wdt_remove(struct platform_device *pdev) |
| 189 | { | 189 | { |
| 190 | struct da9055_wdt_data *driver_data = dev_get_drvdata(&pdev->dev); | 190 | struct da9055_wdt_data *driver_data = platform_get_drvdata(pdev); |
| 191 | 191 | ||
| 192 | watchdog_unregister_device(&driver_data->wdt); | 192 | watchdog_unregister_device(&driver_data->wdt); |
| 193 | kref_put(&driver_data->kref, da9055_wdt_release_resources); | 193 | kref_put(&driver_data->kref, da9055_wdt_release_resources); |
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 203766989382..e621098bf663 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c | |||
| @@ -154,8 +154,8 @@ static int dw_wdt_open(struct inode *inode, struct file *filp) | |||
| 154 | return nonseekable_open(inode, filp); | 154 | return nonseekable_open(inode, filp); |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | ssize_t dw_wdt_write(struct file *filp, const char __user *buf, size_t len, | 157 | static ssize_t dw_wdt_write(struct file *filp, const char __user *buf, |
| 158 | loff_t *offset) | 158 | size_t len, loff_t *offset) |
| 159 | { | 159 | { |
| 160 | if (!len) | 160 | if (!len) |
| 161 | return 0; | 161 | return 0; |
| @@ -305,13 +305,13 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) | |||
| 305 | if (IS_ERR(dw_wdt.regs)) | 305 | if (IS_ERR(dw_wdt.regs)) |
| 306 | return PTR_ERR(dw_wdt.regs); | 306 | return PTR_ERR(dw_wdt.regs); |
| 307 | 307 | ||
| 308 | dw_wdt.clk = clk_get(&pdev->dev, NULL); | 308 | dw_wdt.clk = devm_clk_get(&pdev->dev, NULL); |
| 309 | if (IS_ERR(dw_wdt.clk)) | 309 | if (IS_ERR(dw_wdt.clk)) |
| 310 | return PTR_ERR(dw_wdt.clk); | 310 | return PTR_ERR(dw_wdt.clk); |
| 311 | 311 | ||
| 312 | ret = clk_enable(dw_wdt.clk); | 312 | ret = clk_enable(dw_wdt.clk); |
| 313 | if (ret) | 313 | if (ret) |
| 314 | goto out_put_clk; | 314 | return ret; |
| 315 | 315 | ||
| 316 | spin_lock_init(&dw_wdt.lock); | 316 | spin_lock_init(&dw_wdt.lock); |
| 317 | 317 | ||
| @@ -327,8 +327,6 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) | |||
| 327 | 327 | ||
| 328 | out_disable_clk: | 328 | out_disable_clk: |
| 329 | clk_disable(dw_wdt.clk); | 329 | clk_disable(dw_wdt.clk); |
| 330 | out_put_clk: | ||
| 331 | clk_put(dw_wdt.clk); | ||
| 332 | 330 | ||
| 333 | return ret; | 331 | return ret; |
| 334 | } | 332 | } |
| @@ -338,7 +336,6 @@ static int dw_wdt_drv_remove(struct platform_device *pdev) | |||
| 338 | misc_deregister(&dw_wdt_miscdev); | 336 | misc_deregister(&dw_wdt_miscdev); |
| 339 | 337 | ||
| 340 | clk_disable(dw_wdt.clk); | 338 | clk_disable(dw_wdt.clk); |
| 341 | clk_put(dw_wdt.clk); | ||
| 342 | 339 | ||
| 343 | return 0; | 340 | return 0; |
| 344 | } | 341 | } |
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 11796b9b864e..de7e4f497222 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
| @@ -39,7 +39,7 @@ | |||
| 39 | #endif /* CONFIG_HPWDT_NMI_DECODING */ | 39 | #endif /* CONFIG_HPWDT_NMI_DECODING */ |
| 40 | #include <asm/nmi.h> | 40 | #include <asm/nmi.h> |
| 41 | 41 | ||
| 42 | #define HPWDT_VERSION "1.3.1" | 42 | #define HPWDT_VERSION "1.3.2" |
| 43 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) | 43 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) |
| 44 | #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) | 44 | #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) |
| 45 | #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) | 45 | #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) |
| @@ -148,6 +148,7 @@ struct cmn_registers { | |||
| 148 | static unsigned int hpwdt_nmi_decoding; | 148 | static unsigned int hpwdt_nmi_decoding; |
| 149 | static unsigned int allow_kdump = 1; | 149 | static unsigned int allow_kdump = 1; |
| 150 | static unsigned int is_icru; | 150 | static unsigned int is_icru; |
| 151 | static unsigned int is_uefi; | ||
| 151 | static DEFINE_SPINLOCK(rom_lock); | 152 | static DEFINE_SPINLOCK(rom_lock); |
| 152 | static void *cru_rom_addr; | 153 | static void *cru_rom_addr; |
| 153 | static struct cmn_registers cmn_regs; | 154 | static struct cmn_registers cmn_regs; |
| @@ -484,7 +485,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) | |||
| 484 | goto out; | 485 | goto out; |
| 485 | 486 | ||
| 486 | spin_lock_irqsave(&rom_lock, rom_pl); | 487 | spin_lock_irqsave(&rom_lock, rom_pl); |
| 487 | if (!die_nmi_called && !is_icru) | 488 | if (!die_nmi_called && !is_icru && !is_uefi) |
| 488 | asminline_call(&cmn_regs, cru_rom_addr); | 489 | asminline_call(&cmn_regs, cru_rom_addr); |
| 489 | die_nmi_called = 1; | 490 | die_nmi_called = 1; |
| 490 | spin_unlock_irqrestore(&rom_lock, rom_pl); | 491 | spin_unlock_irqrestore(&rom_lock, rom_pl); |
| @@ -492,7 +493,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) | |||
| 492 | if (allow_kdump) | 493 | if (allow_kdump) |
| 493 | hpwdt_stop(); | 494 | hpwdt_stop(); |
| 494 | 495 | ||
| 495 | if (!is_icru) { | 496 | if (!is_icru && !is_uefi) { |
| 496 | if (cmn_regs.u1.ral == 0) { | 497 | if (cmn_regs.u1.ral == 0) { |
| 497 | panic("An NMI occurred, " | 498 | panic("An NMI occurred, " |
| 498 | "but unable to determine source.\n"); | 499 | "but unable to determine source.\n"); |
| @@ -679,6 +680,8 @@ static void dmi_find_icru(const struct dmi_header *dm, void *dummy) | |||
| 679 | smbios_proliant_ptr = (struct smbios_proliant_info *) dm; | 680 | smbios_proliant_ptr = (struct smbios_proliant_info *) dm; |
| 680 | if (smbios_proliant_ptr->misc_features & 0x01) | 681 | if (smbios_proliant_ptr->misc_features & 0x01) |
| 681 | is_icru = 1; | 682 | is_icru = 1; |
| 683 | if (smbios_proliant_ptr->misc_features & 0x408) | ||
| 684 | is_uefi = 1; | ||
| 682 | } | 685 | } |
| 683 | } | 686 | } |
| 684 | 687 | ||
| @@ -697,7 +700,7 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev) | |||
| 697 | * the old cru detect code. | 700 | * the old cru detect code. |
| 698 | */ | 701 | */ |
| 699 | dmi_walk(dmi_find_icru, NULL); | 702 | dmi_walk(dmi_find_icru, NULL); |
| 700 | if (!is_icru) { | 703 | if (!is_icru && !is_uefi) { |
| 701 | 704 | ||
| 702 | /* | 705 | /* |
| 703 | * We need to map the ROM to get the CRU service. | 706 | * We need to map the ROM to get the CRU service. |
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 62946c2cb4f8..693ac3f4de5a 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c | |||
| @@ -261,7 +261,7 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) | |||
| 261 | if (IS_ERR(imx2_wdt.base)) | 261 | if (IS_ERR(imx2_wdt.base)) |
| 262 | return PTR_ERR(imx2_wdt.base); | 262 | return PTR_ERR(imx2_wdt.base); |
| 263 | 263 | ||
| 264 | imx2_wdt.clk = clk_get(&pdev->dev, NULL); | 264 | imx2_wdt.clk = devm_clk_get(&pdev->dev, NULL); |
| 265 | if (IS_ERR(imx2_wdt.clk)) { | 265 | if (IS_ERR(imx2_wdt.clk)) { |
| 266 | dev_err(&pdev->dev, "can't get Watchdog clock\n"); | 266 | dev_err(&pdev->dev, "can't get Watchdog clock\n"); |
| 267 | return PTR_ERR(imx2_wdt.clk); | 267 | return PTR_ERR(imx2_wdt.clk); |
| @@ -286,7 +286,6 @@ static int __init imx2_wdt_probe(struct platform_device *pdev) | |||
| 286 | 286 | ||
| 287 | fail: | 287 | fail: |
| 288 | imx2_wdt_miscdev.parent = NULL; | 288 | imx2_wdt_miscdev.parent = NULL; |
| 289 | clk_put(imx2_wdt.clk); | ||
| 290 | return ret; | 289 | return ret; |
| 291 | } | 290 | } |
| 292 | 291 | ||
| @@ -299,8 +298,7 @@ static int __exit imx2_wdt_remove(struct platform_device *pdev) | |||
| 299 | 298 | ||
| 300 | dev_crit(imx2_wdt_miscdev.parent, | 299 | dev_crit(imx2_wdt_miscdev.parent, |
| 301 | "Device removed: Expect reboot!\n"); | 300 | "Device removed: Expect reboot!\n"); |
| 302 | } else | 301 | } |
| 303 | clk_put(imx2_wdt.clk); | ||
| 304 | 302 | ||
| 305 | imx2_wdt_miscdev.parent = NULL; | 303 | imx2_wdt_miscdev.parent = NULL; |
| 306 | return 0; | 304 | return 0; |
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c index 1cb25f69a96d..d1afdf684c18 100644 --- a/drivers/watchdog/jz4740_wdt.c +++ b/drivers/watchdog/jz4740_wdt.c | |||
| @@ -177,7 +177,7 @@ static int jz4740_wdt_probe(struct platform_device *pdev) | |||
| 177 | goto err_out; | 177 | goto err_out; |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | drvdata->rtc_clk = clk_get(NULL, "rtc"); | 180 | drvdata->rtc_clk = clk_get(&pdev->dev, "rtc"); |
| 181 | if (IS_ERR(drvdata->rtc_clk)) { | 181 | if (IS_ERR(drvdata->rtc_clk)) { |
| 182 | dev_err(&pdev->dev, "cannot find RTC clock\n"); | 182 | dev_err(&pdev->dev, "cannot find RTC clock\n"); |
| 183 | ret = PTR_ERR(drvdata->rtc_clk); | 183 | ret = PTR_ERR(drvdata->rtc_clk); |
diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c new file mode 100644 index 000000000000..96dbba980579 --- /dev/null +++ b/drivers/watchdog/mena21_wdt.c | |||
| @@ -0,0 +1,270 @@ | |||
| 1 | /* | ||
| 2 | * Watchdog driver for the A21 VME CPU Boards | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 MEN Mikro Elektronik Nuernberg GmbH | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License | ||
| 8 | * as published by the Free Software Foundation | ||
| 9 | */ | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/moduleparam.h> | ||
| 12 | #include <linux/types.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/watchdog.h> | ||
| 17 | #include <linux/uaccess.h> | ||
| 18 | #include <linux/gpio.h> | ||
| 19 | #include <linux/of_gpio.h> | ||
| 20 | #include <linux/delay.h> | ||
| 21 | #include <linux/bitops.h> | ||
| 22 | |||
| 23 | #define NUM_GPIOS 6 | ||
| 24 | |||
| 25 | enum a21_wdt_gpios { | ||
| 26 | GPIO_WD_ENAB, | ||
| 27 | GPIO_WD_FAST, | ||
| 28 | GPIO_WD_TRIG, | ||
| 29 | GPIO_WD_RST0, | ||
| 30 | GPIO_WD_RST1, | ||
| 31 | GPIO_WD_RST2, | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct a21_wdt_drv { | ||
| 35 | struct watchdog_device wdt; | ||
| 36 | struct mutex lock; | ||
| 37 | unsigned gpios[NUM_GPIOS]; | ||
| 38 | }; | ||
| 39 | |||
| 40 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
| 41 | module_param(nowayout, bool, 0); | ||
| 42 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | ||
| 43 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 44 | |||
| 45 | static unsigned int a21_wdt_get_bootstatus(struct a21_wdt_drv *drv) | ||
| 46 | { | ||
| 47 | int reset = 0; | ||
| 48 | |||
| 49 | reset |= gpio_get_value(drv->gpios[GPIO_WD_RST0]) ? (1 << 0) : 0; | ||
| 50 | reset |= gpio_get_value(drv->gpios[GPIO_WD_RST1]) ? (1 << 1) : 0; | ||
| 51 | reset |= gpio_get_value(drv->gpios[GPIO_WD_RST2]) ? (1 << 2) : 0; | ||
| 52 | |||
| 53 | return reset; | ||
| 54 | } | ||
| 55 | |||
| 56 | static int a21_wdt_start(struct watchdog_device *wdt) | ||
| 57 | { | ||
| 58 | struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); | ||
| 59 | |||
| 60 | mutex_lock(&drv->lock); | ||
| 61 | |||
| 62 | gpio_set_value(drv->gpios[GPIO_WD_ENAB], 1); | ||
| 63 | |||
| 64 | mutex_unlock(&drv->lock); | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static int a21_wdt_stop(struct watchdog_device *wdt) | ||
| 70 | { | ||
| 71 | struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); | ||
| 72 | |||
| 73 | mutex_lock(&drv->lock); | ||
| 74 | |||
| 75 | gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0); | ||
| 76 | |||
| 77 | mutex_unlock(&drv->lock); | ||
| 78 | |||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | static int a21_wdt_ping(struct watchdog_device *wdt) | ||
| 83 | { | ||
| 84 | struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); | ||
| 85 | |||
| 86 | mutex_lock(&drv->lock); | ||
| 87 | |||
| 88 | gpio_set_value(drv->gpios[GPIO_WD_TRIG], 0); | ||
| 89 | ndelay(10); | ||
| 90 | gpio_set_value(drv->gpios[GPIO_WD_TRIG], 1); | ||
| 91 | |||
| 92 | mutex_unlock(&drv->lock); | ||
| 93 | |||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | static int a21_wdt_set_timeout(struct watchdog_device *wdt, | ||
| 98 | unsigned int timeout) | ||
| 99 | { | ||
| 100 | struct a21_wdt_drv *drv = watchdog_get_drvdata(wdt); | ||
| 101 | |||
| 102 | if (timeout != 1 && timeout != 30) { | ||
| 103 | dev_err(wdt->dev, "Only 1 and 30 allowed as timeout\n"); | ||
| 104 | return -EINVAL; | ||
| 105 | } | ||
| 106 | |||
| 107 | if (timeout == 30 && wdt->timeout == 1) { | ||
| 108 | dev_err(wdt->dev, | ||
| 109 | "Transition from fast to slow mode not allowed\n"); | ||
| 110 | return -EINVAL; | ||
| 111 | } | ||
| 112 | |||
| 113 | mutex_lock(&drv->lock); | ||
| 114 | |||
| 115 | if (timeout == 1) | ||
| 116 | gpio_set_value(drv->gpios[GPIO_WD_FAST], 1); | ||
| 117 | else | ||
| 118 | gpio_set_value(drv->gpios[GPIO_WD_FAST], 0); | ||
| 119 | |||
| 120 | wdt->timeout = timeout; | ||
| 121 | |||
| 122 | mutex_unlock(&drv->lock); | ||
| 123 | |||
| 124 | return 0; | ||
| 125 | } | ||
| 126 | |||
| 127 | static const struct watchdog_info a21_wdt_info = { | ||
| 128 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | ||
| 129 | .identity = "MEN A21 Watchdog", | ||
| 130 | }; | ||
| 131 | |||
| 132 | static const struct watchdog_ops a21_wdt_ops = { | ||
| 133 | .owner = THIS_MODULE, | ||
| 134 | .start = a21_wdt_start, | ||
| 135 | .stop = a21_wdt_stop, | ||
| 136 | .ping = a21_wdt_ping, | ||
| 137 | .set_timeout = a21_wdt_set_timeout, | ||
| 138 | }; | ||
| 139 | |||
| 140 | static struct watchdog_device a21_wdt = { | ||
| 141 | .info = &a21_wdt_info, | ||
| 142 | .ops = &a21_wdt_ops, | ||
| 143 | .min_timeout = 1, | ||
| 144 | .max_timeout = 30, | ||
| 145 | }; | ||
| 146 | |||
| 147 | static int a21_wdt_probe(struct platform_device *pdev) | ||
| 148 | { | ||
| 149 | struct device_node *node; | ||
| 150 | struct a21_wdt_drv *drv; | ||
| 151 | unsigned int reset = 0; | ||
| 152 | int num_gpios; | ||
| 153 | int ret; | ||
| 154 | int i; | ||
| 155 | |||
| 156 | drv = devm_kzalloc(&pdev->dev, sizeof(struct a21_wdt_drv), GFP_KERNEL); | ||
| 157 | if (!drv) | ||
| 158 | return -ENOMEM; | ||
| 159 | |||
| 160 | /* Fill GPIO pin array */ | ||
| 161 | node = pdev->dev.of_node; | ||
| 162 | |||
| 163 | num_gpios = of_gpio_count(node); | ||
| 164 | if (num_gpios != NUM_GPIOS) { | ||
| 165 | dev_err(&pdev->dev, "gpios DT property wrong, got %d want %d", | ||
| 166 | num_gpios, NUM_GPIOS); | ||
| 167 | return -ENODEV; | ||
| 168 | } | ||
| 169 | |||
| 170 | for (i = 0; i < num_gpios; i++) { | ||
| 171 | int val; | ||
| 172 | |||
| 173 | val = of_get_gpio(node, i); | ||
| 174 | if (val < 0) | ||
| 175 | return val; | ||
| 176 | |||
| 177 | drv->gpios[i] = val; | ||
| 178 | } | ||
| 179 | |||
| 180 | /* Request the used GPIOs */ | ||
| 181 | for (i = 0; i < num_gpios; i++) { | ||
| 182 | ret = devm_gpio_request(&pdev->dev, drv->gpios[i], | ||
| 183 | "MEN A21 Watchdog"); | ||
| 184 | if (ret) | ||
| 185 | return ret; | ||
| 186 | |||
| 187 | if (i < GPIO_WD_RST0) | ||
| 188 | ret = gpio_direction_output(drv->gpios[i], | ||
| 189 | gpio_get_value(drv->gpios[i])); | ||
| 190 | else /* GPIO_WD_RST[0..2] are inputs */ | ||
| 191 | ret = gpio_direction_input(drv->gpios[i]); | ||
| 192 | if (ret) | ||
| 193 | return ret; | ||
| 194 | } | ||
| 195 | |||
| 196 | mutex_init(&drv->lock); | ||
| 197 | watchdog_init_timeout(&a21_wdt, 30, &pdev->dev); | ||
| 198 | watchdog_set_nowayout(&a21_wdt, nowayout); | ||
| 199 | watchdog_set_drvdata(&a21_wdt, drv); | ||
| 200 | |||
| 201 | reset = a21_wdt_get_bootstatus(drv); | ||
| 202 | if (reset == 2) | ||
| 203 | a21_wdt.bootstatus |= WDIOF_EXTERN1; | ||
| 204 | else if (reset == 4) | ||
| 205 | a21_wdt.bootstatus |= WDIOF_CARDRESET; | ||
| 206 | else if (reset == 5) | ||
| 207 | a21_wdt.bootstatus |= WDIOF_POWERUNDER; | ||
| 208 | else if (reset == 7) | ||
| 209 | a21_wdt.bootstatus |= WDIOF_EXTERN2; | ||
| 210 | |||
| 211 | ret = watchdog_register_device(&a21_wdt); | ||
| 212 | if (ret) { | ||
| 213 | dev_err(&pdev->dev, "Cannot register watchdog device\n"); | ||
| 214 | goto err_register_wd; | ||
| 215 | } | ||
| 216 | |||
| 217 | dev_set_drvdata(&pdev->dev, drv); | ||
| 218 | |||
| 219 | dev_info(&pdev->dev, "MEN A21 watchdog timer driver enabled\n"); | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | |||
| 223 | err_register_wd: | ||
| 224 | mutex_destroy(&drv->lock); | ||
| 225 | |||
| 226 | return ret; | ||
| 227 | } | ||
| 228 | |||
| 229 | static int a21_wdt_remove(struct platform_device *pdev) | ||
| 230 | { | ||
| 231 | struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev); | ||
| 232 | |||
| 233 | dev_warn(&pdev->dev, | ||
| 234 | "Unregistering A21 watchdog driver, board may reboot\n"); | ||
| 235 | |||
| 236 | watchdog_unregister_device(&drv->wdt); | ||
| 237 | |||
| 238 | mutex_destroy(&drv->lock); | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static void a21_wdt_shutdown(struct platform_device *pdev) | ||
| 244 | { | ||
| 245 | struct a21_wdt_drv *drv = dev_get_drvdata(&pdev->dev); | ||
| 246 | |||
| 247 | gpio_set_value(drv->gpios[GPIO_WD_ENAB], 0); | ||
| 248 | } | ||
| 249 | |||
| 250 | static const struct of_device_id a21_wdt_ids[] = { | ||
| 251 | { .compatible = "men,a021-wdt" }, | ||
| 252 | { }, | ||
| 253 | }; | ||
| 254 | |||
| 255 | static struct platform_driver a21_wdt_driver = { | ||
| 256 | .probe = a21_wdt_probe, | ||
| 257 | .remove = a21_wdt_remove, | ||
| 258 | .shutdown = a21_wdt_shutdown, | ||
| 259 | .driver = { | ||
| 260 | .name = "a21-watchdog", | ||
| 261 | .of_match_table = a21_wdt_ids, | ||
| 262 | }, | ||
| 263 | }; | ||
| 264 | |||
| 265 | module_platform_driver(a21_wdt_driver); | ||
| 266 | |||
| 267 | MODULE_AUTHOR("MEN Mikro Elektronik"); | ||
| 268 | MODULE_DESCRIPTION("MEN A21 Watchdog"); | ||
| 269 | MODULE_LICENSE("GPL"); | ||
| 270 | MODULE_ALIAS("platform:a21-watchdog"); | ||
diff --git a/drivers/watchdog/mpcore_wdt.c b/drivers/watchdog/mpcore_wdt.c deleted file mode 100644 index 233cfadcb21f..000000000000 --- a/drivers/watchdog/mpcore_wdt.c +++ /dev/null | |||
| @@ -1,456 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Watchdog driver for the mpcore watchdog timer | ||
| 3 | * | ||
| 4 | * (c) Copyright 2004 ARM Limited | ||
| 5 | * | ||
| 6 | * Based on the SoftDog driver: | ||
| 7 | * (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>, | ||
| 8 | * All Rights Reserved. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or | ||
| 11 | * modify it under the terms of the GNU General Public License | ||
| 12 | * as published by the Free Software Foundation; either version | ||
| 13 | * 2 of the License, or (at your option) any later version. | ||
| 14 | * | ||
| 15 | * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide | ||
| 16 | * warranty for any of this software. This material is provided | ||
| 17 | * "AS-IS" and at no charge. | ||
| 18 | * | ||
| 19 | * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 24 | |||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/moduleparam.h> | ||
| 27 | #include <linux/types.h> | ||
| 28 | #include <linux/miscdevice.h> | ||
| 29 | #include <linux/watchdog.h> | ||
| 30 | #include <linux/fs.h> | ||
| 31 | #include <linux/reboot.h> | ||
| 32 | #include <linux/init.h> | ||
| 33 | #include <linux/interrupt.h> | ||
| 34 | #include <linux/platform_device.h> | ||
| 35 | #include <linux/uaccess.h> | ||
| 36 | #include <linux/slab.h> | ||
| 37 | #include <linux/io.h> | ||
| 38 | |||
| 39 | #include <asm/smp_twd.h> | ||
| 40 | |||
| 41 | struct mpcore_wdt { | ||
| 42 | unsigned long timer_alive; | ||
| 43 | struct device *dev; | ||
| 44 | void __iomem *base; | ||
| 45 | int irq; | ||
| 46 | unsigned int perturb; | ||
| 47 | char expect_close; | ||
| 48 | }; | ||
| 49 | |||
| 50 | static struct platform_device *mpcore_wdt_pdev; | ||
| 51 | static DEFINE_SPINLOCK(wdt_lock); | ||
| 52 | |||
| 53 | #define TIMER_MARGIN 60 | ||
| 54 | static int mpcore_margin = TIMER_MARGIN; | ||
| 55 | module_param(mpcore_margin, int, 0); | ||
| 56 | MODULE_PARM_DESC(mpcore_margin, | ||
| 57 | "MPcore timer margin in seconds. (0 < mpcore_margin < 65536, default=" | ||
| 58 | __MODULE_STRING(TIMER_MARGIN) ")"); | ||
| 59 | |||
| 60 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
| 61 | module_param(nowayout, bool, 0); | ||
| 62 | MODULE_PARM_DESC(nowayout, | ||
| 63 | "Watchdog cannot be stopped once started (default=" | ||
| 64 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 65 | |||
| 66 | #define ONLY_TESTING 0 | ||
| 67 | static int mpcore_noboot = ONLY_TESTING; | ||
| 68 | module_param(mpcore_noboot, int, 0); | ||
| 69 | MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, " | ||
| 70 | "set to 1 to ignore reboots, 0 to reboot (default=" | ||
| 71 | __MODULE_STRING(ONLY_TESTING) ")"); | ||
| 72 | |||
| 73 | /* | ||
| 74 | * This is the interrupt handler. Note that we only use this | ||
| 75 | * in testing mode, so don't actually do a reboot here. | ||
| 76 | */ | ||
| 77 | static irqreturn_t mpcore_wdt_fire(int irq, void *arg) | ||
| 78 | { | ||
| 79 | struct mpcore_wdt *wdt = arg; | ||
| 80 | |||
| 81 | /* Check it really was our interrupt */ | ||
| 82 | if (readl(wdt->base + TWD_WDOG_INTSTAT)) { | ||
| 83 | dev_crit(wdt->dev, "Triggered - Reboot ignored\n"); | ||
| 84 | /* Clear the interrupt on the watchdog */ | ||
| 85 | writel(1, wdt->base + TWD_WDOG_INTSTAT); | ||
| 86 | return IRQ_HANDLED; | ||
| 87 | } | ||
| 88 | return IRQ_NONE; | ||
| 89 | } | ||
| 90 | |||
| 91 | /* | ||
| 92 | * mpcore_wdt_keepalive - reload the timer | ||
| 93 | * | ||
| 94 | * Note that the spec says a DIFFERENT value must be written to the reload | ||
| 95 | * register each time. The "perturb" variable deals with this by adding 1 | ||
| 96 | * to the count every other time the function is called. | ||
| 97 | */ | ||
| 98 | static void mpcore_wdt_keepalive(struct mpcore_wdt *wdt) | ||
| 99 | { | ||
| 100 | unsigned long count; | ||
| 101 | |||
| 102 | spin_lock(&wdt_lock); | ||
| 103 | /* Assume prescale is set to 256 */ | ||
| 104 | count = __raw_readl(wdt->base + TWD_WDOG_COUNTER); | ||
| 105 | count = (0xFFFFFFFFU - count) * (HZ / 5); | ||
| 106 | count = (count / 256) * mpcore_margin; | ||
| 107 | |||
| 108 | /* Reload the counter */ | ||
| 109 | writel(count + wdt->perturb, wdt->base + TWD_WDOG_LOAD); | ||
| 110 | wdt->perturb = wdt->perturb ? 0 : 1; | ||
| 111 | spin_unlock(&wdt_lock); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void mpcore_wdt_stop(struct mpcore_wdt *wdt) | ||
| 115 | { | ||
| 116 | spin_lock(&wdt_lock); | ||
| 117 | writel(0x12345678, wdt->base + TWD_WDOG_DISABLE); | ||
| 118 | writel(0x87654321, wdt->base + TWD_WDOG_DISABLE); | ||
| 119 | writel(0x0, wdt->base + TWD_WDOG_CONTROL); | ||
| 120 | spin_unlock(&wdt_lock); | ||
| 121 | } | ||
| 122 | |||
| 123 | static void mpcore_wdt_start(struct mpcore_wdt *wdt) | ||
| 124 | { | ||
| 125 | dev_info(wdt->dev, "enabling watchdog\n"); | ||
| 126 | |||
| 127 | /* This loads the count register but does NOT start the count yet */ | ||
| 128 | mpcore_wdt_keepalive(wdt); | ||
| 129 | |||
| 130 | if (mpcore_noboot) { | ||
| 131 | /* Enable watchdog - prescale=256, watchdog mode=0, enable=1 */ | ||
| 132 | writel(0x0000FF01, wdt->base + TWD_WDOG_CONTROL); | ||
| 133 | } else { | ||
| 134 | /* Enable watchdog - prescale=256, watchdog mode=1, enable=1 */ | ||
| 135 | writel(0x0000FF09, wdt->base + TWD_WDOG_CONTROL); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | static int mpcore_wdt_set_heartbeat(int t) | ||
| 140 | { | ||
| 141 | if (t < 0x0001 || t > 0xFFFF) | ||
| 142 | return -EINVAL; | ||
| 143 | |||
| 144 | mpcore_margin = t; | ||
| 145 | return 0; | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 149 | * /dev/watchdog handling | ||
| 150 | */ | ||
| 151 | static int mpcore_wdt_open(struct inode *inode, struct file *file) | ||
| 152 | { | ||
| 153 | struct mpcore_wdt *wdt = platform_get_drvdata(mpcore_wdt_pdev); | ||
| 154 | |||
| 155 | if (test_and_set_bit(0, &wdt->timer_alive)) | ||
| 156 | return -EBUSY; | ||
| 157 | |||
| 158 | if (nowayout) | ||
| 159 | __module_get(THIS_MODULE); | ||
| 160 | |||
| 161 | file->private_data = wdt; | ||
| 162 | |||
| 163 | /* | ||
| 164 | * Activate timer | ||
| 165 | */ | ||
| 166 | mpcore_wdt_start(wdt); | ||
| 167 | |||
| 168 | return nonseekable_open(inode, file); | ||
| 169 | } | ||
| 170 | |||
| 171 | static int mpcore_wdt_release(struct inode *inode, struct file *file) | ||
| 172 | { | ||
| 173 | struct mpcore_wdt *wdt = file->private_data; | ||
| 174 | |||
| 175 | /* | ||
| 176 | * Shut off the timer. | ||
| 177 | * Lock it in if it's a module and we set nowayout | ||
| 178 | */ | ||
| 179 | if (wdt->expect_close == 42) | ||
| 180 | mpcore_wdt_stop(wdt); | ||
| 181 | else { | ||
| 182 | dev_crit(wdt->dev, | ||
| 183 | "unexpected close, not stopping watchdog!\n"); | ||
| 184 | mpcore_wdt_keepalive(wdt); | ||
| 185 | } | ||
| 186 | clear_bit(0, &wdt->timer_alive); | ||
| 187 | wdt->expect_close = 0; | ||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static ssize_t mpcore_wdt_write(struct file *file, const char *data, | ||
| 192 | size_t len, loff_t *ppos) | ||
| 193 | { | ||
| 194 | struct mpcore_wdt *wdt = file->private_data; | ||
| 195 | |||
| 196 | /* | ||
| 197 | * Refresh the timer. | ||
| 198 | */ | ||
| 199 | if (len) { | ||
| 200 | if (!nowayout) { | ||
| 201 | size_t i; | ||
| 202 | |||
| 203 | /* In case it was set long ago */ | ||
| 204 | wdt->expect_close = 0; | ||
| 205 | |||
| 206 | for (i = 0; i != len; i++) { | ||
| 207 | char c; | ||
| 208 | |||
| 209 | if (get_user(c, data + i)) | ||
| 210 | return -EFAULT; | ||
| 211 | if (c == 'V') | ||
| 212 | wdt->expect_close = 42; | ||
| 213 | } | ||
| 214 | } | ||
| 215 | mpcore_wdt_keepalive(wdt); | ||
| 216 | } | ||
| 217 | return len; | ||
| 218 | } | ||
| 219 | |||
| 220 | static const struct watchdog_info ident = { | ||
| 221 | .options = WDIOF_SETTIMEOUT | | ||
| 222 | WDIOF_KEEPALIVEPING | | ||
| 223 | WDIOF_MAGICCLOSE, | ||
| 224 | .identity = "MPcore Watchdog", | ||
| 225 | }; | ||
| 226 | |||
| 227 | static long mpcore_wdt_ioctl(struct file *file, unsigned int cmd, | ||
| 228 | unsigned long arg) | ||
| 229 | { | ||
| 230 | struct mpcore_wdt *wdt = file->private_data; | ||
| 231 | int ret; | ||
| 232 | union { | ||
| 233 | struct watchdog_info ident; | ||
| 234 | int i; | ||
| 235 | } uarg; | ||
| 236 | |||
| 237 | if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg)) | ||
| 238 | return -ENOTTY; | ||
| 239 | |||
| 240 | if (_IOC_DIR(cmd) & _IOC_WRITE) { | ||
| 241 | ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd)); | ||
| 242 | if (ret) | ||
| 243 | return -EFAULT; | ||
| 244 | } | ||
| 245 | |||
| 246 | switch (cmd) { | ||
| 247 | case WDIOC_GETSUPPORT: | ||
| 248 | uarg.ident = ident; | ||
| 249 | ret = 0; | ||
| 250 | break; | ||
| 251 | |||
| 252 | case WDIOC_GETSTATUS: | ||
| 253 | case WDIOC_GETBOOTSTATUS: | ||
| 254 | uarg.i = 0; | ||
| 255 | ret = 0; | ||
| 256 | break; | ||
| 257 | |||
| 258 | case WDIOC_SETOPTIONS: | ||
| 259 | ret = -EINVAL; | ||
| 260 | if (uarg.i & WDIOS_DISABLECARD) { | ||
| 261 | mpcore_wdt_stop(wdt); | ||
| 262 | ret = 0; | ||
| 263 | } | ||
| 264 | if (uarg.i & WDIOS_ENABLECARD) { | ||
| 265 | mpcore_wdt_start(wdt); | ||
| 266 | ret = 0; | ||
| 267 | } | ||
| 268 | break; | ||
| 269 | |||
| 270 | case WDIOC_KEEPALIVE: | ||
| 271 | mpcore_wdt_keepalive(wdt); | ||
| 272 | ret = 0; | ||
| 273 | break; | ||
| 274 | |||
| 275 | case WDIOC_SETTIMEOUT: | ||
| 276 | ret = mpcore_wdt_set_heartbeat(uarg.i); | ||
| 277 | if (ret) | ||
| 278 | break; | ||
| 279 | |||
| 280 | mpcore_wdt_keepalive(wdt); | ||
| 281 | /* Fall */ | ||
| 282 | case WDIOC_GETTIMEOUT: | ||
| 283 | uarg.i = mpcore_margin; | ||
| 284 | ret = 0; | ||
| 285 | break; | ||
| 286 | |||
| 287 | default: | ||
| 288 | return -ENOTTY; | ||
| 289 | } | ||
| 290 | |||
| 291 | if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) { | ||
| 292 | ret = copy_to_user((void __user *)arg, &uarg, _IOC_SIZE(cmd)); | ||
| 293 | if (ret) | ||
| 294 | ret = -EFAULT; | ||
| 295 | } | ||
| 296 | return ret; | ||
| 297 | } | ||
| 298 | |||
| 299 | /* | ||
| 300 | * System shutdown handler. Turn off the watchdog if we're | ||
| 301 | * restarting or halting the system. | ||
| 302 | */ | ||
| 303 | static void mpcore_wdt_shutdown(struct platform_device *pdev) | ||
| 304 | { | ||
| 305 | struct mpcore_wdt *wdt = platform_get_drvdata(pdev); | ||
| 306 | |||
| 307 | if (system_state == SYSTEM_RESTART || system_state == SYSTEM_HALT) | ||
| 308 | mpcore_wdt_stop(wdt); | ||
| 309 | } | ||
| 310 | |||
| 311 | /* | ||
| 312 | * Kernel Interfaces | ||
| 313 | */ | ||
| 314 | static const struct file_operations mpcore_wdt_fops = { | ||
| 315 | .owner = THIS_MODULE, | ||
| 316 | .llseek = no_llseek, | ||
| 317 | .write = mpcore_wdt_write, | ||
| 318 | .unlocked_ioctl = mpcore_wdt_ioctl, | ||
| 319 | .open = mpcore_wdt_open, | ||
| 320 | .release = mpcore_wdt_release, | ||
| 321 | }; | ||
| 322 | |||
| 323 | static struct miscdevice mpcore_wdt_miscdev = { | ||
| 324 | .minor = WATCHDOG_MINOR, | ||
| 325 | .name = "watchdog", | ||
| 326 | .fops = &mpcore_wdt_fops, | ||
| 327 | }; | ||
| 328 | |||
| 329 | static int mpcore_wdt_probe(struct platform_device *pdev) | ||
| 330 | { | ||
| 331 | struct mpcore_wdt *wdt; | ||
| 332 | struct resource *res; | ||
| 333 | int ret; | ||
| 334 | |||
| 335 | /* We only accept one device, and it must have an id of -1 */ | ||
| 336 | if (pdev->id != -1) | ||
| 337 | return -ENODEV; | ||
| 338 | |||
| 339 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 340 | if (!res) | ||
| 341 | return -ENODEV; | ||
| 342 | |||
| 343 | wdt = devm_kzalloc(&pdev->dev, sizeof(struct mpcore_wdt), GFP_KERNEL); | ||
| 344 | if (!wdt) | ||
| 345 | return -ENOMEM; | ||
| 346 | |||
| 347 | wdt->dev = &pdev->dev; | ||
| 348 | wdt->irq = platform_get_irq(pdev, 0); | ||
| 349 | if (wdt->irq >= 0) { | ||
| 350 | ret = devm_request_irq(wdt->dev, wdt->irq, mpcore_wdt_fire, 0, | ||
| 351 | "mpcore_wdt", wdt); | ||
| 352 | if (ret) { | ||
| 353 | dev_err(wdt->dev, | ||
| 354 | "cannot register IRQ%d for watchdog\n", | ||
| 355 | wdt->irq); | ||
| 356 | return ret; | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | wdt->base = devm_ioremap(wdt->dev, res->start, resource_size(res)); | ||
| 361 | if (!wdt->base) | ||
| 362 | return -ENOMEM; | ||
| 363 | |||
| 364 | mpcore_wdt_miscdev.parent = &pdev->dev; | ||
| 365 | ret = misc_register(&mpcore_wdt_miscdev); | ||
| 366 | if (ret) { | ||
| 367 | dev_err(wdt->dev, | ||
| 368 | "cannot register miscdev on minor=%d (err=%d)\n", | ||
| 369 | WATCHDOG_MINOR, ret); | ||
| 370 | return ret; | ||
| 371 | } | ||
| 372 | |||
| 373 | mpcore_wdt_stop(wdt); | ||
| 374 | platform_set_drvdata(pdev, wdt); | ||
| 375 | mpcore_wdt_pdev = pdev; | ||
| 376 | |||
| 377 | return 0; | ||
| 378 | } | ||
| 379 | |||
| 380 | static int mpcore_wdt_remove(struct platform_device *pdev) | ||
| 381 | { | ||
| 382 | platform_set_drvdata(pdev, NULL); | ||
| 383 | |||
| 384 | misc_deregister(&mpcore_wdt_miscdev); | ||
| 385 | |||
| 386 | mpcore_wdt_pdev = NULL; | ||
| 387 | |||
| 388 | return 0; | ||
| 389 | } | ||
| 390 | |||
| 391 | #ifdef CONFIG_PM | ||
| 392 | static int mpcore_wdt_suspend(struct platform_device *pdev, pm_message_t msg) | ||
| 393 | { | ||
| 394 | struct mpcore_wdt *wdt = platform_get_drvdata(pdev); | ||
| 395 | mpcore_wdt_stop(wdt); /* Turn the WDT off */ | ||
| 396 | return 0; | ||
| 397 | } | ||
| 398 | |||
| 399 | static int mpcore_wdt_resume(struct platform_device *pdev) | ||
| 400 | { | ||
| 401 | struct mpcore_wdt *wdt = platform_get_drvdata(pdev); | ||
| 402 | /* re-activate timer */ | ||
| 403 | if (test_bit(0, &wdt->timer_alive)) | ||
| 404 | mpcore_wdt_start(wdt); | ||
| 405 | return 0; | ||
| 406 | } | ||
| 407 | #else | ||
| 408 | #define mpcore_wdt_suspend NULL | ||
| 409 | #define mpcore_wdt_resume NULL | ||
| 410 | #endif | ||
| 411 | |||
| 412 | /* work with hotplug and coldplug */ | ||
| 413 | MODULE_ALIAS("platform:mpcore_wdt"); | ||
| 414 | |||
| 415 | static struct platform_driver mpcore_wdt_driver = { | ||
| 416 | .probe = mpcore_wdt_probe, | ||
| 417 | .remove = mpcore_wdt_remove, | ||
| 418 | .suspend = mpcore_wdt_suspend, | ||
| 419 | .resume = mpcore_wdt_resume, | ||
| 420 | .shutdown = mpcore_wdt_shutdown, | ||
| 421 | .driver = { | ||
| 422 | .owner = THIS_MODULE, | ||
| 423 | .name = "mpcore_wdt", | ||
| 424 | }, | ||
| 425 | }; | ||
| 426 | |||
| 427 | static int __init mpcore_wdt_init(void) | ||
| 428 | { | ||
| 429 | /* | ||
| 430 | * Check that the margin value is within it's range; | ||
| 431 | * if not reset to the default | ||
| 432 | */ | ||
| 433 | if (mpcore_wdt_set_heartbeat(mpcore_margin)) { | ||
| 434 | mpcore_wdt_set_heartbeat(TIMER_MARGIN); | ||
| 435 | pr_info("mpcore_margin value must be 0 < mpcore_margin < 65536, using %d\n", | ||
| 436 | TIMER_MARGIN); | ||
| 437 | } | ||
| 438 | |||
| 439 | pr_info("MPcore Watchdog Timer: 0.1. mpcore_noboot=%d mpcore_margin=%d sec (nowayout= %d)\n", | ||
| 440 | mpcore_noboot, mpcore_margin, nowayout); | ||
| 441 | |||
| 442 | return platform_driver_register(&mpcore_wdt_driver); | ||
| 443 | } | ||
| 444 | |||
| 445 | static void __exit mpcore_wdt_exit(void) | ||
| 446 | { | ||
| 447 | platform_driver_unregister(&mpcore_wdt_driver); | ||
| 448 | } | ||
| 449 | |||
| 450 | module_init(mpcore_wdt_init); | ||
| 451 | module_exit(mpcore_wdt_exit); | ||
| 452 | |||
| 453 | MODULE_AUTHOR("ARM Limited"); | ||
| 454 | MODULE_DESCRIPTION("MPcore Watchdog Device Driver"); | ||
| 455 | MODULE_LICENSE("GPL"); | ||
| 456 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | ||
diff --git a/drivers/watchdog/mtx-1_wdt.c b/drivers/watchdog/mtx-1_wdt.c index 14dab6ff87aa..b4341110ad4f 100644 --- a/drivers/watchdog/mtx-1_wdt.c +++ b/drivers/watchdog/mtx-1_wdt.c | |||
| @@ -209,7 +209,7 @@ static int mtx1_wdt_probe(struct platform_device *pdev) | |||
| 209 | int ret; | 209 | int ret; |
| 210 | 210 | ||
| 211 | mtx1_wdt_device.gpio = pdev->resource[0].start; | 211 | mtx1_wdt_device.gpio = pdev->resource[0].start; |
| 212 | ret = gpio_request_one(mtx1_wdt_device.gpio, | 212 | ret = devm_gpio_request_one(&pdev->dev, mtx1_wdt_device.gpio, |
| 213 | GPIOF_OUT_INIT_HIGH, "mtx1-wdt"); | 213 | GPIOF_OUT_INIT_HIGH, "mtx1-wdt"); |
| 214 | if (ret < 0) { | 214 | if (ret < 0) { |
| 215 | dev_err(&pdev->dev, "failed to request gpio"); | 215 | dev_err(&pdev->dev, "failed to request gpio"); |
| @@ -241,7 +241,6 @@ static int mtx1_wdt_remove(struct platform_device *pdev) | |||
| 241 | wait_for_completion(&mtx1_wdt_device.stop); | 241 | wait_for_completion(&mtx1_wdt_device.stop); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | gpio_free(mtx1_wdt_device.gpio); | ||
| 245 | misc_deregister(&mtx1_wdt_misc); | 244 | misc_deregister(&mtx1_wdt_misc); |
| 246 | return 0; | 245 | return 0; |
| 247 | } | 246 | } |
diff --git a/drivers/watchdog/mv64x60_wdt.c b/drivers/watchdog/mv64x60_wdt.c index c7fb878ca493..e4cf98019265 100644 --- a/drivers/watchdog/mv64x60_wdt.c +++ b/drivers/watchdog/mv64x60_wdt.c | |||
| @@ -276,7 +276,7 @@ static int mv64x60_wdt_probe(struct platform_device *dev) | |||
| 276 | if (!r) | 276 | if (!r) |
| 277 | return -ENODEV; | 277 | return -ENODEV; |
| 278 | 278 | ||
| 279 | mv64x60_wdt_regs = ioremap(r->start, resource_size(r)); | 279 | mv64x60_wdt_regs = devm_ioremap(&dev->dev, r->start, resource_size(r)); |
| 280 | if (mv64x60_wdt_regs == NULL) | 280 | if (mv64x60_wdt_regs == NULL) |
| 281 | return -ENOMEM; | 281 | return -ENOMEM; |
| 282 | 282 | ||
| @@ -293,8 +293,6 @@ static int mv64x60_wdt_remove(struct platform_device *dev) | |||
| 293 | 293 | ||
| 294 | mv64x60_wdt_handler_disable(); | 294 | mv64x60_wdt_handler_disable(); |
| 295 | 295 | ||
| 296 | iounmap(mv64x60_wdt_regs); | ||
| 297 | |||
| 298 | return 0; | 296 | return 0; |
| 299 | } | 297 | } |
| 300 | 298 | ||
diff --git a/drivers/watchdog/nuc900_wdt.c b/drivers/watchdog/nuc900_wdt.c index 04c45a102992..e2b6d2cf5c9d 100644 --- a/drivers/watchdog/nuc900_wdt.c +++ b/drivers/watchdog/nuc900_wdt.c | |||
| @@ -61,7 +61,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " | |||
| 61 | "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 61 | "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
| 62 | 62 | ||
| 63 | struct nuc900_wdt { | 63 | struct nuc900_wdt { |
| 64 | struct resource *res; | ||
| 65 | struct clk *wdt_clock; | 64 | struct clk *wdt_clock; |
| 66 | struct platform_device *pdev; | 65 | struct platform_device *pdev; |
| 67 | void __iomem *wdt_base; | 66 | void __iomem *wdt_base; |
| @@ -244,9 +243,11 @@ static struct miscdevice nuc900wdt_miscdev = { | |||
| 244 | 243 | ||
| 245 | static int nuc900wdt_probe(struct platform_device *pdev) | 244 | static int nuc900wdt_probe(struct platform_device *pdev) |
| 246 | { | 245 | { |
| 246 | struct resource *res; | ||
| 247 | int ret = 0; | 247 | int ret = 0; |
| 248 | 248 | ||
| 249 | nuc900_wdt = kzalloc(sizeof(struct nuc900_wdt), GFP_KERNEL); | 249 | nuc900_wdt = devm_kzalloc(&pdev->dev, sizeof(*nuc900_wdt), |
| 250 | GFP_KERNEL); | ||
| 250 | if (!nuc900_wdt) | 251 | if (!nuc900_wdt) |
| 251 | return -ENOMEM; | 252 | return -ENOMEM; |
| 252 | 253 | ||
| @@ -254,33 +255,20 @@ static int nuc900wdt_probe(struct platform_device *pdev) | |||
| 254 | 255 | ||
| 255 | spin_lock_init(&nuc900_wdt->wdt_lock); | 256 | spin_lock_init(&nuc900_wdt->wdt_lock); |
| 256 | 257 | ||
| 257 | nuc900_wdt->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 258 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 258 | if (nuc900_wdt->res == NULL) { | 259 | if (res == NULL) { |
| 259 | dev_err(&pdev->dev, "no memory resource specified\n"); | 260 | dev_err(&pdev->dev, "no memory resource specified\n"); |
| 260 | ret = -ENOENT; | 261 | return -ENOENT; |
| 261 | goto err_get; | ||
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | if (!request_mem_region(nuc900_wdt->res->start, | 264 | nuc900_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res); |
| 265 | resource_size(nuc900_wdt->res), pdev->name)) { | 265 | if (IS_ERR(nuc900_wdt->wdt_base)) |
| 266 | dev_err(&pdev->dev, "failed to get memory region\n"); | 266 | return PTR_ERR(nuc900_wdt->wdt_base); |
| 267 | ret = -ENOENT; | ||
| 268 | goto err_get; | ||
| 269 | } | ||
| 270 | |||
| 271 | nuc900_wdt->wdt_base = ioremap(nuc900_wdt->res->start, | ||
| 272 | resource_size(nuc900_wdt->res)); | ||
| 273 | if (nuc900_wdt->wdt_base == NULL) { | ||
| 274 | dev_err(&pdev->dev, "failed to ioremap() region\n"); | ||
| 275 | ret = -EINVAL; | ||
| 276 | goto err_req; | ||
| 277 | } | ||
| 278 | 267 | ||
| 279 | nuc900_wdt->wdt_clock = clk_get(&pdev->dev, NULL); | 268 | nuc900_wdt->wdt_clock = devm_clk_get(&pdev->dev, NULL); |
| 280 | if (IS_ERR(nuc900_wdt->wdt_clock)) { | 269 | if (IS_ERR(nuc900_wdt->wdt_clock)) { |
| 281 | dev_err(&pdev->dev, "failed to find watchdog clock source\n"); | 270 | dev_err(&pdev->dev, "failed to find watchdog clock source\n"); |
| 282 | ret = PTR_ERR(nuc900_wdt->wdt_clock); | 271 | return PTR_ERR(nuc900_wdt->wdt_clock); |
| 283 | goto err_map; | ||
| 284 | } | 272 | } |
| 285 | 273 | ||
| 286 | clk_enable(nuc900_wdt->wdt_clock); | 274 | clk_enable(nuc900_wdt->wdt_clock); |
| @@ -298,14 +286,6 @@ static int nuc900wdt_probe(struct platform_device *pdev) | |||
| 298 | 286 | ||
| 299 | err_clk: | 287 | err_clk: |
| 300 | clk_disable(nuc900_wdt->wdt_clock); | 288 | clk_disable(nuc900_wdt->wdt_clock); |
| 301 | clk_put(nuc900_wdt->wdt_clock); | ||
| 302 | err_map: | ||
| 303 | iounmap(nuc900_wdt->wdt_base); | ||
| 304 | err_req: | ||
| 305 | release_mem_region(nuc900_wdt->res->start, | ||
| 306 | resource_size(nuc900_wdt->res)); | ||
| 307 | err_get: | ||
| 308 | kfree(nuc900_wdt); | ||
| 309 | return ret; | 289 | return ret; |
| 310 | } | 290 | } |
| 311 | 291 | ||
| @@ -314,14 +294,6 @@ static int nuc900wdt_remove(struct platform_device *pdev) | |||
| 314 | misc_deregister(&nuc900wdt_miscdev); | 294 | misc_deregister(&nuc900wdt_miscdev); |
| 315 | 295 | ||
| 316 | clk_disable(nuc900_wdt->wdt_clock); | 296 | clk_disable(nuc900_wdt->wdt_clock); |
| 317 | clk_put(nuc900_wdt->wdt_clock); | ||
| 318 | |||
| 319 | iounmap(nuc900_wdt->wdt_base); | ||
| 320 | |||
| 321 | release_mem_region(nuc900_wdt->res->start, | ||
| 322 | resource_size(nuc900_wdt->res)); | ||
| 323 | |||
| 324 | kfree(nuc900_wdt); | ||
| 325 | 297 | ||
| 326 | return 0; | 298 | return 0; |
| 327 | } | 299 | } |
diff --git a/drivers/watchdog/of_xilinx_wdt.c b/drivers/watchdog/of_xilinx_wdt.c index 2761ddb08501..4dd281f2c33f 100644 --- a/drivers/watchdog/of_xilinx_wdt.c +++ b/drivers/watchdog/of_xilinx_wdt.c | |||
| @@ -1,23 +1,13 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * of_xilinx_wdt.c 1.01 A Watchdog Device Driver for Xilinx xps_timebase_wdt | 2 | * Watchdog Device Driver for Xilinx axi/xps_timebase_wdt |
| 3 | * | 3 | * |
| 4 | * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>) | 4 | * (C) Copyright 2011 (Alejandro Cabrera <aldaya@gmail.com>) |
| 5 | * | 5 | * |
| 6 | * ----------------------- | 6 | * This program is free software; you can redistribute it and/or |
| 7 | * | 7 | * modify it under the terms of the GNU General Public License |
| 8 | * This program is free software; you can redistribute it and/or | 8 | * as published by the Free Software Foundation; either version |
| 9 | * modify it under the terms of the GNU General Public License | 9 | * 2 of the License, or (at your option) any later version. |
| 10 | * as published by the Free Software Foundation; either version | 10 | */ |
| 11 | * 2 of the License, or (at your option) any later version. | ||
| 12 | * | ||
| 13 | * ----------------------- | ||
| 14 | * 30-May-2011 Alejandro Cabrera <aldaya@gmail.com> | ||
| 15 | * - If "xlnx,wdt-enable-once" wasn't found on device tree the | ||
| 16 | * module will use CONFIG_WATCHDOG_NOWAYOUT | ||
| 17 | * - If the device tree parameters ("clock-frequency" and | ||
| 18 | * "xlnx,wdt-interval") wasn't found the driver won't | ||
| 19 | * know the wdt reset interval | ||
| 20 | */ | ||
| 21 | 11 | ||
| 22 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 23 | 13 | ||
| @@ -394,6 +384,7 @@ static int xwdt_remove(struct platform_device *dev) | |||
| 394 | 384 | ||
| 395 | /* Match table for of_platform binding */ | 385 | /* Match table for of_platform binding */ |
| 396 | static struct of_device_id xwdt_of_match[] = { | 386 | static struct of_device_id xwdt_of_match[] = { |
| 387 | { .compatible = "xlnx,xps-timebase-wdt-1.00.a", }, | ||
| 397 | { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, | 388 | { .compatible = "xlnx,xps-timebase-wdt-1.01.a", }, |
| 398 | {}, | 389 | {}, |
| 399 | }; | 390 | }; |
| @@ -413,5 +404,5 @@ module_platform_driver(xwdt_driver); | |||
| 413 | 404 | ||
| 414 | MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>"); | 405 | MODULE_AUTHOR("Alejandro Cabrera <aldaya@gmail.com>"); |
| 415 | MODULE_DESCRIPTION("Xilinx Watchdog driver"); | 406 | MODULE_DESCRIPTION("Xilinx Watchdog driver"); |
| 416 | MODULE_LICENSE("GPL"); | 407 | MODULE_LICENSE("GPL v2"); |
| 417 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 408 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index da577980d390..4ea5fcccac02 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c | |||
| @@ -38,6 +38,9 @@ | |||
| 38 | #define WDT_IN_USE 0 | 38 | #define WDT_IN_USE 0 |
| 39 | #define WDT_OK_TO_CLOSE 1 | 39 | #define WDT_OK_TO_CLOSE 1 |
| 40 | 40 | ||
| 41 | #define WDT_RESET_OUT_EN BIT(1) | ||
| 42 | #define WDT_INT_REQ BIT(3) | ||
| 43 | |||
| 41 | static bool nowayout = WATCHDOG_NOWAYOUT; | 44 | static bool nowayout = WATCHDOG_NOWAYOUT; |
| 42 | static int heartbeat = -1; /* module parameter (seconds) */ | 45 | static int heartbeat = -1; /* module parameter (seconds) */ |
| 43 | static unsigned int wdt_max_duration; /* (seconds) */ | 46 | static unsigned int wdt_max_duration; /* (seconds) */ |
| @@ -67,9 +70,7 @@ static int orion_wdt_start(struct watchdog_device *wdt_dev) | |||
| 67 | writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL); | 70 | writel(wdt_tclk * wdt_dev->timeout, wdt_reg + WDT_VAL); |
| 68 | 71 | ||
| 69 | /* Clear watchdog timer interrupt */ | 72 | /* Clear watchdog timer interrupt */ |
| 70 | reg = readl(BRIDGE_CAUSE); | 73 | writel(~WDT_INT_REQ, BRIDGE_CAUSE); |
| 71 | reg &= ~WDT_INT_REQ; | ||
| 72 | writel(reg, BRIDGE_CAUSE); | ||
| 73 | 74 | ||
| 74 | /* Enable watchdog timer */ | 75 | /* Enable watchdog timer */ |
| 75 | reg = readl(wdt_reg + TIMER_CTRL); | 76 | reg = readl(wdt_reg + TIMER_CTRL); |
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index a3684a30eb69..b30bd430f591 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c | |||
| @@ -159,13 +159,13 @@ static int pnx4008_wdt_probe(struct platform_device *pdev) | |||
| 159 | if (IS_ERR(wdt_base)) | 159 | if (IS_ERR(wdt_base)) |
| 160 | return PTR_ERR(wdt_base); | 160 | return PTR_ERR(wdt_base); |
| 161 | 161 | ||
| 162 | wdt_clk = clk_get(&pdev->dev, NULL); | 162 | wdt_clk = devm_clk_get(&pdev->dev, NULL); |
| 163 | if (IS_ERR(wdt_clk)) | 163 | if (IS_ERR(wdt_clk)) |
| 164 | return PTR_ERR(wdt_clk); | 164 | return PTR_ERR(wdt_clk); |
| 165 | 165 | ||
| 166 | ret = clk_enable(wdt_clk); | 166 | ret = clk_enable(wdt_clk); |
| 167 | if (ret) | 167 | if (ret) |
| 168 | goto out; | 168 | return ret; |
| 169 | 169 | ||
| 170 | pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ? | 170 | pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ? |
| 171 | WDIOF_CARDRESET : 0; | 171 | WDIOF_CARDRESET : 0; |
| @@ -186,8 +186,6 @@ static int pnx4008_wdt_probe(struct platform_device *pdev) | |||
| 186 | 186 | ||
| 187 | disable_clk: | 187 | disable_clk: |
| 188 | clk_disable(wdt_clk); | 188 | clk_disable(wdt_clk); |
| 189 | out: | ||
| 190 | clk_put(wdt_clk); | ||
| 191 | return ret; | 189 | return ret; |
| 192 | } | 190 | } |
| 193 | 191 | ||
| @@ -196,7 +194,6 @@ static int pnx4008_wdt_remove(struct platform_device *pdev) | |||
| 196 | watchdog_unregister_device(&pnx4008_wdd); | 194 | watchdog_unregister_device(&pnx4008_wdd); |
| 197 | 195 | ||
| 198 | clk_disable(wdt_clk); | 196 | clk_disable(wdt_clk); |
| 199 | clk_put(wdt_clk); | ||
| 200 | 197 | ||
| 201 | return 0; | 198 | return 0; |
| 202 | } | 199 | } |
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c index f78bc008cbb7..9cf6bc7a234f 100644 --- a/drivers/watchdog/rc32434_wdt.c +++ b/drivers/watchdog/rc32434_wdt.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/platform_device.h> /* For platform_driver framework */ | 32 | #include <linux/platform_device.h> /* For platform_driver framework */ |
| 33 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ | 33 | #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ |
| 34 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | 34 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ |
| 35 | #include <linux/io.h> /* For devm_ioremap_nocache */ | ||
| 35 | 36 | ||
| 36 | #include <asm/mach-rc32434/integ.h> /* For the Watchdog registers */ | 37 | #include <asm/mach-rc32434/integ.h> /* For the Watchdog registers */ |
| 37 | 38 | ||
| @@ -271,7 +272,7 @@ static int rc32434_wdt_probe(struct platform_device *pdev) | |||
| 271 | return -ENODEV; | 272 | return -ENODEV; |
| 272 | } | 273 | } |
| 273 | 274 | ||
| 274 | wdt_reg = ioremap_nocache(r->start, resource_size(r)); | 275 | wdt_reg = devm_ioremap_nocache(&pdev->dev, r->start, resource_size(r)); |
| 275 | if (!wdt_reg) { | 276 | if (!wdt_reg) { |
| 276 | pr_err("failed to remap I/O resources\n"); | 277 | pr_err("failed to remap I/O resources\n"); |
| 277 | return -ENXIO; | 278 | return -ENXIO; |
| @@ -293,23 +294,18 @@ static int rc32434_wdt_probe(struct platform_device *pdev) | |||
| 293 | ret = misc_register(&rc32434_wdt_miscdev); | 294 | ret = misc_register(&rc32434_wdt_miscdev); |
| 294 | if (ret < 0) { | 295 | if (ret < 0) { |
| 295 | pr_err("failed to register watchdog device\n"); | 296 | pr_err("failed to register watchdog device\n"); |
| 296 | goto unmap; | 297 | return ret; |
| 297 | } | 298 | } |
| 298 | 299 | ||
| 299 | pr_info("Watchdog Timer version " VERSION ", timer margin: %d sec\n", | 300 | pr_info("Watchdog Timer version " VERSION ", timer margin: %d sec\n", |
| 300 | timeout); | 301 | timeout); |
| 301 | 302 | ||
| 302 | return 0; | 303 | return 0; |
| 303 | |||
| 304 | unmap: | ||
| 305 | iounmap(wdt_reg); | ||
| 306 | return ret; | ||
| 307 | } | 304 | } |
| 308 | 305 | ||
| 309 | static int rc32434_wdt_remove(struct platform_device *pdev) | 306 | static int rc32434_wdt_remove(struct platform_device *pdev) |
| 310 | { | 307 | { |
| 311 | misc_deregister(&rc32434_wdt_miscdev); | 308 | misc_deregister(&rc32434_wdt_miscdev); |
| 312 | iounmap(wdt_reg); | ||
| 313 | return 0; | 309 | return 0; |
| 314 | } | 310 | } |
| 315 | 311 | ||
diff --git a/drivers/watchdog/riowd.c b/drivers/watchdog/riowd.c index 0040451aec1d..3dd8ed28adc8 100644 --- a/drivers/watchdog/riowd.c +++ b/drivers/watchdog/riowd.c | |||
| @@ -183,7 +183,7 @@ static int riowd_probe(struct platform_device *op) | |||
| 183 | goto out; | 183 | goto out; |
| 184 | 184 | ||
| 185 | err = -ENOMEM; | 185 | err = -ENOMEM; |
| 186 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 186 | p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL); |
| 187 | if (!p) | 187 | if (!p) |
| 188 | goto out; | 188 | goto out; |
| 189 | 189 | ||
| @@ -192,7 +192,7 @@ static int riowd_probe(struct platform_device *op) | |||
| 192 | p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME); | 192 | p->regs = of_ioremap(&op->resource[0], 0, 2, DRIVER_NAME); |
| 193 | if (!p->regs) { | 193 | if (!p->regs) { |
| 194 | pr_err("Cannot map registers\n"); | 194 | pr_err("Cannot map registers\n"); |
| 195 | goto out_free; | 195 | goto out; |
| 196 | } | 196 | } |
| 197 | /* Make miscdev useable right away */ | 197 | /* Make miscdev useable right away */ |
| 198 | riowd_device = p; | 198 | riowd_device = p; |
| @@ -206,27 +206,23 @@ static int riowd_probe(struct platform_device *op) | |||
| 206 | pr_info("Hardware watchdog [%i minutes], regs at %p\n", | 206 | pr_info("Hardware watchdog [%i minutes], regs at %p\n", |
| 207 | riowd_timeout, p->regs); | 207 | riowd_timeout, p->regs); |
| 208 | 208 | ||
| 209 | dev_set_drvdata(&op->dev, p); | 209 | platform_set_drvdata(op, p); |
| 210 | return 0; | 210 | return 0; |
| 211 | 211 | ||
| 212 | out_iounmap: | 212 | out_iounmap: |
| 213 | riowd_device = NULL; | 213 | riowd_device = NULL; |
| 214 | of_iounmap(&op->resource[0], p->regs, 2); | 214 | of_iounmap(&op->resource[0], p->regs, 2); |
| 215 | 215 | ||
| 216 | out_free: | ||
| 217 | kfree(p); | ||
| 218 | |||
| 219 | out: | 216 | out: |
| 220 | return err; | 217 | return err; |
| 221 | } | 218 | } |
| 222 | 219 | ||
| 223 | static int riowd_remove(struct platform_device *op) | 220 | static int riowd_remove(struct platform_device *op) |
| 224 | { | 221 | { |
| 225 | struct riowd *p = dev_get_drvdata(&op->dev); | 222 | struct riowd *p = platform_get_drvdata(op); |
| 226 | 223 | ||
| 227 | misc_deregister(&riowd_miscdev); | 224 | misc_deregister(&riowd_miscdev); |
| 228 | of_iounmap(&op->resource[0], p->regs, 2); | 225 | of_iounmap(&op->resource[0], p->regs, 2); |
| 229 | kfree(p); | ||
| 230 | 226 | ||
| 231 | return 0; | 227 | return 0; |
| 232 | } | 228 | } |
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 3a9f6961db2d..6a22cf5d35bd 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
| @@ -358,7 +358,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
| 358 | 358 | ||
| 359 | ret = s3c2410wdt_cpufreq_register(); | 359 | ret = s3c2410wdt_cpufreq_register(); |
| 360 | if (ret < 0) { | 360 | if (ret < 0) { |
| 361 | pr_err("failed to register cpufreq\n"); | 361 | dev_err(dev, "failed to register cpufreq\n"); |
| 362 | goto err_clk; | 362 | goto err_clk; |
| 363 | } | 363 | } |
| 364 | 364 | ||
| @@ -448,12 +448,12 @@ static void s3c2410wdt_shutdown(struct platform_device *dev) | |||
| 448 | s3c2410wdt_stop(&s3c2410_wdd); | 448 | s3c2410wdt_stop(&s3c2410_wdd); |
| 449 | } | 449 | } |
| 450 | 450 | ||
| 451 | #ifdef CONFIG_PM | 451 | #ifdef CONFIG_PM_SLEEP |
| 452 | 452 | ||
| 453 | static unsigned long wtcon_save; | 453 | static unsigned long wtcon_save; |
| 454 | static unsigned long wtdat_save; | 454 | static unsigned long wtdat_save; |
| 455 | 455 | ||
| 456 | static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state) | 456 | static int s3c2410wdt_suspend(struct device *dev) |
| 457 | { | 457 | { |
| 458 | /* Save watchdog state, and turn it off. */ | 458 | /* Save watchdog state, and turn it off. */ |
| 459 | wtcon_save = readl(wdt_base + S3C2410_WTCON); | 459 | wtcon_save = readl(wdt_base + S3C2410_WTCON); |
| @@ -465,7 +465,7 @@ static int s3c2410wdt_suspend(struct platform_device *dev, pm_message_t state) | |||
| 465 | return 0; | 465 | return 0; |
| 466 | } | 466 | } |
| 467 | 467 | ||
| 468 | static int s3c2410wdt_resume(struct platform_device *dev) | 468 | static int s3c2410wdt_resume(struct device *dev) |
| 469 | { | 469 | { |
| 470 | /* Restore watchdog state. */ | 470 | /* Restore watchdog state. */ |
| 471 | 471 | ||
| @@ -473,16 +473,15 @@ static int s3c2410wdt_resume(struct platform_device *dev) | |||
| 473 | writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ | 473 | writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */ |
| 474 | writel(wtcon_save, wdt_base + S3C2410_WTCON); | 474 | writel(wtcon_save, wdt_base + S3C2410_WTCON); |
| 475 | 475 | ||
| 476 | pr_info("watchdog %sabled\n", | 476 | dev_info(dev, "watchdog %sabled\n", |
| 477 | (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); | 477 | (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis"); |
| 478 | 478 | ||
| 479 | return 0; | 479 | return 0; |
| 480 | } | 480 | } |
| 481 | #endif | ||
| 481 | 482 | ||
| 482 | #else | 483 | static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend, |
| 483 | #define s3c2410wdt_suspend NULL | 484 | s3c2410wdt_resume); |
| 484 | #define s3c2410wdt_resume NULL | ||
| 485 | #endif /* CONFIG_PM */ | ||
| 486 | 485 | ||
| 487 | #ifdef CONFIG_OF | 486 | #ifdef CONFIG_OF |
| 488 | static const struct of_device_id s3c2410_wdt_match[] = { | 487 | static const struct of_device_id s3c2410_wdt_match[] = { |
| @@ -496,11 +495,10 @@ static struct platform_driver s3c2410wdt_driver = { | |||
| 496 | .probe = s3c2410wdt_probe, | 495 | .probe = s3c2410wdt_probe, |
| 497 | .remove = s3c2410wdt_remove, | 496 | .remove = s3c2410wdt_remove, |
| 498 | .shutdown = s3c2410wdt_shutdown, | 497 | .shutdown = s3c2410wdt_shutdown, |
| 499 | .suspend = s3c2410wdt_suspend, | ||
| 500 | .resume = s3c2410wdt_resume, | ||
| 501 | .driver = { | 498 | .driver = { |
| 502 | .owner = THIS_MODULE, | 499 | .owner = THIS_MODULE, |
| 503 | .name = "s3c2410-wdt", | 500 | .name = "s3c2410-wdt", |
| 501 | .pm = &s3c2410wdt_pm_ops, | ||
| 504 | .of_match_table = of_match_ptr(s3c2410_wdt_match), | 502 | .of_match_table = of_match_ptr(s3c2410_wdt_match), |
| 505 | }, | 503 | }, |
| 506 | }; | 504 | }; |
diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index 6185af2b3310..5bca79457768 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c | |||
| @@ -241,7 +241,7 @@ static int sh_wdt_probe(struct platform_device *pdev) | |||
| 241 | 241 | ||
| 242 | wdt->dev = &pdev->dev; | 242 | wdt->dev = &pdev->dev; |
| 243 | 243 | ||
| 244 | wdt->clk = clk_get(&pdev->dev, NULL); | 244 | wdt->clk = devm_clk_get(&pdev->dev, NULL); |
| 245 | if (IS_ERR(wdt->clk)) { | 245 | if (IS_ERR(wdt->clk)) { |
| 246 | /* | 246 | /* |
| 247 | * Clock framework support is optional, continue on | 247 | * Clock framework support is optional, continue on |
| @@ -251,10 +251,8 @@ static int sh_wdt_probe(struct platform_device *pdev) | |||
| 251 | } | 251 | } |
| 252 | 252 | ||
| 253 | wdt->base = devm_ioremap_resource(wdt->dev, res); | 253 | wdt->base = devm_ioremap_resource(wdt->dev, res); |
| 254 | if (IS_ERR(wdt->base)) { | 254 | if (IS_ERR(wdt->base)) |
| 255 | rc = PTR_ERR(wdt->base); | 255 | return PTR_ERR(wdt->base); |
| 256 | goto err; | ||
| 257 | } | ||
| 258 | 256 | ||
| 259 | watchdog_set_nowayout(&sh_wdt_dev, nowayout); | 257 | watchdog_set_nowayout(&sh_wdt_dev, nowayout); |
| 260 | watchdog_set_drvdata(&sh_wdt_dev, wdt); | 258 | watchdog_set_drvdata(&sh_wdt_dev, wdt); |
| @@ -277,7 +275,7 @@ static int sh_wdt_probe(struct platform_device *pdev) | |||
| 277 | rc = watchdog_register_device(&sh_wdt_dev); | 275 | rc = watchdog_register_device(&sh_wdt_dev); |
| 278 | if (unlikely(rc)) { | 276 | if (unlikely(rc)) { |
| 279 | dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc); | 277 | dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc); |
| 280 | goto err; | 278 | return rc; |
| 281 | } | 279 | } |
| 282 | 280 | ||
| 283 | init_timer(&wdt->timer); | 281 | init_timer(&wdt->timer); |
| @@ -292,23 +290,15 @@ static int sh_wdt_probe(struct platform_device *pdev) | |||
| 292 | pm_runtime_enable(&pdev->dev); | 290 | pm_runtime_enable(&pdev->dev); |
| 293 | 291 | ||
| 294 | return 0; | 292 | return 0; |
| 295 | |||
| 296 | err: | ||
| 297 | clk_put(wdt->clk); | ||
| 298 | |||
| 299 | return rc; | ||
| 300 | } | 293 | } |
| 301 | 294 | ||
| 302 | static int sh_wdt_remove(struct platform_device *pdev) | 295 | static int sh_wdt_remove(struct platform_device *pdev) |
| 303 | { | 296 | { |
| 304 | struct sh_wdt *wdt = platform_get_drvdata(pdev); | 297 | struct sh_wdt *wdt = platform_get_drvdata(pdev); |
| 305 | 298 | ||
| 306 | platform_set_drvdata(pdev, NULL); | ||
| 307 | |||
| 308 | watchdog_unregister_device(&sh_wdt_dev); | 299 | watchdog_unregister_device(&sh_wdt_dev); |
| 309 | 300 | ||
| 310 | pm_runtime_disable(&pdev->dev); | 301 | pm_runtime_disable(&pdev->dev); |
| 311 | clk_put(wdt->clk); | ||
| 312 | 302 | ||
| 313 | return 0; | 303 | return 0; |
| 314 | } | 304 | } |
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c index fe83beb8f1b7..b68b1e519d53 100644 --- a/drivers/watchdog/softdog.c +++ b/drivers/watchdog/softdog.c | |||
| @@ -152,7 +152,6 @@ static struct watchdog_ops softdog_ops = { | |||
| 152 | .owner = THIS_MODULE, | 152 | .owner = THIS_MODULE, |
| 153 | .start = softdog_ping, | 153 | .start = softdog_ping, |
| 154 | .stop = softdog_stop, | 154 | .stop = softdog_stop, |
| 155 | .ping = softdog_ping, | ||
| 156 | .set_timeout = softdog_set_timeout, | 155 | .set_timeout = softdog_set_timeout, |
| 157 | }; | 156 | }; |
| 158 | 157 | ||
diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index 8872642505c0..58df98aec122 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c | |||
| @@ -231,7 +231,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) | |||
| 231 | goto err; | 231 | goto err; |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | wdt->clk = clk_get(&adev->dev, NULL); | 234 | wdt->clk = devm_clk_get(&adev->dev, NULL); |
| 235 | if (IS_ERR(wdt->clk)) { | 235 | if (IS_ERR(wdt->clk)) { |
| 236 | dev_warn(&adev->dev, "Clock not found\n"); | 236 | dev_warn(&adev->dev, "Clock not found\n"); |
| 237 | ret = PTR_ERR(wdt->clk); | 237 | ret = PTR_ERR(wdt->clk); |
| @@ -251,15 +251,13 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) | |||
| 251 | if (ret) { | 251 | if (ret) { |
| 252 | dev_err(&adev->dev, "watchdog_register_device() failed: %d\n", | 252 | dev_err(&adev->dev, "watchdog_register_device() failed: %d\n", |
| 253 | ret); | 253 | ret); |
| 254 | goto err_register; | 254 | goto err; |
| 255 | } | 255 | } |
| 256 | amba_set_drvdata(adev, wdt); | 256 | amba_set_drvdata(adev, wdt); |
| 257 | 257 | ||
| 258 | dev_info(&adev->dev, "registration successful\n"); | 258 | dev_info(&adev->dev, "registration successful\n"); |
| 259 | return 0; | 259 | return 0; |
| 260 | 260 | ||
| 261 | err_register: | ||
| 262 | clk_put(wdt->clk); | ||
| 263 | err: | 261 | err: |
| 264 | dev_err(&adev->dev, "Probe Failed!!!\n"); | 262 | dev_err(&adev->dev, "Probe Failed!!!\n"); |
| 265 | return ret; | 263 | return ret; |
| @@ -272,7 +270,6 @@ static int sp805_wdt_remove(struct amba_device *adev) | |||
| 272 | watchdog_unregister_device(&wdt->wdd); | 270 | watchdog_unregister_device(&wdt->wdd); |
| 273 | amba_set_drvdata(adev, NULL); | 271 | amba_set_drvdata(adev, NULL); |
| 274 | watchdog_set_drvdata(&wdt->wdd, NULL); | 272 | watchdog_set_drvdata(&wdt->wdd, NULL); |
| 275 | clk_put(wdt->clk); | ||
| 276 | 273 | ||
| 277 | return 0; | 274 | return 0; |
| 278 | } | 275 | } |
diff --git a/drivers/watchdog/ts72xx_wdt.c b/drivers/watchdog/ts72xx_wdt.c index b8a92459f10f..4da59b4d73f0 100644 --- a/drivers/watchdog/ts72xx_wdt.c +++ b/drivers/watchdog/ts72xx_wdt.c | |||
| @@ -396,7 +396,7 @@ static int ts72xx_wdt_probe(struct platform_device *pdev) | |||
| 396 | struct resource *r1, *r2; | 396 | struct resource *r1, *r2; |
| 397 | int error = 0; | 397 | int error = 0; |
| 398 | 398 | ||
| 399 | wdt = kzalloc(sizeof(struct ts72xx_wdt), GFP_KERNEL); | 399 | wdt = devm_kzalloc(&pdev->dev, sizeof(struct ts72xx_wdt), GFP_KERNEL); |
| 400 | if (!wdt) { | 400 | if (!wdt) { |
| 401 | dev_err(&pdev->dev, "failed to allocate memory\n"); | 401 | dev_err(&pdev->dev, "failed to allocate memory\n"); |
| 402 | return -ENOMEM; | 402 | return -ENOMEM; |
| @@ -405,44 +405,22 @@ static int ts72xx_wdt_probe(struct platform_device *pdev) | |||
| 405 | r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 405 | r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 406 | if (!r1) { | 406 | if (!r1) { |
| 407 | dev_err(&pdev->dev, "failed to get memory resource\n"); | 407 | dev_err(&pdev->dev, "failed to get memory resource\n"); |
| 408 | error = -ENODEV; | 408 | return -ENODEV; |
| 409 | goto fail; | ||
| 410 | } | 409 | } |
| 411 | 410 | ||
| 412 | r1 = request_mem_region(r1->start, resource_size(r1), pdev->name); | 411 | wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1); |
| 413 | if (!r1) { | 412 | if (IS_ERR(wdt->control_reg)) |
| 414 | dev_err(&pdev->dev, "cannot request memory region\n"); | 413 | return PTR_ERR(wdt->control_reg); |
| 415 | error = -EBUSY; | ||
| 416 | goto fail; | ||
| 417 | } | ||
| 418 | |||
| 419 | wdt->control_reg = ioremap(r1->start, resource_size(r1)); | ||
| 420 | if (!wdt->control_reg) { | ||
| 421 | dev_err(&pdev->dev, "failed to map memory\n"); | ||
| 422 | error = -ENODEV; | ||
| 423 | goto fail_free_control; | ||
| 424 | } | ||
| 425 | 414 | ||
| 426 | r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 415 | r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| 427 | if (!r2) { | 416 | if (!r2) { |
| 428 | dev_err(&pdev->dev, "failed to get memory resource\n"); | 417 | dev_err(&pdev->dev, "failed to get memory resource\n"); |
| 429 | error = -ENODEV; | 418 | return -ENODEV; |
| 430 | goto fail_unmap_control; | ||
| 431 | } | ||
| 432 | |||
| 433 | r2 = request_mem_region(r2->start, resource_size(r2), pdev->name); | ||
| 434 | if (!r2) { | ||
| 435 | dev_err(&pdev->dev, "cannot request memory region\n"); | ||
| 436 | error = -EBUSY; | ||
| 437 | goto fail_unmap_control; | ||
| 438 | } | 419 | } |
| 439 | 420 | ||
| 440 | wdt->feed_reg = ioremap(r2->start, resource_size(r2)); | 421 | wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2); |
| 441 | if (!wdt->feed_reg) { | 422 | if (IS_ERR(wdt->feed_reg)) |
| 442 | dev_err(&pdev->dev, "failed to map memory\n"); | 423 | return PTR_ERR(wdt->feed_reg); |
| 443 | error = -ENODEV; | ||
| 444 | goto fail_free_feed; | ||
| 445 | } | ||
| 446 | 424 | ||
| 447 | platform_set_drvdata(pdev, wdt); | 425 | platform_set_drvdata(pdev, wdt); |
| 448 | ts72xx_wdt_pdev = pdev; | 426 | ts72xx_wdt_pdev = pdev; |
| @@ -455,45 +433,20 @@ static int ts72xx_wdt_probe(struct platform_device *pdev) | |||
| 455 | error = misc_register(&ts72xx_wdt_miscdev); | 433 | error = misc_register(&ts72xx_wdt_miscdev); |
| 456 | if (error) { | 434 | if (error) { |
| 457 | dev_err(&pdev->dev, "failed to register miscdev\n"); | 435 | dev_err(&pdev->dev, "failed to register miscdev\n"); |
| 458 | goto fail_unmap_feed; | 436 | return error; |
| 459 | } | 437 | } |
| 460 | 438 | ||
| 461 | dev_info(&pdev->dev, "TS-72xx Watchdog driver\n"); | 439 | dev_info(&pdev->dev, "TS-72xx Watchdog driver\n"); |
| 462 | 440 | ||
| 463 | return 0; | 441 | return 0; |
| 464 | |||
| 465 | fail_unmap_feed: | ||
| 466 | platform_set_drvdata(pdev, NULL); | ||
| 467 | iounmap(wdt->feed_reg); | ||
| 468 | fail_free_feed: | ||
| 469 | release_mem_region(r2->start, resource_size(r2)); | ||
| 470 | fail_unmap_control: | ||
| 471 | iounmap(wdt->control_reg); | ||
| 472 | fail_free_control: | ||
| 473 | release_mem_region(r1->start, resource_size(r1)); | ||
| 474 | fail: | ||
| 475 | kfree(wdt); | ||
| 476 | return error; | ||
| 477 | } | 442 | } |
| 478 | 443 | ||
| 479 | static int ts72xx_wdt_remove(struct platform_device *pdev) | 444 | static int ts72xx_wdt_remove(struct platform_device *pdev) |
| 480 | { | 445 | { |
| 481 | struct ts72xx_wdt *wdt = platform_get_drvdata(pdev); | ||
| 482 | struct resource *res; | ||
| 483 | int error; | 446 | int error; |
| 484 | 447 | ||
| 485 | error = misc_deregister(&ts72xx_wdt_miscdev); | 448 | error = misc_deregister(&ts72xx_wdt_miscdev); |
| 486 | platform_set_drvdata(pdev, NULL); | ||
| 487 | |||
| 488 | iounmap(wdt->feed_reg); | ||
| 489 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
| 490 | release_mem_region(res->start, resource_size(res)); | ||
| 491 | |||
| 492 | iounmap(wdt->control_reg); | ||
| 493 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 494 | release_mem_region(res->start, resource_size(res)); | ||
| 495 | 449 | ||
| 496 | kfree(wdt); | ||
| 497 | return error; | 450 | return error; |
| 498 | } | 451 | } |
| 499 | 452 | ||
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index 0f03106f7516..2d4535dc2676 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c | |||
| @@ -90,10 +90,8 @@ static int twl4030_wdt_probe(struct platform_device *pdev) | |||
| 90 | twl4030_wdt_stop(wdt); | 90 | twl4030_wdt_stop(wdt); |
| 91 | 91 | ||
| 92 | ret = watchdog_register_device(wdt); | 92 | ret = watchdog_register_device(wdt); |
| 93 | if (ret) { | 93 | if (ret) |
| 94 | platform_set_drvdata(pdev, NULL); | ||
| 95 | return ret; | 94 | return ret; |
| 96 | } | ||
| 97 | 95 | ||
| 98 | return 0; | 96 | return 0; |
| 99 | } | 97 | } |
| @@ -103,7 +101,6 @@ static int twl4030_wdt_remove(struct platform_device *pdev) | |||
| 103 | struct watchdog_device *wdt = platform_get_drvdata(pdev); | 101 | struct watchdog_device *wdt = platform_get_drvdata(pdev); |
| 104 | 102 | ||
| 105 | watchdog_unregister_device(wdt); | 103 | watchdog_unregister_device(wdt); |
| 106 | platform_set_drvdata(pdev, NULL); | ||
| 107 | 104 | ||
| 108 | return 0; | 105 | return 0; |
| 109 | } | 106 | } |
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index faf4e189fe42..6aaefbad303e 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c | |||
| @@ -469,8 +469,10 @@ static int watchdog_release(struct inode *inode, struct file *file) | |||
| 469 | * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then | 469 | * or if WDIOF_MAGICCLOSE is not set. If nowayout was set then |
| 470 | * watchdog_stop will fail. | 470 | * watchdog_stop will fail. |
| 471 | */ | 471 | */ |
| 472 | if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) || | 472 | if (!test_bit(WDOG_ACTIVE, &wdd->status)) |
| 473 | !(wdd->info->options & WDIOF_MAGICCLOSE)) | 473 | err = 0; |
| 474 | else if (test_and_clear_bit(WDOG_ALLOW_RELEASE, &wdd->status) || | ||
| 475 | !(wdd->info->options & WDIOF_MAGICCLOSE)) | ||
| 474 | err = watchdog_stop(wdd); | 476 | err = watchdog_stop(wdd); |
| 475 | 477 | ||
| 476 | /* If the watchdog was not stopped, send a keepalive ping */ | 478 | /* If the watchdog was not stopped, send a keepalive ping */ |
diff --git a/drivers/watchdog/wdrtas.c b/drivers/watchdog/wdrtas.c index 0a77655cda60..3045debd5411 100644 --- a/drivers/watchdog/wdrtas.c +++ b/drivers/watchdog/wdrtas.c | |||
| @@ -162,31 +162,6 @@ static void wdrtas_timer_stop(void) | |||
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | /** | 164 | /** |
| 165 | * wdrtas_log_scanned_event - logs an event we received during keepalive | ||
| 166 | * | ||
| 167 | * wdrtas_log_scanned_event prints a message to the log buffer dumping | ||
| 168 | * the results of the last event-scan call | ||
| 169 | */ | ||
| 170 | static void wdrtas_log_scanned_event(void) | ||
| 171 | { | ||
| 172 | int i; | ||
| 173 | |||
| 174 | for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16) | ||
| 175 | pr_info("dumping event (line %i/%i), data = " | ||
| 176 | "%02x %02x %02x %02x %02x %02x %02x %02x " | ||
| 177 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", | ||
| 178 | (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16), | ||
| 179 | wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1], | ||
| 180 | wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3], | ||
| 181 | wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5], | ||
| 182 | wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7], | ||
| 183 | wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9], | ||
| 184 | wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11], | ||
| 185 | wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13], | ||
| 186 | wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]); | ||
| 187 | } | ||
| 188 | |||
| 189 | /** | ||
| 190 | * wdrtas_timer_keepalive - resets watchdog timer to keep system alive | 165 | * wdrtas_timer_keepalive - resets watchdog timer to keep system alive |
| 191 | * | 166 | * |
| 192 | * wdrtas_timer_keepalive restarts the watchdog timer by calling the | 167 | * wdrtas_timer_keepalive restarts the watchdog timer by calling the |
| @@ -205,7 +180,9 @@ static void wdrtas_timer_keepalive(void) | |||
| 205 | if (result < 0) | 180 | if (result < 0) |
| 206 | pr_err("event-scan failed: %li\n", result); | 181 | pr_err("event-scan failed: %li\n", result); |
| 207 | if (result == 0) | 182 | if (result == 0) |
| 208 | wdrtas_log_scanned_event(); | 183 | print_hex_dump(KERN_INFO, "dumping event, data: ", |
| 184 | DUMP_PREFIX_OFFSET, 16, 1, | ||
| 185 | wdrtas_logbuffer, WDRTAS_LOGBUFFER_LEN, false); | ||
| 209 | } while (result == 0); | 186 | } while (result == 0); |
| 210 | } | 187 | } |
| 211 | 188 | ||
diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 9dcb6d082277..d4e47eda4182 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c | |||
| @@ -247,9 +247,10 @@ static int wm831x_wdt_probe(struct platform_device *pdev) | |||
| 247 | reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT; | 247 | reg |= pdata->software << WM831X_WDOG_RST_SRC_SHIFT; |
| 248 | 248 | ||
| 249 | if (pdata->update_gpio) { | 249 | if (pdata->update_gpio) { |
| 250 | ret = gpio_request_one(pdata->update_gpio, | 250 | ret = devm_gpio_request_one(&pdev->dev, |
| 251 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, | 251 | pdata->update_gpio, |
| 252 | "Watchdog update"); | 252 | GPIOF_OUT_INIT_LOW, |
| 253 | "Watchdog update"); | ||
| 253 | if (ret < 0) { | 254 | if (ret < 0) { |
| 254 | dev_err(wm831x->dev, | 255 | dev_err(wm831x->dev, |
| 255 | "Failed to request update GPIO: %d\n", | 256 | "Failed to request update GPIO: %d\n", |
| @@ -270,7 +271,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev) | |||
| 270 | } else { | 271 | } else { |
| 271 | dev_err(wm831x->dev, | 272 | dev_err(wm831x->dev, |
| 272 | "Failed to unlock security key: %d\n", ret); | 273 | "Failed to unlock security key: %d\n", ret); |
| 273 | goto err_gpio; | 274 | goto err; |
| 274 | } | 275 | } |
| 275 | } | 276 | } |
| 276 | 277 | ||
| @@ -278,29 +279,23 @@ static int wm831x_wdt_probe(struct platform_device *pdev) | |||
| 278 | if (ret != 0) { | 279 | if (ret != 0) { |
| 279 | dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n", | 280 | dev_err(wm831x->dev, "watchdog_register_device() failed: %d\n", |
| 280 | ret); | 281 | ret); |
| 281 | goto err_gpio; | 282 | goto err; |
| 282 | } | 283 | } |
| 283 | 284 | ||
| 284 | dev_set_drvdata(&pdev->dev, driver_data); | 285 | platform_set_drvdata(pdev, driver_data); |
| 285 | 286 | ||
| 286 | return 0; | 287 | return 0; |
| 287 | 288 | ||
| 288 | err_gpio: | ||
| 289 | if (driver_data->update_gpio) | ||
| 290 | gpio_free(driver_data->update_gpio); | ||
| 291 | err: | 289 | err: |
| 292 | return ret; | 290 | return ret; |
| 293 | } | 291 | } |
| 294 | 292 | ||
| 295 | static int wm831x_wdt_remove(struct platform_device *pdev) | 293 | static int wm831x_wdt_remove(struct platform_device *pdev) |
| 296 | { | 294 | { |
| 297 | struct wm831x_wdt_drvdata *driver_data = dev_get_drvdata(&pdev->dev); | 295 | struct wm831x_wdt_drvdata *driver_data = platform_get_drvdata(pdev); |
| 298 | 296 | ||
| 299 | watchdog_unregister_device(&driver_data->wdt); | 297 | watchdog_unregister_device(&driver_data->wdt); |
| 300 | 298 | ||
| 301 | if (driver_data->update_gpio) | ||
| 302 | gpio_free(driver_data->update_gpio); | ||
| 303 | |||
| 304 | return 0; | 299 | return 0; |
| 305 | } | 300 | } |
| 306 | 301 | ||
