@@ -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);
@@ -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,
};
/*****************************************************************************\
@@ -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 {
@@ -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;