diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-18 11:42:47 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-18 11:42:47 -0500 |
| commit | 928fce2f6d8152d897790c1a5bbeef5642f69e0e (patch) | |
| tree | bb8b583bae3b76c94c274bbea47d07c00847f465 | |
| parent | a5ac1fb13c1265f942ea1d24c43b42d76c1660c2 (diff) | |
| parent | 94613431619b555ac1299634efabde2ffd0eb2b4 (diff) | |
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck:
"This adds the following new drivers:
- ImgTec PDC Watchdog Timer Driver,
- Mediatek SoC integrated watchdog
Add support for BCM5301X, IT8783, NCT6791 and NCT6792 WDT's
Add bcm47xx_wdt and da9063 restart handlers and contains overall
improvements and fixes"
* git://www.linux-watchdog.org/linux-watchdog:
watchdog: bcm47xx_wdt.c: allow enabling on BCM5301X arch
watchdog: jz4740: Add DT support
dt: watchdog: Add DT binding documentation for jz4740 watchdog timer
watchdog: dw_wdt: Try to get a 30 second watchdog by default
watchdog: dw_wdt: pat the watchdog before enabling it
watchdog: w83627hf_wdt: Add support for NCT6791 and NCT6792
watchdog: bcm47xx_wdt.c: add restart handler support
watchdog: gpio_wdt: Add "always_running" feature to GPIO watchdog
watchdog: da9063: Add restart handler support
ARM: mediatek: dts: Add bindings for watchdog
watchdog: Add driver for Mediatek watchdog
watchdog: Fix omap watchdogs to enable the magic close bit
watchdog: rt2880_wdt: minor clean up
watchdog: hpwdt: Fix initialization message in hpwdt.c
watchdog: it87_wdt: add IT8783 ID
watchdog: imx2: Constify struct regmap_config and watchdog_ops
DT: watchdog: Add ImgTec PDC Watchdog Timer binding documentation
watchdog: ImgTec PDC Watchdog Timer Driver
22 files changed, 758 insertions, 32 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt index 37afec194949..198794963786 100644 --- a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt | |||
| @@ -13,6 +13,11 @@ Required Properties: | |||
| 13 | by the GPIO flags. | 13 | by the GPIO flags. |
| 14 | - hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds). | 14 | - hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds). |
| 15 | 15 | ||
| 16 | Optional Properties: | ||
| 17 | - always-running: If the watchdog timer cannot be disabled, add this flag to | ||
| 18 | have the driver keep toggling the signal without a client. It will only cease | ||
| 19 | to toggle the signal when the device is open and the timeout elapsed. | ||
| 20 | |||
| 16 | Example: | 21 | Example: |
| 17 | watchdog: watchdog { | 22 | watchdog: watchdog { |
| 18 | /* ADM706 */ | 23 | /* ADM706 */ |
diff --git a/Documentation/devicetree/bindings/watchdog/imgpdc-wdt.txt b/Documentation/devicetree/bindings/watchdog/imgpdc-wdt.txt new file mode 100644 index 000000000000..b2fa11fd43de --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/imgpdc-wdt.txt | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | *ImgTec PowerDown Controller (PDC) Watchdog Timer (WDT) | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible : Should be "img,pdc-wdt" | ||
| 5 | - reg : Should contain WDT registers location and length | ||
| 6 | - clocks: Must contain an entry for each entry in clock-names. | ||
| 7 | - clock-names: Should contain "wdt" and "sys"; the watchdog counter | ||
| 8 | clock and register interface clock respectively. | ||
| 9 | - interrupts : Should contain WDT interrupt | ||
| 10 | |||
| 11 | Examples: | ||
| 12 | |||
| 13 | watchdog@18102100 { | ||
| 14 | compatible = "img,pdc-wdt"; | ||
| 15 | reg = <0x18102100 0x100>; | ||
| 16 | clocks = <&pdc_wdt_clk>, <&sys_clk>; | ||
| 17 | clock-names = "wdt", "sys"; | ||
| 18 | interrupts = <0 52 IRQ_TYPE_LEVEL_HIGH>; | ||
| 19 | }; | ||
diff --git a/Documentation/devicetree/bindings/watchdog/ingenic,jz4740-wdt.txt b/Documentation/devicetree/bindings/watchdog/ingenic,jz4740-wdt.txt new file mode 100644 index 000000000000..e27763ef0049 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/ingenic,jz4740-wdt.txt | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | Ingenic Watchdog Timer (WDT) Controller for JZ4740 | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | compatible: "ingenic,jz4740-watchdog" | ||
| 5 | reg: Register address and length for watchdog registers | ||
| 6 | |||
| 7 | Example: | ||
| 8 | |||
| 9 | watchdog: jz4740-watchdog@0x10002000 { | ||
| 10 | compatible = "ingenic,jz4740-watchdog"; | ||
| 11 | reg = <0x10002000 0x100>; | ||
| 12 | }; | ||
diff --git a/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt new file mode 100644 index 000000000000..af9eb5b8a253 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/mtk-wdt.txt | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | Mediatek SoCs Watchdog timer | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - compatible : should be "mediatek,mt6589-wdt" | ||
| 6 | - reg : Specifies base physical address and size of the registers. | ||
| 7 | |||
| 8 | Example: | ||
| 9 | |||
| 10 | wdt: watchdog@010000000 { | ||
| 11 | compatible = "mediatek,mt6589-wdt"; | ||
| 12 | reg = <0x10000000 0x18>; | ||
| 13 | }; | ||
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 08f41add1461..16f202350997 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
| @@ -505,6 +505,16 @@ config MESON_WATCHDOG | |||
| 505 | To compile this driver as a module, choose M here: the | 505 | To compile this driver as a module, choose M here: the |
| 506 | module will be called meson_wdt. | 506 | module will be called meson_wdt. |
| 507 | 507 | ||
| 508 | config MEDIATEK_WATCHDOG | ||
| 509 | tristate "Mediatek SoCs watchdog support" | ||
| 510 | depends on ARCH_MEDIATEK | ||
| 511 | select WATCHDOG_CORE | ||
| 512 | help | ||
| 513 | Say Y here to include support for the watchdog timer | ||
| 514 | in Mediatek SoCs. | ||
| 515 | To compile this driver as a module, choose M here: the | ||
| 516 | module will be called mtk_wdt. | ||
| 517 | |||
| 508 | # AVR32 Architecture | 518 | # AVR32 Architecture |
| 509 | 519 | ||
| 510 | config AT32AP700X_WDT | 520 | config AT32AP700X_WDT |
| @@ -1005,6 +1015,8 @@ config W83627HF_WDT | |||
| 1005 | NCT6775 | 1015 | NCT6775 |
| 1006 | NCT6776 | 1016 | NCT6776 |
| 1007 | NCT6779 | 1017 | NCT6779 |
| 1018 | NCT6791 | ||
| 1019 | NCT6792 | ||
| 1008 | 1020 | ||
| 1009 | This watchdog simply watches your kernel to make sure it doesn't | 1021 | This watchdog simply watches your kernel to make sure it doesn't |
| 1010 | freeze, and if it does, it reboots your computer after a certain | 1022 | freeze, and if it does, it reboots your computer after a certain |
| @@ -1101,7 +1113,7 @@ config ATH79_WDT | |||
| 1101 | 1113 | ||
| 1102 | config BCM47XX_WDT | 1114 | config BCM47XX_WDT |
| 1103 | tristate "Broadcom BCM47xx Watchdog Timer" | 1115 | tristate "Broadcom BCM47xx Watchdog Timer" |
| 1104 | depends on BCM47XX | 1116 | depends on BCM47XX || ARCH_BCM_5301X |
| 1105 | select WATCHDOG_CORE | 1117 | select WATCHDOG_CORE |
| 1106 | help | 1118 | help |
| 1107 | Hardware driver for the Broadcom BCM47xx Watchdog Timer. | 1119 | Hardware driver for the Broadcom BCM47xx Watchdog Timer. |
| @@ -1235,6 +1247,17 @@ config BCM_KONA_WDT_DEBUG | |||
| 1235 | 1247 | ||
| 1236 | If in doubt, say 'N'. | 1248 | If in doubt, say 'N'. |
| 1237 | 1249 | ||
| 1250 | config IMGPDC_WDT | ||
| 1251 | tristate "Imagination Technologies PDC Watchdog Timer" | ||
| 1252 | depends on HAS_IOMEM | ||
| 1253 | depends on METAG || MIPS || COMPILE_TEST | ||
| 1254 | help | ||
| 1255 | Driver for Imagination Technologies PowerDown Controller | ||
| 1256 | Watchdog Timer. | ||
| 1257 | |||
| 1258 | To compile this driver as a loadable module, choose M here. | ||
| 1259 | The module will be called imgpdc_wdt. | ||
| 1260 | |||
| 1238 | config LANTIQ_WDT | 1261 | config LANTIQ_WDT |
| 1239 | tristate "Lantiq SoC watchdog" | 1262 | tristate "Lantiq SoC watchdog" |
| 1240 | depends on LANTIQ | 1263 | depends on LANTIQ |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index c569ec8f8a76..5c19294d1c30 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
| @@ -63,6 +63,7 @@ obj-$(CONFIG_QCOM_WDT) += qcom-wdt.o | |||
| 63 | obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o | 63 | obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o |
| 64 | obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o | 64 | obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o |
| 65 | obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o | 65 | obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o |
| 66 | obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o | ||
| 66 | 67 | ||
| 67 | # AVR32 Architecture | 68 | # AVR32 Architecture |
| 68 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o | 69 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o |
| @@ -142,6 +143,7 @@ obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o | |||
| 142 | octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o | 143 | octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o |
| 143 | obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o | 144 | obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o |
| 144 | obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o | 145 | obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o |
| 146 | obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o | ||
| 145 | 147 | ||
| 146 | # PARISC Architecture | 148 | # PARISC Architecture |
| 147 | 149 | ||
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index 9816485f6825..b28a072abf78 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c | |||
| @@ -169,6 +169,17 @@ static int bcm47xx_wdt_notify_sys(struct notifier_block *this, | |||
| 169 | return NOTIFY_DONE; | 169 | return NOTIFY_DONE; |
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | static int bcm47xx_wdt_restart(struct notifier_block *this, unsigned long mode, | ||
| 173 | void *cmd) | ||
| 174 | { | ||
| 175 | struct bcm47xx_wdt *wdt; | ||
| 176 | |||
| 177 | wdt = container_of(this, struct bcm47xx_wdt, restart_handler); | ||
| 178 | wdt->timer_set(wdt, 1); | ||
| 179 | |||
| 180 | return NOTIFY_DONE; | ||
| 181 | } | ||
| 182 | |||
| 172 | static struct watchdog_ops bcm47xx_wdt_soft_ops = { | 183 | static struct watchdog_ops bcm47xx_wdt_soft_ops = { |
| 173 | .owner = THIS_MODULE, | 184 | .owner = THIS_MODULE, |
| 174 | .start = bcm47xx_wdt_soft_start, | 185 | .start = bcm47xx_wdt_soft_start, |
| @@ -209,15 +220,23 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev) | |||
| 209 | if (ret) | 220 | if (ret) |
| 210 | goto err_timer; | 221 | goto err_timer; |
| 211 | 222 | ||
| 212 | ret = watchdog_register_device(&wdt->wdd); | 223 | wdt->restart_handler.notifier_call = &bcm47xx_wdt_restart; |
| 224 | wdt->restart_handler.priority = 64; | ||
| 225 | ret = register_restart_handler(&wdt->restart_handler); | ||
| 213 | if (ret) | 226 | if (ret) |
| 214 | goto err_notifier; | 227 | goto err_notifier; |
| 215 | 228 | ||
| 229 | ret = watchdog_register_device(&wdt->wdd); | ||
| 230 | if (ret) | ||
| 231 | goto err_handler; | ||
| 232 | |||
| 216 | dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n", | 233 | dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n", |
| 217 | timeout, nowayout ? ", nowayout" : "", | 234 | timeout, nowayout ? ", nowayout" : "", |
| 218 | soft ? ", Software Timer" : ""); | 235 | soft ? ", Software Timer" : ""); |
| 219 | return 0; | 236 | return 0; |
| 220 | 237 | ||
| 238 | err_handler: | ||
| 239 | unregister_restart_handler(&wdt->restart_handler); | ||
| 221 | err_notifier: | 240 | err_notifier: |
| 222 | unregister_reboot_notifier(&wdt->notifier); | 241 | unregister_reboot_notifier(&wdt->notifier); |
| 223 | err_timer: | 242 | err_timer: |
diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index 2cd6b2c2dd2a..e2fe2ebdebd4 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
| 21 | #include <linux/mfd/da9063/registers.h> | 21 | #include <linux/mfd/da9063/registers.h> |
| 22 | #include <linux/mfd/da9063/core.h> | 22 | #include <linux/mfd/da9063/core.h> |
| 23 | #include <linux/reboot.h> | ||
| 23 | #include <linux/regmap.h> | 24 | #include <linux/regmap.h> |
| 24 | 25 | ||
| 25 | /* | 26 | /* |
| @@ -38,6 +39,7 @@ static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 }; | |||
| 38 | struct da9063_watchdog { | 39 | struct da9063_watchdog { |
| 39 | struct da9063 *da9063; | 40 | struct da9063 *da9063; |
| 40 | struct watchdog_device wdtdev; | 41 | struct watchdog_device wdtdev; |
| 42 | struct notifier_block restart_handler; | ||
| 41 | }; | 43 | }; |
| 42 | 44 | ||
| 43 | static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs) | 45 | static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs) |
| @@ -119,6 +121,23 @@ static int da9063_wdt_set_timeout(struct watchdog_device *wdd, | |||
| 119 | return ret; | 121 | return ret; |
| 120 | } | 122 | } |
| 121 | 123 | ||
| 124 | static int da9063_wdt_restart_handler(struct notifier_block *this, | ||
| 125 | unsigned long mode, void *cmd) | ||
| 126 | { | ||
| 127 | struct da9063_watchdog *wdt = container_of(this, | ||
| 128 | struct da9063_watchdog, | ||
| 129 | restart_handler); | ||
| 130 | int ret; | ||
| 131 | |||
| 132 | ret = regmap_write(wdt->da9063->regmap, DA9063_REG_CONTROL_F, | ||
| 133 | DA9063_SHUTDOWN); | ||
| 134 | if (ret) | ||
| 135 | dev_alert(wdt->da9063->dev, "Failed to shutdown (err = %d)\n", | ||
| 136 | ret); | ||
| 137 | |||
| 138 | return NOTIFY_DONE; | ||
| 139 | } | ||
| 140 | |||
| 122 | static const struct watchdog_info da9063_watchdog_info = { | 141 | static const struct watchdog_info da9063_watchdog_info = { |
| 123 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 142 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, |
| 124 | .identity = "DA9063 Watchdog", | 143 | .identity = "DA9063 Watchdog", |
| @@ -163,14 +182,25 @@ static int da9063_wdt_probe(struct platform_device *pdev) | |||
| 163 | dev_set_drvdata(&pdev->dev, wdt); | 182 | dev_set_drvdata(&pdev->dev, wdt); |
| 164 | 183 | ||
| 165 | ret = watchdog_register_device(&wdt->wdtdev); | 184 | ret = watchdog_register_device(&wdt->wdtdev); |
| 185 | if (ret) | ||
| 186 | return ret; | ||
| 166 | 187 | ||
| 167 | return ret; | 188 | wdt->restart_handler.notifier_call = da9063_wdt_restart_handler; |
| 189 | wdt->restart_handler.priority = 128; | ||
| 190 | ret = register_restart_handler(&wdt->restart_handler); | ||
| 191 | if (ret) | ||
| 192 | dev_err(wdt->da9063->dev, | ||
| 193 | "Failed to register restart handler (err = %d)\n", ret); | ||
| 194 | |||
| 195 | return 0; | ||
| 168 | } | 196 | } |
| 169 | 197 | ||
| 170 | static int da9063_wdt_remove(struct platform_device *pdev) | 198 | static int da9063_wdt_remove(struct platform_device *pdev) |
| 171 | { | 199 | { |
| 172 | struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev); | 200 | struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev); |
| 173 | 201 | ||
| 202 | unregister_restart_handler(&wdt->restart_handler); | ||
| 203 | |||
| 174 | watchdog_unregister_device(&wdt->wdtdev); | 204 | watchdog_unregister_device(&wdt->wdtdev); |
| 175 | 205 | ||
| 176 | return 0; | 206 | return 0; |
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index b34a2e4e4e43..d0bb9499d12c 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c | |||
| @@ -51,6 +51,8 @@ | |||
| 51 | /* The maximum TOP (timeout period) value that can be set in the watchdog. */ | 51 | /* The maximum TOP (timeout period) value that can be set in the watchdog. */ |
| 52 | #define DW_WDT_MAX_TOP 15 | 52 | #define DW_WDT_MAX_TOP 15 |
| 53 | 53 | ||
| 54 | #define DW_WDT_DEFAULT_SECONDS 30 | ||
| 55 | |||
| 54 | static bool nowayout = WATCHDOG_NOWAYOUT; | 56 | static bool nowayout = WATCHDOG_NOWAYOUT; |
| 55 | module_param(nowayout, bool, 0); | 57 | module_param(nowayout, bool, 0); |
| 56 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " | 58 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " |
| @@ -96,6 +98,12 @@ static inline void dw_wdt_set_next_heartbeat(void) | |||
| 96 | dw_wdt.next_heartbeat = jiffies + dw_wdt_get_top() * HZ; | 98 | dw_wdt.next_heartbeat = jiffies + dw_wdt_get_top() * HZ; |
| 97 | } | 99 | } |
| 98 | 100 | ||
| 101 | static void dw_wdt_keepalive(void) | ||
| 102 | { | ||
| 103 | writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs + | ||
| 104 | WDOG_COUNTER_RESTART_REG_OFFSET); | ||
| 105 | } | ||
| 106 | |||
| 99 | static int dw_wdt_set_top(unsigned top_s) | 107 | static int dw_wdt_set_top(unsigned top_s) |
| 100 | { | 108 | { |
| 101 | int i, top_val = DW_WDT_MAX_TOP; | 109 | int i, top_val = DW_WDT_MAX_TOP; |
| @@ -110,21 +118,27 @@ static int dw_wdt_set_top(unsigned top_s) | |||
| 110 | break; | 118 | break; |
| 111 | } | 119 | } |
| 112 | 120 | ||
| 113 | /* Set the new value in the watchdog. */ | 121 | /* |
| 122 | * Set the new value in the watchdog. Some versions of dw_wdt | ||
| 123 | * have have TOPINIT in the TIMEOUT_RANGE register (as per | ||
| 124 | * CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1). On those we | ||
| 125 | * effectively get a pat of the watchdog right here. | ||
| 126 | */ | ||
| 114 | writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT, | 127 | writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT, |
| 115 | dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); | 128 | dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET); |
| 116 | 129 | ||
| 130 | /* | ||
| 131 | * Add an explicit pat to handle versions of the watchdog that | ||
| 132 | * don't have TOPINIT. This won't hurt on versions that have | ||
| 133 | * it. | ||
| 134 | */ | ||
| 135 | dw_wdt_keepalive(); | ||
| 136 | |||
| 117 | dw_wdt_set_next_heartbeat(); | 137 | dw_wdt_set_next_heartbeat(); |
| 118 | 138 | ||
| 119 | return dw_wdt_top_in_seconds(top_val); | 139 | return dw_wdt_top_in_seconds(top_val); |
| 120 | } | 140 | } |
| 121 | 141 | ||
| 122 | static void dw_wdt_keepalive(void) | ||
| 123 | { | ||
| 124 | writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs + | ||
| 125 | WDOG_COUNTER_RESTART_REG_OFFSET); | ||
| 126 | } | ||
| 127 | |||
| 128 | static int dw_wdt_restart_handle(struct notifier_block *this, | 142 | static int dw_wdt_restart_handle(struct notifier_block *this, |
| 129 | unsigned long mode, void *cmd) | 143 | unsigned long mode, void *cmd) |
| 130 | { | 144 | { |
| @@ -167,9 +181,9 @@ static int dw_wdt_open(struct inode *inode, struct file *filp) | |||
| 167 | if (!dw_wdt_is_enabled()) { | 181 | if (!dw_wdt_is_enabled()) { |
| 168 | /* | 182 | /* |
| 169 | * The watchdog is not currently enabled. Set the timeout to | 183 | * The watchdog is not currently enabled. Set the timeout to |
| 170 | * the maximum and then start it. | 184 | * something reasonable and then start it. |
| 171 | */ | 185 | */ |
| 172 | dw_wdt_set_top(DW_WDT_MAX_TOP); | 186 | dw_wdt_set_top(DW_WDT_DEFAULT_SECONDS); |
| 173 | writel(WDOG_CONTROL_REG_WDT_EN_MASK, | 187 | writel(WDOG_CONTROL_REG_WDT_EN_MASK, |
| 174 | dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); | 188 | dw_wdt.regs + WDOG_CONTROL_REG_OFFSET); |
| 175 | } | 189 | } |
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c index bbdb19b45332..cbc313d37c59 100644 --- a/drivers/watchdog/gpio_wdt.c +++ b/drivers/watchdog/gpio_wdt.c | |||
| @@ -31,6 +31,8 @@ struct gpio_wdt_priv { | |||
| 31 | int gpio; | 31 | int gpio; |
| 32 | bool active_low; | 32 | bool active_low; |
| 33 | bool state; | 33 | bool state; |
| 34 | bool always_running; | ||
| 35 | bool armed; | ||
| 34 | unsigned int hw_algo; | 36 | unsigned int hw_algo; |
| 35 | unsigned int hw_margin; | 37 | unsigned int hw_margin; |
| 36 | unsigned long last_jiffies; | 38 | unsigned long last_jiffies; |
| @@ -48,14 +50,20 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv) | |||
| 48 | gpio_direction_input(priv->gpio); | 50 | gpio_direction_input(priv->gpio); |
| 49 | } | 51 | } |
| 50 | 52 | ||
| 51 | static int gpio_wdt_start(struct watchdog_device *wdd) | 53 | static void gpio_wdt_start_impl(struct gpio_wdt_priv *priv) |
| 52 | { | 54 | { |
| 53 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||
| 54 | |||
| 55 | priv->state = priv->active_low; | 55 | priv->state = priv->active_low; |
| 56 | gpio_direction_output(priv->gpio, priv->state); | 56 | gpio_direction_output(priv->gpio, priv->state); |
| 57 | priv->last_jiffies = jiffies; | 57 | priv->last_jiffies = jiffies; |
| 58 | mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin); | 58 | mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin); |
| 59 | } | ||
| 60 | |||
| 61 | static int gpio_wdt_start(struct watchdog_device *wdd) | ||
| 62 | { | ||
| 63 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||
| 64 | |||
| 65 | gpio_wdt_start_impl(priv); | ||
| 66 | priv->armed = true; | ||
| 59 | 67 | ||
| 60 | return 0; | 68 | return 0; |
| 61 | } | 69 | } |
| @@ -64,8 +72,11 @@ static int gpio_wdt_stop(struct watchdog_device *wdd) | |||
| 64 | { | 72 | { |
| 65 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | 73 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 66 | 74 | ||
| 67 | mod_timer(&priv->timer, 0); | 75 | priv->armed = false; |
| 68 | gpio_wdt_disable(priv); | 76 | if (!priv->always_running) { |
| 77 | mod_timer(&priv->timer, 0); | ||
| 78 | gpio_wdt_disable(priv); | ||
| 79 | } | ||
| 69 | 80 | ||
| 70 | return 0; | 81 | return 0; |
| 71 | } | 82 | } |
| @@ -91,8 +102,8 @@ static void gpio_wdt_hwping(unsigned long data) | |||
| 91 | struct watchdog_device *wdd = (struct watchdog_device *)data; | 102 | struct watchdog_device *wdd = (struct watchdog_device *)data; |
| 92 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | 103 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); |
| 93 | 104 | ||
| 94 | if (time_after(jiffies, priv->last_jiffies + | 105 | if (priv->armed && time_after(jiffies, priv->last_jiffies + |
| 95 | msecs_to_jiffies(wdd->timeout * 1000))) { | 106 | msecs_to_jiffies(wdd->timeout * 1000))) { |
| 96 | dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); | 107 | dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); |
| 97 | return; | 108 | return; |
| 98 | } | 109 | } |
| @@ -197,6 +208,9 @@ static int gpio_wdt_probe(struct platform_device *pdev) | |||
| 197 | /* Use safe value (1/2 of real timeout) */ | 208 | /* Use safe value (1/2 of real timeout) */ |
| 198 | priv->hw_margin = msecs_to_jiffies(hw_margin / 2); | 209 | priv->hw_margin = msecs_to_jiffies(hw_margin / 2); |
| 199 | 210 | ||
| 211 | priv->always_running = of_property_read_bool(pdev->dev.of_node, | ||
| 212 | "always-running"); | ||
| 213 | |||
| 200 | watchdog_set_drvdata(&priv->wdd, priv); | 214 | watchdog_set_drvdata(&priv->wdd, priv); |
| 201 | 215 | ||
| 202 | priv->wdd.info = &gpio_wdt_ident; | 216 | priv->wdd.info = &gpio_wdt_ident; |
| @@ -216,8 +230,15 @@ static int gpio_wdt_probe(struct platform_device *pdev) | |||
| 216 | priv->notifier.notifier_call = gpio_wdt_notify_sys; | 230 | priv->notifier.notifier_call = gpio_wdt_notify_sys; |
| 217 | ret = register_reboot_notifier(&priv->notifier); | 231 | ret = register_reboot_notifier(&priv->notifier); |
| 218 | if (ret) | 232 | if (ret) |
| 219 | watchdog_unregister_device(&priv->wdd); | 233 | goto error_unregister; |
| 220 | 234 | ||
| 235 | if (priv->always_running) | ||
| 236 | gpio_wdt_start_impl(priv); | ||
| 237 | |||
| 238 | return 0; | ||
| 239 | |||
| 240 | error_unregister: | ||
| 241 | watchdog_unregister_device(&priv->wdd); | ||
| 221 | return ret; | 242 | return ret; |
| 222 | } | 243 | } |
| 223 | 244 | ||
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 75d2243b94f5..ada3e44f9932 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
| @@ -745,7 +745,7 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev) | |||
| 745 | 745 | ||
| 746 | dev_info(&dev->dev, | 746 | dev_info(&dev->dev, |
| 747 | "HP Watchdog Timer Driver: NMI decoding initialized" | 747 | "HP Watchdog Timer Driver: NMI decoding initialized" |
| 748 | ", allow kernel dump: %s (default = 0/OFF)\n", | 748 | ", allow kernel dump: %s (default = 1/ON)\n", |
| 749 | (allow_kdump == 0) ? "OFF" : "ON"); | 749 | (allow_kdump == 0) ? "OFF" : "ON"); |
| 750 | return 0; | 750 | return 0; |
| 751 | 751 | ||
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c new file mode 100644 index 000000000000..c8def68d9e4c --- /dev/null +++ b/drivers/watchdog/imgpdc_wdt.c | |||
| @@ -0,0 +1,289 @@ | |||
| 1 | /* | ||
| 2 | * Imagination Technologies PowerDown Controller Watchdog Timer. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2014 Imagination Technologies Ltd. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License version 2 as published by | ||
| 8 | * the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * Based on drivers/watchdog/sunxi_wdt.c Copyright (c) 2013 Carlo Caione | ||
| 11 | * 2012 Henrik Nordstrom | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/clk.h> | ||
| 15 | #include <linux/io.h> | ||
| 16 | #include <linux/log2.h> | ||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/watchdog.h> | ||
| 21 | |||
| 22 | /* registers */ | ||
| 23 | #define PDC_WDT_SOFT_RESET 0x00 | ||
| 24 | #define PDC_WDT_CONFIG 0x04 | ||
| 25 | #define PDC_WDT_CONFIG_ENABLE BIT(31) | ||
| 26 | #define PDC_WDT_CONFIG_DELAY_MASK 0x1f | ||
| 27 | |||
| 28 | #define PDC_WDT_TICKLE1 0x08 | ||
| 29 | #define PDC_WDT_TICKLE1_MAGIC 0xabcd1234 | ||
| 30 | #define PDC_WDT_TICKLE2 0x0c | ||
| 31 | #define PDC_WDT_TICKLE2_MAGIC 0x4321dcba | ||
| 32 | |||
| 33 | #define PDC_WDT_TICKLE_STATUS_MASK 0x7 | ||
| 34 | #define PDC_WDT_TICKLE_STATUS_SHIFT 0 | ||
| 35 | #define PDC_WDT_TICKLE_STATUS_HRESET 0x0 /* Hard reset */ | ||
| 36 | #define PDC_WDT_TICKLE_STATUS_TIMEOUT 0x1 /* Timeout */ | ||
| 37 | #define PDC_WDT_TICKLE_STATUS_TICKLE 0x2 /* Tickled incorrectly */ | ||
| 38 | #define PDC_WDT_TICKLE_STATUS_SRESET 0x3 /* Soft reset */ | ||
| 39 | #define PDC_WDT_TICKLE_STATUS_USER 0x4 /* User reset */ | ||
| 40 | |||
| 41 | /* Timeout values are in seconds */ | ||
| 42 | #define PDC_WDT_MIN_TIMEOUT 1 | ||
| 43 | #define PDC_WDT_DEF_TIMEOUT 64 | ||
| 44 | |||
| 45 | static int heartbeat; | ||
| 46 | module_param(heartbeat, int, 0); | ||
| 47 | MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. " | ||
| 48 | "(default = " __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")"); | ||
| 49 | |||
| 50 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
| 51 | module_param(nowayout, bool, 0); | ||
| 52 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " | ||
| 53 | "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 54 | |||
| 55 | struct pdc_wdt_dev { | ||
| 56 | struct watchdog_device wdt_dev; | ||
| 57 | struct clk *wdt_clk; | ||
| 58 | struct clk *sys_clk; | ||
| 59 | void __iomem *base; | ||
| 60 | }; | ||
| 61 | |||
| 62 | static int pdc_wdt_keepalive(struct watchdog_device *wdt_dev) | ||
| 63 | { | ||
| 64 | struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev); | ||
| 65 | |||
| 66 | writel(PDC_WDT_TICKLE1_MAGIC, wdt->base + PDC_WDT_TICKLE1); | ||
| 67 | writel(PDC_WDT_TICKLE2_MAGIC, wdt->base + PDC_WDT_TICKLE2); | ||
| 68 | |||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | static int pdc_wdt_stop(struct watchdog_device *wdt_dev) | ||
| 73 | { | ||
| 74 | unsigned int val; | ||
| 75 | struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev); | ||
| 76 | |||
| 77 | val = readl(wdt->base + PDC_WDT_CONFIG); | ||
| 78 | val &= ~PDC_WDT_CONFIG_ENABLE; | ||
| 79 | writel(val, wdt->base + PDC_WDT_CONFIG); | ||
| 80 | |||
| 81 | /* Must tickle to finish the stop */ | ||
| 82 | pdc_wdt_keepalive(wdt_dev); | ||
| 83 | |||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int pdc_wdt_set_timeout(struct watchdog_device *wdt_dev, | ||
| 88 | unsigned int new_timeout) | ||
| 89 | { | ||
| 90 | unsigned int val; | ||
| 91 | struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev); | ||
| 92 | unsigned long clk_rate = clk_get_rate(wdt->wdt_clk); | ||
| 93 | |||
| 94 | wdt->wdt_dev.timeout = new_timeout; | ||
| 95 | |||
| 96 | val = readl(wdt->base + PDC_WDT_CONFIG) & ~PDC_WDT_CONFIG_DELAY_MASK; | ||
| 97 | val |= order_base_2(new_timeout * clk_rate) - 1; | ||
| 98 | writel(val, wdt->base + PDC_WDT_CONFIG); | ||
| 99 | |||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | /* Start the watchdog timer (delay should already be set) */ | ||
| 104 | static int pdc_wdt_start(struct watchdog_device *wdt_dev) | ||
| 105 | { | ||
| 106 | unsigned int val; | ||
| 107 | struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev); | ||
| 108 | |||
| 109 | val = readl(wdt->base + PDC_WDT_CONFIG); | ||
| 110 | val |= PDC_WDT_CONFIG_ENABLE; | ||
| 111 | writel(val, wdt->base + PDC_WDT_CONFIG); | ||
| 112 | |||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | static struct watchdog_info pdc_wdt_info = { | ||
| 117 | .identity = "IMG PDC Watchdog", | ||
| 118 | .options = WDIOF_SETTIMEOUT | | ||
| 119 | WDIOF_KEEPALIVEPING | | ||
| 120 | WDIOF_MAGICCLOSE, | ||
| 121 | }; | ||
| 122 | |||
| 123 | static const struct watchdog_ops pdc_wdt_ops = { | ||
| 124 | .owner = THIS_MODULE, | ||
| 125 | .start = pdc_wdt_start, | ||
| 126 | .stop = pdc_wdt_stop, | ||
| 127 | .ping = pdc_wdt_keepalive, | ||
| 128 | .set_timeout = pdc_wdt_set_timeout, | ||
| 129 | }; | ||
| 130 | |||
| 131 | static int pdc_wdt_probe(struct platform_device *pdev) | ||
| 132 | { | ||
| 133 | int ret, val; | ||
| 134 | unsigned long clk_rate; | ||
| 135 | struct resource *res; | ||
| 136 | struct pdc_wdt_dev *pdc_wdt; | ||
| 137 | |||
| 138 | pdc_wdt = devm_kzalloc(&pdev->dev, sizeof(*pdc_wdt), GFP_KERNEL); | ||
| 139 | if (!pdc_wdt) | ||
| 140 | return -ENOMEM; | ||
| 141 | |||
| 142 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 143 | pdc_wdt->base = devm_ioremap_resource(&pdev->dev, res); | ||
| 144 | if (IS_ERR(pdc_wdt->base)) | ||
| 145 | return PTR_ERR(pdc_wdt->base); | ||
| 146 | |||
| 147 | pdc_wdt->sys_clk = devm_clk_get(&pdev->dev, "sys"); | ||
| 148 | if (IS_ERR(pdc_wdt->sys_clk)) { | ||
| 149 | dev_err(&pdev->dev, "failed to get the sys clock\n"); | ||
| 150 | return PTR_ERR(pdc_wdt->sys_clk); | ||
| 151 | } | ||
| 152 | |||
| 153 | pdc_wdt->wdt_clk = devm_clk_get(&pdev->dev, "wdt"); | ||
| 154 | if (IS_ERR(pdc_wdt->wdt_clk)) { | ||
| 155 | dev_err(&pdev->dev, "failed to get the wdt clock\n"); | ||
| 156 | return PTR_ERR(pdc_wdt->wdt_clk); | ||
| 157 | } | ||
| 158 | |||
| 159 | ret = clk_prepare_enable(pdc_wdt->sys_clk); | ||
| 160 | if (ret) { | ||
| 161 | dev_err(&pdev->dev, "could not prepare or enable sys clock\n"); | ||
| 162 | return ret; | ||
| 163 | } | ||
| 164 | |||
| 165 | ret = clk_prepare_enable(pdc_wdt->wdt_clk); | ||
| 166 | if (ret) { | ||
| 167 | dev_err(&pdev->dev, "could not prepare or enable wdt clock\n"); | ||
| 168 | goto disable_sys_clk; | ||
| 169 | } | ||
| 170 | |||
| 171 | /* We use the clock rate to calculate the max timeout */ | ||
| 172 | clk_rate = clk_get_rate(pdc_wdt->wdt_clk); | ||
| 173 | if (clk_rate == 0) { | ||
| 174 | dev_err(&pdev->dev, "failed to get clock rate\n"); | ||
| 175 | ret = -EINVAL; | ||
| 176 | goto disable_wdt_clk; | ||
| 177 | } | ||
| 178 | |||
| 179 | if (order_base_2(clk_rate) > PDC_WDT_CONFIG_DELAY_MASK + 1) { | ||
| 180 | dev_err(&pdev->dev, "invalid clock rate\n"); | ||
| 181 | ret = -EINVAL; | ||
| 182 | goto disable_wdt_clk; | ||
| 183 | } | ||
| 184 | |||
| 185 | if (order_base_2(clk_rate) == 0) | ||
| 186 | pdc_wdt->wdt_dev.min_timeout = PDC_WDT_MIN_TIMEOUT + 1; | ||
| 187 | else | ||
| 188 | pdc_wdt->wdt_dev.min_timeout = PDC_WDT_MIN_TIMEOUT; | ||
| 189 | |||
| 190 | pdc_wdt->wdt_dev.info = &pdc_wdt_info; | ||
| 191 | pdc_wdt->wdt_dev.ops = &pdc_wdt_ops; | ||
| 192 | pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK; | ||
| 193 | pdc_wdt->wdt_dev.parent = &pdev->dev; | ||
| 194 | |||
| 195 | ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev); | ||
| 196 | if (ret < 0) { | ||
| 197 | pdc_wdt->wdt_dev.timeout = pdc_wdt->wdt_dev.max_timeout; | ||
| 198 | dev_warn(&pdev->dev, | ||
| 199 | "Initial timeout out of range! setting max timeout\n"); | ||
| 200 | } | ||
| 201 | |||
| 202 | pdc_wdt_stop(&pdc_wdt->wdt_dev); | ||
| 203 | |||
| 204 | /* Find what caused the last reset */ | ||
| 205 | val = readl(pdc_wdt->base + PDC_WDT_TICKLE1); | ||
| 206 | val = (val & PDC_WDT_TICKLE_STATUS_MASK) >> PDC_WDT_TICKLE_STATUS_SHIFT; | ||
| 207 | switch (val) { | ||
| 208 | case PDC_WDT_TICKLE_STATUS_TICKLE: | ||
| 209 | case PDC_WDT_TICKLE_STATUS_TIMEOUT: | ||
| 210 | pdc_wdt->wdt_dev.bootstatus |= WDIOF_CARDRESET; | ||
| 211 | dev_info(&pdev->dev, | ||
| 212 | "watchdog module last reset due to timeout\n"); | ||
| 213 | break; | ||
| 214 | case PDC_WDT_TICKLE_STATUS_HRESET: | ||
| 215 | dev_info(&pdev->dev, | ||
| 216 | "watchdog module last reset due to hard reset\n"); | ||
| 217 | break; | ||
| 218 | case PDC_WDT_TICKLE_STATUS_SRESET: | ||
| 219 | dev_info(&pdev->dev, | ||
| 220 | "watchdog module last reset due to soft reset\n"); | ||
| 221 | break; | ||
| 222 | case PDC_WDT_TICKLE_STATUS_USER: | ||
| 223 | dev_info(&pdev->dev, | ||
| 224 | "watchdog module last reset due to user reset\n"); | ||
| 225 | break; | ||
| 226 | default: | ||
| 227 | dev_info(&pdev->dev, | ||
| 228 | "contains an illegal status code (%08x)\n", val); | ||
| 229 | break; | ||
| 230 | } | ||
| 231 | |||
| 232 | watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout); | ||
| 233 | |||
| 234 | platform_set_drvdata(pdev, pdc_wdt); | ||
| 235 | watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt); | ||
| 236 | |||
| 237 | ret = watchdog_register_device(&pdc_wdt->wdt_dev); | ||
| 238 | if (ret) | ||
| 239 | goto disable_wdt_clk; | ||
| 240 | |||
| 241 | return 0; | ||
| 242 | |||
| 243 | disable_wdt_clk: | ||
| 244 | clk_disable_unprepare(pdc_wdt->wdt_clk); | ||
| 245 | disable_sys_clk: | ||
| 246 | clk_disable_unprepare(pdc_wdt->sys_clk); | ||
| 247 | return ret; | ||
| 248 | } | ||
| 249 | |||
| 250 | static void pdc_wdt_shutdown(struct platform_device *pdev) | ||
| 251 | { | ||
| 252 | struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev); | ||
| 253 | |||
| 254 | pdc_wdt_stop(&pdc_wdt->wdt_dev); | ||
| 255 | } | ||
| 256 | |||
| 257 | static int pdc_wdt_remove(struct platform_device *pdev) | ||
| 258 | { | ||
| 259 | struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev); | ||
| 260 | |||
| 261 | pdc_wdt_stop(&pdc_wdt->wdt_dev); | ||
| 262 | watchdog_unregister_device(&pdc_wdt->wdt_dev); | ||
| 263 | clk_disable_unprepare(pdc_wdt->wdt_clk); | ||
| 264 | clk_disable_unprepare(pdc_wdt->sys_clk); | ||
| 265 | |||
| 266 | return 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | static const struct of_device_id pdc_wdt_match[] = { | ||
| 270 | { .compatible = "img,pdc-wdt" }, | ||
| 271 | {} | ||
| 272 | }; | ||
| 273 | MODULE_DEVICE_TABLE(of, pdc_wdt_match); | ||
| 274 | |||
| 275 | static struct platform_driver pdc_wdt_driver = { | ||
| 276 | .driver = { | ||
| 277 | .name = "imgpdc-wdt", | ||
| 278 | .of_match_table = pdc_wdt_match, | ||
| 279 | }, | ||
| 280 | .probe = pdc_wdt_probe, | ||
| 281 | .remove = pdc_wdt_remove, | ||
| 282 | .shutdown = pdc_wdt_shutdown, | ||
| 283 | }; | ||
| 284 | module_platform_driver(pdc_wdt_driver); | ||
| 285 | |||
| 286 | MODULE_AUTHOR("Jude Abraham <Jude.Abraham@imgtec.com>"); | ||
| 287 | MODULE_AUTHOR("Naidu Tellapati <Naidu.Tellapati@imgtec.com>"); | ||
| 288 | MODULE_DESCRIPTION("Imagination Technologies PDC Watchdog Timer Driver"); | ||
| 289 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c index 5142bbabe027..5e6d808d358a 100644 --- a/drivers/watchdog/imx2_wdt.c +++ b/drivers/watchdog/imx2_wdt.c | |||
| @@ -205,7 +205,7 @@ static inline void imx2_wdt_ping_if_active(struct watchdog_device *wdog) | |||
| 205 | } | 205 | } |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | static struct watchdog_ops imx2_wdt_ops = { | 208 | static const struct watchdog_ops imx2_wdt_ops = { |
| 209 | .owner = THIS_MODULE, | 209 | .owner = THIS_MODULE, |
| 210 | .start = imx2_wdt_start, | 210 | .start = imx2_wdt_start, |
| 211 | .stop = imx2_wdt_stop, | 211 | .stop = imx2_wdt_stop, |
| @@ -213,7 +213,7 @@ static struct watchdog_ops imx2_wdt_ops = { | |||
| 213 | .set_timeout = imx2_wdt_set_timeout, | 213 | .set_timeout = imx2_wdt_set_timeout, |
| 214 | }; | 214 | }; |
| 215 | 215 | ||
| 216 | static struct regmap_config imx2_wdt_regmap_config = { | 216 | static const struct regmap_config imx2_wdt_regmap_config = { |
| 217 | .reg_bits = 16, | 217 | .reg_bits = 16, |
| 218 | .reg_stride = 2, | 218 | .reg_stride = 2, |
| 219 | .val_bits = 16, | 219 | .val_bits = 16, |
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index 0b93739c0106..e54839b12650 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c | |||
| @@ -12,8 +12,8 @@ | |||
| 12 | * http://www.ite.com.tw/ | 12 | * http://www.ite.com.tw/ |
| 13 | * | 13 | * |
| 14 | * Support of the watchdog timers, which are available on | 14 | * Support of the watchdog timers, which are available on |
| 15 | * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 | 15 | * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726, |
| 16 | * and IT8728. | 16 | * IT8728 and IT8783. |
| 17 | * | 17 | * |
| 18 | * This program is free software; you can redistribute it and/or | 18 | * This program is free software; you can redistribute it and/or |
| 19 | * modify it under the terms of the GNU General Public License | 19 | * modify it under the terms of the GNU General Public License |
| @@ -87,6 +87,7 @@ | |||
| 87 | #define IT8721_ID 0x8721 | 87 | #define IT8721_ID 0x8721 |
| 88 | #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ | 88 | #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ |
| 89 | #define IT8728_ID 0x8728 | 89 | #define IT8728_ID 0x8728 |
| 90 | #define IT8783_ID 0x8783 | ||
| 90 | 91 | ||
| 91 | /* GPIO Configuration Registers LDN=0x07 */ | 92 | /* GPIO Configuration Registers LDN=0x07 */ |
| 92 | #define WDTCTRL 0x71 | 93 | #define WDTCTRL 0x71 |
| @@ -633,6 +634,7 @@ static int __init it87_wdt_init(void) | |||
| 633 | case IT8720_ID: | 634 | case IT8720_ID: |
| 634 | case IT8721_ID: | 635 | case IT8721_ID: |
| 635 | case IT8728_ID: | 636 | case IT8728_ID: |
| 637 | case IT8783_ID: | ||
| 636 | max_units = 65535; | 638 | max_units = 65535; |
| 637 | try_gameport = 0; | 639 | try_gameport = 0; |
| 638 | break; | 640 | break; |
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c index 18e41afa4da3..4c2cc09c0c57 100644 --- a/drivers/watchdog/jz4740_wdt.c +++ b/drivers/watchdog/jz4740_wdt.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/err.h> | 26 | #include <linux/err.h> |
| 27 | #include <linux/of.h> | ||
| 27 | 28 | ||
| 28 | #include <asm/mach-jz4740/timer.h> | 29 | #include <asm/mach-jz4740/timer.h> |
| 29 | 30 | ||
| @@ -142,6 +143,14 @@ static const struct watchdog_ops jz4740_wdt_ops = { | |||
| 142 | .set_timeout = jz4740_wdt_set_timeout, | 143 | .set_timeout = jz4740_wdt_set_timeout, |
| 143 | }; | 144 | }; |
| 144 | 145 | ||
| 146 | #ifdef CONFIG_OF | ||
| 147 | static const struct of_device_id jz4740_wdt_of_matches[] = { | ||
| 148 | { .compatible = "ingenic,jz4740-watchdog", }, | ||
| 149 | { /* sentinel */ } | ||
| 150 | }; | ||
| 151 | MODULE_DEVICE_TABLE(of, jz4740_wdt_of_matches) | ||
| 152 | #endif | ||
| 153 | |||
| 145 | static int jz4740_wdt_probe(struct platform_device *pdev) | 154 | static int jz4740_wdt_probe(struct platform_device *pdev) |
| 146 | { | 155 | { |
| 147 | struct jz4740_wdt_drvdata *drvdata; | 156 | struct jz4740_wdt_drvdata *drvdata; |
| @@ -211,6 +220,7 @@ static struct platform_driver jz4740_wdt_driver = { | |||
| 211 | .remove = jz4740_wdt_remove, | 220 | .remove = jz4740_wdt_remove, |
| 212 | .driver = { | 221 | .driver = { |
| 213 | .name = "jz4740-wdt", | 222 | .name = "jz4740-wdt", |
| 223 | .of_match_table = of_match_ptr(jz4740_wdt_of_matches), | ||
| 214 | }, | 224 | }, |
| 215 | }; | 225 | }; |
| 216 | 226 | ||
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c new file mode 100644 index 000000000000..a87f6df6e85f --- /dev/null +++ b/drivers/watchdog/mtk_wdt.c | |||
| @@ -0,0 +1,251 @@ | |||
| 1 | /* | ||
| 2 | * Mediatek Watchdog Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Matthias Brugger | ||
| 5 | * | ||
| 6 | * Matthias Brugger <matthias.bgg@gmail.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * Based on sunxi_wdt.c | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include <linux/err.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/io.h> | ||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/moduleparam.h> | ||
| 27 | #include <linux/of.h> | ||
| 28 | #include <linux/platform_device.h> | ||
| 29 | #include <linux/types.h> | ||
| 30 | #include <linux/watchdog.h> | ||
| 31 | #include <linux/notifier.h> | ||
| 32 | #include <linux/reboot.h> | ||
| 33 | #include <linux/delay.h> | ||
| 34 | |||
| 35 | #define WDT_MAX_TIMEOUT 31 | ||
| 36 | #define WDT_MIN_TIMEOUT 1 | ||
| 37 | #define WDT_LENGTH_TIMEOUT(n) ((n) << 5) | ||
| 38 | |||
| 39 | #define WDT_LENGTH 0x04 | ||
| 40 | #define WDT_LENGTH_KEY 0x8 | ||
| 41 | |||
| 42 | #define WDT_RST 0x08 | ||
| 43 | #define WDT_RST_RELOAD 0x1971 | ||
| 44 | |||
| 45 | #define WDT_MODE 0x00 | ||
| 46 | #define WDT_MODE_EN (1 << 0) | ||
| 47 | #define WDT_MODE_EXT_POL_LOW (0 << 1) | ||
| 48 | #define WDT_MODE_EXT_POL_HIGH (1 << 1) | ||
| 49 | #define WDT_MODE_EXRST_EN (1 << 2) | ||
| 50 | #define WDT_MODE_IRQ_EN (1 << 3) | ||
| 51 | #define WDT_MODE_AUTO_START (1 << 4) | ||
| 52 | #define WDT_MODE_DUAL_EN (1 << 6) | ||
| 53 | #define WDT_MODE_KEY 0x22000000 | ||
| 54 | |||
| 55 | #define WDT_SWRST 0x14 | ||
| 56 | #define WDT_SWRST_KEY 0x1209 | ||
| 57 | |||
| 58 | #define DRV_NAME "mtk-wdt" | ||
| 59 | #define DRV_VERSION "1.0" | ||
| 60 | |||
| 61 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
| 62 | static unsigned int timeout = WDT_MAX_TIMEOUT; | ||
| 63 | |||
| 64 | struct mtk_wdt_dev { | ||
| 65 | struct watchdog_device wdt_dev; | ||
| 66 | void __iomem *wdt_base; | ||
| 67 | struct notifier_block restart_handler; | ||
| 68 | }; | ||
| 69 | |||
| 70 | static int mtk_reset_handler(struct notifier_block *this, unsigned long mode, | ||
| 71 | void *cmd) | ||
| 72 | { | ||
| 73 | struct mtk_wdt_dev *mtk_wdt; | ||
| 74 | void __iomem *wdt_base; | ||
| 75 | |||
| 76 | mtk_wdt = container_of(this, struct mtk_wdt_dev, restart_handler); | ||
| 77 | wdt_base = mtk_wdt->wdt_base; | ||
| 78 | |||
| 79 | while (1) { | ||
| 80 | writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST); | ||
| 81 | mdelay(5); | ||
| 82 | } | ||
| 83 | |||
| 84 | return NOTIFY_DONE; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int mtk_wdt_ping(struct watchdog_device *wdt_dev) | ||
| 88 | { | ||
| 89 | struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev); | ||
| 90 | void __iomem *wdt_base = mtk_wdt->wdt_base; | ||
| 91 | |||
| 92 | iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST); | ||
| 93 | |||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev, | ||
| 98 | unsigned int timeout) | ||
| 99 | { | ||
| 100 | struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev); | ||
| 101 | void __iomem *wdt_base = mtk_wdt->wdt_base; | ||
| 102 | u32 reg; | ||
| 103 | |||
| 104 | wdt_dev->timeout = timeout; | ||
| 105 | |||
| 106 | /* | ||
| 107 | * One bit is the value of 512 ticks | ||
| 108 | * The clock has 32 KHz | ||
| 109 | */ | ||
| 110 | reg = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY; | ||
| 111 | iowrite32(reg, wdt_base + WDT_LENGTH); | ||
| 112 | |||
| 113 | mtk_wdt_ping(wdt_dev); | ||
| 114 | |||
| 115 | return 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | static int mtk_wdt_stop(struct watchdog_device *wdt_dev) | ||
| 119 | { | ||
| 120 | struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev); | ||
| 121 | void __iomem *wdt_base = mtk_wdt->wdt_base; | ||
| 122 | u32 reg; | ||
| 123 | |||
| 124 | reg = readl(wdt_base + WDT_MODE); | ||
| 125 | reg &= ~WDT_MODE_EN; | ||
| 126 | iowrite32(reg, wdt_base + WDT_MODE); | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int mtk_wdt_start(struct watchdog_device *wdt_dev) | ||
| 132 | { | ||
| 133 | u32 reg; | ||
| 134 | struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev); | ||
| 135 | void __iomem *wdt_base = mtk_wdt->wdt_base; | ||
| 136 | u32 ret; | ||
| 137 | |||
| 138 | ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout); | ||
| 139 | if (ret < 0) | ||
| 140 | return ret; | ||
| 141 | |||
| 142 | reg = ioread32(wdt_base + WDT_MODE); | ||
| 143 | reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN); | ||
| 144 | reg |= (WDT_MODE_EN | WDT_MODE_KEY); | ||
| 145 | iowrite32(reg, wdt_base + WDT_MODE); | ||
| 146 | |||
| 147 | return 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | static const struct watchdog_info mtk_wdt_info = { | ||
| 151 | .identity = DRV_NAME, | ||
| 152 | .options = WDIOF_SETTIMEOUT | | ||
| 153 | WDIOF_KEEPALIVEPING | | ||
| 154 | WDIOF_MAGICCLOSE, | ||
| 155 | }; | ||
| 156 | |||
| 157 | static const struct watchdog_ops mtk_wdt_ops = { | ||
| 158 | .owner = THIS_MODULE, | ||
| 159 | .start = mtk_wdt_start, | ||
| 160 | .stop = mtk_wdt_stop, | ||
| 161 | .ping = mtk_wdt_ping, | ||
| 162 | .set_timeout = mtk_wdt_set_timeout, | ||
| 163 | }; | ||
| 164 | |||
| 165 | static int mtk_wdt_probe(struct platform_device *pdev) | ||
| 166 | { | ||
| 167 | struct mtk_wdt_dev *mtk_wdt; | ||
| 168 | struct resource *res; | ||
| 169 | int err; | ||
| 170 | |||
| 171 | mtk_wdt = devm_kzalloc(&pdev->dev, sizeof(*mtk_wdt), GFP_KERNEL); | ||
| 172 | if (!mtk_wdt) | ||
| 173 | return -ENOMEM; | ||
| 174 | |||
| 175 | platform_set_drvdata(pdev, mtk_wdt); | ||
| 176 | |||
| 177 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 178 | mtk_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res); | ||
| 179 | if (IS_ERR(mtk_wdt->wdt_base)) | ||
| 180 | return PTR_ERR(mtk_wdt->wdt_base); | ||
| 181 | |||
| 182 | mtk_wdt->wdt_dev.info = &mtk_wdt_info; | ||
| 183 | mtk_wdt->wdt_dev.ops = &mtk_wdt_ops; | ||
| 184 | mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT; | ||
| 185 | mtk_wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT; | ||
| 186 | mtk_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT; | ||
| 187 | mtk_wdt->wdt_dev.parent = &pdev->dev; | ||
| 188 | |||
| 189 | watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, &pdev->dev); | ||
| 190 | watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout); | ||
| 191 | |||
| 192 | watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt); | ||
| 193 | |||
| 194 | mtk_wdt_stop(&mtk_wdt->wdt_dev); | ||
| 195 | |||
| 196 | err = watchdog_register_device(&mtk_wdt->wdt_dev); | ||
| 197 | if (unlikely(err)) | ||
| 198 | return err; | ||
| 199 | |||
| 200 | mtk_wdt->restart_handler.notifier_call = mtk_reset_handler; | ||
| 201 | mtk_wdt->restart_handler.priority = 128; | ||
| 202 | err = register_restart_handler(&mtk_wdt->restart_handler); | ||
| 203 | if (err) | ||
| 204 | dev_warn(&pdev->dev, | ||
| 205 | "cannot register restart handler (err=%d)\n", err); | ||
| 206 | |||
| 207 | dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n", | ||
| 208 | mtk_wdt->wdt_dev.timeout, nowayout); | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | static int mtk_wdt_remove(struct platform_device *pdev) | ||
| 214 | { | ||
| 215 | struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); | ||
| 216 | |||
| 217 | unregister_restart_handler(&mtk_wdt->restart_handler); | ||
| 218 | |||
| 219 | watchdog_unregister_device(&mtk_wdt->wdt_dev); | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | static const struct of_device_id mtk_wdt_dt_ids[] = { | ||
| 225 | { .compatible = "mediatek,mt6589-wdt" }, | ||
| 226 | { /* sentinel */ } | ||
| 227 | }; | ||
| 228 | MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids); | ||
| 229 | |||
| 230 | static struct platform_driver mtk_wdt_driver = { | ||
| 231 | .probe = mtk_wdt_probe, | ||
| 232 | .remove = mtk_wdt_remove, | ||
| 233 | .driver = { | ||
| 234 | .name = DRV_NAME, | ||
| 235 | .of_match_table = mtk_wdt_dt_ids, | ||
| 236 | }, | ||
| 237 | }; | ||
| 238 | |||
| 239 | module_platform_driver(mtk_wdt_driver); | ||
| 240 | |||
| 241 | module_param(timeout, uint, 0); | ||
| 242 | MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds"); | ||
| 243 | |||
| 244 | module_param(nowayout, bool, 0); | ||
| 245 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | ||
| 246 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
| 247 | |||
| 248 | MODULE_LICENSE("GPL"); | ||
| 249 | MODULE_AUTHOR("Matthias Brugger <matthias.bgg@gmail.com>"); | ||
| 250 | MODULE_DESCRIPTION("Mediatek WatchDog Timer Driver"); | ||
| 251 | MODULE_VERSION(DRV_VERSION); | ||
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index 9f2709db61ca..1e6be9e40577 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c | |||
| @@ -189,7 +189,7 @@ static int omap_wdt_set_timeout(struct watchdog_device *wdog, | |||
| 189 | } | 189 | } |
| 190 | 190 | ||
| 191 | static const struct watchdog_info omap_wdt_info = { | 191 | static const struct watchdog_info omap_wdt_info = { |
| 192 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 192 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, |
| 193 | .identity = "OMAP Watchdog", | 193 | .identity = "OMAP Watchdog", |
| 194 | }; | 194 | }; |
| 195 | 195 | ||
diff --git a/drivers/watchdog/retu_wdt.c b/drivers/watchdog/retu_wdt.c index a7a0695971e4..b7c68e275aeb 100644 --- a/drivers/watchdog/retu_wdt.c +++ b/drivers/watchdog/retu_wdt.c | |||
| @@ -94,7 +94,7 @@ static int retu_wdt_set_timeout(struct watchdog_device *wdog, | |||
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | static const struct watchdog_info retu_wdt_info = { | 96 | static const struct watchdog_info retu_wdt_info = { |
| 97 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 97 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, |
| 98 | .identity = "Retu watchdog", | 98 | .identity = "Retu watchdog", |
| 99 | }; | 99 | }; |
| 100 | 100 | ||
diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index 11aad5b7aafe..a6f7e2e29beb 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | static struct clk *rt288x_wdt_clk; | 45 | static struct clk *rt288x_wdt_clk; |
| 46 | static unsigned long rt288x_wdt_freq; | 46 | static unsigned long rt288x_wdt_freq; |
| 47 | static void __iomem *rt288x_wdt_base; | 47 | static void __iomem *rt288x_wdt_base; |
| 48 | static struct reset_control *rt288x_wdt_reset; | ||
| 48 | 49 | ||
| 49 | static bool nowayout = WATCHDOG_NOWAYOUT; | 50 | static bool nowayout = WATCHDOG_NOWAYOUT; |
| 50 | module_param(nowayout, bool, 0); | 51 | module_param(nowayout, bool, 0); |
| @@ -151,16 +152,18 @@ static int rt288x_wdt_probe(struct platform_device *pdev) | |||
| 151 | if (IS_ERR(rt288x_wdt_clk)) | 152 | if (IS_ERR(rt288x_wdt_clk)) |
| 152 | return PTR_ERR(rt288x_wdt_clk); | 153 | return PTR_ERR(rt288x_wdt_clk); |
| 153 | 154 | ||
| 154 | device_reset(&pdev->dev); | 155 | rt288x_wdt_reset = devm_reset_control_get(&pdev->dev, NULL); |
| 156 | if (!IS_ERR(rt288x_wdt_reset)) | ||
| 157 | reset_control_deassert(rt288x_wdt_reset); | ||
| 155 | 158 | ||
| 156 | rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE; | 159 | rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE; |
| 157 | 160 | ||
| 158 | rt288x_wdt_dev.dev = &pdev->dev; | 161 | rt288x_wdt_dev.dev = &pdev->dev; |
| 159 | rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); | 162 | rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); |
| 160 | |||
| 161 | rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); | 163 | rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); |
| 162 | rt288x_wdt_dev.timeout = rt288x_wdt_dev.max_timeout; | ||
| 163 | 164 | ||
| 165 | watchdog_init_timeout(&rt288x_wdt_dev, rt288x_wdt_dev.max_timeout, | ||
| 166 | &pdev->dev); | ||
| 164 | watchdog_set_nowayout(&rt288x_wdt_dev, nowayout); | 167 | watchdog_set_nowayout(&rt288x_wdt_dev, nowayout); |
| 165 | 168 | ||
| 166 | ret = watchdog_register_device(&rt288x_wdt_dev); | 169 | ret = watchdog_register_device(&rt288x_wdt_dev); |
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index 12c15903d098..2c1db6fa9a27 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c | |||
| @@ -57,7 +57,7 @@ static int twl4030_wdt_set_timeout(struct watchdog_device *wdt, | |||
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | static const struct watchdog_info twl4030_wdt_info = { | 59 | static const struct watchdog_info twl4030_wdt_info = { |
| 60 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | 60 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, |
| 61 | .identity = "TWL4030 Watchdog", | 61 | .identity = "TWL4030 Watchdog", |
| 62 | }; | 62 | }; |
| 63 | 63 | ||
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 7165704a3e33..5824e25eebbb 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c | |||
| @@ -50,7 +50,7 @@ static int cr_wdt_control; /* WDT control register */ | |||
| 50 | 50 | ||
| 51 | enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, | 51 | enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, |
| 52 | w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, | 52 | w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, |
| 53 | w83667hg_b, nct6775, nct6776, nct6779 }; | 53 | w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792 }; |
| 54 | 54 | ||
| 55 | static int timeout; /* in seconds */ | 55 | static int timeout; /* in seconds */ |
| 56 | module_param(timeout, int, 0); | 56 | module_param(timeout, int, 0); |
| @@ -95,6 +95,8 @@ MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)"); | |||
| 95 | #define NCT6775_ID 0xb4 | 95 | #define NCT6775_ID 0xb4 |
| 96 | #define NCT6776_ID 0xc3 | 96 | #define NCT6776_ID 0xc3 |
| 97 | #define NCT6779_ID 0xc5 | 97 | #define NCT6779_ID 0xc5 |
| 98 | #define NCT6791_ID 0xc8 | ||
| 99 | #define NCT6792_ID 0xc9 | ||
| 98 | 100 | ||
| 99 | #define W83627HF_WDT_TIMEOUT 0xf6 | 101 | #define W83627HF_WDT_TIMEOUT 0xf6 |
| 100 | #define W83697HF_WDT_TIMEOUT 0xf4 | 102 | #define W83697HF_WDT_TIMEOUT 0xf4 |
| @@ -195,6 +197,8 @@ static int w83627hf_init(struct watchdog_device *wdog, enum chips chip) | |||
| 195 | case nct6775: | 197 | case nct6775: |
| 196 | case nct6776: | 198 | case nct6776: |
| 197 | case nct6779: | 199 | case nct6779: |
| 200 | case nct6791: | ||
| 201 | case nct6792: | ||
| 198 | /* | 202 | /* |
| 199 | * These chips have a fixed WDTO# output pin (W83627UHG), | 203 | * These chips have a fixed WDTO# output pin (W83627UHG), |
| 200 | * or support more than one WDTO# output pin. | 204 | * or support more than one WDTO# output pin. |
| @@ -395,6 +399,12 @@ static int wdt_find(int addr) | |||
| 395 | case NCT6779_ID: | 399 | case NCT6779_ID: |
| 396 | ret = nct6779; | 400 | ret = nct6779; |
| 397 | break; | 401 | break; |
| 402 | case NCT6791_ID: | ||
| 403 | ret = nct6791; | ||
| 404 | break; | ||
| 405 | case NCT6792_ID: | ||
| 406 | ret = nct6792; | ||
| 407 | break; | ||
| 398 | case 0xff: | 408 | case 0xff: |
| 399 | ret = -ENODEV; | 409 | ret = -ENODEV; |
| 400 | break; | 410 | break; |
| @@ -428,6 +438,8 @@ static int __init wdt_init(void) | |||
| 428 | "NCT6775", | 438 | "NCT6775", |
| 429 | "NCT6776", | 439 | "NCT6776", |
| 430 | "NCT6779", | 440 | "NCT6779", |
| 441 | "NCT6791", | ||
| 442 | "NCT6792", | ||
| 431 | }; | 443 | }; |
| 432 | 444 | ||
| 433 | wdt_io = 0x2e; | 445 | wdt_io = 0x2e; |
diff --git a/include/linux/bcm47xx_wdt.h b/include/linux/bcm47xx_wdt.h index b708786d4cbf..5582c211f594 100644 --- a/include/linux/bcm47xx_wdt.h +++ b/include/linux/bcm47xx_wdt.h | |||
| @@ -16,6 +16,7 @@ struct bcm47xx_wdt { | |||
| 16 | 16 | ||
| 17 | struct watchdog_device wdd; | 17 | struct watchdog_device wdd; |
| 18 | struct notifier_block notifier; | 18 | struct notifier_block notifier; |
| 19 | struct notifier_block restart_handler; | ||
| 19 | 20 | ||
| 20 | struct timer_list soft_timer; | 21 | struct timer_list soft_timer; |
| 21 | atomic_t soft_ticks; | 22 | atomic_t soft_ticks; |
