2 * Copyright © 2016 Keith Packard <keithp@keithp.com>
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.
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.
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.
21 struct ao_spi_stm_info {
22 uint8_t miso_dma_index;
23 uint8_t mosi_dma_index;
24 struct stm_spi *stm_spi;
27 static uint8_t ao_spi_mutex[STM_NUM_SPI];
28 static uint8_t ao_spi_index[STM_NUM_SPI];
30 static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
32 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
33 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
37 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
38 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
43 static uint8_t spi_dev_null;
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))
56 #define SPI_CR2_DMA (SPI_CR2 | \
57 (1 << STM_SPI_CR2_TXDMAEN) | \
58 (1 << STM_SPI_CR2_RXDMAEN))
60 #define SPI_CR2_SYNC (SPI_CR2 | \
61 (0 << STM_SPI_CR2_TXDMAEN) | \
62 (0 << STM_SPI_CR2_RXDMAEN))
71 static uint8_t spi_task_index;
74 validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
76 uint32_t sr = stm_spi->sr;
78 if (stm_spi != &stm_spi2)
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))
87 if (sr & (1 << STM_SPI_SR_BSY))
89 if (sr & (1 << STM_SPI_SR_OVR))
91 if (sr & (1 << STM_SPI_SR_MODF))
93 if (sr & (1 << STM_SPI_SR_UDR))
95 if ((sr & (1 << STM_SPI_SR_TXE)) == 0)
97 if (sr & (1 << STM_SPI_SR_RXNE))
99 if (which != 5 && which != 6 && which != 13)
100 if (ao_cur_task->task_id != ao_spi_mutex[1])
104 #define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
108 ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
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;
114 validate_spi(stm_spi, which, len);
116 stm_spi->cr2 = SPI_CR2_DMA;
118 ao_dma_start(miso_dma_index);
119 ao_dma_start(mosi_dma_index);
122 while (!ao_dma_done[miso_dma_index])
123 ao_sleep(&ao_dma_done[miso_dma_index]);
126 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
127 while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
129 validate_spi(stm_spi, which+1, len);
133 ao_dma_done_transfer(mosi_dma_index);
134 ao_dma_done_transfer(miso_dma_index);
138 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
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;
145 /* Set up the transmit DMA to deliver data */
146 ao_dma_set_transfer(mosi_dma_index,
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));
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
164 ao_dma_set_transfer(miso_dma_index,
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));
178 ao_spi_run(id, 1, len);
182 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
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;
189 /* Set up the transmit DMA to deliver data */
190 ao_dma_set_transfer(mosi_dma_index,
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));
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
208 ao_dma_set_transfer(miso_dma_index,
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));
222 ao_spi_run(id, 3, len);
226 ao_spi_start_bytes(uint8_t spi_index)
228 uint8_t id = AO_SPI_INDEX(spi_index);
229 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
231 stm_spi->cr2 = SPI_CR2_SYNC;
232 validate_spi(stm_spi, 5, 0xffff);
236 ao_spi_stop_bytes(uint8_t spi_index)
238 uint8_t id = AO_SPI_INDEX(spi_index);
239 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
241 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
243 while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
245 /* Clear the OVR flag */
248 validate_spi(stm_spi, 6, 0xffff);
253 ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
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;
259 stm_spi->cr2 = SPI_CR2_SYNC;
261 validate_spi(stm_spi, 7, len);
263 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
266 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
268 while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
270 /* Clear the OVR flag */
273 validate_spi(stm_spi, 8, len);
277 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
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;
286 /* Set up transmit DMA to make the SPI hardware actually run */
287 ao_dma_set_transfer(mosi_dma_index,
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));
301 /* Set up the receive DMA to capture data */
302 ao_dma_set_transfer(miso_dma_index,
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));
316 ao_spi_run(id, 9, len);
320 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
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;
327 /* Set up transmit DMA to send data */
328 ao_dma_set_transfer(mosi_dma_index,
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));
342 /* Set up the receive DMA to capture data */
343 ao_dma_set_transfer(miso_dma_index,
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));
357 ao_spi_run(id, 11, len);
361 ao_spi_disable_index(uint8_t spi_index)
363 /* Disable current 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);
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);
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);
388 ao_spi_enable_index(uint8_t spi_index)
391 case AO_SPI_1_PA5_PA6_PA7:
392 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
393 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
394 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
396 case AO_SPI_1_PB3_PB4_PB5:
397 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
398 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
399 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
401 case AO_SPI_2_PB13_PB14_PB15:
402 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0);
403 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0);
404 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0);
410 ao_spi_config(uint8_t spi_index, uint32_t speed)
412 uint8_t id = AO_SPI_INDEX(spi_index);
413 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
415 if (spi_index != ao_spi_index[id]) {
417 /* Disable old config
419 ao_spi_disable_index(ao_spi_index[id]);
423 ao_spi_enable_index(spi_index);
425 /* Remember current config
427 ao_spi_index[id] = spi_index;
429 stm_spi->cr2 = SPI_CR2;
430 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
431 (0 << STM_SPI_CR1_BIDIOE) |
432 (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
433 (0 << STM_SPI_CR1_CRCNEXT) |
434 (0 << STM_SPI_CR1_CRCL) |
435 (0 << STM_SPI_CR1_RXONLY) |
436 (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
437 (1 << STM_SPI_CR1_SSI) | /* ... */
438 (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
439 (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
440 (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
441 (1 << STM_SPI_CR1_MSTR) |
442 (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
443 (0 << STM_SPI_CR1_CPHA));
447 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
449 uint8_t id = AO_SPI_INDEX(spi_index);
451 if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
453 ao_spi_config(spi_index, speed);
458 ao_spi_get(uint8_t spi_index, uint32_t speed)
460 uint8_t id = AO_SPI_INDEX(spi_index);
461 ao_mutex_get(&ao_spi_mutex[id]);
462 ao_spi_config(spi_index, speed);
466 ao_spi_put(uint8_t spi_index)
468 uint8_t id = AO_SPI_INDEX(spi_index);
469 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
472 ao_mutex_put(&ao_spi_mutex[id]);
476 ao_spi_channel_init(uint8_t spi_index)
478 uint8_t id = AO_SPI_INDEX(spi_index);
479 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
481 ao_spi_disable_index(spi_index);
484 stm_spi->cr2 = SPI_CR2_SYNC;
486 /* Clear any pending data and error flags */
493 ao_spi_dump_cmd(void)
497 for (s = 0; s < 64; s++) {
498 int i = (spi_task_index + s) & 63;
499 if (spi_tasks[i].which) {
501 const char *name = "(none)";
502 for (t = 0; t < ao_num_tasks; t++)
503 if (ao_tasks[t]->task_id == spi_tasks[i].task) {
504 name = ao_tasks[t]->name;
507 printf("%2d: %5d task %2d which %2d len %5d %s\n",
516 for (s = 0; s < STM_NUM_SPI; s++) {
517 struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
519 printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
520 s, ao_spi_mutex[s], ao_spi_index[s],
521 ao_spi_stm_info[s].miso_dma_index,
522 ao_spi_stm_info[s].mosi_dma_index);
523 printf(" cr1 %04x cr2 %02x sr %03x\n",
524 spi->cr1, spi->cr2, spi->sr);
529 static const struct ao_cmds ao_spi_cmds[] = {
530 { ao_spi_dump_cmd, "S\0Dump SPI status" },
539 #ifndef SPI_1_PA5_PA6_PA7
540 #error SPI_1_PA5_PA6_PA7 undefined
542 # if SPI_1_PA5_PA6_PA7
543 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
544 stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
545 stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
546 stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
548 # ifndef SPI_1_PB3_PB4_PB5
549 # error SPI_1_PB3_PB4_PB5 undefined
551 # if SPI_1_PB3_PB4_PB5
552 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
553 stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
554 stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
555 stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
557 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
558 ao_spi_index[0] = AO_SPI_CONFIG_NONE;
559 ao_spi_channel_init(STM_SPI_INDEX(1));
563 # if SPI_2_PB10_PB13_PB14
564 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
565 stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
566 stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
567 stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
569 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
570 ao_spi_index[1] = AO_SPI_CONFIG_NONE;
571 ao_spi_channel_init(STM_SPI_INDEX(2));
574 ao_cmd_register(&ao_spi_cmds[0]);