On 6/03/23 06:07, Brad Larson wrote: > Add support for mmc hardware reset using a reset-controller > that would need to be enabled in the device tree with > a supporting driver. The default is disabled for all > existing designs. > > Signed-off-by: Brad Larson <blarson@xxxxxxx> Acked-by: Adrian Hunter <adrian.hunter@xxxxxxxxx> > --- > > v9 changes: > - Previously patch 17/17 > - Changed delay after reset_control_assert() from 9 to 3 usec > - Renamed sdhci_mmc_hw_reset() to sdhci_cdns_mmc_hw_reset() > > --- > drivers/mmc/host/sdhci-cadence.c | 27 +++++++++++++++++++++++++++ > 1 file changed, 27 insertions(+) > > diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c > index 31c77d32aa7d..d13081da5e30 100644 > --- a/drivers/mmc/host/sdhci-cadence.c > +++ b/drivers/mmc/host/sdhci-cadence.c > @@ -12,6 +12,7 @@ > #include <linux/mmc/mmc.h> > #include <linux/of.h> > #include <linux/of_device.h> > +#include <linux/reset.h> > > #include "sdhci-pltfm.h" > > @@ -70,6 +71,7 @@ struct sdhci_cdns_priv { > spinlock_t wrlock; /* write lock */ > bool enhanced_strobe; > void (*priv_writel)(struct sdhci_cdns_priv *priv, u32 val, void __iomem *reg); > + struct reset_control *rst_hw; > unsigned int nr_phy_params; > struct sdhci_cdns_phy_param phy_params[]; > }; > @@ -460,6 +462,22 @@ static void sdhci_cdns_hs400_enhanced_strobe(struct mmc_host *mmc, > SDHCI_CDNS_HRS06_MODE_MMC_HS400); > } > > +static void sdhci_cdns_mmc_hw_reset(struct mmc_host *mmc) > +{ > + struct sdhci_host *host = mmc_priv(mmc); > + struct sdhci_cdns_priv *priv = sdhci_cdns_priv(host); > + > + dev_dbg(mmc_dev(host->mmc), "emmc hardware reset\n"); > + > + reset_control_assert(priv->rst_hw); > + /* For eMMC, minimum is 1us but give it 3us for good measure */ > + udelay(3); > + > + reset_control_deassert(priv->rst_hw); > + /* For eMMC, minimum is 200us but give it 300us for good measure */ > + usleep_range(300, 1000); > +} > + > static int sdhci_cdns_probe(struct platform_device *pdev) > { > struct sdhci_host *host; > @@ -523,6 +541,15 @@ static int sdhci_cdns_probe(struct platform_device *pdev) > if (ret) > goto free; > > + if (host->mmc->caps & MMC_CAP_HW_RESET) { > + priv->rst_hw = devm_reset_control_get_optional_exclusive(dev, "hw"); > + if (IS_ERR(priv->rst_hw)) > + return dev_err_probe(mmc_dev(host->mmc), PTR_ERR(priv->rst_hw), > + "reset controller error\n"); > + if (priv->rst_hw) > + host->mmc_host_ops.card_hw_reset = sdhci_cdns_mmc_hw_reset; > + } > + > ret = sdhci_add_host(host); > if (ret) > goto free;