OSDN Git Service

Merge android-4.4.191 (6da3fbc) into msm-4.4
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / mmc / core / sd.c
index 7e3f2c7..f24c6ad 100644 (file)
 #include "sd.h"
 #include "sd_ops.h"
 
+#define UHS_SDR104_MIN_DTR     (100 * 1000 * 1000)
+#define UHS_DDR50_MIN_DTR      (50 * 1000 * 1000)
+#define UHS_SDR50_MIN_DTR      (50 * 1000 * 1000)
+#define UHS_SDR25_MIN_DTR      (25 * 1000 * 1000)
+#define UHS_SDR12_MIN_DTR      (12.5 * 1000 * 1000)
+
+#define ENOCALLBACK 1
+
 static const unsigned int tran_exp[] = {
        10000,          100000,         1000000,        10000000,
        0,              0,              0,              0
@@ -337,6 +345,7 @@ static int mmc_read_switch(struct mmc_card *card)
                card->sw_caps.sd3_bus_mode = status[13];
                /* Driver Strengths supported by the card */
                card->sw_caps.sd3_drv_type = status[9];
+               card->sw_caps.sd3_curr_limit = status[7] | status[6] << 8;
        }
 
 out:
@@ -377,9 +386,9 @@ int mmc_sd_switch_hs(struct mmc_card *card)
                goto out;
 
        if ((status[16] & 0xF) != 1) {
-               pr_warn("%s: Problem switching card into high-speed mode!\n",
-                       mmc_hostname(card->host));
-               err = 0;
+               pr_warn("%s: Problem switching card into high-speed mode!, status:%x\n",
+                       mmc_hostname(card->host), (status[16] & 0xF));
+               err = -EBUSY;
        } else {
                err = 1;
        }
@@ -433,24 +442,28 @@ static void sd_update_bus_speed_mode(struct mmc_card *card)
        }
 
        if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
-           (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
-                       card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
-       } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
-                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
-                       card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
+           (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104) &&
+           (card->host->f_max > UHS_SDR104_MIN_DTR)) {
+               card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
        } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
                    MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
-                   SD_MODE_UHS_SDR50)) {
-                       card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
+                   SD_MODE_UHS_SDR50) &&
+                   (card->host->f_max > UHS_SDR50_MIN_DTR)) {
+               card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
+       } else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50) &&
+                   (card->host->f_max > UHS_DDR50_MIN_DTR)) {
+               card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
        } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
                    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
-                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
-                       card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
+                  (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25) &&
+                (card->host->f_max > UHS_SDR25_MIN_DTR)) {
+               card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
        } else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
                    MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
                    MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
                    SD_MODE_UHS_SDR12)) {
-                       card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
+               card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
        }
 }
 
@@ -488,15 +501,21 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
        if (err)
                return err;
 
-       if ((status[16] & 0xF) != card->sd_bus_speed)
-               pr_warn("%s: Problem setting bus speed mode!\n",
-                       mmc_hostname(card->host));
-       else {
+       if ((status[16] & 0xF) != card->sd_bus_speed) {
+               pr_warn("%s: Problem setting bus speed mode(%u)! max_dtr:%u, timing:%u, status:%x\n",
+                       mmc_hostname(card->host), card->sd_bus_speed,
+                       card->sw_caps.uhs_max_dtr, timing, (status[16] & 0xF));
+               err = -EBUSY;
+       } else {
                mmc_set_timing(card->host, timing);
-               mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
+               if (card->host->ops->check_temp(card->host) &&
+                               timing == MMC_TIMING_UHS_SDR104)
+                       mmc_set_clock(card->host, UHS_SDR50_MAX_DTR);
+               else
+                       mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
        }
 
-       return 0;
+       return err;
 }
 
 /* Get host's max current setting at its current voltage */
@@ -553,14 +572,25 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status)
         * when we set current limit to 200ma, the card will draw 200ma, and
         * when we set current limit to 400/600/800ma, the card will draw its
         * maximum 300ma from the host.
+        *
+        * The above is incorrect: if we try to set a current limit that is
+        * not supported by the card, the card can rightfully error out the
+        * attempt, and remain at the default current limit.  This results
+        * in a 300mA card being limited to 200mA even though the host
+        * supports 800mA. Failures seen with SanDisk 8GB UHS cards with
+        * an iMX6 host. --rmk
         */
