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 uint8_t ao_spi_mutex[STM_NUM_SPI];
28 static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
30 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
31 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
35 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
36 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
41 static uint8_t spi_dev_null;
44 ao_spi_send(void *block, uint16_t len, uint8_t spi_index)
46 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
47 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
48 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
50 ao_dma_set_transfer(mosi_dma_index,
54 (0 << STM_DMA_CCR_MEM2MEM) |
55 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
56 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
57 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
58 (1 << STM_DMA_CCR_MINC) |
59 (0 << STM_DMA_CCR_PINC) |
60 (0 << STM_DMA_CCR_CIRC) |
61 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
62 /* Clear any stale data */
64 ao_dma_set_transfer(miso_dma_index,
68 (0 << STM_DMA_CCR_MEM2MEM) |
69 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
70 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
71 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
72 (0 << STM_DMA_CCR_MINC) |
73 (0 << STM_DMA_CCR_PINC) |
74 (0 << STM_DMA_CCR_CIRC) |
75 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
76 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
77 (0 << STM_SPI_CR2_RXNEIE) |
78 (0 << STM_SPI_CR2_ERRIE) |
79 (0 << STM_SPI_CR2_SSOE) |
80 (1 << STM_SPI_CR2_TXDMAEN) |
81 (1 << STM_SPI_CR2_RXDMAEN));
82 ao_dma_start(miso_dma_index);
83 ao_dma_start(mosi_dma_index);
85 while (!ao_dma_done[miso_dma_index])
86 ao_sleep(&ao_dma_done[miso_dma_index]);
88 ao_dma_done_transfer(mosi_dma_index);
89 ao_dma_done_transfer(miso_dma_index);
93 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
95 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
101 while (!(stm_spi->sr & (1 << STM_SPI_SR_RXNE)));
104 while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
106 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
107 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
109 ao_dma_set_transfer(mosi_dma_index,
113 (0 << STM_DMA_CCR_MEM2MEM) |
114 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
115 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
116 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
117 (0 << STM_DMA_CCR_MINC) |
118 (0 << STM_DMA_CCR_PINC) |
119 (0 << STM_DMA_CCR_CIRC) |
120 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
121 /* Clear any stale data */
123 ao_dma_set_transfer(miso_dma_index,
127 (0 << STM_DMA_CCR_MEM2MEM) |
128 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
129 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
130 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
131 (1 << STM_DMA_CCR_MINC) |
132 (0 << STM_DMA_CCR_PINC) |
133 (0 << STM_DMA_CCR_CIRC) |
134 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
135 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
136 (0 << STM_SPI_CR2_RXNEIE) |
137 (0 << STM_SPI_CR2_ERRIE) |
138 (0 << STM_SPI_CR2_SSOE) |
139 (1 << STM_SPI_CR2_TXDMAEN) |
140 (1 << STM_SPI_CR2_RXDMAEN));
141 ao_dma_start(miso_dma_index);
142 ao_dma_start(mosi_dma_index);
144 while (!ao_dma_done[miso_dma_index])
145 ao_sleep(&ao_dma_done[miso_dma_index]);
147 ao_dma_done_transfer(mosi_dma_index);
148 ao_dma_done_transfer(miso_dma_index);
153 ao_spi_channel_init(uint8_t spi_index)
155 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
159 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |
160 (0 << STM_SPI_CR1_BIDIOE) |
161 (0 << STM_SPI_CR1_CRCEN) |
162 (0 << STM_SPI_CR1_CRCNEXT) |
163 (0 << STM_SPI_CR1_DFF) |
164 (0 << STM_SPI_CR1_RXONLY) |
165 (1 << STM_SPI_CR1_SSM) |
166 (1 << STM_SPI_CR1_SSI) |
167 (0 << STM_SPI_CR1_LSBFIRST) |
168 (1 << STM_SPI_CR1_SPE) |
169 (STM_SPI_CR1_BR_PCLK_4 << STM_SPI_CR1_BR) |
170 (1 << STM_SPI_CR1_MSTR) |
171 (0 << STM_SPI_CR1_CPOL) |
172 (0 << STM_SPI_CR1_CPHA));
173 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
174 (0 << STM_SPI_CR2_RXNEIE) |
175 (0 << STM_SPI_CR2_ERRIE) |
176 (0 << STM_SPI_CR2_SSOE) |
177 (0 << STM_SPI_CR2_TXDMAEN) |
178 (0 << STM_SPI_CR2_RXDMAEN));
185 # if SPI_1_PA5_PA6_PA7
186 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
187 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
188 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
189 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
191 # if SPI_1_PB3_PB4_PB5
192 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
193 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
194 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
195 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
197 # if SPI_1_PE13_PE14_PE15
198 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
199 stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
200 stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
201 stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
203 # error "No SPI_1 port configuration specified"
208 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
210 ao_spi_channel_init(0);
212 stm_nvic_set_enable(STM_ISR_SPI1_POS);
213 stm_nvic_set_priority(STM_ISR_SPI1_POS, 3);
217 # if SPI_2_PB13_PB14_PB15
218 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
219 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
220 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
221 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
223 # if SPI_2_PPD1_PD3_PD4
224 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
225 stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
226 stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
227 stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
229 # error "No SPI_2 port configuration specified"
233 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
235 ao_spi_channel_init(1);
237 stm_nvic_set_enable(STM_ISR_SPI2_POS);
238 stm_nvic_set_priority(STM_ISR_SPI2_POS, 3);