Newer
Older
mbed-os / targets / TARGET_Cypress / TARGET_PSOC6 / mtb-pdl-cat1 / drivers / source / cy_sd_host.c
@Dustin Crossman Dustin Crossman on 4 Jun 2021 191 KB Fix file modes.
/*******************************************************************************
* \file cy_sd_host.c
* \version 1.80
*
* \brief
*  This file provides the driver code to the API for the SD Host Controller
*  driver.
*
********************************************************************************
* \copyright
* Copyright 2018-2021 Cypress Semiconductor Corporation
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

#include "cy_device.h"

#if defined (CY_IP_MXSDHC)

#include "cy_sd_host.h"
#include <string.h>
#include <stdlib.h>

#if defined(__cplusplus)
extern "C" {
#endif

CY_MISRA_DEVIATE_BLOCK_START('MISRA C-2012 Rule 18.1', 11, \
            'Checked manually, base pointer will not exceed register range.');

/** \cond internal */

/* Timeouts. */
#define CY_SD_HOST_INT_CLK_STABLE_TIMEOUT_MS (150U)  /* The Internal Clock Stable timeout. */
#define CY_SD_HOST_1_8_REG_STABLE_TIME_MS   (30UL)   /* The 1.8 voltage regulator stable time. */
#define CY_SD_HOST_SUPPLY_RAMP_UP_TIME_MS   (35UL)   /* The host supply ramp up time. */
#define CY_SD_HOST_BUS_RAMP_UP_TIME_MS      (1000UL) /* The host bus voltage ramp up time. */

#define CY_SD_HOST_EMMC_CMD6_TIMEOUT_MULT   (10UL)   /* The 10x multiplier of GENERIC_CMD6_TIME[248]. */
#define CY_SD_HOST_RETRY_TIME               (1000UL) /* The number loops to make the timeout in msec. */
#define CY_SD_HOST_VOLTAGE_CHECK_RETRY      (2UL)    /* The number loops for voltage check. */
#define CY_SD_HOST_SDIO_CMD5_TIMEOUT_MS     (1000U)  /* The SDIO CMD5 timeout. */
#define CY_SD_HOST_ACMD41_TIMEOUT_MS        (1000U)  /* The ACMD41 timeout. */
#define CY_SD_HOST_CMD1_TIMEOUT_MS          (1000U)  /* The eMMC device timeout to complete its initialization. */
#define CY_SD_HOST_CMD_TIMEOUT_MS           (3U)     /* The Command complete timeout. */
#define CY_SD_HOST_BUFFER_RDY_TIMEOUT_MS    (150U)   /* The Buffer read ready timeout. */
#define CY_SD_HOST_RD_WR_ENABLE_TIMEOUT     (1U)     /* The valid data in the Host buffer timeout. */
#define CY_SD_HOST_READ_TIMEOUT_MS          (100U)   /* The Read timeout for one block. */
#define CY_SD_HOST_WRITE_TIMEOUT_MS         (250U)   /* The Write timeout for one block. */
#define CY_SD_HOST_MAX_TIMEOUT              (0x0EU)  /* The data max timeout for TOUT_CTRL_R. */
#define CY_SD_HOST_NCC_MIN_CYCLES           (8U)     /* The period (clock cycles) between an end bit
                                                      * of the command and a start bit of the next command.
                                                      */
#define CY_SD_HOST_NCC_MIN_US               ((1000U * CY_SD_HOST_NCC_MIN_CYCLES) / CY_SD_HOST_INIT_CLK_FREQUENCY_KHZ)

/* Commands codes. */
#define CY_SD_HOST_SD_CMD0                  (0UL)
#define CY_SD_HOST_SD_CMD1                  (1UL)
#define CY_SD_HOST_SD_CMD2                  (2UL)
#define CY_SD_HOST_SD_CMD3                  (3UL)
#define CY_SD_HOST_SD_CMD5                  (5UL)
#define CY_SD_HOST_SD_CMD6                  (6UL)
#define CY_SD_HOST_SD_CMD7                  (7UL)
#define CY_SD_HOST_SD_CMD8                  (8UL)
#define CY_SD_HOST_SD_CMD9                  (9UL)
#define CY_SD_HOST_SD_CMD10                 (10UL)
#define CY_SD_HOST_SD_CMD11                 (11UL)
#define CY_SD_HOST_SD_CMD12                 (12UL)
#define CY_SD_HOST_SD_CMD13                 (13UL)

#define CY_SD_HOST_SD_CMD16                 (16UL)
#define CY_SD_HOST_SD_CMD17                 (17UL)
#define CY_SD_HOST_SD_CMD18                 (18UL)

#define CY_SD_HOST_SD_CMD23                 (23UL)
#define CY_SD_HOST_SD_CMD24                 (24UL)
#define CY_SD_HOST_SD_CMD25                 (25UL)

#define CY_SD_HOST_SD_CMD27                 (27UL)
#define CY_SD_HOST_SD_CMD28                 (28UL)
#define CY_SD_HOST_SD_CMD29                 (29UL)
#define CY_SD_HOST_SD_CMD30                 (30UL)

#define CY_SD_HOST_SD_CMD32                 (32UL)
#define CY_SD_HOST_SD_CMD33                 (33UL)
#define CY_SD_HOST_SD_CMD35                 (35UL)
#define CY_SD_HOST_SD_CMD36                 (36UL)
#define CY_SD_HOST_SD_CMD38                 (38UL)

#define CY_SD_HOST_SD_CMD42                 (42UL)
#define CY_SD_HOST_SD_CMD52                 (52UL)

#define CY_SD_HOST_SD_CMD55                 (55UL)

#define CY_SD_HOST_MMC_CMD_TAG              (0x80UL)
#define CY_SD_HOST_MMC_CMD8                 (0x8UL | CY_SD_HOST_MMC_CMD_TAG)

#define CY_SD_HOST_SD_ACMD_OFFSET           (0x40UL)
#define CY_SD_HOST_SD_ACMD6                 (CY_SD_HOST_SD_ACMD_OFFSET + 6UL)
#define CY_SD_HOST_SD_ACMD13                (CY_SD_HOST_SD_ACMD_OFFSET + 13UL)
#define CY_SD_HOST_SD_ACMD41                (CY_SD_HOST_SD_ACMD_OFFSET + 41UL)
#define CY_SD_HOST_SD_ACMD51                (CY_SD_HOST_SD_ACMD_OFFSET + 51UL)

/* CMD5/CMD8/ACMD41 constants. */
#define CY_SD_HOST_CMD5_IO_NUM_MASK         (0x70000000UL) /* The Number of IO functions mask. */
#define CY_SD_HOST_CMD5_MP_MASK             (0x08000000UL) /* The Memory Present mask. */
#define CY_SD_HOST_IO_OCR_MASK              (0x00FFFFFFUL) /* The IO OCR register mask. */
#define CY_SD_HOST_IO_OCR_C                 (0x80000000UL) /* The IO power up status (IORDY). */
#define CY_SD_HOST_MIN_SDXC_SECTORS         (67108864UL) /* Minimum sectors for SDXC: 32 Gbytes / 512. */
#define CY_SD_HOST_MMC_LEGACY_SIZE_BYTES    (0x200000UL)
#define CY_SD_HOST_CMD8_VHS_27_36           (0x100UL) /* CMD8 voltage supplied 2.7-3.6 V. */
#define CY_SD_HOST_CMD8_PATTERN_MASK        (0xFFUL)
#define CY_SD_HOST_CMD8_CHECK_PATTERN       (0xAAUL)
#define CY_SD_HOST_ACMD41_S18R              (1UL << 24U) /* The 1.8 V request. */
#define CY_SD_HOST_ACMD41_HCS               (1UL << 30U) /* SDHC or SDXC supported. */
#define CY_SD_HOST_OCR_S18A                 (1UL << 24U) /* The 1.8 V accepted. */
#define CY_SD_HOST_OCR_35_36_V              (1UL << 23U) /* The 3.5 - 3.6 voltage window. */
#define CY_SD_HOST_OCR_34_35_V              (1UL << 22U) /* The 3.4 - 3.5 voltage window. */
#define CY_SD_HOST_OCR_33_34_V              (1UL << 21U) /* The 3.3 - 3.4 voltage window. */
#define CY_SD_HOST_OCR_32_33_V              (1UL << 20U) /* The 3.2 - 3.3 voltage window. */
#define CY_SD_HOST_OCR_31_32_V              (1UL << 19U) /* The 3.1 - 3.2 voltage window. */
#define CY_SD_HOST_OCR_30_31_V              (1UL << 18U) /* The 3.0 - 3.1 voltage window. */
#define CY_SD_HOST_OCR_29_30_V              (1UL << 17U) /* The 2.9 - 3.0 voltage window. */
#define CY_SD_HOST_OCR_28_29_V              (1UL << 16U) /* The 2.8 - 2.9 voltage window. */
#define CY_SD_HOST_OCR_27_28_V              (1UL << 15U) /* The 2.7 - 2.8 voltage window. */
#define CY_SD_HOST_ACMD41_VOLTAGE_MASK      (CY_SD_HOST_OCR_35_36_V |\
                                             CY_SD_HOST_OCR_34_35_V |\
                                             CY_SD_HOST_OCR_33_34_V |\
                                             CY_SD_HOST_OCR_32_33_V |\
                                             CY_SD_HOST_OCR_31_32_V |\
                                             CY_SD_HOST_OCR_30_31_V |\
                                             CY_SD_HOST_OCR_29_30_V |\
                                             CY_SD_HOST_OCR_28_29_V |\
                                             CY_SD_HOST_OCR_27_28_V)
#define CY_SD_HOST_ARG_ACMD41_BUSY          (0x80000000UL)
#define CY_SD_HOST_OCR_BUSY_BIT             (0x80000000UL) /* The Card power up status bit (busy). */
#define CY_SD_HOST_OCR_CAPACITY_MASK        (0x40000000UL) /* The OCR sector access mode bit. */
#define CY_SD_HOST_ACMD_OFFSET_MASK         (0x3FUL)
#define CY_SD_HOST_EMMC_DUAL_VOLTAGE        (0x00000080UL)
#define CY_SD_HOST_EMMC_VOLTAGE_WINDOW      (CY_SD_HOST_OCR_CAPACITY_MASK |\
                                             CY_SD_HOST_EMMC_DUAL_VOLTAGE |\
                                             CY_SD_HOST_ACMD41_VOLTAGE_MASK)

/* Other constants. */
#define CY_SD_HOST_SWITCH_FUNCTION_BIT      (31U)
#define CY_SD_HOST_DEFAULT_SPEED            (0UL)
#define CY_SD_HOST_HIGH_SPEED               (1UL)
#define CY_SD_HOST_SDR12_SPEED              (0UL)  /* The SDR12/Legacy speed. */
#define CY_SD_HOST_SDR25_SPEED              (1UL)  /* The SDR25/High Speed SDR speed. */
#define CY_SD_HOST_SDR50_SPEED              (2UL)  /* The SDR50 speed. */
#define CY_SD_HOST_EMMC_BUS_WIDTH_ADDR      (0xB7UL)
#define CY_SD_HOST_EMMC_HS_TIMING_ADDR      (0xB9UL)
#define CY_SD_HOST_CMD23_BLOCKS_NUM_MASK    (0xFFFFUL)
#define CY_SD_HOST_CMD23_RELIABLE_WRITE_POS (31U)
#define CY_SD_HOST_RCA_SHIFT                (16U)
#define CY_SD_HOST_RESPONSE_SIZE            (4U)
#define CY_SD_HOST_CID_SIZE                 (4U)
#define CY_SD_HOST_CSD_SIZE                 (4U)
#define CY_SD_HOST_SCR_BLOCKS               (8UL)
#define CY_SD_HOST_CSD_BLOCKS               (16UL)
#define CY_SD_HOST_SD_STATUS_BLOCKS         (64UL)
#define CY_SD_HOST_SWITCH_STATUS_LEN        (16UL)
#define CY_SD_HOST_PERI_FREQUENCY           (100000000UL)
#define CY_SD_HOST_FREQ_SEL_MSK             (0xFFUL)
#define CY_SD_HOST_UPPER_FREQ_SEL_POS       (8U)

/* CMD6 SWITCH command bitfields. */
#define CY_SD_HOST_EMMC_CMD6_ACCESS_OFFSET  (24U)
#define CY_SD_HOST_EMMC_CMD6_IDX_OFFSET     (16U)
#define CY_SD_HOST_EMMC_CMD6_VALUE_OFFSET   (8U)
#define CY_SD_HOST_EMMC_CMD6_CMD_SET_OFFSET (0U)

/* EMMC EXTCSD register bitfields. */
#define CY_SD_HOST_EXTCSD_SEC_COUNT         (53U)
#define CY_SD_HOST_EXTCSD_GENERIC_CMD6_TIME (62U)
#define CY_SD_HOST_EXTCSD_GENERIC_CMD6_TIME_MSK (0xFFUL)
#define CY_SD_HOST_EXTCSD_SIZE              (128U)

/* CSD register masks/positions. */
#define CY_SD_HOST_CSD_V1_C_SIZE_MSB_MASK   (0x00000003UL)
#define CY_SD_HOST_CSD_V1_C_SIZE_ISB_MASK   (0xFF000000UL)
#define CY_SD_HOST_CSD_V1_C_SIZE_LSB_MASK   (0x00C00000UL)
#define CY_SD_HOST_CSD_V1_C_SIZE_MSB_POS    (0U)
#define CY_SD_HOST_CSD_V1_C_SIZE_ISB_POS    (24U)
#define CY_SD_HOST_CSD_V1_C_SIZE_LSB_POS    (22U)
#define CY_SD_HOST_CSD_V1_C_SIZE_MSB_MULT   (10U)
#define CY_SD_HOST_CSD_V1_C_SIZE_ISB_MULT   (2U)
#define CY_SD_HOST_CSD_V1_C_SIZE_MULT_MASK  (0x00000380UL)
#define CY_SD_HOST_CSD_V1_C_SIZE_MULT_POS   (7U)
#define CY_SD_HOST_CSD_V1_READ_BL_LEN_MASK  (0x00000F00UL)
#define CY_SD_HOST_CSD_V1_READ_BL_LEN_POS   (8U)
#define CY_SD_HOST_CSD_V1_BL_LEN_512        (9UL)
#define CY_SD_HOST_CSD_V1_BL_LEN_1024       (10UL)
#define CY_SD_HOST_CSD_V1_BL_LEN_2048       (11UL)
#define CY_SD_HOST_CSD_V1_1024_SECT_FACTOR  (2UL)
#define CY_SD_HOST_CSD_V1_2048_SECT_FACTOR  (4UL)
#define CY_SD_HOST_CSD_V2_C_SIZE_POS        (8U)
#define CY_SD_HOST_CSD_V2_SECTOR_MULT       (10U)
#define CY_SD_HOST_CSD_TEMP_WRITE_PROTECT   (20U)
#define CY_SD_HOST_CSD_PERM_WRITE_PROTECT   (21U)
#define CY_SD_HOST_CSD_LSB_MASK             (0x000000FFUL)
#define CY_SD_HOST_CSD_ISBR_MASK            (0x0000FF00UL)
#define CY_SD_HOST_CSD_ISBL_MASK            (0x00FF0000UL)
#define CY_SD_HOST_CSD_MSB_MASK             (0xFF000000UL)
#define CY_SD_HOST_CSD_ISB_SHIFT            (16U)

/* CMD6 EXT_CSD access mode. */
#define CY_SD_HOST_EMMC_ACCESS_COMMAND_SET  (0x0U)
#define CY_SD_HOST_EMMC_ACCESS_SET_BITS     (0x1U)
#define CY_SD_HOST_EMMC_ACCESS_CLEAR_BITS   (0x2U)
#define CY_SD_HOST_EMMC_ACCESS_WRITE_BYTE   (0x3UL)

/* CCCR register values. */
#define CY_SD_HOST_CCCR_SPEED_CONTROL       (0x00013UL)
#define CY_SD_HOST_CCCR_IO_ABORT            (0x00006UL)
#define CY_SD_HOST_CCCR_SPEED_SHS_MASK      (0x1UL)
#define CY_SD_HOST_CCCR_SPEED_EHS_MASK      (0x2UL)
#define CY_SD_HOST_CCCR_SPEED_BSS0_MASK     (0x2UL)
#define CY_SD_HOST_CCCR_SPEED_BSS1_MASK     (0x4UL)
#define CY_SD_HOST_CCCR_BUS_INTERFACE_CTR   (0x00007UL)
#define CY_SD_HOST_CCCR_BUS_WIDTH_0         (0x1UL)
#define CY_SD_HOST_CCCR_BUS_WIDTH_1         (0x2UL)
#define CY_SD_HOST_CCCR_S8B                 (0x4UL)

/* SDMA constants. */
#define CY_SD_HOST_SDMA_BUF_BYTES_4K        (0x0U) /* 4K bytes SDMA Buffer Boundary. */
#define CY_SD_HOST_SDMA_BUF_BYTES_8K        (0x1U) /* 8K bytes SDMA Buffer Boundary. */
#define CY_SD_HOST_SDMA_BUF_BYTES_16K       (0x2U) /* 16K bytes SDMA Buffer Boundary. */
#define CY_SD_HOST_SDMA_BUF_BYTES_32K       (0x3U) /* 32K bytes SDMA Buffer Boundary. */
#define CY_SD_HOST_SDMA_BUF_BYTES_64K       (0x4U) /* 64K bytes SDMA Buffer Boundary. */
#define CY_SD_HOST_SDMA_BUF_BYTES_128K      (0x5U) /* 128K bytes SDMA Buffer Boundary. */
#define CY_SD_HOST_SDMA_BUF_BYTES_256K      (0x6U) /* 256K bytes SDMA Buffer Boundary. */
#define CY_SD_HOST_SDMA_BUF_BYTES_512K      (0x7U) /* 512K bytes SDMA Buffer Boundary. */

/* CMD38 arguments. */
#define CY_SD_HOST_ERASE                    (0x00000000UL)  /* The SD/eMMC Erase. */
#define CY_SD_HOST_SD_DISCARD               (0x00000001UL)  /* The SD Discard. */
#define CY_SD_HOST_SD_FULE                  (0x00000002UL)  /* The SD FULE. */
#define CY_SD_HOST_EMMC_DISCARD             (0x00000003UL)  /* The eMMC Discard. */
#define CY_SD_HOST_EMMC_SECURE_ERASE        (0x80000000UL)  /* The eMMC Secure Erase. */
#define CY_SD_HOST_EMMC_SECURE_TRIM_STEP_2  (0x80008000UL)  /* The eMMC Secure Trim Step 2. */
#define CY_SD_HOST_EMMC_SECURE_TRIM_STEP_1  (0x80000001UL)  /* The eMMC Secure Trim Step 1. */
#define CY_SD_HOST_EMMC_TRIM                (0x00000001UL)  /* The eMMC Trim. */

/* CMD52 constants. */
#define CY_SD_HOST_CMD52_RWFLAG_POS         (31U)          /* The CMD52 RW Flag position. */
#define CY_SD_HOST_CMD52_FUNCT_NUM_POS      (28U)          /* The CMD52 Function Number position. */
#define CY_SD_HOST_CMD52_FUNCT_NUM_MSK      (0x07UL)       /* The CMD52 Function Number mask. */
#define CY_SD_HOST_CMD52_RAWFLAG_POS        (27U)          /* The CMD52 Raw Flag position. */
#define CY_SD_HOST_CMD52_REG_ADDR_POS       (9U)           /* The CMD52 Register Address position. */
#define CY_SD_HOST_CMD52_REG_ADDR_MSK       (0x1FFFFUL)    /* The CMD52 Register Address mask. */
#define CY_SD_HOST_CMD52_DATA_MSK           (0xFFUL)       /* The CMD52 data mask. */

/* Interrupt masks. */
#define CY_SD_HOST_NORMAL_INT_MSK           (0x1FFFU)  /* The enabled Normal Interrupts. */
#define CY_SD_HOST_ERROR_INT_MSK            (0x07FFU)  /* The enabled Error Interrupts. */

/* SD output clock. */
#define CY_SD_HOST_CLK_400K                 (400UL * 1000UL)    /* 400 kHz. */
#define CY_SD_HOST_CLK_10M                  (10UL * 1000UL * 1000UL) /* 10 MHz. */
#define CY_SD_HOST_CLK_20M                  (20UL * 1000UL * 1000UL) /* 20 MHz. */

/** \endcond */

/** \cond PARAM_CHECK_MACROS */

#define CY_SD_HOST_FREQ_MAX                 (50000000UL)  /* The maximum clk frequency. */
#define CY_SD_HOST_IS_FREQ_VALID(frequency) ((0UL < (frequency)) && (CY_SD_HOST_FREQ_MAX >= (frequency)))

#define CY_SD_HOST_IS_SD_BUS_WIDTH_VALID(width)         ((CY_SD_HOST_BUS_WIDTH_1_BIT == (width)) || \
                                                         (CY_SD_HOST_BUS_WIDTH_4_BIT == (width)))

