/**
 * \file
 *
 * \brief SD/MMC protocol definitions.
 *
 * Copyright (c) 2012 Atmel Corporation. All rights reserved.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 *    Atmel microcontroller product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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.
 *
 * \asf_license_stop
 *
 */

#ifndef SD_MMC_PROTOCOL_H_INCLUDED
#define SD_MMC_PROTOCOL_H_INCLUDED

#include  "compiler.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * \addtogroup sd_mmc_protocol SD/MMC Protocol Definition
 * \ingroup sd_mmc_stack_group
 * @{
 */

// SD/MMC/SDIO default clock frequency for initialization (400KHz)
#define SDMMC_CLOCK_INIT   400000


/**
 * \name Macros for command definition
 *
 * Commands types:
 * - broadcast commands (bc), no response
 * - broadcast commands with response (bcr) (Note: No open drain on SD card)
 * - addressed (point-to-point) commands (ac), no data transfer on DAT lines
 * - addressed (point-to-point) data transfer commands (adtc), data transfer
 * on DAT lines
 *
 * Specific MMC norms:
 * CMD1, CMD2 & CMD3 are processed in the open-drain mode.
 * The CMD line is driven with push-pull drivers.
 *
 * Specific SD norms:
 * There is no open drain mode in SD memory card.
 *
 ***************************************
 * Responses types:
 *
 * R1, R3, R4 & R5 use a 48 bits response protected by a 7bit CRC checksum
 * - R1 receiv data not specified
 * - R3 receiv OCR
 * - R4, R5 RCA management (MMC only)
 * - R6, R7 RCA management (SD only)
 *
 * R1b assert the BUSY signal and respond with R1.
 * If the busy signal is asserted, it is done two clock cycles (Nsr time)
 * after the end bit of the command. The DAT0 line is driven low.
 * DAT1-DAT7 lines are driven by the card though their values are not relevant.
 *
 * R2 use a 136 bits response protected by a 7bit CRC checksum
 * The content is CID or CSD
 *
 * Specific MMC norms:
 * - R4 (Fast I/O) return RCA
 * - R5 (interrupt request) return RCA null
 *
 * Specific SD norms:
 * - R6 (Published RCA) return RCA
 * - R7 (Card interface condition) return RCA null
 *
 * @{
 */

//! Value to define a SD/MMC/SDIO command
typedef uint32_t sdmmc_cmd_def_t;

//! \name Flags used to define a SD/MMC/SDIO command
//! @{
#define SDMMC_CMD_GET_INDEX(cmd) (cmd & 0x3F)
//! Have response (MCI only)
#define SDMMC_RESP_PRESENT      (1lu << 8)
//! 8 bit response (SPI only)
#define SDMMC_RESP_8            (1lu << 9)
//! 32 bit response (SPI only)
#define SDMMC_RESP_32           (1lu << 10)
//! 136 bit response (MCI only)
#define SDMMC_RESP_136          (1lu << 11)
//! Expect valid crc (MCI only)
#define SDMMC_RESP_CRC          (1lu << 12)
//! Card may send busy
#define SDMMC_RESP_BUSY         (1lu << 13)
// Open drain for a braodcast command (bc)
// or to enter in inactive state (MCI only)
#define SDMMC_CMD_OPENDRAIN     (1lu << 14)
//! To signal a data write operation
#define SDMMC_CMD_WRITE         (1lu << 15)
//! To signal a SDIO tranfer in multi byte mode
#define SDMMC_CMD_SDIO_BYTE     (1lu << 16)
//! To signal a SDIO tranfer in block mode
#define SDMMC_CMD_SDIO_BLOCK    (1lu << 17)
//! To signal a data transfer in stream mode
#define SDMMC_CMD_STREAM        (1lu << 18)
//! To signal a data transfer in single block mode
#define SDMMC_CMD_SINGLE_BLOCK  (1lu << 19)
//! To signal a data transfer in multi block mode
#define SDMMC_CMD_MULTI_BLOCK   (1lu << 20)
//! @}

//! \name Set of flags to define a reponse type
//! @{
#define SDMMC_CMD_NO_RESP (0)
#define SDMMC_CMD_R1      (SDMMC_RESP_PRESENT | SDMMC_RESP_CRC)
#define SDMMC_CMD_R1B     (SDMMC_RESP_PRESENT | SDMMC_RESP_CRC | SDMMC_RESP_BUSY)
#define SDMMC_CMD_R2      (SDMMC_RESP_PRESENT | SDMMC_RESP_8 | SDMMC_RESP_136 | SDMMC_RESP_CRC)
#define SDMMC_CMD_R3      (SDMMC_RESP_PRESENT | SDMMC_RESP_32)
#define SDMMC_CMD_R4      (SDMMC_RESP_PRESENT | SDMMC_RESP_32)
#define SDMMC_CMD_R5      (SDMMC_RESP_PRESENT | SDMMC_RESP_8 | SDMMC_RESP_CRC)
#define SDMMC_CMD_R6      (SDMMC_RESP_PRESENT | SDMMC_RESP_CRC)
#define SDMMC_CMD_R7      (SDMMC_RESP_PRESENT | SDMMC_RESP_32 | SDMMC_RESP_CRC)
//! @}

//! \name SD/MMC/SDIO command definitions
//! SDMMC_CMDx are include in SD and MMC norms
//! MMC_CMDx   are include in MMC norms only
//! SD_CMDx    are include in SD norms only
//! SDIO_CMDx  are include in SDIO norms only
//! @{

/*
 * --- Basic commands and read-stream command (class 0 and class 1) ---
 */

/** Cmd0(bc): Reset all cards to idle state */
#define SDMMC_SPI_CMD0_GO_IDLE_STATE     (0 | SDMMC_CMD_R1)
#define SDMMC_MCI_CMD0_GO_IDLE_STATE     (0 | SDMMC_CMD_NO_RESP | SDMMC_CMD_OPENDRAIN)
/** MMC Cmd1(bcr, R3): Ask the card to send its Operating Conditions */
#define MMC_SPI_CMD1_SEND_OP_COND        (1 | SDMMC_CMD_R1)
#define MMC_MCI_CMD1_SEND_OP_COND        (1 | SDMMC_CMD_R3 | SDMMC_CMD_OPENDRAIN)
/** Cmd2(bcr, R2): Ask the card to send its CID number (stuff but arg 0 used) */
#define SDMMC_CMD2_ALL_SEND_CID          (2 | SDMMC_CMD_R2 | SDMMC_CMD_OPENDRAIN)
/** SD Cmd3(bcr, R6): Ask the card to publish a new relative address (RCA) */
#define SD_CMD3_SEND_RELATIVE_ADDR       (3 | SDMMC_CMD_R6 | SDMMC_CMD_OPENDRAIN)
/** MMC Cmd3(ac, R1): Assigns relative address to the card */
#define MMC_CMD3_SET_RELATIVE_ADDR       (3 | SDMMC_CMD_R1)
/** Cmd4(bc): Program the DSR of all cards (MCI only) */
#define SDMMC_CMD4_SET_DSR               (4 | SDMMC_CMD_NO_RESP)
/** MMC Cmd5(ac, R1b): Toggle the card between Sleep state and Standby state. */
#define MMC_CMD5_SLEEP_AWAKE             (5 | SDMMC_CMD_R1B)
/** Cmd7(ac, R1/R1b): Select/Deselect card
 * For SD: R1b only from the selected card.
 * For MMC: R1 while selecting from Stand-By State to Transfer State;
 *          R1b while selecting from Disconnected State to Programming State.
 */
#define SDMMC_CMD7_SELECT_CARD_CMD       (7 | SDMMC_CMD_R1B)
#define SDMMC_CMD7_DESELECT_CARD_CMD     (7 | SDMMC_CMD_R1)
/** MMC Cmd8(adtc, R1): Send EXT_CSD register as a block of data */
#define MMC_CMD8_SEND_EXT_CSD            (8 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)
/** SD Cmd8(bcr, R7) : Send SD Memory Card interface condition */
#define SD_CMD8_SEND_IF_COND             (8 | SDMMC_CMD_R7 | SDMMC_CMD_OPENDRAIN)
/** Cmd9 SPI (R1): Addressed card sends its card-specific data (CSD) */
#define SDMMC_SPI_CMD9_SEND_CSD          (9 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)
/** Cmd9 MCI (ac, R2): Addressed card sends its card-specific data (CSD) */
#define SDMMC_MCI_CMD9_SEND_CSD          (9 | SDMMC_CMD_R2)
/** Cmd10(ac, R2): Addressed card sends its card identification (CID) */
#define SDMMC_CMD10_SEND_CID             (10 | SDMMC_CMD_R2)
/**
 * MMC Cmd11(adtc, R1): Read data stream from the card, starting at the given
 * address, until a STOP_TRANSMISSION follows.
 */
#define MMC_CMD11_READ_DAT_UNTIL_STOP    (11 | SDMMC_CMD_R1)
/* SD Cmd11 MCI (ac, R1): Voltage switching */
#define SD_CMD11_READ_DAT_UNTIL_STOP     (11 | SDMMC_CMD_R1)
/** Cmd12(ac, R1b): Force the card to stop transmission */
#define SDMMC_CMD12_STOP_TRANSMISSION    (12 | SDMMC_CMD_R1B)
/** Cmd13(R2): Addressed card sends its status register. */
#define SDMMC_SPI_CMD13_SEND_STATUS      (13 | SDMMC_CMD_R2)
/** Cmd13(ac, R1): Addressed card sends its status register. */
#define SDMMC_MCI_CMD13_SEND_STATUS      (13 | SDMMC_CMD_R1)
/** MMC Cmd14(adtc, R1): Read the reversed bus testing data pattern from a card. */
#define MMC_CMD14_BUSTEST_R              (14 | SDMMC_CMD_R1)
/** Cmd15(ac): Send an addressed card into the Inactive State. */
// Note: It is a ac cmd, but it must be send like bc cmd to open drain
#define SDMMC_CMD15_GO_INACTIVE_STATE    (15 | SDMMC_CMD_NO_RESP | SDMMC_CMD_OPENDRAIN)
/** MMC Cmd19(adtc, R1): Send the bus test data pattern */
#define MMC_CMD19_BUSTEST_W              (19 | SDMMC_CMD_R1)
/** Cmd58(R3): Reads the OCR register of a card */
#define SDMMC_SPI_CMD58_READ_OCR         (58 | SDMMC_CMD_R3)
/** Cmd59(R1): Turns the CRC option on or off */
#define SDMMC_SPI_CMD59_CRC_ON_OFF       (59 | SDMMC_CMD_R1)

/*
 * --- Block-oriented read commands (class 2) ---
 */
/** Cmd16(ac, R1): Set the block length (in bytes) */
#define SDMMC_CMD16_SET_BLOCKLEN         (16 | SDMMC_CMD_R1)
/** Cmd17(adtc, R1): Read single block */
#define SDMMC_CMD17_READ_SINGLE_BLOCK    (17 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)
/** Cmd18(adtc, R1): Read multiple block */
#define SDMMC_CMD18_READ_MULTIPLE_BLOCK  (18 | SDMMC_CMD_R1 | SDMMC_CMD_MULTI_BLOCK)

/*
 * --- Sequential write commands (class 3) ---
 */

/**
 * MMC Cmd20(adtc, R1): Write a data stream from the host, starting at the
 * given address, until a STOP_TRANSMISSION follows.
 */
#define MMC_CMD20_WRITE_DAT_UNTIL_STOP   (20 | SDMMC_CMD_R1)

/*
 * --- Block-oriented write commands (class 4) ---
 */
/** MMC Cmd23(ac, R1): Set block count */
#define MMC_CMD23_SET_BLOCK_COUNT        (23 | SDMMC_CMD_R1)
/** Cmd24(adtc, R1): Write block */
#define SDMMC_CMD24_WRITE_BLOCK          (24 | SDMMC_CMD_R1 | SDMMC_CMD_WRITE | SDMMC_CMD_SINGLE_BLOCK)
/** Cmd25(adtc, R1): Write multiple block */
#define SDMMC_CMD25_WRITE_MULTIPLE_BLOCK (25 | SDMMC_CMD_R1 | SDMMC_CMD_WRITE | SDMMC_CMD_MULTI_BLOCK)
/** MMC Cmd26(adtc, R1): Programming of the card identification register. */
#define MMC_CMD26_PROGRAM_CID            (26 | SDMMC_CMD_R1)
/** Cmd27(adtc, R1): Programming of the programmable bits of the CSD. */
#define SDMMC_CMD27_PROGRAM_CSD          (27 | SDMMC_CMD_R1)

/*
 * --- Erase commands  (class 5) ---
 */
/** SD Cmd32(ac, R1): */
#define SD_CMD32_ERASE_WR_BLK_START      (32 | SDMMC_CMD_R1)
/** SD Cmd33(ac, R1): */
#define SD_CMD33_ERASE_WR_BLK_END        (33 | SDMMC_CMD_R1)
/** MMC Cmd35(ac, R1): */
#define MMC_CMD35_ERASE_GROUP_START      (35 | SDMMC_CMD_R1)
/** MMC Cmd36(ac, R1): */
#define MMC_CMD36_ERASE_GROUP_END        (36 | SDMMC_CMD_R1)
/** Cmd38(ac, R1B): */
#define SDMMC_CMD38_ERASE                (38 | SDMMC_CMD_R1B)

/*
 * --- Block Oriented Write Protection Commands (class 6) ---
 */
/** Cmd28(ac, R1b): Set write protection */
#define SDMMC_CMD28_SET_WRITE_PROT       (28 | SDMMC_CMD_R1B)
/** Cmd29(ac, R1b): Clr write protection */
#define SDMMC_CMD29_CLR_WRITE_PROT       (29 | SDMMC_CMD_R1B)
/** Cmd30(adtc, R1b): Send write protection */
#define SDMMC_CMD30_SEND_WRITE_PROT      (30 | SDMMC_CMD_R1)

/*
 * --- Lock Card (class 7) ---
 */
/** Cmd42(adtc, R1): Used to set/reset the password or lock/unlock the card. */
#define SDMMC_CMD42_LOCK_UNLOCK          (42 | SDMMC_CMD_R1)

/*
 * --- Application-specific commands (class 8) ---
 */
/**
 * Cmd55(ac, R1): Indicate to the card that the next command is an application
 * specific command rather than a standard command.
 */
#define SDMMC_CMD55_APP_CMD              (55 | SDMMC_CMD_R1)
/**
 * Cmd 56(adtc, R1): Used either to transfer a data block to the card or to get
 * a data block from the card for general purpose/application specific commands.
 */
#define SDMMC_CMD56_GEN_CMD              (56 | SDMMC_CMD_R1)

/**
 * MMC Cmd6(ac, R1b) : Switche the mode of operation of the selected card
 * or modifies the EXT_CSD registers.
 */
#define MMC_CMD6_SWITCH                  (6 | SDMMC_CMD_R1B)
/**
 * SD Cmd6(adtc, R1) : Check switchable function (mode 0)
 * and switch card function (mode 1).
 */
#define SD_CMD6_SWITCH_FUNC              (6 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)
/** ACMD6(ac, R1): Define the data bus width */
#define SD_ACMD6_SET_BUS_WIDTH           (6 | SDMMC_CMD_R1)
/** ACMD13(adtc, R1): Send the SD Status. */
#define SD_ACMD13_SD_STATUS              (13 | SDMMC_CMD_R1)
/**
 * ACMD22(adtc, R1): Send the number of the written (with-out errors) write
 * blocks.
 */
#define SD_ACMD22_SEND_NUM_WR_BLOCKS     (22 | SDMMC_CMD_R1)
/**
 * ACMD23(ac, R1): Set the number of write blocks to be pre-erased before
 * writing
 */
#define SD_ACMD23_SET_WR_BLK_ERASE_COUNT (23 | SDMMC_CMD_R1)
/**
 * ACMD41(bcr, R3): Send host capacity support information (HCS) and asks the
 * accessed card to send its operating condition register (OCR) content
 * in the response
 */
#define SD_MCI_ACMD41_SD_SEND_OP_COND    (41 | SDMMC_CMD_R3 | SDMMC_CMD_OPENDRAIN)
/**
 * ACMD41(R1): Send host capacity support information (HCS) and activates the
 * card's initilization process
 */
#define SD_SPI_ACMD41_SD_SEND_OP_COND    (41 | SDMMC_CMD_R1)
/**
 * ACMD42(ac, R1): Connect[1]/Disconnect[0] the 50 KOhm pull-up resistor on
 * CD/DAT3 (pin 1) of the card.
 */
#define SD_ACMD42_SET_CLR_CARD_DETECT    (42 | SDMMC_CMD_R1)
/** ACMD51(adtc, R1): Read the SD Configuration Register (SCR). */
#define SD_ACMD51_SEND_SCR               (51 | SDMMC_CMD_R1 | SDMMC_CMD_SINGLE_BLOCK)

/*
 * --- I/O mode commands (class 9) ---
 */
/** MMC Cmd39(ac, R4): Used to write and read 8 bit (register) data fields. */
#define MMC_CMD39_FAST_IO                (39 | SDMMC_CMD_R4)
/** MMC Cmd40(bcr, R5): Set the system into interrupt mode */
#define MMC_CMD40_GO_IRQ_STATE           (40 | SDMMC_CMD_R5 | SDMMC_CMD_OPENDRAIN)
/** SDIO Cmd5(R4): Send operation condition */
#define SDIO_CMD5_SEND_OP_COND           (5 | SDMMC_CMD_R4 | SDMMC_CMD_OPENDRAIN)
/** SDIO CMD52(R5): Direct IO read/write */
#define SDIO_CMD52_IO_RW_DIRECT          (52 | SDMMC_CMD_R5)
/** SDIO CMD53(R5): Extended IO read/write */
#define SDIO_CMD53_IO_R_BYTE_EXTENDED    (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BYTE)
#define SDIO_CMD53_IO_W_BYTE_EXTENDED    (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BYTE | SDMMC_CMD_WRITE)
#define SDIO_CMD53_IO_R_BLOCK_EXTENDED   (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BLOCK)
#define SDIO_CMD53_IO_W_BLOCK_EXTENDED   (53 | SDMMC_CMD_R5 | SDMMC_CMD_SDIO_BLOCK | SDMMC_CMD_WRITE)
//! @}
//! @}


//! \name Macros for command argument definition
//! @{

  //! \name MMC CMD6 argument structure
  //! @{
//! [31:26] Set to 0
//! [25:24] Access
#define MMC_CMD6_ACCESS_COMMAND_SET (0lu << 24)
#define MMC_CMD6_ACCESS_SET_BITS    (1lu << 24)
#define MMC_CMD6_ACCESS_CLEAR_BITS  (2lu << 24)
#define MMC_CMD6_ACCESS_WRITE_BYTE  (3lu << 24)
//! [23:16] Index for Mode Segment
#define MMC_CMD6_INDEX_CMD_SET         (EXT_CSD_CMD_SET_INDEX << 16)
#define MMC_CMD6_INDEX_CMD_SET_REV     (EXT_CSD_CMD_SET_REV_INDEX << 16)
#define MMC_CMD6_INDEX_POWER_CLASS     (EXT_CSD_POWER_CLASS_INDEX << 16)
#define MMC_CMD6_INDEX_HS_TIMING       (EXT_CSD_HS_TIMING_INDEX << 16)
#define MMC_CMD6_INDEX_BUS_WIDTH       (EXT_CSD_BUS_WIDTH_INDEX << 16)
#define MMC_CMD6_INDEX_ERASED_MEM_CONT (EXT_CSD_ERASED_MEM_CONT_INDEX << 16)
#define MMC_CMD6_INDEX_BOOT_CONFIG     (EXT_CSD_BOOT_CONFIG_INDEX << 16)
#define MMC_CMD6_INDEX_BOOT_BUS_WIDTH  (EXT_CSD_BOOT_BUS_WIDTH_INDEX << 16)
#define MMC_CMD6_INDEX_ERASE_GROUP_DEF (EXT_CSD_ERASE_GROUP_DEF_INDEX << 16)
//! [15:8] Value
#define MMC_CMD6_VALUE_BUS_WIDTH_1BIT    (0x0lu << 8)
#define MMC_CMD6_VALUE_BUS_WIDTH_4BIT    (0x1lu << 8)
#define MMC_CMD6_VALUE_BUS_WIDTH_8BIT    (0x2lu << 8)
#define MMC_CMD6_VALUE_HS_TIMING_ENABLE  (0x1lu << 8)
#define MMC_CMD6_VALUE_HS_TIMING_DISABLE (0x0lu << 8)
//! [7:3] Set to 0
//! [2:0] Cmd Set
  //! @}

  //! \name SD CMD6 argument structure
  //! @{
//! CMD6 arg[ 3: 0] function group 1, access mode
#define SD_CMD6_GRP1_HIGH_SPEED     (0x1lu << 0)
#define SD_CMD6_GRP1_DEFAULT        (0x0lu << 0)
//! CMD6 arg[ 7: 4] function group 2, command system
#define SD_CMD6_GRP2_NO_INFLUENCE   (0xFlu << 4)
#define SD_CMD6_GRP2_DEFAULT        (0x0lu << 4)
//! CMD6 arg[11: 8] function group 3, 0xF or 0x0
#define SD_CMD6_GRP3_NO_INFLUENCE   (0xFlu << 8)
#define SD_CMD6_GRP3_DEFAULT        (0x0lu << 8)
//! CMD6 arg[15:12] function group 4, 0xF or 0x0
#define SD_CMD6_GRP4_NO_INFLUENCE   (0xFlu << 12)
#define SD_CMD6_GRP4_DEFAULT        (0x0lu << 12)
//! CMD6 arg[19:16] function group 5, 0xF or 0x0
#define SD_CMD6_GRP5_NO_INFLUENCE   (0xFlu << 16)
#define SD_CMD6_GRP5_DEFAULT        (0x0lu << 16)
//! CMD6 arg[23:20] function group 6, 0xF or 0x0
#define SD_CMD6_GRP6_NO_INFLUENCE   (0xFlu << 20)
#define SD_CMD6_GRP6_DEFAULT        (0x0lu << 20)
//! CMD6 arg[30:24] reserved 0
//! CMD6 arg[31   ] Mode, 0: Check, 1: Switch
#define SD_CMD6_MODE_CHECK          (0lu << 31)
#define SD_CMD6_MODE_SWITCH         (1lu << 31)
  //! @}

  //! \name SD CMD8 argument structure
  //! @{
#define SD_CMD8_PATTERN       0xAA
#define SD_CMD8_MASK_PATTERN  0xFF
#define SD_CMD8_HIGH_VOLTAGE  0x100
#define SD_CMD8_MASK_VOLTAGE  0xF00
  //! @}

  //! \name SD ACMD41 arguments
  //! @{
#define SD_ACMD41_HCS   (1lu << 30) //!< (SD) Host Capacity Support
  //! @}
//! @}


//! \name SDIO definitions
//! @{

  //! \name SDIO state (in R5)
  //! @{
#define SDIO_R5_COM_CRC_ERROR   (1lu << 15) /**< CRC check error */
#define SDIO_R5_ILLEGAL_COMMAND (1lu << 14) /**< Illegal command */
#define SDIO_R5_STATE           (3lu << 12) /**< SDIO R5 state mask */
#define SDIO_R5_STATE_DIS       (0lu << 12) /**< Disabled */
#define SDIO_R5_STATE_CMD       (1lu << 12) /**< DAT lines free */
#define SDIO_R5_STATE_TRN       (2lu << 12) /**< Transfer */
#define SDIO_R5_STATE_RFU       (3lu << 12) /**< Reserved */
#define SDIO_R5_ERROR           (1lu << 11) /**< General error */
#define SDIO_R5_FUNC_NUM        (1lu << 9)  /**< Invalid function number */
#define SDIO_R5_OUT_OF_RANGE    (1lu << 8)  /**< Argument out of range */
#define SDIO_R5_STATUS_ERR      (SDIO_R5_ERROR | SDIO_R5_FUNC_NUM \
		| SDIO_R5_OUT_OF_RANGE) //!< Errro status bits mask
  //! @}

  //! \name SDIO state (in R6)
  //! @{
