0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0029
0030 #include <linux/module.h>
0031 #include <linux/moduleparam.h>
0032 #include <linux/types.h>
0033 #include <linux/watchdog.h>
0034 #include <linux/ioport.h>
0035 #include <linux/init.h>
0036 #include <linux/io.h>
0037 #include <linux/dmi.h>
0038
0039 #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
0040 #define WATCHDOG_TIMEOUT 60
0041
0042 static int wdt_io;
0043 static int cr_wdt_timeout;
0044 static int cr_wdt_control;
0045 static int cr_wdt_csr;
0046 static int wdt_cfg_enter = 0x87;
0047 static int wdt_cfg_leave = 0xAA;
0048
0049 enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
0050 w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p,
0051 w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792, nct6793,
0052 nct6795, nct6796, nct6102, nct6116 };
0053
0054 static int timeout;
0055 module_param(timeout, int, 0);
0056 MODULE_PARM_DESC(timeout,
0057 "Watchdog timeout in seconds. 1 <= timeout <= 255, default="
0058 __MODULE_STRING(WATCHDOG_TIMEOUT) ".");
0059
0060 static bool nowayout = WATCHDOG_NOWAYOUT;
0061 module_param(nowayout, bool, 0);
0062 MODULE_PARM_DESC(nowayout,
0063 "Watchdog cannot be stopped once started (default="
0064 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0065
0066 static int early_disable;
0067 module_param(early_disable, int, 0);
0068 MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)");
0069
0070
0071
0072
0073
0074 #define WDT_EFER (wdt_io+0)
0075 #define WDT_EFIR (wdt_io+0)
0076
0077 #define WDT_EFDR (WDT_EFIR+1)
0078
0079 #define W83627HF_LD_WDT 0x08
0080
0081 #define W83627HF_ID 0x52
0082 #define W83627S_ID 0x59
0083 #define W83697HF_ID 0x60
0084 #define W83697UG_ID 0x68
0085 #define W83637HF_ID 0x70
0086 #define W83627THF_ID 0x82
0087 #define W83687THF_ID 0x85
0088 #define W83627EHF_ID 0x88
0089 #define W83627DHG_ID 0xa0
0090 #define W83627UHG_ID 0xa2
0091 #define W83667HG_ID 0xa5
0092 #define W83627DHG_P_ID 0xb0
0093 #define W83667HG_B_ID 0xb3
0094 #define NCT6775_ID 0xb4
0095 #define NCT6776_ID 0xc3
0096 #define NCT6102_ID 0xc4
0097 #define NCT6116_ID 0xd2
0098 #define NCT6779_ID 0xc5
0099 #define NCT6791_ID 0xc8
0100 #define NCT6792_ID 0xc9
0101 #define NCT6793_ID 0xd1
0102 #define NCT6795_ID 0xd3
0103 #define NCT6796_ID 0xd4
0104
0105 #define W83627HF_WDT_TIMEOUT 0xf6
0106 #define W83697HF_WDT_TIMEOUT 0xf4
0107 #define NCT6102D_WDT_TIMEOUT 0xf1
0108
0109 #define W83627HF_WDT_CONTROL 0xf5
0110 #define W83697HF_WDT_CONTROL 0xf3
0111 #define NCT6102D_WDT_CONTROL 0xf0
0112
0113 #define W836X7HF_WDT_CSR 0xf7
0114 #define NCT6102D_WDT_CSR 0xf2
0115
0116 static void superio_outb(int reg, int val)
0117 {
0118 outb(reg, WDT_EFER);
0119 outb(val, WDT_EFDR);
0120 }
0121
0122 static inline int superio_inb(int reg)
0123 {
0124 outb(reg, WDT_EFER);
0125 return inb(WDT_EFDR);
0126 }
0127
0128 static int superio_enter(void)
0129 {
0130 if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME))
0131 return -EBUSY;
0132
0133 outb_p(wdt_cfg_enter, WDT_EFER);
0134 outb_p(wdt_cfg_enter, WDT_EFER);
0135
0136 return 0;
0137 }
0138
0139 static void superio_select(int ld)
0140 {
0141 superio_outb(0x07, ld);
0142 }
0143
0144 static void superio_exit(void)
0145 {
0146 outb_p(wdt_cfg_leave, WDT_EFER);
0147 release_region(wdt_io, 2);
0148 }
0149
0150 static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
0151 {
0152 int ret;
0153 unsigned char t;
0154
0155 ret = superio_enter();
0156 if (ret)
0157 return ret;
0158
0159 superio_select(W83627HF_LD_WDT);
0160
0161
0162 t = superio_inb(0x30);
0163 if (!(t & 0x01))
0164 superio_outb(0x30, t | 0x01);
0165
0166 switch (chip) {
0167 case w83627hf:
0168 case w83627s:
0169 t = superio_inb(0x2B) & ~0x10;
0170 superio_outb(0x2B, t);
0171 break;
0172 case w83697hf:
0173
0174 t = superio_inb(0x29) & ~0x60;
0175 t |= 0x20;
0176 superio_outb(0x29, t);
0177 break;
0178 case w83697ug:
0179
0180 t = superio_inb(0x2b) & ~0x04;
0181 superio_outb(0x2b, t);
0182 break;
0183 case w83627thf:
0184 t = (superio_inb(0x2B) & ~0x08) | 0x04;
0185 superio_outb(0x2B, t);
0186 break;
0187 case w83627dhg:
0188 case w83627dhg_p:
0189 t = superio_inb(0x2D) & ~0x01;
0190 superio_outb(0x2D, t);
0191 t = superio_inb(cr_wdt_control);
0192 t |= 0x02;
0193
0194 superio_outb(cr_wdt_control, t);
0195 break;
0196 case w83637hf:
0197 break;
0198 case w83687thf:
0199 t = superio_inb(0x2C) & ~0x80;
0200 superio_outb(0x2C, t);
0201 break;
0202 case w83627ehf:
0203 case w83627uhg:
0204 case w83667hg:
0205 case w83667hg_b:
0206 case nct6775:
0207 case nct6776:
0208 case nct6779:
0209 case nct6791:
0210 case nct6792:
0211 case nct6793:
0212 case nct6795:
0213 case nct6796:
0214 case nct6102:
0215 case nct6116:
0216
0217
0218
0219
0220
0221
0222 t = superio_inb(cr_wdt_control);
0223 t |= 0x02;
0224
0225 superio_outb(cr_wdt_control, t);
0226 break;
0227 default:
0228 break;
0229 }
0230
0231 t = superio_inb(cr_wdt_timeout);
0232 if (t != 0) {
0233 if (early_disable) {
0234 pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
0235 superio_outb(cr_wdt_timeout, 0);
0236 } else {
0237 pr_info("Watchdog already running. Resetting timeout to %d sec\n",
0238 wdog->timeout);
0239 superio_outb(cr_wdt_timeout, wdog->timeout);
0240 }
0241 }
0242
0243
0244 t = superio_inb(cr_wdt_control) & ~0x0C;
0245 superio_outb(cr_wdt_control, t);
0246
0247
0248 t = superio_inb(cr_wdt_csr) & ~0xD0;
0249 superio_outb(cr_wdt_csr, t);
0250
0251 superio_exit();
0252
0253 return 0;
0254 }
0255
0256 static int wdt_set_time(unsigned int timeout)
0257 {
0258 int ret;
0259
0260 ret = superio_enter();
0261 if (ret)
0262 return ret;
0263
0264 superio_select(W83627HF_LD_WDT);
0265 superio_outb(cr_wdt_timeout, timeout);
0266 superio_exit();
0267
0268 return 0;
0269 }
0270
0271 static int wdt_start(struct watchdog_device *wdog)
0272 {
0273 return wdt_set_time(wdog->timeout);
0274 }
0275
0276 static int wdt_stop(struct watchdog_device *wdog)
0277 {
0278 return wdt_set_time(0);
0279 }
0280
0281 static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout)
0282 {
0283 wdog->timeout = timeout;
0284
0285 return 0;
0286 }
0287
0288 static unsigned int wdt_get_time(struct watchdog_device *wdog)
0289 {
0290 unsigned int timeleft;
0291 int ret;
0292
0293 ret = superio_enter();
0294 if (ret)
0295 return 0;
0296
0297 superio_select(W83627HF_LD_WDT);
0298 timeleft = superio_inb(cr_wdt_timeout);
0299 superio_exit();
0300
0301 return timeleft;
0302 }
0303
0304
0305
0306
0307
0308 static const struct watchdog_info wdt_info = {
0309 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
0310 .identity = "W83627HF Watchdog",
0311 };
0312
0313 static const struct watchdog_ops wdt_ops = {
0314 .owner = THIS_MODULE,
0315 .start = wdt_start,
0316 .stop = wdt_stop,
0317 .set_timeout = wdt_set_timeout,
0318 .get_timeleft = wdt_get_time,
0319 };
0320
0321 static struct watchdog_device wdt_dev = {
0322 .info = &wdt_info,
0323 .ops = &wdt_ops,
0324 .timeout = WATCHDOG_TIMEOUT,
0325 .min_timeout = 1,
0326 .max_timeout = 255,
0327 };
0328
0329
0330
0331
0332
0333
0334 static int wdt_find(int addr)
0335 {
0336 u8 val;
0337 int ret;
0338
0339 cr_wdt_timeout = W83627HF_WDT_TIMEOUT;
0340 cr_wdt_control = W83627HF_WDT_CONTROL;
0341 cr_wdt_csr = W836X7HF_WDT_CSR;
0342
0343 ret = superio_enter();
0344 if (ret)
0345 return ret;
0346 superio_select(W83627HF_LD_WDT);
0347 val = superio_inb(0x20);
0348 switch (val) {
0349 case W83627HF_ID:
0350 ret = w83627hf;
0351 break;
0352 case W83627S_ID:
0353 ret = w83627s;
0354 break;
0355 case W83697HF_ID:
0356 ret = w83697hf;
0357 cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
0358 cr_wdt_control = W83697HF_WDT_CONTROL;
0359 break;
0360 case W83697UG_ID:
0361 ret = w83697ug;
0362 cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
0363 cr_wdt_control = W83697HF_WDT_CONTROL;
0364 break;
0365 case W83637HF_ID:
0366 ret = w83637hf;
0367 break;
0368 case W83627THF_ID:
0369 ret = w83627thf;
0370 break;
0371 case W83687THF_ID:
0372 ret = w83687thf;
0373 break;
0374 case W83627EHF_ID:
0375 ret = w83627ehf;
0376 break;
0377 case W83627DHG_ID:
0378 ret = w83627dhg;
0379 break;
0380 case W83627DHG_P_ID:
0381 ret = w83627dhg_p;
0382 break;
0383 case W83627UHG_ID:
0384 ret = w83627uhg;
0385 break;
0386 case W83667HG_ID:
0387 ret = w83667hg;
0388 break;
0389 case W83667HG_B_ID:
0390 ret = w83667hg_b;
0391 break;
0392 case NCT6775_ID:
0393 ret = nct6775;
0394 break;
0395 case NCT6776_ID:
0396 ret = nct6776;
0397 break;
0398 case NCT6779_ID:
0399 ret = nct6779;
0400 break;
0401 case NCT6791_ID:
0402 ret = nct6791;
0403 break;
0404 case NCT6792_ID:
0405 ret = nct6792;
0406 break;
0407 case NCT6793_ID:
0408 ret = nct6793;
0409 break;
0410 case NCT6795_ID:
0411 ret = nct6795;
0412 break;
0413 case NCT6796_ID:
0414 ret = nct6796;
0415 break;
0416 case NCT6102_ID:
0417 ret = nct6102;
0418 cr_wdt_timeout = NCT6102D_WDT_TIMEOUT;
0419 cr_wdt_control = NCT6102D_WDT_CONTROL;
0420 cr_wdt_csr = NCT6102D_WDT_CSR;
0421 break;
0422 case NCT6116_ID:
0423 ret = nct6116;
0424 cr_wdt_timeout = NCT6102D_WDT_TIMEOUT;
0425 cr_wdt_control = NCT6102D_WDT_CONTROL;
0426 cr_wdt_csr = NCT6102D_WDT_CSR;
0427 break;
0428 case 0xff:
0429 ret = -ENODEV;
0430 break;
0431 default:
0432 ret = -ENODEV;
0433 pr_err("Unsupported chip ID: 0x%02x\n", val);
0434 break;
0435 }
0436 superio_exit();
0437 return ret;
0438 }
0439
0440
0441
0442
0443
0444
0445 static int __init wdt_use_alt_key(const struct dmi_system_id *d)
0446 {
0447 wdt_cfg_enter = 0x88;
0448 wdt_cfg_leave = 0xBB;
0449
0450 return 0;
0451 }
0452
0453 static const struct dmi_system_id wdt_dmi_table[] __initconst = {
0454 {
0455 .matches = {
0456 DMI_EXACT_MATCH(DMI_SYS_VENDOR, "INVES"),
0457 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CTS"),
0458 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "INVES"),
0459 DMI_EXACT_MATCH(DMI_BOARD_NAME, "SHARKBAY"),
0460 },
0461 .callback = wdt_use_alt_key,
0462 },
0463 {}
0464 };
0465
0466 static int __init wdt_init(void)
0467 {
0468 int ret;
0469 int chip;
0470 static const char * const chip_name[] = {
0471 "W83627HF",
0472 "W83627S",
0473 "W83697HF",
0474 "W83697UG",
0475 "W83637HF",
0476 "W83627THF",
0477 "W83687THF",
0478 "W83627EHF",
0479 "W83627DHG",
0480 "W83627UHG",
0481 "W83667HG",
0482 "W83667DHG-P",
0483 "W83667HG-B",
0484 "NCT6775",
0485 "NCT6776",
0486 "NCT6779",
0487 "NCT6791",
0488 "NCT6792",
0489 "NCT6793",
0490 "NCT6795",
0491 "NCT6796",
0492 "NCT6102",
0493 "NCT6116",
0494 };
0495
0496
0497 dmi_check_system(wdt_dmi_table);
0498
0499 wdt_io = 0x2e;
0500 chip = wdt_find(0x2e);
0501 if (chip < 0) {
0502 wdt_io = 0x4e;
0503 chip = wdt_find(0x4e);
0504 if (chip < 0)
0505 return chip;
0506 }
0507
0508 pr_info("WDT driver for %s Super I/O chip initialising\n",
0509 chip_name[chip]);
0510
0511 watchdog_init_timeout(&wdt_dev, timeout, NULL);
0512 watchdog_set_nowayout(&wdt_dev, nowayout);
0513 watchdog_stop_on_reboot(&wdt_dev);
0514
0515 ret = w83627hf_init(&wdt_dev, chip);
0516 if (ret) {
0517 pr_err("failed to initialize watchdog (err=%d)\n", ret);
0518 return ret;
0519 }
0520
0521 ret = watchdog_register_device(&wdt_dev);
0522 if (ret)
0523 return ret;
0524
0525 pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
0526 wdt_dev.timeout, nowayout);
0527
0528 return ret;
0529 }
0530
0531 static void __exit wdt_exit(void)
0532 {
0533 watchdog_unregister_device(&wdt_dev);
0534 }
0535
0536 module_init(wdt_init);
0537 module_exit(wdt_exit);
0538
0539 MODULE_LICENSE("GPL");
0540 MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>");
0541 MODULE_DESCRIPTION("w83627hf/thf WDT driver");