SAMV71 Xplained Ultra Software Package 1.3

hsmci.c

Go to the documentation of this file.
00001 /* ----------------------------------------------------------------------------
00002  *         SAM Software Package License 
00003  * ----------------------------------------------------------------------------
00004  * Copyright (c) 2011, Atmel Corporation
00005  *
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright notice,
00012  * this list of conditions and the disclaimer below.
00013  *
00014  * Atmel's name may not be used to endorse or promote products derived from
00015  * this software without specific prior written permission.
00016  *
00017  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
00020  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00025  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00026  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  * ----------------------------------------------------------------------------
00028  */
00029 
00030 /** \file
00031  *
00032  * Implementation of High Speed MultiMedia Card Interface (HSMCI) controller.
00033  */
00034 
00035 /*---------------------------------------------------------------------------
00036  *         Headers
00037  *---------------------------------------------------------------------------*/
00038 
00039 #include "chip.h"
00040 #include <assert.h>
00041 
00042 /*---------------------------------------------------------------------------
00043  *         Exported functions
00044  *---------------------------------------------------------------------------*/
00045 
00046 /** \addtogroup hsmci_functions
00047  *@{
00048  */
00049 
00050 /**
00051  * \brief Enable Multi-Media Interface
00052  *
00053  * \param pRMci Pointer to a Hsmci instance
00054  */
00055 extern void HSMCI_Enable(Hsmci* pRMci)
00056 {
00057     pRMci->HSMCI_CR = HSMCI_CR_MCIEN;
00058 }
00059 
00060 /**
00061  * \brief Disable Multi-Media Interface
00062  *
00063  * \param pRMci Pointer to a Hsmci instance
00064  */
00065 extern void HSMCI_Disable(Hsmci* pRMci)
00066 {
00067     pRMci->HSMCI_CR = HSMCI_CR_MCIDIS;
00068 
00069 }
00070 
00071 /**
00072  * \brief Reset (& Disable) Multi-Media Interface
00073  *
00074  * \param mci Pointer to a Hsmci instance
00075  * \param bBackup Backup registers values to keep previous settings, including
00076  *                _MR, _SDCR, _DTOR, _CSTOR, _DMA and _CFG.
00077  */
00078 extern void HSMCI_Reset(Hsmci* pRMci, uint8_t bBackup)
00079 {
00080     if (bBackup) {
00081         uint32_t mr    = pRMci->HSMCI_MR;
00082         uint32_t dtor  = pRMci->HSMCI_DTOR;
00083         uint32_t sdcr  = pRMci->HSMCI_SDCR;
00084         uint32_t cstor = pRMci->HSMCI_CSTOR;
00085         uint32_t dma   = pRMci->HSMCI_DMA;
00086         uint32_t cfg   = pRMci->HSMCI_CFG;
00087 
00088         pRMci->HSMCI_CR = HSMCI_CR_SWRST;
00089 
00090         pRMci->HSMCI_MR    = mr;
00091         pRMci->HSMCI_DTOR  = dtor;
00092         pRMci->HSMCI_SDCR  = sdcr;
00093         pRMci->HSMCI_CSTOR = cstor;
00094         pRMci->HSMCI_DMA   = dma;
00095         pRMci->HSMCI_CFG   = cfg;
00096     } else {
00097         pRMci->HSMCI_CR = HSMCI_CR_SWRST;
00098     }
00099 }
00100 
00101 /**
00102  * \brief Select slot
00103  * \param pRMci Pointer to a Hsmci instance
00104  * \param bSlot Slot ID (0~3 for A~D).
00105  */
00106 extern void HSMCI_Select(Hsmci *pRMci, uint8_t bSlot, uint8_t bBusWidth)
00107 {
00108     uint32_t dwSdcr;
00109     dwSdcr = (HSMCI_SDCR_SDCSEL_Msk & bSlot);
00110     switch(bBusWidth) {
00111     case 1:
00112         pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_1;
00113         break;
00114     case 4:
00115         pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_4;
00116         break;
00117     case 8:
00118         pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_8;
00119         break;
00120     }
00121 }
00122 
00123 /**
00124  * \brief Set slot
00125  * \param pRMci Pointer to a Hsmci instance
00126  * \param bSlot Slot ID (0~3 for A~D).
00127  */
00128 extern void HSMCI_SetSlot(Hsmci *pRMci, uint8_t bSlot)
00129 {
00130     uint32_t dwSdcr = pRMci->HSMCI_SDCR & ~HSMCI_SDCR_SDCSEL_Msk;
00131     pRMci->HSMCI_SDCR = dwSdcr | (HSMCI_SDCR_SDCSEL_Msk & bSlot);
00132 }
00133 
00134 /**
00135  * \brief Set bus width of MCI
00136  * \param pRMci Pointer to a Hsmci instance
00137  * \param bBusWidth 1,4 or 8 (bits).
00138  */
00139 extern void HSMCI_SetBusWidth(Hsmci * pRMci,uint8_t bBusWidth)
00140 {
00141     uint32_t dwSdcr = pRMci->HSMCI_SDCR & ~HSMCI_SDCR_SDCBUS_Msk;
00142     switch(bBusWidth) {
00143     case 1:
00144         pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_1;
00145         break;
00146     case 4:
00147         pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_4;
00148         break;
00149     case 8:
00150         pRMci->HSMCI_SDCR = dwSdcr | HSMCI_SDCR_SDCBUS_8;
00151         break;
00152     }
00153 }
00154 
00155 /**
00156  * \brief Return bus width setting.
00157  *
00158  * \param pRMci  Pointer to an MCI instance.
00159  * \return 1, 4 or 8.
00160  */
00161 extern uint8_t HSMCI_GetBusWidth(Hsmci * pRMci)
00162 {
00163     switch(pRMci->HSMCI_SDCR & HSMCI_SDCR_SDCBUS_Msk) {
00164     case HSMCI_SDCR_SDCBUS_1: return 1;
00165     case HSMCI_SDCR_SDCBUS_4: return 4;
00166     case HSMCI_SDCR_SDCBUS_8: return 8;
00167     }
00168     return 0;
00169 }
00170 
00171 /**
00172  * \brief Configures a MCI peripheral as specified.
00173  *
00174  * \param pRMci  Pointer to an MCI instance.
00175  * \param dwMode Value of the MCI Mode register.
00176  */
00177 extern void HSMCI_ConfigureMode(Hsmci *pRMci, uint32_t dwMode)
00178 {
00179     pRMci->HSMCI_MR = dwMode;
00180 
00181 }
00182 
00183 /**
00184  * \brief Return mode register
00185  * \param pRMci  Pointer to an MCI instance.
00186  */
00187 extern uint32_t HSMCI_GetMode(Hsmci * pRMci)
00188 {
00189     return pRMci->HSMCI_MR;
00190 }
00191 
00192 /**
00193  * \brief Enable/Disable R/W proof
00194  *
00195  * \param pRMci    Pointer to an MCI instance.
00196  * \param bRdProof Read proof enable/disable.
00197  * \param bWrProof Write proof enable/disable.
00198  */
00199 extern void HSMCI_ProofEnable(Hsmci *pRMci, uint8_t bRdProof, uint8_t bWrProof)
00200 {
00201     uint32_t mr = pRMci->HSMCI_MR;
00202     pRMci->HSMCI_MR = (mr & (~(HSMCI_MR_WRPROOF | HSMCI_MR_RDPROOF)))
00203         | (bRdProof ? HSMCI_MR_RDPROOF : 0)
00204         | (bWrProof ? HSMCI_MR_WRPROOF : 0)
00205         ;
00206 }
00207 
00208 /**
00209  * \brief Padding value setting.
00210  *
00211  * \param pRMci    Pointer to an MCI instance.
00212  * \param bPadvEn  Padding value 0xFF/0x00.
00213  */
00214 extern void HSMCI_PadvCtl(Hsmci *pRMci, uint8_t bPadv)
00215 {
00216     if (bPadv) {
00217         pRMci->HSMCI_MR |= HSMCI_MR_PADV;
00218     } else {
00219         pRMci->HSMCI_MR &= ~HSMCI_MR_PADV;
00220     }
00221 }
00222 
00223 /**
00224  * \brief Force byte transfer enable/disable.
00225  *
00226  * \param pRMci    Pointer to an MCI instance.
00227  * \param bFByteEn FBYTE enable/disable.
00228  */
00229 extern void HSMCI_FByteEnable(Hsmci *pRMci, uint8_t bFByteEn)
00230 {
00231     if (bFByteEn) {
00232         pRMci->HSMCI_MR |= HSMCI_MR_FBYTE;
00233     } else {
00234         pRMci->HSMCI_MR &= ~HSMCI_MR_FBYTE;
00235     }
00236 }
00237 
00238 /**
00239  * \brief Check if Force Byte mode enabled.
00240  *
00241  * \param pRMci    Pointer to an MCI instance.
00242  * \return 1 if _FBYTE is enabled.
00243  */
00244 extern uint8_t HSMCI_IsFByteEnabled(Hsmci *pRMci)
00245 {
00246     return ((pRMci->HSMCI_MR & HSMCI_MR_FBYTE) > 0);
00247 }
00248 
00249 /**
00250  * \brief Set Clock Divider & Power save divider for MCI.
00251  *
00252  * \param pRMci    Pointer to an MCI instance.
00253  * \param bClkDiv  Clock Divider value (0 ~ 255).
00254  * \param bPwsDiv  Power Saving Divider (1 ~ 7).
00255  */
00256 extern void HSMCI_DivCtrl(Hsmci *pRMci, uint32_t bClkDiv, uint8_t bPwsDiv)
00257 {
00258     uint32_t mr = pRMci->HSMCI_MR;
00259     uint32_t clkdiv ,clkodd;
00260     clkdiv = bClkDiv - 2 ;
00261     clkodd = (bClkDiv & 1)? HSMCI_MR_CLKODD: 0;
00262     clkdiv = clkdiv >> 1;
00263 
00264     pRMci->HSMCI_MR = (mr & ~(HSMCI_MR_CLKDIV_Msk | HSMCI_MR_PWSDIV_Msk))
00265         | HSMCI_MR_CLKDIV(clkdiv)
00266         | HSMCI_MR_PWSDIV(bPwsDiv)
00267         | clkodd
00268         ;
00269 }
00270 
00271 /**
00272  * \brief Enables one or more interrupt sources of MCI peripheral.
00273  *
00274  * \param pRMci   Pointer to an Hsmci instance.
00275  * \param sources Bitwise OR of selected interrupt sources.
00276  */
00277 extern void HSMCI_EnableIt(Hsmci *pRMci, uint32_t dwSources)
00278 {
00279     pRMci->HSMCI_IER = dwSources;
00280 }
00281 
00282 /**
00283  * \brief Disable one or more interrupt sources of MCI peripheral.
00284  *
00285  * \param pRMci   Pointer to an Hsmci instance.
00286  * \param sources Bitwise OR of selected interrupt sources.
00287  */
00288 extern void HSMCI_DisableIt(Hsmci *pRMci, uint32_t dwSources)
00289 {
00290     pRMci->HSMCI_IDR = dwSources;
00291 }
00292 
00293 /**
00294  * \brief Return the interrupt mask register.
00295  *
00296  * \param pRMci   Pointer to an Hsmci instance.
00297  * \return MCI interrupt mask register.
00298  */
00299 extern uint32_t HSMCI_GetItMask(Hsmci *pRMci)
00300 {
00301     return (pRMci->HSMCI_IMR) ;
00302 }
00303 
00304 /**
00305  * \brief Set block len & count for transfer
00306  * 
00307  * \param pRMci     Pointer to an Hsmci instance.
00308  * \param wBlkLen   Block size.
00309  * \param wCnt      Block(byte) count.
00310  */
00311 extern void HSMCI_ConfigureTransfer(Hsmci *pRMci,
00312         uint16_t wBlkLen,
00313         uint16_t wCnt)
00314 {
00315     pRMci->HSMCI_BLKR = (wBlkLen << 16) | wCnt;
00316 }
00317 
00318 /**
00319  * \brief Set block length
00320  *
00321  *  Count is reset to 0.
00322  *
00323  * \param pRMci     Pointer to an Hsmci instance.
00324  * \param wBlkSize  Block size.
00325  */
00326 extern void HSMCI_SetBlockLen(Hsmci *pRMci, uint16_t wBlkSize)
00327 {
00328     pRMci->HSMCI_BLKR = wBlkSize << 16;
00329 }
00330 
00331 /**
00332  * \brief Set block (byte) count
00333  *
00334  * \param pRMci     Pointer to an Hsmci instance.
00335  * \param wBlkCnt   Block(byte) count.
00336  */
00337 extern void HSMCI_SetBlockCount(Hsmci *pRMci, uint16_t wBlkCnt)
00338 {
00339     pRMci->HSMCI_BLKR |= wBlkCnt;
00340 }
00341 
00342 /**
00343  * \brief Configure the Completion Signal Timeout
00344  *
00345  * \param pRMci Pointer to an Hsmci instance.
00346  * \param dwConfigure Completion Signal Timeout configure.
00347  */
00348 extern void HSMCI_ConfigureCompletionTO(Hsmci *pRMci, uint32_t dwConfigure)
00349 {
00350     pRMci->HSMCI_CSTOR = dwConfigure;
00351 }
00352 
00353 /**
00354  * \brief Configure the Data Timeout
00355  *
00356  * \param pRMci Pointer to an Hsmci instance.
00357  * \param dwConfigure Data Timeout configure.
00358  */
00359 extern void HSMCI_ConfigureDataTO(Hsmci *pRMci, uint32_t dwConfigure)
00360 {
00361     pRMci->HSMCI_DTOR = dwConfigure;
00362 }
00363 
00364 /**
00365  * \brief Send command
00366  *
00367  * \param pRMci Pointer to an Hsmci instance.
00368  * \param dwCmd Command register value.
00369  * \param dwArg Argument register value.
00370  */
00371 extern void HSMCI_SendCmd(Hsmci *pRMci, uint32_t dwCmd, uint32_t dwArg)
00372 {
00373     pRMci->HSMCI_ARGR = dwArg;
00374     pRMci->HSMCI_CMDR = dwCmd;
00375 }
00376 
00377 
00378 /**
00379  * \brief Return the response register.
00380  *
00381  * \param pRMci   Pointer to an Hsmci instance.
00382  * \return MCI response register.
00383  */
00384 extern uint32_t HSMCI_GetResponse(Hsmci *pRMci)
00385 {
00386     return pRMci->HSMCI_RSPR[0];
00387 }
00388 
00389 /**
00390  * \brief Return the receive data register.
00391  *
00392  * \param pRMci   Pointer to an Hsmci instance.
00393  * \return MCI receive data register.
00394  */
00395 extern uint32_t HSMCI_Read(Hsmci *pRMci)
00396 {
00397     return pRMci->HSMCI_RDR;
00398 }
00399 
00400 /**
00401  * \brief Read from FIFO
00402  *
00403  * \param pRMci   Pointer to an Hsmci instance.
00404  * \param pdwData Pointer to data buffer.
00405  * \param dwSize  Size of data buffer (in DWord).
00406  */
00407 extern void HSMCI_ReadFifo(Hsmci *pRMci, uint8_t *pdwData, uint32_t dwSize)
00408 {
00409     volatile uint32_t *pFIFO = (volatile uint32_t*)(pRMci->HSMCI_FIFO);
00410     register uint32_t c4, c1;
00411 
00412     if (dwSize == 0)
00413         return;
00414 
00415     c4 = dwSize >> 2;
00416     c1 = dwSize & 0x3;
00417 
00418     for(;c4;c4 --) {
00419         *pdwData ++ = *pFIFO ++;
00420         *pdwData ++ = *pFIFO ++;
00421         *pdwData ++ = *pFIFO ++;
00422         *pdwData ++ = *pFIFO ++;
00423     }
00424     for(;c1;c1 --) {
00425         *pdwData ++ = *pFIFO ++;
00426     }
00427 }
00428 
00429 /**
00430  * \brief Sends data through MCI peripheral.
00431  *
00432  * \param pRMci   Pointer to an Hsmci instance.
00433  * \param
00434  */
00435 extern void HSMCI_Write(Hsmci *pRMci, uint32_t dwData)
00436 {
00437     pRMci->HSMCI_TDR = dwData;
00438 }
00439 
00440 /**
00441  * \brief Write to FIFO
00442  *
00443  * \param pRMci   Pointer to an Hsmci instance.
00444  * \param pdwData Pointer to data buffer.
00445  * \param dwSize  Size of data buffer (In DWord).
00446  */
00447 extern void HSMCI_WriteFifo(Hsmci *pRMci, uint8_t *pdwData, uint32_t dwSize)
00448 {
00449     volatile uint32_t *pFIFO = (volatile uint32_t*)(pRMci->HSMCI_FIFO);
00450     register uint32_t c4, c1;
00451 
00452     if (dwSize == 0)
00453         return;
00454 
00455     c4 = dwSize >> 2;
00456     c1 = dwSize & 0x3;
00457 
00458     for(;c4;c4 --) {
00459         *pFIFO ++ = *pdwData ++;
00460         *pFIFO ++ = *pdwData ++;
00461         *pFIFO ++ = *pdwData ++;
00462         *pFIFO ++ = *pdwData ++;
00463     }
00464     for(;c1;c1 --) {
00465         *pFIFO ++ = *pdwData ++;
00466     }
00467 }
00468 
00469 /**
00470  * \brief Return the status register.
00471  *
00472  * \param pRMci   Pointer to an Hsmci instance.
00473  * \return MCI status register.
00474  */
00475 extern uint32_t HSMCI_GetStatus(Hsmci *pRMci)
00476 {
00477     return pRMci->HSMCI_SR;
00478 }
00479 
00480 /**
00481  * \brief Configure the HSMCI DMA
00482  *  
00483  * \param pRMci Pointer to an Hsmci instance.
00484  * \param dwConfigure Configure value. 
00485  */
00486 extern void HSMCI_ConfigureDma(Hsmci *pRMci, uint32_t dwConfigure)
00487 {
00488     pRMci->HSMCI_DMA = dwConfigure;
00489 }
00490 
00491 /**
00492  * \brief Enable the HSMCI DMA
00493  *  
00494  * \param pRMci Pointer to an Hsmci instance.
00495  * \param bEnable 1 to enable, 0 to disable.
00496  */
00497 extern void HSMCI_EnableDma(Hsmci *pRMci, uint8_t bEnable)
00498 {
00499     if (bEnable) {
00500         pRMci->HSMCI_DMA |= HSMCI_DMA_DMAEN ;//| HSMCI_DMA_CHKSIZE_32;
00501     } else {
00502         pRMci->HSMCI_DMA &= ~HSMCI_DMA_DMAEN;
00503     }
00504 }
00505 
00506 /**
00507  * \brief Configure the HSMCI
00508  *  
00509  * \param pRMci   Pointer to an Hsmci instance.
00510  * \param dwConfigure Configure value. 
00511  */
00512 extern void HSMCI_Configure(Hsmci *pRMci, uint32_t dwConfigure)
00513 {
00514     pRMci->HSMCI_CFG = dwConfigure;
00515 }
00516 
00517 /**
00518  * \brief Enable/Disable High-Speed mode for MCI
00519  * 
00520  * \param pRMci Pointer to an Hsmci instance.
00521  * \param bHsEnable Enable/Disable high-speed.
00522  */
00523 extern void HSMCI_HsEnable(Hsmci *pRMci, uint8_t bHsEnable)
00524 {
00525     if (bHsEnable) {
00526         pRMci->HSMCI_CFG |= HSMCI_CFG_HSMODE;
00527     } else {
00528         pRMci->HSMCI_CFG &= ~HSMCI_CFG_HSMODE;
00529     }
00530 }
00531 
00532 /**
00533  * \brief Check if High-speed mode is enabled on MCI
00534  * \param pRMci Pointer to an Hsmci instance.
00535  * \return 1 
00536  */
00537 extern uint8_t HSMCI_IsHsEnabled(Hsmci * pRMci)
00538 {
00539     return ((pRMci->HSMCI_CFG & HSMCI_CFG_HSMODE) > 0);
00540 }
00541 
00542 /**
00543  * \brief Configure the Write Protection Mode
00544  *  
00545  * \param pRMci   Pointer to an Hsmci instance.
00546  * \param dwConfigure WP mode configure value. 
00547  */
00548 extern void HSMCI_ConfigureWP(Hsmci *pRMci, uint32_t dwConfigure)
00549 {
00550     pRMci->HSMCI_WPMR = dwConfigure;
00551 }
00552 
00553 /**
00554  * \brief Return the write protect status register.
00555  *
00556  * \param pRMci   Pointer to an Hsmci instance.
00557  * \return MCI write protect status register.
00558  */
00559 extern uint32_t HSMCI_GetWPStatus(Hsmci *pRMci)
00560 {
00561     return pRMci->HSMCI_WPSR;
00562 }
00563 
00564 /**@}*/
00565 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines