提交 962c04f5 编写于 作者: G Guenter Roeck 提交者: Wim Van Sebroeck

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: NGuenter Roeck <linux@roeck-us.net>
Signed-off-by: NWim Van Sebroeck <wim@iguana.be>
上级 f72fa00f
...@@ -892,13 +892,20 @@ config VIA_WDT ...@@ -892,13 +892,20 @@ config VIA_WDT
Most people will say N. Most people will say N.
config W83627HF_WDT config W83627HF_WDT
tristate "W83627HF/W83627DHG Watchdog Timer" tristate "Watchdog timer for W83627HF/W83627DHG and compatibles"
depends on X86 depends on X86
select WATCHDOG_CORE select WATCHDOG_CORE
---help--- ---help---
This is the driver for the hardware watchdog on the W83627HF chipset This is the driver for the hardware watchdog on the following
as used in Advantech PC-9578 and Tyan S2721-533 motherboards Super I/O chips.
(and likely others). The driver also supports the W83627DHG chip. W83627DHG/DHG-P/EHF/EHG/F/G/HF/S/SF/THF/UHG/UG
W83637HF
W83667HG/HG-B
W83687THF
NCT6775
NCT6776
NCT6779
This watchdog simply watches your kernel to make sure it doesn't This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain freeze, and if it does, it reboots your computer after a certain
amount of time. amount of time.
......
...@@ -44,10 +44,11 @@ ...@@ -44,10 +44,11 @@
#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */
/* You must set this - there is no sane way to probe for this board. */ static int wdt_io;
static int wdt_io = 0x2E;
module_param(wdt_io, int, 0); enum chips { w83627hf, w83627s, w83637hf, w83627thf, w83687thf,
MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, w83667hg_b,
nct6775, nct6776, nct6779 };
static int timeout; /* in seconds */ static int timeout; /* in seconds */
module_param(timeout, int, 0); module_param(timeout, int, 0);
...@@ -72,6 +73,21 @@ MODULE_PARM_DESC(nowayout, ...@@ -72,6 +73,21 @@ MODULE_PARM_DESC(nowayout,
#define W83627HF_LD_WDT 0x08 #define W83627HF_LD_WDT 0x08
#define W83627HF_ID 0x52
#define W83627S_ID 0x59
#define W83637HF_ID 0x70
#define W83627THF_ID 0x82
#define W83687THF_ID 0x85
#define W83627EHF_ID 0x88
#define W83627DHG_ID 0xa0
#define W83627UHG_ID 0xa2
#define W83667HG_ID 0xa5
#define W83627DHG_P_ID 0xb0
#define W83667HG_B_ID 0xb3
#define NCT6775_ID 0xb4
#define NCT6776_ID 0xc3
#define NCT6779_ID 0xc5
static void superio_outb(int reg, int val) static void superio_outb(int reg, int val)
{ {
outb(reg, WDT_EFER); outb(reg, WDT_EFER);
...@@ -106,10 +122,7 @@ static void superio_exit(void) ...@@ -106,10 +122,7 @@ static void superio_exit(void)
release_region(wdt_io, 2); release_region(wdt_io, 2);
} }
/* tyan motherboards seem to set F5 to 0x4C ? static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
* So explicitly init to appropriate value. */
static int w83627hf_init(struct watchdog_device *wdog)
{ {
int ret; int ret;
unsigned char t; unsigned char t;
...@@ -119,20 +132,59 @@ static int w83627hf_init(struct watchdog_device *wdog) ...@@ -119,20 +132,59 @@ static int w83627hf_init(struct watchdog_device *wdog)
return ret; return ret;
superio_select(W83627HF_LD_WDT); superio_select(W83627HF_LD_WDT);
t = superio_inb(0x20); /* check chip version */
if (t == 0x82) { /* W83627THF */
t = (superio_inb(0x2b) & 0xf7);
superio_outb(0x2b, t | 0x04); /* set GPIO3 to WDT0 */
} else if (t == 0x88 || t == 0xa0) { /* W83627EHF / W83627DHG */
t = superio_inb(0x2d);
superio_outb(0x2d, t & ~0x01); /* set GPIO5 to WDT0 */
}
/* set CR30 bit 0 to activate GPIO2 */ /* set CR30 bit 0 to activate GPIO2 */
t = superio_inb(0x30); t = superio_inb(0x30);
if (!(t & 0x01)) if (!(t & 0x01))
superio_outb(0x30, t | 0x01); superio_outb(0x30, t | 0x01);
switch (chip) {
case w83627hf:
case w83627s:
t = superio_inb(0x2B) & ~0x10;
superio_outb(0x2B, t); /* set GPIO24 to WDT0 */
break;
case w83627thf:
t = (superio_inb(0x2B) & ~0x08) | 0x04;
superio_outb(0x2B, t); /* set GPIO3 to WDT0 */
break;
case w83627dhg:
case w83627dhg_p:
t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */
superio_outb(0x2D, t); /* set GPIO5 to WDT0 */
t = superio_inb(0xF5);
t |= 0x02; /* enable the WDTO# output low pulse
* to the KBRST# pin */
superio_outb(0xF5, t);
break;
case w83637hf:
break;
case w83687thf:
t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */
superio_outb(0x2C, t);
break;
case w83627ehf:
case w83627uhg:
case w83667hg:
case w83667hg_b:
case nct6775:
case nct6776:
case nct6779:
/*
* These chips have a fixed WDTO# output pin (W83627UHG),
* or support more than one WDTO# output pin.
* Don't touch its configuration, and hope the BIOS
* does the right thing.
*/
t = superio_inb(0xF5);
t |= 0x02; /* enable the WDTO# output low pulse
* to the KBRST# pin */
superio_outb(0xF5, t);
break;
default:
break;
}
t = superio_inb(0xF6); t = superio_inb(0xF6);
if (t != 0) { if (t != 0) {
pr_info("Watchdog already running. Resetting timeout to %d sec\n", pr_info("Watchdog already running. Resetting timeout to %d sec\n",
...@@ -142,8 +194,6 @@ static int w83627hf_init(struct watchdog_device *wdog) ...@@ -142,8 +194,6 @@ static int w83627hf_init(struct watchdog_device *wdog)
/* set second mode & disable keyboard turning off watchdog */ /* set second mode & disable keyboard turning off watchdog */
t = superio_inb(0xF5) & ~0x0C; t = superio_inb(0xF5) & ~0x0C;
/* enable the WDTO# output low pulse to the KBRST# pin */
t |= 0x02;
superio_outb(0xF5, t); superio_outb(0xF5, t);
/* disable keyboard & mouse turning off watchdog */ /* disable keyboard & mouse turning off watchdog */
...@@ -249,16 +299,108 @@ static struct notifier_block wdt_notifier = { ...@@ -249,16 +299,108 @@ static struct notifier_block wdt_notifier = {
.notifier_call = wdt_notify_sys, .notifier_call = wdt_notify_sys,
}; };
static int wdt_find(int addr)
{
u8 val;
int ret;
ret = superio_enter();
if (ret)
return ret;
superio_select(W83627HF_LD_WDT);
val = superio_inb(0x20);
switch (val) {
case W83627HF_ID:
ret = w83627hf;
break;
case W83627S_ID:
ret = w83627s;
break;
case W83637HF_ID:
ret = w83637hf;
break;
case W83627THF_ID:
ret = w83627thf;
break;
case W83687THF_ID:
ret = w83687thf;
break;
case W83627EHF_ID:
ret = w83627ehf;
break;
case W83627DHG_ID:
ret = w83627dhg;
break;
case W83627DHG_P_ID:
ret = w83627dhg_p;
break;
case W83627UHG_ID:
ret = w83627uhg;
break;
case W83667HG_ID:
ret = w83667hg;
break;
case W83667HG_B_ID:
ret = w83667hg_b;
break;
case NCT6775_ID:
ret = nct6775;
break;
case NCT6776_ID:
ret = nct6776;
break;
case NCT6779_ID:
ret = nct6779;
break;
case 0xff:
ret = -ENODEV;
break;
default:
ret = -ENODEV;
pr_err("Unsupported chip ID: 0x%02x\n", val);
break;
}
superio_exit();
return ret;
}
static int __init wdt_init(void) static int __init wdt_init(void)
{ {
int ret; int ret;
int chip;
const char * const chip_name[] = {
"W83627HF",
"W83627S",
"W83637HF",
"W83627THF",
"W83687THF",
"W83627EHF",
"W83627DHG",
"W83627UHG",
"W83667HG",
"W83667DHG-P",
"W83667HG-B",
"NCT6775",
"NCT6776",
"NCT6779",
};
wdt_io = 0x2e;
chip = wdt_find(0x2e);
if (chip < 0) {
wdt_io = 0x4e;
chip = wdt_find(0x4e);
if (chip < 0)
return chip;
}
pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n"); pr_info("WDT driver for %s Super I/O chip initialising\n",
chip_name[chip]);
watchdog_init_timeout(&wdt_dev, timeout, NULL); watchdog_init_timeout(&wdt_dev, timeout, NULL);
watchdog_set_nowayout(&wdt_dev, nowayout); watchdog_set_nowayout(&wdt_dev, nowayout);
ret = w83627hf_init(&wdt_dev); ret = w83627hf_init(&wdt_dev, chip);
if (ret) { if (ret) {
pr_err("failed to initialize watchdog (err=%d)\n", ret); pr_err("failed to initialize watchdog (err=%d)\n", ret);
return ret; return ret;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册