From patchwork Fri Mar 4 11:32:44 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arindam Nath X-Patchwork-Id: 608781 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p24BXOPw029838 for ; Fri, 4 Mar 2011 11:34:36 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759412Ab1CDLef (ORCPT ); Fri, 4 Mar 2011 06:34:35 -0500 Received: from mail-iw0-f174.google.com ([209.85.214.174]:35883 "EHLO mail-iw0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752011Ab1CDLef (ORCPT ); Fri, 4 Mar 2011 06:34:35 -0500 Received: by mail-iw0-f174.google.com with SMTP id 34so1816372iwn.19 for ; Fri, 04 Mar 2011 03:34:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:sender:from:to:cc:subject:date:message-id :x-mailer:in-reply-to:references; bh=gAao6wDKRsSLpD33PbfKYiHaugeXFhwul0LheWO0EIk=; b=MSjfL25g79tlHOWiteuHWrM5UIdOPbfQewjWDQVCmKvIVffxiCUmqTUv1lBbCarvz9 G0ixZR4P6rsftWPf49IJQyMwpHgc8JtlCkCkGDIcyuhAzzUBoswO9mgltq0JHXSDSbrT ua8ZMOTXWK+eHO+8FYt2j0HuuGNNkJKIP/ENk= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; b=TGSDwcepRwWuW7L5Uq2pRriD1n7PkcxfiD8O5uTIA3ppfaXn465cTXhCBGe7E8R0UI zZe2G4R1TKZyui312hy82hoLVtIDhBUuCH231EdNok4OQal7ar0vtw607+pR54Kz67SM Wpoiux9Lo0Uv8kchGB2Wgu8lW1qBYI7wAYHWY= Received: by 10.42.135.74 with SMTP id o10mr645875ict.12.1299238474901; Fri, 04 Mar 2011 03:34:34 -0800 (PST) Received: from localhost ([122.167.0.108]) by mx.google.com with ESMTPS id d21sm1882001ibg.3.2011.03.04.03.34.28 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 04 Mar 2011 03:34:34 -0800 (PST) From: Arindam Nath To: cjb@laptop.org Cc: zhangfei.gao@gmail.com, prakity@marvell.com, subhashj@codeaurora.org, linux-mmc@vger.kernel.org, henry.su@amd.com, aaron.lu@amd.com, anath.amd@gmail.com, Arindam Nath Subject: [PATCH v2 07/12] mmc: sd: set current limit for uhs cards Date: Fri, 4 Mar 2011 17:02:44 +0530 Message-Id: <1299238369-1768-8-git-send-email-arindam.nath@amd.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1299238369-1768-1-git-send-email-arindam.nath@amd.com> References: <1299238369-1768-1-git-send-email-arindam.nath@amd.com> Sender: linux-mmc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-mmc@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Fri, 04 Mar 2011 11:34:36 +0000 (UTC) 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; + + /* 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; + + 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; } +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; + + 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, }; /*****************************************************************************\ 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;