BeRTOS
|
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 }