altos: ADS124S0X driver compiles now
[fw/altos] / src / cortexelf-v1 / ao_1802.c
1 /*
2  * Copyright © 2017 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, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include <ao.h>
16 #include <ao_flip_bits.h>
17 #include <ao_1802.h>
18 #include <ao_exti.h>
19
20 /* Decoded address driven by TPA/TPB signals */
21 uint16_t        ADDRESS;
22
23 /* Decoded data, driven by TPB signal */
24 uint8_t         DATA;
25
26 /* Mux control */
27 #define _MUX_1802               0
28 #define _MUX_STM                1
29
30 uint8_t         MUX_CONTROL;
31
32 /* Signals muxed between 1802 and STM */
33 uint8_t
34 MRD(void) {
35         return ao_gpio_get(MRD_PORT, MRD_BIT, MRD_PIN);
36 }
37
38 void
39 MRD_set(uint8_t value) {
40         ao_gpio_set(MRD_PORT, MRD_BIT, MRD_PIN, value);
41 }
42
43 uint8_t
44 MWR(void) {
45         return ao_gpio_get(MWR_PORT, MWR_BIT, MWR_PIN);
46 }
47
48 void
49 MWR_set(uint8_t value) {
50         ao_gpio_set(MWR_PORT, MWR_BIT, MWR_PIN, value);
51 }
52
53 static void
54 TPA_rising(void)
55 {
56         ADDRESS = (ADDRESS & 0x00ff) | ((uint16_t) MA() << 8);
57         ao_wakeup(&ADDRESS);
58 }
59
60 uint8_t
61 TPA(void) {
62         return ao_gpio_get(TPA_PORT, TPA_BIT, TPA_PIN);
63 }
64
65 void
66 TPA_set(uint8_t tpa) {
67         ao_gpio_set(TPA_PORT, TPA_BIT, TPA_PIN, tpa);
68         if (tpa)
69                 TPA_rising();
70 }
71
72 static void
73 TPB_rising(void)
74 {
75         ADDRESS = (ADDRESS & 0xff00) | MA();
76         if (MWR() == 0 || MRD() == 0)
77                 DATA = BUS();
78         ao_wakeup(&ADDRESS);
79 }
80
81 static void
82 TPB_falling(void)
83 {
84 }
85
86 uint8_t
87 TPB(void) {
88         return ao_gpio_get(TPB_PORT, TPB_BIT, TPB_PIN);
89 }
90
91 void
92 TPB_set(uint8_t tpb) {
93         ao_gpio_set(TPB_PORT, TPB_BIT, TPB_PIN, tpb);
94         if (tpb)
95                 TPB_rising();
96         else
97                 TPB_falling();
98 }
99
100 uint8_t
101 MA(void) {
102         return (ao_gpio_get_all(MA_PORT) >> MA_SHIFT) & MA_MASK;
103 }
104
105 void
106 MA_set(uint8_t ma) {
107         ao_gpio_set_mask(MA_PORT, ((uint16_t) ma) << MA_SHIFT, MA_MASK << MA_SHIFT);
108 }
109
110 /* Tri-state data bus */
111
112 uint8_t
113 BUS(void) {
114         return ao_flip_bits_8[(ao_gpio_get_all(BUS_PORT) >> BUS_SHIFT) & BUS_MASK];
115 }
116
117 void
118 BUS_set(uint8_t bus) {
119         ao_gpio_set_mask(BUS_PORT, ao_flip_bits_8[bus] << BUS_SHIFT, BUS_MASK << BUS_SHIFT);
120 }
121
122 void
123 BUS_stm(void)
124 {
125         ao_set_output_mask(BUS_PORT, BUS_MASK << BUS_SHIFT);
126 }
127
128 void
129 BUS_1802(void)
130 {
131         ao_set_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT);
132 }
133
134 /* Pins controlled by 1802 */
135 uint8_t
136 SC(void) {
137         return ao_flip_bits_2[(ao_gpio_get_all(SC_PORT) >> SC_SHIFT) & SC_MASK];
138 }
139
140 uint8_t
141 Q(void) {
142         return ao_gpio_get(Q_PORT, Q_BIT, Q_PIN);
143 }
144
145 uint8_t
146 N(void) {
147         return (ao_gpio_get_all(N_PORT) >> N_SHIFT) & N_MASK;
148 }
149
150 /* Pins controlled by STM */
151 uint8_t
152 EF(void) {
153         return (ao_gpio_get_all(EF_PORT) >> EF_SHIFT) & EF_MASK;
154 }
155
156 void
157 EF_set(uint8_t ef) {
158         ao_gpio_set_mask(EF_PORT, ef << EF_SHIFT, EF_MASK << EF_SHIFT);
159 }
160
161 uint8_t
162 DMA_IN(void) {
163         return ao_gpio_get(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN);
164 }
165
166 void
167 DMA_IN_set(uint8_t dma_in) {
168         ao_gpio_set(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, dma_in);
169 }
170
171 uint8_t
172 DMA_OUT(void) {
173         return ao_gpio_get(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN);
174 }
175
176 void
177 DMA_OUT_set(uint8_t dma_out) {
178         ao_gpio_set(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, dma_out);
179 }
180
181 uint8_t
182 INT(void) {
183         return ao_gpio_get(INT_PORT, INT_BIT, INT_PIN);
184 }
185
186 void
187 INT_set(uint8_t dma_out) {
188         ao_gpio_set(INT_PORT, INT_BIT, INT_PIN, dma_out);
189 }
190
191 uint8_t
192 CLEAR(void) {
193         return ao_gpio_get(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN);
194 }
195
196 void
197 CLEAR_set(uint8_t dma_out) {
198         ao_gpio_set(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, dma_out);
199 }
200
201 uint8_t
202 WAIT(void) {
203         return ao_gpio_get(WAIT_PORT, WAIT_BIT, WAIT_PIN);
204 }
205
206 void
207 WAIT_set(uint8_t dma_out) {
208         ao_gpio_set(WAIT_PORT, WAIT_BIT, WAIT_PIN, dma_out);
209 }
210
211 void
212 tpb_isr(void) {
213         /* Latch low address and data on rising edge of TPB */
214         if (TPB())
215                 TPB_rising();
216         else
217                 TPB_falling();
218 }
219
220 void
221 tpa_isr(void) {
222         /* Latch high address on rising edge of TPA */
223         if (TPA())
224                 TPA_rising();
225 }
226
227 #define ao_1802_in(port, bit, mode) do {                \
228                 ao_gpio_set_mode(port, bit, mode);      \
229                 ao_set_input(port, bit);                \
230         } while (0)
231
232 #define ao_1802_in_isr(port, bit, mode) do {            \
233                 ao_gpio_set_mode(port, bit, mode);      \
234                 ao_set_input(port, bit);                \
235                 ao_exti_enable(port, bit);              \
236         } while (0)
237
238 #define ao_1802_out_isr(port, bit) do { \
239                 ao_exti_disable(port, bit); \
240                 ao_set_output(port, bit); \
241         } while (0)
242
243 void
244 MUX_1802(void)
245 {
246         if (MUX_CONTROL != _MUX_1802) {
247                 /* Set pins to input, but pulled to idle value */
248                 ao_1802_in(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP);
249                 ao_1802_in(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP);
250                 ao_1802_in_isr(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN);
251                 ao_1802_in_isr(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN);
252                 ao_set_input_mask(MA_PORT, MA_MASK << MA_SHIFT);
253
254                 ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 0);
255
256                 /* Now change the pins to eliminate the pull up/down */
257                 ao_gpio_set_mode(MRD_PORT, MRD_BIT, 0);
258                 ao_gpio_set_mode(MWR_PORT, MWR_BIT, 0);
259                 ao_gpio_set_mode(TPB_PORT, TPB_BIT, 0);
260                 ao_gpio_set_mode(TPA_PORT, TPA_BIT, 0);
261
262                 MUX_CONTROL = _MUX_1802;
263         }
264 }
265
266 void
267 MUX_stm(void)
268 {
269         if (MUX_CONTROL != _MUX_STM) {
270                 /* Set the pins back to pull to the idle value */
271                 ao_gpio_set_mode(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP);
272                 ao_gpio_set_mode(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP);
273                 ao_gpio_set_mode(TPB_PORT, TPB_BIT, AO_EXTI_MODE_PULL_DOWN);
274                 ao_gpio_set_mode(TPA_PORT, TPA_BIT, AO_EXTI_MODE_PULL_DOWN);
275
276                 ao_gpio_set(MUX_PORT, MUX_BIT, MUX_PIN, 1);
277
278                 /* Now set the pins as output, driven to the idle value */
279                 ao_set_output(MRD_PORT, MRD_BIT, MRD_PIN, 1);
280                 ao_set_output(MWR_PORT, MWR_BIT, MWR_PIN, 1);
281                 ao_set_output(TPB_PORT, TPB_BIT, TPB_PIN, 0);
282                 ao_set_output(TPA_PORT, TPA_BIT, TPA_PIN, 0);
283                 ao_set_output_mask(MA_PORT, MA_MASK << MA_SHIFT);
284                 MUX_CONTROL = _MUX_STM;
285         }
286 }
287
288 void
289 ao_1802_init(void)
290 {
291         /* Multiplexed signals*/
292
293         /* active low signals */
294         ao_enable_input(MRD_PORT, MRD_BIT, AO_EXTI_MODE_PULL_UP);
295         ao_enable_input(MWR_PORT, MWR_BIT, AO_EXTI_MODE_PULL_UP);
296
297         /* active high signals with interrupts */
298         ao_exti_setup(TPA_PORT, TPA_BIT,
299                       AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING,
300                       tpa_isr);
301         ao_exti_setup(TPB_PORT, TPB_BIT,
302                       AO_EXTI_MODE_PULL_DOWN | AO_EXTI_MODE_RISING | AO_EXTI_MODE_FALLING,
303                       tpb_isr);
304
305         /* multiplexed address bus */
306         ao_enable_input_mask(MA_PORT, MA_MASK << MA_SHIFT, 0);
307
308         /* Data bus */
309
310         ao_enable_input_mask(BUS_PORT, BUS_MASK << BUS_SHIFT, 0);
311
312         /* Pins controlled by 1802 */
313         ao_enable_input_mask(SC_PORT, SC_MASK << SC_SHIFT, 0);
314         ao_enable_input(Q_PORT, Q_BIT, 0);
315         ao_enable_input_mask(N_PORT, N_MASK << N_SHIFT, 0);
316
317         /* Pins controlled by STM */
318         ao_enable_output_mask(EF_PORT, 0, EF_MASK << EF_SHIFT);
319         ao_enable_output(DMA_IN_PORT, DMA_IN_BIT, DMA_IN_PIN, 1);
320         ao_enable_output(DMA_OUT_PORT, DMA_OUT_BIT, DMA_OUT_PIN, 1);
321         ao_enable_output(INT_PORT, INT_BIT, INT_PIN, 1);
322         ao_enable_output(CLEAR_PORT, CLEAR_BIT, CLEAR_PIN, 1);
323         ao_enable_output(WAIT_PORT, WAIT_BIT, WAIT_PIN, 1);
324
325         /* Force configuration to STM so that MUX_1802 will do something */
326         MUX_CONTROL = _MUX_STM;
327         MUX_1802();
328 }