linux/drivers/watchdog/w83627hf_wdt.c
<<
>>
Prefs
   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");
 542