1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /*************************************************************************** 3 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> * 4 * Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com> * 5 * Copyright (C) 2010 Giel van Schijndel <me@mortis.eu> * 6 * * 7 ***************************************************************************/ 8 9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 10 11 #include <linux/err.h> 12 #include <linux/init.h> 13 #include <linux/io.h> 14 #include <linux/ioport.h> 15 #include <linux/module.h> 16 #include <linux/platform_device.h> 17 #include <linux/watchdog.h> 18 19 #define DRVNAME "f71808e_wdt" 20 21 #define SIO_F71808FG_LD_WDT 0x07 /* Watchdog timer logical device */ 22 #define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ 23 #define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */ 24 25 #define SIO_REG_LDSEL 0x07 /* Logical device select */ 26 #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ 27 #define SIO_REG_DEVREV 0x22 /* Device revision */ 28 #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ 29 #define SIO_REG_CLOCK_SEL 0x26 /* Clock select */ 30 #define SIO_REG_ROM_ADDR_SEL 0x27 /* ROM address select */ 31 #define SIO_F81866_REG_PORT_SEL 0x27 /* F81866 Multi-Function Register */ 32 #define SIO_REG_TSI_LEVEL_SEL 0x28 /* TSI Level select */ 33 #define SIO_REG_MFUNCT1 0x29 /* Multi function select 1 */ 34 #define SIO_REG_MFUNCT2 0x2a /* Multi function select 2 */ 35 #define SIO_REG_MFUNCT3 0x2b /* Multi function select 3 */ 36 #define SIO_F81866_REG_GPIO1 0x2c /* F81866 GPIO1 Enable Register */ 37 #define SIO_REG_ENABLE 0x30 /* Logical device enable */ 38 #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ 39 40 #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ 41 #define SIO_F71808_ID 0x0901 /* Chipset ID */ 42 #define SIO_F71858_ID 0x0507 /* Chipset ID */ 43 #define SIO_F71862_ID 0x0601 /* Chipset ID */ 44 #define SIO_F71868_ID 0x1106 /* Chipset ID */ 45 #define SIO_F71869_ID 0x0814 /* Chipset ID */ 46 #define SIO_F71869A_ID 0x1007 /* Chipset ID */ 47 #define SIO_F71882_ID 0x0541 /* Chipset ID */ 48 #define SIO_F71889_ID 0x0723 /* Chipset ID */ 49 #define SIO_F81803_ID 0x1210 /* Chipset ID */ 50 #define SIO_F81865_ID 0x0704 /* Chipset ID */ 51 #define SIO_F81866_ID 0x1010 /* Chipset ID */ 52 53 #define F71808FG_REG_WDO_CONF 0xf0 54 #define F71808FG_REG_WDT_CONF 0xf5 55 #define F71808FG_REG_WD_TIME 0xf6 56 57 #define F71808FG_FLAG_WDOUT_EN 7 58 59 #define F71808FG_FLAG_WDTMOUT_STS 6 60 #define F71808FG_FLAG_WD_EN 5 61 #define F71808FG_FLAG_WD_PULSE 4 62 #define F71808FG_FLAG_WD_UNIT 3 63 64 #define F81865_REG_WDO_CONF 0xfa 65 #define F81865_FLAG_WDOUT_EN 0 66 67 /* Default values */ 68 #define WATCHDOG_TIMEOUT 60 /* 1 minute default timeout */ 69 #define WATCHDOG_MAX_TIMEOUT (60 * 255) 70 #define WATCHDOG_PULSE_WIDTH 125 /* 125 ms, default pulse width for 71 watchdog signal */ 72 #define WATCHDOG_F71862FG_PIN 63 /* default watchdog reset output 73 pin number 63 */ 74 75 static unsigned short force_id; 76 module_param(force_id, ushort, 0); 77 MODULE_PARM_DESC(force_id, "Override the detected device ID"); 78 79 static int timeout = WATCHDOG_TIMEOUT; /* default timeout in seconds */ 80 module_param(timeout, int, 0); 81 MODULE_PARM_DESC(timeout, 82 "Watchdog timeout in seconds. 1<= timeout <=" 83 __MODULE_STRING(WATCHDOG_MAX_TIMEOUT) " (default=" 84 __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); 85 86 static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH; 87 module_param(pulse_width, uint, 0); 88 MODULE_PARM_DESC(pulse_width, 89 "Watchdog signal pulse width. 0(=level), 1, 25, 30, 125, 150, 5000 or 6000 ms" 90 " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")"); 91 92 static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN; 93 module_param(f71862fg_pin, uint, 0); 94 MODULE_PARM_DESC(f71862fg_pin, 95 "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63" 96 " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")"); 97 98 static bool nowayout = WATCHDOG_NOWAYOUT; 99 module_param(nowayout, bool, 0444); 100 MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close"); 101 102 static unsigned int start_withtimeout; 103 module_param(start_withtimeout, uint, 0); 104 MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with" 105 " given initial timeout. Zero (default) disables this feature."); 106 107 enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg, 108 f81803, f81865, f81866}; 109 110 static const char * const fintek_wdt_names[] = { 111 "f71808fg", 112 "f71858fg", 113 "f71862fg", 114 "f71868", 115 "f71869", 116 "f71882fg", 117 "f71889fg", 118 "f81803", 119 "f81865", 120 "f81866", 121 }; 122 123 /* Super-I/O Function prototypes */ 124 static inline int superio_inb(int base, int reg); 125 static inline int superio_inw(int base, int reg); 126 static inline void superio_outb(int base, int reg, u8 val); 127 static inline void superio_set_bit(int base, int reg, int bit); 128 static inline void superio_clear_bit(int base, int reg, int bit); 129 static inline int superio_enter(int base); 130 static inline void superio_select(int base, int ld); 131 static inline void superio_exit(int base); 132 133 struct fintek_wdt { 134 struct watchdog_device wdd; 135 unsigned short sioaddr; 136 enum chips type; 137 struct watchdog_info ident; 138 139 u8 timer_val; /* content for the wd_time register */ 140 char minutes_mode; 141 u8 pulse_val; /* pulse width flag */ 142 char pulse_mode; /* enable pulse output mode? */ 143 }; 144 145 struct fintek_wdt_pdata { 146 enum chips type; 147 }; 148 149 /* Super I/O functions */ 150 static inline int superio_inb(int base, int reg) 151 { 152 outb(reg, base); 153 return inb(base + 1); 154 } 155 156 static int superio_inw(int base, int reg) 157 { 158 int val; 159 val = superio_inb(base, reg) << 8; 160 val |= superio_inb(base, reg + 1); 161 return val; 162 } 163 164 static inline void superio_outb(int base, int reg, u8 val) 165 { 166 outb(reg, base); 167 outb(val, base + 1); 168 } 169 170 static inline void superio_set_bit(int base, int reg, int bit) 171 { 172 unsigned long val = superio_inb(base, reg); 173 __set_bit(bit, &val); 174 superio_outb(base, reg, val); 175 } 176 177 static inline void superio_clear_bit(int base, int reg, int bit) 178 { 179 unsigned long val = superio_inb(base, reg); 180 __clear_bit(bit, &val); 181 superio_outb(base, reg, val); 182 } 183 184 static inline int superio_enter(int base) 185 { 186 /* Don't step on other drivers' I/O space by accident */ 187 if (!request_muxed_region(base, 2, DRVNAME)) { 188 pr_err("I/O address 0x%04x already in use\n", (int)base); 189 return -EBUSY; 190 } 191 192 /* according to the datasheet the key must be sent twice! */ 193 outb(SIO_UNLOCK_KEY, base); 194 outb(SIO_UNLOCK_KEY, base); 195 196 return 0; 197 } 198 199 static inline void superio_select(int base, int ld) 200 { 201 outb(SIO_REG_LDSEL, base); 202 outb(ld, base + 1); 203 } 204 205 static inline void superio_exit(int base) 206 { 207 outb(SIO_LOCK_KEY, base); 208 release_region(base, 2); 209 } 210 211 static int fintek_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout) 212 { 213 struct fintek_wdt *wd = watchdog_get_drvdata(wdd); 214 215 if (timeout > 0xff) { 216 wd->timer_val = DIV_ROUND_UP(timeout, 60); 217 wd->minutes_mode = true; 218 timeout = wd->timer_val * 60; 219 } else { 220 wd->timer_val = timeout; 221 wd->minutes_mode = false; 222 } 223 224 wdd->timeout = timeout; 225 226 return 0; 227 } 228 229 static int fintek_wdt_set_pulse_width(struct fintek_wdt *wd, unsigned int pw) 230 { 231 unsigned int t1 = 25, t2 = 125, t3 = 5000; 232 233 if (wd->type == f71868) { 234 t1 = 30; 235 t2 = 150; 236 t3 = 6000; 237 } 238 239 if (pw <= 1) { 240 wd->pulse_val = 0; 241 } else if (pw <= t1) { 242 wd->pulse_val = 1; 243 } else if (pw <= t2) { 244 wd->pulse_val = 2; 245 } else if (pw <= t3) { 246 wd->pulse_val = 3; 247 } else { 248 pr_err("pulse width out of range\n"); 249 return -EINVAL; 250 } 251 252 wd->pulse_mode = pw; 253 254 return 0; 255 } 256 257 static int fintek_wdt_keepalive(struct watchdog_device *wdd) 258 { 259 struct fintek_wdt *wd = watchdog_get_drvdata(wdd); 260 int err; 261 262 err = superio_enter(wd->sioaddr); 263 if (err) 264 return err; 265 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT); 266 267 if (wd->minutes_mode) 268 /* select minutes for timer units */ 269 superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF, 270 F71808FG_FLAG_WD_UNIT); 271 else 272 /* select seconds for timer units */ 273 superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF, 274 F71808FG_FLAG_WD_UNIT); 275 276 /* Set timer value */ 277 superio_outb(wd->sioaddr, F71808FG_REG_WD_TIME, 278 wd->timer_val); 279 280 superio_exit(wd->sioaddr); 281 282 return 0; 283 } 284 285 static int fintek_wdt_start(struct watchdog_device *wdd) 286 { 287 struct fintek_wdt *wd = watchdog_get_drvdata(wdd); 288 int err; 289 u8 tmp; 290 291 /* Make sure we don't die as soon as the watchdog is enabled below */ 292 err = fintek_wdt_keepalive(wdd); 293 if (err) 294 return err; 295 296 err = superio_enter(wd->sioaddr); 297 if (err) 298 return err; 299 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT); 300 301 /* Watchdog pin configuration */ 302 switch (wd->type) { 303 case f71808fg: 304 /* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */ 305 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT2, 3); 306 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 3); 307 break; 308 309 case f71862fg: 310 if (f71862fg_pin == 63) { 311 /* SPI must be disabled first to use this pin! */ 312 superio_clear_bit(wd->sioaddr, SIO_REG_ROM_ADDR_SEL, 6); 313 superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT3, 4); 314 } else if (f71862fg_pin == 56) { 315 superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1); 316 } 317 break; 318 319 case f71868: 320 case f71869: 321 /* GPIO14 --> WDTRST# */ 322 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT1, 4); 323 break; 324 325 case f71882fg: 326 /* Set pin 56 to WDTRST# */ 327 superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1); 328 break; 329 330 case f71889fg: 331 /* set pin 40 to WDTRST# */ 332 superio_outb(wd->sioaddr, SIO_REG_MFUNCT3, 333 superio_inb(wd->sioaddr, SIO_REG_MFUNCT3) & 0xcf); 334 break; 335 336 case f81803: 337 /* Enable TSI Level register bank */ 338 superio_clear_bit(wd->sioaddr, SIO_REG_CLOCK_SEL, 3); 339 /* Set pin 27 to WDTRST# */ 340 superio_outb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL, 0x5f & 341 superio_inb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL)); 342 break; 343 344 case f81865: 345 /* Set pin 70 to WDTRST# */ 346 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 5); 347 break; 348 349 case f81866: 350 /* 351 * GPIO1 Control Register when 27h BIT3:2 = 01 & BIT0 = 0. 352 * The PIN 70(GPIO15/WDTRST) is controlled by 2Ch: 353 * BIT5: 0 -> WDTRST# 354 * 1 -> GPIO15 355 */ 356 tmp = superio_inb(wd->sioaddr, SIO_F81866_REG_PORT_SEL); 357 tmp &= ~(BIT(3) | BIT(0)); 358 tmp |= BIT(2); 359 superio_outb(wd->sioaddr, SIO_F81866_REG_PORT_SEL, tmp); 360 361 superio_clear_bit(wd->sioaddr, SIO_F81866_REG_GPIO1, 5); 362 break; 363 364 default: 365 /* 366 * 'default' label to shut up the compiler and catch 367 * programmer errors 368 */ 369 err = -ENODEV; 370 goto exit_superio; 371 } 372 373 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT); 374 superio_set_bit(wd->sioaddr, SIO_REG_ENABLE, 0); 375 376 if (wd->type == f81865 || wd->type == f81866) 377 superio_set_bit(wd->sioaddr, F81865_REG_WDO_CONF, 378 F81865_FLAG_WDOUT_EN); 379 else 380 superio_set_bit(wd->sioaddr, F71808FG_REG_WDO_CONF, 381 F71808FG_FLAG_WDOUT_EN); 382 383 superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF, 384 F71808FG_FLAG_WD_EN); 385 386 if (wd->pulse_mode) { 387 /* Select "pulse" output mode with given duration */ 388 u8 wdt_conf = superio_inb(wd->sioaddr, 389 F71808FG_REG_WDT_CONF); 390 391 /* Set WD_PSWIDTH bits (1:0) */ 392 wdt_conf = (wdt_conf & 0xfc) | (wd->pulse_val & 0x03); 393 /* Set WD_PULSE to "pulse" mode */ 394 wdt_conf |= BIT(F71808FG_FLAG_WD_PULSE); 395 396 superio_outb(wd->sioaddr, F71808FG_REG_WDT_CONF, 397 wdt_conf); 398 } else { 399 /* Select "level" output mode */ 400 superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF, 401 F71808FG_FLAG_WD_PULSE); 402 } 403 404 exit_superio: 405 superio_exit(wd->sioaddr); 406 407 return err; 408 } 409 410 static int fintek_wdt_stop(struct watchdog_device *wdd) 411 { 412 struct fintek_wdt *wd = watchdog_get_drvdata(wdd); 413 int err; 414 415 err = superio_enter(wd->sioaddr); 416 if (err) 417 return err; 418 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT); 419 420 superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF, 421 F71808FG_FLAG_WD_EN); 422 423 superio_exit(wd->sioaddr); 424 425 return 0; 426 } 427 428 static bool fintek_wdt_is_running(struct fintek_wdt *wd, u8 wdt_conf) 429 { 430 return (superio_inb(wd->sioaddr, SIO_REG_ENABLE) & BIT(0)) 431 && (wdt_conf & BIT(F71808FG_FLAG_WD_EN)); 432 } 433 434 static const struct watchdog_ops fintek_wdt_ops = { 435 .owner = THIS_MODULE, 436 .start = fintek_wdt_start, 437 .stop = fintek_wdt_stop, 438 .ping = fintek_wdt_keepalive, 439 .set_timeout = fintek_wdt_set_timeout, 440 }; 441 442 static int fintek_wdt_probe(struct platform_device *pdev) 443 { 444 struct device *dev = &pdev->dev; 445 struct fintek_wdt_pdata *pdata; 446 struct watchdog_device *wdd; 447 struct fintek_wdt *wd; 448 int wdt_conf, err = 0; 449 struct resource *res; 450 int sioaddr; 451 452 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 453 if (!res) 454 return -ENXIO; 455 456 sioaddr = res->start; 457 458 wd = devm_kzalloc(dev, sizeof(*wd), GFP_KERNEL); 459 if (!wd) 460 return -ENOMEM; 461 462 pdata = dev->platform_data; 463 464 wd->type = pdata->type; 465 wd->sioaddr = sioaddr; 466 wd->ident.options = WDIOF_SETTIMEOUT 467 | WDIOF_MAGICCLOSE 468 | WDIOF_KEEPALIVEPING 469 | WDIOF_CARDRESET; 470 471 snprintf(wd->ident.identity, 472 sizeof(wd->ident.identity), "%s watchdog", 473 fintek_wdt_names[wd->type]); 474 475 err = superio_enter(sioaddr); 476 if (err) 477 return err; 478 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT); 479 480 wdt_conf = superio_inb(sioaddr, F71808FG_REG_WDT_CONF); 481 482 /* 483 * We don't want WDTMOUT_STS to stick around till regular reboot. 484 * Write 1 to the bit to clear it to zero. 485 */ 486 superio_outb(sioaddr, F71808FG_REG_WDT_CONF, 487 wdt_conf | BIT(F71808FG_FLAG_WDTMOUT_STS)); 488 489 wdd = &wd->wdd; 490 491 if (fintek_wdt_is_running(wd, wdt_conf)) 492 set_bit(WDOG_HW_RUNNING, &wdd->status); 493 494 superio_exit(sioaddr); 495 496 wdd->parent = dev; 497 wdd->info = &wd->ident; 498 wdd->ops = &fintek_wdt_ops; 499 wdd->min_timeout = 1; 500 wdd->max_timeout = WATCHDOG_MAX_TIMEOUT; 501 502 watchdog_set_drvdata(wdd, wd); 503 watchdog_set_nowayout(wdd, nowayout); 504 watchdog_stop_on_unregister(wdd); 505 watchdog_stop_on_reboot(wdd); 506 watchdog_init_timeout(wdd, start_withtimeout ?: timeout, NULL); 507 508 if (wdt_conf & BIT(F71808FG_FLAG_WDTMOUT_STS)) 509 wdd->bootstatus = WDIOF_CARDRESET; 510 511 /* 512 * WATCHDOG_HANDLE_BOOT_ENABLED can result in keepalive being directly 513 * called without a set_timeout before, so it needs to be done here 514 * unconditionally. 515 */ 516 fintek_wdt_set_timeout(wdd, wdd->timeout); 517 fintek_wdt_set_pulse_width(wd, pulse_width); 518 519 if (start_withtimeout) { 520 err = fintek_wdt_start(wdd); 521 if (err) { 522 dev_err(dev, "cannot start watchdog timer\n"); 523 return err; 524 } 525 526 set_bit(WDOG_HW_RUNNING, &wdd->status); 527 dev_info(dev, "watchdog started with initial timeout of %u sec\n", 528 start_withtimeout); 529 } 530 531 return devm_watchdog_register_device(dev, wdd); 532 } 533 534 static int __init fintek_wdt_find(int sioaddr) 535 { 536 enum chips type; 537 u16 devid; 538 int err = superio_enter(sioaddr); 539 if (err) 540 return err; 541 542 devid = superio_inw(sioaddr, SIO_REG_MANID); 543 if (devid != SIO_FINTEK_ID) { 544 pr_debug("Not a Fintek device\n"); 545 err = -ENODEV; 546 goto exit; 547 } 548 549 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); 550 switch (devid) { 551 case SIO_F71808_ID: 552 type = f71808fg; 553 break; 554 case SIO_F71862_ID: 555 type = f71862fg; 556 break; 557 case SIO_F71868_ID: 558 type = f71868; 559 break; 560 case SIO_F71869_ID: 561 case SIO_F71869A_ID: 562 type = f71869; 563 break; 564 case SIO_F71882_ID: 565 type = f71882fg; 566 break; 567 case SIO_F71889_ID: 568 type = f71889fg; 569 break; 570 case SIO_F71858_ID: 571 /* Confirmed (by datasheet) not to have a watchdog. */ 572 err = -ENODEV; 573 goto exit; 574 case SIO_F81803_ID: 575 type = f81803; 576 break; 577 case SIO_F81865_ID: 578 type = f81865; 579 break; 580 case SIO_F81866_ID: 581 type = f81866; 582 break; 583 default: 584 pr_info("Unrecognized Fintek device: %04x\n", 585 (unsigned int)devid); 586 err = -ENODEV; 587 goto exit; 588 } 589 590 pr_info("Found %s watchdog chip, revision %d\n", 591 fintek_wdt_names[type], 592 (int)superio_inb(sioaddr, SIO_REG_DEVREV)); 593 594 exit: 595 superio_exit(sioaddr); 596 return err ? err : type; 597 } 598 599 static struct platform_driver fintek_wdt_driver = { 600 .probe = fintek_wdt_probe, 601 .driver = { 602 .name = DRVNAME, 603 }, 604 }; 605 606 static struct platform_device *fintek_wdt_pdev; 607 608 static int __init fintek_wdt_init(void) 609 { 610 static const unsigned short addrs[] = { 0x2e, 0x4e }; 611 struct fintek_wdt_pdata pdata; 612 struct resource wdt_res = {}; 613 int ret; 614 int i; 615 616 if (f71862fg_pin != 63 && f71862fg_pin != 56) { 617 pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin); 618 return -EINVAL; 619 } 620 621 for (i = 0; i < ARRAY_SIZE(addrs); i++) { 622 ret = fintek_wdt_find(addrs[i]); 623 if (ret >= 0) 624 break; 625 } 626 if (i == ARRAY_SIZE(addrs)) 627 return ret; 628 629 pdata.type = ret; 630 631 platform_driver_register(&fintek_wdt_driver); 632 633 wdt_res.name = "superio port"; 634 wdt_res.flags = IORESOURCE_IO; 635 wdt_res.start = addrs[i]; 636 wdt_res.end = addrs[i] + 1; 637 638 fintek_wdt_pdev = platform_device_register_resndata(NULL, DRVNAME, -1, 639 &wdt_res, 1, 640 &pdata, sizeof(pdata)); 641 if (IS_ERR(fintek_wdt_pdev)) { 642 platform_driver_unregister(&fintek_wdt_driver); 643 return PTR_ERR(fintek_wdt_pdev); 644 } 645 646 return 0; 647 } 648 649 static void __exit fintek_wdt_exit(void) 650 { 651 platform_device_unregister(fintek_wdt_pdev); 652 platform_driver_unregister(&fintek_wdt_driver); 653 } 654 655 MODULE_DESCRIPTION("F71808E Watchdog Driver"); 656 MODULE_AUTHOR("Giel van Schijndel <me@mortis.eu>"); 657 MODULE_LICENSE("GPL"); 658 659 module_init(fintek_wdt_init); 660 module_exit(fintek_wdt_exit); 661