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 | |
| 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>
| -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; |
