1 /*
2  * Copyright (c) 2016 Erik Gilling
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 #include <platform/spi.h>
9 
10 #include <stdbool.h>
11 
12 #include <arch/arm/cm.h>
13 #include <kernel/event.h>
14 #include <kernel/mutex.h>
15 #include <platform/dma.h>
16 #include <platform/rcc.h>
17 
18 #define SPI_SR_FRLVL_VAL(reg)  ((reg) >> 9 & 0x3)
19 #define SPI_SR_FTLVL_VAL(reg)  ((reg) >> 11 & 0x3)
20 
21 #define SPI_FIFO_EMPTY   0x0
22 #define SPI_FIFO_QUARTER 0x1
23 #define SPI_FIFO_HALF    0x2
24 #define SPI_FIFO_FULL    0x3
25 
26 typedef SPI_TypeDef spi_regs_t;
27 
28 uint32_t spi_dma_width_flag;
29 mutex_t spi_mutex;
30 
spi_init(spi_data_size_t data_size,spi_cpol_t cpol,spi_cpha_t cpha,spi_bit_order_t bit_order,spi_prescaler_t prescaler)31 void spi_init(spi_data_size_t data_size,
32               spi_cpol_t cpol,
33               spi_cpha_t cpha,
34               spi_bit_order_t bit_order,
35               spi_prescaler_t prescaler) {
36 
37     spi_regs_t *regs = SPI1;
38     uint16_t temp_reg;
39 
40     mutex_init(&spi_mutex);
41 
42     stm32_rcc_set_enable(STM32_RCC_CLK_SPI1, true);
43 
44     regs->CR1 = cpol | cpha | bit_order | prescaler | SPI_CR1_SSM;
45 
46     temp_reg = regs->CR2;
47     temp_reg &= ~(SPI_CR2_DS | SPI_CR2_FRXTH);
48     temp_reg |= data_size;
49     if (data_size < SPI_DATA_SIZE_9) {
50         // RXNE asserted when fifo has at least 8 bits.  Defaults to 16bits.
51         temp_reg |= SPI_CR2_FRXTH;
52         spi_dma_width_flag = DMA_FLAG_PERIPH_8_BIT | DMA_FLAG_MEM_8_BIT;
53     } else {
54         spi_dma_width_flag = DMA_FLAG_PERIPH_16_BIT | DMA_FLAG_MEM_16_BIT;
55     }
56     regs->CR2 = temp_reg;
57 
58     temp_reg = regs->CR1;
59     temp_reg |= SPI_CR1_MSTR | SPI_CR1_SSI;
60     regs->CR1 = temp_reg;
61 }
62 
spi_xfer(const void * tx_buf,void * rx_buf,size_t len)63 ssize_t spi_xfer(const void *tx_buf, void *rx_buf, size_t len) {
64     // Assure only a single transaction is ever active.
65     mutex_acquire(&spi_mutex);
66 
67     // Ensure we're idle before starting.
68     dma_wait(DMA_CHANNEL_2);
69     dma_wait(DMA_CHANNEL_3);
70 
71     spi_regs_t *regs = SPI1;
72     regs->CR1 &= ~SPI_CR1_SPE;
73 
74     // Make sure to start read DMA first.
75     dma_transfer_start(DMA_CHANNEL_2,
76                        (uint32_t)&regs->DR, (uint32_t)rx_buf, len,
77                        DMA_FLAG_FROM_PERIPH | DMA_FLAG_MEM_INCREMENT
78                        | DMA_FLAG_PRIORITY(1) | spi_dma_width_flag);
79     dma_transfer_start(DMA_CHANNEL_3,
80                        (uint32_t)&regs->DR, (uint32_t)tx_buf, len,
81                        DMA_FLAG_FROM_MEM | DMA_FLAG_MEM_INCREMENT
82                        | DMA_FLAG_PRIORITY(0) | spi_dma_width_flag);
83     regs->CR2 |= SPI_CR2_TXDMAEN | SPI_CR2_RXDMAEN;
84     regs->CR1 |= SPI_CR1_SPE;
85 
86     // We only wait for channel 2 (RX) assuming that TX will be done first.
87     dma_wait(DMA_CHANNEL_2);
88 
89     mutex_release(&spi_mutex);
90     return len;
91 }
92 
93