c4f26fc40af8ef41a0f3189f2b17a2d9685b796f
[fw/altos] / src / lpc / ao_fast_timer_lpc.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include <ao.h>
19 #include <ao_fast_timer.h>
20
21 static void (*ao_fast_timer_callback[AO_FAST_TIMER_MAX])(void);
22 static uint8_t ao_fast_timer_count;
23 static uint8_t ao_fast_timer_users;
24
25 static void
26 ao_fast_timer_enable(void)
27 {
28         lpc_ct16b0.tcr = ((1 << LPC_CT16B_TCR_CEN) |
29                           (1 << LPC_CT16B_TCR_CRST));
30 }
31
32 static void
33 ao_fast_timer_disable(void)
34 {
35         lpc_ct16b0.tcr = ((0 << LPC_CT16B_TCR_CEN) |
36                           (0 << LPC_CT16B_TCR_CRST));
37 }
38
39 void
40 ao_fast_timer_on(void (*callback)(void))
41 {
42         ao_fast_timer_callback[ao_fast_timer_count] = callback;
43         if (!ao_fast_timer_count++)
44                 ao_fast_timer_enable();
45 }
46
47 void
48 ao_fast_timer_off(void (*callback)(void))
49 {
50         uint8_t n;
51
52         for (n = 0; n < ao_fast_timer_count; n++)
53                 if (ao_fast_timer_callback[n] == callback) {
54                         for (; n < ao_fast_timer_count-1; n++) {
55                                 ao_fast_timer_callback[n] = ao_fast_timer_callback[n+1];
56                         }
57                         if (!--ao_fast_timer_count)
58                                 ao_fast_timer_disable();
59                         break;
60                 }
61 }
62
63 void lpc_ct16b0_isr(void)
64 {
65         uint32_t        v = lpc_ct16b0.ir;
66         int             i;
67
68         lpc_ct16b0.ir = v;
69         if (v & (1 << LPC_CT16B_IR_MR0INT)) {
70                 for (i = 0; i < ao_fast_timer_count; i++)
71                         (*ao_fast_timer_callback[i])();
72         }
73 }
74
75 #ifndef FAST_TIMER_FREQ
76 #define FAST_TIMER_FREQ 10000
77 #endif
78
79 #define TIMER_FAST      (AO_LPC_SYSCLK / FAST_TIMER_FREQ)
80
81 void
82 ao_fast_timer_init(void)
83 {
84         if (!ao_fast_timer_users) {
85
86                 lpc_nvic_set_enable(LPC_ISR_CT16B0_POS);
87                 lpc_nvic_set_priority(LPC_ISR_CT16B0_POS, AO_LPC_NVIC_CLOCK_PRIORITY);
88                 /* Turn on 16-bit timer CT16B0 */
89
90                 lpc_scb.sysahbclkctrl |= 1 << LPC_SCB_SYSAHBCLKCTRL_CT16B0;
91
92                 /* Disable timer */
93                 lpc_ct16b0.tcr = 0;
94
95                 /* scale factor 1 */
96                 lpc_ct16b0.pr = 0;
97                 lpc_ct16b0.pc = 0;
98
99                 lpc_ct16b0.mcr = ((1 << LPC_CT16B_MCR_MR0I) |
100                                   (1 << LPC_CT16B_MCR_MR0R));
101
102                 lpc_ct16b0.mr[0] = TIMER_FAST;
103
104                 ao_fast_timer_disable();
105         }
106         if (ao_fast_timer_users == AO_FAST_TIMER_MAX)
107                 ao_panic(AO_PANIC_FAST_TIMER);
108         ao_fast_timer_users++;
109 }
110