altos/stm32f1: Allow PA6 to be left alone in the SPI code
[fw/altos] / src / stm32f1 / 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; 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_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_mutex[STM_NUM_SPI];
28 static uint8_t          ao_spi_pin_config[STM_NUM_SPI];
29
30 static const struct ao_spi_stm_info ao_spi_stm_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 #if DEBUG
46 static struct {
47         uint8_t task;
48         uint8_t which;
49         AO_TICK_TYPE tick;
50         uint16_t len;
51 } spi_tasks[64];
52 static uint8_t  spi_task_index;
53
54 static void
55 validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
56 {
57         uint32_t        sr = stm_spi->sr;
58
59         if (stm_spi != &stm_spi2)
60                 return;
61         spi_tasks[spi_task_index].task = ao_cur_task ? ao_cur_task->task_id : 0;
62         spi_tasks[spi_task_index].which = which;
63         spi_tasks[spi_task_index].tick = ao_time();
64         spi_tasks[spi_task_index].len = len;
65         spi_task_index = (spi_task_index + 1) & (63);
66         if (sr & (1 << STM_SPI_SR_FRE))
67                 ao_panic(0x40 | 1);
68         if (sr & (1 << STM_SPI_SR_BSY))
69                 ao_panic(0x40 | 2);
70         if (sr & (1 << STM_SPI_SR_OVR))
71                 ao_panic(0x40 | 3);
72         if (sr & (1 << STM_SPI_SR_MODF))
73                 ao_panic(0x40 | 4);
74         if (sr & (1 << STM_SPI_SR_UDR))
75                 ao_panic(0x40 | 5);
76         if ((sr & (1 << STM_SPI_SR_TXE)) == 0)
77                 ao_panic(0x40 | 6);
78         if (sr & (1 << STM_SPI_SR_RXNE))
79                 ao_panic(0x40 | 7);
80         if (which != 5 && which != 6 && which != 13)
81                 if (ao_cur_task->task_id != ao_spi_mutex[1])
82                         ao_panic(0x40 | 8);
83 }
84 #else
85 #define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
86 #endif
87
88 static void
89 ao_spi_set_dma_mosi(uint8_t id, const void *data, uint16_t len, uint32_t minc)
90 {
91         struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
92         uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
93
94         ao_dma_set_transfer(mosi_dma_index,
95                             &stm_spi->dr,
96                             (void *) data,
97                             len,
98                             (0 << STM_DMA_CCR_MEM2MEM) |
99                             (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
100                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
101                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
102                             (minc << STM_DMA_CCR_MINC) |
103                             (0 << STM_DMA_CCR_PINC) |
104                             (0 << STM_DMA_CCR_CIRC) |
105                             (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
106 }
107
108 static void
109 ao_spi_set_dma_miso(uint8_t id, void *data, uint16_t len, uint32_t minc)
110 {
111         struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
112         uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
113
114         ao_dma_set_transfer(miso_dma_index,
115                             &stm_spi->dr,
116                             data,
117                             len,
118                             (0 << STM_DMA_CCR_MEM2MEM) |
119                             (STM_DMA_CCR_PL_VERY_HIGH << STM_DMA_CCR_PL) |
120                             (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
121                             (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
122                             (minc << STM_DMA_CCR_MINC) |
123                             (0 << STM_DMA_CCR_PINC) |
124                             (0 << STM_DMA_CCR_CIRC) |
125                             (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
126 }
127
128 static void
129 ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
130 {
131         struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
132         uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
133         uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
134
135         validate_spi(stm_spi, which, len);
136
137         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
138                         (0 << STM_SPI_CR2_RXNEIE) |
139                         (0 << STM_SPI_CR2_ERRIE) |
140                         (0 << STM_SPI_CR2_SSOE) |
141                         (1 << STM_SPI_CR2_TXDMAEN) |
142                         (1 << STM_SPI_CR2_RXDMAEN));
143
144         ao_dma_start(miso_dma_index);
145         ao_dma_start(mosi_dma_index);
146
147         ao_arch_critical(
148                 while (!ao_dma_done[miso_dma_index])
149                         ao_sleep(&ao_dma_done[miso_dma_index]);
150                 );
151
152         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
153         while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
154
155         validate_spi(stm_spi, which+1, len);
156
157         stm_spi->cr2 = 0;
158
159         ao_dma_done_transfer(mosi_dma_index);
160         ao_dma_done_transfer(miso_dma_index);
161 }
162
163 void
164 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
165 {
166         uint8_t id = AO_SPI_INDEX(spi_index);
167
168         /* Set up the transmit DMA to deliver data */
169         ao_spi_set_dma_mosi(id, block, len, 1);
170
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
173          * be cleared
174          */
175         ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
176
177         ao_spi_run(id, 1, len);
178 }
179
180 void
181 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
182 {
183         uint8_t id = AO_SPI_INDEX(spi_index);
184
185         /* Set up the transmit DMA to deliver data */
186         ao_spi_set_dma_mosi(id, &value, len, 0);
187
188         /* Set up the receive DMA -- when this is done, we know the SPI unit
189          * is idle. Without this, we'd have to poll waiting for the BSY bit to
190          * be cleared
191          */
192         ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
193
194         ao_spi_run(id, 3, len);
195 }
196
197 void
198 ao_spi_start_bytes(uint8_t spi_index)
199 {
200         uint8_t         id = AO_SPI_INDEX(spi_index);
201         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
202
203         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
204                         (0 << STM_SPI_CR2_RXNEIE) |
205                         (0 << STM_SPI_CR2_ERRIE) |
206                         (0 << STM_SPI_CR2_SSOE) |
207                         (0 << STM_SPI_CR2_TXDMAEN) |
208                         (0 << STM_SPI_CR2_RXDMAEN));
209         validate_spi(stm_spi, 5, 0xffff);
210 }
211
212 void
213 ao_spi_stop_bytes(uint8_t spi_index)
214 {
215         uint8_t         id = AO_SPI_INDEX(spi_index);
216         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
217
218         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
219                 ;
220         while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
221                 ;
222         /* Clear the OVR flag */
223         (void) stm_spi->dr;
224         (void) stm_spi->sr;
225         validate_spi(stm_spi, 6, 0xffff);
226         stm_spi->cr2 = 0;
227 }
228
229 void
230 ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
231 {
232         uint8_t         id = AO_SPI_INDEX(spi_index);
233         const uint8_t   *b = block;
234         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
235
236         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
237                         (0 << STM_SPI_CR2_RXNEIE) |
238                         (0 << STM_SPI_CR2_ERRIE) |
239                         (0 << STM_SPI_CR2_SSOE) |
240                         (0 << STM_SPI_CR2_TXDMAEN) |
241                         (0 << STM_SPI_CR2_RXDMAEN));
242         validate_spi(stm_spi, 7, len);
243         while (len--) {
244                 while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
245                 stm_spi->dr = *b++;
246         }
247         while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
248                 ;
249         while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
250                 ;
251         /* Clear the OVR flag */
252         (void) stm_spi->dr;
253         (void) stm_spi->sr;
254         validate_spi(stm_spi, 8, len);
255 }
256
257 void
258 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
259 {
260         uint8_t         id = AO_SPI_INDEX(spi_index);
261
262         spi_dev_null = 0xff;
263
264         /* Set up transmit DMA to make the SPI hardware actually run */
265         ao_spi_set_dma_mosi(id, &spi_dev_null, len, 0);
266
267         /* Set up the receive DMA to capture data */
268         ao_spi_set_dma_miso(id, block, len, 1);
269
270         ao_spi_run(id, 9, len);
271 }
272
273 void
274 ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index)
275 {
276         uint8_t         id = AO_SPI_INDEX(spi_index);
277
278         /* Set up transmit DMA to send data */
279         ao_spi_set_dma_mosi(id, out, len, 1);
280
281         /* Set up the receive DMA to capture data */
282         ao_spi_set_dma_miso(id, in, len, 1);
283
284         ao_spi_run(id, 11, len);
285 }
286
287 #define stm_spi_input_disable(gpio, pin) do {                   \
288                 stm_gpio_conf(gpio, pin,                        \
289                               STM_GPIO_CR_MODE_INPUT,           \
290                               STM_GPIO_CR_CNF_INPUT_FLOATING);  \
291         } while(0)
292
293 #define stm_spi_output_disable(gpio, pin, mode) do {                    \
294                 ao_gpio_set(gpio, pin, 1);                              \
295                 stm_gpio_conf(gpio, pin,                                \
296                               mode,                                     \
297                               STM_GPIO_CR_CNF_OUTPUT_PUSH_PULL);        \
298         } while(0)
299
300 static void
301 ao_spi_disable_pin_config(uint8_t spi_pin_config)
302 {
303         /* Disable current config
304          */
305         switch (spi_pin_config) {
306 #if SPI_1_PA5_PA6_PA7
307         case AO_SPI_1_PA5_PA6_PA7:
308                 stm_spi_output_disable(&stm_gpioa, 5, SPI_1_MODE_OUTPUT);
309 #ifndef SPI_1_PA6_DISABLE
310                 stm_spi_input_disable(&stm_gpioa, 6);
311 #endif
312                 stm_spi_output_disable(&stm_gpioa, 7, SPI_1_MODE_OUTPUT);
313                 break;
314 #endif
315 #if SPI_1_PB3_PB4_PB5
316         case AO_SPI_1_PB3_PB4_PB5:
317                 stm_spi_output_disable(&stm_gpiob, 3, SPI_1_MODE_OUTPUT);
318                 stm_spi_input_disable(&stm_gpiob, 4);
319                 stm_spi_output_disable(&stm_gpiob, 5, SPI_1_MODE_OUTPUT);
320                 break;
321 #endif
322 #if SPI_2_PB13_PB14_PB15
323         case AO_SPI_2_PB13_PB14_PB15:
324                 stm_spi_output_disable(&stm_gpiob, 13, SPI_2_MODE_OUTPUT);
325                 stm_spi_input_disable(&stm_gpiob, 14);
326                 stm_spi_output_disable(&stm_gpiob, 15, SPI_2_MODE_OUTPUT);
327                 break;
328 #endif
329         }
330 }
331
332 #define stm_spi_input_enable(gpio, pin) do {                    \
333                 stm_gpio_conf(gpio, pin,                        \
334                               STM_GPIO_CR_MODE_INPUT,           \
335                               STM_GPIO_CR_CNF_INPUT_FLOATING);  \
336         } while(0)
337
338 #define stm_spi_output_enable(gpio, pin, mode) do {                     \
339                 stm_gpio_conf(gpio, pin,                                \
340                               mode,                                     \
341                               STM_GPIO_CR_CNF_OUTPUT_AF_PUSH_PULL);     \
342         } while(0)
343
344 static void
345 ao_spi_enable_pin_config(uint8_t spi_pin_config)
346 {
347         /* Enable new config
348          */
349         switch (spi_pin_config) {
350 #if SPI_1_PA5_PA6_PA7
351         case AO_SPI_1_PA5_PA6_PA7:
352                 stm_set_afio_mapr(STM_AFIO_MAPR_SPI1_REMAP,
353                                   STM_AFIO_MAPR_SPI1_REMAP_PA4_PA5_PA6_PA7,
354                                   STM_AFIO_MAPR_SPI1_REMAP_MASK);
355                 stm_spi_output_enable(&stm_gpioa, 5, SPI_1_MODE_OUTPUT);
356 #ifndef SPI_1_PA6_DISABLE
357                 stm_spi_input_enable(&stm_gpioa, 6);
358 #endif
359                 stm_spi_output_enable(&stm_gpioa, 7, SPI_1_MODE_OUTPUT);
360                 break;
361 #endif
362 #if SPI_1_PB3_PB4_PB5
363         case AO_SPI_1_PB3_PB4_PB5:
364                 stm_set_afio_mapr(STM_AFIO_MAPR_SPI1_REMAP,
365                                   STM_AFIO_MAPR_SPI1_REMAP_PA15_PB3_PB4_PB5,
366                                   STM_AFIO_MAPR_SPI1_REMAP_MASK);
367                 stm_spi_output_enable(&stm_gpiob, 3, SPI_1_MODE_OUTPUT);
368                 stm_spi_input_enable(&stm_gpiob, 4);
369                 stm_spi_output_enable(&stm_gpiob, 5, SPI_1_MODE_OUTPUT);
370                 break;
371 #endif
372 #if SPI_2_PB13_PB14_PB15
373         case AO_SPI_2_PB13_PB14_PB15:
374                 stm_spi_output_enable(&stm_gpiob, 13, SPI_2_MODE_OUTPUT);
375                 stm_spi_input_enable(&stm_gpiob, 14);
376                 stm_spi_output_enable(&stm_gpiob, 15, SPI_2_MODE_OUTPUT);
377                 break;
378 #endif
379         }
380 }
381
382 static void
383 ao_spi_config(uint8_t spi_index, uint32_t speed)
384 {
385         uint8_t         spi_pin_config = AO_SPI_PIN_CONFIG(spi_index);
386         uint8_t         id = AO_SPI_INDEX(spi_index);
387         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
388
389         if (spi_pin_config != ao_spi_pin_config[id]) {
390
391                 /* Disable old config
392                  */
393                 ao_spi_disable_pin_config(ao_spi_pin_config[id]);
394
395                 /* Enable new config
396                  */
397                 ao_spi_enable_pin_config(spi_pin_config);
398
399                 /* Remember current config
400                  */
401                 ao_spi_pin_config[id] = spi_pin_config;
402         }
403
404         /* Turn the SPI transceiver on and set the mode */
405         stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |           /* Three wire mode */
406                         (0 << STM_SPI_CR1_BIDIOE) |
407                         (0 << STM_SPI_CR1_CRCEN) |              /* CRC disabled */
408                         (0 << STM_SPI_CR1_CRCNEXT) |
409                         (0 << STM_SPI_CR1_DFF) |
410                         (0 << STM_SPI_CR1_RXONLY) |
411                         (1 << STM_SPI_CR1_SSM) |                /* Software SS handling */
412                         (1 << STM_SPI_CR1_SSI) |                /*  ... */
413                         (0 << STM_SPI_CR1_LSBFIRST) |           /* Big endian */
414                         (1 << STM_SPI_CR1_SPE) |                /* Enable SPI unit */
415                         (speed << STM_SPI_CR1_BR) |             /* baud rate to pclk/4 */
416                         (1 << STM_SPI_CR1_MSTR) |
417                         (AO_SPI_CPOL(spi_index) << STM_SPI_CR1_CPOL) |  /* Format */
418                         (AO_SPI_CPHA(spi_index) << STM_SPI_CR1_CPHA));
419         validate_spi(stm_spi, 13, 0);
420 }
421
422 uint8_t
423 ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
424 {
425         uint8_t         id = AO_SPI_INDEX(spi_index);
426
427         if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
428                 return 0;
429         ao_spi_config(spi_index, speed);
430         return 1;
431 }
432
433 void
434 ao_spi_get(uint8_t spi_index, uint32_t speed)
435 {
436         uint8_t         id = AO_SPI_INDEX(spi_index);
437
438         ao_mutex_get(&ao_spi_mutex[id]);
439         ao_spi_config(spi_index, speed);
440 }
441
442 void
443 ao_spi_put(uint8_t spi_index)
444 {
445         uint8_t         id = AO_SPI_INDEX(spi_index);
446         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
447
448         stm_spi->cr1 = 0;
449         ao_mutex_put(&ao_spi_mutex[id]);
450 }
451
452 void
453 ao_spi_put_pins(uint8_t spi_index)
454 {
455         uint8_t         id = AO_SPI_INDEX(spi_index);
456
457         ao_spi_disable_pin_config(ao_spi_pin_config[id]);
458         ao_spi_pin_config[id] = AO_SPI_CONFIG_NONE;
459         ao_spi_put(spi_index);
460 }
461
462 static void
463 ao_spi_channel_init(uint8_t spi_index)
464 {
465         uint8_t         id = AO_SPI_INDEX(spi_index);
466         struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
467
468         ao_spi_disable_pin_config(AO_SPI_PIN_CONFIG(spi_index));
469
470         stm_spi->cr1 = 0;
471         stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
472                         (0 << STM_SPI_CR2_RXNEIE) |
473                         (0 << STM_SPI_CR2_ERRIE) |
474                         (0 << STM_SPI_CR2_SSOE) |
475                         (0 << STM_SPI_CR2_TXDMAEN) |
476                         (0 << STM_SPI_CR2_RXDMAEN));
477
478         /* Clear any pending data and error flags */
479         (void) stm_spi->dr;
480         (void) stm_spi->sr;
481 }
482
483 #if DEBUG
484 void
485 ao_spi_dump_cmd(void)
486 {
487         int s;
488
489         for (s = 0; s < 64; s++) {
490                 int i = (spi_task_index + s) & 63;
491                 if (spi_tasks[i].which) {
492                         int t;
493                         const char *name = "(none)";
494                         for (t = 0; t < ao_num_tasks; t++)
495                                 if (ao_tasks[t]->task_id == spi_tasks[i].task) {
496                                         name = ao_tasks[t]->name;
497                                         break;
498                                 }
499                         printf("%2d: %5d task %2d which %2d len %5d %s\n",
500                                s,
501                                spi_tasks[i].tick,
502                                spi_tasks[i].task,
503                                spi_tasks[i].which,
504                                spi_tasks[i].len,
505                                name);
506                 }
507         }
508         for (s = 0; s < STM_NUM_SPI; s++) {
509                 struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
510
511                 printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
512                        s, ao_spi_mutex[s], ao_spi_index[s],
513                        ao_spi_stm_info[s].miso_dma_index,
514                        ao_spi_stm_info[s].mosi_dma_index);
515                 printf(" cr1 %04x cr2 %02x sr %03x\n",
516                        spi->cr1, spi->cr2, spi->sr);
517         }
518
519 }
520
521 static const struct ao_cmds ao_spi_cmds[] = {
522         { ao_spi_dump_cmd,      "S\0Dump SPI status" },
523         { 0, NULL }
524 };
525 #endif
526
527 void
528 ao_spi_init(void)
529 {
530 #if HAS_SPI_1
531 # if SPI_1_PA5_PA6_PA7
532         ao_enable_port(&stm_gpioa);
533 # endif
534 # if SPI_1_PB3_PB4_PB5
535         ao_enable_port(&stm_gpiob);
536 # endif
537         stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
538         ao_spi_pin_config[0] = AO_SPI_CONFIG_NONE;
539         ao_spi_channel_init(0);
540 #endif
541
542 #if HAS_SPI_2
543 # if SPI_2_PB13_PB14_PB15
544         ao_enable_port(&stm_gpiob);
545 # endif
546         stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
547         ao_spi_pin_config[1] = AO_SPI_CONFIG_NONE;
548         ao_spi_channel_init(1);
549 #endif
550 #if DEBUG
551         ao_cmd_register(&ao_spi_cmds[0]);
552 #endif
553 }