summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Hemp <c.hemp@phytec.de>2013-10-04 11:35:40 +0200
committerJustin Waters <justin.waters@timesys.com>2013-11-12 11:44:12 -0500
commitecacd71082e5eab9fdc6a82fa197ba7092374f2d (patch)
tree5850eeab12c0e63717cb978960b988d11b402da0
parentdb29867c3a08bd41d83d260fc86ea8b88b242fac (diff)
drivers: mmc: prepare mmc driver for tiwi
Signed-off-by: Grigory Milev <g.milev@sam-solutions.net> Signed-off-by: Christian Hemp <c.hemp@phytec.de>
-rw-r--r--arch/arm/plat-mxc/include/mach/esdhc.h1
-rw-r--r--drivers/mmc/core/sdio.c74
-rw-r--r--drivers/mmc/core/sdio_cis.c18
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c1
4 files changed, 91 insertions, 3 deletions
diff --git a/arch/arm/plat-mxc/include/mach/esdhc.h b/arch/arm/plat-mxc/include/mach/esdhc.h
index bb15db1ecbc2..294e4cdc338e 100644
--- a/arch/arm/plat-mxc/include/mach/esdhc.h
+++ b/arch/arm/plat-mxc/include/mach/esdhc.h
@@ -34,6 +34,7 @@ struct esdhc_platform_data {
unsigned int support_18v;
unsigned int support_8bit;
unsigned int keep_power_at_suspend;
+ unsigned int caps;
unsigned int delay_line;
int (*platform_pad_change)(unsigned int index, int clock);
};
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index cc3736bedb2b..6871378578a1 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -882,3 +882,77 @@ err:
return err;
}
+int sdio_reset_comm(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ u32 ocr;
+ int err;
+
+ printk(KERN_ERR "%s():\n", __func__);
+ mmc_claim_host(host);
+
+ mmc_go_idle(host);
+
+ mmc_set_clock(host, host->f_min);
+
+ err = mmc_send_io_op_cond(host, 0, &ocr);
+ if (err)
+ goto err;
+
+ host->ocr = mmc_select_voltage(host, ocr);
+ if (!host->ocr) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ err = mmc_send_io_op_cond(host, host->ocr, &ocr);
+ if (err)
+ goto err;
+
+ if (mmc_host_is_spi(host)) {
+ err = mmc_spi_set_crc(host, use_spi_crc);
+ if (err)
+ goto err;
+ }
+
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_send_relative_addr(host, &card->rca);
+ if (err)
+ goto err;
+ mmc_set_bus_mode(host, MMC_BUSMODE_PUSHPULL);
+ }
+ if (!mmc_host_is_spi(host)) {
+ err = mmc_select_card(card);
+ if (err)
+ goto err;
+ }
+
+ /*
+ * Switch to high-speed (if supported).
+ */
+ err = sdio_enable_hs(card);
+ if (err > 0)
+ mmc_sd_go_highspeed(card);
+ else if (err)
+ goto err;
+
+ /*
+ * Change to the card's maximum speed.
+ */
+ mmc_set_clock(host, mmc_sdio_get_max_clock(card));
+
+ err = sdio_enable_4bit_bus(card);
+ if (err > 0)
+ mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
+ else if (err)
+ goto err;
+
+ mmc_release_host(host);
+ return 0;
+err:
+ printk(KERN_ERR "%s: Error resetting SDIO communications (%d)\n",
+ mmc_hostname(host), err);
+ mmc_release_host(host);
+ return err;
+}
+EXPORT_SYMBOL(sdio_reset_comm);
diff --git a/drivers/mmc/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index 541bdb89e0c5..3b0ca8379897 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -230,6 +230,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
int ret;
struct sdio_func_tuple *this, **prev;
unsigned i, ptr = 0;
+ unsigned ptr_null_end;
/*
* Note that this works for the common CIS (function number 0) as
@@ -258,6 +259,7 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
BUG_ON(*prev);
+ ptr_null_end = (ptr | 0xff) + 1;
do {
unsigned char tpl_code, tpl_link;
@@ -269,6 +271,9 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
if (tpl_code == 0xff)
break;
+ if ((tpl_code == 0x00) && (ptr == ptr_null_end))
+ break; /* patch for misbehaving rtl8712 card */
+
/* null entries have no link field or data */
if (tpl_code == 0x00)
continue;
@@ -282,9 +287,10 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
break;
this = kmalloc(sizeof(*this) + tpl_link, GFP_KERNEL);
- if (!this)
- return -ENOMEM;
-
+ if (!this) {
+ ret = -ENOMEM;
+ break;
+ }
for (i = 0; i < tpl_link; i++) {
ret = mmc_io_rw_direct(card, 0, 0,
ptr + i, 0, &this->data[i]);
@@ -328,6 +334,12 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func)
* not going to be queued for a driver.
*/
kfree(this);
+ if (ret) {
+ printk(KERN_WARNING "%s: dropping invalid"
+ " CIS tuple 0x%02x (%u bytes)\n",
+ mmc_hostname(card->host),
+ tpl_code, tpl_link);
+ }
}
ptr += tpl_link;
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 35fd825f4709..7b08196eb4cf 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -855,6 +855,7 @@ static int esdhc_pltfm_init(struct sdhci_host *host, struct sdhci_pltfm_data *pd
if (boarddata->support_8bit)
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
+ host->mmc->caps |= boarddata->caps;
if (boarddata->keep_power_at_suspend)
host->mmc->pm_caps |= (MMC_PM_KEEP_POWER | \
MMC_PM_WAKE_SDIO_IRQ);