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; 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_pin_config[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;
52 static uint8_t spi_task_index;
55 validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
57 uint32_t sr = stm_spi->sr;
59 if (stm_spi != &stm_spi2)
61 spi_tasks[spi_task_index].task = ao_cur_task ? ao_cur_task->task_id : 0;
62 spi_tasks[spi_task_index].which = which;
63 spi_tasks[spi_task_index].tick = ao_time();
64 spi_tasks[spi_task_index].len = len;
65 spi_task_index = (spi_task_index + 1) & (63);
66 if (sr & (1 << STM_SPI_SR_FRE))
68 if (sr & (1 << STM_SPI_SR_BSY))
70 if (sr & (1 << STM_SPI_SR_OVR))
72 if (sr & (1 << STM_SPI_SR_MODF))
74 if (sr & (1 << STM_SPI_SR_UDR))
76 if ((sr & (1 << STM_SPI_SR_TXE)) == 0)
78 if (sr & (1 << STM_SPI_SR_RXNE))
80 if (which != 5 && which != 6 && which != 13)
81 if (ao_cur_task->task_id != ao_spi_mutex[1])
85 #define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
89 ao_spi_set_dma_mosi(uint8_t id, const void *data, uint16_t len, uint32_t minc)
91 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
92 uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
94 ao_dma_set_transfer(mosi_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 (minc << STM_DMA_CCR_MINC) |
103 (0 << STM_DMA_CCR_PINC) |
104 (0 << STM_DMA_CCR_CIRC) |
105 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
109 ao_spi_set_dma_miso(uint8_t id, void *data, uint16_t len, uint32_t minc)
111 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
112 uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
114 ao_dma_set_transfer(miso_dma_index,
118 (0 << STM_DMA_CCR_MEM2MEM) |
119 (STM_DMA_CCR_PL_VERY_HIGH << STM_DMA_CCR_PL) |
120 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
121 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
122 (minc << STM_DMA_CCR_MINC) |
123 (0 << STM_DMA_CCR_PINC) |
124 (0 << STM_DMA_CCR_CIRC) |
125 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
129 ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
131 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
132 uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
133 uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
135 validate_spi(stm_spi, which, len);
137 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
138 (0 << STM_SPI_CR2_RXNEIE) |
139 (0 << STM_SPI_CR2_ERRIE) |
140 (0 << STM_SPI_CR2_SSOE) |
141 (1 << STM_SPI_CR2_TXDMAEN) |
142 (1 << STM_SPI_CR2_RXDMAEN));
144 ao_dma_start(miso_dma_index);
145 ao_dma_start(mosi_dma_index);
148 while (!ao_dma_done[miso_dma_index])
149 ao_sleep(&ao_dma_done[miso_dma_index]);
152 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
153 while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
155 validate_spi(stm_spi, which+1, len);
159 ao_dma_done_transfer(mosi_dma_index);
160 ao_dma_done_transfer(miso_dma_index);
164 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
166 uint8_t id = AO_SPI_INDEX(spi_index);
168 /* Set up the transmit DMA to deliver data */
169 ao_spi_set_dma_mosi(id, block, len, 1);
171 /* Set up the receive DMA -- when this is done, we know the SPI unit
172 * is idle. Without this, we'd have to poll waiting for the BSY bit to
175 ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
177 ao_spi_run(id, 1, len);
181 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
183 uint8_t id = AO_SPI_INDEX(spi_index);
185 /* Set up the transmit DMA to deliver data */
186 ao_spi_set_dma_mosi(id, &value, len, 0);
188 /* Set up the receive DMA -- when this is done, we know the SPI unit
189 * is idle. Without this, we'd have to poll waiting for the BSY bit to
192 ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
194 ao_spi_run(id, 3, len);
198 ao_spi_start_bytes(uint8_t spi_index)
200 uint8_t id = AO_SPI_INDEX(spi_index);
201 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
203 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
204 (0 << STM_SPI_CR2_RXNEIE) |
205 (0 << STM_SPI_CR2_ERRIE) |
206 (0 << STM_SPI_CR2_SSOE) |
207 (0 << STM_SPI_CR2_TXDMAEN) |
208 (0 << STM_SPI_CR2_RXDMAEN));
209 validate_spi(stm_spi, 5, 0xffff);
213 ao_spi_stop_bytes(uint8_t spi_index)
215 uint8_t id = AO_SPI_INDEX(spi_index);
216 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
218 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
220 while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
222 /* Clear the OVR flag */
225 validate_spi(stm_spi, 6, 0xffff);
230 ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
232 uint8_t id = AO_SPI_INDEX(spi_index);
233 const uint8_t *b = block;
234 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
236 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
237 (0 << STM_SPI_CR2_RXNEIE) |
238 (0 << STM_SPI_CR2_ERRIE) |
239 (0 << STM_SPI_CR2_SSOE) |
240 (0 << STM_SPI_CR2_TXDMAEN) |
241 (0 << STM_SPI_CR2_RXDMAEN));
242 validate_spi(stm_spi, 7, len);
244 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
247 while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
249 while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
251 /* Clear the OVR flag */
254 validate_spi(stm_spi, 8, len);
258 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
260 uint8_t id = AO_SPI_INDEX(spi_index);
264 /* Set up transmit DMA to make the SPI hardware actually run */
265 ao_spi_set_dma_mosi(id, &spi_dev_null, len, 0);
267 /* Set up the receive DMA to capture data */
268 ao_spi_set_dma_miso(id, block, len, 1);
270 ao_spi_run(id, 9, len);
274 ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index)
276 uint8_t id = AO_SPI_INDEX(spi_index);
278 /* Set up transmit DMA to send data */
279 ao_spi_set_dma_mosi(id, out, len, 1);
281 /* Set up the receive DMA to capture data */
282 ao_spi_set_dma_miso(id, in, len, 1);
284 ao_spi_run(id, 11, len);
287 #define stm_spi_input_disable(gpio, pin) do { \
288 stm_gpio_conf(gpio, pin, \
289 STM_GPIO_CR_MODE_INPUT, \
290 STM_GPIO_CR_CNF_INPUT_FLOATING); \
293 #define stm_spi_output_disable(gpio, pin, mode) do { \
294 ao_gpio_set(gpio, pin, 1); \
295 stm_gpio_conf(gpio, pin, \
297 STM_GPIO_CR_CNF_OUTPUT_PUSH_PULL); \
301 ao_spi_disable_pin_config(uint8_t spi_pin_config)
303 /* Disable current config
305 switch (spi_pin_config) {
306 #if SPI_1_PA5_PA6_PA7
307 case AO_SPI_1_PA5_PA6_PA7:
308 stm_spi_output_disable(&stm_gpioa, 5, SPI_1_MODE_OUTPUT);
309 stm_spi_input_disable(&stm_gpioa, 6);
310 stm_spi_output_disable(&stm_gpioa, 7, SPI_1_MODE_OUTPUT);
313 #if SPI_1_PB3_PB4_PB5
314 case AO_SPI_1_PB3_PB4_PB5:
315 stm_spi_output_disable(&stm_gpiob, 3, SPI_1_MODE_OUTPUT);
316 stm_spi_input_disable(&stm_gpiob, 4);
317 stm_spi_output_disable(&stm_gpiob, 5, SPI_1_MODE_OUTPUT);
320 #if SPI_2_PB13_PB14_PB15
321 case AO_SPI_2_PB13_PB14_PB15:
322 stm_spi_output_disable(&stm_gpiob, 13, SPI_2_MODE_OUTPUT);
323 stm_spi_input_disable(&stm_gpiob, 14);
324 stm_spi_output_disable(&stm_gpiob, 15, SPI_2_MODE_OUTPUT);
330 #define stm_spi_input_enable(gpio, pin) do { \
331 stm_gpio_conf(gpio, pin, \
332 STM_GPIO_CR_MODE_INPUT, \
333 STM_GPIO_CR_CNF_INPUT_FLOATING); \
336 #define stm_spi_output_enable(gpio, pin, mode) do { \
337 stm_gpio_conf(gpio, pin, \
339 STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL); \
343 ao_spi_enable_pin_config(uint8_t spi_pin_config)
347 switch (spi_pin_config) {
348 #if SPI_1_PA5_PA6_PA7
349 case AO_SPI_1_PA5_PA6_PA7:
350 stm_set_afio_mapr(STM_AFIO_MAPR_SPI1_REMAP,
351 STM_AFIO_MAPR_SPI1_REMAP_PA4_PA5_PA6_PA7,
352 STM_AFIO_MAPR_SPI1_REMAP_MASK);
353 stm_spi_output_enable(&stm_gpioa, 5, SPI_1_MODE_OUTPUT);
354 stm_spi_input_enable(&stm_gpioa, 6);
355 stm_spi_output_enable(&stm_gpioa, 7, SPI_1_MODE_OUTPUT);
358 #if SPI_1_PB3_PB4_PB5
359 case AO_SPI_1_PB3_PB4_PB5:
360 stm_set_afio_mapr(STM_AFIO_MAPR_SPI1_REMAP,
361 STM_AFIO_MAPR_SPI1_REMAP_PA15_PB3_PB4_PB5,
362 STM_AFIO_MAPR_SPI1_REMAP_MASK);
363 stm_spi_output_enable(&stm_gpiob, 3, SPI_1_MODE_OUTPUT);
364 stm_spi_input_enable(&stm_gpiob, 4);
365 stm_spi_output_enable(&stm_gpiob, 5, SPI_1_MODE_OUTPUT);
368 #if SPI_2_PB13_PB14_PB15
369 case AO_SPI_2_PB13_PB14_PB15:
370 stm_spi_output_enable(&stm_gpiob, 13, SPI_2_MODE_OUTPUT);
371 stm_spi_input_enable(&stm_gpiob, 14);
372 stm_spi_output_enable(&stm_gpiob, 15, SPI_2_MODE_OUTPUT);
379 ao_spi_config(uint8_t spi_index, uint32_t speed)
381 uint8_t spi_pin_config = AO_SPI_PIN_CONFIG(spi_index);
382 uint8_t id = AO_SPI_INDEX(spi_index);
383 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
385 if (spi_pin_config != ao_spi_pin_config[id]) {
387 /* Disable old config
389 ao_spi_disable_pin_config(ao_spi_pin_config[id]);
393 ao_spi_enable_pin_config(spi_pin_config);
395 /* Remember current config
397 ao_spi_pin_config[id] = spi_pin_config;
400 /* Turn the SPI transceiver on and set the mode */
401 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
402 (0 << STM_SPI_CR1_BIDIOE) |
403 (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
404 (0 << STM_SPI_CR1_CRCNEXT) |
405 (0 << STM_SPI_CR1_DFF) |
406 (0 << STM_SPI_CR1_RXONLY) |
407 (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
408 (1 << STM_SPI_CR1_SSI) | /* ... */
409 (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
410 (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
411 (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
412 (1 << STM_SPI_CR1_MSTR) |
413 (AO_SPI_CPOL(spi_index) << STM_SPI_CR1_CPOL) | /* Format */
414 (AO_SPI_CPHA(spi_index) << STM_SPI_CR1_CPHA));
415 validate_spi(stm_spi, 13, 0);
419 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
421 uint8_t id = AO_SPI_INDEX(spi_index);
423 if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
425 ao_spi_config(spi_index, speed);
430 ao_spi_get(uint8_t spi_index, uint32_t speed)
432 uint8_t id = AO_SPI_INDEX(spi_index);
434 ao_mutex_get(&ao_spi_mutex[id]);
435 ao_spi_config(spi_index, speed);
439 ao_spi_put(uint8_t spi_index)
441 uint8_t id = AO_SPI_INDEX(spi_index);
442 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
445 ao_mutex_put(&ao_spi_mutex[id]);
449 ao_spi_put_pins(uint8_t spi_index)
451 uint8_t id = AO_SPI_INDEX(spi_index);
453 ao_spi_disable_pin_config(ao_spi_pin_config[id]);
454 ao_spi_pin_config[id] = AO_SPI_CONFIG_NONE;
455 ao_spi_put(spi_index);
459 ao_spi_channel_init(uint8_t spi_index)
461 uint8_t id = AO_SPI_INDEX(spi_index);
462 struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
464 ao_spi_disable_pin_config(AO_SPI_PIN_CONFIG(spi_index));
467 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
468 (0 << STM_SPI_CR2_RXNEIE) |
469 (0 << STM_SPI_CR2_ERRIE) |
470 (0 << STM_SPI_CR2_SSOE) |
471 (0 << STM_SPI_CR2_TXDMAEN) |
472 (0 << STM_SPI_CR2_RXDMAEN));
474 /* Clear any pending data and error flags */
481 ao_spi_dump_cmd(void)
485 for (s = 0; s < 64; s++) {
486 int i = (spi_task_index + s) & 63;
487 if (spi_tasks[i].which) {
489 const char *name = "(none)";
490 for (t = 0; t < ao_num_tasks; t++)
491 if (ao_tasks[t]->task_id == spi_tasks[i].task) {
492 name = ao_tasks[t]->name;
495 printf("%2d: %5d task %2d which %2d len %5d %s\n",
504 for (s = 0; s < STM_NUM_SPI; s++) {
505 struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
507 printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
508 s, ao_spi_mutex[s], ao_spi_index[s],
509 ao_spi_stm_info[s].miso_dma_index,
510 ao_spi_stm_info[s].mosi_dma_index);
511 printf(" cr1 %04x cr2 %02x sr %03x\n",
512 spi->cr1, spi->cr2, spi->sr);
517 static const struct ao_cmds ao_spi_cmds[] = {
518 { ao_spi_dump_cmd, "S\0Dump SPI status" },
527 # if SPI_1_PA5_PA6_PA7
528 ao_enable_port(&stm_gpioa);
530 # if SPI_1_PB3_PB4_PB5
531 ao_enable_port(&stm_gpiob);
533 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
534 ao_spi_pin_config[0] = AO_SPI_CONFIG_NONE;
535 ao_spi_channel_init(0);
539 # if SPI_2_PB13_PB14_PB15
540 ao_enable_port(&stm_gpiob);
542 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
543 ao_spi_pin_config[1] = AO_SPI_CONFIG_NONE;
544 ao_spi_channel_init(1);
547 ao_cmd_register(&ao_spi_cmds[0]);