iTCO_wdt.c 16.7 KB
Newer Older
1
/*
2
 *	intel TCO Watchdog Driver
3
 *
4
 *	(c) Copyright 2006-2011 Wim Van Sebroeck <wim@iguana.be>.
5 6 7 8 9 10 11 12 13 14 15 16
 *
 *	This program is free software; you can redistribute it and/or
 *	modify it under the terms of the GNU General Public License
 *	as published by the Free Software Foundation; either version
 *	2 of the License, or (at your option) any later version.
 *
 *	Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor
 *	provide warranty for any of this software. This material is
 *	provided "AS-IS" and at no charge.
 *
 *	The TCO watchdog is implemented in the following I/O controller hubs:
 *	(See the intel documentation on http://developer.intel.com.)
17 18 19 20 21 22 23 24 25 26 27 28
 *	document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO)
 *	document number 290687-002, 298242-027: 82801BA (ICH2)
 *	document number 290733-003, 290739-013: 82801CA (ICH3-S)
 *	document number 290716-001, 290718-007: 82801CAM (ICH3-M)
 *	document number 290744-001, 290745-025: 82801DB (ICH4)
 *	document number 252337-001, 252663-008: 82801DBM (ICH4-M)
 *	document number 273599-001, 273645-002: 82801E (C-ICH)
 *	document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R)
 *	document number 300641-004, 300884-013: 6300ESB
 *	document number 301473-002, 301474-026: 82801F (ICH6)
 *	document number 313082-001, 313075-006: 631xESB, 632xESB
 *	document number 307013-003, 307014-024: 82801G (ICH7)
29
 *	document number 322896-001, 322897-001: NM10
30 31 32
 *	document number 313056-003, 313057-017: 82801H (ICH8)
 *	document number 316972-004, 316973-012: 82801I (ICH9)
 *	document number 319973-002, 319974-002: 82801J (ICH10)
33
 *	document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
34
 *	document number 320066-003, 320257-008: EP80597 (IICH)
35
 *	document number 324645-001, 324646-001: Cougar Point (CPT)
36
 *	document number TBD                   : Patsburg (PBG)
37
 *	document number TBD                   : DH89xxCC
38
 *	document number TBD                   : Panther Point
39
 *	document number TBD                   : Lynx Point
40
 *	document number TBD                   : Lynx Point-LP
41 42 43 44 45 46
 */

/*
 *	Includes, defines, variables, module parameters, ...
 */

47 48
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

49
/* Module and version information */
50
#define DRV_NAME	"iTCO_wdt"
51
#define DRV_VERSION	"1.10"
52 53

/* Includes */
54 55 56 57 58 59 60 61 62 63 64 65
#include <linux/module.h>		/* For module specific items */
#include <linux/moduleparam.h>		/* For new moduleparam's */
#include <linux/types.h>		/* For standard types (like size_t) */
#include <linux/errno.h>		/* For the -ENODEV/... values */
#include <linux/kernel.h>		/* For printk/panic/... */
#include <linux/watchdog.h>		/* For the watchdog specific items */
#include <linux/init.h>			/* For __init/__exit/... */
#include <linux/fs.h>			/* For file operations */
#include <linux/platform_device.h>	/* For platform_driver framework */
#include <linux/pci.h>			/* For pci functions */
#include <linux/ioport.h>		/* For io-port access */
#include <linux/spinlock.h>		/* For spin_lock/spin_unlock/... */
66 67
#include <linux/uaccess.h>		/* For copy_to_user/put_user/... */
#include <linux/io.h>			/* For inb/outb/... */
68 69
#include <linux/mfd/core.h>
#include <linux/mfd/lpc_ich.h>
70

71
#include "iTCO_vendor.h"
72 73

/* Address definitions for the TCO */
74
/* TCO base address */
75
#define TCOBASE		(iTCO_wdt_private.tco_res->start)
76
/* SMI Control and Enable Register */
77
#define SMI_EN		(iTCO_wdt_private.smi_res->start)
78

