xref: /openbmc/linux/drivers/watchdog/f71808e_wdt.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
296cb4eb0SGiel van Schijndel /***************************************************************************
396cb4eb0SGiel van Schijndel  *   Copyright (C) 2006 by Hans Edgington <hans@edgington.nl>              *
496cb4eb0SGiel van Schijndel  *   Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com>           *
596cb4eb0SGiel van Schijndel  *   Copyright (C) 2010 Giel van Schijndel <me@mortis.eu>                  *
696cb4eb0SGiel van Schijndel  *                                                                         *
796cb4eb0SGiel van Schijndel  ***************************************************************************/
896cb4eb0SGiel van Schijndel 
927c766aaSJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1027c766aaSJoe Perches 
1196cb4eb0SGiel van Schijndel #include <linux/err.h>
1296cb4eb0SGiel van Schijndel #include <linux/init.h>
1396cb4eb0SGiel van Schijndel #include <linux/io.h>
1496cb4eb0SGiel van Schijndel #include <linux/ioport.h>
1596cb4eb0SGiel van Schijndel #include <linux/module.h>
1627e0fe00SAhmad Fatoum #include <linux/platform_device.h>
1796cb4eb0SGiel van Schijndel #include <linux/watchdog.h>
1896cb4eb0SGiel van Schijndel 
1996cb4eb0SGiel van Schijndel #define DRVNAME "f71808e_wdt"
2096cb4eb0SGiel van Schijndel 
2196cb4eb0SGiel van Schijndel #define SIO_F71808FG_LD_WDT	0x07	/* Watchdog timer logical device */
2296cb4eb0SGiel van Schijndel #define SIO_UNLOCK_KEY		0x87	/* Key to enable Super-I/O */
2385c130a8SKnud Poulsen #define SIO_LOCK_KEY		0xAA	/* Key to disable Super-I/O */
2496cb4eb0SGiel van Schijndel 
2596cb4eb0SGiel van Schijndel #define SIO_REG_LDSEL		0x07	/* Logical device select */
2696cb4eb0SGiel van Schijndel #define SIO_REG_DEVID		0x20	/* Device ID (2 bytes) */
2796cb4eb0SGiel van Schijndel #define SIO_REG_DEVREV		0x22	/* Device revision */
2896cb4eb0SGiel van Schijndel #define SIO_REG_MANID		0x23	/* Fintek ID (2 bytes) */
29ca2fc5efSJaret Cantu #define SIO_REG_CLOCK_SEL	0x26	/* Clock select */
307977ff6eSLutz Ballaschke #define SIO_REG_ROM_ADDR_SEL	0x27	/* ROM address select */
3114b24a88SJi-Ze Hong (Peter Hong) #define SIO_F81866_REG_PORT_SEL	0x27	/* F81866 Multi-Function Register */
32ca2fc5efSJaret Cantu #define SIO_REG_TSI_LEVEL_SEL	0x28	/* TSI Level select */
33f9a9f096SLutz Ballaschke #define SIO_REG_MFUNCT1		0x29	/* Multi function select 1 */
34f9a9f096SLutz Ballaschke #define SIO_REG_MFUNCT2		0x2a	/* Multi function select 2 */
35f9a9f096SLutz Ballaschke #define SIO_REG_MFUNCT3		0x2b	/* Multi function select 3 */
3614b24a88SJi-Ze Hong (Peter Hong) #define SIO_F81866_REG_GPIO1	0x2c	/* F81866 GPIO1 Enable Register */
3796cb4eb0SGiel van Schijndel #define SIO_REG_ENABLE		0x30	/* Logical device enable */
3896cb4eb0SGiel van Schijndel #define SIO_REG_ADDR		0x60	/* Logical device address (2 bytes) */
3996cb4eb0SGiel van Schijndel 
4096cb4eb0SGiel van Schijndel #define SIO_FINTEK_ID		0x1934	/* Manufacturers ID */
4196cb4eb0SGiel van Schijndel #define SIO_F71808_ID		0x0901	/* Chipset ID */
4296cb4eb0SGiel van Schijndel #define SIO_F71858_ID		0x0507	/* Chipset ID */
4396cb4eb0SGiel van Schijndel #define SIO_F71862_ID		0x0601	/* Chipset ID */
44166fbcf8SMaciej S. Szmigiero #define SIO_F71868_ID		0x1106	/* Chipset ID */
45df278dacSMichel Arboi #define SIO_F71869_ID		0x0814	/* Chipset ID */
463017020dSJustin Wheeler #define SIO_F71869A_ID		0x1007	/* Chipset ID */
4796cb4eb0SGiel van Schijndel #define SIO_F71882_ID		0x0541	/* Chipset ID */
4896cb4eb0SGiel van Schijndel #define SIO_F71889_ID		0x0723	/* Chipset ID */
49ca2fc5efSJaret Cantu #define SIO_F81803_ID		0x1210	/* Chipset ID */
50ea0c03e8SKnud Poulsen #define SIO_F81865_ID		0x0704	/* Chipset ID */
5114b24a88SJi-Ze Hong (Peter Hong) #define SIO_F81866_ID		0x1010	/* Chipset ID */
52cea62f9fSAaeonIot #define SIO_F81966_ID		0x1502  /* F81804 chipset ID, same for f81966 */
5396cb4eb0SGiel van Schijndel 
5496cb4eb0SGiel van Schijndel #define F71808FG_REG_WDO_CONF		0xf0
5596cb4eb0SGiel van Schijndel #define F71808FG_REG_WDT_CONF		0xf5
5696cb4eb0SGiel van Schijndel #define F71808FG_REG_WD_TIME		0xf6
5796cb4eb0SGiel van Schijndel 
5896cb4eb0SGiel van Schijndel #define F71808FG_FLAG_WDOUT_EN		7
5996cb4eb0SGiel van Schijndel 
60b97cb21aSKnud Poulsen #define F71808FG_FLAG_WDTMOUT_STS	6
6196cb4eb0SGiel van Schijndel #define F71808FG_FLAG_WD_EN		5
6296cb4eb0SGiel van Schijndel #define F71808FG_FLAG_WD_PULSE		4
6396cb4eb0SGiel van Schijndel #define F71808FG_FLAG_WD_UNIT		3
6496cb4eb0SGiel van Schijndel 
65ea0c03e8SKnud Poulsen #define F81865_REG_WDO_CONF		0xfa
66ea0c03e8SKnud Poulsen #define F81865_FLAG_WDOUT_EN		0
67ea0c03e8SKnud Poulsen 
6896cb4eb0SGiel van Schijndel /* Default values */
6996cb4eb0SGiel van Schijndel #define WATCHDOG_TIMEOUT	60	/* 1 minute default timeout */
7096cb4eb0SGiel van Schijndel #define WATCHDOG_MAX_TIMEOUT	(60 * 255)
7196cb4eb0SGiel van Schijndel #define WATCHDOG_PULSE_WIDTH	125	/* 125 ms, default pulse width for
7296cb4eb0SGiel van Schijndel 					   watchdog signal */
737977ff6eSLutz Ballaschke #define WATCHDOG_F71862FG_PIN	63	/* default watchdog reset output
747977ff6eSLutz Ballaschke 					   pin number 63 */
7596cb4eb0SGiel van Schijndel 
7696cb4eb0SGiel van Schijndel static unsigned short force_id;
7796cb4eb0SGiel van Schijndel module_param(force_id, ushort, 0);
7896cb4eb0SGiel van Schijndel MODULE_PARM_DESC(force_id, "Override the detected device ID");
7996cb4eb0SGiel van Schijndel 
80f9a9f096SLutz Ballaschke static int timeout = WATCHDOG_TIMEOUT;	/* default timeout in seconds */
8196cb4eb0SGiel van Schijndel module_param(timeout, int, 0);
8296cb4eb0SGiel van Schijndel MODULE_PARM_DESC(timeout,
8396cb4eb0SGiel van Schijndel 	"Watchdog timeout in seconds. 1<= timeout <="
8496cb4eb0SGiel van Schijndel 			__MODULE_STRING(WATCHDOG_MAX_TIMEOUT) " (default="
8596cb4eb0SGiel van Schijndel 			__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
8696cb4eb0SGiel van Schijndel 
8796cb4eb0SGiel van Schijndel static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH;
8896cb4eb0SGiel van Schijndel module_param(pulse_width, uint, 0);
8996cb4eb0SGiel van Schijndel MODULE_PARM_DESC(pulse_width,
90166fbcf8SMaciej S. Szmigiero 	"Watchdog signal pulse width. 0(=level), 1, 25, 30, 125, 150, 5000 or 6000 ms"
9196cb4eb0SGiel van Schijndel 			" (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
9296cb4eb0SGiel van Schijndel 
937977ff6eSLutz Ballaschke static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
947977ff6eSLutz Ballaschke module_param(f71862fg_pin, uint, 0);
957977ff6eSLutz Ballaschke MODULE_PARM_DESC(f71862fg_pin,
967977ff6eSLutz Ballaschke 	"Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63"
977977ff6eSLutz Ballaschke 			" (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")");
987977ff6eSLutz Ballaschke 
9990ab5ee9SRusty Russell static bool nowayout = WATCHDOG_NOWAYOUT;
10096cb4eb0SGiel van Schijndel module_param(nowayout, bool, 0444);
10196cb4eb0SGiel van Schijndel MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
10296cb4eb0SGiel van Schijndel 
10396cb4eb0SGiel van Schijndel static unsigned int start_withtimeout;
10496cb4eb0SGiel van Schijndel module_param(start_withtimeout, uint, 0);
10596cb4eb0SGiel van Schijndel MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
10696cb4eb0SGiel van Schijndel 	" given initial timeout. Zero (default) disables this feature.");
10796cb4eb0SGiel van Schijndel 
108166fbcf8SMaciej S. Szmigiero enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg,
109cea62f9fSAaeonIot 	     f81803, f81865, f81866, f81966};
11096cb4eb0SGiel van Schijndel 
1113a2c4895SAhmad Fatoum static const char * const fintek_wdt_names[] = {
11296cb4eb0SGiel van Schijndel 	"f71808fg",
11396cb4eb0SGiel van Schijndel 	"f71858fg",
11496cb4eb0SGiel van Schijndel 	"f71862fg",
115166fbcf8SMaciej S. Szmigiero 	"f71868",
116df278dacSMichel Arboi 	"f71869",
11796cb4eb0SGiel van Schijndel 	"f71882fg",
11896cb4eb0SGiel van Schijndel 	"f71889fg",
119ca2fc5efSJaret Cantu 	"f81803",
120ea0c03e8SKnud Poulsen 	"f81865",
12114b24a88SJi-Ze Hong (Peter Hong) 	"f81866",
122cea62f9fSAaeonIot 	"f81966"
12396cb4eb0SGiel van Schijndel };
12496cb4eb0SGiel van Schijndel 
12596cb4eb0SGiel van Schijndel /* Super-I/O Function prototypes */
12696cb4eb0SGiel van Schijndel static inline int superio_inb(int base, int reg);
12796cb4eb0SGiel van Schijndel static inline int superio_inw(int base, int reg);
12896cb4eb0SGiel van Schijndel static inline void superio_outb(int base, int reg, u8 val);
12996cb4eb0SGiel van Schijndel static inline void superio_set_bit(int base, int reg, int bit);
13096cb4eb0SGiel van Schijndel static inline void superio_clear_bit(int base, int reg, int bit);
13196cb4eb0SGiel van Schijndel static inline int superio_enter(int base);
13296cb4eb0SGiel van Schijndel static inline void superio_select(int base, int ld);
13396cb4eb0SGiel van Schijndel static inline void superio_exit(int base);
13496cb4eb0SGiel van Schijndel 
1353a2c4895SAhmad Fatoum struct fintek_wdt {
1368bea27edSAhmad Fatoum 	struct watchdog_device wdd;
13796cb4eb0SGiel van Schijndel 	unsigned short	sioaddr;
13896cb4eb0SGiel van Schijndel 	enum chips	type;
13996cb4eb0SGiel van Schijndel 	struct watchdog_info ident;
14096cb4eb0SGiel van Schijndel 
14196cb4eb0SGiel van Schijndel 	u8		timer_val;	/* content for the wd_time register */
14296cb4eb0SGiel van Schijndel 	char		minutes_mode;
14396cb4eb0SGiel van Schijndel 	u8		pulse_val;	/* pulse width flag */
14496cb4eb0SGiel van Schijndel 	char		pulse_mode;	/* enable pulse output mode? */
14596cb4eb0SGiel van Schijndel };
14696cb4eb0SGiel van Schijndel 
147a7876735SAhmad Fatoum struct fintek_wdt_pdata {
148a7876735SAhmad Fatoum 	enum chips	type;
149a7876735SAhmad Fatoum };
15096cb4eb0SGiel van Schijndel 
15196cb4eb0SGiel van Schijndel /* Super I/O functions */
superio_inb(int base,int reg)15296cb4eb0SGiel van Schijndel static inline int superio_inb(int base, int reg)
15396cb4eb0SGiel van Schijndel {
15496cb4eb0SGiel van Schijndel 	outb(reg, base);
15596cb4eb0SGiel van Schijndel 	return inb(base + 1);
15696cb4eb0SGiel van Schijndel }
15796cb4eb0SGiel van Schijndel 
superio_inw(int base,int reg)15896cb4eb0SGiel van Schijndel static int superio_inw(int base, int reg)
15996cb4eb0SGiel van Schijndel {
16096cb4eb0SGiel van Schijndel 	int val;
16196cb4eb0SGiel van Schijndel 	val  = superio_inb(base, reg) << 8;
16296cb4eb0SGiel van Schijndel 	val |= superio_inb(base, reg + 1);
16396cb4eb0SGiel van Schijndel 	return val;
16496cb4eb0SGiel van Schijndel }
16596cb4eb0SGiel van Schijndel 
superio_outb(int base,int reg,u8 val)16696cb4eb0SGiel van Schijndel static inline void superio_outb(int base, int reg, u8 val)
16796cb4eb0SGiel van Schijndel {
16896cb4eb0SGiel van Schijndel 	outb(reg, base);
16996cb4eb0SGiel van Schijndel 	outb(val, base + 1);
17096cb4eb0SGiel van Schijndel }
17196cb4eb0SGiel van Schijndel 
superio_set_bit(int base,int reg,int bit)17296cb4eb0SGiel van Schijndel static inline void superio_set_bit(int base, int reg, int bit)
17396cb4eb0SGiel van Schijndel {
17496cb4eb0SGiel van Schijndel 	unsigned long val = superio_inb(base, reg);
17596cb4eb0SGiel van Schijndel 	__set_bit(bit, &val);
17696cb4eb0SGiel van Schijndel 	superio_outb(base, reg, val);
17796cb4eb0SGiel van Schijndel }
17896cb4eb0SGiel van Schijndel 
superio_clear_bit(int base,int reg,int bit)17996cb4eb0SGiel van Schijndel static inline void superio_clear_bit(int base, int reg, int bit)
18096cb4eb0SGiel van Schijndel {
18196cb4eb0SGiel van Schijndel 	unsigned long val = superio_inb(base, reg);
18296cb4eb0SGiel van Schijndel 	__clear_bit(bit, &val);
18396cb4eb0SGiel van Schijndel 	superio_outb(base, reg, val);
18496cb4eb0SGiel van Schijndel }
18596cb4eb0SGiel van Schijndel 
superio_enter(int base)18696cb4eb0SGiel van Schijndel static inline int superio_enter(int base)
18796cb4eb0SGiel van Schijndel {
18896cb4eb0SGiel van Schijndel 	/* Don't step on other drivers' I/O space by accident */
18996cb4eb0SGiel van Schijndel 	if (!request_muxed_region(base, 2, DRVNAME)) {
19027c766aaSJoe Perches 		pr_err("I/O address 0x%04x already in use\n", (int)base);
19196cb4eb0SGiel van Schijndel 		return -EBUSY;
19296cb4eb0SGiel van Schijndel 	}
19396cb4eb0SGiel van Schijndel 
1943017020dSJustin Wheeler 	/* according to the datasheet the key must be sent twice! */
19596cb4eb0SGiel van Schijndel 	outb(SIO_UNLOCK_KEY, base);
19696cb4eb0SGiel van Schijndel 	outb(SIO_UNLOCK_KEY, base);
19796cb4eb0SGiel van Schijndel 
19896cb4eb0SGiel van Schijndel 	return 0;
19996cb4eb0SGiel van Schijndel }
20096cb4eb0SGiel van Schijndel 
superio_select(int base,int ld)20196cb4eb0SGiel van Schijndel static inline void superio_select(int base, int ld)
20296cb4eb0SGiel van Schijndel {
20396cb4eb0SGiel van Schijndel 	outb(SIO_REG_LDSEL, base);
20496cb4eb0SGiel van Schijndel 	outb(ld, base + 1);
20596cb4eb0SGiel van Schijndel }
20696cb4eb0SGiel van Schijndel 
superio_exit(int base)20796cb4eb0SGiel van Schijndel static inline void superio_exit(int base)
20896cb4eb0SGiel van Schijndel {
20996cb4eb0SGiel van Schijndel 	outb(SIO_LOCK_KEY, base);
21096cb4eb0SGiel van Schijndel 	release_region(base, 2);
21196cb4eb0SGiel van Schijndel }
21296cb4eb0SGiel van Schijndel 
fintek_wdt_set_timeout(struct watchdog_device * wdd,unsigned int timeout)2138bea27edSAhmad Fatoum static int fintek_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
21496cb4eb0SGiel van Schijndel {
215a7876735SAhmad Fatoum 	struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
216a7876735SAhmad Fatoum 
21796cb4eb0SGiel van Schijndel 	if (timeout > 0xff) {
218a7876735SAhmad Fatoum 		wd->timer_val = DIV_ROUND_UP(timeout, 60);
219a7876735SAhmad Fatoum 		wd->minutes_mode = true;
220a7876735SAhmad Fatoum 		timeout = wd->timer_val * 60;
22196cb4eb0SGiel van Schijndel 	} else {
222a7876735SAhmad Fatoum 		wd->timer_val = timeout;
223a7876735SAhmad Fatoum 		wd->minutes_mode = false;
22496cb4eb0SGiel van Schijndel 	}
22596cb4eb0SGiel van Schijndel 
2268bea27edSAhmad Fatoum 	wdd->timeout = timeout;
22796cb4eb0SGiel van Schijndel 
22896cb4eb0SGiel van Schijndel 	return 0;
22996cb4eb0SGiel van Schijndel }
23096cb4eb0SGiel van Schijndel 
fintek_wdt_set_pulse_width(struct fintek_wdt * wd,unsigned int pw)231a7876735SAhmad Fatoum static int fintek_wdt_set_pulse_width(struct fintek_wdt *wd, unsigned int pw)
23296cb4eb0SGiel van Schijndel {
233166fbcf8SMaciej S. Szmigiero 	unsigned int t1 = 25, t2 = 125, t3 = 5000;
234166fbcf8SMaciej S. Szmigiero 
235a7876735SAhmad Fatoum 	if (wd->type == f71868) {
236166fbcf8SMaciej S. Szmigiero 		t1 = 30;
237166fbcf8SMaciej S. Szmigiero 		t2 = 150;
238166fbcf8SMaciej S. Szmigiero 		t3 = 6000;
239166fbcf8SMaciej S. Szmigiero 	}
24096cb4eb0SGiel van Schijndel 
24196cb4eb0SGiel van Schijndel 	if        (pw <=  1) {
242a7876735SAhmad Fatoum 		wd->pulse_val = 0;
243166fbcf8SMaciej S. Szmigiero 	} else if (pw <= t1) {
244a7876735SAhmad Fatoum 		wd->pulse_val = 1;
245166fbcf8SMaciej S. Szmigiero 	} else if (pw <= t2) {
246a7876735SAhmad Fatoum 		wd->pulse_val = 2;
247166fbcf8SMaciej S. Szmigiero 	} else if (pw <= t3) {
248a7876735SAhmad Fatoum 		wd->pulse_val = 3;
24996cb4eb0SGiel van Schijndel 	} else {
25027c766aaSJoe Perches 		pr_err("pulse width out of range\n");
2518bea27edSAhmad Fatoum 		return -EINVAL;
25296cb4eb0SGiel van Schijndel 	}
25396cb4eb0SGiel van Schijndel 
254a7876735SAhmad Fatoum 	wd->pulse_mode = pw;
25596cb4eb0SGiel van Schijndel 
2568bea27edSAhmad Fatoum 	return 0;
25796cb4eb0SGiel van Schijndel }
25896cb4eb0SGiel van Schijndel 
fintek_wdt_keepalive(struct watchdog_device * wdd)2598bea27edSAhmad Fatoum static int fintek_wdt_keepalive(struct watchdog_device *wdd)
26096cb4eb0SGiel van Schijndel {
261a7876735SAhmad Fatoum 	struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
2628bea27edSAhmad Fatoum 	int err;
26396cb4eb0SGiel van Schijndel 
264a7876735SAhmad Fatoum 	err = superio_enter(wd->sioaddr);
26596cb4eb0SGiel van Schijndel 	if (err)
2668bea27edSAhmad Fatoum 		return err;
267a7876735SAhmad Fatoum 	superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
26896cb4eb0SGiel van Schijndel 
269a7876735SAhmad Fatoum 	if (wd->minutes_mode)
27096cb4eb0SGiel van Schijndel 		/* select minutes for timer units */
271a7876735SAhmad Fatoum 		superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
27296cb4eb0SGiel van Schijndel 				F71808FG_FLAG_WD_UNIT);
27396cb4eb0SGiel van Schijndel 	else
27496cb4eb0SGiel van Schijndel 		/* select seconds for timer units */
275a7876735SAhmad Fatoum 		superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
27696cb4eb0SGiel van Schijndel 				F71808FG_FLAG_WD_UNIT);
27796cb4eb0SGiel van Schijndel 
27896cb4eb0SGiel van Schijndel 	/* Set timer value */
279a7876735SAhmad Fatoum 	superio_outb(wd->sioaddr, F71808FG_REG_WD_TIME,
280a7876735SAhmad Fatoum 			   wd->timer_val);
28196cb4eb0SGiel van Schijndel 
282a7876735SAhmad Fatoum 	superio_exit(wd->sioaddr);
28396cb4eb0SGiel van Schijndel 
2848bea27edSAhmad Fatoum 	return 0;
28596cb4eb0SGiel van Schijndel }
28696cb4eb0SGiel van Schijndel 
fintek_wdt_start(struct watchdog_device * wdd)2878bea27edSAhmad Fatoum static int fintek_wdt_start(struct watchdog_device *wdd)
28896cb4eb0SGiel van Schijndel {
289a7876735SAhmad Fatoum 	struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
290a3f764d2SJi-Ze Hong (Peter Hong) 	int err;
291e347afa5SJi-Ze Hong (Peter Hong) 	u8 tmp;
292a3f764d2SJi-Ze Hong (Peter Hong) 
29396cb4eb0SGiel van Schijndel 	/* Make sure we don't die as soon as the watchdog is enabled below */
2948bea27edSAhmad Fatoum 	err = fintek_wdt_keepalive(wdd);
29596cb4eb0SGiel van Schijndel 	if (err)
29696cb4eb0SGiel van Schijndel 		return err;
29796cb4eb0SGiel van Schijndel 
298a7876735SAhmad Fatoum 	err = superio_enter(wd->sioaddr);
29996cb4eb0SGiel van Schijndel 	if (err)
3008bea27edSAhmad Fatoum 		return err;
301a7876735SAhmad Fatoum 	superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
30296cb4eb0SGiel van Schijndel 
30396cb4eb0SGiel van Schijndel 	/* Watchdog pin configuration */
304a7876735SAhmad Fatoum 	switch (wd->type) {
30596cb4eb0SGiel van Schijndel 	case f71808fg:
30696cb4eb0SGiel van Schijndel 		/* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */
307a7876735SAhmad Fatoum 		superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT2, 3);
308a7876735SAhmad Fatoum 		superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 3);
30996cb4eb0SGiel van Schijndel 		break;
31096cb4eb0SGiel van Schijndel 
3117977ff6eSLutz Ballaschke 	case f71862fg:
3125edc8c68SAhmad Fatoum 		if (f71862fg_pin == 63) {
3135edc8c68SAhmad Fatoum 			/* SPI must be disabled first to use this pin! */
314a7876735SAhmad Fatoum 			superio_clear_bit(wd->sioaddr, SIO_REG_ROM_ADDR_SEL, 6);
315a7876735SAhmad Fatoum 			superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT3, 4);
3165edc8c68SAhmad Fatoum 		} else if (f71862fg_pin == 56) {
317a7876735SAhmad Fatoum 			superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
3185edc8c68SAhmad Fatoum 		}
3197977ff6eSLutz Ballaschke 		break;
3207977ff6eSLutz Ballaschke 
321166fbcf8SMaciej S. Szmigiero 	case f71868:
322df278dacSMichel Arboi 	case f71869:
323df278dacSMichel Arboi 		/* GPIO14 --> WDTRST# */
324a7876735SAhmad Fatoum 		superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT1, 4);
325df278dacSMichel Arboi 		break;
326df278dacSMichel Arboi 
32796cb4eb0SGiel van Schijndel 	case f71882fg:
32896cb4eb0SGiel van Schijndel 		/* Set pin 56 to WDTRST# */
329a7876735SAhmad Fatoum 		superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
33096cb4eb0SGiel van Schijndel 		break;
33196cb4eb0SGiel van Schijndel 
332dee00abbSGiel van Schijndel 	case f71889fg:
333dee00abbSGiel van Schijndel 		/* set pin 40 to WDTRST# */
334a7876735SAhmad Fatoum 		superio_outb(wd->sioaddr, SIO_REG_MFUNCT3,
335a7876735SAhmad Fatoum 			superio_inb(wd->sioaddr, SIO_REG_MFUNCT3) & 0xcf);
336dee00abbSGiel van Schijndel 		break;
337dee00abbSGiel van Schijndel 
338ca2fc5efSJaret Cantu 	case f81803:
339ca2fc5efSJaret Cantu 		/* Enable TSI Level register bank */
340a7876735SAhmad Fatoum 		superio_clear_bit(wd->sioaddr, SIO_REG_CLOCK_SEL, 3);
341ca2fc5efSJaret Cantu 		/* Set pin 27 to WDTRST# */
342a7876735SAhmad Fatoum 		superio_outb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL, 0x5f &
343a7876735SAhmad Fatoum 			superio_inb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL));
344ca2fc5efSJaret Cantu 		break;
345ca2fc5efSJaret Cantu 
346ea0c03e8SKnud Poulsen 	case f81865:
347ea0c03e8SKnud Poulsen 		/* Set pin 70 to WDTRST# */
348a7876735SAhmad Fatoum 		superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 5);
349ea0c03e8SKnud Poulsen 		break;
350ea0c03e8SKnud Poulsen 
35114b24a88SJi-Ze Hong (Peter Hong) 	case f81866:
352cea62f9fSAaeonIot 	case f81966:
35314b24a88SJi-Ze Hong (Peter Hong) 		/*
35414b24a88SJi-Ze Hong (Peter Hong) 		 * GPIO1 Control Register when 27h BIT3:2 = 01 & BIT0 = 0.
35514b24a88SJi-Ze Hong (Peter Hong) 		 * The PIN 70(GPIO15/WDTRST) is controlled by 2Ch:
35614b24a88SJi-Ze Hong (Peter Hong) 		 *     BIT5: 0 -> WDTRST#
35714b24a88SJi-Ze Hong (Peter Hong) 		 *           1 -> GPIO15
35814b24a88SJi-Ze Hong (Peter Hong) 		 */
359a7876735SAhmad Fatoum 		tmp = superio_inb(wd->sioaddr, SIO_F81866_REG_PORT_SEL);
360e347afa5SJi-Ze Hong (Peter Hong) 		tmp &= ~(BIT(3) | BIT(0));
361e347afa5SJi-Ze Hong (Peter Hong) 		tmp |= BIT(2);
362a7876735SAhmad Fatoum 		superio_outb(wd->sioaddr, SIO_F81866_REG_PORT_SEL, tmp);
363e347afa5SJi-Ze Hong (Peter Hong) 
364a7876735SAhmad Fatoum 		superio_clear_bit(wd->sioaddr, SIO_F81866_REG_GPIO1, 5);
36514b24a88SJi-Ze Hong (Peter Hong) 		break;
36614b24a88SJi-Ze Hong (Peter Hong) 
36796cb4eb0SGiel van Schijndel 	default:
36896cb4eb0SGiel van Schijndel 		/*
36996cb4eb0SGiel van Schijndel 		 * 'default' label to shut up the compiler and catch
37096cb4eb0SGiel van Schijndel 		 * programmer errors
37196cb4eb0SGiel van Schijndel 		 */
37296cb4eb0SGiel van Schijndel 		err = -ENODEV;
37396cb4eb0SGiel van Schijndel 		goto exit_superio;
37496cb4eb0SGiel van Schijndel 	}
37596cb4eb0SGiel van Schijndel 
376a7876735SAhmad Fatoum 	superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
377a7876735SAhmad Fatoum 	superio_set_bit(wd->sioaddr, SIO_REG_ENABLE, 0);
378ea0c03e8SKnud Poulsen 
379cea62f9fSAaeonIot 	if (wd->type == f81865 || wd->type == f81866 || wd->type == f81966)
380a7876735SAhmad Fatoum 		superio_set_bit(wd->sioaddr, F81865_REG_WDO_CONF,
381ea0c03e8SKnud Poulsen 				F81865_FLAG_WDOUT_EN);
382ea0c03e8SKnud Poulsen 	else
383a7876735SAhmad Fatoum 		superio_set_bit(wd->sioaddr, F71808FG_REG_WDO_CONF,
38496cb4eb0SGiel van Schijndel 				F71808FG_FLAG_WDOUT_EN);
38596cb4eb0SGiel van Schijndel 
386a7876735SAhmad Fatoum 	superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
38796cb4eb0SGiel van Schijndel 			F71808FG_FLAG_WD_EN);
38896cb4eb0SGiel van Schijndel 
389a7876735SAhmad Fatoum 	if (wd->pulse_mode) {
39096cb4eb0SGiel van Schijndel 		/* Select "pulse" output mode with given duration */
391a7876735SAhmad Fatoum 		u8 wdt_conf = superio_inb(wd->sioaddr,
39296cb4eb0SGiel van Schijndel 				F71808FG_REG_WDT_CONF);
39396cb4eb0SGiel van Schijndel 
39496cb4eb0SGiel van Schijndel 		/* Set WD_PSWIDTH bits (1:0) */
395a7876735SAhmad Fatoum 		wdt_conf = (wdt_conf & 0xfc) | (wd->pulse_val & 0x03);
39696cb4eb0SGiel van Schijndel 		/* Set WD_PULSE to "pulse" mode */
39796cb4eb0SGiel van Schijndel 		wdt_conf |= BIT(F71808FG_FLAG_WD_PULSE);
39896cb4eb0SGiel van Schijndel 
399a7876735SAhmad Fatoum 		superio_outb(wd->sioaddr, F71808FG_REG_WDT_CONF,
40096cb4eb0SGiel van Schijndel 				wdt_conf);
40196cb4eb0SGiel van Schijndel 	} else {
40296cb4eb0SGiel van Schijndel 		/* Select "level" output mode */
403a7876735SAhmad Fatoum 		superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
40496cb4eb0SGiel van Schijndel 				F71808FG_FLAG_WD_PULSE);
40596cb4eb0SGiel van Schijndel 	}
40696cb4eb0SGiel van Schijndel 
40796cb4eb0SGiel van Schijndel exit_superio:
408a7876735SAhmad Fatoum 	superio_exit(wd->sioaddr);
40996cb4eb0SGiel van Schijndel 
41096cb4eb0SGiel van Schijndel 	return err;
41196cb4eb0SGiel van Schijndel }
41296cb4eb0SGiel van Schijndel 
fintek_wdt_stop(struct watchdog_device * wdd)4138bea27edSAhmad Fatoum static int fintek_wdt_stop(struct watchdog_device *wdd)
41496cb4eb0SGiel van Schijndel {
415a7876735SAhmad Fatoum 	struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
4168bea27edSAhmad Fatoum 	int err;
41796cb4eb0SGiel van Schijndel 
418a7876735SAhmad Fatoum 	err = superio_enter(wd->sioaddr);
41996cb4eb0SGiel van Schijndel 	if (err)
4208bea27edSAhmad Fatoum 		return err;
421a7876735SAhmad Fatoum 	superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
42296cb4eb0SGiel van Schijndel 
423a7876735SAhmad Fatoum 	superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
42496cb4eb0SGiel van Schijndel 			F71808FG_FLAG_WD_EN);
42596cb4eb0SGiel van Schijndel 
426a7876735SAhmad Fatoum 	superio_exit(wd->sioaddr);
42796cb4eb0SGiel van Schijndel 
42896cb4eb0SGiel van Schijndel 	return 0;
42996cb4eb0SGiel van Schijndel }
43096cb4eb0SGiel van Schijndel 
fintek_wdt_is_running(struct fintek_wdt * wd,u8 wdt_conf)431a7876735SAhmad Fatoum static bool fintek_wdt_is_running(struct fintek_wdt *wd, u8 wdt_conf)
43296cb4eb0SGiel van Schijndel {
433a7876735SAhmad Fatoum 	return (superio_inb(wd->sioaddr, SIO_REG_ENABLE) & BIT(0))
4348bea27edSAhmad Fatoum 		&& (wdt_conf & BIT(F71808FG_FLAG_WD_EN));
43596cb4eb0SGiel van Schijndel }
43696cb4eb0SGiel van Schijndel 
4378bea27edSAhmad Fatoum static const struct watchdog_ops fintek_wdt_ops = {
43896cb4eb0SGiel van Schijndel 	.owner = THIS_MODULE,
4398bea27edSAhmad Fatoum 	.start = fintek_wdt_start,
4408bea27edSAhmad Fatoum 	.stop = fintek_wdt_stop,
4418bea27edSAhmad Fatoum 	.ping = fintek_wdt_keepalive,
4428bea27edSAhmad Fatoum 	.set_timeout = fintek_wdt_set_timeout,
44396cb4eb0SGiel van Schijndel };
44496cb4eb0SGiel van Schijndel 
fintek_wdt_probe(struct platform_device * pdev)44527e0fe00SAhmad Fatoum static int fintek_wdt_probe(struct platform_device *pdev)
44696cb4eb0SGiel van Schijndel {
44727e0fe00SAhmad Fatoum 	struct device *dev = &pdev->dev;
448a7876735SAhmad Fatoum 	struct fintek_wdt_pdata *pdata;
4498bea27edSAhmad Fatoum 	struct watchdog_device *wdd;
450a7876735SAhmad Fatoum 	struct fintek_wdt *wd;
45196cb4eb0SGiel van Schijndel 	int wdt_conf, err = 0;
45227e0fe00SAhmad Fatoum 	struct resource *res;
45327e0fe00SAhmad Fatoum 	int sioaddr;
45427e0fe00SAhmad Fatoum 
45527e0fe00SAhmad Fatoum 	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
45627e0fe00SAhmad Fatoum 	if (!res)
45727e0fe00SAhmad Fatoum 		return -ENXIO;
45827e0fe00SAhmad Fatoum 
45927e0fe00SAhmad Fatoum 	sioaddr = res->start;
46096cb4eb0SGiel van Schijndel 
461a7876735SAhmad Fatoum 	wd = devm_kzalloc(dev, sizeof(*wd), GFP_KERNEL);
462a7876735SAhmad Fatoum 	if (!wd)
463a7876735SAhmad Fatoum 		return -ENOMEM;
464a7876735SAhmad Fatoum 
465a7876735SAhmad Fatoum 	pdata = dev->platform_data;
466a7876735SAhmad Fatoum 
467a7876735SAhmad Fatoum 	wd->type = pdata->type;
468a7876735SAhmad Fatoum 	wd->sioaddr = sioaddr;
469a7876735SAhmad Fatoum 	wd->ident.options = WDIOF_SETTIMEOUT
4708bea27edSAhmad Fatoum 			| WDIOF_MAGICCLOSE
471e871e93fSAhmad Fatoum 			| WDIOF_KEEPALIVEPING
472e871e93fSAhmad Fatoum 			| WDIOF_CARDRESET;
47396cb4eb0SGiel van Schijndel 
474a7876735SAhmad Fatoum 	snprintf(wd->ident.identity,
475a7876735SAhmad Fatoum 		sizeof(wd->ident.identity), "%s watchdog",
476a7876735SAhmad Fatoum 		fintek_wdt_names[wd->type]);
47796cb4eb0SGiel van Schijndel 
47896cb4eb0SGiel van Schijndel 	err = superio_enter(sioaddr);
47996cb4eb0SGiel van Schijndel 	if (err)
48096cb4eb0SGiel van Schijndel 		return err;
481a7876735SAhmad Fatoum 	superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
48296cb4eb0SGiel van Schijndel 
48396cb4eb0SGiel van Schijndel 	wdt_conf = superio_inb(sioaddr, F71808FG_REG_WDT_CONF);
48496cb4eb0SGiel van Schijndel 
4854f39d575SAhmad Fatoum 	/*
4864f39d575SAhmad Fatoum 	 * We don't want WDTMOUT_STS to stick around till regular reboot.
4874f39d575SAhmad Fatoum 	 * Write 1 to the bit to clear it to zero.
4884f39d575SAhmad Fatoum 	 */
4894f39d575SAhmad Fatoum 	superio_outb(sioaddr, F71808FG_REG_WDT_CONF,
4904f39d575SAhmad Fatoum 		     wdt_conf | BIT(F71808FG_FLAG_WDTMOUT_STS));
4914f39d575SAhmad Fatoum 
492a7876735SAhmad Fatoum 	wdd = &wd->wdd;
4938bea27edSAhmad Fatoum 
494a7876735SAhmad Fatoum 	if (fintek_wdt_is_running(wd, wdt_conf))
4958bea27edSAhmad Fatoum 		set_bit(WDOG_HW_RUNNING, &wdd->status);
4968bea27edSAhmad Fatoum 
49796cb4eb0SGiel van Schijndel 	superio_exit(sioaddr);
49896cb4eb0SGiel van Schijndel 
49927e0fe00SAhmad Fatoum 	wdd->parent		= dev;
500a7876735SAhmad Fatoum 	wdd->info               = &wd->ident;
5018bea27edSAhmad Fatoum 	wdd->ops                = &fintek_wdt_ops;
5028bea27edSAhmad Fatoum 	wdd->min_timeout        = 1;
5038bea27edSAhmad Fatoum 	wdd->max_timeout        = WATCHDOG_MAX_TIMEOUT;
50496cb4eb0SGiel van Schijndel 
505a7876735SAhmad Fatoum 	watchdog_set_drvdata(wdd, wd);
5068bea27edSAhmad Fatoum 	watchdog_set_nowayout(wdd, nowayout);
5078bea27edSAhmad Fatoum 	watchdog_stop_on_unregister(wdd);
5088bea27edSAhmad Fatoum 	watchdog_stop_on_reboot(wdd);
5098bea27edSAhmad Fatoum 	watchdog_init_timeout(wdd, start_withtimeout ?: timeout, NULL);
51096cb4eb0SGiel van Schijndel 
5118bea27edSAhmad Fatoum 	if (wdt_conf & BIT(F71808FG_FLAG_WDTMOUT_STS))
5128bea27edSAhmad Fatoum 		wdd->bootstatus = WDIOF_CARDRESET;
5138bea27edSAhmad Fatoum 
5148bea27edSAhmad Fatoum 	/*
5158bea27edSAhmad Fatoum 	 * WATCHDOG_HANDLE_BOOT_ENABLED can result in keepalive being directly
5168bea27edSAhmad Fatoum 	 * called without a set_timeout before, so it needs to be done here
5178bea27edSAhmad Fatoum 	 * unconditionally.
5188bea27edSAhmad Fatoum 	 */
5198bea27edSAhmad Fatoum 	fintek_wdt_set_timeout(wdd, wdd->timeout);
520a7876735SAhmad Fatoum 	fintek_wdt_set_pulse_width(wd, pulse_width);
52196cb4eb0SGiel van Schijndel 
52296cb4eb0SGiel van Schijndel 	if (start_withtimeout) {
5238bea27edSAhmad Fatoum 		err = fintek_wdt_start(wdd);
52496cb4eb0SGiel van Schijndel 		if (err) {
52527e0fe00SAhmad Fatoum 			dev_err(dev, "cannot start watchdog timer\n");
5268bea27edSAhmad Fatoum 			return err;
52796cb4eb0SGiel van Schijndel 		}
52896cb4eb0SGiel van Schijndel 
5298bea27edSAhmad Fatoum 		set_bit(WDOG_HW_RUNNING, &wdd->status);
53027e0fe00SAhmad Fatoum 		dev_info(dev, "watchdog started with initial timeout of %u sec\n",
53196cb4eb0SGiel van Schijndel 			 start_withtimeout);
53296cb4eb0SGiel van Schijndel 	}
53396cb4eb0SGiel van Schijndel 
53427e0fe00SAhmad Fatoum 	return devm_watchdog_register_device(dev, wdd);
53596cb4eb0SGiel van Schijndel }
53696cb4eb0SGiel van Schijndel 
fintek_wdt_find(int sioaddr)5373a2c4895SAhmad Fatoum static int __init fintek_wdt_find(int sioaddr)
53896cb4eb0SGiel van Schijndel {
539a7876735SAhmad Fatoum 	enum chips type;
54096cb4eb0SGiel van Schijndel 	u16 devid;
54196cb4eb0SGiel van Schijndel 	int err = superio_enter(sioaddr);
54296cb4eb0SGiel van Schijndel 	if (err)
54396cb4eb0SGiel van Schijndel 		return err;
54496cb4eb0SGiel van Schijndel 
54596cb4eb0SGiel van Schijndel 	devid = superio_inw(sioaddr, SIO_REG_MANID);
54696cb4eb0SGiel van Schijndel 	if (devid != SIO_FINTEK_ID) {
54727c766aaSJoe Perches 		pr_debug("Not a Fintek device\n");
54896cb4eb0SGiel van Schijndel 		err = -ENODEV;
54996cb4eb0SGiel van Schijndel 		goto exit;
55096cb4eb0SGiel van Schijndel 	}
55196cb4eb0SGiel van Schijndel 
55296cb4eb0SGiel van Schijndel 	devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
55396cb4eb0SGiel van Schijndel 	switch (devid) {
55496cb4eb0SGiel van Schijndel 	case SIO_F71808_ID:
555a7876735SAhmad Fatoum 		type = f71808fg;
55696cb4eb0SGiel van Schijndel 		break;
5577977ff6eSLutz Ballaschke 	case SIO_F71862_ID:
558a7876735SAhmad Fatoum 		type = f71862fg;
5597977ff6eSLutz Ballaschke 		break;
560166fbcf8SMaciej S. Szmigiero 	case SIO_F71868_ID:
561a7876735SAhmad Fatoum 		type = f71868;
562166fbcf8SMaciej S. Szmigiero 		break;
563df278dacSMichel Arboi 	case SIO_F71869_ID:
5643017020dSJustin Wheeler 	case SIO_F71869A_ID:
565a7876735SAhmad Fatoum 		type = f71869;
566df278dacSMichel Arboi 		break;
56796cb4eb0SGiel van Schijndel 	case SIO_F71882_ID:
568a7876735SAhmad Fatoum 		type = f71882fg;
56996cb4eb0SGiel van Schijndel 		break;
57096cb4eb0SGiel van Schijndel 	case SIO_F71889_ID:
571a7876735SAhmad Fatoum 		type = f71889fg;
572dee00abbSGiel van Schijndel 		break;
57396cb4eb0SGiel van Schijndel 	case SIO_F71858_ID:
57496cb4eb0SGiel van Schijndel 		/* Confirmed (by datasheet) not to have a watchdog. */
57596cb4eb0SGiel van Schijndel 		err = -ENODEV;
57696cb4eb0SGiel van Schijndel 		goto exit;
577ca2fc5efSJaret Cantu 	case SIO_F81803_ID:
578a7876735SAhmad Fatoum 		type = f81803;
579ca2fc5efSJaret Cantu 		break;
580ea0c03e8SKnud Poulsen 	case SIO_F81865_ID:
581a7876735SAhmad Fatoum 		type = f81865;
582ea0c03e8SKnud Poulsen 		break;
58314b24a88SJi-Ze Hong (Peter Hong) 	case SIO_F81866_ID:
584a7876735SAhmad Fatoum 		type = f81866;
58514b24a88SJi-Ze Hong (Peter Hong) 		break;
586cea62f9fSAaeonIot 	case SIO_F81966_ID:
587cea62f9fSAaeonIot 		type = f81966;
588cea62f9fSAaeonIot 		break;
58996cb4eb0SGiel van Schijndel 	default:
59027c766aaSJoe Perches 		pr_info("Unrecognized Fintek device: %04x\n",
59196cb4eb0SGiel van Schijndel 			(unsigned int)devid);
59296cb4eb0SGiel van Schijndel 		err = -ENODEV;
59396cb4eb0SGiel van Schijndel 		goto exit;
59496cb4eb0SGiel van Schijndel 	}
59596cb4eb0SGiel van Schijndel 
59627c766aaSJoe Perches 	pr_info("Found %s watchdog chip, revision %d\n",
597a7876735SAhmad Fatoum 		fintek_wdt_names[type],
59896cb4eb0SGiel van Schijndel 		(int)superio_inb(sioaddr, SIO_REG_DEVREV));
599a7876735SAhmad Fatoum 
60096cb4eb0SGiel van Schijndel exit:
60196cb4eb0SGiel van Schijndel 	superio_exit(sioaddr);
602a7876735SAhmad Fatoum 	return err ? err : type;
60396cb4eb0SGiel van Schijndel }
60496cb4eb0SGiel van Schijndel 
60527e0fe00SAhmad Fatoum static struct platform_driver fintek_wdt_driver = {
60627e0fe00SAhmad Fatoum 	.probe          = fintek_wdt_probe,
60727e0fe00SAhmad Fatoum 	.driver         = {
60827e0fe00SAhmad Fatoum 		.name   = DRVNAME,
60927e0fe00SAhmad Fatoum 	},
61027e0fe00SAhmad Fatoum };
61127e0fe00SAhmad Fatoum 
61227e0fe00SAhmad Fatoum static struct platform_device *fintek_wdt_pdev;
61327e0fe00SAhmad Fatoum 
fintek_wdt_init(void)6143a2c4895SAhmad Fatoum static int __init fintek_wdt_init(void)
61596cb4eb0SGiel van Schijndel {
61696cb4eb0SGiel van Schijndel 	static const unsigned short addrs[] = { 0x2e, 0x4e };
617a7876735SAhmad Fatoum 	struct fintek_wdt_pdata pdata;
61827e0fe00SAhmad Fatoum 	struct resource wdt_res = {};
619a7876735SAhmad Fatoum 	int ret;
62096cb4eb0SGiel van Schijndel 	int i;
62196cb4eb0SGiel van Schijndel 
6225edc8c68SAhmad Fatoum 	if (f71862fg_pin != 63 && f71862fg_pin != 56) {
6235edc8c68SAhmad Fatoum 		pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin);
6245edc8c68SAhmad Fatoum 		return -EINVAL;
6255edc8c68SAhmad Fatoum 	}
6265edc8c68SAhmad Fatoum 
62796cb4eb0SGiel van Schijndel 	for (i = 0; i < ARRAY_SIZE(addrs); i++) {
628a7876735SAhmad Fatoum 		ret = fintek_wdt_find(addrs[i]);
629a7876735SAhmad Fatoum 		if (ret >= 0)
63096cb4eb0SGiel van Schijndel 			break;
63196cb4eb0SGiel van Schijndel 	}
63296cb4eb0SGiel van Schijndel 	if (i == ARRAY_SIZE(addrs))
633a7876735SAhmad Fatoum 		return ret;
634a7876735SAhmad Fatoum 
635a7876735SAhmad Fatoum 	pdata.type = ret;
63696cb4eb0SGiel van Schijndel 
637*97d5ec54SJiasheng Jiang 	ret = platform_driver_register(&fintek_wdt_driver);
638*97d5ec54SJiasheng Jiang 	if (ret)
639*97d5ec54SJiasheng Jiang 		return ret;
64027e0fe00SAhmad Fatoum 
64127e0fe00SAhmad Fatoum 	wdt_res.name = "superio port";
64227e0fe00SAhmad Fatoum 	wdt_res.flags = IORESOURCE_IO;
64327e0fe00SAhmad Fatoum 	wdt_res.start = addrs[i];
64427e0fe00SAhmad Fatoum 	wdt_res.end   = addrs[i] + 1;
64527e0fe00SAhmad Fatoum 
646a7876735SAhmad Fatoum 	fintek_wdt_pdev = platform_device_register_resndata(NULL, DRVNAME, -1,
647a7876735SAhmad Fatoum 							    &wdt_res, 1,
648a7876735SAhmad Fatoum 							    &pdata, sizeof(pdata));
64927e0fe00SAhmad Fatoum 	if (IS_ERR(fintek_wdt_pdev)) {
65027e0fe00SAhmad Fatoum 		platform_driver_unregister(&fintek_wdt_driver);
65127e0fe00SAhmad Fatoum 		return PTR_ERR(fintek_wdt_pdev);
65227e0fe00SAhmad Fatoum 	}
65327e0fe00SAhmad Fatoum 
65427e0fe00SAhmad Fatoum 	return 0;
65596cb4eb0SGiel van Schijndel }
65696cb4eb0SGiel van Schijndel 
fintek_wdt_exit(void)6573a2c4895SAhmad Fatoum static void __exit fintek_wdt_exit(void)
65896cb4eb0SGiel van Schijndel {
65927e0fe00SAhmad Fatoum 	platform_device_unregister(fintek_wdt_pdev);
66027e0fe00SAhmad Fatoum 	platform_driver_unregister(&fintek_wdt_driver);
66196cb4eb0SGiel van Schijndel }
66296cb4eb0SGiel van Schijndel 
66396cb4eb0SGiel van Schijndel MODULE_DESCRIPTION("F71808E Watchdog Driver");
66496cb4eb0SGiel van Schijndel MODULE_AUTHOR("Giel van Schijndel <me@mortis.eu>");
66596cb4eb0SGiel van Schijndel MODULE_LICENSE("GPL");
66696cb4eb0SGiel van Schijndel 
6673a2c4895SAhmad Fatoum module_init(fintek_wdt_init);
6683a2c4895SAhmad Fatoum module_exit(fintek_wdt_exit);
669