]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/mmc/host/sdhci.c
Merge remote-tracking branch 'mmc/mmc-next'
[karo-tx-linux.git] / drivers / mmc / host / sdhci.c
index 7a7fb4f0d5a43a4829fa1e258afbf112f4dd9b82..ec3eb30845c76fb5295a5c2027319d289ce9dd1d 100644 (file)
@@ -49,7 +49,6 @@ static unsigned int debug_quirks2;
 
 static void sdhci_finish_data(struct sdhci_host *);
 
-static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
 static void sdhci_finish_command(struct sdhci_host *);
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
 static void sdhci_tuning_timer(unsigned long data);
@@ -899,8 +898,13 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
        u16 mode;
        struct mmc_data *data = cmd->data;
 
-       if (data == NULL)
+       if (data == NULL) {
+               /* clear Auto CMD settings for no data CMDs */
+               mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
+               sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
+                               SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
                return;
+       }
 
        WARN_ON(!host->data);
 
@@ -981,7 +985,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
                tasklet_schedule(&host->finish_tasklet);
 }
 
-static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
+void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 {
        int flags;
        u32 mask;
@@ -1053,6 +1057,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 
        sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
 }
+EXPORT_SYMBOL_GPL(sdhci_send_command);
 
 static void sdhci_finish_command(struct sdhci_host *host)
 {
@@ -1391,6 +1396,13 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
                                        mmc->card->type == MMC_TYPE_MMC ?
                                        MMC_SEND_TUNING_BLOCK_HS200 :
                                        MMC_SEND_TUNING_BLOCK;
+
+                               /* Here we need to set the host->mrq to NULL,
+                                * in case the pending finish_tasklet
+                                * finishes it incorrectly.
+                                */
+                               host->mrq = NULL;
+
                                spin_unlock_irqrestore(&host->lock, flags);
                                sdhci_execute_tuning(mmc, tuning_opcode);
                                spin_lock_irqsave(&host->lock, flags);
@@ -1435,7 +1447,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
        }
 
        if (host->version >= SDHCI_SPEC_300 &&
-               (ios->power_mode == MMC_POWER_UP))
+               (ios->power_mode == MMC_POWER_UP) &&
+               !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
                sdhci_enable_preset_value(host, false);
 
        sdhci_set_clock(host, ios->clock);
@@ -1875,6 +1888,14 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                return 0;
        }
 
+       if (host->ops->platform_execute_tuning) {
+               spin_unlock(&host->lock);
+               enable_irq(host->irq);
+               err = host->ops->platform_execute_tuning(host, opcode);
+               sdhci_runtime_pm_put(host);
+               return err;
+       }
+
        sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
        /*
@@ -1981,6 +2002,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
        if (!tuning_loop_counter || !timeout) {
                ctrl &= ~SDHCI_CTRL_TUNED_CLK;
                sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+               err = -EIO;
        } else {
                if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
                        pr_info(DRIVER_NAME ": Tuning procedure"
@@ -2491,6 +2513,14 @@ again:
        result = IRQ_HANDLED;
 
        intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+
+       /*
+        * If we know we'll call the driver to signal SDIO IRQ, disregard
+        * further indications of Card Interrupt in the status to avoid a
+        * needless loop.
+        */
+       if (cardint)
+               intmask &= ~SDHCI_INT_CARD_INT;
        if (intmask && --max_loops)
                goto again;
 out:
@@ -2546,8 +2576,6 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
 
 int sdhci_suspend_host(struct sdhci_host *host)
 {
-       int ret;
-
        if (host->ops->platform_suspend)
                host->ops->platform_suspend(host);
 
@@ -2559,19 +2587,6 @@ int sdhci_suspend_host(struct sdhci_host *host)
                host->flags &= ~SDHCI_NEEDS_RETUNING;
        }
 
-       ret = mmc_suspend_host(host->mmc);
-       if (ret) {
-               if (host->flags & SDHCI_USING_RETUNING_TIMER) {
-                       host->flags |= SDHCI_NEEDS_RETUNING;
-                       mod_timer(&host->tuning_timer, jiffies +
-                                       host->tuning_count * HZ);
-               }
-
-               sdhci_enable_card_detection(host);
-
-               return ret;
-       }
-
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
                sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
                free_irq(host->irq, host);
@@ -2579,14 +2594,14 @@ int sdhci_suspend_host(struct sdhci_host *host)
                sdhci_enable_irq_wakeups(host);
                enable_irq_wake(host->irq);
        }
-       return ret;
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(sdhci_suspend_host);
 
 int sdhci_resume_host(struct sdhci_host *host)
 {
-       int ret;
+       int ret = 0;
 
        if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
                if (host->ops->enable_dma)
@@ -2615,7 +2630,6 @@ int sdhci_resume_host(struct sdhci_host *host)
                mmiowb();
        }
 
-       ret = mmc_resume_host(host->mmc);
        sdhci_enable_card_detection(host);
 
        if (host->ops->platform_resume)
@@ -3002,7 +3016,8 @@ int sdhci_add_host(struct sdhci_host *host)
                /* SD3.0: SDR104 is supported so (for eMMC) the caps2
                 * field can be promoted to support HS200.
                 */
-               mmc->caps2 |= MMC_CAP2_HS200;
+               if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200))
+                       mmc->caps2 |= MMC_CAP2_HS200;
        } else if (caps[1] & SDHCI_SUPPORT_SDR50)
                mmc->caps |= MMC_CAP_UHS_SDR50;