-       if (max_current >= 800)
+       if (max_current >= 800 &&
+           card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
                current_limit = SD_SET_CURRENT_LIMIT_800;
-       else if (max_current >= 600)
+       else if (max_current >= 600 &&
+                card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
                current_limit = SD_SET_CURRENT_LIMIT_600;
-       else if (max_current >= 400)
+       else if (max_current >= 400 &&
+                card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
                current_limit = SD_SET_CURRENT_LIMIT_400;
-       else if (max_current >= 200)
+       else if (max_current >= 200 &&
+                card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
                current_limit = SD_SET_CURRENT_LIMIT_200;
 
        if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
@@ -577,6 +607,64 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status)
        return 0;
 }
 
+/**
+ * mmc_sd_change_bus_speed() - Change SD card bus frequency at runtime
+ * @host: pointer to mmc host structure
+ * @freq: pointer to desired frequency to be set
+ *
+ * Change the SD card bus frequency at runtime after the card is
+ * initialized. Callers are expected to make sure of the card's
+ * state (DATA/RCV/TRANSFER) beforing changing the frequency at runtime.
+ *
+ * If the frequency to change is greater than max. supported by card,
+ * *freq is changed to max. supported by card and if it is less than min.
+ * supported by host, *freq is changed to min. supported by host.
+ */
+static int mmc_sd_change_bus_speed(struct mmc_host *host, unsigned long *freq)
+{
+       int err = 0;
+       struct mmc_card *card;
+
+       mmc_claim_host(host);
+       /*
+        * Assign card pointer after claiming host to avoid race
+        * conditions that may arise during removal of the card.
+        */
+       card = host->card;
+
+       /* sanity checks */
+       if (!card || !freq) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       mmc_set_clock(host, (unsigned int) (*freq));
+
+       if (!mmc_host_is_spi(card->host) && mmc_card_uhs(card)
+                       && card->host->ops->execute_tuning) {
+               /*
+                * We try to probe host driver for tuning for any
+                * frequency, it is host driver responsibility to
+                * perform actual tuning only when required.
+                */
+               mmc_host_clk_hold(card->host);
+               err = card->host->ops->execute_tuning(card->host,
+                               MMC_SEND_TUNING_BLOCK);
+               mmc_host_clk_release(card->host);
+
+               if (err) {
+                       pr_warn("%s: %s: tuning execution failed %d. Restoring to previous clock %lu\n",
+                                  mmc_hostname(card->host), __func__, err,
+                                  host->clk_scaling.curr_freq);
+                       mmc_set_clock(host, host->clk_scaling.curr_freq);
+               }
+       }
+
+out:
+       mmc_release_host(host);
+       return err;
+}
+
 /*
  * UHS-I specific initialization procedure
  */
@@ -808,7 +896,9 @@ static int mmc_sd_get_ro(struct mmc_host *host)
        if (!host->ops->get_ro)
                return -1;
 
+       mmc_host_clk_hold(host);
        ro = host->ops->get_ro(host);
+       mmc_host_clk_release(host);
 
        return ro;
 }
@@ -903,7 +993,10 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
 {
        unsigned max_dtr = (unsigned int)-1;
 
-       if (mmc_card_hs(card)) {
+       if (mmc_card_uhs(card)) {
+               if (max_dtr > card->sw_caps.uhs_max_dtr)
+                       max_dtr = card->sw_caps.uhs_max_dtr;
+       } else if (mmc_card_hs(card)) {
                if (max_dtr > card->sw_caps.hs_max_dtr)
                        max_dtr = card->sw_caps.hs_max_dtr;
        } else if (max_dtr > card->csd.max_dtr) {
@@ -965,6 +1058,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
                err = mmc_send_relative_addr(host, &card->rca);
                if (err)
                        goto free_card;
+               host->card = card;
        }
 
        if (!oldcard) {
@@ -1028,16 +1122,48 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
                }
        }
 
-       host->card = card;
+       card->clk_scaling_highest = mmc_sd_get_max_clock(card);
+       card->clk_scaling_lowest = host->f_min;
+
        return 0;
 
 free_card:
-       if (!oldcard)
+       if (!oldcard) {
+               host->card = NULL;
                mmc_remove_card(card);
+       }
 
        return err;
 }
 
+static int mmc_sd_init_temp_control_clk_scaling(struct mmc_host *host)
+{
+       int ret;
+
+       if (host->ops->reg_temp_callback) {
+               ret = host->ops->reg_temp_callback(host);
+       } else {
+               pr_err("%s: %s: couldn't find init temp control clk scaling cb\n",
+                       mmc_hostname(host), __func__);
+               ret = -ENOCALLBACK;
+       }
+       return ret;
+}
+
+static int mmc_sd_dereg_temp_control_clk_scaling(struct mmc_host *host)
+{
+       int ret;
+
+       if (host->ops->dereg_temp_callback) {
+               ret = host->ops->dereg_temp_callback(host);
+       } else {
+               pr_err("%s: %s: couldn't find dereg temp control clk scaling cb\n",
+                       mmc_hostname(host), __func__);
+               ret = -ENOCALLBACK;
+       }
+       return ret;
+}
+
 /*
  * Host is being removed. Free up the current card.
  */
@@ -1046,8 +1172,13 @@ static void mmc_sd_remove(struct mmc_host *host)
        BUG_ON(!host);
        BUG_ON(!host->card);
 
+       mmc_exit_clk_scaling(host);
+       mmc_sd_dereg_temp_control_clk_scaling(host);
        mmc_remove_card(host->card);
+
+       mmc_claim_host(host);
        host->card = NULL;
+       mmc_release_host(host);
 }
 
 /*
@@ -1055,6 +1186,9 @@ static void mmc_sd_remove(struct mmc_host *host)
  */
 static int mmc_sd_alive(struct mmc_host *host)
 {
+       if (host->ops->get_cd && !host->ops->get_cd(host))
+               return -ENOMEDIUM;
+
        return mmc_send_status(host->card, NULL);
 }
 
