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
);