Revert LPC usb performance improvements
[fw/altos] / src / lpc / ao_spi_lpc.c
index 05688f5205f205ad72bd3a4861cda3c8d25f7b60..5a358919937c7027e5af06b71fd97dac95168cdb 100644 (file)
 
 static uint8_t         ao_spi_mutex[LPC_NUM_SPI];
 
+struct ao_lpc_ssp_state {
+       int             tx_count;
+       const uint8_t   *tx;
+       int             tx_inc;
+       int             rx_count;
+       uint8_t         *rx;
+       int             rx_inc;
+};
+
+static struct ao_lpc_ssp_state ao_lpc_ssp_state[LPC_NUM_SPI];
+
 static struct lpc_ssp * const ao_lpc_ssp[LPC_NUM_SPI] = { &lpc_ssp0, &lpc_ssp1 };
 
-static uint8_t spi_dev_null;
-
-#define spi_loop(len, put, get) do {                                   \
-               while (len--) {                                         \
-                       /* Wait for space in the fifo */                \
-                       while ((lpc_ssp->sr & (1 << LPC_SSP_SR_TNF)) == 0) \
-                               ;                                       \
-                       /* send a byte */                               \
-                       lpc_ssp->dr = put;                              \
-                                                                       \
-                       /* recv a byte */                               \
-                       get lpc_ssp->dr;                                \
-               }                                                       \
-                                                                       \
-               /* Wait for the fifo to drain */                        \
-               while ((lpc_ssp->sr & (1 << LPC_SSP_SR_BSY)))           \
-                       ;                                               \
-       } while (0);
+static inline void
+ao_lpc_ssp_recv(struct lpc_ssp *lpc_ssp, struct ao_lpc_ssp_state *state)
+{
+       while ((lpc_ssp->sr & (1 << LPC_SSP_SR_RNE)) &&
+              state->rx_count)
+       {
+               /* RX ready, read a byte */
+               *state->rx = lpc_ssp->dr;
+               state->rx += state->rx_inc;
+               state->rx_count--;
+       }
+}
+
+static void
+ao_lpc_ssp_isr(struct lpc_ssp *lpc_ssp, struct ao_lpc_ssp_state *state)
+{
+       ao_lpc_ssp_recv(lpc_ssp, state);
+       while ((lpc_ssp->sr & (1 << LPC_SSP_SR_TNF)) &&
+              state->tx_count)
+       {
+               /* TX ready, write a byte */
+               lpc_ssp->dr = *state->tx;
+               state->tx += state->tx_inc;
+               state->tx_count--;
+               ao_lpc_ssp_recv(lpc_ssp, state);
+       }
+       if (!state->rx_count) {
+               lpc_ssp->imsc &= ~(1 << LPC_SSP_IMSC_TXIM);
+               ao_wakeup(state);
+       }
+}
+
+void
+lpc_ssp0_isr(void)
+{
+       ao_lpc_ssp_isr(&lpc_ssp0, &ao_lpc_ssp_state[0]);
+}
+
+void
+lpc_ssp1_isr(void)
+{
+       ao_lpc_ssp_isr(&lpc_ssp1, &ao_lpc_ssp_state[1]);
+}
+
+static void
+ao_spi_run(struct lpc_ssp *lpc_ssp, struct ao_lpc_ssp_state *state)
+{
+       ao_arch_block_interrupts();
+       lpc_ssp->imsc = (1 << LPC_SSP_IMSC_TXIM);
+       while (state->rx_count)
+               ao_sleep(state);
+       ao_arch_release_interrupts();
+}
+
+static uint8_t ao_spi_tx_dummy = 0xff;
+static uint8_t ao_spi_rx_dummy;
 
 void
-ao_spi_send(void *block, uint16_t len, uint8_t id)
+ao_spi_send(const void *block, uint16_t len, uint8_t id)
 {
-       uint8_t *b = block;
        struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+       struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
 
-       spi_loop(len, *b++, (void));
+       state->tx_count = state->rx_count = len;
+       state->tx = block;
+       state->tx_inc = 1;
+       state->rx = &ao_spi_rx_dummy;
+       state->rx_inc = 0;
+       ao_spi_run(lpc_ssp, state);
 }
 
 void
 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t id)
 {
        struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+       struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
 
-       spi_loop(len, value, (void));
+       state->tx_count = state->rx_count = len;
+       state->tx = &value;
+       state->tx_inc = 0;
+       state->rx = &ao_spi_rx_dummy;
+       state->rx_inc = 0;
+       ao_spi_run(lpc_ssp, state);
 }
 
 void
 ao_spi_recv(void *block, uint16_t len, uint8_t id)
 {
-       uint8_t *b = block;
        struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+       struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
 
-       spi_loop(len, 0xff, *b++ =);
+       state->tx_count = state->rx_count = len;
+       state->tx = &ao_spi_tx_dummy;
+       state->tx_inc = 0;
+       state->rx = block;
+       state->rx_inc = 1;
+       ao_spi_run(lpc_ssp, state);
 }
 
 void
-ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t id)
+ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t id)
 {
-       uint8_t *o = out;
-       uint8_t *i = in;
        struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+       struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
 
-       spi_loop(len, *o++, *i++ =);
+       state->tx_count = state->rx_count = len;
+       state->tx = out;
+       state->tx_inc = 1;
+       state->rx = in;
+       state->rx_inc = 1;
+       ao_spi_run(lpc_ssp, state);
 }
 
 void
