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 void spi0_dma_write_irq_handler(void) __attribute__ ((interrupt));
00079 static void spi0_dma_write_irq_handler(void)
00080 {
00081 SPI_DMA_STROBE_ON();
00082
00083 tx_fifo.head = (uint8_t *)SPI0_TPR;
00084 if (tx_fifo.head > tx_fifo.end)
00085 tx_fifo.head = tx_fifo.begin;
00086
00087 spi_dma_startTx();
00088
00089 AIC_EOICR = 0;
00090 SPI_DMA_STROBE_OFF();
00091 }
00092
00093
00094 void spi_dma_setclock(uint32_t rate)
00095 {
00096 SPI0_CSR0 &= ~SPI_SCBR;
00097
00098 ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
00099 SPI0_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
00100 }
00101
00102 static size_t spi_dma_write(UNUSED_ARG(struct KFile *, fd), const void *_buf, size_t size)
00103 {
00104 size_t count, total_wr = 0;
00105 const uint8_t *buf = (const uint8_t *) _buf;
00106
00107
00108 while (size)
00109 {
00110 #if CONFIG_SPI_DMA_TX_TIMEOUT != -1
00111 ticks_t start = timer_clock();
00112 while (fifo_isfull(&tx_fifo) && (timer_clock() - start < ms_to_ticks(CONFIG_SPI_DMA_TX_TIMEOUT)))
00113 cpu_relax();
00114
00115 if (fifo_isfull(&tx_fifo))
00116 break;
00117 #else
00118 while (fifo_isfull(&tx_fifo))
00119 cpu_relax();
00120 #endif
00121
00122
00123 count = kfile_write(&kfifo.fd, buf, size);
00124 size -= count;
00125 buf += count;
00126 total_wr += count;
00127 spi_dma_startTx();
00128 }
00129
00130 return total_wr;
00131 }
00132
00133 static int spi_dma_flush(UNUSED_ARG(struct KFile *, fd))
00134 {
00135
00136 while (!fifo_isempty(&tx_fifo))
00137 cpu_relax();
00138
00139
00140 while (!(SPI0_SR & BV(SPI_TXEMPTY)))
00141 cpu_relax();
00142
00143 return 0;
00144 }
00145
00146 static void spi0_dma_read_irq_handler(void) __attribute__ ((interrupt));
00147 static void spi0_dma_read_irq_handler(void)
00148 {
00149
00150 AIC_EOICR = 0;
00151 }
00152
00153
00154
00155
00156
00157
00158 static const uint8_t tx_dummy_buf[CONFIG_SPI_DMA_MAX_RX] = { [0 ... (CONFIG_SPI_DMA_MAX_RX - 1)] = 0xFF };
00159
00160 static size_t spi_dma_read(struct KFile *fd, void *_buf, size_t size)
00161 {
00162 size_t count, total_rx = 0;
00163 uint8_t *buf = (uint8_t *)_buf;
00164
00165 spi_dma_flush(fd);
00166
00167
00168 AIC_SVR(SPI0_ID) = spi0_dma_read_irq_handler;
00169
00170 while (size)
00171 {
00172 count = MIN(size, (size_t)CONFIG_SPI_DMA_MAX_RX);
00173
00174 SPI0_PTCR = BV(PDC_TXTDIS) | BV(PDC_RXTDIS);
00175
00176 SPI0_RPR = (reg32_t)buf;
00177 SPI0_RCR = count;
00178 SPI0_TPR = (reg32_t)tx_dummy_buf;
00179 SPI0_TCR = count;
00180
00181
00182 *buf = SPI0_RDR;
00183
00184
00185 SPI0_PTCR = BV(PDC_RXTEN) | BV(PDC_TXTEN);
00186
00187
00188 while (!(SPI0_SR & BV(SPI_ENDRX)))
00189 cpu_relax();
00190
00191 size -= count;
00192 total_rx += count;
00193 buf += count;
00194 }
00195 SPI0_PTCR = BV(PDC_RXTDIS) | BV(PDC_TXTDIS);
00196
00197
00198 AIC_SVR(SPI0_ID) = spi0_dma_write_irq_handler;
00199
00200 return total_rx;
00201 }
00202
00203 #define SPI_DMA_IRQ_PRIORITY 4
00204
00205 void spi_dma_init(SpiDmaAt91 *spi)
00206 {
00207
00208 PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO);
00209
00210
00211 SPI0_CR = BV(SPI_SWRST);
00212
00213
00214
00215
00216
00217 SPI0_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS);
00218
00219
00220
00221
00222
00223
00224 SPI0_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
00225
00226
00227 SPI0_IDR = 0xFFFFFFFF;
00228
00229 AIC_SVR(SPI0_ID) = spi0_dma_write_irq_handler;
00230
00231 AIC_SMR(SPI0_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED | SPI_DMA_IRQ_PRIORITY;
00232
00233 AIC_IECR = BV(SPI0_ID);
00234 PMC_PCER = BV(SPI0_ID);
00235
00236
00237 SPI0_IER = BV(SPI_ENDTX);
00238
00239
00240 SPI0_CR = BV(SPI_SPIEN);
00241
00242 DB(spi->fd._type = KFT_SPIDMAAT91);
00243 spi->fd.write = spi_dma_write;
00244 spi->fd.read = spi_dma_read;
00245 spi->fd.flush = spi_dma_flush;
00246
00247 fifo_init(&tx_fifo, tx_fifo_buffer, sizeof(tx_fifo_buffer));
00248 kfilefifo_init(&kfifo, &tx_fifo);
00249
00250 SPI_DMA_STROBE_INIT();
00251 }