From patchwork Fri Dec 17 17:56:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 525512 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 alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (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 1E155C433F5 for ; Fri, 17 Dec 2021 18:01:42 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id DEBD91AC9; Fri, 17 Dec 2021 19:00:49 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz DEBD91AC9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1639764100; bh=RSRSyNB2bIRIGR9AmgpslVLPosGed3rGZvncjaY2fKw=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=QHRaqNccdrG8CMyvdJSxIHqJYy61Hkeh3Z6i9A+CEc5o7es71QD/u2i7aXELDX14u 8Vpzz8+Wellw4Y1GsFTgle+rYbNfMCF72kNX7B8eGYtiyDSE6aARWPrsJ/0LGeCM8A taB5SnkI0zy67dvk0WIskUj1jxHwYXgFXBxQRPbE= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 64E0DF80528; Fri, 17 Dec 2021 18:58:28 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 5FCA8F80510; Fri, 17 Dec 2021 18:58:22 +0100 (CET) Received: from mail-lj1-x231.google.com (mail-lj1-x231.google.com [IPv6:2a00:1450:4864:20::231]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 4A07FF80161 for ; Fri, 17 Dec 2021 18:58:13 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 4A07FF80161 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="F/+REdls" Received: by mail-lj1-x231.google.com with SMTP id l7so4628157lja.2 for ; Fri, 17 Dec 2021 09:58:12 -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=Rf4HABf9hwf+vnoImyk/B+FAlr699NfkudJmwSj3syw=; b=F/+REdlsnNvoF3FARVHxq3vwNQi10r9TMMrUEmjFlGBpTFIacXreSj1Jo3lknWOES/ j1Gb+hs7XwfP/hAGGSy0hzxAHK86+XolIiNHom6J3dsaEzIVHeBhMOSoBjESN2pSVdEo bHH1ISvjx1SGlAFLEsvcSjI6n2R4sYNeQD7trBdwXqWK3kyQlo5vIW8ikBtPwm3uuKvB L/RTq4f+jZmYzcxUu64by+DbP6fBQBXgqaLIy5cJZvBi8quyxeH/LbEiiQeqlvi5Z8CM Y6AClpP8wLEzbvQ2jSC/mYDZITDM8DPVgkx7H0SSvgSP3IdzIJ7Q9l24Ed6B+6WQC0q0 OcSA== 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=Rf4HABf9hwf+vnoImyk/B+FAlr699NfkudJmwSj3syw=; b=LMIGTPHKpf3IoERroDnzwlA1J39GEqp4DemJta2tpCpiin/XpFpC3zOBecXrDTGP8B +nfk8V2YQg6ywzuzN6+oh0NbUMXb1Qw55TJ31MHNkQ1GXhphNFs+xdlIo6c5dX0f0hxf B2h4y9HSHr0PR5qhhfWPnbp7l28cOUff2P0EtpBwvGqtGe1srVWBWjeFD9/CT7TwkI4/ 3AbaK0eRtPrLyucCfq8KBClvdq+K99Iab8vOnnB1NBoBsOv+J9AaaiRUlX9SmYFiQ5/T q/fVeU3OELUTJ75Rh67zZgpQYoLdd9/3kDQ2Ivwfx9UrgD6tXrPKgwCmsrfdWUZpOAoy UlSQ== X-Gm-Message-State: AOAM531YAOfK9Fhj8jWEPV8o1S99BVV01ru1kjKmNXbBS1RkTYYWd/n3 7OJ/Cjczwv6LITFg5lOeFxY= X-Google-Smtp-Source: ABdhPJzSS0s1ORcsGwDzBVpKSNbAYe4H3eM6AY2Kg4eLWmj78Aq5e2x+wvrPeJ2D82Ph3/blgr+nKQ== X-Received: by 2002:a05:651c:4c6:: with SMTP id e6mr3630495lji.411.1639763890924; Fri, 17 Dec 2021 09:58:10 -0800 (PST) Received: from localhost.localdomain (94-29-63-156.dynamic.spd-mgts.ru. [94.29.63.156]) by smtp.gmail.com with ESMTPSA id w23sm1479244lfa.191.2021.12.17.09.58.10 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Dec 2021 09:58:10 -0800 (PST) From: Dmitry Osipenko To: Thierry Reding , Jonathan Hunter , Mark Brown , Takashi Iwai , Jaroslav Kysela , Liam Girdwood , Agneli Subject: [PATCH v5 10/11] ASoC: tegra20: spdif: Filter out unsupported rates Date: Fri, 17 Dec 2021 20:56:05 +0300 Message-Id: <20211217175606.22645-11-digetx@gmail.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20211217175606.22645-1-digetx@gmail.com> References: <20211217175606.22645-1-digetx@gmail.com> MIME-Version: 1.0 Cc: linux-tegra@vger.kernel.org, devicetree@vger.kernel.org, alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-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. Acked-by: Thierry Reding Signed-off-by: Dmitry Osipenko --- sound/soc/tegra/tegra20_spdif.c | 63 ++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index a4aa5614aef4..8cc114c1862f 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -78,7 +78,8 @@ 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, spdifclock; + int ret; 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 %ld doesn't match requested rate %ld\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 = {