altos/stmf0: Fixup for SPI mode support
[fw/altos] / src / stmf0 / ao_spi_stm.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; 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  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20
21 struct ao_spi_stm_info {
22         uint8_t miso_dma_index;
23         uint8_t mosi_dma_index;
24         struct stm_spi *stm_spi;
25 };
26
27 static uint8_t          ao_spi_mutex[STM_NUM_SPI];
28 static uint8_t          ao_spi_pin_config[STM_NUM_SPI];
29
30 static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
31         {
32                 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
33                 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
34                 &stm_spi1
35         },
36         {
37                 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
38                 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
39                 &stm_spi2
40         }
41 };
42
43 static uint8_t  spi_dev_null;
44
45 #define SPI_CR2 ((0 << STM_SPI_CR2_LDMA_TX) |                           \
46                  (0 << STM_SPI_CR2_LDMA_RX) |                           \
47                  (1 << STM_SPI_CR2_FRXTH) |                             \
48                  (STM_SPI_CR2_DS_8 << STM_SPI_CR2_DS) |                 \
49                  (0 << STM_SPI_CR2_TXEIE) |                             \
50                  (0 << STM_SPI_CR2_RXNEIE) |                            \
51                  (0 << STM_SPI_CR2_ERRIE) |                             \
52                  (STM_SPI_CR2_FRF_MOTOROLA << STM_SPI_CR2_FRF) |        \
53                  (0 << STM_SPI_CR2_NSSP) |                              \
54                  (0 << STM_SPI_CR2_SSOE))
55
56 #define SPI_CR2_DMA     (SPI_CR2 |                      \
57                          (1 << STM_SPI_CR2_TXDMAEN) |   \
58                          (1 << STM_SPI_CR2_RXDMAEN))
59
60 #define SPI_CR2_SYNC    (SPI_CR2 |                      \
61                          (0 << STM_SPI_CR2_TXDMAEN) |   \
62                          (0 << STM_SPI_CR2_RXDMAEN))
63
64 #if DEBUG
65 static struct {
66         uint8_t task;
67         uint8_t which;
68         AO_TICK_TYPE tick;
69         uint16_t len;
70 } spi_tasks[64];
71 static uint8_t  spi_task_index;
72
73 static void
74 validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
75 {
76         uint32_t        sr = stm_spi->sr;
77
78         if (stm_spi != &stm_spi2)
79                 return;
80         spi_tasks[spi_task_index].task = ao_cur_task ? ao_cur_task->task_id : 0;
81         spi_tasks[spi_task_index].which = which;
82         spi_tasks[spi_task_index].tick = ao_time();
83         spi_tasks[spi_task_index].len = len;
84         spi_task_index = (spi_task_index + 1) & (63);
85         if (sr & (1 << STM_SPI_SR_FRE))
86                 ao_panic(0x40 | 1);
87         if (sr & (1 << STM_SPI_SR_BSY))
88                 ao_panic(0x40 | 2);
89         if (sr & (1 << STM_SPI_SR_OVR))
90                 ao_panic(0x40 | 3);
91         if (sr & (1 << STM_SPI_SR_MODF))
92                 ao_panic(0x40 | 4);
93         if (sr & (1 << STM_SPI_SR_UDR))
94                 ao_panic(0x40 | 5);
95         if ((sr & (1 << STM_SPI_SR_TXE)) == 0)
96                 ao_panic(0x40 | 6);
97         if (sr & (1 << STM_SPI_SR_RXNE))
98                 ao_panic(0x40 | 7);
99         if (which != 5 && which != 6 && which != 13)
100                 if (ao_cur_task->task_id != ao_spi_mutex[1])
101                         ao_panic(0x40 | 8);
102 }
103 #else
104 #define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
105 #endif
106
107 static void
108 ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
109 {
110         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
111         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
112         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
113
114         validate_spi(stm_spi, which, len);
115
116         stm_spi->cr2 = SPI_CR2_DMA;
117
118         ao_dma_start(miso_dma_index);
119         ao_dma_start(mosi_dma_index);
120
121         ao_arch_critical(
122                 while (!ao_dma_done[miso_dma_index])
123                         ao_sleep(&ao_dma_done[miso_dma_index]);
124                 );
125
126         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
127         while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
128
129         validate_spi(stm_spi, which+1, len);
130
131         stm_spi->cr2 = 0;
132
133         ao_dma_done_transfer(mosi_dma_index);
134         ao_dma_done_transfer(miso_dma_index);
135 }
136
137 void
138 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
139 {
140         uint8_t         id = AO_SPI_INDEX(spi_index);
141         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
142         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
143         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
144
145         /* Set up the transmit DMA to deliver data */
146         ao_dma_set_transfer(mosi_dma_index,
147                             &stm_spi->dr,
148                             (void *) block,
149                             len,
150                             (0 << STM_DMA_CCR_MEM2MEM) |
151                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
152                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
153                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
154                             (1 << STM_DMA_CCR_MINC) |
155                             (0 << STM_DMA_CCR_PINC) |
156                             (0 << STM_DMA_CCR_CIRC) |
157                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
158                             (0 << STM_DMA_CCR_TCIE));
159
160         /* Set up the receive DMA -- when this is done, we know the SPI unit
161          * is idle. Without this, we'd have to poll waiting for the BSY bit to
162          * be cleared
163          */
164         ao_dma_set_transfer(miso_dma_index,
165                             &stm_spi->dr,
166                             &spi_dev_null,
167                             len,
168                             (0 << STM_DMA_CCR_MEM2MEM) |
169                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
170                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
171                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
172                             (0 << STM_DMA_CCR_MINC) |
173                             (0 << STM_DMA_CCR_PINC) |
174                             (0 << STM_DMA_CCR_CIRC) |
175                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
176                             (1 << STM_DMA_CCR_TCIE));
177
178         ao_spi_run(id, 1, len);
179 }
180
181 void
182 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
183 {
184         uint8_t         id = AO_SPI_INDEX(spi_index);
185         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
186         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
187         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
188
189         /* Set up the transmit DMA to deliver data */
190         ao_dma_set_transfer(mosi_dma_index,
191                             &stm_spi->dr,
192                             &value,
193                             len,
194                             (0 << STM_DMA_CCR_MEM2MEM) |
195                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
196                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
197                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
198                             (0 << STM_DMA_CCR_MINC) |
199                             (0 << STM_DMA_CCR_PINC) |
200                             (0 << STM_DMA_CCR_CIRC) |
201                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
202                             (0 << STM_DMA_CCR_TCIE));
203
204         /* Set up the receive DMA -- when this is done, we know the SPI unit
205          * is idle. Without this, we'd have to poll waiting for the BSY bit to
206          * be cleared
207          */
208         ao_dma_set_transfer(miso_dma_index,
209                             &stm_spi->dr,
210                             &spi_dev_null,
211                             len,
212                             (0 << STM_DMA_CCR_MEM2MEM) |
213                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
214                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
215                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
216                             (0 << STM_DMA_CCR_MINC) |
217                             (0 << STM_DMA_CCR_PINC) |
218                             (0 << STM_DMA_CCR_CIRC) |
219                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
220                             (1 << STM_DMA_CCR_TCIE));
221
222         ao_spi_run(id, 3, len);
223 }
224
225 void
226 ao_spi_start_bytes(uint8_t spi_index)
227 {
228         uint8_t         id = AO_SPI_INDEX(spi_index);
229         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
230
231         stm_spi->cr2 = SPI_CR2_SYNC;
232         validate_spi(stm_spi, 5, 0xffff);
233 }
234
235 void
236 ao_spi_stop_bytes(uint8_t spi_index)
237 {
238         uint8_t         id = AO_SPI_INDEX(spi_index);
239         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
240
241         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
242                 ;
243         while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
244                 ;
245         /* Clear the OVR flag */
246         (void) stm_spi->dr;
247         (void) stm_spi->sr;
248         validate_spi(stm_spi, 6, 0xffff);
249         stm_spi->cr2 = 0;
250 }
251
252 void
253 ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
254 {
255         uint8_t         id = AO_SPI_INDEX(spi_index);
256         const uint8_t   *b = block;
257         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
258
259         stm_spi->cr2 = SPI_CR2_SYNC;
260
261         validate_spi(stm_spi, 7, len);
262         while (len--) {
263                 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
264                 stm_spi->dr = *b++;
265         }
266         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
267                 ;
268         while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
269                 ;
270         /* Clear the OVR flag */
271         (void) stm_spi->dr;
272         (void) stm_spi->sr;
273         validate_spi(stm_spi, 8, len);
274 }
275
276 void
277 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
278 {
279         uint8_t         id = AO_SPI_INDEX(spi_index);
280         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
281         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
282         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
283
284         spi_dev_null = 0xff;
285
286         /* Set up transmit DMA to make the SPI hardware actually run */
287         ao_dma_set_transfer(mosi_dma_index,
288                             &stm_spi->dr,
289                             &spi_dev_null,
290                             len,
291                             (0 << STM_DMA_CCR_MEM2MEM) |
292                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
293                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
294                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
295                             (0 << STM_DMA_CCR_MINC) |
296                             (0 << STM_DMA_CCR_PINC) |
297                             (0 << STM_DMA_CCR_CIRC) |
298                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
299                             (0 << STM_DMA_CCR_TCIE));
300
301         /* Set up the receive DMA to capture data */
302         ao_dma_set_transfer(miso_dma_index,
303                             &stm_spi->dr,
304                             block,
305                             len,
306                             (0 << STM_DMA_CCR_MEM2MEM) |
307                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
308                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
309                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
310                             (1 << STM_DMA_CCR_MINC) |
311                             (0 << STM_DMA_CCR_PINC) |
312                             (0 << STM_DMA_CCR_CIRC) |
313                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
314                             (1 << STM_DMA_CCR_TCIE));
315
316         ao_spi_run(id, 9, len);
317 }
318
319 void
320 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
321 {
322         uint8_t         id = AO_SPI_INDEX(spi_index);
323         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
324         uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
325         uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
326
327         /* Set up transmit DMA to send data */
328         ao_dma_set_transfer(mosi_dma_index,
329                             &stm_spi->dr,
330                             out,
331                             len,
332                             (0 << STM_DMA_CCR_MEM2MEM) |
333                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
334                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
335                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
336                             (1 << STM_DMA_CCR_MINC) |
337                             (0 << STM_DMA_CCR_PINC) |
338                             (0 << STM_DMA_CCR_CIRC) |
339                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
340                             (0 << STM_DMA_CCR_TCIE));
341
342         /* Set up the receive DMA to capture data */
343         ao_dma_set_transfer(miso_dma_index,
344                             &stm_spi->dr,
345                             in,
346                             len,
347                             (0 << STM_DMA_CCR_MEM2MEM) |
348                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
349                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
350                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
351                             (1 << STM_DMA_CCR_MINC) |
352                             (0 << STM_DMA_CCR_PINC) |
353                             (0 << STM_DMA_CCR_CIRC) |
354                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
355                             (1 << STM_DMA_CCR_TCIE));
356
357         ao_spi_run(id, 11, len);
358 }
359
360 static void
361 ao_spi_disable_pin_config(uint8_t spi_pin_config)
362 {
363         /* disable config
364          */
365         switch (spi_pin_config) {
366         case AO_SPI_1_PA5_PA6_PA7:
367                 stm_gpio_set(&stm_gpioa, 5, 1);
368                 stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
369                 stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
370                 stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
371                 break;
372         case AO_SPI_1_PB3_PB4_PB5:
373                 stm_gpio_set(&stm_gpiob, 3, 1);
374                 stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
375                 stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
376                 stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
377                 break;
378         case AO_SPI_2_PB13_PB14_PB15:
379                 stm_gpio_set(&stm_gpiob, 13, 1);
380                 stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
381                 stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
382                 stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
383                 break;
384         }
385 }
386
387 static void
388 ao_spi_enable_pin_config(uint8_t spi_pin_config)
389 {
390         /* Disable current config
391          */
392         switch (spi_pin_config) {
393         case AO_SPI_1_PA5_PA6_PA7:
394                 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
395                 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
396                 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
397                 break;
398         case AO_SPI_1_PB3_PB4_PB5:
399                 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
400                 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
401                 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
402                 break;
403         case AO_SPI_2_PB13_PB14_PB15:
404                 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0);
405                 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0);
406                 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0);
407                 break;
408         }
409 }
410
411 static void
412 ao_spi_config(uint8_t spi_index, uint32_t speed)
413 {
414         uint8_t         spi_pin_config = AO_SPI_PIN_CONFIG(spi_index);
415         uint8_t         id = AO_SPI_INDEX(spi_index);
416         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
417
418         switch (id) {
419 #if SPI_1_POWER_MANAGE
420         case 0:
421                 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
422                 break;
423 #endif
424 #if SPI_2_POWER_MANAGE
425         case 1:
426                 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
427                 break;
428 #endif
429         }
430         if (spi_pin_config != ao_spi_pin_config[id]) {
431
432                 /* Disable old config
433                  */
434                 ao_spi_disable_pin_config(ao_spi_pin_config[id]);
435
436                 /* Enable new config
437                  */
438                 ao_spi_enable_pin_config(spi_pin_config);
439
440                 /* Remember current config
441                  */
442                 ao_spi_pin_config[id] = spi_pin_config;
443         }
444         stm_spi->cr2 = SPI_CR2;
445         stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |                   /* Three wire mode */
446                         (0 << STM_SPI_CR1_BIDIOE) |
447                         (0 << STM_SPI_CR1_CRCEN) |                      /* CRC disabled */
448                         (0 << STM_SPI_CR1_CRCNEXT) |
449                         (0 << STM_SPI_CR1_CRCL) |
450                         (0 << STM_SPI_CR1_RXONLY) |
451                         (1 << STM_SPI_CR1_SSM) |                        /* Software SS handling */
452                         (1 << STM_SPI_CR1_SSI) |                        /*  ... */
453                         (0 << STM_SPI_CR1_LSBFIRST) |                   /* Big endian */
454                         (1 << STM_SPI_CR1_SPE) |                        /* Enable SPI unit */
455                         (speed << STM_SPI_CR1_BR) |                     /* baud rate to pclk/4 */
456                         (1 << STM_SPI_CR1_MSTR) |
457                         (AO_SPI_CPOL(spi_index) << STM_SPI_CR1_CPOL) |  /* Format */
458                         (AO_SPI_CPHA(spi_index) << STM_SPI_CR1_CPHA));
459 }
460
461 uint8_t
462 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
463 {
464         uint8_t         id = AO_SPI_INDEX(spi_index);
465
466         if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
467                 return 0;
468         ao_spi_config(spi_index, speed);
469         return 1;
470 }
471
472 void
473 ao_spi_get(uint8_t spi_index, uint32_t speed)
474 {
475         uint8_t         id = AO_SPI_INDEX(spi_index);
476         ao_mutex_get(&ao_spi_mutex[id]);
477         ao_spi_config(spi_index, speed);
478 }
479
480 void
481 ao_spi_put(uint8_t spi_index)
482 {
483         uint8_t         id = AO_SPI_INDEX(spi_index);
484         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
485
486         stm_spi->cr1 = 0;
487         switch (id) {
488 #if SPI_1_POWER_MANAGE
489         case 0:
490                 stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_SPI1EN);
491                 break;
492 #endif
493 #if SPI_2_POWER_MANAGE
494         case 1:
495                 stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_SPI2EN);
496                 break;
497 #endif
498         }
499         ao_mutex_put(&ao_spi_mutex[id]);
500 }
501
502 static void
503 ao_spi_channel_init(uint8_t spi_index)
504 {
505         uint8_t         id = AO_SPI_INDEX(spi_index);
506         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
507
508         ao_spi_disable_pin_config(AO_SPI_PIN_CONFIG(spi_index));
509
510         stm_spi->cr1 = 0;
511         stm_spi->cr2 = SPI_CR2_SYNC;
512
513         /* Clear any pending data and error flags */
514         (void) stm_spi->dr;
515         (void) stm_spi->sr;
516 }
517
518 #if DEBUG
519 void
520 ao_spi_dump_cmd(void)
521 {
522         int s;
523
524         for (s = 0; s < 64; s++) {
525                 int i = (spi_task_index + s) & 63;
526                 if (spi_tasks[i].which) {
527                         int t;
528                         const char *name = "(none)";
529                         for (t = 0; t < ao_num_tasks; t++)
530                                 if (ao_tasks[t]->task_id == spi_tasks[i].task) {
531                                         name = ao_tasks[t]->name;
532                                         break;
533                                 }
534                         printf("%2d: %5d task %2d which %2d len %5d %s\n",
535                                s,
536                                spi_tasks[i].tick,
537                                spi_tasks[i].task,
538                                spi_tasks[i].which,
539                                spi_tasks[i].len,
540                                name);
541                 }
542         }
543         for (s = 0; s < STM_NUM_SPI; s++) {
544                 struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
545
546                 printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
547                        s, ao_spi_mutex[s], ao_spi_index[s],
548                        ao_spi_stm_info[s].miso_dma_index,
549                        ao_spi_stm_info[s].mosi_dma_index);
550                 printf(" cr1 %04x cr2 %02x sr %03x\n",
551                        spi->cr1, spi->cr2, spi->sr);
552         }
553
554 }
555
556 static const struct ao_cmds ao_spi_cmds[] = {
557         { ao_spi_dump_cmd,      "S\0Dump SPI status" },
558         { 0, NULL }
559 };
560 #endif
561
562 void
563 ao_spi_init(void)
564 {
565 #if HAS_SPI_1
566 #ifndef SPI_1_PA5_PA6_PA7
567 #error SPI_1_PA5_PA6_PA7 undefined
568 #endif
569 # if SPI_1_PA5_PA6_PA7
570         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
571         stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
572         stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
573         stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
574 # endif
575 # ifndef SPI_1_PB3_PB4_PB5
576 # error SPI_1_PB3_PB4_PB5 undefined
577 # endif
578 # if SPI_1_PB3_PB4_PB5
579         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
580         stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
581         stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
582         stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
583 # endif
584         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
585         ao_spi_pin_config[0] = AO_SPI_CONFIG_NONE;
586         ao_spi_channel_init(STM_SPI_INDEX(1));
587 #endif
588
589 #if HAS_SPI_2
590 # if SPI_2_PB10_PB13_PB14
591         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
592         stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
593         stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
594         stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
595 # endif
596         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
597         ao_spi_index[1] = AO_SPI_CONFIG_NONE;
598         ao_spi_channel_init(STM_SPI_INDEX(2));
599 #endif
600 #if DEBUG
601         ao_cmd_register(&ao_spi_cmds[0]);
602 #endif
603 }