[ARM] remove memzero()
[deliverable/linux.git] / arch / arm / plat-mxc / time.c
1 /*
2 * linux/arch/arm/plat-mxc/time.c
3 *
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)
8 *
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.
17 *
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,
21 * MA 02110-1301, USA.
22 */
23
24 #include <linux/interrupt.h>
25 #include <linux/irq.h>
26 #include <linux/clockchips.h>
27 #include <linux/clk.h>
28
29 #include <mach/hardware.h>
30 #include <asm/mach/time.h>
31 #include <mach/common.h>
32 #include <mach/mxc_timer.h>
33
34 static struct clock_event_device clockevent_mxc;
35 static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
36
37 /* clock source for the timer */
38 static struct clk *timer_clk;
39
40 /* clock source */
41
42 static cycle_t mxc_get_cycles(void)
43 {
44 return __raw_readl(TIMER_BASE + MXC_TCN);
45 }
46
47 static struct clocksource clocksource_mxc = {
48 .name = "mxc_timer1",
49 .rating = 200,
50 .read = mxc_get_cycles,
51 .mask = CLOCKSOURCE_MASK(32),
52 .shift = 20,
53 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
54 };
55
56 static int __init mxc_clocksource_init(void)
57 {
58 unsigned int clock;
59
60 clock = clk_get_rate(timer_clk);
61
62 clocksource_mxc.mult = clocksource_hz2mult(clock,
63 clocksource_mxc.shift);
64 clocksource_register(&clocksource_mxc);
65
66 return 0;
67 }
68
69 /* clock event */
70
71 static int mxc_set_next_event(unsigned long evt,
72 struct clock_event_device *unused)
73 {
74 unsigned long tcmp;
75
76 tcmp = __raw_readl(TIMER_BASE + MXC_TCN) + evt;
77 __raw_writel(tcmp, TIMER_BASE + MXC_TCMP);
78
79 return (int)(tcmp - __raw_readl(TIMER_BASE + MXC_TCN)) < 0 ?
80 -ETIME : 0;
81 }
82
83 #ifdef DEBUG
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"
89 };
90 #endif /* DEBUG */
91
92 static void mxc_set_mode(enum clock_event_mode mode,
93 struct clock_event_device *evt)
94 {
95 unsigned long flags;
96
97 /*
98 * The timer interrupt generation is disabled at least
99 * for enough time to call mxc_set_next_event()
100 */
101 local_irq_save(flags);
102
103 /* Disable interrupt in GPT module */
104 gpt_irq_disable();
105
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();
112 }
113
114 #ifdef DEBUG
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]);
118 #endif /* DEBUG */
119
120 /* Remember timer mode */
121 clockevent_mode = mode;
122 local_irq_restore(flags);
123
124 switch (mode) {
125 case CLOCK_EVT_MODE_PERIODIC:
126 printk(KERN_ERR"mxc_set_mode: Periodic mode is not "
127 "supported for i.MX\n");
128 break;
129 case CLOCK_EVT_MODE_ONESHOT:
130 /*
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
134 * mode switching
135 */
136 local_irq_save(flags);
137 gpt_irq_enable();
138 local_irq_restore(flags);
139 break;
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 */
144 break;
145 }
146 }
147
148 /*
149 * IRQ handler for the timer
150 */
151 static irqreturn_t mxc_timer_interrupt(int irq, void *dev_id)
152 {
153 struct clock_event_device *evt = &clockevent_mxc;
154 uint32_t tstat;
155
156 tstat = __raw_readl(TIMER_BASE + MXC_TSTAT);
157
158 gpt_irq_acknowledge();
159
160 evt->event_handler(evt);
161
162 return IRQ_HANDLED;
163 }
164
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,
169 };
170
171 static struct clock_event_device clockevent_mxc = {
172 .name = "mxc_timer1",
173 .features = CLOCK_EVT_FEAT_ONESHOT,
174 .shift = 32,
175 .set_mode = mxc_set_mode,
176 .set_next_event = mxc_set_next_event,
177 .rating = 200,
178 };
179
180 static int __init mxc_clockevent_init(void)
181 {
182 unsigned int clock;
183
184 clock = clk_get_rate(timer_clk);
185
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);
192
193 clockevent_mxc.cpumask = cpumask_of_cpu(0);
194
195 clockevents_register_device(&clockevent_mxc);
196
197 return 0;
198 }
199
200 void __init mxc_timer_init(const char *clk_timer)
201 {
202 timer_clk = clk_get(NULL, clk_timer);
203 if (!timer_clk) {
204 printk(KERN_ERR"Cannot determine timer clock. Giving up.\n");
205 return;
206 }
207
208 clk_enable(timer_clk);
209
210 /*
211 * Initialise to a known state (all timers off, and timing reset)
212 */
213 __raw_writel(0, TIMER_BASE + MXC_TCTL);
214 __raw_writel(0, TIMER_BASE + MXC_TPRER); /* see datasheet note */
215
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);
220
221 /* init and register the timer to the framework */
222 mxc_clocksource_init();
223 mxc_clockevent_init();
224
225 /* Make irqs happen */
226 setup_irq(TIMER_INTERRUPT, &mxc_timer_irq);
227 }
228
This page took 0.039952 seconds and 5 git commands to generate.