On Mar 16, 2011, at 7:32 AM, Nath, Arindam wrote: > Hi Philip, > > >> -----Original Message----- >> From: Philip Rakity [mailto:prakity@xxxxxxxxxxx] >> Sent: Wednesday, March 16, 2011 7:56 PM >> To: Nath, Arindam >> Cc: cjb@xxxxxxxxxx; zhangfei.gao@xxxxxxxxx; subhashj@xxxxxxxxxxxxxx; >> linux-mmc@xxxxxxxxxxxxxxx; Su, Henry; Lu, Aaron; anath.amd@xxxxxxxxx >> Subject: Re: [PATCH v2 07/12] mmc: sd: set current limit for uhs cards >> >> >> On Mar 4, 2011, at 3:32 AM, Arindam Nath 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. >>> >>> Signed-off-by: Arindam Nath <arindam.nath@xxxxxxx> >>> --- >>> drivers/mmc/core/sd.c | 45 >> +++++++++++++++++++++++++++++++++++++++++++++ >>> drivers/mmc/host/sdhci.c | 24 ++++++++++++++++++++++++ >>> include/linux/mmc/card.h | 9 +++++++++ >>> include/linux/mmc/host.h | 1 + >>> 4 files changed, 79 insertions(+), 0 deletions(-) >>> >>> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c >>> index ec0d8e6..df98a2c 100644 >>> --- a/drivers/mmc/core/sd.c >>> +++ b/drivers/mmc/core/sd.c >>> @@ -550,6 +550,46 @@ 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) >>> +{ >>> + struct mmc_host *host = card->host; >>> + int mmc_host_max_current_180, current_limit; >>> + int err; >>> + >>> + /* sanity check */ >>> + if (!host->ops->get_max_current_180) >>> + return 0; >> >> a better name would be get_max_current rather than get_max_current_180 > > The Max Current Capabilities register reports maximum currents for 1.8V, 3.0V and 3.3V. Since we are only interested in the maximum current at 1.8V, so I have added *_180 to the variable names to make it explicit. understand but that is the usage now and if we need to extend the code the name becomes misleading. > >> >> do you want a test for get_max_current_180 < 400 ? and return 0 have >> it do the switch >> by setting the value ? > > As mentioned in the Physical Layer spec v3.01, <400mA falls under the default current limit, so we don't need to set it in case any or all of the above conditions fail. if future cards have memory or power is not removed they will they retain the old setting ? if so better to explicitly initialize. > > Thanks, > Arindam > >>> + >>> + /* Maximum current supported by host at 1.8V */ >>> + mmc_host_max_current_180 = host->ops->get_max_current_180(host); >>> + >>> + if (mmc_host_max_current_180 >= 800) { >>> + if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_800) >>> + current_limit = SD_SET_CURRENT_LIMIT_800; >>> + else if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_600) >>> + current_limit = SD_SET_CURRENT_LIMIT_600; >>> + else if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_400) >>> + current_limit = SD_SET_CURRENT_LIMIT_400; >>> + } else if (mmc_host_max_current_180 >= 600) { >>> + if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_600) >>> + current_limit = SD_SET_CURRENT_LIMIT_600; >>> + else if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_400) >>> + current_limit = SD_SET_CURRENT_LIMIT_400; >>> + } else if (mmc_host_max_current_180 >= 400) >>> + if (card->sw_caps.uhs_curr_limit & SD_MAX_CURRENT_400) >>> + current_limit = SD_SET_CURRENT_LIMIT_400; >> >> or >> 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 >>> */ >>> @@ -590,6 +630,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 f127fa2..245cc39 100644 >>> --- a/drivers/mmc/host/sdhci.c >>> +++ b/drivers/mmc/host/sdhci.c >>> @@ -1462,12 +1462,36 @@ static int >> sdhci_start_signal_voltage_switch(struct mmc_host *mmc) >>> return -EAGAIN; >>> } >>> >> >> better name is sdhci_get_max_current >> >>> +static int sdhci_get_max_current_180(struct mmc_host *mmc) >>> +{ >>> + struct sdhci_host *host; >>> + u32 max_current_caps; >>> + unsigned long flags; >>> + int max_current_180; >>> + >>> + host = mmc_priv(mmc); >>> + >>> + spin_lock_irqsave(&host->lock, flags); >>> + >>> + max_current_caps = sdhci_readl(host, SDHCI_MAX_CURRENT); >>> + >>> + spin_unlock_irqrestore(&host->lock, flags); >>> + >>> + /* Maximum current is 4 times the register value for 1.8V */ >>> + max_current_180 = ((max_current_caps & >> SDHCI_MAX_CURRENT_180_MASK) >> >>> + SDHCI_MAX_CURRENT_180_SHIFT) * >>> + SDHCI_MAX_CURRENT_MULTIPLIER; >> >> SDHCI_MAX_CURRENT_SHIFT is better name. >> >>> + >>> + return max_current_180; >>> +} >>> + >>> 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, >>> + .get_max_current_180 = sdhci_get_max_current_180, >> >> .get_max_current = sdhci_get_max_current; >>> }; >>> >>> >> /********************************************************************** >> *******\ >>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h >>> index 0b24c41..a6811ae 100644 >>> --- a/include/linux/mmc/card.h >>> +++ b/include/linux/mmc/card.h >>> @@ -98,6 +98,15 @@ struct sd_switch_caps { >>> #define SD_DRIVER_TYPE_C 0x04 >>> #define SD_DRIVER_TYPE_D 0x08 >>> unsigned int uhs_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 4dfff6d..e84cd05 100644 >>> --- a/include/linux/mmc/host.h >>> +++ b/include/linux/mmc/host.h >>> @@ -128,6 +128,7 @@ struct mmc_host_ops { >>> void (*init_card)(struct mmc_host *host, struct mmc_card *card); >>> >>> int (*start_signal_voltage_switch)(struct mmc_host *host); >>> + int (*get_max_current_180)(struct mmc_host *mmc); >>> }; >>> >>> struct mmc_card; >>> -- >>> 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