aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/renesas_sdhi_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/renesas_sdhi_core.c')
-rw-r--r--drivers/mmc/host/renesas_sdhi_core.c38
1 files changed, 28 insertions, 10 deletions
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index 158c21e5a942..635bf31a6735 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -20,6 +20,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/mfd/tmio.h>
#include <linux/mmc/host.h>
@@ -32,6 +33,7 @@
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
#include <linux/sh_dma.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>
@@ -557,24 +559,35 @@ static int renesas_sdhi_prepare_hs400_tuning(struct mmc_host *mmc, struct mmc_io
return 0;
}
+static void renesas_sdhi_scc_reset(struct tmio_mmc_host *host, struct renesas_sdhi *priv)
+{
+ renesas_sdhi_disable_scc(host->mmc);
+ renesas_sdhi_reset_hs400_mode(host, priv);
+ priv->needs_adjust_hs400 = false;
+
+ sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
+ ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
+ sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+}
+
/* only populated for TMIO_MMC_MIN_RCAR2 */
static void renesas_sdhi_reset(struct tmio_mmc_host *host)
{
struct renesas_sdhi *priv = host_to_priv(host);
+ int ret;
u16 val;
- if (priv->scc_ctl) {
- renesas_sdhi_disable_scc(host->mmc);
- renesas_sdhi_reset_hs400_mode(host, priv);
+ if (priv->rstc) {
+ reset_control_reset(priv->rstc);
+ /* Unknown why but without polling reset status, it will hang */
+ read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
+ false, priv->rstc);
priv->needs_adjust_hs400 = false;
-
- sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL,
- ~SH_MOBILE_SDHI_SCC_RVSCNTL_RVSEN &
- sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_RVSCNTL));
+ renesas_sdhi_set_clock(host, host->clk_cache);
+ } else if (priv->scc_ctl) {
+ renesas_sdhi_scc_reset(host, priv);
}
- sd_ctrl_write32_as_16_and_16(host, CTL_IRQ_MASK, TMIO_MASK_INIT_RCAR2);
-
if (sd_ctrl_read16(host, CTL_VERSION) >= SDHI_VER_GEN3_SD) {
val = sd_ctrl_read16(host, CTL_SD_MEM_CARD_OPT);
val |= CARD_OPT_EXTOP;
@@ -691,7 +704,7 @@ static int renesas_sdhi_execute_tuning(struct mmc_host *mmc, u32 opcode)
ret = renesas_sdhi_select_tuning(host);
if (ret < 0)
- renesas_sdhi_reset(host);
+ renesas_sdhi_scc_reset(host, priv);
return ret;
}
@@ -1034,6 +1047,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
host->ops.start_signal_voltage_switch =
renesas_sdhi_start_signal_voltage_switch;
host->sdcard_irq_setbit_mask = TMIO_STAT_ALWAYS_SET_27;
+ host->sdcard_irq_mask_all = TMIO_MASK_ALL_RCAR2;
host->reset = renesas_sdhi_reset;
}
@@ -1076,6 +1090,10 @@ int renesas_sdhi_probe(struct platform_device *pdev,
if (ret)
goto efree;
+ priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+ if (IS_ERR(priv->rstc))
+ return PTR_ERR(priv->rstc);
+
ver = sd_ctrl_read16(host, CTL_VERSION);
/* GEN2_SDR104 is first known SDHI to use 32bit block count */
if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX)