diff options
| -rw-r--r-- | drivers/watchdog/iTCO_wdt.c | 68 | ||||
| -rw-r--r-- | drivers/watchdog/s3c2410_wdt.c | 89 |
2 files changed, 112 insertions, 45 deletions
diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index 6a51edde6ea7..e44fbb31bc6f 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * intel TCO Watchdog Driver (Used in i82801 and i63xxESB chipsets) | 2 | * intel TCO Watchdog Driver |
| 3 | * | 3 | * |
| 4 | * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>. | 4 | * (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>. |
| 5 | * | 5 | * |
| @@ -14,47 +14,22 @@ | |||
| 14 | * | 14 | * |
| 15 | * The TCO watchdog is implemented in the following I/O controller hubs: | 15 | * The TCO watchdog is implemented in the following I/O controller hubs: |
| 16 | * (See the intel documentation on http://developer.intel.com.) | 16 | * (See the intel documentation on http://developer.intel.com.) |
| 17 | * 82801AA (ICH) : document number 290655-003, 290677-014, | 17 | * document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO) |
| 18 | * 82801AB (ICHO) : document number 290655-003, 290677-014, | 18 | * document number 290687-002, 298242-027: 82801BA (ICH2) |
| 19 | * 82801BA (ICH2) : document number 290687-002, 298242-027, | 19 | * document number 290733-003, 290739-013: 82801CA (ICH3-S) |
| 20 | * 82801BAM (ICH2-M) : document number 290687-002, 298242-027, | 20 | * document number 290716-001, 290718-007: 82801CAM (ICH3-M) |
| 21 | * 82801CA (ICH3-S) : document number 290733-003, 290739-013, | 21 | * document number 290744-001, 290745-025: 82801DB (ICH4) |
| 22 | * 82801CAM (ICH3-M) : document number 290716-001, 290718-007, | 22 | * document number 252337-001, 252663-008: 82801DBM (ICH4-M) |
| 23 | * 82801DB (ICH4) : document number 290744-001, 290745-025, | 23 | * document number 273599-001, 273645-002: 82801E (C-ICH) |
| 24 | * 82801DBM (ICH4-M) : document number 252337-001, 252663-008, | 24 | * document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R) |
| 25 | * 82801E (C-ICH) : document number 273599-001, 273645-002, | 25 | * document number 300641-004, 300884-013: 6300ESB |
| 26 | * 82801EB (ICH5) : document number 252516-001, 252517-028, | 26 | * document number 301473-002, 301474-026: 82801F (ICH6) |
| 27 | * 82801ER (ICH5R) : document number 252516-001, 252517-028, | 27 | * document number 313082-001, 313075-006: 631xESB, 632xESB |
| 28 | * 6300ESB (6300ESB) : document number 300641-004, 300884-013, | 28 | * document number 307013-003, 307014-024: 82801G (ICH7) |
| 29 | * 82801FB (ICH6) : document number 301473-002, 301474-026, | 29 | * document number 313056-003, 313057-017: 82801H (ICH8) |
| 30 | * 82801FR (ICH6R) : document number 301473-002, 301474-026, | 30 | * document number 316972-004, 316973-012: 82801I (ICH9) |
| 31 | * 82801FBM (ICH6-M) : document number 301473-002, 301474-026, | 31 | * document number 319973-002, 319974-002: 82801J (ICH10) |
| 32 | * 82801FW (ICH6W) : document number 301473-001, 301474-026, | 32 | * document number 322169-001, 322170-001: 5 Series, 3400 Series (PCH) |
| 33 | * 82801FRW (ICH6RW) : document number 301473-001, 301474-026, | ||
| 34 | * 631xESB (631xESB) : document number 313082-001, 313075-006, | ||
| 35 | * 632xESB (632xESB) : document number 313082-001, 313075-006, | ||
| 36 | * 82801GB (ICH7) : document number 307013-003, 307014-024, | ||
| 37 | * 82801GR (ICH7R) : document number 307013-003, 307014-024, | ||
| 38 | * 82801GDH (ICH7DH) : document number 307013-003, 307014-024, | ||
| 39 | * 82801GBM (ICH7-M) : document number 307013-003, 307014-024, | ||
| 40 | * 82801GHM (ICH7-M DH) : document number 307013-003, 307014-024, | ||
| 41 | * 82801GU (ICH7-U) : document number 307013-003, 307014-024, | ||
| 42 | * 82801HB (ICH8) : document number 313056-003, 313057-017, | ||
| 43 | * 82801HR (ICH8R) : document number 313056-003, 313057-017, | ||
| 44 | * 82801HBM (ICH8M) : document number 313056-003, 313057-017, | ||
| 45 | * 82801HH (ICH8DH) : document number 313056-003, 313057-017, | ||
| 46 | * 82801HO (ICH8DO) : document number 313056-003, 313057-017, | ||
| 47 | * 82801HEM (ICH8M-E) : document number 313056-003, 313057-017, | ||
| 48 | * 82801IB (ICH9) : document number 316972-004, 316973-012, | ||
| 49 | * 82801IR (ICH9R) : document number 316972-004, 316973-012, | ||
| 50 | * 82801IH (ICH9DH) : document number 316972-004, 316973-012, | ||
| 51 | * 82801IO (ICH9DO) : document number 316972-004, 316973-012, | ||
| 52 | * 82801IBM (ICH9M) : document number 316972-004, 316973-012, | ||
| 53 | * 82801IEM (ICH9M-E) : document number 316972-004, 316973-012, | ||
| 54 | * 82801JIB (ICH10) : document number 319973-002, 319974-002, | ||
| 55 | * 82801JIR (ICH10R) : document number 319973-002, 319974-002, | ||
| 56 | * 82801JD (ICH10D) : document number 319973-002, 319974-002, | ||
| 57 | * 82801JDO (ICH10DO) : document number 319973-002, 319974-002 | ||
| 58 | */ | 33 | */ |
| 59 | 34 | ||
| 60 | /* | 35 | /* |
| @@ -122,6 +97,9 @@ enum iTCO_chipsets { | |||
| 122 | TCO_ICH10R, /* ICH10R */ | 97 | TCO_ICH10R, /* ICH10R */ |
| 123 | TCO_ICH10D, /* ICH10D */ | 98 | TCO_ICH10D, /* ICH10D */ |
| 124 | TCO_ICH10DO, /* ICH10DO */ | 99 | TCO_ICH10DO, /* ICH10DO */ |
| 100 | TCO_PCH, /* PCH Desktop Full Featured */ | ||
| 101 | TCO_PCHM, /* PCH Mobile Full Featured */ | ||
| 102 | TCO_PCHMSFF, /* PCH Mobile SFF Full Featured */ | ||
| 125 | }; | 103 | }; |
| 126 | 104 | ||
| 127 | static struct { | 105 | static struct { |
| @@ -162,6 +140,9 @@ static struct { | |||
| 162 | {"ICH10R", 2}, | 140 | {"ICH10R", 2}, |
| 163 | {"ICH10D", 2}, | 141 | {"ICH10D", 2}, |
| 164 | {"ICH10DO", 2}, | 142 | {"ICH10DO", 2}, |
| 143 | {"PCH Desktop Full Featured", 2}, | ||
| 144 | {"PCH Mobile Full Featured", 2}, | ||
| 145 | {"PCH Mobile SFF Full Featured", 2}, | ||
| 165 | {NULL, 0} | 146 | {NULL, 0} |
| 166 | }; | 147 | }; |
| 167 | 148 | ||
| @@ -230,6 +211,9 @@ static struct pci_device_id iTCO_wdt_pci_tbl[] = { | |||
| 230 | { ITCO_PCI_DEVICE(0x3a16, TCO_ICH10R)}, | 211 | { ITCO_PCI_DEVICE(0x3a16, TCO_ICH10R)}, |
| 231 | { ITCO_PCI_DEVICE(0x3a1a, TCO_ICH10D)}, | 212 | { ITCO_PCI_DEVICE(0x3a1a, TCO_ICH10D)}, |
| 232 | { ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)}, | 213 | { ITCO_PCI_DEVICE(0x3a14, TCO_ICH10DO)}, |
| 214 | { ITCO_PCI_DEVICE(0x3b00, TCO_PCH)}, | ||
| 215 | { ITCO_PCI_DEVICE(0x3b01, TCO_PCHM)}, | ||
| 216 | { ITCO_PCI_DEVICE(0x3b0d, TCO_PCHMSFF)}, | ||
| 233 | { 0, }, /* End of list */ | 217 | { 0, }, /* End of list */ |
| 234 | }; | 218 | }; |
| 235 | MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); | 219 | MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); |
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index b57ac6b49147..85b93e15d011 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/clk.h> | 36 | #include <linux/clk.h> |
| 37 | #include <linux/uaccess.h> | 37 | #include <linux/uaccess.h> |
| 38 | #include <linux/io.h> | 38 | #include <linux/io.h> |
| 39 | #include <linux/cpufreq.h> | ||
| 39 | 40 | ||
| 40 | #include <mach/map.h> | 41 | #include <mach/map.h> |
| 41 | 42 | ||
| @@ -142,9 +143,14 @@ static void s3c2410wdt_start(void) | |||
| 142 | spin_unlock(&wdt_lock); | 143 | spin_unlock(&wdt_lock); |
| 143 | } | 144 | } |
| 144 | 145 | ||
| 146 | static inline int s3c2410wdt_is_running(void) | ||
| 147 | { | ||
| 148 | return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE; | ||
| 149 | } | ||
| 150 | |||
| 145 | static int s3c2410wdt_set_heartbeat(int timeout) | 151 | static int s3c2410wdt_set_heartbeat(int timeout) |
| 146 | { | 152 | { |
| 147 | unsigned int freq = clk_get_rate(wdt_clock); | 153 | unsigned long freq = clk_get_rate(wdt_clock); |
| 148 | unsigned int count; | 154 | unsigned int count; |
| 149 | unsigned int divisor = 1; | 155 | unsigned int divisor = 1; |
| 150 | unsigned long wtcon; | 156 | unsigned long wtcon; |
| @@ -155,7 +161,7 @@ static int s3c2410wdt_set_heartbeat(int timeout) | |||
| 155 | freq /= 128; | 161 | freq /= 128; |
| 156 | count = timeout * freq; | 162 | count = timeout * freq; |
| 157 | 163 | ||
| 158 | DBG("%s: count=%d, timeout=%d, freq=%d\n", | 164 | DBG("%s: count=%d, timeout=%d, freq=%lu\n", |
| 159 | __func__, count, timeout, freq); | 165 | __func__, count, timeout, freq); |
| 160 | 166 | ||
| 161 | /* if the count is bigger than the watchdog register, | 167 | /* if the count is bigger than the watchdog register, |
| @@ -324,6 +330,73 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param) | |||
| 324 | s3c2410wdt_keepalive(); | 330 | s3c2410wdt_keepalive(); |
| 325 | return IRQ_HANDLED; | 331 | return IRQ_HANDLED; |
| 326 | } | 332 | } |
| 333 | |||
| 334 | |||
| 335 | #ifdef CONFIG_CPU_FREQ | ||
| 336 | |||
| 337 | static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb, | ||
| 338 | unsigned long val, void *data) | ||
| 339 | { | ||
| 340 | int ret; | ||
| 341 | |||
| 342 | if (!s3c2410wdt_is_running()) | ||
| 343 | goto done; | ||
| 344 | |||
| 345 | if (val == CPUFREQ_PRECHANGE) { | ||
| 346 | /* To ensure that over the change we don't cause the | ||
| 347 | * watchdog to trigger, we perform an keep-alive if | ||
| 348 | * the watchdog is running. | ||
| 349 | */ | ||
| 350 | |||
| 351 | s3c2410wdt_keepalive(); | ||
| 352 | } else if (val == CPUFREQ_POSTCHANGE) { | ||
| 353 | s3c2410wdt_stop(); | ||
| 354 | |||
| 355 | ret = s3c2410wdt_set_heartbeat(tmr_margin); | ||
| 356 | |||
| 357 | if (ret >= 0) | ||
| 358 | s3c2410wdt_start(); | ||
| 359 | else | ||
| 360 | goto err; | ||
| 361 | } | ||
| 362 | |||
| 363 | done: | ||
| 364 | return 0; | ||
| 365 | |||
| 366 | err: | ||
| 367 | dev_err(wdt_dev, "cannot set new value for timeout %d\n", tmr_margin); | ||
| 368 | return ret; | ||
| 369 | } | ||
| 370 | |||
| 371 | static struct notifier_block s3c2410wdt_cpufreq_transition_nb = { | ||
| 372 | .notifier_call = s3c2410wdt_cpufreq_transition, | ||
| 373 | }; | ||
| 374 | |||
| 375 | static inline int s3c2410wdt_cpufreq_register(void) | ||
| 376 | { | ||
| 377 | return cpufreq_register_notifier(&s3c2410wdt_cpufreq_transition_nb, | ||
| 378 | CPUFREQ_TRANSITION_NOTIFIER); | ||
| 379 | } | ||
| 380 | |||
| 381 | static inline void s3c2410wdt_cpufreq_deregister(void) | ||
| 382 | { | ||
| 383 | cpufreq_unregister_notifier(&s3c2410wdt_cpufreq_transition_nb, | ||
| 384 | CPUFREQ_TRANSITION_NOTIFIER); | ||
| 385 | } | ||
| 386 | |||
| 387 | #else | ||
| 388 | static inline int s3c2410wdt_cpufreq_register(void) | ||
| 389 | { | ||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | static inline void s3c2410wdt_cpufreq_deregister(void) | ||
| 394 | { | ||
| 395 | } | ||
| 396 | #endif | ||
| 397 | |||
| 398 | |||
| 399 | |||
| 327 | /* device interface */ | 400 | /* device interface */ |
| 328 | 401 | ||
| 329 | static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | 402 | static int __devinit s3c2410wdt_probe(struct platform_device *pdev) |
| @@ -387,6 +460,11 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
| 387 | 460 | ||
| 388 | clk_enable(wdt_clock); | 461 | clk_enable(wdt_clock); |
| 389 | 462 | ||
| 463 | if (s3c2410wdt_cpufreq_register() < 0) { | ||
| 464 | printk(KERN_ERR PFX "failed to register cpufreq\n"); | ||
| 465 | goto err_clk; | ||
| 466 | } | ||
| 467 | |||
| 390 | /* see if we can actually set the requested timer margin, and if | 468 | /* see if we can actually set the requested timer margin, and if |
| 391 | * not, try the default value */ | 469 | * not, try the default value */ |
| 392 | 470 | ||
| @@ -407,7 +485,7 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
| 407 | if (ret) { | 485 | if (ret) { |
| 408 | dev_err(dev, "cannot register miscdev on minor=%d (%d)\n", | 486 | dev_err(dev, "cannot register miscdev on minor=%d (%d)\n", |
| 409 | WATCHDOG_MINOR, ret); | 487 | WATCHDOG_MINOR, ret); |
| 410 | goto err_clk; | 488 | goto err_cpufreq; |
| 411 | } | 489 | } |
| 412 | 490 | ||
| 413 | if (tmr_atboot && started == 0) { | 491 | if (tmr_atboot && started == 0) { |
| @@ -432,6 +510,9 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
| 432 | 510 | ||
| 433 | return 0; | 511 | return 0; |
| 434 | 512 | ||
| 513 | err_cpufreq: | ||
| 514 | s3c2410wdt_cpufreq_deregister(); | ||
| 515 | |||
| 435 | err_clk: | 516 | err_clk: |
| 436 | clk_disable(wdt_clock); | 517 | clk_disable(wdt_clock); |
| 437 | clk_put(wdt_clock); | 518 | clk_put(wdt_clock); |
| @@ -451,6 +532,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) | |||
| 451 | 532 | ||
| 452 | static int __devexit s3c2410wdt_remove(struct platform_device *dev) | 533 | static int __devexit s3c2410wdt_remove(struct platform_device *dev) |
| 453 | { | 534 | { |
| 535 | s3c2410wdt_cpufreq_deregister(); | ||
| 536 | |||
| 454 | release_resource(wdt_mem); | 537 | release_resource(wdt_mem); |
| 455 | kfree(wdt_mem); | 538 | kfree(wdt_mem); |
| 456 | wdt_mem = NULL; | 539 | wdt_mem = NULL; |
