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>
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
;
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
},
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
) &
100 void omap_dm_timer_set_source(struct omap_dm_timer
*timer
, int source
)
102 int n
= (timer
- dm_timers
) << 1;
105 l
= omap_readl(MOD_CONF_CTRL_1
) & ~(0x03 << n
);
107 omap_writel(l
, MOD_CONF_CTRL_1
);
111 static void omap_dm_timer_reset(struct omap_dm_timer
*timer
)
113 /* Reset and set posted mode */
114 omap_dm_timer_write_reg(timer
, OMAP_TIMER_IF_CTRL_REG
, 0x06);
115 omap_dm_timer_write_reg(timer
, OMAP_TIMER_OCP_CFG_REG
, 0x02);
117 omap_dm_timer_set_source(timer
, OMAP_TIMER_SRC_ARMXOR
);
122 struct omap_dm_timer
* omap_dm_timer_request(void)
124 struct omap_dm_timer
*timer
= NULL
;
127 spin_lock_irqsave(&dm_timer_lock
, flags
);
128 if (!list_empty(&dm_timer_info
.unused_timers
)) {
129 timer
= (struct omap_dm_timer
*)
130 dm_timer_info
.unused_timers
.next
;
131 list_move_tail((struct list_head
*)timer
,
132 &dm_timer_info
.reserved_timers
);
134 spin_unlock_irqrestore(&dm_timer_lock
, flags
);
140 void omap_dm_timer_free(struct omap_dm_timer
*timer
)
144 omap_dm_timer_reset(timer
);
146 spin_lock_irqsave(&dm_timer_lock
, flags
);
147 list_move_tail((struct list_head
*)timer
, &dm_timer_info
.unused_timers
);
148 spin_unlock_irqrestore(&dm_timer_lock
, flags
);
151 void omap_dm_timer_set_int_enable(struct omap_dm_timer
*timer
,
154 omap_dm_timer_write_reg(timer
, OMAP_TIMER_INT_EN_REG
, value
);
157 unsigned int omap_dm_timer_read_status(struct omap_dm_timer
*timer
)
159 return omap_dm_timer_read_reg(timer
, OMAP_TIMER_STAT_REG
);
162 void omap_dm_timer_write_status(struct omap_dm_timer
*timer
, unsigned int value
)
164 omap_dm_timer_write_reg(timer
, OMAP_TIMER_STAT_REG
, value
);
167 void omap_dm_timer_enable_autoreload(struct omap_dm_timer
*timer
)
170 l
= omap_dm_timer_read_reg(timer
, OMAP_TIMER_CTRL_REG
);
171 l
|= OMAP_TIMER_CTRL_AR
;
172 omap_dm_timer_write_reg(timer
, OMAP_TIMER_CTRL_REG
, l
);
175 void omap_dm_timer_trigger(struct omap_dm_timer
*timer
)
177 omap_dm_timer_write_reg(timer
, OMAP_TIMER_TRIGGER_REG
, 1);
180 void omap_dm_timer_set_trigger(struct omap_dm_timer
*timer
, unsigned int value
)
184 l
= omap_dm_timer_read_reg(timer
, OMAP_TIMER_CTRL_REG
);
186 omap_dm_timer_write_reg(timer
, OMAP_TIMER_CTRL_REG
, l
);
189 void omap_dm_timer_start(struct omap_dm_timer
*timer
)
193 l
= omap_dm_timer_read_reg(timer
, OMAP_TIMER_CTRL_REG
);
194 l
|= OMAP_TIMER_CTRL_ST
;
195 omap_dm_timer_write_reg(timer
, OMAP_TIMER_CTRL_REG
, l
);
198 void omap_dm_timer_stop(struct omap_dm_timer
*timer
)
202 l
= omap_dm_timer_read_reg(timer
, OMAP_TIMER_CTRL_REG
);
204 omap_dm_timer_write_reg(timer
, OMAP_TIMER_CTRL_REG
, l
);
207 unsigned int omap_dm_timer_read_counter(struct omap_dm_timer
*timer
)
209 return omap_dm_timer_read_reg(timer
, OMAP_TIMER_COUNTER_REG
);
212 void omap_dm_timer_reset_counter(struct omap_dm_timer
*timer
)
214 omap_dm_timer_write_reg(timer
, OMAP_TIMER_COUNTER_REG
, 0);
217 void omap_dm_timer_set_load(struct omap_dm_timer
*timer
, unsigned int load
)
219 omap_dm_timer_write_reg(timer
, OMAP_TIMER_LOAD_REG
, load
);
222 void omap_dm_timer_set_match(struct omap_dm_timer
*timer
, unsigned int match
)
224 omap_dm_timer_write_reg(timer
, OMAP_TIMER_MATCH_REG
, match
);
227 void omap_dm_timer_enable_compare(struct omap_dm_timer
*timer
)
231 l
= omap_dm_timer_read_reg(timer
, OMAP_TIMER_CTRL_REG
);
232 l
|= OMAP_TIMER_CTRL_CE
;
233 omap_dm_timer_write_reg(timer
, OMAP_TIMER_CTRL_REG
, l
);
237 static inline void __dm_timer_init(void)
239 struct omap_dm_timer
*timer
;
241 spin_lock_init(&dm_timer_lock
);
242 INIT_LIST_HEAD(&dm_timer_info
.unused_timers
);
243 INIT_LIST_HEAD(&dm_timer_info
.reserved_timers
);
245 timer
= &dm_timers
[0];
246 while (timer
->base
) {
247 list_add_tail((struct list_head
*)timer
, &dm_timer_info
.unused_timers
);
248 omap_dm_timer_reset(timer
);
253 static int __init
omap_dm_timer_init(void)
255 if (cpu_is_omap16xx())
260 arch_initcall(omap_dm_timer_init
);