diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index eeac479..7913cd8 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -39,7 +39,6 @@ enum {
 	EVENT_STOP_COMPLETE,
 	EVENT_DMA_COMPLETE,
 	EVENT_DMA_ERROR,
-	EVENT_CARD_DETECT,
 };
 
 struct atmel_mci_dma {
@@ -70,6 +69,9 @@ struct atmel_mci {
 	int			detect_pin;
 	int			wp_pin;
 
+	/* For detect pin debouncing */
+	struct timer_list	detect_timer;
+
 	unsigned long		bus_hz;
 	unsigned long		mapbase;
 	struct clk		*mck;
@@ -108,8 +110,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
 	test_bit(EVENT_DMA_COMPLETE, &host->completed_events)
 #define mci_dma_error_is_complete(host)			\
 	test_bit(EVENT_DMA_ERROR, &host->completed_events)
-#define mci_card_detect_is_complete(host)			\
-	test_bit(EVENT_CARD_DETECT, &host->completed_events)
 
 /* Test and clear bit macros for pending events */
 #define mci_clear_cmd_is_pending(host)			\
@@ -124,8 +124,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
 	test_and_clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
 #define mci_clear_dma_error_is_pending(host)		\
 	test_and_clear_bit(EVENT_DMA_ERROR, &host->pending_events)
-#define mci_clear_card_detect_is_pending(host)		\
-	test_and_clear_bit(EVENT_CARD_DETECT, &host->pending_events)
 
 /* Test and set bit macros for completed events */
 #define mci_set_cmd_is_completed(host)			\
@@ -140,8 +138,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
 	test_and_set_bit(EVENT_STOP_COMPLETE, &host->completed_events)
 #define mci_set_dma_error_is_completed(host)		\
 	test_and_set_bit(EVENT_DMA_ERROR, &host->completed_events)
-#define mci_set_card_detect_is_completed(host)		\
-	test_and_set_bit(EVENT_CARD_DETECT, &host->completed_events)
 
 /* Set bit macros for completed events */
 #define mci_set_cmd_complete(host)			\
@@ -158,8 +154,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
 	set_bit(EVENT_DMA_COMPLETE, &host->completed_events)
 #define mci_set_dma_error_complete(host)		\
 	set_bit(EVENT_DMA_ERROR, &host->completed_events)
-#define mci_set_card_detect_complete(host)		\
-	set_bit(EVENT_CARD_DETECT, &host->completed_events)
 
 /* Set bit macros for pending events */
 #define mci_set_cmd_pending(host)			\
@@ -174,8 +168,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
 	set_bit(EVENT_STOP_COMPLETE, &host->pending_events)
 #define mci_set_dma_error_pending(host)			\
 	set_bit(EVENT_DMA_ERROR, &host->pending_events)
-#define mci_set_card_detect_pending(host)		\
-	set_bit(EVENT_CARD_DETECT, &host->pending_events)
 
 /* Clear bit macros for pending events */
 #define mci_clear_cmd_pending(host)			\
@@ -190,8 +182,6 @@ MODULE_PARM_DESC(fmax, "Max frequency in Hz of the MMC bus clock");
 	clear_bit(EVENT_STOP_COMPLETE, &host->pending_events)
 #define mci_clear_dma_error_pending(host)		\
 	clear_bit(EVENT_DMA_ERROR, &host->pending_events)
-#define mci_clear_card_detect_pending(host)		\
-	clear_bit(EVENT_CARD_DETECT, &host->pending_events)
 
 
 #ifdef CONFIG_DEBUG_FS
@@ -560,6 +550,21 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 				mci_readl(host, IMR));
 
 	WARN_ON(host->mrq != NULL);
+
+	/*
+	 * We may "know" the card is gone even though there's still an
+	 * electrical connection. If so, we really need to communicate
+	 * this to the MMC core since there won't be any more
+	 * interrupts as the card is completely removed. Otherwise,
+	 * the MMC core might believe the card is still there even
+	 * though the card was just removed very slowly.
+	 */
+	if (!host->present) {
+		mrq->cmd->error = -ENOMEDIUM;
+		mmc_request_done(mmc, mrq);
+		return;
+	}
+
 	host->mrq = mrq;
 	host->pending_events = 0;
 	host->completed_events = 0;
@@ -729,6 +734,61 @@ static void atmci_command_complete(struct atmel_mci *host,
 	}
 }
 
