|
@@ -1050,6 +1050,20 @@ static struct mmc_host_ops wbsd_ops = {
|
|
|
* *
|
|
|
\*****************************************************************************/
|
|
|
|
|
|
+/*
|
|
|
+ * Helper function for card detection
|
|
|
+ */
|
|
|
+static void wbsd_detect_card(unsigned long data)
|
|
|
+{
|
|
|
+ struct wbsd_host *host = (struct wbsd_host*)data;
|
|
|
+
|
|
|
+ BUG_ON(host == NULL);
|
|
|
+
|
|
|
+ DBG("Executing card detection\n");
|
|
|
+
|
|
|
+ mmc_detect_change(host->mmc);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Tasklets
|
|
|
*/
|
|
@@ -1075,7 +1089,6 @@ static void wbsd_tasklet_card(unsigned long param)
|
|
|
{
|
|
|
struct wbsd_host* host = (struct wbsd_host*)param;
|
|
|
u8 csr;
|
|
|
- int change = 0;
|
|
|
|
|
|
spin_lock(&host->lock);
|
|
|
|
|
@@ -1094,14 +1107,20 @@ static void wbsd_tasklet_card(unsigned long param)
|
|
|
{
|
|
|
DBG("Card inserted\n");
|
|
|
host->flags |= WBSD_FCARD_PRESENT;
|
|
|
- change = 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Delay card detection to allow electrical connections
|
|
|
+ * to stabilise.
|
|
|
+ */
|
|
|
+ mod_timer(&host->timer, jiffies + HZ/2);
|
|
|
}
|
|
|
+
|
|
|
+ spin_unlock(&host->lock);
|
|
|
}
|
|
|
else if (host->flags & WBSD_FCARD_PRESENT)
|
|
|
{
|
|
|
DBG("Card removed\n");
|
|
|
host->flags &= ~WBSD_FCARD_PRESENT;
|
|
|
- change = 1;
|
|
|
|
|
|
if (host->mrq)
|
|
|
{
|
|
@@ -1112,15 +1131,14 @@ static void wbsd_tasklet_card(unsigned long param)
|
|
|
host->mrq->cmd->error = MMC_ERR_FAILED;
|
|
|
tasklet_schedule(&host->finish_tasklet);
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Unlock first since we might get a call back.
|
|
|
- */
|
|
|
- spin_unlock(&host->lock);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Unlock first since we might get a call back.
|
|
|
+ */
|
|
|
+ spin_unlock(&host->lock);
|
|
|
|
|
|
- if (change)
|
|
|
mmc_detect_change(host->mmc);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static void wbsd_tasklet_fifo(unsigned long param)
|
|
@@ -1324,6 +1342,13 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
|
|
|
|
|
|
spin_lock_init(&host->lock);
|
|
|
|
|
|
+ /*
|
|
|
+ * Set up detection timer
|
|
|
+ */
|
|
|
+ init_timer(&host->timer);
|
|
|
+ host->timer.data = (unsigned long)host;
|
|
|
+ host->timer.function = wbsd_detect_card;
|
|
|
+
|
|
|
/*
|
|
|
* Maximum number of segments. Worst case is one sector per segment
|
|
|
* so this will be 64kB/512.
|
|
@@ -1351,11 +1376,17 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
|
|
|
static void __devexit wbsd_free_mmc(struct device* dev)
|
|
|
{
|
|
|
struct mmc_host* mmc;
|
|
|
+ struct wbsd_host* host;
|
|
|
|
|
|
mmc = dev_get_drvdata(dev);
|
|
|
if (!mmc)
|
|
|
return;
|
|
|
|
|
|
+ host = mmc_priv(mmc);
|
|
|
+ BUG_ON(host == NULL);
|
|
|
+
|
|
|
+ del_timer_sync(&host->timer);
|
|
|
+
|
|
|
mmc_free_host(mmc);
|
|
|
|
|
|
dev_set_drvdata(dev, NULL);
|