From 60c9e5240f35047a0f52b51cf551e47b9d0ceb71 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 1 Jun 2023 10:30:48 +0800 Subject: [PATCH] mmc: dw_mmc: Add normal and idle pinctrl control normal pinctrl is used for sd working mode. idle pinctrl is used when the card is added or removed, so pull down the IO to avoid power leak which makes the card unable to work. Signed-off-by: Shawn Lin Change-Id: I8780b9de735b86918b4d5ba857711e56de740ecf --- drivers/mmc/host/dw_mmc.c | 25 +++++++++++++++++++++++++ drivers/mmc/host/dw_mmc.h | 3 +++ 2 files changed, 28 insertions(+) diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index a2114fb47edd..fde49464a637 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -1507,6 +1507,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_UP: + if (!IS_ERR_OR_NULL(slot->host->pinctrl)) + pinctrl_select_state(slot->host->pinctrl, slot->host->idle_state); + if (!IS_ERR(mmc->supply.vmmc)) { ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); @@ -1523,6 +1526,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) mci_writel(slot->host, PWREN, regs); break; case MMC_POWER_ON: + if (!IS_ERR_OR_NULL(slot->host->pinctrl)) + pinctrl_select_state(slot->host->pinctrl, slot->host->normal_state); + if (!slot->host->vqmmc_enabled) { if (!IS_ERR(mmc->supply.vqmmc)) { ret = regulator_enable(mmc->supply.vqmmc); @@ -1547,6 +1553,9 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) break; case MMC_POWER_OFF: + if (!IS_ERR_OR_NULL(slot->host->pinctrl)) + pinctrl_select_state(slot->host->pinctrl, slot->host->idle_state); + /* Turn clock off before power goes down */ dw_mci_setup_bus(slot, false); @@ -3262,6 +3271,22 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host) return ERR_PTR(ret); } + host->pinctrl = devm_pinctrl_get(host->dev); + if (!IS_ERR(host->pinctrl)) { + host->normal_state = pinctrl_lookup_state(host->pinctrl, "normal"); + if (IS_ERR(host->normal_state)) + dev_warn(dev, "No normal pinctrl state\n"); + + host->idle_state = pinctrl_lookup_state(host->pinctrl, "idle"); + if (IS_ERR(host->idle_state)) + dev_warn(dev, "No idle pinctrl state\n"); + + if (!IS_ERR(host->normal_state) && !IS_ERR(host->idle_state)) + pinctrl_select_state(host->pinctrl, host->idle_state); + else + host->pinctrl = NULL; + } + return pdata; } diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h index 0160a1769f62..6ffa2fd6db38 100644 --- a/drivers/mmc/host/dw_mmc.h +++ b/drivers/mmc/host/dw_mmc.h @@ -233,6 +233,9 @@ struct dw_mci { bool need_xfer_timer; struct timer_list xfer_timer; bool is_rv1106_sd; + struct pinctrl *pinctrl; + struct pinctrl_state *normal_state; + struct pinctrl_state *idle_state; }; /* DMA ops for Internal/External DMAC interface */