79 80 81 82 83 84 85 86 87
#define TCO_RLD		(TCOBASE + 0x00) /* TCO Timer Reload and Curr. Value */
#define TCOv1_TMR	(TCOBASE + 0x01) /* TCOv1 Timer Initial Value	*/
#define TCO_DAT_IN	(TCOBASE + 0x02) /* TCO Data In Register	*/
#define TCO_DAT_OUT	(TCOBASE + 0x03) /* TCO Data Out Register	*/
#define TCO1_STS	(TCOBASE + 0x04) /* TCO1 Status Register	*/
#define TCO2_STS	(TCOBASE + 0x06) /* TCO2 Status Register	*/
#define TCO1_CNT	(TCOBASE + 0x08) /* TCO1 Control Register	*/
#define TCO2_CNT	(TCOBASE + 0x0a) /* TCO2 Control Register	*/
#define TCOv2_TMR	(TCOBASE + 0x12) /* TCOv2 Timer Initial Value	*/
88 89

/* internal variables */
90 91 92
static struct {		/* this is private data for the iTCO_wdt device */
	/* TCO version/generation */
	unsigned int iTCO_version;
93 94 95
	struct resource *tco_res;
	struct resource *smi_res;
	struct resource *gcs_res;
96 97 98 99
	/* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/
	unsigned long __iomem *gcs;
	/* the lock for io operations */
	spinlock_t io_lock;
100
	struct platform_device *dev;
101 102
	/* the PCI-device */
	struct pci_dev *pdev;
103 104 105
} iTCO_wdt_private;

/* module parameters */
106 107
#define WATCHDOG_TIMEOUT 30	/* 30 sec default heartbeat */
static int heartbeat = WATCHDOG_TIMEOUT;  /* in seconds */
108
module_param(heartbeat, int, 0);
109 110
MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. "
	"5..76 (TCO v1) or 3..614 (TCO v2), default="
111
				__MODULE_STRING(WATCHDOG_TIMEOUT) ")");
112

W
Wim Van Sebroeck 已提交
113 114
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
115 116 117
MODULE_PARM_DESC(nowayout,
	"Watchdog cannot be stopped once started (default="
				__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
118

119
static int turn_SMI_watchdog_clear_off = 1;
120 121
module_param(turn_SMI_watchdog_clear_off, int, 0);
MODULE_PARM_DESC(turn_SMI_watchdog_clear_off,
122
	"Turn off SMI clearing watchdog (depends on TCO-version)(default=1)");
123

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
/*
 * Some TCO specific functions
 */

static inline unsigned int seconds_to_ticks(int seconds)
{
	/* the internal timer is stored as ticks which decrement
	 * every 0.6 seconds */
	return (seconds * 10) / 6;
}

static void iTCO_wdt_set_NO_REBOOT_bit(void)
{
	u32 val32;

	/* Set the NO_REBOOT bit: this disables reboots */
	if (iTCO_wdt_private.iTCO_version == 2) {
		val32 = readl(iTCO_wdt_private.gcs);
		val32 |= 0x00000020;
		writel(val32, iTCO_wdt_private.gcs);
	} else if (iTCO_wdt_private.iTCO_version == 1) {
		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
		val32 |= 0x00000002;
		pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
	}
}

static int iTCO_wdt_unset_NO_REBOOT_bit(void)
{
	int ret = 0;
	u32 val32;

	/* Unset the NO_REBOOT bit: this enables reboots */
	if (iTCO_wdt_private.iTCO_version == 2) {
		val32 = readl(iTCO_wdt_private.gcs);
		val32 &= 0xffffffdf;
		writel(val32, iTCO_wdt_private.gcs);

		val32 = readl(iTCO_wdt_private.gcs);
		if (val32 & 0x00000020)
			ret = -EIO;
	} else if (iTCO_wdt_private.iTCO_version == 1) {
		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
		val32 &= 0xfffffffd;
		pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);

		pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
		if (val32 & 0x00000002)
			ret = -EIO;
	}

	return ret; /* returns: 0 = OK, -EIO = Error */
}

