diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-pci-core.c')
-rw-r--r-- | drivers/mmc/host/sdhci-pci-core.c | 78 |
1 files changed, 51 insertions, 27 deletions
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c index 6d1a983e6227..787434e5589d 100644 --- a/drivers/mmc/host/sdhci-pci-core.c +++ b/drivers/mmc/host/sdhci-pci-core.c @@ -41,18 +41,25 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host); static int sdhci_pci_init_wakeup(struct sdhci_pci_chip *chip) { mmc_pm_flag_t pm_flags = 0; + bool cap_cd_wake = false; int i; for (i = 0; i < chip->num_slots; i++) { struct sdhci_pci_slot *slot = chip->slots[i]; - if (slot) + if (slot) { pm_flags |= slot->host->mmc->pm_flags; + if (slot->host->mmc->caps & MMC_CAP_CD_WAKE) + cap_cd_wake = true; + } } - return device_set_wakeup_enable(&chip->pdev->dev, - (pm_flags & MMC_PM_KEEP_POWER) && - (pm_flags & MMC_PM_WAKE_SDIO_IRQ)); + if ((pm_flags & MMC_PM_KEEP_POWER) && (pm_flags & MMC_PM_WAKE_SDIO_IRQ)) + return device_wakeup_enable(&chip->pdev->dev); + else if (!cap_cd_wake) + return device_wakeup_disable(&chip->pdev->dev); + + return 0; } static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) @@ -76,6 +83,9 @@ static int sdhci_pci_suspend_host(struct sdhci_pci_chip *chip) ret = sdhci_suspend_host(host); if (ret) goto err_pci_suspend; + + if (device_may_wakeup(&chip->pdev->dev)) + mmc_gpio_set_cd_wake(host->mmc, true); } return 0; @@ -99,6 +109,8 @@ int sdhci_pci_resume_host(struct sdhci_pci_chip *chip) ret = sdhci_resume_host(slot->host); if (ret) return ret; + + mmc_gpio_set_cd_wake(slot->host->mmc, false); } return 0; @@ -654,9 +666,36 @@ static void byt_read_dsm(struct sdhci_pci_slot *slot) slot->chip->rpm_retune = intel_host->d3_retune; } -static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) +static int intel_execute_tuning(struct mmc_host *mmc, u32 opcode) { + int err = sdhci_execute_tuning(mmc, opcode); + struct sdhci_host *host = mmc_priv(mmc); + + if (err) + return err; + + /* + * Tuning can leave the IP in an active state (Buffer Read Enable bit + * set) which prevents the entry to low power states (i.e. S0i3). Data + * reset will clear it. + */ + sdhci_reset(host, SDHCI_RESET_DATA); + + return 0; +} + +static void byt_probe_slot(struct sdhci_pci_slot *slot) +{ + struct mmc_host_ops *ops = &slot->host->mmc_host_ops; + byt_read_dsm(slot); + + ops->execute_tuning = intel_execute_tuning; +} + +static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot) +{ + byt_probe_slot(slot); slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE | MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR | MMC_CAP_CMD_DURING_TFR | @@ -685,26 +724,8 @@ static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot) return ret; } -static void glk_cqe_enable(struct mmc_host *mmc) -{ - struct sdhci_host *host = mmc_priv(mmc); - u32 reg; - - /* - * CQE gets stuck if it sees Buffer Read Enable bit set, which can be - * the case after tuning, so ensure the buffer is drained. - */ - reg = sdhci_readl(host, SDHCI_PRESENT_STATE); - while (reg & SDHCI_DATA_AVAILABLE) { - sdhci_readl(host, SDHCI_BUFFER); - reg = sdhci_readl(host, SDHCI_PRESENT_STATE); - } - - sdhci_cqe_enable(mmc); -} - static const struct cqhci_host_ops glk_cqhci_ops = { - .enable = glk_cqe_enable, + .enable = sdhci_cqe_enable, .disable = sdhci_cqe_disable, .dumpregs = sdhci_pci_dumpregs, }; @@ -779,7 +800,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot) { int err; - byt_read_dsm(slot); + byt_probe_slot(slot); err = ni_set_max_freq(slot); if (err) @@ -792,7 +813,7 @@ static int ni_byt_sdio_probe_slot(struct sdhci_pci_slot *slot) static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) { - byt_read_dsm(slot); + byt_probe_slot(slot); slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE | MMC_CAP_WAIT_WHILE_BUSY; return 0; @@ -800,7 +821,7 @@ static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot) static int byt_sd_probe_slot(struct sdhci_pci_slot *slot) { - byt_read_dsm(slot); + byt_probe_slot(slot); slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_AGGRESSIVE_PM | MMC_CAP_CD_WAKE; slot->cd_idx = 0; @@ -1689,6 +1710,9 @@ static struct sdhci_pci_slot *sdhci_pci_probe_slot( if (device_can_wakeup(&pdev->dev)) host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; + if (host->mmc->caps & MMC_CAP_CD_WAKE) + device_init_wakeup(&pdev->dev, true); + if (slot->cd_idx >= 0) { ret = mmc_gpiod_request_cd(host->mmc, NULL, slot->cd_idx, slot->cd_override_level, 0, NULL); |