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 /* Set up the transmit DMA to deliver data */
51 ao_dma_set_transfer(mosi_dma_index,
55 (0 << STM_DMA_CCR_MEM2MEM) |
56 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
57 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
58 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
59 (1 << STM_DMA_CCR_MINC) |
60 (0 << STM_DMA_CCR_PINC) |
61 (0 << STM_DMA_CCR_CIRC) |
62 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
67 /* Set up the receive DMA -- when this is done, we know the SPI unit
68 * is idle. Without this, we'd have to poll waiting for the BSY bit to
71 ao_dma_set_transfer(miso_dma_index,
75 (0 << STM_DMA_CCR_MEM2MEM) |
76 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
77 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
78 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
79 (0 << STM_DMA_CCR_MINC) |
80 (0 << STM_DMA_CCR_PINC) |
81 (0 << STM_DMA_CCR_CIRC) |
82 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
83 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
84 (0 << STM_SPI_CR2_RXNEIE) |
85 (0 << STM_SPI_CR2_ERRIE) |
86 (0 << STM_SPI_CR2_SSOE) |
87 (1 << STM_SPI_CR2_TXDMAEN) |
88 (1 << STM_SPI_CR2_RXDMAEN));
89 ao_dma_start(miso_dma_index);
90 ao_dma_start(mosi_dma_index);
92 while (!ao_dma_done[miso_dma_index])
93 ao_sleep(&ao_dma_done[miso_dma_index]);
95 ao_dma_done_transfer(mosi_dma_index);
96 ao_dma_done_transfer(miso_dma_index);
100 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
102 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
103 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
104 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
106 /* Set up the transmit DMA to deliver data */
107 ao_dma_set_transfer(mosi_dma_index,
111 (0 << STM_DMA_CCR_MEM2MEM) |
112 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
113 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
114 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
115 (0 << STM_DMA_CCR_MINC) |
116 (0 << STM_DMA_CCR_PINC) |
117 (0 << STM_DMA_CCR_CIRC) |
118 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
123 /* Set up the receive DMA -- when this is done, we know the SPI unit
124 * is idle. Without this, we'd have to poll waiting for the BSY bit to
127 ao_dma_set_transfer(miso_dma_index,
131 (0 << STM_DMA_CCR_MEM2MEM) |
132 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
133 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
134 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
135 (0 << STM_DMA_CCR_MINC) |
136 (0 << STM_DMA_CCR_PINC) |
137 (0 << STM_DMA_CCR_CIRC) |
138 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
139 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
140 (0 << STM_SPI_CR2_RXNEIE) |
141 (0 << STM_SPI_CR2_ERRIE) |
142 (0 << STM_SPI_CR2_SSOE) |
143 (1 << STM_SPI_CR2_TXDMAEN) |
144 (1 << STM_SPI_CR2_RXDMAEN));
145 ao_dma_start(miso_dma_index);
146 ao_dma_start(mosi_dma_index);
148 while (!ao_dma_done[miso_dma_index])
149 ao_sleep(&ao_dma_done[miso_dma_index]);
151 ao_dma_done_transfer(mosi_dma_index);
152 ao_dma_done_transfer(miso_dma_index);
156 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
158 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
159 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
160 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
162 /* Set up transmit DMA to make the SPI hardware actually run */
163 ao_dma_set_transfer(mosi_dma_index,
167 (0 << STM_DMA_CCR_MEM2MEM) |
168 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
169 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
170 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
171 (0 << STM_DMA_CCR_MINC) |
172 (0 << STM_DMA_CCR_PINC) |
173 (0 << STM_DMA_CCR_CIRC) |
174 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
179 /* Set up the receive DMA to capture data */
180 ao_dma_set_transfer(miso_dma_index,
184 (0 << STM_DMA_CCR_MEM2MEM) |
185 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
186 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
187 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
188 (1 << STM_DMA_CCR_MINC) |
189 (0 << STM_DMA_CCR_PINC) |
190 (0 << STM_DMA_CCR_CIRC) |
191 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
193 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
194 (0 << STM_SPI_CR2_RXNEIE) |
195 (0 << STM_SPI_CR2_ERRIE) |
196 (0 << STM_SPI_CR2_SSOE) |
197 (1 << STM_SPI_CR2_TXDMAEN) |
198 (1 << STM_SPI_CR2_RXDMAEN));
199 ao_dma_start(miso_dma_index);
200 ao_dma_start(mosi_dma_index);
202 /* Wait until the SPI unit is done */
204 while (!ao_dma_done[miso_dma_index])
205 ao_sleep(&ao_dma_done[miso_dma_index]);
208 ao_dma_done_transfer(mosi_dma_index);
209 ao_dma_done_transfer(miso_dma_index);
213 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
215 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
216 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
217 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
219 /* Set up transmit DMA to send data */
220 ao_dma_set_transfer(mosi_dma_index,
224 (0 << STM_DMA_CCR_MEM2MEM) |
225 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
226 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
227 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
228 (1 << STM_DMA_CCR_MINC) |
229 (0 << STM_DMA_CCR_PINC) |
230 (0 << STM_DMA_CCR_CIRC) |
231 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
236 /* Set up the receive DMA to capture data */
237 ao_dma_set_transfer(miso_dma_index,
241 (0 << STM_DMA_CCR_MEM2MEM) |
242 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
243 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
244 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
245 (1 << STM_DMA_CCR_MINC) |
246 (0 << STM_DMA_CCR_PINC) |
247 (0 << STM_DMA_CCR_CIRC) |
248 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
250 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
251 (0 << STM_SPI_CR2_RXNEIE) |
252 (0 << STM_SPI_CR2_ERRIE) |
253 (0 << STM_SPI_CR2_SSOE) |
254 (1 << STM_SPI_CR2_TXDMAEN) |
255 (1 << STM_SPI_CR2_RXDMAEN));
256 ao_dma_start(miso_dma_index);
257 ao_dma_start(mosi_dma_index);
259 /* Wait until the SPI unit is done */
261 while (!ao_dma_done[miso_dma_index])
262 ao_sleep(&ao_dma_done[miso_dma_index]);
265 ao_dma_done_transfer(mosi_dma_index);
266 ao_dma_done_transfer(miso_dma_index);
270 ao_spi_get(uint8_t spi_index)
272 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
274 ao_mutex_get(&ao_spi_mutex[spi_index]);
275 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
276 (0 << STM_SPI_CR1_BIDIOE) |
277 (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
278 (0 << STM_SPI_CR1_CRCNEXT) |
279 (0 << STM_SPI_CR1_DFF) |
280 (0 << STM_SPI_CR1_RXONLY) |
281 (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
282 (1 << STM_SPI_CR1_SSI) | /* ... */
283 (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
284 (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
285 (STM_SPI_CR1_BR_PCLK_4 << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
286 (1 << STM_SPI_CR1_MSTR) |
287 (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
288 (0 << STM_SPI_CR1_CPHA));
292 ao_spi_put(uint8_t spi_index)
294 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
297 ao_mutex_put(&ao_spi_mutex[spi_index]);
301 ao_spi_channel_init(uint8_t spi_index)
303 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
307 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
308 (0 << STM_SPI_CR2_RXNEIE) |
309 (0 << STM_SPI_CR2_ERRIE) |
310 (0 << STM_SPI_CR2_SSOE) |
311 (0 << STM_SPI_CR2_TXDMAEN) |
312 (0 << STM_SPI_CR2_RXDMAEN));
319 # if SPI_1_PA5_PA6_PA7
320 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
321 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
322 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
323 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
325 # if SPI_1_PB3_PB4_PB5
326 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
327 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
328 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
329 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
331 # if SPI_1_PE13_PE14_PE15
332 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
333 stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
334 stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
335 stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
337 # error "No SPI_1 port configuration specified"
342 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
344 ao_spi_channel_init(0);
348 # if SPI_2_PB13_PB14_PB15
349 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
350 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
351 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
352 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
354 # if SPI_2_PPD1_PD3_PD4
355 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
356 stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
357 stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
358 stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
360 # error "No SPI_2 port configuration specified"
364 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
366 ao_spi_channel_init(1);