diff mbox

DM355 SDIO support

Message ID 200907291256.n6TCunJk028509@webmail01.myhsphere.biz (mailing list archive)
State Rejected
Headers show

Commit Message

Phaneendra kumar July 29, 2009, 12:56 p.m. UTC
Hi all,

This patch will add SDIO support to the DM355 host controller driver.

I have verified this on DM355 EVM board in both DMA and PIO modes. And i have used open source libertas driver for verifying the SDIO functionality.

Signed-off-by: Phaneendra Kumar <phani@embwise.com>
-----

Comments

s-paulraj@ti.com July 29, 2009, 1:25 p.m. UTC | #1
Phaneendra,

The patch description should be 

[PATCH] DaVinci: DM355 SDIO support

You use a printk in your patch. That should be replaced I believe with an appropriate dev_dbg or dev_warn. BTW you use dev_dbg in another part of your patch.

Thanks,
Sandeep


> -----Original Message-----
> From: davinci-linux-open-source-bounces@linux.davincidsp.com
> [mailto:davinci-linux-open-source-bounces@linux.davincidsp.com] On Behalf
> Of Phaneendra kumar
> Sent: Wednesday, July 29, 2009 8:57 AM
> To: davinci-linux-open-source@linux.davincidsp.com
> Subject: DM355 SDIO support
> 
> 
> Hi all,
> 
> This patch will add SDIO support to the DM355 host controller driver.
> 
> I have verified this on DM355 EVM board in both DMA and PIO modes. And i
> have used open source libertas driver for verifying the SDIO
> functionality.
> 
> Signed-off-by: Phaneendra Kumar <phani@embwise.com>
> -----
> diff --git a/drivers/mmc/host/davinci_mmc.c
> b/drivers/mmc/host/davinci_mmc.c
> index 8907b72..0744059 100644
> --- a/drivers/mmc/host/davinci_mmc.c
> +++ b/drivers/mmc/host/davinci_mmc.c
> @@ -31,6 +31,8 @@
>  #include <linux/delay.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/mmc/mmc.h>
> +#include <linux/timer.h>
> +#include <linux/mmc/card.h>
> 
>  #include <mach/mmc.h>
>  #include <mach/edma.h>
> @@ -65,8 +67,8 @@
>  #define DAVINCI_MMCBLNC      0x60
>  #define DAVINCI_SDIOCTL      0x64
>  #define DAVINCI_SDIOST0      0x68
> -#define DAVINCI_SDIOEN       0x6C
> -#define DAVINCI_SDIOST       0x70
> +#define DAVINCI_SDIOIEN      0x6C
> +#define DAVINCI_SDIOIST      0x70
>  #define DAVINCI_MMCFIFOCTL   0x74 /* FIFO Control Register             */
> 
>  /* DAVINCI_MMCCTL definitions */
> @@ -133,6 +135,23 @@
>  /* MMCSD Init clock in Hz in opendrain mode */
>  #define MMCSD_INIT_CLOCK		200000
> 
> +/* DAVINCI_SDIOCTL definitions */
> +#define SDIOCTL_RDWTRQ_SET	  (1 << 0)
> +#define SDIOCTL_RDWTCR_SET	  (1 << 0)
> +
> +/* DAVINCI_SDIOST0 definitions */
> +#define SDIOST0_DAT1_HI		  (1 << 0)
> +#define SDIOST0_INTPRD		  (1 << 1)
> +#define SDIOST0_RDWTST		  (1 << 2)
> +
> +/* DAVINCI_SDIOIEN definitions */
> +#define SDIOIEN_IOINTEN		  (1 << 0)
> +#define SDIOIEN_RWSEN		  (1 << 1)
> +
> +/* DAVINCI_SDIOIST definitions */
> +#define SDIOIST_IOINT		  (1 << 0)
> +#define SDIOIST_RWS			  (1 << 1)
> +
>  /*
>   * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
>   * and we handle up to NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
> @@ -181,6 +200,10 @@ struct mmc_davinci_host {
>  	u32 rxdma, txdma;
>  	bool use_dma;
>  	bool do_dma;
> +	struct timer_list sdio_timer;
> +	u32 sdioInt;
> +	/* For sdio irq enabling and disabling */
> +	spinlock_t sdio_lock;
> 
>  	/* Scatterlist DMA uses one or more parameter RAM entries:
>  	 * the main one (associated with rxdma or txdma) plus zero or
> @@ -202,6 +225,41 @@ struct mmc_davinci_host {
>  	unsigned ns_in_one_cycle;
>  };
> 
> +static void mmc_enable_sdio_irq(struct mmc_host *mmc, int enable);
> +
> +static inline void davinci_sdio_intr_chck(struct mmc_davinci_host *host)
> +{
> +	if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
> +		if (!((readl(host->base + DAVINCI_SDIOST0)) & SDIOST0_DAT1_HI)
> +				&& host->sdioInt) {
> +			writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
> +			mmc_signal_sdio_irq(host->mmc);
> +		}
> +	}
> +}
> +
> +static inline void davinci_cmd_dat_reset(struct mmc_davinci_host *host)
> +{
> +	u32 temp = 0;
> +
> +	if (host->mmc->card) {
> +		if (mmc_card_sdio(host->mmc->card)) {
> +			temp = readl(host->base + DAVINCI_MMCCTL);
> +			writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST,
> +					host->base + DAVINCI_MMCCTL);
> +
> +			temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
> +			writel(temp, host->base + DAVINCI_MMCCTL);
> +		}
> +	}
> +}
> +
> +static void davinci_sdio_timer(unsigned long data)
> +{
> +	struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
> +
> +	davinci_sdio_intr_chck(host);
> +}
> 
>  /* PIO only */
>  static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
> @@ -387,6 +445,15 @@ static void mmc_davinci_dma_cb(unsigned channel, u16
> ch_status, void *data)
>  	if (DMA_COMPLETE != ch_status) {
>  		struct mmc_davinci_host *host = data;
> 
> +		if (!(host->data)) {
> +			printk(KERN_ERR "DMA Event Miss / NULL Transfr\n");
> +			edma_stop(host->txdma);
> +			edma_clean_channel(host->txdma);
> +			edma_stop(host->rxdma);
> +			edma_clean_channel(host->rxdma);
> +			return;
> +		}
> +
>  		/* Currently means:  DMA Event Missed, or "null" transfer
>  		 * request was seen.  In the future, TC errors (like bad
>  		 * addresses) might be presented too.
> @@ -664,6 +731,14 @@ mmc_davinci_prepare_data(struct mmc_davinci_host
> *host, struct mmc_request *req)
>  	host->buffer = NULL;
>  	host->bytes_left = data->blocks * data->blksz;
> 
> +	if (host->mmc->card) {
> +		if (mmc_card_sdio(host->mmc->card)) {
> +			if (data->blksz == 64) {
> +				mdelay(5);
> +			}
> +		}
> +	}
> +
>  	/* For now we try to use DMA whenever we won't need partial FIFO
>  	 * reads or writes, either for the whole transfer (as tested here)
>  	 * or for any individual scatterlist segment (tested when we call
> @@ -706,6 +781,8 @@ static void mmc_davinci_request(struct mmc_host *mmc,
> struct mmc_request *req)
>  		return;
>  	}
> 
> +	davinci_cmd_dat_reset(host);
> +
>  	host->do_dma = 0;
>  	mmc_davinci_prepare_data(host, req);
>  	mmc_davinci_start_command(host, req->cmd);
> @@ -826,12 +903,9 @@ static void mmc_davinci_set_ios(struct mmc_host *mmc,
> struct mmc_ios *ios)
>  static void
>  mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data
> *data)
>  {
> -	host->data = NULL;
> -	host->data_dir = DAVINCI_MMC_DATADIR_NONE;
> +	davinci_abort_dma(host);
> 
>  	if (host->do_dma) {
> -		davinci_abort_dma(host);
> -
>  		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
>  			     (data->flags & MMC_DATA_WRITE)
>  			     ? DMA_TO_DEVICE
> @@ -839,11 +913,18 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host,
> struct mmc_data *data)
>  		host->do_dma = false;
>  	}
> 
> +	host->data = NULL;
> +	host->data_dir = DAVINCI_MMC_DATADIR_NONE;
> +
> +	davinci_cmd_dat_reset(host);
> +
>  	if (!data->stop || (host->cmd && host->cmd->error)) {
>  		mmc_request_done(host->mmc, data->mrq);
>  		writel(0, host->base + DAVINCI_MMCIM);
>  	} else
>  		mmc_davinci_start_command(host, data->stop);
> +
> +	davinci_sdio_intr_chck(host);
>  }
> 
>  static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
> @@ -870,6 +951,7 @@ static void mmc_davinci_cmd_done(struct
> mmc_davinci_host *host,
>  		mmc_request_done(host->mmc, cmd->mrq);
>  		writel(0, host->base + DAVINCI_MMCIM);
>  	}
> +	davinci_sdio_intr_chck(host);
>  }
> 
>  static void
> @@ -895,6 +977,17 @@ static irqreturn_t mmc_davinci_irq(int irq, void
> *dev_id)
>  	int end_transfer = 0;
>  	struct mmc_data *data = host->data;
> 
> +	if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
> +		status = readl(host->base + DAVINCI_SDIOIST);
> +		if (status & SDIOIST_IOINT) {
> +			dev_dbg(mmc_dev(host->mmc),
> +					"SDIO interrupt status %x\n", status);
> +			writel(status | SDIOIST_IOINT,
> +					host->base + DAVINCI_SDIOIST);
> +			mmc_signal_sdio_irq(host->mmc);
> +		}
> +	}
> +
>  	if (host->cmd == NULL && host->data == NULL) {
>  		status = readl(host->base + DAVINCI_MMCST0);
>  		dev_dbg(mmc_dev(host->mmc),
> @@ -904,6 +997,7 @@ static irqreturn_t mmc_davinci_irq(int irq, void
> *dev_id)
>  		return IRQ_NONE;
>  	}
> 
> +	davinci_sdio_intr_chck(host);
>  	status = readl(host->base + DAVINCI_MMCST0);
>  	qstatus = status;
> 
> @@ -1031,11 +1125,41 @@ static int mmc_davinci_get_ro(struct mmc_host
> *mmc)
>  	return config->get_ro(pdev->id);
>  }
> 
> +static void mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> +{
> +	struct mmc_davinci_host *host = mmc_priv(mmc);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&host->sdio_lock, flags);
> +
> +	if (enable) {
> +		if (!((readl(host->base + DAVINCI_SDIOST0))
> +			    & SDIOST0_DAT1_HI)) {
> +			writel(SDIOIST_IOINT,
> +					host->base + DAVINCI_SDIOIST);
> +			mmc_signal_sdio_irq(host->mmc);
> +		}else {
> +			host->sdioInt = 1;
> +			mod_timer(&host->sdio_timer, jiffies + (HZ/100));
> +			writel(readl(host->base + DAVINCI_SDIOIEN) |
> +				SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN);
> +		}
> +	} else {
> +		host->sdioInt = 0;
> +		del_timer(&host->sdio_timer);
> +		writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN,
> +				host->base + DAVINCI_SDIOIEN);
> +	}
> +
> +	spin_unlock_irqrestore(&host->sdio_lock, flags);
> +}
> +
>  static struct mmc_host_ops mmc_davinci_ops = {
>  	.request	= mmc_davinci_request,
>  	.set_ios	= mmc_davinci_set_ios,
>  	.get_cd		= mmc_davinci_get_cd,
>  	.get_ro		= mmc_davinci_get_ro,
> +	.enable_sdio_irq	= mmc_enable_sdio_irq,
>  };
> 
>  /*----------------------------------------------------------------------
> */
> @@ -1132,6 +1256,12 @@ static int __init davinci_mmcsd_probe(struct
> platform_device *pdev)
>  	/* REVISIT:  someday, support IRQ-driven card detection.  */
>  	mmc->caps |= MMC_CAP_NEEDS_POLL;
> 
> +	mmc->caps |= MMC_CAP_SDIO_IRQ;
> +	spin_lock_init(&host->sdio_lock);
> +	setup_timer(&host->sdio_timer, davinci_sdio_timer,
> +		 (unsigned long)host);
> +	host->sdioInt = 0;
> +
>  	if (!pdata || pdata->wires == 4 || pdata->wires == 0)
>  		mmc->caps |= MMC_CAP_4_BIT_DATA;
> 
> _______________________________________________
> Davinci-linux-open-source mailing list
> Davinci-linux-open-source@linux.davincidsp.com
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
Sekhar Nori July 29, 2009, 4:15 p.m. UTC | #2
Hello Phaneendra,

On Wed, Jul 29, 2009 at 18:26:49, Phaneendra kumar wrote:
>
> Hi all,
>
> This patch will add SDIO support to the DM355 host controller driver.
>
> I have verified this on DM355 EVM board in both DMA and PIO modes. And i have used open source libertas driver for verifying the SDIO functionality.
>
> Signed-off-by: Phaneendra Kumar <phani@embwise.com>
> -----
> diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
> index 8907b72..0744059 100644
> --- a/drivers/mmc/host/davinci_mmc.c
> +++ b/drivers/mmc/host/davinci_mmc.c
> @@ -31,6 +31,8 @@
[..]
> +/* DAVINCI_SDIOCTL definitions */
> +#define SDIOCTL_RDWTRQ_SET     (1 << 0)
> +#define SDIOCTL_RDWTCR_SET     (1 << 0)
> +
> +/* DAVINCI_SDIOST0 definitions */
> +#define SDIOST0_DAT1_HI                (1 << 0)
> +#define SDIOST0_INTPRD                 (1 << 1)
> +#define SDIOST0_RDWTST                 (1 << 2)
> +
> +/* DAVINCI_SDIOIEN definitions */
> +#define SDIOIEN_IOINTEN                (1 << 0)
> +#define SDIOIEN_RWSEN                  (1 << 1)
> +
> +/* DAVINCI_SDIOIST definitions */
> +#define SDIOIST_IOINT                  (1 << 0)
> +#define SDIOIST_RWS                    (1 << 1)

The comments are superfluous also please use BIT(x)

> +
>  /*
>   * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
>   * and we handle up to NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
> @@ -181,6 +200,10 @@ struct mmc_davinci_host {
>       u32 rxdma, txdma;
>       bool use_dma;
>       bool do_dma;
> +     struct timer_list sdio_timer;
> +     u32 sdioInt;

CamelCase..

> +     /* For sdio irq enabling and disabling */
> +     spinlock_t sdio_lock;

Why spin lock just to disable SDIO irq? May be comment
needs correction?

>
>       /* Scatterlist DMA uses one or more parameter RAM entries:
>        * the main one (associated with rxdma or txdma) plus zero or
> @@ -202,6 +225,41 @@ struct mmc_davinci_host {
>       unsigned ns_in_one_cycle;
>  };
>
> +static void mmc_enable_sdio_irq(struct mmc_host *mmc, int enable);

Declaring a static function should not typically
be needed.

> +
> +static inline void davinci_sdio_intr_chck(struct mmc_davinci_host *host)
> +{
> +     if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
> +             if (!((readl(host->base + DAVINCI_SDIOST0)) & SDIOST0_DAT1_HI)
> +                             && host->sdioInt) {

May be using host->sdioInt as the first operand to &&
will save a register read in case sdioInt is not enabled?

> +                     writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
> +                     mmc_signal_sdio_irq(host->mmc);
> +             }
> +     }
> +}
> +
> +static inline void davinci_cmd_dat_reset(struct mmc_davinci_host *host)
> +{
> +     u32 temp = 0;
> +
> +     if (host->mmc->card) {
> +             if (mmc_card_sdio(host->mmc->card)) {
> +                     temp = readl(host->base + DAVINCI_MMCCTL);
> +                     writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST,
> +                                     host->base + DAVINCI_MMCCTL);
> +
> +                     temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
> +                     writel(temp, host->base + DAVINCI_MMCCTL);
> +             }
> +     }
> +}
> +
> +static void davinci_sdio_timer(unsigned long data)
> +{
> +     struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
> +
> +     davinci_sdio_intr_chck(host);

Can eliminate 'host' variable.

> +}
>
>  /* PIO only */
>  static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
> @@ -387,6 +445,15 @@ static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void *data)
>       if (DMA_COMPLETE != ch_status) {
>               struct mmc_davinci_host *host = data;
>
> +             if (!(host->data)) {
> +                     printk(KERN_ERR "DMA Event Miss / NULL Transfr\n");
> +                     edma_stop(host->txdma);
> +                     edma_clean_channel(host->txdma);
> +                     edma_stop(host->rxdma);
> +                     edma_clean_channel(host->rxdma);
> +                     return;
> +             }
> +
>               /* Currently means:  DMA Event Missed, or "null" transfer
>                * request was seen.  In the future, TC errors (like bad
>                * addresses) might be presented too.
> @@ -664,6 +731,14 @@ mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)
>       host->buffer = NULL;
>       host->bytes_left = data->blocks * data->blksz;
>
> +     if (host->mmc->card) {
> +             if (mmc_card_sdio(host->mmc->card)) {
> +                     if (data->blksz == 64) {
> +                             mdelay(5);
> +                     }

Can you include a comment explaining why the delay
is needed? Please include a reference to spru section
if applicable.

> +             }
> +     }
> +
>       /* For now we try to use DMA whenever we won't need partial FIFO
>        * reads or writes, either for the whole transfer (as tested here)
>        * or for any individual scatterlist segment (tested when we call
> @@ -706,6 +781,8 @@ static void mmc_davinci_request(struct mmc_host *mmc, struct mmc_request *req)
>               return;
>       }
>
> +     davinci_cmd_dat_reset(host);
> +
>       host->do_dma = 0;
>       mmc_davinci_prepare_data(host, req);
>       mmc_davinci_start_command(host, req->cmd);
> @@ -826,12 +903,9 @@ static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
>  static void
>  mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
>  {
> -     host->data = NULL;
> -     host->data_dir = DAVINCI_MMC_DATADIR_NONE;
> +     davinci_abort_dma(host);
>
>       if (host->do_dma) {
> -             davinci_abort_dma(host);
> -
>               dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
>                            (data->flags & MMC_DATA_WRITE)
>                            ? DMA_TO_DEVICE
> @@ -839,11 +913,18 @@ mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
>               host->do_dma = false;
>       }
>
> +     host->data = NULL;
> +     host->data_dir = DAVINCI_MMC_DATADIR_NONE;
> +
> +     davinci_cmd_dat_reset(host);
> +
>       if (!data->stop || (host->cmd && host->cmd->error)) {
>               mmc_request_done(host->mmc, data->mrq);
>               writel(0, host->base + DAVINCI_MMCIM);
>       } else
>               mmc_davinci_start_command(host, data->stop);
> +
> +     davinci_sdio_intr_chck(host);
>  }
>
>  static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
> @@ -870,6 +951,7 @@ static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
>               mmc_request_done(host->mmc, cmd->mrq);
>               writel(0, host->base + DAVINCI_MMCIM);
>       }
> +     davinci_sdio_intr_chck(host);
>  }
>
>  static void
> @@ -895,6 +977,17 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
>       int end_transfer = 0;
>       struct mmc_data *data = host->data;
>
> +     if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
> +             status = readl(host->base + DAVINCI_SDIOIST);
> +             if (status & SDIOIST_IOINT) {
> +                     dev_dbg(mmc_dev(host->mmc),
> +                                     "SDIO interrupt status %x\n", status);
> +                     writel(status | SDIOIST_IOINT,
> +                                     host->base + DAVINCI_SDIOIST);
> +                     mmc_signal_sdio_irq(host->mmc);
> +             }
> +     }
> +
>       if (host->cmd == NULL && host->data == NULL) {
>               status = readl(host->base + DAVINCI_MMCST0);
>               dev_dbg(mmc_dev(host->mmc),
> @@ -904,6 +997,7 @@ static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
>               return IRQ_NONE;
>       }
>
> +     davinci_sdio_intr_chck(host);
>       status = readl(host->base + DAVINCI_MMCST0);
>       qstatus = status;
>
> @@ -1031,11 +1125,41 @@ static int mmc_davinci_get_ro(struct mmc_host *mmc)
>       return config->get_ro(pdev->id);
>  }
>
> +static void mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> +{
> +     struct mmc_davinci_host *host = mmc_priv(mmc);
> +     unsigned long flags;
> +
> +     spin_lock_irqsave(&host->sdio_lock, flags);
> +
> +     if (enable) {
> +             if (!((readl(host->base + DAVINCI_SDIOST0))
> +                         & SDIOST0_DAT1_HI)) {
> +                     writel(SDIOIST_IOINT,
> +                                     host->base + DAVINCI_SDIOIST);
> +                     mmc_signal_sdio_irq(host->mmc);
> +             }else {
> +                     host->sdioInt = 1;
> +                     mod_timer(&host->sdio_timer, jiffies + (HZ/100));
> +                     writel(readl(host->base + DAVINCI_SDIOIEN) |
> +                             SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN);
> +             }
> +     } else {
> +             host->sdioInt = 0;
> +             del_timer(&host->sdio_timer);
> +             writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN,
> +                             host->base + DAVINCI_SDIOIEN);
> +     }

Why not setup & add the timer here itself if enable == TRUE?

I don't understand the hardware, but a timer task every jiffy
will affect power management support in future.

> +
> +     spin_unlock_irqrestore(&host->sdio_lock, flags);
> +}
> +
>  static struct mmc_host_ops mmc_davinci_ops = {
>       .request        = mmc_davinci_request,
>       .set_ios        = mmc_davinci_set_ios,
>       .get_cd         = mmc_davinci_get_cd,
>       .get_ro         = mmc_davinci_get_ro,
> +     .enable_sdio_irq        = mmc_enable_sdio_irq,
>  };
>
>  /*----------------------------------------------------------------------*/
> @@ -1132,6 +1256,12 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
>       /* REVISIT:  someday, support IRQ-driven card detection.  */
>       mmc->caps |= MMC_CAP_NEEDS_POLL;
>
> +     mmc->caps |= MMC_CAP_SDIO_IRQ;
> +     spin_lock_init(&host->sdio_lock);
> +     setup_timer(&host->sdio_timer, davinci_sdio_timer,
> +              (unsigned long)host);

Does the timer need to be deleted on module exit or
is that taken care by mmc_enable_sdio_irq() itself?

Thanks,
Sekhar

> +     host->sdioInt = 0;
> +
>       if (!pdata || pdata->wires == 4 || pdata->wires == 0)
>               mmc->caps |= MMC_CAP_4_BIT_DATA;
>
> _______________________________________________
> Davinci-linux-open-source mailing list
> Davinci-linux-open-source@linux.davincidsp.com
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
>
Phaneendra kumar Aug. 6, 2009, 2:36 p.m. UTC | #3
Thanks for the valuable inputs. I have made some modifications to the
davinci host controller driver and to the MMC frame work. I will send the
patches soon and also ensure to follow the community guidelines from now on.

-Phaneedra Kumar.A

2009/7/29 Nori, Sekhar <nsekhar@ti.com>

> Hello Phaneendra,
>
> On Wed, Jul 29, 2009 at 18:26:49, Phaneendra kumar wrote:
> >
> > Hi all,
> >
> > This patch will add SDIO support to the DM355 host controller driver.
> >
> > I have verified this on DM355 EVM board in both DMA and PIO modes. And i
> have used open source libertas driver for verifying the SDIO functionality.
> >
> > Signed-off-by: Phaneendra Kumar <phani@embwise.com>
> > -----
> > diff --git a/drivers/mmc/host/davinci_mmc.c
> b/drivers/mmc/host/davinci_mmc.c
> > index 8907b72..0744059 100644
> > --- a/drivers/mmc/host/davinci_mmc.c
> > +++ b/drivers/mmc/host/davinci_mmc.c
> > @@ -31,6 +31,8 @@
> [..]
> > +/* DAVINCI_SDIOCTL definitions */
> > +#define SDIOCTL_RDWTRQ_SET     (1 << 0)
> > +#define SDIOCTL_RDWTCR_SET     (1 << 0)
> > +
> > +/* DAVINCI_SDIOST0 definitions */
> > +#define SDIOST0_DAT1_HI                (1 << 0)
> > +#define SDIOST0_INTPRD                 (1 << 1)
> > +#define SDIOST0_RDWTST                 (1 << 2)
> > +
> > +/* DAVINCI_SDIOIEN definitions */
> > +#define SDIOIEN_IOINTEN                (1 << 0)
> > +#define SDIOIEN_RWSEN                  (1 << 1)
> > +
> > +/* DAVINCI_SDIOIST definitions */
> > +#define SDIOIST_IOINT                  (1 << 0)
> > +#define SDIOIST_RWS                    (1 << 1)
>
> The comments are superfluous also please use BIT(x)
>
> > +
> >  /*
> >   * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
> >   * and we handle up to NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
> > @@ -181,6 +200,10 @@ struct mmc_davinci_host {
> >       u32 rxdma, txdma;
> >       bool use_dma;
> >       bool do_dma;
> > +     struct timer_list sdio_timer;
> > +     u32 sdioInt;
>
> CamelCase..
>
> > +     /* For sdio irq enabling and disabling */
> > +     spinlock_t sdio_lock;
>
> Why spin lock just to disable SDIO irq? May be comment
> needs correction?
>
> >
> >       /* Scatterlist DMA uses one or more parameter RAM entries:
> >        * the main one (associated with rxdma or txdma) plus zero or
> > @@ -202,6 +225,41 @@ struct mmc_davinci_host {
> >       unsigned ns_in_one_cycle;
> >  };
> >
> > +static void mmc_enable_sdio_irq(struct mmc_host *mmc, int enable);
>
> Declaring a static function should not typically
> be needed.
>
> > +
> > +static inline void davinci_sdio_intr_chck(struct mmc_davinci_host *host)
> > +{
> > +     if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
> > +             if (!((readl(host->base + DAVINCI_SDIOST0)) &
> SDIOST0_DAT1_HI)
> > +                             && host->sdioInt) {
>
> May be using host->sdioInt as the first operand to &&
> will save a register read in case sdioInt is not enabled?
>
> > +                     writel(SDIOIST_IOINT, host->base +
> DAVINCI_SDIOIST);
> > +                     mmc_signal_sdio_irq(host->mmc);
> > +             }
> > +     }
> > +}
> > +
> > +static inline void davinci_cmd_dat_reset(struct mmc_davinci_host *host)
> > +{
> > +     u32 temp = 0;
> > +
> > +     if (host->mmc->card) {
> > +             if (mmc_card_sdio(host->mmc->card)) {
> > +                     temp = readl(host->base + DAVINCI_MMCCTL);
> > +                     writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST,
> > +                                     host->base + DAVINCI_MMCCTL);
> > +
> > +                     temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
> > +                     writel(temp, host->base + DAVINCI_MMCCTL);
> > +             }
> > +     }
> > +}
> > +
> > +static void davinci_sdio_timer(unsigned long data)
> > +{
> > +     struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
> > +
> > +     davinci_sdio_intr_chck(host);
>
> Can eliminate 'host' variable.
>
> > +}
> >
> >  /* PIO only */
> >  static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
> > @@ -387,6 +445,15 @@ static void mmc_davinci_dma_cb(unsigned channel, u16
> ch_status, void *data)
> >       if (DMA_COMPLETE != ch_status) {
> >               struct mmc_davinci_host *host = data;
> >
> > +             if (!(host->data)) {
> > +                     printk(KERN_ERR "DMA Event Miss / NULL Transfr\n");
> > +                     edma_stop(host->txdma);
> > +                     edma_clean_channel(host->txdma);
> > +                     edma_stop(host->rxdma);
> > +                     edma_clean_channel(host->rxdma);
> > +                     return;
> > +             }
> > +
> >               /* Currently means:  DMA Event Missed, or "null" transfer
> >                * request was seen.  In the future, TC errors (like bad
> >                * addresses) might be presented too.
> > @@ -664,6 +731,14 @@ mmc_davinci_prepare_data(struct mmc_davinci_host
> *host, struct mmc_request *req)
> >       host->buffer = NULL;
> >       host->bytes_left = data->blocks * data->blksz;
> >
> > +     if (host->mmc->card) {
> > +             if (mmc_card_sdio(host->mmc->card)) {
> > +                     if (data->blksz == 64) {
> > +                             mdelay(5);
> > +                     }
>
> Can you include a comment explaining why the delay
> is needed? Please include a reference to spru section
> if applicable.
>
> > +             }
> > +     }
> > +
> >       /* For now we try to use DMA whenever we won't need partial FIFO
> >        * reads or writes, either for the whole transfer (as tested here)
> >        * or for any individual scatterlist segment (tested when we call
> > @@ -706,6 +781,8 @@ static void mmc_davinci_request(struct mmc_host *mmc,
> struct mmc_request *req)
> >               return;
> >       }
> >
> > +     davinci_cmd_dat_reset(host);
> > +
> >       host->do_dma = 0;
> >       mmc_davinci_prepare_data(host, req);
> >       mmc_davinci_start_command(host, req->cmd);
> > @@ -826,12 +903,9 @@ static void mmc_davinci_set_ios(struct mmc_host
> *mmc, struct mmc_ios *ios)
> >  static void
> >  mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data
> *data)
> >  {
> > -     host->data = NULL;
> > -     host->data_dir = DAVINCI_MMC_DATADIR_NONE;
> > +     davinci_abort_dma(host);
> >
> >       if (host->do_dma) {
> > -             davinci_abort_dma(host);
> > -
> >               dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
> >                            (data->flags & MMC_DATA_WRITE)
> >                            ? DMA_TO_DEVICE
> > @@ -839,11 +913,18 @@ mmc_davinci_xfer_done(struct mmc_davinci_host
> *host, struct mmc_data *data)
> >               host->do_dma = false;
> >       }
> >
> > +     host->data = NULL;
> > +     host->data_dir = DAVINCI_MMC_DATADIR_NONE;
> > +
> > +     davinci_cmd_dat_reset(host);
> > +
> >       if (!data->stop || (host->cmd && host->cmd->error)) {
> >               mmc_request_done(host->mmc, data->mrq);
> >               writel(0, host->base + DAVINCI_MMCIM);
> >       } else
> >               mmc_davinci_start_command(host, data->stop);
> > +
> > +     davinci_sdio_intr_chck(host);
> >  }
> >
> >  static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
> > @@ -870,6 +951,7 @@ static void mmc_davinci_cmd_done(struct
> mmc_davinci_host *host,
> >               mmc_request_done(host->mmc, cmd->mrq);
> >               writel(0, host->base + DAVINCI_MMCIM);
> >       }
> > +     davinci_sdio_intr_chck(host);
> >  }
> >
> >  static void
> > @@ -895,6 +977,17 @@ static irqreturn_t mmc_davinci_irq(int irq, void
> *dev_id)
> >       int end_transfer = 0;
> >       struct mmc_data *data = host->data;
> >
> > +     if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
> > +             status = readl(host->base + DAVINCI_SDIOIST);
> > +             if (status & SDIOIST_IOINT) {
> > +                     dev_dbg(mmc_dev(host->mmc),
> > +                                     "SDIO interrupt status %x\n",
> status);
> > +                     writel(status | SDIOIST_IOINT,
> > +                                     host->base + DAVINCI_SDIOIST);
> > +                     mmc_signal_sdio_irq(host->mmc);
> > +             }
> > +     }
> > +
> >       if (host->cmd == NULL && host->data == NULL) {
> >               status = readl(host->base + DAVINCI_MMCST0);
> >               dev_dbg(mmc_dev(host->mmc),
> > @@ -904,6 +997,7 @@ static irqreturn_t mmc_davinci_irq(int irq, void
> *dev_id)
> >               return IRQ_NONE;
> >       }
> >
> > +     davinci_sdio_intr_chck(host);
> >       status = readl(host->base + DAVINCI_MMCST0);
> >       qstatus = status;
> >
> > @@ -1031,11 +1125,41 @@ static int mmc_davinci_get_ro(struct mmc_host
> *mmc)
> >       return config->get_ro(pdev->id);
> >  }
> >
> > +static void mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
> > +{
> > +     struct mmc_davinci_host *host = mmc_priv(mmc);
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&host->sdio_lock, flags);
> > +
> > +     if (enable) {
> > +             if (!((readl(host->base + DAVINCI_SDIOST0))
> > +                         & SDIOST0_DAT1_HI)) {
> > +                     writel(SDIOIST_IOINT,
> > +                                     host->base + DAVINCI_SDIOIST);
> > +                     mmc_signal_sdio_irq(host->mmc);
> > +             }else {
> > +                     host->sdioInt = 1;
> > +                     mod_timer(&host->sdio_timer, jiffies + (HZ/100));
> > +                     writel(readl(host->base + DAVINCI_SDIOIEN) |
> > +                             SDIOIEN_IOINTEN, host->base +
> DAVINCI_SDIOIEN);
> > +             }
> > +     } else {
> > +             host->sdioInt = 0;
> > +             del_timer(&host->sdio_timer);
> > +             writel(readl(host->base + DAVINCI_SDIOIEN) &
> ~SDIOIEN_IOINTEN,
> > +                             host->base + DAVINCI_SDIOIEN);
> > +     }
>
> Why not setup & add the timer here itself if enable == TRUE?
>
> I don't understand the hardware, but a timer task every jiffy
> will affect power management support in future.
>
> > +
> > +     spin_unlock_irqrestore(&host->sdio_lock, flags);
> > +}
> > +
> >  static struct mmc_host_ops mmc_davinci_ops = {
> >       .request        = mmc_davinci_request,
> >       .set_ios        = mmc_davinci_set_ios,
> >       .get_cd         = mmc_davinci_get_cd,
> >       .get_ro         = mmc_davinci_get_ro,
> > +     .enable_sdio_irq        = mmc_enable_sdio_irq,
> >  };
> >
> >
>  /*----------------------------------------------------------------------*/
> > @@ -1132,6 +1256,12 @@ static int __init davinci_mmcsd_probe(struct
> platform_device *pdev)
> >       /* REVISIT:  someday, support IRQ-driven card detection.  */
> >       mmc->caps |= MMC_CAP_NEEDS_POLL;
> >
> > +     mmc->caps |= MMC_CAP_SDIO_IRQ;
> > +     spin_lock_init(&host->sdio_lock);
> > +     setup_timer(&host->sdio_timer, davinci_sdio_timer,
> > +              (unsigned long)host);
>
> Does the timer need to be deleted on module exit or
> is that taken care by mmc_enable_sdio_irq() itself?
>
> Thanks,
> Sekhar
>
> > +     host->sdioInt = 0;
> > +
> >       if (!pdata || pdata->wires == 4 || pdata->wires == 0)
> >               mmc->caps |= MMC_CAP_4_BIT_DATA;
> >
> > _______________________________________________
> > Davinci-linux-open-source mailing list
> > Davinci-linux-open-source@linux.davincidsp.com
> > http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
> >
>
>
>
diff mbox

Patch

diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 8907b72..0744059 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -31,6 +31,8 @@ 
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/mmc/mmc.h>
+#include <linux/timer.h>
+#include <linux/mmc/card.h>
 
 #include <mach/mmc.h>
 #include <mach/edma.h>
@@ -65,8 +67,8 @@ 
 #define DAVINCI_MMCBLNC      0x60
 #define DAVINCI_SDIOCTL      0x64
 #define DAVINCI_SDIOST0      0x68
-#define DAVINCI_SDIOEN       0x6C
-#define DAVINCI_SDIOST       0x70
+#define DAVINCI_SDIOIEN      0x6C
+#define DAVINCI_SDIOIST      0x70
 #define DAVINCI_MMCFIFOCTL   0x74 /* FIFO Control Register             */
 
 /* DAVINCI_MMCCTL definitions */
@@ -133,6 +135,23 @@ 
 /* MMCSD Init clock in Hz in opendrain mode */
 #define MMCSD_INIT_CLOCK		200000
 
+/* DAVINCI_SDIOCTL definitions */
+#define SDIOCTL_RDWTRQ_SET	  (1 << 0)
+#define SDIOCTL_RDWTCR_SET	  (1 << 0)
+
+/* DAVINCI_SDIOST0 definitions */
+#define SDIOST0_DAT1_HI		  (1 << 0)
+#define SDIOST0_INTPRD		  (1 << 1)
+#define SDIOST0_RDWTST		  (1 << 2)
+
+/* DAVINCI_SDIOIEN definitions */
+#define SDIOIEN_IOINTEN		  (1 << 0)
+#define SDIOIEN_RWSEN		  (1 << 1)
+
+/* DAVINCI_SDIOIST definitions */
+#define SDIOIST_IOINT		  (1 << 0)
+#define SDIOIST_RWS			  (1 << 1)
+
 /*
  * One scatterlist dma "segment" is at most MAX_CCNT rw_threshold units,
  * and we handle up to NR_SG segments.  MMC_BLOCK_BOUNCE kicks in only
@@ -181,6 +200,10 @@  struct mmc_davinci_host {
 	u32 rxdma, txdma;
 	bool use_dma;
 	bool do_dma;
+	struct timer_list sdio_timer;
+	u32 sdioInt;
+	/* For sdio irq enabling and disabling */
+	spinlock_t sdio_lock;
 
 	/* Scatterlist DMA uses one or more parameter RAM entries:
 	 * the main one (associated with rxdma or txdma) plus zero or
@@ -202,6 +225,41 @@  struct mmc_davinci_host {
 	unsigned ns_in_one_cycle;
 };
 
+static void mmc_enable_sdio_irq(struct mmc_host *mmc, int enable);
+
+static inline void davinci_sdio_intr_chck(struct mmc_davinci_host *host)
+{
+	if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
+		if (!((readl(host->base + DAVINCI_SDIOST0)) & SDIOST0_DAT1_HI)
+				&& host->sdioInt) {
+			writel(SDIOIST_IOINT, host->base + DAVINCI_SDIOIST);
+			mmc_signal_sdio_irq(host->mmc);
+		}
+	}
+}
+
+static inline void davinci_cmd_dat_reset(struct mmc_davinci_host *host)
+{
+	u32 temp = 0;
+
+	if (host->mmc->card) {
+		if (mmc_card_sdio(host->mmc->card)) {
+			temp = readl(host->base + DAVINCI_MMCCTL);
+			writel(temp | MMCCTL_CMDRST | MMCCTL_DATRST,
+					host->base + DAVINCI_MMCCTL);
+
+			temp &= ~(MMCCTL_CMDRST | MMCCTL_DATRST);
+			writel(temp, host->base + DAVINCI_MMCCTL);
+		}
+	}
+}
+
+static void davinci_sdio_timer(unsigned long data)
+{
+	struct mmc_davinci_host *host = (struct mmc_davinci_host *)data;
+
+	davinci_sdio_intr_chck(host);
+}
 
 /* PIO only */
 static void mmc_davinci_sg_to_buf(struct mmc_davinci_host *host)
@@ -387,6 +445,15 @@  static void mmc_davinci_dma_cb(unsigned channel, u16 ch_status, void *data)
 	if (DMA_COMPLETE != ch_status) {
 		struct mmc_davinci_host *host = data;
 
+		if (!(host->data)) {
+			printk(KERN_ERR "DMA Event Miss / NULL Transfr\n");
+			edma_stop(host->txdma);
+			edma_clean_channel(host->txdma);
+			edma_stop(host->rxdma);
+			edma_clean_channel(host->rxdma);
+			return;
+		}
+
 		/* Currently means:  DMA Event Missed, or "null" transfer
 		 * request was seen.  In the future, TC errors (like bad
 		 * addresses) might be presented too.
@@ -664,6 +731,14 @@  mmc_davinci_prepare_data(struct mmc_davinci_host *host, struct mmc_request *req)
 	host->buffer = NULL;
 	host->bytes_left = data->blocks * data->blksz;
 
+	if (host->mmc->card) {
+		if (mmc_card_sdio(host->mmc->card)) {
+			if (data->blksz == 64) {
+				mdelay(5);
+			}
+		}
+	}
+
 	/* For now we try to use DMA whenever we won't need partial FIFO
 	 * reads or writes, either for the whole transfer (as tested here)
 	 * or for any individual scatterlist segment (tested when we call
@@ -706,6 +781,8 @@  static void mmc_davinci_request(struct mmc_host *mmc, struct mmc_request *req)
 		return;
 	}
 
+	davinci_cmd_dat_reset(host);
+
 	host->do_dma = 0;
 	mmc_davinci_prepare_data(host, req);
 	mmc_davinci_start_command(host, req->cmd);
@@ -826,12 +903,9 @@  static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 static void
 mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
 {
-	host->data = NULL;
-	host->data_dir = DAVINCI_MMC_DATADIR_NONE;
+	davinci_abort_dma(host);
 
 	if (host->do_dma) {
-		davinci_abort_dma(host);
-
 		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
 			     (data->flags & MMC_DATA_WRITE)
 			     ? DMA_TO_DEVICE
@@ -839,11 +913,18 @@  mmc_davinci_xfer_done(struct mmc_davinci_host *host, struct mmc_data *data)
 		host->do_dma = false;
 	}
 
+	host->data = NULL;
+	host->data_dir = DAVINCI_MMC_DATADIR_NONE;
+
+	davinci_cmd_dat_reset(host);
+
 	if (!data->stop || (host->cmd && host->cmd->error)) {
 		mmc_request_done(host->mmc, data->mrq);
 		writel(0, host->base + DAVINCI_MMCIM);
 	} else
 		mmc_davinci_start_command(host, data->stop);
+
+	davinci_sdio_intr_chck(host);
 }
 
 static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
@@ -870,6 +951,7 @@  static void mmc_davinci_cmd_done(struct mmc_davinci_host *host,
 		mmc_request_done(host->mmc, cmd->mrq);
 		writel(0, host->base + DAVINCI_MMCIM);
 	}
+	davinci_sdio_intr_chck(host);
 }
 
 static void
@@ -895,6 +977,17 @@  static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
 	int end_transfer = 0;
 	struct mmc_data *data = host->data;
 
+	if (host->mmc->caps & MMC_CAP_SDIO_IRQ) {
+		status = readl(host->base + DAVINCI_SDIOIST);
+		if (status & SDIOIST_IOINT) {
+			dev_dbg(mmc_dev(host->mmc),
+					"SDIO interrupt status %x\n", status);
+			writel(status | SDIOIST_IOINT,
+					host->base + DAVINCI_SDIOIST);
+			mmc_signal_sdio_irq(host->mmc);
+		}
+	}
+
 	if (host->cmd == NULL && host->data == NULL) {
 		status = readl(host->base + DAVINCI_MMCST0);
 		dev_dbg(mmc_dev(host->mmc),
@@ -904,6 +997,7 @@  static irqreturn_t mmc_davinci_irq(int irq, void *dev_id)
 		return IRQ_NONE;
 	}
 
+	davinci_sdio_intr_chck(host);
 	status = readl(host->base + DAVINCI_MMCST0);
 	qstatus = status;
 
@@ -1031,11 +1125,41 @@  static int mmc_davinci_get_ro(struct mmc_host *mmc)
 	return config->get_ro(pdev->id);
 }
 
+static void mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+	struct mmc_davinci_host *host = mmc_priv(mmc);
+	unsigned long flags;
+
+	spin_lock_irqsave(&host->sdio_lock, flags);
+
+	if (enable) {
+		if (!((readl(host->base + DAVINCI_SDIOST0))
+			    & SDIOST0_DAT1_HI)) {
+			writel(SDIOIST_IOINT,
+					host->base + DAVINCI_SDIOIST);
+			mmc_signal_sdio_irq(host->mmc);
+		}else {
+			host->sdioInt = 1;
+			mod_timer(&host->sdio_timer, jiffies + (HZ/100));
+			writel(readl(host->base + DAVINCI_SDIOIEN) |
+				SDIOIEN_IOINTEN, host->base + DAVINCI_SDIOIEN);
+		}
+	} else {
+		host->sdioInt = 0;
+		del_timer(&host->sdio_timer);
+		writel(readl(host->base + DAVINCI_SDIOIEN) & ~SDIOIEN_IOINTEN,
+				host->base + DAVINCI_SDIOIEN);
+	}
+
+	spin_unlock_irqrestore(&host->sdio_lock, flags);
+}
+
 static struct mmc_host_ops mmc_davinci_ops = {
 	.request	= mmc_davinci_request,
 	.set_ios	= mmc_davinci_set_ios,
 	.get_cd		= mmc_davinci_get_cd,
 	.get_ro		= mmc_davinci_get_ro,
+	.enable_sdio_irq	= mmc_enable_sdio_irq,
 };
 
 /*----------------------------------------------------------------------*/
@@ -1132,6 +1256,12 @@  static int __init davinci_mmcsd_probe(struct platform_device *pdev)
 	/* REVISIT:  someday, support IRQ-driven card detection.  */
 	mmc->caps |= MMC_CAP_NEEDS_POLL;
 
+	mmc->caps |= MMC_CAP_SDIO_IRQ;
+	spin_lock_init(&host->sdio_lock);
+	setup_timer(&host->sdio_timer, davinci_sdio_timer,
+		 (unsigned long)host);
+	host->sdioInt = 0;
+
 	if (!pdata || pdata->wires == 4 || pdata->wires == 0)
 		mmc->caps |= MMC_CAP_4_BIT_DATA;