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_slave_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_slave_mutex[STM_NUM_SPI];
28 static uint8_t ao_spi_slave_index[STM_NUM_SPI];
30 static const struct ao_spi_stm_slave_info ao_spi_stm_slave_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;
46 ao_spi_slave_send(void *block, uint16_t len)
48 struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi;
49 uint8_t mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index;
50 uint8_t miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index;
52 /* Set up the transmit DMA to deliver data */
53 ao_dma_set_transfer(mosi_dma_index,
57 (0 << STM_DMA_CCR_MEM2MEM) |
58 (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) |
59 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
60 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
61 (1 << STM_DMA_CCR_MINC) |
62 (0 << STM_DMA_CCR_PINC) |
63 (0 << STM_DMA_CCR_CIRC) |
64 (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
69 /* Set up the receive DMA -- when this is done, we know the SPI unit
70 * is idle. Without this, we'd have to poll waiting for the BSY bit to
73 ao_dma_set_transfer(miso_dma_index,
77 (0 << STM_DMA_CCR_MEM2MEM) |
78 (STM_DMA_CCR_PL_VERY_HIGH << STM_DMA_CCR_PL) |
79 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
80 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
81 (0 << STM_DMA_CCR_MINC) |
82 (0 << STM_DMA_CCR_PINC) |
83 (0 << STM_DMA_CCR_CIRC) |
84 (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
85 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
86 (0 << STM_SPI_CR2_RXNEIE) |
87 (0 << STM_SPI_CR2_ERRIE) |
88 (0 << STM_SPI_CR2_SSOE) |
89 (1 << STM_SPI_CR2_TXDMAEN) |
90 (1 << STM_SPI_CR2_RXDMAEN));
91 ao_dma_start(miso_dma_index);
92 ao_dma_start(mosi_dma_index);
94 while (!ao_dma_done[miso_dma_index])
95 ao_sleep(&ao_dma_done[miso_dma_index]);
97 ao_dma_done_transfer(mosi_dma_index);
98 ao_dma_done_transfer(miso_dma_index);
102 ao_spi_slave_recv(void *block, uint16_t len)
104 struct stm_spi *stm_spi = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].stm_spi;
105 uint8_t mosi_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].mosi_dma_index;
106 uint8_t miso_dma_index = ao_spi_stm_slave_info[AO_SPI_INDEX(SPI_SLAVE_INDEX)].miso_dma_index;
108 /* Set up transmit DMA to make the SPI hardware actually run */
109 ao_dma_set_transfer(mosi_dma_index,
113 (0 << STM_DMA_CCR_MEM2MEM) |
114 (STM_DMA_CCR_PL_HIGH << 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));
125 /* Set up the receive DMA to capture data */
126 ao_dma_set_transfer(miso_dma_index,
130 (0 << STM_DMA_CCR_MEM2MEM) |
131 (STM_DMA_CCR_PL_VERY_HIGH << STM_DMA_CCR_PL) |
132 (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
133 (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
134 (1 << STM_DMA_CCR_MINC) |
135 (0 << STM_DMA_CCR_PINC) |
136 (0 << STM_DMA_CCR_CIRC) |
137 (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 /* Wait until the SPI unit is done */
150 while (!ao_dma_done[miso_dma_index])
151 ao_sleep(&ao_dma_done[miso_dma_index]);
154 ao_dma_done_transfer(mosi_dma_index);
155 ao_dma_done_transfer(miso_dma_index);
160 ao_spi_slave_disable_index(uint8_t spi_index)
162 /* Disable current config
164 switch (AO_SPI_INDEX(spi_index)) {
165 case STM_SPI_INDEX(1):
167 case AO_SPI_1_PA5_PA6_PA7:
168 stm_gpio_set(&stm_gpioa, 5, 1);
169 stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
170 stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
171 stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
173 case AO_SPI_1_PB3_PB4_PB5:
174 stm_gpio_set(&stm_gpiob, 3, 1);
175 stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
176 stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
177 stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
179 case AO_SPI_1_PE13_PE14_PE15:
180 stm_gpio_set(&stm_gpioe, 13, 1);
181 stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
182 stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
183 stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
187 case STM_SPI_INDEX(2):
189 case AO_SPI_2_PB13_PB14_PB15:
190 stm_gpio_set(&stm_gpiob, 13, 1);
191 stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
192 stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
193 stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
195 case AO_SPI_2_PD1_PD3_PD4:
196 stm_gpio_set(&stm_gpiod, 1, 1);
197 stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
198 stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
199 stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
207 ao_spi_slave_enable_index(uint8_t spi_index)
209 switch (AO_SPI_INDEX(spi_index)) {
210 case STM_SPI_INDEX(1):
212 case AO_SPI_1_PA5_PA6_PA7:
213 stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
214 stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
215 stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
217 case AO_SPI_1_PB3_PB4_PB5:
218 stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
219 stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
220 stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
222 case AO_SPI_1_PE13_PE14_PE15:
223 stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
224 stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
225 stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
229 case STM_SPI_INDEX(2):
231 case AO_SPI_2_PB13_PB14_PB15:
232 stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
233 stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
234 stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
236 case AO_SPI_2_PD1_PD3_PD4:
237 stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
238 stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
239 stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
247 ao_spi_slave_get(uint8_t spi_index, uint32_t speed)
249 uint8_t id = AO_SPI_INDEX(spi_index);
250 struct stm_spi *stm_spi = ao_spi_stm_slave_info[id].stm_spi;
252 ao_mutex_get(&ao_spi_slave_mutex[id]);
253 stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
254 (0 << STM_SPI_CR1_BIDIOE) |
255 (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
256 (0 << STM_SPI_CR1_CRCNEXT) |
257 (0 << STM_SPI_CR1_DFF) |
258 (0 << STM_SPI_CR1_RXONLY) |
259 (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
260 (1 << STM_SPI_CR1_SSI) | /* ... */
261 (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
262 (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
263 (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
264 (1 << STM_SPI_CR1_MSTR) |
265 (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
266 (0 << STM_SPI_CR1_CPHA));
267 if (spi_index != ao_spi_slave_index[id]) {
269 /* Disable old config
271 ao_spi_slave_disable_index(ao_spi_slave_index[id]);
275 ao_spi_slave_enable_index(spi_index);
277 /* Remember current config
279 ao_spi_slave_index[id] = spi_index;
284 ao_spi_slave_put(uint8_t spi_index)
286 uint8_t id = AO_SPI_INDEX(spi_index);
287 struct stm_spi *stm_spi = ao_spi_stm_slave_info[id].stm_spi;
290 ao_mutex_put(&ao_spi_slave_mutex[id]);
294 ao_spi_channel_init(uint8_t spi_index)
296 uint8_t id = AO_SPI_INDEX(spi_index);
297 struct stm_spi *stm_spi = ao_spi_stm_slave_info[id].stm_spi;
299 ao_spi_slave_disable_index(spi_index);
303 stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
304 (0 << STM_SPI_CR2_RXNEIE) |
305 (0 << STM_SPI_CR2_ERRIE) |
306 (0 << STM_SPI_CR2_SSOE) |
307 (0 << STM_SPI_CR2_TXDMAEN) |
308 (0 << STM_SPI_CR2_RXDMAEN));
312 ao_spi_slave_init(void)
315 # if SPI_1_PA5_PA6_PA7
316 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
318 # if SPI_1_PB3_PB4_PB5
319 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
321 # if SPI_1_PE13_PE14_PE15
322 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
324 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
325 ao_spi_slave_index[0] = AO_SPI_CONFIG_NONE;
326 ao_spi_channel_init(0);
330 # if SPI_2_PB13_PB14_PB15
331 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
333 # if SPI_2_PD1_PD3_PD4
334 stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
336 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
337 ao_spi_slave_index[1] = AO_SPI_CONFIG_NONE;
338 ao_spi_channel_init(1);