altos/stm: move spi execution to common ao_spi_run
[fw/altos] / src / stm / ao_spi_stm.c
index 3b5773b6ed75e70da31d498eaaf0ecf467356a18..2b6834fdd36a0fa4e12e7ec1b5853e72406336b8 100644 (file)
@@ -84,12 +84,48 @@ validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
 #define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
 #endif
 
+static void
+ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
+
+       validate_spi(stm_spi, which, len);
+
+       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+                       (0 << STM_SPI_CR2_RXNEIE) |
+                       (0 << STM_SPI_CR2_ERRIE) |
+                       (0 << STM_SPI_CR2_SSOE) |
+                       (1 << STM_SPI_CR2_TXDMAEN) |
+                       (1 << STM_SPI_CR2_RXDMAEN));
+
+       ao_dma_start(miso_dma_index);
+       ao_dma_start(mosi_dma_index);
+
+       ao_arch_critical(
+               while (!ao_dma_done[miso_dma_index])
+                       ao_sleep(&ao_dma_done[miso_dma_index]);
+               );
+
+       while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
+       while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
+
+       validate_spi(stm_spi, which+1, len);
+
+       stm_spi->cr2 = 0;
+
+       ao_dma_done_transfer(mosi_dma_index);
+       ao_dma_done_transfer(miso_dma_index);
+}
+
 void
 ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
 {
-       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
-       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
-       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+       uint8_t id = AO_SPI_INDEX(spi_index);
+       struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
 
        /* Set up the transmit DMA to deliver data */
        ao_dma_set_transfer(mosi_dma_index,
@@ -105,9 +141,6 @@ ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
 
-       /* Clear RXNE */
-       (void) stm_spi->dr;
-
        /* Set up the receive DMA -- when this is done, we know the SPI unit
         * is idle. Without this, we'd have to poll waiting for the BSY bit to
         * be cleared
@@ -124,28 +157,17 @@ ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
                            (0 << STM_DMA_CCR_PINC) |
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
-       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
-                       (0 << STM_SPI_CR2_RXNEIE) |
-                       (0 << STM_SPI_CR2_ERRIE) |
-                       (0 << STM_SPI_CR2_SSOE) |
-                       (1 << STM_SPI_CR2_TXDMAEN) |
-                       (1 << STM_SPI_CR2_RXDMAEN));
-       ao_dma_start(miso_dma_index);
-       ao_dma_start(mosi_dma_index);
-       ao_arch_critical(
-               while (!ao_dma_done[miso_dma_index])
-                       ao_sleep(&ao_dma_done[miso_dma_index]);
-               );
-       ao_dma_done_transfer(mosi_dma_index);
-       ao_dma_done_transfer(miso_dma_index);
+
+       ao_spi_run(id, 1, len);
 }
 
 void
 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
 {
-       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
-       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
-       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+       uint8_t id = AO_SPI_INDEX(spi_index);
+       struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
 
        /* Set up the transmit DMA to deliver data */
        ao_dma_set_transfer(mosi_dma_index,
@@ -161,9 +183,6 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
 
-       /* Clear RXNE */
-       (void) stm_spi->dr;
-
        /* Set up the receive DMA -- when this is done, we know the SPI unit
         * is idle. Without this, we'd have to poll waiting for the BSY bit to
         * be cleared
@@ -180,27 +199,16 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
                            (0 << STM_DMA_CCR_PINC) |
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
-       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
-                       (0 << STM_SPI_CR2_RXNEIE) |
-                       (0 << STM_SPI_CR2_ERRIE) |
-                       (0 << STM_SPI_CR2_SSOE) |
-                       (1 << STM_SPI_CR2_TXDMAEN) |
-                       (1 << STM_SPI_CR2_RXDMAEN));
-       ao_dma_start(miso_dma_index);
-       ao_dma_start(mosi_dma_index);
-       ao_arch_critical(
-               while (!ao_dma_done[miso_dma_index])
-                       ao_sleep(&ao_dma_done[miso_dma_index]);
-               );
-       ao_dma_done_transfer(mosi_dma_index);
-       ao_dma_done_transfer(miso_dma_index);
+
+       ao_spi_run(id, 3, len);
 }
 
 void
 ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
 {
-       uint8_t         *b = block;
-       struct stm_spi  *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       const uint8_t   *b = block;
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
 
        stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
                        (0 << STM_SPI_CR2_RXNEIE) |
@@ -208,22 +216,28 @@ ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
                        (0 << STM_SPI_CR2_SSOE) |
                        (0 << STM_SPI_CR2_TXDMAEN) |
                        (0 << STM_SPI_CR2_RXDMAEN));
-
-       /* Clear RXNE */
-       (void) stm_spi->dr;
-
+       validate_spi(stm_spi, 7, len);
        while (len--) {
                while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
                stm_spi->dr = *b++;
        }
+       while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
+               ;
+       while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
+               ;
+       /* Clear the OVR flag */
+       (void) stm_spi->dr;
+       (void) stm_spi->sr;
+       validate_spi(stm_spi, 8, len);
 }
 
 void
 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
 {
-       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
-       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
-       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
+       uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+       uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
 
        spi_dev_null = 0xff;
 
@@ -241,9 +255,6 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
 
-       /* Clear RXNE */
-       (void) stm_spi->dr;
-
        /* Set up the receive DMA to capture data */
        ao_dma_set_transfer(miso_dma_index,
                            &stm_spi->dr,
@@ -258,31 +269,16 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
 
-       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
-                       (0 << STM_SPI_CR2_RXNEIE) |
-                       (0 << STM_SPI_CR2_ERRIE) |
-                       (0 << STM_SPI_CR2_SSOE) |
-                       (1 << STM_SPI_CR2_TXDMAEN) |
-                       (1 << STM_SPI_CR2_RXDMAEN));
-       ao_dma_start(miso_dma_index);
-       ao_dma_start(mosi_dma_index);
-
-       /* Wait until the SPI unit is done */
-       ao_arch_critical(
-               while (!ao_dma_done[miso_dma_index])
-                       ao_sleep(&ao_dma_done[miso_dma_index]);
-               );
-
-       ao_dma_done_transfer(mosi_dma_index);
-       ao_dma_done_transfer(miso_dma_index);
+       ao_spi_run(id, 9, len);
 }
 
 void
 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
 {
-       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
-       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
-       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
+       uint8_t         mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+       uint8_t         miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
 
        /* Set up transmit DMA to send data */
        ao_dma_set_transfer(mosi_dma_index,
@@ -298,9 +294,6 @@ ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
 
-       /* Clear RXNE */
-       (void) stm_spi->dr;
-
        /* Set up the receive DMA to capture data */
        ao_dma_set_transfer(miso_dma_index,
                            &stm_spi->dr,
@@ -314,24 +307,7 @@ ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
                            (0 << STM_DMA_CCR_PINC) |
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
-
-       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
-                       (0 << STM_SPI_CR2_RXNEIE) |
-                       (0 << STM_SPI_CR2_ERRIE) |
-                       (0 << STM_SPI_CR2_SSOE) |
-                       (1 << STM_SPI_CR2_TXDMAEN) |
-                       (1 << STM_SPI_CR2_RXDMAEN));
-       ao_dma_start(miso_dma_index);
-       ao_dma_start(mosi_dma_index);
-
-       /* Wait until the SPI unit is done */
-       ao_arch_critical(
-               while (!ao_dma_done[miso_dma_index])
-                       ao_sleep(&ao_dma_done[miso_dma_index]);
-               );
-
-       ao_dma_done_transfer(mosi_dma_index);
-       ao_dma_done_transfer(miso_dma_index);
+       ao_spi_run(id, 11, len);
 }
 
 static void
@@ -426,20 +402,7 @@ ao_spi_config(uint8_t spi_index, uint32_t speed)
 {
        uint8_t         id = AO_SPI_INDEX(spi_index);
        struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
-       stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |                   /* Three wire mode */
-                       (0 << STM_SPI_CR1_BIDIOE) |
-                       (0 << STM_SPI_CR1_CRCEN) |                      /* CRC disabled */
-                       (0 << STM_SPI_CR1_CRCNEXT) |
-                       (0 << STM_SPI_CR1_DFF) |
-                       (0 << STM_SPI_CR1_RXONLY) |
-                       (1 << STM_SPI_CR1_SSM) |                        /* Software SS handling */
-                       (1 << STM_SPI_CR1_SSI) |                        /*  ... */
-                       (0 << STM_SPI_CR1_LSBFIRST) |                   /* Big endian */
-                       (1 << STM_SPI_CR1_SPE) |                        /* Enable SPI unit */
-                       (speed << STM_SPI_CR1_BR) |     /* baud rate to pclk/4 */
-                       (1 << STM_SPI_CR1_MSTR) |
-                       (0 << STM_SPI_CR1_CPOL) |                       /* Format 0 */
-                       (0 << STM_SPI_CR1_CPHA));
+
        if (spi_index != ao_spi_index[id]) {
 
                /* Disable old config
@@ -454,6 +417,21 @@ ao_spi_config(uint8_t spi_index, uint32_t speed)
                 */
                ao_spi_index[id] = spi_index;
        }
+       stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |           /* Three wire mode */
+                       (0 << STM_SPI_CR1_BIDIOE) |
+                       (0 << STM_SPI_CR1_CRCEN) |              /* CRC disabled */
+                       (0 << STM_SPI_CR1_CRCNEXT) |
+                       (0 << STM_SPI_CR1_DFF) |
+                       (0 << STM_SPI_CR1_RXONLY) |
+                       (1 << STM_SPI_CR1_SSM) |                /* Software SS handling */
+                       (1 << STM_SPI_CR1_SSI) |                /*  ... */
+                       (0 << STM_SPI_CR1_LSBFIRST) |           /* Big endian */
+                       (1 << STM_SPI_CR1_SPE) |                /* Enable SPI unit */
+                       (speed << STM_SPI_CR1_BR) |             /* baud rate to pclk/4 */
+                       (1 << STM_SPI_CR1_MSTR) |
+                       (0 << STM_SPI_CR1_CPOL) |               /* Format 0 */
+                       (0 << STM_SPI_CR1_CPHA));
+       validate_spi(stm_spi, 13, 0);
 }
 
 uint8_t
@@ -471,6 +449,7 @@ void
 ao_spi_get(uint8_t spi_index, uint32_t speed)
 {
        uint8_t         id = AO_SPI_INDEX(spi_index);
+
        ao_mutex_get(&ao_spi_mutex[id]);
        ao_spi_config(spi_index, speed);
 }
@@ -494,13 +473,16 @@ ao_spi_channel_init(uint8_t spi_index)
        ao_spi_disable_index(spi_index);
 
        stm_spi->cr1 = 0;
-       (void) stm_spi->sr;
        stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
                        (0 << STM_SPI_CR2_RXNEIE) |
                        (0 << STM_SPI_CR2_ERRIE) |
                        (0 << STM_SPI_CR2_SSOE) |
                        (0 << STM_SPI_CR2_TXDMAEN) |
                        (0 << STM_SPI_CR2_RXDMAEN));
+
+       /* Clear any pending data and error flags */
+       (void) stm_spi->dr;
+       (void) stm_spi->sr;
 }
 
 #if DEBUG