diff options
author | Anton Vorontsov <avorontsov@ru.mvista.com> | 2009-03-16 17:13:52 -0400 |
---|---|---|
committer | Pierre Ossman <drzeus@drzeus.cx> | 2009-03-24 16:30:08 -0400 |
commit | 68d1fb7e229c6f95be4fbbe3eb46b24e41184924 (patch) | |
tree | 09e60a2e1e5b3569dd309348a8c164c859c89671 /drivers/mmc/host/sdhci.c | |
parent | 6aa943ab8994fe6e4ccba22c5bc8150a84268bdd (diff) |
sdhci: Add support for card-detection polling
This patch adds SDHCI_QUIRK_BROKEN_CARD_DETECTION quirk. When specified,
sdhci driver will set MMC_CAP_NEEDS_POLL MMC host capability, and won't
enable card insert/remove interrupts.
This is needed for hosts with unreliable card detection, such as FSL
eSDHC. The original eSDHC driver was tring to "debounce" card-detection
IRQs by reading present state and disabling particular interrupts. But
with this debouncing scheme I noticed that sometimes we miss card
insertion/removal events.
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6fbbc005dd7f..fc7cb489bdb7 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -112,6 +112,9 @@ static void sdhci_set_card_detection(struct sdhci_host *host, bool enable) | |||
112 | { | 112 | { |
113 | u32 irqs = SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT; | 113 | u32 irqs = SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT; |
114 | 114 | ||
115 | if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) | ||
116 | return; | ||
117 | |||
115 | if (enable) | 118 | if (enable) |
116 | sdhci_unmask_irqs(host, irqs); | 119 | sdhci_unmask_irqs(host, irqs); |
117 | else | 120 | else |
@@ -1041,6 +1044,7 @@ out: | |||
1041 | static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) | 1044 | static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) |
1042 | { | 1045 | { |
1043 | struct sdhci_host *host; | 1046 | struct sdhci_host *host; |
1047 | bool present; | ||
1044 | unsigned long flags; | 1048 | unsigned long flags; |
1045 | 1049 | ||
1046 | host = mmc_priv(mmc); | 1050 | host = mmc_priv(mmc); |
@@ -1055,8 +1059,14 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
1055 | 1059 | ||
1056 | host->mrq = mrq; | 1060 | host->mrq = mrq; |
1057 | 1061 | ||
1058 | if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT) | 1062 | /* If polling, assume that the card is always present. */ |
1059 | || (host->flags & SDHCI_DEVICE_DEAD)) { | 1063 | if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) |
1064 | present = true; | ||
1065 | else | ||
1066 | present = sdhci_readl(host, SDHCI_PRESENT_STATE) & | ||
1067 | SDHCI_CARD_PRESENT; | ||
1068 | |||
1069 | if (!present || host->flags & SDHCI_DEVICE_DEAD) { | ||
1060 | host->mrq->cmd->error = -ENOMEDIUM; | 1070 | host->mrq->cmd->error = -ENOMEDIUM; |
1061 | tasklet_schedule(&host->finish_tasklet); | 1071 | tasklet_schedule(&host->finish_tasklet); |
1062 | } else | 1072 | } else |
@@ -1690,6 +1700,9 @@ int sdhci_add_host(struct sdhci_host *host) | |||
1690 | if (caps & SDHCI_CAN_DO_HISPD) | 1700 | if (caps & SDHCI_CAN_DO_HISPD) |
1691 | mmc->caps |= MMC_CAP_SD_HIGHSPEED; | 1701 | mmc->caps |= MMC_CAP_SD_HIGHSPEED; |
1692 | 1702 | ||
1703 | if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) | ||
1704 | mmc->caps |= MMC_CAP_NEEDS_POLL; | ||
1705 | |||
1693 | mmc->ocr_avail = 0; | 1706 | mmc->ocr_avail = 0; |
1694 | if (caps & SDHCI_CAN_VDD_330) | 1707 | if (caps & SDHCI_CAN_VDD_330) |
1695 | mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; | 1708 | mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34; |