From af51715079e7fb6b290e1881d63d815dc4de5011 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 8 Aug 2007 09:11:32 -0700 Subject: 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 Signed-off-by: Pierre Ossman --- drivers/mmc/core/core.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'drivers/mmc/core/core.c') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index bffcaf8df35..bad39442f8f 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -41,6 +41,14 @@ extern int mmc_attach_sdio(struct mmc_host *host, u32 ocr); static struct workqueue_struct *workqueue; +/* + * Enabling software CRCs on the data blocks can be a significant (30%) + * performance cost, and for other reasons may not always be desired. + * So we allow it it to be disabled. + */ +int use_spi_crc = 1; +module_param(use_spi_crc, bool, 0); + /* * Internal function. Schedule delayed work in the MMC work queue. */ @@ -71,6 +79,11 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq) struct mmc_command *cmd = mrq->cmd; int err = cmd->error; + if (err && cmd->retries && mmc_host_is_spi(host)) { + if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) + cmd->retries = 0; + } + if (err && cmd->retries) { pr_debug("%s: req failed (CMD%u): %d, retrying...\n", mmc_hostname(host), cmd->opcode, err); @@ -453,8 +466,13 @@ static void mmc_power_up(struct mmc_host *host) int bit = fls(host->ocr_avail) - 1; host->ios.vdd = bit; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (mmc_host_is_spi(host)) { + host->ios.chip_select = MMC_CS_HIGH; + host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; + } else { + host->ios.chip_select = MMC_CS_DONTCARE; + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + } host->ios.power_mode = MMC_POWER_UP; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; @@ -481,8 +499,10 @@ static void mmc_power_off(struct mmc_host *host) { host->ios.clock = 0; host->ios.vdd = 0; - host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; - host->ios.chip_select = MMC_CS_DONTCARE; + if (!mmc_host_is_spi(host)) { + host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; + host->ios.chip_select = MMC_CS_DONTCARE; + } host->ios.power_mode = MMC_POWER_OFF; host->ios.bus_width = MMC_BUS_WIDTH_1; host->ios.timing = MMC_TIMING_LEGACY; -- cgit v1.2.3-18-g5258