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; version 2 of the License.
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.
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.
20 struct ao_spi_stm_info {
21 uint8_t miso_dma_index;
22 uint8_t mosi_dma_index;
23 struct stm_spi *stm_spi;
26 static uint8_t ao_spi_mutex[STM_NUM_SPI];
27 static uint8_t ao_spi_index[STM_NUM_SPI];
29 static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
31 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
32 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
36 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
37 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
42 static uint8_t spi_dev_null;
46 #define SPI_CR2 ((0 << STM_SPI_CR2_LDMA_TX) | \
47 (0 << STM_SPI_CR2_LDMA_RX) | \
48 (1 << STM_SPI_CR2_FRXTH) | \
49 (STM_SPI_CR2_DS_8 << STM_SPI_CR2_DS) | \
50 (0 << STM_SPI_CR2_TXEIE) | \
51 (0 << STM_SPI_CR2_RXNEIE) | \
52 (0 << STM_SPI_CR2_ERRIE) | \
53 (STM_SPI_CR2_FRF_MOTOROLA << STM_SPI_CR2_FRF) | \
54 (0 << STM_SPI_CR2_NSSP) | \
55 (0 << STM_SPI_CR2_SSOE))
57 #define SPI_CR2_DMA (SPI_CR2 | \
58 (1 << STM_SPI_CR2_TXDMAEN) | \
59 (1 << STM_SPI_CR2_RXDMAEN))
61 #define SPI_CR2_SYNC (SPI_CR2 | \
62 (0 << STM_SPI_CR2_TXDMAEN) | \
63 (0 << STM_SPI_CR2_RXDMAEN))
66 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
68 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
69 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
70 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
72 /* Set up the transmit DMA to deliver data */
73 ao_dma_set_transfer(mosi_dma_index,
77 (0 << STM_DMA_CCR_MEM2MEM) |
78 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
79 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
80 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
81 (1 << STM_DMA_CCR_MINC) |
82 (0 << STM_DMA_CCR_PINC) |
83 (0 << STM_DMA_CCR_CIRC) |
84 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
85 (0 << STM_DMA_CCR_TCIE));
90 /* Set up the receive DMA -- when this is done, we know the SPI unit
91 * is idle. Without this, we'd have to poll waiting for the BSY bit to
94 ao_dma_set_transfer(miso_dma_index,
98 (0 << STM_DMA_CCR_MEM2MEM) |
99 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
100 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
101 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
102 (0 << STM_DMA_CCR_MINC) |
103 (0 << STM_DMA_CCR_PINC) |
104 (0 << STM_DMA_CCR_CIRC) |
105 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
106 (1 << STM_DMA_CCR_TCIE));
108 stm_spi->cr2 = SPI_CR2_DMA;
110 ao_dma_start(miso_dma_index);
111 ao_dma_start(mosi_dma_index);
113 while (!ao_dma_done[miso_dma_index])
114 ao_sleep(&ao_dma_done[miso_dma_index]);
116 ao_dma_done_transfer(mosi_dma_index);
117 ao_dma_done_transfer(miso_dma_index);
121 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
123 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
124 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
125 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
127 /* Set up the transmit DMA to deliver data */
128 ao_dma_set_transfer(mosi_dma_index,
132 (0 << STM_DMA_CCR_MEM2MEM) |
133 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
134 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
135 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
136 (0 << STM_DMA_CCR_MINC) |
137 (0 << STM_DMA_CCR_PINC) |
138 (0 << STM_DMA_CCR_CIRC) |
139 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
140 (0 << STM_DMA_CCR_TCIE));
145 /* Set up the receive DMA -- when this is done, we know the SPI unit
146 * is idle. Without this, we'd have to poll waiting for the BSY bit to
149 ao_dma_set_transfer(miso_dma_index,
153 (0 << STM_DMA_CCR_MEM2MEM) |
154 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
155 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
156 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
157 (0 << STM_DMA_CCR_MINC) |
158 (0 << STM_DMA_CCR_PINC) |
159 (0 << STM_DMA_CCR_CIRC) |
160 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
161 (1 << STM_DMA_CCR_TCIE));
163 stm_spi->cr2 = SPI_CR2_DMA;
164 ao_dma_start(miso_dma_index);
165 ao_dma_start(mosi_dma_index);
167 while (!ao_dma_done[miso_dma_index])
168 ao_sleep(&ao_dma_done[miso_dma_index]);
170 ao_dma_done_transfer(mosi_dma_index);
171 ao_dma_done_transfer(miso_dma_index);
175 ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index)
178 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
180 stm_spi->cr2 = SPI_CR2_SYNC;
186 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
192 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
194 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
195 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
196 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
200 /* Set up transmit DMA to make the SPI hardware actually run */
201 ao_dma_set_transfer(mosi_dma_index,
205 (0 << STM_DMA_CCR_MEM2MEM) |
206 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
207 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
208 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
209 (0 << STM_DMA_CCR_MINC) |
210 (0 << STM_DMA_CCR_PINC) |
211 (0 << STM_DMA_CCR_CIRC) |
212 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
213 (0 << STM_DMA_CCR_TCIE));
218 /* Set up the receive DMA to capture data */
219 ao_dma_set_transfer(miso_dma_index,
223 (0 << STM_DMA_CCR_MEM2MEM) |
224 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
225 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
226 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
227 (1 << STM_DMA_CCR_MINC) |
228 (0 << STM_DMA_CCR_PINC) |
229 (0 << STM_DMA_CCR_CIRC) |
230 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
231 (1 << STM_DMA_CCR_TCIE));
233 stm_spi->cr2 = SPI_CR2_DMA;
234 ao_dma_start(miso_dma_index);
235 ao_dma_start(mosi_dma_index);
237 /* Wait until the SPI unit is done */
239 while (!ao_dma_done[miso_dma_index])
240 ao_sleep(&ao_dma_done[miso_dma_index]);
243 ao_dma_done_transfer(mosi_dma_index);
244 ao_dma_done_transfer(miso_dma_index);
248 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
250 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
251 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
252 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
254 /* Set up transmit DMA to send data */
255 ao_dma_set_transfer(mosi_dma_index,
259 (0 << STM_DMA_CCR_MEM2MEM) |
260 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
261 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
262 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
263 (1 << STM_DMA_CCR_MINC) |
264 (0 << STM_DMA_CCR_PINC) |
265 (0 << STM_DMA_CCR_CIRC) |
266 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
267 (0 << STM_DMA_CCR_TCIE));
272 /* Set up the receive DMA to capture data */
273 ao_dma_set_transfer(miso_dma_index,
277 (0 << STM_DMA_CCR_MEM2MEM) |
278 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
279 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
280 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
281 (1 << STM_DMA_CCR_MINC) |
282 (0 << STM_DMA_CCR_PINC) |
283 (0 << STM_DMA_CCR_CIRC) |
284 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
285 (1 << STM_DMA_CCR_TCIE));
287 stm_spi->cr2 = SPI_CR2_DMA;
288 ao_dma_start(miso_dma_index);
289 ao_dma_start(mosi_dma_index);
291 /* Wait until the SPI unit is done */
293 while (!ao_dma_done[miso_dma_index])
294 ao_sleep(&ao_dma_done[miso_dma_index]);
297 ao_dma_done_transfer(mosi_dma_index);
298 ao_dma_done_transfer(miso_dma_index);
302 ao_spi_disable_index(uint8_t spi_index)
304 /* Disable current config
306 switch (AO_SPI_INDEX(spi_index)) {
307 case STM_SPI_INDEX(1):
309 case AO_SPI_1_PA5_PA6_PA7:
310 stm_gpio_set(&stm_gpioa, 5, 1);
311 stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
312 stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
313 stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
315 case AO_SPI_1_PB3_PB4_PB5:
316 stm_gpio_set(&stm_gpiob, 3, 1);
317 stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
318 stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
319 stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
323 case STM_SPI_INDEX(2):
325 case AO_SPI_2_PB13_PB14_PB15:
326 stm_gpio_set(&stm_gpiob, 13, 1);
327 stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
328 stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
329 stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
337 ao_spi_enable_index(uint8_t spi_index)
339 switch (AO_SPI_INDEX(spi_index)) {
340 case STM_SPI_INDEX(1):
342 case AO_SPI_1_PA5_PA6_PA7:
343 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
344 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
345 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
347 case AO_SPI_1_PB3_PB4_PB5:
348 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
349 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
350 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
354 case STM_SPI_INDEX(2):
356 case AO_SPI_2_PB13_PB14_PB15:
357 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0);
358 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0);
359 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0);
367 ao_spi_config(uint8_t spi_index, uint32_t speed)
369 uint8_t id = AO_SPI_INDEX(spi_index);
370 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
372 stm_spi->cr2 = SPI_CR2;
373 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
374 (0 << STM_SPI_CR1_BIDIOE) |
375 (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
376 (0 << STM_SPI_CR1_CRCNEXT) |
377 (0 << STM_SPI_CR1_CRCL) |
378 (0 << STM_SPI_CR1_RXONLY) |
379 (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
380 (1 << STM_SPI_CR1_SSI) | /* ... */
381 (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
382 (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
383 (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
384 (1 << STM_SPI_CR1_MSTR) |
385 (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
386 (0 << STM_SPI_CR1_CPHA));
388 if (spi_index != ao_spi_index[id]) {
390 /* Disable old config
392 ao_spi_disable_index(ao_spi_index[id]);
396 ao_spi_enable_index(spi_index);
398 /* Remember current config
400 ao_spi_index[id] = spi_index;
405 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
407 uint8_t id = AO_SPI_INDEX(spi_index);
409 if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
411 ao_spi_config(spi_index, speed);
416 ao_spi_get(uint8_t spi_index, uint32_t speed)
418 uint8_t id = AO_SPI_INDEX(spi_index);
419 ao_mutex_get(&ao_spi_mutex[id]);
420 ao_spi_config(spi_index, speed);
424 ao_spi_put(uint8_t spi_index)
426 uint8_t id = AO_SPI_INDEX(spi_index);
427 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
430 ao_mutex_put(&ao_spi_mutex[id]);
434 ao_spi_channel_init(uint8_t spi_index)
436 uint8_t id = AO_SPI_INDEX(spi_index);
437 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
439 ao_spi_disable_index(spi_index);
443 stm_spi->cr2 = SPI_CR2_SYNC;
450 # if SPI_1_PA5_PA6_PA7
451 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
452 stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
453 stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
454 stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
456 # if SPI_1_PB3_PB4_PB5
457 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
458 stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
459 stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
460 stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
462 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
463 ao_spi_index[0] = AO_SPI_CONFIG_NONE;
464 ao_spi_channel_init(STM_SPI_INDEX(1));
468 # if SPI_2_PB10_PB13_PB14
469 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
470 stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
471 stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
472 stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
474 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
475 ao_spi_index[1] = AO_SPI_CONFIG_NONE;
476 ao_spi_channel_init(STM_SPI_INDEX(2));