brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 3e8c151 Raw
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