On Mar 16, 2011, at 7:32 AM, Nath, Arindam wrote: > Hi Philip, > > >> -----Original Message----- >> From: Philip Rakity [mailto:prak...@marvell.com] >> Sent: Wednesday, March 16, 2011 7:56 PM >> To: Nath, Arindam >> Cc: c...@laptop.org; zhangfei....@gmail.com; subha...@codeaurora.org; >> linux-mmc@vger.kernel.org; Su, Henry; Lu, Aaron; anath....@gmail.com >> 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.n...@amd.com> >>> --- >>> 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 majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html