OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [arm/] [mach-imx/] [time.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 *  linux/arch/arm/mach-imx/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
 *
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.
11
 */
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>
20
 
21
#include <asm/hardware.h>
22
#include <asm/io.h>
23
#include <asm/leds.h>
24
#include <asm/irq.h>
25
#include <asm/mach/time.h>
26
 
27
/* Use timer 1 as system timer */
28
#define TIMER_BASE IMX_TIM1_BASE
29
 
30
static struct clock_event_device clockevent_imx;
31
static enum clock_event_mode clockevent_mode = CLOCK_EVT_MODE_UNUSED;
32
 
33
/*
34
 * IRQ handler for the timer
35
 */
36
static irqreturn_t
37
imx_timer_interrupt(int irq, void *dev_id)
38
{
39
        struct clock_event_device *evt = &clockevent_imx;
40
        uint32_t tstat;
41
        irqreturn_t ret = IRQ_NONE;
42
 
43
        /* clear the interrupt */
44
        tstat = IMX_TSTAT(TIMER_BASE);
45
        IMX_TSTAT(TIMER_BASE) = 0;
46
 
47
        if (tstat & TSTAT_COMP) {
48
                evt->event_handler(evt);
49
                ret = IRQ_HANDLED;
50
        }
51
 
52
        return ret;
53
}
54
 
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,
59
};
60
 
61
/*
62
 * Set up timer hardware into expected mode and state.
63
 */
64
static void __init imx_timer_hardware_init(void)
65
{
66
        /*
67
         * Initialise to a known state (all timers off, and timing reset)
68
         */
69
        IMX_TCTL(TIMER_BASE) = 0;
70
        IMX_TPRER(TIMER_BASE) = 0;
71
 
72
        IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_TEN;
73
}
74
 
75
cycle_t imx_get_cycles(void)
76
{
77
        return IMX_TCN(TIMER_BASE);
78
}
79
 
80
static struct clocksource clocksource_imx = {
81
        .name           = "imx_timer1",
82
        .rating         = 200,
83
        .read           = imx_get_cycles,
84
        .mask           = 0xFFFFFFFF,
85
        .shift          = 20,
86
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
87
};
88
 
89
static int __init imx_clocksource_init(void)
90
{
91
        clocksource_imx.mult =
92
                clocksource_hz2mult(imx_get_perclk1(), clocksource_imx.shift);
93
        clocksource_register(&clocksource_imx);
94
 
95
        return 0;
96
}
97
 
98
static int imx_set_next_event(unsigned long evt,
99
                                  struct clock_event_device *unused)
100
{
101
        unsigned long tcmp;
102
 
103
        tcmp = IMX_TCN(TIMER_BASE) + evt;
104
        IMX_TCMP(TIMER_BASE) = tcmp;
105
 
106
        return (int32_t)(tcmp - IMX_TCN(TIMER_BASE)) < 0 ? -ETIME : 0;
107
}
108
 
109
#ifdef DEBUG
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"
115
};
116
#endif /*DEBUG*/
117
 
118
static void imx_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
119
{
120
        unsigned long flags;
121
 
122
        /*
123
         * The timer interrupt generation is disabled at least
124
         * for enough time to call imx_set_next_event()
125
         */
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;
134
        }
135
 
136
#ifdef DEBUG
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]);
139
#endif /*DEBUG*/
140
 
141
        /* Remember timer mode */
142
        clockevent_mode = mode;
143
        local_irq_restore(flags);
144
 
145
        switch (mode) {
146
        case CLOCK_EVT_MODE_PERIODIC:
147
                printk(KERN_ERR "imx_set_mode: Periodic mode is not supported for i.MX\n");
148
                break;
149
        case CLOCK_EVT_MODE_ONESHOT:
150
                /*
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
154
                 * mode switching
155
                 */
156
                local_irq_save(flags);
157
                IMX_TCTL(TIMER_BASE) |= TCTL_IRQEN;
158
                local_irq_restore(flags);
159
                break;
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 */
164
                break;
165
        }
166
}
167
 
168
static struct clock_event_device clockevent_imx = {
169
        .name           = "imx_timer1",
170
        .features       = CLOCK_EVT_FEAT_ONESHOT,
171
        .shift          = 32,
172
        .set_mode       = imx_set_mode,
173
        .set_next_event = imx_set_next_event,
174
        .rating         = 200,
175
};
176
 
177
static int __init imx_clockevent_init(void)
178
{
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);
185
 
186
        clockevent_imx.cpumask = cpumask_of_cpu(0);
187
 
188
        clockevents_register_device(&clockevent_imx);
189
 
190
        return 0;
191
}
192
 
193
 
194
static void __init imx_timer_init(void)
195
{
196
        imx_timer_hardware_init();
197
        imx_clocksource_init();
198
 
199
        imx_clockevent_init();
200
 
201
        /*
202
         * Make irqs happen for the system timer
203
         */
204
        setup_irq(TIM1_INT, &imx_timer_irq);
205
}
206
 
207
struct sys_timer imx_timer = {
208
        .init           = imx_timer_init,
209
};

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.