/** The CRC check of the previous command failed. */
#define SDIO_R6_COM_CRC_ERROR   (1lu << 15)
/** Command not legal for the card state. */
#define SDIO_R6_ILLEGAL_COMMAND (1lu << 14)
/** A general or an unknown error occurred during the operation. */
#define SDIO_R6_ERROR           (1lu << 13)
/** Status bits mask for SDIO R6 */
#define SDIO_STATUS_R6  (SDIO_R6_COM_CRC_ERROR \
		| SDIO_R6_ILLEGAL_COMMAND | SDIO_R6_ERROR)
  //! @}

  //! \name SDIO CMD52 argument bit offset
  //! @{
//! CMD52 arg[ 7: 0] Write data or stuff bits
#define SDIO_CMD52_WR_DATA      0
//! CMD52 arg[    8] Reserved
#define SDIO_CMD52_STUFF0       8
//! CMD52 arg[25: 9] Register address
#define SDIO_CMD52_REG_ADRR     9
//! CMD52 arg[   26] Reserved
#define SDIO_CMD52_STUFF1       26
//! CMD52 arg[   27] Read after Write flag
#define SDIO_CMD52_RAW_FLAG     27
//! CMD52 arg[30:28] Number of the function
#define SDIO_CMD52_FUNCTION_NUM 28
//! CMD52 arg[   31] Direction, 1:write, 0:read.
#define SDIO_CMD52_RW_FLAG      31
#  define SDIO_CMD52_READ_FLAG    0
#  define SDIO_CMD52_WRITE_FLAG   1
  //! @}

  //! \name SDIO CMD53 argument structure
  //! @{
