aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/hpet.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/hpet.c')
-rw-r--r--drivers/char/hpet.c90
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
54static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ; 63static u32 hpet_nhpet, hpet_max_freq = HPET_USER_FREQ;
55 64
65/* This clocksource driver currently only works on ia64 */
66#ifdef CONFIG_IA64
67static void __iomem *hpet_mctr;
68
69static cycle_t read_hpet(void)
70{
71 return (cycle_t)read_counter((void __iomem *)hpet_mctr);
72}
73
74static 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};
83static 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. */
57static DEFINE_SPINLOCK(hpet_lock); 87static 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
106static inline unsigned long long readq(void __iomem *addr) 129static inline unsigned long long readq(void __iomem *addr)
@@ -737,27 +760,6 @@ static ctl_table dev_root[] = {
737 760
738static struct ctl_table_header *sysctl_header; 761static struct ctl_table_header *sysctl_header;
739 762
740static 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
996static int hpet_acpi_remove(struct acpi_device *device, int type) 1010static 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
1016static const struct acpi_device_id hpet_device_ids[] = {
1017 {"PNP0103", 0},
1018 {"", 0},
1019};
1020MODULE_DEVICE_TABLE(acpi, hpet_device_ids);
1021
1002static struct acpi_driver hpet_acpi_driver = { 1022static 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,