diff options
author | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2008-10-03 11:48:16 -0400 |
---|---|---|
committer | Haavard Skinnemoen <haavard.skinnemoen@atmel.com> | 2008-10-05 14:39:20 -0400 |
commit | 945533b538c6c6185afc77ba4a81eeba8f6ef8dd (patch) | |
tree | 5bb72f5ac9e50cdaeca19f14c18970acc30acccf /drivers/mmc/host | |
parent | c06ad2580dca4eb14ca07541d4f00a3b7cbcf12f (diff) |
atmel-mci: Don't stop the clock between transfers
Some cards might get upset if we turn off the clock for extended periods
of time. So keep the clock running until the mmc core tells us to turn
it off.
Also, don't reset the controller between each transfer. That was an
attempt to work around earlier bugs, and it never really worked very
well.
Signed-off-by: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r-- | drivers/mmc/host/atmel-mci.c | 60 |
1 files changed, 22 insertions, 38 deletions
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index d834e3756aef..14ab28da7fa8 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c | |||
@@ -279,23 +279,6 @@ err: | |||
279 | "failed to initialize debugfs for controller\n"); | 279 | "failed to initialize debugfs for controller\n"); |
280 | } | 280 | } |
281 | 281 | ||
282 | static void atmci_enable(struct atmel_mci *host) | ||
283 | { | ||
284 | clk_enable(host->mck); | ||
285 | mci_writel(host, CR, MCI_CR_MCIEN); | ||
286 | mci_writel(host, MR, host->mode_reg); | ||
287 | mci_writel(host, SDCR, host->sdc_reg); | ||
288 | } | ||
289 | |||
290 | static void atmci_disable(struct atmel_mci *host) | ||
291 | { | ||
292 | mci_writel(host, CR, MCI_CR_SWRST); | ||
293 | |||
294 | /* Stall until write is complete, then disable the bus clock */ | ||
295 | mci_readl(host, SR); | ||
296 | clk_disable(host->mck); | ||
297 | } | ||
298 | |||
299 | static inline unsigned int ns_to_clocks(struct atmel_mci *host, | 282 | static inline unsigned int ns_to_clocks(struct atmel_mci *host, |
300 | unsigned int ns) | 283 | unsigned int ns) |
301 | { | 284 | { |
@@ -408,8 +391,6 @@ static void atmci_request_end(struct mmc_host *mmc, struct mmc_request *mrq) | |||
408 | WARN_ON(host->cmd || host->data); | 391 | WARN_ON(host->cmd || host->data); |
409 | host->mrq = NULL; | 392 | host->mrq = NULL; |
410 | 393 | ||
411 | atmci_disable(host); | ||
412 | |||
413 | mmc_request_done(mmc, mrq); | 394 | mmc_request_done(mmc, mrq); |
414 | } | 395 | } |
415 | 396 | ||
@@ -476,8 +457,6 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
476 | host->completed_events = 0; | 457 | host->completed_events = 0; |
477 | host->state = STATE_SENDING_CMD; | 458 | host->state = STATE_SENDING_CMD; |
478 | 459 | ||
479 | atmci_enable(host); | ||
480 | |||
481 | /* We don't support multiple blocks of weird lengths. */ | 460 | /* We don't support multiple blocks of weird lengths. */ |
482 | data = mrq->data; | 461 | data = mrq->data; |
483 | if (data) { | 462 | if (data) { |
@@ -520,7 +499,6 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq) | |||
520 | return; | 499 | return; |
521 | 500 | ||
522 | fail: | 501 | fail: |
523 | atmci_disable(host); | ||
524 | host->mrq = NULL; | 502 | host->mrq = NULL; |
525 | mrq->cmd->error = -EINVAL; | 503 | mrq->cmd->error = -EINVAL; |
526 | mmc_request_done(mmc, mrq); | 504 | mmc_request_done(mmc, mrq); |
@@ -530,9 +508,21 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
530 | { | 508 | { |
531 | struct atmel_mci *host = mmc_priv(mmc); | 509 | struct atmel_mci *host = mmc_priv(mmc); |
532 | 510 | ||
511 | switch (ios->bus_width) { | ||
512 | case MMC_BUS_WIDTH_1: | ||
513 | host->sdc_reg = 0; | ||
514 | break; | ||
515 | case MMC_BUS_WIDTH_4: | ||
516 | host->sdc_reg = MCI_SDCBUS_4BIT; | ||
517 | break; | ||
518 | } | ||
519 | |||
533 | if (ios->clock) { | 520 | if (ios->clock) { |
534 | u32 clkdiv; | 521 | u32 clkdiv; |
535 | 522 | ||
523 | if (!host->mode_reg) | ||
524 | clk_enable(host->mck); | ||
525 | |||
536 | /* Set clock rate */ | 526 | /* Set clock rate */ |
537 | clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * ios->clock) - 1; | 527 | clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * ios->clock) - 1; |
538 | if (clkdiv > 255) { | 528 | if (clkdiv > 255) { |
@@ -544,26 +534,20 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
544 | 534 | ||
545 | host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF | 535 | host->mode_reg = MCI_MR_CLKDIV(clkdiv) | MCI_MR_WRPROOF |
546 | | MCI_MR_RDPROOF; | 536 | | MCI_MR_RDPROOF; |
547 | } | ||
548 | 537 | ||
549 | switch (ios->bus_width) { | 538 | mci_writel(host, CR, MCI_CR_MCIEN); |
550 | case MMC_BUS_WIDTH_1: | 539 | mci_writel(host, MR, host->mode_reg); |
551 | host->sdc_reg = 0; | 540 | mci_writel(host, SDCR, host->sdc_reg); |
552 | break; | 541 | } else { |
553 | case MMC_BUS_WIDTH_4: | 542 | mci_writel(host, CR, MCI_CR_MCIDIS); |
554 | host->sdc_reg = MCI_SDCBUS_4BIT; | 543 | if (host->mode_reg) { |
555 | break; | 544 | mci_readl(host, MR); |
545 | clk_disable(host->mck); | ||
546 | } | ||
547 | host->mode_reg = 0; | ||
556 | } | 548 | } |
557 | 549 | ||
558 | switch (ios->power_mode) { | 550 | switch (ios->power_mode) { |
559 | case MMC_POWER_ON: | ||
560 | /* Send init sequence (74 clock cycles) */ | ||
561 | atmci_enable(host); | ||
562 | mci_writel(host, CMDR, MCI_CMDR_SPCMD_INIT); | ||
563 | while (!(mci_readl(host, SR) & MCI_CMDRDY)) | ||
564 | cpu_relax(); | ||
565 | atmci_disable(host); | ||
566 | break; | ||
567 | default: | 551 | default: |
568 | /* | 552 | /* |
569 | * TODO: None of the currently available AVR32-based | 553 | * TODO: None of the currently available AVR32-based |