*
* \brief SPI driver with DMA.
*
- * \version $Id$
* \author Francesco Sacchi <batt@develer.com>
* \author Luca Ottaviano <lottaviano@develer.com>
*/
-#include "cfg/cfg_spi_dma.h"
+#include <drv/spi_dma.h>
-#include "spi_dma_at91.h"
+#include "cfg/cfg_spi_dma.h"
#include "hw/hw_spi_dma.h"
-#include <kern/kfile.h>
+#include <io/at91sam7.h>
+#include <io/kfile.h>
+
#include <struct/fifobuf.h>
#include <struct/kfile_fifo.h>
+
#include <drv/timer.h>
#include <cpu/attr.h>
#include <string.h> /* memset */
-static uint8_t tx_fifo_buffer[CONFIG_SPI_DMA_TXBUFSIZE];
-static FIFOBuffer tx_fifo;
-static KFileFifo kfifo;
-
-
-INLINE void spi_dma_startTx(void)
-{
- if (fifo_isempty(&tx_fifo))
- return;
-
- if (SPI0_SR & BV(SPI_TXBUFE))
- {
- SPI0_PTCR = BV(PDC_TXTDIS);
- SPI0_TPR = (reg32_t)tx_fifo.head;
- if (tx_fifo.head < tx_fifo.tail)
- SPI0_TCR = tx_fifo.tail - tx_fifo.head;
- else
- SPI0_TCR = tx_fifo.end - tx_fifo.head + 1;
-
- SPI0_PTCR = BV(PDC_TXTEN);
- }
-}
-
-static void spi0_dma_write_irq_handler(void) __attribute__ ((interrupt));
-static void spi0_dma_write_irq_handler(void)
-{
- SPI_DMA_STROBE_ON();
- /* Pop sent chars from FIFO */
- tx_fifo.head = (uint8_t *)SPI0_TPR;
- if (tx_fifo.head > tx_fifo.end)
- tx_fifo.head = tx_fifo.begin;
-
- spi_dma_startTx();
-
- AIC_EOICR = 0;
- SPI_DMA_STROBE_OFF();
-}
-
void spi_dma_setclock(uint32_t rate)
{
SPI0_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
}
-static size_t spi_dma_write(UNUSED_ARG(struct KFile *, fd), const void *_buf, size_t size)
-{
- size_t count, total_wr = 0;
- const uint8_t *buf = (const uint8_t *) _buf;
-
- // copy buffer to internal fifo
- while (size)
- {
- #if CONFIG_SPI_DMA_TX_TIMEOUT != -1
- ticks_t start = timer_clock();
- while (fifo_isfull(&tx_fifo) && (timer_clock() - start < ms_to_ticks(CONFIG_SPI_DMA_TX_TIMEOUT)))
- cpu_relax();
-
- if (fifo_isfull(&tx_fifo))
- break;
- #else
- while (fifo_isfull(&tx_fifo))
- cpu_relax();
- #endif /* CONFIG_SPI_DMA_TX_TIMEOUT */
-
- // FIXME: improve copy performance
- count = kfile_write(&kfifo.fd, buf, size);
- size -= count;
- buf += count;
- total_wr += count;
- spi_dma_startTx();
- }
-
- return total_wr;
-}
static int spi_dma_flush(UNUSED_ARG(struct KFile *, fd))
{
- /* Wait FIFO flush */
- while (!fifo_isempty(&tx_fifo))
+ /* Wait for DMA to finish */
+ while (!(SPI0_SR & BV(SPI_TXBUFE)))
cpu_relax();
/* Wait until last bit has been shifted out */
return 0;
}
-static void spi0_dma_read_irq_handler(void) __attribute__ ((interrupt));
-static void spi0_dma_read_irq_handler(void)
+static size_t spi_dma_write(struct KFile *fd, const void *_buf, size_t size)
{
- /* do nothing */
- AIC_EOICR = 0;
+ SPI0_PTCR = BV(PDC_TXTDIS);
+ SPI0_TPR = (reg32_t)_buf;
+ SPI0_TCR = size;
+ SPI0_PTCR = BV(PDC_TXTEN);
+ spi_dma_flush(fd);
+ return size;
}
+
/*
* Dummy buffer used to transmit 0xff chars while receiving data.
* This buffer is completetly constant and the compiler should allocate it
*/
static const uint8_t tx_dummy_buf[CONFIG_SPI_DMA_MAX_RX] = { [0 ... (CONFIG_SPI_DMA_MAX_RX - 1)] = 0xFF };
-static size_t spi_dma_read(struct KFile *fd, void *_buf, size_t size)
+static size_t spi_dma_read(UNUSED_ARG(struct KFile *, fd), void *_buf, size_t size)
{
size_t count, total_rx = 0;
uint8_t *buf = (uint8_t *)_buf;
- spi_dma_flush(fd);
-
- /* Dummy irq handler that do nothing */
- AIC_SVR(SPI0_ID) = spi0_dma_read_irq_handler;
-
while (size)
{
count = MIN(size, (size_t)CONFIG_SPI_DMA_MAX_RX);
}
SPI0_PTCR = BV(PDC_RXTDIS) | BV(PDC_TXTDIS);
- /* set write irq handler back in place */
- AIC_SVR(SPI0_ID) = spi0_dma_write_irq_handler;
-
return total_rx;
}
#define SPI_DMA_IRQ_PRIORITY 4
-void spi_dma_init(SpiDmaAt91 *spi)
+void spi_dma_init(SpiDma *spi)
{
/* Disable PIO on SPI pins */
PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO);
/* Disable all irqs */
SPI0_IDR = 0xFFFFFFFF;
- /* Set the vector. */
- AIC_SVR(SPI0_ID) = spi0_dma_write_irq_handler;
- /* Initialize to edge triggered with defined priority. */
- AIC_SMR(SPI0_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED | SPI_DMA_IRQ_PRIORITY;
- /* Enable the USART IRQ */
- AIC_IECR = BV(SPI0_ID);
+ /* Enable SPI clock. */
PMC_PCER = BV(SPI0_ID);
- /* Enable interrupt on tx buffer empty */
- SPI0_IER = BV(SPI_ENDTX);
-
/* Enable SPI */
SPI0_CR = BV(SPI_SPIEN);
- DB(spi->fd._type = KFT_SPIDMAAT91);
+ DB(spi->fd._type = KFT_SPIDMA);
spi->fd.write = spi_dma_write;
spi->fd.read = spi_dma_read;
spi->fd.flush = spi_dma_flush;
- fifo_init(&tx_fifo, tx_fifo_buffer, sizeof(tx_fifo_buffer));
- kfilefifo_init(&kfifo, &tx_fifo);
-
SPI_DMA_STROBE_INIT();
}