linux/drivers/watchdog/w83627hf_wdt.c
<<
>>
Prefs
   1/*
   2 *      w83627hf/thf WDT driver
   3 *
   4 *      (c) Copyright 2013 Guenter Roeck
   5 *              converted to watchdog infrastructure
   6 *
   7 *      (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
   8 *              added support for W83627THF.
   9 *
  10 *      (c) Copyright 2003,2007 Pádraig Brady <P@draigBrady.com>
  11 *
  12 *      Based on advantechwdt.c which is based on wdt.c.
  13 *      Original copyright messages:
  14 *
  15 *      (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
  16 *
  17 *      (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
  18 *                                              All Rights Reserved.
  19 *
  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 *      Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
  26 *      warranty for any of this software. This material is provided
  27 *      "AS-IS" and at no charge.
  28 *
  29 *      (c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
  30 */
  31
  32#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  33
  34#include <linux/module.h>
  35#include <linux/moduleparam.h>
  36#include <linux/types.h>
  37#include <linux/watchdog.h>
  38#include <linux/ioport.h>
  39#include <linux/init.h>
  40#include <linux/io.h>
  41
  42#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
  43#define WATCHDOG_TIMEOUT 60             /* 60 sec default timeout */
  44
  45static int wdt_io;
  46static int cr_wdt_timeout;      /* WDT timeout register */
  47static int cr_wdt_control;      /* WDT control register */
  48static int cr_wdt_csr;          /* WDT control & status register */
  49
  50enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
  51             w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p,
  52             w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792, nct6102 };
  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 NCT6779_ID              0xc5
  98#define NCT6791_ID              0xc8
  99#define NCT6792_ID              0xc9
 100
 101#define W83627HF_WDT_TIMEOUT    0xf6
 102#define W83697HF_WDT_TIMEOUT    0xf4
 103#define NCT6102D_WDT_TIMEOUT    0xf1
 104
 105#define W83627HF_WDT_CONTROL    0xf5
 106#define W83697HF_WDT_CONTROL    0xf3
 107#define NCT6102D_WDT_CONTROL    0xf0
 108
 109#define W836X7HF_WDT_CSR        0xf7
 110#define NCT6102D_WDT_CSR        0xf2
 111
 112static void superio_outb(int reg, int val)
 113{
 114        outb(reg, WDT_EFER);
 115        outb(val, WDT_EFDR);
 116}
 117
 118static inline int superio_inb(int reg)
 119{
 120        outb(reg, WDT_EFER);
 121        return inb(WDT_EFDR);
 122}
 123
 124static int superio_enter(void)
 125{
 126        if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME))
 127                return -EBUSY;
 128
 129        outb_p(0x87, WDT_EFER); /* Enter extended function mode */
 130        outb_p(0x87, WDT_EFER); /* Again according to manual */
 131
 132        return 0;
 133}
 134
 135static void superio_select(int ld)
 136{
 137        superio_outb(0x07, ld);
 138}
 139
 140static void superio_exit(void)
 141{
 142        outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
 143        release_region(wdt_io, 2);
 144}
 145
 146static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
 147{
 148        int ret;
 149        unsigned char t;
 150
 151        ret = superio_enter();
 152        if (ret)
 153                return ret;
 154
 155        superio_select(W83627HF_LD_WDT);
 156
 157        /* set CR30 bit 0 to activate GPIO2 */
 158        t = superio_inb(0x30);
 159        if (!(t & 0x01))
 160                superio_outb(0x30, t | 0x01);
 161
 162        switch (chip) {
 163        case w83627hf:
 164        case w83627s:
 165                t = superio_inb(0x2B) & ~0x10;
 166                superio_outb(0x2B, t); /* set GPIO24 to WDT0 */
 167                break;
 168        case w83697hf:
 169                /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
 170                t = superio_inb(0x29) & ~0x60;
 171                t |= 0x20;
 172                superio_outb(0x29, t);
 173                break;
 174        case w83697ug:
 175                /* Set pin 118 to WDTO# mode */
 176                t = superio_inb(0x2b) & ~0x04;
 177                superio_outb(0x2b, t);
 178                break;
 179        case w83627thf:
 180                t = (superio_inb(0x2B) & ~0x08) | 0x04;
 181                superio_outb(0x2B, t); /* set GPIO3 to WDT0 */
 182                break;
 183        case w83627dhg:
 184        case w83627dhg_p:
 185                t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */
 186                superio_outb(0x2D, t); /* set GPIO5 to WDT0 */
 187                t = superio_inb(cr_wdt_control);
 188                t |= 0x02;      /* enable the WDTO# output low pulse
 189                                 * to the KBRST# pin */
 190                superio_outb(cr_wdt_control, t);
 191                break;
 192        case w83637hf:
 193                break;
 194        case w83687thf:
 195                t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */
 196                superio_outb(0x2C, t);
 197                break;
 198        case w83627ehf:
 199        case w83627uhg:
 200        case w83667hg:
 201        case w83667hg_b:
 202        case nct6775:
 203        case nct6776:
 204        case nct6779:
 205        case nct6791:
 206        case nct6792:
 207        case nct6102:
 208                /*
 209                 * These chips have a fixed WDTO# output pin (W83627UHG),
 210                 * or support more than one WDTO# output pin.
 211                 * Don't touch its configuration, and hope the BIOS
 212                 * does the right thing.
 213                 */
 214                t = superio_inb(cr_wdt_control);
 215                t |= 0x02;      /* enable the WDTO# output low pulse
 216                                 * to the KBRST# pin */
 217                superio_outb(cr_wdt_control, t);
 218                break;
 219        default:
 220                break;
 221        }
 222
 223        t = superio_inb(cr_wdt_timeout);
 224        if (t != 0) {
 225                if (early_disable) {
 226                        pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
 227                        superio_outb(cr_wdt_timeout, 0);
 228                } else {
 229                        pr_info("Watchdog already running. Resetting timeout to %d sec\n",
 230                                wdog->timeout);
 231                        superio_outb(cr_wdt_timeout, wdog->timeout);
 232                }
 233        }
 234
 235        /* set second mode & disable keyboard turning off watchdog */
 236        t = superio_inb(cr_wdt_control) & ~0x0C;
 237        superio_outb(cr_wdt_control, t);
 238
 239        /* reset trigger, disable keyboard & mouse turning off watchdog */
 240        t = superio_inb(cr_wdt_csr) & ~0xD0;
 241        superio_outb(cr_wdt_csr, t);
 242
 243        superio_exit();
 244
 245        return 0;
 246}
 247
 248static int wdt_set_time(unsigned int timeout)
 249{
 250        int ret;
 251
 252        ret = superio_enter();
 253        if (ret)
 254                return ret;
 255
 256        superio_select(W83627HF_LD_WDT);
 257        superio_outb(cr_wdt_timeout, timeout);
 258        superio_exit();
 259
 260        return 0;
 261}
 262
 263static int wdt_start(struct watchdog_device *wdog)
 264{
 265        return wdt_set_time(wdog->timeout);
 266}
 267
 268static int wdt_stop(struct watchdog_device *wdog)
 269{
 270        return wdt_set_time(0);
 271}
 272
 273static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout)
 274{
 275        wdog->timeout = timeout;
 276
 277        return 0;
 278}
 279
 280static unsigned int wdt_get_time(struct watchdog_device *wdog)
 281{
 282        unsigned int timeleft;
 283        int ret;
 284
 285        ret = superio_enter();
 286        if (ret)
 287                return 0;
 288
 289        superio_select(W83627HF_LD_WDT);
 290        timeleft = superio_inb(cr_wdt_timeout);
 291        superio_exit();
 292
 293        return timeleft;
 294}
 295
 296/*
 297 *      Kernel Interfaces
 298 */
 299
 300static struct watchdog_info wdt_info = {
 301        .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
 302        .identity = "W83627HF Watchdog",
 303};
 304
 305static const struct watchdog_ops wdt_ops = {
 306        .owner = THIS_MODULE,
 307        .start = wdt_start,
 308        .stop = wdt_stop,
 309        .set_timeout = wdt_set_timeout,
 310        .get_timeleft = wdt_get_time,
 311};
 312
 313static struct watchdog_device wdt_dev = {
 314        .info = &wdt_info,
 315        .ops = &wdt_ops,
 316        .timeout = WATCHDOG_TIMEOUT,
 317        .min_timeout = 1,
 318        .max_timeout = 255,
 319};
 320
 321/*
 322 *      The WDT needs to learn about soft shutdowns in order to
 323 *      turn the timebomb registers off.
 324 */
 325
 326static int wdt_find(int addr)
 327{
 328        u8 val;
 329        int ret;
 330
 331        cr_wdt_timeout = W83627HF_WDT_TIMEOUT;
 332        cr_wdt_control = W83627HF_WDT_CONTROL;
 333        cr_wdt_csr = W836X7HF_WDT_CSR;
 334
 335        ret = superio_enter();
 336        if (ret)
 337                return ret;
 338        superio_select(W83627HF_LD_WDT);
 339        val = superio_inb(0x20);
 340        switch (val) {
 341        case W83627HF_ID:
 342                ret = w83627hf;
 343                break;
 344        case W83627S_ID:
 345                ret = w83627s;
 346                break;
 347        case W83697HF_ID:
 348                ret = w83697hf;
 349                cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
 350                cr_wdt_control = W83697HF_WDT_CONTROL;
 351                break;
 352        case W83697UG_ID:
 353                ret = w83697ug;
 354                cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
 355                cr_wdt_control = W83697HF_WDT_CONTROL;
 356                break;
 357        case W83637HF_ID:
 358                ret = w83637hf;
 359                break;
 360        case W83627THF_ID:
 361                ret = w83627thf;
 362                break;
 363        case W83687THF_ID:
 364                ret = w83687thf;
 365                break;
 366        case W83627EHF_ID:
 367                ret = w83627ehf;
 368                break;
 369        case W83627DHG_ID:
 370                ret = w83627dhg;
 371                break;
 372        case W83627DHG_P_ID:
 373                ret = w83627dhg_p;
 374                break;
 375        case W83627UHG_ID:
 376                ret = w83627uhg;
 377                break;
 378        case W83667HG_ID:
 379                ret = w83667hg;
 380                break;
 381        case W83667HG_B_ID:
 382                ret = w83667hg_b;
 383                break;
 384        case NCT6775_ID:
 385                ret = nct6775;
 386                break;
 387        case NCT6776_ID:
 388                ret = nct6776;
 389                break;
 390        case NCT6779_ID:
 391                ret = nct6779;
 392                break;
 393        case NCT6791_ID:
 394                ret = nct6791;
 395                break;
 396        case NCT6792_ID:
 397                ret = nct6792;
 398                break;
 399        case NCT6102_ID:
 400                ret = nct6102;
 401                cr_wdt_timeout = NCT6102D_WDT_TIMEOUT;
 402                cr_wdt_control = NCT6102D_WDT_CONTROL;
 403                cr_wdt_csr = NCT6102D_WDT_CSR;
 404                break;
 405        case 0xff:
 406                ret = -ENODEV;
 407                break;
 408        default:
 409                ret = -ENODEV;
 410                pr_err("Unsupported chip ID: 0x%02x\n", val);
 411                break;
 412        }
 413        superio_exit();
 414        return ret;
 415}
 416
 417static int __init wdt_init(void)
 418{
 419        int ret;
 420        int chip;
 421        const char * const chip_name[] = {
 422                "W83627HF",
 423                "W83627S",
 424                "W83697HF",
 425                "W83697UG",
 426                "W83637HF",
 427                "W83627THF",
 428                "W83687THF",
 429                "W83627EHF",
 430                "W83627DHG",
 431                "W83627UHG",
 432                "W83667HG",
 433                "W83667DHG-P",
 434                "W83667HG-B",
 435                "NCT6775",
 436                "NCT6776",
 437                "NCT6779",
 438                "NCT6791",
 439                "NCT6792",
 440                "NCT6102",
 441        };
 442
 443        wdt_io = 0x2e;
 444        chip = wdt_find(0x2e);
 445        if (chip < 0) {
 446                wdt_io = 0x4e;
 447                chip = wdt_find(0x4e);
 448                if (chip < 0)
 449                        return chip;
 450        }
 451
 452        pr_info("WDT driver for %s Super I/O chip initialising\n",
 453                chip_name[chip]);
 454
 455        watchdog_init_timeout(&wdt_dev, timeout, NULL);
 456        watchdog_set_nowayout(&wdt_dev, nowayout);
 457        watchdog_stop_on_reboot(&wdt_dev);
 458
 459        ret = w83627hf_init(&wdt_dev, chip);
 460        if (ret) {
 461                pr_err("failed to initialize watchdog (err=%d)\n", ret);
 462                return ret;
 463        }
 464
 465        ret = watchdog_register_device(&wdt_dev);
 466        if (ret)
 467                return ret;
 468
 469        pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
 470                wdt_dev.timeout, nowayout);
 471
 472        return ret;
 473}
 474
 475static void __exit wdt_exit(void)
 476{
 477        watchdog_unregister_device(&wdt_dev);
 478}
 479
 480module_init(wdt_init);
 481module_exit(wdt_exit);
 482
 483MODULE_LICENSE("GPL");
 484MODULE_AUTHOR("Pádraig  Brady <P@draigBrady.com>");
 485MODULE_DESCRIPTION("w83627hf/thf WDT driver");
 486