Reviewed-by: Philip Rakity <[email protected]>

On Jul 3, 2012, at 10:31 PM, Aaron Lu wrote:

> Host has different current capabilities at different voltages, we need
> to record these settings seperately. The defined voltages are 1.8/3.0/3.3.
> For other voltages, we do not touch current limit setting.
> 
> Before set current limit for the sd card, find out the host's operating
> voltage first and then find out the current capabilities of the host at
> that voltage to set the current limit.
> 
> Signed-off-by: Aaron Lu <[email protected]>
> ---
> v2:
> Do not call BUG() when the host's voltage is not supported as suggested by
> Chris Ball.
> Do not use 0/1/2 to represent the host's voltage as suggested by Philip 
> Rakity.
> 
> drivers/mmc/core/sd.c    | 44 +++++++++++++++++++++++++++++++++++++-------
> drivers/mmc/host/sdhci.c | 28 ++++++++++++++++++++++++----
> include/linux/mmc/host.h | 16 ++++++++++++----
> 3 files changed, 73 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 8460568..312b78d 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -521,11 +521,25 @@ static int sd_set_current_limit(struct mmc_card *card, 
> u8 *status)
> {
>       int current_limit = SD_SET_CURRENT_NO_CHANGE;
>       int err;
> +     u32 voltage;
> 
>       /*
>        * Current limit switch is only defined for SDR50, SDR104, and DDR50
>        * bus speed modes. For other bus speed modes, we do not change the
>        * current limit.
> +      */
> +     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))
> +             return 0;
> +
> +     /*
> +      * Host has different current capabilities when operating at
> +      * different voltages, so find out the current voltage first.
> +      */
> +     voltage = 1 << card->host->ios.vdd;
> +
> +     /*
>        * We only check host's capability here, if we set a limit that is
>        * higher than the card's maximum current, the card will be using its
>        * maximum current, e.g. if the card's maximum current is 300ma, and
> @@ -533,16 +547,32 @@ static int sd_set_current_limit(struct mmc_card *card, 
> u8 *status)
>        * when we set current limit to 400/600/800ma, the card will draw its
>        * maximum 300ma from the host.
>        */
> -     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 (voltage == MMC_VDD_165_195) {
> +             if (card->host->caps & MMC_CAP_MAX_CURRENT_800_180)
> +                     current_limit = SD_SET_CURRENT_LIMIT_800;
> +             else if (card->host->caps & MMC_CAP_MAX_CURRENT_600_180)
> +                     current_limit = SD_SET_CURRENT_LIMIT_600;
> +             else if (card->host->caps & MMC_CAP_MAX_CURRENT_400_180)
> +                     current_limit = SD_SET_CURRENT_LIMIT_400;
> +             else if (card->host->caps & MMC_CAP_MAX_CURRENT_200_180)
> +                     current_limit = SD_SET_CURRENT_LIMIT_200;
> +     } else if (voltage & (MMC_VDD_29_30 | MMC_VDD_30_31)) {
> +             if (card->host->caps & MMC_CAP_MAX_CURRENT_800_300)
> +                     current_limit = SD_SET_CURRENT_LIMIT_800;
> +             else if (card->host->caps & MMC_CAP_MAX_CURRENT_600_300)
> +                     current_limit = SD_SET_CURRENT_LIMIT_600;
> +             else if (card->host->caps & MMC_CAP_MAX_CURRENT_400_300)
> +                     current_limit = SD_SET_CURRENT_LIMIT_400;
> +             else if (card->host->caps & MMC_CAP_MAX_CURRENT_200_300)
> +                     current_limit = SD_SET_CURRENT_LIMIT_200;
> +     } else if (voltage & (MMC_VDD_32_33 | MMC_VDD_33_34)) {
> +             if (card->host->caps & MMC_CAP_MAX_CURRENT_800_330)
>                       current_limit = SD_SET_CURRENT_LIMIT_800;
> -             else if (card->host->caps & MMC_CAP_MAX_CURRENT_600)
> +             else if (card->host->caps & MMC_CAP_MAX_CURRENT_600_330)
>                       current_limit = SD_SET_CURRENT_LIMIT_600;
> -             else if (card->host->caps & MMC_CAP_MAX_CURRENT_400)
> +             else if (card->host->caps & MMC_CAP_MAX_CURRENT_400_330)
>                       current_limit = SD_SET_CURRENT_LIMIT_400;
> -             else if (card->host->caps & MMC_CAP_MAX_CURRENT_200)
> +             else if (card->host->caps & MMC_CAP_MAX_CURRENT_200_330)
>                       current_limit = SD_SET_CURRENT_LIMIT_200;
>       }
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 3ec4182..d89e97c 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -2913,6 +2913,16 @@ int sdhci_add_host(struct sdhci_host *host)
> 
>               if (max_current_330 > 150)
>                       mmc->caps |= MMC_CAP_SET_XPC_330;
> +
> +             /* Maximum current capabilities of the host at 3.3V */
> +             if (max_current_330 >= 800)
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_800_330;
> +             else if (max_current_330 >= 600)
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_600_330;
> +             else if (max_current_330 >= 400)
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_400_330;
> +             else if (max_current_330 >= 200)
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_200_330;
>       }
>       if (caps[0] & SDHCI_CAN_VDD_300) {
>               int max_current_300;
> @@ -2926,6 +2936,16 @@ int sdhci_add_host(struct sdhci_host *host)
> 
>               if (max_current_300 > 150)
>                       mmc->caps |= MMC_CAP_SET_XPC_300;
> +
> +             /* Maximum current capabilities of the host at 3.0V */
> +             if (max_current_300 >= 800)
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_800_300;
> +             else if (max_current_300 >= 600)
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_600_300;
> +             else if (max_current_300 >= 400)
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_400_300;
> +             else if (max_current_300 >= 200)
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_200_300;
>       }
>       if (caps[0] & SDHCI_CAN_VDD_180) {
>               int max_current_180;
> @@ -2942,13 +2962,13 @@ int sdhci_add_host(struct sdhci_host *host)
> 
>               /* Maximum current capabilities of the host at 1.8V */
>               if (max_current_180 >= 800)
> -                     mmc->caps |= MMC_CAP_MAX_CURRENT_800;
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_800_180;
>               else if (max_current_180 >= 600)
> -                     mmc->caps |= MMC_CAP_MAX_CURRENT_600;
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_600_180;
>               else if (max_current_180 >= 400)
> -                     mmc->caps |= MMC_CAP_MAX_CURRENT_400;
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_400_180;
>               else if (max_current_180 >= 200)
> -                     mmc->caps |= MMC_CAP_MAX_CURRENT_200;
> +                     mmc->caps |= MMC_CAP_MAX_CURRENT_200_180;
>       }
> 
>       mmc->ocr_avail = ocr_avail;
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 65c64ee..ca84ffb 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -238,10 +238,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 */
> +#define MMC_CAP_MAX_CURRENT_200_180 (1 << 26)        /* Host max current 
> limit is 200mA at 1.8V */
> +#define MMC_CAP_MAX_CURRENT_400_180 (1 << 27)        /* Host max current 
> limit is 400mA at 1.8V */
> +#define MMC_CAP_MAX_CURRENT_600_180 (1 << 28)        /* Host max current 
> limit is 600mA at 1.8V */
> +#define MMC_CAP_MAX_CURRENT_800_180 (1 << 29)        /* Host max current 
> limit is 800mA at 1.8V */
> #define MMC_CAP_CMD23         (1 << 30)       /* CMD23 supported. */
> #define MMC_CAP_HW_RESET      (1 << 31)       /* Hardware reset */
> 
> @@ -261,6 +261,14 @@ struct mmc_host {
> #define MMC_CAP2_HC_ERASE_SZ  (1 << 9)        /* High-capacity erase size */
> #define MMC_CAP2_CD_ACTIVE_HIGH       (1 << 10)       /* Card-detect signal 
> active high */
> #define MMC_CAP2_RO_ACTIVE_HIGH       (1 << 11)       /* Write-protect signal 
> active high */
> +#define MMC_CAP_MAX_CURRENT_200_300 (1 << 12)        /* Host max current 
> limit is 200mA at 3.0V */
> +#define MMC_CAP_MAX_CURRENT_400_300 (1 << 13)        /* Host max current 
> limit is 400mA at 3.0V */
> +#define MMC_CAP_MAX_CURRENT_600_300 (1 << 14)        /* Host max current 
> limit is 600mA at 3.0V */
> +#define MMC_CAP_MAX_CURRENT_800_300 (1 << 15)        /* Host max current 
> limit is 800mA at 3.0V */
> +#define MMC_CAP_MAX_CURRENT_200_330 (1 << 16)        /* Host max current 
> limit is 200mA at 3.3V */
> +#define MMC_CAP_MAX_CURRENT_400_330 (1 << 17)        /* Host max current 
> limit is 400mA at 3.3V */
> +#define MMC_CAP_MAX_CURRENT_600_330 (1 << 18)        /* Host max current 
> limit is 600mA at 3.3V */
> +#define MMC_CAP_MAX_CURRENT_800_330 (1 << 19)        /* Host max current 
> limit is 800mA at 3.3V */
> 
>       mmc_pm_flag_t           pm_caps;        /* supported pm features */
>       unsigned int        power_notify_type;
> -- 
> 1.7.11.1.3.g4c8a9db
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to