/**
 * [ 8: 0] Byte mode: number of bytes to transfer,
 *                    0 cause 512 bytes transfer.
 *         Block mode: number of blocks to transfer,
 *                    0 set count to infinite.
 */
#define SDIO_CMD53_COUNT        0
//! CMD53 arg[25: 9] Start Address I/O register
#define SDIO_CMD53_REG_ADDR     9
//! CMD53 arg[   26] 1:Incrementing address, 0: fixed
#define SDIO_CMD53_OP_CODE      26
//! CMD53 arg[   27] (Optional) 1:block mode
#define SDIO_CMD53_BLOCK_MODE   27
//! CMD53 arg[30:28] Number of the function
#define SDIO_CMD53_FUNCTION_NUM 28
//! CMD53 arg[   31] Direction, 1:WR, 0:RD
#define SDIO_CMD53_RW_FLAG      31
#  define SDIO_CMD53_READ_FLAG    0
#  define SDIO_CMD53_WRITE_FLAG   1
  //! @}

  //! \name SDIO Functions
  //! @{
#define SDIO_CIA  0 /**< SDIO Function 0 (CIA) */
#define SDIO_FN0  0 /**< SDIO Function 0 */
#define SDIO_FN1  1 /**< SDIO Function 1 */
#define SDIO_FN2  2 /**< SDIO Function 2 */
#define SDIO_FN3  3 /**< SDIO Function 3 */
#define SDIO_FN4  4 /**< SDIO Function 4 */
#define SDIO_FN5  5 /**< SDIO Function 5 */
#define SDIO_FN6  6 /**< SDIO Function 6 */
#define SDIO_FN7  7 /**< SDIO Function 7 */
  //! @}

  //! \name SDIO Card Common Control Registers (CCCR)
  //! @{
