From b6831dd13bfb637ee3b29ee15042bcde923212be Mon Sep 17 00:00:00 2001 From: Richard Zhu Date: Thu, 3 Dec 2009 15:25:37 +0800 Subject: [PATCH] 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 --- drivers/mmc/host/mx_sdhci.c | 54 ++++++++++++++++++++----------------- drivers/mmc/host/mx_sdhci.h | 1 + 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/mmc/host/mx_sdhci.c b/drivers/mmc/host/mx_sdhci.c index b0226abcf8f..062bad2af7b 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 509d444a6e8..9800f21d13a 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) */