Commit 962c04f54e4a3c322d19b47256f9aec0b9c8124e
Committed by
Wim Van Sebroeck
1 parent
f72fa00f8a
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>
Showing 2 changed files with 173 additions and 24 deletions Side-by-side Diff
drivers/watchdog/Kconfig
... | ... | @@ -892,13 +892,20 @@ |
892 | 892 | Most people will say N. |
893 | 893 | |
894 | 894 | config W83627HF_WDT |
895 | - tristate "W83627HF/W83627DHG Watchdog Timer" | |
895 | + tristate "Watchdog timer for W83627HF/W83627DHG and compatibles" | |
896 | 896 | depends on X86 |
897 | 897 | select WATCHDOG_CORE |
898 | 898 | ---help--- |
899 | - This is the driver for the hardware watchdog on the W83627HF chipset | |
900 | - as used in Advantech PC-9578 and Tyan S2721-533 motherboards | |
901 | - (and likely others). The driver also supports the W83627DHG chip. | |
899 | + This is the driver for the hardware watchdog on the following | |
900 | + Super I/O chips. | |
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 | 909 | This watchdog simply watches your kernel to make sure it doesn't |
903 | 910 | freeze, and if it does, it reboots your computer after a certain |
904 | 911 | amount of time. |
drivers/watchdog/w83627hf_wdt.c
... | ... | @@ -44,11 +44,12 @@ |
44 | 44 | #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" |
45 | 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. */ | |
48 | -static int wdt_io = 0x2E; | |
49 | -module_param(wdt_io, int, 0); | |
50 | -MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); | |
47 | +static int wdt_io; | |
51 | 48 | |
49 | +enum chips { w83627hf, w83627s, w83637hf, w83627thf, w83687thf, | |
50 | + w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, w83667hg_b, | |
51 | + nct6775, nct6776, nct6779 }; | |
52 | + | |
52 | 53 | static int timeout; /* in seconds */ |
53 | 54 | module_param(timeout, int, 0); |
54 | 55 | MODULE_PARM_DESC(timeout, |
... | ... | @@ -72,6 +73,21 @@ |
72 | 73 | |
73 | 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 | + | |
75 | 91 | static void superio_outb(int reg, int val) |
76 | 92 | { |
77 | 93 | outb(reg, WDT_EFER); |
... | ... | @@ -106,10 +122,7 @@ |
106 | 122 | release_region(wdt_io, 2); |
107 | 123 | } |
108 | 124 | |
109 | -/* tyan motherboards seem to set F5 to 0x4C ? | |
110 | - * So explicitly init to appropriate value. */ | |
111 | - | |
112 | -static int w83627hf_init(struct watchdog_device *wdog) | |
125 | +static int w83627hf_init(struct watchdog_device *wdog, enum chips chip) | |
113 | 126 | { |
114 | 127 | int ret; |
115 | 128 | unsigned char t; |
116 | 129 | |
... | ... | @@ -119,20 +132,59 @@ |
119 | 132 | return ret; |
120 | 133 | |
121 | 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 | 136 | /* set CR30 bit 0 to activate GPIO2 */ |
132 | 137 | t = superio_inb(0x30); |
133 | 138 | if (!(t & 0x01)) |
134 | 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 | 188 | t = superio_inb(0xF6); |
137 | 189 | if (t != 0) { |
138 | 190 | pr_info("Watchdog already running. Resetting timeout to %d sec\n", |
... | ... | @@ -142,8 +194,6 @@ |
142 | 194 | |
143 | 195 | /* set second mode & disable keyboard turning off watchdog */ |
144 | 196 | t = superio_inb(0xF5) & ~0x0C; |
145 | - /* enable the WDTO# output low pulse to the KBRST# pin */ | |
146 | - t |= 0x02; | |
147 | 197 | superio_outb(0xF5, t); |
148 | 198 | |
149 | 199 | /* disable keyboard & mouse turning off watchdog */ |
150 | 200 | |
151 | 201 | |
152 | 202 | |
153 | 203 | |
... | ... | @@ -249,16 +299,108 @@ |
249 | 299 | .notifier_call = wdt_notify_sys, |
250 | 300 | }; |
251 | 301 | |
302 | +static 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 | + | |
252 | 367 | static int __init wdt_init(void) |
253 | 368 | { |
254 | 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 | + }; | |
255 | 387 | |
256 | - pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n"); | |
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 | + } | |
257 | 396 | |
397 | + pr_info("WDT driver for %s Super I/O chip initialising\n", | |
398 | + chip_name[chip]); | |
399 | + | |
258 | 400 | watchdog_init_timeout(&wdt_dev, timeout, NULL); |
259 | 401 | watchdog_set_nowayout(&wdt_dev, nowayout); |
260 | 402 | |
261 | - ret = w83627hf_init(&wdt_dev); | |
403 | + ret = w83627hf_init(&wdt_dev, chip); | |
262 | 404 | if (ret) { |
263 | 405 | pr_err("failed to initialize watchdog (err=%d)\n", ret); |
264 | 406 | return ret; |