#define SDIO_CCCR_SDIO_REV    0x00         /**< CCCR/SDIO revision (RO) */
#define   SDIO_CCCR_REV_1_00    (0x0lu << 0)  /**< CCCR/FBR Version 1.00 */
#define   SDIO_CCCR_REV_1_10    (0x1lu << 0)  /**< CCCR/FBR Version 1.10 */
#define   SDIO_CCCR_REV_2_00    (0x2lu << 0)  /**< CCCR/FBR Version 2.00 */
#define   SDIO_CCCR_REV_3_00    (0x3lu << 0)  /**< CCCR/FBR Version 3.00 */
#define   SDIO_SDIO_REV_1_00    (0x0lu << 4)  /**< SDIO Spec 1.00 */
#define   SDIO_SDIO_REV_1_10    (0x1lu << 4)  /**< SDIO Spec 1.10 */
#define   SDIO_SDIO_REV_1_20    (0x2lu << 4)  /**< SDIO Spec 1.20(unreleased) */
#define   SDIO_SDIO_REV_2_00    (0x3lu << 4)  /**< SDIO Spec Version 2.00 */
#define   SDIO_SDIO_REV_3_00    (0x4lu << 4)  /**< SDIO Spec Version 3.00 */
#define SDIO_CCCR_SD_REV      0x01         /**< SD Spec Revision (RO) */
#define   SDIO_SD_REV_1_01      (0x0lu << 0)  /**< SD 1.01 (Mar 2000) */
#define   SDIO_SD_REV_1_10      (0x1lu << 0)  /**< SD 1.10 (Oct 2004) */
#define   SDIO_SD_REV_2_00      (0x2lu << 0)  /**< SD 2.00 (May 2006) */
#define   SDIO_SD_REV_3_00      (0x3lu << 0)  /**< SD 3.00 */
#define SDIO_CCCR_IOE         0x02         /**< I/O Enable (R/W) */
#define   SDIO_IOE_FN1          (0x1lu << 1)  /**< Function 1 Enable/Disable */
#define   SDIO_IOE_FN2          (0x1lu << 2)  /**< Function 2 Enable/Disable */
#define   SDIO_IOE_FN3          (0x1lu << 3)  /**< Function 3 Enable/Disable */
#define   SDIO_IOE_FN4          (0x1lu << 4)  /**< Function 4 Enable/Disable */
#define   SDIO_IOE_FN5          (0x1lu << 5)  /**< Function 5 Enable/Disable */
#define   SDIO_IOE_FN6          (0x1lu << 6)  /**< Function 6 Enable/Disable */
#define   SDIO_IOE_FN7          (0x1lu << 7)  /**< Function 7 Enable/Disable */
#define SDIO_CCCR_IOR         0x03         /**< I/O Ready (RO) */
#define   SDIO_IOR_FN1          (0x1lu << 1)  /**< Function 1 ready */
#define   SDIO_IOR_FN2          (0x1lu << 2)  /**< Function 2 ready */
#define   SDIO_IOR_FN3          (0x1lu << 3)  /**< Function 3 ready */
#define   SDIO_IOR_FN4          (0x1lu << 4)  /**< Function 4 ready */
#define   SDIO_IOR_FN5          (0x1lu << 5)  /**< Function 5 ready */
#define   SDIO_IOR_FN6          (0x1lu << 6)  /**< Function 6 ready */
#define   SDIO_IOR_FN7          (0x1lu << 7)  /**< Function 7 ready */
#define SDIO_CCCR_IEN         0x04         /**< Int Enable */
#define   SDIO_IENM             (0x1lu << 0)  /**< Int Enable Master (R/W) */
#define   SDIO_IEN_FN1          (0x1lu << 1)  /**< Function 1 Int Enable */
#define   SDIO_IEN_FN2          (0x1lu << 2)  /**< Function 2 Int Enable */
#define   SDIO_IEN_FN3          (0x1lu << 3)  /**< Function 3 Int Enable */
#define   SDIO_IEN_FN4          (0x1lu << 4)  /**< Function 4 Int Enable */
#define   SDIO_IEN_FN5          (0x1lu << 5)  /**< Function 5 Int Enable */
#define   SDIO_IEN_FN6          (0x1lu << 6)  /**< Function 6 Int Enable */
#define   SDIO_IEN_FN7          (0x1lu << 7)  /**< Function 7 Int Enable */
#define SDIO_CCCR_INT         0x05         /**< Int Pending */
#define   SDIO_INT_FN1          (0x1lu << 1)  /**< Function 1 Int pending */
#define   SDIO_INT_FN2          (0x1lu << 2)  /**< Function 2 Int pending */
#define   SDIO_INT_FN3          (0x1lu << 3)  /**< Function 3 Int pending */
#define   SDIO_INT_FN4          (0x1lu << 4)  /**< Function 4 Int pending */
#define   SDIO_INT_FN5          (0x1lu << 5)  /**< Function 5 Int pending */
#define   SDIO_INT_FN6          (0x1lu << 6)  /**< Function 6 Int pending */
#define   SDIO_INT_FN7          (0x1lu << 7)  /**< Function 7 Int pending */
#define SDIO_CCCR_IOA         0x06         /**< I/O Abort */
#define   SDIO_AS_FN1           (0x1lu << 0)  /**< Abort function 1 IO */
#define   SDIO_AS_FN2           (0x2lu << 0)  /**< Abort function 2 IO */
#define   SDIO_AS_FN3           (0x3lu << 0)  /**< Abort function 3 IO */
#define   SDIO_AS_FN4           (0x4lu << 0)  /**< Abort function 4 IO */
#define   SDIO_AS_FN5           (0x5lu << 0)  /**< Abort function 5 IO */
#define   SDIO_AS_FN6           (0x6lu << 0)  /**< Abort function 6 IO */
#define   SDIO_AS_FN7           (0x7lu << 0)  /**< Abort function 7 IO */
#define   SDIO_RES              (0x1lu << 3)  /**< IO CARD RESET (WO) */
#define SDIO_CCCR_BUS_CTRL    0x07         /**< Bus Interface Control */
#define   SDIO_BUSWIDTH_1B      (0x0lu << 0)  /**< 1-bit data bus */
#define   SDIO_BUSWIDTH_4B      (0x2lu << 0)  /**< 4-bit data bus */
/** Enable Continuous SPI interrupt (R/W) */
#define   SDIO_BUS_ECSI         (0x1lu << 5)
/** Support Continuous SPI interrupt (RO) */
#define   SDIO_BUS_SCSI         (0x1lu << 6)
/** Connect(0)/Disconnect(1) pull-up on CD/DAT[3] (R/W) */
#define   SDIO_BUS_CD_DISABLE   (0x1lu << 7)
#define SDIO_CCCR_CAP         0x08         /**< Card Capability */
/** Support Direct Commands during data transfer (RO) */
#define   SDIO_CAP_SDC          (0x1lu << 0)
/** Support Multi-Block (RO) */
#define   SDIO_CAP_SMB          (0x1lu << 1)
/** Support Read Wait (RO) */
#define   SDIO_CAP_SRW          (0x1lu << 2)
/** Support Suspend/Resume (RO) */
#define   SDIO_CAP_SBS          (0x1lu << 3)
/** Support interrupt between blocks of data in 4-bit SD mode (RO) */
#define   SDIO_CAP_S4MI         (0x1lu << 4)
/** Enable interrupt between blocks of data in 4-bit SD mode (R/W) */
#define   SDIO_CAP_E4MI         (0x1lu << 5)
/** Low-Speed Card (RO) */
#define   SDIO_CAP_LSC          (0x1lu << 6)
/** 4-bit support for Low-Speed Card (RO) */
#define   SDIO_CAP_4BLS         (0x1lu << 7)
/** Pointer to CIS (3B, LSB first) */
#define SDIO_CCCR_CIS_PTR     0x09
/** Bus Suspend */
#define SDIO_CCCR_BUS_SUSPEND 0x0C
/** Bus Status (transfer on DAT[x] lines) (RO) */
#define   SDIO_BS               (0x1lu << 0)
/** Bus Release Request/Status (R/W) */
#define   SDIO_BR               (0x1lu << 1)
#define SDIO_CCCR_FUN_SEL     0x0D         /**< Function select */
#define   SDIO_DF               (0x1lu << 7)  /**< Resume Data Flag (RO) */
#define   SDIO_FS_CIA           (0x0lu << 0)  /**< Select CIA (function 0) */
#define   SDIO_FS_FN1           (0x1lu << 0)  /**< Select Function 1 */
#define   SDIO_FS_FN2           (0x2lu << 0)  /**< Select Function 2 */
#define   SDIO_FS_FN3           (0x3lu << 0)  /**< Select Function 3 */
#define   SDIO_FS_FN4           (0x4lu << 0)  /**< Select Function 4 */
#define   SDIO_FS_FN5           (0x5lu << 0)  /**< Select Function 5 */
#define   SDIO_FS_FN6           (0x6lu << 0)  /**< Select Function 6 */
#define   SDIO_FS_FN7           (0x7lu << 0)  /**< Select Function 7 */
#define   SDIO_FS_MEM           (0x8lu << 0)  /**< Select memory in combo card */
#define SDIO_CCCR_EXEC        0x0E         /**< Exec Flags (RO) */
#define   SDIO_EXM              (0x1lu << 0)  /**< Executing status of memory */
#define   SDIO_EX_FN1           (0x1lu << 1)  /**< Executing status of func 1 */
#define   SDIO_EX_FN2           (0x1lu << 2)  /**< Executing status of func 2 */
#define   SDIO_EX_FN3           (0x1lu << 3)  /**< Executing status of func 3 */
#define   SDIO_EX_FN4           (0x1lu << 4)  /**< Executing status of func 4 */
#define   SDIO_EX_FN5           (0x1lu << 5)  /**< Executing status of func 5 */
#define   SDIO_EX_FN6           (0x1lu << 6)  /**< Executing status of func 6 */
#define   SDIO_EX_FN7           (0x1lu << 7)  /**< Executing status of func 7 */
#define SDIO_CCCR_READY       0x0F         /**< Ready Flags (RO) */
#define   SDIO_RFM              (0x1lu << 0)  /**< Ready Flag for memory */
#define   SDIO_RF_FN1           (0x1lu << 1)  /**< Ready Flag for function 1 */
#define   SDIO_RF_FN2           (0x1lu << 2)  /**< Ready Flag for function 2 */
#define   SDIO_RF_FN3           (0x1lu << 3)  /**< Ready Flag for function 3 */
#define   SDIO_RF_FN4           (0x1lu << 4)  /**< Ready Flag for function 4 */
#define   SDIO_RF_FN5           (0x1lu << 5)  /**< Ready Flag for function 5 */
#define   SDIO_RF_FN6           (0x1lu << 6)  /**< Ready Flag for function 6 */
#define   SDIO_RF_FN7           (0x1lu << 7)  /**< Ready Flag for function 7 */
#define SDIO_CCCR_FN0_BLKSIZ  0x10  /**< FN0 Block Size (2B, LSB first) (R/W) */
#define SDIO_CCCR_POWER       0x12         /**< Power Control */
#define   SDIO_POWER_SMPC       (0x1lu << 0)  /**< Support Master Power Control*/
#define   SDIO_POWER_EMPC       (0x1lu << 1)  /**< Enable Master Power Control */
#define SDIO_CCCR_HS          0x13         /**< High-Speed */
#define   SDIO_SHS              (0x1lu << 0)  /**< Support High-Speed (RO) */
#define   SDIO_EHS              (0x1lu << 1)  /**< Enable High-Speed (R/W) */
  //! @}

  //! \name SDIO Card Metaformat
  //! @{
