]> rtime.felk.cvut.cz Git - pes-rpp/rpp-lib.git/blobdiff - rpp/src/drv/spi_tms570.c
Add SPI devices available on hydctr board
[pes-rpp/rpp-lib.git] / rpp / src / drv / spi_tms570.c
index 64f94a1b3e8633bea8dfd8845c735f52688764b5..cc5d1fa0d45df87475512fb3110424f7ab7023d9 100644 (file)
 
 #include "drv/spi.h"
 #include "sys/port.h"
-//#include "drv_spi.h"
-//#include "sys_common.h"
-//#include "ti_drv_dmm.h"
 #include "sys/ti_drv_dmm.h"
-
-static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p);
-
-
-/* Each SPI interface has its own static spi_tms570_drv_t struct
-   Index to this array is "SPI Interface ID -1" */
-spi_tms570_drv_t spi_tms570_ifcs[4];
-
-/* Addresses of SPI devices (=chips) bound to particular interfaces */
-enum spi_ifc1_devices {
-       SPIDEV_MC33972 = 0, SPIDEV_NCV7608_2x
-};
-enum spi_ifc2_devices {
-       SPIDEV_SDCARD = 0
-};
-enum spi_ifc3_devices {
-       SPIDEV_MCP4922_1 = 0, SPIDEV_MCP4922_2, SPIDEV_MCP4922_3
-};
-enum spi_ifc4_devices {
-       SPIDEV_L99H01 = 0, SPIDEV_TJA1082_1, SPIDEV_TJA1082_2
+#include "drv/spi_def.h"
+#include "drv/spi_tms570.h"
+
+#define SPI_FLG_TXINT_m     (1 << 9)
+#define SPI_FLG_RXINT_m     (1 << 8)
+
+#define SPI_INT0_TXINTENA_m (1 << 9)
+#define SPI_INT0_RXINTENA_m (1 << 8)
+
+#define SPI_DAT1_CSHOLD_m   (1 << 28)
+
+typedef volatile struct spiBase {
+       uint32_t GCR0;          /**< 0x0000: Global Control 0 */
+#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
+       uint32_t GCR1 : 8U;       /**< 0x0007: Global Control 1 */
+       uint32_t PD : 1U;         /**< 0x0006: Power down bit */
+       uint32_t : 7U;
+       uint32_t LB : 1U;         /**< 0x0005: Loop back bit */
+       uint32_t : 7U;
+       uint32_t ENA : 1U;        /**< 0x0004: SPI Enable bit */
+       uint32_t : 7U;
+       uint32_t INT0 : 16U;      /**< 0x000A: Interrupt Enable bits */
+       uint32_t DMAREQEN : 1U;       /**< 0x0009: DMA Request enable */
+       uint32_t : 7U;
+       uint32_t ENAHIGHZ : 1U;       /**< 0x0008: Enable HIGHZ outputs */
+       uint32_t : 7U;
+#else
+       uint32_t : 7U;
+       uint32_t ENA : 1U;        /**< 0x0004: SPI Enable bit */
+       uint32_t : 7U;
+       uint32_t LB : 1U;         /**< 0x0005: Loop back bit */
+       uint32_t : 7U;
+       uint32_t PD : 1U;         /**< 0x0006: Power down bit */
+       uint32_t GCR1 : 8U;       /**< 0x0007: Global Control 1 */
+       uint32_t : 7U;
+       uint32_t ENAHIGHZ : 1U;       /**< 0x0008: Enable HIGHZ outputs */
+       uint32_t : 7U;
+       uint32_t DMAREQEN : 1U;       /**< 0x0009: DMA Request enable */
+       uint32_t INT0 : 16U;      /**< 0x000A: Interrupt Enable bits */
+#endif
+       uint32_t LVL;           /**< 0x000C: Interrupt Level */
+#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
+       uint32_t FLG : 16U;       /**< 0x0012: Interrupt flags */
+       uint32_t : 8U;
+       uint32_t BUFINIT : 1U;        /**< 0x0010: Buffer initialization active flag */
+       uint32_t : 7U;
+#else
+       uint32_t : 7U;
+       uint32_t BUFINIT : 1U;        /**< 0x0010: Buffer initialization active flag */
+       uint32_t : 8U;
+       uint32_t FLG : 16U;       /**< 0x0012: Interrupt flags */
+#endif
+       uint32_t PCFUN;         /**< 0x0014: Function Pin Enable */
+       uint32_t PCDIR;         /**< 0x0018: Pin Direction */
+       uint32_t PCDIN;         /**< 0x001C: Pin Input Latch */
+       uint32_t PCDOUT;        /**< 0x0020: Pin Output Latch */
+       uint32_t PCSET;         /**< 0x0024: Output Pin Set */
+       uint32_t PCCLR;         /**< 0x0028: Output Pin Clr */
+       uint32_t PCPDR;         /**< 0x002C: Open Drain Output Enable */
+       uint32_t PCDIS;         /**< 0x0030: Pullup/Pulldown Disable */
+       uint32_t PCPSL;         /**< 0x0034: Pullup/Pulldown Selection */
+       uint32_t DAT0;          /**< 0x0038: Transmit Data */
+       uint32_t DAT1;          /**< 0x003C: Transmit Data with Format and Chip Select */
+       uint32_t BUF;           /**< 0x0040: Receive Buffer */
+       uint32_t EMU;           /**< 0x0044: Emulation Receive Buffer */
+       uint32_t DELAY;         /**< 0x0048: Delays */
+       uint32_t CSDEF;         /**< 0x004C: Default Chip Select */
+       uint32_t FMT0;          /**< 0x0050: Data Format 0 */
+       uint32_t FMT1;          /**< 0x0054: Data Format 1 */
+       uint32_t FMT2;          /**< 0x0058: Data Format 2 */
+       uint32_t FMT3;          /**< 0x005C: Data Format 3 */
+       uint32_t INTVECT0;      /**< 0x0060: Interrupt Vector 0 */
+       uint32_t INTVECT1;      /**< 0x0064: Interrupt Vector 1 */
+       uint32_t SRSEL;         /**< 0x0068: Slew Rate Select */
+
+       uint32_t PMCTRL;        /**< 0x006C: Parallel Mode Control */
+#if ((__little_endian__ == 1) || (__LITTLE_ENDIAN__ == 1))
+       uint32_t MIBSPIE : 16U;       /**< 0x0072: MibSPI Enable */
+       uint32_t RAMACCESS : 16U;     /**< 0x0070: RX Ram Write Access Enable */
+#else
+       uint32_t RAMACCESS : 16U;     /**< 0x0070: RX Ram Write Access Enable */
+       uint32_t MIBSPIE : 16U;       /**< 0x0072: MibSPI Enable */
+#endif
+
+       uint32_t RESERVED[48U];     /**< 0x006C to 0x0130: Reserved */
+       uint32_t IOLPKTSTCR;        /**< 0x0134: IO loopback */
+} spiBASE_compat_t;
+
+#define spi_compat_REG2     ((spiBASE_compat_t *)0xFFF7F600U)
+#define spi_compat_REG4     ((spiBASE_compat_t *)0xFFF7FA00U)
+#define mibspi_compat_REG1  ((spiBASE_compat_t *)0xFFF7F400U)
+#define mibspi_compat_REG3  ((spiBASE_compat_t *)0xFFF7F800U)
+#define mibspi_compat_REG5  ((spiBASE_compat_t *)0xFFF7FC00U)  /* NOT USED ON RPP BOARD */
+
+/* SPI interface */
+struct spi_tms570_iface {
+       spi_drv_t spi_drv;
+       spiBASE_compat_t *reg;      /* Base Reg. for SPI device register array */
+       unsigned txcnt; /* No. of transfered bytes for msg_act */
+       unsigned rxcnt; /* No. of received bytes for msg_act */
+       spi_dev_t *spi_devs;    /* Pointer to table holding information about SPI devices bound to the interface */
+       uint32_t transfer_ctrl; /* Transfer configuration -- upper 16 bits of SPIDAT1 register */
+       /* TODO: Add FMT description here if we need different formats */
 };
 
-spi_dev_t spi_ifc1_devs[] = {
-       [SPIDEV_MC33972] = {
-               .cs = SPI_CS_3,
-               .dfsel = 0,
-               .wdel = 0,
-               .cshold = 1,
-               .dlen = 0
-       },
-       [SPIDEV_NCV7608_2x] = {
-               .cs = SPI_CS_4,
-               .dfsel = 0,
-               .wdel = 0,
-               .cshold = 1,
-               .dlen = 0
-       }
-};
-
-spi_dev_t spi_ifc2_devs[] = {
-       [SPIDEV_SDCARD] = {
-               .cs = SPI_CS_0,
-               .dfsel = 0,
-               .wdel = 0,
-               .cshold = 1,
-               .dlen = 0
-       }
+spi_tms570_iface_t spi_iface[5] = {
+       [SPI_IFACE1] = { .reg = mibspi_compat_REG1,     },
+       [SPI_IFACE2] = { .reg = spi_compat_REG2,        },
+       [SPI_IFACE3] = { .reg = mibspi_compat_REG3,     },
+       [SPI_IFACE4] = { .reg = spi_compat_REG4,        },
+       [SPI_IFACE5] = { .reg = mibspi_compat_REG5,     },
 };
 
-spi_dev_t spi_ifc3_devs[] = {
-       [SPIDEV_MCP4922_1] = {
-               .cs = SPI_CS_0,
-               .dfsel = 1,
-               .wdel = 0,
-               .cshold = 1,
-               .dlen = 0
-       },
-       [SPIDEV_MCP4922_2] = {
-               .cs = SPI_CS_4,
-               .dfsel = 1,
-               .wdel = 0,
-               .cshold = 1,
-               .dlen = 0
-       },
-       [SPIDEV_MCP4922_3] = {
-               .cs = SPI_CS_5,
-               .dfsel = 1,
-               .wdel = 0,
-               .cshold = 1,
-               .dlen = 0
-       }
-};
+spi_drv_t *spi_tms570_get_iface(enum spi_device dev)
+{
+       return &spi_iface[spi_devs[dev].iface].spi_drv;
+}
 
-spi_dev_t spi_ifc4_devs[] = {
-       [SPIDEV_L99H01] = {
-               .cs = SPI_CS_0 | SPI_CS_DMM0,
-               .dfsel = 1,
-               .wdel = 0,
-               .cshold = 1,
-               .dlen = 0
-       },
-       [SPIDEV_TJA1082_1] = {
-               .cs = SPI_CS_0 | SPI_CS_DMM1,
-               .dfsel = 0,
-               .wdel = 0,
-               .cshold = 1,
-               .dlen = 0
-       },
-       [SPIDEV_TJA1082_2] = {
-               .cs = SPI_CS_0 | SPI_CS_DMM2,
-               .dfsel = 0,
-               .wdel = 0,
-               .cshold = 1,
-               .dlen = 0
-       }
-};
+static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p);
 
 /*
    Universal piece of code initializing SPI or MibSPI
@@ -121,7 +141,7 @@ spi_dev_t spi_ifc4_devs[] = {
    ENA register is set even on SPI devices which do not have it --
    this should not be an issue
  */
-void spiInit(spiBASE_compat_t *spiREG)
+static void spiInit(spiBASE_compat_t *spiREG)
 {
        /** bring SPI out of reset */
        spiREG->GCR0 = 1U;
@@ -140,6 +160,7 @@ void spiInit(spiBASE_compat_t *spiREG)
                                        | 0; /* C2EDELAY */
 
        /** - Data Format 0 */
+       /* TODO: Set the formats from spi_tms570_iface_t if we need different formats */
        spiREG->FMT0 = (0 << 24)    /* wdelay */
                                   | (0 << 23) /* parity Polarity */
                                   | (0 << 22) /* parity enable */
@@ -303,54 +324,38 @@ void spiInit(spiBASE_compat_t *spiREG)
        spiREG->ENA = 1U;
 }
 
-static boolean_t spi_initialized = FALSE;
+static void init_iface(spi_tms570_iface_t *iface)
+{
+       spiInit(iface->reg);
+       iface->spi_drv.ctrl_fnc = spi_tms570_ctrl_fnc;
+       spi_rq_queue_init_head(&(iface->spi_drv));
+       iface->spi_drv.msg_act = NULL;
+       iface->spi_drv.flags = 0;
+}
 
-int spi_tms570_init(void)
+void spi_tms570_init()
 {
-       if (spi_initialized == TRUE)
-               return FAILURE;
-       spi_initialized = TRUE;
        int i;
 
-       spi_tms570_ifcs[0].spi = mibspi_compat_REG1;
-       spi_tms570_ifcs[1].spi = spi_compat_REG2;
-       spi_tms570_ifcs[2].spi = mibspi_compat_REG3;
-       spi_tms570_ifcs[3].spi = spi_compat_REG4;
-
-       spi_tms570_ifcs[0].spi_devs = spi_ifc1_devs;
-       spi_tms570_ifcs[1].spi_devs = spi_ifc2_devs;
-       spi_tms570_ifcs[2].spi_devs = spi_ifc3_devs;
-       spi_tms570_ifcs[3].spi_devs = spi_ifc4_devs;
-
-
-       for (i = 0; i <= 3; i++) {
-               spiInit(spi_tms570_ifcs[i].spi);
-               spi_tms570_ifcs[i].spi_drv.ctrl_fnc = spi_tms570_ctrl_fnc;
-               spi_rq_queue_init_head(&(spi_tms570_ifcs[i].spi_drv));
-               spi_tms570_ifcs[i].spi_drv.msg_act = NULL;
-               spi_tms570_ifcs[i].spi_drv.flags = SPI_IFC_ON;
-       }
+       for (i = 0; i < ARRAY_SIZE(spi_iface); i++)
+               init_iface(&spi_iface[i]);
 
        //dmmREG->PC5 = (1 << DMM_DATA5); /* Set to L */
        //dmmREG->PC5 = (1 << DMM_DATA6); /* Set to L */
-
-       return SUCCESS;
 }
 
 
 static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p)
 {
-       spi_tms570_drv_t *tms570_drv =
-               UL_CONTAINEROF(ifc, spi_tms570_drv_t, spi_drv);
+       spi_tms570_iface_t *tms570_drv =
+               UL_CONTAINEROF(ifc, spi_tms570_iface_t, spi_drv);
 
        switch (ctrl) {
        case SPI_CTRL_WAKE_RQ:
-               if (!(ifc->flags & SPI_IFC_ON))
-                       return -1;
                if (spi_rq_queue_is_empty(ifc))
                        return 0;
 
-               tms570_drv->spi->INT0 = SPI_INT0_TXINTENA_m;
+               tms570_drv->reg->INT0 = SPI_INT0_TXINTENA_m;
                // Enable TXINT (Causes an interrupt
                // to be generated every time data is written to the shift
                // register, so that the next word can be written to TXBUF.
@@ -374,10 +379,9 @@ static int spi_tms570_ctrl_fnc(spi_drv_t *ifc, int ctrl, void *p)
 
 void spi_tms570_isr(int spi_ifc, uint32_t flags)
 {
-       spi_msg_head_t *msg;
-       spi_tms570_drv_t *spi_tms570_drv;
-
-       spi_tms570_drv = &spi_tms570_ifcs[spi_ifc];
+       spi_msg_t *msg;
+       spi_tms570_iface_t *iface = &spi_iface[spi_ifc];
+       const spi_dev_t *dev;
        spi_isr_lock_level_t saveif;
        uint8_t val_to_wr;
        uint32_t cs;
@@ -389,33 +393,35 @@ void spi_tms570_isr(int spi_ifc, uint32_t flags)
 
        if (flags & SPI_FLG_TXINT_m) {
                do {
-                       msg = spi_tms570_drv->spi_drv.msg_act;
+                       msg = iface->spi_drv.msg_act;
                        if (!msg) { /* Is there any MSG being processed? */
                                /* If not, get one from a queue */
                                spi_isr_lock(saveif);
-                               msg = spi_tms570_drv->spi_drv.msg_act =
-                                                 spi_rq_queue_first(&spi_tms570_drv->spi_drv);
+                               msg = iface->spi_drv.msg_act =
+                                                 spi_rq_queue_first(&iface->spi_drv);
                                spi_isr_unlock(saveif);
 
                                if (!msg) { /* Nothing to process */
                                        volatile unsigned int dummy_read;
                                        /* Disable TXEMPTY IRQ */
-                                       spi_tms570_drv->spi->INT0 = 0x00;
-                                       spi_tms570_drv->spi->FLG = 0x00;
-                                       dummy_read = spi_tms570_drv->spi->BUF;
+                                       iface->reg->INT0 = 0x00;
+                                       iface->reg->FLG = 0x00;
+                                       dummy_read = iface->reg->BUF;
                                        // FIXME "INT |= " with disabled IRQ ??
                                        return;
                                }
 
-                               spi_tms570_drv->txcnt = 0;
-                               spi_tms570_drv->rxcnt = 0;
-                               cs = spi_tms570_drv->spi_devs[msg->addr].cs;
-                               spi_tms570_drv->transfer_ctrl =
+                               iface->txcnt = 0;
+                               iface->rxcnt = 0;
+                               dev = &spi_devs[msg->dev];
+                               cs = dev->cs;
+                               iface->transfer_ctrl =
                                        (cs & 0xff) << 16
-                                       | (spi_tms570_drv->spi_devs[msg->addr].wdel & 0x1) << 26
-                                       | (spi_tms570_drv->spi_devs[msg->addr].cshold & 0x1) << 28
-                                       | (spi_tms570_drv->spi_devs[msg->addr].dfsel & 0x3) << 24;
+                                       | (dev->wdel & 0x1) << 26
+                                       | (dev->cshold & 0x1) << 28
+                                       | (dev->dfsel & 0x3) << 24;
 
+#if defined(TARGET_TMS570_RPP)
                                /* GPIO CS -- setting the multiplexer */
                                if (cs > 0xff) {
                                        switch (cs & 0xFF00) {
@@ -433,21 +439,22 @@ void spi_tms570_isr(int spi_ifc, uint32_t flags)
                                                break;
                                        }
                                }
+#endif
                        }
 
                        rq_len = msg->rq_len;
-                       rxcnt = spi_tms570_drv->rxcnt;
-                       txcnt = spi_tms570_drv->txcnt;
+                       rxcnt = iface->rxcnt;
+                       txcnt = iface->txcnt;
                        /* RX/TX transfers */
                        do {
                                /* Receive all the incoming data */
-                               while (spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m) {
-                                       rx_data = spi_tms570_drv->spi->BUF;
+                               while (iface->reg->FLG & SPI_FLG_RXINT_m) {
+                                       rx_data = iface->reg->BUF;
 
-                                       if (msg->rx_buf && (rxcnt < rq_len))
+                                       if (msg->rx_buf && (rxcnt < rq_len)) {
+                                               /* This relies on all FMTs having 8 bit CHARLEN */
                                                msg->rx_buf[rxcnt++] = rx_data & 0xFF;
-                                       //FIXME how to make sure we got only 8 bits
-                                       else
+                                       } else
                                                rxcnt++;
                                }
 
@@ -455,66 +462,59 @@ void spi_tms570_isr(int spi_ifc, uint32_t flags)
                                while (1) {
                                        /* Tx buffer full or nothing to send */
                                        stop_fl = ((txcnt >= rq_len) ||
-                                                          (!(spi_tms570_drv->spi->FLG & SPI_FLG_TXINT_m)));
+                                                          (!(iface->reg->FLG & SPI_FLG_TXINT_m)));
 
                                        if (stop_fl)
                                                break;
                                        /* Make it possible to write "empty data"
                                           for "read transfers" */
-                                       if (msg->tx_buf)
+                                       if (msg->tx_buf) {
+                                               /* This relies on all FMTs having 8 bit CHARLEN */
                                                val_to_wr = msg->tx_buf[txcnt++];
-                                       else {
+                                       else {
                                                val_to_wr = 0x00;
                                                txcnt++;
                                        }
 
-                                       if (txcnt == rq_len) /* Disable CS for the last byte of the transfer */
-                                               spi_tms570_drv->transfer_ctrl &= ~SPI_DAT1_CSHOLD_m;
+                                       if (txcnt == rq_len) /* Disable CS after last byte of the transfer */
+                                               iface->transfer_ctrl &= ~SPI_DAT1_CSHOLD_m;
 
-                                       spi_tms570_drv->spi->DAT1 =
-                                               (uint32_t)(spi_tms570_drv->transfer_ctrl | val_to_wr);
+                                       iface->reg->DAT1 =
+                                               (uint32_t)(iface->transfer_ctrl | val_to_wr);
 
                                        /* We just received something */
-                                       if (spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m)
+                                       if (iface->reg->FLG & SPI_FLG_RXINT_m)
                                                break;
                                }
                        } while (!stop_fl);
-                       spi_tms570_drv->rxcnt = rxcnt;
-                       spi_tms570_drv->txcnt = txcnt;
+                       iface->rxcnt = rxcnt;
+                       iface->txcnt = txcnt;
 
                        if ((rxcnt >= rq_len) ||
                                (!msg->rx_buf && (txcnt >= rq_len) &&
-                                !(spi_tms570_drv->spi->FLG & SPI_FLG_RXINT_m))) { // FIXME
+                                !(iface->reg->FLG & SPI_FLG_RXINT_m))) { // FIXME
 
                                /* Sending of the message successfully finished */
                                spi_isr_lock(saveif);
                                spi_rq_queue_del_item(msg);
                                msg->flags |= SPI_MSG_FINISHED;
-                               spi_tms570_drv->spi_drv.msg_act = NULL;
+                               iface->spi_drv.msg_act = NULL;
                                spi_isr_unlock(saveif);
                                if (msg->callback)
-                                       msg->callback(&spi_tms570_drv->spi_drv,
+                                       msg->callback(&iface->spi_drv,
                                                                  SPI_MSG_FINISHED, msg);
 
                                continue;
                        }
                        if (txcnt < rq_len)
-                               spi_tms570_drv->spi->INT0 = SPI_INT0_TXINTENA_m;
+                               iface->reg->INT0 = SPI_INT0_TXINTENA_m;
                        else
-                               spi_tms570_drv->spi->INT0 = SPI_INT0_RXINTENA_m;
+                               iface->reg->INT0 = SPI_INT0_RXINTENA_m;
 
                } while (1);
        }
 }
 
-spi_drv_t *spi_find_drv(char *name, int number)
-{
-       if (number < 1 || number > (sizeof(spi_tms570_ifcs)/sizeof(spi_tms570_ifcs[0])))
-               return NULL;
-
-       return &spi_tms570_ifcs[number - 1].spi_drv;
-}
-
 #pragma INTERRUPT(spi2LowLevelInterrupt, IRQ)
 void spi2LowLevelInterrupt(void)
 {