@@ -1071,7 +1205,27 @@ static void mmc_sd_detect(struct mmc_host *host)
        BUG_ON(!host);
        BUG_ON(!host->card);
 
-       mmc_get_card(host->card);
+       /*
+        * Try to acquire claim host. If failed to get the lock in 2 sec,
+        * just return; This is to ensure that when this call is invoked
+        * due to pm_suspend, not to block suspend for longer duration.
+        */
+       pm_runtime_get_sync(&host->card->dev);
+       if (!mmc_try_claim_host(host, 2000)) {
+               pm_runtime_mark_last_busy(&host->card->dev);
+               pm_runtime_put_autosuspend(&host->card->dev);
+               return;
+       }
+
+       if (mmc_bus_needs_resume(host))
+               mmc_resume_bus(host);
+
+       if (host->ops->get_cd && !host->ops->get_cd(host)) {
+               err = -ENOMEDIUM;
+               mmc_card_set_removed(host->card);
+               mmc_card_clr_suspended(host->card);
+               goto out;
+       }
 
        /*
         * Just check if our card has been removed.
@@ -1089,11 +1243,13 @@ static void mmc_sd_detect(struct mmc_host *host)
        if (!retries) {
                printk(KERN_ERR "%s(%s): Unable to re-detect card (%d)\n",
                       __func__, mmc_hostname(host), err);
+               err = _mmc_detect_card_removed(host);
        }
 #else
        err = _mmc_detect_card_removed(host);
 #endif
 
+out:
        mmc_put_card(host->card);
 
        if (err) {
@@ -1113,6 +1269,13 @@ static int _mmc_sd_suspend(struct mmc_host *host)
        BUG_ON(!host);
        BUG_ON(!host->card);
 
+       err = mmc_suspend_clk_scaling(host);
+       if (err) {
+               pr_err("%s: %s: fail to suspend clock scaling (%d)\n",
+                       mmc_hostname(host), __func__,  err);
+               return err;
+       }
+
        mmc_claim_host(host);
 
        if (mmc_card_suspended(host->card))
@@ -1138,11 +1301,16 @@ static int mmc_sd_suspend(struct mmc_host *host)
 {
        int err;
 
+       MMC_TRACE(host, "%s: Enter\n", __func__);
        err = _mmc_sd_suspend(host);
        if (!err) {
                pm_runtime_disable(&host->card->dev);
                pm_runtime_set_suspended(&host->card->dev);
-       }
+       /* if suspend fails, force mmc_detect_change during resume */
+       } else if (mmc_bus_manual_resume(host))
+               host->ignore_bus_resume_flags = true;
+
+       MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err);
 
        return err;
 }
@@ -1166,6 +1334,11 @@ static int _mmc_sd_resume(struct mmc_host *host)
        if (!mmc_card_suspended(host->card))
                goto out;
 
