aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/core/core.c
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2007-08-08 12:11:32 -0400
committerPierre Ossman <drzeus@drzeus.cx>2007-09-23 15:51:30 -0400
commitaf51715079e7fb6b290e1881d63d815dc4de5011 (patch)
tree324e81b2346955f130dda8515f2ad4f4ce97c864 /drivers/mmc/core/core.c
parent7213d175e3b6f6db60f843b72e88857a350e146a (diff)
MMC core learns about SPI
Teach the MMC/SD/SDIO core about using SPI mode. - Use mmc_host_is_spi() so enumeration works through SPI signaling and protocols, not just the native versions. - Provide the SPI response type flags with each request issued, including requests from the new lock/unlock code. - Understand that cmd->resp[0] and mmc_get_status() results for SPI return different values than for "native" MMC/SD protocol; this affects resetting, checking card lock status, and some others. - Understand that some commands act a bit differently ... notably: * OP_COND command doesn't return the OCR * APP_CMD status doesn't have an R1_APP_CMD analogue Those changes required some new and updated primitives: - Provide utilities to access two SPI-only requests, and one request that wasn't previously needed: * mmc_spi_read_ocr() ... SPI only * mmc_spi_set_crc() ... SPI only (override by module parm) * mmc_send_cid() ... for use without broadcast mode - Updated internal routines: * Previous mmc_send_csd() modified into mmc_send_cxd_native(); it uses native "R2" responses, which include 16 bytes of data. * Previous mmc_send_ext_csd() becomes new mmc_send_cxd_data() helper for command-and-data access * Bugfix to that mmc_send_cxd_data() code: dma-to-stack is unsafe/nonportable, so kmalloc a bounce buffer instead. - Modified mmc_send_ext_csd() now uses mmc_send_cxd_data() helper - Modified mmc_send_csd(), and new mmc_spi_send_cid(), routines use those helper routines based on whether they're native or SPI The newest categories of cards supported by the MMC stack aren't expected to work yet with SPI: MMC or SD cards with over 4GB data, and SDIO. All those cards support SPI mode, so eventually they should work too. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Diffstat (limited to 'drivers/mmc/core/core.c')
-rw-r--r--drivers/mmc/core/core.c28
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);
42static struct workqueue_struct *workqueue; 42static 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 */
49int use_spi_crc = 1;
50module_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 */
47static int mmc_schedule_delayed_work(struct delayed_work *work, 55static 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;