Pull trivial1 into release branch
[linux-2.6] / arch / arm / plat-omap / dmtimer.c
1 /*
2  * linux/arch/arm/plat-omap/dmtimer.c
3  *
4  * OMAP Dual-Mode Timers
5  *
6  * Copyright (C) 2005 Nokia Corporation
7  * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the
11  * Free Software Foundation; either version 2 of the License, or (at your
12  * option) any later version.
13  *
14  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
17  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
21  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22  *
23  * You should have received a copy of the  GNU General Public License along
24  * with this program; if not, write  to the Free Software Foundation, Inc.,
25  * 675 Mass Ave, Cambridge, MA 02139, USA.
26  */
27
28 #include <linux/init.h>
29 #include <asm/hardware.h>
30 #include <asm/arch/dmtimer.h>
31 #include <asm/io.h>
32 #include <asm/arch/irqs.h>
33 #include <linux/spinlock.h>
34 #include <linux/list.h>
35
36 #define OMAP_TIMER_COUNT                8
37
38 #define OMAP_TIMER_ID_REG               0x00
39 #define OMAP_TIMER_OCP_CFG_REG          0x10
40 #define OMAP_TIMER_SYS_STAT_REG         0x14
41 #define OMAP_TIMER_STAT_REG             0x18
42 #define OMAP_TIMER_INT_EN_REG           0x1c
43 #define OMAP_TIMER_WAKEUP_EN_REG        0x20
44 #define OMAP_TIMER_CTRL_REG             0x24
45 #define OMAP_TIMER_COUNTER_REG          0x28
46 #define OMAP_TIMER_LOAD_REG             0x2c
47 #define OMAP_TIMER_TRIGGER_REG          0x30
48 #define OMAP_TIMER_WRITE_PEND_REG       0x34
49 #define OMAP_TIMER_MATCH_REG            0x38
50 #define OMAP_TIMER_CAPTURE_REG          0x3c
51 #define OMAP_TIMER_IF_CTRL_REG          0x40
52
53
54 static struct dmtimer_info_struct {
55         struct list_head        unused_timers;
56         struct list_head        reserved_timers;
57 } dm_timer_info;
58
59 static struct omap_dm_timer dm_timers[] = {
60         { .base=0xfffb1400, .irq=INT_1610_GPTIMER1 },
61         { .base=0xfffb1c00, .irq=INT_1610_GPTIMER2 },
62         { .base=0xfffb2400, .irq=INT_1610_GPTIMER3 },
63         { .base=0xfffb2c00, .irq=INT_1610_GPTIMER4 },
64         { .base=0xfffb3400, .irq=INT_1610_GPTIMER5 },
65         { .base=0xfffb3c00, .irq=INT_1610_GPTIMER6 },
66         { .base=0xfffb4400, .irq=INT_1610_GPTIMER7 },
67         { .base=0xfffb4c00, .irq=INT_1610_GPTIMER8 },
68         { .base=0x0 },
69 };
70
71
72 static spinlock_t dm_timer_lock;
73
74
75 inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
76 {
77         omap_writel(value, timer->base + reg);
78         while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
79                 ;
80 }
81
82 u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
83 {
84         return omap_readl(timer->base + reg);
85 }
86
87 int omap_dm_timers_active(void)
88 {
89         struct omap_dm_timer *timer;
90
91         for (timer = &dm_timers[0]; timer->base; ++timer)
92                 if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
93                     OMAP_TIMER_CTRL_ST)
94                         return 1;
95
96         return 0;
97 }
98
99
100 /**
101  * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
102  * @inputmask: current value of idlect mask
103  */
104 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
105 {
106         int n;
107
108         /* If ARMXOR cannot be idled this function call is unnecessary */
109         if (!(inputmask & (1 << 1)))
110                 return inputmask;
111
112         /* If any active timer is using ARMXOR return modified mask */
113         for (n = 0; dm_timers[n].base; ++n)
114                 if (omap_dm_timer_read_reg(&dm_timers[n], OMAP_TIMER_CTRL_REG)&
115                     OMAP_TIMER_CTRL_ST) {
116                         if (((omap_readl(MOD_CONF_CTRL_1)>>(n*2)) & 0x03) == 0)
117                                 inputmask &= ~(1 << 1);
118                         else
119                                 inputmask &= ~(1 << 2);
120                 }
121
122         return inputmask;
123 }
124
125
126 void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
127 {
128         int n = (timer - dm_timers) << 1;
129         u32 l;
130
131         l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
132         l |= source << n;
133         omap_writel(l, MOD_CONF_CTRL_1);
134 }
135
136
137 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
138 {
139         /* Reset and set posted mode */
140         omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
141         omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, 0x02);
142
143         omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
144 }
145
146
147
148 struct omap_dm_timer * omap_dm_timer_request(void)
149 {
150         struct omap_dm_timer *timer = NULL;
151         unsigned long flags;
152
153         spin_lock_irqsave(&dm_timer_lock, flags);
154         if (!list_empty(&dm_timer_info.unused_timers)) {
155                 timer = (struct omap_dm_timer *)
156                                 dm_timer_info.unused_timers.next;
157                 list_move_tail((struct list_head *)timer,
158                                 &dm_timer_info.reserved_timers);
159         }
160         spin_unlock_irqrestore(&dm_timer_lock, flags);
161
162         return timer;
163 }
164
165
166 void omap_dm_timer_free(struct omap_dm_timer *timer)
167 {
168         unsigned long flags;
169
170         omap_dm_timer_reset(timer);
171
172         spin_lock_irqsave(&dm_timer_lock, flags);
173         list_move_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
174         spin_unlock_irqrestore(&dm_timer_lock, flags);
175 }
176
177 void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
178                                 unsigned int value)
179 {
180         omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
181 }
182
183 unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
184 {
185         return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
186 }
187
188 void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
189 {
190         omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
191 }
192
193 void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer)
194 {
195         u32 l;
196         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
197         l |= OMAP_TIMER_CTRL_AR;
198         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
199 }
200
201 void omap_dm_timer_trigger(struct omap_dm_timer *timer)
202 {
203         omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1);
204 }
205
206 void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value)
207 {
208         u32 l;
209
210         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
211         l |= value & 0x3;
212         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
213 }
214
215 void omap_dm_timer_start(struct omap_dm_timer *timer)
216 {
217         u32 l;
218
219         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
220         l |= OMAP_TIMER_CTRL_ST;
221         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
222 }
223
224 void omap_dm_timer_stop(struct omap_dm_timer *timer)
225 {
226         u32 l;
227
228         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
229         l &= ~0x1;
230         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
231 }
232
233 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
234 {
235         return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
236 }
237
238 void omap_dm_timer_reset_counter(struct omap_dm_timer *timer)
239 {
240         omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0);
241 }
242
243 void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load)
244 {
245         omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
246 }
247
248 void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match)
249 {
250         omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
251 }
252
253 void omap_dm_timer_enable_compare(struct omap_dm_timer *timer)
254 {
255         u32 l;
256
257         l = omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
258         l |= OMAP_TIMER_CTRL_CE;
259         omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
260 }
261
262
263 static inline void __dm_timer_init(void)
264 {
265         struct omap_dm_timer *timer;
266
267         spin_lock_init(&dm_timer_lock);
268         INIT_LIST_HEAD(&dm_timer_info.unused_timers);
269         INIT_LIST_HEAD(&dm_timer_info.reserved_timers);
270
271         timer = &dm_timers[0];
272         while (timer->base) {
273                 list_add_tail((struct list_head *)timer, &dm_timer_info.unused_timers);
274                 omap_dm_timer_reset(timer);
275                 timer++;
276         }
277 }
278
279 static int __init omap_dm_timer_init(void)
280 {
281         if (cpu_is_omap16xx())
282                 __dm_timer_init();
283         return 0;
284 }
285
286 arch_initcall(omap_dm_timer_init);