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