Commit 962c04f54e4a3c322d19b47256f9aec0b9c8124e

Authored by Guenter Roeck
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;