summaryrefslogtreecommitdiff
path: root/drivers/mmc
diff options
context:
space:
mode:
authorMarek Vasut <marex@denx.de>2021-11-13 05:29:43 +0300
committerPatrice Chotard <patrice.chotard@foss.st.com>2021-11-30 18:43:28 +0300
commit8e5266eefdd0fcc139113214a75f287168c006ec (patch)
tree3a3121571303be2a7b279ce121b7ff85d36425fa /drivers/mmc
parent7d35a499bdaa0f8433640452f2db0ba59d86052b (diff)
downloadu-boot-8e5266eefdd0fcc139113214a75f287168c006ec.tar.xz
mmc: stm32_sdmmc2: Add support for probing bus voltage level translator
Add support for testing whether bus voltage level translator is present and operational. This is useful on systems where the bus voltage level translator is optional, as the translator can be auto-detected by the driver and the feedback clock functionality can be disabled if it is not present. The translator test sets CMD high to avoid interfering with a card, and then verifies whether signal set on CK is detected on CKIN. If the signal is detected, translator is present, otherwise the CKIN feedback clock are disabled. Signed-off-by: Marek Vasut <marex@denx.de> Cc: Patrice Chotard <patrice.chotard@foss.st.com> Cc: Patrick Delaunay <patrick.delaunay@foss.st.com> Reviewed-by: Yann Gautier <yann.gautier@foss.st.com>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/stm32_sdmmc2.c63
1 files changed, 62 insertions, 1 deletions
diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c
index a3cdf7bcd9..44bfc911af 100644
--- a/drivers/mmc/stm32_sdmmc2.c
+++ b/drivers/mmc/stm32_sdmmc2.c
@@ -16,6 +16,7 @@
#include <asm/bitops.h>
#include <asm/cache.h>
#include <dm/device_compat.h>
+#include <dm/pinctrl.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/libfdt.h>
@@ -645,6 +646,66 @@ static const struct dm_mmc_ops stm32_sdmmc2_ops = {
.host_power_cycle = stm32_sdmmc2_host_power_cycle,
};
+static int stm32_sdmmc2_probe_level_translator(struct udevice *dev)
+{
+ struct stm32_sdmmc2_priv *priv = dev_get_priv(dev);
+ struct gpio_desc cmd_gpio;
+ struct gpio_desc ck_gpio;
+ struct gpio_desc ckin_gpio;
+ int clk_hi, clk_lo, ret;
+
+ /*
+ * Assume the level translator is present if st,use-ckin is set.
+ * This is to cater for DTs which do not implement this test.
+ */
+ priv->clk_reg_msk |= SDMMC_CLKCR_SELCLKRX_CKIN;
+
+ ret = gpio_request_by_name(dev, "st,cmd-gpios", 0, &cmd_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret)
+ goto exit_cmd;
+
+ ret = gpio_request_by_name(dev, "st,ck-gpios", 0, &ck_gpio,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ if (ret)
+ goto exit_ck;
+
+ ret = gpio_request_by_name(dev, "st,ckin-gpios", 0, &ckin_gpio,
+ GPIOD_IS_IN);
+ if (ret)
+ goto exit_ckin;
+
+ /* All GPIOs are valid, test whether level translator works */
+
+ /* Sample CKIN */
+ clk_hi = !!dm_gpio_get_value(&ckin_gpio);
+
+ /* Set CK low */
+ dm_gpio_set_value(&ck_gpio, 0);
+
+ /* Sample CKIN */
+ clk_lo = !!dm_gpio_get_value(&ckin_gpio);
+
+ /* Tristate all */
+ dm_gpio_set_dir_flags(&cmd_gpio, GPIOD_IS_IN);
+ dm_gpio_set_dir_flags(&ck_gpio, GPIOD_IS_IN);
+
+ /* Level translator is present if CK signal is propagated to CKIN */
+ if (!clk_hi || clk_lo)
+ priv->clk_reg_msk &= ~SDMMC_CLKCR_SELCLKRX_CKIN;
+
+ dm_gpio_free(dev, &ckin_gpio);
+
+exit_ckin:
+ dm_gpio_free(dev, &ck_gpio);
+exit_ck:
+ dm_gpio_free(dev, &cmd_gpio);
+exit_cmd:
+ pinctrl_select_state(dev, "default");
+
+ return 0;
+}
+
static int stm32_sdmmc2_probe(struct udevice *dev)
{
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
@@ -662,7 +723,7 @@ static int stm32_sdmmc2_probe(struct udevice *dev)
if (dev_read_bool(dev, "st,sig-dir"))
priv->pwr_reg_msk |= SDMMC_POWER_DIRPOL;
if (dev_read_bool(dev, "st,use-ckin"))
- priv->clk_reg_msk |= SDMMC_CLKCR_SELCLKRX_CKIN;
+ stm32_sdmmc2_probe_level_translator(dev);
ret = clk_get_by_index(dev, 0, &priv->clk);
if (ret)