aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/hpet.c
diff options
context:
space:
mode:
authorMaxim Levitsky <maximlevitsky@gmail.com>2007-03-29 09:46:48 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-29 13:25:32 -0400
commit399afa4fc9238fbae42116cf25a54671c0e8f56e (patch)
tree875b69d487a1ee858cf1c871649627e213bc1019 /arch/i386/kernel/hpet.c
parent22c8c65d24b37cef1d28583c7a7ffbf84f840e7a (diff)
[PATCH] Add suspend/resume for HPET
This adds support of suspend/resume on i386 for HPET, which fixes a number of timer-related failures around STR. Signed-off-by: Maxim Levitsky <maximlevitsky@gmail.com> Acked-by: Michael S. Tsirkin <mst@dev.mellanox.co.il> Acked-by: Jeff Chua <jeff.chua.linux@gmail.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/i386/kernel/hpet.c')
-rw-r--r--arch/i386/kernel/hpet.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/arch/i386/kernel/hpet.c b/arch/i386/kernel/hpet.c
index 76afea67f691..17d73459fc5f 100644
--- a/arch/i386/kernel/hpet.c
+++ b/arch/i386/kernel/hpet.c
@@ -3,6 +3,8 @@
3#include <linux/errno.h> 3#include <linux/errno.h>
4#include <linux/hpet.h> 4#include <linux/hpet.h>
5#include <linux/init.h> 5#include <linux/init.h>
6#include <linux/sysdev.h>
7#include <linux/pm.h>
6 8
7#include <asm/hpet.h> 9#include <asm/hpet.h>
8#include <asm/io.h> 10#include <asm/io.h>
@@ -307,6 +309,7 @@ int __init hpet_enable(void)
307out_nohpet: 309out_nohpet:
308 iounmap(hpet_virt_address); 310 iounmap(hpet_virt_address);
309 hpet_virt_address = NULL; 311 hpet_virt_address = NULL;
312 boot_hpet_disable = 1;
310 return 0; 313 return 0;
311} 314}
312 315
@@ -521,3 +524,68 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
521 return IRQ_HANDLED; 524 return IRQ_HANDLED;
522} 525}
523#endif 526#endif
527
528
529/*
530 * Suspend/resume part
531 */
532
533#ifdef CONFIG_PM
534
535static int hpet_suspend(struct sys_device *sys_device, pm_message_t state)
536{
537 unsigned long cfg = hpet_readl(HPET_CFG);
538
539 cfg &= ~(HPET_CFG_ENABLE|HPET_CFG_LEGACY);
540 hpet_writel(cfg, HPET_CFG);
541
542 return 0;
543}
544
545static int hpet_resume(struct sys_device *sys_device)
546{
547 unsigned int id;
548
549 hpet_start_counter();
550
551 id = hpet_readl(HPET_ID);
552
553 if (id & HPET_ID_LEGSUP)
554 hpet_enable_int();
555
556 return 0;
557}
558
559static struct sysdev_class hpet_class = {
560 set_kset_name("hpet"),
561 .suspend = hpet_suspend,
562 .resume = hpet_resume,
563};
564
565static struct sys_device hpet_device = {
566 .id = 0,
567 .cls = &hpet_class,
568};
569
570
571static __init int hpet_register_sysfs(void)
572{
573 int err;
574
575 if (!is_hpet_capable())
576 return 0;
577
578 err = sysdev_class_register(&hpet_class);
579
580 if (!err) {
581 err = sysdev_register(&hpet_device);
582 if (err)
583 sysdev_class_unregister(&hpet_class);
584 }
585
586 return err;
587}
588
589device_initcall(hpet_register_sysfs);
590
591#endif