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