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 <mach/hardware.h>
30 #include <asm/mach/time.h>
31 #include <mach/common.h>
32 #include <mach/mxc_timer.h>
34 static struct clock_event_device clockevent_mxc;
35 static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
39 static cycle_t mxc_get_cycles(void)
41 return __raw_readl(TIMER_BASE + MXC_TCN);
44 static struct clocksource clocksource_mxc = {
47 .read = mxc_get_cycles,
48 .mask = CLOCKSOURCE_MASK(32),
50 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
53 static int __init mxc_clocksource_init(struct clk *timer_clk)
55 unsigned int c = clk_get_rate(timer_clk);
57 clocksource_mxc.mult = clocksource_hz2mult(c,
58 clocksource_mxc.shift);
59 clocksource_register(&clocksource_mxc);
66 static int mxc_set_next_event(unsigned long evt,
67 struct clock_event_device *unused)
71 tcmp = __raw_readl(TIMER_BASE + MXC_TCN) + evt;
72 __raw_writel(tcmp, TIMER_BASE + MXC_TCMP);
74 return (int)(tcmp - __raw_readl(TIMER_BASE + MXC_TCN)) < 0 ?
79 static const char *clock_event_mode_label[] = {
80 [CLOCK_EVT_MODE_PERIODIC] = "CLOCK_EVT_MODE_PERIODIC",
81 [CLOCK_EVT_MODE_ONESHOT] = "CLOCK_EVT_MODE_ONESHOT",
82 [CLOCK_EVT_MODE_SHUTDOWN] = "CLOCK_EVT_MODE_SHUTDOWN",
83 [CLOCK_EVT_MODE_UNUSED] = "CLOCK_EVT_MODE_UNUSED"
87 static void mxc_set_mode(enum clock_event_mode mode,
88 struct clock_event_device *evt)
93 * The timer interrupt generation is disabled at least
94 * for enough time to call mxc_set_next_event()
96 local_irq_save(flags);
98 /* Disable interrupt in GPT module */
101 if (mode != clockevent_mode) {
102 /* Set event time into far-far future */
103 __raw_writel(__raw_readl(TIMER_BASE + MXC_TCN) - 3,
104 TIMER_BASE + MXC_TCMP);
105 /* Clear pending interrupt */
106 gpt_irq_acknowledge();
110 printk(KERN_INFO "mxc_set_mode: changing mode from %s to %s\n",
111 clock_event_mode_label[clockevent_mode],
112 clock_event_mode_label[mode]);
115 /* Remember timer mode */
116 clockevent_mode = mode;
117 local_irq_restore(flags);
120 case CLOCK_EVT_MODE_PERIODIC:
121 printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
122 "supported for i.MX\n");
124 case CLOCK_EVT_MODE_ONESHOT:
126 * Do not put overhead of interrupt enable/disable into
127 * mxc_set_next_event(), the core has about 4 minutes
128 * to call mxc_set_next_event() or shutdown clock after
131 local_irq_save(flags);
133 local_irq_restore(flags);
135 case CLOCK_EVT_MODE_SHUTDOWN:
136 case CLOCK_EVT_MODE_UNUSED:
137 case CLOCK_EVT_MODE_RESUME:
138 /* Left event sources disabled, no more interrupts appear */
144 * IRQ handler for the timer
146 static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
148 struct clock_event_device *evt = &clockevent_mxc;
151 tstat = __raw_readl(TIMER_BASE + MXC_TSTAT);
153 gpt_irq_acknowledge();
155 evt->event_handler(evt);
160 static struct irqaction mxc_timer_irq = {
161 .name = "i.MX Timer Tick",
162 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
163 .handler = mxc_timer_interrupt,
166 static struct clock_event_device clockevent_mxc = {
167 .name = "mxc_timer1",
168 .features = CLOCK_EVT_FEAT_ONESHOT,
170 .set_mode = mxc_set_mode,
171 .set_next_event = mxc_set_next_event,
175 static int __init mxc_clockevent_init(struct clk *timer_clk)
177 unsigned int c = clk_get_rate(timer_clk);
179 clockevent_mxc.mult = div_sc(c, NSEC_PER_SEC,
180 clockevent_mxc.shift);
181 clockevent_mxc.max_delta_ns =
182 clockevent_delta2ns(0xfffffffe, &clockevent_mxc);
183 clockevent_mxc.min_delta_ns =
184 clockevent_delta2ns(0xff, &clockevent_mxc);
186 clockevent_mxc.cpumask = cpumask_of(0);
188 clockevents_register_device(&clockevent_mxc);
193 void __init mxc_timer_init(struct clk *timer_clk)
195 clk_enable(timer_clk);
198 * Initialise to a known state (all timers off, and timing reset)
200 __raw_writel(0, TIMER_BASE + MXC_TCTL);
201 __raw_writel(0, TIMER_BASE + MXC_TPRER); /* see datasheet note */
203 __raw_writel(TCTL_FRR | /* free running */
204 TCTL_VAL | /* set clocksource and arch specific bits */
205 TCTL_TEN, /* start the timer */
206 TIMER_BASE + MXC_TCTL);
208 /* init and register the timer to the framework */
209 mxc_clocksource_init(timer_clk);
210 mxc_clockevent_init(timer_clk);
212 /* Make irqs happen */
213 setup_irq(TIMER_INTERRUPT, &mxc_timer_irq);