178
static int iTCO_wdt_start(struct watchdog_device *wd_dev)
179 180 181 182 183
{
	unsigned int val;

	spin_lock(&iTCO_wdt_private.io_lock);

184
	iTCO_vendor_pre_start(iTCO_wdt_private.smi_res, wd_dev->timeout);
185

186 187
	/* disable chipset's NO_REBOOT bit */
	if (iTCO_wdt_unset_NO_REBOOT_bit()) {
188
		spin_unlock(&iTCO_wdt_private.io_lock);
189
		pr_err("failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n");
190 191 192
		return -EIO;
	}

193 194 195 196 197 198 199
	/* Force the timer to its reload value by writing to the TCO_RLD
	   register */
	if (iTCO_wdt_private.iTCO_version == 2)
		outw(0x01, TCO_RLD);
	else if (iTCO_wdt_private.iTCO_version == 1)
		outb(0x01, TCO_RLD);

200 201 202 203 204 205 206 207 208 209 210 211
	/* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
	val = inw(TCO1_CNT);
	val &= 0xf7ff;
	outw(val, TCO1_CNT);
	val = inw(TCO1_CNT);
	spin_unlock(&iTCO_wdt_private.io_lock);

	if (val & 0x0800)
		return -1;
	return 0;
}

212
static int iTCO_wdt_stop(struct watchdog_device *wd_dev)
213 214 215 216 217
{
	unsigned int val;

	spin_lock(&iTCO_wdt_private.io_lock);

218
	iTCO_vendor_pre_stop(iTCO_wdt_private.smi_res);
219

220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235
	/* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
	val = inw(TCO1_CNT);
	val |= 0x0800;
	outw(val, TCO1_CNT);
	val = inw(TCO1_CNT);

	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
	iTCO_wdt_set_NO_REBOOT_bit();

	spin_unlock(&iTCO_wdt_private.io_lock);

	if ((val & 0x0800) == 0)
		return -1;
	return 0;
}

236
static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
237 238 239
{
	spin_lock(&iTCO_wdt_private.io_lock);

240
	iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, wd_dev->timeout);
241

242
	/* Reload the timer by writing to the TCO Timer Counter register */
243
	if (iTCO_wdt_private.iTCO_version == 2)
244
		outw(0x01, TCO_RLD);
245 246 247 248 249
	else if (iTCO_wdt_private.iTCO_version == 1) {
		/* Reset the timeout status bit so that the timer
		 * needs to count down twice again before rebooting */
		outw(0x0008, TCO1_STS);	/* write 1 to clear bit */

250
		outb(0x01, TCO_RLD);
251
	}
252 253 254 255 256

	spin_unlock(&iTCO_wdt_private.io_lock);
	return 0;
}

257
static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
258 259 260 261 262 263
{
	unsigned int val16;
	unsigned char val8;
	unsigned int tmrval;

	tmrval = seconds_to_ticks(t);
264 265 266 267 268

	/* For TCO v1 the timer counts down twice before rebooting */
	if (iTCO_wdt_private.iTCO_version == 1)
		tmrval /= 2;

269 270 271 272 273 274 275 276
	/* from the specs: */
	/* "Values of 0h-3h are ignored and should not be attempted" */
	if (tmrval < 0x04)
		return -EINVAL;
	if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
	    ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
		return -EINVAL;

277 278
	iTCO_vendor_pre_set_heartbeat(tmrval);

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	/* Write new heartbeat to watchdog */
	if (iTCO_wdt_private.iTCO_version == 2) {
		spin_lock(&iTCO_wdt_private.io_lock);
		val16 = inw(TCOv2_TMR);
		val16 &= 0xfc00;
		val16 |= tmrval;
		outw(val16, TCOv2_TMR);
		val16 = inw(TCOv2_TMR);
		spin_unlock(&iTCO_wdt_private.io_lock);

		if ((val16 & 0x3ff) != tmrval)
			return -EINVAL;
	} else if (iTCO_wdt_private.iTCO_version == 1) {
		spin_lock(&iTCO_wdt_private.io_lock);
		val8 = inb(TCOv1_TMR);
		val8 &= 0xc0;
		val8 |= (tmrval & 0xff);
		outb(val8, TCOv1_TMR);
		val8 = inb(TCOv1_TMR);
		spin_unlock(&iTCO_wdt_private.io_lock);

		if ((val8 & 0x3f) != tmrval)
			return -EINVAL;
	}

304
	wd_dev->timeout = t;
305 306 307
	return 0;
}

