summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c')
-rw-r--r--firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c127
1 files changed, 127 insertions, 0 deletions
diff --git a/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c
new file mode 100644
index 0000000000..4654c7c845
--- /dev/null
+++ b/firmware/target/arm/s3c2440/gigabeat-fx/timer-meg-fx.c
@@ -0,0 +1,127 @@
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* Copyright (C) 2007 by Michael Sevakis
11*
12* All files in this archive are subject to the GNU General Public License.
13* See the file COPYING in the source tree root for full license agreement.
14*
15* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16* KIND, either express or implied.
17*
18****************************************************************************/
19#include "config.h"
20#include "cpu.h"
21#include "system.h"
22#include "timer.h"
23#include "logf.h"
24
25/* GPB0/TOUT0 should already have been configured as output so that pin
26 should not be a functional pin and TIMER0 output unseen there */
27void TIMER0(void)
28{
29 if (pfn_timer != NULL)
30 pfn_timer();
31
32 SRCPND = TIMER0_MASK;
33 INTPND = TIMER0_MASK;
34}
35
36static void stop_timer(void)
37{
38 /* mask interrupt */
39 INTMSK |= TIMER0_MASK;
40
41 /* stop any running TIMER0 */
42 TCON &= ~(1 << 0);
43
44 /* clear pending */
45 SRCPND = TIMER0_MASK;
46 INTPND = TIMER0_MASK;
47}
48
49bool __timer_set(long cycles, bool start)
50{
51 bool retval = false;
52
53 /* Find the minimum factor that puts the counter in range 1-65535 */
54 unsigned int prescaler = (cycles + 65534) / 65535;
55
56 /* Maximum divider setting is x / 256 / 16 = x / 4096 */
57 if (prescaler <= 4096)
58 {
59 int oldlevel;
60 unsigned int divider;
61
62 if (start && pfn_unregister != NULL)
63 {
64 pfn_unregister();
65 pfn_unregister = NULL;
66 }
67
68 oldlevel = set_irq_level(HIGHEST_IRQ_LEVEL);
69
70 TCMPB0 = 0;
71 TCNTB0 = (unsigned int)cycles / prescaler;
72
73 /* Max prescale is 255+1 */
74 for (divider = 0; prescaler > 256; prescaler >>= 1, divider++);
75
76 TCFG0 = (TCFG0 & ~0xff) | (prescaler - 1);
77 TCFG1 = (TCFG1 & ~0xf) | divider;
78
79 set_irq_level(oldlevel);
80
81 retval = true;
82 }
83
84 return retval;
85}
86
87bool __timer_register(void)
88{
89 bool retval = true;
90
91 int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS);
92
93 stop_timer();
94
95 /* neurosis - make sure something didn't set GPB0 to TOUT0 */
96 if ((GPBCON & 0x3) != 0x2)
97 {
98 /* manual update: on (to reset count) */
99 TCON |= (1 << 1);
100 /* dead zone: off, inverter: off, manual off */
101 TCON &= ~((1 << 4) | (1 << 2) | (1 << 1));
102 /* interval mode (auto reload): on */
103 TCON |= (1 << 3);
104 /* start timer */
105 TCON |= (1 << 0);
106 /* unmask interrupt */
107 INTMSK &= ~TIMER0_MASK;
108 }
109
110 if (!(TCON & (1 << 0)))
111 {
112 /* timer could not be started due to config error */
113 logf("Timer error: GPB0 set to TOUT0");
114 retval = false;
115 }
116
117 set_interrupt_status(oldstatus, IRQ_FIQ_STATUS);
118
119 return retval;
120}
121
122void __timer_unregister(void)
123{
124 int oldstatus = set_interrupt_status(IRQ_FIQ_DISABLED, IRQ_FIQ_STATUS);
125 stop_timer();
126 set_interrupt_status(oldstatus, IRQ_FIQ_STATUS);
127}