From patchwork Tue Feb 15 09:35:05 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arindam Nath X-Patchwork-Id: 558401 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 p1F9bBK7026706 for ; Tue, 15 Feb 2011 09:37:35 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754369Ab1BOJhf (ORCPT ); Tue, 15 Feb 2011 04:37:35 -0500 Received: from mail-iw0-f174.google.com ([209.85.214.174]:40842 "EHLO mail-iw0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754263Ab1BOJhf (ORCPT ); Tue, 15 Feb 2011 04:37:35 -0500 Received: by iwn9 with SMTP id 9so5732646iwn.19 for ; Tue, 15 Feb 2011 01:37: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=pStWVEnJCJy0anvDYA001ElCXOhXno9L1iIvgflu24g=; b=te/dEi92VP7JId3HxuQSvWyTj5CMybsCkqM9+afl9o/yv/fiQC5elKWbuEA6/pf3Ei 0F5uwJ+bPtfIeVIaI1XckMfj+DbaYjJRwXeiiOIfFTLGWgM0rlpS1uKspOoADXOe9Nb3 T1Uj1u7wqKZlhicEa7Ar3ik8pU4PDjPUTKCtg= 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=GTRve/j3L5K0SA/CQCfgHDZY6HaO8p1piWEwz7pVui3vAU1kswV4405PMspi0AZU/4 vSdy8a2sbD3XIkIEh/mmd9E5rlpP1UZUzWR7JBNuCnM8Ujr5CaHMNHmBFgw7bjQw9Rg5 llMcxyXcRNu80E3diVwQ3DqteXVLsbf1G011M= Received: by 10.231.10.200 with SMTP id q8mr3734402ibq.122.1297762654333; Tue, 15 Feb 2011 01:37:34 -0800 (PST) Received: from localhost ([122.167.0.108]) by mx.google.com with ESMTPS id i16sm3442966ibl.18.2011.02.15.01.37.28 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 15 Feb 2011 01:37:33 -0800 (PST) From: Arindam Nath To: cjb@laptop.org Cc: linux-mmc@vger.kernel.org, henry.su@amd.com, aaron.lu@amd.com, anath.amd@gmail.com, Arindam Nath Subject: [PATCH 07/12] mmc: sd: set current limit for uhs cards Date: Tue, 15 Feb 2011 15:05:05 +0530 Message-Id: <1297762510-2696-8-git-send-email-arindam.nath@amd.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1297762510-2696-1-git-send-email-arindam.nath@amd.com> References: <1297762510-2696-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]); Tue, 15 Feb 2011 09:37:36 +0000 (UTC) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index e681385..80c3831 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -541,6 +541,42 @@ 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; + + /* 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 */ @@ -581,6 +617,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 ae91c6b..fc2cba6 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1471,12 +1471,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 0a21839..65a003d 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;