From patchwork Fri Nov 26 16:17:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 12641101 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 08657C433EF for ; Fri, 26 Nov 2021 16:20:26 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id B0E876F92A; Fri, 26 Nov 2021 16:20:17 +0000 (UTC) Received: from mail-lf1-x135.google.com (mail-lf1-x135.google.com [IPv6:2a00:1450:4864:20::135]) by gabe.freedesktop.org (Postfix) with ESMTPS id 50E876F900 for ; Fri, 26 Nov 2021 16:19:53 +0000 (UTC) Received: by mail-lf1-x135.google.com with SMTP id t26so25466184lfk.9 for ; Fri, 26 Nov 2021 08:19:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=C6zkQtDZQENoW1Sivb5bfco/O//qUuyceF3hyVGGf7c=; b=TJnwJBrvNJkT1a6gaTqkuKSMg/trzJTt+KT0MRm3CDHp+iTU1GPUYU9T2WekDGOWzr 1147WeSkCkbe/ztrnLz9JmpByGJW1VVpLeKOgwlFEjMS4+qUTOJrHwS4QDUzlxmpNpJc UuFYiMsF00Db2/JLMcoPe3eqvib5N7r9d9zoCGXfIx20gWJ+dG1tmyGYv7WpMqTtfv4q XUcFIsJ+Ax0/U30r6hfkAViqXzvCyytLNB8hPCE1Yz2kumH9rKmzHcx/Q+cGokUSKFEO bcdV9LxfZVce0X34M/dfLhwU3rzxnN2QOUEFYiNW8gnVzIv6McjfJyW/HkBJuHg0IzqV Yi9A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=C6zkQtDZQENoW1Sivb5bfco/O//qUuyceF3hyVGGf7c=; b=YSAy9GiBZbJIUs/fxli6Z85uQ2lIKYp42X9WYiWFAGV+bz+td3uCBqLw9sQ3zrlUEI Phr3cPL2QsKL6879IP/NEQuvnAFOu0g2NVyDOG8Fvk9kSe3q81KNAOOXnEsecrxqHxNr V9FN2sxyAYs1dKDMZNu2ZakulbXEFTtnTV3Plcd+2fq+ODmUb9DN9DV7iDCxNkdzJYDI Ig6KemtLPbKOztDqzLfT7URaxPsq21dqC8WWB+0NMIntoDClgRM9V9Pnr3FSHxh5gQvW Jm21byMk70ncpqVt5Jz0590XjEl62kQO3BPHec58a4uOC2dErdrHKscBg6M8MiyceKwL Q4tQ== X-Gm-Message-State: AOAM532+ZkCLcyfpSwHRkaDi8Pm7S7M/LFhD+yAGverp2ZSQvSsdWRkM kr8OQLnOwJlECijxwpsiw08= X-Google-Smtp-Source: ABdhPJwT1QIqpn6SrUIqAx9QKx1rgWGepcJAaepjwG8YbY5Cgfk2W3egIqISDds2VGCoj1Ig2/wwFg== X-Received: by 2002:ac2:58d9:: with SMTP id u25mr32199346lfo.514.1637943591668; Fri, 26 Nov 2021 08:19:51 -0800 (PST) Received: from localhost.localdomain (94-29-48-99.dynamic.spd-mgts.ru. [94.29.48.99]) by smtp.gmail.com with ESMTPSA id t7sm613381lfl.260.2021.11.26.08.19.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 26 Nov 2021 08:19:51 -0800 (PST) From: Dmitry Osipenko To: Thierry Reding , Jonathan Hunter , Mark Brown , Takashi Iwai , Jaroslav Kysela , Liam Girdwood , Agneli , Rob Herring Subject: [PATCH v2 12/20] ASoC: tegra20: spdif: Filter out unsupported rates Date: Fri, 26 Nov 2021 19:17:59 +0300 Message-Id: <20211126161807.15776-13-digetx@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211126161807.15776-1-digetx@gmail.com> References: <20211126161807.15776-1-digetx@gmail.com> MIME-Version: 1.0 X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, alsa-devel@alsa-project.org, Arnd Bergmann , linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-tegra@vger.kernel.org Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" 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 --- 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 89f7fc5c8aad..52be59c58126 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 = {