Switch from GPLv2 to GPLv2+
[fw/altos] / src / lpc / ao_spi_lpc.c
index 7c830053d90557def4e3a104c89b397b1cea6355..a8d4cda9229b32d176c480916ff39c55988af6ed 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
@@ -21,36 +22,27 @@ static uint8_t              ao_spi_mutex[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 tx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_TNF))) != (1 << LPC_SSP_SR_TNF)
-#define rx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_RNE))) != (1 << LPC_SSP_SR_RNE)
-
 #define spi_loop(len, put, get) do {                                   \
                while (len--) {                                         \
-                       /* Wait for space in the fifo */                \
-                       while (tx_busy(lpc_ssp))                        \
-                               ;                                       \
-                                                                       \
                        /* send a byte */                               \
                        lpc_ssp->dr = put;                              \
-                                                                       \
-                       /* Wait for byte to appear in the fifo */       \
-                       while (rx_busy(lpc_ssp))                        \
+                       /* wait for the received byte to appear */      \
+                       while ((lpc_ssp->sr & (1 << LPC_SSP_SR_RNE)) == 0) \
                                ;                                       \
-                                                                       \
-                       /* recv a byte */                               \
+                       /* receive a byte */                            \
                        get lpc_ssp->dr;                                \
                }                                                       \
-       } while (0);
+               /* Wait for the SSP to go idle (it already should be) */ \
+               while (lpc_ssp->sr & (1 << LPC_SSP_SR_BSY));            \
+       } while (0)
 
 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];
+       const uint8_t   *o = block;
 
-       spi_loop(len, *b++, (void));
+       spi_loop(len, *o++, (void));
 }
 
 void
@@ -64,18 +56,18 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t id)
 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];
+       uint8_t *i = block;
 
-       spi_loop(len, 0xff, *b++ =);
+       spi_loop(len, 0xff, *i++ =);
 }
 
 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];
+       const uint8_t *o = out;
+       uint8_t *i = in;
 
        spi_loop(len, *o++, *i++ =);
 }
@@ -86,7 +78,7 @@ 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;
 }
@@ -103,6 +95,11 @@ 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) |
@@ -125,7 +122,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);
 
@@ -139,7 +150,7 @@ 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                    
+#endif
 
 #if HAS_SPI_1
 
@@ -168,7 +179,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
@@ -178,14 +189,15 @@ 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);
 #endif /* HAS_SPI_1 */