aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuenter Roeck <linux@roeck-us.net>2013-08-17 16:58:43 -0400
committerWim Van Sebroeck <wim@iguana.be>2014-01-28 15:35:30 -0500
commit962c04f54e4a3c322d19b47256f9aec0b9c8124e (patch)
tree0dbd271080882c80fc2c6642743c99b4e5b55d65
parentf72fa00f8ab216ee484d61de17ddc84712456c3a (diff)
watchdog: w83627hf: Auto-detect IO address and supported chips
Instead of requiring the user to provide an IO address per module parameter, auto-detect it as well as supported chips. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--drivers/watchdog/Kconfig15
-rw-r--r--drivers/watchdog/w83627hf_wdt.c182
2 files changed, 173 insertions, 24 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 3fc5158ffecf..4fa8428612b2 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -892,13 +892,20 @@ config VIA_WDT
892 Most people will say N. 892 Most people will say N.
893 893
894config W83627HF_WDT 894config W83627HF_WDT
895 tristate "W83627HF/W83627DHG Watchdog Timer" 895 tristate "Watchdog timer for W83627HF/W83627DHG and compatibles"
896 depends on X86 896 depends on X86
897 select WATCHDOG_CORE 897 select WATCHDOG_CORE
898 ---help--- 898 ---help---
899 This is the driver for the hardware watchdog on the W83627HF chipset 899 This is the driver for the hardware watchdog on the following
900 as used in Advantech PC-9578 and Tyan S2721-533 motherboards 900 Super I/O chips.
901 (and likely others). The driver also supports the W83627DHG chip. 901 W83627DHG/DHG-P/EHF/EHG/F/G/HF/S/SF/THF/UHG/UG
902 W83637HF
903 W83667HG/HG-B
904 W83687THF
905 NCT6775
906 NCT6776
907 NCT6779
908
902 This watchdog simply watches your kernel to make sure it doesn't 909 This watchdog simply watches your kernel to make sure it doesn't
903 freeze, and if it does, it reboots your computer after a certain 910 freeze, and if it does, it reboots your computer after a certain
904 amount of time. 911 amount of time.
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index e24b21082874..954becdf9cf5 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -44,10 +44,11 @@
44#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" 44#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
45#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ 45#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
46 46
47/* You must set this - there is no sane way to probe for this board. */ 47static int wdt_io;
48static int wdt_io = 0x2E; 48
49module_param(wdt_io, int, 0); 49enum chips { w83627hf, w83627s, w83637hf, w83627thf, w83687thf,
50MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); 50 w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, w83667hg_b,
51 nct6775, nct6776, nct6779 };
51 52
52static int timeout; /* in seconds */ 53static int timeout; /* in seconds */
53module_param(timeout, int, 0); 54module_param(timeout, int, 0);
@@ -72,6 +73,21 @@ MODULE_PARM_DESC(nowayout,
72 73
73#define W83627HF_LD_WDT 0x08 74#define W83627HF_LD_WDT 0x08
74 75
76#define W83627HF_ID 0x52
77#define W83627S_ID 0x59
78#define W83637HF_ID 0x70
79#define W83627THF_ID 0x82
80#define W83687THF_ID 0x85
81#define W83627EHF_ID 0x88
82#define W83627DHG_ID 0xa0
83#define W83627UHG_ID 0xa2
84#define W83667HG_ID 0xa5
85#define W83627DHG_P_ID 0xb0
86#define W83667HG_B_ID 0xb3
87#define NCT6775_ID 0xb4
88#define NCT6776_ID 0xc3
89#define NCT6779_ID 0xc5
90
75static void superio_outb(int reg, int val) 91static void superio_outb(int reg, int val)
76{ 92{
77 outb(reg, WDT_EFER); 93 outb(reg, WDT_EFER);
@@ -106,10 +122,7 @@ static void superio_exit(void)
106 release_region(wdt_io, 2); 122 release_region(wdt_io, 2);
107} 123}
108 124
109/* tyan motherboards seem to set F5 to 0x4C ? 125static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
110 * So explicitly init to appropriate value. */
111
112static int w83627hf_init(struct watchdog_device *wdog)
113{ 126{
114 int ret; 127 int ret;
115 unsigned char t; 128 unsigned char t;
@@ -119,20 +132,59 @@ static int w83627hf_init(struct watchdog_device *wdog)
119 return ret; 132 return ret;
120 133
121 superio_select(W83627HF_LD_WDT); 134 superio_select(W83627HF_LD_WDT);
122 t = superio_inb(0x20); /* check chip version */
123 if (t == 0x82) { /* W83627THF */
124 t = (superio_inb(0x2b) & 0xf7);
125 superio_outb(0x2b, t | 0x04); /* set GPIO3 to WDT0 */
126 } else if (t == 0x88 || t == 0xa0) { /* W83627EHF / W83627DHG */
127 t = superio_inb(0x2d);
128 superio_outb(0x2d, t & ~0x01); /* set GPIO5 to WDT0 */
129 }
130 135
131 /* set CR30 bit 0 to activate GPIO2 */ 136 /* set CR30 bit 0 to activate GPIO2 */
132 t = superio_inb(0x30); 137 t = superio_inb(0x30);
133 if (!(t & 0x01)) 138 if (!(t & 0x01))
134 superio_outb(0x30, t | 0x01); 139 superio_outb(0x30, t | 0x01);
135 140
141 switch (chip) {
142 case w83627hf:
143 case w83627s:
144 t = superio_inb(0x2B) & ~0x10;
145 superio_outb(0x2B, t); /* set GPIO24 to WDT0 */
146 break;
147 case w83627thf:
148 t = (superio_inb(0x2B) & ~0x08) | 0x04;
149 superio_outb(0x2B, t); /* set GPIO3 to WDT0 */
150 break;
151 case w83627dhg:
152 case w83627dhg_p:
153 t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */
154 superio_outb(0x2D, t); /* set GPIO5 to WDT0 */
155 t = superio_inb(0xF5);
156 t |= 0x02; /* enable the WDTO# output low pulse
157 * to the KBRST# pin */
158 superio_outb(0xF5, t);
159 break;
160 case w83637hf:
161 break;
162 case w83687thf:
163 t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */
164 superio_outb(0x2C, t);
165 break;
166 case w83627ehf:
167 case w83627uhg:
168 case w83667hg:
169 case w83667hg_b:
170 case nct6775:
171 case nct6776:
172 case nct6779:
173 /*
174 * These chips have a fixed WDTO# output pin (W83627UHG),
175 * or support more than one WDTO# output pin.
176 * Don't touch its configuration, and hope the BIOS
177 * does the right thing.
178 */
179 t = superio_inb(0xF5);
180 t |= 0x02; /* enable the WDTO# output low pulse
181 * to the KBRST# pin */
182 superio_outb(0xF5, t);
183 break;
184 default:
185 break;
186 }
187
136 t = superio_inb(0xF6); 188 t = superio_inb(0xF6);
137 if (t != 0) { 189 if (t != 0) {
138 pr_info("Watchdog already running. Resetting timeout to %d sec\n", 190 pr_info("Watchdog already running. Resetting timeout to %d sec\n",
@@ -142,8 +194,6 @@ static int w83627hf_init(struct watchdog_device *wdog)
142 194
143 /* set second mode & disable keyboard turning off watchdog */ 195 /* set second mode & disable keyboard turning off watchdog */
144 t = superio_inb(0xF5) & ~0x0C; 196 t = superio_inb(0xF5) & ~0x0C;
145 /* enable the WDTO# output low pulse to the KBRST# pin */
146 t |= 0x02;
147 superio_outb(0xF5, t); 197 superio_outb(0xF5, t);
148 198
149 /* disable keyboard & mouse turning off watchdog */ 199 /* disable keyboard & mouse turning off watchdog */
@@ -249,16 +299,108 @@ static struct notifier_block wdt_notifier = {
249 .notifier_call = wdt_notify_sys, 299 .notifier_call = wdt_notify_sys,
250}; 300};
251 301
302static int wdt_find(int addr)
303{
304 u8 val;
305 int ret;
306
307 ret = superio_enter();
308 if (ret)
309 return ret;
310 superio_select(W83627HF_LD_WDT);
311 val = superio_inb(0x20);
312 switch (val) {
313 case W83627HF_ID:
314 ret = w83627hf;
315 break;
316 case W83627S_ID:
317 ret = w83627s;
318 break;
319 case W83637HF_ID:
320 ret = w83637hf;
321 break;
322 case W83627THF_ID:
323 ret = w83627thf;
324 break;
325 case W83687THF_ID:
326 ret = w83687thf;
327 break;
328 case W83627EHF_ID:
329 ret = w83627ehf;
330 break;
331 case W83627DHG_ID:
332 ret = w83627dhg;
333 break;
334 case W83627DHG_P_ID:
335 ret = w83627dhg_p;
336 break;
337 case W83627UHG_ID:
338 ret = w83627uhg;
339 break;
340 case W83667HG_ID:
341 ret = w83667hg;
342 break;
343 case W83667HG_B_ID:
344 ret = w83667hg_b;
345 break;
346 case NCT6775_ID:
347 ret = nct6775;
348 break;
349 case NCT6776_ID:
350 ret = nct6776;
351 break;
352 case NCT6779_ID:
353 ret = nct6779;
354 break;
355 case 0xff:
356 ret = -ENODEV;
357 break;
358 default:
359 ret = -ENODEV;
360 pr_err("Unsupported chip ID: 0x%02x\n", val);
361 break;
362 }
363 superio_exit();
364 return ret;
365}
366
252static int __init wdt_init(void) 367static int __init wdt_init(void)
253{ 368{
254 int ret; 369 int ret;
370 int chip;
371 const char * const chip_name[] = {
372 "W83627HF",
373 "W83627S",
374 "W83637HF",
375 "W83627THF",
376 "W83687THF",
377 "W83627EHF",
378 "W83627DHG",
379 "W83627UHG",
380 "W83667HG",
381 "W83667DHG-P",
382 "W83667HG-B",
383 "NCT6775",
384 "NCT6776",
385 "NCT6779",
386 };
387
388 wdt_io = 0x2e;
389 chip = wdt_find(0x2e);
390 if (chip < 0) {
391 wdt_io = 0x4e;
392 chip = wdt_find(0x4e);
393 if (chip < 0)
394 return chip;
395 }
255 396
256 pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n"); 397 pr_info("WDT driver for %s Super I/O chip initialising\n",
398 chip_name[chip]);
257 399
258 watchdog_init_timeout(&wdt_dev, timeout, NULL); 400 watchdog_init_timeout(&wdt_dev, timeout, NULL);
259 watchdog_set_nowayout(&wdt_dev, nowayout); 401 watchdog_set_nowayout(&wdt_dev, nowayout);
260 402
261 ret = w83627hf_init(&wdt_dev); 403 ret = w83627hf_init(&wdt_dev, chip);
262 if (ret) { 404 if (ret) {
263 pr_err("failed to initialize watchdog (err=%d)\n", ret); 405 pr_err("failed to initialize watchdog (err=%d)\n", ret);
264 return ret; 406 return ret;