~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to arch/arm/plat-spear/time.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * arch/arm/plat-spear/time.c
 
3
 *
 
4
 * Copyright (C) 2009 ST Microelectronics
 
5
 * Shiraz Hashim<shiraz.hashim@st.com>
 
6
 *
 
7
 * This file is licensed under the terms of the GNU General Public
 
8
 * License version 2. This program is licensed "as is" without any
 
9
 * warranty of any kind, whether express or implied.
 
10
 */
 
11
 
 
12
#include <linux/clk.h>
 
13
#include <linux/clockchips.h>
 
14
#include <linux/clocksource.h>
 
15
#include <linux/err.h>
 
16
#include <linux/init.h>
 
17
#include <linux/interrupt.h>
 
18
#include <linux/io.h>
 
19
#include <linux/kernel.h>
 
20
#include <linux/time.h>
 
21
#include <linux/irq.h>
 
22
#include <asm/mach/time.h>
 
23
#include <mach/irqs.h>
 
24
#include <mach/hardware.h>
 
25
#include <mach/spear.h>
 
26
#include <mach/generic.h>
 
27
 
 
28
/*
 
29
 * We would use TIMER0 and TIMER1 as clockevent and clocksource.
 
30
 * Timer0 and Timer1 both belong to same gpt block in cpu subbsystem. Further
 
31
 * they share same functional clock. Any change in one's functional clock will
 
32
 * also affect other timer.
 
33
 */
 
34
 
 
35
#define CLKEVT  0       /* gpt0, channel0 as clockevent */
 
36
#define CLKSRC  1       /* gpt0, channel1 as clocksource */
 
37
 
 
38
/* Register offsets, x is channel number */
 
39
#define CR(x)           ((x) * 0x80 + 0x80)
 
40
#define IR(x)           ((x) * 0x80 + 0x84)
 
41
#define LOAD(x)         ((x) * 0x80 + 0x88)
 
42
#define COUNT(x)        ((x) * 0x80 + 0x8C)
 
43
 
 
44
/* Reg bit definitions */
 
45
#define CTRL_INT_ENABLE         0x0100
 
46
#define CTRL_ENABLE             0x0020
 
47
#define CTRL_ONE_SHOT           0x0010
 
48
 
 
49
#define CTRL_PRESCALER1         0x0
 
50
#define CTRL_PRESCALER2         0x1
 
51
#define CTRL_PRESCALER4         0x2
 
52
#define CTRL_PRESCALER8         0x3
 
53
#define CTRL_PRESCALER16        0x4
 
54
#define CTRL_PRESCALER32        0x5
 
55
#define CTRL_PRESCALER64        0x6
 
56
#define CTRL_PRESCALER128       0x7
 
57
#define CTRL_PRESCALER256       0x8
 
58
 
 
59
#define INT_STATUS              0x1
 
60
 
 
61
/*
 
62
 * Minimum clocksource/clockevent timer range in seconds
 
63
 */
 
64
#define SPEAR_MIN_RANGE 4
 
65
 
 
66
static __iomem void *gpt_base;
 
67
static struct clk *gpt_clk;
 
68
 
 
69
static void clockevent_set_mode(enum clock_event_mode mode,
 
70
                                struct clock_event_device *clk_event_dev);
 
71
static int clockevent_next_event(unsigned long evt,
 
72
                                 struct clock_event_device *clk_event_dev);
 
73
 
 
74
static cycle_t clocksource_read_cycles(struct clocksource *cs)
 
75
{
 
76
        return (cycle_t) readw(gpt_base + COUNT(CLKSRC));
 
77
}
 
78
 
 
79
static struct clocksource clksrc = {
 
80
        .name = "tmr1",
 
81
        .rating = 200,          /* its a pretty decent clock */
 
82
        .read = clocksource_read_cycles,
 
83
        .mask = 0xFFFF,         /* 16 bits */
 
84
        .flags = CLOCK_SOURCE_IS_CONTINUOUS,
 
85
};
 
86
 
 
87
static void spear_clocksource_init(void)
 
88
{
 
89
        u32 tick_rate;
 
90
        u16 val;
 
91
 
 
92
        /* program the prescaler (/256)*/
 
93
        writew(CTRL_PRESCALER256, gpt_base + CR(CLKSRC));
 
94
 
 
95
        /* find out actual clock driving Timer */
 
96
        tick_rate = clk_get_rate(gpt_clk);
 
97
        tick_rate >>= CTRL_PRESCALER256;
 
98
 
 
99
        writew(0xFFFF, gpt_base + LOAD(CLKSRC));
 
100
 
 
101
        val = readw(gpt_base + CR(CLKSRC));
 
102
        val &= ~CTRL_ONE_SHOT;  /* autoreload mode */
 
103
        val |= CTRL_ENABLE ;
 
104
        writew(val, gpt_base + CR(CLKSRC));
 
105
 
 
106
        /* register the clocksource */
 
107
        clocksource_register_hz(&clksrc, tick_rate);
 
108
}
 
109
 
 
110
static struct clock_event_device clkevt = {
 
111
        .name = "tmr0",
 
112
        .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
 
113
        .set_mode = clockevent_set_mode,
 
114
        .set_next_event = clockevent_next_event,
 
115
        .shift = 0,     /* to be computed */
 
116
};
 
117
 
 
118
static void clockevent_set_mode(enum clock_event_mode mode,
 
119
                                struct clock_event_device *clk_event_dev)
 
