sdio: add interface for host side SDIO interrupt reporting

Signed-off-by: Nicolas Pitre <npitre@mvista.com>
Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 2c7ce8f..37b7618 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -100,6 +100,9 @@
 {
 	int err;
 
+	WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
+		!host->ops->enable_sdio_irq);
+
 	if (!idr_pre_get(&mmc_host_idr, GFP_KERNEL))
 		return -ENOMEM;
 
diff --git a/drivers/mmc/core/sdio_irq.c b/drivers/mmc/core/sdio_irq.c
index 01922d2..01daee9 100644
--- a/drivers/mmc/core/sdio_irq.c
+++ b/drivers/mmc/core/sdio_irq.c
@@ -70,7 +70,8 @@
 	 * asynchronous notification of pending SDIO card interrupts
 	 * hence we poll for them in that case.
 	 */
-	period = msecs_to_jiffies(10);
+	period = (host->caps & MMC_CAP_SDIO_IRQ) ?
+		MAX_SCHEDULE_TIMEOUT : msecs_to_jiffies(10);
 
 	pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
 		 mmc_hostname(host), period);
@@ -104,11 +105,16 @@
 			ssleep(1);
 
 		set_task_state(current, TASK_INTERRUPTIBLE);
+		if (host->caps & MMC_CAP_SDIO_IRQ)
+			host->ops->enable_sdio_irq(host, 1);
 		if (!kthread_should_stop())
 			schedule_timeout(period);
 		set_task_state(current, TASK_RUNNING);
 	} while (!kthread_should_stop());
 
+	if (host->caps & MMC_CAP_SDIO_IRQ)
+		host->ops->enable_sdio_irq(host, 0);
+
 	pr_debug("%s: IRQ thread exiting with code %d\n",
 		 mmc_hostname(host), ret);
 
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 00dc180..3fd1979 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -51,6 +51,7 @@
 	void	(*request)(struct mmc_host *host, struct mmc_request *req);
 	void	(*set_ios)(struct mmc_host *host, struct mmc_ios *ios);
 	int	(*get_ro)(struct mmc_host *host);
+	void	(*enable_sdio_irq)(struct mmc_host *host, int enable);
 };
 
 struct mmc_card;
@@ -89,6 +90,7 @@
 #define MMC_CAP_MULTIWRITE	(1 << 1)	/* Can accurately report bytes sent to card on error */
 #define MMC_CAP_MMC_HIGHSPEED	(1 << 2)	/* Can do MMC high-speed timing */
 #define MMC_CAP_SD_HIGHSPEED	(1 << 3)	/* Can do SD high-speed timing */
+#define MMC_CAP_SDIO_IRQ	(1 << 4)	/* Can signal pending SDIO IRQs */
 
 	/* host specific block data */
 	unsigned int		max_seg_size;	/* see blk_queue_max_segment_size */
@@ -150,5 +152,11 @@
 extern void mmc_detect_change(struct mmc_host *, unsigned long delay);
 extern void mmc_request_done(struct mmc_host *, struct mmc_request *);
 
+static inline void mmc_signal_sdio_irq(struct mmc_host *host)
+{
+	host->ops->enable_sdio_irq(host, 0);
+	wake_up_process(host->sdio_irq_thread);
+}
+
 #endif