diff options
Diffstat (limited to 'firmware/target/arm/tcc780x/timer-tcc780x.c')
-rw-r--r-- | firmware/target/arm/tcc780x/timer-tcc780x.c | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/firmware/target/arm/tcc780x/timer-tcc780x.c b/firmware/target/arm/tcc780x/timer-tcc780x.c index 17956131c0..ca6613a3ff 100644 --- a/firmware/target/arm/tcc780x/timer-tcc780x.c +++ b/firmware/target/arm/tcc780x/timer-tcc780x.c | |||
@@ -25,40 +25,82 @@ | |||
25 | #include "timer.h" | 25 | #include "timer.h" |
26 | #include "logf.h" | 26 | #include "logf.h" |
27 | 27 | ||
28 | /* Use the TC32 counter [sourced by Xin:12Mhz] for this timer, as it's the | 28 | static const int prescale_shifts[] = {1, 2, 3, 4, 5, 10, 12}; |
29 | only one that allows a 32-bit counter (Timer0-5 are 16/20 bit only). */ | ||
30 | 29 | ||
31 | bool __timer_set(long cycles, bool start) | 30 | bool __timer_set(long cycles, bool start) |
32 | { | 31 | { |
33 | (void)cycles; | 32 | bool found = false; |
34 | (void)start; | 33 | |
35 | return false; | 34 | int prescale_option = 0; |
35 | int actual_cycles = 0; | ||
36 | |||
37 | /* Use the first prescale that fits Timer4's 20-bit counter */ | ||
38 | while (!found && prescale_option < 7) | ||
39 | { | ||
40 | actual_cycles = cycles >> prescale_shifts[prescale_option]; | ||
41 | |||
42 | if (actual_cycles < 0x100000) | ||
43 | found = true; | ||
44 | else | ||
45 | prescale_option++; | ||
46 | } | ||
47 | |||
48 | if (!found) | ||
49 | return false; | ||
50 | |||
51 | /* Stop the timer and set new prescale & ref count */ | ||
52 | TCFG(4) &= ~TCFG_EN; | ||
53 | TCFG(4) = prescale_option << TCFG_SEL; | ||
54 | TREF(4) = actual_cycles; | ||
55 | |||
56 | if (start && pfn_unregister != NULL) | ||
57 | { | ||
58 | pfn_unregister(); | ||
59 | pfn_unregister = NULL; | ||
60 | } | ||
61 | |||
62 | return true; | ||
36 | } | 63 | } |
37 | 64 | ||
38 | bool __timer_register(void) | 65 | bool __timer_register(void) |
39 | { | 66 | { |
40 | return false; | 67 | int oldstatus = disable_interrupt_save(IRQ_STATUS); |
68 | |||
69 | TCFG(4) |= TCFG_CLEAR | TCFG_IEN | TCFG_EN; | ||
70 | |||
71 | restore_interrupt(oldstatus); | ||
72 | |||
73 | return true; | ||
41 | } | 74 | } |
42 | 75 | ||
43 | void __timer_unregister(void) | 76 | void __timer_unregister(void) |
44 | { | 77 | { |
78 | int oldstatus = disable_interrupt_save(IRQ_STATUS); | ||
79 | |||
80 | TCFG(4) &= ~TCFG_EN; | ||
81 | |||
82 | restore_interrupt(oldstatus); | ||
45 | } | 83 | } |
46 | 84 | ||
47 | 85 | ||
48 | /* Timer interrupt processing - all timers (inc. tick) have a single IRQ */ | 86 | /* Timer interrupt processing - all timers (inc. tick) have a single IRQ */ |
49 | void TIMER0(void) | 87 | void TIMER0(void) |
50 | { | 88 | { |
51 | if (TIREQ & TF0) /* Timer0 reached ref value */ | 89 | if (TIREQ & TIREQ_TF0) /* Timer0 reached ref value */ |
52 | { | 90 | { |
53 | /* Run through the list of tick tasks */ | 91 | /* Run through the list of tick tasks */ |
54 | call_tick_tasks(); | 92 | call_tick_tasks(); |
55 | 93 | ||
56 | /* reset Timer 0 IRQ & ref flags */ | 94 | /* reset Timer 0 IRQ & ref flags */ |
57 | TIREQ |= TI0 | TF0; | 95 | TIREQ = TIREQ_TI0 | TIREQ_TF0; |
58 | } | 96 | } |
59 | 97 | ||
60 | if (TC32IRQ & (1<<3)) /* end of TC32 prescale */ | 98 | if (TIREQ & TIREQ_TF4) /* Timer4 reached ref value */ |
61 | { | 99 | { |
62 | /* dispatch timer */ | 100 | /* dispatch user timer */ |
101 | if (pfn_timer != NULL) | ||
102 | pfn_timer(); | ||
103 | |||
104 | TIREQ = TIREQ_TI4 | TIREQ_TF4; | ||
63 | } | 105 | } |
64 | } | 106 | } |