diff options
author | John Crispin <blogic@openwrt.org> | 2016-01-04 14:36:38 -0500 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2016-01-09 11:45:28 -0500 |
commit | ab3f09fe16d158cb4f84e558c61ec5d6d601f2e0 (patch) | |
tree | bedf670e6f21cfd4a9116b62f41363d055a8ddbb | |
parent | 3b8d058cfe6a3b14abee324f4c4b33e64bf61aeb (diff) |
watchdog: add MT7621 watchdog support
This patch adds support for the watchdog core found on newer MediaTek Wifi
SoCs MT7621 and MT7628. There is no symbol for MT7628 as it is a subtype of
MT7620 so we depend on that instead.
Signed-off-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r-- | Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt | 12 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 7 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/mt7621_wdt.c | 186 |
4 files changed, 206 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt b/Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt new file mode 100644 index 000000000000..c15ef0ef609f --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/mt7621-wdt.txt | |||
@@ -0,0 +1,12 @@ | |||
1 | Ralink Watchdog Timers | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: must be "mediatek,mt7621-wdt" | ||
5 | - reg: physical base address of the controller and length of the register range | ||
6 | |||
7 | Example: | ||
8 | |||
9 | watchdog@100 { | ||
10 | compatible = "mediatek,mt7621-wdt"; | ||
11 | reg = <0x100 0x10>; | ||
12 | }; | ||
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index afb7f91795cb..4f0e7be0da34 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -1403,6 +1403,13 @@ config RALINK_WDT | |||
1403 | help | 1403 | help |
1404 | Hardware driver for the Ralink SoC Watchdog Timer. | 1404 | Hardware driver for the Ralink SoC Watchdog Timer. |
1405 | 1405 | ||
1406 | config MT7621_WDT | ||
1407 | tristate "Mediatek SoC watchdog" | ||
1408 | select WATCHDOG_CORE | ||
1409 | depends on SOC_MT7620 || SOC_MT7621 | ||
1410 | help | ||
1411 | Hardware driver for the Mediatek/Ralink MT7621/8 SoC Watchdog Timer. | ||
1412 | |||
1406 | # PARISC Architecture | 1413 | # PARISC Architecture |
1407 | 1414 | ||
1408 | # POWERPC Architecture | 1415 | # POWERPC Architecture |
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 2d203fc3cfdb..f566753256ab 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile | |||
@@ -152,6 +152,7 @@ octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o | |||
152 | obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o | 152 | obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o |
153 | obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o | 153 | obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o |
154 | obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o | 154 | obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o |
155 | obj-$(CONFIG_MT7621_WDT) += mt7621_wdt.o | ||
155 | 156 | ||
156 | # PARISC Architecture | 157 | # PARISC Architecture |
157 | 158 | ||
diff --git a/drivers/watchdog/mt7621_wdt.c b/drivers/watchdog/mt7621_wdt.c new file mode 100644 index 000000000000..4a2290f900a8 --- /dev/null +++ b/drivers/watchdog/mt7621_wdt.c | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * Ralink MT7621/MT7628 built-in hardware watchdog timer | ||
3 | * | ||
4 | * Copyright (C) 2014 John Crispin <blogic@openwrt.org> | ||
5 | * | ||
6 | * This driver was based on: drivers/watchdog/rt2880_wdt.c | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published | ||
10 | * by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/reset.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/watchdog.h> | ||
18 | #include <linux/moduleparam.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | |||
21 | #include <asm/mach-ralink/ralink_regs.h> | ||
22 | |||
23 | #define SYSC_RSTSTAT 0x38 | ||
24 | #define WDT_RST_CAUSE BIT(1) | ||
25 | |||
26 | #define RALINK_WDT_TIMEOUT 30 | ||
27 | |||
28 | #define TIMER_REG_TMRSTAT 0x00 | ||
29 | #define TIMER_REG_TMR1LOAD 0x24 | ||
30 | #define TIMER_REG_TMR1CTL 0x20 | ||
31 | |||
32 | #define TMR1CTL_ENABLE BIT(7) | ||
33 | #define TMR1CTL_RESTART BIT(9) | ||
34 | #define TMR1CTL_PRESCALE_SHIFT 16 | ||
35 | |||
36 | static void __iomem *mt7621_wdt_base; | ||
37 | static struct reset_control *mt7621_wdt_reset; | ||
38 | |||
39 | static bool nowayout = WATCHDOG_NOWAYOUT; | ||
40 | module_param(nowayout, bool, 0); | ||
41 | MODULE_PARM_DESC(nowayout, | ||
42 | "Watchdog cannot be stopped once started (default=" | ||
43 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
44 | |||
45 | static inline void rt_wdt_w32(unsigned reg, u32 val) | ||
46 | { | ||
47 | iowrite32(val, mt7621_wdt_base + reg); | ||
48 | } | ||
49 | |||
50 | static inline u32 rt_wdt_r32(unsigned reg) | ||
51 | { | ||
52 | return ioread32(mt7621_wdt_base + reg); | ||
53 | } | ||
54 | |||
55 | static int mt7621_wdt_ping(struct watchdog_device *w) | ||
56 | { | ||
57 | rt_wdt_w32(TIMER_REG_TMRSTAT, TMR1CTL_RESTART); | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int mt7621_wdt_set_timeout(struct watchdog_device *w, unsigned int t) | ||
63 | { | ||
64 | w->timeout = t; | ||
65 | rt_wdt_w32(TIMER_REG_TMR1LOAD, t * 1000); | ||
66 | mt7621_wdt_ping(w); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int mt7621_wdt_start(struct watchdog_device *w) | ||
72 | { | ||
73 | u32 t; | ||
74 | |||
75 | /* set the prescaler to 1ms == 1000us */ | ||
76 | rt_wdt_w32(TIMER_REG_TMR1CTL, 1000 << TMR1CTL_PRESCALE_SHIFT); | ||
77 | |||
78 | mt7621_wdt_set_timeout(w, w->timeout); | ||
79 | |||
80 | t = rt_wdt_r32(TIMER_REG_TMR1CTL); | ||
81 | t |= TMR1CTL_ENABLE; | ||
82 | rt_wdt_w32(TIMER_REG_TMR1CTL, t); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int mt7621_wdt_stop(struct watchdog_device *w) | ||
88 | { | ||
89 | u32 t; | ||
90 | |||
91 | mt7621_wdt_ping(w); | ||
92 | |||
93 | t = rt_wdt_r32(TIMER_REG_TMR1CTL); | ||
94 | t &= ~TMR1CTL_ENABLE; | ||
95 | rt_wdt_w32(TIMER_REG_TMR1CTL, t); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int mt7621_wdt_bootcause(void) | ||
101 | { | ||
102 | if (rt_sysc_r32(SYSC_RSTSTAT) & WDT_RST_CAUSE) | ||
103 | return WDIOF_CARDRESET; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static struct watchdog_info mt7621_wdt_info = { | ||
109 | .identity = "Mediatek Watchdog", | ||
110 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, | ||
111 | }; | ||
112 | |||
113 | static struct watchdog_ops mt7621_wdt_ops = { | ||
114 | .owner = THIS_MODULE, | ||
115 | .start = mt7621_wdt_start, | ||
116 | .stop = mt7621_wdt_stop, | ||
117 | .ping = mt7621_wdt_ping, | ||
118 | .set_timeout = mt7621_wdt_set_timeout, | ||
119 | }; | ||
120 | |||
121 | static struct watchdog_device mt7621_wdt_dev = { | ||
122 | .info = &mt7621_wdt_info, | ||
123 | .ops = &mt7621_wdt_ops, | ||
124 | .min_timeout = 1, | ||
125 | .max_timeout = 0xfffful / 1000, | ||
126 | }; | ||
127 | |||
128 | static int mt7621_wdt_probe(struct platform_device *pdev) | ||
129 | { | ||
130 | struct resource *res; | ||
131 | int ret; | ||
132 | |||
133 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
134 | mt7621_wdt_base = devm_ioremap_resource(&pdev->dev, res); | ||
135 | if (IS_ERR(mt7621_wdt_base)) | ||
136 | return PTR_ERR(mt7621_wdt_base); | ||
137 | |||
138 | mt7621_wdt_reset = devm_reset_control_get(&pdev->dev, NULL); | ||
139 | if (!IS_ERR(mt7621_wdt_reset)) | ||
140 | reset_control_deassert(mt7621_wdt_reset); | ||
141 | |||
142 | mt7621_wdt_dev.dev = &pdev->dev; | ||
143 | mt7621_wdt_dev.bootstatus = mt7621_wdt_bootcause(); | ||
144 | |||
145 | watchdog_init_timeout(&mt7621_wdt_dev, mt7621_wdt_dev.max_timeout, | ||
146 | &pdev->dev); | ||
147 | watchdog_set_nowayout(&mt7621_wdt_dev, nowayout); | ||
148 | |||
149 | ret = watchdog_register_device(&mt7621_wdt_dev); | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int mt7621_wdt_remove(struct platform_device *pdev) | ||
155 | { | ||
156 | watchdog_unregister_device(&mt7621_wdt_dev); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void mt7621_wdt_shutdown(struct platform_device *pdev) | ||
162 | { | ||
163 | mt7621_wdt_stop(&mt7621_wdt_dev); | ||
164 | } | ||
165 | |||
166 | static const struct of_device_id mt7621_wdt_match[] = { | ||
167 | { .compatible = "mediatek,mt7621-wdt" }, | ||
168 | {}, | ||
169 | }; | ||
170 | MODULE_DEVICE_TABLE(of, mt7621_wdt_match); | ||
171 | |||
172 | static struct platform_driver mt7621_wdt_driver = { | ||
173 | .probe = mt7621_wdt_probe, | ||
174 | .remove = mt7621_wdt_remove, | ||
175 | .shutdown = mt7621_wdt_shutdown, | ||
176 | .driver = { | ||
177 | .name = KBUILD_MODNAME, | ||
178 | .of_match_table = mt7621_wdt_match, | ||
179 | }, | ||
180 | }; | ||
181 | |||
182 | module_platform_driver(mt7621_wdt_driver); | ||
183 | |||
184 | MODULE_DESCRIPTION("MediaTek MT762x hardware watchdog driver"); | ||
185 | MODULE_AUTHOR("John Crispin <blogic@openwrt.org"); | ||
186 | MODULE_LICENSE("GPL v2"); | ||