diff options
Diffstat (limited to 'arch/arm/mach-rpc/time.c')
-rw-r--r-- | arch/arm/mach-rpc/time.c | 38 |
1 files changed, 25 insertions, 13 deletions
diff --git a/arch/arm/mach-rpc/time.c b/arch/arm/mach-rpc/time.c index 2689771c1d38..1c84efc9db1f 100644 --- a/arch/arm/mach-rpc/time.c +++ b/arch/arm/mach-rpc/time.c | |||
@@ -13,7 +13,7 @@ | |||
13 | * 04-Dec-1997 RMK Updated for new arch/arm/time.c | 13 | * 04-Dec-1997 RMK Updated for new arch/arm/time.c |
14 | * 13=Jun-2004 DS Moved to arch/arm/common b/c shared w/CLPS7500 | 14 | * 13=Jun-2004 DS Moved to arch/arm/common b/c shared w/CLPS7500 |
15 | */ | 15 | */ |
16 | #include <linux/timex.h> | 16 | #include <linux/clocksource.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/irq.h> | 19 | #include <linux/irq.h> |
@@ -27,11 +27,15 @@ | |||
27 | #define RPC_CLOCK_FREQ 2000000 | 27 | #define RPC_CLOCK_FREQ 2000000 |
28 | #define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ) | 28 | #define RPC_LATCH DIV_ROUND_CLOSEST(RPC_CLOCK_FREQ, HZ) |
29 | 29 | ||
30 | static u32 ioc_timer_gettimeoffset(void) | 30 | static u32 ioc_time; |
31 | |||
32 | static u64 ioc_timer_read(struct clocksource *cs) | ||
31 | { | 33 | { |
32 | unsigned int count1, count2, status; | 34 | unsigned int count1, count2, status; |
33 | long offset; | 35 | unsigned long flags; |
36 | u32 ticks; | ||
34 | 37 | ||
38 | local_irq_save(flags); | ||
35 | ioc_writeb (0, IOC_T0LATCH); | 39 | ioc_writeb (0, IOC_T0LATCH); |
36 | barrier (); | 40 | barrier (); |
37 | count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); | 41 | count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); |
@@ -41,27 +45,34 @@ static u32 ioc_timer_gettimeoffset(void) | |||
41 | ioc_writeb (0, IOC_T0LATCH); | 45 | ioc_writeb (0, IOC_T0LATCH); |
42 | barrier (); | 46 | barrier (); |
43 | count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); | 47 | count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); |
48 | ticks = ioc_time + RPC_LATCH - count2; | ||
49 | local_irq_restore(flags); | ||
44 | 50 | ||
45 | offset = count2; | ||
46 | if (count2 < count1) { | 51 | if (count2 < count1) { |
47 | /* | 52 | /* |
48 | * We have not had an interrupt between reading count1 | 53 | * The timer has not reloaded between reading count1 and |
49 | * and count2. | 54 | * count2, check whether an interrupt was actually pending. |
50 | */ | 55 | */ |
51 | if (status & (1 << 5)) | 56 | if (status & (1 << 5)) |
52 | offset -= RPC_LATCH; | 57 | ticks += RPC_LATCH; |
53 | } else if (count2 > count1) { | 58 | } else if (count2 > count1) { |
54 | /* | 59 | /* |
55 | * We have just had another interrupt between reading | 60 | * The timer has reloaded, so count2 indicates the new |
56 | * count1 and count2. | 61 | * count since the wrap. The interrupt would not have |
62 | * been processed, so add the missed ticks. | ||
57 | */ | 63 | */ |
58 | offset -= RPC_LATCH; | 64 | ticks += RPC_LATCH; |
59 | } | 65 | } |
60 | 66 | ||
61 | offset = (RPC_LATCH - offset) * (tick_nsec / 1000); | 67 | return ticks; |
62 | return DIV_ROUND_CLOSEST(offset, RPC_LATCH) * 1000; | ||
63 | } | 68 | } |
64 | 69 | ||
70 | static struct clocksource ioctime_clocksource = { | ||
71 | .read = ioc_timer_read, | ||
72 | .mask = CLOCKSOURCE_MASK(32), | ||
73 | .rating = 100, | ||
74 | }; | ||
75 | |||
65 | void __init ioctime_init(void) | 76 | void __init ioctime_init(void) |
66 | { | 77 | { |
67 | ioc_writeb(RPC_LATCH & 255, IOC_T0LTCHL); | 78 | ioc_writeb(RPC_LATCH & 255, IOC_T0LTCHL); |
@@ -72,6 +83,7 @@ void __init ioctime_init(void) | |||
72 | static irqreturn_t | 83 | static irqreturn_t |
73 | ioc_timer_interrupt(int irq, void *dev_id) | 84 | ioc_timer_interrupt(int irq, void *dev_id) |
74 | { | 85 | { |
86 | ioc_time += RPC_LATCH; | ||
75 | timer_tick(); | 87 | timer_tick(); |
76 | return IRQ_HANDLED; | 88 | return IRQ_HANDLED; |
77 | } | 89 | } |
@@ -86,7 +98,7 @@ static struct irqaction ioc_timer_irq = { | |||
86 | */ | 98 | */ |
87 | void __init ioc_timer_init(void) | 99 | void __init ioc_timer_init(void) |
88 | { | 100 | { |
89 | arch_gettimeoffset = ioc_timer_gettimeoffset; | 101 | WARN_ON(clocksource_register_hz(&ioctime_clocksource, RPC_CLOCK_FREQ)); |
90 | ioctime_init(); | 102 | ioctime_init(); |
91 | setup_irq(IRQ_TIMER0, &ioc_timer_irq); | 103 | setup_irq(IRQ_TIMER0, &ioc_timer_irq); |
92 | } | 104 | } |