2 * linux/arch/arm/mach-imx/time.c
4 * Copyright (C) 2000-2001 Deep Blue Solutions
5 * Copyright (C) 2002 Shane Nay (shane@minirl.com)
6 * Copyright (C) 2006-2007 Pavel Pisa (ppisa@pikron.com)
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14 #include <linux/init.h>
15 #include <linux/interrupt.h>
16 #include <linux/irq.h>
17 #include <linux/time.h>
18 #include <linux/clocksource.h>
19 #include <linux/clockchips.h>
21 #include <asm/hardware.h>
25 #include <asm/mach/time.h>
27 /* Use timer 1 as system timer */
28 #define TIMER_BASE IMX_TIM1_BASE
30 static struct clock_event_device clockevent_imx
;
31 static enum clock_event_mode clockevent_mode
= CLOCK_EVT_MODE_UNUSED
;
34 * IRQ handler for the timer
37 imx_timer_interrupt(int irq
, void *dev_id
)
39 struct clock_event_device
*evt
= &clockevent_imx
;
41 irqreturn_t ret
= IRQ_NONE
;
43 /* clear the interrupt */
44 tstat
= IMX_TSTAT(TIMER_BASE
);
45 IMX_TSTAT(TIMER_BASE
) = 0;
47 if (tstat
& TSTAT_COMP
) {
48 evt
->event_handler(evt
);
55 static struct irqaction imx_timer_irq
= {
56 .name
= "i.MX Timer Tick",
57 .flags
= IRQF_DISABLED
| IRQF_TIMER
| IRQF_IRQPOLL
,
58 .handler
= imx_timer_interrupt
,
62 * Set up timer hardware into expected mode and state.
64 static void __init
imx_timer_hardware_init(void)
67 * Initialise to a known state (all timers off, and timing reset)
69 IMX_TCTL(TIMER_BASE
) = 0;
70 IMX_TPRER(TIMER_BASE
) = 0;
72 IMX_TCTL(TIMER_BASE
) = TCTL_FRR
| TCTL_CLK_PCLK1
| TCTL_TEN
;
75 cycle_t
imx_get_cycles(void)
77 return IMX_TCN(TIMER_BASE
);
80 static struct clocksource clocksource_imx
= {
83 .read
= imx_get_cycles
,
86 .flags
= CLOCK_SOURCE_IS_CONTINUOUS
,
89 static int __init
imx_clocksource_init(void)
91 clocksource_imx
.mult
=
92 clocksource_hz2mult(imx_get_perclk1(), clocksource_imx
.shift
);
93 clocksource_register(&clocksource_imx
);
98 static int imx_set_next_event(unsigned long evt
,
99 struct clock_event_device
*unused
)
103 tcmp
= IMX_TCN(TIMER_BASE
) + evt
;
104 IMX_TCMP(TIMER_BASE
) = tcmp
;
106 return (int32_t)(tcmp
- IMX_TCN(TIMER_BASE
)) < 0 ? -ETIME
: 0;
110 static const char *clock_event_mode_label
[]={
111 [CLOCK_EVT_MODE_PERIODIC
] = "CLOCK_EVT_MODE_PERIODIC",
112 [CLOCK_EVT_MODE_ONESHOT
] = "CLOCK_EVT_MODE_ONESHOT",
113 [CLOCK_EVT_MODE_SHUTDOWN
] = "CLOCK_EVT_MODE_SHUTDOWN",
114 [CLOCK_EVT_MODE_UNUSED
] = "CLOCK_EVT_MODE_UNUSED"
118 static void imx_set_mode(enum clock_event_mode mode
, struct clock_event_device
*evt
)
123 * The timer interrupt generation is disabled at least
124 * for enough time to call imx_set_next_event()
126 local_irq_save(flags
);
127 /* Disable interrupt in GPT module */
128 IMX_TCTL(TIMER_BASE
) &= ~TCTL_IRQEN
;
129 if (mode
!= clockevent_mode
) {
130 /* Set event time into far-far future */
131 IMX_TCMP(TIMER_BASE
) = IMX_TCN(TIMER_BASE
) - 3;
132 /* Clear pending interrupt */
133 IMX_TSTAT(TIMER_BASE
) &= ~TSTAT_COMP
;
137 printk(KERN_INFO
"imx_set_mode: changing mode from %s to %s\n",
138 clock_event_mode_label
[clockevent_mode
], clock_event_mode_label
[mode
]);
141 /* Remember timer mode */
142 clockevent_mode
= mode
;
143 local_irq_restore(flags
);
146 case CLOCK_EVT_MODE_PERIODIC
:
147 printk(KERN_ERR
"imx_set_mode: Periodic mode is not supported for i.MX\n");
149 case CLOCK_EVT_MODE_ONESHOT
:
151 * Do not put overhead of interrupt enable/disable into
152 * imx_set_next_event(), the core has about 4 minutes
153 * to call imx_set_next_event() or shutdown clock after
156 local_irq_save(flags
);
157 IMX_TCTL(TIMER_BASE
) |= TCTL_IRQEN
;
158 local_irq_restore(flags
);
160 case CLOCK_EVT_MODE_SHUTDOWN
:
161 case CLOCK_EVT_MODE_UNUSED
:
162 case CLOCK_EVT_MODE_RESUME
:
163 /* Left event sources disabled, no more interrupts appears */
168 static struct clock_event_device clockevent_imx
= {
169 .name
= "imx_timer1",
170 .features
= CLOCK_EVT_FEAT_ONESHOT
,
172 .set_mode
= imx_set_mode
,
173 .set_next_event
= imx_set_next_event
,
177 static int __init
imx_clockevent_init(void)
179 clockevent_imx
.mult
= div_sc(imx_get_perclk1(), NSEC_PER_SEC
,
180 clockevent_imx
.shift
);
181 clockevent_imx
.max_delta_ns
=
182 clockevent_delta2ns(0xfffffffe, &clockevent_imx
);
183 clockevent_imx
.min_delta_ns
=
184 clockevent_delta2ns(0xf, &clockevent_imx
);
186 clockevent_imx
.cpumask
= cpumask_of_cpu(0);
188 clockevents_register_device(&clockevent_imx
);
194 static void __init
imx_timer_init(void)
196 imx_timer_hardware_init();
197 imx_clocksource_init();
199 imx_clockevent_init();
202 * Make irqs happen for the system timer
204 setup_irq(TIM1_INT
, &imx_timer_irq
);
207 struct sys_timer imx_timer
= {
208 .init
= imx_timer_init
,