root/drivers/watchdog/w83627hf_wdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. superio_outb
  2. superio_inb
  3. superio_enter
  4. superio_select
  5. superio_exit
  6. w83627hf_init
  7. wdt_set_time
  8. wdt_start
  9. wdt_stop
  10. wdt_set_timeout
  11. wdt_get_time
  12. wdt_find
  13. wdt_use_alt_key
  14. wdt_init
  15. wdt_exit

   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 
  42 static int wdt_io;
  43 static int cr_wdt_timeout;      /* WDT timeout register */
  44 static int cr_wdt_control;      /* WDT control register */
  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 */
  48 
  49 enum 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 };
  53 
  54 static int timeout;                     /* in seconds */
  55 module_param(timeout, int, 0);
  56 MODULE_PARM_DESC(timeout,
  57                 "Watchdog timeout in seconds. 1 <= timeout <= 255, default="
  58                                 __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
  59 
  60 static bool nowayout = WATCHDOG_NOWAYOUT;
  61 module_param(nowayout, bool, 0);
  62 MODULE_PARM_DESC(nowayout,
  63                 "Watchdog cannot be stopped once started (default="
  64                                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  65 
  66 static int early_disable;
  67 module_param(early_disable, int, 0);
  68 MODULE_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 NCT6779_ID              0xc5
  98 #define NCT6791_ID              0xc8
  99 #define NCT6792_ID              0xc9
 100 #define NCT6793_ID              0xd1
 101 #define NCT6795_ID              0xd3
 102 #define NCT6796_ID              0xd4    /* also NCT9697D, NCT9698D */
 103 
 104 #define W83627HF_WDT_TIMEOUT    0xf6
 105 #define W83697HF_WDT_TIMEOUT    0xf4
 106 #define NCT6102D_WDT_TIMEOUT    0xf1
 107 
 108 #define W83627HF_WDT_CONTROL    0xf5
 109 #define W83697HF_WDT_CONTROL    0xf3
 110 #define NCT6102D_WDT_CONTROL    0xf0
 111 
 112 #define W836X7HF_WDT_CSR        0xf7
 113 #define NCT6102D_WDT_CSR        0xf2
 114 
 115 static void superio_outb(int reg, int val)
 116 {
 117         outb(reg, WDT_EFER);
 118         outb(val, WDT_EFDR);
 119 }
 120 
 121 static inline int superio_inb(int reg)
 122 {
 123         outb(reg, WDT_EFER);
 124         return inb(WDT_EFDR);
 125 }
 126 
 127 static int superio_enter(void)
 128 {
 129         if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME))
 130                 return -EBUSY;
 131 
 132         outb_p(wdt_cfg_enter, WDT_EFER); /* Enter extended function mode */
 133         outb_p(wdt_cfg_enter, WDT_EFER); /* Again according to manual */
 134 
 135         return 0;
 136 }
 137 
 138 static void superio_select(int ld)
 139 {
 140         superio_outb(0x07, ld);
 141 }
 142 
 143 static void superio_exit(void)
 144 {
 145         outb_p(wdt_cfg_leave, WDT_EFER); /* Leave extended function mode */
 146         release_region(wdt_io, 2);
 147 }
 148 
 149 static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
 150 {
 151         int ret;
 152         unsigned char t;
 153 
 154         ret = superio_enter();
 155         if (ret)
 156                 return ret;
 157 
 158         superio_select(W83627HF_LD_WDT);
 159 
 160         /* set CR30 bit 0 to activate GPIO2 */
 161         t = superio_inb(0x30);
 162         if (!(t & 0x01))
 163                 superio_outb(0x30, t | 0x01);
 164 
 165         switch (chip) {
 166         case w83627hf:
 167         case w83627s:
 168                 t = superio_inb(0x2B) & ~0x10;
 169                 superio_outb(0x2B, t); /* set GPIO24 to WDT0 */
 170                 break;
 171         case w83697hf:
 172                 /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
 173                 t = superio_inb(0x29) & ~0x60;
 174                 t |= 0x20;
 175                 superio_outb(0x29, t);
 176                 break;
 177         case w83697ug:
 178                 /* Set pin 118 to WDTO# mode */
 179                 t = superio_inb(0x2b) & ~0x04;
 180                 superio_outb(0x2b, t);
 181                 break;
 182         case w83627thf:
 183                 t = (superio_inb(0x2B) & ~0x08) | 0x04;
 184                 superio_outb(0x2B, t); /* set GPIO3 to WDT0 */
 185                 break;
 186         case w83627dhg:
 187         case w83627dhg_p:
 188                 t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */
 189                 superio_outb(0x2D, t); /* set GPIO5 to WDT0 */
 190                 t = superio_inb(cr_wdt_control);
 191                 t |= 0x02;      /* enable the WDTO# output low pulse
 192                                  * to the KBRST# pin */
 193                 superio_outb(cr_wdt_control, t);
 194                 break;
 195         case w83637hf:
 196                 break;
 197         case w83687thf:
 198                 t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */
 199                 superio_outb(0x2C, t);
 200                 break;
 201         case w83627ehf:
 202         case w83627uhg:
 203         case w83667hg:
 204         case w83667hg_b:
 205         case nct6775:
 206         case nct6776:
 207         case nct6779:
 208         case nct6791:
 209         case nct6792:
 210         case nct6793:
 211         case nct6795:
 212         case nct6796:
 213         case nct6102:
 214                 /*
 215                  * These chips have a fixed WDTO# output pin (W83627UHG),
 216                  * or support more than one WDTO# output pin.
 217                  * Don't touch its configuration, and hope the BIOS
 218                  * does the right thing.
 219                  */
 220                 t = superio_inb(cr_wdt_control);
 221                 t |= 0x02;      /* enable the WDTO# output low pulse
 222                                  * to the KBRST# pin */
 223                 superio_outb(cr_wdt_control, t);
 224                 break;
 225         default:
 226                 break;
 227         }
 228 
 229         t = superio_inb(cr_wdt_timeout);
 230         if (t != 0) {
 231                 if (early_disable) {
 232                         pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
 233                         superio_outb(cr_wdt_timeout, 0);
 234                 } else {
 235                         pr_info("Watchdog already running. Resetting timeout to %d sec\n",
 236                                 wdog->timeout);
 237                         superio_outb(cr_wdt_timeout, wdog->timeout);
 238                 }
 239         }
 240 
 241         /* set second mode & disable keyboard turning off watchdog */
 242         t = superio_inb(cr_wdt_control) & ~0x0C;
 243         superio_outb(cr_wdt_control, t);
 244 
 245         /* reset trigger, disable keyboard & mouse turning off watchdog */
 246         t = superio_inb(cr_wdt_csr) & ~0xD0;
 247         superio_outb(cr_wdt_csr, t);
 248 
 249         superio_exit();
 250 
 251         return 0;
 252 }
 253 
 254 static int wdt_set_time(unsigned int timeout)
 255 {
 256         int ret;
 257 
 258         ret = superio_enter();
 259         if (ret)
 260                 return ret;
 261 
 262         superio_select(W83627HF_LD_WDT);
 263         superio_outb(cr_wdt_timeout, timeout);
 264         superio_exit();
 265 
 266         return 0;
 267 }
 268 
 269 static int wdt_start(struct watchdog_device *wdog)
 270 {
 271         return wdt_set_time(wdog->timeout);
 272 }
 273 
 274 static int wdt_stop(struct watchdog_device *wdog)
 275 {
 276         return wdt_set_time(0);
 277 }
 278 
 279 static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout)
 280 {
 281         wdog->timeout = timeout;
 282 
 283         return 0;
 284 }
 285 
 286 static unsigned int wdt_get_time(struct watchdog_device *wdog)
 287 {
 288         unsigned int timeleft;
 289         int ret;
 290 
 291         ret = superio_enter();
 292         if (ret)
 293                 return 0;
 294 
 295         superio_select(W83627HF_LD_WDT);
 296         timeleft = superio_inb(cr_wdt_timeout);
 297         superio_exit();
 298 
 299         return timeleft;
 300 }
 301 
 302 /*
 303  *      Kernel Interfaces
 304  */
 305 
 306 static const struct watchdog_info wdt_info = {
 307         .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 308         .identity = "W83627HF Watchdog",
 309 };
 310 
 311 static const struct watchdog_ops wdt_ops = {
 312         .owner = THIS_MODULE,
 313         .start = wdt_start,
 314         .stop = wdt_stop,
 315         .set_timeout = wdt_set_timeout,
 316         .get_timeleft = wdt_get_time,
 317 };
 318 
 319 static struct watchdog_device wdt_dev = {
 320         .info = &wdt_info,
 321         .ops = &wdt_ops,
 322         .timeout = WATCHDOG_TIMEOUT,
 323         .min_timeout = 1,
 324         .max_timeout = 255,
 325 };
 326 
 327 /*
 328  *      The WDT needs to learn about soft shutdowns in order to
 329  *      turn the timebomb registers off.
 330  */
 331 
 332 static int wdt_find(int addr)
 333 {
 334         u8 val;
 335         int ret;
 336 
 337         cr_wdt_timeout = W83627HF_WDT_TIMEOUT;
 338         cr_wdt_control = W83627HF_WDT_CONTROL;
 339         cr_wdt_csr = W836X7HF_WDT_CSR;
 340 
 341         ret = superio_enter();
 342         if (ret)
 343                 return ret;
 344         superio_select(W83627HF_LD_WDT);
 345         val = superio_inb(0x20);
 346         switch (val) {
 347         case W83627HF_ID:
 348                 ret = w83627hf;
 349                 break;
 350         case W83627S_ID:
 351                 ret = w83627s;
 352                 break;
 353         case W83697HF_ID:
 354                 ret = w83697hf;
 355                 cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
 356                 cr_wdt_control = W83697HF_WDT_CONTROL;
 357                 break;
 358         case W83697UG_ID:
 359                 ret = w83697ug;
 360                 cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
 361                 cr_wdt_control = W83697HF_WDT_CONTROL;
 362                 break;
 363         case W83637HF_ID:
 364                 ret = w83637hf;
 365                 break;
 366         case W83627THF_ID:
 367                 ret = w83627thf;
 368                 break;
 369         case W83687THF_ID:
 370                 ret = w83687thf;
 371                 break;
 372         case W83627EHF_ID:
 373                 ret = w83627ehf;
 374                 break;
 375         case W83627DHG_ID:
 376                 ret = w83627dhg;
 377                 break;
 378         case W83627DHG_P_ID:
 379                 ret = w83627dhg_p;
 380                 break;
 381         case W83627UHG_ID:
 382                 ret = w83627uhg;
 383                 break;
 384         case W83667HG_ID:
 385                 ret = w83667hg;
 386                 break;
 387         case W83667HG_B_ID:
 388                 ret = w83667hg_b;
 389                 break;
 390         case NCT6775_ID:
 391                 ret = nct6775;
 392                 break;
 393         case NCT6776_ID:
 394                 ret = nct6776;
 395                 break;
 396         case NCT6779_ID:
 397                 ret = nct6779;
 398                 break;
 399         case NCT6791_ID:
 400                 ret = nct6791;
 401                 break;
 402         case NCT6792_ID:
 403                 ret = nct6792;
 404                 break;
 405         case NCT6793_ID:
 406                 ret = nct6793;
 407                 break;
 408         case NCT6795_ID:
 409                 ret = nct6795;
 410                 break;
 411         case NCT6796_ID:
 412                 ret = nct6796;
 413                 break;
 414         case NCT6102_ID:
 415                 ret = nct6102;
 416                 cr_wdt_timeout = NCT6102D_WDT_TIMEOUT;
 417                 cr_wdt_control = NCT6102D_WDT_CONTROL;
 418                 cr_wdt_csr = NCT6102D_WDT_CSR;
 419                 break;
 420         case 0xff:
 421                 ret = -ENODEV;
 422                 break;
 423         default:
 424                 ret = -ENODEV;
 425                 pr_err("Unsupported chip ID: 0x%02x\n", val);
 426                 break;
 427         }
 428         superio_exit();
 429         return ret;
 430 }
 431 
 432 /*
 433  * On some systems, the NCT6791D comes with a companion chip and the
 434  * watchdog function is in this companion chip. We must use a different
 435  * unlocking sequence to access the companion chip.
 436  */
 437 static int __init wdt_use_alt_key(const struct dmi_system_id *d)
 438 {
 439         wdt_cfg_enter = 0x88;
 440         wdt_cfg_leave = 0xBB;
 441 
 442         return 0;
 443 }
 444 
 445 static const struct dmi_system_id wdt_dmi_table[] __initconst = {
 446         {
 447                 .matches = {
 448                         DMI_EXACT_MATCH(DMI_SYS_VENDOR, "INVES"),
 449                         DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CTS"),
 450                         DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "INVES"),
 451                         DMI_EXACT_MATCH(DMI_BOARD_NAME, "SHARKBAY"),
 452                 },
 453                 .callback = wdt_use_alt_key,
 454         },
 455         {}
 456 };
 457 
 458 static int __init wdt_init(void)
 459 {
 460         int ret;
 461         int chip;
 462         static const char * const chip_name[] = {
 463                 "W83627HF",
 464                 "W83627S",
 465                 "W83697HF",
 466                 "W83697UG",
 467                 "W83637HF",
 468                 "W83627THF",
 469                 "W83687THF",
 470                 "W83627EHF",
 471                 "W83627DHG",
 472                 "W83627UHG",
 473                 "W83667HG",
 474                 "W83667DHG-P",
 475                 "W83667HG-B",
 476                 "NCT6775",
 477                 "NCT6776",
 478                 "NCT6779",
 479                 "NCT6791",
 480                 "NCT6792",
 481                 "NCT6793",
 482                 "NCT6795",
 483                 "NCT6796",
 484                 "NCT6102",
 485         };
 486 
 487         /* Apply system-specific quirks */
 488         dmi_check_system(wdt_dmi_table);
 489 
 490         wdt_io = 0x2e;
 491         chip = wdt_find(0x2e);
 492         if (chip < 0) {
 493                 wdt_io = 0x4e;
 494                 chip = wdt_find(0x4e);
 495                 if (chip < 0)
 496                         return chip;
 497         }
 498 
 499         pr_info("WDT driver for %s Super I/O chip initialising\n",
 500                 chip_name[chip]);
 501 
 502         watchdog_init_timeout(&wdt_dev, timeout, NULL);
 503         watchdog_set_nowayout(&wdt_dev, nowayout);
 504         watchdog_stop_on_reboot(&wdt_dev);
 505 
 506         ret = w83627hf_init(&wdt_dev, chip);
 507         if (ret) {
 508                 pr_err("failed to initialize watchdog (err=%d)\n", ret);
 509                 return ret;
 510         }
 511 
 512         ret = watchdog_register_device(&wdt_dev);
 513         if (ret)
 514                 return ret;
 515 
 516         pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
 517                 wdt_dev.timeout, nowayout);
 518 
 519         return ret;
 520 }
 521 
 522 static void __exit wdt_exit(void)
 523 {
 524         watchdog_unregister_device(&wdt_dev);
 525 }
 526 
 527 module_init(wdt_init);
 528 module_exit(wdt_exit);
 529 
 530 MODULE_LICENSE("GPL");
 531 MODULE_AUTHOR("Pádraig  Brady <P@draigBrady.com>");
 532 MODULE_DESCRIPTION("w83627hf/thf WDT driver");

/* [<][>][^][v][top][bottom][index][help] */