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 #include "spid.h"
00035 #include "board.h"
00036 #include <dma/dma.h>
00037 #include <drivers/dmad/dmad.h>
00038 #include <irq/irq.h>
00039
00040
00041
00042
00043
00044
00045 #define SIZE_LL 2
00046
00047
00048 #define DMA_WIDTH 0
00049
00050
00051
00052
00053
00054
00055 #define WRITE_PMC(pPmc, regName, value) pPmc->regName = (value)
00056
00057
00058 #define WRITE_SPI(pSpi, regName, value) pSpi->regName = (value)
00059
00060
00061 #define READ_SPI(pSpi, regName) (pSpi->regName)
00062
00063
00064 #define PERIPH_ENABLE(id) \
00065 WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << (id)))
00066
00067 #define PERIPH_DISABLE(id) \
00068 WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << (id)))
00069
00070
00071
00072
00073
00074
00075
00076 static DmaLinkList dmaTxLinkList[SIZE_LL];
00077 static DmaLinkList dmaRxLinkList[SIZE_LL];
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087 static void configureDmaChannels(void)
00088 {
00089
00090 PERIPH_ENABLE(AT91C_ID_HDMA);
00091
00092 DMA_Enable();
00093
00094
00095 DMA_DisableIt(0xFFFFFFFF);
00096 DMA_GetChannelStatus();
00097 DMA_GetStatus();
00098 DMA_DisableChannels((1 << DMA_CHANNEL_0) | (1 << DMA_CHANNEL_1));
00099
00100 DMA_SetConfiguration(DMA_CHANNEL_0,
00101 AT91C_HDMA_SRC_PER_2
00102 | AT91C_HDMA_DST_PER_2
00103 | AT91C_HDMA_SRC_H2SEL_HW
00104 | AT91C_HDMA_DST_H2SEL_SW
00105 | AT91C_HDMA_SOD_ENABLE
00106 | AT91C_HDMA_FIFOCFG_LARGESTBURST
00107 );
00108
00109
00110 DMA_SetConfiguration(DMA_CHANNEL_1,
00111 AT91C_HDMA_SRC_PER_1
00112 | AT91C_HDMA_DST_PER_1
00113 | AT91C_HDMA_SRC_H2SEL_SW
00114 | AT91C_HDMA_DST_H2SEL_HW
00115 | AT91C_HDMA_SOD_ENABLE
00116 | AT91C_HDMA_FIFOCFG_LARGESTBURST
00117 );
00118 }
00119
00120
00121
00122
00123
00124 static void configureLinkList(AT91S_SPI *pSpiHw,
00125 SpidCmd *pCommand)
00126 {
00127
00128 dmaRxLinkList[0].sourceAddress = (unsigned int)&pSpiHw->SPI_RDR;
00129 dmaRxLinkList[0].destAddress = (unsigned int)pCommand->pCmd;
00130 dmaRxLinkList[0].controlA = pCommand->cmdSize
00131 | AT91C_HDMA_SRC_WIDTH_BYTE
00132 | AT91C_HDMA_DST_WIDTH_BYTE
00133 ;
00134 dmaRxLinkList[0].controlB = AT91C_HDMA_SIF_0
00135 | AT91C_HDMA_DIF_0
00136 | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
00137 | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
00138 | AT91C_HDMA_FC_PER2MEM
00139 | AT91C_HDMA_SRC_ADDRESS_MODE_FIXED
00140 | AT91C_HDMA_DST_ADDRESS_MODE_INCR
00141 ;
00142 dmaTxLinkList[0].sourceAddress = (unsigned int)pCommand->pCmd;
00143 dmaTxLinkList[0].destAddress = (unsigned int)&pSpiHw->SPI_TDR;
00144 dmaTxLinkList[0].controlA = pCommand->cmdSize
00145 | AT91C_HDMA_SRC_WIDTH_BYTE
00146 | AT91C_HDMA_DST_WIDTH_BYTE
00147 ;
00148 dmaTxLinkList[0].controlB = AT91C_HDMA_SIF_0
00149 | AT91C_HDMA_DIF_0
00150 | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
00151 | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
00152 | AT91C_HDMA_FC_MEM2PER
00153 | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
00154 | AT91C_HDMA_DST_ADDRESS_MODE_FIXED
00155 ;
00156
00157
00158 if (pCommand->pData == 0) {
00159
00160 dmaRxLinkList[0].descriptor = 0;
00161 dmaTxLinkList[0].descriptor = 0;
00162 }
00163
00164 else {
00165
00166 dmaRxLinkList[0].descriptor = (unsigned int)&dmaRxLinkList[1];
00167 dmaRxLinkList[1].sourceAddress = (unsigned int)&pSpiHw->SPI_RDR;
00168 dmaRxLinkList[1].destAddress = (unsigned int)pCommand->pData;
00169 dmaRxLinkList[1].controlA = pCommand->dataSize
00170 | AT91C_HDMA_SRC_WIDTH_BYTE
00171 | AT91C_HDMA_DST_WIDTH_BYTE
00172 ;
00173 dmaRxLinkList[1].controlB = AT91C_HDMA_SIF_0
00174 | AT91C_HDMA_DIF_0
00175 | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
00176 | AT91C_HDMA_DST_DSCR_FETCH_DISABLE
00177 | AT91C_HDMA_FC_PER2MEM
00178 | AT91C_HDMA_SRC_ADDRESS_MODE_FIXED
00179 | AT91C_HDMA_DST_ADDRESS_MODE_INCR
00180 ;
00181 dmaRxLinkList[1].descriptor = 0;
00182
00183 dmaTxLinkList[0].descriptor = (unsigned int)&dmaTxLinkList[1];
00184 dmaTxLinkList[1].sourceAddress = (unsigned int)pCommand->pData;
00185 dmaTxLinkList[1].destAddress = (unsigned int)&pSpiHw->SPI_TDR;
00186 dmaTxLinkList[1].controlA = pCommand->dataSize
00187 | AT91C_HDMA_SRC_WIDTH_BYTE
00188 | AT91C_HDMA_DST_WIDTH_BYTE
00189 ;
00190 dmaTxLinkList[1].controlB = AT91C_HDMA_SIF_0
00191 | AT91C_HDMA_DIF_0
00192 | AT91C_HDMA_SRC_DSCR_FETCH_DISABLE
00193 | AT91C_HDMA_DST_DSCR_FETCH_DISABLE
00194 | AT91C_HDMA_FC_MEM2PER
00195 | AT91C_HDMA_SRC_ADDRESS_MODE_INCR
00196 | AT91C_HDMA_DST_ADDRESS_MODE_FIXED
00197 ;
00198 dmaTxLinkList[1].descriptor = 0;
00199 }
00200
00201
00202 DMA_SetDescriptorAddr(DMA_CHANNEL_0, (unsigned int)&dmaRxLinkList[0]);
00203 DMA_SetDescriptorAddr(DMA_CHANNEL_1, (unsigned int)&dmaTxLinkList[0]);
00204 AT91C_BASE_HDMA->HDMA_CH[DMA_CHANNEL_0].HDMA_CTRLB = 0
00205 | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
00206 | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
00207 ;
00208 AT91C_BASE_HDMA->HDMA_CH[DMA_CHANNEL_1].HDMA_CTRLB = 0
00209 | AT91C_HDMA_SRC_DSCR_FETCH_FROM_MEM
00210 | AT91C_HDMA_DST_DSCR_FETCH_FROM_MEM
00211 ;
00212 }
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 unsigned char SPID_Configure(Spid *pSpid, AT91S_SPI *pSpiHw,
00228 unsigned char spiId)
00229 {
00230
00231 pSpid->pSpiHw = pSpiHw;
00232 pSpid->spiId = spiId;
00233 pSpid->semaphore = 1;
00234 pSpid->pCurrentCommand = 0;
00235
00236
00237 PERIPH_ENABLE(pSpid->spiId);
00238
00239
00240 WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
00241 WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SWRST);
00242
00243
00244 WRITE_SPI(pSpiHw, SPI_MR, AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS);
00245
00246
00247 WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
00248
00249
00250 WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIDIS);
00251
00252
00253 PERIPH_DISABLE(pSpid->spiId);
00254
00255 return 0;
00256 }
00257
00258
00259
00260
00261
00262
00263
00264 void SPID_ConfigureCS(Spid *pSpid, unsigned char cs, unsigned int csr)
00265 {
00266 AT91S_SPI *pSpiHw = pSpid->pSpiHw;
00267
00268
00269 PERIPH_ENABLE(pSpid->spiId);
00270
00271
00272 WRITE_SPI(pSpiHw, SPI_CSR[cs], csr);
00273
00274
00275 PERIPH_DISABLE(pSpid->spiId);
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287 unsigned char SPID_SendCommand(Spid *pSpid, SpidCmd *pCommand)
00288 {
00289 AT91S_SPI *pSpiHw = pSpid->pSpiHw;
00290 unsigned int spiMr;
00291
00292
00293 if (pSpid->semaphore == 0)
00294
00295 return SPID_ERROR_LOCK;
00296
00297 pSpid->semaphore--;
00298
00299
00300 PERIPH_ENABLE(pSpid->spiId);
00301
00302
00303 WRITE_SPI(pSpiHw, SPI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);
00304
00305
00306 spiMr = READ_SPI(pSpiHw, SPI_MR);
00307 spiMr |= AT91C_SPI_PCS;
00308 spiMr &= ~((1 << pCommand->spiCs) << 16);
00309 WRITE_SPI(pSpiHw, SPI_MR, spiMr);
00310
00311
00312 configureDmaChannels();
00313 configureLinkList(pSpiHw, pCommand);
00314
00315
00316 pSpid->pCurrentCommand = pCommand;
00317
00318
00319 WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIEN);
00320
00321
00322 DMA_EnableChannels((1 << DMA_CHANNEL_0) | (1 << DMA_CHANNEL_1));
00323
00324
00325 DMA_EnableIt((DMA_CBTC << DMA_CHANNEL_0)
00326 | (DMA_CBTC << DMA_CHANNEL_1));
00327
00328 return 0;
00329 }
00330
00331
00332
00333
00334 void SPID_Handler(Spid *pSpid)
00335 {
00336 unsigned int dmaStatus;
00337 SpidCmd *pSpidCmd = pSpid->pCurrentCommand;
00338 AT91S_SPI *pSpiHw = pSpid->pSpiHw;
00339
00340 dmaStatus = DMA_GetStatus();
00341
00342 if ((dmaStatus & AT91C_CBTC) == 0)
00343 return;
00344
00345 if ((dmaStatus & (DMA_CBTC << DMA_CHANNEL_0)) == 0)
00346 return;
00347
00348
00349 WRITE_SPI(pSpiHw, SPI_CR, AT91C_SPI_SPIDIS);
00350
00351 PERIPH_DISABLE(pSpid->spiId);
00352
00353
00354 DMA_Disable();
00355
00356 PERIPH_DISABLE(AT91C_ID_HDMA);
00357
00358
00359 pSpid->semaphore++;
00360
00361
00362 if (pSpidCmd && pSpidCmd->callback)
00363
00364 pSpidCmd->callback(0, pSpidCmd->pArgument);
00365
00366 }
00367
00368
00369
00370
00371
00372
00373 unsigned char SPID_IsBusy(const Spid *pSpid)
00374 {
00375 if (pSpid->semaphore == 0)
00376 return 1;
00377 else
00378
00379 return 0;
00380 }
00381