diff options
author | Richard Zhu <r65037@freescale.com> | 2009-12-03 15:25:37 +0800 |
---|---|---|
committer | Richard Zhu <r65037@freescale.com> | 2009-12-03 15:52:40 +0800 |
commit | f0a0d65e63e8fafee8d07aa13d598e30261ad9d0 (patch) | |
tree | b8cc3a74bf78c97d854d5f5ae34031dbcf217020 /drivers | |
parent | ffa6d62809930ec39c0bce3d8248f02402b17a26 (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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mmc/host/mx_sdhci.c | 54 | ||||
-rw-r--r-- | 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 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) */ |