aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/w83627hf_wdt.c
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 /drivers/watchdog/w83627hf_wdt.c
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>
Diffstat (limited to 'drivers/watchdog/w83627hf_wdt.c')
-rw-r--r--drivers/watchdog/w83627hf_wdt.c182
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. */ 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;