/** Null tuple (PCMCIA 3.1.9) */
#define SDIO_CISTPL_NULL     0x00
/** Device tuple (PCMCIA 3.2.2) */
#define SDIO_CISTPL_DEVICE   0x01
/** Checksum control (PCMCIA 3.1.1) */
#define SDIO_CISTPL_CHECKSUM 0x10
/** Level 1 version (PCMCIA 3.2.10) */
#define SDIO_CISTPL_VERS_1   0x15
/** Alternate Language String (PCMCIA 3.2.1) */
#define SDIO_CISTPL_ALTSTR   0x16
/** Manufacturer Identification String (PCMCIA 3.2.9) */
#define SDIO_CISTPL_MANFID   0x20
/** Function Identification (PCMCIA 3.2.7) */
#define SDIO_CISTPL_FUNCID   0x21
/** Function Extensions (PCMCIA 3.2.6) */
#define SDIO_CISTPL_FUNCE    0x22
/** Additional information for SDIO (PCMCIA 6.1.2) */
#define SDIO_CISTPL_SDIO_STD 0x91
/** Reserved for future SDIO (PCMCIA 6.1.3) */
#define SDIO_CISTPL_SDIO_EXT 0x92
/** The End-of-chain Tuple (PCMCIA 3.1.2) */
#define SDIO_CISTPL_END      0xFF
  //! @}

