aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2009-03-16 17:13:52 -0400
committerPierre Ossman <drzeus@drzeus.cx>2009-03-24 16:30:08 -0400
commit68d1fb7e229c6f95be4fbbe3eb46b24e41184924 (patch)
tree09e60a2e1e5b3569dd309348a8c164c859c89671
parent6aa943ab8994fe6e4ccba22c5bc8150a84268bdd (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>
-rw-r--r--drivers/mmc/host/sdhci.c17
-rw-r--r--drivers/mmc/host/sdhci.h2
2 files changed, 17 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:
1041static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq) 1044static 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;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index a9e25c6c0c0e..968d713950f1 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -214,6 +214,8 @@ struct sdhci_host {
214#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13) 214#define SDHCI_QUIRK_BROKEN_SMALL_PIO (1<<13)
215/* Controller does not provide transfer-complete interrupt when not busy */ 215/* Controller does not provide transfer-complete interrupt when not busy */
216#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14) 216#define SDHCI_QUIRK_NO_BUSY_IRQ (1<<14)
217/* Controller has unreliable card detection */
218#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
217 219
218 int irq; /* Device IRQ */ 220 int irq; /* Device IRQ */
219 void __iomem * ioaddr; /* Mapped address */ 221 void __iomem * ioaddr; /* Mapped address */