308
static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
309 310 311
{
	unsigned int val16;
	unsigned char val8;
312
	unsigned int time_left = 0;
313 314 315 316 317 318 319 320

	/* read the TCO Timer */
	if (iTCO_wdt_private.iTCO_version == 2) {
		spin_lock(&iTCO_wdt_private.io_lock);
		val16 = inw(TCO_RLD);
		val16 &= 0x3ff;
		spin_unlock(&iTCO_wdt_private.io_lock);

321
		time_left = (val16 * 6) / 10;
322 323 324 325
	} else if (iTCO_wdt_private.iTCO_version == 1) {
		spin_lock(&iTCO_wdt_private.io_lock);
		val8 = inb(TCO_RLD);
		val8 &= 0x3f;
326 327
		if (!(inw(TCO1_STS) & 0x0008))
			val8 += (inb(TCOv1_TMR) & 0x3f);
328 329
		spin_unlock(&iTCO_wdt_private.io_lock);

330
		time_left = (val8 * 6) / 10;
331
	}
332
	return time_left;
333 334 335 336 337 338
}

/*
 *	Kernel Interfaces
 */

339 340 341 342 343 344 345 346 347
static const struct watchdog_info ident = {
	.options =		WDIOF_SETTIMEOUT |
				WDIOF_KEEPALIVEPING |
				WDIOF_MAGICCLOSE,
	.firmware_version =	0,
	.identity =		DRV_NAME,
};

static const struct watchdog_ops iTCO_wdt_ops = {
348
	.owner =		THIS_MODULE,
349
	.start =		iTCO_wdt_start,
350 351
	.stop =			iTCO_wdt_stop,
	.ping =			iTCO_wdt_ping,
352 353
	.set_timeout =		iTCO_wdt_set_timeout,
	.get_timeleft =		iTCO_wdt_get_timeleft,
354 355
};

356 357
static struct watchdog_device iTCO_wdt_watchdog_dev = {
	.info =		&ident,
358
	.ops =		&iTCO_wdt_ops,
359 360 361 362 363 364
};

/*
 *	Init & exit routines
 */

B
Bill Pemberton 已提交
365
static void iTCO_wdt_cleanup(void)
366 367 368
{
	/* Stop the timer before we leave */
	if (!nowayout)
369
		iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
370 371

	/* Deregister */
372
	watchdog_unregister_device(&iTCO_wdt_watchdog_dev);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390

	/* release resources */
	release_region(iTCO_wdt_private.tco_res->start,
			resource_size(iTCO_wdt_private.tco_res));
	release_region(iTCO_wdt_private.smi_res->start,
			resource_size(iTCO_wdt_private.smi_res));
	if (iTCO_wdt_private.iTCO_version == 2) {
		iounmap(iTCO_wdt_private.gcs);
		release_mem_region(iTCO_wdt_private.gcs_res->start,
				resource_size(iTCO_wdt_private.gcs_res));
	}

	iTCO_wdt_private.tco_res = NULL;
	iTCO_wdt_private.smi_res = NULL;
	iTCO_wdt_private.gcs_res = NULL;
	iTCO_wdt_private.gcs = NULL;
}

