diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-25 15:06:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-25 15:06:33 -0400 |
commit | ec96e2fe954c23a54bfdf2673437a39e193a1822 (patch) | |
tree | e4041c68ef20a3337c56aefc8db785156307edd1 /drivers/mmc | |
parent | 8e9815a0f8882aaa68645b001bb7538db8886802 (diff) | |
parent | f949c0edd84101bfd30b3e7389c1a12b067e561d (diff) |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (103 commits)
ARM: 6141/1: Add audio support part in arch/arm/mach-w90x900
ARM: 5939/1: ARM: Add option CMDLINE_FORCE to force usage of the in-kernel cmdline
ARM: 6140/1: silence a bogus sparse warning in unwind.c
ARM: mach-at91: duplicated include
ARM: arch/arm/nwfpe/fpsr.h: Checkpatch cleanup
ARM: arch/arm/mach-shark/pci.c: Checkpatch cleanup
ARM: arch/arm/nwfpe/ChangeLog: Checkpatch cleanup
ARM: arch/arm/mach-sa1100/leds.c: Checkpatch cleanup
ARM: arch/arm/mach-h720x/common.h: Checkpatch cleanup
ARM: arch/arm/mach-footbridge/ebsa285-pci.c: Checkpatch cleanup
ARM: arch/arm/mach-clps711x/Makefile.boot: Checkpatch cleanup
ARM: arch/arm/boot/bootp/bootp.lds: Checkpatch cleanup
ARM: SPEAR6xx: remove duplicated #include
ARM: s3c6400_defconfig: Add NAND driver
ARM: s3c6400_defconfig: enable sound as modules
ARM: s3c6400_defconfig: enable power management
ARM: s5pv210_defconfig: Update s5pv210_defconfig to v2.6.34
ARM: s5pc110_defconfig: Update s5pc110_defconfig to v2.6.34
ARM: s5p6442_defconfig: Update s5p6442_defconfig to v2.6.34
ARM: s5p6440_defconfig: Update s5p6440_defconfig to v2.6.34
...
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/core/sdio.c | 6 | ||||
-rw-r--r-- | drivers/mmc/host/mxcmmc.c | 114 |
2 files changed, 105 insertions, 15 deletions
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 2dd4cfe7ca17..b9dee28ee7d0 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c | |||
@@ -296,6 +296,12 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, | |||
296 | card->type = MMC_TYPE_SDIO; | 296 | card->type = MMC_TYPE_SDIO; |
297 | 297 | ||
298 | /* | 298 | /* |
299 | * Call the optional HC's init_card function to handle quirks. | ||
300 | */ | ||
301 | if (host->ops->init_card) | ||
302 | host->ops->init_card(host, card); | ||
303 | |||
304 | /* | ||
299 | * For native busses: set card RCA and quit open drain mode. | 305 | * For native busses: set card RCA and quit open drain mode. |
300 | */ | 306 | */ |
301 | if (!powered_resume && !mmc_host_is_spi(host)) { | 307 | if (!powered_resume && !mmc_host_is_spi(host)) { |
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 2df90412abb5..ec18e3b60342 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); |
@@ -151,6 +153,8 @@ static void mxcmci_softreset(struct mxcmci_host *host) | |||
151 | { | 153 | { |
152 | int i; | 154 | int i; |
153 | 155 | ||
156 | dev_dbg(mmc_dev(host->mmc), "mxcmci_softreset\n"); | ||
157 | |||
154 | /* reset sequence */ | 158 | /* reset sequence */ |
155 | writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK); | 159 | writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK); |
156 | writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, | 160 | writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK, |
@@ -224,6 +228,9 @@ static int mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data) | |||
224 | 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, |
225 | unsigned int cmdat) | 229 | unsigned int cmdat) |
226 | { | 230 | { |
231 | u32 int_cntr; | ||
232 | unsigned long flags; | ||
233 | |||
227 | WARN_ON(host->cmd != NULL); | 234 | WARN_ON(host->cmd != NULL); |
228 | host->cmd = cmd; | 235 | host->cmd = cmd; |
229 | 236 | ||
@@ -247,12 +254,16 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, | |||
247 | return -EINVAL; | 254 | return -EINVAL; |
248 | } | 255 | } |
249 | 256 | ||
257 | int_cntr = INT_END_CMD_RES_EN; | ||
258 | |||
250 | if (mxcmci_use_dma(host)) | 259 | if (mxcmci_use_dma(host)) |
251 | writel(INT_READ_OP_EN | INT_WRITE_OP_DONE_EN | | 260 | int_cntr |= INT_READ_OP_EN | INT_WRITE_OP_DONE_EN; |
252 | INT_END_CMD_RES_EN, | 261 | |
253 | host->base + MMC_REG_INT_CNTR); | 262 | spin_lock_irqsave(&host->lock, flags); |
254 | else | 263 | if (host->use_sdio) |
255 | 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); | ||
256 | 267 | ||
257 | writew(cmd->opcode, host->base + MMC_REG_CMD); | 268 | writew(cmd->opcode, host->base + MMC_REG_CMD); |
258 | writel(cmd->arg, host->base + MMC_REG_ARG); | 269 | writel(cmd->arg, host->base + MMC_REG_ARG); |
@@ -264,7 +275,14 @@ static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd, | |||
264 | static void mxcmci_finish_request(struct mxcmci_host *host, | 275 | static void mxcmci_finish_request(struct mxcmci_host *host, |
265 | struct mmc_request *req) | 276 | struct mmc_request *req) |
266 | { | 277 | { |
267 | 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); | ||
268 | 286 | ||
269 | host->req = NULL; | 287 | host->req = NULL; |
270 | host->cmd = NULL; | 288 | host->cmd = NULL; |
@@ -290,16 +308,25 @@ static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat) | |||
290 | dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", | 308 | dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n", |
291 | stat); | 309 | stat); |
292 | if (stat & STATUS_CRC_READ_ERR) { | 310 | if (stat & STATUS_CRC_READ_ERR) { |
311 | dev_err(mmc_dev(host->mmc), "%s: -EILSEQ\n", __func__); | ||
293 | data->error = -EILSEQ; | 312 | data->error = -EILSEQ; |
294 | } else if (stat & STATUS_CRC_WRITE_ERR) { | 313 | } else if (stat & STATUS_CRC_WRITE_ERR) { |
295 | u32 err_code = (stat >> 9) & 0x3; | 314 | u32 err_code = (stat >> 9) & 0x3; |
296 | if (err_code == 2) /* No CRC response */ | 315 | if (err_code == 2) { /* No CRC response */ |
316 | dev_err(mmc_dev(host->mmc), | ||
317 | "%s: No CRC -ETIMEDOUT\n", __func__); | ||
297 | data->error = -ETIMEDOUT; | 318 | data->error = -ETIMEDOUT; |
298 | else | 319 | } else { |
320 | dev_err(mmc_dev(host->mmc), | ||
321 | "%s: -EILSEQ\n", __func__); | ||
299 | data->error = -EILSEQ; | 322 | data->error = -EILSEQ; |
323 | } | ||
300 | } else if (stat & STATUS_TIME_OUT_READ) { | 324 | } else if (stat & STATUS_TIME_OUT_READ) { |
325 | dev_err(mmc_dev(host->mmc), | ||
326 | "%s: read -ETIMEDOUT\n", __func__); | ||
301 | data->error = -ETIMEDOUT; | 327 | data->error = -ETIMEDOUT; |
302 | } else { | 328 | } else { |
329 | dev_err(mmc_dev(host->mmc), "%s: -EIO\n", __func__); | ||
303 | data->error = -EIO; | 330 | data->error = -EIO; |
304 | } | 331 | } |
305 | } else { | 332 | } else { |
@@ -433,8 +460,6 @@ static int mxcmci_transfer_data(struct mxcmci_host *host) | |||
433 | struct scatterlist *sg; | 460 | struct scatterlist *sg; |
434 | int stat, i; | 461 | int stat, i; |
435 | 462 | ||
436 | host->datasize = 0; | ||
437 | |||
438 | host->data = data; | 463 | host->data = data; |
439 | host->datasize = 0; | 464 | host->datasize = 0; |
440 | 465 | ||
@@ -464,6 +489,9 @@ static void mxcmci_datawork(struct work_struct *work) | |||
464 | struct mxcmci_host *host = container_of(work, struct mxcmci_host, | 489 | struct mxcmci_host *host = container_of(work, struct mxcmci_host, |
465 | datawork); | 490 | datawork); |
466 | int datastat = mxcmci_transfer_data(host); | 491 | int datastat = mxcmci_transfer_data(host); |
492 | |||
493 | writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, | ||
494 | host->base + MMC_REG_STATUS); | ||
467 | mxcmci_finish_data(host, datastat); | 495 | mxcmci_finish_data(host, datastat); |
468 | 496 | ||
469 | if (host->req->stop) { | 497 | if (host->req->stop) { |
@@ -523,15 +551,35 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat) | |||
523 | static irqreturn_t mxcmci_irq(int irq, void *devid) | 551 | static irqreturn_t mxcmci_irq(int irq, void *devid) |
524 | { | 552 | { |
525 | struct mxcmci_host *host = devid; | 553 | struct mxcmci_host *host = devid; |
554 | unsigned long flags; | ||
555 | bool sdio_irq; | ||
526 | u32 stat; | 556 | u32 stat; |
527 | 557 | ||
528 | stat = readl(host->base + MMC_REG_STATUS); | 558 | stat = readl(host->base + MMC_REG_STATUS); |
529 | writel(stat, host->base + MMC_REG_STATUS); | 559 | writel(stat & ~(STATUS_SDIO_INT_ACTIVE | STATUS_DATA_TRANS_DONE | |
560 | STATUS_WRITE_OP_DONE), host->base + MMC_REG_STATUS); | ||
530 | 561 | ||
531 | dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); | 562 | dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat); |
532 | 563 | ||
564 | spin_lock_irqsave(&host->lock, flags); | ||
565 | sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio; | ||
566 | spin_unlock_irqrestore(&host->lock, flags); | ||
567 | |||
568 | #ifdef HAS_DMA | ||
569 | if (mxcmci_use_dma(host) && | ||
570 | (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE))) | ||
571 | writel(STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE, | ||
572 | host->base + MMC_REG_STATUS); | ||
573 | #endif | ||
574 | |||
575 | if (sdio_irq) { | ||
576 | writel(STATUS_SDIO_INT_ACTIVE, host->base + MMC_REG_STATUS); | ||
577 | mmc_signal_sdio_irq(host->mmc); | ||
578 | } | ||
579 | |||
533 | if (stat & STATUS_END_CMD_RESP) | 580 | if (stat & STATUS_END_CMD_RESP) |
534 | mxcmci_cmd_done(host, stat); | 581 | mxcmci_cmd_done(host, stat); |
582 | |||
535 | #ifdef HAS_DMA | 583 | #ifdef HAS_DMA |
536 | if (mxcmci_use_dma(host) && | 584 | if (mxcmci_use_dma(host) && |
537 | (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) | 585 | (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) |
@@ -668,11 +716,46 @@ static int mxcmci_get_ro(struct mmc_host *mmc) | |||
668 | return -ENOSYS; | 716 | return -ENOSYS; |
669 | } | 717 | } |
670 | 718 | ||
719 | static void mxcmci_enable_sdio_irq(struct mmc_host *mmc, int enable) | ||
720 | { | ||
721 | struct mxcmci_host *host = mmc_priv(mmc); | ||
722 | unsigned long flags; | ||
723 | u32 int_cntr; | ||
724 | |||
725 | spin_lock_irqsave(&host->lock, flags); | ||
726 | host->use_sdio = enable; | ||
727 | int_cntr = readl(host->base + MMC_REG_INT_CNTR); | ||
728 | |||
729 | if (enable) | ||
730 | int_cntr |= INT_SDIO_IRQ_EN; | ||
731 | else | ||
732 | int_cntr &= ~INT_SDIO_IRQ_EN; | ||
733 | |||
734 | writel(int_cntr, host->base + MMC_REG_INT_CNTR); | ||
735 | spin_unlock_irqrestore(&host->lock, flags); | ||
736 | } | ||
737 | |||
738 | static void mxcmci_init_card(struct mmc_host *host, struct mmc_card *card) | ||
739 | { | ||
740 | /* | ||
741 | * MX3 SoCs have a silicon bug which corrupts CRC calculation of | ||
742 | * multi-block transfers when connected SDIO peripheral doesn't | ||
743 | * drive the BUSY line as required by the specs. | ||
744 | * One way to prevent this is to only allow 1-bit transfers. | ||
745 | */ | ||
746 | |||
747 | if (cpu_is_mx3() && card->type == MMC_TYPE_SDIO) | ||
748 | host->caps &= ~MMC_CAP_4_BIT_DATA; | ||
749 | else | ||
750 | host->caps |= MMC_CAP_4_BIT_DATA; | ||
751 | } | ||
671 | 752 | ||
672 | static const struct mmc_host_ops mxcmci_ops = { | 753 | static const struct mmc_host_ops mxcmci_ops = { |
673 | .request = mxcmci_request, | 754 | .request = mxcmci_request, |
674 | .set_ios = mxcmci_set_ios, | 755 | .set_ios = mxcmci_set_ios, |
675 | .get_ro = mxcmci_get_ro, | 756 | .get_ro = mxcmci_get_ro, |
757 | .enable_sdio_irq = mxcmci_enable_sdio_irq, | ||
758 | .init_card = mxcmci_init_card, | ||
676 | }; | 759 | }; |
677 | 760 | ||
678 | static int mxcmci_probe(struct platform_device *pdev) | 761 | static int mxcmci_probe(struct platform_device *pdev) |
@@ -700,7 +783,7 @@ static int mxcmci_probe(struct platform_device *pdev) | |||
700 | } | 783 | } |
701 | 784 | ||
702 | mmc->ops = &mxcmci_ops; | 785 | mmc->ops = &mxcmci_ops; |
703 | mmc->caps = MMC_CAP_4_BIT_DATA; | 786 | mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; |
704 | 787 | ||
705 | /* MMC core transfer sizes tunable parameters */ | 788 | /* MMC core transfer sizes tunable parameters */ |
706 | mmc->max_hw_segs = 64; | 789 | mmc->max_hw_segs = 64; |
@@ -719,6 +802,7 @@ static int mxcmci_probe(struct platform_device *pdev) | |||
719 | 802 | ||
720 | host->mmc = mmc; | 803 | host->mmc = mmc; |
721 | host->pdata = pdev->dev.platform_data; | 804 | host->pdata = pdev->dev.platform_data; |
805 | spin_lock_init(&host->lock); | ||
722 | 806 | ||
723 | if (host->pdata && host->pdata->ocr_avail) | 807 | if (host->pdata && host->pdata->ocr_avail) |
724 | mmc->ocr_avail = host->pdata->ocr_avail; | 808 | mmc->ocr_avail = host->pdata->ocr_avail; |