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;
47 #define SPI_CR2 ((0 << STM_SPI_CR2_LDMA_TX) | \
48 (0 << STM_SPI_CR2_LDMA_RX) | \
49 (1 << STM_SPI_CR2_FRXTH) | \
50 (STM_SPI_CR2_DS_8 << STM_SPI_CR2_DS) | \
51 (0 << STM_SPI_CR2_TXEIE) | \
52 (0 << STM_SPI_CR2_RXNEIE) | \
53 (0 << STM_SPI_CR2_ERRIE) | \
54 (STM_SPI_CR2_FRF_MOTOROLA << STM_SPI_CR2_FRF) | \
55 (0 << STM_SPI_CR2_NSSP) | \
56 (0 << STM_SPI_CR2_SSOE))
58 #define SPI_CR2_DMA (SPI_CR2 | \
59 (1 << STM_SPI_CR2_TXDMAEN) | \
60 (1 << STM_SPI_CR2_RXDMAEN))
62 #define SPI_CR2_SYNC (SPI_CR2 | \
63 (0 << STM_SPI_CR2_TXDMAEN) | \
64 (0 << STM_SPI_CR2_RXDMAEN))
67 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
69 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
70 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
71 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
73 /* Set up the transmit DMA to deliver data */
74 ao_dma_set_transfer(mosi_dma_index,
78 (0 << STM_DMA_CCR_MEM2MEM) |
79 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
80 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
81 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
82 (1 << STM_DMA_CCR_MINC) |
83 (0 << STM_DMA_CCR_PINC) |
84 (0 << STM_DMA_CCR_CIRC) |
85 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
86 (0 << STM_DMA_CCR_TCIE));
91 /* Set up the receive DMA -- when this is done, we know the SPI unit
92 * is idle. Without this, we'd have to poll waiting for the BSY bit to
95 ao_dma_set_transfer(miso_dma_index,
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 (0 << STM_DMA_CCR_MINC) |
104 (0 << STM_DMA_CCR_PINC) |
105 (0 << STM_DMA_CCR_CIRC) |
106 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
107 (1 << STM_DMA_CCR_TCIE));
109 stm_spi->cr2 = SPI_CR2_DMA;
111 ao_dma_start(miso_dma_index);
112 ao_dma_start(mosi_dma_index);
114 while (!ao_dma_done[miso_dma_index])
115 ao_sleep(&ao_dma_done[miso_dma_index]);
117 ao_dma_done_transfer(mosi_dma_index);
118 ao_dma_done_transfer(miso_dma_index);
122 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
124 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
125 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
126 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
128 /* Set up the transmit DMA to deliver data */
129 ao_dma_set_transfer(mosi_dma_index,
133 (0 << STM_DMA_CCR_MEM2MEM) |
134 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
135 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
136 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
137 (0 << STM_DMA_CCR_MINC) |
138 (0 << STM_DMA_CCR_PINC) |
139 (0 << STM_DMA_CCR_CIRC) |
140 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
141 (0 << STM_DMA_CCR_TCIE));
146 /* Set up the receive DMA -- when this is done, we know the SPI unit
147 * is idle. Without this, we'd have to poll waiting for the BSY bit to
150 ao_dma_set_transfer(miso_dma_index,
154 (0 << STM_DMA_CCR_MEM2MEM) |
155 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
156 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
157 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
158 (0 << STM_DMA_CCR_MINC) |
159 (0 << STM_DMA_CCR_PINC) |
160 (0 << STM_DMA_CCR_CIRC) |
161 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
162 (1 << STM_DMA_CCR_TCIE));
164 stm_spi->cr2 = SPI_CR2_DMA;
165 ao_dma_start(miso_dma_index);
166 ao_dma_start(mosi_dma_index);
168 while (!ao_dma_done[miso_dma_index])
169 ao_sleep(&ao_dma_done[miso_dma_index]);
171 ao_dma_done_transfer(mosi_dma_index);
172 ao_dma_done_transfer(miso_dma_index);
176 ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index)
179 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
181 stm_spi->cr2 = SPI_CR2_SYNC;
187 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
193 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
195 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
196 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
197 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
201 /* Set up transmit DMA to make the SPI hardware actually run */
202 ao_dma_set_transfer(mosi_dma_index,
206 (0 << STM_DMA_CCR_MEM2MEM) |
207 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
208 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
209 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
210 (0 << STM_DMA_CCR_MINC) |
211 (0 << STM_DMA_CCR_PINC) |
212 (0 << STM_DMA_CCR_CIRC) |
213 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
214 (0 << STM_DMA_CCR_TCIE));
219 /* Set up the receive DMA to capture data */
220 ao_dma_set_transfer(miso_dma_index,
224 (0 << STM_DMA_CCR_MEM2MEM) |
225 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
226 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
227 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
228 (1 << STM_DMA_CCR_MINC) |
229 (0 << STM_DMA_CCR_PINC) |
230 (0 << STM_DMA_CCR_CIRC) |
231 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
232 (1 << STM_DMA_CCR_TCIE));
234 stm_spi->cr2 = SPI_CR2_DMA;
235 ao_dma_start(miso_dma_index);
236 ao_dma_start(mosi_dma_index);
238 /* Wait until the SPI unit is done */
240 while (!ao_dma_done[miso_dma_index])
241 ao_sleep(&ao_dma_done[miso_dma_index]);
244 ao_dma_done_transfer(mosi_dma_index);
245 ao_dma_done_transfer(miso_dma_index);
249 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
251 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
252 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
253 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
255 /* Set up transmit DMA to send data */
256 ao_dma_set_transfer(mosi_dma_index,
260 (0 << STM_DMA_CCR_MEM2MEM) |
261 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
262 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
263 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
264 (1 << STM_DMA_CCR_MINC) |
265 (0 << STM_DMA_CCR_PINC) |
266 (0 << STM_DMA_CCR_CIRC) |
267 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
268 (0 << STM_DMA_CCR_TCIE));
273 /* Set up the receive DMA to capture data */
274 ao_dma_set_transfer(miso_dma_index,
278 (0 << STM_DMA_CCR_MEM2MEM) |
279 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
280 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
281 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
282 (1 << STM_DMA_CCR_MINC) |
283 (0 << STM_DMA_CCR_PINC) |
284 (0 << STM_DMA_CCR_CIRC) |
285 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
286 (1 << STM_DMA_CCR_TCIE));
288 stm_spi->cr2 = SPI_CR2_DMA;
289 ao_dma_start(miso_dma_index);
290 ao_dma_start(mosi_dma_index);
292 /* Wait until the SPI unit is done */
294 while (!ao_dma_done[miso_dma_index])
295 ao_sleep(&ao_dma_done[miso_dma_index]);
298 ao_dma_done_transfer(mosi_dma_index);
299 ao_dma_done_transfer(miso_dma_index);
303 ao_spi_disable_index(uint8_t spi_index)
305 /* Disable current config
307 switch (AO_SPI_INDEX(spi_index)) {
308 case STM_SPI_INDEX(1):
310 case AO_SPI_1_PA5_PA6_PA7:
311 stm_gpio_set(&stm_gpioa, 5, 1);
312 stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
313 stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
314 stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
316 case AO_SPI_1_PB3_PB4_PB5:
317 stm_gpio_set(&stm_gpiob, 3, 1);
318 stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
319 stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
320 stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
324 case STM_SPI_INDEX(2):
326 case AO_SPI_2_PB13_PB14_PB15:
327 stm_gpio_set(&stm_gpiob, 13, 1);
328 stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
329 stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
330 stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
338 ao_spi_enable_index(uint8_t spi_index)
340 switch (AO_SPI_INDEX(spi_index)) {
341 case STM_SPI_INDEX(1):
343 case AO_SPI_1_PA5_PA6_PA7:
344 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
345 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
346 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
348 case AO_SPI_1_PB3_PB4_PB5:
349 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
350 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
351 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
355 case STM_SPI_INDEX(2):
357 case AO_SPI_2_PB13_PB14_PB15:
358 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0);
359 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0);
360 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0);
368 ao_spi_config(uint8_t spi_index, uint32_t speed)
370 uint8_t id = AO_SPI_INDEX(spi_index);
371 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
373 stm_spi->cr2 = SPI_CR2;
374 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
375 (0 << STM_SPI_CR1_BIDIOE) |
376 (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
377 (0 << STM_SPI_CR1_CRCNEXT) |
378 (0 << STM_SPI_CR1_CRCL) |
379 (0 << STM_SPI_CR1_RXONLY) |
380 (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
381 (1 << STM_SPI_CR1_SSI) | /* ... */
382 (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
383 (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
384 (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
385 (1 << STM_SPI_CR1_MSTR) |
386 (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
387 (0 << STM_SPI_CR1_CPHA));
389 if (spi_index != ao_spi_index[id]) {
391 /* Disable old config
393 ao_spi_disable_index(ao_spi_index[id]);
397 ao_spi_enable_index(spi_index);
399 /* Remember current config
401 ao_spi_index[id] = spi_index;
406 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
408 uint8_t id = AO_SPI_INDEX(spi_index);
410 if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
412 ao_spi_config(spi_index, speed);
417 ao_spi_get(uint8_t spi_index, uint32_t speed)
419 uint8_t id = AO_SPI_INDEX(spi_index);
420 ao_mutex_get(&ao_spi_mutex[id]);
421 ao_spi_config(spi_index, speed);
425 ao_spi_put(uint8_t spi_index)
427 uint8_t id = AO_SPI_INDEX(spi_index);
428 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
431 ao_mutex_put(&ao_spi_mutex[id]);
435 ao_spi_channel_init(uint8_t spi_index)
437 uint8_t id = AO_SPI_INDEX(spi_index);
438 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
440 ao_spi_disable_index(spi_index);
444 stm_spi->cr2 = SPI_CR2_SYNC;
451 # if SPI_1_PA5_PA6_PA7
452 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
453 stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
454 stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
455 stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
457 # if SPI_1_PB3_PB4_PB5
458 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
459 stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
460 stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
461 stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
463 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
464 ao_spi_index[0] = AO_SPI_CONFIG_NONE;
465 ao_spi_channel_init(STM_SPI_INDEX(1));
469 # if SPI_2_PB10_PB13_PB14
470 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
471 stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
472 stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
473 stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
475 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
476 ao_spi_index[1] = AO_SPI_CONFIG_NONE;
477 ao_spi_channel_init(STM_SPI_INDEX(2));