summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Zhu <r65037@freescale.com>2009-12-03 15:25:37 +0800
committerDavid Ungar <david.ungar@timesys.com>2010-04-19 17:03:30 -0400
commit13119016c81b197aff1948c397bd1dcaaf698f39 (patch)
treeb8cc3a74bf78c97d854d5f5ae34031dbcf217020
parenta2acbb430c7235fbab398f6bc6c9303a83b94e8b (diff)
ENGR00118900 [Mx35]Unexpected messages when insert/extract cards.
The unexpected messages are printed by the kernel. The root cause is that the I2C IO func can't be called in the interrupt context, since the SD/MMC port and CD PIN is logically walk through the MCU I2C bus. Solution:Don't call the I2C IO func in the interrupt context in card detection IRQ handler, move them to work-queue enviroment. Signed-off-by: Richard Zhu <r65037@freescale.com>
-rw-r--r--drivers/mmc/host/mx_sdhci.c54
-rw-r--r--drivers/mmc/host/mx_sdhci.h1
2 files changed, 31 insertions, 24 deletions
diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c
index b0226abcf8fd..062bad2af7b7 100644
--- a/drivers/mmc/host/mx_sdhci.c
+++ b/drivers/mmc/host/mx_sdhci.c
@@ -1243,6 +1243,7 @@ static void sdhci_cd_timer(unsigned long data)
struct sdhci_host *host;
host = (struct sdhci_host *)data;
+ host->flags |= SDHCI_CD_TIMEOUT;
schedule_work(&host->cd_wq);
}
@@ -1415,6 +1416,34 @@ static void esdhc_cd_callback(struct work_struct *work)
unsigned int cd_status = 0;
struct sdhci_host *host = container_of(work, struct sdhci_host, cd_wq);
+ do {
+ if (host->detect_irq == 0)
+ break;
+ cd_status = host->plat_data->status(host->mmc->parent);
+ if (cd_status)
+ set_irq_type(host->detect_irq, IRQF_TRIGGER_FALLING);
+ else
+ set_irq_type(host->detect_irq, IRQF_TRIGGER_RISING);
+ } while (cd_status != host->plat_data->status(host->mmc->parent));
+
+ cd_status = host->plat_data->status(host->mmc->parent);
+
+ DBG("cd_status=%d %s\n", cd_status, cd_status ? "removed" : "inserted");
+ /* If there is no card, call the card detection func
+ * immediately. */
+ if (!cd_status) {
+ /* If there is a card in the slot, the timer is start
+ * to work. Then the card detection would be carried
+ * after the timer is timeout.
+ * */
+ if (host->flags & SDHCI_CD_TIMEOUT)
+ host->flags &= ~SDHCI_CD_TIMEOUT;
+ else {
+ mod_timer(&host->cd_timer, jiffies + HZ / 4);
+ return;
+ }
+ }
+
cd_status = host->plat_data->status(host->mmc->parent);
if (cd_status)
host->flags &= ~SDHCI_CD_PRESENT;
@@ -1484,32 +1513,9 @@ static void esdhc_cd_callback(struct work_struct *work)
*/
static irqreturn_t sdhci_cd_irq(int irq, void *dev_id)
{
- unsigned int cd_status = 0;
struct sdhci_host *host = dev_id;
- do {
- if (host->detect_irq == 0)
- break;
- cd_status = host->plat_data->status(host->mmc->parent);
- if (cd_status)
- set_irq_type(host->detect_irq, IRQF_TRIGGER_FALLING);
- else
- set_irq_type(host->detect_irq, IRQF_TRIGGER_RISING);
- } while (cd_status != host->plat_data->status(host->mmc->parent));
-
- DBG("cd_status=%d %s\n", cd_status, cd_status ? "removed" : "inserted");
-
- cd_status = host->plat_data->status(host->mmc->parent);
- if (!cd_status)
- /* If there is a card in the slot, the timer is start
- * to work. Then the card detection would be carried
- * after the timer is timeout.
- * */
- mod_timer(&host->cd_timer, jiffies + HZ / 2);
- else
- /* If there is no card, call the card detection func
- * immediately. */
- schedule_work(&host->cd_wq);
+ schedule_work(&host->cd_wq);
return IRQ_HANDLED;
}
diff --git a/drivers/mmc/host/mx_sdhci.h b/drivers/mmc/host/mx_sdhci.h
index 509d444a6e81..9800f21d13a9 100644
--- a/drivers/mmc/host/mx_sdhci.h
+++ b/drivers/mmc/host/mx_sdhci.h
@@ -220,6 +220,7 @@ struct sdhci_host {
#define SDHCI_USE_EXTERNAL_DMA (1<<2) /* Use the External DMA */
#define SDHCI_CD_PRESENT (1<<8) /* CD present */
#define SDHCI_WP_ENABLED (1<<9) /* Write protect */
+#define SDHCI_CD_TIMEOUT (1<<10) /* cd timer is expired */
unsigned int max_clk; /* Max possible freq (MHz) */
unsigned int min_clk; /* Min possible freq (MHz) */