#define CY_SD_HOST_IS_EMMC_BUS_WIDTH_VALID(width)       ((CY_SD_HOST_BUS_WIDTH_1_BIT == (width)) || \
                                                         (CY_SD_HOST_BUS_WIDTH_4_BIT == (width)) || \
                                                         (CY_SD_HOST_BUS_WIDTH_8_BIT == (width)))

#define CY_SD_HOST_IS_BUS_WIDTH_VALID(width, cardType)  ((CY_SD_HOST_EMMC == (cardType)) ? \
                                                         CY_SD_HOST_IS_EMMC_BUS_WIDTH_VALID(width) : \
                                                         CY_SD_HOST_IS_SD_BUS_WIDTH_VALID(width))

#define CY_SD_HOST_IS_AUTO_CMD_VALID(cmd)               ((CY_SD_HOST_AUTO_CMD_NONE == (cmd)) || \
                                                         (CY_SD_HOST_AUTO_CMD_12 == (cmd)) || \
                                                         (CY_SD_HOST_AUTO_CMD_23 == (cmd)) || \
                                                         (CY_SD_HOST_AUTO_CMD_AUTO == (cmd)))

#define CY_SD_HOST_IS_TIMEOUT_VALID(timeout)            (CY_SD_HOST_MAX_TIMEOUT >= (timeout))

#define CY_SD_HOST_BLK_SIZE_MAX                         (2048UL)  /* The maximum block size. */
#define CY_SD_HOST_IS_BLK_SIZE_VALID(size)              (CY_SD_HOST_BLK_SIZE_MAX >= (size))

#define CY_SD_HOST_IS_ERASE_VALID(eraseType)            ((CY_SD_HOST_ERASE_ERASE == (eraseType)) || \
                                                         (CY_SD_HOST_ERASE_DISCARD == (eraseType)) || \
                                                         (CY_SD_HOST_ERASE_FULE == (eraseType)) || \
                                                         (CY_SD_HOST_ERASE_SECURE == (eraseType)) || \
                                                         (CY_SD_HOST_ERASE_SECURE_TRIM_STEP_2 == (eraseType)) || \
                                                         (CY_SD_HOST_ERASE_SECURE_TRIM_STEP_1 == (eraseType)) || \
                                                         (CY_SD_HOST_ERASE_TRIM == (eraseType)))

#define CY_SD_HOST_IS_CMD_IDX_VALID(cmd)                (0UL == ((cmd) & (uint32_t)~(CY_SD_HOST_ACMD_OFFSET_MASK | \
                                                                                     CY_SD_HOST_MMC_CMD_TAG | \
                                                                                     CY_SD_HOST_SD_ACMD_OFFSET)))

#define CY_SD_HOST_IS_DMA_VALID(dmaType)                ((CY_SD_HOST_DMA_SDMA == (dmaType)) || \
                                                         (CY_SD_HOST_DMA_ADMA2 == (dmaType)) || \
                                                         (CY_SD_HOST_DMA_ADMA2_ADMA3 == (dmaType)))

#define CY_SD_HOST_IS_SPEED_MODE_VALID(speedMode)       ((CY_SD_HOST_BUS_SPEED_DEFAULT == (speedMode)) || \
                                                         (CY_SD_HOST_BUS_SPEED_HIGHSPEED == (speedMode)) || \
                                                         (CY_SD_HOST_BUS_SPEED_SDR12_5 == (speedMode)) || \
                                                         (CY_SD_HOST_BUS_SPEED_SDR25 == (speedMode)) || \
                                                         (CY_SD_HOST_BUS_SPEED_SDR50 == (speedMode)) || \
                                                         (CY_SD_HOST_BUS_SPEED_EMMC_LEGACY == (speedMode)) || \
                                                         (CY_SD_HOST_BUS_SPEED_EMMC_HIGHSPEED_SDR == (speedMode)))

#define CY_SD_HOST_IS_DMA_WR_RD_VALID(dmaType)          ((CY_SD_HOST_DMA_SDMA == (dmaType)) || \
                                                         (CY_SD_HOST_DMA_ADMA2 == (dmaType)))

#define CY_SD_HOST_IS_CMD_TYPE_VALID(cmdType)            ((CY_SD_HOST_CMD_NORMAL == (cmdType)) || \
                                                         (CY_SD_HOST_CMD_SUSPEND == (cmdType)) || \
                                                         (CY_SD_HOST_CMD_RESUME == (cmdType)) || \
                                                         (CY_SD_HOST_CMD_ABORT == (cmdType)))

#define CY_SD_HOST_IS_RELIABLE_WRITE(cardType, rw)      ((CY_SD_HOST_EMMC != (cardType)) && \
                                                          (false == (rw)))

/** \endcond */

__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_eMMC_InitCard(SDHC_Type *base,
                                             cy_stc_sd_host_sd_card_config_t const *config,
                                             cy_stc_sd_host_context_t *context);
static cy_en_sd_host_status_t Cy_SD_Host_CmdRxData(SDHC_Type *base, cy_stc_sd_host_data_config_t *pcmd);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_CmdTxData(SDHC_Type *base, cy_stc_sd_host_data_config_t *pcmd);
static cy_en_sd_host_status_t Cy_SD_Host_OpsGoIdle(SDHC_Type *base);
static cy_en_sd_host_status_t Cy_SD_Host_OpsVoltageSwitch(SDHC_Type *base,
                                                          cy_stc_sd_host_context_t const *context);
static cy_en_sd_host_status_t Cy_SD_Host_OpsSwitchFunc(SDHC_Type *base,
                                                       uint32_t cmdArgument);
static cy_en_sd_host_status_t Cy_SD_Host_SdCardSwitchFunc(SDHC_Type *base, uint32_t cmdArgument,
                                                                     cy_en_sd_host_card_type_t cardType);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_OpsSetBlockCount(SDHC_Type *base,
                                                                   bool reliableWrite,
                                                                   uint32_t blockNum);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_OpsProgramCsd(SDHC_Type *base,
                                                                uint32_t csd,
                                                                cy_stc_sd_host_context_t *context);
static cy_en_sd_host_status_t Cy_SD_Host_OpsSelectCard(SDHC_Type *base,
                                                      cy_stc_sd_host_context_t const *context);
static cy_en_sd_host_status_t Cy_SD_Host_OpsSendIoRwDirectCmd(SDHC_Type *base,
                                                            uint32_t rwFlag,
                                                            uint32_t functionNumber,
                                                            uint32_t rawFlag,
                                                            uint32_t registerAddress,
                                                            uint32_t data);
static cy_en_sd_host_status_t Cy_SD_Host_OpsSendAppCmd(SDHC_Type *base,
                                                       cy_stc_sd_host_context_t const *context);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_OpsSendIfCond(SDHC_Type *base,
                                                       uint32_t cmdArgument,
                                                       bool noResponse);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_OpsSetSdBusWidth(SDHC_Type *base,
                                                        uint32_t cmdArgument,
                                                        cy_stc_sd_host_context_t const *context);
static cy_en_sd_host_status_t Cy_SD_Host_OpsSdioSendOpCond(SDHC_Type *base,
                                                           uint32_t *ocrReg,
                                                           uint32_t cmdArgument);
static cy_en_sd_host_status_t Cy_SD_Host_OpsSdSendOpCond(SDHC_Type *base,
                                                        uint32_t *ocrReg,
                                                        uint32_t cmdArgument,
                                                        cy_stc_sd_host_context_t const *context);
static cy_en_sd_host_status_t Cy_SD_Host_MmcOpsSendOpCond(SDHC_Type *base,
                                                        uint32_t *ocrReg,
                                                        uint32_t cmdArgument);
static cy_en_sd_host_status_t Cy_SD_Host_SdCardChangeClock(SDHC_Type *base, uint32_t frequency);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollBufferReadReady(SDHC_Type *base);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollBufferWriteReady(SDHC_Type *base);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollCmdComplete(SDHC_Type *base);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollTransferComplete(SDHC_Type *base);
static void Cy_SD_Host_ErrorReset(SDHC_Type *base);
static void Cy_SD_Host_NormalReset(SDHC_Type *base);
__STATIC_INLINE bool Cy_SD_Host_VoltageCheck(SDHC_Type *base);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_IoOcr(SDHC_Type *base,
                                      bool lowVoltageSignaling,
                                      uint32_t *s18aFlag,
                                      uint32_t *sdioFlag,
                                      bool *mpFlag,
                                      uint32_t *ocrReg);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_SdOcr(SDHC_Type *base,
                                      bool lowVoltageSignaling,
                                      uint32_t *s18aFlag,
                                      bool *mpFlag,
                                      bool f8Flag,
                                      uint32_t *ocrReg,
                                      cy_stc_sd_host_context_t *context);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollCmdLineFree(SDHC_Type const *base);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollDataLineNotInhibit(SDHC_Type const *base);
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollDataLineFree(SDHC_Type const *base);

/* High-level section */

