[Linux-stm32] [PATCH V2 2/4] mmc: mmci: Add support for probing bus voltage level translator
Ulf Hansson
ulf.hansson at linaro.org
Tue Jan 26 09:58:14 UTC 2021
On Sun, 24 Jan 2021 at 18:03, Marek Vasut <marex at denx.de> wrote:
>
> 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.
>
> This requires additional pinmux state, "init", where the CMD, CK, CKIN
> lines are not configured, so they can be claimed as GPIOs early on in
> probe(). 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.
>
> Tested-by: Yann Gautier <yann.gautier at foss.st.com>
> Reviewed-by: Linus Walleij <linus.walleij at linaro.org>
> Signed-off-by: Marek Vasut <marex at denx.de>
> Cc: Alexandre Torgue <alexandre.torgue at st.com>
> Cc: Linus Walleij <linus.walleij at linaro.org>
> Cc: Ludovic Barre <ludovic.barre at st.com>
> Cc: Ulf Hansson <ulf.hansson at linaro.org>
> Cc: linux-stm32 at st-md-mailman.stormreply.com
Applied for next, thanks!
Kind regards
Uffe
> ---
> V2: Rebase on next-20210122, add TB and RB
> ---
> drivers/mmc/host/mmci.c | 70 ++++++++++++++++++++++++++++++++++++++---
> 1 file changed, 65 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
> index b5a41a7ce165..1bc674577ff9 100644
> --- a/drivers/mmc/host/mmci.c
> +++ b/drivers/mmc/host/mmci.c
> @@ -36,6 +36,7 @@
> #include <linux/types.h>
> #include <linux/pinctrl/consumer.h>
> #include <linux/reset.h>
> +#include <linux/gpio/consumer.h>
>
> #include <asm/div64.h>
> #include <asm/io.h>
> @@ -1888,6 +1889,65 @@ static struct mmc_host_ops mmci_ops = {
> .start_signal_voltage_switch = mmci_sig_volt_switch,
> };
>
> +static void mmci_probe_level_translator(struct mmc_host *mmc)
> +{
> + struct device *dev = mmc_dev(mmc);
> + struct mmci_host *host = mmc_priv(mmc);
> + struct gpio_desc *cmd_gpio;
> + struct gpio_desc *ck_gpio;
> + struct gpio_desc *ckin_gpio;
> + int clk_hi, clk_lo;
> +
> + /*
> + * Assume the level translator is present if st,use-ckin is set.
> + * This is to cater for DTs which do not implement this test.
> + */
> + host->clk_reg_add |= MCI_STM32_CLK_SELCKIN;
> +
> + cmd_gpio = gpiod_get(dev, "st,cmd", GPIOD_OUT_HIGH);
> + if (IS_ERR(cmd_gpio))
> + goto exit_cmd;
> +
> + ck_gpio = gpiod_get(dev, "st,ck", GPIOD_OUT_HIGH);
> + if (IS_ERR(ck_gpio))
> + goto exit_ck;
> +
> + ckin_gpio = gpiod_get(dev, "st,ckin", GPIOD_IN);
> + if (IS_ERR(ckin_gpio))
> + goto exit_ckin;
> +
> + /* All GPIOs are valid, test whether level translator works */
> +
> + /* Sample CKIN */
> + clk_hi = !!gpiod_get_value(ckin_gpio);
> +
> + /* Set CK low */
> + gpiod_set_value(ck_gpio, 0);
> +
> + /* Sample CKIN */
> + clk_lo = !!gpiod_get_value(ckin_gpio);
> +
> + /* Tristate all */
> + gpiod_direction_input(cmd_gpio);
> + gpiod_direction_input(ck_gpio);
> +
> + /* Level translator is present if CK signal is propagated to CKIN */
> + if (!clk_hi || clk_lo) {
> + host->clk_reg_add &= ~MCI_STM32_CLK_SELCKIN;
> + dev_warn(dev,
> + "Level translator inoperable, CK signal not detected on CKIN, disabling.\n");
> + }
> +
> + gpiod_put(ckin_gpio);
> +
> +exit_ckin:
> + gpiod_put(ck_gpio);
> +exit_ck:
> + gpiod_put(cmd_gpio);
> +exit_cmd:
> + pinctrl_select_default_state(dev);
> +}
> +
> static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc)
> {
> struct mmci_host *host = mmc_priv(mmc);
> @@ -1913,7 +1973,7 @@ static int mmci_of_parse(struct device_node *np, struct mmc_host *mmc)
> if (of_get_property(np, "st,neg-edge", NULL))
> host->clk_reg_add |= MCI_STM32_CLK_NEGEDGE;
> if (of_get_property(np, "st,use-ckin", NULL))
> - host->clk_reg_add |= MCI_STM32_CLK_SELCKIN;
> + mmci_probe_level_translator(mmc);
>
> if (of_get_property(np, "mmc-cap-mmc-highspeed", NULL))
> mmc->caps |= MMC_CAP_MMC_HIGHSPEED;
> @@ -1949,15 +2009,15 @@ static int mmci_probe(struct amba_device *dev,
> if (!mmc)
> return -ENOMEM;
>
> - ret = mmci_of_parse(np, mmc);
> - if (ret)
> - goto host_free;
> -
> host = mmc_priv(mmc);
> host->mmc = mmc;
> host->mmc_ops = &mmci_ops;
> mmc->ops = &mmci_ops;
>
> + ret = mmci_of_parse(np, mmc);
> + if (ret)
> + goto host_free;
> +
> /*
> * Some variant (STM32) doesn't have opendrain bit, nevertheless
> * pins can be set accordingly using pinctrl
> --
> 2.29.2
>
More information about the Linux-stm32
mailing list