0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010
0011 #include <linux/err.h>
0012 #include <linux/init.h>
0013 #include <linux/io.h>
0014 #include <linux/ioport.h>
0015 #include <linux/module.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/watchdog.h>
0018
0019 #define DRVNAME "f71808e_wdt"
0020
0021 #define SIO_F71808FG_LD_WDT 0x07
0022 #define SIO_UNLOCK_KEY 0x87
0023 #define SIO_LOCK_KEY 0xAA
0024
0025 #define SIO_REG_LDSEL 0x07
0026 #define SIO_REG_DEVID 0x20
0027 #define SIO_REG_DEVREV 0x22
0028 #define SIO_REG_MANID 0x23
0029 #define SIO_REG_CLOCK_SEL 0x26
0030 #define SIO_REG_ROM_ADDR_SEL 0x27
0031 #define SIO_F81866_REG_PORT_SEL 0x27
0032 #define SIO_REG_TSI_LEVEL_SEL 0x28
0033 #define SIO_REG_MFUNCT1 0x29
0034 #define SIO_REG_MFUNCT2 0x2a
0035 #define SIO_REG_MFUNCT3 0x2b
0036 #define SIO_F81866_REG_GPIO1 0x2c
0037 #define SIO_REG_ENABLE 0x30
0038 #define SIO_REG_ADDR 0x60
0039
0040 #define SIO_FINTEK_ID 0x1934
0041 #define SIO_F71808_ID 0x0901
0042 #define SIO_F71858_ID 0x0507
0043 #define SIO_F71862_ID 0x0601
0044 #define SIO_F71868_ID 0x1106
0045 #define SIO_F71869_ID 0x0814
0046 #define SIO_F71869A_ID 0x1007
0047 #define SIO_F71882_ID 0x0541
0048 #define SIO_F71889_ID 0x0723
0049 #define SIO_F81803_ID 0x1210
0050 #define SIO_F81865_ID 0x0704
0051 #define SIO_F81866_ID 0x1010
0052 #define SIO_F81966_ID 0x1502
0053
0054 #define F71808FG_REG_WDO_CONF 0xf0
0055 #define F71808FG_REG_WDT_CONF 0xf5
0056 #define F71808FG_REG_WD_TIME 0xf6
0057
0058 #define F71808FG_FLAG_WDOUT_EN 7
0059
0060 #define F71808FG_FLAG_WDTMOUT_STS 6
0061 #define F71808FG_FLAG_WD_EN 5
0062 #define F71808FG_FLAG_WD_PULSE 4
0063 #define F71808FG_FLAG_WD_UNIT 3
0064
0065 #define F81865_REG_WDO_CONF 0xfa
0066 #define F81865_FLAG_WDOUT_EN 0
0067
0068
0069 #define WATCHDOG_TIMEOUT 60
0070 #define WATCHDOG_MAX_TIMEOUT (60 * 255)
0071 #define WATCHDOG_PULSE_WIDTH 125
0072
0073 #define WATCHDOG_F71862FG_PIN 63
0074
0075
0076 static unsigned short force_id;
0077 module_param(force_id, ushort, 0);
0078 MODULE_PARM_DESC(force_id, "Override the detected device ID");
0079
0080 static int timeout = WATCHDOG_TIMEOUT;
0081 module_param(timeout, int, 0);
0082 MODULE_PARM_DESC(timeout,
0083 "Watchdog timeout in seconds. 1<= timeout <="
0084 __MODULE_STRING(WATCHDOG_MAX_TIMEOUT) " (default="
0085 __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
0086
0087 static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH;
0088 module_param(pulse_width, uint, 0);
0089 MODULE_PARM_DESC(pulse_width,
0090 "Watchdog signal pulse width. 0(=level), 1, 25, 30, 125, 150, 5000 or 6000 ms"
0091 " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
0092
0093 static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
0094 module_param(f71862fg_pin, uint, 0);
0095 MODULE_PARM_DESC(f71862fg_pin,
0096 "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63"
0097 " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")");
0098
0099 static bool nowayout = WATCHDOG_NOWAYOUT;
0100 module_param(nowayout, bool, 0444);
0101 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
0102
0103 static unsigned int start_withtimeout;
0104 module_param(start_withtimeout, uint, 0);
0105 MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
0106 " given initial timeout. Zero (default) disables this feature.");
0107
0108 enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg,
0109 f81803, f81865, f81866, f81966};
0110
0111 static const char * const fintek_wdt_names[] = {
0112 "f71808fg",
0113 "f71858fg",
0114 "f71862fg",
0115 "f71868",
0116 "f71869",
0117 "f71882fg",
0118 "f71889fg",
0119 "f81803",
0120 "f81865",
0121 "f81866",
0122 "f81966"
0123 };
0124
0125
0126 static inline int superio_inb(int base, int reg);
0127 static inline int superio_inw(int base, int reg);
0128 static inline void superio_outb(int base, int reg, u8 val);
0129 static inline void superio_set_bit(int base, int reg, int bit);
0130 static inline void superio_clear_bit(int base, int reg, int bit);
0131 static inline int superio_enter(int base);
0132 static inline void superio_select(int base, int ld);
0133 static inline void superio_exit(int base);
0134
0135 struct fintek_wdt {
0136 struct watchdog_device wdd;
0137 unsigned short sioaddr;
0138 enum chips type;
0139 struct watchdog_info ident;
0140
0141 u8 timer_val;
0142 char minutes_mode;
0143 u8 pulse_val;
0144 char pulse_mode;
0145 };
0146
0147 struct fintek_wdt_pdata {
0148 enum chips type;
0149 };
0150
0151
0152 static inline int superio_inb(int base, int reg)
0153 {
0154 outb(reg, base);
0155 return inb(base + 1);
0156 }
0157
0158 static int superio_inw(int base, int reg)
0159 {
0160 int val;
0161 val = superio_inb(base, reg) << 8;
0162 val |= superio_inb(base, reg + 1);
0163 return val;
0164 }
0165
0166 static inline void superio_outb(int base, int reg, u8 val)
0167 {
0168 outb(reg, base);
0169 outb(val, base + 1);
0170 }
0171
0172 static inline void superio_set_bit(int base, int reg, int bit)
0173 {
0174 unsigned long val = superio_inb(base, reg);
0175 __set_bit(bit, &val);
0176 superio_outb(base, reg, val);
0177 }
0178
0179 static inline void superio_clear_bit(int base, int reg, int bit)
0180 {
0181 unsigned long val = superio_inb(base, reg);
0182 __clear_bit(bit, &val);
0183 superio_outb(base, reg, val);
0184 }
0185
0186 static inline int superio_enter(int base)
0187 {
0188
0189 if (!request_muxed_region(base, 2, DRVNAME)) {
0190 pr_err("I/O address 0x%04x already in use\n", (int)base);
0191 return -EBUSY;
0192 }
0193
0194
0195 outb(SIO_UNLOCK_KEY, base);
0196 outb(SIO_UNLOCK_KEY, base);
0197
0198 return 0;
0199 }
0200
0201 static inline void superio_select(int base, int ld)
0202 {
0203 outb(SIO_REG_LDSEL, base);
0204 outb(ld, base + 1);
0205 }
0206
0207 static inline void superio_exit(int base)
0208 {
0209 outb(SIO_LOCK_KEY, base);
0210 release_region(base, 2);
0211 }
0212
0213 static int fintek_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
0214 {
0215 struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
0216
0217 if (timeout > 0xff) {
0218 wd->timer_val = DIV_ROUND_UP(timeout, 60);
0219 wd->minutes_mode = true;
0220 timeout = wd->timer_val * 60;
0221 } else {
0222 wd->timer_val = timeout;
0223 wd->minutes_mode = false;
0224 }
0225
0226 wdd->timeout = timeout;
0227
0228 return 0;
0229 }
0230
0231 static int fintek_wdt_set_pulse_width(struct fintek_wdt *wd, unsigned int pw)
0232 {
0233 unsigned int t1 = 25, t2 = 125, t3 = 5000;
0234
0235 if (wd->type == f71868) {
0236 t1 = 30;
0237 t2 = 150;
0238 t3 = 6000;
0239 }
0240
0241 if (pw <= 1) {
0242 wd->pulse_val = 0;
0243 } else if (pw <= t1) {
0244 wd->pulse_val = 1;
0245 } else if (pw <= t2) {
0246 wd->pulse_val = 2;
0247 } else if (pw <= t3) {
0248 wd->pulse_val = 3;
0249 } else {
0250 pr_err("pulse width out of range\n");
0251 return -EINVAL;
0252 }
0253
0254 wd->pulse_mode = pw;
0255
0256 return 0;
0257 }
0258
0259 static int fintek_wdt_keepalive(struct watchdog_device *wdd)
0260 {
0261 struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
0262 int err;
0263
0264 err = superio_enter(wd->sioaddr);
0265 if (err)
0266 return err;
0267 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0268
0269 if (wd->minutes_mode)
0270
0271 superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0272 F71808FG_FLAG_WD_UNIT);
0273 else
0274
0275 superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0276 F71808FG_FLAG_WD_UNIT);
0277
0278
0279 superio_outb(wd->sioaddr, F71808FG_REG_WD_TIME,
0280 wd->timer_val);
0281
0282 superio_exit(wd->sioaddr);
0283
0284 return 0;
0285 }
0286
0287 static int fintek_wdt_start(struct watchdog_device *wdd)
0288 {
0289 struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
0290 int err;
0291 u8 tmp;
0292
0293
0294 err = fintek_wdt_keepalive(wdd);
0295 if (err)
0296 return err;
0297
0298 err = superio_enter(wd->sioaddr);
0299 if (err)
0300 return err;
0301 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0302
0303
0304 switch (wd->type) {
0305 case f71808fg:
0306
0307 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT2, 3);
0308 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 3);
0309 break;
0310
0311 case f71862fg:
0312 if (f71862fg_pin == 63) {
0313
0314 superio_clear_bit(wd->sioaddr, SIO_REG_ROM_ADDR_SEL, 6);
0315 superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT3, 4);
0316 } else if (f71862fg_pin == 56) {
0317 superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
0318 }
0319 break;
0320
0321 case f71868:
0322 case f71869:
0323
0324 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT1, 4);
0325 break;
0326
0327 case f71882fg:
0328
0329 superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
0330 break;
0331
0332 case f71889fg:
0333
0334 superio_outb(wd->sioaddr, SIO_REG_MFUNCT3,
0335 superio_inb(wd->sioaddr, SIO_REG_MFUNCT3) & 0xcf);
0336 break;
0337
0338 case f81803:
0339
0340 superio_clear_bit(wd->sioaddr, SIO_REG_CLOCK_SEL, 3);
0341
0342 superio_outb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL, 0x5f &
0343 superio_inb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL));
0344 break;
0345
0346 case f81865:
0347
0348 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 5);
0349 break;
0350
0351 case f81866:
0352 case f81966:
0353
0354
0355
0356
0357
0358
0359 tmp = superio_inb(wd->sioaddr, SIO_F81866_REG_PORT_SEL);
0360 tmp &= ~(BIT(3) | BIT(0));
0361 tmp |= BIT(2);
0362 superio_outb(wd->sioaddr, SIO_F81866_REG_PORT_SEL, tmp);
0363
0364 superio_clear_bit(wd->sioaddr, SIO_F81866_REG_GPIO1, 5);
0365 break;
0366
0367 default:
0368
0369
0370
0371
0372 err = -ENODEV;
0373 goto exit_superio;
0374 }
0375
0376 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0377 superio_set_bit(wd->sioaddr, SIO_REG_ENABLE, 0);
0378
0379 if (wd->type == f81865 || wd->type == f81866 || wd->type == f81966)
0380 superio_set_bit(wd->sioaddr, F81865_REG_WDO_CONF,
0381 F81865_FLAG_WDOUT_EN);
0382 else
0383 superio_set_bit(wd->sioaddr, F71808FG_REG_WDO_CONF,
0384 F71808FG_FLAG_WDOUT_EN);
0385
0386 superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0387 F71808FG_FLAG_WD_EN);
0388
0389 if (wd->pulse_mode) {
0390
0391 u8 wdt_conf = superio_inb(wd->sioaddr,
0392 F71808FG_REG_WDT_CONF);
0393
0394
0395 wdt_conf = (wdt_conf & 0xfc) | (wd->pulse_val & 0x03);
0396
0397 wdt_conf |= BIT(F71808FG_FLAG_WD_PULSE);
0398
0399 superio_outb(wd->sioaddr, F71808FG_REG_WDT_CONF,
0400 wdt_conf);
0401 } else {
0402
0403 superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0404 F71808FG_FLAG_WD_PULSE);
0405 }
0406
0407 exit_superio:
0408 superio_exit(wd->sioaddr);
0409
0410 return err;
0411 }
0412
0413 static int fintek_wdt_stop(struct watchdog_device *wdd)
0414 {
0415 struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
0416 int err;
0417
0418 err = superio_enter(wd->sioaddr);
0419 if (err)
0420 return err;
0421 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0422
0423 superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
0424 F71808FG_FLAG_WD_EN);
0425
0426 superio_exit(wd->sioaddr);
0427
0428 return 0;
0429 }
0430
0431 static bool fintek_wdt_is_running(struct fintek_wdt *wd, u8 wdt_conf)
0432 {
0433 return (superio_inb(wd->sioaddr, SIO_REG_ENABLE) & BIT(0))
0434 && (wdt_conf & BIT(F71808FG_FLAG_WD_EN));
0435 }
0436
0437 static const struct watchdog_ops fintek_wdt_ops = {
0438 .owner = THIS_MODULE,
0439 .start = fintek_wdt_start,
0440 .stop = fintek_wdt_stop,
0441 .ping = fintek_wdt_keepalive,
0442 .set_timeout = fintek_wdt_set_timeout,
0443 };
0444
0445 static int fintek_wdt_probe(struct platform_device *pdev)
0446 {
0447 struct device *dev = &pdev->dev;
0448 struct fintek_wdt_pdata *pdata;
0449 struct watchdog_device *wdd;
0450 struct fintek_wdt *wd;
0451 int wdt_conf, err = 0;
0452 struct resource *res;
0453 int sioaddr;
0454
0455 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
0456 if (!res)
0457 return -ENXIO;
0458
0459 sioaddr = res->start;
0460
0461 wd = devm_kzalloc(dev, sizeof(*wd), GFP_KERNEL);
0462 if (!wd)
0463 return -ENOMEM;
0464
0465 pdata = dev->platform_data;
0466
0467 wd->type = pdata->type;
0468 wd->sioaddr = sioaddr;
0469 wd->ident.options = WDIOF_SETTIMEOUT
0470 | WDIOF_MAGICCLOSE
0471 | WDIOF_KEEPALIVEPING
0472 | WDIOF_CARDRESET;
0473
0474 snprintf(wd->ident.identity,
0475 sizeof(wd->ident.identity), "%s watchdog",
0476 fintek_wdt_names[wd->type]);
0477
0478 err = superio_enter(sioaddr);
0479 if (err)
0480 return err;
0481 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
0482
0483 wdt_conf = superio_inb(sioaddr, F71808FG_REG_WDT_CONF);
0484
0485
0486
0487
0488
0489 superio_outb(sioaddr, F71808FG_REG_WDT_CONF,
0490 wdt_conf | BIT(F71808FG_FLAG_WDTMOUT_STS));
0491
0492 wdd = &wd->wdd;
0493
0494 if (fintek_wdt_is_running(wd, wdt_conf))
0495 set_bit(WDOG_HW_RUNNING, &wdd->status);
0496
0497 superio_exit(sioaddr);
0498
0499 wdd->parent = dev;
0500 wdd->info = &wd->ident;
0501 wdd->ops = &fintek_wdt_ops;
0502 wdd->min_timeout = 1;
0503 wdd->max_timeout = WATCHDOG_MAX_TIMEOUT;
0504
0505 watchdog_set_drvdata(wdd, wd);
0506 watchdog_set_nowayout(wdd, nowayout);
0507 watchdog_stop_on_unregister(wdd);
0508 watchdog_stop_on_reboot(wdd);
0509 watchdog_init_timeout(wdd, start_withtimeout ?: timeout, NULL);
0510
0511 if (wdt_conf & BIT(F71808FG_FLAG_WDTMOUT_STS))
0512 wdd->bootstatus = WDIOF_CARDRESET;
0513
0514
0515
0516
0517
0518
0519 fintek_wdt_set_timeout(wdd, wdd->timeout);
0520 fintek_wdt_set_pulse_width(wd, pulse_width);
0521
0522 if (start_withtimeout) {
0523 err = fintek_wdt_start(wdd);
0524 if (err) {
0525 dev_err(dev, "cannot start watchdog timer\n");
0526 return err;
0527 }
0528
0529 set_bit(WDOG_HW_RUNNING, &wdd->status);
0530 dev_info(dev, "watchdog started with initial timeout of %u sec\n",
0531 start_withtimeout);
0532 }
0533
0534 return devm_watchdog_register_device(dev, wdd);
0535 }
0536
0537 static int __init fintek_wdt_find(int sioaddr)
0538 {
0539 enum chips type;
0540 u16 devid;
0541 int err = superio_enter(sioaddr);
0542 if (err)
0543 return err;
0544
0545 devid = superio_inw(sioaddr, SIO_REG_MANID);
0546 if (devid != SIO_FINTEK_ID) {
0547 pr_debug("Not a Fintek device\n");
0548 err = -ENODEV;
0549 goto exit;
0550 }
0551
0552 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
0553 switch (devid) {
0554 case SIO_F71808_ID:
0555 type = f71808fg;
0556 break;
0557 case SIO_F71862_ID:
0558 type = f71862fg;
0559 break;
0560 case SIO_F71868_ID:
0561 type = f71868;
0562 break;
0563 case SIO_F71869_ID:
0564 case SIO_F71869A_ID:
0565 type = f71869;
0566 break;
0567 case SIO_F71882_ID:
0568 type = f71882fg;
0569 break;
0570 case SIO_F71889_ID:
0571 type = f71889fg;
0572 break;
0573 case SIO_F71858_ID:
0574
0575 err = -ENODEV;
0576 goto exit;
0577 case SIO_F81803_ID:
0578 type = f81803;
0579 break;
0580 case SIO_F81865_ID:
0581 type = f81865;
0582 break;
0583 case SIO_F81866_ID:
0584 type = f81866;
0585 break;
0586 case SIO_F81966_ID:
0587 type = f81966;
0588 break;
0589 default:
0590 pr_info("Unrecognized Fintek device: %04x\n",
0591 (unsigned int)devid);
0592 err = -ENODEV;
0593 goto exit;
0594 }
0595
0596 pr_info("Found %s watchdog chip, revision %d\n",
0597 fintek_wdt_names[type],
0598 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
0599
0600 exit:
0601 superio_exit(sioaddr);
0602 return err ? err : type;
0603 }
0604
0605 static struct platform_driver fintek_wdt_driver = {
0606 .probe = fintek_wdt_probe,
0607 .driver = {
0608 .name = DRVNAME,
0609 },
0610 };
0611
0612 static struct platform_device *fintek_wdt_pdev;
0613
0614 static int __init fintek_wdt_init(void)
0615 {
0616 static const unsigned short addrs[] = { 0x2e, 0x4e };
0617 struct fintek_wdt_pdata pdata;
0618 struct resource wdt_res = {};
0619 int ret;
0620 int i;
0621
0622 if (f71862fg_pin != 63 && f71862fg_pin != 56) {
0623 pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin);
0624 return -EINVAL;
0625 }
0626
0627 for (i = 0; i < ARRAY_SIZE(addrs); i++) {
0628 ret = fintek_wdt_find(addrs[i]);
0629 if (ret >= 0)
0630 break;
0631 }
0632 if (i == ARRAY_SIZE(addrs))
0633 return ret;
0634
0635 pdata.type = ret;
0636
0637 ret = platform_driver_register(&fintek_wdt_driver);
0638 if (ret)
0639 return ret;
0640
0641 wdt_res.name = "superio port";
0642 wdt_res.flags = IORESOURCE_IO;
0643 wdt_res.start = addrs[i];
0644 wdt_res.end = addrs[i] + 1;
0645
0646 fintek_wdt_pdev = platform_device_register_resndata(NULL, DRVNAME, -1,
0647 &wdt_res, 1,
0648 &pdata, sizeof(pdata));
0649 if (IS_ERR(fintek_wdt_pdev)) {
0650 platform_driver_unregister(&fintek_wdt_driver);
0651 return PTR_ERR(fintek_wdt_pdev);
0652 }
0653
0654 return 0;
0655 }
0656
0657 static void __exit fintek_wdt_exit(void)
0658 {
0659 platform_device_unregister(fintek_wdt_pdev);
0660 platform_driver_unregister(&fintek_wdt_driver);
0661 }
0662
0663 MODULE_DESCRIPTION("F71808E Watchdog Driver");
0664 MODULE_AUTHOR("Giel van Schijndel <me@mortis.eu>");
0665 MODULE_LICENSE("GPL");
0666
0667 module_init(fintek_wdt_init);
0668 module_exit(fintek_wdt_exit);