diff options
Diffstat (limited to 'drivers/watchdog/it87_wdt.c')
| -rw-r--r-- | drivers/watchdog/it87_wdt.c | 107 |
1 files changed, 77 insertions, 30 deletions
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index e96faea24925..3b8488c86a2f 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Watchdog Timer Driver * for ITE IT87xx Environment Control - Low Pin Count Input / Output @@ -12,28 +13,22 @@ * http://www.ite.com.tw/ * * Support of the watchdog timers, which are available on - * IT8607, IT8620, IT8622, IT8625, IT8628, IT8655, IT8665, IT8686, - * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726, IT8728, - * and IT8783. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * IT8607, IT8613, IT8620, IT8622, IT8625, IT8628, IT8655, IT8659, + * IT8665, IT8686, IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, + * IT8726, IT8728, IT8772, IT8783, IT8784 and IT8786. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/bits.h> +#include <linux/dmi.h> +#include <linux/errno.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/kernel.h> +#include <linux/ioport.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/printk.h> #include <linux/types.h> #include <linux/watchdog.h> @@ -49,6 +44,7 @@ #define VAL 0x2f /* Logical device Numbers LDN */ +#define EC 0x04 #define GPIO 0x07 /* Configuration Registers and Functions */ @@ -59,11 +55,13 @@ /* Chip Id numbers */ #define NO_DEV_ID 0xffff #define IT8607_ID 0x8607 +#define IT8613_ID 0x8613 #define IT8620_ID 0x8620 #define IT8622_ID 0x8622 #define IT8625_ID 0x8625 #define IT8628_ID 0x8628 #define IT8655_ID 0x8655 +#define IT8659_ID 0x8659 #define IT8665_ID 0x8665 #define IT8686_ID 0x8686 #define IT8702_ID 0x8702 @@ -75,7 +73,16 @@ #define IT8721_ID 0x8721 #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ #define IT8728_ID 0x8728 +#define IT8772_ID 0x8772 #define IT8783_ID 0x8783 +#define IT8784_ID 0x8784 +#define IT8786_ID 0x8786 + +/* Environment Controller Configuration Registers LDN=0x04 */ +#define SCR1 0xfa + +/* Environment Controller Bits SCR1 */ +#define WDT_PWRGD 0x20 /* GPIO Configuration Registers LDN=0x07 */ #define WDTCTRL 0x71 @@ -151,6 +158,7 @@ static inline void superio_outb(int val, int reg) static inline int superio_inw(int reg) { int val; + outb(reg++, REG); val = inb(VAL) << 8; outb(reg, REG); @@ -158,14 +166,6 @@ static inline int superio_inw(int reg) return val; } -static inline void superio_outw(int val, int reg) -{ - outb(reg++, REG); - outb(val >> 8, VAL); - outb(reg, REG); - outb(val, VAL); -} - /* Internal function, should be called after superio_select(GPIO) */ static void _wdt_update_timeout(unsigned int t) { @@ -224,12 +224,16 @@ static int wdt_stop(struct watchdog_device *wdd) /** * wdt_set_timeout - set a new timeout value with watchdog ioctl + * @wdd: pointer to the watchdog_device structure * @t: timeout value in seconds * * The hardware device has a 8 or 16 bit watchdog timer (depends on * chip version) that can be configured to count seconds or minutes. * * Used within WDIOC_SETTIMEOUT watchdog device ioctl. + * + * Return: 0 if the timeout was set successfully, or a negative error code on + * failure. */ static int wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) @@ -247,6 +251,21 @@ static int wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) return ret; } +enum { + IT87_WDT_OUTPUT_THROUGH_PWRGD = BIT(0), +}; + +static const struct dmi_system_id it87_quirks[] = { + { + /* Qotom Q30900P (IT8786) */ + .matches = { + DMI_EXACT_MATCH(DMI_BOARD_NAME, "QCML04"), + }, + .driver_data = (void *)IT87_WDT_OUTPUT_THROUGH_PWRGD, + }, + {} +}; + static const struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, .firmware_version = 1, @@ -268,7 +287,10 @@ static struct watchdog_device wdt_dev = { static int __init it87_wdt_init(void) { + const struct dmi_system_id *dmi_id; u8 chip_rev; + u8 ctrl; + int quirks = 0; int rc; rc = superio_enter(); @@ -279,6 +301,10 @@ static int __init it87_wdt_init(void) chip_rev = superio_inb(CHIPREV) & 0x0f; superio_exit(); + dmi_id = dmi_first_match(it87_quirks); + if (dmi_id) + quirks = (long)dmi_id->driver_data; + switch (chip_type) { case IT8702_ID: max_units = 255; @@ -286,23 +312,26 @@ static int __init it87_wdt_init(void) case IT8712_ID: max_units = (chip_rev < 8) ? 255 : 65535; break; - case IT8716_ID: - case IT8726_ID: - max_units = 65535; - break; case IT8607_ID: + case IT8613_ID: case IT8620_ID: case IT8622_ID: case IT8625_ID: case IT8628_ID: case IT8655_ID: + case IT8659_ID: case IT8665_ID: case IT8686_ID: + case IT8716_ID: case IT8718_ID: case IT8720_ID: case IT8721_ID: + case IT8726_ID: case IT8728_ID: + case IT8772_ID: case IT8783_ID: + case IT8784_ID: + case IT8786_ID: max_units = 65535; break; case IT8705_ID: @@ -324,7 +353,27 @@ static int __init it87_wdt_init(void) superio_select(GPIO); superio_outb(WDT_TOV1, WDTCFG); - superio_outb(0x00, WDTCTRL); + + switch (chip_type) { + case IT8784_ID: + case IT8786_ID: + ctrl = superio_inb(WDTCTRL); + ctrl &= 0x08; + superio_outb(ctrl, WDTCTRL); + break; + default: + superio_outb(0x00, WDTCTRL); + } + + if (quirks & IT87_WDT_OUTPUT_THROUGH_PWRGD) { + superio_select(EC); + ctrl = superio_inb(SCR1); + if (!(ctrl & WDT_PWRGD)) { + ctrl |= WDT_PWRGD; + superio_outb(ctrl, SCR1); + } + } + superio_exit(); if (timeout < 1 || timeout > max_units * 60) { @@ -341,10 +390,8 @@ static int __init it87_wdt_init(void) watchdog_stop_on_reboot(&wdt_dev); rc = watchdog_register_device(&wdt_dev); - if (rc) { - pr_err("Cannot register watchdog device (err=%d)\n", rc); + if (rc) return rc; - } pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", chip_type, chip_rev, timeout, nowayout, testmode); |
