Re: [PATCH v4 01/15] mmc: sd: add support for signal voltage switch procedure

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, May 5, 2011 at 2:48 AM, Arindam Nath <arindam.nath@xxxxxxx> wrote:
> Host Controller v3.00 adds another Capabilities register. Apart
> from other things, this new register indicates whether the Host
> Controller supports SDR50, SDR104, and DDR50 UHS-I modes. The spec
> doesn't mention about explicit support for SDR12 and SDR25 UHS-I
> modes, so the Host Controller v3.00 should support them by default.
> Also if the controller supports SDR104 mode, it will also support
> SDR50 mode as well. So depending on the host support, we set the
> corresponding MMC_CAP_* flags. One more new register. Host Control2
> is added in v3.00, which is used during Signal Voltage Switch
> procedure described below.
>
> Since as per v3.00 spec, UHS-I supported hosts should set S18R
> to 1, we set S18R (bit 24) of OCR before sending ACMD41. We also
> need to set XPC (bit 28) of OCR in case the host can supply >150mA.
> This support is indicated by the Maximum Current Capabilities
> register of the Host Controller.
>
> If the response of ACMD41 has both CCS and S18A set, we start the
> signal voltage switch procedure, which if successfull, will switch
> the card from 3.3V signalling to 1.8V signalling. Signal voltage
> switch procedure adds support for a new command CMD11 in the
> Physical Layer Spec v3.01. As part of this procedure, we need to
> set 1.8V Signalling Enable (bit 3) of Host Control2 register, which
> if remains set after 5ms, means the switch to 1.8V signalling is
> successfull. Otherwise, we clear bit 24 of OCR and retry the
> initialization sequence. When we remove the card, and insert the
> same or another card, we need to make sure that we start with 3.3V
> signalling voltage. So we call mmc_set_signal_voltage() with
> MMC_SIGNAL_VOLTAGE_330 set so that we are back to 3.3V signalling
> voltage before we actually start initializing the card.
>
> Signed-off-by: Arindam Nath <arindam.nath@xxxxxxx>
> Reviewed-by: Philip Rakity <prakity@xxxxxxxxxxx>
> Tested-by: Philip Rakity <prakity@xxxxxxxxxxx>

Acked-by: Zhangfei Gao<zhangfei.gao@xxxxxxxxxxx>
Verified with Toshiba uhs card and general hs card,   on mmp2 in SDMA mode.

