diff mbox

[RFC/PATCH,v2,2/3] mmc: sdio: add asynchronous interrupt support on device

Message ID 1348196867-15145-3-git-send-email-keyuan.liu@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kevin Liu Sept. 21, 2012, 3:07 a.m. UTC
From: Kevin Liu <kliu5@marvell.com>

Enable asynchronous interrupt on device by default if both host
and device support it and clock gating is allowed.

If asynchronous interrupt is enabled, then no need to switch bus
width to 1bit before suspend.

Signed-off-by: Kevin Liu <kliu5@marvell.com>
---
 drivers/mmc/core/sdio.c  |   22 +++++++++++++++++++---
 include/linux/mmc/card.h |    3 +++
 include/linux/mmc/host.h |    1 +
 include/linux/mmc/sdio.h |    5 +++++
 4 files changed, 28 insertions(+), 3 deletions(-)

Comments

Ulf Hansson Sept. 24, 2012, 9:54 a.m. UTC | #1
On 21 September 2012 05:07, Kevin Liu <keyuan.liu@gmail.com> wrote:
> From: Kevin Liu <kliu5@marvell.com>
>
> Enable asynchronous interrupt on device by default if both host
> and device support it and clock gating is allowed.
>
> If asynchronous interrupt is enabled, then no need to switch bus
> width to 1bit before suspend.
>
> Signed-off-by: Kevin Liu <kliu5@marvell.com>
> ---
>  drivers/mmc/core/sdio.c  |   22 +++++++++++++++++++---
>  include/linux/mmc/card.h |    3 +++
>  include/linux/mmc/host.h |    1 +
>  include/linux/mmc/sdio.h |    5 +++++
>  4 files changed, 28 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
> index 909c835..b3a3ca8 100644
> --- a/drivers/mmc/core/sdio.c
> +++ b/drivers/mmc/core/sdio.c
> @@ -199,6 +199,21 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
>                 }
>         }
>
> +       if (cccr_vsn >= SDIO_CCCR_REV_3_00) {
> +               if (!(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING) &&
> +                       (card->host->caps2 & MMC_CAP2_ASYNC_INT)) {
> +                       if (mmc_io_rw_direct(card, 0, 0,
> +                               SDIO_CCCR_INT_EXT, 0, &data))
> +                               goto out;
> +                       if (data & SDIO_INT_SAI) {
> +                               data |= SDIO_INT_EAI;
> +                               if (mmc_io_rw_direct(card, 1, 0,
> +                                       SDIO_CCCR_INT_EXT, data, NULL))
> +                                       goto out;
> +                               mmc_card_set_async_int(card);
> +                       }
> +               }
> +       }
>  out:
>         return ret;
>  }
> @@ -290,7 +305,6 @@ static int sdio_disable_wide(struct mmc_card *card)
>         return 0;
>  }
>
> -
>  static int sdio_enable_4bit_bus(struct mmc_card *card)
>  {
>         int err;
> @@ -917,7 +931,8 @@ static int mmc_sdio_suspend(struct mmc_host *host)
>                 }
>         }
>
> -       if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
> +       if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)
> +               && !mmc_card_async_int(host->card)) {
>                 mmc_claim_host(host);
>                 sdio_disable_wide(host->card);
>                 mmc_release_host(host);
> @@ -940,7 +955,8 @@ static int mmc_sdio_resume(struct mmc_host *host)
>         if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
>                 err = mmc_sdio_init_card(host, host->ocr, host->card,
>                                         mmc_card_keep_power(host));
> -       else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
> +       else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)
> +               && !mmc_card_async_int(host->card)) {
>                 /* We may have switched to 1-bit mode during suspend */
>                 err = sdio_enable_4bit_bus(host->card);
>                 if (err > 0) {
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index 78cc3be..4f0f554 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -231,6 +231,7 @@ struct mmc_card {
>  #define MMC_STATE_HIGHSPEED_200        (1<<8)          /* card is in HS200 mode */
>  #define MMC_STATE_SLEEP                (1<<9)          /* card is in sleep state */
>  #define MMC_STATE_DOING_BKOPS  (1<<10)         /* card is doing BKOPS */
> +#define MMC_STATE_ASYNC_INT    (1<<11)         /* card is async int enabled */
>         unsigned int            quirks;         /* card quirks */
>  #define MMC_QUIRK_LENIENT_FN0  (1<<0)          /* allow SDIO FN0 writes outside of the VS CCCR range */
>  #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)   /* use func->cur_blksize */
> @@ -399,6 +400,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>  #define mmc_card_removed(c)    ((c) && ((c)->state & MMC_CARD_REMOVED))
>  #define mmc_card_is_sleep(c)   ((c)->state & MMC_STATE_SLEEP)
>  #define mmc_card_doing_bkops(c)        ((c)->state & MMC_STATE_DOING_BKOPS)
> +#define mmc_card_async_int(c)  ((c)->state & MMC_STATE_ASYNC_INT)
>
>  #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
>  #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
> @@ -412,6 +414,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
>  #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
>  #define mmc_card_set_sleep(c)  ((c)->state |= MMC_STATE_SLEEP)
>  #define mmc_card_set_doing_bkops(c)    ((c)->state |= MMC_STATE_DOING_BKOPS)
> +#define mmc_card_set_async_int(c)      ((c)->state |= MMC_STATE_ASYNC_INT)
>
>  #define mmc_card_clr_doing_bkops(c)    ((c)->state &= ~MMC_STATE_DOING_BKOPS)
>  #define mmc_card_clr_sleep(c)  ((c)->state &= ~MMC_STATE_SLEEP)
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index d5d9bd4..78fd877 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -257,6 +257,7 @@ struct mmc_host {
>  #define MMC_CAP2_HC_ERASE_SZ   (1 << 9)        /* High-capacity erase size */
>  #define MMC_CAP2_CD_ACTIVE_HIGH        (1 << 10)       /* Card-detect signal active high */
>  #define MMC_CAP2_RO_ACTIVE_HIGH        (1 << 11)       /* Write-protect signal active high */
> +#define MMC_CAP2_ASYNC_INT     (1 << 12)       /* Asynchronous interrupt support */
>
>         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>         unsigned int        power_notify_type;
> diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h
> index 47e579d..abbb6c8 100644
> --- a/include/linux/mmc/sdio.h
> +++ b/include/linux/mmc/sdio.h
> @@ -161,6 +161,11 @@
>  #define  SDIO_DTSx_SET_TYPE_A  (1 << SDIO_DRIVE_DTSx_SHIFT)
>  #define  SDIO_DTSx_SET_TYPE_C  (2 << SDIO_DRIVE_DTSx_SHIFT)
>  #define  SDIO_DTSx_SET_TYPE_D  (3 << SDIO_DRIVE_DTSx_SHIFT)
> +
> +#define SDIO_CCCR_INT_EXT      0x16
> +#define SDIO_INT_SAI           0x01
> +#define SDIO_INT_EAI           0x02
> +
>  /*
>   * Function Basic Registers (FBR)
>   */
> --
> 1.7.0.4
>

Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>

Kind regards
Ulf Hansson
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 909c835..b3a3ca8 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -199,6 +199,21 @@  static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
 		}
 	}
 
+	if (cccr_vsn >= SDIO_CCCR_REV_3_00) {
+		if (!(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING) &&
+			(card->host->caps2 & MMC_CAP2_ASYNC_INT)) {
+			if (mmc_io_rw_direct(card, 0, 0,
+				SDIO_CCCR_INT_EXT, 0, &data))
+				goto out;
+			if (data & SDIO_INT_SAI) {
+				data |= SDIO_INT_EAI;
+				if (mmc_io_rw_direct(card, 1, 0,
+					SDIO_CCCR_INT_EXT, data, NULL))
+					goto out;
+				mmc_card_set_async_int(card);
+			}
+		}
+	}
 out:
 	return ret;
 }
@@ -290,7 +305,6 @@  static int sdio_disable_wide(struct mmc_card *card)
 	return 0;
 }
 
