text: /**
   * @file sdmmc_block_private_spi.c
   * @date 2016-04-25
   *
   * NOTE:
   * This file is generated by DAVE. Any manual modification done to this file will be lost when the code is regenerated.
   *
   * @cond
   ***********************************************************************************************************************
   * SDMMC_BLOCK_SPI v4.0.10 - Configures the SPI channel to interface the SDMMC card.
   *
   * Copyright (c) 2016, Infineon Technologies AG
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without modification,are permitted provided that the
   * following conditions are met:
   *
   *   Redistributions of source code must retain the above copyright notice, this list of conditions and the  following
   *   disclaimer.
   *
   *   Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
   *   following disclaimer in the documentation and/or other materials provided with the distribution.
   *
   *   Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
   *   products derived from this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE  FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT  OF THE
   * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes
   * with Infineon Technologies AG (dave@infineon.com).
   ***********************************************************************************************************************
   *
   * Change History
   * --------------
   *
   * 2016-01-20:
   *     - Initial version. <br>
   *
   * 2016-02-08:
   *     - Help Doc updated. <br>
   *     - Bug fixes done.<br>
   *
   * 2016-04-05:
   *     - Return status updates are done. <br>
   *     - SDMMC_BLOCK_SPI_lUpdateCardInfo() is splitted in to SDMMC_BLOCK_SPI_lReadCid() and
   *       SDMMC_BLOCK_SPI_lReadCsd.
   *     - SDMMC_BLOCK_SPI_lEraseTimeOut() is added for erase operation to check for timeout.
   *       if card is not able to finish the operation with in the time, returns as failure.
   *     - SDMMC_BLOCK_SPI_TEST_HOOK_SendCommand() is added for to cover the cases by emulating the hardware failures.
   *       This is enabled during testing only.
   *     - MISRA fixes.
   *     - Bug fixes done for PR.<br>
   *
   * @endcond
   *
   */
  
  /***********************************************************************************************************************
    * HEADER FILES
  **********************************************************************************************************************/
  
  #include "sdmmc_block.h"
  #include "sdmmc_block_private_spi.h"
  
  /***********************************************************************************************************************
    * MACROS
  **********************************************************************************************************************/
  
  #ifdef SDMMC_BLOCK_SPI
  #define SDMMC_BLOCK_SPI_CLK_TRAIN_MAX_CNT  (10U)
  #define SDMMC_BLOCK_SPI_DUMMY_READ_MAX_CNT (4U)
  #define SDMMC_BLOCK_SPI_INIT_SPEED         (300000U)
  #define SDMMC_BLOCK_SPI_PARAM_ERROR        (0x40U)
  
  /***********************************************************************************************************************
    * LOCAL DATA
  **********************************************************************************************************************/
  
  
  /***********************************************************************************************************************
    * LOCAL ROUTINES
  **********************************************************************************************************************/
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lInitializeCard(SDMMC_BLOCK_t *const obj);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lErase(const SDMMC_BLOCK_t *const obj,
                                                          const uint32_t start_address,
                                                          const uint32_t end_address,
                                                          const uint32_t timeout_val);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lWriteSingleBlock(const SDMMC_BLOCK_t *const obj,
                                                                     uint8_t *write_buf,
                                                                     const uint32_t write_address);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lWriteMultipleBlocks(const SDMMC_BLOCK_t *const obj,
                                                                        uint8_t *write_buf,
                                                                        const uint32_t write_address,
                                                                        const uint32_t sector_count);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadMultipleBlocks(SDMMC_BLOCK_t *const obj,
                                                                       uint8_t *read_buf,
                                                                       const uint32_t read_address,
                                                                       const uint32_t sector_count);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadSingleBlock(SDMMC_BLOCK_t *const obj,
                                                                    uint8_t *read_buf,
                                                                    const uint32_t read_address);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lQueryOperatingCondVoltage(SDMMC_BLOCK_t *const obj);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSDV1OperatingCondVoltage(SDMMC_BLOCK_t *const obj);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSDV2OperatingCondVoltage(SDMMC_BLOCK_t *const obj);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadCid(SDMMC_BLOCK_t *const obj);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadCsd(SDMMC_BLOCK_t *const obj);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadCardRegister(SDMMC_BLOCK_SPI_t *const obj,
                                                                     uint8_t *buffer,
                                                                     const uint32_t buffer_length);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSendCommand(const SDMMC_BLOCK_t *const obj,
                                                                const uint8_t cmd,
                                                                const uint32_t arg);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSendACMD41(const SDMMC_BLOCK_t *const obj, const uint32_t arg);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadData(SDMMC_BLOCK_SPI_t *const obj,
                                                             uint8_t *response_data,
                                                             const uint32_t num_of_bytes);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSendData(SDMMC_BLOCK_SPI_t *const obj,
                                                             uint8_t *transmit_data,
                                                             const uint32_t num_of_bytes);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lCheckSectorBound(SDMMC_BLOCK_t *const obj,
                                                                     const uint32_t sector_number,
                                                                     const uint32_t sector_count);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSetSpeed(SPI_MASTER_t *const obj,
                                                             const uint32_t baud_rate);
  
  static void SDMMC_BLOCK_SPI_lGetWriteProtect(SDMMC_BLOCK_t *const obj);
  
  static void SDMMC_BLOCK_SPI_lDummyRead(SDMMC_BLOCK_SPI_t *const obj, uint32_t count);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lWaitUntilBusy(SDMMC_BLOCK_SPI_t *const obj);
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lEraseTimeOut(SDMMC_BLOCK_SPI_t *const obj,
                                                                 const uint32_t timeout_val);
  
  static void SDMMC_BLOCK_SPI_lSend_Clocktrain(SDMMC_BLOCK_SPI_t* const obj, uint32_t count);
  
  #ifdef SDMMC_BLOCK_TEST_HOOK_ENABLE
  __WEAK SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_TEST_HOOK_SendCommand(const SDMMC_BLOCK_t *const obj,
                                                                         const uint8_t cmd,
                                                                         const SDMMC_BLOCK_MODE_STATUS_t state);
  #endif
  
  
  /**********************************************************************************************************************
    * API IMPLEMENTATION
  **********************************************************************************************************************/
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_Init(SDMMC_BLOCK_t *const obj)
  {
    SPI_MASTER_STATUS_t spi_status;
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
  
    spi_status = SPI_MASTER_Init(obj->sdmmc_spi->spi_master_handle);
  
    if (spi_status != SPI_MASTER_STATUS_SUCCESS)
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_CardIdentificationProcess(SDMMC_BLOCK_t *const obj)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
  
    if (obj->sdmmc_spi->mode_init_flag == 1U)
    {
      status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
    }
    else
    {
      status = SDMMC_BLOCK_SPI_lInitializeCard(obj);
      if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
      {
        obj->sdmmc_spi->mode_init_flag = 1U;
      }
    }
  
    return status;
  }
  
  SDMMC_BLOCK_STATUS_t SDMMC_BLOCK_SPI_ReadBlock(SDMMC_BLOCK_t *const obj,
                                                 uint8_t *read_buf,
                                                 const uint32_t sector_number,
                                                 const uint32_t sector_count)
  {
    SDMMC_BLOCK_STATUS_t status = SDMMC_BLOCK_STATUS_FAILURE;
    SDMMC_BLOCK_MODE_STATUS_t mode_status;
  
    SDMMC_BLOCK_SPI_t* spi_handle;
    uint32_t read_address;
    uint32_t tmp_blk_cnt;
  
    if ((obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_NOT_INITIALIZED) != (uint8_t)0U)
    {
      status = SDMMC_BLOCK_STATUS_NOTRDY;
    }
    else if ((obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED) != (uint8_t)0U)
    {
      status = SDMMC_BLOCK_STATUS_LOCKED;
    }
    else
    {
  #ifdef SDMMC_BLOCK_SPI_CARD_LED_SIGNAL
      if (obj->led != NULL)
      {
        XMC_GPIO_SetOutputHigh(obj->led->port, obj->led->pin);
      }
  #endif
      mode_status = SDMMC_BLOCK_SPI_lCheckSectorBound(obj, sector_number, sector_count);
  
      if (mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
      {
        tmp_blk_cnt = sector_count;
        read_address = sector_number;
        spi_handle = obj->sdmmc_spi;
  
        /* Block Addressing or Byte Addressing */
        if ((uint32_t)(obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_BLOCK_ADDRESSING) ==  (uint32_t)0)
        {
          read_address = (uint32_t)(sector_number * SDMMC_BLOCK_SPI_BYTES_PER_SECTOR);
        }
  
        if (tmp_blk_cnt == 1U)
        {
          mode_status = SDMMC_BLOCK_SPI_lReadSingleBlock(obj, read_buf, read_address);
        }
        else
        {
          mode_status = SDMMC_BLOCK_SPI_lReadMultipleBlocks(obj, read_buf, read_address, sector_count);
        }
  
        /* Send Extra 8 Cycles */
        SDMMC_BLOCK_SPI_lSend_Clocktrain(spi_handle, 1U);
  
        mode_status = (SDMMC_BLOCK_MODE_STATUS_t)((uint32_t)mode_status |
                                                  (uint32_t)SDMMC_BLOCK_SPI_lWaitUntilBusy(spi_handle));
  
        if (mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
          status = SDMMC_BLOCK_STATUS_SUCCESS;
        }
      }
      else
      {
        status = SDMMC_BLOCK_STATUS_PARERR;
      }
  #ifdef SDMMC_BLOCK_SPI_CARD_LED_SIGNAL
      if (obj->led != NULL)
      {
        XMC_GPIO_SetOutputLow(obj->led->port, obj->led->pin);
      }
  #endif
    }
  
    return status;
  }
  
  SDMMC_BLOCK_STATUS_t SDMMC_BLOCK_SPI_WriteBlock(SDMMC_BLOCK_t *const obj,
                                                  uint8_t *write_buf,
                                                  const uint32_t sector_number,
                                                  const uint32_t sector_count)
  {
    SDMMC_BLOCK_STATUS_t status = SDMMC_BLOCK_STATUS_FAILURE;
    SDMMC_BLOCK_MODE_STATUS_t mode_status;
    uint32_t write_address;
    SDMMC_BLOCK_SPI_t* spi_handle;
  
    uint32_t tmp_blk_cnt; /* Added to avoid the update of the input variable inside the code */
  
    if ((obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_NOT_INITIALIZED) != 0U)
    {
      status = SDMMC_BLOCK_STATUS_NOTRDY;
    }
    else if ((obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED) != (uint8_t)0U)
    {
      status = SDMMC_BLOCK_STATUS_LOCKED;
    }
    else
    {
      if ((obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_WRITE_PROTECTED) != 0U)
      {
        status = SDMMC_BLOCK_STATUS_WRPRT;
      }
  #ifdef SDMMC_BLOCK_CARD_WRITE_PROTECT_SIGNAL
      else if ((obj->sdwc != NULL) && (XMC_GPIO_GetInput(obj->sdwc->port, obj->sdwc->pin)))
      {
        status = SDMMC_BLOCK_STATUS_WRPRT;
      }
  #endif
      else
      {
  #ifdef SDMMC_BLOCK_SPI_CARD_LED_SIGNAL
        if (obj->led != NULL)
        {
          XMC_GPIO_SetOutputHigh(obj->led->port, obj->led->pin);
        }
  #endif
        mode_status = SDMMC_BLOCK_SPI_lCheckSectorBound(obj, sector_number, sector_count);
  
        if (mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
          tmp_blk_cnt = sector_count;
          write_address = sector_number;
          spi_handle = obj->sdmmc_spi;
  
          /* Block Addressing or Byte Addressing */
          if ((uint32_t)(obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_BLOCK_ADDRESSING) ==  (uint32_t)0)
          {
            write_address = (uint32_t)(sector_number * SDMMC_BLOCK_SPI_BYTES_PER_SECTOR);
          }
  
          if (tmp_blk_cnt == 1U)
          {
            mode_status = SDMMC_BLOCK_SPI_lWriteSingleBlock(obj, write_buf, write_address);
          }
          else
          {
            mode_status = SDMMC_BLOCK_SPI_lWriteMultipleBlocks(obj, write_buf, write_address, sector_count);
          }
  
          SDMMC_BLOCK_SPI_lDummyRead(spi_handle, 2U); /* Dummy Bytes */
  
          SDMMC_BLOCK_SPI_lSend_Clocktrain(spi_handle, 1U);
  
          mode_status = (SDMMC_BLOCK_MODE_STATUS_t)((uint32_t)mode_status | 
                                                    (uint32_t)SDMMC_BLOCK_SPI_lWaitUntilBusy(spi_handle));
  
          if (mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
          {
            status = SDMMC_BLOCK_STATUS_SUCCESS;
          }
        }
        else
        {
          status = SDMMC_BLOCK_STATUS_PARERR;
        }
  #ifdef SDMMC_BLOCK_SPI_CARD_LED_SIGNAL
        if (obj->led != NULL)
        {
          XMC_GPIO_SetOutputLow(obj->led->port, obj->led->pin);
        }
  #endif
      }
    }
  
    return status;
  }
  
  /*
    * The function is used to erase data from the card.
  */
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_EraseBlock(SDMMC_BLOCK_t *const obj,
                                                       const uint32_t start_address,
                                                       const uint32_t end_address)
  {
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    uint32_t tmp_start_addr;
    uint32_t num_of_sectors = 0UL;
    /* Allocation Unit to No. of Sectors in 1 AU table mapping*/
    uint32_t au_to_sectors[10] = { 0UL,   32UL,  64UL,  128UL,  256UL,
                                   512UL, 1024UL, 2048UL, 4096UL, 8192UL
                                 };
    uint32_t erase_size = 0U;
    uint32_t erase_offset = 0U;
    uint32_t erase_timeout = 0U;
    uint32_t au_size = 0U;
    uint32_t sectors_in_au = 0UL;
    uint32_t sectors_in_erase_cluster = 0U;
    /* Read SD Status  */
    uint8_t *sd_status;
    uint32_t erase_timeout_per_cluster = 0U;
  
    if ((obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_WRITE_PROTECTED) != 0U)
    {
      status = SDMMC_BLOCK_MODE_STATUS_WP_VIOLATION_ERROR;
    }
  #ifdef SDMMC_BLOCK_CARD_WRITE_PROTECT_SIGNAL
    else if ((obj->sdwc != NULL) && (XMC_GPIO_GetInput(obj->sdwc->port, obj->sdwc->pin)))
    {
      status = SDMMC_BLOCK_MODE_STATUS_WP_VIOLATION_ERROR;
    }
  #endif
    else
    {
      tmp_start_addr = start_address;
      num_of_sectors = (end_address - tmp_start_addr) + 1U;
  
  #ifdef SDMMC_BLOCK_SPI_CARD_LED_SIGNAL
      if (obj->led != NULL)
      {
        XMC_GPIO_SetOutputHigh(obj->led->port, obj->led->pin);
      }
  #endif
      /* Check Sector number is not out of bound */
      status = SDMMC_BLOCK_SPI_lCheckSectorBound(obj, tmp_start_addr, num_of_sectors);
  
      if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
      {
        sd_status = obj->sdmmc_spi->card_info.sd_status;
        /* Erase Timeout Calculation */
        /* Get SD Status */
        status  = SDMMC_BLOCK_SPI_GetSdStatus(obj, sd_status);
  
        if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
          /*
           * Using Nth Byte = 7 + (N-1) * 8 Logic Here ..
           * This gives the MSB bit number of the Nth Byte.
           * Ex: 51st Byte ---- =  7 + (51 -1)*8
           * 407 is the MSB bit of the 51st Byte.
           * Here 51st byte means 50th byte if we take 0th byte as first byte.
           * 407,406,405,404,403,402,401,400
           */
          /* Bits 400-401 in SD status is Erase Offset */
          erase_offset = ((uint32_t)sd_status[50] & 0x03U);
  
          /* Bits 402-407 in SD status is Erase Timeout */
          erase_timeout = (((uint32_t) sd_status[50] & 0xFCU) >> 2U);
  
          /* Bits 408-423 in SD status is Erase Size */
          erase_size =  (((uint32_t) sd_status[51] & 0xFFU) | (((uint32_t) sd_status[52] & 0xFFU) << 8U));
  
          /* Bits 428-431 in SD status is Allocation unit Size*/
          au_size  =  (((uint32_t)sd_status[53] & 0xF0U) >> 4U);
  
          /* Erase Timeout Calculations */
          erase_timeout_per_cluster = (erase_timeout / erase_size) + erase_offset ;
  
          /* Number of Sectors in 1AU */
          sectors_in_au = au_to_sectors[au_size];
  
          sectors_in_erase_cluster = sectors_in_au * erase_size;
  
          while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (num_of_sectors >= sectors_in_erase_cluster))
          {
            status = SDMMC_BLOCK_SPI_lErase(obj,
                                            tmp_start_addr,
                                            (tmp_start_addr + sectors_in_erase_cluster),
                                            erase_timeout_per_cluster);
  
            tmp_start_addr  = tmp_start_addr + sectors_in_erase_cluster;
            num_of_sectors = num_of_sectors - sectors_in_erase_cluster;
          }
          if (num_of_sectors != 0UL )
          {
            status = SDMMC_BLOCK_SPI_lErase(obj, tmp_start_addr, end_address, erase_timeout_per_cluster);
          }
        }
      }
  #ifdef SDMMC_BLOCK_SPI_CARD_LED_SIGNAL
      if (obj->led != NULL)
      {
        XMC_GPIO_SetOutputHigh(obj->led->port, obj->led->pin);
      }
  #endif
    }
    return status;
  }
  
  /*
    * This function is use to get number of sectors present on the card.
  */
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_GetSectorCount(SDMMC_BLOCK_t *const obj, uint32_t *sector_count)
  {
    uint32_t multiplier = 0U;
  
    if (((uint32_t)obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_HIGH_CAPACITY) != (uint32_t)0)
    {
      SDMMC_BLOCK_SDV2_CSD_t *tmp_csd = (SDMMC_BLOCK_SDV2_CSD_t *)&obj->sdmmc_spi->card_info.csd;
  
      /*
       * For High Capacity SD card, (C_SIZE field value + 1) * 1024
       * gives the sector count
       */
      *sector_count = (uint32_t)(((((uint32_t)tmp_csd->dev_size_high << (uint32_t)16) |
                                 ((uint32_t)tmp_csd->dev_size_low )) + (uint32_t)1) << (uint32_t)10);
    }
    else
    {
      SDMMC_BLOCK_SDV1_CSD_t *tmp_csd = (SDMMC_BLOCK_SDV1_CSD_t *)&obj->sdmmc_spi->card_info.csd;
  
      /* Left Shift evaluates 1* 2^(TmpMmcCsd.DeviceSizeMult + 2)*/
      multiplier = (uint32_t)(((uint32_t)tmp_csd->dev_size_mult + (uint32_t)tmp_csd->read_blk_len) - (uint32_t)7);
      /* Sector Count = Device_size * Mult.*/
      *sector_count = (uint32_t)((((uint32_t)tmp_csd->dev_size_high << (uint32_t)2) |
                                 ((uint32_t)tmp_csd->dev_size_low )) + (uint32_t)1) <<  multiplier;
    }
  
    return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
  }
  
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_GetSdStatus(const SDMMC_BLOCK_t *const obj, uint8_t *buffer)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    SDMMC_BLOCK_SPI_t * spi_handle;
    uint32_t timeout_count = 0U;
  
    /* Send the Application Specific Command i.e. Command 55.*/
    status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD55, SDMMC_BLOCK_ARGUMENT0);
    if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
    {
      spi_handle = obj->sdmmc_spi;
  
      /* Read the SD status from the data line */
      status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD13, SDMMC_BLOCK_ARGUMENT0);
  
      if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response == 0U))
      {
        /*
         * The function gets the current SD Bus status from the card.
         * The SD Status contains status bits that are related to the SD
         * Memory Card proprietary features and may be used for future
         * application-specific usage.
         * SD Status is of 512 bits so buffer of 64bytes needs to be passed
         * to this function.
         */
        timeout_count = 0U;
  
        do
        {
          status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &spi_handle->cmd_response, 1U);
          if (timeout_count++ > 0xFFFEU)
          {
            status = SDMMC_BLOCK_MODE_STATUS_COMMAND_TIMEOUT_ERROR;
            XMC_DEBUG("SDMMC_BLOCK_SPI_GetSdStatus : CMD13 Timeout error")
            break;
          }
        } while (spi_handle->cmd_response != SDMMC_BLOCK_SPI_START_BLOCK_TOKEN);
  
        if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
          status = SDMMC_BLOCK_SPI_lReadCardRegister(spi_handle, buffer, 64U);
          /* 16 bit crc follows data */
          SDMMC_BLOCK_SPI_lDummyRead(spi_handle, SDMMC_BLOCK_SPI_CRC_BYTES);
        }
      }
      else
      {
        status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
      }
    }
    else
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
    return status;
  }
  
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_GetLockStatus(SDMMC_BLOCK_t *const obj,
                                                          SDMMC_BLOCK_CARD_LOCK_STATUS_t * lock_status)
  {
    uint8_t card_status;
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
  
    /* Send CMD13 to read card status  */
    status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD13, SDMMC_BLOCK_ARGUMENT0);
  
    if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
    {
      /* Get one more bytes of response */
      status = SDMMC_BLOCK_SPI_lReadData(obj->sdmmc_spi, &card_status, 1U);
  
      if (((uint32_t)card_status & (uint32_t)SDMMC_BLOCK_SPI_CSR_CARD_LOCK_ERROR_MSK) != (uint32_t)0)
      {
        status = SDMMC_BLOCK_MODE_STATUS_LOCK_UNLOCK_ERROR;
      }
      else
      {
        /* Lock/Unlock Status bit in the CSR Register */
        if (((uint32_t)card_status & (uint32_t)SDMMC_BLOCK_SPI_CSR_CARD_LOCK_STATUS_MSK) != (uint32_t)0)
        {
          *lock_status = SDMMC_BLOCK_CARD_LOCK_STATUS_LOCKED;
          obj->card_state |= (uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED ;
        }
        else
        {
          *lock_status = SDMMC_BLOCK_CARD_LOCK_STATUS_UNLOCKED;
          obj->card_state &= (uint8_t)~((uint8_t)SDMMC_BLOCK_CARD_STATE_LOCKED);
        }
      }
    }
    else
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_GetCsd(SDMMC_BLOCK_t *const obj, void *buffer)
  {
    /*
     * Csd Structure includes 7-bit CRC  1-bit fixed bit which is not sent by the card.
     * So while copying skip one byte and copy in the structure
     */
    memcpy(((uint8_t *)buffer),(void *)obj->sdmmc_spi->card_info.csd, SDMMC_BLOCK_SPI_CSD_CID_LENGTH);
  
    return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
  }
  
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_GetCid(SDMMC_BLOCK_t *const obj, void *buffer)
  {
    SDMMC_BLOCK_CID_t *cid = (SDMMC_BLOCK_CID_t *)buffer;
    const uint8_t * tmp_cid;
  
    tmp_cid = obj->sdmmc_spi->card_info.cid;
  
    cid->manufacturing_date = (uint16_t)((uint16_t)((uint16_t)tmp_cid[2] & 0x0FU) << 8);
    cid->manufacturing_date |= ((uint16_t)tmp_cid[1] & 0xFFU);
    cid->product_serial_num = tmp_cid[3];
    cid->product_serial_num |= (((uint32_t)tmp_cid[4] << 8) | ((uint32_t)tmp_cid[5] << 16) | ((uint32_t)tmp_cid[6] << 24));
    cid->product_rev = (tmp_cid[7] & 0xFFU);
    cid->product_name[0] = tmp_cid[12];
    cid->product_name[1] = tmp_cid[11];
    cid->product_name[2] = tmp_cid[10];
    cid->product_name[3] = tmp_cid[9];
    cid->product_name[4] = tmp_cid[8];
    cid->app_oem_id[0] = tmp_cid[14];
    cid->app_oem_id[1] = tmp_cid[13];
    cid->manufacturer_id = tmp_cid[15];
  
    return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
  }
  
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_GetOcr(const SDMMC_BLOCK_t *const obj, void *buffer)
  {
    memcpy(((uint8_t *)buffer),(void *)obj->sdmmc_spi->card_info.ocr, SDMMC_BLOCK_SPI_OCR_LENGTH);
  
    return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
  }
  
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_GetBlockSize(SDMMC_BLOCK_t *const obj, uint32_t *block_size)
  {
    /* SD High capacity card i.e. CSD V2*/
    if (((uint32_t)obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_HIGH_CAPACITY) != 0U)
    {
      SDMMC_BLOCK_SDV2_CSD_t *temp_csd_v2 = (SDMMC_BLOCK_SDV2_CSD_t *)&obj->sdmmc_spi->card_info.csd;
      *block_size = (uint32_t)((uint32_t)temp_csd_v2->erase_sector_size + 1U);
    }
    /* SD standard capacity card i.e. CSD V1*/
    else
    {
      SDMMC_BLOCK_SDV1_CSD_t *temp_csd_v1  = (SDMMC_BLOCK_SDV1_CSD_t *)&obj->sdmmc_spi->card_info.csd;
      *block_size = (uint32_t)((uint32_t)temp_csd_v1->erase_sector_size + 1U);
    }
  
    return SDMMC_BLOCK_MODE_STATUS_SUCCESS;
  }
  
  /*
    * This function is use to  de-activate the  Card
  */
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_EjectCard(SDMMC_BLOCK_t *const obj)
  {
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
  
    if ((obj->card_state & (uint8_t)SDMMC_BLOCK_CARD_STATE_NO_CARD) == 0U)
    {
       /*
        * Reset the card. i.e CMD0
        * Resetting a card (using CMD0) will terminate any pending or active programming
        * operation. This may destroy the data contents on the card. It is the host's responsibility to prevent
        * this.
        */
      status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD0, SDMMC_BLOCK_ARGUMENT0);
  
      if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response != SDMMC_BLOCK_IN_IDLE_STATE))
      {
        status = SDMMC_BLOCK_MODE_STATUS_COMMAND_TIMEOUT_ERROR;
        XMC_DEBUG("SDMMC_BLOCK_SPI_EjectCard : CMD0 Timeout error")
      }
      else
      {
        status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
      }
  
      /* Card Cleanup */
      memset((void*)&obj->sdmmc_spi->card_info, 0, sizeof(obj->sdmmc_spi->card_info));
      obj->card_type = (uint8_t)0;
      obj->card_state = (uint8_t)SDMMC_BLOCK_CARD_STATE_NO_CARD;
      obj->card_capacity = (uint8_t)SDMMC_BLOCK_CARD_CAPACITY_UNKNOWN;
      obj->sdmmc_spi->mode_init_flag = 0U;
    }
  
    return status;
  }
  
  SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_LockUnlockCard(SDMMC_BLOCK_t *const obj,
                                                           SDMMC_BLOCK_LOCK_STRUCTURE_t *lock,
                                                           const SDMMC_BLOCK_CARD_LOCK_STATUS_t expected_state)
  {
    SDMMC_BLOCK_MODE_STATUS_t mode_status;
    SDMMC_BLOCK_CARD_LOCK_STATUS_t lock_status;
    uint32_t data_length;
    uint8_t send_data;
    SDMMC_BLOCK_SPI_t *spi_handle;
  
    /* Password data + mode + password length */
    data_length = ((uint32_t)((uint32_t)((uint32_t)lock->pwd_len + 1U) >> 1U) << 1U) + 2U;
  
    mode_status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD16, data_length);
  
    if ((mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
    {
      mode_status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD42, SDMMC_BLOCK_ARGUMENT0);
  
      if ((mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response != 0U))
      {
        mode_status = SDMMC_BLOCK_MODE_STATUS_COMMAND_TIMEOUT_ERROR;
        XMC_DEBUG("SDMMC_BLOCK_SPI_LockUnlockCard : CMD42 Timeout error")
      }
      else
      {
        spi_handle = obj->sdmmc_spi;
  
        /* This has to be dummy clock */
        SDMMC_BLOCK_SPI_lSend_Clocktrain(spi_handle, 1U);
  
        send_data = (uint8_t)SDMMC_BLOCK_SPI_START_BLOCK_TOKEN;
  
        mode_status = SDMMC_BLOCK_SPI_lSendData(spi_handle, &send_data, 1U);
  
        if (mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
          mode_status = SDMMC_BLOCK_SPI_lSendData(spi_handle, (uint8_t *)lock, data_length);
  
          SDMMC_BLOCK_SPI_lDummyRead(spi_handle, SDMMC_BLOCK_SPI_CRC_BYTES);
        }
  
        mode_status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &obj->sdmmc_spi->cmd_response, 1U);
  
        if ((obj->sdmmc_spi->cmd_response & SDMMC_BLOCK_SPI_DR_MSK) != SDMMC_BLOCK_SPI_DR_ACCEPT)
        {
          mode_status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
        }
  
        if (mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
          do
          {
            mode_status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &obj->sdmmc_spi->cmd_response, 1U);
          } while ((mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response != 0xFFU));
  
          mode_status = SDMMC_BLOCK_SPI_GetLockStatus(obj, &lock_status);
  
          if (mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
          {
            if ((expected_state == SDMMC_BLOCK_CARD_LOCK_STATUS_LOCKED) &&
                (lock_status == SDMMC_BLOCK_CARD_LOCK_STATUS_UNLOCKED))
            {
              mode_status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
            }
            /* For unlock, card state must be "unlocked" */
            else if ((expected_state == SDMMC_BLOCK_CARD_LOCK_STATUS_UNLOCKED) &&
                     (lock_status == SDMMC_BLOCK_CARD_LOCK_STATUS_LOCKED))
            {
              mode_status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
            }
            else
            {
              mode_status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
            }
          }
        }
      }
  
      mode_status = (SDMMC_BLOCK_MODE_STATUS_t)((uint32_t)mode_status |
                                                (uint32_t)SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD16, SDMMC_BLOCK_SPI_BYTES_PER_SECTOR));
  
      if ((mode_status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
      {
        mode_status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
      }
      else
      {
        mode_status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
      }
    }
    else
    {
      mode_status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return mode_status;
  }
  
  /***********************************************************************************************************************
    * LOCAL API IMPLEMENTATION
  **********************************************************************************************************************/
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lInitializeCard(SDMMC_BLOCK_t *const obj)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    uint32_t count = 10U;
    SDMMC_BLOCK_CARD_LOCK_STATUS_t lock_status;
    SDMMC_BLOCK_SPI_t *spi_handle;
    spi_handle = obj->sdmmc_spi;
    /* During initialization recommended baud rate is 300K only */
    status = SDMMC_BLOCK_SPI_lSetSpeed(spi_handle->spi_master_handle, SDMMC_BLOCK_SPI_INIT_SPEED);
  
    if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
    {
      /*
       * Init SPI with a very slow transfer rate first !
       * Give minimum 74 SPI clock pulses before sending commands dummy write 80 clock.
       */
      SDMMC_BLOCK_SPI_lSend_Clocktrain(spi_handle, count);
  
      /* Reset the card. i.e CMD0 */
      status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD0, SDMMC_BLOCK_ARGUMENT0);
  
      if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response != SDMMC_BLOCK_IN_IDLE_STATE))
      {
        status = SDMMC_BLOCK_MODE_STATUS_COMMAND_TIMEOUT_ERROR;
        XMC_DEBUG("SDMMC_BLOCK_SPI_lInitializeCard : CMD0 Timeout error")
      }
      else
      {
        /* Query the Operation Condition Info from the card.*/
        status = SDMMC_BLOCK_SPI_lQueryOperatingCondVoltage(obj);
  
        if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
          status = SDMMC_BLOCK_SPI_lReadCid(obj);
          if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
          {
            status = SDMMC_BLOCK_SPI_lReadCsd(obj);
            if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
            {
              /* Get Write protection flags */
              SDMMC_BLOCK_SPI_lGetWriteProtect(obj);
              /* Check the card Lock/ Unlock Status */
              status = SDMMC_BLOCK_SPI_GetLockStatus(obj, &lock_status);
  
              if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
              {
                if (lock_status == SDMMC_BLOCK_CARD_LOCK_STATUS_LOCKED)
                {
                  status = SDMMC_BLOCK_MODE_STATUS_INITIALIZED_BUT_LOCKED;
                }
                /* Since the channel is disabled inside the set baud, this check is needed to avaoid the issues. */
                while (SPI_MASTER_GetFlagStatus(spi_handle->spi_master_handle, (uint32_t)XMC_SPI_CH_STATUS_FLAG_MSLS) != 0U)
                {
                  /* To abide coding guidelines */
                }
  
                status = SDMMC_BLOCK_SPI_lSetSpeed(spi_handle->spi_master_handle,
                                                   spi_handle->spi_master_handle->config->channel_config->baudrate);
                if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
                {
                  /* Update card initialization Status */
                  obj->card_state &= (uint8_t)~((uint8_t)SDMMC_BLOCK_CARD_STATE_NOT_INITIALIZED);
                  obj->card_state &= (uint8_t)~((uint8_t)SDMMC_BLOCK_CARD_STATE_NO_CARD);
                }
              }
            }
          }
        }
      }
    }
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadCid(SDMMC_BLOCK_t *const obj)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    SDMMC_BLOCK_SPI_CARD_INFORMATION_t* card_info;
    SDMMC_BLOCK_SPI_t* spi_handle;
    uint32_t retry;
  
    card_info = &obj->sdmmc_spi->card_info;
    spi_handle = obj->sdmmc_spi;
  
    /* Read CID */
    status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD10, SDMMC_BLOCK_ARGUMENT0);
  
    if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response == 0U))
    {
      retry = 0U;
      do
      {
        status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &spi_handle->cmd_response, 1U);
        retry++;
      } while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) &&
               (spi_handle->cmd_response != SDMMC_BLOCK_SPI_START_BLOCK_TOKEN) &&
               (retry < 255U));
  
      if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (retry < 255U))
      {
        status = SDMMC_BLOCK_SPI_lReadCardRegister(spi_handle, card_info->cid, SDMMC_BLOCK_SPI_CSD_CID_LENGTH);
      }
      else
      {
        status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
      }
      /* 16 bit CRC follows data */
      SDMMC_BLOCK_SPI_lDummyRead(spi_handle, SDMMC_BLOCK_SPI_CRC_BYTES);
    }
    else
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadCsd(SDMMC_BLOCK_t *const obj)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    SDMMC_BLOCK_SPI_CARD_INFORMATION_t* card_info;
    SDMMC_BLOCK_SPI_t* spi_handle;
    uint32_t retry;
  
    card_info = &obj->sdmmc_spi->card_info;
    spi_handle = obj->sdmmc_spi;
  
    /* Read CID */
    status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD9, SDMMC_BLOCK_ARGUMENT0);
  
    if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response == 0U))
    {
      retry = 0U;
      do
      {
        status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &spi_handle->cmd_response, 1U);
        retry++;
      } while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) &&
               (spi_handle->cmd_response != SDMMC_BLOCK_SPI_START_BLOCK_TOKEN) &&
               (retry < 255U));
  
      if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (retry < 255U))
      {
        status = SDMMC_BLOCK_SPI_lReadCardRegister(spi_handle, card_info->csd, SDMMC_BLOCK_SPI_CSD_CID_LENGTH);
      }
      else
      {
        status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
      }
      /* 16 bit CRC follows data */
      SDMMC_BLOCK_SPI_lDummyRead(spi_handle, SDMMC_BLOCK_SPI_CRC_BYTES);
    }
    else
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lQueryOperatingCondVoltage(SDMMC_BLOCK_t *const obj)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    uint32_t count = 0xFFU;
  
    /* Standard Capacity V1 Card */
    obj->card_capacity = (uint8_t)SDMMC_BLOCK_CARD_CAPACITY_UNKNOWN;
    obj->card_type = (uint8_t)SDMMC_BLOCK_CARD_TYPE_STANDARD_CAPACITY_V1X;
  
    /*
     * CMD8 has to be send for SDHC cards to expand ACMD41 functions
     * Check pattern = 0x22 Bits 7..0 (calculated for crc=0x95
     * VHS Voltage supplied 2.7-3.6V 0b0001 Bits 11..8
     * SEND_IF_COND
     */
    do
    {
      status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD8, SDMMC_BLOCK_SD_CMD8_ARG);
      count--;
    } while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) &&
             ((obj->sdmmc_spi->cmd_response & SDMMC_BLOCK_SPI_PARAM_ERROR) != 0U) &&
             (count > 0U));
  
    if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
    {
      if (count == 0U)
      {
        status = SDMMC_BLOCK_MODE_STATUS_OUT_OF_RANGE_ERROR;
      }
      else if ((obj->sdmmc_spi->cmd_response & SDMMC_BLOCK_ILLEGAL_COMMAND) == 0U)
      {
        /* SD card V2.xx */
        status = SDMMC_BLOCK_SPI_lSDV2OperatingCondVoltage(obj);
      }
      else /* SD card V1.xx */
      {
        status = SDMMC_BLOCK_SPI_lSDV1OperatingCondVoltage(obj);
      }
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSDV2OperatingCondVoltage(SDMMC_BLOCK_t *const obj)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    uint8_t response[4] = {0U};
  
    /*Support Standard V2.x*/
    status = SDMMC_BLOCK_SPI_lReadData(obj->sdmmc_spi, response, 4U);
  
    /*
     * Check whether Check pattern matches in the Argument,Response and
     * Check the Voltage Supplied is Accepted by the card in the response
     */
    if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) &&
        ((response[2] != SDMMC_BLOCK_SD_VHS_PATTERN_2_7_3_6_VALUE) ||
         (response[3] != SDMMC_BLOCK_SD_CMD8_CHECK_PATTERN_VALUE)))
    {
      /* Test voltage range failed */
      if (response[3] == 0x01U)
      {
        /*Test Voltage range failed */
        status = SDMMC_BLOCK_MODE_STATUS_VOLTAGE_ERROR;
      }
      else
      {
        /* Test pattern failed */
        status = SDMMC_BLOCK_MODE_STATUS_PATTERN_ERROR;
      }
    }
    else
    {
      status = SDMMC_BLOCK_SPI_lSendACMD41(obj, SDMMC_BLOCK_SD_ACMD41_F81_ARG);
  
      if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS))
      {
        /* Send CMD58 Read OCR */
        status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD58, SDMMC_BLOCK_ARGUMENT0);
  
        if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
        {
          status = SDMMC_BLOCK_SPI_lReadCardRegister(obj->sdmmc_spi,
                                                     obj->sdmmc_spi->card_info.ocr,
                                                     SDMMC_BLOCK_SPI_OCR_LENGTH);
          if  (status ==  SDMMC_BLOCK_MODE_STATUS_SUCCESS)
          {
            /* Check CCS bit in the OCR register, CCS=1 means High Capacity  card*/
            if (obj->sdmmc_spi->card_info.ocr[3] & SDMMC_BLOCK_SPI_OCR_CCS_BIT_MSK)
            {
              /* High capacity card if bit 30 of OCR is set */
              obj->card_capacity = (uint8_t)SDMMC_BLOCK_CARD_CAPACITY_SDHC;
              /* High capacity card SDHC Type */
              obj->card_type = ((uint8_t)SDMMC_BLOCK_CARD_TYPE_HIGH_CAPACITY |
                                (uint8_t)SDMMC_BLOCK_CARD_TYPE_BLOCK_ADDRESSING);
            }
            /* CCS=0 means Standard Capacity Version2 */
            else
            {
              obj->card_capacity = (uint8_t)SDMMC_BLOCK_CARD_CAPACITY_SD; /* High capacity card if bit 30 of OCR is set */
              obj->card_type = (uint8_t)SDMMC_BLOCK_CARD_TYPE_STANDARD_CAPACITY_V2;
              /* Set Block Length as 512 CMD16  */
              status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD16, SDMMC_BLOCK_SPI_BYTES_PER_SECTOR);
  
              if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
              {
                 status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
              }
              else
              {
                 status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
              }
            }
          }
        }
        else
        {
          status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
        }
      }
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSDV1OperatingCondVoltage(SDMMC_BLOCK_t *const obj)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
  
    /* CMD 8 response bytes */
    SDMMC_BLOCK_SPI_lDummyRead(obj->sdmmc_spi, 4U);
    /*
     * CMD8 illegal command
     * Note: CMD1 is not supported by all SD cards ?
     * Thin 1,4mm cards don't accept CMD1 before sending ACMD41
     * Try ACMD41 first here !
     * nSend CMD55
     * SEND_APP_CMD
     */
    /* Send Command55 for Application Specific Command with default Argument as 0*/
    status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD55, SDMMC_BLOCK_ARGUMENT0);
  
    if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
    {
      if ((obj->sdmmc_spi->cmd_response & SDMMC_BLOCK_ILLEGAL_COMMAND) == 0U) /* SD card V1.xx */
      {
        /*Support Standard V1.x*/
        obj->card_type = (uint8_t)SDMMC_BLOCK_CARD_TYPE_STANDARD_CAPACITY_V1X; /* MMC don't know CMD55  ! */
        obj->card_capacity = (uint8_t)SDMMC_BLOCK_CARD_CAPACITY_SD;
  
        status = SDMMC_BLOCK_SPI_lSendACMD41(obj, SDMMC_BLOCK_ARGUMENT0);
  
        if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
           /* Set Block Length as 512 CMD16, This is ideal if above condition is successful  */
           status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD16, SDMMC_BLOCK_SPI_BYTES_PER_SECTOR);
  
           if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
           {
              status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
           }
           else
           {
              status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
           }
  
        }
      }
      else
      {
        status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
      }
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSetSpeed(SPI_MASTER_t *const obj, const uint32_t baud_rate)
  {
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
    SPI_MASTER_STATUS_t spi_status;
  
    spi_status = SPI_MASTER_SetBaudRate(obj, baud_rate);
  
    if (spi_status !=  SPI_MASTER_STATUS_SUCCESS)
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  static void SDMMC_BLOCK_SPI_lGetWriteProtect(SDMMC_BLOCK_t *const obj)
  {
    /* SD High capacity card i.e. CSD V2*/
    if (((uint32_t)obj->card_type & (uint32_t)SDMMC_BLOCK_CARD_TYPE_HIGH_CAPACITY) != (uint32_t)0)
    {
      SDMMC_BLOCK_SDV2_CSD_t* temp_csd;
      temp_csd = (SDMMC_BLOCK_SDV2_CSD_t *)&obj->sdmmc_spi->card_info.csd;
      if ((temp_csd->temp_write_prot) || (temp_csd->perm_write_prot))
      {
        obj->card_state |= (uint8_t)SDMMC_BLOCK_CARD_STATE_WRITE_PROTECTED;
      }
    }
    else /* SD standard capacity card i.e. CSD V1*/
    {
      SDMMC_BLOCK_SDV1_CSD_t* temp_csd;
      temp_csd  = (SDMMC_BLOCK_SDV1_CSD_t *)obj->sdmmc_spi->card_info.csd;
      if ((temp_csd->temp_write_prot) || (temp_csd->perm_write_prot))
      {
        obj->card_state |= (uint8_t)SDMMC_BLOCK_CARD_STATE_WRITE_PROTECTED;
      }
    }
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lWriteMultipleBlocks(const SDMMC_BLOCK_t *const obj,
                                                                        uint8_t *write_buf,
                                                                        const uint32_t write_address,
                                                                        const uint32_t sector_count)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    uint8_t send_data;
    uint32_t tmp_blk_cnt;
    SDMMC_BLOCK_SPI_t* spi_handle;
  
    status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD25, write_address);
  
    if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
    {
      spi_handle = obj->sdmmc_spi;
      tmp_blk_cnt = sector_count;
  
      /* multiple start block token for next sector */
      send_data = (uint8_t)SDMMC_BLOCK_SPI_START_MULTI_BLOCK_TOKEN;
  
      do
      {
        status = SDMMC_BLOCK_SPI_lSendData(spi_handle, &send_data, 1U);
  
        if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
          status = SDMMC_BLOCK_SPI_lSendData(spi_handle,
                                             write_buf + (SDMMC_BLOCK_SPI_BYTES_PER_SECTOR * (sector_count - tmp_blk_cnt)),
                                             SDMMC_BLOCK_SPI_BYTES_PER_SECTOR);
  
          SDMMC_BLOCK_SPI_lDummyRead(spi_handle, SDMMC_BLOCK_SPI_CRC_BYTES);
  
          /* After data write, card will send a response stating if the card was accepted or if an error occurred */
          status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &spi_handle->cmd_response, 1U);
  
          if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
          {
            if ((spi_handle->cmd_response & SDMMC_BLOCK_SPI_DR_MSK) != SDMMC_BLOCK_SPI_DR_ACCEPT)
            {
              SDMMC_BLOCK_SPI_lDummyRead(spi_handle, 2U); /* Dummy Bytes */
  
              status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
            }
  
            status = SDMMC_BLOCK_SPI_lWaitUntilBusy(spi_handle);
          }
        }
        tmp_blk_cnt--;
      } while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (tmp_blk_cnt > 0U));
  
      /* Send 'stop transmission token' */
      send_data = SDMMC_BLOCK_SPI_STOP_TRANSMISSION;
      status = SDMMC_BLOCK_SPI_lSendData(spi_handle, &send_data, 1U);
    }
    else
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lWriteSingleBlock(const SDMMC_BLOCK_t *const obj,
                                                                     uint8_t *write_buf,
                                                                     const uint32_t write_address)
  {
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    uint8_t send_data;
    SDMMC_BLOCK_SPI_t* spi_handle;
  
  
    status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD24, write_address);
  
    if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
    {
      spi_handle = obj->sdmmc_spi;
  
      /* multiple start block token for next sector */
      send_data = (uint8_t)SDMMC_BLOCK_SPI_START_BLOCK_TOKEN;
  
      status = SDMMC_BLOCK_SPI_lSendData(spi_handle, &send_data, 1U);
  
      if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
      {
        status = SDMMC_BLOCK_SPI_lSendData(spi_handle, write_buf, SDMMC_BLOCK_SPI_BYTES_PER_SECTOR);
  
        SDMMC_BLOCK_SPI_lDummyRead(spi_handle, SDMMC_BLOCK_SPI_CRC_BYTES);
  
        status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &spi_handle->cmd_response, 1U);
  
        if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
        {
          if ((spi_handle->cmd_response & SDMMC_BLOCK_SPI_DR_MSK) != SDMMC_BLOCK_SPI_DR_ACCEPT)
          {
            SDMMC_BLOCK_SPI_lDummyRead(spi_handle, 2U); /* Dummy Bytes */
  
            status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
          }
        }
      }
    }
    else
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadMultipleBlocks(SDMMC_BLOCK_t *const obj,
                                                                       uint8_t *read_buf,
                                                                       const uint32_t read_address,
                                                                       const uint32_t sector_count)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    SDMMC_BLOCK_SPI_t* spi_handle;
    uint32_t card_sector_count;
    uint32_t count;
  
    uint32_t tmp_blk_cnt;
  
    status = SDMMC_BLOCK_SPI_GetSectorCount(obj, &card_sector_count);
  
    if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
    {
      status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD18, read_address);
  
      if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
      {
        spi_handle = obj->sdmmc_spi;
        tmp_blk_cnt = sector_count;
  
        do
        {
          count = 0xFFFEU;
          do
          {
            status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &spi_handle->cmd_response, 1U);
            count--;
          } while ((spi_handle->cmd_response != SDMMC_BLOCK_SPI_START_BLOCK_TOKEN) && (count > 0U));
  
          if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response == SDMMC_BLOCK_SPI_START_BLOCK_TOKEN))
          {
            status = SDMMC_BLOCK_SPI_lReadData(spi_handle,
                                               read_buf+(SDMMC_BLOCK_SPI_BYTES_PER_SECTOR * (sector_count - tmp_blk_cnt)),
                                               SDMMC_BLOCK_SPI_BYTES_PER_SECTOR);
  
            SDMMC_BLOCK_SPI_lDummyRead(spi_handle, SDMMC_BLOCK_SPI_CRC_BYTES);
  
            /* Send Extra 8 Cycles */
            SDMMC_BLOCK_SPI_lSend_Clocktrain(spi_handle, 1U);
  
            /* Decrement Number of blocks Variable */
            tmp_blk_cnt--;
          }
          else
          {
            SDMMC_BLOCK_SPI_lDummyRead(spi_handle, 1U);
  
            status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
          }
        } while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (tmp_blk_cnt > 0U));
  
        if (tmp_blk_cnt == 0U)
        {
          status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD12, SDMMC_BLOCK_ARGUMENT0);
  
          count = 255U;
          while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response != 0U) && (count > 0U))
          {
            if (card_sector_count == (read_address + sector_count))
            {
              /*
               * When the last block of user area is read using CMD18, the host should ignore OUT_OF_RANGE error.
               * That may occur even the sequence is correct.
               */
              spi_handle->cmd_response &= 0xBFU;
            }
            if (spi_handle->cmd_response != 0U)
            {
              status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &spi_handle->cmd_response, 1U);
            }
            else
            {
              break;
            }
  
            count--;
          }
  
          if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
          {
            if (spi_handle->cmd_response != 0x0U)
            {
              status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
            }
          }
        }
        SDMMC_BLOCK_SPI_lDummyRead(spi_handle, 2U); /* Dummy Read */
      }
      else
      {
        status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
      }
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadSingleBlock(SDMMC_BLOCK_t *const obj,
                                                                    uint8_t *read_buf,
                                                                    const uint32_t read_address)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    SDMMC_BLOCK_SPI_t* spi_handle;
    uint32_t count;
  
    status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD17, read_address);
  
    if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response == 0U))
    {
      spi_handle = obj->sdmmc_spi;
      count = 0xFFFEU;
      do
      {
        status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &spi_handle->cmd_response, 1U);
        count--;
      } while ((spi_handle->cmd_response != SDMMC_BLOCK_SPI_START_BLOCK_TOKEN) && (count > 0U));
  
      if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response == SDMMC_BLOCK_SPI_START_BLOCK_TOKEN))
      {
        status = SDMMC_BLOCK_SPI_lReadData(spi_handle, read_buf, SDMMC_BLOCK_SPI_BYTES_PER_SECTOR);
  
        SDMMC_BLOCK_SPI_lDummyRead(spi_handle, SDMMC_BLOCK_SPI_CRC_BYTES);
  
        /* Send Extra 8 Cycles */
        SDMMC_BLOCK_SPI_lSend_Clocktrain(spi_handle, 1U);
      }
      else
      {
        SDMMC_BLOCK_SPI_lDummyRead(spi_handle, 1U);
  
        status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
      }
    }
    else
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  /*
    * The function performs the actual erase operation.
  */
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lErase(const SDMMC_BLOCK_t *const obj,
                                                          const uint32_t start_address,
                                                          const uint32_t end_address,
                                                          const uint32_t timeout_val)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    uint32_t tmp_start_addr = start_address;
    uint32_t tmp_end_addr = end_address;
    SDMMC_BLOCK_SPI_t * spi_handle;
  
    spi_handle = obj->sdmmc_spi;
  
    if ((obj->card_type & (uint8_t)SDMMC_BLOCK_CARD_TYPE_BLOCK_ADDRESSING) == 0U)
    {
      tmp_start_addr *= SDMMC_BLOCK_SPI_BYTES_PER_SECTOR;
      tmp_end_addr *=  SDMMC_BLOCK_SPI_BYTES_PER_SECTOR;
    }
    /* SD Erase Start Command */
    status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD32, tmp_start_addr);
  
    if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response == 0U))
    {
      /* SD Erase End Command */
      status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD33, tmp_end_addr);
  
      if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response == 0U))
      {
        status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD38, tmp_start_addr);
  
        if ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (spi_handle->cmd_response == 0U))
        {
          /*
           * Card will respond with the DATA OUT line pulled low if the card is still busy
           * erasing. Continue checking DATA OUT line until line is released high.
           */
          /* Send Extra 8 Cycles */
          SDMMC_BLOCK_SPI_lSend_Clocktrain(spi_handle, 1U);
  
          status = (SDMMC_BLOCK_MODE_STATUS_t)((uint32_t)status |
                                               (uint32_t)SDMMC_BLOCK_SPI_lEraseTimeOut(obj->sdmmc_spi, timeout_val));
        }
        else
        {
          status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
        }
      }
      else
      {
        status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
      }
    }
    else
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  /*
    * This function reads for the response received for the command issued.
  */
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadData(SDMMC_BLOCK_SPI_t *const obj,
                                                             uint8_t *response_data,
                                                             const uint32_t num_of_bytes)
  {
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
    SPI_MASTER_STATUS_t spi_status;
  
    spi_status = SPI_MASTER_Receive(obj->spi_master_handle, response_data, num_of_bytes);
    while (obj->spi_master_handle->runtime->tx_busy == true)
    { }
    while (obj->spi_master_handle->runtime->rx_busy == true)
    { }
  
    if (spi_status != SPI_MASTER_STATUS_SUCCESS)
    {
      status = SDMMC_BLOCK_MODE_STATUS_COMMUNICATION_ERROR;
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSendData(SDMMC_BLOCK_SPI_t *const obj,
                                                             uint8_t *transmit_data,
                                                             const uint32_t num_of_bytes)
  {
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
    SPI_MASTER_STATUS_t spi_status;
  
    spi_status = SPI_MASTER_Transmit(obj->spi_master_handle, transmit_data, num_of_bytes);
    while (obj->spi_master_handle->runtime->tx_busy == true)
    { }
  
    if (spi_status != SPI_MASTER_STATUS_SUCCESS)
    {
      status = SDMMC_BLOCK_MODE_STATUS_COMMUNICATION_ERROR;
    }
  
    return status;
  }
  
  /*
   * This function issues the command.
   */
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSendCommand(const SDMMC_BLOCK_t *const obj,
                                                                const uint8_t cmd,
                                                                const uint32_t arg)
  {
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
    uint32_t retry = 0U;
    uint32_t exp_res;
    uint32_t num_of_tries;
    SDMMC_BLOCK_SPI_t * spi_handle;
  
    uint8_t send_data[7] = {0xffU,
                            cmd,
                            (uint8_t)(((uint32_t)arg >> 24) & 0xffU),
                            (uint8_t)(((uint32_t)arg >> 16) & 0xffU),
                            (uint8_t)(((uint32_t)arg >> 8) & 0xffU),
                            (uint8_t)((uint32_t)arg & 0xffU),
                             0xffU
                            };
  
    spi_handle = obj->sdmmc_spi;
  
    switch (cmd)
    {
      case SDMMC_BLOCK_SPI_CMD0:
        send_data[6] = 0x95U;
        exp_res = SDMMC_BLOCK_IN_IDLE_STATE;
        num_of_tries = 255U;
        break;
  
      case SDMMC_BLOCK_SPI_CMD1:
        exp_res = 0U;
        num_of_tries = 1024U;
        break;
  
      case SDMMC_BLOCK_SPI_CMD8:
        send_data[6] = 0x87U;
        exp_res = 0U;
        num_of_tries = 1U;
        break;
  
      case SDMMC_BLOCK_SPI_CMD9:
        exp_res = 0U;
        num_of_tries = 255U;
        break;
  
      case SDMMC_BLOCK_SPI_CMD10:
        exp_res = 0U;
        num_of_tries = 255U;
        break;
  
      case SDMMC_BLOCK_SPI_CMD17:
        exp_res = 0U;
        num_of_tries = 255U;
        break;
  
      case SDMMC_BLOCK_SPI_CMD18:
        exp_res = 0U;
        num_of_tries = 255U;
        break;
  
      case SDMMC_BLOCK_SPI_CMD24:
        exp_res = 0U;
        num_of_tries = 255U;
        break;
  
      case SDMMC_BLOCK_SPI_CMD25:
        exp_res = 0U;
        num_of_tries = 255U;
        break;
  
      default :
        exp_res = 0U;
        num_of_tries = 1U;
        break;
    }
  
    do
    {
      SDMMC_BLOCK_SPI_lSend_Clocktrain(spi_handle, 1U);
  
      status = SDMMC_BLOCK_SPI_lSendData(spi_handle, &send_data[1], 6U);
  
      if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
      {
        retry = 0U;
        do
        {
          status = SDMMC_BLOCK_SPI_lReadData(spi_handle, &spi_handle->cmd_response, 1U);
  
          if ((retry++ > SDMMC_BLOCK_SPI_CMD_TIMOUT) || (status != SDMMC_BLOCK_MODE_STATUS_SUCCESS))
          {
            if (status != SDMMC_BLOCK_MODE_STATUS_SUCCESS)
            {
              status = SDMMC_BLOCK_MODE_STATUS_COMMUNICATION_ERROR;
            }
            break;      /* time out error */
          }
        } while (spi_handle->cmd_response == 0xffU);  /* wait response */
      }
      num_of_tries--;
    } while ((spi_handle->cmd_response != exp_res) && (num_of_tries > 0U));
  
  #ifdef SDMMC_BLOCK_TEST_HOOK_ENABLE
    if (sdmmc_block_test_hook_expected_command == (cmd - 64U))
    {
      status = SDMMC_BLOCK_SPI_TEST_HOOK_SendCommand(obj, cmd, status);
    }
  #endif
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lSendACMD41(const SDMMC_BLOCK_t *const obj, const uint32_t arg)
  {
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
    uint32_t count = 1024U;
  
    do
    {
      /* Send Command55 for Application Specific Command with default Argument as 0*/
      (void)SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_CMD55, SDMMC_BLOCK_ARGUMENT0);
      /* Send ACMD41 to query the card's voltage window */
      status = SDMMC_BLOCK_SPI_lSendCommand(obj, SDMMC_BLOCK_SPI_ACMD41, arg);
  
      count--;
    } while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (obj->sdmmc_spi->cmd_response != 0U) && (count > 0U));
  
    if ((obj->sdmmc_spi->cmd_response != 0U) && (count == 0U))
    {
      status = SDMMC_BLOCK_MODE_STATUS_COMMAND_TIMEOUT_ERROR;
      XMC_DEBUG("SDMMC_BLOCK_SPI_lInitializeCard : ACMD41 Timeout error")
    }
  
    return status;
  }
  
  /**
    * This function is used to check the sector address is out of bound or not.
  */
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lCheckSectorBound(SDMMC_BLOCK_t *const obj,
                                                                     const uint32_t sector_number,
                                                                     const uint32_t sector_count)
  {
    SDMMC_BLOCK_MODE_STATUS_t status;
    uint32_t max_sector_count;
  
    /* Get Sector Count function   */
    status = SDMMC_BLOCK_SPI_GetSectorCount(obj, &max_sector_count);
  
    if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
    {
      /* Check the Sector Count limit */
      if ((sector_number + sector_count) > max_sector_count)
      {
        status = SDMMC_BLOCK_MODE_STATUS_SECTOR_OUT_OF_BOUND;
      }
    }
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lReadCardRegister(SDMMC_BLOCK_SPI_t *const obj,
                                                                     uint8_t *buffer,
                                                                     const uint32_t buffer_length)
  {
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
  
     /*
      * Since tshe first byte is CRC field hence it is ignored.
      * And also 0th bit is always 1 and it is not used as in spec
      * Csd Struture includes 7-bit CRC  1-bit fixed bit which is not sent by the card.
      * So while copying skip one byte and copy in the structure
      */
    uint32_t left_index;
    uint32_t right_index;
    uint32_t count;
    uint8_t temp;
  
    status = SDMMC_BLOCK_SPI_lReadData(obj, buffer, buffer_length);
  
    if (status == SDMMC_BLOCK_MODE_STATUS_SUCCESS)
    {
      count = buffer_length >> 1U;
      left_index = 0U;
      right_index = buffer_length - 1U;
  
      /* Reverse the buffer to align the word according the register */
      while (left_index < count){
        temp = buffer[left_index];
        buffer[left_index] = buffer[right_index];
        buffer[right_index] = temp;
        left_index++;
        right_index--;
      }
    }
  
    return status;
  }
  
  static void SDMMC_BLOCK_SPI_lDummyRead(SDMMC_BLOCK_SPI_t *const obj, uint32_t count)
  {
    uint8_t dummy[SDMMC_BLOCK_SPI_DUMMY_READ_MAX_CNT];
  
    /* Read out CRC */
    (void)SDMMC_BLOCK_SPI_lReadData(obj, dummy, count);
  }
  
  static void SDMMC_BLOCK_SPI_lSend_Clocktrain(SDMMC_BLOCK_SPI_t* const obj, uint32_t count)
  {
    uint8_t dummy[SDMMC_BLOCK_SPI_CLK_TRAIN_MAX_CNT];
    /*
     * Using LLD may trigger the SPI receive event. SO should be careful about the Configured SPI,
     * like disabling the events
     */
    while (SPI_MASTER_GetFlagStatus(obj->spi_master_handle, (uint32_t)XMC_SPI_CH_STATUS_FLAG_MSLS) != 0U)
    { }
    SPI_MASTER_DisableSlaveSelectSignal(obj->spi_master_handle);
    (void)SDMMC_BLOCK_SPI_lReadData(obj, dummy, count);
    while (SPI_MASTER_GetFlagStatus(obj->spi_master_handle, (uint32_t)XMC_SPI_CH_STATUS_FLAG_MSLS) != 0U)
    { }
    SPI_MASTER_EnableSlaveSelectSignal(obj->spi_master_handle,
                                       (SPI_MASTER_SS_SIGNAL_t)obj->spi_master_handle->config->slave_select_pin_config[0]->slave_select_ch);
  
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lWaitUntilBusy(SDMMC_BLOCK_SPI_t *const obj)
  {
    uint32_t count = (uint32_t)SDMMC_BLOCK_SPI_BUSY_TIMOUT;
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
    uint8_t response;
  
    do
    {
      status = SDMMC_BLOCK_SPI_lReadData(obj, &response, 1U);
      count--;
    } while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (response != 0xFFU) && (count > 0U));
  
    if (count == 0U)
    {
      status = SDMMC_BLOCK_MODE_STATUS_FAILURE;
    }
  
    return status;
  }
  
  static SDMMC_BLOCK_MODE_STATUS_t SDMMC_BLOCK_SPI_lEraseTimeOut(SDMMC_BLOCK_SPI_t *const obj,
                                                                 const uint32_t timeout_val)
  {
    uint32_t count;
    SDMMC_BLOCK_MODE_STATUS_t status = SDMMC_BLOCK_MODE_STATUS_SUCCESS;
    uint8_t response;
  
    count = (uint32_t)(timeout_val * (obj->spi_master_handle->config->channel_config->baudrate)) >> 3U;
  
    do
    {
      status = SDMMC_BLOCK_SPI_lReadData(obj, &response, 1U);
      count--;
    } while ((status == SDMMC_BLOCK_MODE_STATUS_SUCCESS) && (response != 0xFFU) && (count > 0U));
  
    if (count == 0U)
    {
      status = SDMMC_BLOCK_MODE_STATUS_TIMEOUT_OCCURED;
    }
  
    return status;
  }
  #endif /* SDMMC_BLOCK_SPI */
  
  