diff options
Diffstat (limited to 'drivers/watchdog/sp5100_tco.c')
-rw-r--r-- | drivers/watchdog/sp5100_tco.c | 321 |
1 files changed, 271 insertions, 50 deletions
diff --git a/drivers/watchdog/sp5100_tco.c b/drivers/watchdog/sp5100_tco.c index b3876812ff07..2b0e000d4377 100644 --- a/drivers/watchdog/sp5100_tco.c +++ b/drivers/watchdog/sp5100_tco.c | |||
@@ -13,7 +13,9 @@ | |||
13 | * as published by the Free Software Foundation; either version | 13 | * as published by the Free Software Foundation; either version |
14 | * 2 of the License, or (at your option) any later version. | 14 | * 2 of the License, or (at your option) any later version. |
15 | * | 15 | * |
16 | * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide" | 16 | * See AMD Publication 43009 "AMD SB700/710/750 Register Reference Guide", |
17 | * AMD Publication 45482 "AMD SB800-Series Southbridges Register | ||
18 | * Reference Guide" | ||
17 | */ | 19 | */ |
18 | 20 | ||
19 | /* | 21 | /* |
@@ -38,18 +40,24 @@ | |||
38 | #include "sp5100_tco.h" | 40 | #include "sp5100_tco.h" |
39 | 41 | ||
40 | /* Module and version information */ | 42 | /* Module and version information */ |
41 | #define TCO_VERSION "0.01" | 43 | #define TCO_VERSION "0.03" |
42 | #define TCO_MODULE_NAME "SP5100 TCO timer" | 44 | #define TCO_MODULE_NAME "SP5100 TCO timer" |
43 | #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION | 45 | #define TCO_DRIVER_NAME TCO_MODULE_NAME ", v" TCO_VERSION |
44 | 46 | ||
45 | /* internal variables */ | 47 | /* internal variables */ |
46 | static u32 tcobase_phys; | 48 | static u32 tcobase_phys; |
49 | static u32 resbase_phys; | ||
50 | static u32 tco_wdt_fired; | ||
47 | static void __iomem *tcobase; | 51 | static void __iomem *tcobase; |
48 | static unsigned int pm_iobase; | 52 | static unsigned int pm_iobase; |
49 | static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ | 53 | static DEFINE_SPINLOCK(tco_lock); /* Guards the hardware */ |
50 | static unsigned long timer_alive; | 54 | static unsigned long timer_alive; |
51 | static char tco_expect_close; | 55 | static char tco_expect_close; |
52 | static struct pci_dev *sp5100_tco_pci; | 56 | static struct pci_dev *sp5100_tco_pci; |
57 | static struct resource wdt_res = { | ||
58 | .name = "Watchdog Timer", | ||
59 | .flags = IORESOURCE_MEM, | ||
60 | }; | ||
53 | 61 | ||
54 | /* the watchdog platform device */ | 62 | /* the watchdog platform device */ |
55 | static struct platform_device *sp5100_tco_platform_device; | 63 | static struct platform_device *sp5100_tco_platform_device; |
@@ -64,9 +72,15 @@ MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (default=" | |||
64 | 72 | ||
65 | static bool nowayout = WATCHDOG_NOWAYOUT; | 73 | static bool nowayout = WATCHDOG_NOWAYOUT; |
66 | module_param(nowayout, bool, 0); | 74 | module_param(nowayout, bool, 0); |
67 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started" | 75 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started." |
68 | " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 76 | " (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
69 | 77 | ||
78 | static unsigned int force_addr; | ||
79 | module_param(force_addr, uint, 0); | ||
80 | MODULE_PARM_DESC(force_addr, "Force the use of specified MMIO address." | ||
81 | " ONLY USE THIS PARAMETER IF YOU REALLY KNOW" | ||
82 | " WHAT YOU ARE DOING (default=none)"); | ||
83 | |||
70 | /* | 84 | /* |
71 | * Some TCO specific functions | 85 | * Some TCO specific functions |
72 | */ | 86 | */ |
@@ -122,6 +136,79 @@ static int tco_timer_set_heartbeat(int t) | |||
122 | return 0; | 136 | return 0; |
123 | } | 137 | } |
124 | 138 | ||
139 | static void tco_timer_enable(void) | ||
140 | { | ||
141 | int val; | ||
142 | |||
143 | if (sp5100_tco_pci->revision >= 0x40) { | ||
144 | /* For SB800 or later */ | ||
145 | /* Set the Watchdog timer resolution to 1 sec */ | ||
146 | outb(SB800_PM_WATCHDOG_CONFIG, SB800_IO_PM_INDEX_REG); | ||
147 | val = inb(SB800_IO_PM_DATA_REG); | ||
148 | val |= SB800_PM_WATCHDOG_SECOND_RES; | ||
149 | outb(val, SB800_IO_PM_DATA_REG); | ||
150 | |||
151 | /* Enable watchdog decode bit and watchdog timer */ | ||
152 | outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG); | ||
153 | val = inb(SB800_IO_PM_DATA_REG); | ||
154 | val |= SB800_PCI_WATCHDOG_DECODE_EN; | ||
155 | val &= ~SB800_PM_WATCHDOG_DISABLE; | ||
156 | outb(val, SB800_IO_PM_DATA_REG); | ||
157 | } else { | ||
158 | /* For SP5100 or SB7x0 */ | ||
159 | /* Enable watchdog decode bit */ | ||
160 | pci_read_config_dword(sp5100_tco_pci, | ||
161 | SP5100_PCI_WATCHDOG_MISC_REG, | ||
162 | &val); | ||
163 | |||
164 | val |= SP5100_PCI_WATCHDOG_DECODE_EN; | ||
165 | |||
166 | pci_write_config_dword(sp5100_tco_pci, | ||
167 | SP5100_PCI_WATCHDOG_MISC_REG, | ||
168 | val); | ||
169 | |||
170 | /* Enable Watchdog timer and set the resolution to 1 sec */ | ||
171 | outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG); | ||
172 | val = inb(SP5100_IO_PM_DATA_REG); | ||
173 | val |= SP5100_PM_WATCHDOG_SECOND_RES; | ||
174 | val &= ~SP5100_PM_WATCHDOG_DISABLE; | ||
175 | outb(val, SP5100_IO_PM_DATA_REG); | ||
176 | } | ||
177 | } | ||
178 | |||
179 | static void tco_timer_disable(void) | ||
180 | { | ||
181 | int val; | ||
182 | |||
183 | if (sp5100_tco_pci->revision >= 0x40) { | ||
184 | /* For SB800 or later */ | ||
185 | /* Enable watchdog decode bit and Disable watchdog timer */ | ||
186 | outb(SB800_PM_WATCHDOG_CONTROL, SB800_IO_PM_INDEX_REG); | ||
187 | val = inb(SB800_IO_PM_DATA_REG); | ||
188 | val |= SB800_PCI_WATCHDOG_DECODE_EN; | ||
189 | val |= SB800_PM_WATCHDOG_DISABLE; | ||
190 | outb(val, SB800_IO_PM_DATA_REG); | ||
191 | } else { | ||
192 | /* For SP5100 or SB7x0 */ | ||
193 | /* Enable watchdog decode bit */ | ||
194 | pci_read_config_dword(sp5100_tco_pci, | ||
195 | SP5100_PCI_WATCHDOG_MISC_REG, | ||
196 | &val); | ||
197 | |||
198 | val |= SP5100_PCI_WATCHDOG_DECODE_EN; | ||
199 | |||
200 | pci_write_config_dword(sp5100_tco_pci, | ||
201 | SP5100_PCI_WATCHDOG_MISC_REG, | ||
202 | val); | ||
203 | |||
204 | /* Disable Watchdog timer */ | ||
205 | outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG); | ||
206 | val = inb(SP5100_IO_PM_DATA_REG); | ||
207 | val |= SP5100_PM_WATCHDOG_DISABLE; | ||
208 | outb(val, SP5100_IO_PM_DATA_REG); | ||
209 | } | ||
210 | } | ||
211 | |||
125 | /* | 212 | /* |
126 | * /dev/watchdog handling | 213 | * /dev/watchdog handling |
127 | */ | 214 | */ |
@@ -270,11 +357,12 @@ MODULE_DEVICE_TABLE(pci, sp5100_tco_pci_tbl); | |||
270 | /* | 357 | /* |
271 | * Init & exit routines | 358 | * Init & exit routines |
272 | */ | 359 | */ |
273 | |||
274 | static unsigned char sp5100_tco_setupdevice(void) | 360 | static unsigned char sp5100_tco_setupdevice(void) |
275 | { | 361 | { |
276 | struct pci_dev *dev = NULL; | 362 | struct pci_dev *dev = NULL; |
363 | const char *dev_name = NULL; | ||
277 | u32 val; | 364 | u32 val; |
365 | u32 index_reg, data_reg, base_addr; | ||
278 | 366 | ||
279 | /* Match the PCI device */ | 367 | /* Match the PCI device */ |
280 | for_each_pci_dev(dev) { | 368 | for_each_pci_dev(dev) { |
@@ -287,29 +375,160 @@ static unsigned char sp5100_tco_setupdevice(void) | |||
287 | if (!sp5100_tco_pci) | 375 | if (!sp5100_tco_pci) |
288 | return 0; | 376 | return 0; |
289 | 377 | ||
378 | pr_info("PCI Revision ID: 0x%x\n", sp5100_tco_pci->revision); | ||
379 | |||
380 | /* | ||
381 | * Determine type of southbridge chipset. | ||
382 | */ | ||
383 | if (sp5100_tco_pci->revision >= 0x40) { | ||
384 | dev_name = SB800_DEVNAME; | ||
385 | index_reg = SB800_IO_PM_INDEX_REG; | ||
386 | data_reg = SB800_IO_PM_DATA_REG; | ||
387 | base_addr = SB800_PM_WATCHDOG_BASE; | ||
388 | } else { | ||
389 | dev_name = SP5100_DEVNAME; | ||
390 | index_reg = SP5100_IO_PM_INDEX_REG; | ||
391 | data_reg = SP5100_IO_PM_DATA_REG; | ||
392 | base_addr = SP5100_PM_WATCHDOG_BASE; | ||
393 | } | ||
394 | |||
290 | /* Request the IO ports used by this driver */ | 395 | /* Request the IO ports used by this driver */ |
291 | pm_iobase = SP5100_IO_PM_INDEX_REG; | 396 | pm_iobase = SP5100_IO_PM_INDEX_REG; |
292 | if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, "SP5100 TCO")) { | 397 | if (!request_region(pm_iobase, SP5100_PM_IOPORTS_SIZE, dev_name)) { |
293 | pr_err("I/O address 0x%04x already in use\n", pm_iobase); | 398 | pr_err("I/O address 0x%04x already in use\n", pm_iobase); |
294 | goto exit; | 399 | goto exit; |
295 | } | 400 | } |
296 | 401 | ||
297 | /* Find the watchdog base address. */ | 402 | /* |
298 | outb(SP5100_PM_WATCHDOG_BASE3, SP5100_IO_PM_INDEX_REG); | 403 | * First, Find the watchdog timer MMIO address from indirect I/O. |
299 | val = inb(SP5100_IO_PM_DATA_REG); | 404 | */ |
300 | outb(SP5100_PM_WATCHDOG_BASE2, SP5100_IO_PM_INDEX_REG); | 405 | outb(base_addr+3, index_reg); |
301 | val = val << 8 | inb(SP5100_IO_PM_DATA_REG); | 406 | val = inb(data_reg); |
302 | outb(SP5100_PM_WATCHDOG_BASE1, SP5100_IO_PM_INDEX_REG); | 407 | outb(base_addr+2, index_reg); |
303 | val = val << 8 | inb(SP5100_IO_PM_DATA_REG); | 408 | val = val << 8 | inb(data_reg); |
304 | outb(SP5100_PM_WATCHDOG_BASE0, SP5100_IO_PM_INDEX_REG); | 409 | outb(base_addr+1, index_reg); |
305 | /* Low three bits of BASE0 are reserved. */ | 410 | val = val << 8 | inb(data_reg); |
306 | val = val << 8 | (inb(SP5100_IO_PM_DATA_REG) & 0xf8); | 411 | outb(base_addr+0, index_reg); |
412 | /* Low three bits of BASE are reserved */ | ||
413 | val = val << 8 | (inb(data_reg) & 0xf8); | ||
414 | |||
415 | pr_debug("Got 0x%04x from indirect I/O\n", val); | ||
416 | |||
417 | /* Check MMIO address conflict */ | ||
418 | if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, | ||
419 | dev_name)) | ||
420 | goto setup_wdt; | ||
421 | else | ||
422 | pr_debug("MMIO address 0x%04x already in use\n", val); | ||
423 | |||
424 | /* | ||
425 | * Secondly, Find the watchdog timer MMIO address | ||
426 | * from SBResource_MMIO register. | ||
427 | */ | ||
428 | if (sp5100_tco_pci->revision >= 0x40) { | ||
429 | /* Read SBResource_MMIO from AcpiMmioEn(PM_Reg: 24h) */ | ||
430 | outb(SB800_PM_ACPI_MMIO_EN+3, SB800_IO_PM_INDEX_REG); | ||
431 | val = inb(SB800_IO_PM_DATA_REG); | ||
432 | outb(SB800_PM_ACPI_MMIO_EN+2, SB800_IO_PM_INDEX_REG); | ||
433 | val = val << 8 | inb(SB800_IO_PM_DATA_REG); | ||
434 | outb(SB800_PM_ACPI_MMIO_EN+1, SB800_IO_PM_INDEX_REG); | ||
435 | val = val << 8 | inb(SB800_IO_PM_DATA_REG); | ||
436 | outb(SB800_PM_ACPI_MMIO_EN+0, SB800_IO_PM_INDEX_REG); | ||
437 | val = val << 8 | inb(SB800_IO_PM_DATA_REG); | ||
438 | } else { | ||
439 | /* Read SBResource_MMIO from PCI config(PCI_Reg: 9Ch) */ | ||
440 | pci_read_config_dword(sp5100_tco_pci, | ||
441 | SP5100_SB_RESOURCE_MMIO_BASE, &val); | ||
442 | } | ||
443 | |||
444 | /* The SBResource_MMIO is enabled and mapped memory space? */ | ||
445 | if ((val & (SB800_ACPI_MMIO_DECODE_EN | SB800_ACPI_MMIO_SEL)) == | ||
446 | SB800_ACPI_MMIO_DECODE_EN) { | ||
447 | /* Clear unnecessary the low twelve bits */ | ||
448 | val &= ~0xFFF; | ||
449 | /* Add the Watchdog Timer offset to base address. */ | ||
450 | val += SB800_PM_WDT_MMIO_OFFSET; | ||
451 | /* Check MMIO address conflict */ | ||
452 | if (request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, | ||
453 | dev_name)) { | ||
454 | pr_debug("Got 0x%04x from SBResource_MMIO register\n", | ||
455 | val); | ||
456 | goto setup_wdt; | ||
457 | } else | ||
458 | pr_debug("MMIO address 0x%04x already in use\n", val); | ||
459 | } else | ||
460 | pr_debug("SBResource_MMIO is disabled(0x%04x)\n", val); | ||
461 | |||
462 | /* | ||
463 | * Lastly re-programming the watchdog timer MMIO address, | ||
464 | * This method is a last resort... | ||
465 | * | ||
466 | * Before re-programming, to ensure that the watchdog timer | ||
467 | * is disabled, disable the watchdog timer. | ||
468 | */ | ||
469 | tco_timer_disable(); | ||
470 | |||
471 | if (force_addr) { | ||
472 | /* | ||
473 | * Force the use of watchdog timer MMIO address, and aligned to | ||
474 | * 8byte boundary. | ||
475 | */ | ||
476 | force_addr &= ~0x7; | ||
477 | val = force_addr; | ||
478 | |||
479 | pr_info("Force the use of 0x%04x as MMIO address\n", val); | ||
480 | } else { | ||
481 | /* | ||
482 | * Get empty slot into the resource tree for watchdog timer. | ||
483 | */ | ||
484 | if (allocate_resource(&iomem_resource, | ||
485 | &wdt_res, | ||
486 | SP5100_WDT_MEM_MAP_SIZE, | ||
487 | 0xf0000000, | ||
488 | 0xfffffff8, | ||
489 | 0x8, | ||
490 | NULL, | ||
491 | NULL)) { | ||
492 | pr_err("MMIO allocation failed\n"); | ||
493 | goto unreg_region; | ||
494 | } | ||
495 | |||
496 | val = resbase_phys = wdt_res.start; | ||
497 | pr_debug("Got 0x%04x from resource tree\n", val); | ||
498 | } | ||
499 | |||
500 | /* Restore to the low three bits, if chipset is SB8x0(or later) */ | ||
501 | if (sp5100_tco_pci->revision >= 0x40) { | ||
502 | u8 reserved_bit; | ||
503 | reserved_bit = inb(base_addr) & 0x7; | ||
504 | val |= (u32)reserved_bit; | ||
505 | } | ||
506 | |||
507 | /* Re-programming the watchdog timer base address */ | ||
508 | outb(base_addr+0, index_reg); | ||
509 | /* Low three bits of BASE are reserved */ | ||
510 | outb((val >> 0) & 0xf8, data_reg); | ||
511 | outb(base_addr+1, index_reg); | ||
512 | outb((val >> 8) & 0xff, data_reg); | ||
513 | outb(base_addr+2, index_reg); | ||
514 | outb((val >> 16) & 0xff, data_reg); | ||
515 | outb(base_addr+3, index_reg); | ||
516 | outb((val >> 24) & 0xff, data_reg); | ||
517 | |||
518 | /* | ||
519 | * Clear unnecessary the low three bits, | ||
520 | * if chipset is SB8x0(or later) | ||
521 | */ | ||
522 | if (sp5100_tco_pci->revision >= 0x40) | ||
523 | val &= ~0x7; | ||
307 | 524 | ||
308 | if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, | 525 | if (!request_mem_region_exclusive(val, SP5100_WDT_MEM_MAP_SIZE, |
309 | "SP5100 TCO")) { | 526 | dev_name)) { |
310 | pr_err("mmio address 0x%04x already in use\n", val); | 527 | pr_err("MMIO address 0x%04x already in use\n", val); |
311 | goto unreg_region; | 528 | goto unreg_resource; |
312 | } | 529 | } |
530 | |||
531 | setup_wdt: | ||
313 | tcobase_phys = val; | 532 | tcobase_phys = val; |
314 | 533 | ||
315 | tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); | 534 | tcobase = ioremap(val, SP5100_WDT_MEM_MAP_SIZE); |
@@ -318,26 +537,18 @@ static unsigned char sp5100_tco_setupdevice(void) | |||
318 | goto unreg_mem_region; | 537 | goto unreg_mem_region; |
319 | } | 538 | } |
320 | 539 | ||
321 | /* Enable watchdog decode bit */ | 540 | pr_info("Using 0x%04x for watchdog MMIO address\n", val); |
322 | pci_read_config_dword(sp5100_tco_pci, | ||
323 | SP5100_PCI_WATCHDOG_MISC_REG, | ||
324 | &val); | ||
325 | |||
326 | val |= SP5100_PCI_WATCHDOG_DECODE_EN; | ||
327 | 541 | ||
328 | pci_write_config_dword(sp5100_tco_pci, | 542 | /* Setup the watchdog timer */ |
329 | SP5100_PCI_WATCHDOG_MISC_REG, | 543 | tco_timer_enable(); |
330 | val); | ||
331 | 544 | ||
332 | /* Enable Watchdog timer and set the resolution to 1 sec. */ | 545 | /* Check that the watchdog action is set to reset the system */ |
333 | outb(SP5100_PM_WATCHDOG_CONTROL, SP5100_IO_PM_INDEX_REG); | ||
334 | val = inb(SP5100_IO_PM_DATA_REG); | ||
335 | val |= SP5100_PM_WATCHDOG_SECOND_RES; | ||
336 | val &= ~SP5100_PM_WATCHDOG_DISABLE; | ||
337 | outb(val, SP5100_IO_PM_DATA_REG); | ||
338 | |||
339 | /* Check that the watchdog action is set to reset the system. */ | ||
340 | val = readl(SP5100_WDT_CONTROL(tcobase)); | 546 | val = readl(SP5100_WDT_CONTROL(tcobase)); |
547 | /* | ||
548 | * Save WatchDogFired status, because WatchDogFired flag is | ||
549 | * cleared here. | ||
550 | */ | ||
551 | tco_wdt_fired = val & SP5100_PM_WATCHDOG_FIRED; | ||
341 | val &= ~SP5100_PM_WATCHDOG_ACTION_RESET; | 552 | val &= ~SP5100_PM_WATCHDOG_ACTION_RESET; |
342 | writel(val, SP5100_WDT_CONTROL(tcobase)); | 553 | writel(val, SP5100_WDT_CONTROL(tcobase)); |
343 | 554 | ||
@@ -355,6 +566,9 @@ static unsigned char sp5100_tco_setupdevice(void) | |||
355 | 566 | ||
356 | unreg_mem_region: | 567 | unreg_mem_region: |
357 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); | 568 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); |
569 | unreg_resource: | ||
570 | if (resbase_phys) | ||
571 | release_resource(&wdt_res); | ||
358 | unreg_region: | 572 | unreg_region: |
359 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); | 573 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); |
360 | exit: | 574 | exit: |
@@ -364,23 +578,18 @@ exit: | |||
364 | static int sp5100_tco_init(struct platform_device *dev) | 578 | static int sp5100_tco_init(struct platform_device *dev) |
365 | { | 579 | { |
366 | int ret; | 580 | int ret; |
367 | u32 val; | 581 | char addr_str[16]; |
368 | 582 | ||
369 | /* Check whether or not the hardware watchdog is there. If found, then | 583 | /* |
584 | * Check whether or not the hardware watchdog is there. If found, then | ||
370 | * set it up. | 585 | * set it up. |
371 | */ | 586 | */ |
372 | if (!sp5100_tco_setupdevice()) | 587 | if (!sp5100_tco_setupdevice()) |
373 | return -ENODEV; | 588 | return -ENODEV; |
374 | 589 | ||
375 | /* Check to see if last reboot was due to watchdog timeout */ | 590 | /* Check to see if last reboot was due to watchdog timeout */ |
376 | pr_info("Watchdog reboot %sdetected\n", | 591 | pr_info("Last reboot was %striggered by watchdog.\n", |
377 | readl(SP5100_WDT_CONTROL(tcobase)) & SP5100_PM_WATCHDOG_FIRED ? | 592 | tco_wdt_fired ? "" : "not "); |
378 | "" : "not "); | ||
379 | |||
380 | /* Clear out the old status */ | ||
381 | val = readl(SP5100_WDT_CONTROL(tcobase)); | ||
382 | val &= ~SP5100_PM_WATCHDOG_FIRED; | ||
383 | writel(val, SP5100_WDT_CONTROL(tcobase)); | ||
384 | 593 | ||
385 | /* | 594 | /* |
386 | * Check that the heartbeat value is within it's range. | 595 | * Check that the heartbeat value is within it's range. |
@@ -400,14 +609,24 @@ static int sp5100_tco_init(struct platform_device *dev) | |||
400 | 609 | ||
401 | clear_bit(0, &timer_alive); | 610 | clear_bit(0, &timer_alive); |
402 | 611 | ||
403 | pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n", | 612 | /* Show module parameters */ |
404 | tcobase, heartbeat, nowayout); | 613 | if (force_addr == tcobase_phys) |
614 | /* The force_addr is vaild */ | ||
615 | sprintf(addr_str, "0x%04x", force_addr); | ||
616 | else | ||
617 | strcpy(addr_str, "none"); | ||
618 | |||
619 | pr_info("initialized (0x%p). heartbeat=%d sec (nowayout=%d, " | ||
620 | "force_addr=%s)\n", | ||
621 | tcobase, heartbeat, nowayout, addr_str); | ||
405 | 622 | ||
406 | return 0; | 623 | return 0; |
407 | 624 | ||
408 | exit: | 625 | exit: |
409 | iounmap(tcobase); | 626 | iounmap(tcobase); |
410 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); | 627 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); |
628 | if (resbase_phys) | ||
629 | release_resource(&wdt_res); | ||
411 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); | 630 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); |
412 | return ret; | 631 | return ret; |
413 | } | 632 | } |
@@ -422,6 +641,8 @@ static void sp5100_tco_cleanup(void) | |||
422 | misc_deregister(&sp5100_tco_miscdev); | 641 | misc_deregister(&sp5100_tco_miscdev); |
423 | iounmap(tcobase); | 642 | iounmap(tcobase); |
424 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); | 643 | release_mem_region(tcobase_phys, SP5100_WDT_MEM_MAP_SIZE); |
644 | if (resbase_phys) | ||
645 | release_resource(&wdt_res); | ||
425 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); | 646 | release_region(pm_iobase, SP5100_PM_IOPORTS_SIZE); |
426 | } | 647 | } |
427 | 648 | ||
@@ -451,7 +672,7 @@ static int __init sp5100_tco_init_module(void) | |||
451 | { | 672 | { |
452 | int err; | 673 | int err; |
453 | 674 | ||
454 | pr_info("SP5100 TCO WatchDog Timer Driver v%s\n", TCO_VERSION); | 675 | pr_info("SP5100/SB800 TCO WatchDog Timer Driver v%s\n", TCO_VERSION); |
455 | 676 | ||
456 | err = platform_driver_register(&sp5100_tco_driver); | 677 | err = platform_driver_register(&sp5100_tco_driver); |
457 | if (err) | 678 | if (err) |
@@ -475,13 +696,13 @@ static void __exit sp5100_tco_cleanup_module(void) | |||
475 | { | 696 | { |
476 | platform_device_unregister(sp5100_tco_platform_device); | 697 | platform_device_unregister(sp5100_tco_platform_device); |
477 | platform_driver_unregister(&sp5100_tco_driver); | 698 | platform_driver_unregister(&sp5100_tco_driver); |
478 | pr_info("SP5100 TCO Watchdog Module Unloaded\n"); | 699 | pr_info("SP5100/SB800 TCO Watchdog Module Unloaded\n"); |
479 | } | 700 | } |
480 | 701 | ||
481 | module_init(sp5100_tco_init_module); | 702 | module_init(sp5100_tco_init_module); |
482 | module_exit(sp5100_tco_cleanup_module); | 703 | module_exit(sp5100_tco_cleanup_module); |
483 | 704 | ||
484 | MODULE_AUTHOR("Priyanka Gupta"); | 705 | MODULE_AUTHOR("Priyanka Gupta"); |
485 | MODULE_DESCRIPTION("TCO timer driver for SP5100 chipset"); | 706 | MODULE_DESCRIPTION("TCO timer driver for SP5100/SB800 chipset"); |
486 | MODULE_LICENSE("GPL"); | 707 | MODULE_LICENSE("GPL"); |
487 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 708 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |