diff options
Diffstat (limited to 'drivers/char/hpet.c')
-rw-r--r-- | drivers/char/hpet.c | 90 |
1 files changed, 55 insertions, 35 deletions
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 0be700f4e8fd..4c16778e3f84 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/bcd.h> | 29 | #include <linux/bcd.h> |
30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
31 | #include <linux/bitops.h> | 31 | #include <linux/bitops.h> |
32 | #include <linux/clocksource.h> | ||
32 | 33 | ||
33 | #include <asm/current.h> | 34 | #include <asm/current.h> |
34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
@@ -51,8 +52,37 @@ | |||
51 | 52 | ||
52 | #define HPET_RANGE_SIZE 1024 /* from HPET spec */ | 53 | #define HPET_RANGE_SIZE 1024 /* from HPET spec */ |
53 | 54 | ||
55 | #if BITS_PER_LONG == 64 | ||
56 | #define write_counter(V, MC) writeq(V, MC) | ||
57 | #define read_counter(MC) readq(MC) | ||
58 | #else | ||
59 | #define write_counter(V, MC) writel(V, MC) | ||
60 | #define read_counter(MC) readl(MC) | ||
61 | #endif | ||
62 | |||
54 | static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; | 63 | static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; |
55 | 64 | ||
65 | /* This clocksource driver currently only works on ia64 */ | ||
66 | #ifdef CONFIG_IA64 | ||
67 | static void __iomem *hpet_mctr; | ||
68 | |||
69 | static cycle_t read_hpet(void) | ||
70 | { | ||
71 | return (cycle_t)read_counter((void __iomem *)hpet_mctr); | ||
72 | } | ||
73 | |||
74 | static struct clocksource clocksource_hpet = { | ||
75 | .name = "hpet", | ||
76 | .rating = 250, | ||
77 | .read = read_hpet, | ||
78 | .mask = CLOCKSOURCE_MASK(64), | ||
79 | .mult = 0, /*to be caluclated*/ | ||
80 | .shift = 10, | ||
81 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
82 | }; | ||
83 | static struct clocksource *hpet_clocksource; | ||
84 | #endif | ||
85 | |||
56 | /* A lock for concurrent access by app and isr hpet activity. */ | 86 | /* A lock for concurrent access by app and isr hpet activity. */ |
57 | static DEFINE_SPINLOCK(hpet_lock); | 87 | static DEFINE_SPINLOCK(hpet_lock); |
58 | /* A lock for concurrent intermodule access to hpet and isr hpet activity. */ | 88 | /* A lock for concurrent intermodule access to hpet and isr hpet activity. */ |
@@ -79,7 +109,7 @@ struct hpets { | |||
79 | struct hpets *hp_next; | 109 | struct hpets *hp_next; |
80 | struct hpet __iomem *hp_hpet; | 110 | struct hpet __iomem *hp_hpet; |
81 | unsigned long hp_hpet_phys; | 111 | unsigned long hp_hpet_phys; |
82 | struct time_interpolator *hp_interpolator; | 112 | struct clocksource *hp_clocksource; |
83 | unsigned long long hp_tick_freq; | 113 | unsigned long long hp_tick_freq; |
84 | unsigned long hp_delta; | 114 | unsigned long hp_delta; |
85 | unsigned int hp_ntimer; | 115 | unsigned int hp_ntimer; |
@@ -94,13 +124,6 @@ static struct hpets *hpets; | |||
94 | #define HPET_PERIODIC 0x0004 | 124 | #define HPET_PERIODIC 0x0004 |
95 | #define HPET_SHARED_IRQ 0x0008 | 125 | #define HPET_SHARED_IRQ 0x0008 |
96 | 126 | ||
97 | #if BITS_PER_LONG == 64 | ||
98 | #define write_counter(V, MC) writeq(V, MC) | ||
99 | #define read_counter(MC) readq(MC) | ||
100 | #else | ||
101 | #define write_counter(V, MC) writel(V, MC) | ||
102 | #define read_counter(MC) readl(MC) | ||
103 | #endif | ||
104 | 127 | ||
105 | #ifndef readq | 128 | #ifndef readq |
106 | static inline unsigned long long readq(void __iomem *addr) | 129 | static inline unsigned long long readq(void __iomem *addr) |
@@ -737,27 +760,6 @@ static ctl_table dev_root[] = { | |||
737 | 760 | ||
738 | static struct ctl_table_header *sysctl_header; | 761 | static struct ctl_table_header *sysctl_header; |
739 | 762 | ||
740 | static void hpet_register_interpolator(struct hpets *hpetp) | ||
741 | { | ||
742 | #ifdef CONFIG_TIME_INTERPOLATION | ||
743 | struct time_interpolator *ti; | ||
744 | |||
745 | ti = kzalloc(sizeof(*ti), GFP_KERNEL); | ||
746 | if (!ti) | ||
747 | return; | ||
748 | |||
749 | ti->source = TIME_SOURCE_MMIO64; | ||
750 | ti->shift = 10; | ||
751 | ti->addr = &hpetp->hp_hpet->hpet_mc; | ||
752 | ti->frequency = hpetp->hp_tick_freq; | ||
753 | ti->drift = HPET_DRIFT; | ||
754 | ti->mask = -1; | ||
755 | |||
756 | hpetp->hp_interpolator = ti; | ||
757 | register_time_interpolator(ti); | ||
758 | #endif | ||
759 | } | ||
760 | |||
761 | /* | 763 | /* |
762 | * Adjustment for when arming the timer with | 764 | * Adjustment for when arming the timer with |
763 | * initial conditions. That is, main counter | 765 | * initial conditions. That is, main counter |
@@ -909,7 +911,19 @@ int hpet_alloc(struct hpet_data *hdp) | |||
909 | } | 911 | } |
910 | 912 | ||
911 | hpetp->hp_delta = hpet_calibrate(hpetp); | 913 | hpetp->hp_delta = hpet_calibrate(hpetp); |
912 | hpet_register_interpolator(hpetp); | 914 | |
915 | /* This clocksource driver currently only works on ia64 */ | ||
916 | #ifdef CONFIG_IA64 | ||
917 | if (!hpet_clocksource) { | ||
918 | hpet_mctr = (void __iomem *)&hpetp->hp_hpet->hpet_mc; | ||
919 | CLKSRC_FSYS_MMIO_SET(clocksource_hpet.fsys_mmio, hpet_mctr); | ||
920 | clocksource_hpet.mult = clocksource_hz2mult(hpetp->hp_tick_freq, | ||
921 | clocksource_hpet.shift); | ||
922 | clocksource_register(&clocksource_hpet); | ||
923 | hpetp->hp_clocksource = &clocksource_hpet; | ||
924 | hpet_clocksource = &clocksource_hpet; | ||
925 | } | ||
926 | #endif | ||
913 | 927 | ||
914 | return 0; | 928 | return 0; |
915 | } | 929 | } |
@@ -932,14 +946,14 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) | |||
932 | printk(KERN_DEBUG "%s: 0x%lx is busy\n", | 946 | printk(KERN_DEBUG "%s: 0x%lx is busy\n", |
933 | __FUNCTION__, hdp->hd_phys_address); | 947 | __FUNCTION__, hdp->hd_phys_address); |
934 | iounmap(hdp->hd_address); | 948 | iounmap(hdp->hd_address); |
935 | return -EBUSY; | 949 | return AE_ALREADY_EXISTS; |
936 | } | 950 | } |
937 | } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { | 951 | } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) { |
938 | struct acpi_resource_fixed_memory32 *fixmem32; | 952 | struct acpi_resource_fixed_memory32 *fixmem32; |
939 | 953 | ||
940 | fixmem32 = &res->data.fixed_memory32; | 954 | fixmem32 = &res->data.fixed_memory32; |
941 | if (!fixmem32) | 955 | if (!fixmem32) |
942 | return -EINVAL; | 956 | return AE_NO_MEMORY; |
943 | 957 | ||
944 | hdp->hd_phys_address = fixmem32->address; | 958 | hdp->hd_phys_address = fixmem32->address; |
945 | hdp->hd_address = ioremap(fixmem32->address, | 959 | hdp->hd_address = ioremap(fixmem32->address, |
@@ -949,7 +963,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) | |||
949 | printk(KERN_DEBUG "%s: 0x%lx is busy\n", | 963 | printk(KERN_DEBUG "%s: 0x%lx is busy\n", |
950 | __FUNCTION__, hdp->hd_phys_address); | 964 | __FUNCTION__, hdp->hd_phys_address); |
951 | iounmap(hdp->hd_address); | 965 | iounmap(hdp->hd_address); |
952 | return -EBUSY; | 966 | return AE_ALREADY_EXISTS; |
953 | } | 967 | } |
954 | } else if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { | 968 | } else if (res->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) { |
955 | struct acpi_resource_extended_irq *irqp; | 969 | struct acpi_resource_extended_irq *irqp; |
@@ -995,13 +1009,19 @@ static int hpet_acpi_add(struct acpi_device *device) | |||
995 | 1009 | ||
996 | static int hpet_acpi_remove(struct acpi_device *device, int type) | 1010 | static int hpet_acpi_remove(struct acpi_device *device, int type) |
997 | { | 1011 | { |
998 | /* XXX need to unregister interpolator, dealloc mem, etc */ | 1012 | /* XXX need to unregister clocksource, dealloc mem, etc */ |
999 | return -EINVAL; | 1013 | return -EINVAL; |
1000 | } | 1014 | } |
1001 | 1015 | ||
1016 | static const struct acpi_device_id hpet_device_ids[] = { | ||
1017 | {"PNP0103", 0}, | ||
1018 | {"", 0}, | ||
1019 | }; | ||
1020 | MODULE_DEVICE_TABLE(acpi, hpet_device_ids); | ||
1021 | |||
1002 | static struct acpi_driver hpet_acpi_driver = { | 1022 | static struct acpi_driver hpet_acpi_driver = { |
1003 | .name = "hpet", | 1023 | .name = "hpet", |
1004 | .ids = "PNP0103", | 1024 | .ids = hpet_device_ids, |
1005 | .ops = { | 1025 | .ops = { |
1006 | .add = hpet_acpi_add, | 1026 | .add = hpet_acpi_add, |
1007 | .remove = hpet_acpi_remove, | 1027 | .remove = hpet_acpi_remove, |