diff options
Diffstat (limited to 'drivers/mmc/host/sdhci_f_sdh30.c')
-rw-r--r-- | drivers/mmc/host/sdhci_f_sdh30.c | 31 |
1 files changed, 29 insertions, 2 deletions
diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c index 3f5977979cf2..a202a69a4b08 100644 --- a/drivers/mmc/host/sdhci_f_sdh30.c +++ b/drivers/mmc/host/sdhci_f_sdh30.c @@ -5,6 +5,7 @@ * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd * Vincent Yang <vincent.yang@tw.fujitsu.com> * Copyright (C) 2015 Linaro Ltd Andy Green <andy.green@linaro.org> + * Copyright (C) 2019 Socionext Inc. */ #include <linux/acpi.h> @@ -14,6 +15,7 @@ #include <linux/of.h> #include <linux/property.h> #include <linux/clk.h> +#include <linux/reset.h> #include "sdhci-pltfm.h" #include "sdhci_f_sdh30.h" @@ -21,6 +23,7 @@ struct f_sdhost_priv { struct clk *clk_iface; struct clk *clk; + struct reset_control *rst; u32 vendor_hs200; struct device *dev; bool enable_cmd_dat_delay; @@ -74,6 +77,13 @@ static void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask) ctl |= F_SDH30_CMD_DAT_DELAY; sdhci_writel(host, ctl, F_SDH30_ESD_CONTROL); } + + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) && + !(sdhci_readl(host, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT)) { + ctl = sdhci_readl(host, F_SDH30_TEST); + ctl |= F_SDH30_FORCE_CARD_INSERT; + sdhci_writel(host, ctl, F_SDH30_TEST); + } } static const struct sdhci_ops sdhci_f_sdh30_ops = { @@ -150,6 +160,16 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev) ret = clk_prepare_enable(priv->clk); if (ret) goto err_clk; + + priv->rst = devm_reset_control_get_optional_shared(dev, NULL); + if (IS_ERR(priv->rst)) { + ret = PTR_ERR(priv->rst); + goto err_rst; + } + + ret = reset_control_deassert(priv->rst); + if (ret) + goto err_rst; } /* init vendor specific regs */ @@ -168,6 +188,9 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev) if (reg & SDHCI_CAN_DO_8BIT) priv->vendor_hs200 = F_SDH30_EMMC_HS200; + if (!(reg & SDHCI_TIMEOUT_CLK_MASK)) + host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; + ret = sdhci_add_host(host); if (ret) goto err_add_host; @@ -175,6 +198,8 @@ static int sdhci_f_sdh30_probe(struct platform_device *pdev) return 0; err_add_host: + reset_control_assert(priv->rst); +err_rst: clk_disable_unprepare(priv->clk); err_clk: clk_disable_unprepare(priv->clk_iface); @@ -191,8 +216,9 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev) sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff); - clk_disable_unprepare(priv->clk_iface); + reset_control_assert(priv->rst); clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk_iface); sdhci_free_host(host); platform_set_drvdata(pdev, NULL); @@ -203,6 +229,7 @@ static int sdhci_f_sdh30_remove(struct platform_device *pdev) #ifdef CONFIG_OF static const struct of_device_id f_sdh30_dt_ids[] = { { .compatible = "fujitsu,mb86s70-sdhci-3.0" }, + { .compatible = "socionext,f-sdh30-e51-mmc" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids); @@ -232,5 +259,5 @@ module_platform_driver(sdhci_f_sdh30_driver); MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver"); MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD."); +MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD., Socionext Inc."); MODULE_ALIAS("platform:f_sdh30"); |