diff options
Diffstat (limited to 'arch/arm/mach-at91/at91sam926x_time.c')
-rw-r--r-- | arch/arm/mach-at91/at91sam926x_time.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/arch/arm/mach-at91/at91sam926x_time.c new file mode 100644 index 000000000000..a4dded27fa16 --- /dev/null +++ b/arch/arm/mach-at91/at91sam926x_time.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * linux/arch/arm/mach-at91/at91sam926x_time.c | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 M. Amine SAYA, ATMEL Rousset, France | ||
5 | * Revision 2005 M. Nicolas Diremdjian, ATMEL Rousset, France | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/interrupt.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/time.h> | ||
18 | |||
19 | #include <asm/hardware.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <asm/mach/time.h> | ||
22 | |||
23 | #include <asm/arch/at91_pit.h> | ||
24 | |||
25 | |||
26 | #define PIT_CPIV(x) ((x) & AT91_PIT_CPIV) | ||
27 | #define PIT_PICNT(x) (((x) & AT91_PIT_PICNT) >> 20) | ||
28 | |||
29 | /* | ||
30 | * Returns number of microseconds since last timer interrupt. Note that interrupts | ||
31 | * will have been disabled by do_gettimeofday() | ||
32 | * 'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy. | ||
33 | */ | ||
34 | static unsigned long at91sam926x_gettimeoffset(void) | ||
35 | { | ||
36 | unsigned long elapsed; | ||
37 | unsigned long t = at91_sys_read(AT91_PIT_PIIR); | ||
38 | |||
39 | elapsed = (PIT_PICNT(t) * LATCH) + PIT_CPIV(t); /* hardware clock cycles */ | ||
40 | |||
41 | return (unsigned long)(elapsed * jiffies_to_usecs(1)) / LATCH; | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * IRQ handler for the timer. | ||
46 | */ | ||
47 | static irqreturn_t at91sam926x_timer_interrupt(int irq, void *dev_id) | ||
48 | { | ||
49 | volatile long nr_ticks; | ||
50 | |||
51 | if (at91_sys_read(AT91_PIT_SR) & AT91_PIT_PITS) { /* This is a shared interrupt */ | ||
52 | write_seqlock(&xtime_lock); | ||
53 | |||
54 | /* Get number to ticks performed before interrupt and clear PIT interrupt */ | ||
55 | nr_ticks = PIT_PICNT(at91_sys_read(AT91_PIT_PIVR)); | ||
56 | do { | ||
57 | timer_tick(); | ||
58 | nr_ticks--; | ||
59 | } while (nr_ticks); | ||
60 | |||
61 | write_sequnlock(&xtime_lock); | ||
62 | return IRQ_HANDLED; | ||
63 | } else | ||
64 | return IRQ_NONE; /* not handled */ | ||
65 | } | ||
66 | |||
67 | static struct irqaction at91sam926x_timer_irq = { | ||
68 | .name = "at91_tick", | ||
69 | .flags = IRQF_SHARED | IRQF_DISABLED | IRQF_TIMER, | ||
70 | .handler = at91sam926x_timer_interrupt | ||
71 | }; | ||
72 | |||
73 | void at91sam926x_timer_reset(void) | ||
74 | { | ||
75 | /* Disable timer */ | ||
76 | at91_sys_write(AT91_PIT_MR, 0); | ||
77 | |||
78 | /* Clear any pending interrupts */ | ||
79 | (void) at91_sys_read(AT91_PIT_PIVR); | ||
80 | |||
81 | /* Set Period Interval timer and enable its interrupt */ | ||
82 | at91_sys_write(AT91_PIT_MR, (LATCH & AT91_PIT_PIV) | AT91_PIT_PITIEN | AT91_PIT_PITEN); | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * Set up timer interrupt. | ||
87 | */ | ||
88 | void __init at91sam926x_timer_init(void) | ||
89 | { | ||
90 | /* Initialize and enable the timer */ | ||
91 | at91sam926x_timer_reset(); | ||
92 | |||
93 | /* Make IRQs happen for the system timer. */ | ||
94 | setup_irq(AT91_ID_SYS, &at91sam926x_timer_irq); | ||
95 | } | ||
96 | |||
97 | #ifdef CONFIG_PM | ||
98 | static void at91sam926x_timer_suspend(void) | ||
99 | { | ||
100 | /* Disable timer */ | ||
101 | at91_sys_write(AT91_PIT_MR, 0); | ||
102 | } | ||
103 | #else | ||
104 | #define at91sam926x_timer_suspend NULL | ||
105 | #endif | ||
106 | |||
107 | struct sys_timer at91sam926x_timer = { | ||
108 | .init = at91sam926x_timer_init, | ||
109 | .offset = at91sam926x_gettimeoffset, | ||
110 | .suspend = at91sam926x_timer_suspend, | ||
111 | .resume = at91sam926x_timer_reset, | ||
112 | }; | ||
113 | |||