120
{
 
121
        u32 period;
 
122
        u16 val;
 
123
 
 
124
        /* stop the timer */
 
125
        val = readw(gpt_base + CR(CLKEVT));
 
126
        val &= ~CTRL_ENABLE;
 
127
        writew(val, gpt_base + CR(CLKEVT));
 
128
 
 
129
        switch (mode) {
 
130
        case CLOCK_EVT_MODE_PERIODIC:
 
131
                period = clk_get_rate(gpt_clk) / HZ;
 
132
                period >>= CTRL_PRESCALER16;
 
133
                writew(period, gpt_base + LOAD(CLKEVT));
 
134
 
 
135
                val = readw(gpt_base + CR(CLKEVT));
 
136
                val &= ~CTRL_ONE_SHOT;
 
137
                val |= CTRL_ENABLE | CTRL_INT_ENABLE;
 
138
                writew(val, gpt_base + CR(CLKEVT));
 
139
 
 
140
                break;
 
141
        case CLOCK_EVT_MODE_ONESHOT:
 
142
                val = readw(gpt_base + CR(CLKEVT));
 
143
                val |= CTRL_ONE_SHOT;
 
144
                writew(val, gpt_base + CR(CLKEVT));
 
145
 
 
146
                break;
 
147
        case CLOCK_EVT_MODE_UNUSED:
 
148
        case CLOCK_EVT_MODE_SHUTDOWN:
 
149
        case CLOCK_EVT_MODE_RESUME:
 
150
 
 
151
                break;
 
152
        default:
 
153
                pr_err("Invalid mode requested\n");
 
154
                break;
 
155
        }
 
156
}
 
157
 
 
158
static int clockevent_next_event(unsigned long cycles,
 
159
                                 struct clock_event_device *clk_event_dev)
 
160
{
 
161
        u16 val;
 
162
 
 
163
        writew(cycles, gpt_base + LOAD(CLKEVT));
 
164
 
 
165
        val = readw(gpt_base + CR(CLKEVT));
 
166
        val |= CTRL_ENABLE | CTRL_INT_ENABLE;
 
167
        writew(val, gpt_base + CR(CLKEVT));
 
168
 
 
169
        return 0;
 
170
}
 
171
 
 
172
static irqreturn_t spear_timer_interrupt(int irq, void *dev_id)
 
173
{
 
174
        struct clock_event_device *evt = &clkevt;
 
175
 
 
176
        writew(INT_STATUS, gpt_base + IR(CLKEVT));
 
177
 
 
178
        evt->event_handler(evt);
 
179
 
 
180
        return IRQ_HANDLED;
 
181
}
 
182
 
 
183
static struct irqaction spear_timer_irq = {
 
184
        .name = "timer",
 
185
        .flags = IRQF_DISABLED | IRQF_TIMER,
 
186
        .handler = spear_timer_interrupt
 
187
};
 
188
 
 
189
static void __init spear_clockevent_init(void)
 
190
{
 
191
        u32 tick_rate;
 
192
 
 
193
        /* program the prescaler */
 
194
        writew(CTRL_PRESCALER16, gpt_base + CR(CLKEVT));
 
195
 
 
196
        tick_rate = clk_get_rate(gpt_clk);
 
197
        tick_rate >>= CTRL_PRESCALER16;
 
198
 
 
199
        clockevents_calc_mult_shift(&clkevt, tick_rate, SPEAR_MIN_RANGE);
 
200
 
 
201
        clkevt.max_delta_ns = clockevent_delta2ns(0xfff0,
 
202
                        &clkevt);
 
203
        clkevt.min_delta_ns = clockevent_delta2ns(3, &clkevt);
 
204
 
 
205
        clkevt.cpumask = cpumask_of(0);
 
206
 
 
207
        clockevents_register_device(&clkevt);
 
208
 
 
209
        setup_irq(SPEAR_GPT0_CHAN0_IRQ, &spear_timer_irq);
 
210
}
 
211
 
 
212
void __init spear_setup_timer(void)
 
213
{
 
214
        struct clk *pll3_clk;
 
215
 
 
216
        if (!request_mem_region(SPEAR_GPT0_BASE, SZ_1K, "gpt0")) {
 
217
                pr_err("%s:cannot get IO addr\n", __func__);
 
218
                return;
 
219
        }
 
220
 
 
221
        gpt_base = (void __iomem *)ioremap(SPEAR_GPT0_BASE, SZ_1K);
 
222
        if (!gpt_base) {
 
223
                pr_err("%s:ioremap failed for gpt\n", __func__);
 
224
                goto err_mem;
 
225
        }
 
226
 
 
227
        gpt_clk = clk_get_sys("gpt0", NULL);
 
228
        if (!gpt_clk) {
 
229
                pr_err("%s:couldn't get clk for gpt\n", __func__);
 
230
                goto err_iomap;
 
231
        }
 
232
 
 
233
        pll3_clk = clk_get(NULL, "pll3_48m_clk");
 
234
        if (!pll3_clk) {
 
235
                pr_err("%s:couldn't get PLL3 as parent for gpt\n", __func__);
 
236
                goto err_iomap;
 
237
        }
 
238
 
 
239
        clk_set_parent(gpt_clk, pll3_clk);
 
240
 
 
241
        spear_clockevent_init();
 
242
        spear_clocksource_init();
 
243
 
 
244
        return;
 
245
 
 
246
err_iomap:
 
247
        iounmap(gpt_base);
 
248
 
 
249
err_mem:
 
250
        release_mem_region(SPEAR_GPT0_BASE, SZ_1K);
 
251
}
 
252
 
 
253
struct sys_timer spear_sys_timer = {
 
254
        .init = spear_setup_timer,
 
255
};