diff options
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
| -rw-r--r-- | drivers/mmc/host/sdhci.c | 34 | 
1 files changed, 30 insertions, 4 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 58d5436ff649..c31a3343340d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -127,11 +127,15 @@ static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)  static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)  { -	u32 irqs = SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT; +	u32 present, irqs;  	if (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)  		return; +	present = sdhci_readl(host, SDHCI_PRESENT_STATE) & +			      SDHCI_CARD_PRESENT; +	irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT; +  	if (enable)  		sdhci_unmask_irqs(host, irqs);  	else @@ -2154,13 +2158,30 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)  		mmc_hostname(host->mmc), intmask);  	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) { +		u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) & +			      SDHCI_CARD_PRESENT; + +		/* +		 * There is a observation on i.mx esdhc.  INSERT bit will be +		 * immediately set again when it gets cleared, if a card is +		 * inserted.  We have to mask the irq to prevent interrupt +		 * storm which will freeze the system.  And the REMOVE gets +		 * the same situation. +		 * +		 * More testing are needed here to ensure it works for other +		 * platforms though. +		 */ +		sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT : +						SDHCI_INT_CARD_REMOVE); +		sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE : +						  SDHCI_INT_CARD_INSERT); +  		sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT | -			SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); +			     SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS); +		intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);  		tasklet_schedule(&host->card_tasklet);  	} -	intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE); -  	if (intmask & SDHCI_INT_CMD_MASK) {  		sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,  			SDHCI_INT_STATUS); @@ -2488,6 +2509,11 @@ int sdhci_add_host(struct sdhci_host *host)  	} else  		mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; +	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) +		mmc->max_discard_to = (1 << 27) / (mmc->f_max / 1000); +	else +		mmc->max_discard_to = (1 << 27) / host->timeout_clk; +  	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;  	if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)  |