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];
27 static void (*ao_spi_callback[STM_NUM_SPI])(int spi_index);
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_setup_send(void *block, uint16_t len, uint8_t spi_index)
47 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
48 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
49 uint8_t miso_dma_index = ao_spi_stm_info[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));
93 ao_spi_start_send(uint8_t spi_index)
95 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
96 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
98 ao_dma_start(miso_dma_index);
99 ao_dma_start(mosi_dma_index);
103 ao_spi_finish_send(uint8_t spi_index)
105 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
106 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
108 ao_dma_done_transfer(mosi_dma_index);
109 ao_dma_done_transfer(miso_dma_index);
113 ao_spi_dma_isr(int spi_index)
115 ao_spi_callback[spi_index](spi_index);
116 ao_spi_finish_send(spi_index);
120 ao_spi_queue_send(void *block, uint16_t len, uint8_t spi_index,
121 void (*callback)(int spi_index))
123 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
125 ao_spi_setup_send(block, len, spi_index);
126 ao_spi_callback[spi_index] = callback;
127 ao_dma_set_isr(miso_dma_index, ao_spi_dma_isr, spi_index);
128 ao_spi_start_send(spi_index);
132 ao_spi_send(void *block, uint16_t len, uint8_t spi_index)
134 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
135 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
137 ao_spi_setup_send(block, len, spi_index);
138 ao_spi_start_send(spi_index);
140 while (!ao_dma_done[miso_dma_index])
141 ao_sleep(&ao_dma_done[miso_dma_index]);
144 ao_spi_finish_send(spi_index);
148 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
150 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
151 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
152 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
154 /* Set up the transmit DMA to deliver data */
155 ao_dma_set_transfer(mosi_dma_index,
159 (0 << STM_DMA_CCR_MEM2MEM) |
160 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
161 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
162 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
163 (0 << STM_DMA_CCR_MINC) |
164 (0 << STM_DMA_CCR_PINC) |
165 (0 << STM_DMA_CCR_CIRC) |
166 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
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_dma_set_transfer(miso_dma_index,
179 (0 << STM_DMA_CCR_MEM2MEM) |
180 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
181 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
182 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
183 (0 << STM_DMA_CCR_MINC) |
184 (0 << STM_DMA_CCR_PINC) |
185 (0 << STM_DMA_CCR_CIRC) |
186 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
187 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
188 (0 << STM_SPI_CR2_RXNEIE) |
189 (0 << STM_SPI_CR2_ERRIE) |
190 (0 << STM_SPI_CR2_SSOE) |
191 (1 << STM_SPI_CR2_TXDMAEN) |
192 (1 << STM_SPI_CR2_RXDMAEN));
193 ao_dma_start(miso_dma_index);
194 ao_dma_start(mosi_dma_index);
196 while (!ao_dma_done[miso_dma_index])
197 ao_sleep(&ao_dma_done[miso_dma_index]);
199 ao_dma_done_transfer(mosi_dma_index);
200 ao_dma_done_transfer(miso_dma_index);
204 ao_spi_setup_recv(void *block, uint16_t len, uint8_t spi_index)
206 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
207 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
208 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
210 /* Set up transmit DMA to make the SPI hardware actually run */
211 ao_dma_set_transfer(mosi_dma_index,
215 (0 << STM_DMA_CCR_MEM2MEM) |
216 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
217 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
218 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
219 (0 << STM_DMA_CCR_MINC) |
220 (0 << STM_DMA_CCR_PINC) |
221 (0 << STM_DMA_CCR_CIRC) |
222 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
227 /* Set up the receive DMA to capture data */
228 ao_dma_set_transfer(miso_dma_index,
232 (0 << STM_DMA_CCR_MEM2MEM) |
233 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
234 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
235 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
236 (1 << STM_DMA_CCR_MINC) |
237 (0 << STM_DMA_CCR_PINC) |
238 (0 << STM_DMA_CCR_CIRC) |
239 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
241 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
242 (0 << STM_SPI_CR2_RXNEIE) |
243 (0 << STM_SPI_CR2_ERRIE) |
244 (0 << STM_SPI_CR2_SSOE) |
245 (1 << STM_SPI_CR2_TXDMAEN) |
246 (1 << STM_SPI_CR2_RXDMAEN));
250 ao_spi_start_recv(uint8_t spi_index)
252 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
253 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
254 ao_dma_start(miso_dma_index);
255 ao_dma_start(mosi_dma_index);
259 ao_spi_done_recv(uint8_t spi_index)
261 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
262 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
263 ao_dma_done_transfer(mosi_dma_index);
264 ao_dma_done_transfer(miso_dma_index);
268 ao_spi_queue_recv(void *block, uint16_t len, uint8_t spi_index, void (*callback)(int spi_index))
270 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
271 ao_spi_setup_recv(block, len, spi_index);
272 ao_spi_callback[spi_index] = callback;
273 ao_dma_set_isr(miso_dma_index, ao_spi_dma_isr, spi_index);
274 ao_spi_start_recv(spi_index);
278 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
280 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
281 ao_spi_setup_recv(block, len, spi_index);
282 ao_spi_start_recv(spi_index);
283 /* Wait until the SPI unit is done */
285 while (!ao_dma_done[miso_dma_index])
286 ao_sleep(&ao_dma_done[miso_dma_index]);
288 ao_spi_done_recv(spi_index);
292 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
294 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
295 uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
296 uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
298 /* Set up transmit DMA to send data */
299 ao_dma_set_transfer(mosi_dma_index,
303 (0 << STM_DMA_CCR_MEM2MEM) |
304 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
305 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
306 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
307 (1 << STM_DMA_CCR_MINC) |
308 (0 << STM_DMA_CCR_PINC) |
309 (0 << STM_DMA_CCR_CIRC) |
310 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
315 /* Set up the receive DMA to capture data */
316 ao_dma_set_transfer(miso_dma_index,
320 (0 << STM_DMA_CCR_MEM2MEM) |
321 (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
322 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
323 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
324 (1 << STM_DMA_CCR_MINC) |
325 (0 << STM_DMA_CCR_PINC) |
326 (0 << STM_DMA_CCR_CIRC) |
327 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
329 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
330 (0 << STM_SPI_CR2_RXNEIE) |
331 (0 << STM_SPI_CR2_ERRIE) |
332 (0 << STM_SPI_CR2_SSOE) |
333 (1 << STM_SPI_CR2_TXDMAEN) |
334 (1 << STM_SPI_CR2_RXDMAEN));
335 ao_dma_start(miso_dma_index);
336 ao_dma_start(mosi_dma_index);
338 /* Wait until the SPI unit is done */
340 while (!ao_dma_done[miso_dma_index])
341 ao_sleep(&ao_dma_done[miso_dma_index]);
344 ao_dma_done_transfer(mosi_dma_index);
345 ao_dma_done_transfer(miso_dma_index);
349 ao_spi_get(uint8_t spi_index)
351 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
353 ao_mutex_get(&ao_spi_mutex[spi_index]);
354 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
355 (0 << STM_SPI_CR1_BIDIOE) |
356 (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
357 (0 << STM_SPI_CR1_CRCNEXT) |
358 (0 << STM_SPI_CR1_DFF) |
359 (0 << STM_SPI_CR1_RXONLY) |
360 (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
361 (1 << STM_SPI_CR1_SSI) | /* ... */
362 (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
363 (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
364 (STM_SPI_CR1_BR_PCLK_4 << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
365 (1 << STM_SPI_CR1_MSTR) |
366 (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
367 (0 << STM_SPI_CR1_CPHA));
371 ao_spi_put(uint8_t spi_index)
373 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
376 ao_mutex_put(&ao_spi_mutex[spi_index]);
380 ao_spi_channel_init(uint8_t spi_index)
382 struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
386 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
387 (0 << STM_SPI_CR2_RXNEIE) |
388 (0 << STM_SPI_CR2_ERRIE) |
389 (0 << STM_SPI_CR2_SSOE) |
390 (0 << STM_SPI_CR2_TXDMAEN) |
391 (0 << STM_SPI_CR2_RXDMAEN));
398 # if SPI_1_PA5_PA6_PA7
399 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
400 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
401 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
402 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
404 # if SPI_1_PB3_PB4_PB5
405 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
406 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
407 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
408 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
410 # if SPI_1_PE13_PE14_PE15
411 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
412 stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
413 stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
414 stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
416 # error "No SPI_1 port configuration specified"
421 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
423 ao_spi_channel_init(0);
427 # if SPI_2_PB13_PB14_PB15
428 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
429 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
430 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
431 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
433 # if SPI_2_PPD1_PD3_PD4
434 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
435 stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
436 stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
437 stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
439 # error "No SPI_2 port configuration specified"
443 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
445 ao_spi_channel_init(1);