altos: ADS124S0X driver compiles now
[fw/altos] / src / stm / ao_spi_stm_slave.c
1 /*
2  * Copyright © 2012 Keith Packard <keithp@keithp.com>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include <ao.h>
20
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;
25 };
26
27 static uint8_t          ao_spi_slave_mutex[STM_NUM_SPI];
28 static uint8_t          ao_spi_slave_index[STM_NUM_SPI];
29
30 static const struct ao_spi_stm_slave_info ao_spi_stm_slave_info[STM_NUM_SPI] = {
31         {
32                 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
33                 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
34                 &stm_spi1
35         },
36         {
37                 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
38                 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
39                 &stm_spi2
40         }
41 };
42
43 static uint8_t  spi_dev_null;
44
45 void
46 ao_spi_slave_send(void *block, uint16_t len)
47 {
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;
51
52         /* Set up the transmit DMA to deliver data */
53         ao_dma_set_transfer(mosi_dma_index,
54                             &stm_spi->dr,
55                             block,
56                             len,
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));
65
66         /* Clear RXNE */
67         (void) stm_spi->dr;
68
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
71          * be cleared
72          */
73         ao_dma_set_transfer(miso_dma_index,
74                             &stm_spi->dr,
75                             &spi_dev_null,
76                             len,
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);
93         ao_arch_critical(
94                 while (!ao_dma_done[miso_dma_index])
95                         ao_sleep(&ao_dma_done[miso_dma_index]);
96                 );
97         ao_dma_done_transfer(mosi_dma_index);
98         ao_dma_done_transfer(miso_dma_index);
99 }
100
101 uint8_t
102 ao_spi_slave_recv(void *block, uint16_t len)
103 {
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;
107
108         /* Set up transmit DMA to make the SPI hardware actually run */
109         ao_dma_set_transfer(mosi_dma_index,
110                             &stm_spi->dr,
111                             &spi_dev_null,
112                             len,
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));
121
122         /* Clear RXNE */
123         (void) stm_spi->dr;
124
125         /* Set up the receive DMA to capture data */
126         ao_dma_set_transfer(miso_dma_index,
127                             &stm_spi->dr,
128                             block,
129                             len,
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));
138
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);
147
148         /* Wait until the SPI unit is done */
149         ao_arch_critical(
150                 while (!ao_dma_done[miso_dma_index])
151                         ao_sleep(&ao_dma_done[miso_dma_index]);
152                 );
153
154         ao_dma_done_transfer(mosi_dma_index);
155         ao_dma_done_transfer(miso_dma_index);
156         return 1;
157 }
158
159 static void
160 ao_spi_slave_disable_index(uint8_t spi_index)
161 {
162         /* Disable current config
163          */
164         switch (AO_SPI_INDEX(spi_index)) {
165         case STM_SPI_INDEX(1):
166                 switch (spi_index) {
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);
172                         break;
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);
178                         break;
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);
184                         break;
185                 }
186                 break;
187         case STM_SPI_INDEX(2):
188                 switch (spi_index) {
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);
194                         break;
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);
200                         break;
201                 }
202                 break;
203         }
204 }
205
206 static void
207 ao_spi_slave_enable_index(uint8_t spi_index)
208 {
209         switch (AO_SPI_INDEX(spi_index)) {
210         case STM_SPI_INDEX(1):
211                 switch (spi_index) {
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);
216                         break;
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);
221                         break;
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);
226                         break;
227                 }
228                 break;
229         case STM_SPI_INDEX(2):
230                 switch (spi_index) {
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);
235                         break;
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);
240                         break;
241                 }
242                 break;
243         }
244 }
245
246 void
247 ao_spi_slave_get(uint8_t spi_index, uint32_t speed)
248 {
249         uint8_t         id = AO_SPI_INDEX(spi_index);
250         struct stm_spi  *stm_spi = ao_spi_stm_slave_info[id].stm_spi;
251
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]) {
268                 
269                 /* Disable old config
270                  */
271                 ao_spi_slave_disable_index(ao_spi_slave_index[id]);
272
273                 /* Enable new config
274                  */
275                 ao_spi_slave_enable_index(spi_index);
276                 
277                 /* Remember current config
278                  */
279                 ao_spi_slave_index[id] = spi_index;
280         }
281 }
282
283 void
284 ao_spi_slave_put(uint8_t spi_index)
285 {
286         uint8_t         id = AO_SPI_INDEX(spi_index);
287         struct stm_spi  *stm_spi = ao_spi_stm_slave_info[id].stm_spi;
288
289         stm_spi->cr1 = 0;
290         ao_mutex_put(&ao_spi_slave_mutex[id]);
291 }
292
293 static void
294 ao_spi_channel_init(uint8_t spi_index)
295 {
296         uint8_t         id = AO_SPI_INDEX(spi_index);
297         struct stm_spi  *stm_spi = ao_spi_stm_slave_info[id].stm_spi;
298
299         ao_spi_slave_disable_index(spi_index);
300
301         stm_spi->cr1 = 0;
302         (void) stm_spi->sr;
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));
309 }
310
311 void
312 ao_spi_slave_init(void)
313 {
314 #if HAS_SPI_SLAVE_1
315 # if SPI_1_PA5_PA6_PA7
316         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
317 # endif
318 # if SPI_1_PB3_PB4_PB5
319         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
320 # endif
321 # if SPI_1_PE13_PE14_PE15
322         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
323 # endif
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);
327 #endif
328
329 #if HAS_SPI_SLAVE_2
330 # if SPI_2_PB13_PB14_PB15
331         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
332 # endif
333 # if SPI_2_PD1_PD3_PD4
334         stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
335 # endif
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);
339 #endif
340 }