lkml.org 
[lkml]   [2020]   [Nov]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[RFC PATCH v3.1 12/27] mmc: sdhci-uhs2: add reset function
    Date
    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>
    ---
    drivers/mmc/host/sdhci-uhs2.c | 49 +++++++++++++++++++++++++++++++++++
    drivers/mmc/host/sdhci-uhs2.h | 1 +
    drivers/mmc/host/sdhci.c | 3 ++-
    drivers/mmc/host/sdhci.h | 1 +
    4 files changed, 53 insertions(+), 1 deletion(-)

    diff --git a/drivers/mmc/host/sdhci-uhs2.c b/drivers/mmc/host/sdhci-uhs2.c
    index 08905ed081fb..e2b9743fe17d 100644
    --- a/drivers/mmc/host/sdhci-uhs2.c
    +++ b/drivers/mmc/host/sdhci-uhs2.c
    @@ -10,6 +10,7 @@
    * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
    */

    +#include <linux/delay.h>
    #include <linux/module.h>

    #include "sdhci.h"
    @@ -49,6 +50,54 @@ 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)
    +{
    + unsigned long timeout;
    +
    + if (!(host->mmc->caps & MMC_CAP_UHS2))
    + return;
    +
    + sdhci_writew(host, mask, SDHCI_UHS2_SW_RESET);
    +
    + if (mask & SDHCI_UHS2_SW_RESET_FULL) {
    + host->clock = 0;
    + /* Reset-all turns off SD Bus Power */
    + if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
    + sdhci_runtime_pm_bus_off(host);
    + }
    +
    + /* Wait max 100 ms */
    + timeout = 10000;
    +
    + /* hw clears the bit when it's done */
    + while (sdhci_readw(host, SDHCI_UHS2_SW_RESET) & mask) {
    + if (timeout == 0) {
    + pr_err("%s: %s: Reset 0x%x never completed.\n",
    + __func__, mmc_hostname(host->mmc), (int)mask);
    + pr_err("%s: clean reset bit\n",
    + mmc_hostname(host->mmc));
    + sdhci_writeb(host, 0, SDHCI_UHS2_SW_RESET);
    + return;
    + }
    + timeout--;
    + udelay(10);
    + }
    +}
    +EXPORT_SYMBOL_GPL(sdhci_uhs2_reset);
    +
    /*****************************************************************************\
    * *
    * Driver init/exit *
    diff --git a/drivers/mmc/host/sdhci-uhs2.h b/drivers/mmc/host/sdhci-uhs2.h
    index b9529d32b58d..7bb7a0d67109 100644
    --- a/drivers/mmc/host/sdhci-uhs2.h
    +++ b/drivers/mmc/host/sdhci-uhs2.h
    @@ -210,5 +210,6 @@
    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 */
    diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
    index d4a57e8c9bb8..af336bdb4305 100644
    --- a/drivers/mmc/host/sdhci.c
    +++ b/drivers/mmc/host/sdhci.c
    @@ -195,13 +195,14 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
    pm_runtime_get_noresume(host->mmc->parent);
    }

    -static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
    +void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
    {
    if (!host->bus_on)
    return;
    host->bus_on = false;
    pm_runtime_put_noidle(host->mmc->parent);
    }
    +EXPORT_SYMBOL_GPL(sdhci_runtime_pm_bus_off);

    void sdhci_reset(struct sdhci_host *host, u8 mask)
    {
    diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
    index d9d7a76cedc1..b9932423db08 100644
    --- a/drivers/mmc/host/sdhci.h
    +++ b/drivers/mmc/host/sdhci.h
    @@ -831,6 +831,7 @@ static inline void sdhci_read_caps(struct sdhci_host *host)
    __sdhci_read_caps(host, NULL, NULL, NULL);
    }

    +void sdhci_runtime_pm_bus_off(struct sdhci_host *host);
    u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
    unsigned int *actual_clock);
    void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
    --
    2.28.0
    \
     
     \ /
      Last update: 2020-11-06 03:29    [W:3.819 / U:0.008 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site