diff options
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r-- | drivers/mmc/core/core.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bffcaf8df352..bad39442f8fe 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c | |||
@@ -42,6 +42,14 @@ extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr); | |||
42 | static struct workqueue_struct *workqueue; | 42 | static struct workqueue_struct *workqueue; |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * Enabling software CRCs on the data blocks can be a significant (30%) | ||
46 | * performance cost, and for other reasons may not always be desired. | ||
47 | * So we allow it it to be disabled. | ||
48 | */ | ||
49 | int use_spi_crc = 1; | ||
50 | module_param(use_spi_crc, bool, 0); | ||
51 | |||
52 | /* | ||
45 | * Internal function. Schedule delayed work in the MMC work queue. | 53 | * Internal function. Schedule delayed work in the MMC work queue. |
46 | */ | 54 | */ |
47 | static int mmc_schedule_delayed_work(struct delayed_work *work, | 55 | static int mmc_schedule_delayed_work(struct delayed_work *work, |
@@ -71,6 +79,11 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) | |||
71 | struct mmc_command *cmd = mrq->cmd; | 79 | struct mmc_command *cmd = mrq->cmd; |
72 | int err = cmd->error; | 80 | int err = cmd->error; |
73 | 81 | ||
82 | if (err && cmd->retries && mmc_host_is_spi(host)) { | ||
83 | if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) | ||
84 | cmd->retries = 0; | ||
85 | } | ||
86 | |||
74 | if (err && cmd->retries) { | 87 | if (err && cmd->retries) { |
75 | pr_debug("%s: req failed (CMD%u): %d, retrying...\n", | 88 | pr_debug("%s: req failed (CMD%u): %d, retrying...\n", |
76 | mmc_hostname(host), cmd->opcode, err); | 89 | mmc_hostname(host), cmd->opcode, err); |
@@ -453,8 +466,13 @@ static void mmc_power_up(struct mmc_host *host) | |||
453 | int bit = fls(host->ocr_avail) - 1; | 466 | int bit = fls(host->ocr_avail) - 1; |
454 | 467 | ||
455 | host->ios.vdd = bit; | 468 | host->ios.vdd = bit; |
456 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | 469 | if (mmc_host_is_spi(host)) { |
457 | host->ios.chip_select = MMC_CS_DONTCARE; | 470 | host->ios.chip_select = MMC_CS_HIGH; |
471 | host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; | ||
472 | } else { | ||
473 | host->ios.chip_select = MMC_CS_DONTCARE; | ||
474 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | ||
475 | } | ||
458 | host->ios.power_mode = MMC_POWER_UP; | 476 | host->ios.power_mode = MMC_POWER_UP; |
459 | host->ios.bus_width = MMC_BUS_WIDTH_1; | 477 | host->ios.bus_width = MMC_BUS_WIDTH_1; |
460 | host->ios.timing = MMC_TIMING_LEGACY; | 478 | host->ios.timing = MMC_TIMING_LEGACY; |
@@ -481,8 +499,10 @@ static void mmc_power_off(struct mmc_host *host) | |||
481 | { | 499 | { |
482 | host->ios.clock = 0; | 500 | host->ios.clock = 0; |
483 | host->ios.vdd = 0; | 501 | host->ios.vdd = 0; |
484 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; | 502 | if (!mmc_host_is_spi(host)) { |
485 | host->ios.chip_select = MMC_CS_DONTCARE; | 503 | host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; |
504 | host->ios.chip_select = MMC_CS_DONTCARE; | ||
505 | } | ||
486 | host->ios.power_mode = MMC_POWER_OFF; | 506 | host->ios.power_mode = MMC_POWER_OFF; |
487 | host->ios.bus_width = MMC_BUS_WIDTH_1; | 507 | host->ios.bus_width = MMC_BUS_WIDTH_1; |
488 | host->ios.timing = MMC_TIMING_LEGACY; | 508 | host->ios.timing = MMC_TIMING_LEGACY; |