-
 static int sdio_enable_4bit_bus(struct mmc_card *card)
 {
 	int err;
@@ -917,7 +931,8 @@  static int mmc_sdio_suspend(struct mmc_host *host)
 		}
 	}
 
-	if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+	if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)
+		&& !mmc_card_async_int(host->card)) {
 		mmc_claim_host(host);
 		sdio_disable_wide(host->card);
 		mmc_release_host(host);
@@ -940,7 +955,8 @@  static int mmc_sdio_resume(struct mmc_host *host)
 	if (mmc_card_is_removable(host) || !mmc_card_keep_power(host))
 		err = mmc_sdio_init_card(host, host->ocr, host->card,
 					mmc_card_keep_power(host));
-	else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
+	else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)
+		&& !mmc_card_async_int(host->card)) {
 		/* We may have switched to 1-bit mode during suspend */
 		err = sdio_enable_4bit_bus(host->card);
 		if (err > 0) {
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index 78cc3be..4f0f554 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -231,6 +231,7 @@  struct mmc_card {
 #define MMC_STATE_HIGHSPEED_200	(1<<8)		/* card is in HS200 mode */
 #define MMC_STATE_SLEEP		(1<<9)		/* card is in sleep state */
 #define MMC_STATE_DOING_BKOPS	(1<<10)		/* card is doing BKOPS */
+#define MMC_STATE_ASYNC_INT	(1<<11)		/* card is async int enabled */
 	unsigned int		quirks; 	/* card quirks */
 #define MMC_QUIRK_LENIENT_FN0	(1<<0)		/* allow SDIO FN0 writes outside of the VS CCCR range */
 #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1)	/* use func->cur_blksize */
@@ -399,6 +400,7 @@  static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_removed(c)	((c) && ((c)->state & MMC_CARD_REMOVED))
 #define mmc_card_is_sleep(c)	((c)->state & MMC_STATE_SLEEP)
 #define mmc_card_doing_bkops(c)	((c)->state & MMC_STATE_DOING_BKOPS)
+#define mmc_card_async_int(c)	((c)->state & MMC_STATE_ASYNC_INT)
 
 #define mmc_card_set_present(c)	((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
@@ -412,6 +414,7 @@  static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
 #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
 #define mmc_card_set_sleep(c)	((c)->state |= MMC_STATE_SLEEP)
 #define mmc_card_set_doing_bkops(c)	((c)->state |= MMC_STATE_DOING_BKOPS)
+#define mmc_card_set_async_int(c)	((c)->state |= MMC_STATE_ASYNC_INT)
 
 #define mmc_card_clr_doing_bkops(c)	((c)->state &= ~MMC_STATE_DOING_BKOPS)
 #define mmc_card_clr_sleep(c)	((c)->state &= ~MMC_STATE_SLEEP)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index d5d9bd4..78fd877 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -257,6 +257,7 @@  struct mmc_host {
 #define MMC_CAP2_HC_ERASE_SZ	(1 << 9)	/* High-capacity erase size */
 #define MMC_CAP2_CD_ACTIVE_HIGH	(1 << 10)	/* Card-detect signal active high */
 #define MMC_CAP2_RO_ACTIVE_HIGH	(1 << 11)	/* Write-protect signal active high */
+#define MMC_CAP2_ASYNC_INT	(1 << 12)	/* Asynchronous interrupt support */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 	unsigned int        power_notify_type;
diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h
index 47e579d..abbb6c8 100644
--- a/include/linux/mmc/sdio.h
+++ b/include/linux/mmc/sdio.h
@@ -161,6 +161,11 @@ 
 #define  SDIO_DTSx_SET_TYPE_A	(1 << SDIO_DRIVE_DTSx_SHIFT)
 #define  SDIO_DTSx_SET_TYPE_C	(2 << SDIO_DRIVE_DTSx_SHIFT)
 #define  SDIO_DTSx_SET_TYPE_D	(3 << SDIO_DRIVE_DTSx_SHIFT)
+
+#define SDIO_CCCR_INT_EXT	0x16
+#define SDIO_INT_SAI		0x01
+#define SDIO_INT_EAI		0x02
+
 /*
  * Function Basic Registers (FBR)
  */