@@ -82,27 +151,14 @@ ao_spi_get(uint8_t id, uint32_t speed)
        struct lpc_ssp  *lpc_ssp = ao_lpc_ssp[id];
 
        ao_mutex_get(&ao_spi_mutex[id]);
-       
+
        /* Set the clock prescale */
        lpc_ssp->cpsr = speed;
-
-       /* Enable the device */
-       lpc_ssp->cr1 = ((0 << LPC_SSP_CR1_LBM) |
-                       (1 << LPC_SSP_CR1_SSE) |
-                       (LPC_SSP_CR1_MS_MASTER << LPC_SSP_CR1_MS) |
-                       (0 << LPC_SSP_CR1_SOD));
 }
 
 void
 ao_spi_put(uint8_t id)
 {
-       struct lpc_ssp  *lpc_ssp = ao_lpc_ssp[id];
-
-       /* Disable the device */
-       lpc_ssp->cr1 = ((0 << LPC_SSP_CR1_LBM) |
-                       (0 << LPC_SSP_CR1_SSE) |
-                       (LPC_SSP_CR1_MS_MASTER << LPC_SSP_CR1_MS) |
-                       (0 << LPC_SSP_CR1_SOD));
        ao_mutex_put(&ao_spi_mutex[id]);
 }
 
@@ -112,11 +168,23 @@ ao_spi_channel_init(uint8_t id)
        struct lpc_ssp  *lpc_ssp = ao_lpc_ssp[id];
        uint8_t d;
 
+       /* Clear interrupt registers */
+       lpc_ssp->imsc = 0;
+       lpc_ssp->ris = 0;
+       lpc_ssp->mis = 0;
+
        lpc_ssp->cr0 = ((LPC_SSP_CR0_DSS_8 << LPC_SSP_CR0_DSS) |
                        (LPC_SSP_CR0_FRF_SPI << LPC_SSP_CR0_FRF) |
                        (0 << LPC_SSP_CR0_CPOL) |
                        (0 << LPC_SSP_CR0_CPHA) |
                        (0 << LPC_SSP_CR0_SCR));
+
+       /* Enable the device */
+       lpc_ssp->cr1 = ((0 << LPC_SSP_CR1_LBM) |
+                       (1 << LPC_SSP_CR1_SSE) |
+                       (LPC_SSP_CR1_MS_MASTER << LPC_SSP_CR1_MS) |
+                       (0 << LPC_SSP_CR1_SOD));
+
        /* Drain the receive fifo */
        for (d = 0; d < LPC_SSP_FIFOSIZE; d++)
                (void) lpc_ssp->dr;
@@ -127,7 +195,21 @@ ao_spi_init(void)
 {
 #if HAS_SPI_0
        /* Configure pins */
-       lpc_ioconf.pio0_6 = ao_lpc_alternate(LPC_IOCONF_FUNC_SCK0);
+#if SPI_SCK0_P0_6
+       lpc_ioconf.pio0_6 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_6_SCK0);
+#define HAS_SCK0
+#endif
+#if SPI_SCK0_P0_10
+       lpc_ioconf.pio0_10 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_10_SCK0);
+#define HAS_SCK0
+#endif
+#if SPI_SCK0_P1_29
+       lpc_ioconf.pio1_29 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_29_SCK0);
+#define HAS_SCK0
+#endif
+#ifndef HAS_SCK0
+#error "No pin specified for SCK0"
+#endif
        lpc_ioconf.pio0_8 = ao_lpc_alternate(LPC_IOCONF_FUNC_MISO0);
        lpc_ioconf.pio0_9 = ao_lpc_alternate(LPC_IOCONF_FUNC_MOSI0);
 
@@ -141,7 +223,11 @@ ao_spi_init(void)
        lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
        lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
        ao_spi_channel_init(0);
-#endif                    
+
+       /* Configure NVIC */
+       lpc_nvic_set_enable(LPC_ISR_SSP0_POS);
+       lpc_nvic_set_priority(LPC_ISR_SSP0_POS, 0);
+#endif
 
 #if HAS_SPI_1
 
@@ -170,7 +256,7 @@ ao_spi_init(void)
 #endif
 
 #if SPI_MOSI1_P0_21
-       lpc_ioconf.pio1_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_21_MOSI1);
+       lpc_ioconf.pio0_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_21_MOSI1);
 #define HAS_MOSI1
 #endif
 #if SPI_MOSI1_P1_22
@@ -180,15 +266,21 @@ ao_spi_init(void)
 #ifndef HAS_MOSI1
 #error "No pin specified for MOSI1"
 #endif
-               
+
        /* Enable the device */
        lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP1);
 
        /* Turn on the clock */
        lpc_scb.ssp1clkdiv = 1;
 
-       /* De-assert reset */
+       /* Reset the device */
+       lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
        lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
        ao_spi_channel_init(1);
+
+       /* Configure NVIC */
+       lpc_nvic_set_enable(LPC_ISR_SSP1_POS);
+       lpc_nvic_set_priority(LPC_ISR_SSP1_POS, 0);
+
 #endif /* HAS_SPI_1 */
 }