summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-04 13:45:17 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-04 13:45:17 -0700
commit173192958d06b8d1eb44f56d74373052ad6a9a60 (patch)
tree838a4f063c994d4d0a6259a85f21005c4098b752 /drivers
parente72a5d1ceb1c5cbe39c35c1c7a7f5909cbe8451a (diff)
parente4404fab2e0b70287a471a1e760c9338ce683fde (diff)
Merge tag 'mmc-updates-for-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
Pull MMC update from Chris Ball: "MMC highlights for 3.10: Core: - Introduce MMC_CAP2_NO_PRESCAN_POWERUP to allow skipping mmc_power_up() at boot/initialization time if it's already happened, for performance (faster boot time) reasons. - Fix a bit width test failure that resulted in old eMMC cards being put into 1-bit mode when 4-bit mode was available. - Expose fwrev/hwrev for MMCv4 parts. - Improve card removal logic in the case where the card's removed slowly; we were missing card removal events if the card retained contact with the slot pads for long enough to reply to a CMD13 while being removed. Drivers: - davinci_mmc: Support using PIO instead of DMA. - dw_mmc: Add support for Exynos4412. - mxcmmc: DT support, use slot-gpio API. - mxs-mmc: Add broken-cd/cd-inverted/non-removable DT property support. - sdhci-sirf: New sdhci-pltfm driver for CSR SiRF SoCs: SiRFprimaII: unicore ARM Cortex-A9 SiRFatlas6: unicore ARM Cortex-A9 SiRFmarco: dual core ARM Cortex-A9 SMP - sdhci-tegra: Add support for Tegra114 platforms, use mmc_of_parse()" * tag 'mmc-updates-for-3.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (66 commits) mmc: sdhci-tegra: fix MODULE_DEVICE_TABLE mmc: core: fix init controller performance regression, updated patch mmc: mxcmmc: enable DMA support on mpc512x mmc: mxcmmc: constify mxcmci_devtype mmc: mxcmmc: use slot-gpio API for write-protect detection mmc: mxcmmc: add mpc512x SDHC support mmc: mxcmmc: fix race conditions for host->req and host->data access mmc: mxcmmc: DT support mmc: dw_mmc: let device core setup the default pin configuration mmc: mxs-mmc: add broken-cd property mmc: mxs-mmc: add non-removable property mmc: mxs-mmc: add cd-inverted property mmc: core: call pm_runtime_put_noidle in pm_runtime_get_sync failed case mmc: mxcmmc: Fix bug when card is present during boot mmc: core: fix performance regression initializing MMC host controllers Revert "mmc: core: wait while adding MMC host to ensure root mounts successfully" mmc: atmel-mci: pio hang on block errors mmc: core: Fix bit width test failing on old eMMC cards mmc: dw_mmc: Use pr_info instead of printk mmc: dw_mmc: Check return value of regulator_enable ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mmc/card/block.c10
-rw-r--r--drivers/mmc/card/queue.c3
-rw-r--r--drivers/mmc/card/queue.h2
-rw-r--r--drivers/mmc/core/core.c18
-rw-r--r--drivers/mmc/core/mmc.c5
-rw-r--r--drivers/mmc/core/sdio.c4
-rw-r--r--drivers/mmc/core/sdio_bus.c23
-rw-r--r--drivers/mmc/host/Kconfig31
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/android-goldfish.c2
-rw-r--r--drivers/mmc/host/atmel-mci.c16
-rw-r--r--drivers/mmc/host/davinci_mmc.c23
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c54
-rw-r--r--drivers/mmc/host/dw_mmc.c153
-rw-r--r--drivers/mmc/host/dw_mmc.h3
-rw-r--r--drivers/mmc/host/mvsdio.c54
-rw-r--r--drivers/mmc/host/mxcmmc.c296
-rw-r--r--drivers/mmc/host/mxs-mmc.c15
-rw-r--r--drivers/mmc/host/omap_hsmmc.c14
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c10
-rw-r--r--drivers/mmc/host/sdhci-acpi.c2
-rw-r--r--drivers/mmc/host/sdhci-bcm2835.c4
-rw-r--r--drivers/mmc/host/sdhci-cns3xxx.c4
-rw-r--r--drivers/mmc/host/sdhci-dove.c4
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c4
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c4
-rw-r--r--drivers/mmc/host/sdhci-of-hlwd.c4
-rw-r--r--drivers/mmc/host/sdhci-pci.c4
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c7
-rw-r--r--drivers/mmc/host/sdhci-pltfm.h6
-rw-r--r--drivers/mmc/host/sdhci-pxav2.c2
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c49
-rw-r--r--drivers/mmc/host/sdhci-s3c.c88
-rw-r--r--drivers/mmc/host/sdhci-sirf.c193
-rw-r--r--drivers/mmc/host/sdhci-spear.c4
-rw-r--r--drivers/mmc/host/sdhci-tegra.c124
-rw-r--r--drivers/mmc/host/sdhci.c39
-rw-r--r--drivers/mmc/host/wmt-sdmmc.c4
38 files changed, 770 insertions, 513 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 5bab73b91c20..e12a03cc2a6e 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -1932,8 +1932,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
}
out:
- if (!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST))
- /* release host only when there are no more requests */
+ if ((!req && !(mq->flags & MMC_QUEUE_NEW_REQUEST)) ||
+ (req && (req->cmd_flags & MMC_REQ_SPECIAL_MASK)))
+ /*
+ * Release host when there are no more requests
+ * and after special request(discard, flush) is done.
+ * In case sepecial request, there is no reentry to
+ * the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
+ */
mmc_release_host(card->host);
return ret;
}
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index fa4e44ee7961..9447a0e970d1 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -22,9 +22,6 @@
#define MMC_QUEUE_BOUNCESZ 65536
-
-#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH)
-
/*
* Prepare a MMC request. This just filters out odd stuff.
*/
diff --git a/drivers/mmc/card/queue.h b/drivers/mmc/card/queue.h
index 031bf6376c99..5752d50049a3 100644
--- a/drivers/mmc/card/queue.h
+++ b/drivers/mmc/card/queue.h
@@ -1,6 +1,8 @@
#ifndef MMC_QUEUE_H
#define MMC_QUEUE_H
+#define MMC_REQ_SPECIAL_MASK (REQ_DISCARD | REQ_FLUSH)
+
struct request;
struct task_struct;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9290bb51a06a..c40396f23202 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2289,6 +2289,19 @@ int _mmc_detect_card_removed(struct mmc_host *host)
return 1;
ret = host->bus_ops->alive(host);
+
+ /*
+ * Card detect status and alive check may be out of sync if card is
+ * removed slowly, when card detect switch changes while card/slot
+ * pads are still contacted in hardware (refer to "SD Card Mechanical
+ * Addendum, Appendix C: Card Detection Switch"). So reschedule a
+ * detect work 200ms later for this case.
+ */
+ if (!ret && host->ops->get_cd && !host->ops->get_cd(host)) {
+ mmc_detect_change(host, msecs_to_jiffies(200));
+ pr_debug("%s: card removed too slowly\n", mmc_hostname(host));
+ }
+
if (ret) {
mmc_card_set_removed(host->card);
pr_debug("%s: card remove detected\n", mmc_hostname(host));
@@ -2403,7 +2416,10 @@ void mmc_start_host(struct mmc_host *host)
{
host->f_init = max(freqs[0], host->f_min);
host->rescan_disable = 0;
- mmc_power_up(host);
+ if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
+ mmc_power_off(host);
+ else
+ mmc_power_up(host);
mmc_detect_change(host, 0);
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index c8f3d6e0684e..0cbd1effe960 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -96,6 +96,7 @@ static int mmc_decode_cid(struct mmc_card *card)
card->cid.prod_name[3] = UNSTUFF_BITS(resp, 72, 8);
card->cid.prod_name[4] = UNSTUFF_BITS(resp, 64, 8);
card->cid.prod_name[5] = UNSTUFF_BITS(resp, 56, 8);
+ card->cid.prv = UNSTUFF_BITS(resp, 48, 8);
card->cid.serial = UNSTUFF_BITS(resp, 16, 32);
card->cid.month = UNSTUFF_BITS(resp, 12, 4);
card->cid.year = UNSTUFF_BITS(resp, 8, 4) + 1997;
@@ -368,13 +369,13 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT];
card->ext_csd.raw_trim_mult =
ext_csd[EXT_CSD_TRIM_MULT];
+ card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
if (card->ext_csd.rev >= 4) {
/*
* Enhanced area feature support -- check whether the eMMC
* card has the Enhanced area enabled. If so, export enhanced
* area offset and size to user by adding sysfs interface.
*/
- card->ext_csd.raw_partition_support = ext_csd[EXT_CSD_PARTITION_SUPPORT];
if ((ext_csd[EXT_CSD_PARTITION_SUPPORT] & 0x2) &&
(ext_csd[EXT_CSD_PARTITION_ATTRIBUTE] & 0x1)) {
hc_erase_grp_sz =
@@ -627,6 +628,7 @@ MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
+MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv);
MMC_DEV_ATTR(serial, "0x%08x\n", card->cid.serial);
MMC_DEV_ATTR(enhanced_area_offset, "%llu\n",
card->ext_csd.enhanced_area_offset);
@@ -645,6 +647,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_manfid.attr,
&dev_attr_name.attr,
&dev_attr_oemid.attr,
+ &dev_attr_prv.attr,
&dev_attr_serial.attr,
&dev_attr_enhanced_area_offset.attr,
&dev_attr_enhanced_area_size.attr,
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index aa0719a4dfd1..6889a821c1da 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -861,8 +861,10 @@ static void mmc_sdio_detect(struct mmc_host *host)
/* Make sure card is powered before detecting it */
if (host->caps & MMC_CAP_POWER_OFF_CARD) {
err = pm_runtime_get_sync(&host->card->dev);
- if (err < 0)
+ if (err < 0) {
+ pm_runtime_put_noidle(&host->card->dev);
goto out;
+ }
}
mmc_claim_host(host);
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 5e57048e2c1d..546c67c2bbbf 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -16,6 +16,7 @@
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -137,7 +138,7 @@ static int sdio_bus_probe(struct device *dev)
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD) {
ret = pm_runtime_get_sync(dev);
if (ret < 0)
- goto out;
+ goto disable_runtimepm;
}
/* Set the default block size so the driver is sure it's something
@@ -157,7 +158,6 @@ static int sdio_bus_probe(struct device *dev)
disable_runtimepm:
if (func->card->host->caps & MMC_CAP_POWER_OFF_CARD)
pm_runtime_put_noidle(dev);
-out:
return ret;
}
@@ -299,6 +299,19 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card)
return func;
}
+#ifdef CONFIG_ACPI
+static void sdio_acpi_set_handle(struct sdio_func *func)
+{
+ struct mmc_host *host = func->card->host;
+ u64 addr = (host->slotno << 16) | func->num;
+
+ ACPI_HANDLE_SET(&func->dev,
+ acpi_get_child(ACPI_HANDLE(host->parent), addr));
+}
+#else
+static inline void sdio_acpi_set_handle(struct sdio_func *func) {}
+#endif
+
/*
* Register a new SDIO function with the driver model.
*/
@@ -308,9 +321,12 @@ int sdio_add_func(struct sdio_func *func)
dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
+ sdio_acpi_set_handle(func);
ret = device_add(&func->dev);
- if (ret == 0)
+ if (ret == 0) {
sdio_func_set_present(func);
+ acpi_dev_pm_attach(&func->dev, false);
+ }
return ret;
}
@@ -326,6 +342,7 @@ void sdio_remove_func(struct sdio_func *func)
if (!sdio_func_present(func))
return;
+ acpi_dev_pm_detach(&func->dev, false);
device_del(&func->dev);
put_device(&func->dev);
}
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index d88219e1d86e..9ab8f8dee942 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -190,6 +190,17 @@ config MMC_SDHCI_S3C
If unsure, say N.
+config MMC_SDHCI_SIRF
+ tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs"
+ depends on ARCH_SIRF
+ depends on MMC_SDHCI_PLTFM
+ help
+ This selects the SDHCI support for SiRF System-on-Chip devices.
+
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
config MMC_SDHCI_PXAV3
tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
depends on CLKDEV_LOOKUP
@@ -300,16 +311,6 @@ config MMC_ATMELMCI
If unsure, say N.
-config MMC_ATMELMCI_DMA
- bool "Atmel MCI DMA support"
- depends on MMC_ATMELMCI && (AVR32 || ARCH_AT91SAM9G45) && DMA_ENGINE
- help
- Say Y here to have the Atmel MCI driver use a DMA engine to
- do data transfers and thus increase the throughput and
- reduce the CPU utilization.
-
- If unsure, say N.
-
config MMC_MSM
tristate "Qualcomm SDCC Controller Support"
depends on MMC && ARCH_MSM
@@ -319,12 +320,12 @@ config MMC_MSM
support for SDIO devices.
config MMC_MXC
- tristate "Freescale i.MX21/27/31 Multimedia Card Interface support"
- depends on ARCH_MXC
+ tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support"
+ depends on ARCH_MXC || PPC_MPC512x
help
- This selects the Freescale i.MX21, i.MX27 and i.MX31 Multimedia card
- Interface. If you have a i.MX platform with a Multimedia Card slot,
- say Y or M here.
+ This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x
+ Multimedia Card Interface. If you have an i.MX or MPC512x platform
+ with a Multimedia Card slot, say Y or M here.
If unsure, say N.
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index c380e3cf0a3b..cd3228075553 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MMC_SDHCI_ACPI) += sdhci-acpi.o
obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o
obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
+obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c
index ef3aef0f376d..7780c14704c4 100644
--- a/drivers/mmc/host/android-goldfish.c
+++ b/drivers/mmc/host/android-goldfish.c
@@ -476,7 +476,7 @@ static int goldfish_mmc_probe(struct platform_device *pdev)
host->mmc = mmc;
pr_err("mmc: Mapping %lX to %lX\n", (long)res->start, (long)res->end);
- host->reg_base = ioremap(res->start, res->end - res->start + 1);
+ host->reg_base = ioremap(res->start, resource_size(res));
if (host->reg_base == NULL) {
ret = -ENOMEM;
goto ioremap_failed;
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 722af1de7967..e75774f72606 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -178,6 +178,7 @@ struct atmel_mci {
void __iomem *regs;
struct scatterlist *sg;
+ unsigned int sg_len;
unsigned int pio_offset;
unsigned int *buffer;
unsigned int buf_size;
@@ -892,6 +893,7 @@ static u32 atmci_prepare_data(struct atmel_mci *host, struct mmc_data *data)
data->error = -EINPROGRESS;
host->sg = data->sg;
+ host->sg_len = data->sg_len;
host->data = data;
host->data_chan = NULL;
@@ -1826,7 +1828,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
if (offset == sg->length) {
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
- if (!sg)
+ host->sg_len--;
+ if (!sg || !host->sg_len)
goto done;
offset = 0;
@@ -1839,7 +1842,8 @@ static void atmci_read_data_pio(struct atmel_mci *host)
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
- if (!sg)
+ host->sg_len--;
+ if (!sg || !host->sg_len)
goto done;
offset = 4 - remaining;
@@ -1890,7 +1894,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
nbytes += 4;
if (offset == sg->length) {
host->sg = sg = sg_next(sg);
- if (!sg)
+ host->sg_len--;
+ if (!sg || !host->sg_len)
goto done;
offset = 0;
@@ -1904,7 +1909,8 @@ static void atmci_write_data_pio(struct atmel_mci *host)
nbytes += remaining;
host->sg = sg = sg_next(sg);
- if (!sg) {
+ host->sg_len--;
+ if (!sg || !host->sg_len) {
atmci_writel(host, ATMCI_TDR, value);
goto done;
}
@@ -2487,10 +2493,8 @@ static int __exit atmci_remove(struct platform_device *pdev)
atmci_readl(host, ATMCI_SR);
clk_disable(host->mck);
-#ifdef CONFIG_MMC_ATMELMCI_DMA
if (host->dma.chan)
dma_release_channel(host->dma.chan);
-#endif
free_irq(platform_get_irq(pdev, 0), host);
iounmap(host->regs);
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index f8a96d652e9e..3946a0eb3a03 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -1264,13 +1264,15 @@ static int __init davinci_mmcsd_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r)
- goto out;
- host->rxdma = r->start;
+ dev_warn(&pdev->dev, "RX DMA resource not specified\n");
+ else
+ host->rxdma = r->start;
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r)
- goto out;
- host->txdma = r->start;
+ dev_warn(&pdev->dev, "TX DMA resource not specified\n");
+ else
+ host->txdma = r->start;
host->mem_res = mem;
host->base = ioremap(mem->start, mem_size);
@@ -1488,18 +1490,7 @@ static struct platform_driver davinci_mmcsd_driver = {
.id_table = davinci_mmc_devtype,
};
-static int __init davinci_mmcsd_init(void)
-{
- return platform_driver_probe(&davinci_mmcsd_driver,
- davinci_mmcsd_probe);
-}
-module_init(davinci_mmcsd_init);
-
-static void __exit davinci_mmcsd_exit(void)
-{
- platform_driver_unregister(&davinci_mmcsd_driver);
-}
-module_exit(davinci_mmcsd_exit);
+module_platform_driver_probe(davinci_mmcsd_driver, davinci_mmcsd_probe);
MODULE_AUTHOR("Texas Instruments India");
MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 72fd0f2c9013..f013e7e3746b 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -152,45 +152,8 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
return 0;
}
-static int dw_mci_exynos_setup_bus(struct dw_mci *host,
- struct device_node *slot_np, u8 bus_width)
-{
- int idx, gpio, ret;
-
- if (!slot_np)
- return -EINVAL;
-
- /* cmd + clock + bus-width pins */
- for (idx = 0; idx < NUM_PINS(bus_width); idx++) {
- gpio = of_get_gpio(slot_np, idx);
- if (!gpio_is_valid(gpio)) {
- dev_err(host->dev, "invalid gpio: %d\n", gpio);
- return -EINVAL;
- }
-
- ret = devm_gpio_request(host->dev, gpio, "dw-mci-bus");
- if (ret) {
- dev_err(host->dev, "gpio [%d] request failed\n", gpio);
- return -EBUSY;
- }
- }
-
- if (host->pdata->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
- return 0;
-
- gpio = of_get_named_gpio(slot_np, "samsung,cd-pinmux-gpio", 0);
- if (gpio_is_valid(gpio)) {
- if (devm_gpio_request(host->dev, gpio, "dw-mci-cd"))
- dev_err(host->dev, "gpio [%d] request failed\n", gpio);
- } else {
- dev_info(host->dev, "cd gpio not available");
- }
-
- return 0;
-}
-
-/* Exynos5250 controller specific capabilities */
-static unsigned long exynos5250_dwmmc_caps[4] = {
+/* Common capabilities of Exynos4/Exynos5 SoC */
+static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
MMC_CAP_CMD23,
@@ -198,24 +161,25 @@ static unsigned long exynos5250_dwmmc_caps[4] = {
MMC_CAP_CMD23,
};
-static const struct dw_mci_drv_data exynos5250_drv_data = {
- .caps = exynos5250_dwmmc_caps,
+static const struct dw_mci_drv_data exynos_drv_data = {
+ .caps = exynos_dwmmc_caps,
.init = dw_mci_exynos_priv_init,
.setup_clock = dw_mci_exynos_setup_clock,
.prepare_command = dw_mci_exynos_prepare_command,
.set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt,
- .setup_bus = dw_mci_exynos_setup_bus,
};
static const struct of_device_id dw_mci_exynos_match[] = {
+ { .compatible = "samsung,exynos4412-dw-mshc",
+ .data = &exynos_drv_data, },
{ .compatible = "samsung,exynos5250-dw-mshc",
- .data = &exynos5250_drv_data, },
+ .data = &exynos_drv_data, },
{},
};
MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
-int dw_mci_exynos_probe(struct platform_device *pdev)
+static int dw_mci_exynos_probe(struct platform_device *pdev)
{
const struct dw_mci_drv_data *drv_data;
const struct of_device_id *match;
@@ -230,7 +194,7 @@ static struct platform_driver dw_mci_exynos_pltfm_driver = {
.remove = __exit_p(dw_mci_pltfm_remove),
.driver = {
.name = "dwmmc_exynos",
- .of_match_table = of_match_ptr(dw_mci_exynos_match),
+ .of_match_table = dw_mci_exynos_match,
.pm = &dw_mci_pltfm_pmops,
},
};
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 98342213ed21..bc3a1bc4940f 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -795,9 +795,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* DDR mode set */
if (ios->timing == MMC_TIMING_UHS_DDR50)
- regs |= (0x1 << slot->id) << 16;
+ regs |= ((0x1 << slot->id) << 16);
else
- regs &= ~(0x1 << slot->id) << 16;
+ regs &= ~((0x1 << slot->id) << 16);
mci_writel(slot->host, UHS_REG, regs);
@@ -818,6 +818,20 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) {
case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
+ /* Power up slot */
+ if (slot->host->pdata->setpower)
+ slot->host->pdata->setpower(slot->id, mmc->ocr_avail);
+ regs = mci_readl(slot->host, PWREN);
+ regs |= (1 << slot->id);
+ mci_writel(slot->host, PWREN, regs);
+ break;
+ case MMC_POWER_OFF:
+ /* Power down slot */
+ if (slot->host->pdata->setpower)
+ slot->host->pdata->setpower(slot->id, 0);
+ regs = mci_readl(slot->host, PWREN);
+ regs &= ~(1 << slot->id);
+ mci_writel(slot->host, PWREN, regs);
break;
default:
break;
@@ -1191,12 +1205,15 @@ static void dw_mci_pull_final_bytes(struct dw_mci *host, void *buf, int cnt)
static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
{
+ struct mmc_data *data = host->data;
+ int init_cnt = cnt;
+
/* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len;
cnt -= len;
- if (!sg_next(host->sg) || host->part_buf_count == 2) {
+ if (host->part_buf_count == 2) {
mci_writew(host, DATA(host->data_offset),
host->part_buf16);
host->part_buf_count = 0;
@@ -1229,9 +1246,11 @@ static void dw_mci_push_data16(struct dw_mci *host, void *buf, int cnt)
/* put anything remaining in the part_buf */
if (cnt) {
dw_mci_set_part_bytes(host, buf, cnt);
- if (!sg_next(host->sg))
+ /* Push data if we have reached the expected data length */
+ if ((data->bytes_xfered + init_cnt) ==
+ (data->blksz * data->blocks))
mci_writew(host, DATA(host->data_offset),
- host->part_buf16);
+ host->part_buf16);
}
}
@@ -1269,12 +1288,15 @@ static void dw_mci_pull_data16(struct dw_mci *host, void *buf, int cnt)
static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
{
+ struct mmc_data *data = host->data;
+ int init_cnt = cnt;
+
/* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len;
cnt -= len;
- if (!sg_next(host->sg) || host->part_buf_count == 4) {
+ if (host->part_buf_count == 4) {
mci_writel(host, DATA(host->data_offset),
host->part_buf32);
host->part_buf_count = 0;
@@ -1307,9 +1329,11 @@ static void dw_mci_push_data32(struct dw_mci *host, void *buf, int cnt)
/* put anything remaining in the part_buf */
if (cnt) {
dw_mci_set_part_bytes(host, buf, cnt);
- if (!sg_next(host->sg))
+ /* Push data if we have reached the expected data length */
+ if ((data->bytes_xfered + init_cnt) ==
+ (data->blksz * data->blocks))
mci_writel(host, DATA(host->data_offset),
- host->part_buf32);
+ host->part_buf32);
}
}
@@ -1347,13 +1371,17 @@ static void dw_mci_pull_data32(struct dw_mci *host, void *buf, int cnt)
static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
{
+ struct mmc_data *data = host->data;
+ int init_cnt = cnt;
+
/* try and push anything in the part_buf */
if (unlikely(host->part_buf_count)) {
int len = dw_mci_push_part_bytes(host, buf, cnt);
buf += len;
cnt -= len;
- if (!sg_next(host->sg) || host->part_buf_count == 8) {
- mci_writew(host, DATA(host->data_offset),
+
+ if (host->part_buf_count == 8) {
+ mci_writeq(host, DATA(host->data_offset),
host->part_buf);
host->part_buf_count = 0;
}
@@ -1385,9 +1413,11 @@ static void dw_mci_push_data64(struct dw_mci *host, void *buf, int cnt)
/* put anything remaining in the part_buf */
if (cnt) {
dw_mci_set_part_bytes(host, buf, cnt);
- if (!sg_next(host->sg))
+ /* Push data if we have reached the expected data length */
+ if ((data->bytes_xfered + init_cnt) ==
+ (data->blksz * data->blocks))
mci_writeq(host, DATA(host->data_offset),
- host->part_buf);
+ host->part_buf);
}
}
@@ -1438,7 +1468,7 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
host->pull_data(host, buf, cnt);
}
-static void dw_mci_read_data_pio(struct dw_mci *host)
+static void dw_mci_read_data_pio(struct dw_mci *host, bool dto)
{
struct sg_mapping_iter *sg_miter = &host->sg_miter;
void *buf;
@@ -1446,7 +1476,7 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
struct mmc_data *data = host->data;
int shift = host->data_shift;
u32 status;
- unsigned int nbytes = 0, len;
+ unsigned int len;
unsigned int remain, fcnt;
do {
@@ -1465,16 +1495,17 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
if (!len)
break;
dw_mci_pull_data(host, (void *)(buf + offset), len);
+ data->bytes_xfered += len;
offset += len;
- nbytes += len;
remain -= len;
} while (remain);
sg_miter->consumed = offset;
status = mci_readl(host, MINTSTS);
mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
- } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
- data->bytes_xfered += nbytes;
+ /* if the RXDR is ready read again */
+ } while ((status & SDMMC_INT_RXDR) ||
+ (dto && SDMMC_GET_FCNT(mci_readl(host, STATUS))));
if (!remain) {
if (!sg_miter_next(sg_miter))
@@ -1485,7 +1516,6 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
return;
done:
- data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb();
@@ -1500,7 +1530,7 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
struct mmc_data *data = host->data;
int shift = host->data_shift;
u32 status;
- unsigned int nbytes = 0, len;
+ unsigned int len;
unsigned int fifo_depth = host->fifo_depth;
unsigned int remain, fcnt;
@@ -1521,8 +1551,8 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
if (!len)
break;
host->push_data(host, (void *)(buf + offset), len);
+ data->bytes_xfered += len;
offset += len;
- nbytes += len;
remain -= len;
} while (remain);
@@ -1530,7 +1560,6 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
status = mci_readl(host, MINTSTS);
mci_wr