3b5773b6ed75e70da31d498eaaf0ecf467356a18
[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 void
88 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
89 {
90         struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
91         uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
92         uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
93
94         /* Set up the transmit DMA to deliver data */
95         ao_dma_set_transfer(mosi_dma_index,
96                             &stm_spi->dr,
97                             (void *) block,
98                             len,
99                             (0 << STM_DMA_CCR_MEM2MEM) |
100                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
101                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
102                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
103                             (1 << STM_DMA_CCR_MINC) |
104                             (0 << STM_DMA_CCR_PINC) |
105                             (0 << STM_DMA_CCR_CIRC) |
106                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
107
108         /* Clear RXNE */
109         (void) stm_spi->dr;
110
111         /* Set up the receive DMA -- when this is done, we know the SPI unit
112          * is idle. Without this, we'd have to poll waiting for the BSY bit to
113          * be cleared
114          */
115         ao_dma_set_transfer(miso_dma_index,
116                             &stm_spi->dr,
117                             &spi_dev_null,
118                             len,
119                             (0 << STM_DMA_CCR_MEM2MEM) |
120                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
121                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
122                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
123                             (0 << STM_DMA_CCR_MINC) |
124                             (0 << STM_DMA_CCR_PINC) |
125                             (0 << STM_DMA_CCR_CIRC) |
126                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
127         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
128                         (0 << STM_SPI_CR2_RXNEIE) |
129                         (0 << STM_SPI_CR2_ERRIE) |
130                         (0 << STM_SPI_CR2_SSOE) |
131                         (1 << STM_SPI_CR2_TXDMAEN) |
132                         (1 << STM_SPI_CR2_RXDMAEN));
133         ao_dma_start(miso_dma_index);
134         ao_dma_start(mosi_dma_index);
135         ao_arch_critical(
136                 while (!ao_dma_done[miso_dma_index])
137                         ao_sleep(&ao_dma_done[miso_dma_index]);
138                 );
139         ao_dma_done_transfer(mosi_dma_index);
140         ao_dma_done_transfer(miso_dma_index);
141 }
142
143 void
144 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
145 {
146         struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
147         uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
148         uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
149
150         /* Set up the transmit DMA to deliver data */
151         ao_dma_set_transfer(mosi_dma_index,
152                             &stm_spi->dr,
153                             &value,
154                             len,
155                             (0 << STM_DMA_CCR_MEM2MEM) |
156                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
157                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
158                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
159                             (0 << STM_DMA_CCR_MINC) |
160                             (0 << STM_DMA_CCR_PINC) |
161                             (0 << STM_DMA_CCR_CIRC) |
162                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
163
164         /* Clear RXNE */
165         (void) stm_spi->dr;
166
167         /* Set up the receive DMA -- when this is done, we know the SPI unit
168          * is idle. Without this, we'd have to poll waiting for the BSY bit to
169          * be cleared
170          */
171         ao_dma_set_transfer(miso_dma_index,
172                             &stm_spi->dr,
173                             &spi_dev_null,
174                             len,
175                             (0 << STM_DMA_CCR_MEM2MEM) |
176                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
177                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
178                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
179                             (0 << STM_DMA_CCR_MINC) |
180                             (0 << STM_DMA_CCR_PINC) |
181                             (0 << STM_DMA_CCR_CIRC) |
182                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
183         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
184                         (0 << STM_SPI_CR2_RXNEIE) |
185                         (0 << STM_SPI_CR2_ERRIE) |
186                         (0 << STM_SPI_CR2_SSOE) |
187                         (1 << STM_SPI_CR2_TXDMAEN) |
188                         (1 << STM_SPI_CR2_RXDMAEN));
189         ao_dma_start(miso_dma_index);
190         ao_dma_start(mosi_dma_index);
191         ao_arch_critical(
192                 while (!ao_dma_done[miso_dma_index])
193                         ao_sleep(&ao_dma_done[miso_dma_index]);
194                 );
195         ao_dma_done_transfer(mosi_dma_index);
196         ao_dma_done_transfer(miso_dma_index);
197 }
198
199 void
200 ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
201 {
202         uint8_t         *b = block;
203         struct stm_spi  *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
204
205         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
206                         (0 << STM_SPI_CR2_RXNEIE) |
207                         (0 << STM_SPI_CR2_ERRIE) |
208                         (0 << STM_SPI_CR2_SSOE) |
209                         (0 << STM_SPI_CR2_TXDMAEN) |
210                         (0 << STM_SPI_CR2_RXDMAEN));
211
212         /* Clear RXNE */
213         (void) stm_spi->dr;
214
215         while (len--) {
216                 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
217                 stm_spi->dr = *b++;
218         }
219 }
220
221 void
222 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
223 {
224         struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
225         uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
226         uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
227
228         spi_dev_null = 0xff;
229
230         /* Set up transmit DMA to make the SPI hardware actually run */
231         ao_dma_set_transfer(mosi_dma_index,
232                             &stm_spi->dr,
233                             &spi_dev_null,
234                             len,
235                             (0 << STM_DMA_CCR_MEM2MEM) |
236                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
237                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
238                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
239                             (0 << STM_DMA_CCR_MINC) |
240                             (0 << STM_DMA_CCR_PINC) |
241                             (0 << STM_DMA_CCR_CIRC) |
242                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
243
244         /* Clear RXNE */
245         (void) stm_spi->dr;
246
247         /* Set up the receive DMA to capture data */
248         ao_dma_set_transfer(miso_dma_index,
249                             &stm_spi->dr,
250                             block,
251                             len,
252                             (0 << STM_DMA_CCR_MEM2MEM) |
253                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
254                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
255                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
256                             (1 << STM_DMA_CCR_MINC) |
257                             (0 << STM_DMA_CCR_PINC) |
258                             (0 << STM_DMA_CCR_CIRC) |
259                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
260
261         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
262                         (0 << STM_SPI_CR2_RXNEIE) |
263                         (0 << STM_SPI_CR2_ERRIE) |
264                         (0 << STM_SPI_CR2_SSOE) |
265                         (1 << STM_SPI_CR2_TXDMAEN) |
266                         (1 << STM_SPI_CR2_RXDMAEN));
267         ao_dma_start(miso_dma_index);
268         ao_dma_start(mosi_dma_index);
269
270         /* Wait until the SPI unit is done */
271         ao_arch_critical(
272                 while (!ao_dma_done[miso_dma_index])
273                         ao_sleep(&ao_dma_done[miso_dma_index]);
274                 );
275
276         ao_dma_done_transfer(mosi_dma_index);
277         ao_dma_done_transfer(miso_dma_index);
278 }
279
280 void
281 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
282 {
283         struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
284         uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
285         uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
286
287         /* Set up transmit DMA to send data */
288         ao_dma_set_transfer(mosi_dma_index,
289                             &stm_spi->dr,
290                             out,
291                             len,
292                             (0 << STM_DMA_CCR_MEM2MEM) |
293                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
294                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
295                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
296                             (1 << STM_DMA_CCR_MINC) |
297                             (0 << STM_DMA_CCR_PINC) |
298                             (0 << STM_DMA_CCR_CIRC) |
299                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
300
301         /* Clear RXNE */
302         (void) stm_spi->dr;
303
304         /* Set up the receive DMA to capture data */
305         ao_dma_set_transfer(miso_dma_index,
306                             &stm_spi->dr,
307                             in,
308                             len,
309                             (0 << STM_DMA_CCR_MEM2MEM) |
310                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
311                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
312                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
313                             (1 << STM_DMA_CCR_MINC) |
314                             (0 << STM_DMA_CCR_PINC) |
315                             (0 << STM_DMA_CCR_CIRC) |
316                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
317
318         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
319                         (0 << STM_SPI_CR2_RXNEIE) |
320                         (0 << STM_SPI_CR2_ERRIE) |
321                         (0 << STM_SPI_CR2_SSOE) |
322                         (1 << STM_SPI_CR2_TXDMAEN) |
323                         (1 << STM_SPI_CR2_RXDMAEN));
324         ao_dma_start(miso_dma_index);
325         ao_dma_start(mosi_dma_index);
326
327         /* Wait until the SPI unit is done */
328         ao_arch_critical(
329                 while (!ao_dma_done[miso_dma_index])
330                         ao_sleep(&ao_dma_done[miso_dma_index]);
331                 );
332
333         ao_dma_done_transfer(mosi_dma_index);
334         ao_dma_done_transfer(miso_dma_index);
335 }
336
337 static void
338 ao_spi_disable_index(uint8_t spi_index)
339 {
340         /* Disable current config
341          */
342         switch (AO_SPI_INDEX(spi_index)) {
343         case STM_SPI_INDEX(1):
344                 switch (spi_index) {
345                 case AO_SPI_1_PA5_PA6_PA7:
346                         stm_gpio_set(&stm_gpioa, 5, 1);
347                         stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
348                         stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
349                         stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
350                         break;
351                 case AO_SPI_1_PB3_PB4_PB5:
352                         stm_gpio_set(&stm_gpiob, 3, 1);
353                         stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
354                         stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
355                         stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
356                         break;
357                 case AO_SPI_1_PE13_PE14_PE15:
358                         stm_gpio_set(&stm_gpioe, 13, 1);
359                         stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
360                         stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
361                         stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
362                         break;
363                 }
364                 break;
365         case STM_SPI_INDEX(2):
366                 switch (spi_index) {
367                 case AO_SPI_2_PB13_PB14_PB15:
368                         stm_gpio_set(&stm_gpiob, 13, 1);
369                         stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
370                         stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
371                         stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
372                         break;
373                 case AO_SPI_2_PD1_PD3_PD4:
374                         stm_gpio_set(&stm_gpiod, 1, 1);
375                         stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
376                         stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
377                         stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
378                         break;
379                 }
380                 break;
381         }
382 }
383
384 static void
385 ao_spi_enable_index(uint8_t spi_index)
386 {
387         switch (AO_SPI_INDEX(spi_index)) {
388         case STM_SPI_INDEX(1):
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                 }
406                 break;
407         case STM_SPI_INDEX(2):
408                 switch (spi_index) {
409                 case AO_SPI_2_PB13_PB14_PB15:
410                         stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
411                         stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
412                         stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
413                         break;
414                 case AO_SPI_2_PD1_PD3_PD4:
415                         stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
416                         stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
417                         stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
418                         break;
419                 }
420                 break;
421         }
422 }
423
424 static void
425 ao_spi_config(uint8_t spi_index, uint32_t speed)
426 {
427         uint8_t         id = AO_SPI_INDEX(spi_index);
428         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
429         stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |                   /* Three wire mode */
430                         (0 << STM_SPI_CR1_BIDIOE) |
431                         (0 << STM_SPI_CR1_CRCEN) |                      /* CRC disabled */
432                         (0 << STM_SPI_CR1_CRCNEXT) |
433                         (0 << STM_SPI_CR1_DFF) |
434                         (0 << STM_SPI_CR1_RXONLY) |
435                         (1 << STM_SPI_CR1_SSM) |                        /* Software SS handling */
436                         (1 << STM_SPI_CR1_SSI) |                        /*  ... */
437                         (0 << STM_SPI_CR1_LSBFIRST) |                   /* Big endian */
438                         (1 << STM_SPI_CR1_SPE) |                        /* Enable SPI unit */
439                         (speed << STM_SPI_CR1_BR) |     /* baud rate to pclk/4 */
440                         (1 << STM_SPI_CR1_MSTR) |
441                         (0 << STM_SPI_CR1_CPOL) |                       /* Format 0 */
442                         (0 << STM_SPI_CR1_CPHA));
443         if (spi_index != ao_spi_index[id]) {
444
445                 /* Disable old config
446                  */
447                 ao_spi_disable_index(ao_spi_index[id]);
448
449                 /* Enable new config
450                  */
451                 ao_spi_enable_index(spi_index);
452
453                 /* Remember current config
454                  */
455                 ao_spi_index[id] = spi_index;
456         }
457 }
458
459 uint8_t
460 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
461 {
462         uint8_t         id = AO_SPI_INDEX(spi_index);
463
464         if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
465                 return 0;
466         ao_spi_config(spi_index, speed);
467         return 1;
468 }
469
470 void
471 ao_spi_get(uint8_t spi_index, uint32_t speed)
472 {
473         uint8_t         id = AO_SPI_INDEX(spi_index);
474         ao_mutex_get(&ao_spi_mutex[id]);
475         ao_spi_config(spi_index, speed);
476 }
477
478 void
479 ao_spi_put(uint8_t spi_index)
480 {
481         uint8_t         id = AO_SPI_INDEX(spi_index);
482         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
483
484         stm_spi->cr1 = 0;
485         ao_mutex_put(&ao_spi_mutex[id]);
486 }
487
488 static void
489 ao_spi_channel_init(uint8_t spi_index)
490 {
491         uint8_t         id = AO_SPI_INDEX(spi_index);
492         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
493
494         ao_spi_disable_index(spi_index);
495
496         stm_spi->cr1 = 0;
497         (void) stm_spi->sr;
498         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
499                         (0 << STM_SPI_CR2_RXNEIE) |
500                         (0 << STM_SPI_CR2_ERRIE) |
501                         (0 << STM_SPI_CR2_SSOE) |
502                         (0 << STM_SPI_CR2_TXDMAEN) |
503                         (0 << STM_SPI_CR2_RXDMAEN));
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 }