+       if (host->ops->get_cd && !host->ops->get_cd(host)) {
+               mmc_card_clr_suspended(host->card);
+               goto out;
+       }
+
        mmc_power_up(host, host->card->ocr);
 #ifdef CONFIG_MMC_PARANOID_SD_INIT
        retries = 5;
@@ -1175,8 +1348,11 @@ static int _mmc_sd_resume(struct mmc_host *host)
                if (err) {
                        printk(KERN_ERR "%s: Re-init card rc = %d (retries = %d)\n",
                               mmc_hostname(host), err, retries);
-                       mdelay(5);
                        retries--;
+                       mmc_power_off(host);
+                       usleep_range(5000, 5500);
+                       mmc_power_up(host, host->card->ocr);
+                       mmc_select_voltage(host, host->card->ocr);
                        continue;
                }
                break;
@@ -1184,8 +1360,23 @@ static int _mmc_sd_resume(struct mmc_host *host)
 #else
        err = mmc_sd_init_card(host, host->card->ocr, host->card);
 #endif
+       if (err) {
+               pr_err("%s: %s: mmc_sd_init_card_failed (%d)\n",
+                               mmc_hostname(host), __func__, err);
+               mmc_power_off(host);
+               goto out;
+       }
        mmc_card_clr_suspended(host->card);
 
+       if (host->card->sdr104_blocked)
+               goto out;
+       err = mmc_resume_clk_scaling(host);
+       if (err) {
+               pr_err("%s: %s: fail to resume clock scaling (%d)\n",
+                       mmc_hostname(host), __func__, err);
+               goto out;
+       }
+
 out:
        mmc_release_host(host);
        return err;
@@ -1198,12 +1389,14 @@ static int mmc_sd_resume(struct mmc_host *host)
 {
        int err = 0;
 
+       MMC_TRACE(host, "%s: Enter\n", __func__);
        if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
                err = _mmc_sd_resume(host);
                pm_runtime_set_active(&host->card->dev);
                pm_runtime_mark_last_busy(&host->card->dev);
        }
        pm_runtime_enable(&host->card->dev);
+       MMC_TRACE(host, "%s: Exit err: %d\n", __func__, err);
 
        return err;
 }
@@ -1246,6 +1439,9 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
 
 static int mmc_sd_reset(struct mmc_host *host)
 {
+       if (host->ops->get_cd && !host->ops->get_cd(host))
+               return -ENOMEDIUM;
+
        mmc_power_cycle(host, host->card->ocr);
        return mmc_sd_init_card(host, host->card->ocr, host->card);
 }
@@ -1258,7 +1454,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
        .suspend = mmc_sd_suspend,
        .resume = mmc_sd_resume,
        .alive = mmc_sd_alive,
-       .shutdown = mmc_sd_suspend,
+       .change_bus_speed = mmc_sd_change_bus_speed,
        .reset = mmc_sd_reset,
 };
 
@@ -1295,6 +1491,12 @@ int mmc_attach_sd(struct mmc_host *host)
                        goto err;
        }
 
+       /*
+        * Some SD cards claims an out of spec VDD voltage range. Let's treat
+        * these bits as being in-valid and especially also bit7.
+        */
+       ocr &= ~0x7FFF;
+
        rocr = mmc_select_voltage(host, ocr);
 
        /*
@@ -1305,6 +1507,9 @@ int mmc_attach_sd(struct mmc_host *host)
                goto err;
        }
 
+       if (mmc_sd_init_temp_control_clk_scaling(host))
+               pr_err("%s: failed to init temp control clk scaling\n",
+                       mmc_hostname(host));
        /*
         * Detect and init the card.
         */
@@ -1314,6 +1519,10 @@ int mmc_attach_sd(struct mmc_host *host)
                err = mmc_sd_init_card(host, rocr, NULL);
                if (err) {
                        retries--;
+                       mmc_power_off(host);
+                       usleep_range(5000, 5500);
+                       mmc_power_up(host, rocr);
+                       mmc_select_voltage(host, rocr);
                        continue;
                }
                break;
@@ -1336,6 +1545,13 @@ int mmc_attach_sd(struct mmc_host *host)
                goto remove_card;
 
        mmc_claim_host(host);
+
+       err = mmc_init_clk_scaling(host);
+       if (err) {
+               mmc_release_host(host);
+               goto remove_card;
+       }
+
        return 0;
 
 remove_card: