Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/arm/mach-footbridge/isa-timer.c | |
3 | * | |
4 | * Copyright (C) 1998 Russell King. | |
5 | * Copyright (C) 1998 Phil Blundell | |
6 | */ | |
7 | #include <linux/init.h> | |
8 | #include <linux/interrupt.h> | |
55e86989 | 9 | #include <linux/irq.h> |
fced80c7 | 10 | #include <linux/io.h> |
1da177e4 | 11 | |
1da177e4 LT |
12 | #include <asm/irq.h> |
13 | ||
14 | #include <asm/mach/time.h> | |
15 | ||
16 | #include "common.h" | |
17 | ||
18 | /* | |
19 | * ISA timer tick support | |
20 | */ | |
21 | #define mSEC_10_from_14 ((14318180 + 100) / 200) | |
22 | ||
23 | static unsigned long isa_gettimeoffset(void) | |
24 | { | |
25 | int count; | |
26 | ||
27 | static int count_p = (mSEC_10_from_14/6); /* for the first call after boot */ | |
28 | static unsigned long jiffies_p = 0; | |
29 | ||
30 | /* | |
31 | * cache volatile jiffies temporarily; we have IRQs turned off. | |
32 | */ | |
33 | unsigned long jiffies_t; | |
34 | ||
35 | /* timer count may underflow right here */ | |
36 | outb_p(0x00, 0x43); /* latch the count ASAP */ | |
37 | ||
38 | count = inb_p(0x40); /* read the latched count */ | |
39 | ||
40 | /* | |
41 | * We do this guaranteed double memory access instead of a _p | |
42 | * postfix in the previous port access. Wheee, hackady hack | |
43 | */ | |
44 | jiffies_t = jiffies; | |
45 | ||
46 | count |= inb_p(0x40) << 8; | |
47 | ||
48 | /* Detect timer underflows. If we haven't had a timer tick since | |
49 | the last time we were called, and time is apparently going | |
50 | backwards, the counter must have wrapped during this routine. */ | |
51 | if ((jiffies_t == jiffies_p) && (count > count_p)) | |
52 | count -= (mSEC_10_from_14/6); | |
53 | else | |
54 | jiffies_p = jiffies_t; | |
55 | ||
56 | count_p = count; | |
57 | ||
58 | count = (((mSEC_10_from_14/6)-1) - count) * (tick_nsec / 1000); | |
59 | count = (count + (mSEC_10_from_14/6)/2) / (mSEC_10_from_14/6); | |
60 | ||
61 | return count; | |
62 | } | |
63 | ||
64 | static irqreturn_t | |
0cd61b68 | 65 | isa_timer_interrupt(int irq, void *dev_id) |
1da177e4 | 66 | { |
0cd61b68 | 67 | timer_tick(); |
1da177e4 LT |
68 | return IRQ_HANDLED; |
69 | } | |
70 | ||
71 | static struct irqaction isa_timer_irq = { | |
72 | .name = "ISA timer tick", | |
73 | .handler = isa_timer_interrupt, | |
b30fabad | 74 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, |
1da177e4 LT |
75 | }; |
76 | ||
77 | static void __init isa_timer_init(void) | |
78 | { | |
79 | isa_rtc_init(); | |
80 | ||
81 | /* enable PIT timer */ | |
82 | /* set for periodic (4) and LSB/MSB write (0x30) */ | |
83 | outb(0x34, 0x43); | |
84 | outb((mSEC_10_from_14/6) & 0xFF, 0x40); | |
85 | outb((mSEC_10_from_14/6) >> 8, 0x40); | |
86 | ||
87 | setup_irq(IRQ_ISA_TIMER, &isa_timer_irq); | |
88 | } | |
89 | ||
90 | struct sys_timer isa_timer = { | |
91 | .init = isa_timer_init, | |
92 | .offset = isa_gettimeoffset, | |
93 | }; |