BeRTOS
spi_dma_at91.c
Go to the documentation of this file.
00001 
00039 #include "cfg/cfg_spi_dma.h"
00040 
00041 #include "spi_dma_at91.h"
00042 #include "hw/hw_spi_dma.h"
00043 
00044 #include <io/kfile.h>
00045 #include <struct/fifobuf.h>
00046 #include <struct/kfile_fifo.h>
00047 #include <drv/timer.h>
00048 
00049 #include <cpu/attr.h>
00050 #include <cpu/power.h>
00051 
00052 #include <string.h> /* memset */
00053 
00054 
00055 void spi_dma_setclock(uint32_t rate)
00056 {
00057     SPI0_CSR0 &= ~SPI_SCBR;
00058 
00059     ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
00060     SPI0_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
00061 }
00062 
00063 
00064 static int spi_dma_flush(UNUSED_ARG(struct KFile *, fd))
00065 {
00066     /* Wait for DMA to finish */
00067     while (!(SPI0_SR & BV(SPI_TXBUFE)))
00068         cpu_relax();
00069 
00070     /* Wait until last bit has been shifted out */
00071     while (!(SPI0_SR & BV(SPI_TXEMPTY)))
00072         cpu_relax();
00073 
00074     return 0;
00075 }
00076 
00077 static size_t spi_dma_write(struct KFile *fd, const void *_buf, size_t size)
00078 {
00079     SPI0_PTCR = BV(PDC_TXTDIS);
00080     SPI0_TPR = (reg32_t)_buf;
00081     SPI0_TCR = size;
00082     SPI0_PTCR = BV(PDC_TXTEN);
00083     spi_dma_flush(fd);
00084     return size;
00085 }
00086 
00087 
00088 /*
00089  * Dummy buffer used to transmit 0xff chars while receiving data.
00090  * This buffer is completetly constant and the compiler should allocate it
00091  * in flash memory.
00092  */
00093 static const uint8_t tx_dummy_buf[CONFIG_SPI_DMA_MAX_RX] = { [0 ... (CONFIG_SPI_DMA_MAX_RX - 1)] = 0xFF };
00094 
00095 static size_t spi_dma_read(UNUSED_ARG(struct KFile *, fd), void *_buf, size_t size)
00096 {
00097     size_t count, total_rx = 0;
00098     uint8_t *buf = (uint8_t *)_buf;
00099 
00100     while (size)
00101     {
00102         count = MIN(size, (size_t)CONFIG_SPI_DMA_MAX_RX);
00103 
00104         SPI0_PTCR = BV(PDC_TXTDIS) | BV(PDC_RXTDIS);
00105 
00106         SPI0_RPR = (reg32_t)buf;
00107         SPI0_RCR = count;
00108         SPI0_TPR = (reg32_t)tx_dummy_buf;
00109         SPI0_TCR = count;
00110 
00111         /* Avoid reading the previous sent char */
00112         *buf = SPI0_RDR;
00113 
00114         /* Start transfer */
00115         SPI0_PTCR = BV(PDC_RXTEN) | BV(PDC_TXTEN);
00116 
00117         /* wait for transfer to finish */
00118         while (!(SPI0_SR & BV(SPI_ENDRX)))
00119             cpu_relax();
00120 
00121         size -= count;
00122         total_rx += count;
00123         buf += count;
00124     }
00125     SPI0_PTCR = BV(PDC_RXTDIS) | BV(PDC_TXTDIS);
00126 
00127     return total_rx;
00128 }
00129 
00130 #define SPI_DMA_IRQ_PRIORITY 4
00131 
00132 void spi_dma_init(SpiDmaAt91 *spi)
00133 {
00134     /* Disable PIO on SPI pins */
00135     PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO);
00136 
00137     /* Reset device */
00138     SPI0_CR = BV(SPI_SWRST);
00139 
00140     /*
00141      * Set SPI to master mode, fixed peripheral select, chip select directly connected to a peripheral device,
00142      * SPI clock set to MCK, mode fault detection disabled, loopback disable, NPCS0 active, Delay between CS = 0
00143      */
00144     SPI0_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS);
00145 
00146     /*
00147      * Set SPI mode.
00148      * At reset clock division factor is set to 0, that is
00149      * *forbidden*. Set SPI clock to minimum to keep it valid.
00150      */
00151     SPI0_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
00152 
00153     /* Disable all irqs */
00154     SPI0_IDR = 0xFFFFFFFF;
00155     /* Enable SPI clock. */
00156     PMC_PCER = BV(SPI0_ID);
00157 
00158     /* Enable SPI */
00159     SPI0_CR = BV(SPI_SPIEN);
00160 
00161     DB(spi->fd._type = KFT_SPIDMAAT91);
00162     spi->fd.write = spi_dma_write;
00163     spi->fd.read = spi_dma_read;
00164     spi->fd.flush = spi_dma_flush;
00165 
00166     SPI_DMA_STROBE_INIT();
00167 }