aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host')
-rw-r--r--drivers/mmc/host/Kconfig12
-rw-r--r--drivers/mmc/host/Makefile4
-rw-r--r--drivers/mmc/host/atmel-mci.c28
-rw-r--r--drivers/mmc/host/bcm2835.c12
-rw-r--r--drivers/mmc/host/cavium.c4
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c4
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c48
-rw-r--r--drivers/mmc/host/dw_mmc.c225
-rw-r--r--drivers/mmc/host/dw_mmc.h7
-rw-r--r--drivers/mmc/host/meson-gx-mmc.c9
-rw-r--r--drivers/mmc/host/mtk-sd.c2
-rw-r--r--drivers/mmc/host/omap_hsmmc.c55
-rw-r--r--drivers/mmc/host/pxamci.c6
-rw-r--r--drivers/mmc/host/renesas_sdhi.h39
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c (renamed from drivers/mmc/host/sh_mobile_sdhi.c)273
-rw-r--r--drivers/mmc/host/renesas_sdhi_sys_dmac.c (renamed from drivers/mmc/host/tmio_mmc_dma.c)186
-rw-r--r--drivers/mmc/host/sdhci-acpi.c4
-rw-r--r--drivers/mmc/host/sdhci-brcmstb.c3
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c192
-rw-r--r--drivers/mmc/host/sdhci-esdhc.h1
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c2
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c677
-rw-r--r--drivers/mmc/host/sdhci-pci.h46
-rw-r--r--drivers/mmc/host/sdricoh_cs.c3
-rw-r--r--drivers/mmc/host/tmio_mmc.c20
-rw-r--r--drivers/mmc/host/tmio_mmc.h75
-rw-r--r--drivers/mmc/host/tmio_mmc_core.c (renamed from drivers/mmc/host/tmio_mmc_pio.c)282
-rw-r--r--drivers/mmc/host/vub300.c3
28 files changed, 958 insertions, 1264 deletions
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 2db84dd664d7..5755b69f2f72 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -408,11 +408,11 @@ config MMC_AU1X
config MMC_ATMELMCI
tristate "Atmel SD/MMC Driver (Multimedia Card Interface)"
- depends on AVR32 || ARCH_AT91
+ depends on ARCH_AT91
help
- This selects the Atmel Multimedia Card Interface driver. If
- you have an AT32 (AVR32) or AT91 platform with a Multimedia
- Card slot, say Y or M here.
+ This selects the Atmel Multimedia Card Interface driver.
+ If you have an AT91 platform with a Multimedia Card slot,
+ say Y or M here.
If unsure, say N.
@@ -571,13 +571,13 @@ config MMC_TMIO
T7L66XB and also HTC ASIC3
config MMC_SDHI
- tristate "SH-Mobile SDHI SD/SDIO controller support"
+ tristate "Renesas SDHI SD/SDIO controller support"
depends on SUPERH || ARM || ARM64
depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
select MMC_TMIO_CORE
help
This provides support for the SDHI SD/SDIO controller found in
- SuperH and ARM SH-Mobile SoCs
+ Renesas SuperH, ARM and ARM64 based SoCs
config MMC_CB710
tristate "ENE CB710 MMC/SD Interface support"
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 926347c2eeb4..4d4547116311 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -36,9 +36,7 @@ obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
obj-$(CONFIG_MMC_TMIO_CORE) += tmio_mmc_core.o
-tmio_mmc_core-y := tmio_mmc_pio.o
-tmio_mmc_core-$(subst m,y,$(CONFIG_MMC_SDHI)) += tmio_mmc_dma.o
-obj-$(CONFIG_MMC_SDHI) += sh_mobile_sdhi.o
+obj-$(CONFIG_MMC_SDHI) += renesas_sdhi_core.o renesas_sdhi_sys_dmac.o
obj-$(CONFIG_MMC_CB710) += cb710-mmc.o
obj-$(CONFIG_MMC_VIA_SDMMC) += via-sdmmc.o
obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 388e4a3f13e6..97de2d32ba84 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -44,7 +44,7 @@
#include <asm/unaligned.h>
/*
- * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors
+ * Superset of MCI IP registers integrated in Atmel AT91 Processor
* Registers and bitfields marked with [2] are only available in MCI2
*/
@@ -172,13 +172,6 @@
#define atmci_writel(port, reg, value) \
__raw_writel((value), (port)->regs + reg)
-/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */
-#ifdef CONFIG_AVR32
-# define ATMCI_PDC_CONNECTED 0
-#else
-# define ATMCI_PDC_CONNECTED 1
-#endif
-
#define AUTOSUSPEND_DELAY 50
#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
@@ -667,10 +660,8 @@ atmci_of_init(struct platform_device *pdev)
}
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(&pdev->dev, "could not allocate memory for pdata\n");
+ if (!pdata)
return ERR_PTR(-ENOMEM);
- }
for_each_child_of_node(np, cnp) {
if (of_property_read_u32(cnp, "reg", &slot_id)) {
@@ -1549,21 +1540,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
break;
default:
- /*
- * TODO: None of the currently available AVR32-based
- * boards allow MMC power to be turned off. Implement
- * power control when this can be tested properly.
- *
- * We also need to hook this into the clock management
- * somehow so that newly inserted cards aren't
- * subjected to a fast clock before we have a chance
- * to figure out what the maximum rate is. Currently,
- * there's no way to avoid this, and there never will
- * be for boards that don't support power control.
- */
break;
}
-
}
static int atmci_get_ro(struct mmc_host *mmc)
@@ -2464,7 +2442,7 @@ static void atmci_get_cap(struct atmel_mci *host)
"version: 0x%x\n", version);
host->caps.has_dma_conf_reg = 0;
- host->caps.has_pdc = ATMCI_PDC_CONNECTED;
+ host->caps.has_pdc = 1;
host->caps.has_cfg_reg = 0;
host->caps.has_cstor_reg = 0;
host->caps.has_highspeed = 0;
diff --git a/drivers/mmc/host/bcm2835.c b/drivers/mmc/host/bcm2835.c
index 1f343a477b3d..abba9a2a78b8 100644
--- a/drivers/mmc/host/bcm2835.c
+++ b/drivers/mmc/host/bcm2835.c
@@ -1172,7 +1172,10 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (mrq->data && !is_power_of_2(mrq->data->blksz)) {
dev_err(dev, "unsupported block size (%d bytes)\n",
mrq->data->blksz);
- mrq->cmd->error = -EINVAL;
+
+ if (mrq->cmd)
+ mrq->cmd->error = -EINVAL;
+
mmc_request_done(mmc, mrq);
return;
}
@@ -1194,7 +1197,10 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq)
readl(host->ioaddr + SDCMD) & SDCMD_CMD_MASK,
edm);
bcm2835_dumpregs(host);
- mrq->cmd->error = -EILSEQ;
+
+ if (mrq->cmd)
+ mrq->cmd->error = -EILSEQ;
+
bcm2835_finish_request(host);
mutex_unlock(&host->mutex);
return;
@@ -1207,7 +1213,7 @@ static void bcm2835_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (!host->use_busy)
bcm2835_finish_command(host);
}
- } else if (bcm2835_send_command(host, mrq->cmd)) {
+ } else if (mrq->cmd && bcm2835_send_command(host, mrq->cmd)) {
if (host->data && host->dma_desc) {
/* DMA transfer starts now, PIO starts after irq */
bcm2835_start_dma(host);
diff --git a/drivers/mmc/host/cavium.c b/drivers/mmc/host/cavium.c
index b8aaf0fdb77c..3686d77c717b 100644
--- a/drivers/mmc/host/cavium.c
+++ b/drivers/mmc/host/cavium.c
@@ -1035,10 +1035,12 @@ int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host)
* We only have a 3.3v supply, we cannot support any
* of the UHS modes. We do support the high speed DDR
* modes up to 52MHz.
+ *
+ * Disable bounce buffers for max_segs = 1
*/
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD |
- MMC_CAP_3_3V_DDR;
+ MMC_CAP_3_3V_DDR | MMC_CAP_NO_BOUNCE_BUFF;
if (host->use_sg)
mmc->max_segs = 16;
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 25691cca1881..35026795be28 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -157,8 +157,8 @@ static void dw_mci_exynos_set_clksel_timing(struct dw_mci *host, u32 timing)
* HOLD register should be bypassed in case there is no phase shift
* applied on CMD/DATA that is sent to the card.
*/
- if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->cur_slot)
- set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags);
+ if (!SDMMC_CLKSEL_GET_DRV_WD3(clksel) && host->slot)
+ set_bit(DW_MMC_CARD_NO_USE_HOLD, &host->slot->flags);
}
#ifdef CONFIG_PM
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 372fb6e948c1..a3f1c2b30145 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -25,6 +25,7 @@ struct dw_mci_rockchip_priv_data {
struct clk *drv_clk;
struct clk *sample_clk;
int default_sample_phase;
+ int num_phases;
};
static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
@@ -133,8 +134,8 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
}
}
-#define NUM_PHASES 360
-#define TUNING_ITERATION_TO_PHASE(i) (DIV_ROUND_UP((i) * 360, NUM_PHASES))
+#define TUNING_ITERATION_TO_PHASE(i, num_phases) \
+ (DIV_ROUND_UP((i) * 360, num_phases))
static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
{
@@ -159,13 +160,15 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
return -EIO;
}
- ranges = kmalloc_array(NUM_PHASES / 2 + 1, sizeof(*ranges), GFP_KERNEL);
+ ranges = kmalloc_array(priv->num_phases / 2 + 1,
+ sizeof(*ranges), GFP_KERNEL);
if (!ranges)
return -ENOMEM;
/* Try each phase and extract good ranges */
- for (i = 0; i < NUM_PHASES; ) {
- clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(i));
+ for (i = 0; i < priv->num_phases; ) {
+ clk_set_phase(priv->sample_clk,
+ TUNING_ITERATION_TO_PHASE(i, priv->num_phases));
v = !mmc_send_tuning(mmc, opcode, NULL);
@@ -179,7 +182,7 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
if (v) {
ranges[range_count-1].end = i;
i++;
- } else if (i == NUM_PHASES - 1) {
+ } else if (i == priv->num_phases - 1) {
/* No extra skipping rules if we're at the end */
i++;
} else {
@@ -188,11 +191,11 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
* one since testing bad phases is slow. Skip
* 20 degrees.
*/
- i += DIV_ROUND_UP(20 * NUM_PHASES, 360);
+ i += DIV_ROUND_UP(20 * priv->num_phases, 360);
/* Always test the last one */
- if (i >= NUM_PHASES)
- i = NUM_PHASES - 1;
+ if (i >= priv->num_phases)
+ i = priv->num_phases - 1;
}
prev_v = v;
@@ -210,7 +213,7 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
range_count--;
}
- if (ranges[0].start == 0 && ranges[0].end == NUM_PHASES - 1) {
+ if (ranges[0].start == 0 && ranges[0].end == priv->num_phases - 1) {
clk_set_phase(priv->sample_clk, priv->default_sample_phase);
dev_info(host->dev, "All phases work, using default phase %d.",
priv->default_sample_phase);
@@ -222,7 +225,7 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
int len = (ranges[i].end - ranges[i].start + 1);
if (len < 0)
- len += NUM_PHASES;
+ len += priv->num_phases;
if (longest_range_len < len) {
longest_range_len = len;
@@ -230,25 +233,30 @@ static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
}
dev_dbg(host->dev, "Good phase range %d-%d (%d len)\n",
- TUNING_ITERATION_TO_PHASE(ranges[i].start),
- TUNING_ITERATION_TO_PHASE(ranges[i].end),
+ TUNING_ITERATION_TO_PHASE(ranges[i].start,
+ priv->num_phases),
+ TUNING_ITERATION_TO_PHASE(ranges[i].end,
+ priv->num_phases),
len
);
}
dev_dbg(host->dev, "Best phase range %d-%d (%d len)\n",
- TUNING_ITERATION_TO_PHASE(ranges[longest_range].start),
- TUNING_ITERATION_TO_PHASE(ranges[longest_range].end),
+ TUNING_ITERATION_TO_PHASE(ranges[longest_range].start,
+ priv->num_phases),
+ TUNING_ITERATION_TO_PHASE(ranges[longest_range].end,
+ priv->num_phases),
longest_range_len
);
middle_phase = ranges[longest_range].start + longest_range_len / 2;
- middle_phase %= NUM_PHASES;
+ middle_phase %= priv->num_phases;
dev_info(host->dev, "Successfully tuned phase to %d\n",
- TUNING_ITERATION_TO_PHASE(middle_phase));
+ TUNING_ITERATION_TO_PHASE(middle_phase, priv->num_phases));
clk_set_phase(priv->sample_clk,
- TUNING_ITERATION_TO_PHASE(middle_phase));
+ TUNING_ITERATION_TO_PHASE(middle_phase,
+ priv->num_phases));
free:
kfree(ranges);
@@ -264,6 +272,10 @@ static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
if (!priv)
return -ENOMEM;
+ if (of_property_read_u32(np, "rockchip,desired-num-phases",
+ &priv->num_phases))
+ priv->num_phases = 360;
+
if (of_property_read_u32(np, "rockchip,default-sample-phase",
&priv->default_sample_phase))
priv->default_sample_phase = 0;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index e45129f48174..a9dfb26972f2 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -392,7 +392,7 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
cmdr = stop->opcode | SDMMC_CMD_STOP |
SDMMC_CMD_RESP_CRC | SDMMC_CMD_RESP_EXP;
- if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &host->cur_slot->flags))
+ if (!test_bit(DW_MMC_CARD_NO_USE_HOLD, &host->slot->flags))
cmdr |= SDMMC_CMD_USE_HOLD_REG;
return cmdr;
@@ -480,7 +480,7 @@ static void dw_mci_dmac_complete_dma(void *arg)
if ((host->use_dma == TRANS_MODE_EDMAC) &&
data && (data->flags & MMC_DATA_READ))
/* Invalidate cache after read */
- dma_sync_sg_for_cpu(mmc_dev(host->cur_slot->mmc),
+ dma_sync_sg_for_cpu(mmc_dev(host->slot->mmc),
data->sg,
data->sg_len,
DMA_FROM_DEVICE);
@@ -820,7 +820,7 @@ static int dw_mci_edmac_start_dma(struct dw_mci *host,
/* Flush cache before write */
if (host->data->flags & MMC_DATA_WRITE)
- dma_sync_sg_for_device(mmc_dev(host->cur_slot->mmc), sgl,
+ dma_sync_sg_for_device(mmc_dev(host->slot->mmc), sgl,
sg_elems, DMA_TO_DEVICE);
dma_async_issue_pending(host->dms->ch);
@@ -1282,7 +1282,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
mrq = slot->mrq;
- host->cur_slot = slot;
host->mrq = mrq;
host->pending_events = 0;
@@ -1621,16 +1620,10 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
if (card->type == MMC_TYPE_SDIO ||
card->type == MMC_TYPE_SD_COMBO) {
- if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) {
- pm_runtime_get_noresume(mmc->parent);
- set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
- }
+ set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
clk_en_a = clk_en_a_old & ~clken_low_pwr;
} else {
- if (test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags)) {
- pm_runtime_put_noidle(mmc->parent);
- clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
- }
+ clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
clk_en_a = clk_en_a_old | clken_low_pwr;
}
@@ -1642,9 +1635,8 @@ static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
}
}
-static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
+static void __dw_mci_enable_sdio_irq(struct dw_mci_slot *slot, int enb)
{
- struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
unsigned long irqflags;
u32 int_mask;
@@ -1662,6 +1654,27 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
spin_unlock_irqrestore(&host->irq_lock, irqflags);
}
+static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+ struct dw_mci *host = slot->host;
+
+ __dw_mci_enable_sdio_irq(slot, enb);
+
+ /* Avoid runtime suspending the device when SDIO IRQ is enabled */
+ if (enb)
+ pm_runtime_get_noresume(host->dev);
+ else
+ pm_runtime_put_noidle(host->dev);
+}
+
+static void dw_mci_ack_sdio_irq(struct mmc_host *mmc)
+{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
+
+ __dw_mci_enable_sdio_irq(slot, 1);
+}
+
static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
@@ -1749,7 +1762,7 @@ static bool dw_mci_reset(struct dw_mci *host)
ciu_out:
/* After a CTRL reset we need to have CIU set clock registers */
- mci_send_cmd(host->cur_slot, SDMMC_CMD_UPD_CLK, 0);
+ mci_send_cmd(host->slot, SDMMC_CMD_UPD_CLK, 0);
return ret;
}
@@ -1763,6 +1776,7 @@ static const struct mmc_host_ops dw_mci_ops = {
.get_cd = dw_mci_get_cd,
.hw_reset = dw_mci_hw_reset,
.enable_sdio_irq = dw_mci_enable_sdio_irq,
+ .ack_sdio_irq = dw_mci_ack_sdio_irq,
.execute_tuning = dw_mci_execute_tuning,
.card_busy = dw_mci_card_busy,
.start_signal_voltage_switch = dw_mci_switch_voltage,
@@ -1775,11 +1789,11 @@ static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
__acquires(&host->lock)
{
struct dw_mci_slot *slot;
- struct mmc_host *prev_mmc = host->cur_slot->mmc;
+ struct mmc_host *prev_mmc = host->slot->mmc;
WARN_ON(host->cmd || host->data);
- host->cur_slot->mrq = NULL;
+ host->slot->mrq = NULL;
host->mrq = NULL;
if (!list_empty(&host->queue)) {
slot = list_entry(host->queue.next,
@@ -1929,7 +1943,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
err = dw_mci_command_complete(host, cmd);
if (cmd == mrq->sbc && !err) {
prev_state = state = STATE_SENDING_CMD;
- __dw_mci_start_request(host, host->cur_slot,
+ __dw_mci_start_request(host, host->slot,
mrq->cmd);
goto unlock;
}
@@ -2548,26 +2562,19 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
static void dw_mci_handle_cd(struct dw_mci *host)
{
- int i;
+ struct dw_mci_slot *slot = host->slot;
- for (i = 0; i < host->num_slots; i++) {
- struct dw_mci_slot *slot = host->slot[i];
-
- if (!slot)
- continue;
-
- if (slot->mmc->ops->card_event)
- slot->mmc->ops->card_event(slot->mmc);
- mmc_detect_change(slot->mmc,
- msecs_to_jiffies(host->pdata->detect_delay_ms));
- }
+ if (slot->mmc->ops->card_event)
+ slot->mmc->ops->card_event(slot->mmc);
+ mmc_detect_change(slot->mmc,
+ msecs_to_jiffies(host->pdata->detect_delay_ms));
}
static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
{
struct dw_mci *host = dev_id;
u32 pending;
- int i;
+ struct dw_mci_slot *slot = host->slot;
pending = mci_readl(host, MINTSTS); /* read-only mask reg */
@@ -2644,18 +2651,11 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
dw_mci_handle_cd(host);
}
- /* Handle SDIO Interrupts */
- for (i = 0; i < host->num_slots; i++) {
- struct dw_mci_slot *slot = host->slot[i];
-
- if (!slot)
- continue;
-
- if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
- mci_writel(host, RINTSTS,
- SDMMC_INT_SDIO(slot->sdio_id));
- mmc_signal_sdio_irq(slot->mmc);
- }
+ if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
+ mci_writel(host, RINTSTS,
+ SDMMC_INT_SDIO(slot->sdio_id));
+ __dw_mci_enable_sdio_irq(slot, 0);
+ sdio_signal_irq(slot->mmc);
}
}
@@ -2687,7 +2687,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
+static int dw_mci_init_slot(struct dw_mci *host)
{
struct mmc_host *mmc;
struct dw_mci_slot *slot;
@@ -2700,15 +2700,15 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
return -ENOMEM;
slot = mmc_priv(mmc);
- slot->id = id;
- slot->sdio_id = host->sdio_id0 + id;
+ slot->id = 0;
+ slot->sdio_id = host->sdio_id0 + slot->id;
slot->mmc = mmc;
slot->host = host;
- host->slot[id] = slot;
+ host->slot = slot;
mmc->ops = &dw_mci_ops;
- if (of_property_read_u32_array(host->dev->of_node,
- "clock-freq-min-max", freq, 2)) {
+ if (device_property_read_u32_array(host->dev, "clock-freq-min-max",
+ freq, 2)) {
mmc->f_min = DW_MCI_FREQ_MIN;
mmc->f_max = DW_MCI_FREQ_MAX;
} else {
@@ -2755,6 +2755,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (ret)
goto err_host_allocated;
+ /* Process SDIO IRQs through the sdio_irq_work. */
+ if (mmc->caps & MMC_CAP_SDIO_IRQ)
+ mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
+
/* Useful defaults if platform data is unset. */
if (host->use_dma == TRANS_MODE_IDMAC) {
mmc->max_segs = host->ring_size;
@@ -2796,11 +2800,11 @@ err_host_allocated:
return ret;
}
-static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
+static void dw_mci_cleanup_slot(struct dw_mci_slot *slot)
{
/* Debugfs stuff is cleaned up by mmc core */
mmc_remove_host(slot->mmc);
- slot->host->slot[id] = NULL;
+ slot->host->slot = NULL;
mmc_free_host(slot->mmc);
}
@@ -2808,7 +2812,6 @@ static void dw_mci_init_dma(struct dw_mci *host)
{
int addr_config;
struct device *dev = host->dev;
- struct device_node *np = dev->of_node;
/*
* Check tansfer mode from HCON[17:16]
@@ -2869,8 +2872,9 @@ static void dw_mci_init_dma(struct dw_mci *host)
dev_info(host->dev, "Using internal DMA controller.\n");
} else {
/* TRANS_MODE_EDMAC: check dma bindings again */
- if ((of_property_count_strings(np, "dma-names") < 0) ||
- (!of_find_property(np, "dmas", NULL))) {
+ if ((device_property_read_string_array(dev, "dma-names",
+ NULL, 0) < 0) ||
+ !device_property_present(dev, "dmas")) {
goto no_dma;
}
host->dma_ops = &dw_mci_edmac_ops;
@@ -2937,7 +2941,6 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
{
struct dw_mci_board *pdata;
struct device *dev = host->dev;
- struct device_node *np = dev->of_node;
const struct dw_mci_drv_data *drv_data = host->drv_data;
int ret;
u32 clock_frequency;
@@ -2954,20 +2957,22 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
}
/* find out number of slots supported */
- of_property_read_u32(np, "num-slots", &pdata->num_slots);
+ if (device_property_read_u32(dev, "num-slots", &pdata->num_slots))
+ dev_info(dev, "'num-slots' was deprecated.\n");
- if (of_property_read_u32(np, "fifo-depth", &pdata->fifo_depth))
+ if (device_property_read_u32(dev, "fifo-depth", &pdata->fifo_depth))
dev_info(dev,
"fifo-depth property not found, using value of FIFOTH register as default\n");
- of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
+ device_property_read_u32(dev, "card-detect-delay",
+ &pdata->detect_delay_ms);
- of_property_read_u32(np, "data-addr", &host->data_addr_override);
+ device_property_read_u32(dev, "data-addr", &host->data_addr_override);
- if (of_get_property(np, "fifo-watermark-aligned", NULL))
+ if (device_property_present(dev, "fifo-watermark-aligned"))
host->wm_aligned = true;
- if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
+ if (!device_property_read_u32(dev, "clock-frequency", &clock_frequency))
pdata->bus_hz = clock_frequency;
if (drv_data && drv_data->parse_dt) {
@@ -2990,29 +2995,21 @@ static void dw_mci_enable_cd(struct dw_mci *host)
{
unsigned long irqflags;
u32 temp;
- int i;
- struct dw_mci_slot *slot;
/*
* No need for CD if all slots have a non-error GPIO
* as well as broken card detection is found.
*/
- for (i = 0; i < host->num_slots; i++) {
- slot = host->slot[i];
- if (slot->mmc->caps & MMC_CAP_NEEDS_POLL)
- return;
-
- if (mmc_gpio_get_cd(slot->mmc) < 0)
- break;
- }
- if (i == host->num_slots)
+ if (host->slot->mmc->caps & MMC_CAP_NEEDS_POLL)
return;
- spin_lock_irqsave(&host->irq_lock, irqflags);
- temp = mci_readl(host, INTMASK);
- temp |= SDMMC_INT_CD;
- mci_writel(host, INTMASK, temp);
- spin_unlock_irqrestore(&host->irq_lock, irqflags);
+ if (mmc_gpio_get_cd(host->slot->mmc) < 0) {
+ spin_lock_irqsave(&host->irq_lock, irqflags);
+ temp = mci_readl(host, INTMASK);
+ temp |= SDMMC_INT_CD;
+ mci_writel(host, INTMASK, temp);
+ spin_unlock_irqrestore(&host->irq_lock, irqflags);
+ }
}
int dw_mci_probe(struct dw_mci *host)
@@ -3020,7 +3017,6 @@ int dw_mci_probe(struct dw_mci *host)
const struct dw_mci_drv_data *drv_data = host->drv_data;
int width, i, ret = 0;
u32 fifo_size;
- int init_slots = 0;
if (!host->pdata) {
host->pdata = dw_mci_parse_dt(host);
@@ -3183,19 +3179,6 @@ int dw_mci_probe(struct dw_mci *host)
if (ret)
goto err_dmaunmap;
- if (host->pdata->num_slots)
- host->num_slots = host->pdata->num_slots;
- else
- host->num_slots = 1;
-
- if (host->num_slots < 1 ||
- host->num_slots > SDMMC_GET_SLOT_NUM(mci_readl(host, HCON))) {
- dev_err(host->dev,
- "Platform data must supply correct num_slots.\n");
- ret = -ENODEV;
- goto err_clk_ciu;
- }
-
/*
* Enable interrupts for command done, data over, data empty,
* receive ready and error such as transmit, receive timeout, crc error
@@ -3211,20 +3194,9 @@ int dw_mci_probe(struct dw_mci *host)
host->irq, width, fifo_size);
/* We need at least one slot to succeed */
- for (i = 0; i < host->num_slots; i++) {
- ret = dw_mci_init_slot(host, i);
- if (ret)
- dev_dbg(host->dev, "slot %d init failed\n", i);
- else
- init_slots++;
- }
-
- if (init_slots) {
- dev_info(host->dev, "%d slots initialized\n", init_slots);
- } else {
- dev_dbg(host->dev,
- "attempted to initialize %d slots, but failed on all\n",
- host->num_slots);
+ ret = dw_mci_init_slot(host);
+ if (ret) {
+ dev_dbg(host->dev, "slot %d init failed\n", i);
goto err_dmaunmap;
}
@@ -3252,13 +3224,9 @@ EXPORT_SYMBOL(dw_mci_probe);
void dw_mci_remove(struct dw_mci *host)
{
- int i;
-
- for (i = 0; i < host->num_slots; i++) {
- dev_dbg(host->dev, "remove slot %d\n", i);
- if (host->slot[i])
- dw_mci_cleanup_slot(host->slot[i], i);
- }
+ dev_dbg(host->dev, "remove slot\n");
+ if (host->slot)
+ dw_mci_cleanup_slot(host->slot);
mci_writel(host, RINTSTS, 0xFFFFFFFF);
mci_writel(host, INTMASK, 0); /* disable all mmc interrupt first */
@@ -3290,9 +3258,9 @@ int dw_mci_runtime_suspend(struct device *dev)
clk_disable_unprepare(host->ciu_clk);
- if (host->cur_slot &&
- (mmc_can_gpio_cd(host->cur_slot->mmc) ||
- !mmc_card_is_removable(host->cur_slot->mmc)))
+ if (host->slot &&
+ (mmc_can_gpio_cd(host->slot->mmc) ||
+ !mmc_card_is_removable(host->slot->mmc)))
clk_disable_unprepare(host->biu_clk);
return 0;
@@ -3301,12 +3269,12 @@ EXPORT_SYMBOL(dw_mci_runtime_suspend);
int dw_mci_runtime_resume(struct device *dev)
{
- int i, ret = 0;
+ int ret = 0;
struct dw_mci *host = dev_get_drvdata(dev);
- if (host->cur_slot &&
- (mmc_can_gpio_cd(host->cur_slot->mmc) ||
- !mmc_card_is_removable(host->cur_slot->mmc))) {
+ if (host->slot &&
+ (mmc_can_gpio_cd(host->slot->mmc) ||
+ !mmc_card_is_removable(host->slot->mmc))) {
ret = clk_prepare_enable(host->biu_clk);
if (ret)
return ret;
@@ -3341,17 +3309,12 @@ int dw_mci_runtime_resume(struct device *dev)
DW_MCI_ERROR_FLAGS);
mci_writel(host, CTRL, SDMMC_CTRL_INT_ENABLE);
- for (i = 0; i < host->num_slots; i++) {
- struct dw_mci_slot *slot = host->slot[i];
- if (!slot)
- continue;
- if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER)
- dw_mci_set_ios(slot->mmc, &slot->mmc->ios);
+ if (host->slot->mmc->pm_flags & MMC_PM_KEEP_POWER)
+ dw_mci_set_ios(host->slot->mmc, &host->slot->mmc->ios);
- /* Force setup bus to guarantee available clock output */
- dw_mci_setup_bus(slot, true);
- }
+ /* Force setup bus to guarantee available clock output */
+ dw_mci_setup_bus(host->slot, true);
/* Now that slots are all setup, we can enable card detect */
dw_mci_enable_cd(host);
@@ -3359,9 +3322,9 @@ int dw_mci_runtime_resume(struct device *dev)
return 0;
err:
- if (host->cur_slot &&
- (mmc_can_gpio_cd(host->cur_slot->mmc) ||
- !mmc_card_is_removable(host->cur_slot->mmc)))
+ if (host->slot &&
+ (mmc_can_gpio_cd(host->slot->mmc) ||
+ !mmc_card_is_removable(host->slot->mmc)))
clk_disable_unprepare(host->biu_clk);
return ret;
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index ce347361f3dc..75da3756955d 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -20,8 +20,6 @@
#include <linux/reset.h>
#include <linux/interrupt.h>
-#define MAX_MCI_SLOTS 2
-
enum dw_mci_state {
STATE_IDLE = 0,
STATE_SENDING_CMD,
@@ -134,7 +132,6 @@ struct dw_mci_dma_slave {
* =======
*
* @lock is a softirq-safe spinlock protecting @queue as well as
- * @cur_slot, @mrq and @state. These must always be updated
* at the same time while holding @lock.
*
* @irq_lock is an irq-safe spinlock protecting the INTMASK register
@@ -170,7 +167,6 @@ struct dw_mci {
struct scatterlist *sg;
struct sg_mapping_iter sg_miter;
- struct dw_mci_slot *cur_slot;
struct mmc_request *mrq;
struct mmc_command *cmd;
struct mmc_data *data;
@@ -206,7 +202,6 @@ struct dw_mci {
u32 bus_hz;
u32 current_speed;
- u32 num_slots;
u32 fifoth_val;
u16 verid;
struct device *dev;
@@ -215,7 +210,7 @@ struct dw_mci {
void *priv;
struct clk *biu_clk;
struct clk *ciu_clk;
- struct dw_mci_slot *slot[MAX_MCI_SLOTS];
+ struct dw_mci_slot *slot;
/* FIFO push and pull */
int fifo_depth;
diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c
index 1842ed341af1..de962c2d5e00 100644
--- a/drivers/mmc/host/meson-gx-mmc.c
+++ b/drivers/mmc/host/meson-gx-mmc.c
@@ -210,6 +210,15 @@ static void meson_mmc_get_transfer_mode(struct mmc_host *mmc,
int i;
bool use_desc_chain_mode = true;
+ /*
+ * Broken SDIO with AP6255-based WiFi on Khadas VIM Pro has been
+ * reported. For some strange reason this occurs in descriptor
+ * chain mode only. So let's fall back to bounce buffer mode
+ * for command SD_IO_RW_EXTENDED.
+ */
+ if (mrq->cmd->opcode == SD_IO_RW_EXTENDED)
+ return;
+
for_each_sg(data->sg, sg, data->sg_len, i)
/* check for 8 byte alignment */
if (sg->offset & 7) {
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 5c1e178fc5f9..5a672a5218ad 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -1774,7 +1774,7 @@ static int msdc_drv_remove(struct platform_device *pdev)
pm_runtime_disable(host->dev);
pm_runtime_put_noidle(host->dev);
dma_free_coherent(&pdev->dev,
- sizeof(struct mt_gpdma_desc),
+ 2 * sizeof(struct mt_gpdma_desc),
host->dma.gpd, host->dma.gpd_addr);
dma_free_coherent(&pdev->dev, MAX_BD_NUM * sizeof(struct mt_bdma_desc),
host->dma.bd, host->dma.bd_addr);
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 8c39dccacf39..7c12f3715676 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -250,14 +250,14 @@ static int omap_hsmmc_enable_supply(struct mmc_host *mmc)
struct omap_hsmmc_host *host = mmc_priv(mmc);
struct mmc_ios *ios = &mmc->ios;
- if (mmc->supply.vmmc) {
+ if (!IS_ERR(mmc->supply.vmmc)) {
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
if (ret)
return ret;
}
/* Enable interface voltage rail, if needed */
- if (mmc->supply.vqmmc && !host->vqmmc_enabled) {
+ if (!IS_ERR(mmc->supply.vqmmc) && !host->vqmmc_enabled) {
ret = regulator_enable(mmc->supply.vqmmc);
if (ret) {
dev_err(mmc_dev(mmc), "vmmc_aux reg enable failed\n");
@@ -269,7 +269,7 @@ static int omap_hsmmc_enable_supply(struct mmc_host *mmc)
return 0;
err_vqmmc:
- if (mmc->supply.vmmc)
+ if (!IS_ERR(mmc->supply.vmmc))
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
return ret;
@@ -281,7 +281,7 @@ static int omap_hsmmc_disable_supply(struct mmc_host *mmc)
int status;
struct omap_hsmmc_host *host = mmc_priv(mmc);
- if (mmc->supply.vqmmc && host->vqmmc_enabled) {
+ if (!IS_ERR(mmc->supply.vqmmc) && host->vqmmc_enabled) {
ret = regulator_disable(mmc->supply.vqmmc);
if (ret) {
dev_err(mmc_dev(mmc), "vmmc_aux reg disable failed\n");
@@ -290,7 +290,7 @@ static int omap_hsmmc_disable_supply(struct mmc_host *mmc)
host->vqmmc_enabled = 0;
}
- if (mmc->supply.vmmc) {
+ if (!IS_ERR(mmc->supply.vmmc)) {
ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
if (ret)
goto err_set_ocr;
@@ -299,7 +299,7 @@ static int omap_hsmmc_disable_supply(struct mmc_host *mmc)
return 0;
err_set_ocr:
- if (mmc->supply.vqmmc) {
+ if (!IS_ERR(mmc->supply.vqmmc)) {
status = regulator_enable(mmc->supply.vqmmc);
if (status)
dev_err(mmc_dev(mmc), "vmmc_aux re-enable failed\n");
@@ -313,7 +313,7 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on,
{
int ret;
- if (!host->pbias)
+ if (IS_ERR(host->pbias))
return 0;
if (power_on) {
@@ -363,7 +363,7 @@ static int omap_hsmmc_set_power(struct omap_hsmmc_host *host, int power_on,
* If we don't see a Vcc regulator, assume it's a fixed
* voltage always-on regulator.
*/
- if (!mmc->supply.vmmc)
+ if (IS_ERR(mmc->supply.vmmc))
return 0;
if (mmc_pdata(host)->before_set_reg)
@@ -415,7 +415,7 @@ static int omap_hsmmc_disable_boot_regulator(struct regulator *reg)
{
int ret;
- if (!reg)
+ if (IS_ERR(reg))
return 0;
if (regulator_is_enabled(reg)) {
@@ -466,36 +466,27 @@ static int omap_hsmmc_disable_boot_regulators(struct omap_hsmmc_host *host)
static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
{
- int ocr_value = 0;
int ret;
struct mmc_host *mmc = host->mmc;
if (mmc_pdata(host)->set_power)
return 0;
- mmc->supply.vmmc = devm_regulator_get_optional(host->dev, "vmmc");
- if (IS_ERR(mmc->supply.vmmc)) {
- ret = PTR_ERR(mmc->supply.vmmc);
- if ((ret != -ENODEV) && host->dev->of_node)
- return ret;
- dev_dbg(host->dev, "unable to get vmmc regulator %ld\n",
- PTR_ERR(mmc->supply.vmmc));
- mmc->supply.vmmc = NULL;
- } else {
- ocr_value = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
- if (ocr_value > 0)
- mmc_pdata(host)->ocr_mask = ocr_value;
- }
+ ret = mmc_regulator_get_supply(mmc);
+ if (ret == -EPROBE_DEFER)
+ return ret;
/* Allow an aux regulator */
- mmc->supply.vqmmc = devm_regulator_get_optional(host->dev, "vmmc_aux");
if (IS_ERR(mmc->supply.vqmmc)) {
- ret = PTR_ERR(mmc->supply.vqmmc);
- if ((ret != -ENODEV) && host->dev->of_node)
- return ret;
- dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n",
- PTR_ERR(mmc->supply.vqmmc));
- mmc->supply.vqmmc = NULL;
+ mmc->supply.vqmmc = devm_regulator_get_optional(host->dev,
+ "vmmc_aux");
+ if (IS_ERR(mmc->supply.vqmmc)) {
+ ret = PTR_ERR(mmc->supply.vqmmc);
+ if ((ret != -ENODEV) && host->dev->of_node)
+ return ret;
+ dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n",
+ PTR_ERR(mmc->supply.vqmmc));
+ }
}
host->pbias = devm_regulator_get_optional(host->dev, "pbias");
@@ -508,7 +499,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
}
dev_dbg(host->dev, "unable to get pbias regulator %ld\n",
PTR_ERR(host->pbias));
- host->pbias = NULL;
}
/* For eMMC do not power off when not in sleep state */
@@ -2146,7 +2136,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (ret)
goto err_irq;
- mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
+ if (!mmc->ocr_avail)
+ mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
omap_hsmmc_disable_irq(host);
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index c763b404510f..59ab194cb009 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -702,7 +702,11 @@ static int pxamci_probe(struct platform_device *pdev)
pxamci_init_ocr(host);
- mmc->caps = 0;
+ /*
+ * This architecture used to disable bounce buffers through its
+ * defconfig, now it is done at runtime as a host property.
+ */
+ mmc->caps = MMC_CAP_NO_BOUNCE_BUFF;
host->cmdat = 0;
if (!cpu_is_pxa25x()) {
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
new file mode 100644
index 000000000000..ca83acc113b8
--- /dev/null
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -0,0 +1,39 @@
+/*
+ * Renesas Mobile SDHI
+ *
+ * Copyright (C) 2017 Horms Solutions Ltd., Simon Horman
+ * Copyright (C) 2017 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef RENESAS_SDHI_H
+#define RENESAS_SDHI_H
+
+#include <linux/platform_device.h>
+#include "tmio_mmc.h"
+
+struct renesas_sdhi_scc {
+ unsigned long clk_rate; /* clock rate for SDR104 */
+ u32 tap; /* sampling clock position for SDR104 */
+};
+
+struct renesas_sdhi_of_data {
+ unsigned long tmio_flags;
+ u32 tmio_ocr_mask;
+ unsigned long capabilities;
+ unsigned long capabilities2;
+ enum dma_slave_buswidth dma_buswidth;
+ dma_addr_t dma_rx_offset;
+ unsigned int bus_shift;
+ int scc_offset;
+ struct renesas_sdhi_scc *taps;
+ int taps_num;
+};
+
+int renesas_sdhi_probe(struct platform_device *pdev,
+ const struct tmio_mmc_dma_ops *dma_ops);
+int renesas_sdhi_remove(struct platform_device *pdev);
+#endif
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/renesas_sdhi_core.c
index bc6be0dbea39..a4fb07d0ea91 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -1,8 +1,9 @@
/*
- * SuperH Mobile SDHI
+ * Renesas SDHI
*
- * Copyright (C) 2016 Sang Engineering, Wolfram Sang
- * Copyright (C) 2015-16 Renesas Electronics Corporation
+ * Copyright (C) 2015-17 Renesas Electronics Corporation
+ * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang
+ * Copyright (C) 2016-17 Horms Solutions, Simon Horman
* Copyright (C) 2009 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
@@ -23,8 +24,6 @@
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/slab.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/mmc/host.h>
@@ -35,6 +34,7 @@
#include <linux/pinctrl/pinctrl-state.h>
#include <linux/regulator/consumer.h>
+#include "renesas_sdhi.h"
#include "tmio_mmc.h"
#define EXT_ACC 0xe4
@@ -45,103 +45,10 @@
#define SDHI_VER_GEN3_SD 0xcc10
#define SDHI_VER_GEN3_SDMMC 0xcd10
-#define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data)
+#define host_to_priv(host) \
+ container_of((host)->pdata, struct renesas_sdhi, mmc_data)
-struct sh_mobile_sdhi_scc {
- unsigned long clk_rate; /* clock rate for SDR104 */
- u32 tap; /* sampling clock position for SDR104 */
-};
-
-struct sh_mobile_sdhi_of_data {
- unsigned long tmio_flags;
- u32 tmio_ocr_mask;
- unsigned long capabilities;
- unsigned long capabilities2;
- enum dma_slave_buswidth dma_buswidth;
- dma_addr_t dma_rx_offset;
- unsigned bus_shift;
- int scc_offset;
- struct sh_mobile_sdhi_scc *taps;
- int taps_num;
-};
-
-static const struct sh_mobile_sdhi_of_data of_default_cfg = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
-};
-
-static const struct sh_mobile_sdhi_of_data of_rz_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_32BIT_DATA_PORT,
- .tmio_ocr_mask = MMC_VDD_32_33,
- .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
-};
-
-static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL,
- .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
-};
-
-/* Definitions for sampling clocks */
-static struct sh_mobile_sdhi_scc rcar_gen2_scc_taps[] = {
- {
- .clk_rate = 156000000,
- .tap = 0x00000703,
- },
- {
- .clk_rate = 0,
- .tap = 0x00000300,
- },
-};
-
-static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
- .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
- .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .dma_rx_offset = 0x2000,
- .scc_offset = 0x0300,
- .taps = rcar_gen2_scc_taps,
- .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
-};
-
-/* Definitions for sampling clocks */
-static struct sh_mobile_sdhi_scc rcar_gen3_scc_taps[] = {
- {
- .clk_rate = 0,
- .tap = 0x00000300,
- },
-};
-
-static const struct sh_mobile_sdhi_of_data of_rcar_gen3_compatible = {
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
- TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
- .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
- .bus_shift = 2,
- .scc_offset = 0x1000,
- .taps = rcar_gen3_scc_taps,
- .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
-};
-
-static const struct of_device_id sh_mobile_sdhi_of_match[] = {
- { .compatible = "renesas,sdhi-shmobile" },
- { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
- { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
- { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
- { .compatible = "renesas,sdhi-r7s72100", .data = &of_rz_compatible, },
- { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
- { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
- { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
- { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
- { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
- {},
-};
-MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
-
-struct sh_mobile_sdhi {
+struct renesas_sdhi {
struct clk *clk;
struct clk *clk_cd;
struct tmio_mmc_data mmc_data;
@@ -151,13 +58,13 @@ struct sh_mobile_sdhi {
void __iomem *scc_ctl;
};
-static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
+static void renesas_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
{
u32 val;
/*
* see also
- * sh_mobile_sdhi_of_data :: dma_buswidth
+ * renesas_sdhi_of_data :: dma_buswidth
*/
switch (sd_ctrl_read16(host, CTL_VERSION)) {
case SDHI_VER_GEN2_SDR50:
@@ -183,11 +90,12 @@ static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
sd_ctrl_write16(host, EXT_ACC, val);
}
-static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host)
+static int renesas_sdhi_clk_enable(struct tmio_mmc_host *host)
{
struct mmc_host *mmc = host->mmc;
- struct sh_mobile_sdhi *priv = host_to_priv(host);
+ struct renesas_sdhi *priv = host_to_priv(host);
int ret = clk_prepare_enable(priv->clk);
+
if (ret < 0)
return ret;
@@ -213,19 +121,19 @@ static int sh_mobile_sdhi_clk_enable(struct tmio_mmc_host *host)
mmc->f_min = max(clk_round_rate(priv->clk, 1) / 512, 1L);
/* enable 16bit data access on SDBUF as default */
- sh_mobile_sdhi_sdbuf_width(host, 16);
+ renesas_sdhi_sdbuf_width(host, 16);
return 0;
}
-static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host,
- unsigned int new_clock)
+static unsigned int renesas_sdhi_clk_update(struct tmio_mmc_host *host,
+ unsigned int new_clock)
{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
+ struct renesas_sdhi *priv = host_to_priv(host);
unsigned int freq, diff, best_freq = 0, diff_min = ~0;
int i, ret;
- /* tested only on RCar Gen2+ currently; may work for others */
+ /* tested only on R-Car Gen2+ currently; may work for others */
if (!(host->pdata->flags & TMIO_MMC_MIN_RCAR2))
return clk_get_rate(priv->clk);
@@ -257,26 +165,27 @@ static unsigned int sh_mobile_sdhi_clk_update(struct tmio_mmc_host *host,
return ret == 0 ? best_freq : clk_get_rate(priv->clk);
}
-static void sh_mobile_sdhi_clk_disable(struct tmio_mmc_host *host)
+static void renesas_sdhi_clk_disable(struct tmio_mmc_host *host)
{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
+ struct renesas_sdhi *priv = host_to_priv(host);
clk_disable_unprepare(priv->clk);
clk_disable_unprepare(priv->clk_cd);
}
-static int sh_mobile_sdhi_card_busy(struct mmc_host *mmc)
+static int renesas_sdhi_card_busy(struct mmc_host *mmc)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
- return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) & TMIO_STAT_DAT0);
+ return !(sd_ctrl_read16_and_16_as_32(host, CTL_STATUS) &
+ TMIO_STAT_DAT0);
}
-static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
- struct mmc_ios *ios)
+static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
+ struct mmc_ios *ios)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
- struct sh_mobile_sdhi *priv = host_to_priv(host);
+ struct renesas_sdhi *priv = host_to_priv(host);
struct pinctrl_state *pin_state;
int ret;
@@ -327,21 +236,21 @@ static int sh_mobile_sdhi_start_signal_voltage_switch(struct mmc_host *mmc,
#define SH_MOBILE_SDHI_SCC_RVSREQ_RVSERR BIT(2)
static inline u32 sd_scc_read32(struct tmio_mmc_host *host,
- struct sh_mobile_sdhi *priv, int addr)
+ struct renesas_sdhi *priv, int addr)
{
return readl(priv->scc_ctl + (addr << host->bus_shift));
}
static inline void sd_scc_write32(struct tmio_mmc_host *host,
- struct sh_mobile_sdhi *priv,
+ struct renesas_sdhi *priv,
int addr, u32 val)
{
writel(val, priv->scc_ctl + (addr << host->bus_shift));
}
-static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host)
+static unsigned int renesas_sdhi_init_tuning(struct tmio_mmc_host *host)
{
- struct sh_mobile_sdhi *priv;
+ struct renesas_sdhi *priv;
priv = host_to_priv(host);
@@ -378,10 +287,10 @@ static unsigned int sh_mobile_sdhi_init_tuning(struct tmio_mmc_host *host)
SH_MOBILE_SDHI_SCC_DTCNTL_TAPNUM_MASK;
}
-static void sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host,
- unsigned long tap)
+static void renesas_sdhi_prepare_tuning(struct tmio_mmc_host *host,
+ unsigned long tap)
{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
+ struct renesas_sdhi *priv = host_to_priv(host);
/* Set sampling clock position */
sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_TAPSET, tap);
@@ -389,9 +298,9 @@ static void sh_mobile_sdhi_prepare_tuning(struct tmio_mmc_host *host,
#define SH_MOBILE_SDHI_MAX_TAP 3
-static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host)
+static int renesas_sdhi_select_tuning(struct tmio_mmc_host *host)
{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
+ struct renesas_sdhi *priv = host_to_priv(host);
unsigned long tap_cnt; /* counter of tuning success */
unsigned long tap_set; /* tap position */
unsigned long tap_start;/* start position of tuning success */
@@ -412,9 +321,9 @@ static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host)
tap_start = 0;
tap_end = 0;
for (i = 0; i < host->tap_num * 2; i++) {
- if (test_bit(i, host->taps))
+ if (test_bit(i, host->taps)) {
ntap++;
- else {
+ } else {
if (ntap > tap_cnt) {
tap_start = i - ntap;
tap_end = i - 1;
@@ -446,10 +355,9 @@ static int sh_mobile_sdhi_select_tuning(struct tmio_mmc_host *host)
return 0;
}
-
-static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host)
+static bool renesas_sdhi_check_scc_error(struct tmio_mmc_host *host)
{
- struct sh_mobile_sdhi *priv = host_to_priv(host);
+ struct renesas_sdhi *priv = host_to_priv(host);
/* Check SCC error */
if (sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL) &
@@ -464,9 +372,9 @@ static bool sh_mobile_sdhi_check_scc_error(struct tmio_mmc_host *host)
return false;
}
-static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host)
+static void renesas_sdhi_hw_reset(struct tmio_mmc_host *host)
{
- struct sh_mobile_sdhi *priv;
+ struct renesas_sdhi *priv;
priv = host_to_priv(host);
@@ -490,7 +398,7 @@ static void sh_mobile_sdhi_hw_reset(struct tmio_mmc_host *host)
sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
}
-static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
+static int renesas_sdhi_wait_idle(struct tmio_mmc_host *host)
{
int timeout = 1000;
@@ -506,10 +414,9 @@ static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
return 0;
}
-static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
+static int renesas_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
{
- switch (addr)
- {
+ switch (addr) {
case CTL_SD_CMD:
case CTL_STOP_INTERNAL_ACTION:
case CTL_XFER_BLK_COUNT:
@@ -519,14 +426,14 @@ static int sh_mobile_sdhi_write16_hook(struct tmio_mmc_host *host, int addr)
case CTL_TRANSACTION_CTL:
case CTL_DMA_ENABLE:
case EXT_ACC:
- return sh_mobile_sdhi_wait_idle(host);
+ return renesas_sdhi_wait_idle(host);
}
return 0;
}
-static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card,
- unsigned int direction, int blk_size)
+static int renesas_sdhi_multi_io_quirk(struct mmc_card *card,
+ unsigned int direction, int blk_size)
{
/*
* In Renesas controllers, when performing a
@@ -543,30 +450,34 @@ static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card,
return blk_size;
}
-static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
+static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
{
sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
/* enable 32bit access if DMA mode if possibile */
- sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16);
+ renesas_sdhi_sdbuf_width(host, enable ? 32 : 16);
}
-static int sh_mobile_sdhi_probe(struct platform_device *pdev)
+int renesas_sdhi_probe(struct platform_device *pdev,
+ const struct tmio_mmc_dma_ops *dma_ops)
{
- const struct sh_mobile_sdhi_of_data *of_data = of_device_get_match_data(&pdev->dev);
- struct sh_mobile_sdhi *priv;
- struct tmio_mmc_data *mmc_data;
struct tmio_mmc_data *mmd = pdev->dev.platform_data;
+ const struct renesas_sdhi_of_data *of_data;
+ struct tmio_mmc_data *mmc_data;
+ struct tmio_mmc_dma *dma_priv;
struct tmio_mmc_host *host;
+ struct renesas_sdhi *priv;
struct resource *res;
int irq, ret, i;
- struct tmio_mmc_dma *dma_priv;
+
+ of_data = of_device_get_match_data(&pdev->dev);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -EINVAL;
- priv = devm_kzalloc(&pdev->dev, sizeof(struct sh_mobile_sdhi), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct renesas_sdhi),
+ GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -609,7 +520,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
goto eprobe;
}
-
if (of_data) {
mmc_data->flags |= of_data->tmio_flags;
mmc_data->ocr_mask = of_data->tmio_ocr_mask;
@@ -621,18 +531,18 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
}
host->dma = dma_priv;
- host->write16_hook = sh_mobile_sdhi_write16_hook;
- host->clk_enable = sh_mobile_sdhi_clk_enable;
- host->clk_update = sh_mobile_sdhi_clk_update;
- host->clk_disable = sh_mobile_sdhi_clk_disable;
- host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
+ host->write16_hook = renesas_sdhi_write16_hook;
+ host->clk_enable = renesas_sdhi_clk_enable;
+ host->clk_update = renesas_sdhi_clk_update;
+ host->clk_disable = renesas_sdhi_clk_disable;
+ host->multi_io_quirk = renesas_sdhi_multi_io_quirk;
/* SDR speeds are only available on Gen2+ */
if (mmc_data->flags & TMIO_MMC_MIN_RCAR2) {
/* card_busy caused issues on r8a73a4 (pre-Gen2) CD-less SDHI */
- host->card_busy = sh_mobile_sdhi_card_busy;
+ host->card_busy = renesas_sdhi_card_busy;
host->start_signal_voltage_switch =
- sh_mobile_sdhi_start_signal_voltage_switch;
+ renesas_sdhi_start_signal_voltage_switch;
}
/* Orginally registers were 16 bit apart, could be 32 or 64 nowadays */
@@ -643,7 +553,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
*mmc_data = *mmd;
dma_priv->filter = shdma_chan_filter;
- dma_priv->enable = sh_mobile_sdhi_enable_dma;
+ dma_priv->enable = renesas_sdhi_enable_dma;
mmc_data->alignment_shift = 1; /* 2-byte alignment */
mmc_data->capabilities |= MMC_CAP_MMC_HIGHSPEED;
@@ -659,15 +569,13 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
*/
mmc_data->flags |= TMIO_MMC_SDIO_IRQ;
- /*
- * All SDHI have CMD12 controll bit
- */
+ /* All SDHI have CMD12 control bit */
mmc_data->flags |= TMIO_MMC_HAVE_CMD12_CTRL;
/* All SDHI have SDIO status bits which must be 1 */
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_SETBITS;
- ret = tmio_mmc_host_probe(host, mmc_data);
+ ret = tmio_mmc_host_probe(host, mmc_data, dma_ops);
if (ret < 0)
goto efree;
@@ -675,7 +583,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
if (of_data && of_data->scc_offset &&
(host->mmc->caps & MMC_CAP_UHS_SDR104 ||
host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR)) {
- const struct sh_mobile_sdhi_scc *taps = of_data->taps;
+ const struct renesas_sdhi_scc *taps = of_data->taps;
bool hit = false;
host->mmc->caps |= MMC_CAP_HW_RESET;
@@ -693,11 +601,11 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
dev_warn(&host->pdev->dev, "Unknown clock rate for SDR104\n");
priv->scc_ctl = host->ctl + of_data->scc_offset;
- host->init_tuning = sh_mobile_sdhi_init_tuning;
- host->prepare_tuning = sh_mobile_sdhi_prepare_tuning;
- host->select_tuning = sh_mobile_sdhi_select_tuning;
- host->check_scc_error = sh_mobile_sdhi_check_scc_error;
- host->hw_reset = sh_mobile_sdhi_hw_reset;
+ host->init_tuning = renesas_sdhi_init_tuning;
+ host->prepare_tuning = renesas_sdhi_prepare_tuning;
+ host->select_tuning = renesas_sdhi_select_tuning;
+ host->check_scc_error = renesas_sdhi_check_scc_error;
+ host->hw_reset = renesas_sdhi_hw_reset;
}
i = 0;
@@ -707,7 +615,7 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
break;
i++;
ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0,
- dev_name(&pdev->dev), host);
+ dev_name(&pdev->dev), host);
if (ret)
goto eirq;
}
@@ -732,8 +640,9 @@ efree:
eprobe:
return ret;
}
+EXPORT_SYMBOL_GPL(renesas_sdhi_probe);
-static int sh_mobile_sdhi_remove(struct platform_device *pdev)
+int renesas_sdhi_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc);
@@ -742,28 +651,4 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
return 0;
}
-
-static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
- pm_runtime_force_resume)
- SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
- tmio_mmc_host_runtime_resume,
- NULL)
-};
-
-static struct platform_driver sh_mobile_sdhi_driver = {
- .driver = {
- .name = "sh_mobile_sdhi",
- .pm = &tmio_mmc_dev_pm_ops,
- .of_match_table = sh_mobile_sdhi_of_match,
- },
- .probe = sh_mobile_sdhi_probe,
- .remove = sh_mobile_sdhi_remove,
-};
-
-module_platform_driver(sh_mobile_sdhi_driver);
-
-MODULE_DESCRIPTION("SuperH Mobile SDHI driver");
-MODULE_AUTHOR("Magnus Damm");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:sh_mobile_sdhi");
+EXPORT_SYMBOL_GPL(renesas_sdhi_remove);
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
index e2093db2b7ff..642a0dcc8c5c 100644
--- a/drivers/mmc/host/tmio_mmc_dma.c
+++ b/drivers/mmc/host/renesas_sdhi_sys_dmac.c
@@ -1,13 +1,14 @@
/*
- * linux/drivers/mmc/tmio_mmc_dma.c
+ * DMA function for TMIO MMC implementations
*
+ * Copyright (C) 2016-17 Renesas Electronics Corporation
+ * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang
+ * Copyright (C) 2017 Horms Solutions, Simon Horman
* Copyright (C) 2010-2011 Guennadi Liakhovetski
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * DMA function for TMIO MMC implementations
*/
#include <linux/device.h>
@@ -15,14 +16,96 @@
#include <linux/dmaengine.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
+#include "renesas_sdhi.h"
#include "tmio_mmc.h"
#define TMIO_MMC_MIN_DMA_LEN 8
-void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
+static const struct renesas_sdhi_of_data of_default_cfg = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
+};
+
+static const struct renesas_sdhi_of_data of_rz_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_32BIT_DATA_PORT,
+ .tmio_ocr_mask = MMC_VDD_32_33,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen1_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+};
+
+/* Definitions for sampling clocks */
+static struct renesas_sdhi_scc rcar_gen2_scc_taps[] = {
+ {
+ .clk_rate = 156000000,
+ .tap = 0x00000703,
+ },
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen2_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
+ MMC_CAP_CMD23,
+ .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .dma_rx_offset = 0x2000,
+ .scc_offset = 0x0300,
+ .taps = rcar_gen2_scc_taps,
+ .taps_num = ARRAY_SIZE(rcar_gen2_scc_taps),
+};
+
+/* Definitions for sampling clocks */
+static struct renesas_sdhi_scc rcar_gen3_scc_taps[] = {
+ {
+ .clk_rate = 0,
+ .tap = 0x00000300,
+ },
+};
+
+static const struct renesas_sdhi_of_data of_rcar_gen3_compatible = {
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
+ TMIO_MMC_CLK_ACTUAL | TMIO_MMC_MIN_RCAR2,
+ .capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
+ MMC_CAP_CMD23,
+ .bus_shift = 2,
+ .scc_offset = 0x1000,
+ .taps = rcar_gen3_scc_taps,
+ .taps_num = ARRAY_SIZE(rcar_gen3_scc_taps),
+};
+
+static const struct of_device_id renesas_sdhi_sys_dmac_of_match[] = {
+ { .compatible = "renesas,sdhi-shmobile" },
+ { .compatible = "renesas,sdhi-sh73a0", .data = &of_default_cfg, },
+ { .compatible = "renesas,sdhi-r8a73a4", .data = &of_default_cfg, },
+ { .compatible = "renesas,sdhi-r8a7740", .data = &of_default_cfg, },
+ { .compatible = "renesas,sdhi-r7s72100", .data = &of_rz_compatible, },
+ { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
+ { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
+ { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7792", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7793", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7794", .data = &of_rcar_gen2_compatible, },
+ { .compatible = "renesas,sdhi-r8a7795", .data = &of_rcar_gen3_compatible, },
+ { .compatible = "renesas,sdhi-r8a7796", .data = &of_rcar_gen3_compatible, },
+ {},
+};
+MODULE_DEVICE_TABLE(of, renesas_sdhi_sys_dmac_of_match);
+
+static void renesas_sdhi_sys_dmac_enable_dma(struct tmio_mmc_host *host,
+ bool enable)
{
if (!host->chan_tx || !host->chan_rx)
return;
@@ -31,19 +114,19 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
host->dma->enable(host, enable);
}
-void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
+static void renesas_sdhi_sys_dmac_abort_dma(struct tmio_mmc_host *host)
{
- tmio_mmc_enable_dma(host, false);
+ renesas_sdhi_sys_dmac_enable_dma(host, false);
if (host->chan_rx)
dmaengine_terminate_all(host->chan_rx);
if (host->chan_tx)
dmaengine_terminate_all(host->chan_tx);
- tmio_mmc_enable_dma(host, true);
+ renesas_sdhi_sys_dmac_enable_dma(host, true);
}
-static void tmio_mmc_dma_callback(void *arg)
+static void renesas_sdhi_sys_dmac_dma_callback(void *arg)
{
struct tmio_mmc_host *host = arg;
@@ -71,7 +154,7 @@ out:
spin_unlock_irq(&host->lock);
}
-static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
+static void renesas_sdhi_sys_dmac_start_dma_rx(struct tmio_mmc_host *host)
{
struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL;
@@ -112,12 +195,12 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_FROM_DEVICE);
if (ret > 0)
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_DEV_TO_MEM, DMA_CTRL_ACK);
+ desc = dmaengine_prep_slave_sg(chan, sg, ret, DMA_DEV_TO_MEM,
+ DMA_CTRL_ACK);
if (desc) {
reinit_completion(&host->dma_dataend);
- desc->callback = tmio_mmc_dma_callback;
+ desc->callback = renesas_sdhi_sys_dmac_dma_callback;
desc->callback_param = host;
cookie = dmaengine_submit(desc);
@@ -129,7 +212,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
pio:
if (!desc) {
/* DMA failed, fall back to PIO */
- tmio_mmc_enable_dma(host, false);
+ renesas_sdhi_sys_dmac_enable_dma(host, false);
if (ret >= 0)
ret = -EIO;
host->chan_rx = NULL;
@@ -145,7 +228,7 @@ pio:
}
}
-static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
+static void renesas_sdhi_sys_dmac_start_dma_tx(struct tmio_mmc_host *host)
{
struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL;
@@ -181,6 +264,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
if (!aligned) {
unsigned long flags;
void *sg_vaddr = tmio_mmc_kmap_atomic(sg, &flags);
+
sg_init_one(&host->bounce_sg, host->bounce_buf, sg->length);
memcpy(host->bounce_buf, sg_vaddr, host->bounce_sg.length);
tmio_mmc_kunmap_atomic(sg, &flags, sg_vaddr);
@@ -190,12 +274,12 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
ret = dma_map_sg(chan->device->dev, sg, host->sg_len, DMA_TO_DEVICE);
if (ret > 0)
- desc = dmaengine_prep_slave_sg(chan, sg, ret,
- DMA_MEM_TO_DEV, DMA_CTRL_ACK);
+ desc = dmaengine_prep_slave_sg(chan, sg, ret, DMA_MEM_TO_DEV,
+ DMA_CTRL_ACK);
if (desc) {
reinit_completion(&host->dma_dataend);
- desc->callback = tmio_mmc_dma_callback;
+ desc->callback = renesas_sdhi_sys_dmac_dma_callback;
desc->callback_param = host;
cookie = dmaengine_submit(desc);
@@ -207,7 +291,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
pio:
if (!desc) {
/* DMA failed, fall back to PIO */
- tmio_mmc_enable_dma(host, false);
+ renesas_sdhi_sys_dmac_enable_dma(host, false);
if (ret >= 0)
ret = -EIO;
host->chan_tx = NULL;
@@ -223,19 +307,19 @@ pio:
}
}
-void tmio_mmc_start_dma(struct tmio_mmc_host *host,
- struct mmc_data *data)
+static void renesas_sdhi_sys_dmac_start_dma(struct tmio_mmc_host *host,
+ struct mmc_data *data)
{
if (data->flags & MMC_DATA_READ) {
if (host->chan_rx)
- tmio_mmc_start_dma_rx(host);
+ renesas_sdhi_sys_dmac_start_dma_rx(host);
} else {
if (host->chan_tx)
- tmio_mmc_start_dma_tx(host);
+ renesas_sdhi_sys_dmac_start_dma_tx(host);
}
}
-static void tmio_mmc_issue_tasklet_fn(unsigned long priv)
+static void renesas_sdhi_sys_dmac_issue_tasklet_fn(unsigned long priv)
{
struct tmio_mmc_host *host = (struct tmio_mmc_host *)priv;
struct dma_chan *chan = NULL;
@@ -257,11 +341,12 @@ static void tmio_mmc_issue_tasklet_fn(unsigned long priv)
dma_async_issue_pending(chan);
}
-void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
+static void renesas_sdhi_sys_dmac_request_dma(struct tmio_mmc_host *host,
+ struct tmio_mmc_data *pdata)
{
/* We can only either use DMA for both Tx and Rx or not use it at all */
if (!host->dma || (!host->pdev->dev.of_node &&
- (!pdata->chan_priv_tx || !pdata->chan_priv_rx)))
+ (!pdata->chan_priv_tx || !pdata->chan_priv_rx)))
return;
if (!host->chan_tx && !host->chan_rx) {
@@ -287,7 +372,8 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
return;
cfg.direction = DMA_MEM_TO_DEV;
- cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift);
+ cfg.dst_addr = res->start +
+ (CTL_SD_DATA_PORT << host->bus_shift);
cfg.dst_addr_width = host->dma->dma_buswidth;
if (!cfg.dst_addr_width)
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
@@ -320,10 +406,12 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
goto ebouncebuf;
init_completion(&host->dma_dataend);
- tasklet_init(&host->dma_issue, tmio_mmc_issue_tasklet_fn, (unsigned long)host);
+ tasklet_init(&host->dma_issue,
+ renesas_sdhi_sys_dmac_issue_tasklet_fn,
+ (unsigned long)host);
}
- tmio_mmc_enable_dma(host, true);
+ renesas_sdhi_sys_dmac_enable_dma(host, true);
return;
@@ -337,15 +425,17 @@ ecfgtx:
host->chan_tx = NULL;
}
-void tmio_mmc_release_dma(struct tmio_mmc_host *host)
+static void renesas_sdhi_sys_dmac_release_dma(struct tmio_mmc_host *host)
{
if (host->chan_tx) {
struct dma_chan *chan = host->chan_tx;
+
host->chan_tx = NULL;
dma_release_channel(chan);
}
if (host->chan_rx) {
struct dma_chan *chan = host->chan_rx;
+
host->chan_rx = NULL;
dma_release_channel(chan);
}
@@ -354,3 +444,41 @@ void tmio_mmc_release_dma(struct tmio_mmc_host *host)
host->bounce_buf = NULL;
}
}
+
+static const struct tmio_mmc_dma_ops renesas_sdhi_sys_dmac_dma_ops = {
+ .start = renesas_sdhi_sys_dmac_start_dma,
+ .enable = renesas_sdhi_sys_dmac_enable_dma,
+ .request = renesas_sdhi_sys_dmac_request_dma,
+ .release = renesas_sdhi_sys_dmac_release_dma,
+ .abort = renesas_sdhi_sys_dmac_abort_dma,
+};
+
+static int renesas_sdhi_sys_dmac_probe(struct platform_device *pdev)
+{
+ return renesas_sdhi_probe(pdev, &renesas_sdhi_sys_dmac_dma_ops);
+}
+
+static const struct dev_pm_ops renesas_sdhi_sys_dmac_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+ tmio_mmc_host_runtime_resume,
+ NULL)
+};
+
+static struct platform_driver renesas_sys_dmac_sdhi_driver = {
+ .driver = {
+ .name = "sh_mobile_sdhi",
+ .pm = &renesas_sdhi_sys_dmac_dev_pm_ops,
+ .of_match_table = renesas_sdhi_sys_dmac_of_match,
+ },
+ .probe = renesas_sdhi_sys_dmac_probe,
+ .remove = renesas_sdhi_remove,
+};
+
+module_platform_driver(renesas_sys_dmac_sdhi_driver);
+
+MODULE_DESCRIPTION("Renesas SDHI driver");
+MODULE_AUTHOR("Magnus Damm");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh_mobile_sdhi");
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index c6a9a1bfaa22..cf66a3db71b8 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -274,7 +274,6 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
.caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
MMC_CAP_CMD_DURING_TFR | MMC_CAP_WAIT_WHILE_BUSY,
- .caps2 = MMC_CAP2_HC_ERASE_SZ,
.flags = SDHCI_ACPI_RUNTIME_PM,
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
@@ -396,9 +395,6 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
if (child->status.present && child->status.enabled)
acpi_device_fix_up_power(child);
- if (acpi_bus_get_status(device) || !device->status.present)
- return -ENODEV;
-
if (sdhci_acpi_byt_defer(dev))
return -EPROBE_DEFER;
diff --git a/drivers/mmc/host/sdhci-brcmstb.c b/drivers/mmc/host/sdhci-brcmstb.c
index 242c5dc7a81e..e2f638338e8f 100644
--- a/drivers/mmc/host/sdhci-brcmstb.c
+++ b/drivers/mmc/host/sdhci-brcmstb.c
@@ -89,9 +89,6 @@ static int sdhci_brcmstb_probe(struct platform_device *pdev)
goto err_clk;
}
- /* Enable MMC_CAP2_HC_ERASE_SZ for better max discard calculations */
- host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
-
sdhci_get_of_property(pdev);
mmc_of_parse(host->mmc);
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 23d8b8a73ae9..85140c9af581 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -95,7 +95,7 @@
#define ESDHC_CTRL_BUSWIDTH_MASK (0x3 << 1)
/*
- * There is an INT DMA ERR mis-match between eSDHC and STD SDHC SPEC:
+ * There is an INT DMA ERR mismatch between eSDHC and STD SDHC SPEC:
* Bit25 is used in STD SPEC, and is reserved in fsl eSDHC design,
* but bit28 is used as the INT DMA ERR in fsl eSDHC design.
* Define this macro DMA error INT for fsl eSDHC
@@ -110,16 +110,11 @@
* In exact block transfer, the controller doesn't complete the
* operations automatically as required at the end of the
* transfer and remains on hold if the abort command is not sent.
- * As a result, the TC flag is not asserted and SW received timeout
- * exeception. Bit1 of Vendor Spec registor is used to fix it.
+ * As a result, the TC flag is not asserted and SW received timeout
+ * exception. Bit1 of Vendor Spec register is used to fix it.
*/
#define ESDHC_FLAG_MULTIBLK_NO_INT BIT(1)
/*
- * The flag enables the workaround for ESDHC errata ENGcm07207 which
- * affects i.MX25 and i.MX35.
- */
-#define ESDHC_FLAG_ENGCM07207 BIT(2)
-/*
* The flag tells that the ESDHC controller is an USDHC block that is
* integrated on the i.MX6 series.
*/
@@ -131,9 +126,11 @@
/* The IP has SDHCI_CAPABILITIES_1 register */
#define ESDHC_FLAG_HAVE_CAP1 BIT(6)
/*
- * The IP has errata ERR004536
+ * The IP has erratum ERR004536
* uSDHC: ADMA Length Mismatch Error occurs if the AHB read access is slow,
* when reading data from the card
+ * This flag is also set for i.MX25 and i.MX35 in order to get
+ * SDHCI_QUIRK_BROKEN_ADMA, but for different reasons (ADMA capability bits).
*/
#define ESDHC_FLAG_ERR004536 BIT(7)
/* The IP supports HS200 mode */
@@ -141,7 +138,7 @@
/* The IP supports HS400 mode */
#define ESDHC_FLAG_HS400 BIT(9)
-/* A higher clock ferquency than this rate requires strobell dll control */
+/* A clock frequency higher than this rate requires strobe dll control */
#define ESDHC_STROBE_DLL_CLK_FREQ 100000000
struct esdhc_soc_data {
@@ -149,11 +146,11 @@ struct esdhc_soc_data {
};
static struct esdhc_soc_data esdhc_imx25_data = {
- .flags = ESDHC_FLAG_ENGCM07207,
+ .flags = ESDHC_FLAG_ERR004536,
};
static struct esdhc_soc_data esdhc_imx35_data = {
- .flags = ESDHC_FLAG_ENGCM07207,
+ .flags = ESDHC_FLAG_ERR004536,
};
static struct esdhc_soc_data esdhc_imx51_data = {
@@ -197,7 +194,7 @@ struct pltfm_imx_data {
struct clk *clk_ahb;
struct clk *clk_per;
enum {
- NO_CMD_PENDING, /* no multiblock command pending*/
+ NO_CMD_PENDING, /* no multiblock command pending */
MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
} multiblock_status;
@@ -286,7 +283,7 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
* ADMA2 capability of esdhc, but this bit is messed up on
* some SOCs (e.g. on MX25, MX35 this bit is set, but they
* don't actually support ADMA2). So set the BROKEN_ADMA
- * uirk on MX25/35 platforms.
+ * quirk on MX25/35 platforms.
*/
if (val & SDHCI_CAN_DO_ADMA1) {
@@ -351,7 +348,7 @@ static void esdhc_writel_le(struct sdhci_host *host, u32 val, int reg)
if ((val & SDHCI_INT_CARD_INT) && !esdhc_is_usdhc(imx_data)) {
/*
* Clear and then set D3CD bit to avoid missing the
- * card interrupt. This is a eSDHC controller problem
+ * card interrupt. This is an eSDHC controller problem
* so we need to apply the following workaround: clear
* and set D3CD bit will make eSDHC re-sample the card
* interrupt. In case a card interrupt was lost,
@@ -579,7 +576,7 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
- u32 new_val;
+ u32 new_val = 0;
u32 mask;
switch (reg) {
@@ -604,35 +601,52 @@ static void esdhc_writeb_le(struct sdhci_host *host, u8 val, int reg)
* Do not touch buswidth bits here. This is done in
* esdhc_pltfm_bus_width.
* Do not touch the D3CD bit either which is used for the
- * SDIO interrupt errata workaround.
+ * SDIO interrupt erratum workaround.
*/
mask = 0xffff & ~(ESDHC_CTRL_BUSWIDTH_MASK | ESDHC_CTRL_D3CD);
esdhc_clrset_le(host, mask, new_val, reg);
return;
+ case SDHCI_SOFTWARE_RESET:
+ if (val & SDHCI_RESET_DATA)
+ new_val = readl(host->ioaddr + SDHCI_HOST_CONTROL);
+ break;
}
esdhc_clrset_le(host, 0xff, val, reg);
- /*
- * The esdhc has a design violation to SDHC spec which tells
- * that software reset should not affect card detection circuit.
- * But esdhc clears its SYSCTL register bits [0..2] during the
- * software reset. This will stop those clocks that card detection
- * circuit relies on. To work around it, we turn the clocks on back
- * to keep card detection circuit functional.
- */
- if ((reg == SDHCI_SOFTWARE_RESET) && (val & 1)) {
- esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
- /*
- * The reset on usdhc fails to clear MIX_CTRL register.
- * Do it manually here.
- */
- if (esdhc_is_usdhc(imx_data)) {
- /* the tuning bits should be kept during reset */
- new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
- writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK,
- host->ioaddr + ESDHC_MIX_CTRL);
- imx_data->is_ddr = 0;
+ if (reg == SDHCI_SOFTWARE_RESET) {
+ if (val & SDHCI_RESET_ALL) {
+ /*
+ * The esdhc has a design violation to SDHC spec which
+ * tells that software reset should not affect card
+ * detection circuit. But esdhc clears its SYSCTL
+ * register bits [0..2] during the software reset. This
+ * will stop those clocks that card detection circuit
+ * relies on. To work around it, we turn the clocks on
+ * back to keep card detection circuit functional.
+ */
+ esdhc_clrset_le(host, 0x7, 0x7, ESDHC_SYSTEM_CONTROL);
+ /*
+ * The reset on usdhc fails to clear MIX_CTRL register.
+ * Do it manually here.
+ */
+ if (esdhc_is_usdhc(imx_data)) {
+ /*
+ * the tuning bits should be kept during reset
+ */
+ new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
+ writel(new_val & ESDHC_MIX_CTRL_TUNING_MASK,
+ host->ioaddr + ESDHC_MIX_CTRL);
+ imx_data->is_ddr = 0;
+ }
+ } else if (val & SDHCI_RESET_DATA) {
+ /*
+ * The eSDHC DAT line software reset clears at least the
+ * data transfer width on i.MX25, so make sure that the
+ * Host Control register is unaffected.
+ */
+ esdhc_clrset_le(host, 0xff, new_val,
+ SDHCI_HOST_CONTROL);
}
}
}
@@ -657,7 +671,8 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
unsigned int host_clock = pltfm_host->clock;
- int pre_div = 2;
+ int ddr_pre_div = imx_data->is_ddr ? 2 : 1;
+ int pre_div = 1;
int div = 1;
u32 temp, val;
@@ -672,28 +687,23 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
return;
}
- if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr)
- pre_div = 1;
-
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
| ESDHC_CLOCK_MASK);
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
- while (host_clock / pre_div / 16 > clock && pre_div < 256)
+ while (host_clock / (16 * pre_div * ddr_pre_div) > clock &&
+ pre_div < 256)
pre_div *= 2;
- while (host_clock / pre_div / div > clock && div < 16)
+ while (host_clock / (div * pre_div * ddr_pre_div) > clock && div < 16)
div++;
- host->mmc->actual_clock = host_clock / pre_div / div;
+ host->mmc->actual_clock = host_clock / (div * pre_div * ddr_pre_div);
dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
clock, host->mmc->actual_clock);
- if (imx_data->is_ddr)
- pre_div >>= 2;
- else
- pre_div >>= 1;
+ pre_div >>= 1;
div--;
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
@@ -763,7 +773,7 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
writel(reg, host->ioaddr + ESDHC_MIX_CTRL);
writel(val << 8, host->ioaddr + ESDHC_TUNE_CTRL_STATUS);
dev_dbg(mmc_dev(host->mmc),
- "tunning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n",
+ "tuning with delay 0x%x ESDHC_TUNE_CTRL_STATUS 0x%x\n",
val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS));
}
@@ -807,7 +817,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
ret = mmc_send_tuning(host->mmc, opcode, NULL);
esdhc_post_tuning(host);
- dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
+ dev_dbg(mmc_dev(host->mmc), "tuning %s at 0x%x ret %d\n",
ret ? "failed" : "passed", avg, ret);
return ret;
@@ -847,15 +857,15 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
}
/*
- * For HS400 eMMC, there is a data_strobe line, this signal is generated
+ * For HS400 eMMC, there is a data_strobe line. This signal is generated
* by the device and used for data output and CRC status response output
* in HS400 mode. The frequency of this signal follows the frequency of
- * CLK generated by host. Host receive the data which is aligned to the
+ * CLK generated by host. The host receives the data which is aligned to the
* edge of data_strobe line. Due to the time delay between CLK line and
* data_strobe line, if the delay time is larger than one clock cycle,
- * then CLK and data_strobe line will misaligned, read error shows up.
+ * then CLK and data_strobe line will be misaligned, read error shows up.
* So when the CLK is higher than 100MHz, each clock cycle is short enough,
- * host should config the delay target.
+ * host should configure the delay target.
*/
static void esdhc_set_strobe_dll(struct sdhci_host *host)
{
@@ -895,7 +905,7 @@ static void esdhc_reset_tuning(struct sdhci_host *host)
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
u32 ctrl;
- /* Rest the tuning circurt */
+ /* Reset the tuning circuit */
if (esdhc_is_usdhc(imx_data)) {
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
ctrl = readl(host->ioaddr + ESDHC_MIX_CTRL);
@@ -976,7 +986,7 @@ static unsigned int esdhc_get_max_timeout_count(struct sdhci_host *host)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
- /* Doc Errata: the uSDHC actual maximum timeout count is 1 << 29 */
+ /* Doc Erratum: the uSDHC actual maximum timeout count is 1 << 29 */
return esdhc_is_usdhc(imx_data) ? 1 << 29 : 1 << 27;
}
@@ -1032,10 +1042,10 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
/*
* ROM code will change the bit burst_length_enable setting
- * to zero if this usdhc is choosed to boot system. Change
+ * to zero if this usdhc is chosen to boot system. Change
* it back here, otherwise it will impact the performance a
* lot. This bit is used to enable/disable the burst length
- * for the external AHB2AXI bridge, it's usefully especially
+ * for the external AHB2AXI bridge. It's useful especially
* for INCR transfer because without burst length indicator,
* the AHB2AXI bridge does not know the burst length in
* advance. And without burst length indicator, AHB INCR
@@ -1045,7 +1055,7 @@ static void sdhci_esdhc_imx_hwinit(struct sdhci_host *host)
| ESDHC_BURST_LEN_EN_INCR,
host->ioaddr + SDHCI_HOST_CONTROL);
/*
- * errata ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
+ * erratum ESDHC_FLAG_ERR004536 fix for MX6Q TO1.2 and MX6DL
* TO1.1, it's harmless for MX6SL
*/
writel(readl(host->ioaddr + 0x6c) | BIT(7),
@@ -1104,7 +1114,7 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
mmc_of_parse_voltage(np, &host->ocr_mask);
- /* sdr50 and sdr104 needs work on 1.8v signal voltage */
+ /* sdr50 and sdr104 need work on 1.8v signal voltage */
if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) &&
!IS_ERR(imx_data->pins_default)) {
imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
@@ -1116,7 +1126,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev,
dev_warn(mmc_dev(host->mmc),
"could not get ultra high speed state, work on normal mode\n");
/*
- * fall back to not support uhs by specify no 1.8v quirk
+ * fall back to not supporting uhs by specifying no
+ * 1.8v quirk
*/
host->quirks2 |= SDHCI_QUIRK2_NO_1_8_V;
}
@@ -1250,14 +1261,20 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
pltfm_host->clk = imx_data->clk_per;
pltfm_host->clock = clk_get_rate(pltfm_host->clk);
- clk_prepare_enable(imx_data->clk_per);
- clk_prepare_enable(imx_data->clk_ipg);
- clk_prepare_enable(imx_data->clk_ahb);
+ err = clk_prepare_enable(imx_data->clk_per);
+ if (err)
+ goto free_sdhci;
+ err = clk_prepare_enable(imx_data->clk_ipg);
+ if (err)
+ goto disable_per_clk;
+ err = clk_prepare_enable(imx_data->clk_ahb);
+ if (err)
+ goto disable_ipg_clk;
imx_data->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(imx_data->pinctrl)) {
err = PTR_ERR(imx_data->pinctrl);
- goto disable_clk;
+ goto disable_ahb_clk;
}
imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
@@ -1265,11 +1282,6 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
if (IS_ERR(imx_data->pins_default))
dev_warn(mmc_dev(host->mmc), "could not get default state\n");
- if (imx_data->socdata->flags & ESDHC_FLAG_ENGCM07207)
- /* Fix errata ENGcm07207 present on i.MX25 and i.MX35 */
- host->quirks |= SDHCI_QUIRK_NO_MULTIBLOCK
- | SDHCI_QUIRK_BROKEN_ADMA;
-
if (esdhc_is_usdhc(imx_data)) {
host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN;
host->mmc->caps |= MMC_CAP_1_8V_DDR;
@@ -1297,13 +1309,13 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
else
err = sdhci_esdhc_imx_probe_nondt(pdev, host, imx_data);
if (err)
- goto disable_clk;
+ goto disable_ahb_clk;
sdhci_esdhc_imx_hwinit(host);
err = sdhci_add_host(host);
if (err)
- goto disable_clk;
+ goto disable_ahb_clk;
pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
@@ -1313,10 +1325,12 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
return 0;
-disable_clk:
- clk_disable_unprepare(imx_data->clk_per);
- clk_disable_unprepare(imx_data->clk_ipg);
+disable_ahb_clk:
clk_disable_unprepare(imx_data->clk_ahb);
+disable_ipg_clk:
+ clk_disable_unprepare(imx_data->clk_ipg);
+disable_per_clk:
+ clk_disable_unprepare(imx_data->clk_per);
free_sdhci:
sdhci_pltfm_free(pdev);
return err;
@@ -1393,14 +1407,34 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
+ int err;
if (!sdhci_sdio_irq_enabled(host)) {
- clk_prepare_enable(imx_data->clk_per);
- clk_prepare_enable(imx_data->clk_ipg);
+ err = clk_prepare_enable(imx_data->clk_per);
+ if (err)
+ return err;
+ err = clk_prepare_enable(imx_data->clk_ipg);
+ if (err)
+ goto disable_per_clk;
}
- clk_prepare_enable(imx_data->clk_ahb);
+ err = clk_prepare_enable(imx_data->clk_ahb);
+ if (err)
+ goto disable_ipg_clk;
+ err = sdhci_runtime_resume_host(host);
+ if (err)
+ goto disable_ahb_clk;
+
+ return 0;
- return sdhci_runtime_resume_host(host);
+disable_ahb_clk:
+ clk_disable_unprepare(imx_data->clk_ahb);
+disable_ipg_clk:
+ if (!sdhci_sdio_irq_enabled(host))
+ clk_disable_unprepare(imx_data->clk_ipg);
+disable_per_clk:
+ if (!sdhci_sdio_irq_enabled(host))
+ clk_disable_unprepare(imx_data->clk_per);
+ return err;
}
#endif
diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index c4bbd7485987..e7893f21b65e 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -19,6 +19,7 @@
*/
#define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
+ SDHCI_QUIRK_32BIT_DMA_ADDR | \
SDHCI_QUIRK_NO_BUSY_IRQ | \
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
SDHCI_QUIRK_PIO_NEEDS_DELAY | \
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index ea6b36c88ae7..b13c0a7d50e4 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -638,7 +638,7 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
ret = mmc_of_parse(host->mmc);
if (ret) {
- dev_err(&pdev->dev, "parsing dt failed (%u)\n", ret);
+ dev_err(&pdev->dev, "parsing dt failed (%d)\n", ret);
goto unreg_clk;
}
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index 92fc3f7c538d..e1721ac37919 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -347,8 +347,7 @@ static inline void sdhci_pci_remove_own_cd(struct sdhci_pci_slot *slot)
static int mfd_emmc_probe_slot(struct sdhci_pci_slot *slot)
{
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE;
- slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC |
- MMC_CAP2_HC_ERASE_SZ;
+ slot->host->mmc->caps2 |= MMC_CAP2_BOOTPART_NOACC;
return 0;
}
@@ -404,10 +403,9 @@ struct intel_host {
bool d3_retune;
};
-const u8 intel_dsm_uuid[] = {
- 0xA5, 0x3E, 0xC1, 0xF6, 0xCD, 0x65, 0x1F, 0x46,
- 0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61,
-};
+static const guid_t intel_dsm_guid =
+ GUID_INIT(0xF6C13EA5, 0x65CD, 0x461F,
+ 0xAB, 0x7A, 0x29, 0xF7, 0xE8, 0xD5, 0xBD, 0x61);
static int __intel_dsm(struct intel_host *intel_host, struct device *dev,
unsigned int fn, u32 *result)
@@ -416,7 +414,7 @@ static int __intel_dsm(struct intel_host *intel_host, struct device *dev,
int err = 0;
size_t len;
- obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), intel_dsm_uuid, 0, fn, NULL);
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), &intel_dsm_guid, 0, fn, NULL);
if (!obj)
return -EOPNOTSUPP;
@@ -543,6 +541,23 @@ static void sdhci_intel_set_power(struct sdhci_host *host, unsigned char mode,
}
}
+#define INTEL_HS400_ES_REG 0x78
+#define INTEL_HS400_ES_BIT BIT(0)
+
+static void intel_hs400_enhanced_strobe(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ u32 val;
+
+ val = sdhci_readl(host, INTEL_HS400_ES_REG);
+ if (ios->enhanced_strobe)
+ val |= INTEL_HS400_ES_BIT;
+ else
+ val &= ~INTEL_HS400_ES_BIT;
+ sdhci_writel(host, val, INTEL_HS400_ES_REG);
+}
+
static const struct sdhci_ops sdhci_intel_byt_ops = {
.set_clock = sdhci_set_clock,
.set_power = sdhci_intel_set_power,
@@ -570,7 +585,6 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
MMC_CAP_CMD_DURING_TFR |
MMC_CAP_WAIT_WHILE_BUSY;
- slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
slot->hw_reset = sdhci_pci_int_hw_reset;
if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC)
slot->host->timeout_clk = 1000; /* 1000 kHz i.e. 1 MHz */
@@ -579,6 +593,19 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
return 0;
}
+static int glk_emmc_probe_slot(struct sdhci_pci_slot *slot)
+{
+ int ret = byt_emmc_probe_slot(slot);
+
+ if (slot->chip->pdev->device != PCI_DEVICE_ID_INTEL_GLK_EMMC) {
+ slot->host->mmc->caps2 |= MMC_CAP2_HS400_ES,
+ slot->host->mmc_host_ops.hs400_enhanced_strobe =
+ intel_hs400_enhanced_strobe;
+ }
+
+ return ret;
+}
+
#ifdef CONFIG_ACPI
static int ni_set_max_freq(struct sdhci_pci_slot *slot)
{
@@ -631,7 +658,7 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
{
byt_read_dsm(slot);
slot->host->mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY |
- MMC_CAP_AGGRESSIVE_PM;
+ MMC_CAP_AGGRESSIVE_PM | MMC_CAP_CD_WAKE;
slot->cd_idx = 0;
slot->cd_override_level = true;
if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BXT_SD ||
@@ -654,6 +681,17 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
.priv_size = sizeof(struct intel_host),
};
+static const struct sdhci_pci_fixes sdhci_intel_glk_emmc = {
+ .allow_runtime_pm = true,
+ .probe_slot = glk_emmc_probe_slot,
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+ SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 |
+ SDHCI_QUIRK2_STOP_WITH_TC,
+ .ops = &sdhci_intel_byt_ops,
+ .priv_size = sizeof(struct intel_host),
+};
+
static const struct sdhci_pci_fixes sdhci_ni_byt_sdio = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON |
@@ -1171,554 +1209,79 @@ static const struct sdhci_pci_fixes sdhci_amd = {
};
static const struct pci_device_id pci_ids[] = {
- {
- .vendor = PCI_VENDOR_ID_RICOH,
- .device = PCI_DEVICE_ID_RICOH_R5C822,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ricoh,
- },
-
- {
- .vendor = PCI_VENDOR_ID_RICOH,
- .device = 0x843,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_RICOH,
- .device = 0xe822,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_RICOH,
- .device = 0xe823,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ricoh_mmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_ENE,
- .device = PCI_DEVICE_ID_ENE_CB712_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ene_712,
- },
-
- {
- .vendor = PCI_VENDOR_ID_ENE,
- .device = PCI_DEVICE_ID_ENE_CB712_SD_2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ene_712,
- },
-
- {
- .vendor = PCI_VENDOR_ID_ENE,
- .device = PCI_DEVICE_ID_ENE_CB714_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ene_714,
- },
-
- {
- .vendor = PCI_VENDOR_ID_ENE,
- .device = PCI_DEVICE_ID_ENE_CB714_SD_2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_ene_714,
- },
-
- {
- .vendor = PCI_VENDOR_ID_MARVELL,
- .device = PCI_DEVICE_ID_MARVELL_88ALP01_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_cafe,
- },
-
- {
- .vendor = PCI_VENDOR_ID_JMICRON,
- .device = PCI_DEVICE_ID_JMICRON_JMB38X_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_jmicron,
- },
-
- {
- .vendor = PCI_VENDOR_ID_JMICRON,
- .device = PCI_DEVICE_ID_JMICRON_JMB38X_MMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_jmicron,
- },
-
- {
- .vendor = PCI_VENDOR_ID_JMICRON,
- .device = PCI_DEVICE_ID_JMICRON_JMB388_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_jmicron,
- },
-
- {
- .vendor = PCI_VENDOR_ID_JMICRON,
- .device = PCI_DEVICE_ID_JMICRON_JMB388_ESD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_jmicron,
- },
-
- {
- .vendor = PCI_VENDOR_ID_SYSKONNECT,
- .device = 0x8000,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_syskt,
- },
-
- {
- .vendor = PCI_VENDOR_ID_VIA,
- .device = 0x95d0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_via,
- },
-
- {
- .vendor = PCI_VENDOR_ID_REALTEK,
- .device = 0x5250,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_rtsx,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_QRK_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_qrk,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MRST_SD0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc0,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MRST_SD1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MRST_SD2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mrst_hc1_hc2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MFD_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MFD_SDIO1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MFD_SDIO2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MFD_EMMC0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MFD_EMMC1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_PCH_SDIO0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_PCH_SDIO1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_pch_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BYT_EMMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BYT_SDIO,
- .subvendor = PCI_VENDOR_ID_NI,
- .subdevice = 0x7884,
- .driver_data = (kernel_ulong_t)&sdhci_ni_byt_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BYT_SDIO,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BYT_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BYT_EMMC2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BSW_EMMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BSW_SDIO,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BSW_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_SDIO0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_SDIO1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_SDIO2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_EMMC0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_CLV_EMMC1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_MRFLD_MMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_mrfld_mmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_SPT_EMMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_SPT_SDIO,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_SPT_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_DNV_EMMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BXT_EMMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BXT_SDIO,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BXT_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BXTM_EMMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BXTM_SDIO,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_BXTM_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_APL_EMMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_APL_SDIO,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_APL_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_GLK_EMMC,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_GLK_SDIO,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sdio,
- },
-
- {
- .vendor = PCI_VENDOR_ID_INTEL,
- .device = PCI_DEVICE_ID_INTEL_GLK_SD,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_intel_byt_sd,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8120,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8220,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8221,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8320,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_8321,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_FUJIN2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_SDS0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_SDS1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_SEABIRD0,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
-
- {
- .vendor = PCI_VENDOR_ID_O2,
- .device = PCI_DEVICE_ID_O2_SEABIRD1,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_o2,
- },
- {
- .vendor = PCI_VENDOR_ID_AMD,
- .device = PCI_ANY_ID,
- .class = PCI_CLASS_SYSTEM_SDHCI << 8,
- .class_mask = 0xFFFF00,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .driver_data = (kernel_ulong_t)&sdhci_amd,
- },
- { /* Generic SD host controller */
- PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
- },
-
+ SDHCI_PCI_DEVICE(RICOH, R5C822, ricoh),
+ SDHCI_PCI_DEVICE(RICOH, R5C843, ricoh_mmc),
+ SDHCI_PCI_DEVICE(RICOH, R5CE822, ricoh_mmc),
+ SDHCI_PCI_DEVICE(RICOH, R5CE823, ricoh_mmc),
+ SDHCI_PCI_DEVICE(ENE, CB712_SD, ene_712),
+ SDHCI_PCI_DEVICE(ENE, CB712_SD_2, ene_712),
+ SDHCI_PCI_DEVICE(ENE, CB714_SD, ene_714),
+ SDHCI_PCI_DEVICE(ENE, CB714_SD_2, ene_714),
+ SDHCI_PCI_DEVICE(MARVELL, 88ALP01_SD, cafe),
+ SDHCI_PCI_DEVICE(JMICRON, JMB38X_SD, jmicron),
+ SDHCI_PCI_DEVICE(JMICRON, JMB38X_MMC, jmicron),
+ SDHCI_PCI_DEVICE(JMICRON, JMB388_SD, jmicron),
+ SDHCI_PCI_DEVICE(JMICRON, JMB388_ESD, jmicron),
+ SDHCI_PCI_DEVICE(SYSKONNECT, 8000, syskt),
+ SDHCI_PCI_DEVICE(VIA, 95D0, via),
+ SDHCI_PCI_DEVICE(REALTEK, 5250, rtsx),
+ SDHCI_PCI_DEVICE(INTEL, QRK_SD, intel_qrk),
+ SDHCI_PCI_DEVICE(INTEL, MRST_SD0, intel_mrst_hc0),
+ SDHCI_PCI_DEVICE(INTEL, MRST_SD1, intel_mrst_hc1_hc2),
+ SDHCI_PCI_DEVICE(INTEL, MRST_SD2, intel_mrst_hc1_hc2),
+ SDHCI_PCI_DEVICE(INTEL, MFD_SD, intel_mfd_sd),
+ SDHCI_PCI_DEVICE(INTEL, MFD_SDIO1, intel_mfd_sdio),
+ SDHCI_PCI_DEVICE(INTEL, MFD_SDIO2, intel_mfd_sdio),
+ SDHCI_PCI_DEVICE(INTEL, MFD_EMMC0, intel_mfd_emmc),
+ SDHCI_PCI_DEVICE(INTEL, MFD_EMMC1, intel_mfd_emmc),
+ SDHCI_PCI_DEVICE(INTEL, PCH_SDIO0, intel_pch_sdio),
+ SDHCI_PCI_DEVICE(INTEL, PCH_SDIO1, intel_pch_sdio),
+ SDHCI_PCI_DEVICE(INTEL, BYT_EMMC, intel_byt_emmc),
+ SDHCI_PCI_SUBDEVICE(INTEL, BYT_SDIO, NI, 7884, ni_byt_sdio),
+ SDHCI_PCI_DEVICE(INTEL, BYT_SDIO, intel_byt_sdio),
+ SDHCI_PCI_DEVICE(INTEL, BYT_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, BYT_EMMC2, intel_byt_emmc),
+ SDHCI_PCI_DEVICE(INTEL, BSW_EMMC, intel_byt_emmc),
+ SDHCI_PCI_DEVICE(INTEL, BSW_SDIO, intel_byt_sdio),
+ SDHCI_PCI_DEVICE(INTEL, BSW_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, CLV_SDIO0, intel_mfd_sd),
+ SDHCI_PCI_DEVICE(INTEL, CLV_SDIO1, intel_mfd_sdio),
+ SDHCI_PCI_DEVICE(INTEL, CLV_SDIO2, intel_mfd_sdio),
+ SDHCI_PCI_DEVICE(INTEL, CLV_EMMC0, intel_mfd_emmc),
+ SDHCI_PCI_DEVICE(INTEL, CLV_EMMC1, intel_mfd_emmc),
+ SDHCI_PCI_DEVICE(INTEL, MRFLD_MMC, intel_mrfld_mmc),
+ SDHCI_PCI_DEVICE(INTEL, SPT_EMMC, intel_byt_emmc),
+ SDHCI_PCI_DEVICE(INTEL, SPT_SDIO, intel_byt_sdio),
+ SDHCI_PCI_DEVICE(INTEL, SPT_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, DNV_EMMC, intel_byt_emmc),
+ SDHCI_PCI_DEVICE(INTEL, BXT_EMMC, intel_byt_emmc),
+ SDHCI_PCI_DEVICE(INTEL, BXT_SDIO, intel_byt_sdio),
+ SDHCI_PCI_DEVICE(INTEL, BXT_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, BXTM_EMMC, intel_byt_emmc),
+ SDHCI_PCI_DEVICE(INTEL, BXTM_SDIO, intel_byt_sdio),
+ SDHCI_PCI_DEVICE(INTEL, BXTM_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, APL_EMMC, intel_byt_emmc),
+ SDHCI_PCI_DEVICE(INTEL, APL_SDIO, intel_byt_sdio),
+ SDHCI_PCI_DEVICE(INTEL, APL_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, GLK_EMMC, intel_glk_emmc),
+ SDHCI_PCI_DEVICE(INTEL, GLK_SDIO, intel_byt_sdio),
+ SDHCI_PCI_DEVICE(INTEL, GLK_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, CNP_EMMC, intel_glk_emmc),
+ SDHCI_PCI_DEVICE(INTEL, CNP_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(INTEL, CNPH_SD, intel_byt_sd),
+ SDHCI_PCI_DEVICE(O2, 8120, o2),
+ SDHCI_PCI_DEVICE(O2, 8220, o2),
+ SDHCI_PCI_DEVICE(O2, 8221, o2),
+ SDHCI_PCI_DEVICE(O2, 8320, o2),
+ SDHCI_PCI_DEVICE(O2, 8321, o2),
+ SDHCI_PCI_DEVICE(O2, FUJIN2, o2),
+ SDHCI_PCI_DEVICE(O2, SDS0, o2),
+ SDHCI_PCI_DEVICE(O2, SDS1, o2),
+ SDHCI_PCI_DEVICE(O2, SEABIRD0, o2),
+ SDHCI_PCI_DEVICE(O2, SEABIRD1, o2),
+ SDHCI_PCI_DEVICE_CLASS(AMD, SYSTEM_SDHCI, PCI_CLASS_MASK, amd),
+ /* Generic SD host controller */
+ {PCI_DEVICE_CLASS(SYSTEM_SDHCI, PCI_CLASS_MASK)},
{ /* end: all zeroes */ },
};
diff --git a/drivers/mmc/host/sdhci-pci.h b/drivers/mmc/host/sdhci-pci.h
index 37766d20a600..75196a2b5289 100644
--- a/drivers/mmc/host/sdhci-pci.h
+++ b/drivers/mmc/host/sdhci-pci.h
@@ -2,7 +2,7 @@
#define __SDHCI_PCI_H
/*
- * PCI device IDs
+ * PCI device IDs, sub IDs
*/
#define PCI_DEVICE_ID_INTEL_PCH_SDIO0 0x8809
@@ -37,6 +37,50 @@
#define PCI_DEVICE_ID_INTEL_GLK_SD 0x31ca
#define PCI_DEVICE_ID_INTEL_GLK_EMMC 0x31cc
#define PCI_DEVICE_ID_INTEL_GLK_SDIO 0x31d0
+#define PCI_DEVICE_ID_INTEL_CNP_EMMC 0x9dc4
+#define PCI_DEVICE_ID_INTEL_CNP_SD 0x9df5
+#define PCI_DEVICE_ID_INTEL_CNPH_SD 0xa375
+
+#define PCI_DEVICE_ID_SYSKONNECT_8000 0x8000
+#define PCI_DEVICE_ID_VIA_95D0 0x95d0
+#define PCI_DEVICE_ID_REALTEK_5250 0x5250
+
+#define PCI_SUBDEVICE_ID_NI_7884 0x7884
+
+/*
+ * PCI device class and mask
+ */
+
+#define SYSTEM_SDHCI (PCI_CLASS_SYSTEM_SDHCI << 8)
+#define PCI_CLASS_MASK 0xFFFF00
+
+/*
+ * Macros for PCI device-description
+ */
+
+#define _PCI_VEND(vend) PCI_VENDOR_ID_##vend
+#define _PCI_DEV(vend, dev) PCI_DEVICE_ID_##vend##_##dev
+#define _PCI_SUBDEV(subvend, subdev) PCI_SUBDEVICE_ID_##subvend##_##subdev
+
+#define SDHCI_PCI_DEVICE(vend, dev, cfg) { \
+ .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \
+ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \
+ .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \
+}
+
+#define SDHCI_PCI_SUBDEVICE(vend, dev, subvend, subdev, cfg) { \
+ .vendor = _PCI_VEND(vend), .device = _PCI_DEV(vend, dev), \
+ .subvendor = _PCI_VEND(subvend), \
+ .subdevice = _PCI_SUBDEV(subvend, subdev), \
+ .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \
+}
+
+#define SDHCI_PCI_DEVICE_CLASS(vend, cl, cl_msk, cfg) { \
+ .vendor = _PCI_VEND(vend), .device = PCI_ANY_ID, \
+ .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, \
+ .class = (cl), .class_mask = (cl_msk), \
+ .driver_data = (kernel_ulong_t)&(sdhci_##cfg) \
+}
/*
* PCI registers
diff --git a/drivers/mmc/host/sdricoh_cs.c b/drivers/mmc/host/sdricoh_cs.c
index 5ff26ab81eb1..70cb00aa79a0 100644
--- a/drivers/mmc/host/sdricoh_cs.c
+++ b/drivers/mmc/host/sdricoh_cs.c
@@ -256,9 +256,6 @@ static int sdricoh_blockio(struct sdricoh_host *host, int read,
}
}
- if (len)
- return -EIO;
-
return 0;
}
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index e897e7fc3b14..64b7e9f18361 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -1,16 +1,16 @@
/*
- * linux/drivers/mmc/host/tmio_mmc.c
+ * Driver for the MMC / SD / SDIO cell found in:
+ *
+ * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
*
+ * Copyright (C) 2017 Renesas Electronics Corporation
+ * Copyright (C) 2017 Horms Solutions, Simon Horman
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
- *
- * Driver for the MMC / SD / SDIO cell found in:
- *
- * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
*/
#include <linux/device.h>
@@ -99,13 +99,13 @@ static int tmio_mmc_probe(struct platform_device *pdev)
/* SD control register space size is 0x200, 0x400 for bus_shift=1 */
host->bus_shift = resource_size(res) >> 10;
- ret = tmio_mmc_host_probe(host, pdata);
+ ret = tmio_mmc_host_probe(host, pdata, NULL);
if (ret)
goto host_free;
ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq,
- IRQF_TRIGGER_FALLING,
- dev_name(&pdev->dev), host);
+ IRQF_TRIGGER_FALLING,
+ dev_name(&pdev->dev), host);
if (ret)
goto host_remove;
@@ -132,6 +132,7 @@ static int tmio_mmc_remove(struct platform_device *pdev)
if (mmc) {
struct tmio_mmc_host *host = mmc_priv(mmc);
+
tmio_mmc_host_remove(host);
if (cell->disable)
cell->disable(pdev);
@@ -145,8 +146,7 @@ static int tmio_mmc_remove(struct platform_device *pdev)
static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume)
SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
- tmio_mmc_host_runtime_resume,
- NULL)
+ tmio_mmc_host_runtime_resume, NULL)
};
static struct platform_driver tmio_mmc_driver = {
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index d0edb5730d3f..6ad6704175dc 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -1,8 +1,11 @@
/*
- * linux/drivers/mmc/host/tmio_mmc.h
+ * Driver for the MMC / SD / SDIO cell found in:
+ *
+ * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
*
- * Copyright (C) 2016 Sang Engineering, Wolfram Sang
- * Copyright (C) 2015-16 Renesas Electronics Corporation
+ * Copyright (C) 2015-17 Renesas Electronics Corporation
+ * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang
+ * Copyright (C) 2016-17 Horms Solutions, Simon Horman
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
*
@@ -10,9 +13,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Driver for the MMC / SD / SDIO cell found in:
- *
- * TC6393XB TC6391XB TC6387XB T7L66XB ASIC3
*/
#ifndef TMIO_MMC_H
@@ -115,6 +115,15 @@ struct tmio_mmc_dma {
void (*enable)(struct tmio_mmc_host *host, bool enable);
};
+struct tmio_mmc_dma_ops {
+ void (*start)(struct tmio_mmc_host *host, struct mmc_data *data);
+ void (*enable)(struct tmio_mmc_host *host, bool enable);
+ void (*request)(struct tmio_mmc_host *host,
+ struct tmio_mmc_data *pdata);
+ void (*release)(struct tmio_mmc_host *host);
+ void (*abort)(struct tmio_mmc_host *host);
+};
+
struct tmio_mmc_host {
void __iomem *ctl;
struct mmc_command *cmd;
@@ -189,12 +198,15 @@ struct tmio_mmc_host {
/* Tuning values: 1 for success, 0 for failure */
DECLARE_BITMAP(taps, BITS_PER_BYTE * sizeof(long));
unsigned int tap_num;
+
+ const struct tmio_mmc_dma_ops *dma_ops;
};
struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev);
void tmio_mmc_host_free(struct tmio_mmc_host *host);
int tmio_mmc_host_probe(struct tmio_mmc_host *host,
- struct tmio_mmc_data *pdata);
+ struct tmio_mmc_data *pdata,
+ const struct tmio_mmc_dma_ops *dma_ops);
void tmio_mmc_host_remove(struct tmio_mmc_host *host);
void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
@@ -216,38 +228,6 @@ static inline void tmio_mmc_kunmap_atomic(struct scatterlist *sg,
local_irq_restore(*flags);
}
-#if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
-void tmio_mmc_start_dma(struct tmio_mmc_host *host, struct mmc_data *data);
-void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable);
-void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata);
-void tmio_mmc_release_dma(struct tmio_mmc_host *host);
-void tmio_mmc_abort_dma(struct tmio_mmc_host *host);
-#else
-static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
- struct mmc_data *data)
-{
-}
-
-static inline void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
-{
-}
-
-static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host,
- struct tmio_mmc_data *pdata)
-{
- host->chan_tx = NULL;
- host->chan_rx = NULL;
-}
-
-static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
-{
-}
-
-static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
-{
-}
-#endif
-
#ifdef CONFIG_PM
int tmio_mmc_host_runtime_suspend(struct device *dev);
int tmio_mmc_host_runtime_resume(struct device *dev);
@@ -259,24 +239,26 @@ static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
}
static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
- u16 *buf, int count)
+ u16 *buf, int count)
{
readsw(host->ctl + (addr << host->bus_shift), buf, count);
}
-static inline u32 sd_ctrl_read16_and_16_as_32(struct tmio_mmc_host *host, int addr)
+static inline u32 sd_ctrl_read16_and_16_as_32(struct tmio_mmc_host *host,
+ int addr)
{
return readw(host->ctl + (addr << host->bus_shift)) |
readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
}
static inline void sd_ctrl_read32_rep(struct tmio_mmc_host *host, int addr,
- u32 *buf, int count)
+ u32 *buf, int count)
{
readsl(host->ctl + (addr << host->bus_shift), buf, count);
}
-static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val)
+static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr,
+ u16 val)
{
/* If there is a hook and it returns non-zero then there
* is an error and the write should be skipped
@@ -287,19 +269,20 @@ static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val
}
static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
- u16 *buf, int count)
+ u16 *buf, int count)
{
writesw(host->ctl + (addr << host->bus_shift), buf, count);
}
-static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host, int addr, u32 val)
+static inline void sd_ctrl_write32_as_16_and_16(struct tmio_mmc_host *host,
+ int addr, u32 val)
{
writew(val & 0xffff, host->ctl + (addr << host->bus_shift));
writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
}
static inline void sd_ctrl_write32_rep(struct tmio_mmc_host *host, int addr,
- const u32 *buf, int count)
+ const u32 *buf, int count)
{
writesl(host->ctl + (addr << host->bus_shift), buf, count);
}
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_core.c
index a2d92f10501b..82b80d42f7ae 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -1,8 +1,11 @@
/*
- * linux/drivers/mmc/host/tmio_mmc_pio.c
+ * Driver for the MMC / SD / SDIO IP found in:
+ *
+ * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs
*
- * Copyright (C) 2016 Sang Engineering, Wolfram Sang
- * Copyright (C) 2015-16 Renesas Electronics Corporation
+ * Copyright (C) 2015-17 Renesas Electronics Corporation
+ * Copyright (C) 2016-17 Sang Engineering, Wolfram Sang
+ * Copyright (C) 2017 Horms Solutions, Simon Horman
* Copyright (C) 2011 Guennadi Liakhovetski
* Copyright (C) 2007 Ian Molton
* Copyright (C) 2004 Ian Molton
@@ -11,10 +14,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Driver for the MMC / SD / SDIO IP found in:
- *
- * TC6393XB, TC6391XB, TC6387XB, T7L66XB, ASIC3, SH-Mobile SoCs
- *
* This driver draws mainly on scattered spec sheets, Reverse engineering
* of the toshiba e800 SD driver and some parts of the 2.4 ASIC3 driver (4 bit
* support). (Further 4 bit support from a later datasheet).
@@ -52,17 +51,55 @@
#include "tmio_mmc.h"
+static inline void tmio_mmc_start_dma(struct tmio_mmc_host *host,
+ struct mmc_data *data)
+{
+ if (host->dma_ops)
+ host->dma_ops->start(host, data);
+}
+
+static inline void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
+{
+ if (host->dma_ops)
+ host->dma_ops->enable(host, enable);
+}
+
+static inline void tmio_mmc_request_dma(struct tmio_mmc_host *host,
+ struct tmio_mmc_data *pdata)
+{
+ if (host->dma_ops) {
+ host->dma_ops->request(host, pdata);
+ } else {
+ host->chan_tx = NULL;
+ host->chan_rx = NULL;
+ }
+}
+
+static inline void tmio_mmc_release_dma(struct tmio_mmc_host *host)
+{
+ if (host->dma_ops)
+ host->dma_ops->release(host);
+}
+
+static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
+{
+ if (host->dma_ops)
+ host->dma_ops->abort(host);
+}
+
void tmio_mmc_enable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
{
host->sdcard_irq_mask &= ~(i & TMIO_MASK_IRQ);
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
}
+EXPORT_SYMBOL_GPL(tmio_mmc_enable_mmc_irqs);
void tmio_mmc_disable_mmc_irqs(struct tmio_mmc_host *host, u32 i)
{
host->sdcard_irq_mask |= (i & TMIO_MASK_IRQ);
sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, host->sdcard_irq_mask);
}
+EXPORT_SYMBOL_GPL(tmio_mmc_disable_mmc_irqs);
static void tmio_mmc_ack_mmc_irqs(struct tmio_mmc_host *host, u32 i)
{
@@ -90,16 +127,17 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host)
#define STATUS_TO_TEXT(a, status, i) \
do { \
- if (status & TMIO_STAT_##a) { \
- if (i++) \
- printk(" | "); \
- printk(#a); \
+ if ((status) & TMIO_STAT_##a) { \
+ if ((i)++) \
+ printk(KERN_DEBUG " | "); \
+ printk(KERN_DEBUG #a); \
} \
} while (0)
static void pr_debug_status(u32 status)
{
int i = 0;
+
pr_debug("status: %08x = ", status);
STATUS_TO_TEXT(CARD_REMOVE, status, i);
STATUS_TO_TEXT(CARD_INSERT, status, i);
@@ -140,8 +178,7 @@ static void tmio_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
pm_runtime_get_sync(mmc_dev(mmc));
host->sdio_irq_enabled = true;
- host->sdio_irq_mask = TMIO_SDIO_MASK_ALL &
- ~TMIO_SDIO_STAT_IOIRQ;
+ host->sdio_irq_mask = TMIO_SDIO_MASK_ALL & ~TMIO_SDIO_STAT_IOIRQ;
/* Clear obsolete interrupts before enabling */
sdio_status = sd_ctrl_read16(host, CTL_SDIO_STATUS) & ~TMIO_SDIO_MASK_ALL;
@@ -185,7 +222,7 @@ static void tmio_mmc_clk_stop(struct tmio_mmc_host *host)
}
static void tmio_mmc_set_clock(struct tmio_mmc_host *host,
- unsigned int new_clock)
+ unsigned int new_clock)
{
u32 clk = 0, clock;
@@ -229,6 +266,12 @@ static void tmio_mmc_reset(struct tmio_mmc_host *host)
if (host->pdata->flags & TMIO_MMC_HAVE_HIGH_REG)
sd_ctrl_write16(host, CTL_RESET_SDIO, 0x0001);
msleep(10);
+
+ if (host->pdata->flags & TMIO_MMC_SDIO_IRQ) {
+ sd_ctrl_write16(host, CTL_SDIO_IRQ_MASK, host->sdio_irq_mask);
+ sd_ctrl_write16(host, CTL_TRANSACTION_CTL, 0x0001);
+ }
+
}
static void tmio_mmc_reset_work(struct work_struct *work)
@@ -246,16 +289,16 @@ static void tmio_mmc_reset_work(struct work_struct *work)
* cancel_delayed_work(), it can happen, that a .set_ios() call preempts
* us, so, have to check for IS_ERR(host->mrq)
*/
- if (IS_ERR_OR_NULL(mrq)
- || time_is_after_jiffies(host->last_req_ts +
- msecs_to_jiffies(CMDREQ_TIMEOUT))) {
+ if (IS_ERR_OR_NULL(mrq) ||
+ time_is_after_jiffies(host->last_req_ts +
+ msecs_to_jiffies(CMDREQ_TIMEOUT))) {
spin_unlock_irqrestore(&host->lock, flags);
return;
}
dev_warn(&host->pdev->dev,
- "timeout waiting for hardware interrupt (CMD%u)\n",
- mrq->cmd->opcode);
+ "timeout waiting for hardware interrupt (CMD%u)\n",
+ mrq->cmd->opcode);
if (host->data)
host->data->error = -ETIMEDOUT;
@@ -279,45 +322,6 @@ static void tmio_mmc_reset_work(struct work_struct *work)
mmc_request_done(host->mmc, mrq);
}
-/* called with host->lock held, interrupts disabled */
-static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
-{
- struct mmc_request *mrq;
- unsigned long flags;
-
- spin_lock_irqsave(&host->lock, flags);
-
- mrq = host->mrq;
- if (IS_ERR_OR_NULL(mrq)) {
- spin_unlock_irqrestore(&host->lock, flags);
- return;
- }
-
- host->cmd = NULL;
- host->data = NULL;
- host->force_pio = false;
-
- cancel_delayed_work(&host->delayed_reset_work);
-
- host->mrq = NULL;
- spin_unlock_irqrestore(&host->lock, flags);
-
- if (mrq->cmd->error || (mrq->data && mrq->data->error))
- tmio_mmc_abort_dma(host);
-
- if (host->check_scc_error)
- host->check_scc_error(host);
-
- mmc_request_done(host->mmc, mrq);
-}
-
-static void tmio_mmc_done_work(struct work_struct *work)
-{
- struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host,
- done);
- tmio_mmc_finish_request(host);
-}
-
/* These are the bitmasks the tmio chip requires to implement the MMC response
* types. Note that R1 and R6 are the same in this scheme. */
#define APP_CMD 0x0040
@@ -332,7 +336,8 @@ static void tmio_mmc_done_work(struct work_struct *work)
#define SECURITY_CMD 0x4000
#define NO_CMD12_ISSUE 0x4000 /* TMIO_MMC_HAVE_CMD12_CTRL */
-static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
+static int tmio_mmc_start_command(struct tmio_mmc_host *host,
+ struct mmc_command *cmd)
{
struct mmc_data *data = host->data;
int c = cmd->opcode;
@@ -371,11 +376,11 @@ static int tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command
c |= TRANSFER_MULTI;
/*
- * Disable auto CMD12 at IO_RW_EXTENDED when
- * multiple block transfer
+ * Disable auto CMD12 at IO_RW_EXTENDED and
+ * SET_BLOCK_COUNT when doing multiple block transfer
*/
if ((host->pdata->flags & TMIO_MMC_HAVE_CMD12_CTRL) &&
- (cmd->opcode == SD_IO_RW_EXTENDED))
+ (cmd->opcode == SD_IO_RW_EXTENDED || host->mrq->sbc))
c |= NO_CMD12_ISSUE;
}
if (data->flags & MMC_DATA_READ)
@@ -497,8 +502,6 @@ static void tmio_mmc_pio_irq(struct tmio_mmc_host *host)
if (host->sg_off == host->sg_ptr->length)
tmio_mmc_next_sg(host);
-
- return;
}
static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host)
@@ -506,6 +509,7 @@ static void tmio_mmc_check_bounce_buffer(struct tmio_mmc_host *host)
if (host->sg_ptr == &host->bounce_sg) {
unsigned long flags;
void *sg_vaddr = tmio_mmc_kmap_atomic(host->sg_orig, &flags);
+
memcpy(sg_vaddr, host->bounce_buf, host->bounce_sg.length);
tmio_mmc_kunmap_atomic(host->sg_orig, &flags, sg_vaddr);
}
@@ -552,7 +556,7 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
host->mrq);
}
- if (stop) {
+ if (stop && !host->mrq->sbc) {
if (stop->opcode != MMC_STOP_TRANSMISSION || stop->arg)
dev_err(&host->pdev->dev, "unsupported stop: CMD%u,0x%x. We did CMD12,0\n",
stop->opcode, stop->arg);
@@ -565,10 +569,12 @@ void tmio_mmc_do_data_irq(struct tmio_mmc_host *host)
schedule_work(&host->done);
}
+EXPORT_SYMBOL_GPL(tmio_mmc_do_data_irq);
static void tmio_mmc_data_irq(struct tmio_mmc_host *host, unsigned int stat)
{
struct mmc_data *data;
+
spin_lock(&host->lock);
data = host->data;
@@ -613,8 +619,7 @@ out:
spin_unlock(&host->lock);
}
-static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host,
- unsigned int stat)
+static void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat)
{
struct mmc_command *cmd = host->cmd;
int i, addr;
@@ -675,7 +680,7 @@ out:
}
static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
- int ireg, int status)
+ int ireg, int status)
{
struct mmc_host *mmc = host->mmc;
@@ -693,14 +698,13 @@ static bool __tmio_mmc_card_detect_irq(struct tmio_mmc_host *host,
return false;
}
-static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host,
- int ireg, int status)
+static bool __tmio_mmc_sdcard_irq(struct tmio_mmc_host *host, int ireg,
+ int status)
{
/* Command completion */
if (ireg & (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT)) {
- tmio_mmc_ack_mmc_irqs(host,
- TMIO_STAT_CMDRESPEND |
- TMIO_STAT_CMDTIMEOUT);
+ tmio_mmc_ack_mmc_irqs(host, TMIO_STAT_CMDRESPEND |
+ TMIO_STAT_CMDTIMEOUT);
tmio_mmc_cmd_irq(host, status);
return true;
}
@@ -768,10 +772,10 @@ irqreturn_t tmio_mmc_irq(int irq, void *devid)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL(tmio_mmc_irq);
+EXPORT_SYMBOL_GPL(tmio_mmc_irq);
static int tmio_mmc_start_data(struct tmio_mmc_host *host,
- struct mmc_data *data)
+ struct mmc_data *data)
{
struct tmio_mmc_data *pdata = host->pdata;
@@ -826,7 +830,7 @@ static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (host->tap_num * 2 >= sizeof(host->taps) * BITS_PER_BYTE) {
dev_warn_once(&host->pdev->dev,
- "Too many taps, skipping tuning. Please consider updating size of taps field of tmio_mmc_host\n");
+ "Too many taps, skipping tuning. Please consider updating size of taps field of tmio_mmc_host\n");
goto out;
}
@@ -857,12 +861,43 @@ out:
return ret;
}
+static void tmio_process_mrq(struct tmio_mmc_host *host,
+ struct mmc_request *mrq)
+{
+ struct mmc_command *cmd;
+ int ret;
+
+ if (mrq->sbc && host->cmd != mrq->sbc) {
+ cmd = mrq->sbc;
+ } else {
+ cmd = mrq->cmd;
+ if (mrq->data) {
+ ret = tmio_mmc_start_data(host, mrq->data);
+ if (ret)
+ goto fail;
+ }
+ }
+
+ ret = tmio_mmc_start_command(host, cmd);
+ if (ret)
+ goto fail;
+
+ schedule_delayed_work(&host->delayed_reset_work,
+ msecs_to_jiffies(CMDREQ_TIMEOUT));
+ return;
+
+fail:
+ host->force_pio = false;
+ host->mrq = NULL;
+ mrq->cmd->error = ret;
+ mmc_request_done(host->mmc, mrq);
+}
+
/* Process requests from the MMC layer */
static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct tmio_mmc_host *host = mmc_priv(mmc);
unsigned long flags;
- int ret;
spin_lock_irqsave(&host->lock, flags);
@@ -882,24 +917,54 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
spin_unlock_irqrestore(&host->lock, flags);
- if (mrq->data) {
- ret = tmio_mmc_start_data(host, mrq->data);
- if (ret)
- goto fail;
+ tmio_process_mrq(host, mrq);
+}
+
+static void tmio_mmc_finish_request(struct tmio_mmc_host *host)
+{
+ struct mmc_request *mrq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ mrq = host->mrq;
+ if (IS_ERR_OR_NULL(mrq)) {
+ spin_unlock_irqrestore(&host->lock, flags);
+ return;
+ }
+
+ /* If not SET_BLOCK_COUNT, clear old data */
+ if (host->cmd != mrq->sbc) {
+ host->cmd = NULL;
+ host->data = NULL;
+ host->force_pio = false;
+ host->mrq = NULL;
}
- ret = tmio_mmc_start_command(host, mrq->cmd);
- if (!ret) {
- schedule_delayed_work(&host->delayed_reset_work,
- msecs_to_jiffies(CMDREQ_TIMEOUT));
+ cancel_delayed_work(&host->delayed_reset_work);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ if (mrq->cmd->error || (mrq->data && mrq->data->error))
+ tmio_mmc_abort_dma(host);
+
+ if (host->check_scc_error)
+ host->check_scc_error(host);
+
+ /* If SET_BLOCK_COUNT, continue with main command */
+ if (host->mrq) {
+ tmio_process_mrq(host, mrq);
return;
}
-fail:
- host->force_pio = false;
- host->mrq = NULL;
- mrq->cmd->error = ret;
- mmc_request_done(mmc, mrq);
+ mmc_request_done(host->mmc, mrq);
+}
+
+static void tmio_mmc_done_work(struct work_struct *work)
+{
+ struct tmio_mmc_host *host = container_of(work, struct tmio_mmc_host,
+ done);
+ tmio_mmc_finish_request(host);
}
static int tmio_mmc_clk_enable(struct tmio_mmc_host *host)
@@ -965,7 +1030,7 @@ static void tmio_mmc_power_off(struct tmio_mmc_host *host)
}
static void tmio_mmc_set_bus_width(struct tmio_mmc_host *host,
- unsigned char bus_width)
+ unsigned char bus_width)
{
u16 reg = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT)
& ~(CARD_OPT_WIDTH | CARD_OPT_WIDTH8);
@@ -1005,7 +1070,8 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
dev_dbg(dev,
"%s.%d: CMD%u active since %lu, now %lu!\n",
current->comm, task_pid_nr(current),
- host->mrq->cmd->opcode, host->last_req_ts, jiffies);
+ host->mrq->cmd->opcode, host->last_req_ts,
+ jiffies);
}
spin_unlock_irqrestore(&host->lock, flags);
@@ -1052,6 +1118,7 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc)
struct tmio_mmc_host *host = mmc_priv(mmc);
struct tmio_mmc_data *pdata = host->pdata;
int ret = mmc_gpio_get_ro(mmc);
+
if (ret >= 0)
return ret;
@@ -1108,6 +1175,7 @@ static void tmio_mmc_of_parse(struct platform_device *pdev,
struct tmio_mmc_data *pdata)
{
const struct device_node *np = pdev->dev.of_node;
+
if (!np)
return;
@@ -1131,16 +1199,17 @@ tmio_mmc_host_alloc(struct platform_device *pdev)
return host;
}
-EXPORT_SYMBOL(tmio_mmc_host_alloc);
+EXPORT_SYMBOL_GPL(tmio_mmc_host_alloc);
void tmio_mmc_host_free(struct tmio_mmc_host *host)
{
mmc_free_host(host->mmc);
}
-EXPORT_SYMBOL(tmio_mmc_host_free);
+EXPORT_SYMBOL_GPL(tmio_mmc_host_free);
int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
- struct tmio_mmc_data *pdata)
+ struct tmio_mmc_data *pdata,
+ const struct tmio_mmc_dma_ops *dma_ops)
{
struct platform_device *pdev = _host->pdev;
struct mmc_host *mmc = _host->mmc;
@@ -1177,7 +1246,8 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
return -ENOMEM;
tmio_mmc_ops.card_busy = _host->card_busy;
- tmio_mmc_ops.start_signal_voltage_switch = _host->start_signal_voltage_switch;
+ tmio_mmc_ops.start_signal_voltage_switch =
+ _host->start_signal_voltage_switch;
mmc->ops = &tmio_mmc_ops;
mmc->caps |= MMC_CAP_4_BIT_DATA | pdata->capabilities;
@@ -1221,6 +1291,10 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
if (_host->native_hotplug)
pm_runtime_get_noresume(&pdev->dev);
+ _host->sdio_irq_enabled = false;
+ if (pdata->flags & TMIO_MMC_SDIO_IRQ)
+ _host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
+
tmio_mmc_clk_stop(_host);
tmio_mmc_reset(_host);
@@ -1237,13 +1311,6 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
_host->sdcard_irq_mask &= ~irq_mask;
- _host->sdio_irq_enabled = false;
- if (pdata->flags & TMIO_MMC_SDIO_IRQ) {
- _host->sdio_irq_mask = TMIO_SDIO_MASK_ALL;
- sd_ctrl_write16(_host, CTL_SDIO_IRQ_MASK, _host->sdio_irq_mask);
- sd_ctrl_write16(_host, CTL_TRANSACTION_CTL, 0x0001);
- }
-
spin_lock_init(&_host->lock);
mutex_init(&_host->ios_lock);
@@ -1252,6 +1319,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
INIT_WORK(&_host->done, tmio_mmc_done_work);
/* See if we also get DMA */
+ _host->dma_ops = dma_ops;
tmio_mmc_request_dma(_host, pdata);
pm_runtime_set_active(&pdev->dev);
@@ -1278,7 +1346,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
return 0;
}
-EXPORT_SYMBOL(tmio_mmc_host_probe);
+EXPORT_SYMBOL_GPL(tmio_mmc_host_probe);
void tmio_mmc_host_remove(struct tmio_mmc_host *host)
{
@@ -1303,7 +1371,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
tmio_mmc_clk_disable(host);
}
-EXPORT_SYMBOL(tmio_mmc_host_remove);
+EXPORT_SYMBOL_GPL(tmio_mmc_host_remove);
#ifdef CONFIG_PM
int tmio_mmc_host_runtime_suspend(struct device *dev)
@@ -1320,7 +1388,7 @@ int tmio_mmc_host_runtime_suspend(struct device *dev)
return 0;
}
-EXPORT_SYMBOL(tmio_mmc_host_runtime_suspend);
+EXPORT_SYMBOL_GPL(tmio_mmc_host_runtime_suspend);
static bool tmio_mmc_can_retune(struct tmio_mmc_host *host)
{
@@ -1345,7 +1413,7 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
return 0;
}
-EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
+EXPORT_SYMBOL_GPL(tmio_mmc_host_runtime_resume);
#endif
MODULE_LICENSE("GPL v2");
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index c061e7c704be..fbeea1a491a6 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -2107,7 +2107,8 @@ static int vub300_probe(struct usb_interface *interface,
usb_string(udev, udev->descriptor.iSerialNumber, serial_number,
sizeof(serial_number));
dev_info(&udev->dev, "probing VID:PID(%04X:%04X) %s %s %s\n",
- udev->descriptor.idVendor, udev->descriptor.idProduct,
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
manufacturer, product, serial_number);
command_out_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!command_out_urb) {