.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0+ |
---|
1 | 2 | /* |
---|
2 | 3 | * w83627hf/thf WDT driver |
---|
3 | 4 | * |
---|
.. | .. |
---|
17 | 18 | * (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>, |
---|
18 | 19 | * All Rights Reserved. |
---|
19 | 20 | * |
---|
20 | | - * This program is free software; you can redistribute it and/or |
---|
21 | | - * modify it under the terms of the GNU General Public License |
---|
22 | | - * as published by the Free Software Foundation; either version |
---|
23 | | - * 2 of the License, or (at your option) any later version. |
---|
24 | | - * |
---|
25 | 21 | * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide |
---|
26 | 22 | * warranty for any of this software. This material is provided |
---|
27 | 23 | * "AS-IS" and at no charge. |
---|
.. | .. |
---|
38 | 34 | #include <linux/ioport.h> |
---|
39 | 35 | #include <linux/init.h> |
---|
40 | 36 | #include <linux/io.h> |
---|
| 37 | +#include <linux/dmi.h> |
---|
41 | 38 | |
---|
42 | 39 | #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" |
---|
43 | 40 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ |
---|
.. | .. |
---|
46 | 43 | static int cr_wdt_timeout; /* WDT timeout register */ |
---|
47 | 44 | static int cr_wdt_control; /* WDT control register */ |
---|
48 | 45 | static int cr_wdt_csr; /* WDT control & status register */ |
---|
| 46 | +static int wdt_cfg_enter = 0x87;/* key to unlock configuration space */ |
---|
| 47 | +static int wdt_cfg_leave = 0xAA;/* key to lock configuration space */ |
---|
49 | 48 | |
---|
50 | 49 | enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, |
---|
51 | 50 | w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, |
---|
52 | 51 | w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793, |
---|
53 | | - nct6795, nct6796, nct6102 }; |
---|
| 52 | + nct6795, nct6796, nct6102, nct6116 }; |
---|
54 | 53 | |
---|
55 | 54 | static int timeout; /* in seconds */ |
---|
56 | 55 | module_param(timeout, int, 0); |
---|
.. | .. |
---|
95 | 94 | #define NCT6775_ID 0xb4 |
---|
96 | 95 | #define NCT6776_ID 0xc3 |
---|
97 | 96 | #define NCT6102_ID 0xc4 |
---|
| 97 | +#define NCT6116_ID 0xd2 |
---|
98 | 98 | #define NCT6779_ID 0xc5 |
---|
99 | 99 | #define NCT6791_ID 0xc8 |
---|
100 | 100 | #define NCT6792_ID 0xc9 |
---|
.. | .. |
---|
130 | 130 | if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME)) |
---|
131 | 131 | return -EBUSY; |
---|
132 | 132 | |
---|
133 | | - outb_p(0x87, WDT_EFER); /* Enter extended function mode */ |
---|
134 | | - outb_p(0x87, WDT_EFER); /* Again according to manual */ |
---|
| 133 | + outb_p(wdt_cfg_enter, WDT_EFER); /* Enter extended function mode */ |
---|
| 134 | + outb_p(wdt_cfg_enter, WDT_EFER); /* Again according to manual */ |
---|
135 | 135 | |
---|
136 | 136 | return 0; |
---|
137 | 137 | } |
---|
.. | .. |
---|
143 | 143 | |
---|
144 | 144 | static void superio_exit(void) |
---|
145 | 145 | { |
---|
146 | | - outb_p(0xAA, WDT_EFER); /* Leave extended function mode */ |
---|
| 146 | + outb_p(wdt_cfg_leave, WDT_EFER); /* Leave extended function mode */ |
---|
147 | 147 | release_region(wdt_io, 2); |
---|
148 | 148 | } |
---|
149 | 149 | |
---|
.. | .. |
---|
212 | 212 | case nct6795: |
---|
213 | 213 | case nct6796: |
---|
214 | 214 | case nct6102: |
---|
| 215 | + case nct6116: |
---|
215 | 216 | /* |
---|
216 | 217 | * These chips have a fixed WDTO# output pin (W83627UHG), |
---|
217 | 218 | * or support more than one WDTO# output pin. |
---|
.. | .. |
---|
418 | 419 | cr_wdt_control = NCT6102D_WDT_CONTROL; |
---|
419 | 420 | cr_wdt_csr = NCT6102D_WDT_CSR; |
---|
420 | 421 | break; |
---|
| 422 | + case NCT6116_ID: |
---|
| 423 | + ret = nct6116; |
---|
| 424 | + cr_wdt_timeout = NCT6102D_WDT_TIMEOUT; |
---|
| 425 | + cr_wdt_control = NCT6102D_WDT_CONTROL; |
---|
| 426 | + cr_wdt_csr = NCT6102D_WDT_CSR; |
---|
| 427 | + break; |
---|
421 | 428 | case 0xff: |
---|
422 | 429 | ret = -ENODEV; |
---|
423 | 430 | break; |
---|
.. | .. |
---|
429 | 436 | superio_exit(); |
---|
430 | 437 | return ret; |
---|
431 | 438 | } |
---|
| 439 | + |
---|
| 440 | +/* |
---|
| 441 | + * On some systems, the NCT6791D comes with a companion chip and the |
---|
| 442 | + * watchdog function is in this companion chip. We must use a different |
---|
| 443 | + * unlocking sequence to access the companion chip. |
---|
| 444 | + */ |
---|
| 445 | +static int __init wdt_use_alt_key(const struct dmi_system_id *d) |
---|
| 446 | +{ |
---|
| 447 | + wdt_cfg_enter = 0x88; |
---|
| 448 | + wdt_cfg_leave = 0xBB; |
---|
| 449 | + |
---|
| 450 | + return 0; |
---|
| 451 | +} |
---|
| 452 | + |
---|
| 453 | +static const struct dmi_system_id wdt_dmi_table[] __initconst = { |
---|
| 454 | + { |
---|
| 455 | + .matches = { |
---|
| 456 | + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "INVES"), |
---|
| 457 | + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CTS"), |
---|
| 458 | + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "INVES"), |
---|
| 459 | + DMI_EXACT_MATCH(DMI_BOARD_NAME, "SHARKBAY"), |
---|
| 460 | + }, |
---|
| 461 | + .callback = wdt_use_alt_key, |
---|
| 462 | + }, |
---|
| 463 | + {} |
---|
| 464 | +}; |
---|
432 | 465 | |
---|
433 | 466 | static int __init wdt_init(void) |
---|
434 | 467 | { |
---|
.. | .. |
---|
457 | 490 | "NCT6795", |
---|
458 | 491 | "NCT6796", |
---|
459 | 492 | "NCT6102", |
---|
| 493 | + "NCT6116", |
---|
460 | 494 | }; |
---|
461 | 495 | |
---|
| 496 | + /* Apply system-specific quirks */ |
---|
| 497 | + dmi_check_system(wdt_dmi_table); |
---|
| 498 | + |
---|
462 | 499 | wdt_io = 0x2e; |
---|
463 | 500 | chip = wdt_find(0x2e); |
---|
464 | 501 | if (chip < 0) { |
---|