//! @}

//! \name CSD, OCR, SCR, Switch status, extend CSD definitions
//! @{

/**
 * \brief Macro function to extract a bits field from a large SD MMC register
 * Used by : CSD, SCR, Switch status
 */
static inline uint32_t SDMMC_UNSTUFF_BITS(uint8_t *reg, uint16_t reg_size,
		uint16_t pos, uint8_t size)
{
	uint32_t value;
	value = reg[((reg_size - pos + 7) / 8) - 1] >> (pos % 8);
	if (((pos % 8) + size) > 8) {
		value |= (uint32_t)reg[((reg_size - pos + 7) / 8) - 2] << (8 - (pos % 8));
	}
	if (((pos % 8) + size) > 16) {
		value |= (uint32_t)reg[((reg_size - pos + 7) / 8) - 3] << (16 - (pos % 8));
	}
	if (((pos % 8) + size) > 16) {
		value |= (uint32_t)reg[((reg_size - pos + 7) / 8) - 3] << (16 - (pos % 8));
	}
	value &=  ((uint32_t)1 << size) - 1;
	return value;
}

  //! \name CSD Fields
  //! @{
#define CSD_REG_BIT_SIZE            128 //!< 128 bits
#define CSD_REG_BSIZE               (CSD_REG_BIT_SIZE / 8) //!< 16 bytes
#define CSD_STRUCTURE(csd, pos, size) \
		SDMMC_UNSTUFF_BITS(csd, CSD_REG_BIT_SIZE, pos, size)
#define CSD_STRUCTURE_VERSION(csd)  CSD_STRUCTURE(csd, 126, 2)
#define   SD_CSD_VER_1_0            0
#define   SD_CSD_VER_2_0            1
#define   MMC_CSD_VER_1_0           0
#define   MMC_CSD_VER_1_1           1
#define   MMC_CSD_VER_1_2           2
#define CSD_TRAN_SPEED(csd)         CSD_STRUCTURE(csd, 96, 8)
#define SD_CSD_1_0_C_SIZE(csd)      CSD_STRUCTURE(csd, 62, 12)
#define SD_CSD_1_0_C_SIZE_MULT(csd) CSD_STRUCTURE(csd, 47, 3)
#define SD_CSD_1_0_READ_BL_LEN(csd) CSD_STRUCTURE(csd, 80, 4)
#define SD_CSD_2_0_C_SIZE(csd)      CSD_STRUCTURE(csd, 48, 22)
#define MMC_CSD_C_SIZE(csd)         CSD_STRUCTURE(csd, 62, 12)
#define MMC_CSD_C_SIZE_MULT(csd)    CSD_STRUCTURE(csd, 47, 3)
#define MMC_CSD_READ_BL_LEN(csd)    CSD_STRUCTURE(csd, 80, 4)
#define MMC_CSD_SPEC_VERS(csd)      CSD_STRUCTURE(csd, 122, 4)
  //! @}

  //! \name OCR Register Fields
  //! @{
#define OCR_REG_BSIZE          (32 / 8)    /**< 32 bits, 4 bytes */
#define OCR_VDD_170_195        (1lu << 7)
#define OCR_VDD_20_21          (1lu << 8)
#define OCR_VDD_21_22          (1lu << 9)
#define OCR_VDD_22_23          (1lu << 10)
#define OCR_VDD_23_24          (1lu << 11)
#define OCR_VDD_24_25          (1lu << 12)
#define OCR_VDD_25_26          (1lu << 13)
#define OCR_VDD_26_27          (1lu << 14)
#define OCR_VDD_27_28          (1lu << 15)
#define OCR_VDD_28_29          (1lu << 16)
#define OCR_VDD_29_30          (1lu << 17)
#define OCR_VDD_30_31          (1lu << 18)
#define OCR_VDD_31_32          (1lu << 19)
#define OCR_VDD_32_33          (1lu << 20)
#define OCR_VDD_33_34          (1lu << 21)
#define OCR_VDD_34_35          (1lu << 22)
#define OCR_VDD_35_36          (1lu << 23)
#define OCR_SDIO_S18R          (1lu << 24) /**< Switching to 1.8V Accepted */
#define OCR_SDIO_MP            (1lu << 27) /**< Memory Present */
#define OCR_SDIO_NF            (7lu << 28) /**< Number of I/O Functions */
#define OCR_ACCESS_MODE_MASK   (3lu << 29) /**< (MMC) Access mode mask */
#define OCR_ACCESS_MODE_BYTE   (0lu << 29) /**< (MMC) Byte access mode */
#define OCR_ACCESS_MODE_SECTOR (2lu << 29) /**< (MMC) Sector access mode */
#define OCR_CCS                (1lu << 30) /**< (SD) Card Capacity Status */
#define OCR_POWER_UP_BUSY      (1lu << 31) /**< Card power up status bit */
  //! @}

  //! \name SD SCR Register Fields
  //! @{
