374 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Watchdog Timer Driver4 * for ITE IT87xx Environment Control - Low Pin Count Input / Output5 *6 * (c) Copyright 2007 Oliver Schuster <olivers137@aol.com>7 *8 * Based on softdog.c by Alan Cox,9 * 83977f_wdt.c by Jose Goncalves,10 * it87.c by Chris Gauthron, Jean Delvare11 *12 * Data-sheets: Publicly available at the ITE website13 * http://www.ite.com.tw/14 *15 * Support of the watchdog timers, which are available on16 * IT8607, IT8613, IT8620, IT8622, IT8625, IT8628, IT8655, IT8659,17 * IT8665, IT8686, IT8702, IT8712, IT8716, IT8718, IT8720, IT8721,18 * IT8726, IT8728, IT8772, IT8783, IT8784 and IT8786.19 */20 21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt22 23#include <linux/init.h>24#include <linux/io.h>25#include <linux/kernel.h>26#include <linux/module.h>27#include <linux/moduleparam.h>28#include <linux/types.h>29#include <linux/watchdog.h>30 31#define WATCHDOG_NAME "IT87 WDT"32 33/* Defaults for Module Parameter */34#define DEFAULT_TIMEOUT 6035#define DEFAULT_TESTMODE 036#define DEFAULT_NOWAYOUT WATCHDOG_NOWAYOUT37 38/* IO Ports */39#define REG 0x2e40#define VAL 0x2f41 42/* Logical device Numbers LDN */43#define GPIO 0x0744 45/* Configuration Registers and Functions */46#define LDNREG 0x0747#define CHIPID 0x2048#define CHIPREV 0x2249 50/* Chip Id numbers */51#define NO_DEV_ID 0xffff52#define IT8607_ID 0x860753#define IT8613_ID 0x861354#define IT8620_ID 0x862055#define IT8622_ID 0x862256#define IT8625_ID 0x862557#define IT8628_ID 0x862858#define IT8655_ID 0x865559#define IT8659_ID 0x865960#define IT8665_ID 0x866561#define IT8686_ID 0x868662#define IT8702_ID 0x870263#define IT8705_ID 0x870564#define IT8712_ID 0x871265#define IT8716_ID 0x871666#define IT8718_ID 0x871867#define IT8720_ID 0x872068#define IT8721_ID 0x872169#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */70#define IT8728_ID 0x872871#define IT8772_ID 0x877272#define IT8783_ID 0x878373#define IT8784_ID 0x878474#define IT8786_ID 0x878675 76/* GPIO Configuration Registers LDN=0x07 */77#define WDTCTRL 0x7178#define WDTCFG 0x7279#define WDTVALLSB 0x7380#define WDTVALMSB 0x7481 82/* GPIO Bits WDTCFG */83#define WDT_TOV1 0x8084#define WDT_KRST 0x4085#define WDT_TOVE 0x2086#define WDT_PWROK 0x10 /* not in it8721 */87#define WDT_INT_MASK 0x0f88 89static unsigned int max_units, chip_type;90 91static unsigned int timeout = DEFAULT_TIMEOUT;92static int testmode = DEFAULT_TESTMODE;93static bool nowayout = DEFAULT_NOWAYOUT;94 95module_param(timeout, int, 0);96MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds, default="97 __MODULE_STRING(DEFAULT_TIMEOUT));98module_param(testmode, int, 0);99MODULE_PARM_DESC(testmode, "Watchdog test mode (1 = no reboot), default="100 __MODULE_STRING(DEFAULT_TESTMODE));101module_param(nowayout, bool, 0);102MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started, default="103 __MODULE_STRING(WATCHDOG_NOWAYOUT));104 105/* Superio Chip */106 107static inline int superio_enter(void)108{109 /*110 * Try to reserve REG and REG + 1 for exclusive access.111 */112 if (!request_muxed_region(REG, 2, WATCHDOG_NAME))113 return -EBUSY;114 115 outb(0x87, REG);116 outb(0x01, REG);117 outb(0x55, REG);118 outb(0x55, REG);119 return 0;120}121 122static inline void superio_exit(void)123{124 outb(0x02, REG);125 outb(0x02, VAL);126 release_region(REG, 2);127}128 129static inline void superio_select(int ldn)130{131 outb(LDNREG, REG);132 outb(ldn, VAL);133}134 135static inline int superio_inb(int reg)136{137 outb(reg, REG);138 return inb(VAL);139}140 141static inline void superio_outb(int val, int reg)142{143 outb(reg, REG);144 outb(val, VAL);145}146 147static inline int superio_inw(int reg)148{149 int val;150 151 outb(reg++, REG);152 val = inb(VAL) << 8;153 outb(reg, REG);154 val |= inb(VAL);155 return val;156}157 158/* Internal function, should be called after superio_select(GPIO) */159static void _wdt_update_timeout(unsigned int t)160{161 unsigned char cfg = WDT_KRST;162 163 if (testmode)164 cfg = 0;165 166 if (t <= max_units)167 cfg |= WDT_TOV1;168 else169 t /= 60;170 171 if (chip_type != IT8721_ID)172 cfg |= WDT_PWROK;173 174 superio_outb(cfg, WDTCFG);175 superio_outb(t, WDTVALLSB);176 if (max_units > 255)177 superio_outb(t >> 8, WDTVALMSB);178}179 180static int wdt_update_timeout(unsigned int t)181{182 int ret;183 184 ret = superio_enter();185 if (ret)186 return ret;187 188 superio_select(GPIO);189 _wdt_update_timeout(t);190 superio_exit();191 192 return 0;193}194 195static int wdt_round_time(int t)196{197 t += 59;198 t -= t % 60;199 return t;200}201 202/* watchdog timer handling */203 204static int wdt_start(struct watchdog_device *wdd)205{206 return wdt_update_timeout(wdd->timeout);207}208 209static int wdt_stop(struct watchdog_device *wdd)210{211 return wdt_update_timeout(0);212}213 214/**215 * wdt_set_timeout - set a new timeout value with watchdog ioctl216 * @wdd: pointer to the watchdog_device structure217 * @t: timeout value in seconds218 *219 * The hardware device has a 8 or 16 bit watchdog timer (depends on220 * chip version) that can be configured to count seconds or minutes.221 *222 * Used within WDIOC_SETTIMEOUT watchdog device ioctl.223 *224 * Return: 0 if the timeout was set successfully, or a negative error code on225 * failure.226 */227 228static int wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)229{230 int ret = 0;231 232 if (t > max_units)233 t = wdt_round_time(t);234 235 wdd->timeout = t;236 237 if (watchdog_hw_running(wdd))238 ret = wdt_update_timeout(t);239 240 return ret;241}242 243static const struct watchdog_info ident = {244 .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,245 .firmware_version = 1,246 .identity = WATCHDOG_NAME,247};248 249static const struct watchdog_ops wdt_ops = {250 .owner = THIS_MODULE,251 .start = wdt_start,252 .stop = wdt_stop,253 .set_timeout = wdt_set_timeout,254};255 256static struct watchdog_device wdt_dev = {257 .info = &ident,258 .ops = &wdt_ops,259 .min_timeout = 1,260};261 262static int __init it87_wdt_init(void)263{264 u8 chip_rev;265 u8 ctrl;266 int rc;267 268 rc = superio_enter();269 if (rc)270 return rc;271 272 chip_type = superio_inw(CHIPID);273 chip_rev = superio_inb(CHIPREV) & 0x0f;274 superio_exit();275 276 switch (chip_type) {277 case IT8702_ID:278 max_units = 255;279 break;280 case IT8712_ID:281 max_units = (chip_rev < 8) ? 255 : 65535;282 break;283 case IT8607_ID:284 case IT8613_ID:285 case IT8620_ID:286 case IT8622_ID:287 case IT8625_ID:288 case IT8628_ID:289 case IT8655_ID:290 case IT8659_ID:291 case IT8665_ID:292 case IT8686_ID:293 case IT8716_ID:294 case IT8718_ID:295 case IT8720_ID:296 case IT8721_ID:297 case IT8726_ID:298 case IT8728_ID:299 case IT8772_ID:300 case IT8783_ID:301 case IT8784_ID:302 case IT8786_ID:303 max_units = 65535;304 break;305 case IT8705_ID:306 pr_err("Unsupported Chip found, Chip %04x Revision %02x\n",307 chip_type, chip_rev);308 return -ENODEV;309 case NO_DEV_ID:310 pr_err("no device\n");311 return -ENODEV;312 default:313 pr_err("Unknown Chip found, Chip %04x Revision %04x\n",314 chip_type, chip_rev);315 return -ENODEV;316 }317 318 rc = superio_enter();319 if (rc)320 return rc;321 322 superio_select(GPIO);323 superio_outb(WDT_TOV1, WDTCFG);324 325 switch (chip_type) {326 case IT8784_ID:327 case IT8786_ID:328 ctrl = superio_inb(WDTCTRL);329 ctrl &= 0x08;330 superio_outb(ctrl, WDTCTRL);331 break;332 default:333 superio_outb(0x00, WDTCTRL);334 }335 336 superio_exit();337 338 if (timeout < 1 || timeout > max_units * 60) {339 timeout = DEFAULT_TIMEOUT;340 pr_warn("Timeout value out of range, use default %d sec\n",341 DEFAULT_TIMEOUT);342 }343 344 if (timeout > max_units)345 timeout = wdt_round_time(timeout);346 347 wdt_dev.timeout = timeout;348 wdt_dev.max_timeout = max_units * 60;349 350 watchdog_stop_on_reboot(&wdt_dev);351 rc = watchdog_register_device(&wdt_dev);352 if (rc) {353 pr_err("Cannot register watchdog device (err=%d)\n", rc);354 return rc;355 }356 357 pr_info("Chip IT%04x revision %d initialized. timeout=%d sec (nowayout=%d testmode=%d)\n",358 chip_type, chip_rev, timeout, nowayout, testmode);359 360 return 0;361}362 363static void __exit it87_wdt_exit(void)364{365 watchdog_unregister_device(&wdt_dev);366}367 368module_init(it87_wdt_init);369module_exit(it87_wdt_exit);370 371MODULE_AUTHOR("Oliver Schuster");372MODULE_DESCRIPTION("Hardware Watchdog Device Driver for IT87xx EC-LPC I/O");373MODULE_LICENSE("GPL");374