2 * Copyright © 2012 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;
45 ao_spi_send(void *block, uint16_t len, uint8_t spi_index)
47 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
48 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
49 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
51 /* Set up the transmit DMA to deliver data */
52 ao_dma_set_transfer(mosi_dma_index,
56 (0 << STM_DMA_CCR_MEM2MEM) |
57 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
58 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
59 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
60 (1 << STM_DMA_CCR_MINC) |
61 (0 << STM_DMA_CCR_PINC) |
62 (0 << STM_DMA_CCR_CIRC) |
63 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
68 /* Set up the receive DMA -- when this is done, we know the SPI unit
69 * is idle. Without this, we'd have to poll waiting for the BSY bit to
72 ao_dma_set_transfer(miso_dma_index,
76 (0 << STM_DMA_CCR_MEM2MEM) |
77 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
78 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
79 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
80 (0 << STM_DMA_CCR_MINC) |
81 (0 << STM_DMA_CCR_PINC) |
82 (0 << STM_DMA_CCR_CIRC) |
83 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
84 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
85 (0 << STM_SPI_CR2_RXNEIE) |
86 (0 << STM_SPI_CR2_ERRIE) |
87 (0 << STM_SPI_CR2_SSOE) |
88 (1 << STM_SPI_CR2_TXDMAEN) |
89 (1 << STM_SPI_CR2_RXDMAEN));
90 ao_dma_start(miso_dma_index);
91 ao_dma_start(mosi_dma_index);
93 while (!ao_dma_done[miso_dma_index])
94 ao_sleep(&ao_dma_done[miso_dma_index]);
96 ao_dma_done_transfer(mosi_dma_index);
97 ao_dma_done_transfer(miso_dma_index);
101 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
103 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
104 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
105 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
107 /* Set up the transmit DMA to deliver data */
108 ao_dma_set_transfer(mosi_dma_index,
112 (0 << STM_DMA_CCR_MEM2MEM) |
113 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
114 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
115 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
116 (0 << STM_DMA_CCR_MINC) |
117 (0 << STM_DMA_CCR_PINC) |
118 (0 << STM_DMA_CCR_CIRC) |
119 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
124 /* Set up the receive DMA -- when this is done, we know the SPI unit
125 * is idle. Without this, we'd have to poll waiting for the BSY bit to
128 ao_dma_set_transfer(miso_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_PER_TO_MEM << STM_DMA_CCR_DIR));
140 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
141 (0 << STM_SPI_CR2_RXNEIE) |
142 (0 << STM_SPI_CR2_ERRIE) |
143 (0 << STM_SPI_CR2_SSOE) |
144 (1 << STM_SPI_CR2_TXDMAEN) |
145 (1 << STM_SPI_CR2_RXDMAEN));
146 ao_dma_start(miso_dma_index);
147 ao_dma_start(mosi_dma_index);
149 while (!ao_dma_done[miso_dma_index])
150 ao_sleep(&ao_dma_done[miso_dma_index]);
152 ao_dma_done_transfer(mosi_dma_index);
153 ao_dma_done_transfer(miso_dma_index);
157 ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index)
160 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
162 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
163 (0 << STM_SPI_CR2_RXNEIE) |
164 (0 << STM_SPI_CR2_ERRIE) |
165 (0 << STM_SPI_CR2_SSOE) |
166 (0 << STM_SPI_CR2_TXDMAEN) |
167 (0 << STM_SPI_CR2_RXDMAEN));
173 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
179 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
181 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
182 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
183 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
187 /* Set up transmit DMA to make the SPI hardware actually run */
188 ao_dma_set_transfer(mosi_dma_index,
192 (0 << STM_DMA_CCR_MEM2MEM) |
193 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
194 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
195 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
196 (0 << STM_DMA_CCR_MINC) |
197 (0 << STM_DMA_CCR_PINC) |
198 (0 << STM_DMA_CCR_CIRC) |
199 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
204 /* Set up the receive DMA to capture data */
205 ao_dma_set_transfer(miso_dma_index,
209 (0 << STM_DMA_CCR_MEM2MEM) |
210 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
211 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
212 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
213 (1 << STM_DMA_CCR_MINC) |
214 (0 << STM_DMA_CCR_PINC) |
215 (0 << STM_DMA_CCR_CIRC) |
216 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
218 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
219 (0 << STM_SPI_CR2_RXNEIE) |
220 (0 << STM_SPI_CR2_ERRIE) |
221 (0 << STM_SPI_CR2_SSOE) |
222 (1 << STM_SPI_CR2_TXDMAEN) |
223 (1 << STM_SPI_CR2_RXDMAEN));
224 ao_dma_start(miso_dma_index);
225 ao_dma_start(mosi_dma_index);
227 /* Wait until the SPI unit is done */
229 while (!ao_dma_done[miso_dma_index])
230 ao_sleep(&ao_dma_done[miso_dma_index]);
233 ao_dma_done_transfer(mosi_dma_index);
234 ao_dma_done_transfer(miso_dma_index);
238 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
240 struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
241 uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
242 uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
244 /* Set up transmit DMA to send data */
245 ao_dma_set_transfer(mosi_dma_index,
249 (0 << STM_DMA_CCR_MEM2MEM) |
250 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
251 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
252 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
253 (1 << STM_DMA_CCR_MINC) |
254 (0 << STM_DMA_CCR_PINC) |
255 (0 << STM_DMA_CCR_CIRC) |
256 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
261 /* Set up the receive DMA to capture data */
262 ao_dma_set_transfer(miso_dma_index,
266 (0 << STM_DMA_CCR_MEM2MEM) |
267 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
268 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
269 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
270 (1 << STM_DMA_CCR_MINC) |
271 (0 << STM_DMA_CCR_PINC) |
272 (0 << STM_DMA_CCR_CIRC) |
273 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
275 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
276 (0 << STM_SPI_CR2_RXNEIE) |
277 (0 << STM_SPI_CR2_ERRIE) |
278 (0 << STM_SPI_CR2_SSOE) |
279 (1 << STM_SPI_CR2_TXDMAEN) |
280 (1 << STM_SPI_CR2_RXDMAEN));
281 ao_dma_start(miso_dma_index);
282 ao_dma_start(mosi_dma_index);
284 /* Wait until the SPI unit is done */
286 while (!ao_dma_done[miso_dma_index])
287 ao_sleep(&ao_dma_done[miso_dma_index]);
290 ao_dma_done_transfer(mosi_dma_index);
291 ao_dma_done_transfer(miso_dma_index);
295 ao_spi_disable_index(uint8_t spi_index)
297 /* Disable current config
299 switch (AO_SPI_INDEX(spi_index)) {
300 case STM_SPI_INDEX(1):
302 case AO_SPI_1_PA5_PA6_PA7:
303 stm_gpio_set(&stm_gpioa, 5, 1);
304 stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
305 stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
306 stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
308 case AO_SPI_1_PB3_PB4_PB5:
309 stm_gpio_set(&stm_gpiob, 3, 1);
310 stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
311 stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
312 stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
314 case AO_SPI_1_PE13_PE14_PE15:
315 stm_gpio_set(&stm_gpioe, 13, 1);
316 stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
317 stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
318 stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
322 case STM_SPI_INDEX(2):
324 case AO_SPI_2_PB13_PB14_PB15:
325 stm_gpio_set(&stm_gpiob, 13, 1);
326 stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
327 stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
328 stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
330 case AO_SPI_2_PD1_PD3_PD4:
331 stm_gpio_set(&stm_gpiod, 1, 1);
332 stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
333 stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
334 stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
342 ao_spi_enable_index(uint8_t spi_index)
344 switch (AO_SPI_INDEX(spi_index)) {
345 case STM_SPI_INDEX(1):
347 case AO_SPI_1_PA5_PA6_PA7:
348 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
349 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
350 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
352 case AO_SPI_1_PB3_PB4_PB5:
353 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
354 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
355 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
357 case AO_SPI_1_PE13_PE14_PE15:
358 stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
359 stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
360 stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
364 case STM_SPI_INDEX(2):
366 case AO_SPI_2_PB13_PB14_PB15:
367 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
368 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
369 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
371 case AO_SPI_2_PD1_PD3_PD4:
372 stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
373 stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
374 stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
382 ao_spi_config(uint8_t spi_index, uint32_t speed)
384 uint8_t id = AO_SPI_INDEX(spi_index);
385 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
386 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
387 (0 << STM_SPI_CR1_BIDIOE) |
388 (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
389 (0 << STM_SPI_CR1_CRCNEXT) |
390 (0 << STM_SPI_CR1_DFF) |
391 (0 << STM_SPI_CR1_RXONLY) |
392 (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
393 (1 << STM_SPI_CR1_SSI) | /* ... */
394 (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
395 (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
396 (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
397 (1 << STM_SPI_CR1_MSTR) |
398 (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
399 (0 << STM_SPI_CR1_CPHA));
400 if (spi_index != ao_spi_index[id]) {
402 /* Disable old config
404 ao_spi_disable_index(ao_spi_index[id]);
408 ao_spi_enable_index(spi_index);
410 /* Remember current config
412 ao_spi_index[id] = spi_index;
417 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
419 uint8_t id = AO_SPI_INDEX(spi_index);
421 if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
423 ao_spi_config(spi_index, speed);
428 ao_spi_get(uint8_t spi_index, uint32_t speed)
430 uint8_t id = AO_SPI_INDEX(spi_index);
431 ao_mutex_get(&ao_spi_mutex[id]);
432 ao_spi_config(spi_index, speed);
436 ao_spi_put(uint8_t spi_index)
438 uint8_t id = AO_SPI_INDEX(spi_index);
439 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
442 ao_mutex_put(&ao_spi_mutex[id]);
446 ao_spi_channel_init(uint8_t spi_index)
448 uint8_t id = AO_SPI_INDEX(spi_index);
449 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
451 ao_spi_disable_index(spi_index);
455 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
456 (0 << STM_SPI_CR2_RXNEIE) |
457 (0 << STM_SPI_CR2_ERRIE) |
458 (0 << STM_SPI_CR2_SSOE) |
459 (0 << STM_SPI_CR2_TXDMAEN) |
460 (0 << STM_SPI_CR2_RXDMAEN));
467 # if SPI_1_PA5_PA6_PA7
468 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
469 stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
470 stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
471 stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
473 # if SPI_1_PB3_PB4_PB5
474 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
475 stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
476 stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
477 stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
479 # if SPI_1_PE13_PE14_PE15
480 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
481 stm_ospeedr_set(&stm_gpioe, 13, SPI_1_OSPEEDR);
482 stm_ospeedr_set(&stm_gpioe, 14, SPI_1_OSPEEDR);
483 stm_ospeedr_set(&stm_gpioe, 15, SPI_1_OSPEEDR);
485 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
486 ao_spi_index[0] = AO_SPI_CONFIG_NONE;
487 ao_spi_channel_init(0);
491 # if SPI_2_PB13_PB14_PB15
492 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
493 stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
494 stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
495 stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
497 # if SPI_2_PD1_PD3_PD4
498 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
499 stm_ospeedr_set(&stm_gpiod, 1, SPI_2_OSPEEDR);
500 stm_ospeedr_set(&stm_gpiod, 3, SPI_2_OSPEEDR);
501 stm_ospeedr_set(&stm_gpiod, 4, SPI_2_OSPEEDR);
503 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
504 ao_spi_index[1] = AO_SPI_CONFIG_NONE;
505 ao_spi_channel_init(1);