#define SD_SCR_REG_BIT_SIZE    64 //!< 64 bits
#define SD_SCR_REG_BSIZE       (SD_SCR_REG_BIT_SIZE / 8) //!< 8 bytes
#define SD_SCR_STRUCTURE(scr, pos, size) \
		SDMMC_UNSTUFF_BITS(scr, SD_SCR_REG_BIT_SIZE, pos, size)
#define SD_SCR_SCR_STRUCTURE(scr)            SD_SCR_STRUCTURE(scr, 60, 4)
#define   SD_SCR_SCR_STRUCTURE_1_0             0
#define SD_SCR_SD_SPEC(scr)                  SD_SCR_STRUCTURE(scr, 56, 4)
#define   SD_SCR_SD_SPEC_1_0_01                0
#define   SD_SCR_SD_SPEC_1_10                  1
#define   SD_SCR_SD_SPEC_2_00                  2
#define SD_SCR_DATA_STATUS_AFTER_ERASE(scr)  SD_SCR_STRUCTURE(scr, 55, 1)
#define SD_SCR_SD_SECURITY(scr)              SD_SCR_STRUCTURE(scr, 52, 3)
#define   SD_SCR_SD_SECURITY_NO                0
#define   SD_SCR_SD_SECURITY_NOTUSED           1
#define   SD_SCR_SD_SECURITY_1_01              2
#define   SD_SCR_SD_SECURITY_2_00              3
#define   SD_SCR_SD_SECURITY_3_00              4
#define SD_SCR_SD_BUS_WIDTHS(scr)            SD_SCR_STRUCTURE(scr, 48, 4)
#define   SD_SCR_SD_BUS_WIDTH_1BITS            (1lu << 0)
#define   SD_SCR_SD_BUS_WIDTH_4BITS            (1lu << 2)
#define SD_SCR_SD_SPEC3(scr)                 SD_SCR_STRUCTURE(scr, 47, 1)
#define   SD_SCR_SD_SPEC_3_00                  1
#define SD_SCR_SD_EX_SECURITY(scr)           SD_SCR_STRUCTURE(scr, 43, 4)
#define SD_SCR_SD_CMD_SUPPORT(scr)           SD_SCR_STRUCTURE(scr, 32, 2)
  //! @}

  //! \name SD Switch Status Fields
  //! @{
#define SD_SW_STATUS_BIT_SIZE   512 //!< 512 bits
#define SD_SW_STATUS_BSIZE      (SD_SW_STATUS_BIT_SIZE / 8) //!< 64 bytes
#define SD_SW_STATUS_STRUCTURE(sd_sw_status, pos, size) \
		SDMMC_UNSTUFF_BITS(sd_sw_status, SD_SW_STATUS_BIT_SIZE, pos, size)
#define SD_SW_STATUS_MAX_CURRENT_CONSUMPTION(status) \
		SD_SW_STATUS_STRUCTURE(status, 496, 16)
#define SD_SW_STATUS_FUN_GRP6_INFO(status) \
		SD_SW_STATUS_STRUCTURE(status, 480, 16)
#define SD_SW_STATUS_FUN_GRP5_INFO(status) \
		SD_SW_STATUS_STRUCTURE(status, 464, 16)
#define SD_SW_STATUS_FUN_GRP4_INFO(status) \
		SD_SW_STATUS_STRUCTURE(status, 448, 16)
#define SD_SW_STATUS_FUN_GRP3_INFO(status) \
		SD_SW_STATUS_STRUCTURE(status, 432, 16)
#define SD_SW_STATUS_FUN_GRP2_INFO(status) \
		SD_SW_STATUS_STRUCTURE(status, 416, 16)
#define SD_SW_STATUS_FUN_GRP1_INFO(status) \
		SD_SW_STATUS_STRUCTURE(status, 400, 16)
#define SD_SW_STATUS_FUN_GRP6_RC(status) \
		SD_SW_STATUS_STRUCTURE(status, 396, 4)
#define SD_SW_STATUS_FUN_GRP5_RC(status) \
		SD_SW_STATUS_STRUCTURE(status, 392, 4)
#define SD_SW_STATUS_FUN_GRP4_RC(status) \
		SD_SW_STATUS_STRUCTURE(status, 388, 4)
#define SD_SW_STATUS_FUN_GRP3_RC(status) \
		SD_SW_STATUS_STRUCTURE(status, 384, 4)
#define SD_SW_STATUS_FUN_GRP2_RC(status) \
		SD_SW_STATUS_STRUCTURE(status, 380, 4)
#define SD_SW_STATUS_FUN_GRP1_RC(status) \
		SD_SW_STATUS_STRUCTURE(status, 376, 4)
#define SD_SW_STATUS_FUN_GRP_RC_ERROR   0xFU
#define SD_SW_STATUS_DATA_STRUCT_VER(status) \
		SD_SW_STATUS_STRUCTURE(status, 368, 8)
#define SD_SW_STATUS_FUN_GRP6_BUSY(status) \
		SD_SW_STATUS_STRUCTURE(status, 352, 16)
#define SD_SW_STATUS_FUN_GRP5_BUSY(status) \
		SD_SW_STATUS_STRUCTURE(status, 336, 16)
#define SD_SW_STATUS_FUN_GRP4_BUSY(status) \
		SD_SW_STATUS_STRUCTURE(status, 320, 16)
#define SD_SW_STATUS_FUN_GRP3_BUSY(status) \
		SD_SW_STATUS_STRUCTURE(status, 304, 16)
#define SD_SW_STATUS_FUN_GRP2_BUSY(status) \
		SD_SW_STATUS_STRUCTURE(status, 288, 16)
#define SD_SW_STATUS_FUN_GRP1_BUSY(status) \
		SD_SW_STATUS_STRUCTURE(status, 272, 16)
  //! @}

  //! \name Card Status Fields
  //! @{
#define CARD_STATUS_APP_CMD           (1lu << 5)
#define CARD_STATUS_SWITCH_ERROR      (1lu << 7)
#define CARD_STATUS_READY_FOR_DATA    (1lu << 8)
#define CARD_STATUS_STATE_IDLE        (0lu << 9)
#define CARD_STATUS_STATE_READY       (1lu << 9)
#define CARD_STATUS_STATE_IDENT       (2lu << 9)
#define CARD_STATUS_STATE_STBY        (3lu << 9)
#define CARD_STATUS_STATE_TRAN        (4lu << 9)
#define CARD_STATUS_STATE_DATA        (5lu << 9)
#define CARD_STATUS_STATE_RCV         (6lu << 9)
#define CARD_STATUS_STATE_PRG         (7lu << 9)
#define CARD_STATUS_STATE_DIS         (8lu << 9)
#define CARD_STATUS_STATE             (0xFlu << 9)
#define CARD_STATUS_ERASE_RESET       (1lu << 13)
#define CARD_STATUS_WP_ERASE_SKIP     (1lu << 15)
#define CARD_STATUS_CIDCSD_OVERWRITE  (1lu << 16)
#define CARD_STATUS_OVERRUN           (1lu << 17)
#define CARD_STATUS_UNERRUN           (1lu << 18)
#define CARD_STATUS_ERROR             (1lu << 19)
#define CARD_STATUS_CC_ERROR          (1lu << 20)
#define CARD_STATUS_CARD_ECC_FAILED   (1lu << 21)
#define CARD_STATUS_ILLEGAL_COMMAND   (1lu << 22)
#define CARD_STATUS_COM_CRC_ERROR     (1lu << 23)
#define CARD_STATUS_UNLOCK_FAILED     (1lu << 24)
#define CARD_STATUS_CARD_IS_LOCKED    (1lu << 25)
#define CARD_STATUS_WP_VIOLATION      (1lu << 26)
#define CARD_STATUS_ERASE_PARAM       (1lu << 27)
#define CARD_STATUS_ERASE_SEQ_ERROR   (1lu << 28)
#define CARD_STATUS_BLOCK_LEN_ERROR   (1lu << 29)
#define CARD_STATUS_ADDRESS_MISALIGN  (1lu << 30)
#define CARD_STATUS_ADDR_OUT_OF_RANGE (1lu << 31)