+static void atmci_detect_change(unsigned long data)
+{
+	struct atmel_mci *host = (struct atmel_mci *)data;
+	struct mmc_request *mrq = host->mrq;
+	int present;
+
+	/*
+	 * atmci_remove() sets detect_pin to -1 before freeing the
+	 * interrupt. We must not re-enable the interrupt if it has
+	 * been freed.
+	 */
+	smp_rmb();
+	if (host->detect_pin < 0)
+		return;
+
+	enable_irq(gpio_to_irq(host->detect_pin));
+	present = !gpio_get_value(host->detect_pin);
+
+	dev_vdbg(&host->pdev->dev, "detect change: %d (was %d)\n",
+			present, host->present);
+
+	if (present != host->present) {
+		dev_dbg(&host->mmc->class_dev, "card %s\n",
+			present ? "inserted" : "removed");
+		host->present = present;
+
+		/* Reset controller if card is gone */
+		if (!present) {
+			mci_writel(host, CR, MCI_BIT(SWRST));
+			mci_writel(host, IDR, ~0UL);
+			mci_writel(host, CR, MCI_BIT(MCIEN));
+		}
+
+		/* Clean up queue if present */
+		if (mrq) {
+			if (!mci_cmd_is_complete(host))
+				mrq->cmd->error = -ENOMEDIUM;
+			if (mrq->data && !mci_data_is_complete(host)
+			    && !mci_data_error_is_complete(host)) {
+				dma_stop_request(host->dma.req.req.dmac,
+						host->dma.req.req.channel);
+				host->data->error = -ENOMEDIUM;
+				atmci_data_complete(host, host->data);
+			}
+			if (mrq->stop && !mci_stop_is_complete(host))
+				mrq->stop->error = -ENOMEDIUM;
+
+			host->cmd = NULL;
+			atmci_request_end(host->mmc, mrq);
+		}
+
+		mmc_detect_change(host->mmc, 0);
+	}
+}
+
 static void atmci_tasklet_func(unsigned long priv)
 {
 	struct mmc_host *mmc = (struct mmc_host *)priv;
@@ -806,33 +866,6 @@ static void atmci_tasklet_func(unsigned long priv)
 		data->bytes_xfered = data->blocks * data->blksz;
 		atmci_data_complete(host, data);
 	}
-	if (mci_clear_card_detect_is_pending(host)) {
-		/* Reset controller if card is gone */
-		if (!host->present) {
-			mci_writel(host, CR, MCI_BIT(SWRST));
-			mci_writel(host, IDR, ~0UL);
-			mci_writel(host, CR, MCI_BIT(MCIEN));
-		}
-
-		/* Clean up queue if present */
-		if (mrq) {
-			if (!mci_cmd_is_complete(host))
-				mrq->cmd->error = -ETIMEDOUT;
-			if (mrq->data && !mci_data_is_complete(host)
-			    && !mci_data_error_is_complete(host)) {
-				dma_stop_request(host->dma.req.req.dmac,
-						host->dma.req.req.channel);
-				host->data->error = -ETIMEDOUT;
-				atmci_data_complete(host, data);
-			}
-			if (mrq->stop && !mci_stop_is_complete(host))
-				mrq->stop->error = -ETIMEDOUT;
-
-			host->cmd = NULL;
-			atmci_request_end(mmc, mrq);
-		}
-		mmc_detect_change(host->mmc, msecs_to_jiffies(100));
-	}
 }
 
 static void atmci_cmd_interrupt(struct mmc_host *mmc, u32 status)
@@ -957,20 +990,19 @@ static irqreturn_t atmci_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static irqreturn_t atmci_detect_change(int irq, void *dev_id)
+static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
 {
 	struct mmc_host *mmc = dev_id;
 	struct atmel_mci *host = mmc_priv(mmc);
 
-	int present = !gpio_get_value(irq_to_gpio(irq));
+	/*
+	 * Disable interrupts until the pin has stabilized and check
+	 * the state then. Use mod_timer() since we may be in the
+	 * middle of the timer routine when this interrupt triggers.
+	 */
+	disable_irq_nosync(irq);
+	mod_timer(&host->detect_timer, jiffies + msecs_to_jiffies(20));
 
-	if (present != host->present) {
-		dev_dbg(&mmc->class_dev, "card %s\n",
-			present ? "inserted" : "removed");
-		host->present = present;
-		mci_set_card_detect_pending(host);
-		tasklet_schedule(&host->tasklet);
-	}
 	return IRQ_HANDLED;
 }
 
@@ -1079,8 +1111,11 @@ static int __devinit atmci_probe(struct platform_device *pdev)
 	mmc_add_host(mmc);
 
 	if (host->detect_pin >= 0) {
+		setup_timer(&host->detect_timer, atmci_detect_change,
+				(unsigned long)host);
+
 		ret = request_irq(gpio_to_irq(host->detect_pin),
-				  atmci_detect_change,
+				  atmci_detect_interrupt,
 				  IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
 				  DRIVER_NAME, mmc);
 		if (ret) {
@@ -1125,9 +1160,16 @@ static int __devexit atmci_remove(struct platform_device *pdev)
 		atmci_cleanup_debugfs(host);
 
 		if (host->detect_pin >= 0) {
-			free_irq(gpio_to_irq(host->detect_pin), host->mmc);
+			int pin = host->detect_pin;
+
+			/* Make sure our timer doesn't enable the interrupt */
+			host->detect_pin = -1;
+			smp_wmb();
+
+			free_irq(gpio_to_irq(pin), host->mmc);
+			del_timer_sync(&host->detect_timer);
 			cancel_delayed_work(&host->mmc->detect);
-			gpio_free(host->detect_pin);
+			gpio_free(pin);
 		}
 
 		mmc_remove_host(host->mmc);