diff options
author | Guenter Roeck <linux@roeck-us.net> | 2013-08-17 16:58:43 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2014-01-28 15:35:30 -0500 |
commit | 962c04f54e4a3c322d19b47256f9aec0b9c8124e (patch) | |
tree | 0dbd271080882c80fc2c6642743c99b4e5b55d65 /drivers/watchdog/w83627hf_wdt.c | |
parent | f72fa00f8ab216ee484d61de17ddc84712456c3a (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>
Diffstat (limited to 'drivers/watchdog/w83627hf_wdt.c')
-rw-r--r-- | drivers/watchdog/w83627hf_wdt.c | 182 |
1 files changed, 162 insertions, 20 deletions
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. */ | 47 | static int wdt_io; |
48 | static int wdt_io = 0x2E; | 48 | |
49 | module_param(wdt_io, int, 0); | 49 | enum chips { w83627hf, w83627s, w83637hf, w83627thf, w83687thf, |
50 | MODULE_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 | ||
52 | static int timeout; /* in seconds */ | 53 | static int timeout; /* in seconds */ |
53 | module_param(timeout, int, 0); | 54 | module_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 | |||
75 | static void superio_outb(int reg, int val) | 91 | static 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 ? | 125 | static int w83627hf_init(struct watchdog_device *wdog, enum chips chip) |
110 | * So explicitly init to appropriate value. */ | ||
111 | |||
112 | static 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 | ||
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 | static int __init wdt_init(void) | 367 | static 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; |