Merge tag 'drm-misc-next-2022-11-24' of git://anongit.freedesktop.org/drm/drm-misc...
[linux-block.git] / drivers / watchdog / f71808e_wdt.c
CommitLineData
1a59d1b8 1// SPDX-License-Identifier: GPL-2.0-or-later
96cb4eb0
GS
2/***************************************************************************
3 * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> *
4 * Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com> *
5 * Copyright (C) 2010 Giel van Schijndel <me@mortis.eu> *
6 * *
96cb4eb0
GS
7 ***************************************************************************/
8
27c766aa
JP
9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10
96cb4eb0 11#include <linux/err.h>
96cb4eb0
GS
12#include <linux/init.h>
13#include <linux/io.h>
14#include <linux/ioport.h>
96cb4eb0 15#include <linux/module.h>
27e0fe00 16#include <linux/platform_device.h>
96cb4eb0
GS
17#include <linux/watchdog.h>
18
19#define DRVNAME "f71808e_wdt"
20
21#define SIO_F71808FG_LD_WDT 0x07 /* Watchdog timer logical device */
22#define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */
85c130a8 23#define SIO_LOCK_KEY 0xAA /* Key to disable Super-I/O */
96cb4eb0
GS
24
25#define SIO_REG_LDSEL 0x07 /* Logical device select */
26#define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */
27#define SIO_REG_DEVREV 0x22 /* Device revision */
28#define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */
ca2fc5ef 29#define SIO_REG_CLOCK_SEL 0x26 /* Clock select */
7977ff6e 30#define SIO_REG_ROM_ADDR_SEL 0x27 /* ROM address select */
14b24a88 31#define SIO_F81866_REG_PORT_SEL 0x27 /* F81866 Multi-Function Register */
ca2fc5ef 32#define SIO_REG_TSI_LEVEL_SEL 0x28 /* TSI Level select */
f9a9f096
LB
33#define SIO_REG_MFUNCT1 0x29 /* Multi function select 1 */
34#define SIO_REG_MFUNCT2 0x2a /* Multi function select 2 */
35#define SIO_REG_MFUNCT3 0x2b /* Multi function select 3 */
14b24a88 36#define SIO_F81866_REG_GPIO1 0x2c /* F81866 GPIO1 Enable Register */
96cb4eb0
GS
37#define SIO_REG_ENABLE 0x30 /* Logical device enable */
38#define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */
39
40#define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */
f9a9f096
LB
41#define SIO_F71808_ID 0x0901 /* Chipset ID */
42#define SIO_F71858_ID 0x0507 /* Chipset ID */
96cb4eb0 43#define SIO_F71862_ID 0x0601 /* Chipset ID */
166fbcf8 44#define SIO_F71868_ID 0x1106 /* Chipset ID */
df278dac 45#define SIO_F71869_ID 0x0814 /* Chipset ID */
3017020d 46#define SIO_F71869A_ID 0x1007 /* Chipset ID */
96cb4eb0
GS
47#define SIO_F71882_ID 0x0541 /* Chipset ID */
48#define SIO_F71889_ID 0x0723 /* Chipset ID */
ca2fc5ef 49#define SIO_F81803_ID 0x1210 /* Chipset ID */
ea0c03e8 50#define SIO_F81865_ID 0x0704 /* Chipset ID */
14b24a88 51#define SIO_F81866_ID 0x1010 /* Chipset ID */
cea62f9f 52#define SIO_F81966_ID 0x1502 /* F81804 chipset ID, same for f81966 */
96cb4eb0 53
96cb4eb0
GS
54#define F71808FG_REG_WDO_CONF 0xf0
55#define F71808FG_REG_WDT_CONF 0xf5
56#define F71808FG_REG_WD_TIME 0xf6
57
58#define F71808FG_FLAG_WDOUT_EN 7
59
b97cb21a 60#define F71808FG_FLAG_WDTMOUT_STS 6
96cb4eb0
GS
61#define F71808FG_FLAG_WD_EN 5
62#define F71808FG_FLAG_WD_PULSE 4
63#define F71808FG_FLAG_WD_UNIT 3
64
ea0c03e8
KP
65#define F81865_REG_WDO_CONF 0xfa
66#define F81865_FLAG_WDOUT_EN 0
67
96cb4eb0
GS
68/* Default values */
69#define WATCHDOG_TIMEOUT 60 /* 1 minute default timeout */
70#define WATCHDOG_MAX_TIMEOUT (60 * 255)
71#define WATCHDOG_PULSE_WIDTH 125 /* 125 ms, default pulse width for
72 watchdog signal */
7977ff6e
LB
73#define WATCHDOG_F71862FG_PIN 63 /* default watchdog reset output
74 pin number 63 */
96cb4eb0
GS
75
76static unsigned short force_id;
77module_param(force_id, ushort, 0);
78MODULE_PARM_DESC(force_id, "Override the detected device ID");
79
f9a9f096 80static int timeout = WATCHDOG_TIMEOUT; /* default timeout in seconds */
96cb4eb0
GS
81module_param(timeout, int, 0);
82MODULE_PARM_DESC(timeout,
83 "Watchdog timeout in seconds. 1<= timeout <="
84 __MODULE_STRING(WATCHDOG_MAX_TIMEOUT) " (default="
85 __MODULE_STRING(WATCHDOG_TIMEOUT) ")");
86
87static unsigned int pulse_width = WATCHDOG_PULSE_WIDTH;
88module_param(pulse_width, uint, 0);
89MODULE_PARM_DESC(pulse_width,
166fbcf8 90 "Watchdog signal pulse width. 0(=level), 1, 25, 30, 125, 150, 5000 or 6000 ms"
96cb4eb0
GS
91 " (default=" __MODULE_STRING(WATCHDOG_PULSE_WIDTH) ")");
92
7977ff6e
LB
93static unsigned int f71862fg_pin = WATCHDOG_F71862FG_PIN;
94module_param(f71862fg_pin, uint, 0);
95MODULE_PARM_DESC(f71862fg_pin,
96 "Watchdog f71862fg reset output pin configuration. Choose pin 56 or 63"
97 " (default=" __MODULE_STRING(WATCHDOG_F71862FG_PIN)")");
98
90ab5ee9 99static bool nowayout = WATCHDOG_NOWAYOUT;
96cb4eb0
GS
100module_param(nowayout, bool, 0444);
101MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
102
103static unsigned int start_withtimeout;
104module_param(start_withtimeout, uint, 0);
105MODULE_PARM_DESC(start_withtimeout, "Start watchdog timer on module load with"
106 " given initial timeout. Zero (default) disables this feature.");
107
166fbcf8 108enum chips { f71808fg, f71858fg, f71862fg, f71868, f71869, f71882fg, f71889fg,
cea62f9f 109 f81803, f81865, f81866, f81966};
96cb4eb0 110
3a2c4895 111static const char * const fintek_wdt_names[] = {
96cb4eb0
GS
112 "f71808fg",
113 "f71858fg",
114 "f71862fg",
166fbcf8 115 "f71868",
df278dac 116 "f71869",
96cb4eb0
GS
117 "f71882fg",
118 "f71889fg",
ca2fc5ef 119 "f81803",
ea0c03e8 120 "f81865",
14b24a88 121 "f81866",
cea62f9f 122 "f81966"
96cb4eb0
GS
123};
124
125/* Super-I/O Function prototypes */
126static inline int superio_inb(int base, int reg);
127static inline int superio_inw(int base, int reg);
128static inline void superio_outb(int base, int reg, u8 val);
129static inline void superio_set_bit(int base, int reg, int bit);
130static inline void superio_clear_bit(int base, int reg, int bit);
131static inline int superio_enter(int base);
132static inline void superio_select(int base, int ld);
133static inline void superio_exit(int base);
134
3a2c4895 135struct fintek_wdt {
8bea27ed 136 struct watchdog_device wdd;
96cb4eb0
GS
137 unsigned short sioaddr;
138 enum chips type;
96cb4eb0
GS
139 struct watchdog_info ident;
140
96cb4eb0
GS
141 u8 timer_val; /* content for the wd_time register */
142 char minutes_mode;
143 u8 pulse_val; /* pulse width flag */
144 char pulse_mode; /* enable pulse output mode? */
96cb4eb0
GS
145};
146
a7876735
AF
147struct fintek_wdt_pdata {
148 enum chips type;
149};
96cb4eb0
GS
150
151/* Super I/O functions */
152static inline int superio_inb(int base, int reg)
153{
154 outb(reg, base);
155 return inb(base + 1);
156}
157
158static int superio_inw(int base, int reg)
159{
160 int val;
161 val = superio_inb(base, reg) << 8;
162 val |= superio_inb(base, reg + 1);
163 return val;
164}
165
166static inline void superio_outb(int base, int reg, u8 val)
167{
168 outb(reg, base);
169 outb(val, base + 1);
170}
171
172static inline void superio_set_bit(int base, int reg, int bit)
173{
174 unsigned long val = superio_inb(base, reg);
175 __set_bit(bit, &val);
176 superio_outb(base, reg, val);
177}
178
179static inline void superio_clear_bit(int base, int reg, int bit)
180{
181 unsigned long val = superio_inb(base, reg);
182 __clear_bit(bit, &val);
183 superio_outb(base, reg, val);
184}
185
186static inline int superio_enter(int base)
187{
188 /* Don't step on other drivers' I/O space by accident */
189 if (!request_muxed_region(base, 2, DRVNAME)) {
27c766aa 190 pr_err("I/O address 0x%04x already in use\n", (int)base);
96cb4eb0
GS
191 return -EBUSY;
192 }
193
3017020d 194 /* according to the datasheet the key must be sent twice! */
96cb4eb0
GS
195 outb(SIO_UNLOCK_KEY, base);
196 outb(SIO_UNLOCK_KEY, base);
197
198 return 0;
199}
200
201static inline void superio_select(int base, int ld)
202{
203 outb(SIO_REG_LDSEL, base);
204 outb(ld, base + 1);
205}
206
207static inline void superio_exit(int base)
208{
209 outb(SIO_LOCK_KEY, base);
210 release_region(base, 2);
211}
212
8bea27ed 213static int fintek_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
96cb4eb0 214{
a7876735
AF
215 struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
216
96cb4eb0 217 if (timeout > 0xff) {
a7876735
AF
218 wd->timer_val = DIV_ROUND_UP(timeout, 60);
219 wd->minutes_mode = true;
220 timeout = wd->timer_val * 60;
96cb4eb0 221 } else {
a7876735
AF
222 wd->timer_val = timeout;
223 wd->minutes_mode = false;
96cb4eb0
GS
224 }
225
8bea27ed 226 wdd->timeout = timeout;
96cb4eb0
GS
227
228 return 0;
229}
230
a7876735 231static int fintek_wdt_set_pulse_width(struct fintek_wdt *wd, unsigned int pw)
96cb4eb0 232{
166fbcf8
MS
233 unsigned int t1 = 25, t2 = 125, t3 = 5000;
234
a7876735 235 if (wd->type == f71868) {
166fbcf8
MS
236 t1 = 30;
237 t2 = 150;
238 t3 = 6000;
239 }
96cb4eb0 240
166fbcf8 241 if (pw <= 1) {
a7876735 242 wd->pulse_val = 0;
166fbcf8 243 } else if (pw <= t1) {
a7876735 244 wd->pulse_val = 1;
166fbcf8 245 } else if (pw <= t2) {
a7876735 246 wd->pulse_val = 2;
166fbcf8 247 } else if (pw <= t3) {
a7876735 248 wd->pulse_val = 3;
96cb4eb0 249 } else {
27c766aa 250 pr_err("pulse width out of range\n");
8bea27ed 251 return -EINVAL;
96cb4eb0
GS
252 }
253
a7876735 254 wd->pulse_mode = pw;
96cb4eb0 255
8bea27ed 256 return 0;
96cb4eb0
GS
257}
258
8bea27ed 259static int fintek_wdt_keepalive(struct watchdog_device *wdd)
96cb4eb0 260{
a7876735 261 struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
8bea27ed 262 int err;
96cb4eb0 263
a7876735 264 err = superio_enter(wd->sioaddr);
96cb4eb0 265 if (err)
8bea27ed 266 return err;
a7876735 267 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
96cb4eb0 268
a7876735 269 if (wd->minutes_mode)
96cb4eb0 270 /* select minutes for timer units */
a7876735 271 superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
96cb4eb0
GS
272 F71808FG_FLAG_WD_UNIT);
273 else
274 /* select seconds for timer units */
a7876735 275 superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
96cb4eb0
GS
276 F71808FG_FLAG_WD_UNIT);
277
278 /* Set timer value */
a7876735
AF
279 superio_outb(wd->sioaddr, F71808FG_REG_WD_TIME,
280 wd->timer_val);
96cb4eb0 281
a7876735 282 superio_exit(wd->sioaddr);
96cb4eb0 283
8bea27ed 284 return 0;
96cb4eb0
GS
285}
286
8bea27ed 287static int fintek_wdt_start(struct watchdog_device *wdd)
96cb4eb0 288{
a7876735 289 struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
a3f764d2 290 int err;
e347afa5 291 u8 tmp;
a3f764d2 292
96cb4eb0 293 /* Make sure we don't die as soon as the watchdog is enabled below */
8bea27ed 294 err = fintek_wdt_keepalive(wdd);
96cb4eb0
GS
295 if (err)
296 return err;
297
a7876735 298 err = superio_enter(wd->sioaddr);
96cb4eb0 299 if (err)
8bea27ed 300 return err;
a7876735 301 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
96cb4eb0
GS
302
303 /* Watchdog pin configuration */
a7876735 304 switch (wd->type) {
96cb4eb0
GS
305 case f71808fg:
306 /* Set pin 21 to GPIO23/WDTRST#, then to WDTRST# */
a7876735
AF
307 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT2, 3);
308 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 3);
96cb4eb0
GS
309 break;
310
7977ff6e 311 case f71862fg:
5edc8c68
AF
312 if (f71862fg_pin == 63) {
313 /* SPI must be disabled first to use this pin! */
a7876735
AF
314 superio_clear_bit(wd->sioaddr, SIO_REG_ROM_ADDR_SEL, 6);
315 superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT3, 4);
5edc8c68 316 } else if (f71862fg_pin == 56) {
a7876735 317 superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
5edc8c68 318 }
7977ff6e
LB
319 break;
320
166fbcf8 321 case f71868:
df278dac
MA
322 case f71869:
323 /* GPIO14 --> WDTRST# */
a7876735 324 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT1, 4);
df278dac
MA
325 break;
326
96cb4eb0
GS
327 case f71882fg:
328 /* Set pin 56 to WDTRST# */
a7876735 329 superio_set_bit(wd->sioaddr, SIO_REG_MFUNCT1, 1);
96cb4eb0
GS
330 break;
331
dee00abb
GS
332 case f71889fg:
333 /* set pin 40 to WDTRST# */
a7876735
AF
334 superio_outb(wd->sioaddr, SIO_REG_MFUNCT3,
335 superio_inb(wd->sioaddr, SIO_REG_MFUNCT3) & 0xcf);
dee00abb
GS
336 break;
337
ca2fc5ef
JC
338 case f81803:
339 /* Enable TSI Level register bank */
a7876735 340 superio_clear_bit(wd->sioaddr, SIO_REG_CLOCK_SEL, 3);
ca2fc5ef 341 /* Set pin 27 to WDTRST# */
a7876735
AF
342 superio_outb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL, 0x5f &
343 superio_inb(wd->sioaddr, SIO_REG_TSI_LEVEL_SEL));
ca2fc5ef
JC
344 break;
345
ea0c03e8
KP
346 case f81865:
347 /* Set pin 70 to WDTRST# */
a7876735 348 superio_clear_bit(wd->sioaddr, SIO_REG_MFUNCT3, 5);
ea0c03e8
KP
349 break;
350
14b24a88 351 case f81866:
cea62f9f 352 case f81966:
14b24a88
JZHPH
353 /*
354 * GPIO1 Control Register when 27h BIT3:2 = 01 & BIT0 = 0.
355 * The PIN 70(GPIO15/WDTRST) is controlled by 2Ch:
356 * BIT5: 0 -> WDTRST#
357 * 1 -> GPIO15
358 */
a7876735 359 tmp = superio_inb(wd->sioaddr, SIO_F81866_REG_PORT_SEL);
e347afa5
JZHPH
360 tmp &= ~(BIT(3) | BIT(0));
361 tmp |= BIT(2);
a7876735 362 superio_outb(wd->sioaddr, SIO_F81866_REG_PORT_SEL, tmp);
e347afa5 363
a7876735 364 superio_clear_bit(wd->sioaddr, SIO_F81866_REG_GPIO1, 5);
14b24a88
JZHPH
365 break;
366
96cb4eb0
GS
367 default:
368 /*
369 * 'default' label to shut up the compiler and catch
370 * programmer errors
371 */
372 err = -ENODEV;
373 goto exit_superio;
374 }
375
a7876735
AF
376 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
377 superio_set_bit(wd->sioaddr, SIO_REG_ENABLE, 0);
ea0c03e8 378
cea62f9f 379 if (wd->type == f81865 || wd->type == f81866 || wd->type == f81966)
a7876735 380 superio_set_bit(wd->sioaddr, F81865_REG_WDO_CONF,
ea0c03e8
KP
381 F81865_FLAG_WDOUT_EN);
382 else
a7876735 383 superio_set_bit(wd->sioaddr, F71808FG_REG_WDO_CONF,
ea0c03e8 384 F71808FG_FLAG_WDOUT_EN);
96cb4eb0 385
a7876735 386 superio_set_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
96cb4eb0
GS
387 F71808FG_FLAG_WD_EN);
388
a7876735 389 if (wd->pulse_mode) {
96cb4eb0 390 /* Select "pulse" output mode with given duration */
a7876735 391 u8 wdt_conf = superio_inb(wd->sioaddr,
96cb4eb0
GS
392 F71808FG_REG_WDT_CONF);
393
394 /* Set WD_PSWIDTH bits (1:0) */
a7876735 395 wdt_conf = (wdt_conf & 0xfc) | (wd->pulse_val & 0x03);
96cb4eb0
GS
396 /* Set WD_PULSE to "pulse" mode */
397 wdt_conf |= BIT(F71808FG_FLAG_WD_PULSE);
398
a7876735 399 superio_outb(wd->sioaddr, F71808FG_REG_WDT_CONF,
96cb4eb0
GS
400 wdt_conf);
401 } else {
402 /* Select "level" output mode */
a7876735 403 superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
96cb4eb0
GS
404 F71808FG_FLAG_WD_PULSE);
405 }
406
407exit_superio:
a7876735 408 superio_exit(wd->sioaddr);
96cb4eb0
GS
409
410 return err;
411}
412
8bea27ed 413static int fintek_wdt_stop(struct watchdog_device *wdd)
96cb4eb0 414{
a7876735 415 struct fintek_wdt *wd = watchdog_get_drvdata(wdd);
8bea27ed 416 int err;
96cb4eb0 417
a7876735 418 err = superio_enter(wd->sioaddr);
96cb4eb0 419 if (err)
8bea27ed 420 return err;
a7876735 421 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
96cb4eb0 422
a7876735 423 superio_clear_bit(wd->sioaddr, F71808FG_REG_WDT_CONF,
96cb4eb0
GS
424 F71808FG_FLAG_WD_EN);
425
a7876735 426 superio_exit(wd->sioaddr);
96cb4eb0 427
96cb4eb0
GS
428 return 0;
429}
430
a7876735 431static bool fintek_wdt_is_running(struct fintek_wdt *wd, u8 wdt_conf)
96cb4eb0 432{
a7876735 433 return (superio_inb(wd->sioaddr, SIO_REG_ENABLE) & BIT(0))
8bea27ed 434 && (wdt_conf & BIT(F71808FG_FLAG_WD_EN));
96cb4eb0
GS
435}
436
8bea27ed
AF
437static const struct watchdog_ops fintek_wdt_ops = {
438 .owner = THIS_MODULE,
439 .start = fintek_wdt_start,
440 .stop = fintek_wdt_stop,
441 .ping = fintek_wdt_keepalive,
442 .set_timeout = fintek_wdt_set_timeout,
96cb4eb0
GS
443};
444
27e0fe00 445static int fintek_wdt_probe(struct platform_device *pdev)
96cb4eb0 446{
27e0fe00 447 struct device *dev = &pdev->dev;
a7876735 448 struct fintek_wdt_pdata *pdata;
8bea27ed 449 struct watchdog_device *wdd;
a7876735 450 struct fintek_wdt *wd;
96cb4eb0 451 int wdt_conf, err = 0;
27e0fe00
AF
452 struct resource *res;
453 int sioaddr;
454
455 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
456 if (!res)
457 return -ENXIO;
458
459 sioaddr = res->start;
96cb4eb0 460
a7876735
AF
461 wd = devm_kzalloc(dev, sizeof(*wd), GFP_KERNEL);
462 if (!wd)
463 return -ENOMEM;
464
465 pdata = dev->platform_data;
466
467 wd->type = pdata->type;
468 wd->sioaddr = sioaddr;
469 wd->ident.options = WDIOF_SETTIMEOUT
470 | WDIOF_MAGICCLOSE
471 | WDIOF_KEEPALIVEPING
472 | WDIOF_CARDRESET;
96cb4eb0 473
a7876735
AF
474 snprintf(wd->ident.identity,
475 sizeof(wd->ident.identity), "%s watchdog",
476 fintek_wdt_names[wd->type]);
96cb4eb0
GS
477
478 err = superio_enter(sioaddr);
479 if (err)
480 return err;
a7876735 481 superio_select(wd->sioaddr, SIO_F71808FG_LD_WDT);
96cb4eb0
GS
482
483 wdt_conf = superio_inb(sioaddr, F71808FG_REG_WDT_CONF);
96cb4eb0 484
4f39d575
AF
485 /*
486 * We don't want WDTMOUT_STS to stick around till regular reboot.
487 * Write 1 to the bit to clear it to zero.
488 */
489 superio_outb(sioaddr, F71808FG_REG_WDT_CONF,
490 wdt_conf | BIT(F71808FG_FLAG_WDTMOUT_STS));
491
a7876735 492 wdd = &wd->wdd;
8bea27ed 493
a7876735 494 if (fintek_wdt_is_running(wd, wdt_conf))
8bea27ed
AF
495 set_bit(WDOG_HW_RUNNING, &wdd->status);
496
96cb4eb0
GS
497 superio_exit(sioaddr);
498
27e0fe00 499 wdd->parent = dev;
a7876735 500 wdd->info = &wd->ident;
8bea27ed
AF
501 wdd->ops = &fintek_wdt_ops;
502 wdd->min_timeout = 1;
503 wdd->max_timeout = WATCHDOG_MAX_TIMEOUT;
96cb4eb0 504
a7876735 505 watchdog_set_drvdata(wdd, wd);
8bea27ed
AF
506 watchdog_set_nowayout(wdd, nowayout);
507 watchdog_stop_on_unregister(wdd);
508 watchdog_stop_on_reboot(wdd);
509 watchdog_init_timeout(wdd, start_withtimeout ?: timeout, NULL);
96cb4eb0 510
8bea27ed
AF
511 if (wdt_conf & BIT(F71808FG_FLAG_WDTMOUT_STS))
512 wdd->bootstatus = WDIOF_CARDRESET;
96cb4eb0 513
8bea27ed
AF
514 /*
515 * WATCHDOG_HANDLE_BOOT_ENABLED can result in keepalive being directly
516 * called without a set_timeout before, so it needs to be done here
517 * unconditionally.
518 */
519 fintek_wdt_set_timeout(wdd, wdd->timeout);
a7876735 520 fintek_wdt_set_pulse_width(wd, pulse_width);
96cb4eb0 521
8bea27ed
AF
522 if (start_withtimeout) {
523 err = fintek_wdt_start(wdd);
96cb4eb0 524 if (err) {
27e0fe00 525 dev_err(dev, "cannot start watchdog timer\n");
8bea27ed 526 return err;
96cb4eb0
GS
527 }
528
8bea27ed 529 set_bit(WDOG_HW_RUNNING, &wdd->status);
27e0fe00
AF
530 dev_info(dev, "watchdog started with initial timeout of %u sec\n",
531 start_withtimeout);
96cb4eb0
GS
532 }
533
27e0fe00 534 return devm_watchdog_register_device(dev, wdd);
96cb4eb0
GS
535}
536
3a2c4895 537static int __init fintek_wdt_find(int sioaddr)
96cb4eb0 538{
a7876735 539 enum chips type;
96cb4eb0
GS
540 u16 devid;
541 int err = superio_enter(sioaddr);
542 if (err)
543 return err;
544
545 devid = superio_inw(sioaddr, SIO_REG_MANID);
546 if (devid != SIO_FINTEK_ID) {
27c766aa 547 pr_debug("Not a Fintek device\n");
96cb4eb0
GS
548 err = -ENODEV;
549 goto exit;
550 }
551
552 devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID);
553 switch (devid) {
554 case SIO_F71808_ID:
a7876735 555 type = f71808fg;
96cb4eb0 556 break;
7977ff6e 557 case SIO_F71862_ID:
a7876735 558 type = f71862fg;
7977ff6e 559 break;
166fbcf8 560 case SIO_F71868_ID:
a7876735 561 type = f71868;
166fbcf8 562 break;
df278dac 563 case SIO_F71869_ID:
3017020d 564 case SIO_F71869A_ID:
a7876735 565 type = f71869;
df278dac 566 break;
96cb4eb0 567 case SIO_F71882_ID:
a7876735 568 type = f71882fg;
96cb4eb0 569 break;
96cb4eb0 570 case SIO_F71889_ID:
a7876735 571 type = f71889fg;
dee00abb 572 break;
96cb4eb0
GS
573 case SIO_F71858_ID:
574 /* Confirmed (by datasheet) not to have a watchdog. */
575 err = -ENODEV;
576 goto exit;
ca2fc5ef 577 case SIO_F81803_ID:
a7876735 578 type = f81803;
ca2fc5ef 579 break;
ea0c03e8 580 case SIO_F81865_ID:
a7876735 581 type = f81865;
14b24a88
JZHPH
582 break;
583 case SIO_F81866_ID:
a7876735 584 type = f81866;
ea0c03e8 585 break;
cea62f9f
A
586 case SIO_F81966_ID:
587 type = f81966;
588 break;
96cb4eb0 589 default:
27c766aa
JP
590 pr_info("Unrecognized Fintek device: %04x\n",
591 (unsigned int)devid);
96cb4eb0
GS
592 err = -ENODEV;
593 goto exit;
594 }
595
27c766aa 596 pr_info("Found %s watchdog chip, revision %d\n",
a7876735 597 fintek_wdt_names[type],
96cb4eb0 598 (int)superio_inb(sioaddr, SIO_REG_DEVREV));
a7876735 599
96cb4eb0
GS
600exit:
601 superio_exit(sioaddr);
a7876735 602 return err ? err : type;
96cb4eb0
GS
603}
604
27e0fe00
AF
605static struct platform_driver fintek_wdt_driver = {
606 .probe = fintek_wdt_probe,
607 .driver = {
608 .name = DRVNAME,
609 },
610};
611
612static struct platform_device *fintek_wdt_pdev;
613
3a2c4895 614static int __init fintek_wdt_init(void)
96cb4eb0
GS
615{
616 static const unsigned short addrs[] = { 0x2e, 0x4e };
a7876735 617 struct fintek_wdt_pdata pdata;
27e0fe00 618 struct resource wdt_res = {};
a7876735 619 int ret;
96cb4eb0
GS
620 int i;
621
5edc8c68
AF
622 if (f71862fg_pin != 63 && f71862fg_pin != 56) {
623 pr_err("Invalid argument f71862fg_pin=%d\n", f71862fg_pin);
624 return -EINVAL;
625 }
626
96cb4eb0 627 for (i = 0; i < ARRAY_SIZE(addrs); i++) {
a7876735
AF
628 ret = fintek_wdt_find(addrs[i]);
629 if (ret >= 0)
96cb4eb0
GS
630 break;
631 }
632 if (i == ARRAY_SIZE(addrs))
a7876735
AF
633 return ret;
634
635 pdata.type = ret;
96cb4eb0 636
97d5ec54
JJ
637 ret = platform_driver_register(&fintek_wdt_driver);
638 if (ret)
639 return ret;
27e0fe00
AF
640
641 wdt_res.name = "superio port";
642 wdt_res.flags = IORESOURCE_IO;
643 wdt_res.start = addrs[i];
644 wdt_res.end = addrs[i] + 1;
645
a7876735
AF
646 fintek_wdt_pdev = platform_device_register_resndata(NULL, DRVNAME, -1,
647 &wdt_res, 1,
648 &pdata, sizeof(pdata));
27e0fe00
AF
649 if (IS_ERR(fintek_wdt_pdev)) {
650 platform_driver_unregister(&fintek_wdt_driver);
651 return PTR_ERR(fintek_wdt_pdev);
652 }
653
654 return 0;
96cb4eb0
GS
655}
656
3a2c4895 657static void __exit fintek_wdt_exit(void)
96cb4eb0 658{
27e0fe00
AF
659 platform_device_unregister(fintek_wdt_pdev);
660 platform_driver_unregister(&fintek_wdt_driver);
96cb4eb0
GS
661}
662
663MODULE_DESCRIPTION("F71808E Watchdog Driver");
664MODULE_AUTHOR("Giel van Schijndel <me@mortis.eu>");
665MODULE_LICENSE("GPL");
666
3a2c4895
AF
667module_init(fintek_wdt_init);
668module_exit(fintek_wdt_exit);