Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00044 #include <cfg/spi.h>
00045 
00046 #include <sys/timer.h>
00047 #include <sys/nutdebug.h>
00048 
00049 #include <stdlib.h>
00050 #include <memdebug.h>
00051 
00052 #include <dev/spibus_at91.h>
00053 
00054 #define SPI_DOUBLE_BUFFER_MIN_TRANSFER_SIZE 4
00055 
00056 #if defined(SPIBUS0_DOUBLE_BUFFER) || defined(SPIBUS1_DOUBLE_BUFFER)
00057 
00061 static void At91SpiInterrupt(void *arg)
00062 {
00063     NutEventPostFromIrq((void **)arg);
00064 }
00065 #endif 
00066 
00074 int At91SpiSetup(NUTSPINODE * node)
00075 {
00076     uint32_t clk;
00077     uint32_t clkdiv;
00078     AT91SPIREG *spireg;
00079 
00080     NUTASSERT(node != NULL);
00081     NUTASSERT(node->node_stat != NULL);
00082     NUTASSERT(node->node_bus != NULL);
00083     NUTASSERT(node->node_bus->bus_base != 0);
00084     spireg = node->node_stat;
00085 
00086     spireg->at91spi_mr &= ~(SPI_MODFDIS | SPI_LLB);
00087     if ((node->node_mode & SPI_MODE_FAULT) == 0) {
00088         spireg->at91spi_mr |= SPI_MODFDIS;
00089     }
00090     if (node->node_mode & SPI_MODE_LOOPBACK) {
00091         spireg->at91spi_mr |= SPI_LLB;
00092     }
00093 
00094     spireg->at91spi_csr &= ~(SPI_BITS | SPI_CPOL | SPI_NCPHA | SPI_CSAAT | SPI_SCBR);
00095     if (node->node_bits) {
00096         spireg->at91spi_csr |= ((uint32_t)(node->node_bits - 8) << SPI_BITS_LSB) & SPI_BITS;
00097     }
00098     if (node->node_mode & SPI_MODE_CPOL) {
00099         spireg->at91spi_csr |= SPI_CPOL;
00100     }
00101     if ((node->node_mode & SPI_MODE_CPHA) == 0) {
00102         spireg->at91spi_csr |= SPI_NCPHA;
00103     }
00104     if (node->node_mode & SPI_MODE_CSKEEP) {
00105         spireg->at91spi_csr |= SPI_CSAAT;
00106     }
00107 
00108     
00109     clk = NutClockGet(NUT_HWCLK_PERIPHERAL);
00110     
00111     clkdiv = (clk + node->node_rate - 1) / node->node_rate;
00112     
00113     if (clkdiv < 1) {
00114         clkdiv++;
00115     }
00116     
00117     else if (clkdiv > 255) {
00118         clkdiv = 255;
00119     }
00120     spireg->at91spi_csr |= clkdiv << SPI_SCBR_LSB;
00121 
00122     
00123     node->node_rate = clk / clkdiv;
00124     node->node_mode &= ~SPI_MODE_UPDATE;
00125 
00126     return 0;
00127 }
00128 
00139 int At91SpiBusNodeInit(NUTSPINODE * node)
00140 {
00141     int rc;
00142     NUTSPIBUS *bus;
00143 
00144     
00145     NUTASSERT(node != NULL);
00146     NUTASSERT(node->node_bus != NULL);
00147     bus = node->node_bus;
00148 
00149     
00150 #if defined(SPI1_BASE)
00151     if (bus->bus_base == SPI1_BASE) {
00152         rc = At91Spi1ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0);
00153     } else
00154 #endif
00155     rc = At91Spi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0);
00156 
00157     
00158 
00159     if (rc == 0 && node->node_stat == NULL) {
00160         
00161         AT91SPIREG *spireg = malloc(sizeof(AT91SPIREG));
00162         if (spireg) {
00163             
00164             spireg->at91spi_mr = SPI_MODFDIS | SPI_MSTR;
00165             switch (node->node_cs) {
00166             case 0:
00167                 spireg->at91spi_mr |= SPI_PCS_0;
00168                 break;
00169             case 1:
00170                 spireg->at91spi_mr |= SPI_PCS_1;
00171                 break;
00172             case 2:
00173                 spireg->at91spi_mr |= SPI_PCS_2;
00174                 break;
00175             case 3:
00176                 spireg->at91spi_mr |= SPI_PCS_3;
00177                 break;
00178             }
00179             spireg->at91spi_csr = 0;
00180             
00181             node->node_stat = (void *)spireg;
00182             At91SpiSetup(node);
00183 
00184             
00185 
00186 
00187 #if !defined(SPIBUS1_POLLING_MODE) && defined(SPI1_BASE)
00188             if (bus->bus_base == SPI1_BASE) {
00189 #if defined(SPIBUS1_DOUBLE_BUFFER)
00190                 NutRegisterIrqHandler(bus->bus_sig, At91SpiInterrupt, &bus->bus_ready);
00191 #else
00192                 NutRegisterIrqHandler(bus->bus_sig, At91SpiBus1Interrupt, &bus->bus_ready);
00193 #endif
00194                 outr(bus->bus_base + SPI_IDR_OFF, (unsigned int) - 1);
00195                 NutIrqEnable(bus->bus_sig);
00196             } else
00197 #endif 
00198 
00199             {
00200 #if !defined(SPIBUS0_POLLING_MODE)
00201 #if defined(SPIBUS0_DOUBLE_BUFFER)
00202                 NutRegisterIrqHandler(bus->bus_sig, At91SpiInterrupt, &bus->bus_ready);
00203 #else
00204                 NutRegisterIrqHandler(bus->bus_sig, At91SpiBus0Interrupt, &bus->bus_ready);
00205 #endif
00206                 outr(bus->bus_base + SPI_IDR_OFF, (unsigned int) - 1);
00207                 NutIrqEnable(bus->bus_sig);
00208 #endif 
00209             }
00210         } else {
00211             
00212             rc = -1;
00213         }
00214     }
00215     return rc;
00216 }
00217 
00218 #if defined(SPIBUS0_POLLING_MODE) || defined(SPIBUS1_POLLING_MODE) || defined(SPIBUS0_DOUBLE_BUFFER_HEURISTIC) || defined(SPIBUS1_DOUBLE_BUFFER_HEURISTIC)
00219 
00233 int At91SpiBusPollTransfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen)
00234 {
00235     uint8_t b = 0xff;
00236     uint8_t *txp = (uint8_t *) txbuf;
00237     uint8_t *rxp = (uint8_t *) rxbuf;
00238     uintptr_t base;
00239 
00240     
00241     NUTASSERT(node != NULL);
00242     NUTASSERT(node->node_bus != NULL);
00243     NUTASSERT(node->node_bus->bus_base != 0);
00244     base = node->node_bus->bus_base;
00245 
00246     while (xlen--) {
00247         if (txp) {
00248             b = *txp++;
00249         }
00250         
00251         outr(base + SPI_TDR_OFF, b);
00252         
00253         while((inr(base + SPI_SR_OFF) & SPI_RDRF) == 0);
00254         
00255         b = (uint8_t)inr(base + SPI_RDR_OFF);
00256         if (rxp) {
00257             *rxp++ = b;
00258         }
00259     }
00260     return 0;
00261 }
00262 #endif
00263 
00264 #if defined(SPIBUS0_DOUBLE_BUFFER) || defined(SPIBUS1_DOUBLE_BUFFER)
00265 
00284 int At91SpiBusDblBufTransfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen)
00285 {
00286     uintptr_t base;
00287     uint32_t cr;
00288     uint32_t ir = 0;
00289 
00290 #if defined(SPIBUS0_DOUBLE_BUFFER_HEURISTIC) || defined(SPIBUS1_DOUBLE_BUFFER_HEURISTIC)
00291     if (xlen < SPI_DOUBLE_BUFFER_MIN_TRANSFER_SIZE) {
00292         return At91SpiBusPollTransfer(node, txbuf, rxbuf, xlen);
00293     }
00294 #endif
00295 
00296     
00297     NUTASSERT(node != NULL);
00298     NUTASSERT(node->node_bus != NULL);
00299     NUTASSERT(node->node_bus->bus_base != 0);
00300     base = node->node_bus->bus_base;
00301 
00302     outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00303 
00304     if (xlen) {
00305         
00306         if (txbuf) {
00307             outr(base + PERIPH_TPR_OFF, (uint32_t)txbuf);
00308         } else {
00309             outr(base + PERIPH_TPR_OFF, (uint32_t)rxbuf);
00310         }
00311         cr = PDC_TXTEN;
00312         outr(base + PERIPH_TCR_OFF, xlen);
00313         
00314         if (rxbuf) {
00315             outr(base + PERIPH_RPR_OFF, (uint32_t)rxbuf);
00316             outr(base + PERIPH_RCR_OFF, xlen);
00317             cr |= PDC_RXTEN;
00318             ir = SPI_RXBUFF;
00319         } else {
00320             cr |= PDC_RXTDIS;
00321             ir = SPI_TXBUFE;
00322             outr(base + PERIPH_RPR_OFF, 0);
00323             outr(base + PERIPH_RCR_OFF, 0);
00324         }
00325         outr(base + PERIPH_TNPR_OFF, 0);
00326         outr(base + PERIPH_TNCR_OFF, 0);
00327         outr(base + PERIPH_RNPR_OFF, 0);
00328         outr(base + PERIPH_RNCR_OFF, 0);
00329 
00330         outr(base + SPI_IDR_OFF, (unsigned int) - 1);
00331         outr(base + SPI_IER_OFF, ir);
00332         outr(base + PERIPH_PTCR_OFF, cr);
00333         
00334         NutEventWait(&node->node_bus->bus_ready, NUT_WAIT_INFINITE);
00335         outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00336     }
00337     return 0;
00338 }
00339 #endif
00340 
00341 #if defined(SPIBUS0_DOUBLE_BUFFER) || defined(SPIBUS1_DOUBLE_BUFFER)
00342 
00351 int At91SpiBusWait(NUTSPINODE * node, uint32_t tmo)
00352 {
00353     while ((inr(node->node_bus->bus_base + SPI_SR_OFF) & SPI_RXBUFF) == 0) {
00354         if (NutEventWait(&node->node_bus->bus_ready, tmo)) {
00355             return -1;
00356         }
00357     }
00358     return 0;
00359 }
00360 #endif