From: Jerome Brunet Date: Wed, 3 Jul 2019 12:07:49 +0000 (+0200) Subject: ASoC: meson: axg-tdm-formatter: add reset X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=751bd5db5260;p=uclinux-h8%2Flinux.git ASoC: meson: axg-tdm-formatter: add reset Add the optional reset line handling which is present on the new SoC families, such as the g12a. Triggering this reset is not critical but it helps solve a channel shift issue on the g12a. Signed-off-by: Jerome Brunet Link: https://lore.kernel.org/r/20190703120749.32341-3-jbrunet@baylibre.com Signed-off-by: Mark Brown --- diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c index 0c6cce5c5773..2e498201139f 100644 --- a/sound/soc/meson/axg-tdm-formatter.c +++ b/sound/soc/meson/axg-tdm-formatter.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "axg-tdm-formatter.h" @@ -20,6 +21,7 @@ struct axg_tdm_formatter { struct clk *lrclk; struct clk *sclk_sel; struct clk *lrclk_sel; + struct reset_control *reset; bool enabled; struct regmap *map; }; @@ -76,6 +78,24 @@ static int axg_tdm_formatter_enable(struct axg_tdm_formatter *formatter) return 0; /* + * On the g12a (and possibly other SoCs), when a stream using + * multiple lanes is restarted, it will sometimes not start + * from the first lane, but randomly from another used one. + * The result is an unexpected and random channel shift. + * + * The hypothesis is that an HW counter is not properly reset + * and the formatter simply starts on the lane it stopped + * before. Unfortunately, there does not seems to be a way to + * reset this through the registers of the block. + * + * However, the g12a has indenpendent reset lines for each audio + * devices. Using this reset before each start solves the issue. + */ + ret = reset_control_reset(formatter->reset); + if (ret) + return ret; + + /* * If sclk is inverted, invert it back and provide the inversion * required by the formatter */ @@ -306,6 +326,15 @@ int axg_tdm_formatter_probe(struct platform_device *pdev) return ret; } + /* Formatter dedicated reset line */ + formatter->reset = reset_control_get_optional_exclusive(dev, NULL); + if (IS_ERR(formatter->reset)) { + ret = PTR_ERR(formatter->reset); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to get reset: %d\n", ret); + return ret; + } + return devm_snd_soc_register_component(dev, drv->component_drv, NULL, 0); }