aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/mxcmmc.c
diff options
context:
space:
mode:
authorDaniel Mack <daniel@caiaq.de>2010-04-01 04:03:24 -0400
committerSascha Hauer <s.hauer@pengutronix.de>2010-04-14 03:18:07 -0400
commitf441b993101d4ee95222ccbaad1e0dd53ea90b64 (patch)
tree66f23ad023c7e06257b3c7f0a1f4b80dc02e4455 /drivers/mmc/host/mxcmmc.c
parent4725f6f17691f4602e3e31d785da5a461a16ccfe (diff)
ARM: MXC: mxcmmc: Teach the driver SDIO operations
Successfully tested on MX31 hardware using libertas SDIO peripherals. Signed-off-by: Daniel Mack <daniel@caiaq.de> Cc: Sascha Hauer <s.hauer@pengutronix.de> Cc: Dan Williams <dan.j.williams@intel.com> Cc: Volker Ernst <volker.ernst@txtr.com> Cc: Jiri Kosina <jkosina@suse.cz> Cc: Michał Mirosław <mirqus@gmail.com> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/mmc/host/mxcmmc.c')
-rw-r--r--drivers/mmc/host/mxcmmc.c70
1 files changed, 59 insertions, 11 deletions
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index 44a53ee5e21..51e880c8f19 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -119,6 +119,7 @@ struct mxcmci_host {
119 int detect_irq; 119 int detect_irq;
120 int dma; 120 int dma;
121 int do_dma; 121 int do_dma;
122 int use_sdio;
122 unsigned int power_mode; 123 unsigned int power_mode;
123 struct imxmmc_platform_data *pdata; 124 struct imxmmc_platform_data *pdata;
124 125
@@ -138,6 +139,7 @@ struct mxcmci_host {
138 int clock; 139 int clock;
139 140
140 struct work_struct datawork; 141 struct work_struct datawork;
142 spinlock_t lock;
141}; 143};
142 144
143static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); 145static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
@@ -226,6 +228,9 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
226static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, 228static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
227 unsigned int cmdat) 229 unsigned int cmdat)
228{ 230{
231 u32 int_cntr;
232 unsigned long flags;
233
229 WARN_ON(host->cmd != NULL); 234 WARN_ON(host->cmd != NULL);
230 host->cmd = cmd; 235 host->cmd = cmd;
231 236
@@ -249,12 +254,16 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
249 return -EINVAL; 254 return -EINVAL;
250 } 255 }
251 256
257 int_cntr = INT_END_CMD_RES_EN;
258
252 if (mxcmci_use_dma(host)) 259 if (mxcmci_use_dma(host))
253 writel(INT_READ_OP_EN | INT_WRITE_OP_DONE_EN | 260 int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN;
254 INT_END_CMD_RES_EN, 261
255 host->base + MMC_REG_INT_CNTR); 262 spin_lock_irqsave(&host->lock, flags);
256 else 263 if (host->use_sdio)
257 writel(INT_END_CMD_RES_EN, host->base + MMC_REG_INT_CNTR); 264 int_cntr |= INT_SDIO_IRQ_EN;
265 writel(int_cntr, host->base + MMC_REG_INT_CNTR);
266 spin_unlock_irqrestore(&host->lock, flags);
258 267
259 writew(cmd->opcode, host->base + MMC_REG_CMD); 268 writew(cmd->opcode, host->base + MMC_REG_CMD);
260 writel(cmd->arg, host->base + MMC_REG_ARG); 269 writel(cmd->arg, host->base + MMC_REG_ARG);
@@ -266,7 +275,14 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
266static void mxcmci_finish_request(struct mxcmci_host *host, 275static void mxcmci_finish_request(struct mxcmci_host *host,
267 struct mmc_request *req) 276 struct mmc_request *req)
268{ 277{
269 writel(0, host->base + MMC_REG_INT_CNTR); 278 u32 int_cntr = 0;
279 unsigned long flags;
280
281 spin_lock_irqsave(&host->lock, flags);
282 if (host->use_sdio)
283 int_cntr |= INT_SDIO_IRQ_EN;
284 writel(int_cntr, host->base + MMC_REG_INT_CNTR);
285 spin_unlock_irqrestore(&host->lock, flags);
270 286
271 host->req = NULL; 287 host->req = NULL;
272 host->cmd = NULL; 288 host->cmd = NULL;
@@ -532,15 +548,27 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
532static irqreturn_t mxcmci_irq(int irq, void *devid) 548static irqreturn_t mxcmci_irq(int irq, void *devid)
533{ 549{
534 struct mxcmci_host *host = devid; 550 struct mxcmci_host *host = devid;
551 unsigned long flags;
552 bool sdio_irq;
535 u32 stat; 553 u32 stat;
536 554
537 stat = readl(host->base + MMC_REG_STATUS); 555 stat = readl(host->base + MMC_REG_STATUS);
538 writel(stat, host->base + MMC_REG_STATUS); 556 writel(stat & ~STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
539 557
540 dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); 558 dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
541 559
560 spin_lock_irqsave(&host->lock, flags);
561 sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
562 spin_unlock_irqrestore(&host->lock, flags);
563
564 if (sdio_irq) {
565 writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS);
566 mmc_signal_sdio_irq(host->mmc);
567 }
568
542 if (stat & STATUS_END_CMD_RESP) 569 if (stat & STATUS_END_CMD_RESP)
543 mxcmci_cmd_done(host, stat); 570 mxcmci_cmd_done(host, stat);
571
544#ifdef HAS_DMA 572#ifdef HAS_DMA
545 if (mxcmci_use_dma(host) && 573 if (mxcmci_use_dma(host) &&
546 (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) 574 (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE)))
@@ -677,11 +705,30 @@ static int mxcmci_get_ro(struct mmc_host *mmc)
677 return -ENOSYS; 705 return -ENOSYS;
678} 706}
679 707
708static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable)
709{
710 struct mxcmci_host *host = mmc_priv(mmc);
711 unsigned long flags;
712 u32 int_cntr;
713
714 spin_lock_irqsave(&host->lock, flags);
715 host->use_sdio = enable;
716 int_cntr = readl(host->base + MMC_REG_INT_CNTR);
717
718 if (enable)
719 int_cntr |= INT_SDIO_IRQ_EN;
720 else
721 int_cntr &= ~INT_SDIO_IRQ_EN;
722
723 writel(int_cntr, host->base + MMC_REG_INT_CNTR);
724 spin_unlock_irqrestore(&host->lock, flags);
725}
680 726
681static const struct mmc_host_ops mxcmci_ops = { 727static const struct mmc_host_ops mxcmci_ops = {
682 .request = mxcmci_request, 728 .request = mxcmci_request,
683 .set_ios = mxcmci_set_ios, 729 .set_ios = mxcmci_set_ios,
684 .get_ro = mxcmci_get_ro, 730 .get_ro = mxcmci_get_ro,
731 .enable_sdio_irq = mxcmci_enable_sdio_irq,
685}; 732};
686 733
687static int mxcmci_probe(struct platform_device *pdev) 734static int mxcmci_probe(struct platform_device *pdev)
@@ -709,7 +756,7 @@ static int mxcmci_probe(struct platform_device *pdev)
709 } 756 }
710 757
711 mmc->ops = &mxcmci_ops; 758 mmc->ops = &mxcmci_ops;
712 mmc->caps = MMC_CAP_4_BIT_DATA; 759 mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
713 760
714 /* MMC core transfer sizes tunable parameters */ 761 /* MMC core transfer sizes tunable parameters */
715 mmc->max_hw_segs = 64; 762 mmc->max_hw_segs = 64;
@@ -728,6 +775,7 @@ static int mxcmci_probe(struct platform_device *pdev)
728 775
729 host->mmc = mmc; 776 host->mmc = mmc;
730 host->pdata = pdev->dev.platform_data; 777 host->pdata = pdev->dev.platform_data;
778 spin_lock_init(&host->lock);
731 779
732 if (host->pdata && host->pdata->ocr_avail) 780 if (host->pdata && host->pdata->ocr_avail)
733 mmc->ocr_avail = host->pdata->ocr_avail; 781 mmc->ocr_avail = host->pdata->ocr_avail;