11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
20e94f2ee0d1947ba6c2c00c3e971ff93ce8edec1Vlad Drukker *	w83627hf/thf WDT driver
30e94f2ee0d1947ba6c2c00c3e971ff93ce8edec1Vlad Drukker *
430a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck *	(c) Copyright 2013 Guenter Roeck
530a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck *		converted to watchdog infrastructure
630a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck *
70e94f2ee0d1947ba6c2c00c3e971ff93ce8edec1Vlad Drukker *	(c) Copyright 2007 Vlad Drukker <vlad@storewiz.com>
80e94f2ee0d1947ba6c2c00c3e971ff93ce8edec1Vlad Drukker *		added support for W83627THF.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
10d36b691077dc59c74efec0d54ed21b86f7a2a21aAl Viro *	(c) Copyright 2003,2007 Pádraig Brady <P@draigBrady.com>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Based on advantechwdt.c which is based on wdt.c.
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Original copyright messages:
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	(c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1729fa0586de4fe518f122a915b8c6e92d12e8ca7fAlan Cox *	(c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
1829fa0586de4fe518f122a915b8c6e92d12e8ca7fAlan Cox *						All Rights Reserved.
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	This program is free software; you can redistribute it and/or
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	modify it under the terms of the GNU General Public License
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	as published by the Free Software Foundation; either version
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	2 of the License, or (at your option) any later version.
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Neither Alan Cox nor CymruNet Ltd. admit liability nor provide
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	warranty for any of this software. This material is provided
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	"AS-IS" and at no charge.
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
2929fa0586de4fe518f122a915b8c6e92d12e8ca7fAlan Cox *	(c) Copyright 1995    Alan Cox <alan@lxorguk.ukuu.org.uk>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3227c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
3327c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/watchdog.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/notifier.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/reboot.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
4246a3949ddc422882cc27c88d078838cd31885d78Alan Cox#include <linux/io.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
449c67bea419c384561eeb84bdf251d521a3234e45Benny Loenstrup Ammitzboell#define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WATCHDOG_TIMEOUT 60		/* 60 sec default timeout */
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeckstatic int wdt_io;
487b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeckstatic int cr_wdt_timeout;	/* WDT timeout register */
497b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeckstatic int cr_wdt_control;	/* WDT control register */
50962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck
517b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeckenum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
527b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	     w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p,
537b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	     w83667hg_b, nct6775, nct6776, nct6779 };
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5530a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeckstatic int timeout;			/* in seconds */
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(timeout, int, 0);
5746a3949ddc422882cc27c88d078838cd31885d78Alan CoxMODULE_PARM_DESC(timeout,
5846a3949ddc422882cc27c88d078838cd31885d78Alan Cox		"Watchdog timeout in seconds. 1 <= timeout <= 255, default="
5946a3949ddc422882cc27c88d078838cd31885d78Alan Cox				__MODULE_STRING(WATCHDOG_TIMEOUT) ".");
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6186a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckstatic bool nowayout = WATCHDOG_NOWAYOUT;
6286a1e1896c2710402e29a875d8d830244274244dWim Van Sebroeckmodule_param(nowayout, bool, 0);
6346a3949ddc422882cc27c88d078838cd31885d78Alan CoxMODULE_PARM_DESC(nowayout,
6446a3949ddc422882cc27c88d078838cd31885d78Alan Cox		"Watchdog cannot be stopped once started (default="
6546a3949ddc422882cc27c88d078838cd31885d78Alan Cox				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
67be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeckstatic int early_disable;
68be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeckmodule_param(early_disable, int, 0);
69be281588d0bb21ccb07b1747939e0c919c2203fcGuenter RoeckMODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)");
70be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeck
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Kernel methods.
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WDT_EFER (wdt_io+0)   /* Extended Function Enable Registers */
7646a3949ddc422882cc27c88d078838cd31885d78Alan Cox#define WDT_EFIR (wdt_io+0)   /* Extended Function Index Register
7746a3949ddc422882cc27c88d078838cd31885d78Alan Cox							(same as EFER) */
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WDT_EFDR (WDT_EFIR+1) /* Extended Function Data Register */
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
80ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck#define W83627HF_LD_WDT		0x08
81ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck
82962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83627HF_ID		0x52
83962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83627S_ID		0x59
847b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck#define W83697HF_ID		0x60
857b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck#define W83697UG_ID		0x68
86962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83637HF_ID		0x70
87962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83627THF_ID		0x82
88962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83687THF_ID		0x85
89962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83627EHF_ID		0x88
90962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83627DHG_ID		0xa0
91962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83627UHG_ID		0xa2
92962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83667HG_ID		0xa5
93962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83627DHG_P_ID		0xb0
94962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define W83667HG_B_ID		0xb3
95962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define NCT6775_ID		0xb4
96962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define NCT6776_ID		0xc3
97962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck#define NCT6779_ID		0xc5
98962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck
997b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck#define W83627HF_WDT_TIMEOUT	0xf6
1007b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck#define W83697HF_WDT_TIMEOUT	0xf4
1017b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck
1027b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck#define W83627HF_WDT_CONTROL	0xf5
1037b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck#define W83697HF_WDT_CONTROL	0xf3
1047b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck
105ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeckstatic void superio_outb(int reg, int val)
106ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck{
107ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	outb(reg, WDT_EFER);
108ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	outb(val, WDT_EFDR);
109ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck}
110ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck
111ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeckstatic inline int superio_inb(int reg)
112ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck{
113ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	outb(reg, WDT_EFER);
114ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	return inb(WDT_EFDR);
115ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck}
116ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck
117ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeckstatic int superio_enter(void)
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
119ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	if (!request_muxed_region(wdt_io, 2, WATCHDOG_NAME))
120ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck		return -EBUSY;
121ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(0x87, WDT_EFER); /* Enter extended function mode */
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(0x87, WDT_EFER); /* Again according to manual */
124ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck
125ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	return 0;
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
128ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeckstatic void superio_select(int ld)
129ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck{
130ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	superio_outb(0x07, ld);
131ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck}
132ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck
133ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeckstatic void superio_exit(void)
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	outb_p(0xAA, WDT_EFER); /* Leave extended function mode */
136ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	release_region(wdt_io, 2);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
139962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeckstatic int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
141ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	int ret;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char t;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
144ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	ret = superio_enter();
145ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	if (ret)
146ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck		return ret;
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
148ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	superio_select(W83627HF_LD_WDT);
1498f526389599fc543b204c12a36de8345eb298085Guenter Roeck
150ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	/* set CR30 bit 0 to activate GPIO2 */
151ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	t = superio_inb(0x30);
152ac461103c57ac46cd6778f1fd0352ff0e4a2d38eGuenter Roeck	if (!(t & 0x01))
153ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck		superio_outb(0x30, t | 0x01);
1548f526389599fc543b204c12a36de8345eb298085Guenter Roeck
155962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	switch (chip) {
156962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83627hf:
157962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83627s:
158962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		t = superio_inb(0x2B) & ~0x10;
159962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		superio_outb(0x2B, t); /* set GPIO24 to WDT0 */
160962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
1617b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	case w83697hf:
1627b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		/* Set pin 119 to WDTO# mode (= CR29, WDT0) */
1637b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		t = superio_inb(0x29) & ~0x60;
1647b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		t |= 0x20;
1657b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		superio_outb(0x29, t);
1667b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		break;
1677b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	case w83697ug:
1687b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		/* Set pin 118 to WDTO# mode */
1697b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		t = superio_inb(0x2b) & ~0x04;
1707b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		superio_outb(0x2b, t);
1717b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		break;
172962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83627thf:
173962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		t = (superio_inb(0x2B) & ~0x08) | 0x04;
174962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		superio_outb(0x2B, t); /* set GPIO3 to WDT0 */
175962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
176962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83627dhg:
177962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83627dhg_p:
178962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */
179962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		superio_outb(0x2D, t); /* set GPIO5 to WDT0 */
1807b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		t = superio_inb(cr_wdt_control);
181962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		t |= 0x02;	/* enable the WDTO# output low pulse
182962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck				 * to the KBRST# pin */
1837b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		superio_outb(cr_wdt_control, t);
184962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
185962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83637hf:
186962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
187962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83687thf:
188962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */
189962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		superio_outb(0x2C, t);
190962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
191962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83627ehf:
192962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83627uhg:
193962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83667hg:
194962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case w83667hg_b:
195962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case nct6775:
196962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case nct6776:
197962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case nct6779:
198962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		/*
199962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		 * These chips have a fixed WDTO# output pin (W83627UHG),
200962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		 * or support more than one WDTO# output pin.
201962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		 * Don't touch its configuration, and hope the BIOS
202962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		 * does the right thing.
203962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		 */
2047b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		t = superio_inb(cr_wdt_control);
205962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		t |= 0x02;	/* enable the WDTO# output low pulse
206962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck				 * to the KBRST# pin */
2077b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		superio_outb(cr_wdt_control, t);
208962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
209962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	default:
210962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
211962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	}
212962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck
2137b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	t = superio_inb(cr_wdt_timeout);
21493642ecd463df30d032da8ac37c2676cee4ad876P@Draig Brady	if (t != 0) {
215be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeck		if (early_disable) {
216be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeck			pr_warn("Stopping previously enabled watchdog until userland kicks in\n");
217be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeck			superio_outb(cr_wdt_timeout, 0);
218be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeck		} else {
219be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeck			pr_info("Watchdog already running. Resetting timeout to %d sec\n",
220be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeck				wdog->timeout);
221be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeck			superio_outb(cr_wdt_timeout, wdog->timeout);
222be281588d0bb21ccb07b1747939e0c919c2203fcGuenter Roeck		}
22393642ecd463df30d032da8ac37c2676cee4ad876P@Draig Brady	}
22428dd1b0b9191ac9cd0b96fa4d09d951498bfbadbP�draig Brady
225ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	/* set second mode & disable keyboard turning off watchdog */
2267b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	t = superio_inb(cr_wdt_control) & ~0x0C;
2277b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	superio_outb(cr_wdt_control, t);
228ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck
229ea3d4011a871e1802e201086195c61e6dbeaf6d5Guenter Roeck	/* reset trigger, disable keyboard & mouse turning off watchdog */
230ea3d4011a871e1802e201086195c61e6dbeaf6d5Guenter Roeck	t = superio_inb(0xF7) & ~0xD0;
231ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	superio_outb(0xF7, t);
232ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck
233ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	superio_exit();
234ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck
235ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	return 0;
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23830a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeckstatic int wdt_set_time(unsigned int timeout)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
240ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	int ret;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
242ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	ret = superio_enter();
243ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	if (ret)
244ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck		return ret;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
246ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	superio_select(W83627HF_LD_WDT);
2477b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	superio_outb(cr_wdt_timeout, timeout);
248ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	superio_exit();
249ab9d441425559aa035ba6327f21e8922e8a13927Wim Van Sebroeck
25030a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	return 0;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25330a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeckstatic int wdt_start(struct watchdog_device *wdog)
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
25530a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	return wdt_set_time(wdog->timeout);
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
25830a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeckstatic int wdt_stop(struct watchdog_device *wdog)
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26030a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	return wdt_set_time(0);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26330a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeckstatic int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout)
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
26530a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	wdog->timeout = timeout;
26630a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
27030a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeckstatic unsigned int wdt_get_time(struct watchdog_device *wdog)
271c63b6d02be22899a5c8d47b8ee40e0534cd01a43Greg Lee{
27230a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	unsigned int timeleft;
273ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	int ret;
274c63b6d02be22899a5c8d47b8ee40e0534cd01a43Greg Lee
275ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	ret = superio_enter();
276ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	if (ret)
277ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck		return 0;
278c63b6d02be22899a5c8d47b8ee40e0534cd01a43Greg Lee
279ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	superio_select(W83627HF_LD_WDT);
2807b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	timeleft = superio_inb(cr_wdt_timeout);
281ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	superio_exit();
282c63b6d02be22899a5c8d47b8ee40e0534cd01a43Greg Lee
283c63b6d02be22899a5c8d47b8ee40e0534cd01a43Greg Lee	return timeleft;
284c63b6d02be22899a5c8d47b8ee40e0534cd01a43Greg Lee}
285c63b6d02be22899a5c8d47b8ee40e0534cd01a43Greg Lee
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Notifier for system down
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
28946a3949ddc422882cc27c88d078838cd31885d78Alan Coxstatic int wdt_notify_sys(struct notifier_block *this, unsigned long code,
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *unused)
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2927944d3a5a70ee5c1904ed1e8b1d71ff0af2854d9Wim Van Sebroeck	if (code == SYS_DOWN || code == SYS_HALT)
29330a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck		wdt_set_time(0);	/* Turn the WDT off */
2947944d3a5a70ee5c1904ed1e8b1d71ff0af2854d9Wim Van Sebroeck
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NOTIFY_DONE;
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Kernel Interfaces
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30230a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeckstatic struct watchdog_info wdt_info = {
30330a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
30430a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.identity = "W83627HF Watchdog",
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
30730a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeckstatic struct watchdog_ops wdt_ops = {
30830a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.owner = THIS_MODULE,
30930a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.start = wdt_start,
31030a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.stop = wdt_stop,
31130a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.set_timeout = wdt_set_timeout,
31230a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.get_timeleft = wdt_get_time,
31330a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck};
31430a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck
31530a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeckstatic struct watchdog_device wdt_dev = {
31630a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.info = &wdt_info,
31730a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.ops = &wdt_ops,
31830a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.timeout = WATCHDOG_TIMEOUT,
31930a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.min_timeout = 1,
32030a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	.max_timeout = 255,
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	The WDT needs to learn about soft shutdowns in order to
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	turn the timebomb registers off.
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct notifier_block wdt_notifier = {
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.notifier_call = wdt_notify_sys,
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
332962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeckstatic int wdt_find(int addr)
333962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck{
334962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	u8 val;
335962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	int ret;
336962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck
3377b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	cr_wdt_timeout = W83627HF_WDT_TIMEOUT;
3387b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	cr_wdt_control = W83627HF_WDT_CONTROL;
3397b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck
340962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	ret = superio_enter();
341962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	if (ret)
342962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		return ret;
343962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	superio_select(W83627HF_LD_WDT);
344962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	val = superio_inb(0x20);
345962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	switch (val) {
346962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83627HF_ID:
347962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83627hf;
348962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
349962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83627S_ID:
350962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83627s;
351962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
3527b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	case W83697HF_ID:
3537b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		ret = w83697hf;
3547b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
3557b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		cr_wdt_control = W83697HF_WDT_CONTROL;
3567b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		break;
3577b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck	case W83697UG_ID:
3587b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		ret = w83697ug;
3597b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
3607b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		cr_wdt_control = W83697HF_WDT_CONTROL;
3617b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		break;
362962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83637HF_ID:
363962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83637hf;
364962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
365962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83627THF_ID:
366962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83627thf;
367962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
368962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83687THF_ID:
369962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83687thf;
370962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
371962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83627EHF_ID:
372962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83627ehf;
373962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
374962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83627DHG_ID:
375962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83627dhg;
376962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
377962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83627DHG_P_ID:
378962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83627dhg_p;
379962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
380962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83627UHG_ID:
381962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83627uhg;
382962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
383962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83667HG_ID:
384962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83667hg;
385962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
386962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case W83667HG_B_ID:
387962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = w83667hg_b;
388962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
389962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case NCT6775_ID:
390962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = nct6775;
391962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
392962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case NCT6776_ID:
393962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = nct6776;
394962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
395962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case NCT6779_ID:
396962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = nct6779;
397962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
398962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	case 0xff:
399962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = -ENODEV;
400962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
401962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	default:
402962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		ret = -ENODEV;
403962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		pr_err("Unsupported chip ID: 0x%02x\n", val);
404962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		break;
405962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	}
406962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	superio_exit();
407962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	return ret;
408962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck}
409962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck
41046a3949ddc422882cc27c88d078838cd31885d78Alan Coxstatic int __init wdt_init(void)
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
413962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	int chip;
414962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	const char * const chip_name[] = {
415962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83627HF",
416962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83627S",
4177b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		"W83697HF",
4187b6d0b6ad49e55f8b82dbf233ece4e091417a738Guenter Roeck		"W83697UG",
419962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83637HF",
420962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83627THF",
421962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83687THF",
422962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83627EHF",
423962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83627DHG",
424962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83627UHG",
425962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83667HG",
426962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83667DHG-P",
427962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"W83667HG-B",
428962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"NCT6775",
429962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"NCT6776",
430962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		"NCT6779",
431962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	};
432962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck
433962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	wdt_io = 0x2e;
434962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	chip = wdt_find(0x2e);
435962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	if (chip < 0) {
436962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		wdt_io = 0x4e;
437962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		chip = wdt_find(0x4e);
438962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		if (chip < 0)
439962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck			return chip;
440962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
442962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	pr_info("WDT driver for %s Super I/O chip initialising\n",
443962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck		chip_name[chip]);
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
44530a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	watchdog_init_timeout(&wdt_dev, timeout, NULL);
44630a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	watchdog_set_nowayout(&wdt_dev, nowayout);
44730a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck
448962c04f54e4a3c322d19b47256f9aec0b9c8124eGuenter Roeck	ret = w83627hf_init(&wdt_dev, chip);
449ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	if (ret) {
450ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck		pr_err("failed to initialize watchdog (err=%d)\n", ret);
451ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck		return ret;
452ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck	}
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ret = register_reboot_notifier(&wdt_notifier);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret != 0) {
45627c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches		pr_err("cannot register reboot notifier (err=%d)\n", ret);
457ef0c1a6b1b05f85f0a1cf6ef283512fd25d86ad4Guenter Roeck		return ret;
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46030a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	ret = watchdog_register_device(&wdt_dev);
46130a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	if (ret)
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto unreg_reboot;
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
46427c766aaacb265d625dc634bf7903f7f9fd0c697Joe Perches	pr_info("initialized. timeout=%d sec (nowayout=%d)\n",
46530a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck		wdt_dev.timeout, nowayout);
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
46830a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunreg_reboot:
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_reboot_notifier(&wdt_notifier);
47130a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	return ret;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47446a3949ddc422882cc27c88d078838cd31885d78Alan Coxstatic void __exit wdt_exit(void)
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
47630a83695aa2ed3ffb1445d6daef1e620c3ca4e6dGuenter Roeck	watchdog_unregister_device(&wdt_dev);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_reboot_notifier(&wdt_notifier);
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(wdt_init);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(wdt_exit);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
484d36b691077dc59c74efec0d54ed21b86f7a2a21aAl ViroMODULE_AUTHOR("Pádraig  Brady <P@draigBrady.com>");
4850e94f2ee0d1947ba6c2c00c3e971ff93ce8edec1Vlad DrukkerMODULE_DESCRIPTION("w83627hf/thf WDT driver");
486