spi_dma_at91.c
Go to the documentation of this file.00001
00040 #include "cfg/cfg_spi_dma.h"
00041
00042 #include "spi_dma_at91.h"
00043 #include "hw/hw_spi_dma.h"
00044
00045 #include <kern/kfile.h>
00046 #include <struct/fifobuf.h>
00047 #include <struct/kfile_fifo.h>
00048 #include <drv/timer.h>
00049
00050 #include <cpu/attr.h>
00051 #include <cpu/power.h>
00052
00053 #include <string.h>
00054
00055 static uint8_t tx_fifo_buffer[CONFIG_SPI_DMA_TXBUFSIZE];
00056 static FIFOBuffer tx_fifo;
00057 static KFileFifo kfifo;
00058
00059
00060 INLINE void spi_dma_startTx(void)
00061 {
00062 if (fifo_isempty(&tx_fifo))
00063 return;
00064
00065 if (SPI0_SR & BV(SPI_TXBUFE))
00066 {
00067 SPI0_PTCR = BV(PDC_TXTDIS);
00068 SPI0_TPR = (reg32_t)tx_fifo.head;
00069 if (tx_fifo.head < tx_fifo.tail)
00070 SPI0_TCR = tx_fifo.tail - tx_fifo.head;
00071 else
00072 SPI0_TCR = tx_fifo.end - tx_fifo.head + 1;
00073
00074 SPI0_PTCR = BV(PDC_TXTEN);
00075 }
00076 }
00077
00078 static DECLARE_ISR(spi0_dma_write_irq_handler)
00079 {
00080 SPI_DMA_STROBE_ON();
00081
00082 tx_fifo.head = (uint8_t *)SPI0_TPR;
00083 if (tx_fifo.head > tx_fifo.end)
00084 tx_fifo.head = tx_fifo.begin;
00085
00086 spi_dma_startTx();
00087
00088 AIC_EOICR = 0;
00089 SPI_DMA_STROBE_OFF();
00090 }
00091
00092
00093 void spi_dma_setclock(uint32_t rate)
00094 {
00095 SPI0_CSR0 &= ~SPI_SCBR;
00096
00097 ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
00098 SPI0_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
00099 }
00100
00101 static size_t spi_dma_write(UNUSED_ARG(struct KFile *, fd), const void *_buf, size_t size)
00102 {
00103 size_t count, total_wr = 0;
00104 const uint8_t *buf = (const uint8_t *) _buf;
00105
00106
00107 while (size)
00108 {
00109 #if CONFIG_SPI_DMA_TX_TIMEOUT != -1
00110 ticks_t start = timer_clock();
00111 while (fifo_isfull(&tx_fifo) && (timer_clock() - start < ms_to_ticks(CONFIG_SPI_DMA_TX_TIMEOUT)))
00112 cpu_relax();
00113
00114 if (fifo_isfull(&tx_fifo))
00115 break;
00116 #else
00117 while (fifo_isfull(&tx_fifo))
00118 cpu_relax();
00119 #endif
00120
00121
00122 count = kfile_write(&kfifo.fd, buf, size);
00123 size -= count;
00124 buf += count;
00125 total_wr += count;
00126 spi_dma_startTx();
00127 }
00128
00129 return total_wr;
00130 }
00131
00132 static int spi_dma_flush(UNUSED_ARG(struct KFile *, fd))
00133 {
00134
00135 while (!fifo_isempty(&tx_fifo))
00136 cpu_relax();
00137
00138
00139 while (!(SPI0_SR & BV(SPI_TXEMPTY)))
00140 cpu_relax();
00141
00142 return 0;
00143 }
00144
00145 static DECLARE_ISR(spi0_dma_read_irq_handler)
00146 {
00147
00148 AIC_EOICR = 0;
00149 }
00150
00151
00152
00153
00154
00155
00156 static const uint8_t tx_dummy_buf[CONFIG_SPI_DMA_MAX_RX] = { [0 ... (CONFIG_SPI_DMA_MAX_RX - 1)] = 0xFF };
00157
00158 static size_t spi_dma_read(struct KFile *fd, void *_buf, size_t size)
00159 {
00160 size_t count, total_rx = 0;
00161 uint8_t *buf = (uint8_t *)_buf;
00162
00163 spi_dma_flush(fd);
00164
00165
00166 AIC_SVR(SPI0_ID) = spi0_dma_read_irq_handler;
00167
00168 while (size)
00169 {
00170 count = MIN(size, (size_t)CONFIG_SPI_DMA_MAX_RX);
00171
00172 SPI0_PTCR = BV(PDC_TXTDIS) | BV(PDC_RXTDIS);
00173
00174 SPI0_RPR = (reg32_t)buf;
00175 SPI0_RCR = count;
00176 SPI0_TPR = (reg32_t)tx_dummy_buf;
00177 SPI0_TCR = count;
00178
00179
00180 *buf = SPI0_RDR;
00181
00182
00183 SPI0_PTCR = BV(PDC_RXTEN) | BV(PDC_TXTEN);
00184
00185
00186 while (!(SPI0_SR & BV(SPI_ENDRX)))
00187 cpu_relax();
00188
00189 size -= count;
00190 total_rx += count;
00191 buf += count;
00192 }
00193 SPI0_PTCR = BV(PDC_RXTDIS) | BV(PDC_TXTDIS);
00194
00195
00196 AIC_SVR(SPI0_ID) = spi0_dma_write_irq_handler;
00197
00198 return total_rx;
00199 }
00200
00201 #define SPI_DMA_IRQ_PRIORITY 4
00202
00203 void spi_dma_init(SpiDmaAt91 *spi)
00204 {
00205
00206 PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO);
00207
00208
00209 SPI0_CR = BV(SPI_SWRST);
00210
00211
00212
00213
00214
00215 SPI0_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS);
00216
00217
00218
00219
00220
00221
00222 SPI0_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
00223
00224
00225 SPI0_IDR = 0xFFFFFFFF;
00226
00227 AIC_SVR(SPI0_ID) = spi0_dma_write_irq_handler;
00228
00229 AIC_SMR(SPI0_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED | SPI_DMA_IRQ_PRIORITY;
00230
00231 AIC_IECR = BV(SPI0_ID);
00232 PMC_PCER = BV(SPI0_ID);
00233
00234
00235 SPI0_IER = BV(SPI_ENDTX);
00236
00237
00238 SPI0_CR = BV(SPI_SPIEN);
00239
00240 DB(spi->fd._type = KFT_SPIDMAAT91);
00241 spi->fd.write = spi_dma_write;
00242 spi->fd.read = spi_dma_read;
00243 spi->fd.flush = spi_dma_flush;
00244
00245 fifo_init(&tx_fifo, tx_fifo_buffer, sizeof(tx_fifo_buffer));
00246 kfilefifo_init(&kfifo, &tx_fifo);
00247
00248 SPI_DMA_STROBE_INIT();
00249 }