mmc: sdhci-uhs2: add reset function
authorVictor Shih <victor.shih@genesyslogic.com.tw>
Fri, 18 Oct 2024 10:53:22 +0000 (18:53 +0800)
committerUlf Hansson <ulf.hansson@linaro.org>
Thu, 24 Oct 2024 12:36:56 +0000 (14:36 +0200)
Sdhci_uhs2_reset() does a UHS-II specific reset operation.

Signed-off-by: Ben Chuang <ben.chuang@genesyslogic.com.tw>
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Victor Shih <victor.shih@genesyslogic.com.tw>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Message-ID: <20241018105333.4569-6-victorshihgli@gmail.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/sdhci-uhs2.c
drivers/mmc/host/sdhci-uhs2.h

index 1451471..71c6095 100644 (file)
@@ -10,7 +10,9 @@
  *  Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
  */
 
+#include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/iopoll.h>
 
 #include "sdhci.h"
 #include "sdhci-uhs2.h"
@@ -21,6 +23,8 @@
 #define SDHCI_UHS2_DUMP(f, x...) \
        pr_err("%s: " DRIVER_NAME ": " f, mmc_hostname(host->mmc), ## x)
 
+#define UHS2_RESET_TIMEOUT_100MS               100000
+
 void sdhci_uhs2_dump_regs(struct sdhci_host *host)
 {
        if (!(mmc_card_uhs2(host->mmc)))
@@ -49,6 +53,39 @@ void sdhci_uhs2_dump_regs(struct sdhci_host *host)
 }
 EXPORT_SYMBOL_GPL(sdhci_uhs2_dump_regs);
 
+/*****************************************************************************\
+ *                                                                           *
+ * Low level functions                                                       *
+ *                                                                           *
+\*****************************************************************************/
+
+/**
+ * sdhci_uhs2_reset - invoke SW reset
+ * @host: SDHCI host
+ * @mask: Control mask
+ *
+ * Invoke SW reset, depending on a bit in @mask and wait for completion.
+ */
+void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask)
+{
+       u32 val;
+
+       sdhci_writew(host, mask, SDHCI_UHS2_SW_RESET);
+
+       if (mask & SDHCI_UHS2_SW_RESET_FULL)
+               host->clock = 0;
+
+       /* hw clears the bit when it's done */
+       if (read_poll_timeout_atomic(sdhci_readw, val, !(val & mask), 10,
+                                    UHS2_RESET_TIMEOUT_100MS, true, host, SDHCI_UHS2_SW_RESET)) {
+               pr_warn("%s: %s: Reset 0x%x never completed. %s: clean reset bit.\n", __func__,
+                       mmc_hostname(host->mmc), (int)mask, mmc_hostname(host->mmc));
+               sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET);
+               return;
+       }
+}
+EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
+
 /*****************************************************************************\
  *                                                                           *
  * Driver init/exit                                                          *
index 04d7516..bc8395a 100644 (file)
 struct sdhci_host;
 
 void sdhci_uhs2_dump_regs(struct sdhci_host *host);
+void sdhci_uhs2_reset(struct sdhci_host *host, u16 mask);
 
 #endif /* __SDHCI_UHS2_H */