altos/telefireone-v1.0: Track ao_led_init API change
[fw/altos] / src / stm / ao_spi_stm.c
index 3b5773b6ed75e70da31d498eaaf0ecf467356a18..1a04a2899a825afa758726d5625d3c11a7536c34 100644 (file)
@@ -3,7 +3,8 @@
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -24,7 +25,7 @@ struct ao_spi_stm_info {
 };
 
 static uint8_t         ao_spi_mutex[STM_NUM_SPI];
-static uint8_t         ao_spi_index[STM_NUM_SPI];
+static uint8_t         ao_spi_pin_config[STM_NUM_SPI];
 
 static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
        {
@@ -84,123 +85,153 @@ 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
 
-void
-ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
+static void
+ao_spi_set_dma_mosi(uint8_t id, const void *data, uint16_t len, uint32_t minc)
 {
-       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;
+       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;
 
-       /* Set up the transmit DMA to deliver data */
        ao_dma_set_transfer(mosi_dma_index,
                            &stm_spi->dr,
-                           (void *) block,
+                           (void *) data,
                            len,
                            (0 << STM_DMA_CCR_MEM2MEM) |
                            (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
                            (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
                            (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
-                           (1 << STM_DMA_CCR_MINC) |
+                           (minc << STM_DMA_CCR_MINC) |
                            (0 << STM_DMA_CCR_PINC) |
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
+}
 
-       /* Clear RXNE */
-       (void) stm_spi->dr;
+static void
+ao_spi_set_dma_miso(uint8_t id, void *data, uint16_t len, uint32_t minc)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+       uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
 
-       /* 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
-        */
        ao_dma_set_transfer(miso_dma_index,
                            &stm_spi->dr,
-                           &spi_dev_null,
+                           data,
                            len,
                            (0 << STM_DMA_CCR_MEM2MEM) |
-                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) |
                            (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
                            (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
-                           (0 << STM_DMA_CCR_MINC) |
+                           (minc << STM_DMA_CCR_MINC) |
                            (0 << STM_DMA_CCR_PINC) |
                            (0 << STM_DMA_CCR_CIRC) |
                            (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+}
+
+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_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
+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);
 
        /* Set up the transmit DMA to deliver data */
-       ao_dma_set_transfer(mosi_dma_index,
-                           &stm_spi->dr,
-                           &value,
-                           len,
-                           (0 << STM_DMA_CCR_MEM2MEM) |
-                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
-                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
-                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
-                           (0 << STM_DMA_CCR_MINC) |
-                           (0 << STM_DMA_CCR_PINC) |
-                           (0 << STM_DMA_CCR_CIRC) |
-                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
+       ao_spi_set_dma_mosi(id, block, len, 1);
 
-       /* 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
+        */
+       ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
+
+       ao_spi_run(id, 1, len);
+}
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
+{
+       uint8_t id = AO_SPI_INDEX(spi_index);
+
+       /* Set up the transmit DMA to deliver data */
+       ao_spi_set_dma_mosi(id, &value, len, 0);
 
        /* 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
         */
-       ao_dma_set_transfer(miso_dma_index,
-                           &stm_spi->dr,
-                           &spi_dev_null,
-                           len,
-                           (0 << STM_DMA_CCR_MEM2MEM) |
-                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
-                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
-                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
-                           (0 << STM_DMA_CCR_MINC) |
-                           (0 << STM_DMA_CCR_PINC) |
-                           (0 << STM_DMA_CCR_CIRC) |
-                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+       ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
+
+       ao_spi_run(id, 3, len);
+}
+
+void
+ao_spi_start_bytes(uint8_t spi_index)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       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) |
                        (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);
+                       (0 << STM_SPI_CR2_TXDMAEN) |
+                       (0 << STM_SPI_CR2_RXDMAEN));
+       validate_spi(stm_spi, 5, 0xffff);
+}
+
+void
+ao_spi_stop_bytes(uint8_t spi_index)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+       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, 6, 0xffff);
+       stm_spi->cr2 = 0;
 }
 
 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,215 +239,120 @@ 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);
 
        spi_dev_null = 0xff;
 
        /* Set up transmit DMA to make the SPI hardware actually run */
-       ao_dma_set_transfer(mosi_dma_index,
-                           &stm_spi->dr,
-                           &spi_dev_null,
-                           len,
-                           (0 << STM_DMA_CCR_MEM2MEM) |
-                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
-                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
-                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
-                           (0 << STM_DMA_CCR_MINC) |
-                           (0 << STM_DMA_CCR_PINC) |
-                           (0 << STM_DMA_CCR_CIRC) |
-                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
-
-       /* Clear RXNE */
-       (void) stm_spi->dr;
+       ao_spi_set_dma_mosi(id, &spi_dev_null, len, 0);
 
        /* Set up the receive DMA to capture data */
-       ao_dma_set_transfer(miso_dma_index,
-                           &stm_spi->dr,
-                           block,
-                           len,
-                           (0 << STM_DMA_CCR_MEM2MEM) |
-                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
-                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
-                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
-                           (1 << STM_DMA_CCR_MINC) |
-                           (0 << STM_DMA_CCR_PINC) |
-                           (0 << STM_DMA_CCR_CIRC) |
-                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+       ao_spi_set_dma_miso(id, block, len, 1);
 
-       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)
+ao_spi_duplex(const 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);
 
        /* Set up transmit DMA to send data */
-       ao_dma_set_transfer(mosi_dma_index,
-                           &stm_spi->dr,
-                           out,
-                           len,
-                           (0 << STM_DMA_CCR_MEM2MEM) |
-                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
-                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
-                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
-                           (1 << STM_DMA_CCR_MINC) |
-                           (0 << STM_DMA_CCR_PINC) |
-                           (0 << STM_DMA_CCR_CIRC) |
-                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
-
-       /* Clear RXNE */
-       (void) stm_spi->dr;
+       ao_spi_set_dma_mosi(id, out, len, 1);
 
        /* Set up the receive DMA to capture data */
-       ao_dma_set_transfer(miso_dma_index,
-                           &stm_spi->dr,
-                           in,
-                           len,
-                           (0 << STM_DMA_CCR_MEM2MEM) |
-                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
-                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
-                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
-                           (1 << STM_DMA_CCR_MINC) |
-                           (0 << STM_DMA_CCR_PINC) |
-                           (0 << STM_DMA_CCR_CIRC) |
-                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+       ao_spi_set_dma_miso(id, in, len, 1);
 
-       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
-ao_spi_disable_index(uint8_t spi_index)
+ao_spi_disable_pin_config(uint8_t spi_pin_config)
 {
        /* Disable current config
         */
-       switch (AO_SPI_INDEX(spi_index)) {
-       case STM_SPI_INDEX(1):
-               switch (spi_index) {
-               case AO_SPI_1_PA5_PA6_PA7:
-                       stm_gpio_set(&stm_gpioa, 5, 1);
-                       stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
-                       stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
-                       stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
-                       break;
-               case AO_SPI_1_PB3_PB4_PB5:
-                       stm_gpio_set(&stm_gpiob, 3, 1);
-                       stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
-                       stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
-                       stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
-                       break;
-               case AO_SPI_1_PE13_PE14_PE15:
-                       stm_gpio_set(&stm_gpioe, 13, 1);
-                       stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
-                       stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
-                       stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
-                       break;
-               }
+       switch (spi_pin_config) {
+       case AO_SPI_1_PA5_PA6_PA7:
+               stm_gpio_set(&stm_gpioa, 5, 1);
+               stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
+               stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
+               stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
                break;
-       case STM_SPI_INDEX(2):
-               switch (spi_index) {
-               case AO_SPI_2_PB13_PB14_PB15:
-                       stm_gpio_set(&stm_gpiob, 13, 1);
-                       stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
-                       stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
-                       stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
-                       break;
-               case AO_SPI_2_PD1_PD3_PD4:
-                       stm_gpio_set(&stm_gpiod, 1, 1);
-                       stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
-                       stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
-                       stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
-                       break;
-               }
+       case AO_SPI_1_PB3_PB4_PB5:
+               stm_gpio_set(&stm_gpiob, 3, 1);
+               stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
+               stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
+               stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
+               break;
+       case AO_SPI_1_PE13_PE14_PE15:
+               stm_gpio_set(&stm_gpioe, 13, 1);
+               stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
+               stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
+               stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
+               break;
+       case AO_SPI_2_PB13_PB14_PB15:
+               stm_gpio_set(&stm_gpiob, 13, 1);
+               stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
+               stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
+               stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
+               break;
+       case AO_SPI_2_PD1_PD3_PD4:
+               stm_gpio_set(&stm_gpiod, 1, 1);
+               stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
+               stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
+               stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
                break;
        }
 }
 
 static void
-ao_spi_enable_index(uint8_t spi_index)
+ao_spi_enable_pin_config(uint8_t spi_pin_config)
 {
-       switch (AO_SPI_INDEX(spi_index)) {
-       case STM_SPI_INDEX(1):
-               switch (spi_index) {
-               case AO_SPI_1_PA5_PA6_PA7:
-                       stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
-                       break;
-               case AO_SPI_1_PB3_PB4_PB5:
-                       stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
-                       break;
-               case AO_SPI_1_PE13_PE14_PE15:
-                       stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
-                       break;
-               }
+       /* Enable new config
+        */
+       switch (spi_pin_config) {
+       case AO_SPI_1_PA5_PA6_PA7:
+               stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
+               stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
+               stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
                break;
-       case STM_SPI_INDEX(2):
-               switch (spi_index) {
-               case AO_SPI_2_PB13_PB14_PB15:
-                       stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
-                       break;
-               case AO_SPI_2_PD1_PD3_PD4:
-                       stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
-                       stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
-                       break;
-               }
+       case AO_SPI_1_PB3_PB4_PB5:
+               stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
+               stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
+               stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
+               break;
+       case AO_SPI_1_PE13_PE14_PE15:
+               stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
+               stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
+               stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
+               break;
+       case AO_SPI_2_PB13_PB14_PB15:
+               stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
+               stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
+               stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
+               break;
+       case AO_SPI_2_PD1_PD3_PD4:
+               stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
+               stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
+               stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
                break;
        }
 }
@@ -424,36 +360,41 @@ ao_spi_enable_index(uint8_t spi_index)
 static void
 ao_spi_config(uint8_t spi_index, uint32_t speed)
 {
+       uint8_t         spi_pin_config = AO_SPI_PIN_CONFIG(spi_index);
        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]) {
+
+       if (spi_pin_config != ao_spi_pin_config[id]) {
 
                /* Disable old config
                 */
-               ao_spi_disable_index(ao_spi_index[id]);
+               ao_spi_disable_pin_config(ao_spi_pin_config[id]);
 
                /* Enable new config
                 */
-               ao_spi_enable_index(spi_index);
+               ao_spi_enable_pin_config(spi_pin_config);
 
                /* Remember current config
                 */
-               ao_spi_index[id] = spi_index;
+               ao_spi_pin_config[id] = spi_pin_config;
        }
+
+       /* Turn the SPI transceiver on and set the mode */
+       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) |
+                       (AO_SPI_CPOL(spi_index) << STM_SPI_CR1_CPOL) |  /* Format */
+                       (AO_SPI_CPHA(spi_index) << STM_SPI_CR1_CPHA));
+       validate_spi(stm_spi, 13, 0);
 }
 
 uint8_t
@@ -471,6 +412,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);
 }
@@ -491,16 +433,19 @@ ao_spi_channel_init(uint8_t spi_index)
        uint8_t         id = AO_SPI_INDEX(spi_index);
        struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
 
-       ao_spi_disable_index(spi_index);
+       ao_spi_disable_pin_config(AO_SPI_PIN_CONFIG(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
@@ -570,7 +515,7 @@ ao_spi_init(void)
        stm_ospeedr_set(&stm_gpioe, 15, SPI_1_OSPEEDR);
 # endif
        stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
-       ao_spi_index[0] = AO_SPI_CONFIG_NONE;
+       ao_spi_pin_config[0] = AO_SPI_CONFIG_NONE;
        ao_spi_channel_init(0);
 #endif
 
@@ -588,7 +533,7 @@ ao_spi_init(void)
        stm_ospeedr_set(&stm_gpiod, 4, SPI_2_OSPEEDR);
 # endif
        stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
-       ao_spi_index[1] = AO_SPI_CONFIG_NONE;
+       ao_spi_pin_config[1] = AO_SPI_CONFIG_NONE;
        ao_spi_channel_init(1);
 #endif
 #if DEBUG