diff options
Diffstat (limited to 'KSDK_1.2.0/platform/composite/src')
-rwxr-xr-x | KSDK_1.2.0/platform/composite/src/sdcard/fsl_sdcard_spi.c | 1074 | ||||
-rwxr-xr-x | KSDK_1.2.0/platform/composite/src/sdcard/fsl_sdhc_card.c | 1576 | ||||
-rwxr-xr-x | KSDK_1.2.0/platform/composite/src/soundcard/fsl_soundcard.c | 612 |
3 files changed, 3262 insertions, 0 deletions
diff --git a/KSDK_1.2.0/platform/composite/src/sdcard/fsl_sdcard_spi.c b/KSDK_1.2.0/platform/composite/src/sdcard/fsl_sdcard_spi.c new file mode 100755 index 0000000..d2caa9a --- /dev/null +++ b/KSDK_1.2.0/platform/composite/src/sdcard/fsl_sdcard_spi.c @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2014, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include "fsl_os_abstraction.h" + +#include "fsl_sdmmc_card.h" +#include "fsl_sdcard_spi.h" + +/* rate unit is divided by 1000 */ +static const uint32_t g_transpeedru[] = +{ + /* 100Kbps, 1Mbps, 10Mbps, 100Mbps*/ + 100, 1000, 10000, 100000, +}; + +/* time value multiplied by 1000 */ +static const uint32_t g_transpeedtv[] = +{ + 0, 1000, 1200, 1300, + 1500, 2000, 2500, 3000, + 3500, 4000, 4500, 5000, + 5500, 6000, 7000, 8000, +}; + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_GenerateCRC7 + * Description: calculate CRC7 + * + *END*********************************************************************/ +static uint32_t SDSPI_DRV_GenerateCRC7(uint8_t *buffer, + uint32_t length, + uint32_t crc) +{ + uint32_t index; + + static const uint8_t crcTable[] = { + 0x00, 0x09, 0x12, 0x1B, 0x24, 0x2D, 0x36, 0x3F, + 0x48, 0x41, 0x5A, 0x53, 0x6C, 0x65, 0x7E, 0x77 + }; + + while (length) + { + index = ((crc >> 3) & 0x0F) ^ ((*buffer) >> 4); + crc = (crc << 4) ^ crcTable[index]; + + index = ((crc >> 3) & 0x0F) ^ ((*buffer) & 0x0F); + crc = (crc << 4) ^ crcTable[index]; + + buffer++; + length--; + } + + return (crc & 0x7F); +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_WaitReady + * Description: wait ready + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_WaitReady(sdspi_spi_t *spi) +{ + uint8_t response; + uint32_t startTime, elapsedTime; + + startTime = OSA_TimeGetMsec(); + do + { + response = spi->ops->sendWord(spi, 0xFF); + elapsedTime = OSA_TimeGetMsec() - startTime; + } while ((response != 0xFF) && elapsedTime < 500); + + if (response != 0xFF) + { + return kStatus_SDSPI_CardIsBusyError; + } + + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_SendCommand + * Description: send command + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_SendCommand(sdspi_spi_t *spi, + sdspi_request_t *req, + uint32_t timeout) +{ + uint8_t buffer[6]; + uint8_t response; + uint8_t i; + sdspi_status_t result = kStatus_SDSPI_NoError; + + assert(spi); + assert(req); + + result = SDSPI_DRV_WaitReady(spi); + if ((result == kStatus_SDSPI_CardIsBusyError) + && (req->cmdIndex != kGoIdleState)) + { + return result; + } + + buffer[0] = SDSPI_MAKE_CMD(req->cmdIndex); + buffer[1] = req->argument >> 24 & 0xFF; + buffer[2] = req->argument >> 16 & 0xFF; + buffer[3] = req->argument >> 8 & 0xFF; + buffer[4] = req->argument & 0xFF; + buffer[5] = (SDSPI_DRV_GenerateCRC7(buffer, 5, 0) << 1) | 1; + + if (spi->ops->exchange(spi, buffer, NULL, sizeof(buffer))) + { + return kStatus_SDSPI_TransferFailed; + } + + if (req->cmdIndex == kStopTransmission) + { + spi->ops->sendWord(spi, 0xFF); + } + /* Wait for the response coming, the left most bit which is transfered first in response is 0 */ + for (i = 0; i < 9; i++) + { + response = spi->ops->sendWord(spi, 0xFF); + if (!(response & 0x80)) + { + break; + } + } + + if ((response & 0x80)) + { + return kStatus_SDSPI_Failed; + } + + req->response[0] = response; + switch(req->respType) + { + case kSdSpiRespTypeR1: + break; + case kSdSpiRespTypeR1b: + { + uint8_t busy = 0; + uint32_t startTime, elapsedTime; + startTime = OSA_TimeGetMsec(); + while (busy != 0xFF) + { + busy = spi->ops->sendWord(spi, 0xFF); + elapsedTime = OSA_TimeGetMsec() - startTime; + if (elapsedTime > timeout) + { + break; + } + } + if (busy != 0xFF) + { + result = kStatus_SDSPI_CardIsBusyError; + } + break; + } + case kSdSpiRespTypeR2: + req->response[1] = spi->ops->sendWord(spi, 0xFF); + break; + case kSdSpiRespTypeR3: + case kSdSpiRespTypeR7: + default: + for (i = 1; i <= 4; i++)/* R7 has total 5 bytes in SPI mode. */ + { + req->response[i] = spi->ops->sendWord(spi, 0xFF); + } + break; + } + + + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_GoIdle + * Description: send CMD0 + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_GoIdle(sdspi_spi_t *spi, sdspi_card_t *card) +{ + uint32_t i, j; + sdspi_request_t *req; + assert(card); + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + + /* + * SD card will enter SPI mode if the CS is asserted (negative) during the + * reception of the reset command (CMD0) and the card is in IDLE state. + */ + for (i = 0; i < 2; i++) + { + for (j = 0; j < 10; j++) + { + spi->ops->sendWord(spi, 0xFF); + } + + req->cmdIndex = kGoIdleState; + req->respType = kSdSpiRespTypeR1; + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + + if (req->response[0] == SDMMC_SPI_R1_IN_IDLE_STATE) + { + break; + } + } + + if (req->response[0] != SDMMC_SPI_R1_IN_IDLE_STATE) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + + OSA_MemFree(req); + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_SendApplicationCmd + * Description: send application command to card + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_SendApplicationCmd(sdspi_spi_t *spi) +{ + sdspi_request_t *req; + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + + req->cmdIndex = kAppCmd; + req->respType = kSdSpiRespTypeR1; + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + + if (req->response[0] && !(req->response[0] & SDMMC_SPI_R1_IN_IDLE_STATE)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + + OSA_MemFree(req); + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_AppSendOpCond + * Description: Get the card to send its operating condition. + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_AppSendOpCond(sdspi_spi_t *spi, + sdspi_card_t *card, + uint32_t argument, + uint8_t *response) +{ + sdspi_request_t *req; + uint32_t startTime, elapsedTime = 0; + assert(card); + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + + req->cmdIndex = kSdAppSendOpCond; + req->argument = argument; + req->respType = kSdSpiRespTypeR1; + + startTime = OSA_TimeGetMsec(); + do + { + if (kStatus_SDSPI_NoError == SDSPI_DRV_SendApplicationCmd(spi)) + { + if (kStatus_SDSPI_NoError == SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + if (!req->response[0]) + { + break; + } + } + } + elapsedTime = OSA_TimeGetMsec() - startTime; + } while (elapsedTime < 1000); + + if (response) + { + memcpy(response, req->response, sizeof(req->response)); + } + OSA_MemFree(req); + + if (elapsedTime < 1000) + { + return kStatus_SDSPI_NoError; + } + return kStatus_SDSPI_TimeoutError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_SendIfCond + * Description: check card interface condition, which includes host supply + * voltage information and asks the card whether card supports voltage. + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_SendIfCond(sdspi_spi_t *spi, + sdspi_card_t *card, + uint8_t pattern, + uint8_t *response) +{ + sdspi_request_t *req; + + assert(card); + assert(response); + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + + req->cmdIndex = kSdSendIfCond; + req->argument = 0x100 | (pattern & 0xFF); + req->respType = kSdSpiRespTypeR7; + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + + memcpy(response, req->response, sizeof(req->response)); + + OSA_MemFree(req); + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_ReadOcr + * Description: Get OCR register from card + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_ReadOcr(sdspi_spi_t *spi, sdspi_card_t *card) +{ + uint32_t i; + sdspi_request_t *req; + assert(card); + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + req->cmdIndex = kReadOcr; + req->respType = kSdSpiRespTypeR3; + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + if (req->response[0]) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + + card->ocr = 0; + for (i = 4; i > 0; i--) + { + card->ocr |= (uint32_t) req->response[i] << ((4 - i) * 8); + } + + OSA_MemFree(req); + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_Write + * Description: write data to card + * + *END*********************************************************************/ +static uint32_t SDSPI_DRV_Write(sdspi_spi_t *spi, uint8_t *buffer, uint32_t size, uint8_t token) +{ + uint8_t response; + assert(spi); + assert(spi->ops); + assert(spi->ops->exchange); + + if (SDSPI_DRV_WaitReady(spi) != kStatus_SDSPI_NoError) + { + return 0; + } + + spi->ops->sendWord(spi, token); + + if (token == SDMMC_SPI_DT_STOP_TRANSFER) + { + return size; + } + + assert(size); + assert(buffer); + + if (spi->ops->exchange(spi, buffer, NULL, size)) + { + return 0; + } + + /* Send CRC */ + spi->ops->sendWord(spi, 0xFF); + spi->ops->sendWord(spi, 0xFF); + + response = spi->ops->sendWord(spi, 0xFF); + if ((response & SDMMC_SPI_DR_MASK) != SDMMC_SPI_DR_ACCEPTED) + { + return 0; + } + return size; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_Read + * Description: read data from card + * + *END*********************************************************************/ +static uint32_t SDSPI_DRV_Read(sdspi_spi_t *spi, uint8_t *buffer, uint32_t size) +{ + uint32_t startTime, elapsedTime; + uint8_t response; + assert(spi); + assert(spi->ops); + assert(spi->ops->exchange); + assert(buffer); + assert(size); + memset(buffer, 0xFF, size); + startTime = OSA_TimeGetMsec(); + do + { + response = spi->ops->sendWord(spi, 0xFF); + elapsedTime = OSA_TimeGetMsec() - startTime; + } while ((response == 0xFF) && elapsedTime < 100); + + if (response != SDMMC_SPI_DT_START_SINGLE_BLK) + { + return 0; + } + + if (spi->ops->exchange(spi, buffer, buffer, size)) + { + return 0; + } + + spi->ops->sendWord(spi, 0xFF); + spi->ops->sendWord(spi, 0xFF); + + return size; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_SendCsd + * Description: get CSD register from card + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_SendCsd(sdspi_spi_t *spi, sdspi_card_t *card) +{ + sdspi_request_t *req; + assert(card); + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + + req->cmdIndex = kSendCsd; + req->respType = kSdSpiRespTypeR1; + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + OSA_MemFree(req); + + if (sizeof(card->rawCsd) != + (SDSPI_DRV_Read(spi, card->rawCsd, sizeof(card->rawCsd)))) + { + return kStatus_SDSPI_Failed; + } + + /* No start single block token if found */ + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_SetBlockSize + * Description: set the block length in bytes for SDSC cards. For SDHC cards, + * it does not affect memory read or write commands, always 512 bytes fixed + * block length is used. + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_SetBlockSize(sdspi_spi_t *spi, uint32_t blockSize) +{ + sdspi_request_t *req = 0; + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + req->cmdIndex = kSetBlockLen; + req->argument = blockSize; + req->respType = kSdSpiRespTypeR1; + + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + req = NULL; + return kStatus_SDSPI_Failed; + } + + OSA_MemFree(req); + req = NULL; + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_CheckCapacity + * Description: check card capacity of the card + * + *END*********************************************************************/ +static void SDSPI_DRV_CheckCapacity(sdspi_card_t *card) +{ + uint32_t cSize, cSizeMult, readBlkLen; + + if (SDMMC_CSD_CSDSTRUCTURE_VERSION(card->rawCsd)) + { + /* SD CSD structure v2.xx */ + cSize = SDV20_CSD_CSIZE(card->rawCsd); + if (cSize >= 0xFFFF) + { + /* extended capacity */ + card->caps |= SDSPI_CAPS_SDXC; + } + else + { + card->caps |= SDSPI_CAPS_SDHC; + } + cSizeMult = 10; + cSize += 1; + readBlkLen = 9; + } + else + { + /* SD CSD structure v1.xx */ + cSize = SDMMC_CSD_CSIZE(card->rawCsd) + 1; + cSizeMult = SDMMC_CSD_CSIZEMULT(card->rawCsd) + 2; + readBlkLen = SDMMC_CSD_READBLK_LEN(card->rawCsd); + } + + if (readBlkLen != 9) + { + /* Force to use 512-byte length block */ + cSizeMult += (readBlkLen - 9); + readBlkLen = 9; + } + + card->blockSize = 1 << readBlkLen; + card->blockCount = cSize << cSizeMult; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_SendCid + * Description: get CID information from card + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_SendCid(sdspi_spi_t *spi, sdspi_card_t *card) +{ + sdspi_request_t *req = 0; + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + req->cmdIndex = kSendCid; + req->respType = kSdSpiRespTypeR1; + + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + req = NULL; + return kStatus_SDSPI_Failed; + } + + OSA_MemFree(req); + req = NULL; + + if (sizeof(card->rawCid) != + (SDSPI_DRV_Read(spi, card->rawCid, sizeof(card->rawCid)))) + { + return kStatus_SDSPI_Failed; + } + + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_InitSd + * Description: initialize SD card + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_InitSd(sdspi_spi_t *spi, sdspi_card_t *card) +{ + uint32_t maxFrequency; + assert(spi); + assert(spi->ops); + assert(spi->ops->getMaxFrequency); + assert(spi->ops->setFrequency); + assert(card); + + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCsd(spi, card)) + { + return kStatus_SDSPI_Failed; + } + + /* Calculate frequency */ + maxFrequency = g_transpeedtv[SDMMC_CSD_TRANSPEED_TV(card->rawCsd)] * + g_transpeedru[SDMMC_CSD_TRANSPEED_RU(card->rawCsd)]; + if (maxFrequency > spi->busBaudRate) + { + maxFrequency = spi->ops->getMaxFrequency(spi); + } + spi->ops->setFrequency(spi, maxFrequency); + + SDSPI_DRV_CheckCapacity(card); + SDSPI_DRV_CheckReadOnly(spi, card); + + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCid(spi, card)) + { + return kStatus_SDSPI_Failed; + } + + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_Init + * Description: initialize card on the given host controller + * + *END*********************************************************************/ +sdspi_status_t SDSPI_DRV_Init(sdspi_spi_t *spi, sdspi_card_t *card) +{ + uint32_t startTime, elapsedTime, acmd41Arg; + uint8_t response[5], acmd41resp[5]; + bool likelyMmc = false, likelySdV1 = false; + assert(card); + assert(spi); + assert(spi->ops); + assert(spi->ops->exchange); + assert(spi->ops->setFrequency); + assert(spi->ops->sendWord); + + card->cardType = kCardTypeUnknown; + if (spi->ops->setFrequency(spi, SDMMC_CLK_400KHZ)) + { + return kStatus_SDSPI_Failed; + } + + if (kStatus_SDSPI_NoError != SDSPI_DRV_GoIdle(spi, card)) + { + return kStatus_SDSPI_Failed; + } + + acmd41Arg = 0; + if (kStatus_SDSPI_NoError != + SDSPI_DRV_SendIfCond(spi, card, 0xAA, response)) + { + likelySdV1 = true; + } + else if ((response[3] == 0x1) || (response[4] == 0xAA)) + { + acmd41Arg |= SD_OCR_HCS; + } + else + { + return kStatus_SDSPI_Failed; + } + + startTime = OSA_TimeGetMsec(); + do + { + if (kStatus_SDSPI_NoError != + SDSPI_DRV_AppSendOpCond(spi, card, acmd41Arg, acmd41resp)) + { + if (likelySdV1) + { + likelyMmc = true; + break; + } + return kStatus_SDSPI_Failed; + } + elapsedTime = OSA_TimeGetMsec() - startTime; + if (!acmd41resp[0]) + { + break; + } + if (elapsedTime > 500) + { + if (likelySdV1) + { + likelyMmc = true; + break; + } + } + } while(acmd41resp[0] == SDMMC_SPI_R1_IN_IDLE_STATE); + + if (likelyMmc) + { + card->cardType = kCardTypeMmc; + return kStatus_SDSPI_NotSupportYet; + } + else + { + card->cardType = kCardTypeSd; + } + + if (!likelySdV1) + { + card->version = kSdCardVersion_2_x; + if (kStatus_SDSPI_NoError != SDSPI_DRV_ReadOcr(spi, card)) + { + return kStatus_SDSPI_Failed; + } + if (card->ocr & SD_OCR_CCS) + { + card->caps = SDSPI_CAPS_ACCESS_IN_BLOCK; + } + } + else + { + card->version = kSdCardVersion_1_x; + } + + /* Force to use 512-byte length block, no matter which version */ + if (kStatus_SDSPI_NoError != SDSPI_DRV_SetBlockSize(spi, 512)) + { + return kStatus_SDSPI_Failed; + } + + if (kStatus_SDSPI_NoError != SDSPI_DRV_InitSd(spi, card)) + { + return kStatus_SDSPI_Failed; + } + + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_StopTransmission + * Description: Send stop transmission command to card to stop ongoing + * data transferring. + * + *END*********************************************************************/ +static sdspi_status_t SDSPI_DRV_StopTransmission(sdspi_spi_t *spi) +{ + sdspi_request_t *req = 0; + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + + req->cmdIndex = kStopTransmission; + req->respType = kSdSpiRespTypeR1b; + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + + OSA_MemFree(req); + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_ReadBlocks + * Description: read blocks from card + * + *END*********************************************************************/ +sdspi_status_t SDSPI_DRV_ReadBlocks(sdspi_spi_t *spi, sdspi_card_t *card, uint8_t *buffer, + uint32_t startBlock, uint32_t blockCount) +{ + uint32_t offset, i; + sdspi_request_t *req; + assert(spi); + assert(card); + assert(buffer); + assert(blockCount); + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + + offset = startBlock; + if (!IS_BLOCK_ACCESS(card)) + { + offset *= card->blockSize; + } + + req->argument = offset; + req->respType = kSdSpiRespTypeR1; + if (blockCount == 1) + { + req->cmdIndex = kReadSingleBlock; + + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + OSA_MemFree(req); + + if (SDSPI_DRV_Read(spi, buffer, card->blockSize) != card->blockSize) + { + return kStatus_SDSPI_Failed; + } + } + else + { + req->cmdIndex = kReadMultipleBlock; + + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + OSA_MemFree(req); + + for (i = 0; i < blockCount; i++) + { + if (SDSPI_DRV_Read(spi, buffer, card->blockSize) != card->blockSize) + { + return kStatus_SDSPI_Failed; + } + buffer += card->blockSize; + } + SDSPI_DRV_StopTransmission(spi); + } + + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_WriteBlocks + * Description: write blocks to card + * + *END*********************************************************************/ +sdspi_status_t SDSPI_DRV_WriteBlocks(sdspi_spi_t *spi, sdspi_card_t *card, uint8_t *buffer, + uint32_t startBlock, uint32_t blockCount) +{ + uint32_t offset, i, startTime, elapsedTime; + uint8_t response; + sdspi_request_t *req; + assert(spi); + assert(card); + assert(buffer); + assert(blockCount); + + if (card->state & SDSPI_STATE_WRITE_PROTECTED) + { + return kStatus_SDSPI_WriteProtected; + } + + req = (sdspi_request_t *)OSA_MemAllocZero(sizeof(sdspi_request_t)); + if (req == NULL) + { + return kStatus_SDSPI_OutOfMemory; + } + + offset = startBlock; + if (!IS_BLOCK_ACCESS(card)) + { + offset *= card->blockSize; + } + + if (blockCount == 1) + { + req->cmdIndex = kWriteBlock; + req->argument = offset; + req->respType = kSdSpiRespTypeR1; + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + if (req->response[0]) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + + OSA_MemFree(req); + if (SDSPI_DRV_Write(spi, buffer, card->blockSize, SDMMC_SPI_DT_START_SINGLE_BLK) != card->blockSize) + { + return kStatus_SDSPI_Failed; + } + } + else + { +#if defined FSL_SDSPI_ENABLE_PRE_ERASE_ON_WRITE + if (IS_SD_CARD(card)) + { + /* Pre-erase before writing data */ + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendApplicationCmd(spi)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + req->cmdIndex = kSdAppSetWrBlkEraseCount; + req->argument = blockCount; + req->respType = kSdSpiRespTypeR1; + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + if (req->response[0]) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + } +#endif + + memset(req, 0, sizeof(sdspi_request_t)); + req->cmdIndex = kWriteMultipleBlock; + req->argument = offset; + req->respType = kSdSpiRespTypeR1; + + if (kStatus_SDSPI_NoError != SDSPI_DRV_SendCommand(spi, req, SDSPI_TIMEOUT)) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + if (req->response[0]) + { + OSA_MemFree(req); + return kStatus_SDSPI_Failed; + } + OSA_MemFree(req); + + for (i = 0; i < blockCount; i++) + { + if (SDSPI_DRV_Write(spi, buffer, card->blockSize, SDMMC_SPI_DT_START_MULTI_BLK) != card->blockSize) + { + return kStatus_SDSPI_Failed; + } + buffer += card->blockSize; + } + + SDSPI_DRV_Write(spi, 0, 0, SDMMC_SPI_DT_STOP_TRANSFER); + + startTime = OSA_TimeGetMsec(); + do + { + response = spi->ops->sendWord(spi, 0xFF); + elapsedTime = OSA_TimeGetMsec() - startTime; + } while ((response != 0xFF) && (elapsedTime < 100)); + } + + return kStatus_SDSPI_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDSPI_DRV_CheckReadOnly + * Description: check if card is read only + * + *END*********************************************************************/ +bool SDSPI_DRV_CheckReadOnly(sdspi_spi_t* spi, sdspi_card_t *card) +{ + assert(card); + + card->state &= ~SDSPI_STATE_WRITE_PROTECTED; + if (card->cardType != kCardTypeSd) + { + return false; + } + + if (SD_CSD_PERM_WRITEPROTECT(card->rawCsd) + || SD_CSD_TEMP_WRITEPROTECT(card->rawCsd)) + { + card->state |= SDSPI_STATE_WRITE_PROTECTED; + return true; + } + + return false; +} + +void SDSPI_DRV_Shutdown(sdspi_spi_t *spi, sdspi_card_t *card) +{ + assert(spi); + assert(card); + + memset(card, 0, sizeof(sdspi_card_t)); + return; +} diff --git a/KSDK_1.2.0/platform/composite/src/sdcard/fsl_sdhc_card.c b/KSDK_1.2.0/platform/composite/src/sdcard/fsl_sdhc_card.c new file mode 100755 index 0000000..884c549 --- /dev/null +++ b/KSDK_1.2.0/platform/composite/src/sdcard/fsl_sdhc_card.c @@ -0,0 +1,1576 @@ +/* + * Copyright (c) 2015, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <assert.h> +#include <stdio.h> +#include <string.h> +#include "fsl_os_abstraction.h" +#include "fsl_sdhc_card.h" +#include "fsl_sdmmc_card.h" + +#if defined(FSL_SDHC_USING_BIG_ENDIAN) +#define swap_be32(x) (x) +#else +#define swap_be32(x) (__REV(x)) +#endif + +#define FSL_SDCARD_REQUEST_TIMEOUT 1000 + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_DelayMsec + * Description: blocking delay msecond + * + *END*********************************************************************/ +static void SDCARD_DRV_DelayMsec(uint32_t msec) +{ + uint32_t startTime, elapsedTime; + assert(msec); + + startTime = OSA_TimeGetMsec(); + do + { + elapsedTime = OSA_TimeGetMsec() - startTime; + } while(elapsedTime < msec); +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_DecodeCsd + * Description: decode csd register + * + *END*********************************************************************/ +static void SDCARD_DRV_DecodeCsd(uint32_t *rawCsd, sdhc_card_t *card) +{ + sdcard_csd_t *csd; + assert(rawCsd); + assert(card); + csd = &(card->csd); + csd->csdStructure = (uint8_t)((rawCsd[3] & 0xC0000000U) >> 30); + csd->taac = (uint8_t)((rawCsd[3] & 0xFF0000) >> 16); + csd->nsac = (uint8_t)((rawCsd[3] & 0xFF00) >> 8); + csd->tranSpeed = (uint8_t)(rawCsd[3] & 0xFF); + csd->ccc = (uint16_t)((rawCsd[2] & 0xFFF00000U) >> 20); + csd->readBlkLen = (uint8_t)((rawCsd[2] & 0xF0000) >> 16); + if (rawCsd[2] & 0x8000) + { + csd->flags |= SDCARD_CSD_READ_BL_PARTIAL; + } + if (rawCsd[2] & 0x4000) + { + csd->flags |= SDCARD_CSD_WRITE_BLK_MISALIGN; + } + if (rawCsd[2] & 0x2000) + { + csd->flags |= SDCARD_CSD_READ_BLK_MISALIGN; + } + if (rawCsd[2] & 0x1000) + { + csd->flags |= SDCARD_CSD_DSR_IMP; + } + if (csd->csdStructure == 0) + { + csd->cSize = (uint32_t)((rawCsd[2] & 0x3FF) << 2); + csd->cSize |= (uint32_t)((rawCsd[1] & 0xC0000000U) >> 30); + csd->vddRCurrMin = (uint8_t)((rawCsd[1] & 0x38000000) >> 27); + csd->vddRCurrMax = (uint8_t)((rawCsd[1] & 0x7000000) >> 24); + csd->vddWCurrMin = (uint8_t)((rawCsd[1] & 0xE00000) >> 20); + csd->vddWCurrMax = (uint8_t)((rawCsd[1] & 0x1C0000) >> 18); + csd->cSizeMult = (uint8_t)((rawCsd[1] & 0x38000) >> 15); + card->blockCount = (csd->cSize + 1) << (csd->cSizeMult + 2); + card->blockSize = CARD_BLOCK_LEN(csd->readBlkLen); + if (card->blockSize != FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE) + { + card->blockCount = card->blockCount * card->blockSize; + card->blockSize = FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE; + card->blockCount = card->blockCount / card->blockSize; + } + } + else if (csd->csdStructure == 1) + { + card->blockSize = FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE; + csd->cSize = (uint32_t)((rawCsd[2] & 0x3F) << 16); + csd->cSize |= (uint32_t)((rawCsd[1] & 0xFFFF0000U) >> 16); + if (csd->cSize >= 0xFFFF) + { + card->caps |= SDMMC_CARD_CAPS_SDXC; + } + card->blockCount = (csd->cSize + 1) * 1024; + } + + if ((uint8_t)((rawCsd[1] & 0x4000) >> 14)) + { + csd->flags |= SDCARD_CSD_ERASE_BLK_ENABLED; + } + + csd->sectorSize = (uint8_t)((rawCsd[1] & 0x3F80) >> 7); + csd->wpGrpSize = (uint8_t)(rawCsd[1] & 0x7F); + if ((uint8_t)(rawCsd[0] & 0x80000000U)) + { + csd->flags |= SDCARD_CSD_WP_GRP_ENABLED; + } + csd->r2wFactor = (uint8_t)((rawCsd[0] & 0x1C000000) >> 26); + csd->writeBlkLen = (uint8_t)((rawCsd[0] & 0x3C00000) >> 22); + if ((uint8_t)((rawCsd[0] & 0x200000) >> 21)) + { + csd->flags |= SDCARD_CSD_WRITE_BL_PARTIAL; + } + if ((uint8_t)((rawCsd[0] & 0x8000) >> 15)) + { + csd->flags |= SDCARD_CSD_FILE_FORMAT_GROUP; + } + if ((uint8_t)((rawCsd[0] & 0x4000) >> 14)) + { + csd->flags |= SDCARD_CSD_COPY; + } + if ((uint8_t)((rawCsd[0] & 0x2000) >> 13)) + { + csd->flags |= SDCARD_CSD_PERM_WRITE_PROTECT; + } + if ((uint8_t)((rawCsd[0] & 0x1000) >> 12)) + { + csd->flags |= SDCARD_CSD_TMP_WRITE_PROTECT; + } + csd->fileFormat = (uint8_t)((rawCsd[0] & 0xC00) >> 10); +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_DecodeCid + * Description: decode cid register + * + *END*********************************************************************/ +static void SDCARD_DRV_DecodeCid(uint32_t *rawCid, sdhc_card_t *card) +{ + sdcard_cid_t *cid; + assert(rawCid); + assert(card); + cid = &(card->cid); + + cid->mid = (uint8_t)((rawCid[3] & 0xFF000000) >> 24); + + cid->oid = (uint16_t)((rawCid[3] & 0xFFFF00) >> 8); + + cid->pnm[0] = (uint8_t)((rawCid[3] & 0xFF)); + cid->pnm[1] = (uint8_t)((rawCid[2] & 0xFF000000U) >> 24); + cid->pnm[2] = (uint8_t)((rawCid[2] & 0xFF0000) >> 16); + cid->pnm[3] = (uint8_t)((rawCid[2] & 0xFF00) >> 8); + cid->pnm[4] = (uint8_t)((rawCid[2] & 0xFF)); + + cid->prv = (uint8_t)((rawCid[1] & 0xFF000000U) >> 24); + + cid->psn = (uint32_t)((rawCid[1] & 0xFFFFFF) << 8); + cid->psn |= (uint32_t)((rawCid[0] & 0xFF000000U) >> 24); + + cid->mdt = (uint16_t)((rawCid[0] & 0xFFF00) >> 8); +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_SendApplicationCmd + * Description: send application command to card + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_SendApplicationCmd(sdhc_card_t *card) +{ + sdhc_request_t *req = 0; + sdhc_status_t ret = kStatus_SDHC_NoError; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->cmdIndex = kAppCmd; + req->argument = 0; + if (card->cardType != kCardTypeUnknown) + { + req->argument = card->rca << 16; + } + req->respType = kSdhcRespTypeR1; + + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { + if (req->error & FSL_SDHC_REQ_ERR_CMD_TIMEOUT) + { + ret = kStatus_SDHC_TimeoutError; + } + else + { + ret = kStatus_SDHC_RequestFailed; + } +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return ret; + } + + if (!(req->response[0] & SDMMC_R1_APP_CMD)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_CardNotSupport; + } +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; +} +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_AllSendCid + * Description: send all_send_cid command + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_AllSendCid(sdhc_card_t *card) +{ + sdhc_request_t *req = 0; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->cmdIndex = kAllSendCid; + req->argument = 0; + req->respType = kSdhcRespTypeR2; + if (kStatus_SDHC_NoError == + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { + memcpy(card->rawCid, req->response, sizeof(card->rawCid)); + SDCARD_DRV_DecodeCid(req->response, card); +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; + } +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_SendRca + * Description: send rca command to card to get relative card address + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_SendRca(sdhc_card_t *card) +{ + sdhc_request_t *req = 0; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->cmdIndex = kSdSendRelativeAddr; + req->argument = 0; + req->respType = kSdhcRespTypeR6; + if (kStatus_SDHC_NoError == + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { + card->rca = req->response[0] >> 16; +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; + } +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_SendCsd + * Description: get csd from card + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_SendCsd(sdhc_card_t *card) +{ + sdhc_request_t *req = 0; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->cmdIndex = kSendCsd; + req->argument = card->rca << 16; + req->respType = kSdhcRespTypeR2; + if (kStatus_SDHC_NoError == + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { + memcpy(card->rawCsd, req->response, sizeof(card->rawCsd)); + SDCARD_DRV_DecodeCsd(req->response, card); +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; + } +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_SelectCard + * Description: select or deselect card + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_SelectCard(sdhc_card_t *card, bool isSelected) +{ + sdhc_request_t *req = 0; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->cmdIndex = kSelectCard; + if (isSelected) + { + req->argument = card->rca << 16; + req->respType = kSdhcRespTypeR1; + } + else + { + req->argument = 0; + req->respType = kSdhcRespTypeNone; + } + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_SetBlockSize + * Description: Set the block length in bytes for SDSC cards. For SDHC cards, + * it does not affect memory read or write commands, always 512 bytes fixed + * block length is used. + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_SetBlockSize(sdhc_card_t *card, uint32_t blockSize) +{ + sdhc_request_t *req = 0; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->cmdIndex = kSetBlockLen; + req->argument = blockSize; + req->respType = kSdhcRespTypeR1; + + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_Switch + * Description: send switch command to card + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_Switch(sdhc_card_t *card, + uint32_t mode, + uint32_t group, + uint32_t value, + uint32_t *resp) +{ + sdhc_request_t *req = 0; + sdhc_data_t data = {0}; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->data = &data; + + req->cmdIndex = kSdSwitch; + req->argument = mode << 31 | 0x00FFFFFF; + req->argument &= ~((uint32_t)(0xF) << (group * 4)); + req->argument |= value << (group * 4); + req->flags = FSL_SDHC_REQ_FLAGS_DATA_READ; + req->respType = kSdhcRespTypeR1; + + + data.blockSize = 64; + data.blockCount = 1; + data.buffer = resp; + data.req = req; + + if (kStatus_SDHC_NoError != SDCARD_DRV_SetBlockSize(card, data.blockSize)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_SetCardBlockSizeFailed; + } + + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_DecodeScr + * Description: decode scr register + * + *END*********************************************************************/ +static void SDCARD_DRV_DecodeScr(uint32_t *rawScr, sdhc_card_t *card) +{ + sdcard_scr_t *scr; + assert(rawScr); + assert(card); + + scr = &(card->scr); + scr->scrStructure = (uint8_t)((rawScr[0] & 0xF0000000U) >> 28); + scr->sdSpec = (uint8_t)((rawScr[0] & 0xF000000) >> 24); + if ((uint8_t)((rawScr[0] & 0x800000) >> 23)) + { + scr->flags |= SDCARD_SCR_DATA_STAT_AFTER_ERASE; + } + scr->sdSecurity = (uint8_t)((rawScr[0] & 0x700000) >> 20); + scr->sdBusWidths = (uint8_t)((rawScr[0] & 0xF0000) >> 16); + if ((uint8_t)((rawScr[0] & 0x8000) >> 15)) + { + scr->flags |= SDCARD_SCR_SD_SPEC3; + } + scr->exSecurity = (uint8_t)((rawScr[0] & 0x7800) >> 10); + scr->cmdSupport = (uint8_t)(rawScr[0] & 0x3); + scr->reservedForMan = rawScr[1]; + + switch(scr->sdSpec) + { + case 0: + card->version = SDMMC_SD_VERSION_1_0; + break; + case 1: + card->version = SDMMC_SD_VERSION_1_1; + break; + case 2: + card->version = SDMMC_SD_VERSION_2_0; + if (card->scr.flags & SDCARD_SCR_SD_SPEC3) + { + card->version = SDMMC_SD_VERSION_3_0; + } + break; + default: + break; + } + if (card->scr.sdBusWidths & SD_SCR_BUS_WIDTHS_4BIT) + { + card->caps |= SDMMC_CARD_CAPS_BUSWIDTH_4BITS; + } +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_SendScr + * Description: fetch scr register from card + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_SendScr(sdhc_card_t *card) +{ + sdhc_request_t *req = 0; + sdhc_data_t data = {0}; + sdhc_status_t err = kStatus_SDHC_NoError; + uint32_t rawScr[2] = {0}; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + err = SDCARD_DRV_SendApplicationCmd(card); + if (err) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return err; + } + + req->data = &data; + req->cmdIndex = kSdAppSendScr; + req->flags = FSL_SDHC_REQ_FLAGS_DATA_READ; + req->respType = kSdhcRespTypeR1; + req->argument = 0; + + data.blockSize = 8; + data.blockCount = 1; + data.buffer = rawScr; + data.req = req; + + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } + rawScr[0] = swap_be32(rawScr[0]); + rawScr[1] = swap_be32(rawScr[1]); + memcpy(card->rawScr, rawScr, sizeof(card->rawScr)); + SDCARD_DRV_DecodeScr(rawScr, card); +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_SwitchHighspeed + * Description: switch high speed mode of the specific card + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_SwitchHighspeed(sdhc_card_t *card) +{ + uint32_t response[16] = {0}; + sdhc_status_t err = kStatus_SDHC_NoError; + assert(card); + + if ((card->version < SDMMC_SD_VERSION_1_1) + || (!(card->csd.ccc & SD_CCC_SWITCH))) + { + return kStatus_SDHC_CardNotSupport; + } + + err = SDCARD_DRV_Switch(card, kSdSwitchCheck, 0, 1, response); + if (err) + { + return err; + } + + if ((!(swap_be32(response[3]) & 0x10000)) || + ((swap_be32(response[4]) & 0x0f000000) == 0x0F000000)) + { + return kStatus_SDHC_CardNotSupport; + } + + err = SDCARD_DRV_Switch(card, kSdSwitchSet, 0, 1, response); + if (err) + { + return err; + } + + if ((swap_be32(response[4]) & 0x0f000000) != 0x01000000) + { + err = kStatus_SDHC_SwitchFailed; + } + + return err; + +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_SetBusWidth + * Description: set desired buswidth + * + *END*********************************************************************/ +static uint32_t SDCARD_DRV_SetBusWidth(sdhc_card_t *card, + sd_buswidth_t busWidth) +{ + sdhc_request_t *req = 0; + sdhc_status_t err = kStatus_SDHC_NoError; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + err = SDCARD_DRV_SendApplicationCmd(card); + if (err != kStatus_SDHC_NoError) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return err; + } + + req->cmdIndex = kSdAppSetBusWdith; + req->respType = kSdhcRespTypeR1; + req->argument = busWidth; + + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return err; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_InitSd + * Description: initialize SD memory card + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_InitSd(sdhc_card_t *card) +{ + assert(card); + sdhc_status_t err = kStatus_SDHC_NoError; + card->cardType = kCardTypeSd; + + if (kStatus_SDHC_NoError != SDCARD_DRV_AllSendCid(card)) + { + return kStatus_SDHC_AllSendCidFailed; + } + + if (kStatus_SDHC_NoError != SDCARD_DRV_SendRca(card)) + { + return kStatus_SDHC_SendRcaFailed; + } + + if (kStatus_SDHC_NoError != SDCARD_DRV_SendCsd(card)) + { + return kStatus_SDHC_SendCsdFailed; + } + + if (kStatus_SDHC_NoError != SDCARD_DRV_SelectCard(card, true)) + { + return kStatus_SDHC_SelectCardFailed; + } + + if (kStatus_SDHC_NoError != SDCARD_DRV_SendScr(card)) + { + return kStatus_SDHC_SendScrFailed; + } + + if (kStatus_SDHC_NoError != + SDHC_DRV_ConfigClock(card->hostInstance, SDMMC_CLK_25MHZ)) + { + return kStatus_SDHC_SetClockFailed; + } + + if (DOES_HOST_SUPPORT_4BITS(card->host) && DOES_CARD_SUPPORT_4BITS(card)) + { + if (kStatus_SDHC_NoError != SDCARD_DRV_SetBusWidth(card, kSdBusWidth4Bit)) + { + return kStatus_SDHC_SetCardWideBusFailed; + } + if (kStatus_SDHC_NoError != + SDHC_DRV_SetBusWidth(card->hostInstance, kSdhcBusWidth4Bit)) + { + return kStatus_SDHC_SetBusWidthFailed; + } + } + + if (DOES_HOST_SUPPORT_HIGHSPEED(card->host)) + { + err = SDCARD_DRV_SwitchHighspeed(card); + if ((err != kStatus_SDHC_NoError) && (kStatus_SDHC_CardNotSupport != err)) + { + return kStatus_SDHC_SwitchHighSpeedFailed; + } + else if (err == kStatus_SDHC_NoError) + { + if (kStatus_SDHC_NoError != + SDHC_DRV_ConfigClock(card->hostInstance, SDMMC_CLK_50MHZ)) + { + return kStatus_SDHC_SetClockFailed; + } + } + else + { + err = kStatus_SDHC_NoError; + } + } + + if (SDCARD_DRV_SetBlockSize(card, FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE)) + { + err = kStatus_SDHC_SetCardBlockSizeFailed; + } + return err; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_AppSendOpCond + * Description: Send host capacity support information and asks the accessed + * card to send its operating condition register content. + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_AppSendOpCond(sdhc_card_t *card, + uint32_t acmd41Arg) +{ + sdhc_request_t *req = 0; + sdhc_status_t err; + uint32_t i = FSL_SDHC_CARD_MAX_VOLT_RETRIES; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->cmdIndex = kSdAppSendOpCond; + req->argument = acmd41Arg; + req->respType = kSdhcRespTypeR3; + + while (i--) + { + err = SDCARD_DRV_SendApplicationCmd(card); + if (err != kStatus_SDHC_NoError) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return err; + } + + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return err; + } + + if (req->response[0] & SDMMC_CARD_BUSY) + { + if (req->response[0] & SD_OCR_CCS) + { + card->caps |= SDMMC_CARD_CAPS_HIGHCAPACITY; + } + err = kStatus_SDHC_NoError; + card->ocr = req->response[0]; + break; + } + err = kStatus_SDHC_TimeoutError; + + SDCARD_DRV_DelayMsec(1); + } + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return err; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_GoIdle + * Description: reset all cards to idle state + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_GoIdle(sdhc_card_t *card) +{ + sdhc_request_t *req = 0; + sdhc_status_t err; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->cmdIndex = kGoIdleState; + err = SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT); +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return err; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_CheckReadOnly + * Description: Check if the card is ready only + * + *END*********************************************************************/ +bool SDCARD_DRV_CheckReadOnly(sdhc_card_t *card) +{ + assert(card); + + return ((card->csd.flags & SDCARD_CSD_PERM_WRITE_PROTECT) || + (card->csd.flags & SDCARD_CSD_TMP_WRITE_PROTECT)); +} + + + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_SendIfCond + * Description: check card interface condition, which includes host supply + * voltage information and asks the card whether card supports voltage. + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_SendIfCond(sdhc_card_t *card) +{ + sdhc_request_t *req = 0; + sdhc_status_t err = kStatus_SDHC_NoError; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + req->cmdIndex = kSdSendIfCond; + req->argument = 0x1AA; + req->respType = kSdhcRespTypeR7; + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { + err = kStatus_SDHC_RequestFailed; + } + else if ((req->response[0] & 0xFF) != 0xAA) + { + err = kStatus_SDHC_CardNotSupport; + } +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return err; +} + +#if ! defined BSP_FSL_SDHC_ENABLE_AUTOCMD12 +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_StopTransmission + * Description: Send stop transmission command to card to stop ongoing + * data transferring. + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_StopTransmission(sdhc_card_t *card) +{ + sdhc_request_t *req = 0; + sdhc_status_t err = kStatus_SDHC_NoError; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + + req->cmdIndex = kStopTransmission; + req->flags |= FSL_SDHC_REQ_FLAGS_STOP_TRANS; + req->argument = 0; + req->respType = kSdhcRespTypeR1b; + req->data = 0; + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return err; +} +#endif + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_Read + * Description: read data from specific card + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_Read(sdhc_card_t *card, + uint8_t *buffer, + uint32_t startBlock, + uint32_t blockSize, + uint32_t blockCount) +{ + sdhc_request_t *req = 0; + sdhc_data_t data = {0}; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + + assert(card); + assert(buffer); + assert(blockCount); + assert(blockSize); + assert(blockSize == FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE); + + if ((IS_HIGHCAPACITY_CARD(card) && (blockSize != 512)) + || (blockSize > card->blockSize) + || (blockSize > card->host->maxBlockSize) + || (blockSize % 4)) + { + return kStatus_SDHC_BlockSizeNotSupportError; + } + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + + data.blockSize = blockSize; + data.blockCount = blockCount; + data.buffer = (uint32_t *)buffer; + + req->data = &data; + req->cmdIndex = kReadMultipleBlock; + if (data.blockCount == 1) + { + req->cmdIndex = kReadSingleBlock; + } + + req->argument = startBlock; + if (!IS_HIGHCAPACITY_CARD(card)) + { + req->argument *= data.blockSize; + } + req->flags = FSL_SDHC_REQ_FLAGS_DATA_READ; + req->respType = kSdhcRespTypeR1; + + data.req = req; + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } + +#if ! defined BSP_FSL_SDHC_ENABLE_AUTOCMD12 + if (data.blockCount > 1) + { + if (kStatus_SDHC_NoError != SDCARD_DRV_StopTransmission(card)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_StopTransmissionFailed; + } + } +#endif +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_Write + * Description: write data from specific card + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_Write(sdhc_card_t *card, + uint8_t *buffer, + uint32_t startBlock, + uint32_t blockSize, + uint32_t blockCount) +{ + sdhc_request_t *req = 0; + sdhc_data_t data = {0}; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + assert(buffer); + assert(blockCount); + assert(blockSize); + assert(blockSize == FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE); + + if ((IS_HIGHCAPACITY_CARD(card) && (blockSize != 512)) + || (blockSize > card->blockSize) + || (blockSize > card->host->maxBlockSize) + || (blockSize % 4)) + { + return kStatus_SDHC_BlockSizeNotSupportError; + } + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + + data.blockSize = blockSize; + data.blockCount = blockCount; + data.buffer = (uint32_t *)buffer; + + req->data = &data; + req->cmdIndex = kWriteMultipleBlock; + if (data.blockCount == 1) + { + req->cmdIndex = kWriteBlock; + } + + req->argument = startBlock; + if (!IS_HIGHCAPACITY_CARD(card)) + { + req->argument *= data.blockSize; + } + req->respType = kSdhcRespTypeR1; + data.req = req; + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } + + if (data.blockCount > 1) + { +#if ! defined BSP_FSL_SDHC_ENABLE_AUTOCMD12 + if (kStatus_SDHC_NoError != SDCARD_DRV_StopTransmission(card)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_StopTransmissionFailed; + } +#endif + } +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_Erase + * Description: erase data for the given block range + * + *END*********************************************************************/ +static sdhc_status_t SDCARD_DRV_Erase(sdhc_card_t *card, + uint32_t startBlock, + uint32_t blockCount) +{ + uint32_t s, e; + sdhc_request_t *req = 0; +#if ! defined BSP_FSL_SDHC_USING_DYNALLOC + sdhc_request_t request = {0}; + req = &request; +#endif + assert(card); + assert(blockCount); + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + req = (sdhc_request_t *)OSA_MemAllocZero(sizeof(sdhc_request_t)); + if (req == NULL) + { + return kStatus_SDHC_OutOfMemory; + } +#endif + s = startBlock; + e = s + blockCount - 1; + if (!IS_HIGHCAPACITY_CARD(card)) + { + s = s * FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE; + e = e * FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE; + } + + req->cmdIndex = kSdEraseWrBlkStart; + req->argument = s; + req->respType = kSdhcRespTypeR1; + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } + req->cmdIndex = kSdEraseWrBlkEnd; + req->argument = e; + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } + req->cmdIndex = kErase; + req->argument = 0; + req->respType = kSdhcRespTypeR1b; + if (kStatus_SDHC_NoError != + SDHC_DRV_IssueRequestBlocking(card->hostInstance, + req, + FSL_SDCARD_REQUEST_TIMEOUT)) + { +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_RequestFailed; + } + +#if defined BSP_FSL_SDHC_USING_DYNALLOC + OSA_MemFree(req); +#endif + req = NULL; + return kStatus_SDHC_NoError; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_Shutdown + * Description: destory initialized card and shutdown the corresponding + * host controller + * + *END*********************************************************************/ +void SDCARD_DRV_Shutdown(sdhc_card_t *card) +{ + assert(card); + SDCARD_DRV_SelectCard(card, false); +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_Init + * Description: initialize card on the given host controller + * + *END*********************************************************************/ +sdhc_status_t SDCARD_DRV_Init(sdhc_host_t *host, sdhc_card_t *card) +{ + sdhc_status_t err = kStatus_SDHC_NoError; + uint32_t acmd41Arg; + assert(card); + assert(host); + + card->cardType = kCardTypeUnknown; + card->host = host; + card->hostInstance = host->instance; + + if (SDHC_DRV_ConfigClock(card->hostInstance, SDMMC_CLK_400KHZ)) + { + return kStatus_SDHC_SetClockFailed; + } + + err = SDCARD_DRV_GoIdle(card); + if (err) + { + return kStatus_SDHC_SetCardToIdle; + } + acmd41Arg = card->host->ocrSupported; + + err = SDCARD_DRV_SendIfCond(card); + if (err == kStatus_SDHC_NoError) + { + /* SDHC or SDXC card */ + acmd41Arg |= SD_OCR_HCS; + card->caps |= SDMMC_CARD_CAPS_SDHC; + } + else + { + /* SDSC card */ + err = SDCARD_DRV_GoIdle(card); + if (err) + { + return kStatus_SDHC_SetCardToIdle; + } + } + + err = SDCARD_DRV_AppSendOpCond(card, acmd41Arg); + if (kStatus_SDHC_TimeoutError == err) + { + /* MMC card */ + return kStatus_SDHC_NotSupportYet; + } + else if (err) + { + return kStatus_SDHC_SendAppOpCondFailed; + } + + return SDCARD_DRV_InitSd(card); +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_WriteBlocks + * Description: write blocks to card with default block size + * + *END*********************************************************************/ +sdhc_status_t SDCARD_DRV_WriteBlocks(sdhc_card_t *card, + uint8_t *buffer, + uint32_t startBlock, + uint32_t blockCount) +{ + uint32_t blkCnt, blkLeft, blkDone; + sdhc_status_t err = kStatus_SDHC_NoError; + + assert(card); + assert(buffer); + assert(blockCount); + + blkLeft = blockCount; + blkDone = 0; + + if ((blockCount + startBlock) > card->blockCount) + { + return kStatus_SDHC_InvalidIORange; + } + + while(blkLeft) + { + if (blkLeft > card->host->maxBlockCount) + { + blkLeft = blkLeft - card->host->maxBlockCount; + blkCnt = card->host->maxBlockCount; + } + else + { + blkCnt = blkLeft; + blkLeft = 0; + } + + err = SDCARD_DRV_Write(card, + buffer + blkDone * FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE, + startBlock + blkDone, + FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE, + blkCnt); + if (err != kStatus_SDHC_NoError) + { + return err; + } + blkDone += blkCnt; + } + + return err; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_ReadBlocks + * Description: read blocks from card with default block size + * + *END*********************************************************************/ +sdhc_status_t SDCARD_DRV_ReadBlocks(sdhc_card_t *card, + uint8_t *buffer, + uint32_t startBlock, + uint32_t blockCount) +{ + uint32_t blkCnt, blkLeft, blkDone; + sdhc_status_t err = kStatus_SDHC_NoError; + + assert(card); + assert(buffer); + assert(blockCount); + + blkLeft = blockCount; + blkDone = 0; + + if ((blockCount + startBlock) > card->blockCount) + { + return kStatus_SDHC_InvalidIORange; + } + + while(blkLeft) + { + if (blkLeft > card->host->maxBlockCount) + { + blkLeft = blkLeft - card->host->maxBlockCount; + blkCnt = card->host->maxBlockCount; + } + else + { + blkCnt = blkLeft; + blkLeft = 0; + } + + err = SDCARD_DRV_Read(card, + buffer + blkDone * FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE, + startBlock + blkDone, + FSL_SDHC_CARD_DEFAULT_BLOCK_SIZE, + blkCnt); + if (err != kStatus_SDHC_NoError) + { + return err; + } + blkDone += blkCnt; + } + + return err; +} + +/*FUNCTION**************************************************************** + * + * Function Name: SDCARD_DRV_EraseBlocks + * Description: erase block range from card with default block size + * + *END*********************************************************************/ +sdhc_status_t SDCARD_DRV_EraseBlocks(sdhc_card_t *card, + uint32_t startBlock, + uint32_t blockCount) +{ + uint32_t blkDone = 0, blkLeft, blkCnt; + + assert(card); + assert(blockCount); + + blkLeft = blockCount; + while(blkLeft) + { + if (blkLeft > (card->csd.sectorSize + 1)) + { + blkCnt = card->csd.sectorSize + 1; + blkLeft = blkLeft - blkCnt; + } + else + { + blkCnt = blkLeft; + blkLeft = 0; + } + + if (kStatus_SDHC_NoError != SDCARD_DRV_Erase(card, + startBlock + blkDone, + blkCnt)) + { + return kStatus_SDHC_CardEraseBlocksFailed; + } + + blkDone += blkCnt; + } + return kStatus_SDHC_NoError; +} diff --git a/KSDK_1.2.0/platform/composite/src/soundcard/fsl_soundcard.c b/KSDK_1.2.0/platform/composite/src/soundcard/fsl_soundcard.c new file mode 100755 index 0000000..8edeeb9 --- /dev/null +++ b/KSDK_1.2.0/platform/composite/src/soundcard/fsl_soundcard.c @@ -0,0 +1,612 @@ +/* + * Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * o Redistributions of source code must retain the above copyright notice, this list + * of conditions and the following disclaimer. + * + * o Redistributions in binary form must reproduce the above copyright notice, this + * list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * o Neither the name of Freescale Semiconductor, Inc. nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "fsl_soundcard.h" +#include <assert.h> +#include <string.h> +#include "fsl_os_abstraction.h" + +/******************************************************************************* + *Definitation + ******************************************************************************/ +#if SOUNDCARD_USE_STATIC_MEM +#if defined( __ICCCF__ ) || defined( __ICCARM__ ) +#pragma segment="SAI_BDT_Z" +#pragma data_alignment=4 +__no_init static uint8_t s_tx_buffer[AUDIO_CONTROLLER_NUM][AUDIO_BUFFER_SIZE] @ "SAI_BDT_Z"; +__no_init static uint8_t s_rx_buffer[AUDIO_CONTROLLER_NUM][AUDIO_BUFFER_SIZE] @ "SAI_BDT_Z"; +#elif defined(__GNUC__) +__attribute__((aligned(4))) static uint8_t s_tx_buffer[AUDIO_CONTROLLER_NUM][AUDIO_BUFFER_SIZE]; +__attribute__((aligned(4))) static uint8_t s_rx_buffer[AUDIO_CONTROLLER_NUM][AUDIO_BUFFER_SIZE]; +#elif defined (__CC_ARM) +__align(4) static uint8_t s_tx_buffer[AUDIO_CONTROLLER_NUM][AUDIO_BUFFER_SIZE]; +__align(4) static uint8_t s_rx_buffer[AUDIO_CONTROLLER_NUM][AUDIO_BUFFER_SIZE]; +#endif +#endif + +#if USEDMA +void SND_TxDmaCallback(void *param, edma_chn_status_t status); +void SND_RxDmaCallback(void *param, edma_chn_status_t status); +#else +void SND_TxCallback(void *param); +void SND_RxCallback(void *param); +#endif + +/* The instance for sai operation structure. */ +audio_ctrl_operation_t g_sai_ops = +{ + SAI_DRV_TxInit, + SAI_DRV_RxInit, + SAI_DRV_TxDeinit, + SAI_DRV_RxDeinit, + SAI_DRV_TxConfigDataFormat, + SAI_DRV_RxConfigDataFormat, + SAI_DRV_TxStartModule, + SAI_DRV_RxStartModule, + SAI_DRV_TxStopModule, + SAI_DRV_RxStopModule, + SAI_DRV_TxRegisterCallback, + SAI_DRV_RxRegisterCallback, + SAI_DRV_TxSetIntCmd, + SAI_DRV_RxSetIntCmd, + SAI_DRV_TxSetDmaCmd, + SAI_DRV_RxSetDmaCmd, + SAI_DRV_TxGetWatermark, + SAI_DRV_RxGetWatermark, + SAI_DRV_TxGetFifoAddr, + SAI_DRV_RxGetFifoAddr, + SAI_DRV_SendDataInt, + SAI_DRV_ReceiveDataInt +}; + +/* Instance of codec operation for sgtl5000. */ +audio_codec_operation_t g_sgtl_ops = +{ + SGTL_Init, + SGTL_Deinit, + SGTL_ConfigDataFormat, + SGTL_SetDACMute, + SGTL_SetDACVoulme, + SGTL_GetDACVolume +}; + +/******************************************************************************* + *Code + ******************************************************************************/ + +/*FUNCTION********************************************************************** +* +* Function Name : SND_TxInit +* Description : Initialize the soundcard. +* The soundcard includes a controller and a codec. +*END**************************************************************************/ +snd_status_t SND_TxInit( + sound_card_t * card, void * ctrl_config, void * codec_config, ctrl_state_t *state) +{ + audio_controller_t *ctrl = &card->controller; + audio_codec_t *codec = &card->codec; + /* Allocate space for buffer */ + audio_buffer_t *buffer = &card->buffer; + /* Buffer size and block settings */ + if ((buffer->blocks == 0) || (buffer->size == 0)) + { + buffer->blocks = AUDIO_BUFFER_BLOCK; + buffer->size = AUDIO_BUFFER_BLOCK_SIZE; + } +#if SOUNDCARD_USE_STATIC_MEM + buffer->buff = &s_tx_buffer[ctrl->instance][0]; +#else + buffer->buff = (uint8_t *)OSA_MemAllocZero(buffer->size * buffer->blocks); + if(!buffer->buff) + { + return kStatus_SND_BufferAllocateFail; + } +#endif + buffer->input_curbuff = buffer->buff; + buffer->output_curbuff = buffer->buff; + /* Initialize the status structure */ + buffer->empty_block = buffer->blocks; + buffer->full_block = 0; + OSA_SemaCreate(&buffer->sem, buffer->blocks); + /* Initialize audio controller and codec */ + ctrl->ops->Ctrl_TxInit(ctrl->instance, ctrl_config, state); + codec->ops->Codec_Init((void *)codec->handler, codec_config); +#if USEDMA + EDMA_DRV_RequestChannel(kEDMAAnyChannel, ctrl->dma_source, &ctrl->dma_channel); + EDMA_DRV_InstallCallback(&ctrl->dma_channel, SND_TxDmaCallback, (void *)card); +#else + ctrl->ops->Ctrl_TxRegisterCallback(ctrl->instance, SND_TxCallback, card); +#endif + return kStatus_SND_Success; +} + +/*FUNCTION********************************************************************** +* +* Function Name : SND_RxInit +* Description : Initialize the Rx soundcard. +* The soundcard includes a controller and a codec. +*END**************************************************************************/ +snd_status_t SND_RxInit( +sound_card_t * card, void * ctrl_config, void * codec_config, ctrl_state_t *state) +{ + audio_controller_t *ctrl = &card->controller; + audio_codec_t *codec = &card->codec; + /* Allocate space for buffer */ + audio_buffer_t *buffer = &card->buffer; + /* Buffer size and block settings */ + if ((buffer->blocks == 0) || (buffer->size == 0)) + { + buffer->blocks = AUDIO_BUFFER_BLOCK; + buffer->size = AUDIO_BUFFER_BLOCK_SIZE; + } +#if SOUNDCARD_USE_STATIC_MEM + buffer->buff = &s_rx_buffer[ctrl->instance][0]; +#else + buffer->buff = (uint8_t *)OSA_MemAllocZero(buffer->size * buffer->blocks); + if(!buffer->buff) + { + return kStatus_SND_BufferAllocateFail; + } +#endif + buffer->input_curbuff = buffer->buff; + buffer->output_curbuff = buffer->buff; + /* Initialize the status structure */ + buffer->empty_block = buffer->blocks; + buffer->full_block = 0; + OSA_SemaCreate(&buffer->sem, 0); + /* Initialize audio controller and codec */ + ctrl->ops->Ctrl_RxInit(ctrl->instance, ctrl_config,state); + codec->ops->Codec_Init((void *)codec->handler, codec_config); +#if USEDMA + EDMA_DRV_RequestChannel(kEDMAAnyChannel, ctrl->dma_source, &ctrl->dma_channel); + EDMA_DRV_InstallCallback(&ctrl->dma_channel, SND_RxDmaCallback, (void *)card); +#else + ctrl->ops->Ctrl_RxRegisterCallback(ctrl->instance, SND_RxCallback, card); +#endif + return kStatus_SND_Success; +} + +/*FUNCTION********************************************************************* +* +* Function Name : SND_TxDeinit +* Description : Deinit the tx soundcard. +* The soundcard includes a controller and a codec. +*END**************************************************************************/ +snd_status_t SND_TxDeinit(sound_card_t *card) +{ + audio_controller_t *ctrl = &card->controller; + audio_codec_t *codec = &card->codec; + audio_buffer_t *buffer = &card->buffer; + /* Call the deinit function of the ctrl and codec. */ + ctrl->ops->Ctrl_TxDeinit(ctrl->instance); + codec->ops->Codec_Deinit((void *)codec->handler); +#if USEDMA + /* Deinit the dma resource */ + EDMA_DRV_StopChannel(&ctrl->dma_channel); + EDMA_DRV_ReleaseChannel(&ctrl->dma_channel); +#endif + OSA_SemaDestroy(&buffer->sem); +#if !SOUNDCARD_USE_STATIC_MEM + /* Free the tx and rx buffer. */ + OSA_MemFree(buffer->buff); +#endif + return kStatus_SND_Success; +} + +/*FUNCTION********************************************************************* +* +* Function Name : SND_RxDeinit +* Description : Deinit the rx soundcard. +* The soundcard includes a controller and a codec. +*END**************************************************************************/ +snd_status_t SND_RxDeinit(sound_card_t *card) +{ + audio_controller_t *ctrl = &card->controller; + audio_codec_t *codec = &card->codec; + audio_buffer_t *buffer = &card->buffer; + /* Call the deinit function of the ctrl and codec. */ + ctrl->ops->Ctrl_RxDeinit(ctrl->instance); + codec->ops->Codec_Deinit((void *)codec->handler); +#if USEDMA + /* Deinit the dma resource */ + EDMA_DRV_StopChannel(&ctrl->dma_channel); + EDMA_DRV_ReleaseChannel(&ctrl->dma_channel); +#endif + OSA_SemaDestroy(&buffer->sem); +#if !SOUNDCARD_USE_STATIC_MEM + /* Free the tx and rx buffer. */ + OSA_MemFree(buffer->buff); +#endif + return kStatus_SND_Success; +} + +/*FUNCTION********************************************************************** +* +* Function Name : SND_TxConfigDataFormat +* Description : Configure the audio file format in tx soundcard. +* The soundcard includes a controller and a codec. The audio format includes +* sample rate, bit length and so on. +*END**************************************************************************/ +snd_status_t SND_TxConfigDataFormat(sound_card_t *card, ctrl_data_format_t *format) +{ + audio_controller_t *ctrl = &card->controller; + audio_codec_t *codec = &card->codec; + + ctrl->ops->Ctrl_TxConfigDataFormat(ctrl->instance, format); + codec->ops->Codec_ConfigDataFormat(codec->handler, format->mclk, format->sample_rate, + format->bits); + /* Configure dma */ +#if USEDMA + audio_buffer_t *buffer = &card->buffer; + uint32_t watermark = ctrl->ops->Ctrl_TxGetWatermark(ctrl->instance); + uint8_t sample_size = format->bits/8; + if((sample_size == 3) || (format->bits & 0x7)) + { + sample_size = 4; + } + uint32_t desAddr = ctrl->ops->Ctrl_TxGetFifoAddr(ctrl->instance, ctrl->fifo_channel); + EDMA_DRV_ConfigLoopTransfer( + &ctrl->dma_channel, ctrl->stcd, kEDMAMemoryToPeripheral, + (uint32_t)buffer->buff, (uint32_t)desAddr, sample_size, + sample_size * (AUDIO_FIFO_LEN -watermark) , AUDIO_BUFFER_SIZE, AUDIO_BUFFER_BLOCK); + EDMA_DRV_StartChannel(&ctrl->dma_channel); +#endif + return kStatus_SND_Success; +} + +/*FUNCTION********************************************************************** +* +* Function Name : SND_RxConfigDataFormat +* Description : Configure the audio file format in rx soundcard. +* The soundcard includes a controller and a codec. The audio format includes +* sample rate, bit length and so on. +*END**************************************************************************/ +snd_status_t SND_RxConfigDataFormat(sound_card_t *card, ctrl_data_format_t *format) +{ + audio_controller_t *ctrl = &card->controller; + audio_codec_t *codec = &card->codec; + + ctrl->ops->Ctrl_RxConfigDataFormat(ctrl->instance, format); + codec->ops->Codec_ConfigDataFormat(codec->handler, format->mclk, format->sample_rate, + format->bits); + /* Configure dma */ +#if USEDMA + audio_buffer_t *buffer = &card->buffer; + uint8_t sample_size = format->bits/8; + uint32_t watermark = ctrl->ops->Ctrl_RxGetWatermark(ctrl->instance); + if((sample_size == 3) || (format->bits & 0x7)) + { + sample_size = 4; + } + uint32_t desAddr = ctrl->ops->Ctrl_RxGetFifoAddr(ctrl->instance,ctrl->fifo_channel); + EDMA_DRV_ConfigLoopTransfer( + &ctrl->dma_channel, ctrl->stcd, kEDMAPeripheralToMemory, + (uint32_t)desAddr, (uint32_t)buffer->buff, sample_size, + sample_size * watermark, AUDIO_BUFFER_SIZE, AUDIO_BUFFER_BLOCK); + EDMA_DRV_StartChannel(&ctrl->dma_channel); +#endif + return kStatus_SND_Success; +} + +/*FUNCTION********************************************************************** +* +* Function Name : SND_TxUpdateStatus +* Description : Update the status of tx soundcard internal logic +* The function would tell tx soundcard how many data applications have written +* to the ring buffer. +*END**************************************************************************/ +uint32_t SND_TxUpdateStatus(sound_card_t * card, uint32_t len) +{ + audio_buffer_t * buffer = &card->buffer; + uint32_t blocks = len/buffer->size; + /* Update the buffer information */ + buffer->requested += len; + buffer->queued += len; + + if(buffer->input_index + blocks < buffer->blocks) + { + buffer->input_index += blocks; + } + else + { + buffer->input_index = blocks - (buffer->blocks - 1 - buffer->input_index) - 1; + } + buffer->input_curbuff = buffer->buff + buffer->input_index * buffer->size; + buffer->empty_block -= blocks; + buffer->full_block += blocks; + /* If sai is not enable, enable the sai */ + if (buffer->first_io) + { + buffer->first_io = false; + SND_TxStart(card); + } + return len; +} + +/*FUNCTION********************************************************************** +* +* Function Name : SND_RxUpdateStatus +* Description : Update the status of rx soundcard internal logic +* The function would tell rx soundcard how many data applications have received +* from the ring buffer. +*END**************************************************************************/ +uint32_t SND_RxUpdateStatus(sound_card_t * card, uint32_t len) +{ + audio_buffer_t * buffer = &card->buffer; + uint32_t blocks = len/buffer->size; + /* Update inner information */ + buffer->requested += len; + buffer->processed += len; + buffer->queued -= len; + /* Switch the buffer */ + if(buffer->output_index + blocks < buffer->blocks) + { + buffer->output_index += blocks; + } + else + { + buffer->output_index = blocks - (buffer->blocks - 1 - buffer->output_index) - 1; + } + buffer->output_curbuff = buffer->buff + buffer->output_index * buffer->size; + buffer->full_block -= blocks; + buffer->empty_block += blocks; + /* If sai is not enable, enable the sai */ + if (buffer->first_io) + { + buffer->first_io = false; + SND_RxStart(card); + } + return len; +} + +/*FUNCTION********************************************************************** +* +* Function Name : SND_TxCallback +* Description : Callback function to tell that audio controller have finished +* a period data. +* The function would update the buffer status information. +*END**************************************************************************/ +void SND_TxCallback(void *param) +{ + sound_card_t *card = (sound_card_t *)param; + audio_buffer_t *buffer = &card->buffer; + if(buffer->queued == 0) + { + return; + } + buffer->processed += buffer->size; + buffer->queued -= buffer->size; + + /* Change the current buffer */ + if (buffer->output_index == buffer->blocks - 1) + { + buffer->output_curbuff = buffer->buff; + buffer->output_index = 0; + } + else + { + buffer->output_index ++; + buffer->output_curbuff += buffer->size; + } + /* Update the status */ + buffer->empty_block += 1; + buffer->full_block -= 1; + /* Judge if need to close the SAI transfer. */ + if (buffer->input_index == buffer->output_index) + { + SND_TxStop(card); + buffer->buffer_error ++; + buffer->first_io = true; + } + else + { +#if !USEDMA + audio_controller_t * ctrl = &card->controller; + ctrl->ops->Ctrl_SendData(ctrl->instance, buffer->output_curbuff, buffer->size); +#endif + } + /* post the sync */ + OSA_SemaPost(&buffer->sem); +} + +/*FUNCTION********************************************************************** +* +* Function Name : SND_RxCallback +* Description : Callback function to tell that audio controller have finished +* a period data. +* The function would update the buffer status information. +*END**************************************************************************/ +void SND_RxCallback(void *param) +{ + sound_card_t *card = (sound_card_t *)param; + audio_buffer_t *buffer = &card->buffer; + buffer->queued += buffer->size; + /* Change the current buffer. */ + if (buffer->input_index == buffer->blocks - 1) + { + buffer->input_curbuff = buffer->buff; + buffer->input_index = 0; + } + else + { + buffer->input_index ++; + buffer->input_curbuff += buffer->size; + } + buffer->empty_block -= 1; + buffer->full_block += 1; + /* Judge if need to close the SAI transfer, while the buffer is full, + * we need to close the SAI */ + if (buffer->input_index == buffer->output_index) + { + SND_RxStop(card); + buffer->buffer_error ++; + buffer->first_io = true; + } + else + { +#if !USEDMA + audio_controller_t *ctrl = &card->controller; + ctrl->ops->Ctrl_ReceiveData(ctrl->instance, buffer->input_curbuff, buffer->size); +#endif + } + OSA_SemaPost(&buffer->sem); +} + +/*FUNCTION********************************************************************** + * + * Function Name : SND_GetStatus + * Description : Get the status of audio buffer, the status includes the empty + * blocks, full blocks and the starting address. + *END**************************************************************************/ + void SND_GetStatus(sound_card_t *card, snd_state_t *status) +{ + audio_buffer_t *buffer = &card->buffer; + status->size = buffer->size; + status->empty_block = buffer->empty_block; + status->full_block = buffer->full_block; + status->input_address = buffer->input_curbuff; + status->output_address = buffer->output_curbuff; +} + +/*FUNCTION********************************************************************** + * + * Function Name : SND_WaitEvent + * Description : This function is used for appliaction to wait for the semaphore + * to copy data in/out the sai buffer. + *END**************************************************************************/ +void SND_WaitEvent(sound_card_t *card) +{ + osa_status_t syncStatus; + audio_buffer_t *buffer = &card->buffer; + do + { + syncStatus = OSA_SemaWait(&buffer->sem, OSA_WAIT_FOREVER); + }while(syncStatus == kStatus_OSA_Idle); +} + +/*FUNCTION********************************************************************** + * + * Function Name : SND_TxStart + * Description : This function is used to start tx transfer. + *END**************************************************************************/ +void SND_TxStart(sound_card_t *card) +{ + audio_controller_t *ctrl = &card->controller; +#if !USEDMA + audio_buffer_t *buffer = &card->buffer; + ctrl->ops->Ctrl_SendData(ctrl->instance, buffer->output_curbuff, buffer->size); + ctrl->ops->Ctrl_TxSetIntCmd(ctrl->instance, true); +#else + ctrl->ops->Ctrl_TxSetDmaCmd(ctrl->instance,true); + EDMA_DRV_StartChannel(&card->controller.dma_channel); +#endif + ctrl->ops->Ctrl_TxStart(ctrl->instance); +} + +/*FUNCTION********************************************************************** + * + * Function Name : SND_RxStart + * Description : This function is used to start rx receive. + *END**************************************************************************/ +void SND_RxStart(sound_card_t *card) +{ + audio_controller_t *ctrl = &card->controller; +#if !USEDMA + audio_buffer_t *buffer = &card->buffer; + ctrl->ops->Ctrl_ReceiveData(ctrl->instance, buffer->input_curbuff, buffer->size); + ctrl->ops->Ctrl_RxSetIntCmd(ctrl->instance, true); +#else + ctrl->ops->Ctrl_RxSetDmaCmd(ctrl->instance,true); + EDMA_DRV_StartChannel(&card->controller.dma_channel); +#endif + ctrl->ops->Ctrl_RxStart(ctrl->instance); +} + +/*FUNCTION********************************************************************** + * + * Function Name : SND_SetMuteCmd + * Description : This function is used to mute or unmute the soundcard. + *END**************************************************************************/ +snd_status_t SND_SetMuteCmd(sound_card_t * card,bool enable) +{ + audio_codec_t *codec = &card->codec; + codec->ops->Codec_SetMuteCmd(codec->handler, enable); + return kStatus_SND_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : SND_SetVolume + * Description : This function is used to set the volume of soundcard. + *END**************************************************************************/ +snd_status_t SND_SetVolume(sound_card_t * card,uint32_t volume) +{ + audio_codec_t *codec = &card->codec; + codec->ops->Codec_SetMuteCmd(codec->handler, false); + codec->ops->Codec_SetVolume(codec->handler,volume); + return kStatus_SND_Success; +} + +/*FUNCTION********************************************************************** + * + * Function Name : SND_GetVolume + * Description : This function is used to get the volume of soundcard. + *END**************************************************************************/ +uint32_t SND_GetVolume(sound_card_t * card) +{ + audio_codec_t *codec = &card->codec; + return codec->ops->Codec_GetVolume(codec->handler); +} + +/*FUNCTION********************************************************************** + * + * Function Name : SND_TxDmaCallback + * Description : This function is as the tx callback function registered to dma module. + *END**************************************************************************/ +void SND_TxDmaCallback(void *param, edma_chn_status_t status) +{ + SND_TxCallback(param); +} + +/*FUNCTION********************************************************************** + * + * Function Name : SND_RxDmaCallback + * Description : This function is as the rx callback function registered to dma module. + *END**************************************************************************/ +void SND_RxDmaCallback(void *param, edma_chn_status_t status) +{ + SND_RxCallback(param); +} + +/******************************************************************************* + *EOF + ******************************************************************************/ + |