B
Bill Pemberton 已提交
391
static int iTCO_wdt_probe(struct platform_device *dev)
392
{
393
	int ret = -ENODEV;
394
	unsigned long val32;
J
Jingoo Han 已提交
395
	struct lpc_ich_info *ich_info = dev_get_platdata(&dev->dev);
396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414

	if (!ich_info)
		goto out;

	spin_lock_init(&iTCO_wdt_private.io_lock);

	iTCO_wdt_private.tco_res =
		platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_TCO);
	if (!iTCO_wdt_private.tco_res)
		goto out;

	iTCO_wdt_private.smi_res =
		platform_get_resource(dev, IORESOURCE_IO, ICH_RES_IO_SMI);
	if (!iTCO_wdt_private.smi_res)
		goto out;

	iTCO_wdt_private.iTCO_version = ich_info->iTCO_version;
	iTCO_wdt_private.dev = dev;
	iTCO_wdt_private.pdev = to_pci_dev(dev->dev.parent);
415 416

	/*
417 418
	 * Get the Memory-Mapped GCS register, we need it for the
	 * NO_REBOOT flag (TCO v2).
419 420
	 */
	if (iTCO_wdt_private.iTCO_version == 2) {
421 422 423 424 425 426 427 428 429 430
		iTCO_wdt_private.gcs_res = platform_get_resource(dev,
							IORESOURCE_MEM,
							ICH_RES_MEM_GCS);

		if (!iTCO_wdt_private.gcs_res)
			goto out;

		if (!request_mem_region(iTCO_wdt_private.gcs_res->start,
			resource_size(iTCO_wdt_private.gcs_res), dev->name)) {
			ret = -EBUSY;
431 432
			goto out;
		}
433 434 435 436 437 438
		iTCO_wdt_private.gcs = ioremap(iTCO_wdt_private.gcs_res->start,
			resource_size(iTCO_wdt_private.gcs_res));
		if (!iTCO_wdt_private.gcs) {
			ret = -EIO;
			goto unreg_gcs;
		}
439 440 441
	}

	/* Check chipset's NO_REBOOT bit */
442
	if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
443
		pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n");
444
		ret = -ENODEV;	/* Cannot reset NO_REBOOT bit */
445
		goto unmap_gcs;
446 447 448 449 450
	}

	/* Set the NO_REBOOT bit to prevent later reboots, just for sure */
	iTCO_wdt_set_NO_REBOOT_bit();

451
	/* The TCO logic uses the TCO_EN bit in the SMI_EN register */
452 453 454
	if (!request_region(iTCO_wdt_private.smi_res->start,
			resource_size(iTCO_wdt_private.smi_res), dev->name)) {
		pr_err("I/O address 0x%04llx already in use, device disabled\n",
455
		       (u64)SMI_EN);
456 457
		ret = -EBUSY;
		goto unmap_gcs;
458
	}
459
	if (turn_SMI_watchdog_clear_off >= iTCO_wdt_private.iTCO_version) {
460 461 462 463
		/*
		 * Bit 13: TCO_EN -> 0
		 * Disables TCO logic generating an SMI#
		 */
464 465 466 467
		val32 = inl(SMI_EN);
		val32 &= 0xffffdfff;	/* Turn off SMI clearing watchdog */
		outl(val32, SMI_EN);
	}
468

469 470 471
	if (!request_region(iTCO_wdt_private.tco_res->start,
			resource_size(iTCO_wdt_private.tco_res), dev->name)) {
		pr_err("I/O address 0x%04llx already in use, device disabled\n",
472
		       (u64)TCOBASE);
473 474
		ret = -EBUSY;
		goto unreg_smi;
475 476
	}

477
	pr_info("Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n",
478
		ich_info->name, ich_info->iTCO_version, (u64)TCOBASE);
479 480

	/* Clear out the (probably old) status */
481 482 483
	outw(0x0008, TCO1_STS);	/* Clear the Time Out Status bit */
	outw(0x0002, TCO2_STS);	/* Clear SECOND_TO_STS bit */
	outw(0x0004, TCO2_STS);	/* Clear BOOT_STS bit */
484

485 486 487
	iTCO_wdt_watchdog_dev.bootstatus = 0;
	iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT;
	watchdog_set_nowayout(&iTCO_wdt_watchdog_dev, nowayout);
488
	iTCO_wdt_watchdog_dev.parent = &dev->dev;
489

490
	/* Make sure the watchdog is not running */
491
	iTCO_wdt_stop(&iTCO_wdt_watchdog_dev);
492

493 494
	/* Check that the heartbeat value is within it's range;
	   if not reset to the default */
495 496 497 498
	if (iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, heartbeat)) {
		iTCO_wdt_set_timeout(&iTCO_wdt_watchdog_dev, WATCHDOG_TIMEOUT);
		pr_info("timeout value out of range, using %d\n",
			WATCHDOG_TIMEOUT);
499 500
	}

501
	ret = watchdog_register_device(&iTCO_wdt_watchdog_dev);
502
	if (ret != 0) {
503
		pr_err("cannot register watchdog device (err=%d)\n", ret);
504
		goto unreg_tco;
505 506
	}

507 508
	pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
		heartbeat, nowayout);
509 510 511

	return 0;

512 513 514 515 516 517 518
unreg_tco:
	release_region(iTCO_wdt_private.tco_res->start,
			resource_size(iTCO_wdt_private.tco_res));
unreg_smi:
	release_region(iTCO_wdt_private.smi_res->start,
			resource_size(iTCO_wdt_private.smi_res));
unmap_gcs:
519 520
	if (iTCO_wdt_private.iTCO_version == 2)
		iounmap(iTCO_wdt_private.gcs);
521
unreg_gcs:
522
	if (iTCO_wdt_private.iTCO_version == 2)
523 524 525 526 527 528 529
		release_mem_region(iTCO_wdt_private.gcs_res->start,
				resource_size(iTCO_wdt_private.gcs_res));
out:
	iTCO_wdt_private.tco_res = NULL;
	iTCO_wdt_private.smi_res = NULL;
	iTCO_wdt_private.gcs_res = NULL;
	iTCO_wdt_private.gcs = NULL;
530

531
	return ret;
532 533
}

B
Bill Pemberton 已提交
534
static int iTCO_wdt_remove(struct platform_device *dev)
535
{
536
	if (iTCO_wdt_private.tco_res || iTCO_wdt_private.smi_res)
537 538
		iTCO_wdt_cleanup();

539 540 541 542 543
	return 0;
}

static void iTCO_wdt_shutdown(struct platform_device *dev)
{
544
	iTCO_wdt_stop(NULL);
545 546 547 548
}

static struct platform_driver iTCO_wdt_driver = {
	.probe          = iTCO_wdt_probe,
549
	.remove         = iTCO_wdt_remove,
550 551 552 553 554 555 556 557 558 559 560
	.shutdown       = iTCO_wdt_shutdown,
	.driver         = {
		.owner  = THIS_MODULE,
		.name   = DRV_NAME,
	},
};

static int __init iTCO_wdt_init_module(void)
{
	int err;

561
	pr_info("Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION);
562 563 564 565 566 567 568 569 570 571 572

	err = platform_driver_register(&iTCO_wdt_driver);
	if (err)
		return err;

	return 0;
}

static void __exit iTCO_wdt_cleanup_module(void)
{
	platform_driver_unregister(&iTCO_wdt_driver);
573
	pr_info("Watchdog Module Unloaded\n");
574 575 576 577 578 579 580
}

module_init(iTCO_wdt_init_module);
module_exit(iTCO_wdt_cleanup_module);

MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
581
MODULE_VERSION(DRV_VERSION);
582
MODULE_LICENSE("GPL");
583
MODULE_ALIAS("platform:" DRV_NAME);