altos: Add DMA, SPI and MS5607 drivers
[fw/altos] / src / stm / ao_spi_stm.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; version 2 of the License.
7  *
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.
12  *
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.
16  */
17
18 #include <ao.h>
19
20 struct ao_spi_stm_info {
21         uint8_t miso_dma_index;
22         uint8_t mosi_dma_index;
23         struct stm_spi *stm_spi;
24 };
25
26 uint8_t ao_spi_mutex[STM_NUM_SPI];
27
28 static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
29         {
30                 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
31                 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
32                 &stm_spi1
33         },
34         {
35                 .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
36                 .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
37                 &stm_spi2
38         }
39 };
40
41 static uint8_t  spi_dev_null;
42
43 void
44 ao_spi_send(void *block, uint16_t len, uint8_t spi_index)
45 {
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;
49
50         ao_dma_set_transfer(mosi_dma_index,
51                             &stm_spi->dr,
52                             block,
53                             len,
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 */
63         (void) stm_spi->dr;
64         ao_dma_set_transfer(miso_dma_index,
65                             &stm_spi->dr,
66                             &spi_dev_null,
67                             len,
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);
84         ao_arch_critical(
85                 while (!ao_dma_done[miso_dma_index])
86                         ao_sleep(&ao_dma_done[miso_dma_index]);
87                 );
88         ao_dma_done_transfer(mosi_dma_index);
89         ao_dma_done_transfer(miso_dma_index);
90 }
91
92 void
93 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
94 {
95         struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
96 #if 0
97         uint8_t *d = block;
98
99         while (len--) {
100                 stm_spi->dr = 0xff;
101                 while (!(stm_spi->sr & (1 << STM_SPI_SR_RXNE)));
102                 *d++ = stm_spi->dr;
103         }
104         while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
105 #else
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;
108
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_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 */
122         (void) stm_spi->dr;
123         ao_dma_set_transfer(miso_dma_index,
124                             &stm_spi->dr,
125                             block,
126                             len,
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);
143         ao_arch_critical(
144                 while (!ao_dma_done[miso_dma_index])
145                         ao_sleep(&ao_dma_done[miso_dma_index]);
146                 );
147         ao_dma_done_transfer(mosi_dma_index);
148         ao_dma_done_transfer(miso_dma_index);
149 #endif
150 }
151
152 static void
153 ao_spi_channel_init(uint8_t spi_index)
154 {
155         struct stm_spi  *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
156
157         stm_spi->cr1 = 0;
158         (void) stm_spi->sr;
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));
179 }
180
181 void
182 ao_spi_init(void)
183 {
184 #if HAS_SPI_1
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);
190 # else
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);
196 #  else
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);
202 #   else
203 #    error "No SPI_1 port configuration specified"
204 #   endif
205 #  endif
206 # endif
207
208         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
209
210         ao_spi_channel_init(0);
211
212         stm_nvic_set_enable(STM_ISR_SPI1_POS);
213         stm_nvic_set_priority(STM_ISR_SPI1_POS, 3);
214 #endif
215
216 #if HAS_SPI_2
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);
222 # else
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);
228 #  else
229 #   error "No SPI_2 port configuration specified"
230 #  endif
231 # endif
232
233         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
234
235         ao_spi_channel_init(1);
236
237         stm_nvic_set_enable(STM_ISR_SPI2_POS);
238         stm_nvic_set_priority(STM_ISR_SPI2_POS, 3);
239 #endif
240 }