diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-11 12:59:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-07-11 12:59:37 -0400 |
commit | 07d306c838c5c30196619baae36107d0615e459b (patch) | |
tree | 5a96d43b193cc001853e3fd8f0fcf853a7bd9d67 /drivers/watchdog | |
parent | a3ddacbae5abc0a5aabb1e75b655e8cd6dc83888 (diff) | |
parent | c013b65ad8a1e132f733404809afc72f7d00e768 (diff) |
Merge git://www.linux-watchdog.org/linux-watchdog
Pull watchdog updates from Wim Van Sebroeck:
- Add Renesas RZ/A WDT Watchdog driver
- STM32 Independent WatchDoG (IWDG) support
- UniPhier watchdog support
- Add F71868 support
- Add support for NCT6793D and NCT6795D
- dw_wdt: add reset lines support
- core: add option to avoid early handling of watchdog
- core: introduce watchdog_worker_should_ping helper
- Cleanups and improvements for sama5d4, intel-mid_wdt, s3c2410_wdt,
orion_wdt, gpio_wdt, it87_wdt, meson_wdt, davinci_wdt, bcm47xx_wdt,
zx2967_wdt, cadence_wdt
* git://www.linux-watchdog.org/linux-watchdog: (32 commits)
watchdog: introduce watchdog_worker_should_ping helper
watchdog: uniphier: add UniPhier watchdog driver
dt-bindings: watchdog: add description for UniPhier WDT controller
watchdog: cadence_wdt: make of_device_ids const.
watchdog: zx2967: constify zx2967_wdt_ops.
watchdog: bcm47xx_wdt: constify bcm47xx_wdt_hard_ops and bcm47xx_wdt_soft_ops
watchdog: davinci: Add missing clk_disable_unprepare().
watchdog: davinci: Handle return value of clk_prepare_enable
watchdog: meson: Handle return value of clk_prepare_enable
watchdog: it87: Add support for various Super-IO chips
watchdog: it87: Use infrastructure to stop watchdog on reboot
watchdog: it87: Drop support for resetting watchdog though CIR and Game port
watchdog: it87: Convert to use watchdog core infrastructure
watchdog: it87: Drop FSF mailing address
watchdog: dw_wdt: get reset lines from dt
watchdog: bindings: dw_wdt: add reset lines
watchdog: w83627hf: Add support for NCT6793D and NCT6795D
watchdog: core: add option to avoid early handling of watchdog
watchdog: f71808e_wdt: Add F71868 support
watchdog: Add STM32 IWDG driver
...
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/Kconfig | 61 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 3 | ||||
-rw-r--r-- | drivers/watchdog/bcm47xx_wdt.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/cadence_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/davinci_wdt.c | 10 | ||||
-rw-r--r-- | drivers/watchdog/dw_wdt.c | 11 | ||||
-rw-r--r-- | drivers/watchdog/f71808e_wdt.c | 27 | ||||
-rw-r--r-- | drivers/watchdog/gpio_wdt.c | 73 | ||||
-rw-r--r-- | drivers/watchdog/intel-mid_wdt.c | 17 | ||||
-rw-r--r-- | drivers/watchdog/it87_wdt.c | 588 | ||||
-rw-r--r-- | drivers/watchdog/meson_gxbb_wdt.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/orion_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/rza_wdt.c | 199 | ||||
-rw-r--r-- | drivers/watchdog/s3c2410_wdt.c | 58 | ||||
-rw-r--r-- | drivers/watchdog/sama5d4_wdt.c | 19 | ||||
-rw-r--r-- | drivers/watchdog/stm32_iwdg.c | 253 | ||||
-rw-r--r-- | drivers/watchdog/uniphier_wdt.c | 268 | ||||
-rw-r--r-- | drivers/watchdog/w83627hf_wdt.c | 15 | ||||
-rw-r--r-- | drivers/watchdog/watchdog_dev.c | 32 | ||||
-rw-r--r-- | drivers/watchdog/zx2967_wdt.c | 2 |
20 files changed, 1003 insertions, 645 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index e6e31a16f68f..c722cbfdc7e6 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -46,6 +46,17 @@ config WATCHDOG_NOWAYOUT | |||
46 | get killed. If you say Y here, the watchdog cannot be stopped once | 46 | get killed. If you say Y here, the watchdog cannot be stopped once |
47 | it has been started. | 47 | it has been started. |
48 | 48 | ||
49 | config WATCHDOG_HANDLE_BOOT_ENABLED | ||
50 | bool "Update boot-enabled watchdog until userspace takes over" | ||
51 | default y | ||
52 | help | ||
53 | The default watchdog behaviour (which you get if you say Y here) is | ||
54 | to ping watchdog devices that were enabled before the driver has | ||
55 | been loaded until control is taken over from userspace using the | ||
56 | /dev/watchdog file. If you say N here, the kernel will not update | ||
57 | the watchdog on its own. Thus if your userspace does not start fast | ||
58 | enough your device will reboot. | ||
59 | |||
49 | config WATCHDOG_SYSFS | 60 | config WATCHDOG_SYSFS |
50 | bool "Read different watchdog information through sysfs" | 61 | bool "Read different watchdog information through sysfs" |
51 | help | 62 | help |
@@ -721,6 +732,14 @@ config RENESAS_WDT | |||
721 | This driver adds watchdog support for the integrated watchdogs in the | 732 | This driver adds watchdog support for the integrated watchdogs in the |
722 | Renesas R-Car and other SH-Mobile SoCs (usually named RWDT or SWDT). | 733 | Renesas R-Car and other SH-Mobile SoCs (usually named RWDT or SWDT). |
723 | 734 | ||
735 | config RENESAS_RZAWDT | ||
736 | tristate "Renesas RZ/A WDT Watchdog" | ||
737 | depends on ARCH_RENESAS || COMPILE_TEST | ||
738 | select WATCHDOG_CORE | ||
739 | help | ||
740 | This driver adds watchdog support for the integrated watchdogs in the | ||
741 | Renesas RZ/A SoCs. These watchdogs can be used to reset a system. | ||
742 | |||
724 | config ASPEED_WATCHDOG | 743 | config ASPEED_WATCHDOG |
725 | tristate "Aspeed 2400 watchdog support" | 744 | tristate "Aspeed 2400 watchdog support" |
726 | depends on ARCH_ASPEED || COMPILE_TEST | 745 | depends on ARCH_ASPEED || COMPILE_TEST |
@@ -744,6 +763,30 @@ config ZX2967_WATCHDOG | |||
744 | To compile this driver as a module, choose M here: the | 763 | To compile this driver as a module, choose M here: the |
745 | module will be called zx2967_wdt. | 764 | module will be called zx2967_wdt. |
746 | 765 | ||
766 | config STM32_WATCHDOG | ||
767 | tristate "STM32 Independent WatchDoG (IWDG) support" | ||
768 | depends on ARCH_STM32 | ||
769 | select WATCHDOG_CORE | ||
770 | default y | ||
771 | help | ||
772 | Say Y here to include support for the watchdog timer | ||
773 | in stm32 SoCs. | ||
774 | |||
775 | To compile this driver as a module, choose M here: the | ||
776 | module will be called stm32_iwdg. | ||
777 | |||
778 | config UNIPHIER_WATCHDOG | ||
779 | tristate "UniPhier watchdog support" | ||
780 | depends on ARCH_UNIPHIER || COMPILE_TEST | ||
781 | depends on OF && MFD_SYSCON | ||
782 | select WATCHDOG_CORE | ||
783 | help | ||
784 | Say Y here to include support watchdog timer embedded | ||
785 | into the UniPhier system. | ||
786 | |||
787 | To compile this driver as a module, choose M here: the | ||
788 | module will be called uniphier_wdt. | ||
789 | |||
747 | # AVR32 Architecture | 790 | # AVR32 Architecture |
748 | 791 | ||
749 | config AT32AP700X_WDT | 792 | config AT32AP700X_WDT |
@@ -829,11 +872,12 @@ config EBC_C384_WDT | |||
829 | the timeout module parameter. | 872 | the timeout module parameter. |
830 | 873 | ||
831 | config F71808E_WDT | 874 | config F71808E_WDT |
832 | tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog" | 875 | tristate "Fintek F718xx, F818xx Super I/O Watchdog" |
833 | depends on X86 | 876 | depends on X86 |
834 | help | 877 | help |
835 | This is the driver for the hardware watchdog on the Fintek | 878 | This is the driver for the hardware watchdog on the Fintek F71808E, |
836 | F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers. | 879 | F71862FG, F71868, F71869, F71882FG, F71889FG, F81865 and F81866 |
880 | Super I/O controllers. | ||
837 | 881 | ||
838 | You can compile this driver directly into the kernel, or use | 882 | You can compile this driver directly into the kernel, or use |
839 | it as a module. The module will be called f71808e_wdt. | 883 | it as a module. The module will be called f71808e_wdt. |
@@ -1037,13 +1081,12 @@ config IT8712F_WDT | |||
1037 | config IT87_WDT | 1081 | config IT87_WDT |
1038 | tristate "IT87 Watchdog Timer" | 1082 | tristate "IT87 Watchdog Timer" |
1039 | depends on X86 | 1083 | depends on X86 |
1084 | select WATCHDOG_CORE | ||
1040 | ---help--- | 1085 | ---help--- |
1041 | This is the driver for the hardware watchdog on the ITE IT8620, | 1086 | This is the driver for the hardware watchdog on the ITE IT8607, |
1042 | IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728 | 1087 | IT8620, IT8622, IT8625, IT8628, IT8655, IT8665, IT8686, IT8702, |
1043 | Super I/O chips. | 1088 | IT8712, IT8716, IT8718, IT8720, IT8721, IT8726, IT8728, and |
1044 | 1089 | IT8783 Super I/O chips. | |
1045 | If the driver does not work, then make sure that the game port in | ||
1046 | the BIOS is enabled. | ||
1047 | 1090 | ||
1048 | This watchdog simply watches your kernel to make sure it doesn't | 1091 | This watchdog simply watches your kernel to make sure it doesn't |
1049 | freeze, and if it does, it reboots your computer after a certain | 1092 | freeze, and if it does, it reboots your computer after a certain |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index a2126e2a99ae..56adf9fa67d0 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
@@ -82,8 +82,11 @@ obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o | |||
82 | obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o | 82 | obj-$(CONFIG_BCM7038_WDT) += bcm7038_wdt.o |
83 | obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o | 83 | obj-$(CONFIG_ATLAS7_WATCHDOG) += atlas7_wdt.o |
84 | obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o | 84 | obj-$(CONFIG_RENESAS_WDT) += renesas_wdt.o |
85 | obj-$(CONFIG_RENESAS_RZAWDT) += rza_wdt.o | ||
85 | obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o | 86 | obj-$(CONFIG_ASPEED_WATCHDOG) += aspeed_wdt.o |
86 | obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o | 87 | obj-$(CONFIG_ZX2967_WATCHDOG) += zx2967_wdt.o |
88 | obj-$(CONFIG_STM32_WATCHDOG) += stm32_iwdg.o | ||
89 | obj-$(CONFIG_UNIPHIER_WATCHDOG) += uniphier_wdt.o | ||
87 | 90 | ||
88 | # AVR32 Architecture | 91 | # AVR32 Architecture |
89 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o | 92 | obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o |
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index 35725e21b18a..236582809336 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c | |||
@@ -97,7 +97,7 @@ static int bcm47xx_wdt_restart(struct watchdog_device *wdd, | |||
97 | return 0; | 97 | return 0; |
98 | } | 98 | } |
99 | 99 | ||
100 | static struct watchdog_ops bcm47xx_wdt_hard_ops = { | 100 | static const struct watchdog_ops bcm47xx_wdt_hard_ops = { |
101 | .owner = THIS_MODULE, | 101 | .owner = THIS_MODULE, |
102 | .start = bcm47xx_wdt_hard_start, | 102 | .start = bcm47xx_wdt_hard_start, |
103 | .stop = bcm47xx_wdt_hard_stop, | 103 | .stop = bcm47xx_wdt_hard_stop, |
@@ -168,7 +168,7 @@ static const struct watchdog_info bcm47xx_wdt_info = { | |||
168 | WDIOF_MAGICCLOSE, | 168 | WDIOF_MAGICCLOSE, |
169 | }; | 169 | }; |
170 | 170 | ||
171 | static struct watchdog_ops bcm47xx_wdt_soft_ops = { | 171 | static const struct watchdog_ops bcm47xx_wdt_soft_ops = { |
172 | .owner = THIS_MODULE, | 172 | .owner = THIS_MODULE, |
173 | .start = bcm47xx_wdt_soft_start, | 173 | .start = bcm47xx_wdt_soft_start, |
174 | .stop = bcm47xx_wdt_soft_stop, | 174 | .stop = bcm47xx_wdt_soft_stop, |
diff --git a/drivers/watchdog/cadence_wdt.c b/drivers/watchdog/cadence_wdt.c index 86e0b5d2e761..05c000081e9d 100644 --- a/drivers/watchdog/cadence_wdt.c +++ b/drivers/watchdog/cadence_wdt.c | |||
@@ -458,7 +458,7 @@ static int __maybe_unused cdns_wdt_resume(struct device *dev) | |||
458 | 458 | ||
459 | static SIMPLE_DEV_PM_OPS(cdns_wdt_pm_ops, cdns_wdt_suspend, cdns_wdt_resume); | 459 | static SIMPLE_DEV_PM_OPS(cdns_wdt_pm_ops, cdns_wdt_suspend, cdns_wdt_resume); |
460 | 460 | ||
461 | static struct of_device_id cdns_wdt_of_match[] = { | 461 | static const struct of_device_id cdns_wdt_of_match[] = { |
462 | { .compatible = "cdns,wdt-r1p2", }, | 462 | { .compatible = "cdns,wdt-r1p2", }, |
463 | { /* end of table */ } | 463 | { /* end of table */ } |
464 | }; | 464 | }; |
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index 0e731d797a2a..2f46487af86d 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c | |||
@@ -173,7 +173,11 @@ static int davinci_wdt_probe(struct platform_device *pdev) | |||
173 | return PTR_ERR(davinci_wdt->clk); | 173 | return PTR_ERR(davinci_wdt->clk); |
174 | } | 174 | } |
175 | 175 | ||
176 | clk_prepare_enable(davinci_wdt->clk); | 176 | ret = clk_prepare_enable(davinci_wdt->clk); |
177 | if (ret) { | ||
178 | dev_err(&pdev->dev, "failed to prepare clock\n"); | ||
179 | return ret; | ||
180 | } | ||
177 | 181 | ||
178 | platform_set_drvdata(pdev, davinci_wdt); | 182 | platform_set_drvdata(pdev, davinci_wdt); |
179 | 183 | ||
@@ -198,8 +202,10 @@ static int davinci_wdt_probe(struct platform_device *pdev) | |||
198 | return PTR_ERR(davinci_wdt->base); | 202 | return PTR_ERR(davinci_wdt->base); |
199 | 203 | ||
200 | ret = watchdog_register_device(wdd); | 204 | ret = watchdog_register_device(wdd); |
201 | if (ret < 0) | 205 | if (ret < 0) { |
206 | clk_disable_unprepare(davinci_wdt->clk); | ||
202 | dev_err(dev, "cannot register watchdog device\n"); | 207 | dev_err(dev, "cannot register watchdog device\n"); |
208 | } | ||
203 | 209 | ||
204 | return ret; | 210 | return ret; |
205 | } | 211 | } |
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c index 914da3a4d334..36be987ff9ef 100644 --- a/drivers/watchdog/dw_wdt.c +++ b/drivers/watchdog/dw_wdt.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/of.h> | 29 | #include <linux/of.h> |
30 | #include <linux/pm.h> | 30 | #include <linux/pm.h> |
31 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
32 | #include <linux/reset.h> | ||
32 | #include <linux/watchdog.h> | 33 | #include <linux/watchdog.h> |
33 | 34 | ||
34 | #define WDOG_CONTROL_REG_OFFSET 0x00 | 35 | #define WDOG_CONTROL_REG_OFFSET 0x00 |
@@ -54,6 +55,7 @@ struct dw_wdt { | |||
54 | struct clk *clk; | 55 | struct clk *clk; |
55 | unsigned long rate; | 56 | unsigned long rate; |
56 | struct watchdog_device wdd; | 57 | struct watchdog_device wdd; |
58 | struct reset_control *rst; | ||
57 | }; | 59 | }; |
58 | 60 | ||
59 | #define to_dw_wdt(wdd) container_of(wdd, struct dw_wdt, wdd) | 61 | #define to_dw_wdt(wdd) container_of(wdd, struct dw_wdt, wdd) |
@@ -234,6 +236,14 @@ static int dw_wdt_drv_probe(struct platform_device *pdev) | |||
234 | goto out_disable_clk; | 236 | goto out_disable_clk; |
235 | } | 237 | } |
236 | 238 | ||
239 | dw_wdt->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL); | ||
240 | if (IS_ERR(dw_wdt->rst)) { | ||
241 | ret = PTR_ERR(dw_wdt->rst); | ||
242 | goto out_disable_clk; | ||
243 | } | ||
244 | |||
245 | reset_control_deassert(dw_wdt->rst); | ||
246 | |||
237 | wdd = &dw_wdt->wdd; | 247 | wdd = &dw_wdt->wdd; |
238 | wdd->info = &dw_wdt_ident; | 248 | wdd->info = &dw_wdt_ident; |
239 | wdd->ops = &dw_wdt_ops; | 249 | wdd->ops = &dw_wdt_ops; |
@@ -279,6 +289,7 @@ static int dw_wdt_drv_remove(struct platform_device *pdev) | |||
279 | struct dw_wdt *dw_wdt = platform_get_drvdata(pdev); | 289 | struct dw_wdt *dw_wdt = platform_get_drvdata(pdev); |
280 | 290 | ||
281 | watchdog_unregister_device(&dw_wdt->wdd); | 291 | watchdog_unregister_device(&dw_wdt->wdd); |
292 | reset_control_assert(dw_wdt->rst); | ||
282 | clk_disable_unprepare(dw_wdt->clk); | 293 | clk_disable_unprepare(dw_wdt->clk); |
283 | 294 | ||
284 | return 0; | 295 | return 0; |
diff --git a/drivers/watchdog/f71808e_wdt.c b/drivers/watchdog/f71808e_wdt.c index 1b7e9169072f..8658dba21768 100644 --- a/drivers/watchdog/f71808e_wdt.c +++ b/drivers/watchdog/f71808e_wdt.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #define SIO_F71808_ID 0x0901 /* Chipset ID */ | 57 | #define SIO_F71808_ID 0x0901 /* Chipset ID */ |
58 | #define SIO_F71858_ID 0x0507 /* Chipset ID */ | 58 | #define SIO_F71858_ID 0x0507 /* Chipset ID */ |
59 | #define SIO_F71862_ID 0x0601 /* Chipset ID */ | 59 | #define SIO_F71862_ID 0x0601 /* Chipset ID */ |
60 | #define SIO_F71868_ID 0x1106 /* Chipset ID */ | ||
60 | #define SIO_F71869_ID 0x0814 /* Chipset ID */ | 61 | #define SIO_F71869_ID 0x0814 /* Chipset ID */ |
61 | #define SIO_F71869A_ID 0x1007 /* Chipset ID */ | 62 | #define SIO_F71869A_ID 0x1007 /* Chipset ID */ |
62 | #define SIO_F71882_ID 0x0541 /* Chipset ID */ | 63 | #define SIO_F71882_ID 0x0541 /* Chipset ID */ |
@@ -101,7 +102,7 @@ MODULE_PARM_DESC(timeout, | |||
101 | static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH; | 102 | static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH; |
102 | module_param(pulse_width, uint, 0); | 103 | module_param(pulse_width, uint, 0); |
103 | MODULE_PARM_DESC(pulse_width, | 104 | MODULE_PARM_DESC(pulse_width, |
104 | "Watchdog signal pulse width. 0(=level), 1 ms, 25 ms, 125 ms or 5000 ms" | 105 | "Watchdog signal pulse width. 0(=level), 1, 25, 30, 125, 150, 5000 or 6000 ms" |
105 | " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")"); | 106 | " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")"); |
106 | 107 | ||
107 | static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN; | 108 | static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN; |
@@ -119,13 +120,14 @@ module_param(start_withtimeout, uint, 0); | |||
119 | MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with" | 120 | MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with" |
120 | " given initial timeout. Zero (default) disables this feature."); | 121 | " given initial timeout. Zero (default) disables this feature."); |
121 | 122 | ||
122 | enum chips { f71808fg, f71858fg, f71862fg, f71869, f71882fg, f71889fg, f81865, | 123 | enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg, |
123 | f81866}; | 124 | f81865, f81866}; |
124 | 125 | ||
125 | static const char *f71808e_names[] = { | 126 | static const char *f71808e_names[] = { |
126 | "f71808fg", | 127 | "f71808fg", |
127 | "f71858fg", | 128 | "f71858fg", |
128 | "f71862fg", | 129 | "f71862fg", |
130 | "f71868", | ||
129 | "f71869", | 131 | "f71869", |
130 | "f71882fg", | 132 | "f71882fg", |
131 | "f71889fg", | 133 | "f71889fg", |
@@ -252,16 +254,23 @@ static int watchdog_set_timeout(int timeout) | |||
252 | static int watchdog_set_pulse_width(unsigned int pw) | 254 | static int watchdog_set_pulse_width(unsigned int pw) |
253 | { | 255 | { |
254 | int err = 0; | 256 | int err = 0; |
257 | unsigned int t1 = 25, t2 = 125, t3 = 5000; | ||
258 | |||
259 | if (watchdog.type == f71868) { | ||
260 | t1 = 30; | ||
261 | t2 = 150; | ||
262 | t3 = 6000; | ||
263 | } | ||
255 | 264 | ||
256 | mutex_lock(&watchdog.lock); | 265 | mutex_lock(&watchdog.lock); |
257 | 266 | ||
258 | if (pw <= 1) { | 267 | if (pw <= 1) { |
259 | watchdog.pulse_val = 0; | 268 | watchdog.pulse_val = 0; |
260 | } else if (pw <= 25) { | 269 | } else if (pw <= t1) { |
261 | watchdog.pulse_val = 1; | 270 | watchdog.pulse_val = 1; |
262 | } else if (pw <= 125) { | 271 | } else if (pw <= t2) { |
263 | watchdog.pulse_val = 2; | 272 | watchdog.pulse_val = 2; |
264 | } else if (pw <= 5000) { | 273 | } else if (pw <= t3) { |
265 | watchdog.pulse_val = 3; | 274 | watchdog.pulse_val = 3; |
266 | } else { | 275 | } else { |
267 | pr_err("pulse width out of range\n"); | 276 | pr_err("pulse width out of range\n"); |
@@ -354,6 +363,7 @@ static int watchdog_start(void) | |||
354 | goto exit_superio; | 363 | goto exit_superio; |
355 | break; | 364 | break; |
356 | 365 | ||
366 | case f71868: | ||
357 | case f71869: | 367 | case f71869: |
358 | /* GPIO14 --> WDTRST# */ | 368 | /* GPIO14 --> WDTRST# */ |
359 | superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4); | 369 | superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 4); |
@@ -792,6 +802,9 @@ static int __init f71808e_find(int sioaddr) | |||
792 | watchdog.type = f71862fg; | 802 | watchdog.type = f71862fg; |
793 | err = f71862fg_pin_configure(0); /* validate module parameter */ | 803 | err = f71862fg_pin_configure(0); /* validate module parameter */ |
794 | break; | 804 | break; |
805 | case SIO_F71868_ID: | ||
806 | watchdog.type = f71868; | ||
807 | break; | ||
795 | case SIO_F71869_ID: | 808 | case SIO_F71869_ID: |
796 | case SIO_F71869A_ID: | 809 | case SIO_F71869A_ID: |
797 | watchdog.type = f71869; | 810 | watchdog.type = f71869; |
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c index 93457cabc178..cb66c2f99ff1 100644 --- a/drivers/watchdog/gpio_wdt.c +++ b/drivers/watchdog/gpio_wdt.c | |||
@@ -18,7 +18,6 @@ | |||
18 | 18 | ||
19 | #define SOFT_TIMEOUT_MIN 1 | 19 | #define SOFT_TIMEOUT_MIN 1 |
20 | #define SOFT_TIMEOUT_DEF 60 | 20 | #define SOFT_TIMEOUT_DEF 60 |
21 | #define SOFT_TIMEOUT_MAX 0xffff | ||
22 | 21 | ||
23 | enum { | 22 | enum { |
24 | HW_ALGO_TOGGLE, | 23 | HW_ALGO_TOGGLE, |
@@ -30,11 +29,7 @@ struct gpio_wdt_priv { | |||
30 | bool active_low; | 29 | bool active_low; |
31 | bool state; | 30 | bool state; |
32 | bool always_running; | 31 | bool always_running; |
33 | bool armed; | ||
34 | unsigned int hw_algo; | 32 | unsigned int hw_algo; |
35 | unsigned int hw_margin; | ||
36 | unsigned long last_jiffies; | ||
37 | struct timer_list timer; | ||
38 | struct watchdog_device wdd; | 33 | struct watchdog_device wdd; |
39 | }; | 34 | }; |
40 | 35 | ||
@@ -47,21 +42,10 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv) | |||
47 | gpio_direction_input(priv->gpio); | 42 | gpio_direction_input(priv->gpio); |
48 | } | 43 | } |
49 | 44 | ||
50 | static void gpio_wdt_hwping(unsigned long data) | 45 | static int gpio_wdt_ping(struct watchdog_device *wdd) |
51 | { | 46 | { |
52 | struct watchdog_device *wdd = (struct watchdog_device *)data; | ||
53 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | 47 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); |
54 | 48 | ||
55 | if (priv->armed && time_after(jiffies, priv->last_jiffies + | ||
56 | msecs_to_jiffies(wdd->timeout * 1000))) { | ||
57 | dev_crit(wdd->parent, | ||
58 | "Timer expired. System will reboot soon!\n"); | ||
59 | return; | ||
60 | } | ||
61 | |||
62 | /* Restart timer */ | ||
63 | mod_timer(&priv->timer, jiffies + priv->hw_margin); | ||
64 | |||
65 | switch (priv->hw_algo) { | 49 | switch (priv->hw_algo) { |
66 | case HW_ALGO_TOGGLE: | 50 | case HW_ALGO_TOGGLE: |
67 | /* Toggle output pin */ | 51 | /* Toggle output pin */ |
@@ -75,55 +59,33 @@ static void gpio_wdt_hwping(unsigned long data) | |||
75 | gpio_set_value_cansleep(priv->gpio, priv->active_low); | 59 | gpio_set_value_cansleep(priv->gpio, priv->active_low); |
76 | break; | 60 | break; |
77 | } | 61 | } |
78 | } | 62 | return 0; |
79 | |||
80 | static void gpio_wdt_start_impl(struct gpio_wdt_priv *priv) | ||
81 | { | ||
82 | priv->state = priv->active_low; | ||
83 | gpio_direction_output(priv->gpio, priv->state); | ||
84 | priv->last_jiffies = jiffies; | ||
85 | gpio_wdt_hwping((unsigned long)&priv->wdd); | ||
86 | } | 63 | } |
87 | 64 | ||
88 | static int gpio_wdt_start(struct watchdog_device *wdd) | 65 | static int gpio_wdt_start(struct watchdog_device *wdd) |
89 | { | 66 | { |
90 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | 67 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); |
91 | 68 | ||
92 | gpio_wdt_start_impl(priv); | 69 | priv->state = priv->active_low; |
93 | priv->armed = true; | 70 | gpio_direction_output(priv->gpio, priv->state); |
94 | 71 | ||
95 | return 0; | 72 | set_bit(WDOG_HW_RUNNING, &wdd->status); |
73 | |||
74 | return gpio_wdt_ping(wdd); | ||
96 | } | 75 | } |
97 | 76 | ||
98 | static int gpio_wdt_stop(struct watchdog_device *wdd) | 77 | static int gpio_wdt_stop(struct watchdog_device *wdd) |
99 | { | 78 | { |
100 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | 79 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); |
101 | 80 | ||
102 | priv->armed = false; | ||
103 | if (!priv->always_running) { | 81 | if (!priv->always_running) { |
104 | mod_timer(&priv->timer, 0); | ||
105 | gpio_wdt_disable(priv); | 82 | gpio_wdt_disable(priv); |
83 | clear_bit(WDOG_HW_RUNNING, &wdd->status); | ||
106 | } | 84 | } |
107 | 85 | ||
108 | return 0; | 86 | return 0; |
109 | } | 87 | } |
110 | 88 | ||
111 | static int gpio_wdt_ping(struct watchdog_device *wdd) | ||
112 | { | ||
113 | struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); | ||
114 | |||
115 | priv->last_jiffies = jiffies; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int gpio_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) | ||
121 | { | ||
122 | wdd->timeout = t; | ||
123 | |||
124 | return gpio_wdt_ping(wdd); | ||
125 | } | ||
126 | |||
127 | static const struct watchdog_info gpio_wdt_ident = { | 89 | static const struct watchdog_info gpio_wdt_ident = { |
128 | .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | | 90 | .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | |
129 | WDIOF_SETTIMEOUT, | 91 | WDIOF_SETTIMEOUT, |
@@ -135,7 +97,6 @@ static const struct watchdog_ops gpio_wdt_ops = { | |||
135 | .start = gpio_wdt_start, | 97 | .start = gpio_wdt_start, |
136 | .stop = gpio_wdt_stop, | 98 | .stop = gpio_wdt_stop, |
137 | .ping = gpio_wdt_ping, | 99 | .ping = gpio_wdt_ping, |
138 | .set_timeout = gpio_wdt_set_timeout, | ||
139 | }; | 100 | }; |
140 | 101 | ||
141 | static int gpio_wdt_probe(struct platform_device *pdev) | 102 | static int gpio_wdt_probe(struct platform_device *pdev) |
@@ -185,9 +146,6 @@ static int gpio_wdt_probe(struct platform_device *pdev) | |||
185 | if (hw_margin < 2 || hw_margin > 65535) | 146 | if (hw_margin < 2 || hw_margin > 65535) |
186 | return -EINVAL; | 147 | return -EINVAL; |
187 | 148 | ||
188 | /* Use safe value (1/2 of real timeout) */ | ||
189 | priv->hw_margin = msecs_to_jiffies(hw_margin / 2); | ||
190 | |||
191 | priv->always_running = of_property_read_bool(pdev->dev.of_node, | 149 | priv->always_running = of_property_read_bool(pdev->dev.of_node, |
192 | "always-running"); | 150 | "always-running"); |
193 | 151 | ||
@@ -196,31 +154,26 @@ static int gpio_wdt_probe(struct platform_device *pdev) | |||
196 | priv->wdd.info = &gpio_wdt_ident; | 154 | priv->wdd.info = &gpio_wdt_ident; |
197 | priv->wdd.ops = &gpio_wdt_ops; | 155 | priv->wdd.ops = &gpio_wdt_ops; |
198 | priv->wdd.min_timeout = SOFT_TIMEOUT_MIN; | 156 | priv->wdd.min_timeout = SOFT_TIMEOUT_MIN; |
199 | priv->wdd.max_timeout = SOFT_TIMEOUT_MAX; | 157 | priv->wdd.max_hw_heartbeat_ms = hw_margin; |
200 | priv->wdd.parent = &pdev->dev; | 158 | priv->wdd.parent = &pdev->dev; |
201 | 159 | ||
202 | if (watchdog_init_timeout(&priv->wdd, 0, &pdev->dev) < 0) | 160 | if (watchdog_init_timeout(&priv->wdd, 0, &pdev->dev) < 0) |
203 | priv->wdd.timeout = SOFT_TIMEOUT_DEF; | 161 | priv->wdd.timeout = SOFT_TIMEOUT_DEF; |
204 | 162 | ||
205 | setup_timer(&priv->timer, gpio_wdt_hwping, (unsigned long)&priv->wdd); | ||
206 | |||
207 | watchdog_stop_on_reboot(&priv->wdd); | 163 | watchdog_stop_on_reboot(&priv->wdd); |
208 | 164 | ||
209 | ret = watchdog_register_device(&priv->wdd); | ||
210 | if (ret) | ||
211 | return ret; | ||
212 | |||
213 | if (priv->always_running) | 165 | if (priv->always_running) |
214 | gpio_wdt_start_impl(priv); | 166 | gpio_wdt_start(&priv->wdd); |
215 | 167 | ||
216 | return 0; | 168 | ret = watchdog_register_device(&priv->wdd); |
169 | |||
170 | return ret; | ||
217 | } | 171 | } |
218 | 172 | ||
219 | static int gpio_wdt_remove(struct platform_device *pdev) | 173 | static int gpio_wdt_remove(struct platform_device *pdev) |
220 | { | 174 | { |
221 | struct gpio_wdt_priv *priv = platform_get_drvdata(pdev); | 175 | struct gpio_wdt_priv *priv = platform_get_drvdata(pdev); |
222 | 176 | ||
223 | del_timer_sync(&priv->timer); | ||
224 | watchdog_unregister_device(&priv->wdd); | 177 | watchdog_unregister_device(&priv->wdd); |
225 | 178 | ||
226 | return 0; | 179 | return 0; |
diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index 45e4d02221b5..72c108a12c19 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c | |||
@@ -147,8 +147,21 @@ static int mid_wdt_probe(struct platform_device *pdev) | |||
147 | return ret; | 147 | return ret; |
148 | } | 148 | } |
149 | 149 | ||
150 | /* Make sure the watchdog is not running */ | 150 | /* |
151 | wdt_stop(wdt_dev); | 151 | * The firmware followed by U-Boot leaves the watchdog running |
152 | * with the default threshold which may vary. When we get here | ||
153 | * we should make a decision to prevent any side effects before | ||
154 | * user space daemon will take care of it. The best option, | ||
155 | * taking into consideration that there is no way to read values | ||
156 | * back from hardware, is to enforce watchdog being run with | ||
157 | * deterministic values. | ||
158 | */ | ||
159 | ret = wdt_start(wdt_dev); | ||
160 | if (ret) | ||
161 | return ret; | ||
162 | |||
163 | /* Make sure the watchdog is serviced */ | ||
164 | set_bit(WDOG_HW_RUNNING, &wdt_dev->status); | ||
152 | 165 | ||
153 | ret = devm_watchdog_register_device(&pdev->dev, wdt_dev); | 166 | ret = devm_watchdog_register_device(&pdev->dev, wdt_dev); |
154 | if (ret) { | 167 | if (ret) { |
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index b9878c41598f..dd1e7eaef50f 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c | |||
@@ -12,8 +12,9 @@ | |||
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 | * IT8620, IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726, | 15 | * IT8607, IT8620, IT8622, IT8625, IT8628, IT8655, IT8665, IT8686, |
16 | * IT8728 and IT8783. | 16 | * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726, IT8728, |
17 | * and IT8783. | ||
17 | * | 18 | * |
18 | * This program is free software; you can redistribute it and/or | 19 | * This program is free software; you can redistribute it and/or |
19 | * modify it under the terms of the GNU General Public License | 20 | * modify it under the terms of the GNU General Public License |
@@ -24,38 +25,21 @@ | |||
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
26 | * GNU General Public License for more details. | 27 | * GNU General Public License for more details. |
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; if not, write to the Free Software | ||
30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
31 | */ | 28 | */ |
32 | 29 | ||
33 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 30 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
34 | 31 | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/io.h> | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/moduleparam.h> | 36 | #include <linux/moduleparam.h> |
37 | #include <linux/types.h> | 37 | #include <linux/types.h> |
38 | #include <linux/kernel.h> | ||
39 | #include <linux/fs.h> | ||
40 | #include <linux/miscdevice.h> | ||
41 | #include <linux/init.h> | ||
42 | #include <linux/ioport.h> | ||
43 | #include <linux/watchdog.h> | 38 | #include <linux/watchdog.h> |
44 | #include <linux/notifier.h> | ||
45 | #include <linux/reboot.h> | ||
46 | #include <linux/uaccess.h> | ||
47 | #include <linux/io.h> | ||
48 | |||
49 | 39 | ||
50 | #define WATCHDOG_VERSION "1.14" | ||
51 | #define WATCHDOG_NAME "IT87 WDT" | 40 | #define WATCHDOG_NAME "IT87 WDT" |
52 | #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" | ||
53 | #define WD_MAGIC 'V' | ||
54 | 41 | ||
55 | /* Defaults for Module Parameter */ | 42 | /* Defaults for Module Parameter */ |
56 | #define DEFAULT_NOGAMEPORT 0 | ||
57 | #define DEFAULT_NOCIR 0 | ||
58 | #define DEFAULT_EXCLUSIVE 1 | ||
59 | #define DEFAULT_TIMEOUT 60 | 43 | #define DEFAULT_TIMEOUT 60 |
60 | #define DEFAULT_TESTMODE 0 | 44 | #define DEFAULT_TESTMODE 0 |
61 | #define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT | 45 | #define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT |
@@ -66,19 +50,22 @@ | |||
66 | 50 | ||
67 | /* Logical device Numbers LDN */ | 51 | /* Logical device Numbers LDN */ |
68 | #define GPIO 0x07 | 52 | #define GPIO 0x07 |
69 | #define GAMEPORT 0x09 | ||
70 | #define CIR 0x0a | ||
71 | 53 | ||
72 | /* Configuration Registers and Functions */ | 54 | /* Configuration Registers and Functions */ |
73 | #define LDNREG 0x07 | 55 | #define LDNREG 0x07 |
74 | #define CHIPID 0x20 | 56 | #define CHIPID 0x20 |
75 | #define CHIPREV 0x22 | 57 | #define CHIPREV 0x22 |
76 | #define ACTREG 0x30 | ||
77 | #define BASEREG 0x60 | ||
78 | 58 | ||
79 | /* Chip Id numbers */ | 59 | /* Chip Id numbers */ |
80 | #define NO_DEV_ID 0xffff | 60 | #define NO_DEV_ID 0xffff |
61 | #define IT8607_ID 0x8607 | ||
81 | #define IT8620_ID 0x8620 | 62 | #define IT8620_ID 0x8620 |
63 | #define IT8622_ID 0x8622 | ||
64 | #define IT8625_ID 0x8625 | ||
65 | #define IT8628_ID 0x8628 | ||
66 | #define IT8655_ID 0x8655 | ||
67 | #define IT8665_ID 0x8665 | ||
68 | #define IT8686_ID 0x8686 | ||
82 | #define IT8702_ID 0x8702 | 69 | #define IT8702_ID 0x8702 |
83 | #define IT8705_ID 0x8705 | 70 | #define IT8705_ID 0x8705 |
84 | #define IT8712_ID 0x8712 | 71 | #define IT8712_ID 0x8712 |
@@ -96,14 +83,6 @@ | |||
96 | #define WDTVALLSB 0x73 | 83 | #define WDTVALLSB 0x73 |
97 | #define WDTVALMSB 0x74 | 84 | #define WDTVALMSB 0x74 |
98 | 85 | ||
99 | /* GPIO Bits WDTCTRL */ | ||
100 | #define WDT_CIRINT 0x80 | ||
101 | #define WDT_MOUSEINT 0x40 | ||
102 | #define WDT_KYBINT 0x20 | ||
103 | #define WDT_GAMEPORT 0x10 /* not in it8718, it8720, it8721, it8728 */ | ||
104 | #define WDT_FORCE 0x02 | ||
105 | #define WDT_ZERO 0x01 | ||
106 | |||
107 | /* GPIO Bits WDTCFG */ | 86 | /* GPIO Bits WDTCFG */ |
108 | #define WDT_TOV1 0x80 | 87 | #define WDT_TOV1 0x80 |
109 | #define WDT_KRST 0x40 | 88 | #define WDT_KRST 0x40 |
@@ -111,55 +90,12 @@ | |||
111 | #define WDT_PWROK 0x10 /* not in it8721 */ | 90 | #define WDT_PWROK 0x10 /* not in it8721 */ |
112 | #define WDT_INT_MASK 0x0f | 91 | #define WDT_INT_MASK 0x0f |
113 | 92 | ||
114 | /* CIR Configuration Register LDN=0x0a */ | 93 | static unsigned int max_units, chip_type; |
115 | #define CIR_ILS 0x70 | 94 | |
116 | 95 | static unsigned int timeout = DEFAULT_TIMEOUT; | |
117 | /* The default Base address is not always available, we use this */ | 96 | static int testmode = DEFAULT_TESTMODE; |
118 | #define CIR_BASE 0x0208 | 97 | static bool nowayout = DEFAULT_NOWAYOUT; |
119 | 98 | ||
120 | /* CIR Controller */ | ||
121 | #define CIR_DR(b) (b) | ||
122 | #define CIR_IER(b) (b + 1) | ||
123 | #define CIR_RCR(b) (b + 2) | ||
124 | #define CIR_TCR1(b) (b + 3) | ||
125 | #define CIR_TCR2(b) (b + 4) | ||
126 | #define CIR_TSR(b) (b + 5) | ||
127 | #define CIR_RSR(b) (b + 6) | ||
128 | #define CIR_BDLR(b) (b + 5) | ||
129 | #define CIR_BDHR(b) (b + 6) | ||
130 | #define CIR_IIR(b) (b + 7) | ||
131 | |||
132 | /* Default Base address of Game port */ | ||
133 | #define GP_BASE_DEFAULT 0x0201 | ||
134 | |||
135 | /* wdt_status */ | ||
136 | #define WDTS_TIMER_RUN 0 | ||
137 | #define WDTS_DEV_OPEN 1 | ||
138 | #define WDTS_KEEPALIVE 2 | ||
139 | #define WDTS_LOCKED 3 | ||
140 | #define WDTS_USE_GP 4 | ||
141 | #define WDTS_EXPECTED 5 | ||
142 | #define WDTS_USE_CIR 6 | ||
143 | |||
144 | static unsigned int base, gpact, ciract, max_units, chip_type; | ||
145 | static unsigned long wdt_status; | ||
146 | |||
147 | static int nogameport = DEFAULT_NOGAMEPORT; | ||
148 | static int nocir = DEFAULT_NOCIR; | ||
149 | static int exclusive = DEFAULT_EXCLUSIVE; | ||
150 | static int timeout = DEFAULT_TIMEOUT; | ||
151 | static int testmode = DEFAULT_TESTMODE; | ||
152 | static bool nowayout = DEFAULT_NOWAYOUT; | ||
153 | |||
154 | module_param(nogameport, int, 0); | ||
155 | MODULE_PARM_DESC(nogameport, "Forbid the activation of game port, default=" | ||
156 | __MODULE_STRING(DEFAULT_NOGAMEPORT)); | ||
157 | module_param(nocir, int, 0); | ||
158 | MODULE_PARM_DESC(nocir, "Forbid the use of Consumer IR interrupts to reset timer, default=" | ||
159 | __MODULE_STRING(DEFAULT_NOCIR)); | ||
160 | module_param(exclusive, int, 0); | ||
161 | MODULE_PARM_DESC(exclusive, "Watchdog exclusive device open, default=" | ||
162 | __MODULE_STRING(DEFAULT_EXCLUSIVE)); | ||
163 | module_param(timeout, int, 0); | 99 | module_param(timeout, int, 0); |
164 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default=" | 100 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default=" |
165 | __MODULE_STRING(DEFAULT_TIMEOUT)); | 101 | __MODULE_STRING(DEFAULT_TIMEOUT)); |
@@ -231,88 +167,59 @@ static inline void superio_outw(int val, int reg) | |||
231 | } | 167 | } |
232 | 168 | ||
233 | /* Internal function, should be called after superio_select(GPIO) */ | 169 | /* Internal function, should be called after superio_select(GPIO) */ |
234 | static void wdt_update_timeout(void) | 170 | static void _wdt_update_timeout(unsigned int t) |
235 | { | 171 | { |
236 | unsigned char cfg = WDT_KRST; | 172 | unsigned char cfg = WDT_KRST; |
237 | int tm = timeout; | ||
238 | 173 | ||
239 | if (testmode) | 174 | if (testmode) |
240 | cfg = 0; | 175 | cfg = 0; |
241 | 176 | ||
242 | if (tm <= max_units) | 177 | if (t <= max_units) |
243 | cfg |= WDT_TOV1; | 178 | cfg |= WDT_TOV1; |
244 | else | 179 | else |
245 | tm /= 60; | 180 | t /= 60; |
246 | 181 | ||
247 | if (chip_type != IT8721_ID) | 182 | if (chip_type != IT8721_ID) |
248 | cfg |= WDT_PWROK; | 183 | cfg |= WDT_PWROK; |
249 | 184 | ||
250 | superio_outb(cfg, WDTCFG); | 185 | superio_outb(cfg, WDTCFG); |
251 | superio_outb(tm, WDTVALLSB); | 186 | superio_outb(t, WDTVALLSB); |
252 | if (max_units > 255) | 187 | if (max_units > 255) |
253 | superio_outb(tm>>8, WDTVALMSB); | 188 | superio_outb(t >> 8, WDTVALMSB); |
254 | } | 189 | } |
255 | 190 | ||
256 | static int wdt_round_time(int t) | 191 | static int wdt_update_timeout(unsigned int t) |
257 | { | 192 | { |
258 | t += 59; | 193 | int ret; |
259 | t -= t % 60; | ||
260 | return t; | ||
261 | } | ||
262 | 194 | ||
263 | /* watchdog timer handling */ | 195 | ret = superio_enter(); |
264 | |||
265 | static void wdt_keepalive(void) | ||
266 | { | ||
267 | if (test_bit(WDTS_USE_GP, &wdt_status)) | ||
268 | inb(base); | ||
269 | else if (test_bit(WDTS_USE_CIR, &wdt_status)) | ||
270 | /* The timer reloads with around 5 msec delay */ | ||
271 | outb(0x55, CIR_DR(base)); | ||
272 | else { | ||
273 | if (superio_enter()) | ||
274 | return; | ||
275 | |||
276 | superio_select(GPIO); | ||
277 | wdt_update_timeout(); | ||
278 | superio_exit(); | ||
279 | } | ||
280 | set_bit(WDTS_KEEPALIVE, &wdt_status); | ||
281 | } | ||
282 | |||
283 | static int wdt_start(void) | ||
284 | { | ||
285 | int ret = superio_enter(); | ||
286 | if (ret) | 196 | if (ret) |
287 | return ret; | 197 | return ret; |
288 | 198 | ||
289 | superio_select(GPIO); | 199 | superio_select(GPIO); |
290 | if (test_bit(WDTS_USE_GP, &wdt_status)) | 200 | _wdt_update_timeout(t); |
291 | superio_outb(WDT_GAMEPORT, WDTCTRL); | ||
292 | else if (test_bit(WDTS_USE_CIR, &wdt_status)) | ||
293 | superio_outb(WDT_CIRINT, WDTCTRL); | ||
294 | wdt_update_timeout(); | ||
295 | |||
296 | superio_exit(); | 201 | superio_exit(); |
297 | 202 | ||
298 | return 0; | 203 | return 0; |
299 | } | 204 | } |
300 | 205 | ||
301 | static int wdt_stop(void) | 206 | static int wdt_round_time(int t) |
302 | { | 207 | { |
303 | int ret = superio_enter(); | 208 | t += 59; |
304 | if (ret) | 209 | t -= t % 60; |
305 | return ret; | 210 | return t; |
211 | } | ||
306 | 212 | ||
307 | superio_select(GPIO); | 213 | /* watchdog timer handling */ |
308 | superio_outb(0x00, WDTCTRL); | ||
309 | superio_outb(WDT_TOV1, WDTCFG); | ||
310 | superio_outb(0x00, WDTVALLSB); | ||
311 | if (max_units > 255) | ||
312 | superio_outb(0x00, WDTVALMSB); | ||
313 | 214 | ||
314 | superio_exit(); | 215 | static int wdt_start(struct watchdog_device *wdd) |
315 | return 0; | 216 | { |
217 | return wdt_update_timeout(wdd->timeout); | ||
218 | } | ||
219 | |||
220 | static int wdt_stop(struct watchdog_device *wdd) | ||
221 | { | ||
222 | return wdt_update_timeout(0); | ||
316 | } | 223 | } |
317 | 224 | ||
318 | /** | 225 | /** |
@@ -325,292 +232,44 @@ static int wdt_stop(void) | |||
325 | * Used within WDIOC_SETTIMEOUT watchdog device ioctl. | 232 | * Used within WDIOC_SETTIMEOUT watchdog device ioctl. |
326 | */ | 233 | */ |
327 | 234 | ||
328 | static int wdt_set_timeout(int t) | 235 | static int wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) |
329 | { | 236 | { |
330 | if (t < 1 || t > max_units * 60) | 237 | int ret = 0; |
331 | return -EINVAL; | ||
332 | 238 | ||
333 | if (t > max_units) | 239 | if (t > max_units) |
334 | timeout = wdt_round_time(t); | 240 | t = wdt_round_time(t); |
335 | else | ||
336 | timeout = t; | ||
337 | |||
338 | if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { | ||
339 | int ret = superio_enter(); | ||
340 | if (ret) | ||
341 | return ret; | ||
342 | |||
343 | superio_select(GPIO); | ||
344 | wdt_update_timeout(); | ||
345 | superio_exit(); | ||
346 | } | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * wdt_get_status - determines the status supported by watchdog ioctl | ||
352 | * @status: status returned to user space | ||
353 | * | ||
354 | * The status bit of the device does not allow to distinguish | ||
355 | * between a regular system reset and a watchdog forced reset. | ||
356 | * But, in test mode it is useful, so it is supported through | ||
357 | * WDIOC_GETSTATUS watchdog ioctl. Additionally the driver | ||
358 | * reports the keepalive signal and the acception of the magic. | ||
359 | * | ||
360 | * Used within WDIOC_GETSTATUS watchdog device ioctl. | ||
361 | */ | ||
362 | |||
363 | static int wdt_get_status(int *status) | ||
364 | { | ||
365 | *status = 0; | ||
366 | if (testmode) { | ||
367 | int ret = superio_enter(); | ||
368 | if (ret) | ||
369 | return ret; | ||
370 | |||
371 | superio_select(GPIO); | ||
372 | if (superio_inb(WDTCTRL) & WDT_ZERO) { | ||
373 | superio_outb(0x00, WDTCTRL); | ||
374 | clear_bit(WDTS_TIMER_RUN, &wdt_status); | ||
375 | *status |= WDIOF_CARDRESET; | ||
376 | } | ||
377 | |||
378 | superio_exit(); | ||
379 | } | ||
380 | if (test_and_clear_bit(WDTS_KEEPALIVE, &wdt_status)) | ||
381 | *status |= WDIOF_KEEPALIVEPING; | ||
382 | if (test_bit(WDTS_EXPECTED, &wdt_status)) | ||
383 | *status |= WDIOF_MAGICCLOSE; | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /* /dev/watchdog handling */ | ||
388 | |||
389 | /** | ||
390 | * wdt_open - watchdog file_operations .open | ||
391 | * @inode: inode of the device | ||
392 | * @file: file handle to the device | ||
393 | * | ||
394 | * The watchdog timer starts by opening the device. | ||
395 | * | ||
396 | * Used within the file operation of the watchdog device. | ||
397 | */ | ||
398 | 241 | ||
399 | static int wdt_open(struct inode *inode, struct file *file) | 242 | wdd->timeout = t; |
400 | { | ||
401 | if (exclusive && test_and_set_bit(WDTS_DEV_OPEN, &wdt_status)) | ||
402 | return -EBUSY; | ||
403 | if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) { | ||
404 | int ret; | ||
405 | if (nowayout && !test_and_set_bit(WDTS_LOCKED, &wdt_status)) | ||
406 | __module_get(THIS_MODULE); | ||
407 | |||
408 | ret = wdt_start(); | ||
409 | if (ret) { | ||
410 | clear_bit(WDTS_LOCKED, &wdt_status); | ||
411 | clear_bit(WDTS_TIMER_RUN, &wdt_status); | ||
412 | clear_bit(WDTS_DEV_OPEN, &wdt_status); | ||
413 | return ret; | ||
414 | } | ||
415 | } | ||
416 | return nonseekable_open(inode, file); | ||
417 | } | ||
418 | 243 | ||
419 | /** | 244 | if (watchdog_hw_running(wdd)) |
420 | * wdt_release - watchdog file_operations .release | 245 | ret = wdt_update_timeout(t); |
421 | * @inode: inode of the device | ||
422 | * @file: file handle to the device | ||
423 | * | ||
424 | * Closing the watchdog device either stops the watchdog timer | ||
425 | * or in the case, that nowayout is set or the magic character | ||
426 | * wasn't written, a critical warning about an running watchdog | ||
427 | * timer is given. | ||
428 | * | ||
429 | * Used within the file operation of the watchdog device. | ||
430 | */ | ||
431 | 246 | ||
432 | static int wdt_release(struct inode *inode, struct file *file) | 247 | return ret; |
433 | { | ||
434 | if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { | ||
435 | if (test_and_clear_bit(WDTS_EXPECTED, &wdt_status)) { | ||
436 | int ret = wdt_stop(); | ||
437 | if (ret) { | ||
438 | /* | ||
439 | * Stop failed. Just keep the watchdog alive | ||
440 | * and hope nothing bad happens. | ||
441 | */ | ||
442 | set_bit(WDTS_EXPECTED, &wdt_status); | ||
443 | wdt_keepalive(); | ||
444 | return ret; | ||
445 | } | ||
446 | clear_bit(WDTS_TIMER_RUN, &wdt_status); | ||
447 | } else { | ||
448 | wdt_keepalive(); | ||
449 | pr_crit("unexpected close, not stopping watchdog!\n"); | ||
450 | } | ||
451 | } | ||
452 | clear_bit(WDTS_DEV_OPEN, &wdt_status); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | /** | ||
457 | * wdt_write - watchdog file_operations .write | ||
458 | * @file: file handle to the watchdog | ||
459 | * @buf: buffer to write | ||
460 | * @count: count of bytes | ||
461 | * @ppos: pointer to the position to write. No seeks allowed | ||
462 | * | ||
463 | * A write to a watchdog device is defined as a keepalive signal. Any | ||
464 | * write of data will do, as we don't define content meaning. | ||
465 | * | ||
466 | * Used within the file operation of the watchdog device. | ||
467 | */ | ||
468 | |||
469 | static ssize_t wdt_write(struct file *file, const char __user *buf, | ||
470 | size_t count, loff_t *ppos) | ||
471 | { | ||
472 | if (count) { | ||
473 | clear_bit(WDTS_EXPECTED, &wdt_status); | ||
474 | wdt_keepalive(); | ||
475 | } | ||
476 | if (!nowayout) { | ||
477 | size_t ofs; | ||
478 | |||
479 | /* note: just in case someone wrote the magic character long ago */ | ||
480 | for (ofs = 0; ofs != count; ofs++) { | ||
481 | char c; | ||
482 | if (get_user(c, buf + ofs)) | ||
483 | return -EFAULT; | ||
484 | if (c == WD_MAGIC) | ||
485 | set_bit(WDTS_EXPECTED, &wdt_status); | ||
486 | } | ||
487 | } | ||
488 | return count; | ||
489 | } | 248 | } |
490 | 249 | ||
491 | static const struct watchdog_info ident = { | 250 | static const struct watchdog_info ident = { |
492 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, | 251 | .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, |
493 | .firmware_version = 1, | 252 | .firmware_version = 1, |
494 | .identity = WATCHDOG_NAME, | 253 | .identity = WATCHDOG_NAME, |
495 | }; | 254 | }; |
496 | 255 | ||
497 | /** | 256 | static struct watchdog_ops wdt_ops = { |
498 | * wdt_ioctl - watchdog file_operations .unlocked_ioctl | 257 | .owner = THIS_MODULE, |
499 | * @file: file handle to the device | 258 | .start = wdt_start, |
500 | * @cmd: watchdog command | 259 | .stop = wdt_stop, |
501 | * @arg: argument pointer | 260 | .set_timeout = wdt_set_timeout, |
502 | * | ||
503 | * The watchdog API defines a common set of functions for all watchdogs | ||
504 | * according to their available features. | ||
505 | * | ||
506 | * Used within the file operation of the watchdog device. | ||
507 | */ | ||
508 | |||
509 | static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
510 | { | ||
511 | int rc = 0, status, new_options, new_timeout; | ||
512 | union { | ||
513 | struct watchdog_info __user *ident; | ||
514 | int __user *i; | ||
515 | } uarg; | ||
516 | |||
517 | uarg.i = (int __user *)arg; | ||
518 | |||
519 | switch (cmd) { | ||
520 | case WDIOC_GETSUPPORT: | ||
521 | return copy_to_user(uarg.ident, | ||
522 | &ident, sizeof(ident)) ? -EFAULT : 0; | ||
523 | |||
524 | case WDIOC_GETSTATUS: | ||
525 | rc = wdt_get_status(&status); | ||
526 | if (rc) | ||
527 | return rc; | ||
528 | return put_user(status, uarg.i); | ||
529 | |||
530 | case WDIOC_GETBOOTSTATUS: | ||
531 | return put_user(0, uarg.i); | ||
532 | |||
533 | case WDIOC_KEEPALIVE: | ||
534 | wdt_keepalive(); | ||
535 | return 0; | ||
536 | |||
537 | case WDIOC_SETOPTIONS: | ||
538 | if (get_user(new_options, uarg.i)) | ||
539 | return -EFAULT; | ||
540 | |||
541 | switch (new_options) { | ||
542 | case WDIOS_DISABLECARD: | ||
543 | if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { | ||
544 | rc = wdt_stop(); | ||
545 | if (rc) | ||
546 | return rc; | ||
547 | } | ||
548 | clear_bit(WDTS_TIMER_RUN, &wdt_status); | ||
549 | return 0; | ||
550 | |||
551 | case WDIOS_ENABLECARD: | ||
552 | if (!test_and_set_bit(WDTS_TIMER_RUN, &wdt_status)) { | ||
553 | rc = wdt_start(); | ||
554 | if (rc) { | ||
555 | clear_bit(WDTS_TIMER_RUN, &wdt_status); | ||
556 | return rc; | ||
557 | } | ||
558 | } | ||
559 | return 0; | ||
560 | |||
561 | default: | ||
562 | return -EFAULT; | ||
563 | } | ||
564 | |||
565 | case WDIOC_SETTIMEOUT: | ||
566 | if (get_user(new_timeout, uarg.i)) | ||
567 | return -EFAULT; | ||
568 | rc = wdt_set_timeout(new_timeout); | ||
569 | case WDIOC_GETTIMEOUT: | ||
570 | if (put_user(timeout, uarg.i)) | ||
571 | return -EFAULT; | ||
572 | return rc; | ||
573 | |||
574 | default: | ||
575 | return -ENOTTY; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | ||
580 | void *unused) | ||
581 | { | ||
582 | if (code == SYS_DOWN || code == SYS_HALT) | ||
583 | wdt_stop(); | ||
584 | return NOTIFY_DONE; | ||
585 | } | ||
586 | |||
587 | static const struct file_operations wdt_fops = { | ||
588 | .owner = THIS_MODULE, | ||
589 | .llseek = no_llseek, | ||
590 | .write = wdt_write, | ||
591 | .unlocked_ioctl = wdt_ioctl, | ||
592 | .open = wdt_open, | ||
593 | .release = wdt_release, | ||
594 | }; | 261 | }; |
595 | 262 | ||
596 | static struct miscdevice wdt_miscdev = { | 263 | static struct watchdog_device wdt_dev = { |
597 | .minor = WATCHDOG_MINOR, | 264 | .info = &ident, |
598 | .name = "watchdog", | 265 | .ops = &wdt_ops, |
599 | .fops = &wdt_fops, | 266 | .min_timeout = 1, |
600 | }; | ||
601 | |||
602 | static struct notifier_block wdt_notifier = { | ||
603 | .notifier_call = wdt_notify_sys, | ||
604 | }; | 267 | }; |
605 | 268 | ||
606 | static int __init it87_wdt_init(void) | 269 | static int __init it87_wdt_init(void) |
607 | { | 270 | { |
608 | int rc = 0; | ||
609 | int try_gameport = !nogameport; | ||
610 | u8 chip_rev; | 271 | u8 chip_rev; |
611 | int gp_rreq_fail = 0; | 272 | int rc; |
612 | |||
613 | wdt_status = 0; | ||
614 | 273 | ||
615 | rc = superio_enter(); | 274 | rc = superio_enter(); |
616 | if (rc) | 275 | if (rc) |
@@ -631,14 +290,20 @@ static int __init it87_wdt_init(void) | |||
631 | case IT8726_ID: | 290 | case IT8726_ID: |
632 | max_units = 65535; | 291 | max_units = 65535; |
633 | break; | 292 | break; |
293 | case IT8607_ID: | ||
634 | case IT8620_ID: | 294 | case IT8620_ID: |
295 | case IT8622_ID: | ||
296 | case IT8625_ID: | ||
297 | case IT8628_ID: | ||
298 | case IT8655_ID: | ||
299 | case IT8665_ID: | ||
300 | case IT8686_ID: | ||
635 | case IT8718_ID: | 301 | case IT8718_ID: |
636 | case IT8720_ID: | 302 | case IT8720_ID: |
637 | case IT8721_ID: | 303 | case IT8721_ID: |
638 | case IT8728_ID: | 304 | case IT8728_ID: |
639 | case IT8783_ID: | 305 | case IT8783_ID: |
640 | max_units = 65535; | 306 | max_units = 65535; |
641 | try_gameport = 0; | ||
642 | break; | 307 | break; |
643 | case IT8705_ID: | 308 | case IT8705_ID: |
644 | pr_err("Unsupported Chip found, Chip %04x Revision %02x\n", | 309 | pr_err("Unsupported Chip found, Chip %04x Revision %02x\n", |
@@ -660,48 +325,7 @@ static int __init it87_wdt_init(void) | |||
660 | superio_select(GPIO); | 325 | superio_select(GPIO); |
661 | superio_outb(WDT_TOV1, WDTCFG); | 326 | superio_outb(WDT_TOV1, WDTCFG); |
662 | superio_outb(0x00, WDTCTRL); | 327 | superio_outb(0x00, WDTCTRL); |
663 | 328 | superio_exit(); | |
664 | /* First try to get Gameport support */ | ||
665 | if (try_gameport) { | ||
666 | superio_select(GAMEPORT); | ||
667 | base = superio_inw(BASEREG); | ||
668 | if (!base) { | ||
669 | base = GP_BASE_DEFAULT; | ||
670 | superio_outw(base, BASEREG); | ||
671 | } | ||
672 | gpact = superio_inb(ACTREG); | ||
673 | superio_outb(0x01, ACTREG); | ||
674 | if (request_region(base, 1, WATCHDOG_NAME)) | ||
675 | set_bit(WDTS_USE_GP, &wdt_status); | ||
676 | else | ||
677 | gp_rreq_fail = 1; | ||
678 | } | ||
679 | |||
680 | /* If we haven't Gameport support, try to get CIR support */ | ||
681 | if (!nocir && !test_bit(WDTS_USE_GP, &wdt_status)) { | ||
682 | if (!request_region(CIR_BASE, 8, WATCHDOG_NAME)) { | ||
683 | if (gp_rreq_fail) | ||
684 | pr_err("I/O Address 0x%04x and 0x%04x already in use\n", | ||
685 | base, CIR_BASE); | ||
686 | else | ||
687 | pr_err("I/O Address 0x%04x already in use\n", | ||
688 | CIR_BASE); | ||
689 | rc = -EIO; | ||
690 | goto err_out; | ||
691 | } | ||
692 | base = CIR_BASE; | ||
693 | |||
694 | superio_select(CIR); | ||
695 | superio_outw(base, BASEREG); | ||
696 | superio_outb(0x00, CIR_ILS); | ||
697 | ciract = superio_inb(ACTREG); | ||
698 | superio_outb(0x01, ACTREG); | ||
699 | if (gp_rreq_fail) { | ||
700 | superio_select(GAMEPORT); | ||
701 | superio_outb(gpact, ACTREG); | ||
702 | } | ||
703 | set_bit(WDTS_USE_CIR, &wdt_status); | ||
704 | } | ||
705 | 329 | ||
706 | if (timeout < 1 || timeout > max_units * 60) { | 330 | if (timeout < 1 || timeout > max_units * 60) { |
707 | timeout = DEFAULT_TIMEOUT; | 331 | timeout = DEFAULT_TIMEOUT; |
@@ -712,83 +336,25 @@ static int __init it87_wdt_init(void) | |||
712 | if (timeout > max_units) | 336 | if (timeout > max_units) |
713 | timeout = wdt_round_time(timeout); | 337 | timeout = wdt_round_time(timeout); |
714 | 338 | ||
715 | rc = register_reboot_notifier(&wdt_notifier); | 339 | wdt_dev.timeout = timeout; |
716 | if (rc) { | 340 | wdt_dev.max_timeout = max_units * 60; |
717 | pr_err("Cannot register reboot notifier (err=%d)\n", rc); | ||
718 | goto err_out_region; | ||
719 | } | ||
720 | 341 | ||
721 | rc = misc_register(&wdt_miscdev); | 342 | watchdog_stop_on_reboot(&wdt_dev); |
343 | rc = watchdog_register_device(&wdt_dev); | ||
722 | if (rc) { | 344 | if (rc) { |
723 | pr_err("Cannot register miscdev on minor=%d (err=%d)\n", | 345 | pr_err("Cannot register watchdog device (err=%d)\n", rc); |
724 | wdt_miscdev.minor, rc); | 346 | return rc; |
725 | goto err_out_reboot; | ||
726 | } | ||
727 | |||
728 | /* Initialize CIR to use it as keepalive source */ | ||
729 | if (test_bit(WDTS_USE_CIR, &wdt_status)) { | ||
730 | outb(0x00, CIR_RCR(base)); | ||
731 | outb(0xc0, CIR_TCR1(base)); | ||
732 | outb(0x5c, CIR_TCR2(base)); | ||
733 | outb(0x10, CIR_IER(base)); | ||
734 | outb(0x00, CIR_BDHR(base)); | ||
735 | outb(0x01, CIR_BDLR(base)); | ||
736 | outb(0x09, CIR_IER(base)); | ||
737 | } | 347 | } |
738 | 348 | ||
739 | pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d exclusive=%d nogameport=%d nocir=%d)\n", | 349 | pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", |
740 | chip_type, chip_rev, timeout, | 350 | chip_type, chip_rev, timeout, nowayout, testmode); |
741 | nowayout, testmode, exclusive, nogameport, nocir); | ||
742 | 351 | ||
743 | superio_exit(); | ||
744 | return 0; | 352 | return 0; |
745 | |||
746 | err_out_reboot: | ||
747 | unregister_reboot_notifier(&wdt_notifier); | ||
748 | err_out_region: | ||
749 | if (test_bit(WDTS_USE_GP, &wdt_status)) | ||
750 | release_region(base, 1); | ||
751 | else if (test_bit(WDTS_USE_CIR, &wdt_status)) { | ||
752 | release_region(base, 8); | ||
753 | superio_select(CIR); | ||
754 | superio_outb(ciract, ACTREG); | ||
755 | } | ||
756 | err_out: | ||
757 | if (try_gameport) { | ||
758 | superio_select(GAMEPORT); | ||
759 | superio_outb(gpact, ACTREG); | ||
760 | } | ||
761 | |||
762 | superio_exit(); | ||
763 | return rc; | ||
764 | } | 353 | } |
765 | 354 | ||
766 | static void __exit it87_wdt_exit(void) | 355 | static void __exit it87_wdt_exit(void) |
767 | { | 356 | { |
768 | if (superio_enter() == 0) { | 357 | watchdog_unregister_device(&wdt_dev); |
769 | superio_select(GPIO); | ||
770 | superio_outb(0x00, WDTCTRL); | ||
771 | superio_outb(0x00, WDTCFG); | ||
772 | superio_outb(0x00, WDTVALLSB); | ||
773 | if (max_units > 255) | ||
774 | superio_outb(0x00, WDTVALMSB); | ||
775 | if (test_bit(WDTS_USE_GP, &wdt_status)) { | ||
776 | superio_select(GAMEPORT); | ||
777 | superio_outb(gpact, ACTREG); | ||
778 | } else if (test_bit(WDTS_USE_CIR, &wdt_status)) { | ||
779 | superio_select(CIR); | ||
780 | superio_outb(ciract, ACTREG); | ||
781 | } | ||
782 | superio_exit(); | ||
783 | } | ||
784 | |||
785 | misc_deregister(&wdt_miscdev); | ||
786 | unregister_reboot_notifier(&wdt_notifier); | ||
787 | |||
788 | if (test_bit(WDTS_USE_GP, &wdt_status)) | ||
789 | release_region(base, 1); | ||
790 | else if (test_bit(WDTS_USE_CIR, &wdt_status)) | ||
791 | release_region(base, 8); | ||
792 | } | 358 | } |
793 | 359 | ||
794 | module_init(it87_wdt_init); | 360 | module_init(it87_wdt_init); |
diff --git a/drivers/watchdog/meson_gxbb_wdt.c b/drivers/watchdog/meson_gxbb_wdt.c index 45d47664a00a..69a5a57f1446 100644 --- a/drivers/watchdog/meson_gxbb_wdt.c +++ b/drivers/watchdog/meson_gxbb_wdt.c | |||
@@ -203,7 +203,9 @@ static int meson_gxbb_wdt_probe(struct platform_device *pdev) | |||
203 | if (IS_ERR(data->clk)) | 203 | if (IS_ERR(data->clk)) |
204 | return PTR_ERR(data->clk); | 204 | return PTR_ERR(data->clk); |
205 | 205 | ||
206 | clk_prepare_enable(data->clk); | 206 | ret = clk_prepare_enable(data->clk); |
207 | if (ret) | ||
208 | return ret; | ||
207 | 209 | ||
208 | platform_set_drvdata(pdev, data); | 210 | platform_set_drvdata(pdev, data); |
209 | 211 | ||
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index 39be4dd8035e..83af7d6cc37c 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c | |||
@@ -651,5 +651,5 @@ module_param(nowayout, bool, 0); | |||
651 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 651 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
652 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 652 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
653 | 653 | ||
654 | MODULE_LICENSE("GPL"); | 654 | MODULE_LICENSE("GPL v2"); |
655 | MODULE_ALIAS("platform:orion_wdt"); | 655 | MODULE_ALIAS("platform:orion_wdt"); |
diff --git a/drivers/watchdog/rza_wdt.c b/drivers/watchdog/rza_wdt.c new file mode 100644 index 000000000000..e618218d2374 --- /dev/null +++ b/drivers/watchdog/rza_wdt.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Renesas RZ/A Series WDT Driver | ||
3 | * | ||
4 | * Copyright (C) 2017 Renesas Electronics America, Inc. | ||
5 | * Copyright (C) 2017 Chris Brandt | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/bitops.h> | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of_address.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/watchdog.h> | ||
19 | |||
20 | #define DEFAULT_TIMEOUT 30 | ||
21 | |||
22 | /* Watchdog Timer Registers */ | ||
23 | #define WTCSR 0 | ||
24 | #define WTCSR_MAGIC 0xA500 | ||
25 | #define WTSCR_WT BIT(6) | ||
26 | #define WTSCR_TME BIT(5) | ||
27 | #define WTSCR_CKS(i) (i) | ||
28 | |||
29 | #define WTCNT 2 | ||
30 | #define WTCNT_MAGIC 0x5A00 | ||
31 | |||
32 | #define WRCSR 4 | ||
33 | #define WRCSR_MAGIC 0x5A00 | ||
34 | #define WRCSR_RSTE BIT(6) | ||
35 | #define WRCSR_CLEAR_WOVF 0xA500 /* special value */ | ||
36 | |||
37 | struct rza_wdt { | ||
38 | struct watchdog_device wdev; | ||
39 | void __iomem *base; | ||
40 | struct clk *clk; | ||
41 | }; | ||
42 | |||
43 | static int rza_wdt_start(struct watchdog_device *wdev) | ||
44 | { | ||
45 | struct rza_wdt *priv = watchdog_get_drvdata(wdev); | ||
46 | |||
47 | /* Stop timer */ | ||
48 | writew(WTCSR_MAGIC | 0, priv->base + WTCSR); | ||
49 | |||
50 | /* Must dummy read WRCSR:WOVF at least once before clearing */ | ||
51 | readb(priv->base + WRCSR); | ||
52 | writew(WRCSR_CLEAR_WOVF, priv->base + WRCSR); | ||
53 | |||
54 | /* | ||
55 | * Start timer with slowest clock source and reset option enabled. | ||
56 | */ | ||
57 | writew(WRCSR_MAGIC | WRCSR_RSTE, priv->base + WRCSR); | ||
58 | writew(WTCNT_MAGIC | 0, priv->base + WTCNT); | ||
59 | writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME | WTSCR_CKS(7), | ||
60 | priv->base + WTCSR); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int rza_wdt_stop(struct watchdog_device *wdev) | ||
66 | { | ||
67 | struct rza_wdt *priv = watchdog_get_drvdata(wdev); | ||
68 | |||
69 | writew(WTCSR_MAGIC | 0, priv->base + WTCSR); | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int rza_wdt_ping(struct watchdog_device *wdev) | ||
75 | { | ||
76 | struct rza_wdt *priv = watchdog_get_drvdata(wdev); | ||
77 | |||
78 | writew(WTCNT_MAGIC | 0, priv->base + WTCNT); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int rza_wdt_restart(struct watchdog_device *wdev, unsigned long action, | ||
84 | void *data) | ||
85 | { | ||
86 | struct rza_wdt *priv = watchdog_get_drvdata(wdev); | ||
87 | |||
88 | /* Stop timer */ | ||
89 | writew(WTCSR_MAGIC | 0, priv->base + WTCSR); | ||
90 | |||
91 | /* Must dummy read WRCSR:WOVF at least once before clearing */ | ||
92 | readb(priv->base + WRCSR); | ||
93 | writew(WRCSR_CLEAR_WOVF, priv->base + WRCSR); | ||
94 | |||
95 | /* | ||
96 | * Start timer with fastest clock source and only 1 clock left before | ||
97 | * overflow with reset option enabled. | ||
98 | */ | ||
99 | writew(WRCSR_MAGIC | WRCSR_RSTE, priv->base + WRCSR); | ||
100 | writew(WTCNT_MAGIC | 255, priv->base + WTCNT); | ||
101 | writew(WTCSR_MAGIC | WTSCR_WT | WTSCR_TME, priv->base + WTCSR); | ||
102 | |||
103 | /* | ||
104 | * Actually make sure the above sequence hits hardware before sleeping. | ||
105 | */ | ||
106 | wmb(); | ||
107 | |||
108 | /* Wait for WDT overflow (reset) */ | ||
109 | udelay(20); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static const struct watchdog_info rza_wdt_ident = { | ||
115 | .options = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT, | ||
116 | .identity = "Renesas RZ/A WDT Watchdog", | ||
117 | }; | ||
118 | |||
119 | static const struct watchdog_ops rza_wdt_ops = { | ||
120 | .owner = THIS_MODULE, | ||
121 | .start = rza_wdt_start, | ||
122 | .stop = rza_wdt_stop, | ||
123 | .ping = rza_wdt_ping, | ||
124 | .restart = rza_wdt_restart, | ||
125 | }; | ||
126 | |||
127 | static int rza_wdt_probe(struct platform_device *pdev) | ||
128 | { | ||
129 | struct rza_wdt *priv; | ||
130 | struct resource *res; | ||
131 | unsigned long rate; | ||
132 | int ret; | ||
133 | |||
134 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
135 | if (!priv) | ||
136 | return -ENOMEM; | ||
137 | |||
138 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
139 | priv->base = devm_ioremap_resource(&pdev->dev, res); | ||
140 | if (IS_ERR(priv->base)) | ||
141 | return PTR_ERR(priv->base); | ||
142 | |||
143 | priv->clk = devm_clk_get(&pdev->dev, NULL); | ||
144 | if (IS_ERR(priv->clk)) | ||
145 | return PTR_ERR(priv->clk); | ||
146 | |||
147 | rate = clk_get_rate(priv->clk); | ||
148 | if (rate < 16384) { | ||
149 | dev_err(&pdev->dev, "invalid clock rate (%ld)\n", rate); | ||
150 | return -ENOENT; | ||
151 | } | ||
152 | |||
153 | /* Assume slowest clock rate possible (CKS=7) */ | ||
154 | rate /= 16384; | ||
155 | |||
156 | priv->wdev.info = &rza_wdt_ident, | ||
157 | priv->wdev.ops = &rza_wdt_ops, | ||
158 | priv->wdev.parent = &pdev->dev; | ||
159 | |||
160 | /* | ||
161 | * Since the max possible timeout of our 8-bit count register is less | ||
162 | * than a second, we must use max_hw_heartbeat_ms. | ||
163 | */ | ||
164 | priv->wdev.max_hw_heartbeat_ms = (1000 * U8_MAX) / rate; | ||
165 | dev_dbg(&pdev->dev, "max hw timeout of %dms\n", | ||
166 | priv->wdev.max_hw_heartbeat_ms); | ||
167 | |||
168 | priv->wdev.min_timeout = 1; | ||
169 | priv->wdev.timeout = DEFAULT_TIMEOUT; | ||
170 | |||
171 | watchdog_init_timeout(&priv->wdev, 0, &pdev->dev); | ||
172 | watchdog_set_drvdata(&priv->wdev, priv); | ||
173 | |||
174 | ret = devm_watchdog_register_device(&pdev->dev, &priv->wdev); | ||
175 | if (ret) | ||
176 | dev_err(&pdev->dev, "Cannot register watchdog device\n"); | ||
177 | |||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | static const struct of_device_id rza_wdt_of_match[] = { | ||
182 | { .compatible = "renesas,rza-wdt", }, | ||
183 | { /* sentinel */ } | ||
184 | }; | ||
185 | MODULE_DEVICE_TABLE(of, rza_wdt_of_match); | ||
186 | |||
187 | static struct platform_driver rza_wdt_driver = { | ||
188 | .probe = rza_wdt_probe, | ||
189 | .driver = { | ||
190 | .name = "rza_wdt", | ||
191 | .of_match_table = rza_wdt_of_match, | ||
192 | }, | ||
193 | }; | ||
194 | |||
195 | module_platform_driver(rza_wdt_driver); | ||
196 | |||
197 | MODULE_DESCRIPTION("Renesas RZ/A WDT Driver"); | ||
198 | MODULE_AUTHOR("Chris Brandt <chris.brandt@renesas.com>"); | ||
199 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 6ed97596ca80..adaa43543f0a 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* linux/drivers/char/watchdog/s3c2410_wdt.c | 1 | /* |
2 | * | ||
3 | * Copyright (c) 2004 Simtec Electronics | 2 | * Copyright (c) 2004 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 3 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 4 | * |
@@ -17,11 +16,7 @@ | |||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
20 | * | 19 | */ |
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | 20 | ||
26 | #include <linux/module.h> | 21 | #include <linux/module.h> |
27 | #include <linux/moduleparam.h> | 22 | #include <linux/moduleparam.h> |
@@ -37,6 +32,7 @@ | |||
37 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
38 | #include <linux/err.h> | 33 | #include <linux/err.h> |
39 | #include <linux/of.h> | 34 | #include <linux/of.h> |
35 | #include <linux/of_device.h> | ||
40 | #include <linux/mfd/syscon.h> | 36 | #include <linux/mfd/syscon.h> |
41 | #include <linux/regmap.h> | 37 | #include <linux/regmap.h> |
42 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
@@ -94,8 +90,7 @@ MODULE_PARM_DESC(tmr_atboot, | |||
94 | __MODULE_STRING(S3C2410_WATCHDOG_ATBOOT)); | 90 | __MODULE_STRING(S3C2410_WATCHDOG_ATBOOT)); |
95 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 91 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
96 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 92 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
97 | MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, " | 93 | MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, 0 to reboot (default 0)"); |
98 | "0 to reboot (default 0)"); | ||
99 | 94 | ||
100 | /** | 95 | /** |
101 | * struct s3c2410_wdt_variant - Per-variant config data | 96 | * struct s3c2410_wdt_variant - Per-variant config data |
@@ -131,7 +126,7 @@ struct s3c2410_wdt { | |||
131 | unsigned long wtdat_save; | 126 | unsigned long wtdat_save; |
132 | struct watchdog_device wdt_device; | 127 | struct watchdog_device wdt_device; |
133 | struct notifier_block freq_transition; | 128 | struct notifier_block freq_transition; |
134 | struct s3c2410_wdt_variant *drv_data; | 129 | const struct s3c2410_wdt_variant *drv_data; |
135 | struct regmap *pmureg; | 130 | struct regmap *pmureg; |
136 | }; | 131 | }; |
137 | 132 | ||
@@ -310,7 +305,8 @@ static inline int s3c2410wdt_is_running(struct s3c2410_wdt *wdt) | |||
310 | return readl(wdt->reg_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; | 305 | return readl(wdt->reg_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; |
311 | } | 306 | } |
312 | 307 | ||
313 | static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeout) | 308 | static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, |
309 | unsigned int timeout) | ||
314 | { | 310 | { |
315 | struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); | 311 | struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd); |
316 | unsigned long freq = clk_get_rate(wdt->clock); | 312 | unsigned long freq = clk_get_rate(wdt->clock); |
@@ -401,7 +397,7 @@ static const struct watchdog_ops s3c2410wdt_ops = { | |||
401 | .restart = s3c2410wdt_restart, | 397 | .restart = s3c2410wdt_restart, |
402 | }; | 398 | }; |
403 | 399 | ||
404 | static struct watchdog_device s3c2410_wdd = { | 400 | static const struct watchdog_device s3c2410_wdd = { |
405 | .info = &s3c2410_wdt_ident, | 401 | .info = &s3c2410_wdt_ident, |
406 | .ops = &s3c2410wdt_ops, | 402 | .ops = &s3c2410wdt_ops, |
407 | .timeout = S3C2410_WATCHDOG_DEFAULT_TIME, | 403 | .timeout = S3C2410_WATCHDOG_DEFAULT_TIME, |
@@ -507,22 +503,24 @@ static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt) | |||
507 | return 0; | 503 | return 0; |
508 | } | 504 | } |
509 | 505 | ||
510 | static inline struct s3c2410_wdt_variant * | 506 | static inline const struct s3c2410_wdt_variant * |
511 | s3c2410_get_wdt_drv_data(struct platform_device *pdev) | 507 | s3c2410_get_wdt_drv_data(struct platform_device *pdev) |
512 | { | 508 | { |
513 | if (pdev->dev.of_node) { | 509 | const struct s3c2410_wdt_variant *variant; |
514 | const struct of_device_id *match; | 510 | |
515 | match = of_match_node(s3c2410_wdt_match, pdev->dev.of_node); | 511 | variant = of_device_get_match_data(&pdev->dev); |
516 | return (struct s3c2410_wdt_variant *)match->data; | 512 | if (!variant) { |
517 | } else { | 513 | /* Device matched by platform_device_id */ |
518 | return (struct s3c2410_wdt_variant *) | 514 | variant = (struct s3c2410_wdt_variant *) |
519 | platform_get_device_id(pdev)->driver_data; | 515 | platform_get_device_id(pdev)->driver_data; |
520 | } | 516 | } |
517 | |||
518 | return variant; | ||
521 | } | 519 | } |
522 | 520 | ||
523 | static int s3c2410wdt_probe(struct platform_device *pdev) | 521 | static int s3c2410wdt_probe(struct platform_device *pdev) |
524 | { | 522 | { |
525 | struct device *dev; | 523 | struct device *dev = &pdev->dev; |
526 | struct s3c2410_wdt *wdt; | 524 | struct s3c2410_wdt *wdt; |
527 | struct resource *wdt_mem; | 525 | struct resource *wdt_mem; |
528 | struct resource *wdt_irq; | 526 | struct resource *wdt_irq; |
@@ -530,13 +528,11 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
530 | int started = 0; | 528 | int started = 0; |
531 | int ret; | 529 | int ret; |
532 | 530 | ||
533 | dev = &pdev->dev; | ||
534 | |||
535 | wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); | 531 | wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); |
536 | if (!wdt) | 532 | if (!wdt) |
537 | return -ENOMEM; | 533 | return -ENOMEM; |
538 | 534 | ||
539 | wdt->dev = &pdev->dev; | 535 | wdt->dev = dev; |
540 | spin_lock_init(&wdt->lock); | 536 | spin_lock_init(&wdt->lock); |
541 | wdt->wdt_device = s3c2410_wdd; | 537 | wdt->wdt_device = s3c2410_wdd; |
542 | 538 | ||
@@ -592,7 +588,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
592 | /* see if we can actually set the requested timer margin, and if | 588 | /* see if we can actually set the requested timer margin, and if |
593 | * not, try the default value */ | 589 | * not, try the default value */ |
594 | 590 | ||
595 | watchdog_init_timeout(&wdt->wdt_device, tmr_margin, &pdev->dev); | 591 | watchdog_init_timeout(&wdt->wdt_device, tmr_margin, dev); |
596 | ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device, | 592 | ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device, |
597 | wdt->wdt_device.timeout); | 593 | wdt->wdt_device.timeout); |
598 | if (ret) { | 594 | if (ret) { |
@@ -601,11 +597,10 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
601 | 597 | ||
602 | if (started == 0) | 598 | if (started == 0) |
603 | dev_info(dev, | 599 | dev_info(dev, |
604 | "tmr_margin value out of range, default %d used\n", | 600 | "tmr_margin value out of range, default %d used\n", |
605 | S3C2410_WATCHDOG_DEFAULT_TIME); | 601 | S3C2410_WATCHDOG_DEFAULT_TIME); |
606 | else | 602 | else |
607 | dev_info(dev, "default timer value is out of range, " | 603 | dev_info(dev, "default timer value is out of range, cannot start\n"); |
608 | "cannot start\n"); | ||
609 | } | 604 | } |
610 | 605 | ||
611 | ret = devm_request_irq(dev, wdt_irq->start, s3c2410wdt_irq, 0, | 606 | ret = devm_request_irq(dev, wdt_irq->start, s3c2410wdt_irq, 0, |
@@ -619,7 +614,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) | |||
619 | watchdog_set_restart_priority(&wdt->wdt_device, 128); | 614 | watchdog_set_restart_priority(&wdt->wdt_device, 128); |
620 | 615 | ||
621 | wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt); | 616 | wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt); |
622 | wdt->wdt_device.parent = &pdev->dev; | 617 | wdt->wdt_device.parent = dev; |
623 | 618 | ||
624 | ret = watchdog_register_device(&wdt->wdt_device); | 619 | ret = watchdog_register_device(&wdt->wdt_device); |
625 | if (ret) { | 620 | if (ret) { |
@@ -754,7 +749,6 @@ static struct platform_driver s3c2410wdt_driver = { | |||
754 | 749 | ||
755 | module_platform_driver(s3c2410wdt_driver); | 750 | module_platform_driver(s3c2410wdt_driver); |
756 | 751 | ||
757 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, " | 752 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, Dimitry Andric <dimitry.andric@tomtom.com>"); |
758 | "Dimitry Andric <dimitry.andric@tomtom.com>"); | ||
759 | MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver"); | 753 | MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver"); |
760 | MODULE_LICENSE("GPL"); | 754 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c index 362fd229786d..0ae947c3d7bc 100644 --- a/drivers/watchdog/sama5d4_wdt.c +++ b/drivers/watchdog/sama5d4_wdt.c | |||
@@ -228,15 +228,13 @@ static int sama5d4_wdt_probe(struct platform_device *pdev) | |||
228 | 228 | ||
229 | wdt->reg_base = regs; | 229 | wdt->reg_base = regs; |
230 | 230 | ||
231 | if (pdev->dev.of_node) { | 231 | irq = irq_of_parse_and_map(pdev->dev.of_node, 0); |
232 | irq = irq_of_parse_and_map(pdev->dev.of_node, 0); | 232 | if (!irq) |
233 | if (!irq) | 233 | dev_warn(&pdev->dev, "failed to get IRQ from DT\n"); |
234 | dev_warn(&pdev->dev, "failed to get IRQ from DT\n"); | ||
235 | 234 | ||
236 | ret = of_sama5d4_wdt_init(pdev->dev.of_node, wdt); | 235 | ret = of_sama5d4_wdt_init(pdev->dev.of_node, wdt); |
237 | if (ret) | 236 | if (ret) |
238 | return ret; | 237 | return ret; |
239 | } | ||
240 | 238 | ||
241 | if ((wdt->mr & AT91_WDT_WDFIEN) && irq) { | 239 | if ((wdt->mr & AT91_WDT_WDFIEN) && irq) { |
242 | ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler, | 240 | ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler, |
@@ -302,6 +300,11 @@ static int sama5d4_wdt_resume(struct device *dev) | |||
302 | { | 300 | { |
303 | struct sama5d4_wdt *wdt = dev_get_drvdata(dev); | 301 | struct sama5d4_wdt *wdt = dev_get_drvdata(dev); |
304 | 302 | ||
303 | /* | ||
304 | * FIXME: writing MR also pings the watchdog which may not be desired. | ||
305 | * This should only be done when the registers are lost on suspend but | ||
306 | * there is no way to get this information right now. | ||
307 | */ | ||
305 | sama5d4_wdt_init(wdt); | 308 | sama5d4_wdt_init(wdt); |
306 | 309 | ||
307 | return 0; | 310 | return 0; |
diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c new file mode 100644 index 000000000000..6c501b7dba29 --- /dev/null +++ b/drivers/watchdog/stm32_iwdg.c | |||
@@ -0,0 +1,253 @@ | |||
1 | /* | ||
2 | * Driver for STM32 Independent Watchdog | ||
3 | * | ||
4 | * Copyright (C) Yannick Fertre 2017 | ||
5 | * Author: Yannick Fertre <yannick.fertre@st.com> | ||
6 | * | ||
7 | * This driver is based on tegra_wdt.c | ||
8 | * | ||
9 | * License terms: GNU General Public License (GPL), version 2 | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/iopoll.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/watchdog.h> | ||
22 | |||
23 | /* IWDG registers */ | ||
24 | #define IWDG_KR 0x00 /* Key register */ | ||
25 | #define IWDG_PR 0x04 /* Prescaler Register */ | ||
26 | #define IWDG_RLR 0x08 /* ReLoad Register */ | ||
27 | #define IWDG_SR 0x0C /* Status Register */ | ||
28 | #define IWDG_WINR 0x10 /* Windows Register */ | ||
29 | |||
30 | /* IWDG_KR register bit mask */ | ||
31 | #define KR_KEY_RELOAD 0xAAAA /* reload counter enable */ | ||
32 | #define KR_KEY_ENABLE 0xCCCC /* peripheral enable */ | ||
33 | #define KR_KEY_EWA 0x5555 /* write access enable */ | ||
34 | #define KR_KEY_DWA 0x0000 /* write access disable */ | ||
35 | |||
36 | /* IWDG_PR register bit values */ | ||
37 | #define PR_4 0x00 /* prescaler set to 4 */ | ||
38 | #define PR_8 0x01 /* prescaler set to 8 */ | ||
39 | #define PR_16 0x02 /* prescaler set to 16 */ | ||
40 | #define PR_32 0x03 /* prescaler set to 32 */ | ||
41 | #define PR_64 0x04 /* prescaler set to 64 */ | ||
42 | #define PR_128 0x05 /* prescaler set to 128 */ | ||
43 | #define PR_256 0x06 /* prescaler set to 256 */ | ||
44 | |||
45 | /* IWDG_RLR register values */ | ||
46 | #define RLR_MIN 0x07C /* min value supported by reload register */ | ||
47 | #define RLR_MAX 0xFFF /* max value supported by reload register */ | ||
48 | |||
49 | /* IWDG_SR register bit mask */ | ||
50 | #define FLAG_PVU BIT(0) /* Watchdog prescaler value update */ | ||
51 | #define FLAG_RVU BIT(1) /* Watchdog counter reload value update */ | ||
52 | |||
53 | /* set timeout to 100000 us */ | ||
54 | #define TIMEOUT_US 100000 | ||
55 | #define SLEEP_US 1000 | ||
56 | |||
57 | struct stm32_iwdg { | ||
58 | struct watchdog_device wdd; | ||
59 | void __iomem *regs; | ||
60 | struct clk *clk; | ||
61 | unsigned int rate; | ||
62 | }; | ||
63 | |||
64 | static inline u32 reg_read(void __iomem *base, u32 reg) | ||
65 | { | ||
66 | return readl_relaxed(base + reg); | ||
67 | } | ||
68 | |||
69 | static inline void reg_write(void __iomem *base, u32 reg, u32 val) | ||
70 | { | ||
71 | writel_relaxed(val, base + reg); | ||
72 | } | ||
73 | |||
74 | static int stm32_iwdg_start(struct watchdog_device *wdd) | ||
75 | { | ||
76 | struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd); | ||
77 | u32 val = FLAG_PVU | FLAG_RVU; | ||
78 | u32 reload; | ||
79 | int ret; | ||
80 | |||
81 | dev_dbg(wdd->parent, "%s\n", __func__); | ||
82 | |||
83 | /* prescaler fixed to 256 */ | ||
84 | reload = clamp_t(unsigned int, ((wdd->timeout * wdt->rate) / 256) - 1, | ||
85 | RLR_MIN, RLR_MAX); | ||
86 | |||
87 | /* enable write access */ | ||
88 | reg_write(wdt->regs, IWDG_KR, KR_KEY_EWA); | ||
89 | |||
90 | /* set prescaler & reload registers */ | ||
91 | reg_write(wdt->regs, IWDG_PR, PR_256); /* prescaler fix to 256 */ | ||
92 | reg_write(wdt->regs, IWDG_RLR, reload); | ||
93 | reg_write(wdt->regs, IWDG_KR, KR_KEY_ENABLE); | ||
94 | |||
95 | /* wait for the registers to be updated (max 100ms) */ | ||
96 | ret = readl_relaxed_poll_timeout(wdt->regs + IWDG_SR, val, | ||
97 | !(val & (FLAG_PVU | FLAG_RVU)), | ||
98 | SLEEP_US, TIMEOUT_US); | ||
99 | if (ret) { | ||
100 | dev_err(wdd->parent, | ||
101 | "Fail to set prescaler or reload registers\n"); | ||
102 | return ret; | ||
103 | } | ||
104 | |||
105 | /* reload watchdog */ | ||
106 | reg_write(wdt->regs, IWDG_KR, KR_KEY_RELOAD); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int stm32_iwdg_ping(struct watchdog_device *wdd) | ||
112 | { | ||
113 | struct stm32_iwdg *wdt = watchdog_get_drvdata(wdd); | ||
114 | |||
115 | dev_dbg(wdd->parent, "%s\n", __func__); | ||
116 | |||
117 | /* reload watchdog */ | ||
118 | reg_write(wdt->regs, IWDG_KR, KR_KEY_RELOAD); | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int stm32_iwdg_set_timeout(struct watchdog_device *wdd, | ||
124 | unsigned int timeout) | ||
125 | { | ||
126 | dev_dbg(wdd->parent, "%s timeout: %d sec\n", __func__, timeout); | ||
127 | |||
128 | wdd->timeout = timeout; | ||
129 | |||
130 | if (watchdog_active(wdd)) | ||
131 | return stm32_iwdg_start(wdd); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static const struct watchdog_info stm32_iwdg_info = { | ||
137 | .options = WDIOF_SETTIMEOUT | | ||
138 | WDIOF_MAGICCLOSE | | ||
139 | WDIOF_KEEPALIVEPING, | ||
140 | .identity = "STM32 Independent Watchdog", | ||
141 | }; | ||
142 | |||
143 | static struct watchdog_ops stm32_iwdg_ops = { | ||
144 | .owner = THIS_MODULE, | ||
145 | .start = stm32_iwdg_start, | ||
146 | .ping = stm32_iwdg_ping, | ||
147 | .set_timeout = stm32_iwdg_set_timeout, | ||
148 | }; | ||
149 | |||
150 | static int stm32_iwdg_probe(struct platform_device *pdev) | ||
151 | { | ||
152 | struct watchdog_device *wdd; | ||
153 | struct stm32_iwdg *wdt; | ||
154 | struct resource *res; | ||
155 | void __iomem *regs; | ||
156 | struct clk *clk; | ||
157 | int ret; | ||
158 | |||
159 | /* This is the timer base. */ | ||
160 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
161 | regs = devm_ioremap_resource(&pdev->dev, res); | ||
162 | if (IS_ERR(regs)) { | ||
163 | dev_err(&pdev->dev, "Could not get resource\n"); | ||
164 | return PTR_ERR(regs); | ||
165 | } | ||
166 | |||
167 | clk = devm_clk_get(&pdev->dev, NULL); | ||
168 | if (IS_ERR(clk)) { | ||
169 | dev_err(&pdev->dev, "Unable to get clock\n"); | ||
170 | return PTR_ERR(clk); | ||
171 | } | ||
172 | |||
173 | ret = clk_prepare_enable(clk); | ||
174 | if (ret) { | ||
175 | dev_err(&pdev->dev, "Unable to prepare clock %p\n", clk); | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * Allocate our watchdog driver data, which has the | ||
181 | * struct watchdog_device nested within it. | ||
182 | */ | ||
183 | wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); | ||
184 | if (!wdt) { | ||
185 | ret = -ENOMEM; | ||
186 | goto err; | ||
187 | } | ||
188 | |||
189 | /* Initialize struct stm32_iwdg. */ | ||
190 | wdt->regs = regs; | ||
191 | wdt->clk = clk; | ||
192 | wdt->rate = clk_get_rate(clk); | ||
193 | |||
194 | /* Initialize struct watchdog_device. */ | ||
195 | wdd = &wdt->wdd; | ||
196 | wdd->info = &stm32_iwdg_info; | ||
197 | wdd->ops = &stm32_iwdg_ops; | ||
198 | wdd->min_timeout = ((RLR_MIN + 1) * 256) / wdt->rate; | ||
199 | wdd->max_hw_heartbeat_ms = ((RLR_MAX + 1) * 256 * 1000) / wdt->rate; | ||
200 | wdd->parent = &pdev->dev; | ||
201 | |||
202 | watchdog_set_drvdata(wdd, wdt); | ||
203 | watchdog_set_nowayout(wdd, WATCHDOG_NOWAYOUT); | ||
204 | |||
205 | ret = watchdog_init_timeout(wdd, 0, &pdev->dev); | ||
206 | if (ret) | ||
207 | dev_warn(&pdev->dev, | ||
208 | "unable to set timeout value, using default\n"); | ||
209 | |||
210 | ret = watchdog_register_device(wdd); | ||
211 | if (ret) { | ||
212 | dev_err(&pdev->dev, "failed to register watchdog device\n"); | ||
213 | goto err; | ||
214 | } | ||
215 | |||
216 | platform_set_drvdata(pdev, wdt); | ||
217 | |||
218 | return 0; | ||
219 | err: | ||
220 | clk_disable_unprepare(clk); | ||
221 | |||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | static int stm32_iwdg_remove(struct platform_device *pdev) | ||
226 | { | ||
227 | struct stm32_iwdg *wdt = platform_get_drvdata(pdev); | ||
228 | |||
229 | watchdog_unregister_device(&wdt->wdd); | ||
230 | clk_disable_unprepare(wdt->clk); | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static const struct of_device_id stm32_iwdg_of_match[] = { | ||
236 | { .compatible = "st,stm32-iwdg" }, | ||
237 | { /* end node */ } | ||
238 | }; | ||
239 | MODULE_DEVICE_TABLE(of, stm32_iwdg_of_match); | ||
240 | |||
241 | static struct platform_driver stm32_iwdg_driver = { | ||
242 | .probe = stm32_iwdg_probe, | ||
243 | .remove = stm32_iwdg_remove, | ||
244 | .driver = { | ||
245 | .name = "iwdg", | ||
246 | .of_match_table = stm32_iwdg_of_match, | ||
247 | }, | ||
248 | }; | ||
249 | module_platform_driver(stm32_iwdg_driver); | ||
250 | |||
251 | MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>"); | ||
252 | MODULE_DESCRIPTION("STMicroelectronics STM32 Independent Watchdog Driver"); | ||
253 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/watchdog/uniphier_wdt.c b/drivers/watchdog/uniphier_wdt.c new file mode 100644 index 000000000000..0ea2339d9702 --- /dev/null +++ b/drivers/watchdog/uniphier_wdt.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | * Watchdog driver for the UniPhier watchdog timer | ||
3 | * | ||
4 | * (c) Copyright 2014 Panasonic Corporation | ||
5 | * (c) Copyright 2016 Socionext Inc. | ||
6 | * All rights reserved. | ||
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 version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/bitops.h> | ||
19 | #include <linux/mfd/syscon.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/regmap.h> | ||
24 | #include <linux/watchdog.h> | ||
25 | |||
26 | /* WDT timer setting register */ | ||
27 | #define WDTTIMSET 0x3004 | ||
28 | #define WDTTIMSET_PERIOD_MASK (0xf << 0) | ||
29 | #define WDTTIMSET_PERIOD_1_SEC (0x3 << 0) | ||
30 | |||
31 | /* WDT reset selection register */ | ||
32 | #define WDTRSTSEL 0x3008 | ||
33 | #define WDTRSTSEL_RSTSEL_MASK (0x3 << 0) | ||
34 | #define WDTRSTSEL_RSTSEL_BOTH (0x0 << 0) | ||
35 | #define WDTRSTSEL_RSTSEL_IRQ_ONLY (0x2 << 0) | ||
36 | |||
37 | /* WDT control register */ | ||
38 | #define WDTCTRL 0x300c | ||
39 | #define WDTCTRL_STATUS BIT(8) | ||
40 | #define WDTCTRL_CLEAR BIT(1) | ||
41 | #define WDTCTRL_ENABLE BIT(0) | ||
42 | |||
43 | #define SEC_TO_WDTTIMSET_PRD(sec) \ | ||
44 | (ilog2(sec) + WDTTIMSET_PERIOD_1_SEC) | ||
45 | |||
46 | #define WDTST_TIMEOUT 1000 /* usec */ | ||
47 | |||
48 | #define WDT_DEFAULT_TIMEOUT 64 /* Default is 64 seconds */ | ||
49 | #define WDT_PERIOD_MIN 1 | ||
50 | #define WDT_PERIOD_MAX 128 | ||
51 | |||
52 | static unsigned int timeout = 0; | ||
53 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
54 | |||
55 | struct uniphier_wdt_dev { | ||
56 | struct watchdog_device wdt_dev; | ||
57 | struct regmap *regmap; | ||
58 | }; | ||
59 | |||
60 | /* | ||
61 | * UniPhier Watchdog operations | ||
62 | */ | ||
63 | static int uniphier_watchdog_ping(struct watchdog_device *w) | ||
64 | { | ||
65 | struct uniphier_wdt_dev *wdev = watchdog_get_drvdata(w); | ||
66 | unsigned int val; | ||
67 | int ret; | ||
68 | |||
69 | /* Clear counter */ | ||
70 | ret = regmap_write_bits(wdev->regmap, WDTCTRL, | ||
71 | WDTCTRL_CLEAR, WDTCTRL_CLEAR); | ||
72 | if (!ret) | ||
73 | /* | ||
74 | * As SoC specification, after clear counter, | ||
75 | * it needs to wait until counter status is 1. | ||
76 | */ | ||
77 | ret = regmap_read_poll_timeout(wdev->regmap, WDTCTRL, val, | ||
78 | (val & WDTCTRL_STATUS), | ||
79 | 0, WDTST_TIMEOUT); | ||
80 | |||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | static int __uniphier_watchdog_start(struct regmap *regmap, unsigned int sec) | ||
85 | { | ||
86 | unsigned int val; | ||
87 | int ret; | ||
88 | |||
89 | ret = regmap_read_poll_timeout(regmap, WDTCTRL, val, | ||
90 | !(val & WDTCTRL_STATUS), | ||
91 | 0, WDTST_TIMEOUT); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | /* Setup period */ | ||
96 | ret = regmap_write(regmap, WDTTIMSET, | ||
97 | SEC_TO_WDTTIMSET_PRD(sec)); | ||
98 | if (ret) | ||
99 | return ret; | ||
100 | |||
101 | /* Enable and clear watchdog */ | ||
102 | ret = regmap_write(regmap, WDTCTRL, WDTCTRL_ENABLE | WDTCTRL_CLEAR); | ||
103 | if (!ret) | ||
104 | /* | ||
105 | * As SoC specification, after clear counter, | ||
106 | * it needs to wait until counter status is 1. | ||
107 | */ | ||
108 | ret = regmap_read_poll_timeout(regmap, WDTCTRL, val, | ||
109 | (val & WDTCTRL_STATUS), | ||
110 | 0, WDTST_TIMEOUT); | ||
111 | |||
112 | return ret; | ||
113 | } | ||
114 | |||
115 | static int __uniphier_watchdog_stop(struct regmap *regmap) | ||
116 | { | ||
117 | /* Disable and stop watchdog */ | ||
118 | return regmap_write_bits(regmap, WDTCTRL, WDTCTRL_ENABLE, 0); | ||
119 | } | ||
120 | |||
121 | static int __uniphier_watchdog_restart(struct regmap *regmap, unsigned int sec) | ||
122 | { | ||
123 | int ret; | ||
124 | |||
125 | ret = __uniphier_watchdog_stop(regmap); | ||
126 | if (ret) | ||
127 | return ret; | ||
128 | |||
129 | return __uniphier_watchdog_start(regmap, sec); | ||
130 | } | ||
131 | |||
132 | static int uniphier_watchdog_start(struct watchdog_device *w) | ||
133 | { | ||
134 | struct uniphier_wdt_dev *wdev = watchdog_get_drvdata(w); | ||
135 | unsigned int tmp_timeout; | ||
136 | |||
137 | tmp_timeout = roundup_pow_of_two(w->timeout); | ||
138 | |||
139 | return __uniphier_watchdog_start(wdev->regmap, tmp_timeout); | ||
140 | } | ||
141 | |||
142 | static int uniphier_watchdog_stop(struct watchdog_device *w) | ||
143 | { | ||
144 | struct uniphier_wdt_dev *wdev = watchdog_get_drvdata(w); | ||
145 | |||
146 | return __uniphier_watchdog_stop(wdev->regmap); | ||
147 | } | ||
148 | |||
149 | static int uniphier_watchdog_set_timeout(struct watchdog_device *w, | ||
150 | unsigned int t) | ||
151 | { | ||
152 | struct uniphier_wdt_dev *wdev = watchdog_get_drvdata(w); | ||
153 | unsigned int tmp_timeout; | ||
154 | int ret; | ||
155 | |||
156 | tmp_timeout = roundup_pow_of_two(t); | ||
157 | if (tmp_timeout == w->timeout) | ||
158 | return 0; | ||
159 | |||
160 | if (watchdog_active(w)) { | ||
161 | ret = __uniphier_watchdog_restart(wdev->regmap, tmp_timeout); | ||
162 | if (ret) | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | w->timeout = tmp_timeout; | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Kernel Interfaces | ||
173 | */ | ||
174 | static const struct watchdog_info uniphier_wdt_info = { | ||
175 | .identity = "uniphier-wdt", | ||
176 | .options = WDIOF_SETTIMEOUT | | ||
177 | WDIOF_KEEPALIVEPING | | ||
178 | WDIOF_MAGICCLOSE | | ||
179 | WDIOF_OVERHEAT, | ||
180 | }; | ||
181 | |||
182 | static const struct watchdog_ops uniphier_wdt_ops = { | ||
183 | .owner = THIS_MODULE, | ||
184 | .start = uniphier_watchdog_start, | ||
185 | .stop = uniphier_watchdog_stop, | ||
186 | .ping = uniphier_watchdog_ping, | ||
187 | .set_timeout = uniphier_watchdog_set_timeout, | ||
188 | }; | ||
189 | |||
190 | static int uniphier_wdt_probe(struct platform_device *pdev) | ||
191 | { | ||
192 | struct device *dev = &pdev->dev; | ||
193 | struct uniphier_wdt_dev *wdev; | ||
194 | struct regmap *regmap; | ||
195 | struct device_node *parent; | ||
196 | int ret; | ||
197 | |||
198 | wdev = devm_kzalloc(dev, sizeof(*wdev), GFP_KERNEL); | ||
199 | if (!wdev) | ||
200 | return -ENOMEM; | ||
201 | |||
202 | platform_set_drvdata(pdev, wdev); | ||
203 | |||
204 | parent = of_get_parent(dev->of_node); /* parent should be syscon node */ | ||
205 | regmap = syscon_node_to_regmap(parent); | ||
206 | of_node_put(parent); | ||
207 | if (IS_ERR(regmap)) | ||
208 | return PTR_ERR(regmap); | ||
209 | |||
210 | wdev->regmap = regmap; | ||
211 | wdev->wdt_dev.info = &uniphier_wdt_info; | ||
212 | wdev->wdt_dev.ops = &uniphier_wdt_ops; | ||
213 | wdev->wdt_dev.max_timeout = WDT_PERIOD_MAX; | ||
214 | wdev->wdt_dev.min_timeout = WDT_PERIOD_MIN; | ||
215 | wdev->wdt_dev.parent = dev; | ||
216 | |||
217 | if (watchdog_init_timeout(&wdev->wdt_dev, timeout, dev) < 0) { | ||
218 | wdev->wdt_dev.timeout = WDT_DEFAULT_TIMEOUT; | ||
219 | } | ||
220 | watchdog_set_nowayout(&wdev->wdt_dev, nowayout); | ||
221 | watchdog_stop_on_reboot(&wdev->wdt_dev); | ||
222 | |||
223 | watchdog_set_drvdata(&wdev->wdt_dev, wdev); | ||
224 | |||
225 | uniphier_watchdog_stop(&wdev->wdt_dev); | ||
226 | ret = regmap_write(wdev->regmap, WDTRSTSEL, WDTRSTSEL_RSTSEL_BOTH); | ||
227 | if (ret) | ||
228 | return ret; | ||
229 | |||
230 | ret = devm_watchdog_register_device(dev, &wdev->wdt_dev); | ||
231 | if (ret) | ||
232 | return ret; | ||
233 | |||
234 | dev_info(dev, "watchdog driver (timeout=%d sec, nowayout=%d)\n", | ||
235 | wdev->wdt_dev.timeout, nowayout); | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static const struct of_device_id uniphier_wdt_dt_ids[] = { | ||
241 | { .compatible = "socionext,uniphier-wdt" }, | ||
242 | { /* sentinel */ } | ||
243 | }; | ||
244 | MODULE_DEVICE_TABLE(of, uniphier_wdt_dt_ids); | ||
245 | |||
246 | static struct platform_driver uniphier_wdt_driver = { | ||
247 | .probe = uniphier_wdt_probe, | ||
248 | .driver = { | ||
249 | .name = "uniphier-wdt", | ||
250 | .of_match_table = uniphier_wdt_dt_ids, | ||
251 | }, | ||
252 | }; | ||
253 | |||
254 | module_platform_driver(uniphier_wdt_driver); | ||
255 | |||
256 | module_param(timeout, uint, 0000); | ||
257 | MODULE_PARM_DESC(timeout, | ||
258 | "Watchdog timeout seconds in power of 2. (0 < timeout < 128, default=" | ||
259 | __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")"); | ||
260 | |||
261 | module_param(nowayout, bool, 0000); | ||
262 | MODULE_PARM_DESC(nowayout, | ||
263 | "Watchdog cannot be stopped once started (default=" | ||
264 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
265 | |||
266 | MODULE_AUTHOR("Keiji Hayashibara <hayashibara.keiji@socionext.com>"); | ||
267 | MODULE_DESCRIPTION("UniPhier Watchdog Device Driver"); | ||
268 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index 98fd186c6878..d9ba0496713c 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c | |||
@@ -49,7 +49,8 @@ static int cr_wdt_csr; /* WDT control & status register */ | |||
49 | 49 | ||
50 | enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, | 50 | enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, |
51 | w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, | 51 | w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, |
52 | w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792, nct6102 }; | 52 | w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793, |
53 | nct6795, nct6102 }; | ||
53 | 54 | ||
54 | static int timeout; /* in seconds */ | 55 | static int timeout; /* in seconds */ |
55 | module_param(timeout, int, 0); | 56 | module_param(timeout, int, 0); |
@@ -97,6 +98,8 @@ MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)"); | |||
97 | #define NCT6779_ID 0xc5 | 98 | #define NCT6779_ID 0xc5 |
98 | #define NCT6791_ID 0xc8 | 99 | #define NCT6791_ID 0xc8 |
99 | #define NCT6792_ID 0xc9 | 100 | #define NCT6792_ID 0xc9 |
101 | #define NCT6793_ID 0xd1 | ||
102 | #define NCT6795_ID 0xd3 | ||
100 | 103 | ||
101 | #define W83627HF_WDT_TIMEOUT 0xf6 | 104 | #define W83627HF_WDT_TIMEOUT 0xf6 |
102 | #define W83697HF_WDT_TIMEOUT 0xf4 | 105 | #define W83697HF_WDT_TIMEOUT 0xf4 |
@@ -204,6 +207,8 @@ static int w83627hf_init(struct watchdog_device *wdog, enum chips chip) | |||
204 | case nct6779: | 207 | case nct6779: |
205 | case nct6791: | 208 | case nct6791: |
206 | case nct6792: | 209 | case nct6792: |
210 | case nct6793: | ||
211 | case nct6795: | ||
207 | case nct6102: | 212 | case nct6102: |
208 | /* | 213 | /* |
209 | * These chips have a fixed WDTO# output pin (W83627UHG), | 214 | * These chips have a fixed WDTO# output pin (W83627UHG), |
@@ -396,6 +401,12 @@ static int wdt_find(int addr) | |||
396 | case NCT6792_ID: | 401 | case NCT6792_ID: |
397 | ret = nct6792; | 402 | ret = nct6792; |
398 | break; | 403 | break; |
404 | case NCT6793_ID: | ||
405 | ret = nct6793; | ||
406 | break; | ||
407 | case NCT6795_ID: | ||
408 | ret = nct6795; | ||
409 | break; | ||
399 | case NCT6102_ID: | 410 | case NCT6102_ID: |
400 | ret = nct6102; | 411 | ret = nct6102; |
401 | cr_wdt_timeout = NCT6102D_WDT_TIMEOUT; | 412 | cr_wdt_timeout = NCT6102D_WDT_TIMEOUT; |
@@ -437,6 +448,8 @@ static int __init wdt_init(void) | |||
437 | "NCT6779", | 448 | "NCT6779", |
438 | "NCT6791", | 449 | "NCT6791", |
439 | "NCT6792", | 450 | "NCT6792", |
451 | "NCT6793", | ||
452 | "NCT6795", | ||
440 | "NCT6102", | 453 | "NCT6102", |
441 | }; | 454 | }; |
442 | 455 | ||
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index d5d2bbd8f428..0826e663bd5a 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c | |||
@@ -80,6 +80,9 @@ static struct watchdog_core_data *old_wd_data; | |||
80 | 80 | ||
81 | static struct workqueue_struct *watchdog_wq; | 81 | static struct workqueue_struct *watchdog_wq; |
82 | 82 | ||
83 | static bool handle_boot_enabled = | ||
84 | IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED); | ||
85 | |||
83 | static inline bool watchdog_need_worker(struct watchdog_device *wdd) | 86 | static inline bool watchdog_need_worker(struct watchdog_device *wdd) |
84 | { | 87 | { |
85 | /* All variables in milli-seconds */ | 88 | /* All variables in milli-seconds */ |
@@ -192,18 +195,23 @@ static int watchdog_ping(struct watchdog_device *wdd) | |||
192 | return __watchdog_ping(wdd); | 195 | return __watchdog_ping(wdd); |
193 | } | 196 | } |
194 | 197 | ||
198 | static bool watchdog_worker_should_ping(struct watchdog_core_data *wd_data) | ||
199 | { | ||
200 | struct watchdog_device *wdd = wd_data->wdd; | ||
201 | |||
202 | return wdd && (watchdog_active(wdd) || watchdog_hw_running(wdd)); | ||
203 | } | ||
204 | |||
195 | static void watchdog_ping_work(struct work_struct *work) | 205 | static void watchdog_ping_work(struct work_struct *work) |
196 | { | 206 | { |
197 | struct watchdog_core_data *wd_data; | 207 | struct watchdog_core_data *wd_data; |
198 | struct watchdog_device *wdd; | ||
199 | 208 | ||
200 | wd_data = container_of(to_delayed_work(work), struct watchdog_core_data, | 209 | wd_data = container_of(to_delayed_work(work), struct watchdog_core_data, |
201 | work); | 210 | work); |
202 | 211 | ||
203 | mutex_lock(&wd_data->lock); | 212 | mutex_lock(&wd_data->lock); |
204 | wdd = wd_data->wdd; | 213 | if (watchdog_worker_should_ping(wd_data)) |
205 | if (wdd && (watchdog_active(wdd) || watchdog_hw_running(wdd))) | 214 | __watchdog_ping(wd_data->wdd); |
206 | __watchdog_ping(wdd); | ||
207 | mutex_unlock(&wd_data->lock); | 215 | mutex_unlock(&wd_data->lock); |
208 | } | 216 | } |
209 | 217 | ||
@@ -956,9 +964,14 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno) | |||
956 | * and schedule an immediate ping. | 964 | * and schedule an immediate ping. |
957 | */ | 965 | */ |
958 | if (watchdog_hw_running(wdd)) { | 966 | if (watchdog_hw_running(wdd)) { |
959 | __module_get(wdd->ops->owner); | 967 | if (handle_boot_enabled) { |
960 | kref_get(&wd_data->kref); | 968 | __module_get(wdd->ops->owner); |
961 | queue_delayed_work(watchdog_wq, &wd_data->work, 0); | 969 | kref_get(&wd_data->kref); |
970 | queue_delayed_work(watchdog_wq, &wd_data->work, 0); | ||
971 | } else { | ||
972 | pr_info("watchdog%d running and kernel based pre-userspace handler disabled\n", | ||
973 | wdd->id); | ||
974 | } | ||
962 | } | 975 | } |
963 | 976 | ||
964 | return 0; | 977 | return 0; |
@@ -1106,3 +1119,8 @@ void __exit watchdog_dev_exit(void) | |||
1106 | class_unregister(&watchdog_class); | 1119 | class_unregister(&watchdog_class); |
1107 | destroy_workqueue(watchdog_wq); | 1120 | destroy_workqueue(watchdog_wq); |
1108 | } | 1121 | } |
1122 | |||
1123 | module_param(handle_boot_enabled, bool, 0444); | ||
1124 | MODULE_PARM_DESC(handle_boot_enabled, | ||
1125 | "Watchdog core auto-updates boot enabled watchdogs before userspace takes over (default=" | ||
1126 | __MODULE_STRING(IS_ENABLED(CONFIG_WATCHDOG_HANDLE_BOOT_ENABLED)) ")"); | ||
diff --git a/drivers/watchdog/zx2967_wdt.c b/drivers/watchdog/zx2967_wdt.c index c98252733c30..69ec5855584b 100644 --- a/drivers/watchdog/zx2967_wdt.c +++ b/drivers/watchdog/zx2967_wdt.c | |||
@@ -154,7 +154,7 @@ static const struct watchdog_info zx2967_wdt_ident = { | |||
154 | .identity = "zx2967 watchdog", | 154 | .identity = "zx2967 watchdog", |
155 | }; | 155 | }; |
156 | 156 | ||
157 | static struct watchdog_ops zx2967_wdt_ops = { | 157 | static const struct watchdog_ops zx2967_wdt_ops = { |
158 | .owner = THIS_MODULE, | 158 | .owner = THIS_MODULE, |
159 | .start = zx2967_wdt_start, | 159 | .start = zx2967_wdt_start, |
160 | .stop = zx2967_wdt_stop, | 160 | .stop = zx2967_wdt_stop, |