]> git.sur5r.net Git - freertos/blob - Demo/Common/drivers/Atmel/at91lib/peripherals/mci/mci.c
Atmel provided hardware specifics.
[freertos] / Demo / Common / drivers / Atmel / at91lib / peripherals / mci / mci.c
1 /* ----------------------------------------------------------------------------\r
2  *         ATMEL Microcontroller Software Support  -  ROUSSET  -\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2006, Atmel Corporation\r
5 \r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * - Redistributions in binary form must reproduce the above copyright notice,\r
15  * this list of conditions and the disclaimer below in the documentation and/or\r
16  * other materials provided with the distribution.\r
17  *\r
18  * Atmel's name may not be used to endorse or promote products derived from\r
19  * this software without specific prior written permission.\r
20  *\r
21  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
24  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
27  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
31  * ----------------------------------------------------------------------------\r
32  */\r
33 \r
34 //------------------------------------------------------------------------------\r
35 //         Headers\r
36 //------------------------------------------------------------------------------\r
37 \r
38 #include "mci.h"\r
39 #include <utility/assert.h>\r
40 #include <utility/trace.h>\r
41 \r
42 //------------------------------------------------------------------------------\r
43 //         Local constants\r
44 //------------------------------------------------------------------------------\r
45 \r
46 /// Bit mask for status register errors.\r
47 #define STATUS_ERRORS (AT91C_MCI_UNRE  \\r
48                        | AT91C_MCI_OVRE \\r
49                        | AT91C_MCI_DTOE \\r
50                        | AT91C_MCI_DCRCE \\r
51                        | AT91C_MCI_RTOE \\r
52                        | AT91C_MCI_RENDE \\r
53                        | AT91C_MCI_RCRCE \\r
54                        | AT91C_MCI_RDIRE \\r
55                        | AT91C_MCI_RINDE)\r
56 \r
57 /// MCI data timeout configuration with 1048576 MCK cycles between 2 data transfers.\r
58 #define DTOR_1MEGA_CYCLES           (AT91C_MCI_DTOCYC | AT91C_MCI_DTOMUL)\r
59 \r
60 #define SDCARD_APP_OP_COND_CMD      (41 | AT91C_MCI_SPCMD_NONE  | AT91C_MCI_RSPTYP_48   | AT91C_MCI_TRCMD_NO )\r
61 #define MMC_SEND_OP_COND_CMD        (1  | AT91C_MCI_TRCMD_NO    | AT91C_MCI_SPCMD_NONE  | AT91C_MCI_RSPTYP_48 | AT91C_MCI_OPDCMD)\r
62 \r
63 \r
64 #define DISABLE    0    // Disable MCI interface\r
65 #define ENABLE     1    // Enable MCI interface\r
66 \r
67 \r
68 //------------------------------------------------------------------------------\r
69 //         Local macros\r
70 //------------------------------------------------------------------------------\r
71 \r
72 /// Used to write in PMC registers.\r
73 #define WRITE_PMC(pPmc, regName, value)     pPmc->regName = (value)\r
74 \r
75 /// Used to write in MCI registers.\r
76 #define WRITE_MCI(pMci, regName, value)     pMci->regName = (value)\r
77 \r
78 /// Used to read from MCI registers.\r
79 #define READ_MCI(pMci, regName)             (pMci->regName)\r
80 \r
81 //------------------------------------------------------------------------------\r
82 //         Global functions\r
83 //------------------------------------------------------------------------------\r
84 \r
85 //------------------------------------------------------------------------------\r
86 /// Enable/disable a MCI driver instance.\r
87 /// \param pMci  Pointer to a MCI driver instance.\r
88 /// \param enb  0 for disable MCI and 1 for enable MCI.\r
89 //------------------------------------------------------------------------------\r
90 void MCI_Enable(Mci *pMci, unsigned char enb)\r
91 {\r
92         AT91S_MCI *pMciHw = pMci->pMciHw;\r
93 \r
94         SANITY_CHECK(pMci);\r
95     SANITY_CHECK(pMci->pMciHw);\r
96 \r
97     // Set the Control Register: Enable/Disable MCI interface clock\r
98     if(enb == DISABLE) {\r
99         WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS);\r
100     }\r
101     else {\r
102         WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIEN);\r
103     }\r
104 }\r
105 \r
106 //------------------------------------------------------------------------------\r
107 /// Initializes a MCI driver instance and the underlying peripheral.\r
108 /// \param pMci  Pointer to a MCI driver instance.\r
109 /// \param pMciHw  Pointer to a MCI peripheral.\r
110 /// \param mciId  MCI peripheral identifier.\r
111 /// \param mode  Slot and type of connected card.\r
112 //------------------------------------------------------------------------------\r
113 void MCI_Init(\r
114     Mci *pMci,\r
115     AT91S_MCI *pMciHw,\r
116     unsigned char mciId,\r
117     unsigned int mode)\r
118 {\r
119     unsigned short clkDiv;\r
120 \r
121     SANITY_CHECK(pMci);\r
122     SANITY_CHECK(pMciHw);\r
123     SANITY_CHECK((mode == MCI_MMC_SLOTA) || (mode == MCI_MMC_SLOTB)\r
124                  || (mode == MCI_SD_SLOTA) || (mode == MCI_SD_SLOTB));\r
125 \r
126     // Initialize the MCI driver structure\r
127     pMci->pMciHw = pMciHw;\r
128     pMci->mciId  = mciId;\r
129     pMci->semaphore = 1;\r
130     pMci->pCommand = 0;\r
131 \r
132     // Enable the MCI clock\r
133     WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << mciId));\r
134     \r
135      // Reset the MCI\r
136     WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);\r
137 \r
138     // Disable the MCI\r
139     WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);\r
140 \r
141     // Disable all the interrupts\r
142     WRITE_MCI(pMciHw, MCI_IDR, 0xFFFFFFFF);\r
143 \r
144     // Set the Data Timeout Register\r
145     WRITE_MCI(pMciHw, MCI_DTOR, DTOR_1MEGA_CYCLES);\r
146 \r
147     // Set the Mode Register: 400KHz for MCK = 48MHz (CLKDIV = 58)\r
148     clkDiv = (BOARD_MCK / (400000 * 2)) - 1;\r
149     WRITE_MCI(pMciHw, MCI_MR, (clkDiv | (AT91C_MCI_PWSDIV & (0x7 << 8))));\r
150 \r
151     // Set the SDCard Register\r
152     WRITE_MCI(pMciHw, MCI_SDCR, mode);\r
153 \r
154     // Enable the MCI and the Power Saving\r
155     WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIEN);\r
156 \r
157     // Disable the MCI peripheral clock.\r
158     WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << mciId));\r
159 }\r
160 \r
161 //------------------------------------------------------------------------------\r
162 /// Close a MCI driver instance and the underlying peripheral.\r
163 /// \param pMci  Pointer to a MCI driver instance.\r
164 /// \param pMciHw  Pointer to a MCI peripheral.\r
165 /// \param mciId  MCI peripheral identifier.\r
166 //------------------------------------------------------------------------------\r
167 void MCI_Close(Mci *pMci)\r
168 {\r
169     AT91S_MCI *pMciHw = pMci->pMciHw;\r
170 \r
171     SANITY_CHECK(pMci);\r
172     SANITY_CHECK(pMciHw);\r
173 \r
174     // Initialize the MCI driver structure\r
175     pMci->semaphore = 1;\r
176     pMci->pCommand = 0;\r
177 \r
178     // Disable the MCI peripheral clock.\r
179     WRITE_PMC(AT91C_BASE_PMC, PMC_PCDR, (1 << pMci->mciId));\r
180     \r
181     // Disable the MCI\r
182     WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS);\r
183 \r
184     // Disable all the interrupts\r
185     WRITE_MCI(pMciHw, MCI_IDR, 0xFFFFFFFF);\r
186 }\r
187 \r
188 //------------------------------------------------------------------------------\r
189 /// Configure the  MCI CLKDIV in the MCI_MR register. The max. for MCI clock is \r
190 /// MCK/2 and corresponds to CLKDIV = 0\r
191 /// \param pMci  Pointer to the low level MCI driver.\r
192 /// \param mciSpeed  MCI clock speed in Hz.\r
193 //------------------------------------------------------------------------------\r
194 void MCI_SetSpeed(Mci *pMci, unsigned int mciSpeed)\r
195 {\r
196     AT91S_MCI *pMciHw = pMci->pMciHw;\r
197     unsigned int mciMr;\r
198     unsigned short clkdiv;\r
199 \r
200     SANITY_CHECK(pMci);\r
201     SANITY_CHECK(pMci->pMciHw);\r
202 \r
203     // Set the Mode Register: 400KHz for MCK = 48MHz (CLKDIV = 58)\r
204     mciMr = READ_MCI(pMciHw, MCI_MR) & (~AT91C_MCI_CLKDIV);\r
205 \r
206     // Multimedia Card Interface clock (MCCK or MCI_CK) is Master Clock (MCK)\r
207     // divided by (2*(CLKDIV+1))\r
208     if (mciSpeed > 0) {\r
209 \r
210         clkdiv = (BOARD_MCK / (mciSpeed * 2));\r
211         if (clkdiv > 0) {\r
212 \r
213             clkdiv -= 1;\r
214         }\r
215     }\r
216     else {\r
217 \r
218         clkdiv = 0;\r
219     }\r
220 \r
221     WRITE_MCI(pMciHw, MCI_MR, mciMr | clkdiv);\r
222 }\r
223 \r
224 //------------------------------------------------------------------------------\r
225 /// Configure the  MCI SDCBUS in the MCI_SDCR register. Only two modes available\r
226 /// \r
227 /// \param pMci  Pointer to the low level MCI driver.\r
228 /// \param busWidth  MCI bus width mode.\r
229 //------------------------------------------------------------------------------\r
230 void MCI_SetBusWidth(Mci *pMci, unsigned char busWidth)\r
231 {\r
232     AT91S_MCI *pMciHw = pMci->pMciHw;\r
233     unsigned int mciSdcr;\r
234 \r
235     SANITY_CHECK(pMci);\r
236     SANITY_CHECK(pMci->pMciHw);\r
237 \r
238     mciSdcr = (READ_MCI(pMciHw, MCI_SDCR) & ~(AT91C_MCI_SCDBUS));\r
239 \r
240     WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr | busWidth);\r
241 }\r
242 \r
243 //------------------------------------------------------------------------------\r
244 /// Starts a MCI  transfer. This is a non blocking function. It will return\r
245 /// as soon as the transfer is started.\r
246 /// Return 0 if successful; otherwise returns MCI_ERROR_LOCK if the driver is\r
247 /// already in use.\r
248 /// \param pMci  Pointer to an MCI driver instance.\r
249 /// \param pCommand  Pointer to the command to execute.\r
250 //------------------------------------------------------------------------------\r
251 unsigned char MCI_SendCommand(Mci *pMci, MciCmd *pCommand)\r
252 {\r
253     AT91PS_MCI pMciHw = pMci->pMciHw;\r
254     unsigned int mciIer, mciMr;\r
255 \r
256     SANITY_CHECK(pMci);\r
257     SANITY_CHECK(pMciHw);\r
258     SANITY_CHECK(pCommand);\r
259 \r
260     // Try to acquire the MCI semaphore\r
261     if (pMci->semaphore == 0) {\r
262     \r
263         return MCI_ERROR_LOCK;\r
264     }\r
265     pMci->semaphore--;\r
266     // trace_LOG(trace_DEBUG, "MCI_SendCommand %x %d\n\r", READ_MCI(pMciHw, MCI_SR), pCommand->cmd & 0x3f);\r
267 \r
268     // Command is now being executed\r
269     pMci->pCommand = pCommand;\r
270     pCommand->status = MCI_STATUS_PENDING;\r
271 \r
272     // Enable the MCI clock\r
273     WRITE_PMC(AT91C_BASE_PMC, PMC_PCER, (1 << pMci->mciId));\r
274 \r
275     //Disable MCI clock, for multi-block data transfer\r
276     MCI_Enable(pMci, DISABLE);\r
277 \r
278     // Set PDC data transfer direction\r
279     if(pCommand->blockSize > 0) {\r
280         if(pCommand->isRead) {\r
281             WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTEN);\r
282         }\r
283         else {\r
284             WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_TXTEN);\r
285         }\r
286     }\r
287     // Disable transmitter and receiver\r
288     WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS);\r
289 \r
290     mciMr = READ_MCI(pMciHw, MCI_MR) & (~(AT91C_MCI_BLKLEN | AT91C_MCI_PDCMODE));\r
291 \r
292     // Command with DATA stage\r
293     if (pCommand->blockSize > 0) {\r
294         // Enable PDC mode and set block size\r
295         if(pCommand->conTrans != MCI_CONTINUE_TRANSFER) {\r
296 \r
297             WRITE_MCI(pMciHw, MCI_MR, mciMr | AT91C_MCI_PDCMODE | (pCommand->blockSize << 16));\r
298         }\r
299 \r
300         // DATA transfer from card to host\r
301         if (pCommand->isRead) { \r
302             WRITE_MCI(pMciHw, MCI_RPR, (int) pCommand->pData);\r
303 \r
304             // If Multiblock command set the BLKR register\r
305             /* if (pCommand->nbBlock > 1) { \r
306                 WRITE_MCI(pMciHw, MCI_BLKR, pCommand->nbBlock | (pCommand->blockSize << 16));\r
307             }\r
308             else {\r
309                 WRITE_MCI(pMciHw, MCI_BLKR, (pCommand->blockSize << 16));                       \r
310             }*/\r
311 \r
312             // Sanity check\r
313             if (pCommand->nbBlock == 0)\r
314                 pCommand->nbBlock = 1;\r
315             ////////\r
316             if ((pCommand->blockSize & 0x3) != 0) {\r
317                 WRITE_MCI(pMciHw, MCI_RCR, (pCommand->nbBlock * pCommand->blockSize) / 4 + 1);\r
318             }\r
319             else {\r
320                 WRITE_MCI(pMciHw, MCI_RCR, (pCommand->nbBlock * pCommand->blockSize) / 4);\r
321             }\r
322 \r
323             WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_RXTEN);\r
324             mciIer = AT91C_MCI_ENDRX | STATUS_ERRORS;\r
325             // mciIer = AT91C_MCI_RXBUFF | STATUS_ERRORS;\r
326         }\r
327 \r
328         // DATA transfer from host to card\r
329         else {\r
330             // Sanity check\r
331             if (pCommand->nbBlock == 0)\r
332                 pCommand->nbBlock = 1;\r
333             WRITE_MCI(pMciHw, MCI_TPR, (int) pCommand->pData);\r
334             // Update the PDC counter\r
335             if ((pCommand->blockSize & 0x3) != 0) {\r
336                 WRITE_MCI(pMciHw, MCI_TCR, (pCommand->nbBlock * pCommand->blockSize) / 4 + 1);\r
337             }\r
338             else {\r
339                 WRITE_MCI(pMciHw, MCI_TCR, (pCommand->nbBlock * pCommand->blockSize) / 4);\r
340             }\r
341             // MCI_BLKE notifies the end of Multiblock command\r
342             mciIer = AT91C_MCI_BLKE | STATUS_ERRORS;\r
343         }\r
344     }\r
345     // No data transfer: stop at the end of the command\r
346     else {\r
347         WRITE_MCI(pMciHw, MCI_MR, mciMr);\r
348         mciIer = AT91C_MCI_CMDRDY | STATUS_ERRORS;\r
349     }\r
350     // Enable MCI clock\r
351     MCI_Enable(pMci, ENABLE);\r
352 \r
353     // Send the command\r
354     if((pCommand->conTrans != MCI_CONTINUE_TRANSFER) \r
355         || (pCommand->blockSize == 0)) {\r
356 \r
357         WRITE_MCI(pMciHw, MCI_ARGR, pCommand->arg);\r
358         WRITE_MCI(pMciHw, MCI_CMDR, pCommand->cmd);\r
359     }\r
360 \r
361     // In case of transmit, the PDC shall be enabled after sending the command\r
362     if ((pCommand->blockSize > 0) && !(pCommand->isRead)) {\r
363         WRITE_MCI(pMciHw, MCI_PTCR, AT91C_PDC_TXTEN);\r
364     }\r
365 \r
366     // Ignore data error\r
367 //    if (pCommand->blockSize == 0) {\r
368     {\r
369         mciIer &= ~(AT91C_MCI_UNRE | AT91C_MCI_OVRE \\r
370             | AT91C_MCI_DTOE | AT91C_MCI_DCRCE);\r
371     }\r
372 \r
373     // Interrupt enable shall be done after PDC TXTEN and RXTEN\r
374     WRITE_MCI(pMciHw, MCI_IER, mciIer);\r
375 \r
376     return 0;\r
377 }\r
378 \r
379 //------------------------------------------------------------------------------\r
380 /// Check NOTBUSY and DTIP bits of status register on the given MCI driver.\r
381 /// Return value, 0 for bus ready, 1 for bus busy\r
382 /// \param pMci  Pointer to a MCI driver instance.\r
383 //------------------------------------------------------------------------------\r
384 unsigned char MCI_CheckBusy(Mci *pMci)\r
385 {\r
386     AT91S_MCI *pMciHw = pMci->pMciHw;\r
387     unsigned int status;\r
388 \r
389     // Enable MCI clock\r
390     MCI_Enable(pMci, ENABLE);\r
391 \r
392     status = READ_MCI(pMciHw, MCI_SR);\r
393     // trace_LOG(trace_DEBUG, "status %x\n\r",status);\r
394 \r
395 \r
396     if(((status & AT91C_MCI_NOTBUSY)!=0)\r
397         && ((status & AT91C_MCI_DTIP)==0)) {\r
398 \r
399         // Disable MCI clock\r
400         MCI_Enable(pMci, DISABLE);\r
401 \r
402         return 0;\r
403     }\r
404     else {\r
405         return 1;\r
406     }\r
407 }\r
408 \r
409 //------------------------------------------------------------------------------\r
410 /// Check BLKE bit of status register on the given MCI driver.\r
411 /// \param pMci  Pointer to a MCI driver instance.\r
412 //------------------------------------------------------------------------------\r
413 unsigned char MCI_CheckBlke(Mci *pMci)\r
414 {\r
415     AT91S_MCI *pMciHw = pMci->pMciHw;\r
416     unsigned int status;\r
417 \r
418     status = READ_MCI(pMciHw, MCI_SR);\r
419     // trace_LOG(trace_DEBUG, "status %x\n\r",status);\r
420 \r
421     if((status & AT91C_MCI_BLKE)!=0) {\r
422         return 0;\r
423     }\r
424     else {\r
425         return 1;\r
426     }\r
427 }\r
428 \r
429 //------------------------------------------------------------------------------\r
430 /// Processes pending events on the given MCI driver.\r
431 /// \param pMci  Pointer to a MCI driver instance.\r
432 //------------------------------------------------------------------------------\r
433 void MCI_Handler(Mci *pMci)\r
434 {\r
435     AT91S_MCI *pMciHw = pMci->pMciHw;\r
436     MciCmd *pCommand = pMci->pCommand;\r
437     unsigned int status;\r
438     unsigned char i;\r
439     #if defined(at91rm9200)\r
440     unsigned int mciCr, mciSdcr, mciMr, mciDtor;\r
441     #endif\r
442 \r
443     SANITY_CHECK(pMci);\r
444     SANITY_CHECK(pMciHw);\r
445     SANITY_CHECK(pCommand);\r
446 \r
447     // Read the status register\r
448     status = READ_MCI(pMciHw, MCI_SR) & READ_MCI(pMciHw, MCI_IMR);\r
449     // trace_LOG(trace_DEBUG, "status %x\n\r", status);\r
450 \r
451     // Check if an error has occured\r
452     if ((status & STATUS_ERRORS) != 0) {\r
453 \r
454         // Check error code\r
455         if ((status & STATUS_ERRORS) == AT91C_MCI_RTOE) {\r
456         \r
457             pCommand->status = MCI_STATUS_NORESPONSE;\r
458         }\r
459         // if the command is SEND_OP_COND the CRC error flag is always present\r
460         // (cf : R3 response)\r
461         else if (((status & STATUS_ERRORS) != AT91C_MCI_RCRCE)\r
462                   || ((pCommand->cmd != SDCARD_APP_OP_COND_CMD)\r
463                       && (pCommand->cmd != MMC_SEND_OP_COND_CMD))) {\r
464 \r
465             pCommand->status = MCI_STATUS_ERROR;\r
466         }\r
467     }\r
468 \r
469     // Check if a transfer has been completed\r
470     if (((status & AT91C_MCI_CMDRDY) != 0)\r
471         || ((status & AT91C_MCI_ENDRX) != 0)\r
472         || ((status & AT91C_MCI_RXBUFF) != 0)\r
473         || ((status & AT91C_MCI_ENDTX) != 0)\r
474         || ((status & AT91C_MCI_BLKE) != 0)\r
475         || ((status & AT91C_MCI_RTOE) != 0)) {\r
476 \r
477         if (((status & AT91C_MCI_ENDRX) != 0)\r
478             || ((status & AT91C_MCI_RXBUFF) != 0)\r
479             || ((status & AT91C_MCI_ENDTX) != 0)) {\r
480 \r
481             MCI_Enable(pMci, DISABLE);\r
482         }\r
483 \r
484         /// On AT91RM9200-EK, if stop transmission, software reset MCI.\r
485         #if defined(at91rm9200)\r
486         if ((pCommand->cmd & AT91C_MCI_TRCMD_STOP) != 0) {\r
487             mciMr = READ_MCI(pMciHw, MCI_MR);\r
488             mciSdcr = READ_MCI(pMciHw, MCI_SDCR);\r
489             mciDtor = READ_MCI(pMciHw, MCI_DTOR);\r
490             WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_SWRST);\r
491             // trace_LOG(trace_DEBUG, "reset MCI\n\r");\r
492 \r
493             WRITE_MCI(pMciHw, MCI_CR, AT91C_MCI_MCIDIS | AT91C_MCI_PWSDIS);\r
494             WRITE_MCI(pMciHw, MCI_MR, mciMr);\r
495             WRITE_MCI(pMciHw, MCI_SDCR, mciSdcr);\r
496             WRITE_MCI(pMciHw, MCI_DTOR, mciDtor);\r
497         }\r
498         #endif\r
499 \r
500         // If no error occured, the transfer is successful\r
501         if (pCommand->status == MCI_STATUS_PENDING) {\r
502             pCommand->status = 0;\r
503         }\r
504 #if 0\r
505         if ((status & AT91C_MCI_CMDRDY) != 0)\r
506             trace_LOG(trace_DEBUG, ".");\r
507         if ((status & AT91C_MCI_ENDRX) != 0)\r
508             trace_LOG(trace_DEBUG, "<");\r
509         if ((status & AT91C_MCI_ENDTX) != 0)\r
510             trace_LOG(trace_DEBUG, "-");\r
511         if ((status & AT91C_MCI_BLKE) != 0)\r
512             trace_LOG(trace_DEBUG, ">");\r
513         trace_LOG(trace_DEBUG, "\n\r");\r
514 #endif        \r
515         // Store the card response in the provided buffer\r
516         if (pCommand->pResp) {\r
517 \r
518             for (i=0; i < pCommand->resSize; i++) {\r
519 \r
520                 pCommand->pResp[i] = READ_MCI(pMciHw, MCI_RSPR[0]);\r
521             }\r
522         }\r
523 \r
524         // Disable interrupts\r
525         WRITE_MCI(pMciHw, MCI_IDR, READ_MCI(pMciHw, MCI_IMR));\r
526 \r
527         // Release the semaphore\r
528         pMci->semaphore++;\r
529 \r
530         // Invoke the callback associated with the current command (if any)\r
531         if (pCommand->callback) {\r
532             (pCommand->callback)(pCommand->status, pCommand);\r
533         }\r
534     }\r
535 }\r
536 \r
537 //------------------------------------------------------------------------------\r
538 /// Returns 1 if the given MCI transfer is complete; otherwise returns 0.\r
539 /// \param pCommand  Pointer to a MciCmd instance.\r
540 //------------------------------------------------------------------------------\r
541 unsigned char MCI_IsTxComplete(MciCmd *pCommand)\r
542 {\r
543     if (pCommand->status != MCI_STATUS_PENDING) {\r
544         if (pCommand->status != 0)\r
545             printf("MCI_IsTxComplete %d\n\r", pCommand->status);\r
546         return 1;\r
547     }\r
548     else {\r
549         return 0;\r
550     }\r
551 }\r