| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /*************************************************************************** |
|---|
| 2 | 3 | * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> * |
|---|
| 3 | 4 | * Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com> * |
|---|
| 4 | 5 | * Copyright (C) 2010 Giel van Schijndel <me@mortis.eu> * |
|---|
| 5 | 6 | * * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify * |
|---|
| 7 | | - * it under the terms of the GNU General Public License as published by * |
|---|
| 8 | | - * the Free Software Foundation; either version 2 of the License, or * |
|---|
| 9 | | - * (at your option) any later version. * |
|---|
| 10 | | - * * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, * |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of * |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
|---|
| 14 | | - * GNU General Public License for more details. * |
|---|
| 15 | | - * * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License * |
|---|
| 17 | | - * along with this program; if not, write to the * |
|---|
| 18 | | - * Free Software Foundation, Inc., * |
|---|
| 19 | | - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
|---|
| 20 | 7 | ***************************************************************************/ |
|---|
| 21 | 8 | |
|---|
| 22 | 9 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
|---|
| .. | .. |
|---|
| 44 | 31 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ |
|---|
| 45 | 32 | #define SIO_REG_DEVREV 0x22 /* Device revision */ |
|---|
| 46 | 33 | #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ |
|---|
| 34 | +#define SIO_REG_CLOCK_SEL 0x26 /* Clock select */ |
|---|
| 47 | 35 | #define SIO_REG_ROM_ADDR_SEL 0x27 /* ROM address select */ |
|---|
| 48 | 36 | #define SIO_F81866_REG_PORT_SEL 0x27 /* F81866 Multi-Function Register */ |
|---|
| 37 | +#define SIO_REG_TSI_LEVEL_SEL 0x28 /* TSI Level select */ |
|---|
| 49 | 38 | #define SIO_REG_MFUNCT1 0x29 /* Multi function select 1 */ |
|---|
| 50 | 39 | #define SIO_REG_MFUNCT2 0x2a /* Multi function select 2 */ |
|---|
| 51 | 40 | #define SIO_REG_MFUNCT3 0x2b /* Multi function select 3 */ |
|---|
| .. | .. |
|---|
| 62 | 51 | #define SIO_F71869A_ID 0x1007 /* Chipset ID */ |
|---|
| 63 | 52 | #define SIO_F71882_ID 0x0541 /* Chipset ID */ |
|---|
| 64 | 53 | #define SIO_F71889_ID 0x0723 /* Chipset ID */ |
|---|
| 54 | +#define SIO_F81803_ID 0x1210 /* Chipset ID */ |
|---|
| 65 | 55 | #define SIO_F81865_ID 0x0704 /* Chipset ID */ |
|---|
| 66 | 56 | #define SIO_F81866_ID 0x1010 /* Chipset ID */ |
|---|
| 67 | 57 | |
|---|
| .. | .. |
|---|
| 121 | 111 | " given initial timeout. Zero (default) disables this feature."); |
|---|
| 122 | 112 | |
|---|
| 123 | 113 | enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg, |
|---|
| 124 | | - f81865, f81866}; |
|---|
| 114 | + f81803, f81865, f81866}; |
|---|
| 125 | 115 | |
|---|
| 126 | 116 | static const char *f71808e_names[] = { |
|---|
| 127 | 117 | "f71808fg", |
|---|
| .. | .. |
|---|
| 131 | 121 | "f71869", |
|---|
| 132 | 122 | "f71882fg", |
|---|
| 133 | 123 | "f71889fg", |
|---|
| 124 | + "f81803", |
|---|
| 134 | 125 | "f81865", |
|---|
| 135 | 126 | "f81866", |
|---|
| 136 | 127 | }; |
|---|
| .. | .. |
|---|
| 317 | 308 | return err; |
|---|
| 318 | 309 | } |
|---|
| 319 | 310 | |
|---|
| 320 | | -static int f71862fg_pin_configure(unsigned short ioaddr) |
|---|
| 321 | | -{ |
|---|
| 322 | | - /* When ioaddr is non-zero the calling function has to take care of |
|---|
| 323 | | - mutex handling and superio preparation! */ |
|---|
| 324 | | - |
|---|
| 325 | | - if (f71862fg_pin == 63) { |
|---|
| 326 | | - if (ioaddr) { |
|---|
| 327 | | - /* SPI must be disabled first to use this pin! */ |
|---|
| 328 | | - superio_clear_bit(ioaddr, SIO_REG_ROM_ADDR_SEL, 6); |
|---|
| 329 | | - superio_set_bit(ioaddr, SIO_REG_MFUNCT3, 4); |
|---|
| 330 | | - } |
|---|
| 331 | | - } else if (f71862fg_pin == 56) { |
|---|
| 332 | | - if (ioaddr) |
|---|
| 333 | | - superio_set_bit(ioaddr, SIO_REG_MFUNCT1, 1); |
|---|
| 334 | | - } else { |
|---|
| 335 | | - pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin); |
|---|
| 336 | | - return -EINVAL; |
|---|
| 337 | | - } |
|---|
| 338 | | - return 0; |
|---|
| 339 | | -} |
|---|
| 340 | | - |
|---|
| 341 | 311 | static int watchdog_start(void) |
|---|
| 342 | 312 | { |
|---|
| 313 | + int err; |
|---|
| 314 | + u8 tmp; |
|---|
| 315 | + |
|---|
| 343 | 316 | /* Make sure we don't die as soon as the watchdog is enabled below */ |
|---|
| 344 | | - int err = watchdog_keepalive(); |
|---|
| 317 | + err = watchdog_keepalive(); |
|---|
| 345 | 318 | if (err) |
|---|
| 346 | 319 | return err; |
|---|
| 347 | 320 | |
|---|
| .. | .. |
|---|
| 360 | 333 | break; |
|---|
| 361 | 334 | |
|---|
| 362 | 335 | case f71862fg: |
|---|
| 363 | | - err = f71862fg_pin_configure(watchdog.sioaddr); |
|---|
| 364 | | - if (err) |
|---|
| 365 | | - goto exit_superio; |
|---|
| 336 | + if (f71862fg_pin == 63) { |
|---|
| 337 | + /* SPI must be disabled first to use this pin! */ |
|---|
| 338 | + superio_clear_bit(watchdog.sioaddr, SIO_REG_ROM_ADDR_SEL, 6); |
|---|
| 339 | + superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 4); |
|---|
| 340 | + } else if (f71862fg_pin == 56) { |
|---|
| 341 | + superio_set_bit(watchdog.sioaddr, SIO_REG_MFUNCT1, 1); |
|---|
| 342 | + } |
|---|
| 366 | 343 | break; |
|---|
| 367 | 344 | |
|---|
| 368 | 345 | case f71868: |
|---|
| .. | .. |
|---|
| 382 | 359 | superio_inb(watchdog.sioaddr, SIO_REG_MFUNCT3) & 0xcf); |
|---|
| 383 | 360 | break; |
|---|
| 384 | 361 | |
|---|
| 362 | + case f81803: |
|---|
| 363 | + /* Enable TSI Level register bank */ |
|---|
| 364 | + superio_clear_bit(watchdog.sioaddr, SIO_REG_CLOCK_SEL, 3); |
|---|
| 365 | + /* Set pin 27 to WDTRST# */ |
|---|
| 366 | + superio_outb(watchdog.sioaddr, SIO_REG_TSI_LEVEL_SEL, 0x5f & |
|---|
| 367 | + superio_inb(watchdog.sioaddr, SIO_REG_TSI_LEVEL_SEL)); |
|---|
| 368 | + break; |
|---|
| 369 | + |
|---|
| 385 | 370 | case f81865: |
|---|
| 386 | 371 | /* Set pin 70 to WDTRST# */ |
|---|
| 387 | 372 | superio_clear_bit(watchdog.sioaddr, SIO_REG_MFUNCT3, 5); |
|---|
| 388 | 373 | break; |
|---|
| 389 | 374 | |
|---|
| 390 | 375 | case f81866: |
|---|
| 391 | | - /* Set pin 70 to WDTRST# */ |
|---|
| 392 | | - superio_clear_bit(watchdog.sioaddr, SIO_F81866_REG_PORT_SEL, |
|---|
| 393 | | - BIT(3) | BIT(0)); |
|---|
| 394 | | - superio_set_bit(watchdog.sioaddr, SIO_F81866_REG_PORT_SEL, |
|---|
| 395 | | - BIT(2)); |
|---|
| 396 | 376 | /* |
|---|
| 397 | 377 | * GPIO1 Control Register when 27h BIT3:2 = 01 & BIT0 = 0. |
|---|
| 398 | 378 | * The PIN 70(GPIO15/WDTRST) is controlled by 2Ch: |
|---|
| 399 | 379 | * BIT5: 0 -> WDTRST# |
|---|
| 400 | 380 | * 1 -> GPIO15 |
|---|
| 401 | 381 | */ |
|---|
| 402 | | - superio_clear_bit(watchdog.sioaddr, SIO_F81866_REG_GPIO1, |
|---|
| 403 | | - BIT(5)); |
|---|
| 382 | + tmp = superio_inb(watchdog.sioaddr, SIO_F81866_REG_PORT_SEL); |
|---|
| 383 | + tmp &= ~(BIT(3) | BIT(0)); |
|---|
| 384 | + tmp |= BIT(2); |
|---|
| 385 | + superio_outb(watchdog.sioaddr, SIO_F81866_REG_PORT_SEL, tmp); |
|---|
| 386 | + |
|---|
| 387 | + superio_clear_bit(watchdog.sioaddr, SIO_F81866_REG_GPIO1, 5); |
|---|
| 404 | 388 | break; |
|---|
| 405 | 389 | |
|---|
| 406 | 390 | default: |
|---|
| .. | .. |
|---|
| 527 | 511 | __module_get(THIS_MODULE); |
|---|
| 528 | 512 | |
|---|
| 529 | 513 | watchdog.expect_close = 0; |
|---|
| 530 | | - return nonseekable_open(inode, file); |
|---|
| 514 | + return stream_open(inode, file); |
|---|
| 531 | 515 | } |
|---|
| 532 | 516 | |
|---|
| 533 | 517 | static int watchdog_release(struct inode *inode, struct file *file) |
|---|
| .. | .. |
|---|
| 630 | 614 | |
|---|
| 631 | 615 | if (new_options & WDIOS_ENABLECARD) |
|---|
| 632 | 616 | return watchdog_start(); |
|---|
| 633 | | - /* fall through */ |
|---|
| 617 | + fallthrough; |
|---|
| 634 | 618 | |
|---|
| 635 | 619 | case WDIOC_KEEPALIVE: |
|---|
| 636 | 620 | watchdog_keepalive(); |
|---|
| .. | .. |
|---|
| 644 | 628 | return -EINVAL; |
|---|
| 645 | 629 | |
|---|
| 646 | 630 | watchdog_keepalive(); |
|---|
| 647 | | - /* fall through */ |
|---|
| 631 | + fallthrough; |
|---|
| 648 | 632 | |
|---|
| 649 | 633 | case WDIOC_GETTIMEOUT: |
|---|
| 650 | 634 | return put_user(watchdog.timeout, uarg.i); |
|---|
| .. | .. |
|---|
| 670 | 654 | .release = watchdog_release, |
|---|
| 671 | 655 | .write = watchdog_write, |
|---|
| 672 | 656 | .unlocked_ioctl = watchdog_ioctl, |
|---|
| 657 | + .compat_ioctl = compat_ptr_ioctl, |
|---|
| 673 | 658 | }; |
|---|
| 674 | 659 | |
|---|
| 675 | 660 | static struct miscdevice watchdog_miscdev = { |
|---|
| .. | .. |
|---|
| 810 | 795 | break; |
|---|
| 811 | 796 | case SIO_F71862_ID: |
|---|
| 812 | 797 | watchdog.type = f71862fg; |
|---|
| 813 | | - err = f71862fg_pin_configure(0); /* validate module parameter */ |
|---|
| 814 | 798 | break; |
|---|
| 815 | 799 | case SIO_F71868_ID: |
|---|
| 816 | 800 | watchdog.type = f71868; |
|---|
| .. | .. |
|---|
| 829 | 813 | /* Confirmed (by datasheet) not to have a watchdog. */ |
|---|
| 830 | 814 | err = -ENODEV; |
|---|
| 831 | 815 | goto exit; |
|---|
| 816 | + case SIO_F81803_ID: |
|---|
| 817 | + watchdog.type = f81803; |
|---|
| 818 | + break; |
|---|
| 832 | 819 | case SIO_F81865_ID: |
|---|
| 833 | 820 | watchdog.type = f81865; |
|---|
| 834 | 821 | break; |
|---|
| .. | .. |
|---|
| 856 | 843 | int err = -ENODEV; |
|---|
| 857 | 844 | int i; |
|---|
| 858 | 845 | |
|---|
| 846 | + if (f71862fg_pin != 63 && f71862fg_pin != 56) { |
|---|
| 847 | + pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin); |
|---|
| 848 | + return -EINVAL; |
|---|
| 849 | + } |
|---|
| 850 | + |
|---|
| 859 | 851 | for (i = 0; i < ARRAY_SIZE(addrs); i++) { |
|---|
| 860 | 852 | err = f71808e_find(addrs[i]); |
|---|
| 861 | 853 | if (err == 0) |
|---|