summaryrefslogtreecommitdiff
path: root/drivers/mmc/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/cb710-mmc.c6
-rw-r--r--drivers/mmc/host/imxmmc.c2
-rw-r--r--drivers/mmc/host/mmc_spi.c6
-rw-r--r--drivers/mmc/host/mmci.c79
-rw-r--r--drivers/mmc/host/mmci.h2
-rw-r--r--drivers/mmc/host/mvsdio.c4
-rw-r--r--drivers/mmc/host/mxcmmc.c2
-rw-r--r--drivers/mmc/host/pxamci.c4
-rw-r--r--drivers/mmc/host/sdhci-of.c10
-rw-r--r--drivers/mmc/host/sdhci.c15
-rw-r--r--drivers/mmc/host/sdhci.h1
11 files changed, 109 insertions, 22 deletions
diff --git a/drivers/mmc/host/cb710-mmc.c b/drivers/mmc/host/cb710-mmc.c
index 11efefb1af51..4e72964a7b43 100644
--- a/drivers/mmc/host/cb710-mmc.c
+++ b/drivers/mmc/host/cb710-mmc.c
@@ -278,7 +278,7 @@ static int cb710_mmc_receive(struct cb710_slot *slot, struct mmc_data *data)
if (unlikely(data->blksz & 15 && (data->blocks != 1 || data->blksz != 8)))
return -EINVAL;
- sg_miter_start(&miter, data->sg, data->sg_len, 0);
+ sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_TO_SG);
cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
15, CB710_MMC_C2_READ_PIO_SIZE_MASK);
@@ -307,7 +307,7 @@ static int cb710_mmc_receive(struct cb710_slot *slot, struct mmc_data *data)
goto out;
}
out:
- cb710_sg_miter_stop_writing(&miter);
+ sg_miter_stop(&miter);
return err;
}
@@ -322,7 +322,7 @@ static int cb710_mmc_send(struct cb710_slot *slot, struct mmc_data *data)
if (unlikely(data->blocks > 1 && data->blksz & 15))
return -EINVAL;
- sg_miter_start(&miter, data->sg, data->sg_len, 0);
+ sg_miter_start(&miter, data->sg, data->sg_len, SG_MITER_FROM_SG);
cb710_modify_port_8(slot, CB710_MMC_CONFIG2_PORT,
0, CB710_MMC_C2_READ_PIO_SIZE_MASK);
diff --git a/drivers/mmc/host/imxmmc.c b/drivers/mmc/host/imxmmc.c
index e0be21a4a696..bf98d7cc928a 100644
--- a/drivers/mmc/host/imxmmc.c
+++ b/drivers/mmc/host/imxmmc.c
@@ -652,7 +652,7 @@ static irqreturn_t imxmci_irq(int irq, void *devid)
set_bit(IMXMCI_PEND_STARTED_b, &host->pending_events);
tasklet_schedule(&host->tasklet);
- return IRQ_RETVAL(handled);;
+ return IRQ_RETVAL(handled);
}
static void imxmci_tasklet_fnc(unsigned long data)
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 240608cc7ae9..a461017ce5ce 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -1313,6 +1313,12 @@ static int mmc_spi_probe(struct spi_device *spi)
struct mmc_spi_host *host;
int status;
+ /* We rely on full duplex transfers, mostly to reduce
+ * per-transfer overheads (by making fewer transfers).
+ */
+ if (spi->master->flags & SPI_MASTER_HALF_DUPLEX)
+ return -EINVAL;
+
/* MMC and SD specs only seem to care that sampling is on the
* rising edge ... meaning SPI modes 0 or 3. So either SPI mode
* should be legit. We'll use mode 0 since the steady state is 0,
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index e1aa8471ab1c..8741d0f5146a 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -21,6 +21,7 @@
#include <linux/amba/bus.h>
#include <linux/clk.h>
#include <linux/scatterlist.h>
+#include <linux/gpio.h>
#include <asm/cacheflush.h>
#include <asm/div64.h>
@@ -430,7 +431,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
clk = 255;
host->cclk = host->mclk / (2 * (clk + 1));
}
- if (host->hw_designer == 0x80)
+ if (host->hw_designer == AMBA_VENDOR_ST)
clk |= MCI_FCEN; /* Bug fix in ST IP block */
clk |= MCI_CLK_ENABLE;
}
@@ -443,7 +444,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
break;
case MMC_POWER_UP:
/* The ST version does not have this, fall through to POWER_ON */
- if (host->hw_designer != 0x80) {
+ if (host->hw_designer != AMBA_VENDOR_ST) {
pwr |= MCI_PWR_UP;
break;
}
@@ -453,7 +454,7 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
- if (host->hw_designer != 0x80)
+ if (host->hw_designer != AMBA_VENDOR_ST)
pwr |= MCI_ROD;
else {
/*
@@ -472,17 +473,41 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
}
+static int mmci_get_ro(struct mmc_host *mmc)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+
+ if (host->gpio_wp == -ENOSYS)
+ return -ENOSYS;
+
+ return gpio_get_value(host->gpio_wp);
+}
+
+static int mmci_get_cd(struct mmc_host *mmc)
+{
+ struct mmci_host *host = mmc_priv(mmc);
+ unsigned int status;
+
+ if (host->gpio_cd == -ENOSYS)
+ status = host->plat->status(mmc_dev(host->mmc));
+ else
+ status = gpio_get_value(host->gpio_cd);
+
+ return !status;
+}
+
static const struct mmc_host_ops mmci_ops = {
.request = mmci_request,
.set_ios = mmci_set_ios,
+ .get_ro = mmci_get_ro,
+ .get_cd = mmci_get_cd,
};
static void mmci_check_status(unsigned long data)
{
struct mmci_host *host = (struct mmci_host *)data;
- unsigned int status;
+ unsigned int status = mmci_get_cd(host->mmc);
- status = host->plat->status(mmc_dev(host->mmc));
if (status ^ host->oldstat)
mmc_detect_change(host->mmc, 0);
@@ -515,12 +540,15 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
host = mmc_priv(mmc);
host->mmc = mmc;
- /* Bits 12 thru 19 is the designer */
- host->hw_designer = (dev->periphid >> 12) & 0xff;
- /* Bits 20 thru 23 is the revison */
- host->hw_revision = (dev->periphid >> 20) & 0xf;
+
+ host->gpio_wp = -ENOSYS;
+ host->gpio_cd = -ENOSYS;
+
+ host->hw_designer = amba_manf(dev);
+ host->hw_revision = amba_rev(dev);
DBG(host, "designer ID = 0x%02x\n", host->hw_designer);
DBG(host, "revision = 0x%01x\n", host->hw_revision);
+
host->clk = clk_get(&dev->dev, NULL);
if (IS_ERR(host->clk)) {
ret = PTR_ERR(host->clk);
@@ -591,6 +619,27 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
writel(0, host->base + MMCIMASK1);
writel(0xfff, host->base + MMCICLEAR);
+#ifdef CONFIG_GPIOLIB
+ if (gpio_is_valid(plat->gpio_cd)) {
+ ret = gpio_request(plat->gpio_cd, DRIVER_NAME " (cd)");
+ if (ret == 0)
+ ret = gpio_direction_input(plat->gpio_cd);
+ if (ret == 0)
+ host->gpio_cd = plat->gpio_cd;
+ else if (ret != -ENOSYS)
+ goto err_gpio_cd;
+ }
+ if (gpio_is_valid(plat->gpio_wp)) {
+ ret = gpio_request(plat->gpio_wp, DRIVER_NAME " (wp)");
+ if (ret == 0)
+ ret = gpio_direction_input(plat->gpio_wp);
+ if (ret == 0)
+ host->gpio_wp = plat->gpio_wp;
+ else if (ret != -ENOSYS)
+ goto err_gpio_wp;
+ }
+#endif
+
ret = request_irq(dev->irq[0], mmci_irq, IRQF_SHARED, DRIVER_NAME " (cmd)", host);
if (ret)
goto unmap;
@@ -602,6 +651,7 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
writel(MCI_IRQENABLE, host->base + MMCIMASK0);
amba_set_drvdata(dev, mmc);
+ host->oldstat = mmci_get_cd(host->mmc);
mmc_add_host(mmc);
@@ -620,6 +670,12 @@ static int __devinit mmci_probe(struct amba_device *dev, struct amba_id *id)
irq0_free:
free_irq(dev->irq[0], host);
unmap:
+ if (host->gpio_wp != -ENOSYS)
+ gpio_free(host->gpio_wp);
+ err_gpio_wp:
+ if (host->gpio_cd != -ENOSYS)
+ gpio_free(host->gpio_cd);
+ err_gpio_cd:
iounmap(host->base);
clk_disable:
clk_disable(host->clk);
@@ -655,6 +711,11 @@ static int __devexit mmci_remove(struct amba_device *dev)
free_irq(dev->irq[0], host);
free_irq(dev->irq[1], host);
+ if (host->gpio_wp != -ENOSYS)
+ gpio_free(host->gpio_wp);
+ if (host->gpio_cd != -ENOSYS)
+ gpio_free(host->gpio_cd);
+
iounmap(host->base);
clk_disable(host->clk);
clk_put(host->clk);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index 0441bac1c0ec..839f264c9725 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -151,6 +151,8 @@ struct mmci_host {
struct mmc_data *data;
struct mmc_host *mmc;
struct clk *clk;
+ int gpio_cd;
+ int gpio_wp;
unsigned int data_xfered;
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index b56d72ff06e9..34e23489811a 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -384,7 +384,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
u16 val[2] = {0, 0};
val[0] = mvsd_read(MVSD_FIFO);
val[1] = mvsd_read(MVSD_FIFO);
- memcpy(p, &val, s);
+ memcpy(p, ((void *)&val) + 4 - s, s);
s = 0;
intr_status = mvsd_read(MVSD_NOR_INTR_STATUS);
}
@@ -423,7 +423,7 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
if (s < 4) {
if (s && (intr_status & MVSD_NOR_TX_AVAIL)) {
u16 val[2] = {0, 0};
- memcpy(&val, p, s);
+ memcpy(((void *)&val) + 4 - s, p, s);
mvsd_write(MVSD_FIFO, val[0]);
mvsd_write(MVSD_FIFO, val[1]);
s = 0;
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index bc14bb1b0579..88671529c45d 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -512,7 +512,7 @@ static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
}
/* For the DMA case the DMA engine handles the data transfer
- * automatically. For non DMA we have to to it ourselves.
+ * automatically. For non DMA we have to do it ourselves.
* Don't do it in interrupt context though.
*/
if (!mxcmci_use_dma(host) && host->data)
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index d7d7109ef47e..e55ac792d68c 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -168,12 +168,12 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
if (data->flags & MMC_DATA_READ) {
host->dma_dir = DMA_FROM_DEVICE;
- dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG;
+ dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
DRCMR(host->dma_drcmrtx) = 0;
DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD;
} else {
host->dma_dir = DMA_TO_DEVICE;
- dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC;
+ dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
DRCMR(host->dma_drcmrrx) = 0;
DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD;
}
diff --git a/drivers/mmc/host/sdhci-of.c b/drivers/mmc/host/sdhci-of.c
index d79fa55c3b89..1e8aa590bb39 100644
--- a/drivers/mmc/host/sdhci-of.c
+++ b/drivers/mmc/host/sdhci-of.c
@@ -158,6 +158,13 @@ static unsigned int esdhc_get_max_clock(struct sdhci_host *host)
return of_host->clock;
}
+static unsigned int esdhc_get_min_clock(struct sdhci_host *host)
+{
+ struct sdhci_of_host *of_host = sdhci_priv(host);
+
+ return of_host->clock / 256 / 16;
+}
+
static unsigned int esdhc_get_timeout_clock(struct sdhci_host *host)
{
struct sdhci_of_host *of_host = sdhci_priv(host);
@@ -184,6 +191,7 @@ static struct sdhci_of_data sdhci_esdhc = {
.set_clock = esdhc_set_clock,
.enable_dma = esdhc_enable_dma,
.get_max_clock = esdhc_get_max_clock,
+ .get_min_clock = esdhc_get_min_clock,
.get_timeout_clock = esdhc_get_timeout_clock,
},
};
@@ -226,7 +234,7 @@ static int __devinit sdhci_of_probe(struct of_device *ofdev,
return -ENODEV;
host = sdhci_alloc_host(&ofdev->dev, sizeof(*of_host));
- if (!host)
+ if (IS_ERR(host))
return -ENOMEM;
of_host = sdhci_priv(host);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 6779b4ecab18..fc96f8cb9c0b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -773,8 +773,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
}
if (!(host->flags & SDHCI_REQ_USE_DMA)) {
- sg_miter_start(&host->sg_miter,
- data->sg, data->sg_len, SG_MITER_ATOMIC);
+ int flags;
+
+ flags = SG_MITER_ATOMIC;
+ if (host->data->flags & MMC_DATA_READ)
+ flags |= SG_MITER_TO_SG;
+ else
+ flags |= SG_MITER_FROM_SG;
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
host->blocks = data->blocks;
}
@@ -1766,7 +1772,10 @@ int sdhci_add_host(struct sdhci_host *host)
* Set host parameters.
*/
mmc->ops = &sdhci_ops;
- mmc->f_min = host->max_clk / 256;
+ if (host->ops->get_min_clock)
+ mmc->f_min = host->ops->get_min_clock(host);
+ else
+ mmc->f_min = host->max_clk / 256;
mmc->f_max = host->max_clk;
mmc->caps = MMC_CAP_SDIO_IRQ;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 831ddf7dcb49..c77e9ff30223 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -302,6 +302,7 @@ struct sdhci_ops {
int (*enable_dma)(struct sdhci_host *host);
unsigned int (*get_max_clock)(struct sdhci_host *host);
+ unsigned int (*get_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
};