2 * linux/arch/arm/plat-mxc/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)
7 * Copyright (C) 2008 Juergen Beisert (kernel@pengutronix.de)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
24 #include <linux/interrupt.h>
25 #include <linux/irq.h>
26 #include <linux/clockchips.h>
27 #include <linux/clk.h>
29 #include <asm/hardware.h>
30 #include <asm/mach/time.h>
31 #include <asm/arch/common.h>
32 #include <asm/arch/mxc_timer.h>
34 static struct clock_event_device clockevent_mxc
;
35 static enum clock_event_mode clockevent_mode
= CLOCK_EVT_MODE_UNUSED
;
37 /* clock source for the timer */
38 static struct clk
*timer_clk
;
42 static cycle_t
mxc_get_cycles(void)
44 return __raw_readl(TIMER_BASE
+ MXC_TCN
);
47 static struct clocksource clocksource_mxc
= {
50 .read
= mxc_get_cycles
,
51 .mask
= CLOCKSOURCE_MASK(32),
53 .flags
= CLOCK_SOURCE_IS_CONTINUOUS
,
56 static int __init
mxc_clocksource_init(void)
60 clock
= clk_get_rate(timer_clk
);
62 clocksource_mxc
.mult
= clocksource_hz2mult(clock
,
63 clocksource_mxc
.shift
);
64 clocksource_register(&clocksource_mxc
);
71 static int mxc_set_next_event(unsigned long evt
,
72 struct clock_event_device
*unused
)
76 tcmp
= __raw_readl(TIMER_BASE
+ MXC_TCN
) + evt
;
77 __raw_writel(tcmp
, TIMER_BASE
+ MXC_TCMP
);
79 return (int)(tcmp
- __raw_readl(TIMER_BASE
+ MXC_TCN
)) < 0 ?
84 static const char *clock_event_mode_label
[] = {
85 [CLOCK_EVT_MODE_PERIODIC
] = "CLOCK_EVT_MODE_PERIODIC",
86 [CLOCK_EVT_MODE_ONESHOT
] = "CLOCK_EVT_MODE_ONESHOT",
87 [CLOCK_EVT_MODE_SHUTDOWN
] = "CLOCK_EVT_MODE_SHUTDOWN",
88 [CLOCK_EVT_MODE_UNUSED
] = "CLOCK_EVT_MODE_UNUSED"
92 static void mxc_set_mode(enum clock_event_mode mode
,
93 struct clock_event_device
*evt
)
98 * The timer interrupt generation is disabled at least
99 * for enough time to call mxc_set_next_event()
101 local_irq_save(flags
);
103 /* Disable interrupt in GPT module */
106 if (mode
!= clockevent_mode
) {
107 /* Set event time into far-far future */
108 __raw_writel(__raw_readl(TIMER_BASE
+ MXC_TCN
) - 3,
109 TIMER_BASE
+ MXC_TCMP
);
110 /* Clear pending interrupt */
111 gpt_irq_acknowledge();
115 printk(KERN_INFO
"mxc_set_mode: changing mode from %s to %s\n",
116 clock_event_mode_label
[clockevent_mode
],
117 clock_event_mode_label
[mode
]);
120 /* Remember timer mode */
121 clockevent_mode
= mode
;
122 local_irq_restore(flags
);
125 case CLOCK_EVT_MODE_PERIODIC
:
126 printk(KERN_ERR
"mxc_set_mode: Periodic mode is not "
127 "supported for i.MX\n");
129 case CLOCK_EVT_MODE_ONESHOT
:
131 * Do not put overhead of interrupt enable/disable into
132 * mxc_set_next_event(), the core has about 4 minutes
133 * to call mxc_set_next_event() or shutdown clock after
136 local_irq_save(flags
);
138 local_irq_restore(flags
);
140 case CLOCK_EVT_MODE_SHUTDOWN
:
141 case CLOCK_EVT_MODE_UNUSED
:
142 case CLOCK_EVT_MODE_RESUME
:
143 /* Left event sources disabled, no more interrupts appear */
149 * IRQ handler for the timer
151 static irqreturn_t
mxc_timer_interrupt(int irq
, void *dev_id
)
153 struct clock_event_device
*evt
= &clockevent_mxc
;
156 tstat
= __raw_readl(TIMER_BASE
+ MXC_TSTAT
);
158 gpt_irq_acknowledge();
160 evt
->event_handler(evt
);
165 static struct irqaction mxc_timer_irq
= {
166 .name
= "i.MX Timer Tick",
167 .flags
= IRQF_DISABLED
| IRQF_TIMER
| IRQF_IRQPOLL
,
168 .handler
= mxc_timer_interrupt
,
171 static struct clock_event_device clockevent_mxc
= {
172 .name
= "mxc_timer1",
173 .features
= CLOCK_EVT_FEAT_ONESHOT
,
175 .set_mode
= mxc_set_mode
,
176 .set_next_event
= mxc_set_next_event
,
180 static int __init
mxc_clockevent_init(void)
184 clock
= clk_get_rate(timer_clk
);
186 clockevent_mxc
.mult
= div_sc(clock
, NSEC_PER_SEC
,
187 clockevent_mxc
.shift
);
188 clockevent_mxc
.max_delta_ns
=
189 clockevent_delta2ns(0xfffffffe, &clockevent_mxc
);
190 clockevent_mxc
.min_delta_ns
=
191 clockevent_delta2ns(0xff, &clockevent_mxc
);
193 clockevent_mxc
.cpumask
= cpumask_of_cpu(0);
195 clockevents_register_device(&clockevent_mxc
);
200 void __init
mxc_timer_init(const char *clk_timer
)
202 timer_clk
= clk_get(NULL
, clk_timer
);
204 printk(KERN_ERR
"Cannot determine timer clock. Giving up.\n");
208 clk_enable(timer_clk
);
211 * Initialise to a known state (all timers off, and timing reset)
213 __raw_writel(0, TIMER_BASE
+ MXC_TCTL
);
214 __raw_writel(0, TIMER_BASE
+ MXC_TPRER
); /* see datasheet note */
216 __raw_writel(TCTL_FRR
| /* free running */
217 TCTL_VAL
| /* set clocksource and arch specific bits */
218 TCTL_TEN
, /* start the timer */
219 TIMER_BASE
+ MXC_TCTL
);
221 /* init and register the timer to the framework */
222 mxc_clocksource_init();
223 mxc_clockevent_init();
225 /* Make irqs happen */
226 setup_irq(TIMER_INTERRUPT
, &mxc_timer_irq
);