#define CARD_STATUS_ERR_RD_WR    (CARD_STATUS_ADDR_OUT_OF_RANGE \
		| CARD_STATUS_ADDRESS_MISALIGN \
		| CARD_STATUS_BLOCK_LEN_ERROR \
		| CARD_STATUS_WP_VIOLATION \
		| CARD_STATUS_ILLEGAL_COMMAND \
		| CARD_STATUS_CC_ERROR \
		| CARD_STATUS_ERROR)
  //! @}

  //! \name SD Status Field
  //! @{
#define SD_STATUS_BSIZE    (512 / 8)  /**< 512 bits, 64bytes */
  //! @}

  //! \name MMC Extended CSD Register Field
  //! @{
#define EXT_CSD_BSIZE    512  /**< 512 bytes. */
/* Below belongs to Properties Segment */
#define EXT_CSD_S_CMD_SET_INDEX              504lu
#define EXT_CSD_BOOT_INFO_INDEX              228lu
#define EXT_CSD_BOOT_SIZE_MULTI_INDEX        226lu
#define EXT_CSD_ACC_SIZE_INDEX               225lu
#define EXT_CSD_HC_ERASE_GRP_SIZE_INDEX      224lu
#define EXT_CSD_ERASE_TIMEOUT_MULT_INDEX     223lu
#define EXT_CSD_REL_WR_SEC_C_INDEX           222lu
#define EXT_CSD_HC_WP_GRP_SIZE_INDEX         221lu
#define EXT_CSD_S_C_VCC_INDEX                220lu
#define EXT_CSD_S_C_VCCQ_INDEX               219lu
#define EXT_CSD_S_A_TIMEOUT_INDEX            217lu
#define EXT_CSD_SEC_COUNT_INDEX              212lu
#define EXT_CSD_MIN_PERF_W_8_52_INDEX        210lu
#define EXT_CSD_MIN_PERF_R_8_52_INDEX        209lu
#define EXT_CSD_MIN_PERF_W_8_26_4_52_INDEX   208lu
#define EXT_CSD_MIN_PERF_R_8_26_4_52_INDEX   207lu
#define EXT_CSD_MIN_PERF_W_4_26_INDEX        206lu
#define EXT_CSD_MIN_PERF_R_4_26_INDEX        205lu
#define EXT_CSD_PWR_CL_26_360_INDEX          203lu
#define EXT_CSD_PWR_CL_52_360_INDEX          202lu
#define EXT_CSD_PWR_CL_26_195_INDEX          201lu
#define EXT_CSD_PWR_CL_52_195_INDEX          200lu
#define EXT_CSD_CARD_TYPE_INDEX              196lu
/* MMC card type */
#  define MMC_CTYPE_26MHZ    0x1
#  define MMC_CTYPE_52MHZ    0x2
#define EXT_CSD_CSD_STRUCTURE_INDEX          194lu
#define EXT_CSD_EXT_CSD_REV_INDEX            192lu

/* Below belongs to Mode Segment */
#define EXT_CSD_CMD_SET_INDEX                191lu
#define EXT_CSD_CMD_SET_REV_INDEX            189lu
#define EXT_CSD_POWER_CLASS_INDEX            187lu
#define EXT_CSD_HS_TIMING_INDEX              185lu
#define EXT_CSD_BUS_WIDTH_INDEX              183lu
#define EXT_CSD_ERASED_MEM_CONT_INDEX        181lu
#define EXT_CSD_BOOT_CONFIG_INDEX            179lu
#define EXT_CSD_BOOT_BUS_WIDTH_INDEX         177lu
#define EXT_CSD_ERASE_GROUP_DEF_INDEX        175lu
  //! @}
//! @}


//! \name Definition for SPI mode only
//! @{

//! SPI commands start with a start bit "0" and a transmit bit "1"
#define SPI_CMD_ENCODE(x) (0x40 | (x & 0x3F))

//! \name Register R1 definition for SPI mode
//! The R1 register is always send after a command.
//! @{
#define R1_SPI_IDLE                 (1lu << 0)
#define R1_SPI_ERASE_RESET          (1lu << 1)
#define R1_SPI_ILLEGAL_COMMAND      (1lu << 2)
#define R1_SPI_COM_CRC              (1lu << 3)
#define R1_SPI_ERASE_SEQ            (1lu << 4)
#define R1_SPI_ADDRESS              (1lu << 5)
#define R1_SPI_PARAMETER            (1lu << 6)
// R1 bit 7 is always zero, reuse this bit for error
#define R1_SPI_ERROR                (1lu << 7)
//! @}

//! \name Register R2 definition for SPI mode
//! The R2 register can be send after R1 register.
//! @{
#define R2_SPI_CARD_LOCKED      (1lu << 0)
#define R2_SPI_WP_ERASE_SKIP    (1lu << 1)
#define R2_SPI_LOCK_UNLOCK_FAIL R2_SPI_WP_ERASE_SKIP
#define R2_SPI_ERROR            (1lu << 2)
#define R2_SPI_CC_ERROR         (1lu << 3)
#define R2_SPI_CARD_ECC_ERROR   (1lu << 4)
#define R2_SPI_WP_VIOLATION     (1lu << 5)
#define R2_SPI_ERASE_PARAM      (1lu << 6)
#define R2_SPI_OUT_OF_RANGE     (1lu << 7)
#define R2_SPI_CSD_OVERWRITE    R2_SPI_OUT_OF_RANGE
//! @}

//! \name Control Tokens in SPI Mode
//! @{
  //! \name Tokens used for a read operation
  //! @{
#define SPI_TOKEN_SINGLE_MULTI_READ       0xFE
#define SPI_TOKEN_DATA_ERROR_VALID(token) (((token) & 0xF0) == 0)
#define SPI_TOKEN_DATA_ERROR_ERRORS       (0x0F)
#define SPI_TOKEN_DATA_ERROR_ERROR        (1lu << 0)
#define SPI_TOKEN_DATA_ERROR_CC_ERROR     (1lu << 1)
#define SPI_TOKEN_DATA_ERROR_ECC_ERROR    (1lu << 2)
#define SPI_TOKEN_DATA_ERROR_OUT_RANGE    (1lu << 3)
  //! @}
  //! \name Tokens used for a write operation
  //! @{
#define SPI_TOKEN_SINGLE_WRITE            0xFE
#define SPI_TOKEN_MULTI_WRITE             0xFC
#define SPI_TOKEN_STOP_TRAN               0xFD
#define SPI_TOKEN_DATA_RESP_VALID(token)  \
		((((token) & (1 << 4)) == 0) && (((token) & (1 << 0)) == 1))
#define SPI_TOKEN_DATA_RESP_CODE(token)   ((token) & 0x1E)
#define SPI_TOKEN_DATA_RESP_ACCEPTED      (2lu << 1)
#define SPI_TOKEN_DATA_RESP_CRC_ERR       (5lu << 1)
#define SPI_TOKEN_DATA_RESP_WRITE_ERR     (6lu << 1)
  //! @}
//! @}
//! @}


//! @} end of sd_mmc_protocol

#ifdef __cplusplus
}
#endif

#endif /* SD_MMC_PROTOCOL_H_INCLUDED */
