aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@nokia.com>2009-01-12 09:13:08 -0500
committerPierre Ossman <drzeus@drzeus.cx>2009-03-24 16:30:04 -0400
commit4a694dc915c9a223044ce21fc0d99e63facd1d64 (patch)
tree8dda15d5620b189c9e40ebed37a60e722653ffa3 /drivers/mmc
parent82788ff532f75ecd23166e677c970139ff61c363 (diff)
omap_hsmmc: Fix response type for busy after response
Some MMC commands result in the card becoming busy after the response is received. This needs to be specified for the omap_hsmmc host controller, which is what this patch does. However, the effect is that some commands with no data will cause a Transfer Complete (TC) interrupt in addition to the Command Complete (CC) interrupt. In order to deal with that, the irq handler has needed a few changes also. The benefit of this change is that the omap_hsmmc host controller driver now waits for the TC interrupt while the card is busy, so the mmc_block driver needs to poll the card status just once instead of repeatedly. i.e. the net result is more sleep and less cpu. The command sequence for open-ended multi-block write with DMA is now: Issue write command CMD25 Receive CC interrupt Data is sent Receive TC interrupt (DMA is done) Issue stop command CMD12 Receive CC interrupt Card is busy Receive TC interrupt Card is now ready for next transfer Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/omap_hsmmc.c38
1 files changed, 29 insertions, 9 deletions
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 5ff2ca22beea..1f84bd4a3b27 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -150,6 +150,7 @@ struct mmc_omap_host {
150 int initstr; 150 int initstr;
151 int slot_id; 151 int slot_id;
152 int dbclk_enabled; 152 int dbclk_enabled;
153 int response_busy;
153 struct omap_mmc_platform_data *pdata; 154 struct omap_mmc_platform_data *pdata;
154}; 155};
155 156
@@ -244,10 +245,14 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd,
244 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK); 245 OMAP_HSMMC_WRITE(host->base, ISE, INT_EN_MASK);
245 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK); 246 OMAP_HSMMC_WRITE(host->base, IE, INT_EN_MASK);
246 247
248 host->response_busy = 0;
247 if (cmd->flags & MMC_RSP_PRESENT) { 249 if (cmd->flags & MMC_RSP_PRESENT) {
248 if (cmd->flags & MMC_RSP_136) 250 if (cmd->flags & MMC_RSP_136)
249 resptype = 1; 251 resptype = 1;
250 else 252 else if (cmd->flags & MMC_RSP_BUSY) {
253 resptype = 3;
254 host->response_busy = 1;
255 } else
251 resptype = 2; 256 resptype = 2;
252 } 257 }
253 258
@@ -282,6 +287,15 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd,
282static void 287static void
283mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data) 288mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)
284{ 289{
290 if (!data) {
291 struct mmc_request *mrq = host->mrq;
292
293 host->mrq = NULL;
294 mmc_omap_fclk_lazy_disable(host);
295 mmc_request_done(host->mmc, mrq);
296 return;
297 }
298
285 host->data = NULL; 299 host->data = NULL;
286 300
287 if (host->use_dma && host->dma_ch != -1) 301 if (host->use_dma && host->dma_ch != -1)
@@ -323,7 +337,7 @@ mmc_omap_cmd_done(struct mmc_omap_host *host, struct mmc_command *cmd)
323 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10); 337 cmd->resp[0] = OMAP_HSMMC_READ(host->base, RSP10);
324 } 338 }
325 } 339 }
326 if (host->data == NULL || cmd->error) { 340 if ((host->data == NULL && !host->response_busy) || cmd->error) {
327 host->mrq = NULL; 341 host->mrq = NULL;
328 mmc_request_done(host->mmc, cmd->mrq); 342 mmc_request_done(host->mmc, cmd->mrq);
329 } 343 }
@@ -413,7 +427,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
413 struct mmc_data *data; 427 struct mmc_data *data;
414 int end_cmd = 0, end_trans = 0, status; 428 int end_cmd = 0, end_trans = 0, status;
415 429
416 if (host->cmd == NULL && host->data == NULL) { 430 if (host->mrq == NULL) {
417 OMAP_HSMMC_WRITE(host->base, STAT, 431 OMAP_HSMMC_WRITE(host->base, STAT,
418 OMAP_HSMMC_READ(host->base, STAT)); 432 OMAP_HSMMC_READ(host->base, STAT));
419 return IRQ_HANDLED; 433 return IRQ_HANDLED;
@@ -438,18 +452,24 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
438 } 452 }
439 end_cmd = 1; 453 end_cmd = 1;
440 } 454 }
441 if (host->data) { 455 if (host->data || host->response_busy) {
442 mmc_dma_cleanup(host, -ETIMEDOUT); 456 if (host->data)
457 mmc_dma_cleanup(host, -ETIMEDOUT);
458 host->response_busy = 0;
443 mmc_omap_reset_controller_fsm(host, SRD); 459 mmc_omap_reset_controller_fsm(host, SRD);
444 } 460 }
445 } 461 }
446 if ((status & DATA_TIMEOUT) || 462 if ((status & DATA_TIMEOUT) ||
447 (status & DATA_CRC)) { 463 (status & DATA_CRC)) {
448 if (host->data) { 464 if (host->data || host->response_busy) {
449 if (status & DATA_TIMEOUT) 465 int err = (status & DATA_TIMEOUT) ?
450 mmc_dma_cleanup(host, -ETIMEDOUT); 466 -ETIMEDOUT : -EILSEQ;
467
468 if (host->data)
469 mmc_dma_cleanup(host, err);
451 else 470 else
452 mmc_dma_cleanup(host, -EILSEQ); 471 host->mrq->cmd->error = err;
472 host->response_busy = 0;
453 mmc_omap_reset_controller_fsm(host, SRD); 473 mmc_omap_reset_controller_fsm(host, SRD);
454 end_trans = 1; 474 end_trans = 1;
455 } 475 }