diff options
Diffstat (limited to 'drivers/mmc/core/sdio_irq.c')
| -rw-r--r-- | drivers/mmc/core/sdio_irq.c | 52 | 
1 files changed, 42 insertions, 10 deletions
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c index 3d8ceb4084d..5cc13c8d35b 100644 --- a/drivers/mmc/core/sdio_irq.c +++ b/drivers/mmc/core/sdio_irq.c @@ -53,6 +53,17 @@ static int process_sdio_pending_irqs(struct mmc_host *host)  		return ret;  	} +	if (pending && mmc_card_broken_irq_polling(card) && +	    !(host->caps & MMC_CAP_SDIO_IRQ)) { +		unsigned char dummy; + +		/* A fake interrupt could be created when we poll SDIO_CCCR_INTx +		 * register with a Marvell SD8797 card. A dummy CMD52 read to +		 * function 0 register 0xff can avoid this. +		 */ +		mmc_io_rw_direct(card, 0, 0, 0xff, 0, &dummy); +	} +  	count = 0;  	for (i = 1; i <= 7; i++) {  		if (pending & (1 << i)) { @@ -79,6 +90,15 @@ static int process_sdio_pending_irqs(struct mmc_host *host)  	return ret;  } +void sdio_run_irqs(struct mmc_host *host) +{ +	mmc_claim_host(host); +	host->sdio_irq_pending = true; +	process_sdio_pending_irqs(host); +	mmc_release_host(host); +} +EXPORT_SYMBOL_GPL(sdio_run_irqs); +  static int sdio_irq_thread(void *_host)  {  	struct mmc_host *host = _host; @@ -178,14 +198,20 @@ static int sdio_card_irq_get(struct mmc_card *card)  	WARN_ON(!host->claimed);  	if (!host->sdio_irqs++) { -		atomic_set(&host->sdio_irq_thread_abort, 0); -		host->sdio_irq_thread = -			kthread_run(sdio_irq_thread, host, "ksdioirqd/%s", -				mmc_hostname(host)); -		if (IS_ERR(host->sdio_irq_thread)) { -			int err = PTR_ERR(host->sdio_irq_thread); -			host->sdio_irqs--; -			return err; +		if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) { +			atomic_set(&host->sdio_irq_thread_abort, 0); +			host->sdio_irq_thread = +				kthread_run(sdio_irq_thread, host, +					    "ksdioirqd/%s", mmc_hostname(host)); +			if (IS_ERR(host->sdio_irq_thread)) { +				int err = PTR_ERR(host->sdio_irq_thread); +				host->sdio_irqs--; +				return err; +			} +		} else { +			mmc_host_clk_hold(host); +			host->ops->enable_sdio_irq(host, 1); +			mmc_host_clk_release(host);  		}  	} @@ -200,8 +226,14 @@ static int sdio_card_irq_put(struct mmc_card *card)  	BUG_ON(host->sdio_irqs < 1);  	if (!--host->sdio_irqs) { -		atomic_set(&host->sdio_irq_thread_abort, 1); -		kthread_stop(host->sdio_irq_thread); +		if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) { +			atomic_set(&host->sdio_irq_thread_abort, 1); +			kthread_stop(host->sdio_irq_thread); +		} else { +			mmc_host_clk_hold(host); +			host->ops->enable_sdio_irq(host, 0); +			mmc_host_clk_release(host); +		}  	}  	return 0;  | 