> ---
>  drivers/mmc/core/core.c  |   34 ++++++++
>  drivers/mmc/core/core.h  |    1 +
>  drivers/mmc/core/sd.c    |   36 ++++++++-
>  drivers/mmc/host/sdhci.c |  193 ++++++++++++++++++++++++++++++++++++++++++---
>  drivers/mmc/host/sdhci.h |   18 ++++-
>  include/linux/mmc/host.h |   15 ++++
>  include/linux/mmc/sd.h   |    7 ++
>  7 files changed, 287 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 1dbc185..ea5c28d 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -942,6 +942,40 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
>        return ocr;
>  }
>
> +int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
> +{
> +       struct mmc_command cmd;
> +       int err = 0;
> +
> +       BUG_ON(!host);
> +
> +       /*
> +        * Send CMD11 only if the request is to switch the card to
> +        * 1.8V signalling.
> +        */
> +       if (signal_voltage == MMC_SIGNAL_VOLTAGE_180) {
> +               memset(&cmd, 0, sizeof(struct mmc_command));
> +
> +               cmd.opcode = SD_SWITCH_VOLTAGE;
> +               cmd.arg = 0;
> +               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
> +
> +               err = mmc_wait_for_cmd(host, &cmd, 0);
> +               if (err)
> +                       return err;
> +
> +               if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
> +                       return -EIO;
> +       }
> +
> +       host->ios.signal_voltage = signal_voltage;
> +
> +       if (host->ops->start_signal_voltage_switch)
> +               err = host->ops->start_signal_voltage_switch(host, &host->ios);
> +
> +       return err;
> +}
> +
>  /*
>  * Select timing parameters for host.
>  */
> diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
> index ca1fdde..7745dea 100644
> --- a/drivers/mmc/core/core.h
> +++ b/drivers/mmc/core/core.h
> @@ -41,6 +41,7 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
>  void mmc_set_bus_width_ddr(struct mmc_host *host, unsigned int width,
>                           unsigned int ddr);
>  u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
> +int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
>  void mmc_set_timing(struct mmc_host *host, unsigned int timing);
>
>  static inline void mmc_delay(unsigned int ms)
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 6dac89f..b0cd285 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -403,6 +403,7 @@ struct device_type sd_type = {
>  int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
>  {
>        int err;
> +       u32 rocr;
>
>        /*
>         * Since we're changing the OCR value, we seem to
> @@ -420,12 +421,38 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid)
>         */
>        err = mmc_send_if_cond(host, ocr);
>        if (!err)
> -               ocr |= 1 << 30;
> +               ocr |= SD_OCR_CCS;
>
> -       err = mmc_send_app_op_cond(host, ocr, NULL);
> +       /*
> +        * If the host supports one of UHS-I modes, request the card
> +        * to switch to 1.8V signaling level.
> +        */
> +       if (host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
> +           MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))
> +               ocr |= SD_OCR_S18R;
> +
> +       /* If the host can supply more than 150mA, XPC should be set to 1. */
> +       if (host->caps & (MMC_CAP_SET_XPC_330 | MMC_CAP_SET_XPC_300 |
> +           MMC_CAP_SET_XPC_180))
> +               ocr |= SD_OCR_XPC;
> +
> +try_again:
> +       err = mmc_send_app_op_cond(host, ocr, &rocr);
>        if (err)
>                return err;
>
> +       /*
> +        * In case CCS and S18A in the response is set, start Signal Voltage
> +        * Switch procedure. SPI mode doesn't support CMD11.
> +        */
> +       if (!mmc_host_is_spi(host) && ((rocr & 0x41000000) == 0x41000000)) {
> +               err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
> +               if (err) {
> +                       ocr &= ~SD_OCR_S18R;
> +                       goto try_again;
> +               }
> +       }
> +
>        if (mmc_host_is_spi(host))
>                err = mmc_send_cid(host, cid);
>        else
> @@ -773,6 +800,11 @@ int mmc_attach_sd(struct mmc_host *host)
>        BUG_ON(!host);
>        WARN_ON(!host->claimed);
>
> +       /* Make sure we are at 3.3V signalling voltage */
> +       err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
> +       if (err)
> +               return err;
> +
>        err = mmc_send_app_op_cond(host, 0, &ocr);
>        if (err)
>                return err;
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index e5cfe70..52faa50 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -83,6 +83,8 @@ static void sdhci_dumpregs(struct sdhci_host *host)
>        printk(KERN_DEBUG DRIVER_NAME ": Cmd:      0x%08x | Max curr: 0x%08x\n",
>                sdhci_readw(host, SDHCI_COMMAND),
>                sdhci_readl(host, SDHCI_MAX_CURRENT));
> +       printk(KERN_DEBUG DRIVER_NAME ": Host ctl2: 0x%08x\n",
> +               sdhci_readw(host, SDHCI_HOST_CONTROL2));
>
>        if (host->flags & SDHCI_USE_ADMA)
>                printk(KERN_DEBUG DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
> @@ -1323,11 +1325,115 @@ out:
>        spin_unlock_irqrestore(&host->lock, flags);
>  }
>
> +static int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
> +       struct mmc_ios *ios)
> +{
> +       struct sdhci_host *host;
> +       u8 pwr;
> +       u16 clk, ctrl;
> +       u32 present_state;
> +
> +       host = mmc_priv(mmc);
> +
> +       /*
> +        * Signal Voltage Switching is only applicable for Host Controllers
> +        * v3.00 and above.
> +        */
> +       if (host->version < SDHCI_SPEC_300)
> +               return 0;
> +
> +       /*
> +        * We first check whether the request is to set signalling voltage
> +        * to 3.3V. If so, we change the voltage to 3.3V and return quickly.
> +        */
> +       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
> +               /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
> +               ctrl &= ~SDHCI_CTRL_VDD_180;
> +               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
> +
> +               /* Wait for 5ms */
> +               usleep_range(5000, 5500);
> +
> +               /* 3.3V regulator output should be stable within 5 ms */
> +               ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +               if (!(ctrl & SDHCI_CTRL_VDD_180))
> +                       return 0;
> +               else {
> +                       printk(KERN_INFO DRIVER_NAME ": Switching to 3.3V "
> +                               "signalling voltage failed\n");
> +                       return -EIO;
> +               }
> +       } else if (!(ctrl & SDHCI_CTRL_VDD_180) &&
> +                 (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) {
> +               /* Stop SDCLK */
> +               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> +               clk &= ~SDHCI_CLOCK_CARD_EN;
> +               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> +
> +               /* Check whether DAT[3:0] is 0000 */
> +               present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
> +               if (!((present_state & SDHCI_DATA_LVL_MASK) >>
> +                      SDHCI_DATA_LVL_SHIFT)) {
> +                       /*
> +                        * Enable 1.8V Signal Enable in the Host Control2
> +                        * register
> +                        */
> +                       ctrl |= SDHCI_CTRL_VDD_180;
> +                       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
> +
> +                       /* Wait for 5ms */
> +                       usleep_range(5000, 5500);
> +
> +                       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +                       if (ctrl & SDHCI_CTRL_VDD_180) {
> +                               /* Provide SDCLK again and wait for 1ms*/
> +                               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
> +                               clk |= SDHCI_CLOCK_CARD_EN;
> +                               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
> +                               usleep_range(1000, 1500);
> +
> +                               /*
> +                                * If DAT[3:0] level is 1111b, then the card
> +                                * was successfully switched to 1.8V signaling.
> +                                */
> +                               present_state = sdhci_readl(host,
> +                                                       SDHCI_PRESENT_STATE);
> +                               if ((present_state & SDHCI_DATA_LVL_MASK) ==
> +                                    SDHCI_DATA_LVL_MASK) {
> +                                       return 0;
> +                               }
> +                       }
> +               }
> +
> +               /*
> +                * If we are here, that means the switch to 1.8V signaling
> +                * failed. We power cycle the card, and retry initialization
> +                * sequence by setting S18R to 0.
> +                */
> +               pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
> +               pwr &= ~SDHCI_POWER_ON;
> +               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
> +
> +               /* Wait for 1ms as per the spec */
> +               usleep_range(1000, 1500);
> +               pwr |= SDHCI_POWER_ON;
> +               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
> +
> +               printk(KERN_INFO DRIVER_NAME ": Switching to 1.8V signalling "
> +                       "voltage failed, retrying with S18R set to 0\n");
> +               return -EAGAIN;
> +       } else
> +               /* No signal voltage switch required */
> +               return 0;
> +}
> +
>  static const struct mmc_host_ops sdhci_ops = {
>        .request        = sdhci_request,
>        .set_ios        = sdhci_set_ios,
>        .get_ro         = sdhci_get_ro,
>        .enable_sdio_irq = sdhci_enable_sdio_irq,
> +       .start_signal_voltage_switch    = sdhci_start_signal_voltage_switch,
>  };
>
>  /*****************************************************************************\
> @@ -1808,7 +1914,9 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
>  int sdhci_add_host(struct sdhci_host *host)
>  {
>        struct mmc_host *mmc;
> -       unsigned int caps, ocr_avail;
> +       u32 caps[2];
> +       u32 max_current_caps;
> +       unsigned int ocr_avail;
>        int ret;
>
>        WARN_ON(host == NULL);
> @@ -1831,12 +1939,15 @@ int sdhci_add_host(struct sdhci_host *host)
>                        host->version);
>        }
>
> -       caps = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
> +       caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
>                sdhci_readl(host, SDHCI_CAPABILITIES);
>
> +       caps[1] = (host->version >= SDHCI_SPEC_300) ?
> +               sdhci_readl(host, SDHCI_CAPABILITIES_1) : 0;
> +
>        if (host->quirks & SDHCI_QUIRK_FORCE_DMA)
>                host->flags |= SDHCI_USE_SDMA;
> -       else if (!(caps & SDHCI_CAN_DO_SDMA))
> +       else if (!(caps[0] & SDHCI_CAN_DO_SDMA))
>                DBG("Controller doesn't have SDMA capability\n");
>        else
>                host->flags |= SDHCI_USE_SDMA;
> @@ -1847,7 +1958,8 @@ int sdhci_add_host(struct sdhci_host *host)
>                host->flags &= ~SDHCI_USE_SDMA;
>        }
>
> -       if ((host->version >= SDHCI_SPEC_200) && (caps & SDHCI_CAN_DO_ADMA2))
> +       if ((host->version >= SDHCI_SPEC_200) &&
> +               (caps[0] & SDHCI_CAN_DO_ADMA2))
>                host->flags |= SDHCI_USE_ADMA;
>
>        if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
> @@ -1897,10 +2009,10 @@ int sdhci_add_host(struct sdhci_host *host)
>        }
>
>        if (host->version >= SDHCI_SPEC_300)
> -               host->max_clk = (caps & SDHCI_CLOCK_V3_BASE_MASK)
> +               host->max_clk = (caps[0] & SDHCI_CLOCK_V3_BASE_MASK)
>                        >> SDHCI_CLOCK_BASE_SHIFT;
>        else
> -               host->max_clk = (caps & SDHCI_CLOCK_BASE_MASK)
> +               host->max_clk = (caps[0] & SDHCI_CLOCK_BASE_MASK)
>                        >> SDHCI_CLOCK_BASE_SHIFT;
>
>        host->max_clk *= 1000000;
> @@ -1916,7 +2028,7 @@ int sdhci_add_host(struct sdhci_host *host)
>        }
>
>        host->timeout_clk =
> -               (caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
> +               (caps[0] & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
>        if (host->timeout_clk == 0) {
>                if (host->ops->get_timeout_clock) {
>                        host->timeout_clk = host->ops->get_timeout_clock(host);
> @@ -1928,7 +2040,7 @@ int sdhci_add_host(struct sdhci_host *host)
>                        return -ENODEV;
>                }
>        }
> -       if (caps & SDHCI_TIMEOUT_CLK_UNIT)
> +       if (caps[0] & SDHCI_TIMEOUT_CLK_UNIT)
>                host->timeout_clk *= 1000;
>
>        /*
> @@ -1955,21 +2067,76 @@ int sdhci_add_host(struct sdhci_host *host)
>        if (!(host->quirks & SDHCI_QUIRK_FORCE_1_BIT_DATA))
>                mmc->caps |= MMC_CAP_4_BIT_DATA;
>
> -       if (caps & SDHCI_CAN_DO_HISPD)
> +       if (caps[0] & SDHCI_CAN_DO_HISPD)
>                mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
>
>        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) &&
>            mmc_card_is_removable(mmc))
>                mmc->caps |= MMC_CAP_NEEDS_POLL;
>
> +       /* UHS-I mode(s) supported by the host controller. */
> +       if (host->version >= SDHCI_SPEC_300)
> +               mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
> +
> +       /* SDR104 supports also implies SDR50 support */
> +       if (caps[1] & SDHCI_SUPPORT_SDR104)
> +               mmc->caps |= MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_SDR50;
> +       else if (caps[1] & SDHCI_SUPPORT_SDR50)
> +               mmc->caps |= MMC_CAP_UHS_SDR50;
> +
> +       if (caps[1] & SDHCI_SUPPORT_DDR50)
> +               mmc->caps |= MMC_CAP_UHS_DDR50;
> +
>        ocr_avail = 0;
> -       if (caps & SDHCI_CAN_VDD_330)
> +       /*
> +        * According to SD Host Controller spec v3.00, if the Host System
> +        * can afford more than 150mA, Host Driver should set XPC to 1. Also
> +        * the value is meaningful only if Voltage Support in the Capabilities
> +        * register is set. The actual current value is 4 times the register
> +        * value.
> +        */
> +       max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT);
> +
> +       if (caps[0] & SDHCI_CAN_VDD_330) {
> +               int max_current_330;
> +
>                ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
> -       if (caps & SDHCI_CAN_VDD_300)
> +
> +               max_current_330 = ((max_current_caps &
> +                                  SDHCI_MAX_CURRENT_330_MASK) >>
> +                                  SDHCI_MAX_CURRENT_330_SHIFT) *
> +                                  SDHCI_MAX_CURRENT_MULTIPLIER;
> +
> +               if (max_current_330 > 150)
> +                       mmc->caps |= MMC_CAP_SET_XPC_330;
> +       }
> +       if (caps[0] & SDHCI_CAN_VDD_300) {
> +               int max_current_300;
> +
>                ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
> -       if (caps & SDHCI_CAN_VDD_180)
> +
> +               max_current_300 = ((max_current_caps &
> +                                  SDHCI_MAX_CURRENT_300_MASK) >>
> +                                  SDHCI_MAX_CURRENT_300_SHIFT) *
> +                                  SDHCI_MAX_CURRENT_MULTIPLIER;
> +
> +               if (max_current_300 > 150)
> +                       mmc->caps |= MMC_CAP_SET_XPC_300;
> +       }
> +       if (caps[0] & SDHCI_CAN_VDD_180) {
> +               int max_current_180;
> +
>                ocr_avail |= MMC_VDD_165_195;
>
> +               max_current_180 = ((max_current_caps &
> +                                  SDHCI_MAX_CURRENT_180_MASK) >>
> +                                  SDHCI_MAX_CURRENT_180_SHIFT) *
> +                                  SDHCI_MAX_CURRENT_MULTIPLIER;
> +
> +               if (max_current_180 > 150)
> +                       mmc->caps |= MMC_CAP_SET_XPC_180;
> +       }
> +
>        mmc->ocr_avail = ocr_avail;
>        mmc->ocr_avail_sdio = ocr_avail;
>        if (host->ocr_avail_sdio)
> @@ -2029,7 +2196,7 @@ int sdhci_add_host(struct sdhci_host *host)
>        if (host->quirks & SDHCI_QUIRK_FORCE_BLK_SZ_2048) {
>                mmc->max_blk_size = 2;
>        } else {
> -               mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >>
> +               mmc->max_blk_size = (caps[0] & SDHCI_MAX_BLOCK_MASK) >>
>                                SDHCI_MAX_BLOCK_SHIFT;
>                if (mmc->max_blk_size >= 3) {
>                        printk(KERN_WARNING "%s: Invalid maximum block size, "
> diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
> index c6e25a7..5cba2fe 100644
> --- a/drivers/mmc/host/sdhci.h
> +++ b/drivers/mmc/host/sdhci.h
> @@ -68,6 +68,8 @@
>  #define  SDHCI_DATA_AVAILABLE  0x00000800
>  #define  SDHCI_CARD_PRESENT    0x00010000
>  #define  SDHCI_WRITE_PROTECT   0x00080000
> +#define  SDHCI_DATA_LVL_MASK   0x00F00000
> +#define   SDHCI_DATA_LVL_SHIFT 20
>
>  #define SDHCI_HOST_CONTROL     0x28
>  #define  SDHCI_CTRL_LED                0x01
> @@ -146,7 +148,8 @@
>
>  #define SDHCI_ACMD12_ERR       0x3C
>
> -/* 3E-3F reserved */
> +#define SDHCI_HOST_CONTROL2            0x3E
> +#define  SDHCI_CTRL_VDD_180            0x0008
>
>  #define SDHCI_CAPABILITIES     0x40
>  #define  SDHCI_TIMEOUT_CLK_MASK        0x0000003F
> @@ -167,9 +170,20 @@
>  #define  SDHCI_CAN_VDD_180     0x04000000
>  #define  SDHCI_CAN_64BIT       0x10000000
>
> +#define  SDHCI_SUPPORT_SDR50   0x00000001
> +#define  SDHCI_SUPPORT_SDR104  0x00000002
> +#define  SDHCI_SUPPORT_DDR50   0x00000004
> +
>  #define SDHCI_CAPABILITIES_1   0x44
>
> -#define SDHCI_MAX_CURRENT      0x48
> +#define SDHCI_MAX_CURRENT              0x48
> +#define  SDHCI_MAX_CURRENT_330_MASK    0x0000FF
> +#define  SDHCI_MAX_CURRENT_330_SHIFT   0
> +#define  SDHCI_MAX_CURRENT_300_MASK    0x00FF00
> +#define  SDHCI_MAX_CURRENT_300_SHIFT   8
> +#define  SDHCI_MAX_CURRENT_180_MASK    0xFF0000
> +#define  SDHCI_MAX_CURRENT_180_SHIFT   16
> +#define   SDHCI_MAX_CURRENT_MULTIPLIER 4
>
>  /* 4C-4F reserved for more max current */
>
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 0fffa5c..bde5a0b 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -56,6 +56,11 @@ struct mmc_ios {
>  #define MMC_SDR_MODE           0
>  #define MMC_1_2V_DDR_MODE      1
>  #define MMC_1_8V_DDR_MODE      2
> +
> +       unsigned char   signal_voltage;         /* signalling voltage (1.8V or 3.3V) */
> +
> +#define MMC_SIGNAL_VOLTAGE_330 0
> +#define MMC_SIGNAL_VOLTAGE_180 1
>  };
>
>  struct mmc_host_ops {
> @@ -117,6 +122,8 @@ struct mmc_host_ops {
>
>        /* optional callback for HC quirks */
>        void    (*init_card)(struct mmc_host *host, struct mmc_card *card);
> +
> +       int     (*start_signal_voltage_switch)(struct mmc_host *host, struct mmc_ios *ios);
>  };
>
>  struct mmc_card;
> @@ -173,6 +180,14 @@ struct mmc_host {
>                                                /* DDR mode at 1.2V */
>  #define MMC_CAP_POWER_OFF_CARD (1 << 13)       /* Can power off after boot */
>  #define MMC_CAP_BUS_WIDTH_TEST (1 << 14)       /* CMD14/CMD19 bus width ok */
> +#define MMC_CAP_UHS_SDR12      (1 << 15)       /* Host supports UHS SDR12 mode */
> +#define MMC_CAP_UHS_SDR25      (1 << 16)       /* Host supports UHS SDR25 mode */
> +#define MMC_CAP_UHS_SDR50      (1 << 17)       /* Host supports UHS SDR50 mode */
> +#define MMC_CAP_UHS_SDR104     (1 << 18)       /* Host supports UHS SDR104 mode */
> +#define MMC_CAP_UHS_DDR50      (1 << 19)       /* Host supports UHS DDR50 mode */
> +#define MMC_CAP_SET_XPC_330    (1 << 20)       /* Host supports >150mA current at 3.3V */
> +#define MMC_CAP_SET_XPC_300    (1 << 21)       /* Host supports >150mA current at 3.0V */
> +#define MMC_CAP_SET_XPC_180    (1 << 22)       /* Host supports >150mA current at 1.8V */
>
>        mmc_pm_flag_t           pm_caps;        /* supported pm features */
>
> diff --git a/include/linux/mmc/sd.h b/include/linux/mmc/sd.h
> index 3fd85e0..c648878 100644
> --- a/include/linux/mmc/sd.h
> +++ b/include/linux/mmc/sd.h
> @@ -17,6 +17,7 @@
>  /* This is basically the same command as for MMC with some quirks. */
>  #define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
>  #define SD_SEND_IF_COND           8   /* bcr  [11:0] See below   R7  */
> +#define SD_SWITCH_VOLTAGE         11  /* ac                      R1  */
>
>   /* class 10 */
>  #define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */
> @@ -32,6 +33,12 @@
>  #define SD_APP_OP_COND           41   /* bcr  [31:0] OCR         R3  */
>  #define SD_APP_SEND_SCR          51   /* adtc                    R1  */
>
> +/* OCR bit definitions */
> +#define SD_OCR_S18R            (1 << 24)    /* 1.8V switching request */
> +#define SD_ROCR_S18A           SD_OCR_S18R  /* 1.8V switching accepted by card */
> +#define SD_OCR_XPC             (1 << 28)    /* SDXC power control */
> +#define SD_OCR_CCS             (1 << 30)    /* Card Capacity Status */
> +
>  /*
>  * SD_SWITCH argument format:
>  *
> --
> 1.7.1
>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux