devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Dmitry Osipenko <digetx@gmail.com>
To: Thierry Reding <thierry.reding@gmail.com>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Mark Brown <broonie@kernel.org>, Takashi Iwai <tiwai@suse.com>,
	Jaroslav Kysela <perex@perex.cz>,
	Liam Girdwood <lgirdwood@gmail.com>, Agneli <poczt@protonmail.ch>
Cc: linux-tegra@vger.kernel.org, Arnd Bergmann <arnd@arndb.de>,
	Rob Herring <robh+dt@kernel.org>,
	alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org, dri-devel@lists.freedesktop.org
Subject: [PATCH v4 12/22] ASoC: tegra20: spdif: Filter out unsupported rates
Date: Sat,  4 Dec 2021 17:37:15 +0300	[thread overview]
Message-ID: <20211204143725.31646-13-digetx@gmail.com> (raw)
In-Reply-To: <20211204143725.31646-1-digetx@gmail.com>

SPDIF and other SoC components share audio PLL on Tegra, thus only one
component may set the desired base clock rate. This creates problem for
HDMI audio because it uses SPDIF and audio may not work if SPDIF's clock
doesn't exactly match standard audio rate since some receivers may reject
audio in that case. Filter out audio rates which SPDIF output can't
support, assuming that other components won't change rate at runtime.

Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
 sound/soc/tegra/tegra20_spdif.c | 61 +++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)

diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index a4aa5614aef4..d09cd7ee6879 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -79,6 +79,7 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
 	struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev);
 	unsigned int mask = 0, val = 0;
 	int ret, spdifclock;
+	long rate;
 
 	mask |= TEGRA20_SPDIF_CTRL_PACK |
 		TEGRA20_SPDIF_CTRL_BIT_MODE_MASK;
@@ -133,6 +134,12 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream,
 		return ret;
 	}
 
+	rate = clk_get_rate(spdif->clk_spdif_out);
+	if (rate != spdifclock)
+		dev_warn_once(dai->dev,
+			      "SPDIF clock rate %d doesn't match requested rate %lu\n",
+			      spdifclock, rate);
+
 	return 0;
 }
 
@@ -172,6 +179,59 @@ static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
 	return 0;
 }
 
+static int tegra20_spdif_filter_rates(struct snd_pcm_hw_params *params,
+				      struct snd_pcm_hw_rule *rule)
+{
+	struct snd_interval *r = hw_param_interval(params, rule->var);
+	struct snd_soc_dai *dai = rule->private;
+	struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev);
+	struct clk *parent = clk_get_parent(spdif->clk_spdif_out);
+	const unsigned int rates[] = { 32000, 44100, 48000 };
+	long i, parent_rate, valid_rates = 0;
+
+	parent_rate = clk_get_rate(parent);
+	if (parent_rate <= 0) {
+		dev_err(dai->dev, "Can't get parent clock rate: %ld\n",
+			parent_rate);
+		return parent_rate ?: -EINVAL;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(rates); i++) {
+		if (parent_rate % (rates[i] * 128) == 0)
+			valid_rates |= BIT(i);
+	}
+
+	/*
+	 * At least one rate must be valid, otherwise the parent clock isn't
+	 * audio PLL. Nothing should be filtered in this case.
+	 */
+	if (!valid_rates)
+		valid_rates = BIT(ARRAY_SIZE(rates)) - 1;
+
+	return snd_interval_list(r, ARRAY_SIZE(rates), rates, valid_rates);
+}
+
+static int tegra20_spdif_startup(struct snd_pcm_substream *substream,
+				 struct snd_soc_dai *dai)
+{
+	if (!device_property_read_bool(dai->dev, "nvidia,fixed-parent-rate"))
+		return 0;
+
+	/*
+	 * SPDIF and I2S share audio PLL. HDMI takes audio packets from SPDIF
+	 * and audio may not work on some TVs if clock rate isn't precise.
+	 *
+	 * PLL rate is controlled by I2S side. Filter out audio rates that
+	 * don't match PLL rate at the start of stream to allow both SPDIF
+	 * and I2S work simultaneously, assuming that PLL rate won't be
+	 * changed later on.
+	 */
+	return snd_pcm_hw_rule_add(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_RATE,
+				   tegra20_spdif_filter_rates, dai,
+				   SNDRV_PCM_HW_PARAM_RATE, -1);
+}
+
 static int tegra20_spdif_probe(struct snd_soc_dai *dai)
 {
 	struct tegra20_spdif *spdif = dev_get_drvdata(dai->dev);
@@ -185,6 +245,7 @@ static int tegra20_spdif_probe(struct snd_soc_dai *dai)
 static const struct snd_soc_dai_ops tegra20_spdif_dai_ops = {
 	.hw_params = tegra20_spdif_hw_params,
 	.trigger = tegra20_spdif_trigger,
+	.startup = tegra20_spdif_startup,
 };
 
 static struct snd_soc_dai_driver tegra20_spdif_dai = {
-- 
2.33.1


  parent reply	other threads:[~2021-12-04 14:37 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-04 14:37 [PATCH v4 00/22] Support HDMI audio on NVIDIA Tegra20 Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 01/22] ASoC: dt-bindings: Add binding for Tegra20 S/PDIF Dmitry Osipenko
2021-12-16 13:56   ` Thierry Reding
2021-12-04 14:37 ` [PATCH v4 02/22] ASoC: dt-bindings: tegra20-i2s: Convert to schema Dmitry Osipenko
2021-12-16 13:59   ` Thierry Reding
2021-12-04 14:37 ` [PATCH v4 03/22] ASoC: dt-bindings: tegra20-i2s: Document new nvidia,fixed-parent-rate property Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 04/22] dt-bindings: host1x: Document optional HDMI sound-dai-cells Dmitry Osipenko
2021-12-16 14:20   ` Thierry Reding
2021-12-17 11:12     ` Mark Brown
2021-12-17 11:55       ` Dmitry Osipenko
2021-12-17 12:02         ` Thierry Reding
2021-12-17 12:06           ` Dmitry Osipenko
2021-12-17 17:18             ` Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 05/22] ASoC: tegra20: spdif: Set FIFO trigger level Dmitry Osipenko
2021-12-16 15:15   ` Thierry Reding
2021-12-04 14:37 ` [PATCH v4 06/22] ASoC: tegra20-spdif: stop setting slave_id Dmitry Osipenko
2021-12-16 15:16   ` Thierry Reding
2021-12-04 14:37 ` [PATCH v4 07/22] ASoC: tegra20: spdif: Support device-tree Dmitry Osipenko
2021-12-16 15:17   ` Thierry Reding
2021-12-04 14:37 ` [PATCH v4 08/22] ASoC: tegra20: spdif: Improve driver's code Dmitry Osipenko
2021-12-16 15:18   ` Thierry Reding
2021-12-04 14:37 ` [PATCH v4 09/22] ASoC: tegra20: spdif: Use more resource-managed helpers Dmitry Osipenko
2021-12-16 15:21   ` Thierry Reding
2021-12-04 14:37 ` [PATCH v4 10/22] ASoC: tegra20: spdif: Reset hardware Dmitry Osipenko
2021-12-16 15:22   ` Thierry Reding
2021-12-04 14:37 ` [PATCH v4 11/22] ASoC: tegra20: spdif: Support system suspend Dmitry Osipenko
2021-12-16 15:22   ` Thierry Reding
2021-12-04 14:37 ` Dmitry Osipenko [this message]
2021-12-16 15:30   ` [PATCH v4 12/22] ASoC: tegra20: spdif: Filter out unsupported rates Thierry Reding
2021-12-04 14:37 ` [PATCH v4 13/22] ASoC: tegra20: i2s: " Dmitry Osipenko
2021-12-16 15:31   ` Thierry Reding
2021-12-04 14:37 ` [PATCH v4 14/22] drm/tegra: hdmi: Unwind tegra_hdmi_init() errors Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 15/22] drm/tegra: hdmi: Register audio CODEC on Tegra20 Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 16/22] ARM: tegra_defconfig: Enable S/PDIF driver Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 17/22] ARM: config: multi v7: Enable NVIDIA Tegra20 " Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 18/22] ARM: config: multi v7: Enable NVIDIA Tegra20 APB DMA driver Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 19/22] ARM: tegra: Add S/PDIF node to Tegra20 device-tree Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 20/22] ARM: tegra: Add HDMI audio graph " Dmitry Osipenko
2021-12-16 13:46   ` Thierry Reding
2021-12-16 14:24     ` Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 21/22] ARM: tegra: acer-a500: Enable S/PDIF and HDMI audio Dmitry Osipenko
2021-12-04 14:37 ` [PATCH v4 22/22] ARM: tegra: paz00: " Dmitry Osipenko
2021-12-15 18:57 ` [PATCH v4 00/22] Support HDMI audio on NVIDIA Tegra20 Mark Brown
2021-12-15 19:19   ` Dmitry Osipenko
2021-12-15 19:58     ` Mark Brown
2021-12-16 13:55     ` Thierry Reding
2021-12-16 15:09       ` Dmitry Osipenko
2021-12-16 14:29     ` Dmitry Osipenko
2021-12-17  6:04       ` Vinod Koul
2021-12-17 12:06         ` Dmitry Osipenko
2021-12-21  2:50 ` (subset) " Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211204143725.31646-13-digetx@gmail.com \
    --to=digetx@gmail.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=arnd@arndb.de \
    --cc=broonie@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=jonathanh@nvidia.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=perex@perex.cz \
    --cc=poczt@protonmail.ch \
    --cc=robh+dt@kernel.org \
    --cc=thierry.reding@gmail.com \
    --cc=tiwai@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).