Re: [PATCH v4 06/15] mmc: sd: set current limit for uhs cards

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

 



On Thu, May 5, 2011 at 2:49 AM, Arindam Nath <arindam.nath@xxxxxxx> wrote:
> We decide on the current limit to be set for the card based on the
> Capability of Host Controller to provide current at 1.8V signalling,
> and the maximum current limit of the card as indicated by CMD6
> mode 0. We then set the current limit for the card using CMD6 mode 1.
> As per the Physical Layer Spec v3.01, the current limit switch is
> only applicable for SDR50, SDR104, and DDR50 bus speed modes. For
> other UHS-I modes, we set the default current limit of 200mA.
>
> 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/sd.c    |   63 ++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/mmc/host/sdhci.c |   10 +++++++
>  include/linux/mmc/card.h |    9 ++++++
>  include/linux/mmc/host.h |    4 +++
>  4 files changed, 86 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 0491978..9270d82 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -517,6 +517,64 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
>        return 0;
>  }
>
> +static int sd_set_current_limit(struct mmc_card *card, u8 *status)
> +{
> +       int current_limit = 0;
> +       int err;
> +
> +       /*
> +        * Current limit switch is only defined for SDR50, SDR104, and DDR50
> +        * bus speed modes. For other bus speed modes, we set the default
> +        * current limit of 200mA.
> +        */
> +       if ((card->sd_bus_speed == UHS_SDR50_BUS_SPEED) ||
> +           (card->sd_bus_speed == UHS_SDR104_BUS_SPEED) ||
> +           (card->sd_bus_speed == UHS_DDR50_BUS_SPEED)) {
> +               if (card->host->caps & MMC_CAP_MAX_CURRENT_800) {
> +                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
> +                               current_limit = SD_SET_CURRENT_LIMIT_800;
> +                       else if (card->sw_caps.sd3_curr_limit &
> +                                       SD_MAX_CURRENT_600)
> +                               current_limit = SD_SET_CURRENT_LIMIT_600;
> +                       else if (card->sw_caps.sd3_curr_limit &
> +                                       SD_MAX_CURRENT_400)
> +                               current_limit = SD_SET_CURRENT_LIMIT_400;
> +                       else if (card->sw_caps.sd3_curr_limit &
> +                                       SD_MAX_CURRENT_200)
> +                               current_limit = SD_SET_CURRENT_LIMIT_200;
> +               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_600) {
> +                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
> +                               current_limit = SD_SET_CURRENT_LIMIT_600;
> +                       else if (card->sw_caps.sd3_curr_limit &
> +                                       SD_MAX_CURRENT_400)
> +                               current_limit = SD_SET_CURRENT_LIMIT_400;
> +                       else if (card->sw_caps.sd3_curr_limit &
> +                                       SD_MAX_CURRENT_200)
> +                               current_limit = SD_SET_CURRENT_LIMIT_200;
> +               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_400) {
> +                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
> +                               current_limit = SD_SET_CURRENT_LIMIT_400;
> +                       else if (card->sw_caps.sd3_curr_limit &
> +                                       SD_MAX_CURRENT_200)
> +                               current_limit = SD_SET_CURRENT_LIMIT_200;
> +               } else if (card->host->caps & MMC_CAP_MAX_CURRENT_200) {
> +                       if (card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
> +                               current_limit = SD_SET_CURRENT_LIMIT_200;
> +               }
> +       } else
> +               current_limit = SD_SET_CURRENT_LIMIT_200;
> +
> +       err = mmc_sd_switch(card, 1, 3, current_limit, status);
> +       if (err)
> +               return err;
> +
> +       if (((status[15] >> 4) & 0x0F) != current_limit)
> +               printk(KERN_WARNING "%s: Problem setting current limit!\n",
> +                       mmc_hostname(card->host));
> +
> +       return 0;
> +}
> +
>  /*
>  * UHS-I specific initialization procedure
>  */
> @@ -555,6 +613,11 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
>
>        /* Set bus speed mode of the card */
>        err = sd_set_bus_speed_mode(card, status);
> +       if (err)
> +               goto out;
> +
> +       /* Set current limit for the card */
> +       err = sd_set_current_limit(card, status);
>
>  out:
>        kfree(status);
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index de7e6e9..9176911 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -2217,6 +2217,16 @@ int sdhci_add_host(struct sdhci_host *host)
>
>                if (max_current_180 > 150)
>                        mmc->caps |= MMC_CAP_SET_XPC_180;
> +
> +               /* Maximum current capabilities of the host at 1.8V */
> +               if (max_current_180 >= 800)
> +                       mmc->caps |= MMC_CAP_MAX_CURRENT_800;
> +               else if (max_current_180 >= 600)
> +                       mmc->caps |= MMC_CAP_MAX_CURRENT_600;
> +               else if (max_current_180 >= 400)
> +                       mmc->caps |= MMC_CAP_MAX_CURRENT_400;
> +               else
> +                       mmc->caps |= MMC_CAP_MAX_CURRENT_200;
>        }
>
>        mmc->ocr_avail = ocr_avail;
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 4ef6ded..47b5ad3 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -105,6 +105,15 @@ struct sd_switch_caps {
>  #define SD_DRIVER_TYPE_C       0x04
>  #define SD_DRIVER_TYPE_D       0x08
>        unsigned int            sd3_curr_limit;
> +#define SD_SET_CURRENT_LIMIT_200       0
> +#define SD_SET_CURRENT_LIMIT_400       1
> +#define SD_SET_CURRENT_LIMIT_600       2
> +#define SD_SET_CURRENT_LIMIT_800       3
> +
> +#define SD_MAX_CURRENT_200     (1 << SD_SET_CURRENT_LIMIT_200)
> +#define SD_MAX_CURRENT_400     (1 << SD_SET_CURRENT_LIMIT_400)
> +#define SD_MAX_CURRENT_600     (1 << SD_SET_CURRENT_LIMIT_600)
> +#define SD_MAX_CURRENT_800     (1 << SD_SET_CURRENT_LIMIT_800)
>  };
>
>  struct sdio_cccr {
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 6237599..52b5dc9 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -203,6 +203,10 @@ struct mmc_host {
>  #define MMC_CAP_DRIVER_TYPE_A  (1 << 23)       /* Host supports Driver Type A */
>  #define MMC_CAP_DRIVER_TYPE_C  (1 << 24)       /* Host supports Driver Type C */
>  #define MMC_CAP_DRIVER_TYPE_D  (1 << 25)       /* Host supports Driver Type D */
> +#define MMC_CAP_MAX_CURRENT_200        (1 << 26)       /* Host max current limit is 200mA */
> +#define MMC_CAP_MAX_CURRENT_400        (1 << 27)       /* Host max current limit is 400mA */
> +#define MMC_CAP_MAX_CURRENT_600        (1 << 28)       /* Host max current limit is 600mA */
> +#define MMC_CAP_MAX_CURRENT_800        (1 << 29)       /* Host max current limit is 800mA */
>
>        mmc_pm_flag_t           pm_caps;        /* supported pm features */
>
> --
> 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