diff mbox series

[7/8] mmc: sdhci-pxav2: add optional pinctrl for SDIO IRQ workaround

Message ID 20221128024407.224393-8-doug@schmorgal.com (mailing list archive)
State New, archived
Headers show
Series mmc: sdhci-pxav2: Add support for PXA168 | expand

Commit Message

Doug Brown Nov. 28, 2022, 2:44 a.m. UTC
The PXA168 errata recommends that the CMD signal should be detached from
the SD bus while performing the dummy CMD0 to restart the clock.
Implement this using pinctrl states.

Signed-off-by: Doug Brown <doug@schmorgal.com>
---
 drivers/mmc/host/sdhci-pxav2.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)
diff mbox series

Patch

diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index 0b9b2e4b2153..6b30f70675e2 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -22,6 +22,7 @@ 
 #include <linux/of_device.h>
 #include <linux/mmc/sdio.h>
 #include <linux/mmc/mmc.h>
+#include <linux/pinctrl/consumer.h>
 
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
@@ -46,6 +47,9 @@ 
 struct sdhci_pxav2_host {
 	struct clk *clk_core;
 	void (*orig_post_req)(struct mmc_host *mmc, struct mmc_request *mrq, int err);
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pins_default;
+	struct pinctrl_state *pins_cmd_gpio;
 };
 
 static void pxav2_reset(struct sdhci_host *host, u8 mask)
@@ -118,11 +122,19 @@  static void pxav1_post_req(struct mmc_host *mmc, struct mmc_request *mrq, int er
 		/* Clock is now stopped, so restart it by sending a dummy CMD0. */
 		pxav2_host = sdhci_pltfm_priv(sdhci_priv(host));
 
+		/* Set CMD as high output rather than MMC function while we do CMD0 */
+		if (pxav2_host->pinctrl && pxav2_host->pins_cmd_gpio)
+			pinctrl_select_state(pxav2_host->pinctrl, pxav2_host->pins_cmd_gpio);
+
 		dummy_cmd.opcode = MMC_GO_IDLE_STATE;
 		dummy_cmd.arg = 0;
 		dummy_cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_NONE | MMC_CMD_BC;
 
 		mmc_wait_for_cmd(host->mmc, &dummy_cmd, 0);
+
+		/* Set as MMC function after dummy command is complete */
+		if (pxav2_host->pinctrl && pxav2_host->pins_default)
+			pinctrl_select_state(pxav2_host->pinctrl, pxav2_host->pins_default);
 	}
 
 	/* Pass onto SDHCI host driver now */
@@ -288,6 +300,21 @@  static int sdhci_pxav2_probe(struct platform_device *pdev)
 		host->ops = &pxav1_sdhci_ops;
 		pxav2_host->orig_post_req = host->mmc_host_ops.post_req;
 		host->mmc_host_ops.post_req = pxav1_post_req;
+
+		/* Set up optional pinctrl for PXA168 SDIO IRQ fix */
+		pxav2_host->pinctrl = devm_pinctrl_get(&pdev->dev);
+		if (!IS_ERR(pxav2_host->pinctrl)) {
+			pxav2_host->pins_cmd_gpio = pinctrl_lookup_state(pxav2_host->pinctrl,
+									 "state_cmd_gpio");
+			if (IS_ERR(pxav2_host->pins_cmd_gpio))
+				pxav2_host->pins_cmd_gpio = NULL;
+			pxav2_host->pins_default = pinctrl_lookup_state(pxav2_host->pinctrl,
+									"default");
+			if (IS_ERR(pxav2_host->pins_default))
+				pxav2_host->pins_default = NULL;
+		} else {
+			pxav2_host->pinctrl = NULL;
+		}
 	} else {
 		host->ops = &pxav2_sdhci_ops;
 	}