spibus_at91.c
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 #if defined(SPIBUS0_DOUBLE_BUFFER) || defined(SPIBUS1_DOUBLE_BUFFER)
00055 #warning Double buffered SPI not tested for AT91 targets.
00056
00059 static void At91SpiInterrupt(void *arg)
00060 {
00061 NutEventPostFromIrq((void **)arg);
00062 }
00063 #endif
00064
00072 int At91SpiSetup(NUTSPINODE * node)
00073 {
00074 uint32_t clk;
00075 uint32_t clkdiv;
00076 AT91SPIREG *spireg;
00077
00078 NUTASSERT(node != NULL);
00079 NUTASSERT(node->node_stat != NULL);
00080 NUTASSERT(node->node_bus != NULL);
00081 NUTASSERT(node->node_bus->bus_base != 0);
00082 spireg = node->node_stat;
00083
00084 spireg->at91spi_mr &= ~(SPI_MODFDIS | SPI_LLB);
00085 if ((node->node_mode & SPI_MODE_FAULT) == 0) {
00086 spireg->at91spi_mr |= SPI_MODFDIS;
00087 }
00088 if (node->node_mode & SPI_MODE_LOOPBACK) {
00089 spireg->at91spi_mr |= SPI_LLB;
00090 }
00091
00092 spireg->at91spi_csr &= ~(SPI_BITS | SPI_CPOL | SPI_NCPHA | SPI_CSAAT | SPI_SCBR);
00093 if (node->node_bits) {
00094 spireg->at91spi_csr |= ((uint32_t)(node->node_bits - 8) << SPI_BITS_LSB) & SPI_BITS;
00095 }
00096 if (node->node_mode & SPI_MODE_CPOL) {
00097 spireg->at91spi_csr |= SPI_CPOL;
00098 }
00099 if ((node->node_mode & SPI_MODE_CPHA) == 0) {
00100 spireg->at91spi_csr |= SPI_NCPHA;
00101 }
00102 if (node->node_mode & SPI_MODE_CSKEEP) {
00103 spireg->at91spi_csr |= SPI_CSAAT;
00104 }
00105
00106
00107 clk = NutClockGet(NUT_HWCLK_PERIPHERAL);
00108
00109 clkdiv = (clk + node->node_rate - 1) / node->node_rate;
00110
00111 if (clkdiv < 1) {
00112 clkdiv++;
00113 }
00114
00115 else if (clkdiv > 255) {
00116 clkdiv = 255;
00117 }
00118 spireg->at91spi_csr |= clkdiv << SPI_SCBR_LSB;
00119
00120
00121 node->node_rate = clk / clkdiv;
00122 node->node_mode &= ~SPI_MODE_UPDATE;
00123
00124 return 0;
00125 }
00126
00137 int At91SpiBusNodeInit(NUTSPINODE * node)
00138 {
00139 int rc;
00140 NUTSPIBUS *bus;
00141
00142
00143 NUTASSERT(node != NULL);
00144 NUTASSERT(node->node_bus != NULL);
00145 bus = node->node_bus;
00146
00147
00148 #if defined(SPI1_BASE)
00149 if (bus->bus_base == SPI1_BASE) {
00150 rc = At91Spi1ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0);
00151 } else
00152 #endif
00153 rc = At91Spi0ChipSelect(node->node_cs, (node->node_mode & SPI_MODE_CSHIGH) == 0);
00154
00155
00156
00157 if (rc == 0 && node->node_stat == NULL) {
00158
00159 AT91SPIREG *spireg = malloc(sizeof(AT91SPIREG));
00160 if (spireg) {
00161
00162 spireg->at91spi_mr = SPI_MODFDIS | SPI_MSTR;
00163 switch (node->node_cs) {
00164 case 0:
00165 spireg->at91spi_mr |= SPI_PCS_0;
00166 break;
00167 case 1:
00168 spireg->at91spi_mr |= SPI_PCS_1;
00169 break;
00170 case 2:
00171 spireg->at91spi_mr |= SPI_PCS_2;
00172 break;
00173 case 3:
00174 spireg->at91spi_mr |= SPI_PCS_3;
00175 break;
00176 }
00177 spireg->at91spi_csr = 0;
00178
00179 node->node_stat = (void *)spireg;
00180 At91SpiSetup(node);
00181
00182
00183
00184
00185 #if !defined(SPIBUS1_POLLING_MODE) && defined(SPI1_BASE)
00186 if (bus->bus_base == SPI1_BASE) {
00187 #if defined(SPIBUS1_DOUBLE_BUFFER)
00188 NutRegisterIrqHandler(bus->bus_sig, At91SpiInterrupt, &bus->bus_ready);
00189 #else
00190 NutRegisterIrqHandler(bus->bus_sig, At91SpiBus1Interrupt, &bus->bus_ready);
00191 #endif
00192 outr(bus->bus_base + SPI_IDR_OFF, (unsigned int) - 1);
00193 NutIrqEnable(bus->bus_sig);
00194 } else
00195 #endif
00196
00197 {
00198 #if !defined(SPIBUS0_POLLING_MODE)
00199 #if defined(SPIBUS0_DOUBLE_BUFFER)
00200 NutRegisterIrqHandler(bus->bus_sig, At91SpiInterrupt, &bus->bus_ready);
00201 #else
00202 NutRegisterIrqHandler(bus->bus_sig, At91SpiBus0Interrupt, &bus->bus_ready);
00203 #endif
00204 outr(bus->bus_base + SPI_IDR_OFF, (unsigned int) - 1);
00205 NutIrqEnable(bus->bus_sig);
00206 #endif
00207 }
00208 } else {
00209
00210 rc = -1;
00211 }
00212 }
00213 return rc;
00214 }
00215
00216 #if defined(SPIBUS0_POLLING_MODE) || defined(SPIBUS1_POLLING_MODE)
00217
00231 int At91SpiBusPollTransfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen)
00232 {
00233 uint8_t b = 0xff;
00234 uint8_t *txp = (uint8_t *) txbuf;
00235 uint8_t *rxp = (uint8_t *) rxbuf;
00236 uintptr_t base;
00237
00238
00239 NUTASSERT(node != NULL);
00240 NUTASSERT(node->node_bus != NULL);
00241 NUTASSERT(node->node_bus->bus_base != 0);
00242 base = node->node_bus->bus_base;
00243
00244 while (xlen--) {
00245 if (txp) {
00246 b = *txp++;
00247 }
00248
00249 outr(base + SPI_TDR_OFF, b);
00250
00251 while((inr(base + SPI_SR_OFF) & SPI_RDRF) == 0);
00252
00253 b = (uint8_t)inr(base + SPI_RDR_OFF);
00254 if (rxp) {
00255 *rxp++ = b;
00256 }
00257 }
00258 return 0;
00259 }
00260 #endif
00261
00262 #if defined(SPIBUS0_DOUBLE_BUFFER) || defined(SPIBUS1_DOUBLE_BUFFER)
00263
00282 int At91SpiBusDblBufTransfer(NUTSPINODE * node, CONST void *txbuf, void *rxbuf, int xlen)
00283 {
00284 uintptr_t base;
00285 uint32_t cr;
00286 uint32_t ir = 0;
00287
00288
00289 NUTASSERT(node != NULL);
00290 NUTASSERT(node->node_bus != NULL);
00291 NUTASSERT(node->node_bus->bus_base != 0);
00292 base = node->node_bus->bus_base;
00293
00294 outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00295
00296 if (xlen) {
00297
00298 if (txbuf) {
00299 outr(base + PERIPH_TPR_OFF, (uint32_t)txbuf);
00300 } else {
00301 outr(base + PERIPH_TPR_OFF, (uint32_t)rxbuf);
00302 }
00303 cr = PDC_TXTEN;
00304 outr(base + PERIPH_TCR_OFF, xlen);
00305
00306 if (rxbuf) {
00307 outr(base + PERIPH_RPR_OFF, (uint32_t)rxbuf);
00308 outr(base + PERIPH_RCR_OFF, xlen);
00309 cr |= PDC_RXTEN;
00310 ir = SPI_RXBUFF;
00311 } else {
00312 cr |= PDC_RXTDIS;
00313 ir = SPI_TXBUFE;
00314 outr(base + PERIPH_RPR_OFF, 0);
00315 outr(base + PERIPH_RCR_OFF, 0);
00316 }
00317 outr(base + PERIPH_TNPR_OFF, 0);
00318 outr(base + PERIPH_TNCR_OFF, 0);
00319 outr(base + PERIPH_RNPR_OFF, 0);
00320 outr(base + PERIPH_RNCR_OFF, 0);
00321
00322 outr(base + SPI_IDR_OFF, (unsigned int) - 1);
00323 outr(base + SPI_IER_OFF, ir);
00324 outr(base + PERIPH_PTCR_OFF, cr);
00325
00326 NutEventWait(&node->node_bus->bus_ready, NUT_WAIT_INFINITE);
00327 outr(base + PERIPH_PTCR_OFF, PDC_TXTDIS | PDC_RXTDIS);
00328 }
00329 return -1;
00330 }
00331 #endif
00332
00333 #if !defined(SPIBUS0_DOUBLE_BUFFER) || !defined(SPIBUS1_DOUBLE_BUFFER)
00334
00343 int At91SpiBusWait(NUTSPINODE * node, uint32_t tmo)
00344 {
00345 while ((inr(node->node_bus->bus_base + SPI_SR_OFF) & SPI_RXBUFF) == 0) {
00346 if (NutEventWait(&node->node_bus->bus_ready, tmo)) {
00347 return -1;
00348 }
00349 }
00350 return 0;
00351 }
00352 #endif