w83627hf_wdt.c (11915B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * w83627hf/thf WDT driver 4 * 5 * (c) Copyright 2013 Guenter Roeck 6 * converted to watchdog infrastructure 7 * 8 * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com> 9 * added support for W83627THF. 10 * 11 * (c) Copyright 2003,2007 Pádraig Brady <P@draigBrady.com> 12 * 13 * Based on advantechwdt.c which is based on wdt.c. 14 * Original copyright messages: 15 * 16 * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl> 17 * 18 * (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>, 19 * All Rights Reserved. 20 * 21 * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide 22 * warranty for any of this software. This material is provided 23 * "AS-IS" and at no charge. 24 * 25 * (c) Copyright 1995 Alan Cox <alan@lxorguk.ukuu.org.uk> 26 */ 27 28#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 29 30#include <linux/module.h> 31#include <linux/moduleparam.h> 32#include <linux/types.h> 33#include <linux/watchdog.h> 34#include <linux/ioport.h> 35#include <linux/init.h> 36#include <linux/io.h> 37#include <linux/dmi.h> 38 39#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" 40#define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ 41 42static int wdt_io; 43static int cr_wdt_timeout; /* WDT timeout register */ 44static int cr_wdt_control; /* WDT control register */ 45static int cr_wdt_csr; /* WDT control & status register */ 46static int wdt_cfg_enter = 0x87;/* key to unlock configuration space */ 47static int wdt_cfg_leave = 0xAA;/* key to lock configuration space */ 48 49enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf, 50 w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p, 51 w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793, 52 nct6795, nct6796, nct6102, nct6116 }; 53 54static int timeout; /* in seconds */ 55module_param(timeout, int, 0); 56MODULE_PARM_DESC(timeout, 57 "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" 58 __MODULE_STRING(WATCHDOG_TIMEOUT) "."); 59 60static bool nowayout = WATCHDOG_NOWAYOUT; 61module_param(nowayout, bool, 0); 62MODULE_PARM_DESC(nowayout, 63 "Watchdog cannot be stopped once started (default=" 64 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 65 66static int early_disable; 67module_param(early_disable, int, 0); 68MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)"); 69 70/* 71 * Kernel methods. 72 */ 73 74#define WDT_EFER (wdt_io+0) /* Extended Function Enable Registers */ 75#define WDT_EFIR (wdt_io+0) /* Extended Function Index Register 76 (same as EFER) */ 77#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */ 78 79#define W83627HF_LD_WDT 0x08 80 81#define W83627HF_ID 0x52 82#define W83627S_ID 0x59 83#define W83697HF_ID 0x60 84#define W83697UG_ID 0x68 85#define W83637HF_ID 0x70 86#define W83627THF_ID 0x82 87#define W83687THF_ID 0x85 88#define W83627EHF_ID 0x88 89#define W83627DHG_ID 0xa0 90#define W83627UHG_ID 0xa2 91#define W83667HG_ID 0xa5 92#define W83627DHG_P_ID 0xb0 93#define W83667HG_B_ID 0xb3 94#define NCT6775_ID 0xb4 95#define NCT6776_ID 0xc3 96#define NCT6102_ID 0xc4 97#define NCT6116_ID 0xd2 98#define NCT6779_ID 0xc5 99#define NCT6791_ID 0xc8 100#define NCT6792_ID 0xc9 101#define NCT6793_ID 0xd1 102#define NCT6795_ID 0xd3 103#define NCT6796_ID 0xd4 /* also NCT9697D, NCT9698D */ 104 105#define W83627HF_WDT_TIMEOUT 0xf6 106#define W83697HF_WDT_TIMEOUT 0xf4 107#define NCT6102D_WDT_TIMEOUT 0xf1 108 109#define W83627HF_WDT_CONTROL 0xf5 110#define W83697HF_WDT_CONTROL 0xf3 111#define NCT6102D_WDT_CONTROL 0xf0 112 113#define W836X7HF_WDT_CSR 0xf7 114#define NCT6102D_WDT_CSR 0xf2 115 116static void superio_outb(int reg, int val) 117{ 118 outb(reg, WDT_EFER); 119 outb(val, WDT_EFDR); 120} 121 122static inline int superio_inb(int reg) 123{ 124 outb(reg, WDT_EFER); 125 return inb(WDT_EFDR); 126} 127 128static int superio_enter(void) 129{ 130 if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME)) 131 return -EBUSY; 132 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 136 return 0; 137} 138 139static void superio_select(int ld) 140{ 141 superio_outb(0x07, ld); 142} 143 144static void superio_exit(void) 145{ 146 outb_p(wdt_cfg_leave, WDT_EFER); /* Leave extended function mode */ 147 release_region(wdt_io, 2); 148} 149 150static int w83627hf_init(struct watchdog_device *wdog, enum chips chip) 151{ 152 int ret; 153 unsigned char t; 154 155 ret = superio_enter(); 156 if (ret) 157 return ret; 158 159 superio_select(W83627HF_LD_WDT); 160 161 /* set CR30 bit 0 to activate GPIO2 */ 162 t = superio_inb(0x30); 163 if (!(t & 0x01)) 164 superio_outb(0x30, t | 0x01); 165 166 switch (chip) { 167 case w83627hf: 168 case w83627s: 169 t = superio_inb(0x2B) & ~0x10; 170 superio_outb(0x2B, t); /* set GPIO24 to WDT0 */ 171 break; 172 case w83697hf: 173 /* Set pin 119 to WDTO# mode (= CR29, WDT0) */ 174 t = superio_inb(0x29) & ~0x60; 175 t |= 0x20; 176 superio_outb(0x29, t); 177 break; 178 case w83697ug: 179 /* Set pin 118 to WDTO# mode */ 180 t = superio_inb(0x2b) & ~0x04; 181 superio_outb(0x2b, t); 182 break; 183 case w83627thf: 184 t = (superio_inb(0x2B) & ~0x08) | 0x04; 185 superio_outb(0x2B, t); /* set GPIO3 to WDT0 */ 186 break; 187 case w83627dhg: 188 case w83627dhg_p: 189 t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */ 190 superio_outb(0x2D, t); /* set GPIO5 to WDT0 */ 191 t = superio_inb(cr_wdt_control); 192 t |= 0x02; /* enable the WDTO# output low pulse 193 * to the KBRST# pin */ 194 superio_outb(cr_wdt_control, t); 195 break; 196 case w83637hf: 197 break; 198 case w83687thf: 199 t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */ 200 superio_outb(0x2C, t); 201 break; 202 case w83627ehf: 203 case w83627uhg: 204 case w83667hg: 205 case w83667hg_b: 206 case nct6775: 207 case nct6776: 208 case nct6779: 209 case nct6791: 210 case nct6792: 211 case nct6793: 212 case nct6795: 213 case nct6796: 214 case nct6102: 215 case nct6116: 216 /* 217 * These chips have a fixed WDTO# output pin (W83627UHG), 218 * or support more than one WDTO# output pin. 219 * Don't touch its configuration, and hope the BIOS 220 * does the right thing. 221 */ 222 t = superio_inb(cr_wdt_control); 223 t |= 0x02; /* enable the WDTO# output low pulse 224 * to the KBRST# pin */ 225 superio_outb(cr_wdt_control, t); 226 break; 227 default: 228 break; 229 } 230 231 t = superio_inb(cr_wdt_timeout); 232 if (t != 0) { 233 if (early_disable) { 234 pr_warn("Stopping previously enabled watchdog until userland kicks in\n"); 235 superio_outb(cr_wdt_timeout, 0); 236 } else { 237 pr_info("Watchdog already running. Resetting timeout to %d sec\n", 238 wdog->timeout); 239 superio_outb(cr_wdt_timeout, wdog->timeout); 240 } 241 } 242 243 /* set second mode & disable keyboard turning off watchdog */ 244 t = superio_inb(cr_wdt_control) & ~0x0C; 245 superio_outb(cr_wdt_control, t); 246 247 /* reset trigger, disable keyboard & mouse turning off watchdog */ 248 t = superio_inb(cr_wdt_csr) & ~0xD0; 249 superio_outb(cr_wdt_csr, t); 250 251 superio_exit(); 252 253 return 0; 254} 255 256static int wdt_set_time(unsigned int timeout) 257{ 258 int ret; 259 260 ret = superio_enter(); 261 if (ret) 262 return ret; 263 264 superio_select(W83627HF_LD_WDT); 265 superio_outb(cr_wdt_timeout, timeout); 266 superio_exit(); 267 268 return 0; 269} 270 271static int wdt_start(struct watchdog_device *wdog) 272{ 273 return wdt_set_time(wdog->timeout); 274} 275 276static int wdt_stop(struct watchdog_device *wdog) 277{ 278 return wdt_set_time(0); 279} 280 281static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout) 282{ 283 wdog->timeout = timeout; 284 285 return 0; 286} 287 288static unsigned int wdt_get_time(struct watchdog_device *wdog) 289{ 290 unsigned int timeleft; 291 int ret; 292 293 ret = superio_enter(); 294 if (ret) 295 return 0; 296 297 superio_select(W83627HF_LD_WDT); 298 timeleft = superio_inb(cr_wdt_timeout); 299 superio_exit(); 300 301 return timeleft; 302} 303 304/* 305 * Kernel Interfaces 306 */ 307 308static const struct watchdog_info wdt_info = { 309 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 310 .identity = "W83627HF Watchdog", 311}; 312 313static const struct watchdog_ops wdt_ops = { 314 .owner = THIS_MODULE, 315 .start = wdt_start, 316 .stop = wdt_stop, 317 .set_timeout = wdt_set_timeout, 318 .get_timeleft = wdt_get_time, 319}; 320 321static struct watchdog_device wdt_dev = { 322 .info = &wdt_info, 323 .ops = &wdt_ops, 324 .timeout = WATCHDOG_TIMEOUT, 325 .min_timeout = 1, 326 .max_timeout = 255, 327}; 328 329/* 330 * The WDT needs to learn about soft shutdowns in order to 331 * turn the timebomb registers off. 332 */ 333 334static int wdt_find(int addr) 335{ 336 u8 val; 337 int ret; 338 339 cr_wdt_timeout = W83627HF_WDT_TIMEOUT; 340 cr_wdt_control = W83627HF_WDT_CONTROL; 341 cr_wdt_csr = W836X7HF_WDT_CSR; 342 343 ret = superio_enter(); 344 if (ret) 345 return ret; 346 superio_select(W83627HF_LD_WDT); 347 val = superio_inb(0x20); 348 switch (val) { 349 case W83627HF_ID: 350 ret = w83627hf; 351 break; 352 case W83627S_ID: 353 ret = w83627s; 354 break; 355 case W83697HF_ID: 356 ret = w83697hf; 357 cr_wdt_timeout = W83697HF_WDT_TIMEOUT; 358 cr_wdt_control = W83697HF_WDT_CONTROL; 359 break; 360 case W83697UG_ID: 361 ret = w83697ug; 362 cr_wdt_timeout = W83697HF_WDT_TIMEOUT; 363 cr_wdt_control = W83697HF_WDT_CONTROL; 364 break; 365 case W83637HF_ID: 366 ret = w83637hf; 367 break; 368 case W83627THF_ID: 369 ret = w83627thf; 370 break; 371 case W83687THF_ID: 372 ret = w83687thf; 373 break; 374 case W83627EHF_ID: 375 ret = w83627ehf; 376 break; 377 case W83627DHG_ID: 378 ret = w83627dhg; 379 break; 380 case W83627DHG_P_ID: 381 ret = w83627dhg_p; 382 break; 383 case W83627UHG_ID: 384 ret = w83627uhg; 385 break; 386 case W83667HG_ID: 387 ret = w83667hg; 388 break; 389 case W83667HG_B_ID: 390 ret = w83667hg_b; 391 break; 392 case NCT6775_ID: 393 ret = nct6775; 394 break; 395 case NCT6776_ID: 396 ret = nct6776; 397 break; 398 case NCT6779_ID: 399 ret = nct6779; 400 break; 401 case NCT6791_ID: 402 ret = nct6791; 403 break; 404 case NCT6792_ID: 405 ret = nct6792; 406 break; 407 case NCT6793_ID: 408 ret = nct6793; 409 break; 410 case NCT6795_ID: 411 ret = nct6795; 412 break; 413 case NCT6796_ID: 414 ret = nct6796; 415 break; 416 case NCT6102_ID: 417 ret = nct6102; 418 cr_wdt_timeout = NCT6102D_WDT_TIMEOUT; 419 cr_wdt_control = NCT6102D_WDT_CONTROL; 420 cr_wdt_csr = NCT6102D_WDT_CSR; 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; 428 case 0xff: 429 ret = -ENODEV; 430 break; 431 default: 432 ret = -ENODEV; 433 pr_err("Unsupported chip ID: 0x%02x\n", val); 434 break; 435 } 436 superio_exit(); 437 return ret; 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 */ 445static 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 453static 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}; 465 466static int __init wdt_init(void) 467{ 468 int ret; 469 int chip; 470 static const char * const chip_name[] = { 471 "W83627HF", 472 "W83627S", 473 "W83697HF", 474 "W83697UG", 475 "W83637HF", 476 "W83627THF", 477 "W83687THF", 478 "W83627EHF", 479 "W83627DHG", 480 "W83627UHG", 481 "W83667HG", 482 "W83667DHG-P", 483 "W83667HG-B", 484 "NCT6775", 485 "NCT6776", 486 "NCT6779", 487 "NCT6791", 488 "NCT6792", 489 "NCT6793", 490 "NCT6795", 491 "NCT6796", 492 "NCT6102", 493 "NCT6116", 494 }; 495 496 /* Apply system-specific quirks */ 497 dmi_check_system(wdt_dmi_table); 498 499 wdt_io = 0x2e; 500 chip = wdt_find(0x2e); 501 if (chip < 0) { 502 wdt_io = 0x4e; 503 chip = wdt_find(0x4e); 504 if (chip < 0) 505 return chip; 506 } 507 508 pr_info("WDT driver for %s Super I/O chip initialising\n", 509 chip_name[chip]); 510 511 watchdog_init_timeout(&wdt_dev, timeout, NULL); 512 watchdog_set_nowayout(&wdt_dev, nowayout); 513 watchdog_stop_on_reboot(&wdt_dev); 514 515 ret = w83627hf_init(&wdt_dev, chip); 516 if (ret) { 517 pr_err("failed to initialize watchdog (err=%d)\n", ret); 518 return ret; 519 } 520 521 ret = watchdog_register_device(&wdt_dev); 522 if (ret) 523 return ret; 524 525 pr_info("initialized. timeout=%d sec (nowayout=%d)\n", 526 wdt_dev.timeout, nowayout); 527 528 return ret; 529} 530 531static void __exit wdt_exit(void) 532{ 533 watchdog_unregister_device(&wdt_dev); 534} 535 536module_init(wdt_init); 537module_exit(wdt_exit); 538 539MODULE_LICENSE("GPL"); 540MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>"); 541MODULE_DESCRIPTION("w83627hf/thf WDT driver");