altos/stm32l0: Add casts to reduce -Wconversion warnings
[fw/altos] / src / stm32l0 / ao_spi_stm32l0.c
1 /*
2  * Copyright © 2020 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 static uint8_t          ao_spi_mutex;
22 static uint8_t          ao_spi_pin_config;
23
24 #define AO_DMA_SPI1_RX_INDEX    STM_DMA_INDEX(2)
25 #define AO_DMA_SPI1_RX_CSELR    STM_DMA_CSELR_C2S_SPI1_RX
26 #define AO_DMA_SPI1_TX_INDEX    STM_DMA_INDEX(3)
27 #define AO_DMA_SPI1_TX_CSELR    STM_DMA_CSELR_C3S_SPI1_TX
28
29 #if 0
30 static uint8_t  spi_dev_null;
31
32 static void
33 ao_spi_set_dma_mosi(uint8_t id, const void *data, uint16_t len, uint32_t minc)
34 {
35         (void) id;
36         struct stm_spi *stm_spi = &stm_spi1;
37
38         ao_dma_set_transfer(AO_DMA_SPI1_TX_INDEX,
39                             &stm_spi->dr,
40                             (void *) data,
41                             len,
42                             (0 << STM_DMA_CCR_MEM2MEM) |
43                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
44                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
45                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
46                             (minc << STM_DMA_CCR_MINC) |
47                             (0 << STM_DMA_CCR_PINC) |
48                             (0 << STM_DMA_CCR_CIRC) |
49                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
50 }
51
52 static void
53 ao_spi_set_dma_miso(uint8_t id, void *data, uint16_t len, uint32_t minc)
54 {
55         (void) id;
56         uint8_t miso_dma_index = STM_DMA_INDEX(2);
57         struct stm_spi *stm_spi = &stm_spi1;
58
59         ao_dma_set_transfer(miso_dma_index,
60                             &stm_spi->dr,
61                             data,
62                             len,
63                             (0 << STM_DMA_CCR_MEM2MEM) |
64                             (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) |
65                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
66                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
67                             (minc << STM_DMA_CCR_MINC) |
68                             (0 << STM_DMA_CCR_PINC) |
69                             (0 << STM_DMA_CCR_CIRC) |
70                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
71 }
72
73 static void
74 ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
75 {
76         (void) id;
77         uint8_t mosi_dma_index = STM_DMA_INDEX(3);
78         uint8_t miso_dma_index = STM_DMA_INDEX(2);
79         struct stm_spi *stm_spi = &stm_spi1;
80
81         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
82                         (0 << STM_SPI_CR2_RXNEIE) |
83                         (0 << STM_SPI_CR2_ERRIE) |
84                         (0 << STM_SPI_CR2_SSOE) |
85                         (1 << STM_SPI_CR2_TXDMAEN) |
86                         (1 << STM_SPI_CR2_RXDMAEN));
87
88         ao_dma_start(miso_dma_index);
89         ao_dma_start(mosi_dma_index);
90
91         ao_arch_critical(
92                 while (!ao_dma_done[miso_dma_index])
93                         ao_sleep(&ao_dma_done[miso_dma_index]);
94                 );
95
96         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
97         while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
98
99         stm_spi->cr2 = 0;
100
101         ao_dma_done_transfer(mosi_dma_index);
102         ao_dma_done_transfer(miso_dma_index);
103 }
104 #endif
105
106 void
107 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
108 {
109         (void) spi_index;
110 #if 0
111         /* Set up the transmit DMA to deliver data */
112         ao_spi_set_dma_mosi(id, block, len, 1);
113
114         /* Set up the receive DMA -- when this is done, we know the SPI unit
115          * is idle. Without this, we'd have to poll waiting for the BSY bit to
116          * be cleared
117          */
118         ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
119
120         ao_spi_run(id, 1, len);
121 #else
122         const uint8_t *bytes = block;
123         struct stm_spi *stm_spi = &stm_spi1;
124
125         while (len--) {
126                 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
127                 stm_spi->dr = *bytes++;
128                 while ((stm_spi->sr & (1 << STM_SPI_SR_RXNE)) == 0);
129                 (void) stm_spi->dr;
130         }
131 #endif
132 }
133
134 #if 0
135 void
136 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
137 {
138         uint8_t id = AO_SPI_INDEX(spi_index);
139
140         /* Set up the transmit DMA to deliver data */
141         ao_spi_set_dma_mosi(id, &value, len, 0);
142
143         /* Set up the receive DMA -- when this is done, we know the SPI unit
144          * is idle. Without this, we'd have to poll waiting for the BSY bit to
145          * be cleared
146          */
147         ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
148
149         ao_spi_run(id, 3, len);
150 }
151
152 void
153 ao_spi_start_bytes(uint8_t spi_index)
154 {
155         (void) spi_index;
156         struct stm_spi *stm_spi = &stm_spi1;
157
158         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
159                         (0 << STM_SPI_CR2_RXNEIE) |
160                         (0 << STM_SPI_CR2_ERRIE) |
161                         (0 << STM_SPI_CR2_SSOE) |
162                         (0 << STM_SPI_CR2_TXDMAEN) |
163                         (0 << STM_SPI_CR2_RXDMAEN));
164 }
165
166 void
167 ao_spi_stop_bytes(uint8_t spi_index)
168 {
169         (void) spi_index;
170         struct stm_spi *stm_spi = &stm_spi1;
171
172         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
173                 ;
174         while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
175                 ;
176         /* Clear the OVR flag */
177         (void) stm_spi->dr;
178         (void) stm_spi->sr;
179         stm_spi->cr2 = 0;
180 }
181
182 void
183 ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
184 {
185         (void) spi_index;
186         const uint8_t   *b = block;
187         struct stm_spi  *stm_spi = &stm_spi1;
188
189         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
190                         (0 << STM_SPI_CR2_RXNEIE) |
191                         (0 << STM_SPI_CR2_ERRIE) |
192                         (0 << STM_SPI_CR2_SSOE) |
193                         (0 << STM_SPI_CR2_TXDMAEN) |
194                         (0 << STM_SPI_CR2_RXDMAEN));
195         while (len--) {
196                 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
197                 stm_spi->dr = *b++;
198         }
199         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
200                 ;
201         while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
202                 ;
203         /* Clear the OVR flag */
204         (void) stm_spi->dr;
205         (void) stm_spi->sr;
206 }
207 #endif
208
209 void
210 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
211 {
212         (void) spi_index;
213 #if 0
214
215         spi_dev_null = 0xff;
216
217         /* Set up transmit DMA to make the SPI hardware actually run */
218         ao_spi_set_dma_mosi(id, &spi_dev_null, len, 0);
219
220         /* Set up the receive DMA to capture data */
221         ao_spi_set_dma_miso(id, block, len, 1);
222
223         ao_spi_run(id, 9, len);
224 #else
225         uint8_t *bytes = block;
226         struct stm_spi *stm_spi = &stm_spi1;
227
228         while (len--) {
229                 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
230                 stm_spi->dr = 0xff;
231                 while ((stm_spi->sr & (1 << STM_SPI_SR_RXNE)) == 0);
232                 *bytes++ = (uint8_t) stm_spi->dr;
233         }
234 #endif
235 }
236
237 #if 0
238 void
239 ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index)
240 {
241         uint8_t         id = AO_SPI_INDEX(spi_index);
242
243         /* Set up transmit DMA to send data */
244         ao_spi_set_dma_mosi(id, out, len, 1);
245
246         /* Set up the receive DMA to capture data */
247         ao_spi_set_dma_miso(id, in, len, 1);
248
249         ao_spi_run(id, 11, len);
250 }
251 #endif
252
253 static void
254 ao_spi_disable_pin_config(uint8_t spi_pin_config)
255 {
256         /* Disable current config
257          */
258         switch (spi_pin_config) {
259         case AO_SPI_1_PA5_PA6_PA7:
260                 stm_gpio_set(&stm_gpioa, 5, 1);
261                 stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
262                 stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
263                 stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
264                 break;
265         case AO_SPI_1_PA12_PA13_PA14:
266                 stm_gpio_set(&stm_gpioa, 13, 1);
267                 stm_moder_set(&stm_gpioa, 13, STM_MODER_OUTPUT);        /* clk */
268                 stm_moder_set(&stm_gpioa, 12, STM_MODER_OUTPUT);        /* mosi */
269                 stm_moder_set(&stm_gpioa, 14, STM_MODER_INPUT);         /* miso */
270                 break;
271         case AO_SPI_1_PB3_PB4_PB5:
272                 stm_gpio_set(&stm_gpiob, 3, 1);
273                 stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
274                 stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
275                 stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
276                 break;
277         }
278 }
279
280 static void
281 ao_spi_enable_pin_config(uint8_t spi_pin_config)
282 {
283         /* Enable new config
284          */
285         switch (spi_pin_config) {
286         case AO_SPI_1_PA5_PA6_PA7:
287                 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
288                 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
289                 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
290                 break;
291         case AO_SPI_1_PA12_PA13_PA14:
292                 stm_afr_set(&stm_gpioe, 12, STM_AFR_AF0);       /* yes, AF0 */
293                 stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
294                 stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
295                 break;
296         case AO_SPI_1_PB3_PB4_PB5:
297                 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
298                 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
299                 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
300                 break;
301         }
302 }
303
304 static void
305 ao_spi_config(uint8_t spi_index, uint32_t speed)
306 {
307         uint8_t         spi_pin_config = AO_SPI_PIN_CONFIG(spi_index);
308         struct stm_spi  *stm_spi = &stm_spi1;
309
310         if (spi_pin_config != ao_spi_pin_config) {
311
312                 /* Disable old config
313                  */
314                 ao_spi_disable_pin_config(ao_spi_pin_config);
315
316                 /* Enable new config
317                  */
318                 ao_spi_enable_pin_config(spi_pin_config);
319
320                 /* Remember current config
321                  */
322                 ao_spi_pin_config = spi_pin_config;
323         }
324
325         /* Turn the SPI transceiver on and set the mode */
326         stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |           /* Three wire mode */
327                         (0 << STM_SPI_CR1_BIDIOE) |
328                         (0 << STM_SPI_CR1_CRCEN) |              /* CRC disabled */
329                         (0 << STM_SPI_CR1_CRCNEXT) |
330                         (0 << STM_SPI_CR1_DFF) |
331                         (0 << STM_SPI_CR1_RXONLY) |
332                         (1 << STM_SPI_CR1_SSM) |                /* Software SS handling */
333                         (1 << STM_SPI_CR1_SSI) |                /*  ... */
334                         (0 << STM_SPI_CR1_LSBFIRST) |           /* Big endian */
335                         (1 << STM_SPI_CR1_SPE) |                /* Enable SPI unit */
336                         (speed << STM_SPI_CR1_BR) |             /* baud rate to pclk/4 */
337                         (1 << STM_SPI_CR1_MSTR) |
338                         (AO_SPI_CPOL(spi_index) << STM_SPI_CR1_CPOL) |  /* Format */
339                         (AO_SPI_CPHA(spi_index) << STM_SPI_CR1_CPHA));
340 }
341
342 #if HAS_TASK
343 uint8_t
344 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
345 {
346         uint8_t         id = AO_SPI_INDEX(spi_index);
347
348         if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
349                 return 0;
350         ao_spi_config(spi_index, speed);
351         return 1;
352 }
353 #endif
354
355 void
356 ao_spi_get(uint8_t spi_index, uint32_t speed)
357 {
358         (void) spi_index;
359
360         ao_mutex_get(&ao_spi_mutex);
361         ao_spi_config(spi_index, speed);
362 }
363
364 void
365 ao_spi_put(uint8_t spi_index)
366 {
367         (void) spi_index;
368         struct stm_spi  *stm_spi = &stm_spi1;
369
370         stm_spi->cr1 = 0;
371         ao_mutex_put(&ao_spi_mutex);
372 }
373
374 static void
375 ao_spi_channel_init(uint8_t spi_index)
376 {
377         (void) spi_index;
378         struct stm_spi  *stm_spi = &stm_spi1;
379
380         ao_spi_disable_pin_config(AO_SPI_PIN_CONFIG(spi_index));
381
382         stm_spi->cr1 = 0;
383         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
384                         (0 << STM_SPI_CR2_RXNEIE) |
385                         (0 << STM_SPI_CR2_ERRIE) |
386                         (0 << STM_SPI_CR2_SSOE) |
387                         (0 << STM_SPI_CR2_TXDMAEN) |
388                         (0 << STM_SPI_CR2_RXDMAEN));
389
390         /* Clear any pending data and error flags */
391         (void) stm_spi->dr;
392         (void) stm_spi->sr;
393 }
394
395 #if DEBUG
396 void
397 ao_spi_dump_cmd(void)
398 {
399         int s;
400
401         for (s = 0; s < 64; s++) {
402                 int i = (spi_task_index + s) & 63;
403                 if (spi_tasks[i].which) {
404                         int t;
405                         const char *name = "(none)";
406                         for (t = 0; t < ao_num_tasks; t++)
407                                 if (ao_tasks[t]->task_id == spi_tasks[i].task) {
408                                         name = ao_tasks[t]->name;
409                                         break;
410                                 }
411                         printf("%2d: %5d task %2d which %2d len %5d %s\n",
412                                s,
413                                spi_tasks[i].tick,
414                                spi_tasks[i].task,
415                                spi_tasks[i].which,
416                                spi_tasks[i].len,
417                                name);
418                 }
419         }
420         for (s = 0; s < STM_NUM_SPI; s++) {
421                 struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
422
423                 printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
424                        s, ao_spi_mutex[s], ao_spi_index[s],
425                        ao_spi_stm_info[s].miso_dma_index,
426                        ao_spi_stm_info[s].mosi_dma_index);
427                 printf(" cr1 %04x cr2 %02x sr %03x\n",
428                        spi->cr1, spi->cr2, spi->sr);
429         }
430
431 }
432
433 static const struct ao_cmds ao_spi_cmds[] = {
434         { ao_spi_dump_cmd,      "S\0Dump SPI status" },
435         { 0, NULL }
436 };
437 #endif
438
439 void
440 ao_spi_init(void)
441 {
442 #if HAS_SPI_1
443 # if SPI_1_PA5_PA6_PA7
444         ao_enable_port(&stm_gpioa);
445         stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
446         stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
447         stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
448 # endif
449 # if SPI_1_PB3_PB4_PB5
450         ao_enable_port(&stm_gpiob);
451         stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
452         stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
453         stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
454 # endif
455 # if SPI_1_PE13_PE14_PE15
456         ao_enable_port(&stm_gpioe);
457         stm_ospeedr_set(&stm_gpioe, 13, SPI_1_OSPEEDR);
458         stm_ospeedr_set(&stm_gpioe, 14, SPI_1_OSPEEDR);
459         stm_ospeedr_set(&stm_gpioe, 15, SPI_1_OSPEEDR);
460 # endif
461         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
462         ao_spi_pin_config = AO_SPI_CONFIG_NONE;
463         ao_spi_channel_init(0);
464 #if 0
465         ao_dma_alloc(AO_DMA_SPI1_RX_INDEX, AO_DMA_SPI1_RX_CSELR);
466         ao_dma_alloc(AO_DMA_SPI1_TX_INDEX, AO_DMA_SPI1_TX_CSELR);
467 #endif
468 #endif
469
470 #if HAS_SPI_2
471 # if SPI_2_PB13_PB14_PB15
472         ao_enable_port(&stm_gpiob);
473         stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
474         stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
475         stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
476 # define HAS_SPI_2_CONFIG 1
477 # endif
478 # if SPI_2_PD1_PD3_PD4
479         ao_enable_port(&stm_gpiod);
480         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
481         stm_ospeedr_set(&stm_gpiod, 1, SPI_2_OSPEEDR);
482         stm_ospeedr_set(&stm_gpiod, 3, SPI_2_OSPEEDR);
483         stm_ospeedr_set(&stm_gpiod, 4, SPI_2_OSPEEDR);
484 # define HAS_SPI_2_CONFIG 1
485 # endif
486 # ifndef HAS_SPI_2_CONFIG 1
487         #error "no config for SPI2"
488 # endif
489         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
490         ao_spi_pin_config[1] = AO_SPI_CONFIG_NONE;
491         ao_spi_channel_init(1);
492         ao_dma_alloc(AO_DMA_SPI2_RX_INDEX, AO_DMA_SPI2_RX_CSELR);
493         ao_dma_alloc(AO_DMA_SPI2_TX_INDEX, AO_DMA_SPI2_TX_CSELR);
494 #endif
495 #if DEBUG
496         ao_cmd_register(&ao_spi_cmds[0]);
497 #endif
498 }