/*******************************************************************************
* Function Name: Cy_SD_Host_eMMC_InitCard
****************************************************************************//**
*
*  Initializes the eMMC card.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *config
*     The pointer to the SD card configuration structure.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_eMMC_InitCard(SDHC_Type *base,
                                                       cy_stc_sd_host_sd_card_config_t const *config,
                                                       cy_stc_sd_host_context_t *context)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_SUCCESS;
    cy_en_sd_host_bus_speed_mode_t speedMode = CY_SD_HOST_BUS_SPEED_EMMC_LEGACY;
    uint32_t retry;
    uint32_t ocrReg; /* The Operation Condition register. */
    uint32_t cidReg[CY_SD_HOST_CID_SIZE];  /* The Device Identification register. */
    uint32_t extCsd[CY_SD_HOST_EXTCSD_SIZE] = { 0UL };
    uint32_t genericCmd6Time;
    uint32_t csdReg[CY_SD_HOST_CSD_SIZE]; /* The Card-Specific Data register. */

    /* Reset Card (CMD0). */
    ret = Cy_SD_Host_OpsGoIdle(base); /* The Idle state. */

    /* Software reset for the CMD line */
    Cy_SD_Host_SoftwareReset(base, CY_SD_HOST_RESET_DATALINE);
    Cy_SD_Host_SoftwareReset(base, CY_SD_HOST_RESET_CMD_LINE);

    retry = CY_SD_HOST_RETRY_TIME;
    while (retry > 0UL)
    {
        /* Get OCR (CMD1). */
        ret = Cy_SD_Host_MmcOpsSendOpCond(base, &ocrReg, CY_SD_HOST_EMMC_VOLTAGE_WINDOW);

        context->cardCapacity = CY_SD_HOST_EMMC_LESS_2G;

        /* Check if the eMMC capacity is greater than 2GB */
        if (CY_SD_HOST_OCR_CAPACITY_MASK == (ocrReg & CY_SD_HOST_OCR_CAPACITY_MASK))
        {
            context->cardCapacity = CY_SD_HOST_EMMC_GREATER_2G;
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            break;
        }
        else
        {
            Cy_SD_Host_ErrorReset(base);

            Cy_SysLib_DelayUs(CY_SD_HOST_CMD1_TIMEOUT_MS); /* The CMD1 timeout. */
        }
        retry--;
    }

    /* The low voltage operation check. */
    if ((true == config->lowVoltageSignaling) &&
        (CY_SD_HOST_EMMC_DUAL_VOLTAGE == (ocrReg & CY_SD_HOST_EMMC_DUAL_VOLTAGE)))
    {
        /* Power down the MMC bus */
        Cy_SD_Host_DisableCardVoltage(base);

        Cy_SysLib_Delay(CY_SD_HOST_1_8_REG_STABLE_TIME_MS);

        /* Switch the bus to 1.8 V */
        Cy_SD_Host_ChangeIoVoltage(base, CY_SD_HOST_IO_VOLT_1_8V);

        Cy_SD_Host_EnableCardVoltage(base);
        (void)Cy_SD_Host_SdCardChangeClock(base, CY_SD_HOST_CLK_400K);

        /* Wait 10 ms */
        Cy_SysLib_Delay(CY_SD_HOST_1_8_REG_STABLE_TIME_MS);

        retry = CY_SD_HOST_RETRY_TIME;
        while (retry > 0UL)
        {
            /* Get OCR (CMD1). */
            ret = Cy_SD_Host_MmcOpsSendOpCond(base, &ocrReg, CY_SD_HOST_EMMC_VOLTAGE_WINDOW);

            Cy_SD_Host_ErrorReset(base);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                break;
            }

            Cy_SysLib_DelayUs(CY_SD_HOST_CMD1_TIMEOUT_MS); /* The CMD1 timeout. */
            retry--;
        }
    }

    if (CY_SD_HOST_SUCCESS == ret) /* The ready state. */
    {
        /* Get CID (CMD2). */
        ret = Cy_SD_Host_GetCid(base, cidReg);

        Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

        if (CY_SD_HOST_SUCCESS == ret) /* The Identification state. */
        {
            /* Get RCA (CMD3) */
            context->RCA = Cy_SD_Host_GetRca(base);

            /* The stand-by state. */

            /* Get CSD (CMD9)  */
            ret = Cy_SD_Host_GetCsd(base, csdReg, context);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                /* Select the card (CMD7). */
                ret = Cy_SD_Host_OpsSelectCard(base, context);

                if (CY_SD_HOST_SUCCESS == ret) /* The transfer state. */
                {
                    /* Get Ext CSD (CMD8).
                    * Capacity Type and Max Sector Num are in the context.
                    */
                    ret = Cy_SD_Host_GetExtCsd(base, extCsd, context);

                    /* Get GENERIC_CMD6_TIME [248] of the EXTCSD register */
                    genericCmd6Time = CY_SD_HOST_EMMC_CMD6_TIMEOUT_MULT *
                                      (extCsd[CY_SD_HOST_EXTCSD_GENERIC_CMD6_TIME] &
                                       CY_SD_HOST_EXTCSD_GENERIC_CMD6_TIME_MSK);

                    if ((CY_SD_HOST_SUCCESS == ret) &&
                        (CY_SD_HOST_BUS_WIDTH_1_BIT != config->busWidth))
                    {
                            /* Set Bus Width (CMD6) */
                            ret = Cy_SD_Host_SetBusWidth(base,
                                                         config->busWidth,
                                                         context);

                            Cy_SysLib_Delay(genericCmd6Time); /* The CMD6 timeout. */
                    }

                    if (CY_SD_HOST_SUCCESS == ret)
                    {
                        /* Set Bus Speed Mode (CMD6). */
                        ret = Cy_SD_Host_SetBusSpeedMode(base,
                                                         speedMode,
                                                         context);
                        if (CY_SD_HOST_SUCCESS == ret)
                        {
                            (void)Cy_SD_Host_SdCardChangeClock(base, CY_SD_HOST_CLK_25M);
                        }
                        Cy_SysLib_Delay(CY_SD_HOST_CLK_RAMP_UP_TIME_MS);
                    }
                }
            }
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_InitCard
****************************************************************************//**
*
*  Initializes a card if it is connected.
*  After this function is called, the card is in the transfer state.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *config
*     The pointer to the SD card configuration structure.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
* \note When lowVoltageSignaling is True, this function negotiates with
* the card to change the bus signaling level to 1.8V.
* The dedicated io_volt_sel pin is used to change the regulator supplying voltage
* to the VDDIO of the SD block in order to operate at 1.8V. To configure
* the custom IO pin in order to control (using the GPIO driver) the regulator
* supplying voltage, the user must implement weak Cy_SD_Host_ChangeIoVoltage().
* Also, this function must set the SIGNALING_EN bit of the SDHC_CORE_HOST_CTRL2_R
* register when ioVoltage = CY_SD_HOST_IO_VOLT_1_8V.
*
* \note After calling this function, the SD Host is configured in
* Default Speed mode (for the SD card), or SDR12 Speed mode
* (when lowVoltageSignaling is true), or eMMC legacy (for the eMMC card)
* with SD clock = 25 MHz. The Power Limit and Driver Strength functions of
* the CMD6 command are set into the default state (0.72 W and Type B).
* It is the user's responsibility to set Power Limit and Driver Strength
* depending on the capacitance load of the host system.
* To change Speed mode, the user must call the Cy_SD_Host_SetBusSpeedMode()
* and Cy_SD_Host_SdCardChangeClock() functions.
* Additionally, SD SDR25, SD SDR50, eMMC High Speed SDR modes require
* settings CLOCK_OUT_DLY and CLOCK_IN_DLY bit-fields of the GP_OUT_R register.
* For more information about Speed modes, refer to Part 1 Physical Layer
* SD Specification.
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_InitCard(SDHC_Type *base,
                                           cy_stc_sd_host_sd_card_config_t *config,
                                           cy_stc_sd_host_context_t *context)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    cy_en_sd_host_bus_speed_mode_t speedMode = CY_SD_HOST_BUS_SPEED_DEFAULT;
    uint32_t ocrReg; /* The Operation Condition register. */
    uint32_t cidReg[CY_SD_HOST_CID_SIZE]; /* The Device Identification register. */
    uint32_t csdReg[CY_SD_HOST_CSD_SIZE]; /* The Card-Specific Data register. */
    uint32_t sdioFlag = 0UL; /* The IO flag. */
    uint32_t s18aFlag = 0UL; /* The S18A flag. */
    bool f8Flag = false; /* The CMD8 flag. */
    bool mpFlag = false; /* The MEM flag. */

    if ((NULL != base) && (NULL != context) && (NULL != config))
    {
        CY_ASSERT_L3(CY_SD_HOST_IS_BUS_WIDTH_VALID(config->busWidth, context->cardType));

        /* Wait until the card is stable and check if it is connected. */
        if ((true == Cy_SD_Host_IsCardConnected(base)) ||
            (CY_SD_HOST_EMMC == context->cardType))
        {
            Cy_SD_Host_EnableCardVoltage(base);

            Cy_SD_Host_ChangeIoVoltage(base, CY_SD_HOST_IO_VOLT_3_3V);

            /* Set the host bus width to 1 bit. */
            (void)Cy_SD_Host_SetHostBusWidth(base, CY_SD_HOST_BUS_WIDTH_1_BIT);

            /* Change the host SD clock to 400 kHz. */
            (void)Cy_SD_Host_SdCardChangeClock(base, CY_SD_HOST_CLK_400K);

            /* Wait until the voltage and clock are stable. */
            Cy_SysLib_Delay(CY_SD_HOST_BUS_RAMP_UP_TIME_MS);

            context->RCA = 0UL;

            if (CY_SD_HOST_EMMC != context->cardType)
            {
                /* Send CMD0 and CMD8 commands. */
                f8Flag = Cy_SD_Host_VoltageCheck(base);

                /* Set SDHC can be supported. */
                if (f8Flag)
                {
                    context->cardCapacity = CY_SD_HOST_SDHC;
                }

                /* Clear the insert event */
                Cy_SD_Host_NormalReset(base);
                Cy_SysLib_Delay(1);

                /* Send CMD5 to get IO OCR */
                ret = Cy_SD_Host_IoOcr(base,
                                       config->lowVoltageSignaling,
                                       &s18aFlag,
                                       &sdioFlag,
                                       &mpFlag,
                                       &ocrReg);

                /* Check if CMD5 has no response or MP = 1.
                *  This means we have a SD memory card or Combo card.
                */
                if (mpFlag || (0UL == sdioFlag))
                {
                    /* Send ACMD41 */
                    ret = Cy_SD_Host_SdOcr(base,
                                           config->lowVoltageSignaling,
                                           &s18aFlag,
                                           &mpFlag,
                                           f8Flag,
                                           &ocrReg,
                                           context);
                }

                /* Set the card type */
                if (CY_SD_HOST_ERROR_UNUSABLE_CARD != ret) /* The Ready state. */
                {
                    if (true == mpFlag)
                    {
                        if (0UL != sdioFlag)
                        {
                            context->cardType = CY_SD_HOST_COMBO;
                        }
                        else
                        {
                            context->cardType = CY_SD_HOST_SD;
                        }
                    }
                    else if (0UL != sdioFlag)
                    {
                        context->cardType = CY_SD_HOST_SDIO;
                    }
                    else
                    {
                        /* The unusable card */
                        ret = CY_SD_HOST_ERROR_UNUSABLE_CARD;

                        context->cardType = CY_SD_HOST_UNUSABLE;
                    }

                    if (CY_SD_HOST_ERROR_UNUSABLE_CARD != ret)
                    {
                        if ((1UL == s18aFlag) && (config->lowVoltageSignaling))
                        {
                            /* Voltage switch (CMD11). */
                            ret =  Cy_SD_Host_OpsVoltageSwitch(base, context);

                            if (CY_SD_HOST_SUCCESS != ret)  /* Initialize again at 3.3 V. */
                            {
                                Cy_SD_Host_ChangeIoVoltage(base, CY_SD_HOST_IO_VOLT_3_3V);

                                /* Wait until the voltage and clock are stable. */
                                Cy_SysLib_Delay(CY_SD_HOST_BUS_RAMP_UP_TIME_MS);

                                /* Send CMD0 and CMD8 commands. */
                                f8Flag = Cy_SD_Host_VoltageCheck(base);

                                if (0UL < sdioFlag)
                                {
                                    /* Send CMD5 to get IO OCR. */
                                    ret = Cy_SD_Host_IoOcr(base,
                                                           config->lowVoltageSignaling,
                                                           &s18aFlag,
                                                           &sdioFlag,
                                                           &mpFlag,
                                                           &ocrReg);
                                }

                                if (mpFlag)
                                {
                                    /* Send ACMD41 */
                                    ret = Cy_SD_Host_SdOcr(base,
                                                           config->lowVoltageSignaling,
                                                           &s18aFlag,
                                                           &mpFlag,
                                                           f8Flag,
                                                           &ocrReg,
                                                           context);
                                }

                                s18aFlag = 0UL;
                            }
                        }

                        if (CY_SD_HOST_SDIO != context->cardType)
                        {
                            /* Get CID (CMD2).  */
                            ret = Cy_SD_Host_GetCid(base, cidReg);

                            Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);
                        }                                       /* The Identification state. */

                        /* Get RCA (CMD3). */
                        context->RCA = Cy_SD_Host_GetRca(base);

                        Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

                        if (CY_SD_HOST_SDIO != context->cardType) /* The stand-by state. */
                        {
                            /* Get CSD (CMD9) to save
                             * Max Sector Number in the context.
                             */
                            ret = Cy_SD_Host_GetCsd(base, csdReg, context);

                            if (CY_SD_HOST_MIN_SDXC_SECTORS <= context->maxSectorNum)
                            {
                               context->cardCapacity = CY_SD_HOST_SDXC;
                            }

                            Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);
                        }

                        if (CY_SD_HOST_SUCCESS == ret) /* The Standby state. */
                        {
                            /* Select the card (CMD7). */
                            ret = Cy_SD_Host_OpsSelectCard(base, context);
                        }

                        if ((CY_SD_HOST_SUCCESS == ret) &&
                            (CY_SD_HOST_SDIO != context->cardType)) /* The Transition state. */
                        {
                            /* Set Bus Width (ACMD6). */
                            if (CY_SD_HOST_BUS_WIDTH_1_BIT != config->busWidth)
                            {
                                ret = Cy_SD_Host_SetBusWidth(base,
                                                             CY_SD_HOST_BUS_WIDTH_4_BIT,
                                                             context);
                                Cy_SysLib_Delay(CY_SD_HOST_READ_TIMEOUT_MS);
                            }

                            if (CY_SD_HOST_SUCCESS == ret)
                            {
                                if ((1UL == s18aFlag) && (config->lowVoltageSignaling))
                                {
                                    speedMode = CY_SD_HOST_BUS_SPEED_SDR12_5;
                                }

                                /* Set Bus Speed Mode (CMD6). */
                                ret = Cy_SD_Host_SetBusSpeedMode(base,
                                                                 speedMode,
                                                                 context);
                                Cy_SysLib_Delay(CY_SD_HOST_READ_TIMEOUT_MS);

                                if (CY_SD_HOST_SUCCESS == ret)
                                {
                                    (void)Cy_SD_Host_SdCardChangeClock(base,
                                                                       CY_SD_HOST_CLK_25M);
                                }
                                Cy_SysLib_Delay(CY_SD_HOST_CLK_RAMP_UP_TIME_MS);
                            }
                        }
                    }
                }
            }
            else
            {
                ret = Cy_SD_Host_eMMC_InitCard(base, config, context);
            }

            *config->rca = context->RCA;
            *config->cardType = context->cardType;
            *config->cardCapacity = context->cardCapacity;
        }
        else
        {
            /* The SD card is disconnected or an embedded card. */
            ret = CY_SD_HOST_ERROR_DISCONNECTED;
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_Read
****************************************************************************//**
*
*  Reads single- or multiple-block data from the SD card / eMMC. If DMA is not used
*  this function blocks until all data is read.
*  If DMA is used all data is read when the Transfer complete event is set.
*  It is the user responsibility to check and reset the transfer complete event
*  (using \ref Cy_SD_Host_GetNormalInterruptStatus and
*  \ref Cy_SD_Host_ClearNormalInterruptStatus functions).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *config
*     The pointer to the SD card read-write structure.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_Read(SDHC_Type *base,
                                       cy_stc_sd_host_write_read_config_t *config,
                                       cy_stc_sd_host_context_t const *context)
{
    cy_en_sd_host_status_t       ret  = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    cy_stc_sd_host_cmd_config_t  cmd;
    cy_stc_sd_host_data_config_t dataConfig;
    uint32_t                     dataAddress;
    uint32_t aDmaDescriptTbl[CY_SD_HOST_ADMA2_DESCR_SIZE]; /* The ADMA2 descriptor table. */
    uint32_t length; /* The length of data to transfer for a descriptor. */

    if ((NULL != context) && (NULL != config) && (NULL != config->data))
    {
        CY_ASSERT_L3(CY_SD_HOST_IS_AUTO_CMD_VALID(config->autoCommand));
        CY_ASSERT_L2(CY_SD_HOST_IS_TIMEOUT_VALID(config->dataTimeout));
        CY_ASSERT_L3(CY_SD_HOST_IS_DMA_WR_RD_VALID(context->dmaType));

        dataAddress = config->address;
        /* 0 < maxSectorNum check is needed for legacy cards. */
        if (!((0UL < context->maxSectorNum) &&
             ((context->maxSectorNum - dataAddress) < config->numberOfBlocks)))
        {
            if (CY_SD_HOST_SDSC == context->cardCapacity)
            {
                dataAddress = dataAddress << CY_SD_HOST_SDSC_ADDR_SHIFT;
            }

            if (1UL < config->numberOfBlocks)
            {
                cmd.commandIndex = CY_SD_HOST_SD_CMD18;
                dataConfig.enableIntAtBlockGap = true;
            }
            else
            {
                cmd.commandIndex = CY_SD_HOST_SD_CMD17;
                dataConfig.enableIntAtBlockGap = false;
            }

            dataConfig.blockSize = CY_SD_HOST_BLOCK_SIZE;
            dataConfig.numberOfBlock = config->numberOfBlocks;
            dataConfig.enableDma = config->enableDma;
            dataConfig.autoCommand = config->autoCommand;
            dataConfig.read = true;
            dataConfig.dataTimeout = config->dataTimeout;
            dataConfig.enReliableWrite = config->enReliableWrite;

            if ((true == dataConfig.enableDma) &&
                (CY_SD_HOST_DMA_ADMA2 == context->dmaType))
            {
                length = CY_SD_HOST_BLOCK_SIZE * config->numberOfBlocks;

                aDmaDescriptTbl[0] = (1UL << CY_SD_HOST_ADMA_ATTR_VALID_POS) | /* Attr Valid */
                                     (1UL << CY_SD_HOST_ADMA_ATTR_END_POS) |   /* Attr End */
                                     (0UL << CY_SD_HOST_ADMA_ATTR_INT_POS) |   /* Attr Int */
                                     (CY_SD_HOST_ADMA_TRAN << CY_SD_HOST_ADMA_ACT_POS) |
                                     (length << CY_SD_HOST_ADMA_LEN_POS);     /* Len */

                aDmaDescriptTbl[1] = (uint32_t)config->data;

                /* The address of the ADMA2 descriptor table. */
                dataConfig.data = (uint32_t*)&aDmaDescriptTbl[0];
            }
            else
            {
                /* SDMA mode. */
                dataConfig.data = (uint32_t*)config->data;
            }

            ret = Cy_SD_Host_InitDataTransfer(base, &dataConfig);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                cmd.commandArgument = dataAddress;
                cmd.dataPresent     = true;
                cmd.enableAutoResponseErrorCheck = false;
                cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
                cmd.enableCrcCheck  = true;
                cmd.enableIdxCheck  = true;
                cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

                ret = Cy_SD_Host_SendCommand(base, &cmd);

                if (CY_SD_HOST_SUCCESS == ret)
                {
                    /* Wait for the Command Complete event. */
                    ret = Cy_SD_Host_PollCmdComplete(base);
                }

                if ((CY_SD_HOST_SUCCESS == ret) &&
                    (false == dataConfig.enableDma))
                {
                    /* DMA is not used - wait until all data is read. */
                    ret = Cy_SD_Host_CmdRxData(base, &dataConfig);
                }
            }
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_Write
****************************************************************************//**
*
*  Writes single- or multiple-block data to the SD card / eMMC. If DMA is not
*  used this function blocks until all data is written.
*  If DMA is used all data is written when the Transfer complete event is set.
*  It is the user responsibility to check and reset the transfer complete event
*  (using \ref Cy_SD_Host_GetNormalInterruptStatus and
*  \ref Cy_SD_Host_ClearNormalInterruptStatus functions).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *config
*     The pointer to the SD card read-write structure.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_Write(SDHC_Type *base,
                                        cy_stc_sd_host_write_read_config_t *config,
                                        cy_stc_sd_host_context_t const *context)
{
    cy_en_sd_host_status_t       ret  = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    cy_stc_sd_host_cmd_config_t  cmd;
    cy_stc_sd_host_data_config_t dataConfig;
    uint32_t                     dataAddress;
    uint32_t aDmaDescriptTbl[CY_SD_HOST_ADMA2_DESCR_SIZE]; /* The ADMA2 descriptor table. */
    uint32_t length;  /* The length of data to transfer for a descriptor. */

    if ((NULL != context) && (NULL != config) && (NULL != config->data))
    {
        CY_ASSERT_L3(CY_SD_HOST_IS_AUTO_CMD_VALID(config->autoCommand));
        CY_ASSERT_L2(CY_SD_HOST_IS_TIMEOUT_VALID(config->dataTimeout));
        CY_ASSERT_L3(CY_SD_HOST_IS_DMA_WR_RD_VALID(context->dmaType));

        dataAddress = config->address;

        /* 0 < maxSectorNum check is needed for legacy cards */
        if (!((0UL < context->maxSectorNum) &&
             ((context->maxSectorNum - dataAddress) < config->numberOfBlocks)))
        {
            if (CY_SD_HOST_SDSC == context->cardCapacity)
            {
                /* The SDSC card uses a byte-unit address, multiply by 512 */
                dataAddress = dataAddress << CY_SD_HOST_SDSC_ADDR_SHIFT;
            }

            if (1UL < config->numberOfBlocks)
            {
                cmd.commandIndex = CY_SD_HOST_SD_CMD25;
                dataConfig.enableIntAtBlockGap = true;
            }
            else
            {
                cmd.commandIndex = CY_SD_HOST_SD_CMD24;
                dataConfig.enableIntAtBlockGap = false;
            }

            dataConfig.blockSize = CY_SD_HOST_BLOCK_SIZE;
            dataConfig.numberOfBlock = config->numberOfBlocks;
            dataConfig.enableDma = config->enableDma;
            dataConfig.autoCommand = config->autoCommand;
            dataConfig.read = false;
            dataConfig.data = (uint32_t*)config->data;
            dataConfig.dataTimeout = config->dataTimeout;
            dataConfig.enReliableWrite = config->enReliableWrite;

            if ((true == dataConfig.enableDma) &&
                (CY_SD_HOST_DMA_ADMA2 == context->dmaType))
            {
                length = CY_SD_HOST_BLOCK_SIZE * config->numberOfBlocks;

                aDmaDescriptTbl[0] = (1UL << CY_SD_HOST_ADMA_ATTR_VALID_POS) | /* Attr Valid */
                                     (1UL << CY_SD_HOST_ADMA_ATTR_END_POS) |   /* Attr End */
                                     (0UL << CY_SD_HOST_ADMA_ATTR_INT_POS) |   /* Attr Int */
                                     (CY_SD_HOST_ADMA_TRAN << CY_SD_HOST_ADMA_ACT_POS) |
                                     (length << CY_SD_HOST_ADMA_LEN_POS);     /* Len */

                aDmaDescriptTbl[1] = (uint32_t)config->data;

                /* The address of the ADMA descriptor table. */
                dataConfig.data = (uint32_t*)&aDmaDescriptTbl[0];
            }
            else
            {
                dataConfig.data = (uint32_t*)config->data;
            }

            ret = Cy_SD_Host_InitDataTransfer(base, &dataConfig);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                cmd.commandArgument = dataAddress;
                cmd.dataPresent     = true;
                cmd.enableAutoResponseErrorCheck = false;
                cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
                cmd.enableCrcCheck  = true;
                cmd.enableIdxCheck  = true;
                cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

                ret = Cy_SD_Host_SendCommand(base, &cmd);

                if (CY_SD_HOST_SUCCESS == ret)
                {
                    /* Wait for the Command Complete event. */
                    ret = Cy_SD_Host_PollCmdComplete(base);
                }

                if ((CY_SD_HOST_SUCCESS == ret) &&
                    (false == dataConfig.enableDma))
                {
                    /* DMA is not used - wait until all data is written. */
                    ret = Cy_SD_Host_CmdTxData(base, &dataConfig);
                }
            }
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_Erase
****************************************************************************//**
*
*  Erases the number block data of the SD card / eMMC.
*
* \note This function starts the erase operation end exits.
* It is the user's responsibility to check when the erase operation completes.
* The erase operation completes when ref\ Cy_SD_Host_GetCardStatus returns
* the status value where both ready-for-data (CY_SD_HOST_CMD13_READY_FOR_DATA)
* and card-transition (CY_SD_HOST_CARD_TRAN) bits are set.
* Also it is the user's responsibility to clear the CY_SD_HOST_CMD_COMPLETE flag
* after calling this function.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param startAddr
*     The address to start erasing from.
*
* \param endAddr
*     The address to stop erasing.
*
* \param eraseType
*     Specifies the erase type (FULE, DISCARD).
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_Erase(SDHC_Type *base,
                                        uint32_t startAddr,
                                        uint32_t endAddr,
                                        cy_en_sd_host_erase_type_t eraseType,
                                        cy_stc_sd_host_context_t const *context)
{
    cy_en_sd_host_status_t      ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    cy_stc_sd_host_cmd_config_t cmd;

    if ((NULL != context) && (NULL != base))
    {
        /* 0<maxSectorNum check is needed for legacy EMMC cards */
        if (!((0UL < context->maxSectorNum) &&
              ((context->maxSectorNum < (startAddr)) ||
               (context->maxSectorNum < (endAddr)))))
        {
            /* Initialize the command parameters */
            cmd.dataPresent    = false;
            cmd.enableAutoResponseErrorCheck = false;
            cmd.respType       = CY_SD_HOST_RESPONSE_LEN_48;
            cmd.enableCrcCheck = true;
            cmd.enableIdxCheck = true;
            cmd.cmdType        = CY_SD_HOST_CMD_NORMAL;

            /* EraseStartAddr (CMD32) */
            if (CY_SD_HOST_SDSC == context->cardCapacity)
            {
                /* The SDSC card uses a byte-unit address, multiply by 512 */
                startAddr = startAddr << CY_SD_HOST_SDSC_ADDR_SHIFT;
            }

            if (CY_SD_HOST_EMMC == context->cardType)
            {
                cmd.commandIndex = CY_SD_HOST_SD_CMD35;
            }
            else
            {
                cmd.commandIndex = CY_SD_HOST_SD_CMD32;
            }
            cmd.commandArgument = startAddr;

            ret = Cy_SD_Host_SendCommand(base, &cmd);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                /* Wait for the Command Complete event. */
                ret = Cy_SD_Host_PollCmdComplete(base);
            }

            if (CY_SD_HOST_SUCCESS != ret)
            {
                return ret;
            }

            /* EraseEndAddr (CMD33) */
            if (CY_SD_HOST_SDSC == context->cardCapacity)
            {
                /* The SDSC card uses a byte-unit address, multiply by 512 */
                endAddr = endAddr << CY_SD_HOST_SDSC_ADDR_SHIFT;
            }

            if (CY_SD_HOST_EMMC == context->cardType)
            {
                cmd.commandIndex = CY_SD_HOST_SD_CMD36;
            }
            else
            {
                cmd.commandIndex = CY_SD_HOST_SD_CMD33;
            }
            cmd.commandArgument = endAddr;

            ret = Cy_SD_Host_SendCommand(base, &cmd);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                /* Wait for the Command Complete event. */
                ret = Cy_SD_Host_PollCmdComplete(base);
            }

            /* Erase (CMD38) */
            cmd.commandIndex = CY_SD_HOST_SD_CMD38;

            switch (eraseType)
            {
                case CY_SD_HOST_ERASE_ERASE:
                    cmd.commandArgument = CY_SD_HOST_ERASE;
                    break;
                case CY_SD_HOST_ERASE_DISCARD:
                    if (CY_SD_HOST_EMMC == context->cardType)
                    {
                        cmd.commandArgument = CY_SD_HOST_EMMC_DISCARD;
                    }
                    else
                    {
                        cmd.commandArgument = CY_SD_HOST_SD_DISCARD;
                    }
                    break;
                case CY_SD_HOST_ERASE_FULE:
                    cmd.commandArgument = CY_SD_HOST_SD_FULE;
                    break;
                case CY_SD_HOST_ERASE_SECURE:
                    cmd.commandArgument = CY_SD_HOST_EMMC_SECURE_ERASE;
                    break;
                case CY_SD_HOST_ERASE_SECURE_TRIM_STEP_2:
                    cmd.commandArgument = CY_SD_HOST_EMMC_SECURE_TRIM_STEP_2;
                    break;
                case CY_SD_HOST_ERASE_SECURE_TRIM_STEP_1:
                    cmd.commandArgument = CY_SD_HOST_EMMC_SECURE_TRIM_STEP_1;
                    break;
                case CY_SD_HOST_ERASE_TRIM:
                    cmd.commandArgument = CY_SD_HOST_EMMC_TRIM;
                    break;
                default:
                    ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
                    break;
            }

            if (CY_SD_HOST_SUCCESS == ret)
            {
               ret = Cy_SD_Host_SendCommand(base, &cmd);
            }
        }
    }

    return ret;
}

/* The commands low level section */

/*******************************************************************************
* Function Name: Cy_SD_Host_PollCmdLineFree
****************************************************************************//**
*
*  Waits for the command line free.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollCmdLineFree(SDHC_Type const *base)
{
    cy_en_sd_host_status_t ret   = CY_SD_HOST_ERROR_TIMEOUT;
    uint32_t               retry = CY_SD_HOST_RETRY_TIME;
    bool                   commandInhibit;

    while (retry > 0UL)
    {
        commandInhibit = _FLD2BOOL(SDHC_CORE_PSTATE_REG_CMD_INHIBIT,
                                   SDHC_CORE_PSTATE_REG(base));

        if (false == commandInhibit)
        {
            ret = CY_SD_HOST_SUCCESS;
            break;
        }

        Cy_SysLib_DelayUs(CY_SD_HOST_CMD_TIMEOUT_MS);
        retry--;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_PollDataLineNotInhibit
****************************************************************************//**
*
*  Waits for the data line is not inhibit.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollDataLineNotInhibit(SDHC_Type const *base)
{
    cy_en_sd_host_status_t ret   = CY_SD_HOST_ERROR_TIMEOUT;
    uint32_t               retry = CY_SD_HOST_RETRY_TIME;
    bool                   dataInhibit;

    while (retry > 0UL)
    {
        dataInhibit = _FLD2BOOL(SDHC_CORE_PSTATE_REG_CMD_INHIBIT_DAT,
                                SDHC_CORE_PSTATE_REG(base));

        if (false == dataInhibit)
        {
            ret = CY_SD_HOST_SUCCESS;
            break;
        }

        Cy_SysLib_DelayUs(CY_SD_HOST_CMD_TIMEOUT_MS);
        retry--;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_PollDataLineFree
****************************************************************************//**
*
*  Waits for the data line free.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollDataLineFree(SDHC_Type const *base)
{
    cy_en_sd_host_status_t ret   = CY_SD_HOST_SUCCESS;
    uint32_t               retry = CY_SD_HOST_RETRY_TIME;

    while ((true == _FLD2BOOL(SDHC_CORE_PSTATE_REG_DAT_LINE_ACTIVE, SDHC_CORE_PSTATE_REG(base))) &&
           (retry > 0UL))
    {
        Cy_SysLib_DelayUs(CY_SD_HOST_WRITE_TIMEOUT_MS);
        retry--;
    }

    if (true == _FLD2BOOL(SDHC_CORE_PSTATE_REG_DAT_LINE_ACTIVE, SDHC_CORE_PSTATE_REG(base)))
    {
        ret = CY_SD_HOST_ERROR_TIMEOUT;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_PollBufferReadReady
****************************************************************************//**
*
*  Waits for the Buffer Read ready event.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollBufferReadReady(SDHC_Type *base)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_TIMEOUT;
    uint32_t               retry = CY_SD_HOST_RETRY_TIME;

    while (retry > 0UL)
    {
        /* Check the Buffer Read ready */
        if (true == _FLD2BOOL(SDHC_CORE_NORMAL_INT_STAT_R_BUF_RD_READY,
                             SDHC_CORE_NORMAL_INT_STAT_R(base)))
        {
            /* Clear the interrupt flag */
             SDHC_CORE_NORMAL_INT_STAT_R(base) = CY_SD_HOST_BUF_RD_READY;

            ret = CY_SD_HOST_SUCCESS;
            break;
        }

        Cy_SysLib_DelayUs(CY_SD_HOST_BUFFER_RDY_TIMEOUT_MS);
        retry--;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_PollBufferWriteReady
****************************************************************************//**
*
*  Waits for the Buffer Write ready event.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollBufferWriteReady(SDHC_Type *base)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_TIMEOUT;
    uint32_t               retry = CY_SD_HOST_RETRY_TIME;

    while (retry > 0UL)
    {
        /* Check the Buffer Write ready */
        if (true == _FLD2BOOL(SDHC_CORE_NORMAL_INT_STAT_R_BUF_WR_READY,
                              SDHC_CORE_NORMAL_INT_STAT_R(base)))
        {
            /* Clear the interrupt flag */
             SDHC_CORE_NORMAL_INT_STAT_R(base) = CY_SD_HOST_BUF_WR_READY;

            ret = CY_SD_HOST_SUCCESS;
            break;
        }

        Cy_SysLib_DelayUs(CY_SD_HOST_BUFFER_RDY_TIMEOUT_MS);
        retry--;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_PollCmdComplete
****************************************************************************//**
*
*  Waits for the Command Complete event.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollCmdComplete(SDHC_Type *base)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_TIMEOUT;
    uint32_t               retry = CY_SD_HOST_RETRY_TIME;

    while (retry > 0UL)
    {
        /* Command Complete */
        if (true == _FLD2BOOL(SDHC_CORE_NORMAL_INT_STAT_R_CMD_COMPLETE,
                             SDHC_CORE_NORMAL_INT_STAT_R(base)))
        {
            /* Clear the interrupt flag */
             SDHC_CORE_NORMAL_INT_STAT_R(base) = CY_SD_HOST_CMD_COMPLETE;

            ret = CY_SD_HOST_SUCCESS;
            break;
        }

        Cy_SysLib_DelayUs(CY_SD_HOST_CMD_TIMEOUT_MS);
        retry--;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_PollTransferComplete
****************************************************************************//**
*
*  Waits for the Transfer Complete event.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_PollTransferComplete(SDHC_Type *base)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_TIMEOUT;
    uint32_t               retry = CY_SD_HOST_RETRY_TIME;

    while (retry > 0UL)
    {
        /* Transfer Complete */
        if (true == _FLD2BOOL(SDHC_CORE_NORMAL_INT_STAT_R_XFER_COMPLETE,
                             SDHC_CORE_NORMAL_INT_STAT_R(base)))
        {
            /* Clear the interrupt flag */
            SDHC_CORE_NORMAL_INT_STAT_R(base) = CY_SD_HOST_XFER_COMPLETE;

            ret = CY_SD_HOST_SUCCESS;
            break;
        }

        Cy_SysLib_DelayUs(CY_SD_HOST_WRITE_TIMEOUT_MS);
        retry--;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_CmdRxData
****************************************************************************//**
*
*  Reads the command data using a non-DMA data transfer.
*  This function is blocking (it exits after all data is read).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *pcmd
*     The pointer to the current command data structure.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_CmdRxData(SDHC_Type *base,
                                                   cy_stc_sd_host_data_config_t *pcmd)
{
    cy_en_sd_host_status_t ret;
    uint32_t               blkSize;
    uint32_t               blkCnt;
    uint32_t               i;
    uint32_t               retry;

    blkCnt = pcmd->numberOfBlock;
    blkSize = pcmd->blockSize;

    while (blkCnt > 0UL)
    {
        /* Wait for the Buffer Read ready. */
        ret = Cy_SD_Host_PollBufferReadReady(base);

        if (CY_SD_HOST_SUCCESS != ret)
        {
            break;
        }

        for ( i = blkSize >> 2UL; i != 0UL; i-- )
        {
            /* Wait if valid data exists in the Host buffer. */
            retry = CY_SD_HOST_RETRY_TIME;
            while ((false == _FLD2BOOL(SDHC_CORE_PSTATE_REG_BUF_RD_ENABLE,
                                      SDHC_CORE_PSTATE_REG(base))) &&
                   (retry > 0UL))
            {
                Cy_SysLib_DelayUs(CY_SD_HOST_RD_WR_ENABLE_TIMEOUT);
                retry--;
            }

            if (false == _FLD2BOOL(SDHC_CORE_PSTATE_REG_BUF_RD_ENABLE,
                                   SDHC_CORE_PSTATE_REG(base)))
            {
                break;
            }

            /* Read data from the Host buffer. */
            *pcmd->data = Cy_SD_Host_BufferRead(base);
            pcmd->data++;
        }
        blkCnt--;
    }

    /* Wait for the Transfer Complete. */
    ret = Cy_SD_Host_PollTransferComplete(base);

    (void)Cy_SD_Host_PollCmdLineFree(base);
    (void)Cy_SD_Host_PollDataLineNotInhibit(base);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_CmdTxData
****************************************************************************//**
*
*  Writes the command data using a non-DMA data transfer.
*  This function is blocking (it exits after all data is written).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *pcmd
*     The pointer to the current command data structure.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_CmdTxData(SDHC_Type *base,
                                                   cy_stc_sd_host_data_config_t *pcmd)
{
    cy_en_sd_host_status_t ret;
    uint32_t               blkSize;
    uint32_t               blkCnt;
    uint32_t               i;
    uint32_t               retry;

    blkCnt = pcmd->numberOfBlock;
    blkSize = pcmd->blockSize;

    while (0UL < blkCnt)
    {
        /* Wait for the Buffer Write ready. */
        ret = Cy_SD_Host_PollBufferWriteReady(base);

        if (CY_SD_HOST_SUCCESS != ret)
        {
            break;
        }

        for ( i = blkSize >> 2UL; i != 0UL; i-- )
        {
            /* Wait if space is available for writing data. */
            retry = CY_SD_HOST_RETRY_TIME;
            while ((false == _FLD2BOOL(SDHC_CORE_PSTATE_REG_BUF_WR_ENABLE,
                                      SDHC_CORE_PSTATE_REG(base))) &&
                   (retry > 0UL))
            {
                Cy_SysLib_DelayUs(CY_SD_HOST_RD_WR_ENABLE_TIMEOUT);
                retry--;
            }

            if (false == _FLD2BOOL(SDHC_CORE_PSTATE_REG_BUF_WR_ENABLE,
                                   SDHC_CORE_PSTATE_REG(base)))
            {
                break;
            }

            /* Write data to the Host buffer. */
            (void)Cy_SD_Host_BufferWrite(base, *pcmd->data);
            pcmd->data++;
        }
        blkCnt--;
    }

    ret = Cy_SD_Host_PollTransferComplete(base);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Check if DAT line is active. */
        ret = Cy_SD_Host_PollDataLineFree(base);
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SendCommand
****************************************************************************//**
*
*  Starts sending a command on the SD bus. If the command uses the data lines
*  Cy_SD_Host_InitDataTransfer() must be call first.
*  This function returns before the command completes.
*  To determine if the command is done, read the Normal Interrupt Status register
*  and check the CMD_COMPLETE flag. To determine if the entire transfer is done
*  check the XFER_COMPLETE flag. Also the interrupt is used and flags are set
*  on these events in an ISR.
* \note It is the user's responsibility to clear the CY_SD_HOST_CMD_COMPLETE flag
*  after calling this function.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *config
*  The configuration structure for the command.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_SendCommand(SDHC_Type *base,
                                              cy_stc_sd_host_cmd_config_t const *config)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_SUCCESS;

    if ((NULL != base) && (NULL != config))
    {
        CY_ASSERT_L2(CY_SD_HOST_IS_CMD_IDX_VALID(config->commandIndex));
        CY_ASSERT_L3(CY_SD_HOST_IS_CMD_TYPE_VALID(config->cmdType));

        ret = Cy_SD_Host_PollCmdLineFree(base);
        if (CY_SD_HOST_SUCCESS == ret)
        {
            if ((true == config->dataPresent) && (CY_SD_HOST_CMD_ABORT != config->cmdType))
            {
                /* Check the DAT line inhibits only commands with the DAT line is used
                * and when the command is not the ABORT type.
                */
                ret = Cy_SD_Host_PollDataLineNotInhibit(base);
            }

            if (CY_SD_HOST_SUCCESS == ret)
            {
                /* Set the commandArgument directly to the hardware register. */
                SDHC_CORE_ARGUMENT_R(base) = config->commandArgument;

                /* Update the command hardware register (the command is sent)
                * according to the spec, this register should be written only once.
                */
                SDHC_CORE_CMD_R(base) = (uint16_t)(_VAL2FLD(SDHC_CORE_CMD_R_CMD_TYPE, 0U) |
                                   _VAL2FLD(SDHC_CORE_CMD_R_RESP_TYPE_SELECT, (uint32_t)config->respType) |
                                   _VAL2FLD(SDHC_CORE_CMD_R_CMD_TYPE, (uint32_t)config->cmdType) |
                                   _VAL2FLD(SDHC_CORE_CMD_R_DATA_PRESENT_SEL, ((true == config->dataPresent) ? 1U : 0U)) |
                                   _VAL2FLD(SDHC_CORE_CMD_R_CMD_IDX_CHK_ENABLE, ((true == config->enableIdxCheck) ? 1U : 0U)) |
                                   _VAL2FLD(SDHC_CORE_CMD_R_CMD_CRC_CHK_ENABLE, ((true == config->enableCrcCheck) ? 1U : 0U)) |
                                   _VAL2FLD(SDHC_CORE_CMD_R_CMD_INDEX, config->commandIndex & CY_SD_HOST_ACMD_OFFSET_MASK));
            }
        }
    }
    else
    {
        ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SetBusWidth
****************************************************************************//**
*
*  Sends out the SD bus width changing command.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param width
*     The width of the data bus.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_SetBusWidth(SDHC_Type *base,
                                              cy_en_sd_host_bus_width_t width,
                                              cy_stc_sd_host_context_t const *context)
{
    cy_en_sd_host_status_t    ret = CY_SD_HOST_SUCCESS;
    uint32_t                  cmdArgument = 0UL;

    if ((NULL != base) && (NULL != context))
    {
        if (CY_SD_HOST_SD == context->cardType)
        {
            switch (width)
            {
                case CY_SD_HOST_BUS_WIDTH_1_BIT:
                    cmdArgument = 0UL;  /* 0 = 1bit */
                    break;
                case CY_SD_HOST_BUS_WIDTH_4_BIT:
                    cmdArgument = 2UL;  /* 2 = 4bit */
                    break;
                default:
                    ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
                    break;
            }

            if (CY_SD_HOST_SUCCESS == ret)
            {
                ret = Cy_SD_Host_OpsSetSdBusWidth(base, cmdArgument, context);
            }
        }
        else if (CY_SD_HOST_EMMC == context->cardType)
        {
            switch (width)
            {
                /* The CMD6 Argument data structure:
                 * [ACCESS:2]<<24 | [EXT_CSD IDX:8]<<16
                 * |[Value:8]<<8 | [CMD set:2]<<0
                 */
                case CY_SD_HOST_BUS_WIDTH_1_BIT:
                    cmdArgument = (CY_SD_HOST_EMMC_ACCESS_WRITE_BYTE << CY_SD_HOST_EMMC_CMD6_ACCESS_OFFSET) |
                                      (CY_SD_HOST_EMMC_BUS_WIDTH_ADDR << CY_SD_HOST_EMMC_CMD6_IDX_OFFSET) |
                                      (0x0UL << CY_SD_HOST_EMMC_CMD6_VALUE_OFFSET) |
                                      (0x0UL << CY_SD_HOST_EMMC_CMD6_CMD_SET_OFFSET);
                    break;
                case CY_SD_HOST_BUS_WIDTH_4_BIT:
                    cmdArgument = (CY_SD_HOST_EMMC_ACCESS_WRITE_BYTE << CY_SD_HOST_EMMC_CMD6_ACCESS_OFFSET) |
                                      (CY_SD_HOST_EMMC_BUS_WIDTH_ADDR << CY_SD_HOST_EMMC_CMD6_IDX_OFFSET) |
                                      (0x1UL << CY_SD_HOST_EMMC_CMD6_VALUE_OFFSET) |
                                      (0x0UL << CY_SD_HOST_EMMC_CMD6_CMD_SET_OFFSET);
                    break;
                case CY_SD_HOST_BUS_WIDTH_8_BIT:
                    cmdArgument = (CY_SD_HOST_EMMC_ACCESS_WRITE_BYTE << CY_SD_HOST_EMMC_CMD6_ACCESS_OFFSET) |
                                      (CY_SD_HOST_EMMC_BUS_WIDTH_ADDR << CY_SD_HOST_EMMC_CMD6_IDX_OFFSET) |
                                      (0x2UL << CY_SD_HOST_EMMC_CMD6_VALUE_OFFSET) |
                                      (0x0UL << CY_SD_HOST_EMMC_CMD6_CMD_SET_OFFSET);
                    break;
                default:
                    ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
                    break;
            }

            if (CY_SD_HOST_SUCCESS == ret)
            {
                /* Send CMD6 */
                ret = Cy_SD_Host_OpsSwitchFunc(base, cmdArgument);
            }
        }
        else if (CY_SD_HOST_SDIO == context->cardType)
        {
            switch (width)
            {
                case CY_SD_HOST_BUS_WIDTH_1_BIT:
                    cmdArgument = 0UL;
                    break;
                case CY_SD_HOST_BUS_WIDTH_4_BIT:
                    cmdArgument = CY_SD_HOST_CCCR_BUS_WIDTH_1;
                    break;
                case CY_SD_HOST_BUS_WIDTH_8_BIT:
                    cmdArgument = CY_SD_HOST_CCCR_BUS_WIDTH_0 |
                                  CY_SD_HOST_CCCR_BUS_WIDTH_1 |
                                  CY_SD_HOST_CCCR_S8B;
                    break;
                default:
                    ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
                    break;
            }

            if (CY_SD_HOST_SUCCESS == ret)
            {
                ret = Cy_SD_Host_OpsSendIoRwDirectCmd(base,
                                                      1UL,
                                                      0UL,
                                                      0UL,
                                                      CY_SD_HOST_CCCR_BUS_INTERFACE_CTR,
                                                      cmdArgument);
            }
        }
        else
        {
           ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Update the host side setting. */
            ret = Cy_SD_Host_SetHostBusWidth(base, width);
        }
    }
    else
    {
       ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsGoIdle
****************************************************************************//**
*
*  Send CMD0 (Go idle).
*
* \param *base
*     The SD host registers structure pointer.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_OpsGoIdle(SDHC_Type *base)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD0;
    cmd.commandArgument = 0UL;
    cmd.enableCrcCheck  = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_NONE;
    cmd.enableIdxCheck  = false;
    cmd.dataPresent     = false;
    cmd.cmdType         = CY_SD_HOST_CMD_ABORT;

    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsVoltageSwitch
****************************************************************************//**
*
*  Send CMD11 (Signal Voltage Switch to 1.8 V).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_OpsVoltageSwitch(SDHC_Type *base,
                                                          cy_stc_sd_host_context_t const *context)
{
    (void) context;
    cy_en_sd_host_status_t      ret;
    cy_stc_sd_host_cmd_config_t cmd;
    uint32_t                    pState;

    /* Voltage switch (CMD11). */
    cmd.commandIndex                 = CY_SD_HOST_SD_CMD11;
    cmd.commandArgument              = 0UL;
    cmd.enableCrcCheck               = true;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType                     = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableIdxCheck               = true;
    cmd.dataPresent                  = false;
    cmd.cmdType                      = CY_SD_HOST_CMD_NORMAL;

    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Disable providing the SD Clock. */
        Cy_SD_Host_DisableSdClk(base);

        pState = Cy_SD_Host_GetPresentState(base) & SDHC_CORE_PSTATE_REG_DAT_3_0_Msk;

        /* Check DAT[3:0]. */
        if (0UL == pState)
        {
            /* Switch the bus to 1.8 V (Set the IO_VOLT_SEL pin to low)*/
            Cy_SD_Host_ChangeIoVoltage(base, CY_SD_HOST_IO_VOLT_1_8V);

            /* Wait 10 ms to 1.8 voltage regulator to be stable. */
            Cy_SysLib_Delay(CY_SD_HOST_1_8_REG_STABLE_TIME_MS);

            /* Check the 1.8V signaling enable. */
            if (true == _FLD2BOOL(SDHC_CORE_HOST_CTRL2_R_SIGNALING_EN,
                                  SDHC_CORE_HOST_CTRL2_R(base)))
            {
                /* Enable providing the SD Clock. */
                Cy_SD_Host_EnableSdClk(base);

                /* Wait for the stable CLK */
                Cy_SysLib_Delay(CY_SD_HOST_CLK_RAMP_UP_TIME_MS);

                pState = Cy_SD_Host_GetPresentState(base) & SDHC_CORE_PSTATE_REG_DAT_3_0_Msk;

                /* Check DAT[3:0]. */
                if (SDHC_CORE_PSTATE_REG_DAT_3_0_Msk != pState)
                {
                    ret = CY_SD_HOST_ERROR_UNUSABLE_CARD;
                }
            }
            else
            {
                ret = CY_SD_HOST_ERROR_UNUSABLE_CARD;
            }
        }
        else
        {
            ret = CY_SD_HOST_ERROR_UNUSABLE_CARD;
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsSendIoRwDirectCmd
****************************************************************************//**
*
*  Sends CMD52 (Reads/writes 1 byte to the SDIO register).
*
* \param *base
*     The SD host registers structure pointer.
* \param rwFlag
* \param functionNumber
* \param rawFlag
* \param registerAddress
* \param data
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_OpsSendIoRwDirectCmd(SDHC_Type *base,
                                                uint32_t rwFlag,
                                                uint32_t functionNumber,
                                                uint32_t rawFlag,
                                                uint32_t registerAddress,
                                                uint32_t data)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD52;
    cmd.commandArgument = ((rwFlag & 0x01UL) << CY_SD_HOST_CMD52_RWFLAG_POS) |
                          ((functionNumber & CY_SD_HOST_CMD52_FUNCT_NUM_MSK) << CY_SD_HOST_CMD52_FUNCT_NUM_POS) |
                          ((rawFlag & 0x01UL) << CY_SD_HOST_CMD52_RAWFLAG_POS) |
                          ((registerAddress & CY_SD_HOST_CMD52_REG_ADDR_MSK) << CY_SD_HOST_CMD52_REG_ADDR_POS) |
                          (data & CY_SD_HOST_CMD52_DATA_MSK);

    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48B;
    cmd.enableCrcCheck  = true;
    cmd.enableIdxCheck  = true;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsSendAppCmd
****************************************************************************//**
*
*  Sends CMD55 (Sends the application command).
* If no response of CMD55 received, the card is not the SD card.
* The CMD55 response may have an error because some SD card does not support the CMD8
* command.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_OpsSendAppCmd(SDHC_Type *base,
                                                       cy_stc_sd_host_context_t const *context)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD55;
    cmd.commandArgument = context->RCA << CY_SD_HOST_RCA_SHIFT;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableCrcCheck  = true;
    cmd.enableIdxCheck  = true;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsSendIfCond
****************************************************************************//**
*
*  Send CMD8 (Send application command).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param cmdArgument
*     The command argument.
*
* \param noResponse
*     No response if true, false - a 48 bit response with CRC and IDX check.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_OpsSendIfCond(SDHC_Type *base,
                                                uint32_t cmdArgument,
                                                bool noResponse)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD8;
    cmd.commandArgument = cmdArgument;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;
    if (noResponse)
    {
        cmd.respType        = CY_SD_HOST_RESPONSE_NONE;
        cmd.enableCrcCheck  = false;
        cmd.enableIdxCheck  = false;
    }
    else
    {
        cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
        cmd.enableCrcCheck  = true;
        cmd.enableIdxCheck  = true;
    }

    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsSelectCard
****************************************************************************//**
*
*  Send CMD7 (Send select card command).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_OpsSelectCard(SDHC_Type *base,
                                                       cy_stc_sd_host_context_t const *context)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD7;
    cmd.commandArgument = context->RCA << CY_SD_HOST_RCA_SHIFT;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48B;
    cmd.enableCrcCheck  = false;
    cmd.enableIdxCheck  = false;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }
    if (CY_SD_HOST_SUCCESS == ret)
    {
        Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

        /* The R1b response requires sending an optional busy
        * signal to the DAT line. The transfer complete event
        *  should be checked and reset.
        */
        ret = Cy_SD_Host_PollTransferComplete(base);
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsSetSdBusWidth
****************************************************************************//**
*
*  Sends ACMD6 (Send set bus width command).
*
* \param *base
*     The SD host registers structure pointer.

* \param cmdArgument
*     The command argument.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_OpsSetSdBusWidth(SDHC_Type *base,
                                                 uint32_t cmdArgument,
                                                 cy_stc_sd_host_context_t const *context)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret;

    cmd.commandIndex    = CY_SD_HOST_SD_ACMD6;
    cmd.commandArgument = cmdArgument;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableCrcCheck  = false;
    cmd.enableIdxCheck  = false;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    ret = Cy_SD_Host_OpsSendAppCmd(base, context);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        ret = Cy_SD_Host_SendCommand(base, &cmd);

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Wait for the Command Complete event. */
            ret = Cy_SD_Host_PollCmdComplete(base);
        }

        Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsSwitchFunc
****************************************************************************//**
*
*  Sends CMD6 (Sends the Switch function command).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param cmdArgument
*     The command argument.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_OpsSwitchFunc(SDHC_Type *base, uint32_t cmdArgument)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD6;
    cmd.commandArgument = cmdArgument;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableCrcCheck  = true;
    cmd.enableIdxCheck  = true;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SdCardSwitchFunc
****************************************************************************//**
*
*  Sends CMD6 (Switch Function Command) and parses the 512 bits wide
*  response on the DAT lines.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param cmdArgument
*     The command argument.
*
* \param cardType
*     The type of card.
*
* \note
*     This function is applicable only for \ref CY_SD_HOST_SD &
*     \ref CY_SD_HOST_COMBO card types
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_SdCardSwitchFunc(SDHC_Type *base,
                                                                     uint32_t cmdArgument,
                                                                     cy_en_sd_host_card_type_t cardType)
{
    cy_stc_sd_host_cmd_config_t  cmd;
    cy_en_sd_host_status_t       ret;
    cy_stc_sd_host_data_config_t dataConfig;
    uint32_t status[CY_SD_HOST_SWITCH_STATUS_LEN];

    cmd.commandIndex    = CY_SD_HOST_SD_CMD6;
    cmd.commandArgument = cmdArgument;
    cmd.dataPresent     = true;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableCrcCheck  = true;
    cmd.enableIdxCheck  = true;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    dataConfig.blockSize           = CY_SD_HOST_SD_STATUS_BLOCKS;
    dataConfig.numberOfBlock       = 1UL;
    dataConfig.enableDma           = false;
    dataConfig.autoCommand         = CY_SD_HOST_AUTO_CMD_NONE;
    dataConfig.read                = true;
    dataConfig.data                = status;
    dataConfig.dataTimeout         = CY_SD_HOST_MAX_TIMEOUT;
    dataConfig.enableIntAtBlockGap = false;
    dataConfig.enReliableWrite     = false;

    if ((cardType == CY_SD_HOST_SD) || (cardType == CY_SD_HOST_COMBO))
    {
        (void)Cy_SD_Host_InitDataTransfer(base, &dataConfig);

        ret = Cy_SD_Host_SendCommand(base, &cmd);

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Wait for the Command Complete event. */
            ret = Cy_SD_Host_PollCmdComplete(base);
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Wait for the response on the DAT lines. */
            ret = Cy_SD_Host_CmdRxData(base, &dataConfig);
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Parse the response on DAT lines. */
            if ((((status[4] >> 4UL) & 0xFUL) == 0xFUL)   || /* Function group 1 (376-379) */
                ((status[4] & 0xFUL) == 0xFUL)            || /* Function group 2 (380-383) */
                (((status[3] >> 28UL)  & 0xFUL) == 0xFUL) || /* Function group 3 (384-387) */
                (((status[3] >> 24UL) & 0xFUL) == 0xFUL)  || /* Function group 4 (388-391) */
                (((status[3] >> 20UL) & 0xFUL) == 0xFUL)  || /* Function group 5 (392-395) */
                (((status[3] >> 16UL) & 0xFUL) == 0xFUL))    /* Function group 6 (396-399) */
            {
                ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
            }
        }

        Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);
    }
    else
    {
        ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsSetBlockCount
****************************************************************************//**
*
*  Sends CMD23 (Sends the Set Block Count command).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param reliableWrite
*     For EMMC enables the reliable write.
*
* \param blockNum
*     The number of blocks to send.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_OpsSetBlockCount(SDHC_Type *base,
                                                                   bool reliableWrite,
                                                                   uint32_t blockNum)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret;
    uint32_t                    cmdArgument;

    cmdArgument = (blockNum & CY_SD_HOST_CMD23_BLOCKS_NUM_MASK) |
                  (reliableWrite ? (1UL << CY_SD_HOST_CMD23_RELIABLE_WRITE_POS) : 0UL);

    cmd.commandIndex    = CY_SD_HOST_SD_CMD23;
    cmd.commandArgument = cmdArgument;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableCrcCheck  = true;
    cmd.enableIdxCheck  = true;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsProgramCsd
****************************************************************************//**
*
*  Sends CMD27 (Sends the Program CSD command).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param csd
*     The Card-Specific Data register value.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_OpsProgramCsd(SDHC_Type *base,
                                                                uint32_t csd,
                                                                cy_stc_sd_host_context_t *context)
{
    cy_en_sd_host_status_t       ret;
    cy_stc_sd_host_cmd_config_t  cmd;
    cy_stc_sd_host_data_config_t dataConfig;
    uint32_t                     i;
    uint32_t                     blkSize = CY_SD_HOST_CSD_BLOCKS;
    uint32_t                     csdTepm;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD27;
    cmd.commandArgument = context->RCA << CY_SD_HOST_RCA_SHIFT;
    cmd.dataPresent     = true;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableCrcCheck  = true;
    cmd.enableIdxCheck  = true;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    dataConfig.blockSize            = CY_SD_HOST_CSD_BLOCKS;
    dataConfig.numberOfBlock        = 1UL;
    dataConfig.enableDma            = false;
    dataConfig.autoCommand          = CY_SD_HOST_AUTO_CMD_NONE;
    dataConfig.read                 = false;
    dataConfig.data                 = context->csd;
    dataConfig.dataTimeout          = CY_SD_HOST_MAX_TIMEOUT;
    dataConfig.enableIntAtBlockGap  = false;
    dataConfig.enReliableWrite      = false;

    /* The CSD register is sent using DAT lines. Initialize a data transfer in Non-DMA mode. */
    (void)Cy_SD_Host_InitDataTransfer(base, &dataConfig);

    /* Send the program CSD command (CMD27) */
    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait when buffer is read ready. */
        ret = Cy_SD_Host_PollBufferWriteReady(base);

        for (i = (blkSize >> 2UL); i != 0UL; i--)
        {
            /* The CSD register is sent a using usual data (8-bit width) type of the Data packet format.
             * The usual data (8-bit width) is sent in the LSB (Least Significant Byte) first,
             * MSB (Most Significant Byte) last. The bytes in each context->csd[] element
             * should be reordered and shifted right to one byte.
             */
            csdTepm = ((context->csd[i-1UL] & CY_SD_HOST_CSD_ISBL_MASK) >> CY_SD_HOST_CSD_ISB_SHIFT) |
                      (context->csd[i-1UL] & CY_SD_HOST_CSD_ISBR_MASK) |
                      ((context->csd[i-1UL] & CY_SD_HOST_CSD_LSB_MASK) << CY_SD_HOST_CSD_ISB_SHIFT);

            if (i > 1UL)
            {
                csdTepm |= (context->csd[i-2UL] & CY_SD_HOST_CSD_MSB_MASK);
            }
            else
            {
                csdTepm &= ~((1UL << CY_SD_HOST_CSD_TEMP_WRITE_PROTECT) | /* Clear TMP_WRITE_PROTECT bit in the CSD register. */
                             CY_SD_HOST_CSD_MSB_MASK);
                csdTepm |= csd; /* Set writable bits of the CSD register. */
            }

            (void)Cy_SD_Host_BufferWrite(base, csdTepm);
        }

        /* Wait for the transfer complete */
        ret = Cy_SD_Host_PollTransferComplete(base);

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Check if the data line is free. */
            ret = Cy_SD_Host_PollDataLineFree(base);
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsSdioSendOpCond
****************************************************************************//**
*
*  Send CMD5 (Send SDIO operation condition command).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *ocrReg
*     The Operation Condition register (OCR).
*
* \param cmdArgument
*     The command argument.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_OpsSdioSendOpCond(SDHC_Type *base,
                                                           uint32_t *ocrReg,
                                                           uint32_t cmdArgument)
{
    cy_en_sd_host_status_t      ret;
    cy_stc_sd_host_cmd_config_t cmd;
    uint32_t                    response = 0UL;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD5;
    cmd.commandArgument = cmdArgument;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableCrcCheck  = false;
    cmd.enableIdxCheck  = false;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    /* Send the SDIO operation condition command (CMD5) */
    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    (void)Cy_SD_Host_GetResponse(base, (uint32_t *)&response, false);

    *ocrReg = response;

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_OpsSdSendOpCond
****************************************************************************//**
*
*  Send ACMD41 (Send SD operation condition command).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *ocrReg
*     The Operation Condition register (OCR).
*
* \param cmdArgument
*     The command argument.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_OpsSdSendOpCond(SDHC_Type *base,
                                                  uint32_t *ocrReg,
                                                  uint32_t cmdArgument,
                                                  cy_stc_sd_host_context_t const *context)
{
    cy_en_sd_host_status_t      ret;
    cy_stc_sd_host_cmd_config_t cmd;
    uint32_t                    response = 0UL;

    cmd.commandIndex    = CY_SD_HOST_SD_ACMD41;
    cmd.commandArgument = cmdArgument;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableCrcCheck  = false;
    cmd.enableIdxCheck  = false;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    /* Send the application command (CMD55) */
    ret = Cy_SD_Host_OpsSendAppCmd(base, context);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        ret = Cy_SD_Host_SendCommand(base, &cmd);

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Wait for the Command Complete event. */
            ret = Cy_SD_Host_PollCmdComplete(base);
        }

        Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

        (void)Cy_SD_Host_GetResponse(base, (uint32_t *)&response, false);

        *ocrReg = response;

        if (0x0UL == cmdArgument)
        {
            /* Voltage window = 0 */
        }
        else if (0UL == (response & CY_SD_HOST_ARG_ACMD41_BUSY))
        {
            /* Set an error */
            ret = CY_SD_HOST_OPERATION_INPROGRESS;
        }
        else
        {
            /* Success */
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_MmcOpsSendOpCond
****************************************************************************//**
*
*  Send CMD1 (Send MMC operation condition command).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *ocrReg
*     The Operation Condition register (OCR).
*
* \param cmdArgument
*     The command argument.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_MmcOpsSendOpCond(SDHC_Type *base,
                                                   uint32_t *ocrReg,
                                                   uint32_t cmdArgument)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret;
    uint32_t                    response = 0UL;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD1;
    cmd.commandArgument = cmdArgument;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48; /* R3 response */
    cmd.enableCrcCheck  = false;
    cmd.enableIdxCheck  = false;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    ret = Cy_SD_Host_SendCommand(base, &cmd);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Wait for the Command Complete event. */
        ret = Cy_SD_Host_PollCmdComplete(base);
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    /* Get the OCR register */
    (void)Cy_SD_Host_GetResponse(base, (uint32_t *)&response, false);

    *ocrReg = response;

    if (CY_SD_HOST_OCR_BUSY_BIT != (CY_SD_HOST_OCR_BUSY_BIT & response))
    {
        ret = CY_SD_HOST_OPERATION_INPROGRESS;
    }

    return ret;
}

/* The SD driver low-level section */

/*******************************************************************************
* Function Name: Cy_SD_Host_SdCardChangeClock
****************************************************************************//**
*
*  Changes the Host controller SD clock.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param frequency
*     The frequency in Hz.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
static cy_en_sd_host_status_t Cy_SD_Host_SdCardChangeClock(SDHC_Type *base, uint32_t frequency)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    uint32_t               clkDiv;
    uint32_t               clockInput = CY_SD_HOST_PERI_FREQUENCY;

    CY_ASSERT_L2(CY_SD_HOST_IS_FREQ_VALID(frequency));

    if (NULL != base)
    {
        clkDiv = (clockInput / frequency) >> 1UL;
        Cy_SD_Host_DisableSdClk(base);
        ret = Cy_SD_Host_SetSdClkDiv(base, (uint16_t)clkDiv);
        Cy_SD_Host_EnableSdClk(base);
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_Init
****************************************************************************//**
*
*  Initializes the SD host module.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param config
*     The SD host module configuration.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_Init(SDHC_Type *base,
                      const cy_stc_sd_host_init_config_t *config,
                      cy_stc_sd_host_context_t *context)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_SUCCESS;

    /* Check for the NULL pointer. */
    if ((NULL != base) && (NULL != config) && (NULL != context))
    {
        CY_ASSERT_L3(CY_SD_HOST_IS_DMA_VALID(config->dmaType));

        SDHC_CORE_GP_OUT_R(base) = _VAL2FLD(SDHC_CORE_GP_OUT_R_IO_VOLT_SEL_OE, 1u) | /* The IO voltage selection signal. */
                              _VAL2FLD(SDHC_CORE_GP_OUT_R_CARD_MECH_WRITE_PROT_EN, 1u) | /* The mechanical write protection. */
                              _VAL2FLD(SDHC_CORE_GP_OUT_R_LED_CTRL_OE, config->enableLedControl ? 1u : 0u) | /* The LED Control. */
                              _VAL2FLD(SDHC_CORE_GP_OUT_R_CARD_CLOCK_OE, 1u) | /* The Sd Clk. */
                              _VAL2FLD(SDHC_CORE_GP_OUT_R_CARD_IF_PWR_EN_OE, 1u) | /* Enable the card_if_pwr_en. */
                              _VAL2FLD(SDHC_CORE_GP_OUT_R_CARD_DETECT_EN, 1u); /* Enable the card detection. */

        SDHC_CORE_XFER_MODE_R(base) = 0U;

        context->dmaType = config->dmaType;

        if (config->emmc)
        {
            /* Save the card type. */
            context->cardType = CY_SD_HOST_EMMC;

            /* Set the eMMC Card present. */
            SDHC_CORE_EMMC_CTRL_R(base) = (uint16_t)_CLR_SET_FLD16U(SDHC_CORE_EMMC_CTRL_R(base),
                                          SDHC_CORE_EMMC_CTRL_R_CARD_IS_EMMC,
                                          1U);

        }
        else
        {
            /* Save the card type. */
            context->cardType = CY_SD_HOST_NOT_EMMC;
        }

        if (config->enableLedControl)
        {
            /* LED Control. */
            SDHC_CORE_HOST_CTRL1_R(base) = (uint8_t)_CLR_SET_FLD8U(SDHC_CORE_HOST_CTRL1_R(base),
                                          SDHC_CORE_HOST_CTRL1_R_LED_CTRL,
                                          1U);
        }

        /* Select ADMA or not. */
        SDHC_CORE_HOST_CTRL1_R(base) = (uint8_t)_CLR_SET_FLD8U(SDHC_CORE_HOST_CTRL1_R(base),
                                      SDHC_CORE_HOST_CTRL1_R_DMA_SEL,
                                      config->dmaType);

        /* Set the data timeout to the max. */
        SDHC_CORE_TOUT_CTRL_R(base) = _CLR_SET_FLD8U(SDHC_CORE_TOUT_CTRL_R(base),
                                                SDHC_CORE_TOUT_CTRL_R_TOUT_CNT,
                                                CY_SD_HOST_MAX_TIMEOUT);

        /* Enable all statuses. */
        Cy_SD_Host_SetNormalInterruptEnable(base, CY_SD_HOST_NORMAL_INT_MSK);
        Cy_SD_Host_SetErrorInterruptEnable(base, CY_SD_HOST_ERROR_INT_MSK);

        /* Enable Host Version 4. */
        SDHC_CORE_HOST_CTRL2_R(base) = (uint16_t)_CLR_SET_FLD16U(SDHC_CORE_HOST_CTRL2_R(base),
                                      SDHC_CORE_HOST_CTRL2_R_HOST_VER4_ENABLE,
                                      1U);

        /* Wait for the Host stable voltage. */
        Cy_SysLib_Delay(CY_SD_HOST_SUPPLY_RAMP_UP_TIME_MS);

        /* Reset normal events. */
        Cy_SD_Host_NormalReset(base);
    }
    else
    {
        ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_DeInit
****************************************************************************//**
*
* Restores the SD Host block registers back to default.
*
* \param *base
*     The SD host registers structure pointer.
*
*******************************************************************************/
void Cy_SD_Host_DeInit(SDHC_Type *base)
{
    /* Check for the NULL pointer. */
    if (NULL != base)
    {
        (void)Cy_SD_Host_PollCmdLineFree(base);
        (void)Cy_SD_Host_PollDataLineNotInhibit(base);

        Cy_SD_Host_SoftwareReset(base, CY_SD_HOST_RESET_ALL);

        /* Disable the SDHC block. */
        SDHC_WRAP_CTL(base) = _CLR_SET_FLD32U(SDHC_WRAP_CTL(base),
                                              SDHC_WRAP_CTL_ENABLE,
                                              0UL);
    }
}


/*******************************************************************************
* Function Name: Cy_SD_Host_AbortTransfer
****************************************************************************//**
*
*  Calling this function causes abortion of the currently executing command with
*  data. It doesn't issue a reset, that is the users responsibility.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t  Cy_SD_Host_AbortTransfer(SDHC_Type *base,
                                                 cy_stc_sd_host_context_t const *context)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    uint32_t                    response = 0UL;

    /* Check for the NULL pointer. */
    if ((NULL != base) && (NULL != context))
    {
        /* Check the card - Memory or SDIO? */
        if (CY_SD_HOST_SDIO == context->cardType)
        {
            ret = Cy_SD_Host_OpsSendIoRwDirectCmd(base,
                                                  1UL,
                                                  0UL,
                                                  0UL,
                                                  CY_SD_HOST_CCCR_IO_ABORT,
                                                  1UL);
        }
        else
        {
            cmd.commandArgument = context->RCA << CY_SD_HOST_RCA_SHIFT;
            cmd.dataPresent = false;
            cmd.enableAutoResponseErrorCheck = false;
            cmd.respType = CY_SD_HOST_RESPONSE_LEN_48;
            cmd.enableCrcCheck = true;
            cmd.enableIdxCheck = true;

            /* Issue CMD12. */
            cmd.commandIndex = CY_SD_HOST_SD_CMD12;
            cmd.cmdType      = CY_SD_HOST_CMD_ABORT;
            ret = Cy_SD_Host_SendCommand(base, &cmd);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                /* Wait for the Command Complete event. */
                ret = Cy_SD_Host_PollCmdComplete(base);
            }

            if (CY_SD_HOST_SUCCESS != ret)
            {
                return ret;
            }

            Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

            Cy_SD_Host_ErrorReset(base);

            /* Issue CMD13. */
            cmd.commandIndex = CY_SD_HOST_SD_CMD13;
            cmd.cmdType      = CY_SD_HOST_CMD_NORMAL;
            ret = Cy_SD_Host_SendCommand(base, &cmd);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                /* Wait for the Command Complete event. */
                ret = Cy_SD_Host_PollCmdComplete(base);
            }

            if (CY_SD_HOST_SUCCESS != ret)
            {
                return ret;
            }
            
            Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

            /* Get R1 */
            (void)Cy_SD_Host_GetResponse(base, (uint32_t *)&response, false);

            /* Check if the card is in the transition state. */
            if ((CY_SD_HOST_CARD_TRAN << CY_SD_HOST_CMD13_CURRENT_STATE) !=
                (response & CY_SD_HOST_CMD13_CURRENT_STATE_MSK))
            {
                /* Issue CMD12 */
                cmd.commandIndex = CY_SD_HOST_SD_CMD12;
                cmd.cmdType       = CY_SD_HOST_CMD_ABORT;
                ret = Cy_SD_Host_SendCommand(base, &cmd);

                if (CY_SD_HOST_SUCCESS == ret)
                {
                    /* Wait for the Command Complete event. */
                    ret = Cy_SD_Host_PollCmdComplete(base);
                }

                if (CY_SD_HOST_SUCCESS != ret)
                {
                    return ret;
                }

                Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

                Cy_SD_Host_ErrorReset(base);

                /* Issue CMD13. */
                cmd.commandIndex = CY_SD_HOST_SD_CMD13;
                cmd.cmdType      = CY_SD_HOST_CMD_NORMAL;
                ret = Cy_SD_Host_SendCommand(base, &cmd);

                if (CY_SD_HOST_SUCCESS == ret)
                {
                    /* Wait for the Command Complete event. */
                    ret = Cy_SD_Host_PollCmdComplete(base);
                }
                if (CY_SD_HOST_SUCCESS == ret)
                {
                    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

                    /* Get R1. */
                    (void)Cy_SD_Host_GetResponse(base, (uint32_t *)&response, false);

                    /* Check if the card is in the transition state. */
                    if ((CY_SD_HOST_CARD_TRAN << CY_SD_HOST_CMD13_CURRENT_STATE) != 
                        (response & CY_SD_HOST_CMD13_CURRENT_STATE_MSK))
                    {
                       ret = CY_SD_HOST_ERROR;
                    }
                }
            }
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_WriteProtect
****************************************************************************//**
*
*  Write protects the blocks of data from the SD card.
*  This function should only be called after Cy_SD_Host_SDCard_Init()/eMMC_Init().
*
* \param *base
*     The SD host registers structure pointer.
*
* \param writeProtect
*     \ref cy_en_sd_host_write_protect_t.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_WriteProtect(SDHC_Type *base,
                                               cy_en_sd_host_write_protect_t writeProtect,
                                               cy_stc_sd_host_context_t *context)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_SUCCESS;
    uint32_t               csdReg;

    /* Check for the NULL pointer. */
    if ((NULL != base) && (NULL != context))
    {
        switch (writeProtect)
        {
            case CY_SD_HOST_PERMANENT:
                csdReg = 1UL << CY_SD_HOST_CSD_PERM_WRITE_PROTECT;
                break;
            case CY_SD_HOST_ENABLE_TEMPORARY:
                csdReg = 1UL << CY_SD_HOST_CSD_TEMP_WRITE_PROTECT;
                break;
            case CY_SD_HOST_DISABLE_TEMPORARY:
                csdReg = 0UL;
                break;
            default:
                ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
                break;
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            ret = Cy_SD_Host_OpsProgramCsd(base, csdReg, context);
        }
    }
    else
    {
        ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetCardStatus
****************************************************************************//**
*
*  Returns the card status.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return uint32_t
*     The card status (the result of the CMD13 command).
*
*******************************************************************************/
uint32_t Cy_SD_Host_GetCardStatus(SDHC_Type *base,
                                  cy_stc_sd_host_context_t const *context)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    uint32_t                    response = 0UL;
    uint32_t                    status = (1UL << CY_SD_HOST_CMD13_ERROR);

    /* Check for the NULL pointer. */
    if ((NULL != base) && (NULL != context))
    {
        cmd.commandIndex    = CY_SD_HOST_SD_CMD13;
        cmd.commandArgument = context->RCA << CY_SD_HOST_RCA_SHIFT;
        cmd.dataPresent     = false;
        cmd.enableAutoResponseErrorCheck = false;
        cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
        cmd.enableCrcCheck  = true;
        cmd.enableIdxCheck  = true;
        cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

        ret = Cy_SD_Host_SendCommand(base, &cmd);

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Wait for the Command Complete event. */
            ret = Cy_SD_Host_PollCmdComplete(base);
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            (void)Cy_SD_Host_GetResponse(base, (uint32_t *)&response, false);
            status = response;
        }
        else
        {
            status = (1UL << CY_SD_HOST_CMD13_ERROR);
        }
    }

    return status;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetSdStatus
****************************************************************************//**
*
*  Returns the SD status from the card.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *sdStatus
*     The pointer to where to store the SD status array.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_GetSdStatus(SDHC_Type *base,
                                              uint32_t *sdStatus,
                                              cy_stc_sd_host_context_t const *context)
{
    cy_en_sd_host_status_t       ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    cy_stc_sd_host_cmd_config_t  cmd;
    cy_stc_sd_host_data_config_t dataConfig;

    /* Check for the NULL pointer */
    if ((NULL != base) && (NULL != sdStatus) && (NULL != context))
    {
        ret = Cy_SD_Host_OpsSendAppCmd(base, context);
        if (CY_SD_HOST_SUCCESS == ret)
        {
            cmd.commandIndex    = CY_SD_HOST_SD_CMD13;
            cmd.commandArgument = context->RCA << CY_SD_HOST_RCA_SHIFT;
            cmd.dataPresent     = true;
            cmd.enableAutoResponseErrorCheck = false;
            cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
            cmd.enableCrcCheck  = true;
            cmd.enableIdxCheck  = true;
            cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

            dataConfig.blockSize            = CY_SD_HOST_SD_STATUS_BLOCKS;
            dataConfig.numberOfBlock        = 1UL;
            dataConfig.enableDma            = false;
            dataConfig.autoCommand          = CY_SD_HOST_AUTO_CMD_NONE;
            dataConfig.read                 = true;
            dataConfig.data                 = sdStatus;
            dataConfig.dataTimeout          = CY_SD_HOST_MAX_TIMEOUT;
            dataConfig.enableIntAtBlockGap  = false;
            dataConfig.enReliableWrite      = false;

            (void)Cy_SD_Host_InitDataTransfer(base, &dataConfig);

            ret = Cy_SD_Host_SendCommand(base, &cmd);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                /* Wait for the Command Complete event. */
                ret = Cy_SD_Host_PollCmdComplete(base);
            }

            if (CY_SD_HOST_SUCCESS == ret)
            {
                ret = Cy_SD_Host_CmdRxData(base, &dataConfig);
            }
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetOcr
****************************************************************************//**
*
*  Reads the Operating Condition Register (OCR) register from the card.
*
* \note This function can be used only if the card is in the Idle state.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return uint32_t
*     The OCR register.
*
* \note For combo cards, the function returns the OCR register for the IO portion only.
*
*******************************************************************************/
uint32_t Cy_SD_Host_GetOcr(SDHC_Type *base, cy_stc_sd_host_context_t const *context)
{
    uint32_t ocrReg = 0UL;

    if (CY_SD_HOST_SD == context->cardType)
    {
        (void)Cy_SD_Host_OpsSdSendOpCond(base, &ocrReg, 0UL, context);
    }
    else if (CY_SD_HOST_EMMC == context->cardType)
    {
        (void)Cy_SD_Host_MmcOpsSendOpCond(base, &ocrReg, 0UL);
    }
    else if ((CY_SD_HOST_SDIO == context->cardType) ||
             (CY_SD_HOST_COMBO == context->cardType))
    {
        (void)Cy_SD_Host_OpsSdioSendOpCond(base, &ocrReg, 0UL);
    }
    else
    {
        /* Invalid card. */
    }

    return ocrReg;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetCid
****************************************************************************//**
*
*  Returns the Card Identification Register (CID) contents.
*
* \note This function can be used only if the card is in the Ready state.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param cid
*     The pointer to where to store the CID register.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_GetCid(SDHC_Type *base,
                                         uint32_t *cid)
{
    cy_stc_sd_host_cmd_config_t cmd;
    cy_en_sd_host_status_t      ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    uint32_t                    i;
    uint32_t                    response[CY_SD_HOST_RESPONSE_SIZE] = { 0UL };

    /* Check for the NULL pointer */
    if ((NULL != base) && (NULL != cid))
    {
        cmd.commandIndex    = CY_SD_HOST_SD_CMD2;
        cmd.commandArgument = 0UL;
        cmd.dataPresent     = false;
        cmd.enableAutoResponseErrorCheck = false;
        cmd.respType        = CY_SD_HOST_RESPONSE_LEN_136;
        cmd.enableCrcCheck  = true;
        cmd.enableIdxCheck  = false;
        cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

        ret = Cy_SD_Host_SendCommand(base, &cmd);

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Wait for the Command Complete event. */
            ret = Cy_SD_Host_PollCmdComplete(base);
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            (void)Cy_SD_Host_GetResponse(base, (uint32_t *)response, true);

            /* Get CID from the response. */
            for ( i = 0UL; i < CY_SD_HOST_CID_SIZE; i++ )
            {
                cid[i] = *((uint32_t *)(response + i));
            }
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetCsd
****************************************************************************//**
*
*  Returns the Card Specific Data (CSD) register contents.
*
* \note This function can be used only if the card is in the Stand-by state.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *csd
*     The pointer to where to store the CSD register.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_GetCsd(SDHC_Type *base,
                                         uint32_t *csd,
                                         cy_stc_sd_host_context_t *context)
{
    cy_stc_sd_host_cmd_config_t   cmd;
    cy_en_sd_host_status_t        ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    uint32_t                      response[CY_SD_HOST_RESPONSE_SIZE] = { 0UL };
    uint32_t                      numSector;
    uint32_t                      cSize;
    uint32_t                      cSizeMult;
    uint32_t                      readBlLen;

    /* Check for the NULL pointer */
    if ((NULL != base) && (NULL != csd) && (NULL != context))
    {
        cmd.commandIndex    = CY_SD_HOST_SD_CMD9;
        cmd.commandArgument = context->RCA << CY_SD_HOST_RCA_SHIFT;
        cmd.dataPresent     = false;
        cmd.enableAutoResponseErrorCheck = false;
        cmd.respType        = CY_SD_HOST_RESPONSE_LEN_136;
        cmd.enableCrcCheck  = true;
        cmd.enableIdxCheck  = false;
        cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

        ret = Cy_SD_Host_SendCommand(base, &cmd);

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Wait for the Command Complete event. */
            ret = Cy_SD_Host_PollCmdComplete(base);
        }

        if (ret == CY_SD_HOST_SUCCESS)
        {
            (void)Cy_SD_Host_GetResponse(base, (uint32_t *)response, true);

            (void)memcpy(csd, response, sizeof(response));
            (void)memcpy(context->csd, response, sizeof(response));

            if ((CY_SD_HOST_SDHC == context->cardCapacity) ||
                (CY_SD_HOST_SDXC == context->cardCapacity)) /* High/Ext. Capacity (CSD version 2.0) */
            {
                cSize = (response[1] & CY_SD_HOST_CSD_V2_C_SIZE_MASK) >>
                         CY_SD_HOST_CSD_V2_C_SIZE_POS;

                numSector = (cSize + 1UL) << CY_SD_HOST_CSD_V2_SECTOR_MULT;
            }
            else /* Standard Capacity (CSD version 1.0) */
            {
                cSize =  (response[2] & CY_SD_HOST_CSD_V1_C_SIZE_MSB_MASK) <<
                         CY_SD_HOST_CSD_V1_C_SIZE_MSB_MULT;    /* C_SIZE3 */
                cSize +=((response[1] & CY_SD_HOST_CSD_V1_C_SIZE_ISB_MASK) >>
                         CY_SD_HOST_CSD_V1_C_SIZE_ISB_POS) <<
                         CY_SD_HOST_CSD_V1_C_SIZE_ISB_MULT;    /* C_SIZE2 */
                cSize += (response[1] & CY_SD_HOST_CSD_V1_C_SIZE_LSB_MASK) >>
                          CY_SD_HOST_CSD_V1_C_SIZE_LSB_POS;    /* C_SIZE1 */

                cSizeMult = ((response[1] & CY_SD_HOST_CSD_V1_C_SIZE_MULT_MASK) >>
                             CY_SD_HOST_CSD_V1_C_SIZE_MULT_POS);

                readBlLen = (response[2] & CY_SD_HOST_CSD_V1_READ_BL_LEN_MASK) >>
                             CY_SD_HOST_CSD_V1_READ_BL_LEN_POS; /* READ_BL_LEN */

                numSector = (cSize + 1UL) << (cSizeMult + 2UL);

                if (CY_SD_HOST_CSD_V1_BL_LEN_1024 == readBlLen)
                {
                    numSector *= CY_SD_HOST_CSD_V1_1024_SECT_FACTOR;
                }
                else if (CY_SD_HOST_CSD_V1_BL_LEN_2048 == readBlLen)
                {
                    numSector *= CY_SD_HOST_CSD_V1_2048_SECT_FACTOR;
                }
                else
                {
                    /* Block length = 512 bytes (readBlLen = 9u) */
                }
            }

            context->maxSectorNum = numSector;
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetExtCsd
****************************************************************************//**
*
*  Returns the EXTCSD Register contents. This is only for EMMC cards.
*  There are 512 bytes of data being read.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *extCsd
*     The pointer to where to store the EXTCSD register.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_GetExtCsd(SDHC_Type *base, uint32_t *extCsd,
                                                   cy_stc_sd_host_context_t *context)
{
    cy_stc_sd_host_cmd_config_t  cmd;
    cy_en_sd_host_status_t       ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    cy_stc_sd_host_data_config_t dataConfig;

    /* Check for the NULL pointer */
    if ((NULL != base) && (NULL != extCsd) && (NULL != context))
    {
        cmd.commandIndex    = CY_SD_HOST_MMC_CMD8;
        cmd.commandArgument = context->RCA << CY_SD_HOST_RCA_SHIFT;
        cmd.dataPresent     = true;
        cmd.enableAutoResponseErrorCheck = false;
        cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
        cmd.enableCrcCheck  = true;
        cmd.enableIdxCheck  = true;
        cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

        dataConfig.blockSize            = CY_SD_HOST_BLOCK_SIZE;
        dataConfig.numberOfBlock        = 1UL;
        dataConfig.enableDma            = false;
        dataConfig.autoCommand          = CY_SD_HOST_AUTO_CMD_NONE;
        dataConfig.read                 = true;
        dataConfig.data                 = extCsd;
        dataConfig.dataTimeout          = CY_SD_HOST_MAX_TIMEOUT;
        dataConfig.enableIntAtBlockGap  = false;
        dataConfig.enReliableWrite      = false;

        (void)Cy_SD_Host_InitDataTransfer(base, &dataConfig);

        ret = Cy_SD_Host_SendCommand(base, &cmd);

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* Wait for the Command Complete event. */
            ret = Cy_SD_Host_PollCmdComplete(base);
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            ret = Cy_SD_Host_CmdRxData(base, &dataConfig);
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            context->maxSectorNum = extCsd[CY_SD_HOST_EXTCSD_SEC_COUNT];

            context->cardCapacity = CY_SD_HOST_EMMC_LESS_2G;

            /* Check if the eMMC capacity is greater than 2GB */
            if ((CY_SD_HOST_MMC_LEGACY_SIZE_BYTES/CY_SD_HOST_BLOCK_SIZE) <
                 context->maxSectorNum)
            {
                context->cardCapacity = CY_SD_HOST_EMMC_GREATER_2G;
            }
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetRca
****************************************************************************//**
*
*  Reads the Relative Card Address (RCA) register from the card.
*
* \note This function can be used only if the card is in the Identification or
* Stand-by state.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return uint32_t
*     The RCA register.
*
*******************************************************************************/
uint32_t Cy_SD_Host_GetRca(SDHC_Type *base)
{
    cy_stc_sd_host_cmd_config_t cmd;
    uint32_t                    response = 0UL;

    cmd.commandIndex    = CY_SD_HOST_SD_CMD3;
    cmd.commandArgument = 0UL;
    cmd.dataPresent     = false;
    cmd.enableAutoResponseErrorCheck = false;
    cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48;
    cmd.enableCrcCheck  = true;
    cmd.enableIdxCheck  = true;
    cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

    (void)Cy_SD_Host_SendCommand(base, &cmd);

    /* Wait for the Command Complete event. */
    (void)Cy_SD_Host_PollCmdComplete(base);

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    (void)Cy_SD_Host_GetResponse(base, (uint32_t *)&response, false);

    return (response >> CY_SD_HOST_RCA_SHIFT);
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetScr
****************************************************************************//**
*
*  Returns the SD Card Configuration Register (SCR) Register contents.
*
* \note This function can be used only if the card is in the Transition state.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *scr
*     The pointer to where to store the SCR register.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_GetScr(SDHC_Type *base,
                                         uint32_t *scr,
                                         cy_stc_sd_host_context_t const *context)
{
    cy_stc_sd_host_cmd_config_t  cmd;
    cy_en_sd_host_status_t       ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    cy_stc_sd_host_data_config_t dataConfig;

    /* Check for the NULL pointer */
    if ((NULL != base) && (NULL != scr) && (NULL != context))
    {
        ret = Cy_SD_Host_OpsSendAppCmd(base, context);
        if (CY_SD_HOST_SUCCESS == ret)
        {
            cmd.commandIndex    = CY_SD_HOST_SD_ACMD51;
            cmd.commandArgument = context->RCA << CY_SD_HOST_RCA_SHIFT;
            cmd.dataPresent     = true;
            cmd.enableAutoResponseErrorCheck = false;
            cmd.respType        = CY_SD_HOST_RESPONSE_LEN_48B;
            cmd.enableCrcCheck  = true;
            cmd.enableIdxCheck  = true;
            cmd.cmdType         = CY_SD_HOST_CMD_NORMAL;

            dataConfig.blockSize           = CY_SD_HOST_SCR_BLOCKS;
            dataConfig.numberOfBlock       = 1UL;
            dataConfig.enableDma           = false;
            dataConfig.autoCommand         = CY_SD_HOST_AUTO_CMD_NONE;
            dataConfig.read                = true;
            dataConfig.data                = (uint32_t *)scr;
            dataConfig.dataTimeout         = CY_SD_HOST_MAX_TIMEOUT;
            dataConfig.enableIntAtBlockGap = false;
            dataConfig.enReliableWrite     = false;

            (void)Cy_SD_Host_InitDataTransfer(base, &dataConfig);

            ret = Cy_SD_Host_SendCommand(base, &cmd);

            if (CY_SD_HOST_SUCCESS == ret)
            {
                /* Wait for the Command Complete event. */
                ret = Cy_SD_Host_PollCmdComplete(base);
            }

            if (CY_SD_HOST_SUCCESS == ret)
            {
                ret = Cy_SD_Host_CmdRxData(base, &dataConfig);
            }
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_ErrorReset
****************************************************************************//**
*
*  Checks for error event and resets it. Then resets the CMD line.
*
* \param *base
*     The SD host registers structure pointer.
*
*******************************************************************************/
static void Cy_SD_Host_ErrorReset(SDHC_Type *base)
{
    uint32_t intError; /* The error events mask. */

    intError = Cy_SD_Host_GetErrorInterruptStatus(base);

    /* Check the error event. */
    if (0UL < intError)
    {
        /* Clear the error event. */
        Cy_SD_Host_ClearErrorInterruptStatus(base, intError);

        Cy_SD_Host_SoftwareReset(base, CY_SD_HOST_RESET_CMD_LINE);
    }
}


/*******************************************************************************
* Function Name: Cy_SD_Host_NormalReset
****************************************************************************//**
*
*  Checks for a normal event and resets it.
*
* \param *base
*     The SD host registers structure pointer.
*
*******************************************************************************/
static void Cy_SD_Host_NormalReset(SDHC_Type *base)
{
    uint32_t intNormal; /* The normal events mask. */

    intNormal = Cy_SD_Host_GetNormalInterruptStatus(base);

    /* Check the normal event. */
    if (0UL < intNormal)
    {
        /* Clear the normal event. */
        Cy_SD_Host_ClearNormalInterruptStatus(base, intNormal);
    }
}


/*******************************************************************************
* Function Name: Cy_SD_Host_VoltageCheck
****************************************************************************//**
*
*  resets the card (CMD0) and checks the voltage (CMD8).
*
* \param *base
*     The SD host registers structure pointer.
*
* \return The CMD8 valid flag (f8).
*
*******************************************************************************/
__STATIC_INLINE bool Cy_SD_Host_VoltageCheck(SDHC_Type *base)
{
    cy_en_sd_host_status_t ret;
    bool                   f8Flag = false; /* The CMD8 valid flag. */
    uint32_t               response = 0UL;  /* The CMD response. */
    uint32_t               retry = CY_SD_HOST_VOLTAGE_CHECK_RETRY;

    while (retry > 0UL)
    {
        /* Reset Card (CMD0). */
        ret = Cy_SD_Host_OpsGoIdle(base);  /* The Idle state. */

        /* Software reset for the CMD line. */
        Cy_SD_Host_SoftwareReset(base, CY_SD_HOST_RESET_CMD_LINE);

        /* Voltage check (CMD8). */
        ret = Cy_SD_Host_OpsSendIfCond(base,
                                       CY_SD_HOST_CMD8_VHS_27_36 |
                                       CY_SD_HOST_CMD8_CHECK_PATTERN,
                                       false);

        /* Check the response. */
        (void)Cy_SD_Host_GetResponse(base,
                                     (uint32_t *)&response,
                                     false);

        /* Check the pattern. */
        if (CY_SD_HOST_CMD8_CHECK_PATTERN == (response &
                                              CY_SD_HOST_CMD8_PATTERN_MASK))
        {
            /* The pattern is valid. */
            f8Flag = true;
        }
        else if (CY_SD_HOST_VOLTAGE_CHECK_RETRY == retry)
        {
           /* CMD8 fails. Retry one more time */
        }
        else
        {
            /* The unusable card or the SDIO card. */
            ret = CY_SD_HOST_ERROR_UNUSABLE_CARD;
        }

        if ((CY_SD_HOST_ERROR_TIMEOUT == ret) || (f8Flag))
        {
            /* The pattern is valid or voltage mismatch (No response). */
            break;
        }

        retry--;
    }

    if (CY_SD_HOST_SUCCESS != ret)   /* The Idle state. */
    {
        /* Reset the error and the CMD line for the case of the SDIO card. */
        Cy_SD_Host_ErrorReset(base);
        Cy_SD_Host_NormalReset(base);
    }

    return f8Flag;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_IoOcr
****************************************************************************//**
*
*  Sends CMD5 to get IO OCR. Checks if IO is present (sdio),
*   if the memory is present (mpFlag) and if 1.8 signaling can be supported (s18aFlag).
*
* \param *base
*     The SD host registers structure pointer.
*
* \param lowVoltageSignaling
*     The lowVoltageSignaling flag.
*
* \param *s18aFlag
*     The S18A flag (1.8 signaling support).
*
* \param *sdioFlag
*     The IO flag (the number of IO functions).
*
* \param *mpFlag
*     The MEM flag (memory support).
*
* \param *ocrReg
*     The Operation Condition register (OCR).
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_IoOcr(SDHC_Type *base,
                                      bool lowVoltageSignaling,
                                      uint32_t *s18aFlag,
                                      uint32_t *sdioFlag,
                                      bool *mpFlag,
                                      uint32_t *ocrReg)
{
    cy_en_sd_host_status_t ret;
    uint32_t               retry;

    /* Get IO OCR (CMD5) */
    ret = Cy_SD_Host_OpsSdioSendOpCond(base, ocrReg, 0UL);

    /* Get the number of IO functions. */
    *sdioFlag = *ocrReg & CY_SD_HOST_CMD5_IO_NUM_MASK;

    if (0UL < *sdioFlag)
    {
        if (true == lowVoltageSignaling)
        {
            /* Set the OCR to change the signal
            * voltage to 1.8 V for the UHS-I mode.
            */
            *ocrReg = (*ocrReg & CY_SD_HOST_IO_OCR_MASK) |
                           CY_SD_HOST_ACMD41_S18R;
        }

        retry = CY_SD_HOST_RETRY_TIME;
        while (retry > 0UL)
        {
            /* Set S18R and the voltage window in IO OCR (CMD5). */
            ret = Cy_SD_Host_OpsSdioSendOpCond(base,
                                              ocrReg,
                                              *ocrReg);

            /* Check the IO power up status. */
            if (CY_SD_HOST_SUCCESS == ret)
            {
                if (CY_SD_HOST_IO_OCR_C == (*ocrReg & CY_SD_HOST_IO_OCR_C))
                {
                    /* The SDIO card supports 1.8 signaling. */
                    *s18aFlag = 1UL;
                }

                if(CY_SD_HOST_CMD5_MP_MASK == (*ocrReg & CY_SD_HOST_CMD5_MP_MASK))
                {
                    /* MP = 1. (The memory is supported.) */
                    *mpFlag = true;
                }

                /* IO > 0. */
                break;
            }

            Cy_SysLib_DelayUs(CY_SD_HOST_SDIO_CMD5_TIMEOUT_MS); /* 1 sec timeout. */
            retry--;
        }

        if (CY_SD_HOST_SUCCESS != ret)
        {
            /* IO = 0. */
            *sdioFlag = 0UL;
        }
    }
    else
    {
        /* Software reset for the DAT line. */
        Cy_SD_Host_SoftwareReset(base, CY_SD_HOST_RESET_DATALINE);

        /* IO = 0. We have the SD memory card. Reset errors. */
        Cy_SD_Host_ErrorReset(base);

    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SdOcr
****************************************************************************//**
*
*  Sends ACMD41 to get SD OCR.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param lowVoltageSignaling
*     The lowVoltageSignaling flag.
*
* \param *s18aFlag
*     The S18A flag (1.8 signaling support).
*
* \param *mpFlag
*     The MEM flag (memory support).
*
* \param f8Flag
*     The CMD8 flag.
*
* \param *ocrReg
*     The Operation Condition register (OCR).
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
__STATIC_INLINE cy_en_sd_host_status_t Cy_SD_Host_SdOcr(SDHC_Type *base,
                                      bool lowVoltageSignaling,
                                      uint32_t *s18aFlag,
                                      bool *mpFlag,
                                      bool f8Flag,
                                      uint32_t *ocrReg,
                                      cy_stc_sd_host_context_t *context)
{
    cy_en_sd_host_status_t ret;
    uint32_t               response = 0UL;  /* The CMD response. */
    uint32_t               retry;
    uint32_t               cmdArgument;

    /* Get OCR (ACMD41). The voltage window = 0. */
    ret = Cy_SD_Host_OpsSdSendOpCond(base,
                                     ocrReg,
                                     0x00000000UL,
                                     context);

    if (CY_SD_HOST_SUCCESS == ret)
    {
        /* Set the voltage window from 2.7 to 3.6 V.  */
        cmdArgument = CY_SD_HOST_ACMD41_VOLTAGE_MASK;

        if (f8Flag)
        {
            /* Set the SDHC supported bit.*/
            cmdArgument |= CY_SD_HOST_ACMD41_HCS;

            if (true == lowVoltageSignaling)
            {
                /* Set the 1.8 V request bit.*/
                cmdArgument |= CY_SD_HOST_ACMD41_S18R;
            }
        }

        /* Set OCR (ACMD41). */
        retry = CY_SD_HOST_RETRY_TIME;
        while (retry > 0UL)
        {
            ret = Cy_SD_Host_OpsSdSendOpCond(base,
                                             ocrReg,
                                             cmdArgument,
                                             context);
            if (CY_SD_HOST_SUCCESS == ret)
            {
                break;
            }
            Cy_SysLib_DelayUs(CY_SD_HOST_ACMD41_TIMEOUT_MS);
            retry--;
        }

        /* Check the response. */
        (void)Cy_SD_Host_GetResponse(base,
                                    (uint32_t *)&response,
                                    false);

        if (0UL == (response & CY_SD_HOST_OCR_CAPACITY_MASK))
        {
            /* The SDSC card. */
            context->cardCapacity = CY_SD_HOST_SDSC;
        }

        /* Check S18A. */
        if (CY_SD_HOST_OCR_S18A == (response &
                                    CY_SD_HOST_OCR_S18A))
        {
            /* The SD card supports the 1.8 signaling. */
            *s18aFlag |= 1UL;
        }

        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* MP = 1. (The memory is supported.) */
            *mpFlag = true;
        }
        else
        {
            /* MP = 0. (The memory is not supported.) */
            *mpFlag = false;
        }
    }
    else if (false == f8Flag)
    {
        /* Not a SD card */
        ret = CY_SD_HOST_ERROR_UNUSABLE_CARD;
        context->cardType = CY_SD_HOST_UNUSABLE;
    }
    else
    {
        /* The card is not present or busy */
    }

    Cy_SysLib_DelayUs(CY_SD_HOST_NCC_MIN_US);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_Enable
****************************************************************************//**
*
*  Enables the SD host block.
*
* \param *base
*     The SD host registers structure pointer.
*
*******************************************************************************/
void Cy_SD_Host_Enable(SDHC_Type *base)
{
    uint32_t retry;

    /* Check for the NULL pointer */
    if (NULL != base)
    {
        /* Enable the SDHC block. */
        SDHC_WRAP_CTL(base) = _CLR_SET_FLD32U(SDHC_WRAP_CTL(base),
                                              SDHC_WRAP_CTL_ENABLE,
                                              1UL);

        retry = CY_SD_HOST_RETRY_TIME;

        /* Enable the Internal clock. */
        SDHC_CORE_CLK_CTRL_R(base) = (uint16_t)_CLR_SET_FLD16U(SDHC_CORE_CLK_CTRL_R(base),
                                                               SDHC_CORE_CLK_CTRL_R_INTERNAL_CLK_EN,
                                                               1UL);

        while((true != _FLD2BOOL(SDHC_CORE_CLK_CTRL_R_INTERNAL_CLK_STABLE, SDHC_CORE_CLK_CTRL_R(base)))
              && (retry > 0UL))
        {
            /* Wait for the stable Internal Clock . */
            Cy_SysLib_DelayUs(CY_SD_HOST_INT_CLK_STABLE_TIMEOUT_MS);
            retry--;
        }
    }
}


/*******************************************************************************
* Function Name: Cy_SD_Host_Disable
****************************************************************************//**
*
*  Disables the SD host block.
*
* \param *base
*     The SD host registers structure pointer.
*
*******************************************************************************/
void Cy_SD_Host_Disable(SDHC_Type *base)
{
    /* Check for the NULL pointer */
    if (NULL != base)
    {
        Cy_SD_Host_DisableSdClk(base);

        /* Disable the Internal clock. */
        SDHC_CORE_CLK_CTRL_R(base) = (uint16_t)_CLR_SET_FLD16U(SDHC_CORE_CLK_CTRL_R(base),
                                        SDHC_CORE_CLK_CTRL_R_INTERNAL_CLK_EN,
                                        0UL);

        /* Disable the SDHC block. */
        SDHC_WRAP_CTL(base) = _CLR_SET_FLD32U(SDHC_WRAP_CTL(base),
                                        SDHC_WRAP_CTL_ENABLE,
                                        0UL);
    }
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SetSdClkDiv
****************************************************************************//**
*
*  Changes the speed of the SD bus. This function should be called along
*  with \ref Cy_SD_Host_SetHostSpeedMode to configure the bus correctly.
*
* \note
*  The divider is clocked from the CLK_HF clock (100 MHz). To determine
*  the SD bus speed divide the clock CLK_HF by the divider value passed
*  in this function. The divider value is 2^clkDiv.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param clkDiv
*     The clock divider for the SD clock.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_SetSdClkDiv(SDHC_Type *base, uint16_t clkDiv)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;

    /* Check for the NULL pointer */
    if (NULL != base)
    {
        SDHC_CORE_CLK_CTRL_R(base) = (uint16_t)(((uint32_t)SDHC_CORE_CLK_CTRL_R(base) &
                                                ~(SDHC_CORE_CLK_CTRL_R_FREQ_SEL_Msk |            /* Clear the first LSB 8 bits */
                                                  SDHC_CORE_CLK_CTRL_R_UPPER_FREQ_SEL_Msk)) |    /* Clear the upper 2 bits */
        _VAL2FLD(SDHC_CORE_CLK_CTRL_R_FREQ_SEL, ((uint32_t)clkDiv & CY_SD_HOST_FREQ_SEL_MSK)) |             /* Set the first LSB 8 bits */
        _VAL2FLD(SDHC_CORE_CLK_CTRL_R_UPPER_FREQ_SEL, ((uint32_t)clkDiv >> CY_SD_HOST_UPPER_FREQ_SEL_POS))); /* Set the upper 2 bits */

        /* Wait for at least 3 card clock periods */
        Cy_SysLib_DelayUs(CY_SD_HOST_3_PERIODS_US);

        ret = CY_SD_HOST_SUCCESS;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_IsWpSet
****************************************************************************//**
*
*  Returns the state of the write protect switch on the SD card.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return bool
*     true - the write protect is set, false - the write protect is not set.
*
*******************************************************************************/
__WEAK bool Cy_SD_Host_IsWpSet(SDHC_Type const *base)
{
    return _FLD2BOOL(SDHC_CORE_PSTATE_REG_WR_PROTECT_SW_LVL, SDHC_CORE_PSTATE_REG(base));
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SetHostBusWidth
****************************************************************************//**
*
*  Only changes the bus width on the host side.
*  It doesn't change the bus width on the card side.
*  To change the bus width on the card, call Cy_SD_Host_SetBusWidth().
*
* \param *base
*     The SD host registers structure pointer.
*
* \param width
*     The width of the data bus.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_SetHostBusWidth(SDHC_Type *base,
                                                  cy_en_sd_host_bus_width_t width)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;

    /* Check for the NULL pointer */
    if (NULL != base)
    {
        SDHC_CORE_HOST_CTRL1_R(base) = (uint8_t)(((uint32_t)SDHC_CORE_HOST_CTRL1_R(base) &
                                               ~(SDHC_CORE_HOST_CTRL1_R_EXT_DAT_XFER_Msk |
                                                 SDHC_CORE_HOST_CTRL1_R_DAT_XFER_WIDTH_Msk)) |
                                        (_BOOL2FLD(SDHC_CORE_HOST_CTRL1_R_EXT_DAT_XFER, (CY_SD_HOST_BUS_WIDTH_8_BIT == width)) |
                                         _BOOL2FLD(SDHC_CORE_HOST_CTRL1_R_DAT_XFER_WIDTH, (CY_SD_HOST_BUS_WIDTH_4_BIT == width))));

        ret = CY_SD_HOST_SUCCESS;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SetHostSpeedMode
****************************************************************************//**
*
*  Only updates the host register to indicate bus speed mode.
*  This function doesn't change the speed on the bus, or change
*  anything in the card.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param speedMode
*     Bus Speed mode.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_SetHostSpeedMode(SDHC_Type *base,
                                                  cy_en_sd_host_bus_speed_mode_t speedMode)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_SUCCESS;
    uint32_t               ultraHighSpeed;

    /* Check for the NULL pointer */
    if (NULL != base)
    {
        /* UHS Mode/eMMC Speed Mode Select */
        switch (speedMode)
        {
            case CY_SD_HOST_BUS_SPEED_EMMC_LEGACY:
            case CY_SD_HOST_BUS_SPEED_DEFAULT:
            case CY_SD_HOST_BUS_SPEED_SDR12_5:
                ultraHighSpeed = CY_SD_HOST_SDR12_SPEED; /* Max clock = 25 MHz */
                break;
            case CY_SD_HOST_BUS_SPEED_EMMC_HIGHSPEED_SDR:
            case CY_SD_HOST_BUS_SPEED_SDR25:
            case CY_SD_HOST_BUS_SPEED_HIGHSPEED:
                ultraHighSpeed = CY_SD_HOST_SDR25_SPEED; /* Max clock = 50 MHz */
                break;
            case CY_SD_HOST_BUS_SPEED_SDR50:
                ultraHighSpeed = CY_SD_HOST_SDR50_SPEED; /* Max clock = 100 MHz */
                break;
            default:
                ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
                break;
        }

        if (CY_SD_HOST_ERROR_INVALID_PARAMETER != ret)
        {
            SDHC_CORE_HOST_CTRL1_R(base) = (uint8_t)_CLR_SET_FLD8U(SDHC_CORE_HOST_CTRL1_R(base),
                                          SDHC_CORE_HOST_CTRL1_R_HIGH_SPEED_EN,
                                          ((CY_SD_HOST_BUS_SPEED_HIGHSPEED == speedMode) ? 1UL : 0UL));

            SDHC_CORE_HOST_CTRL2_R(base) = (uint16_t)_CLR_SET_FLD16U(SDHC_CORE_HOST_CTRL2_R(base),
                                          SDHC_CORE_HOST_CTRL2_R_UHS_MODE_SEL,
                                          ultraHighSpeed);
        }
    }
    else
    {
        ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SetBusSpeedMode
****************************************************************************//**
*
*  Negotiates with the card to change the bus speed mode of the card
*  and the host. It doesn't change the SD clock frequency that must be done
*  separately.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param speedMode
*     Bus speed mode.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_SetBusSpeedMode(SDHC_Type *base,
                                                  cy_en_sd_host_bus_speed_mode_t speedMode,
                                                  cy_stc_sd_host_context_t const *context)
{
    cy_en_sd_host_status_t  ret = CY_SD_HOST_SUCCESS;
    uint32_t                highSpeedValue = CY_SD_HOST_DEFAULT_SPEED;
    uint32_t                cmdArgument = 0UL;
    uint32_t                response[CY_SD_HOST_RESPONSE_SIZE] = { 0UL };

    /* Check for the NULL pointer */
    if (NULL != base)
    {
        CY_ASSERT_L3(CY_SD_HOST_IS_SPEED_MODE_VALID(speedMode));

        /* 1. Does the card support memory? */
        if ((CY_SD_HOST_SD == context->cardType) ||
            (CY_SD_HOST_EMMC == context->cardType) ||
            (CY_SD_HOST_COMBO == context->cardType))
        {
            /* 2. Change Bus Speed Mode: Issue CMD6 with mode 1 */
            switch (speedMode)
            {
                case CY_SD_HOST_BUS_SPEED_EMMC_LEGACY:
                case CY_SD_HOST_BUS_SPEED_DEFAULT:
                case CY_SD_HOST_BUS_SPEED_SDR12_5:
                    highSpeedValue = CY_SD_HOST_SDR12_SPEED; /* Max clock = 25 MHz */
                    break;
                case CY_SD_HOST_BUS_SPEED_EMMC_HIGHSPEED_SDR:
                case CY_SD_HOST_BUS_SPEED_SDR25:
                case CY_SD_HOST_BUS_SPEED_HIGHSPEED:
                    highSpeedValue = CY_SD_HOST_SDR25_SPEED; /* Max clock = 50 MHz */
                    break;
                case CY_SD_HOST_BUS_SPEED_SDR50:
                    highSpeedValue = CY_SD_HOST_SDR50_SPEED; /* Max clock = 100 MHz */
                    break;
                default:
                    ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
                    break;
            }

            if (CY_SD_HOST_SUCCESS == ret)
            {
                if ((CY_SD_HOST_SD == context->cardType) ||
                    (CY_SD_HOST_COMBO == context->cardType))
                {
                    /* Set the mode bit to 1 and select the default function */
                    cmdArgument = (1UL << CY_SD_HOST_SWITCH_FUNCTION_BIT);

                    /* Set the High Speed/SDR25 bit */
                    cmdArgument |= highSpeedValue & 0xFUL;

                    /* Send CMD6 and parse response */
                    ret = Cy_SD_Host_SdCardSwitchFunc(base, cmdArgument, context->cardType);
                }
                else
                {
                    cmdArgument = (CY_SD_HOST_EMMC_ACCESS_WRITE_BYTE << CY_SD_HOST_EMMC_CMD6_ACCESS_OFFSET) |
                                      (CY_SD_HOST_EMMC_HS_TIMING_ADDR << CY_SD_HOST_EMMC_CMD6_IDX_OFFSET) |
                                      (highSpeedValue << CY_SD_HOST_EMMC_CMD6_VALUE_OFFSET) |
                                      (0x0UL << CY_SD_HOST_EMMC_CMD6_CMD_SET_OFFSET);

                    /* Send CMD6 */
                    ret = Cy_SD_Host_OpsSwitchFunc(base, cmdArgument);
                }
            }
        }

        /* 5. Is SDIO Supported? */
        if ((CY_SD_HOST_SDIO == context->cardType) ||
            (CY_SD_HOST_COMBO == context->cardType))
        {
            /* 6. Change Bus Speed Mode: Set EHS or BSS[2:0] in CCCR */
            ret = Cy_SD_Host_OpsSendIoRwDirectCmd(base,
                                                  0UL,
                                                  0UL,
                                                  0UL,
                                                  CY_SD_HOST_CCCR_SPEED_CONTROL,
                                                  0UL);

            (void)Cy_SD_Host_GetResponse(base, (uint32_t *)response, false);

            /* Check the SHS bit - the High Speed mode operation ability  */
            if (0UL != (response[0] & CY_SD_HOST_CCCR_SPEED_SHS_MASK))
            {
                switch (speedMode)
                {
                    case CY_SD_HOST_BUS_SPEED_DEFAULT:
                    case CY_SD_HOST_BUS_SPEED_SDR12_5:
                        /* BSS0 = 0, BSS1 = 0  */
                        break;
                    case CY_SD_HOST_BUS_SPEED_SDR25:
                    case CY_SD_HOST_BUS_SPEED_HIGHSPEED:
                        response[0] |= CY_SD_HOST_CCCR_SPEED_BSS0_MASK;
                        break;
                    case CY_SD_HOST_BUS_SPEED_SDR50:
                        response[0] |= CY_SD_HOST_CCCR_SPEED_BSS1_MASK;
                        break;
                    default:
                        ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
                        break;
                }

                /* Set the EHS bit to enable High Speed mode */
                if (CY_SD_HOST_SUCCESS == ret)
                {
                    highSpeedValue = response[0] & (CY_SD_HOST_CCCR_SPEED_BSS0_MASK |
                                             CY_SD_HOST_CCCR_SPEED_BSS1_MASK |
                                             CY_SD_HOST_CCCR_SPEED_SHS_MASK);

                    ret = Cy_SD_Host_OpsSendIoRwDirectCmd(base,
                                                          1UL,
                                                          0UL,
                                                          0UL,
                                                          CY_SD_HOST_CCCR_SPEED_CONTROL,
                                                          response[0]);

                    (void)Cy_SD_Host_GetResponse(base, (uint32_t *)response, false);

                    response[0] = response[0] & (CY_SD_HOST_CCCR_SPEED_BSS0_MASK |
                                   CY_SD_HOST_CCCR_SPEED_BSS1_MASK |
                                   CY_SD_HOST_CCCR_SPEED_SHS_MASK);

                    if(highSpeedValue != response[0])
                    {
                        ret = CY_SD_HOST_ERROR_UNINITIALIZED;
                    }
                }
            }
            else
            {
                /* The card can operate in High Speed mode only. */
            }
        }

        /* 3 and 7. Bus Speed Mode changed Successfully  */
        if (CY_SD_HOST_SUCCESS == ret)
        {
            /* 4 and 8. Set the same bus speed mode in the host controller */
            ret = Cy_SD_Host_SetHostSpeedMode(base, speedMode);
        }
    }
    else
    {
        ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SelBusVoltage
****************************************************************************//**
*
*  Negotiates with the SD card to change the bus signaling level to 1.8V.
*  After this function is called, the card is in the ready state.
*
* \note The host needs to change the regulator supplying voltage to
*       the VDDIO of the SD block in order to operate at 1.8V.
* \note This function changes RCA to 0 in the context. RCA in the context
*       should be updated (context.RCA = Cy_SD_Host_GetRca();)
*       when the card is in the Identification state.
* \note This function is applicable for SD cards only.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param enable18VSignal
*     If true, use the 1.8V signaling, false - use the 3.3V signaling.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
* If only the SD host functions which do not require context will be used, pass NULL
* as the pointer to the context.
*
* \return \ref cy_en_sd_host_status_t
*
* \note The SD card power supply should be disabled and initialized again when
*  this function returns CY_SD_HOST_ERROR_UNUSABLE_CARD.
*
* \note The dedicated io_volt_sel pin is used to change the regulator supplying
* voltage to the VDDIO of the SD block in order to operate at 1.8V. To configure
* the custom IO pin in order to control (using the GPIO driver) the regulator
* supplying voltage, the user must implement weak Cy_SD_Host_ChangeIoVoltage().
* Also, this function must set the SIGNALING_EN bit of the SDHC_CORE_HOST_CTRL2_R
* register when ioVoltage = CY_SD_HOST_IO_VOLT_1_8V.
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_SelBusVoltage(SDHC_Type *base,
                                                bool enable18VSignal,
                                                cy_stc_sd_host_context_t *context)
{
    cy_en_sd_host_status_t ret;
    uint32_t               ocrReg; /* The Operation Condition register. */
    uint32_t               s18aFlag = 0UL; /* The S18A flag. */
    bool                   f8Flag = false; /* The CMD8 flag. */
    bool                   mpFlag = false; /* The MEM flag. */

    context->RCA = 0UL;

    /* Send CMD0 and CMD8 commands. */
    f8Flag = Cy_SD_Host_VoltageCheck(base);

    /* Clear the insert event */
    Cy_SD_Host_NormalReset(base);

    /* Send ACMD41 */
    ret = Cy_SD_Host_SdOcr(base,
                           enable18VSignal,
                           &s18aFlag,
                           &mpFlag,
                           f8Flag,
                           &ocrReg,
                           context);

    if ((CY_SD_HOST_SUCCESS == ret) && (enable18VSignal) && (1UL == s18aFlag))
    {
        /* Voltage switch (CMD11). */
        ret = Cy_SD_Host_OpsVoltageSwitch(base, context);
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_EnableCardVoltage
****************************************************************************//**
*
*  Sets the card_if_pwr_en pin high.
*  This pin can be used to enable a voltage regulator used to power the card.
*
* \param *base
*     The SD host registers structure pointer.
*
*******************************************************************************/
__WEAK void Cy_SD_Host_EnableCardVoltage(SDHC_Type *base)
{
    SDHC_CORE_PWR_CTRL_R(base) = _CLR_SET_FLD8U(SDHC_CORE_PWR_CTRL_R(base), SDHC_CORE_PWR_CTRL_R_SD_BUS_PWR_VDD1, 1UL);
}


/*******************************************************************************
* Function Name: Cy_SD_Host_DisableCardVoltage
****************************************************************************//**
*
*  Sets the card_if_pwr_en pin low.
*  This pin can be used to disable a voltage regulator used to power the card.
*
* \param *base
*     The SD host registers structure pointer.
*
*******************************************************************************/
__WEAK void Cy_SD_Host_DisableCardVoltage(SDHC_Type *base)
{

    SDHC_CORE_PWR_CTRL_R(base) = _CLR_SET_FLD8U(SDHC_CORE_PWR_CTRL_R(base), SDHC_CORE_PWR_CTRL_R_SD_BUS_PWR_VDD1, 0UL);
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetResponse
****************************************************************************//**
*
* This function reads the response register from the last completed command.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *responsePtr
*     The pointer to response data.
*
* \param largeResponse
*     If true, the response is 136 bits, false - 32 bits.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t  Cy_SD_Host_GetResponse(SDHC_Type const *base,
                                               uint32_t *responsePtr,
                                               bool largeResponse)
{
    cy_en_sd_host_status_t  ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    volatile uint32_t const *responseBaseAddr;
    uint8_t                 i;
    uint8_t                 responseLength = (true == largeResponse) ? CY_SD_HOST_RESPONSE_SIZE : 1U;

    if ((NULL != base) &&
        (NULL != responsePtr))
    {
        /* Get the Response Register 0 address */
        responseBaseAddr = &SDHC_CORE_RESP01_R(base);

        /* Read the largeResponse Response registers values */
        for (i = 0U; i < responseLength; i++)
        {
            *responsePtr = *responseBaseAddr;
            responsePtr++;
            responseBaseAddr++;
        }

        ret = CY_SD_HOST_SUCCESS;
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_InitDataTransfer
****************************************************************************//**
*
*  Initializes the SD block for a data transfer. It does not start a transfer.
*  To start a transfer call Cy_SD_Host_SendCommand() after calling this function.
*  If DMA is not used for data transfer, the buffer needs to be filled
*  with data first if this is a write.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param dataConfig
*     The pointer to the data transfer configuration structure.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_InitDataTransfer(SDHC_Type *base,
                                                   cy_stc_sd_host_data_config_t const *dataConfig)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_SUCCESS;
    uint32_t               dmaMode;
    uint32_t               transferMode;

    if ((NULL != base) && (NULL != dataConfig) && (NULL != dataConfig->data))
    {
        CY_ASSERT_L3(CY_SD_HOST_IS_AUTO_CMD_VALID(dataConfig->autoCommand));
        CY_ASSERT_L2(CY_SD_HOST_IS_TIMEOUT_VALID(dataConfig->dataTimeout));
        CY_ASSERT_L2(CY_SD_HOST_IS_BLK_SIZE_VALID(dataConfig->blockSize));

        dmaMode = _FLD2VAL(SDHC_CORE_HOST_CTRL1_R_DMA_SEL, SDHC_CORE_HOST_CTRL1_R(base));

        SDHC_CORE_BLOCKSIZE_R(base) = 0U;
        SDHC_CORE_XFER_MODE_R(base) = 0U;

        if (((uint32_t)CY_SD_HOST_DMA_ADMA2_ADMA3 == dmaMode) && (dataConfig->enableDma))
        {
            /* ADMA3 Integrated Descriptor Address. */
            SDHC_CORE_ADMA_ID_LOW_R(base) = (uint32_t)dataConfig->data;
        }
        else
        {
            if (dataConfig->enableDma)
            {
                /* Set the ADMA descriptor table. */
                if ((uint32_t)CY_SD_HOST_DMA_SDMA == dmaMode)
                {
                    /* Set 512K bytes SDMA Buffer Boundary. */
                    SDHC_CORE_BLOCKSIZE_R(base) = _CLR_SET_FLD16U(SDHC_CORE_BLOCKSIZE_R(base),
                                                  SDHC_CORE_BLOCKSIZE_R_SDMA_BUF_BDARY,
                                                  CY_SD_HOST_SDMA_BUF_BYTES_512K);

                    if (true == _FLD2BOOL(SDHC_CORE_HOST_CTRL2_R_HOST_VER4_ENABLE, SDHC_CORE_HOST_CTRL2_R(base)))
                    {
                        /* The data address. */
                        SDHC_CORE_ADMA_SA_LOW_R(base) = (uint32_t)dataConfig->data;

                        /* Set the block count. */
                        SDHC_CORE_SDMASA_R(base) = dataConfig->numberOfBlock;
                    }
                    else
                    {
                        /* The data address. */
                        SDHC_CORE_SDMASA_R(base) = (uint32_t)dataConfig->data;
                    }
                }
                else
                {
                    /* The data address. */
                    SDHC_CORE_ADMA_SA_LOW_R(base) = (uint32_t)dataConfig->data;
                }
            }
            else
            {
                /* Set the block count. */
                SDHC_CORE_SDMASA_R(base) = dataConfig->numberOfBlock;
            }

            /* Set the block size. */
            SDHC_CORE_BLOCKSIZE_R(base) = _CLR_SET_FLD16U(SDHC_CORE_BLOCKSIZE_R(base),
                                          SDHC_CORE_BLOCKSIZE_R_XFER_BLOCK_SIZE,
                                          dataConfig->blockSize);

            /* Set the block count. */
            SDHC_CORE_BLOCKCOUNT_R(base) = (uint16_t)dataConfig->numberOfBlock;


            /* Set a multi- or single-block transfer.*/
            transferMode = _BOOL2FLD(SDHC_CORE_XFER_MODE_R_MULTI_BLK_SEL, (1U < dataConfig->numberOfBlock));

            /* Set the data transfer direction. */
            transferMode |= _BOOL2FLD(SDHC_CORE_XFER_MODE_R_DATA_XFER_DIR, dataConfig->read);

            /* Set the block count enable. */
            transferMode |= SDHC_CORE_XFER_MODE_R_BLOCK_COUNT_ENABLE_Msk;

            /* Enable the DMA or not. */
            transferMode |= _BOOL2FLD(SDHC_CORE_XFER_MODE_R_DMA_ENABLE, dataConfig->enableDma);

            /* Set an interrupt at the block gap. */
            SDHC_CORE_BGAP_CTRL_R(base) = (uint8_t)_CLR_SET_FLD8U(SDHC_CORE_BGAP_CTRL_R(base),
                                          SDHC_CORE_BGAP_CTRL_R_INT_AT_BGAP,
                                          ((dataConfig->enableIntAtBlockGap) ? 1UL : 0UL));

            /* Set the data timeout (Base clock*2^27). */
            SDHC_CORE_TOUT_CTRL_R(base) = _CLR_SET_FLD8U(SDHC_CORE_TOUT_CTRL_R(base),
                                                    SDHC_CORE_TOUT_CTRL_R_TOUT_CNT,
                                                    dataConfig->dataTimeout);

            /* The reliable write setting. */
            if (dataConfig->enReliableWrite)
            {
                ret = Cy_SD_Host_OpsSetBlockCount(base,
                                                  dataConfig->enReliableWrite,
                                                  dataConfig->numberOfBlock);
            }

            /* The auto-command setting. */
            switch (dataConfig->autoCommand)
            {
                case CY_SD_HOST_AUTO_CMD_NONE:
                    transferMode |= _VAL2FLD(SDHC_CORE_XFER_MODE_R_AUTO_CMD_ENABLE, 0UL);
                    break;
                case CY_SD_HOST_AUTO_CMD_12:
                    transferMode |= _VAL2FLD(SDHC_CORE_XFER_MODE_R_AUTO_CMD_ENABLE, 1UL);
                    break;
                case CY_SD_HOST_AUTO_CMD_23:
                    transferMode |= _VAL2FLD(SDHC_CORE_XFER_MODE_R_AUTO_CMD_ENABLE, 2UL);
                    break;
                case CY_SD_HOST_AUTO_CMD_AUTO:
                    transferMode |= _VAL2FLD(SDHC_CORE_XFER_MODE_R_AUTO_CMD_ENABLE, 3UL);
                    break;
                default:
                    ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
                    break;
            }

            SDHC_CORE_XFER_MODE_R(base) = (uint16_t)transferMode;
        }
    }

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_ChangeIoVoltage
****************************************************************************//**
*
*  Changes the logic level on the sd_io_volt_sel line. It assumes that
*  this line is used to control a regulator connected to the VDDIO of the PSoC.
*  This regulator allows for switching between the 3.3V and 1.8V signaling.
*
* \note The dedicated io_volt_sel pin is used to change the regulator supplying
* voltage to the VDDIO of the SD block in order to operate at 1.8V. To configure
* the custom IO pin in order to control (using the GPIO driver) the regulator
* supplying voltage, the user must implement weak Cy_SD_Host_ChangeIoVoltage().
* Also, this function must set the SIGNALING_EN bit of the SDHC_CORE_HOST_CTRL2_R
* register when ioVoltage = CY_SD_HOST_IO_VOLT_1_8V.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param ioVoltage
*     The voltage for IO.
*
*******************************************************************************/
__WEAK void Cy_SD_Host_ChangeIoVoltage(SDHC_Type *base, cy_en_sd_host_io_voltage_t ioVoltage)
{
    /* Set the 1.8V signaling enable. */
    SDHC_CORE_HOST_CTRL2_R(base) = _CLR_SET_FLD16U(SDHC_CORE_HOST_CTRL2_R(base),
                                              SDHC_CORE_HOST_CTRL2_R_SIGNALING_EN,
                                              (CY_SD_HOST_IO_VOLT_1_8V == ioVoltage) ? 1UL : 0UL);
}


/*******************************************************************************
* Function Name: Cy_SD_Host_IsCardConnected
****************************************************************************//**
*
*  Checks to see if a card is currently connected.
*
* \note You can use any GPIO custom pin for Card Detect. Add the SD Host driver
* Cy_SD_Host_IsCardConnected() function with the __WEAK type to your code.
* This function could read the value from any GPIO pin and return true when
* the card is connected.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return bool
*     true - the card is connected, false - the card is removed (not connected).
*
*******************************************************************************/
__WEAK bool Cy_SD_Host_IsCardConnected(SDHC_Type const *base)
{
    while(true != _FLD2BOOL(SDHC_CORE_PSTATE_REG_CARD_STABLE, SDHC_CORE_PSTATE_REG(base)))
    {
        /* Wait until the card is stable. */
    }

    return _FLD2BOOL(SDHC_CORE_PSTATE_REG_CARD_INSERTED, SDHC_CORE_PSTATE_REG(base));
}


/*******************************************************************************
* Function Name: Cy_SD_Host_SoftwareReset
****************************************************************************//**
*
*  Issues the software reset command to the SD card.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param reset
*     The reset type.
*
*******************************************************************************/
void Cy_SD_Host_SoftwareReset(SDHC_Type *base,
                              cy_en_sd_host_reset_t reset)
{
    switch (reset)
    {
        case CY_SD_HOST_RESET_DATALINE:
            SDHC_CORE_SW_RST_R(base) = (uint8_t)_VAL2FLD(SDHC_CORE_SW_RST_R_SW_RST_DAT, 1UL);

            while(false != _FLD2BOOL(SDHC_CORE_SW_RST_R_SW_RST_DAT, SDHC_CORE_SW_RST_R(base)))
            {
                /* Wait until the reset completes. */
            }

            break;
        case CY_SD_HOST_RESET_CMD_LINE:
            SDHC_CORE_SW_RST_R(base) = (uint8_t)_VAL2FLD(SDHC_CORE_SW_RST_R_SW_RST_CMD, 1UL);

            while(false != _FLD2BOOL(SDHC_CORE_SW_RST_R_SW_RST_CMD, SDHC_CORE_SW_RST_R(base)))
            {
                /* Wait until the reset completes. */
            }

            break;
        case CY_SD_HOST_RESET_ALL:

            SDHC_CORE_CLK_CTRL_R(base) = 0U;

            /* Wait for at least 3 card clock periods */
            Cy_SysLib_DelayUs(CY_SD_HOST_3_PERIODS_US);

            SDHC_CORE_SW_RST_R(base) = (uint8_t)_VAL2FLD(SDHC_CORE_SW_RST_R_SW_RST_ALL, 1UL);

            while(false != _FLD2BOOL(SDHC_CORE_SW_RST_R_SW_RST_ALL, SDHC_CORE_SW_RST_R(base)))
            {
                /* Wait until the reset completes. */
            }

            /* Enable the Internal clock. */
            SDHC_CORE_CLK_CTRL_R(base) = (uint16_t)_CLR_SET_FLD16U(SDHC_CORE_CLK_CTRL_R(base),
                                            SDHC_CORE_CLK_CTRL_R_INTERNAL_CLK_EN,
                                            1UL);

            while(true != _FLD2BOOL(SDHC_CORE_CLK_CTRL_R_INTERNAL_CLK_STABLE, SDHC_CORE_CLK_CTRL_R(base)))
            {
                /* Wait for the stable Internal Clock. */
            }

            break;
        default:
            /* Unknown Reset selection*/
            break;
    }
}


/*******************************************************************************
* Function Name: Cy_SD_Host_GetPresentState
****************************************************************************//**
*
*  Returns the values of the present state register.
*
* \param *base
*     The SD host registers structure pointer.
*
* \return The value of the present state register.
*
*******************************************************************************/
uint32_t Cy_SD_Host_GetPresentState(SDHC_Type const *base)
{
    uint32_t ret;

    ret = SDHC_CORE_PSTATE_REG(base);

    return ret;
}


/*******************************************************************************
* Function Name: Cy_SD_Host_DeepSleepCallback
****************************************************************************//**
*
* This function handles the transition of the SD Host into and out of
* Deep Sleep mode. It disables SD CLK before going to Deep Sleep mode and
* enables SD CLK after wake up from Deep Sleep mode.
* If the DAT line is active, or a read (write) transfer is being executed on
* the bus, the device cannot enter Deep Sleep mode.
*
* This function must be called during execution of \ref Cy_SysPm_CpuEnterDeepSleep.
* To do it, register this function as a callback before calling
* \ref Cy_SysPm_CpuEnterDeepSleep : specify \ref CY_SYSPM_DEEPSLEEP as the callback
* type and call \ref Cy_SysPm_RegisterCallback.
*
* \note When waking up from Deep Sleep, the SD Host driver requires up to 1 us
* for clock stabilization. By default the SD Host driver will wait this length
* of time on power up. The waiting loop is implemented in this function.
* If the application is time sensitive this delay can be overridden by the
* application by defining \ref CY_SD_HOST_CLK_RAMP_UP_TIME_US_WAKEUP.
* This allows the application to perform other operations while the clock
* is stabilizing in the background. However, the application must still make sure
* that the SD Host clock has had time to stabilize before attempting to use the
* SD card. The recommended way to override the value is to specify this as
* a custom define on the compiler command line. This can be done by appending
* the entry to the DEFINES variable in the application Makefile.
* Eg: DEFINES+=CY_SD_HOST_CLK_RAMP_UP_TIME_US_WAKEUP=40.
*
* \param callbackParams
* The pointer to the callback parameters structure
* \ref cy_stc_syspm_callback_params_t.
*
* \param mode
* Callback mode, see \ref cy_en_syspm_callback_mode_t
*
* \return
* \ref cy_en_syspm_status_t
*
*******************************************************************************/
cy_en_syspm_status_t Cy_SD_Host_DeepSleepCallback(cy_stc_syspm_callback_params_t *callbackParams,
                                                  cy_en_syspm_callback_mode_t mode)
{
    cy_en_syspm_status_t ret = CY_SYSPM_FAIL;
    SDHC_Type *locBase = (SDHC_Type *) (callbackParams->base);

    switch(mode)
    {
        case CY_SYSPM_CHECK_READY:
        {
            /* Check DAT Line Active */
            uint32_t pState = Cy_SD_Host_GetPresentState(locBase);
            if ((CY_SD_HOST_DAT_LINE_ACTIVE != (pState & CY_SD_HOST_DAT_LINE_ACTIVE)) &&
                (CY_SD_HOST_CMD_CMD_INHIBIT_DAT != (pState & CY_SD_HOST_CMD_CMD_INHIBIT_DAT)))
            {
                ret = CY_SYSPM_SUCCESS;
            }
        }
        break;

        case CY_SYSPM_CHECK_FAIL:
        {
            ret = CY_SYSPM_SUCCESS;
        }
        break;

        case CY_SYSPM_BEFORE_TRANSITION:
        {
            /* Disable SD CLK before going to Deep Sleep mode */
            Cy_SD_Host_DisableSdClk(locBase);

            ret = CY_SYSPM_SUCCESS;
        }
        break;

        case CY_SYSPM_AFTER_TRANSITION:
        {
            /* Enable SD CLK after wake up from Deep Sleep mode */
            Cy_SD_Host_EnableSdClk(locBase);

            /* Wait for the stable CLK */
            Cy_SysLib_DelayUs(CY_SD_HOST_CLK_RAMP_UP_TIME_US_WAKEUP);

            ret = CY_SYSPM_SUCCESS;
        }
        break;

        default:
            /* Unknown state */
            break;
    }

    return (ret);
}

/*******************************************************************************
* Function Name: Cy_SD_Host_GetBlockCount
****************************************************************************//**
*
*  Returns the Block count in SD/eMMC Card.
*
* \param *base
*     The SD host registers structure pointer.
*
* \param *block_count
*     The pointer to store the block_count.
*
* \param context
* The pointer to the context structure \ref cy_stc_sd_host_context_t allocated
* by the user. The structure is used during the SD host operation for internal
* configuration and data retention. The user must not modify anything
* in this structure.
*
* \return \ref cy_en_sd_host_status_t
*
*******************************************************************************/
cy_en_sd_host_status_t Cy_SD_Host_GetBlockCount(SDHC_Type *base,
                                         uint32_t *block_count,
                                         cy_stc_sd_host_context_t *context)
{
    cy_en_sd_host_status_t ret = CY_SD_HOST_SUCCESS;

    /* Check for the NULL pointer */
    if ((NULL != base) && (NULL != block_count) && (NULL != context))
    {
        if ((CY_SD_HOST_SD == context->cardType) || (CY_SD_HOST_EMMC == context->cardType))
        {
            *block_count = context->maxSectorNum;
        }
    }
    else
    {
        ret = CY_SD_HOST_ERROR_INVALID_PARAMETER;
    }

    return ret;
}


CY_MISRA_BLOCK_END('MISRA C-2012 Rule 18.1');

#if defined(__cplusplus)
}
#endif

#endif /* CY_IP_MXSDHC */

/* [] END OF FILE */