[ARM] 3427/1: ARM: OMAP: 2/8 Update timers
[linux-2.6/openmoko-kernel.git] / arch / arm / plat-omap / dmtimer.c
blobeba3cb52ad878567b39c0d87750e84d2a5e44180
1 /*
2 * linux/arch/arm/plat-omap/dmtimer.c
4 * OMAP Dual-Mode Timers
6 * Copyright (C) 2005 Nokia Corporation
7 * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
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.
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.
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.
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>
36 #define OMAP_TIMER_COUNT 8
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
54 static struct dmtimer_info_struct {
55 struct list_head unused_timers;
56 struct list_head reserved_timers;
57 } dm_timer_info;
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 },
72 static spinlock_t dm_timer_lock;
75 inline void omap_dm_timer_write_reg(struct omap_dm_timer *timer, int reg, u32 value)
77 omap_writel(value, timer->base + reg);
78 while (omap_dm_timer_read_reg(timer, OMAP_TIMER_WRITE_PEND_REG))
82 u32 omap_dm_timer_read_reg(struct omap_dm_timer *timer, int reg)
84 return omap_readl(timer->base + reg);
87 int omap_dm_timers_active(void)
89 struct omap_dm_timer *timer;
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;
96 return 0;
101 * omap_dm_timer_modify_idlect_mask - Check if any running timers use ARMXOR
102 * @inputmask: current value of idlect mask
104 __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
106 int n;
108 /* If ARMXOR cannot be idled this function call is unnecessary */
109 if (!(inputmask & (1 << 1)))
110 return inputmask;
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);
122 return inputmask;
126 void omap_dm_timer_set_source(struct omap_dm_timer *timer, int source)
128 int n = (timer - dm_timers) << 1;
129 u32 l;
131 l = omap_readl(MOD_CONF_CTRL_1) & ~(0x03 << n);
132 l |= source << n;
133 omap_writel(l, MOD_CONF_CTRL_1);
137 static void omap_dm_timer_reset(struct omap_dm_timer *timer)
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);
143 omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_ARMXOR);
148 struct omap_dm_timer * omap_dm_timer_request(void)
150 struct omap_dm_timer *timer = NULL;
151 unsigned long flags;
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);
160 spin_unlock_irqrestore(&dm_timer_lock, flags);
162 return timer;
166 void omap_dm_timer_free(struct omap_dm_timer *timer)
168 unsigned long flags;
170 omap_dm_timer_reset(timer);
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);
177 void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
178 unsigned int value)
180 omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
183 unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
185 return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
188 void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
190 omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG, value);
193 void omap_dm_timer_enable_autoreload(struct omap_dm_timer *timer)
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);
201 void omap_dm_timer_trigger(struct omap_dm_timer *timer)
203 omap_dm_timer_write_reg(timer, OMAP_TIMER_TRIGGER_REG, 1);
206 void omap_dm_timer_set_trigger(struct omap_dm_timer *timer, unsigned int value)
208 u32 l;
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);
215 void omap_dm_timer_start(struct omap_dm_timer *timer)
217 u32 l;
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);
224 void omap_dm_timer_stop(struct omap_dm_timer *timer)
226 u32 l;
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);
233 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
235 return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
238 void omap_dm_timer_reset_counter(struct omap_dm_timer *timer)
240 omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, 0);
243 void omap_dm_timer_set_load(struct omap_dm_timer *timer, unsigned int load)
245 omap_dm_timer_write_reg(timer, OMAP_TIMER_LOAD_REG, load);
248 void omap_dm_timer_set_match(struct omap_dm_timer *timer, unsigned int match)
250 omap_dm_timer_write_reg(timer, OMAP_TIMER_MATCH_REG, match);
253 void omap_dm_timer_enable_compare(struct omap_dm_timer *timer)
255 u32 l;
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);
263 static inline void __dm_timer_init(void)
265 struct omap_dm_timer *timer;
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);
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++;
279 static int __init omap_dm_timer_init(void)
281 if (cpu_is_omap16xx())
282 __dm_timer_init();
283 return 0;
286 arch_initcall(omap_dm_timer_init);