diff options
author | Daniel Mack <daniel@caiaq.de> | 2010-04-01 04:03:24 -0400 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2010-04-14 03:18:07 -0400 |
commit | f441b993101d4ee95222ccbaad1e0dd53ea90b64 (patch) | |
tree | 66f23ad023c7e06257b3c7f0a1f4b80dc02e4455 /drivers/mmc | |
parent | 4725f6f17691f4602e3e31d785da5a461a16ccfe (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')
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 70 |
1 files changed, 59 insertions, 11 deletions
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 44a53ee5e212..51e880c8f193 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 | ||
143 | static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); | 145 | static 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) | |||
226 | static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, | 228 | static 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, | |||
266 | static void mxcmci_finish_request(struct mxcmci_host *host, | 275 | static 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) | |||
532 | static irqreturn_t mxcmci_irq(int irq, void *devid) | 548 | static 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 | ||
708 | static 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 | ||
681 | static const struct mmc_host_ops mxcmci_ops = { | 727 | static 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 | ||
687 | static int mxcmci_probe(struct platform_device *pdev) | 734 | static 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; |