mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Sheetal <sheetal@nvidia.com>
To: Liam Girdwood <lgirdwood@gmail.com>, Mark Brown <broonie@kernel.org>
Cc: Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.com>,
	"Thierry Reding" <thierry.reding@kernel.org>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Sameer Pujar <spujar@nvidia.com>,
	Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>,
	Mohan Kumar <mkumard@nvidia.com>, <linux-sound@vger.kernel.org>,
	<linux-tegra@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	Sheetal <sheetal@nvidia.com>
Subject: [RFC PATCH 3/3] ASoC: tegra: Cache ASRC ratios until streams are active
Date: Mon, 21 Sep 2026 08:57:04 +0000	[thread overview]
Message-ID: <20260921085704.1248920-4-sheetal@nvidia.com> (raw)
In-Reply-To: <20260921085704.1248920-1-sheetal@nvidia.com>

Cache software ratio control updates when the ASRC device is runtime
suspended or when the target stream is not active. Program the cached
ratio when the stream is configured, and restore it after runtime resume.

Take a runtime PM reference for ratio-source changes when the ASRC device
is runtime-active, even if the target stream is not active, so a
hardware-to-software source transition can safely capture the live ratio
pair and update the source-select register. If the ASRC device is
suspended, avoid waking it from a control update, update the cached
source state, and mark the cached ratio invalid so the
first software apply refreshes the ratio lock state.

This also avoids unsafe volatile-register access during suspended control
updates. For hardware-sourced ratios, return the cached pair when the
device is not runtime active instead of waking it only for a mixer read.

Return an error from runtime resume if restoring a cached ratio fails.
This lets the PM core see that resume did not fully restore the stream
state instead of leaving the hardware running with stale ratio registers.

Signed-off-by: Sheetal <sheetal@nvidia.com>
---
 sound/soc/tegra/tegra186_asrc.c | 106 ++++++++++++++++++++++++++------
 sound/soc/tegra/tegra186_asrc.h |   1 +
 2 files changed, 89 insertions(+), 18 deletions(-)

diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c
index 2b67d23f5fa7..389bc1a294e1 100644
--- a/sound/soc/tegra/tegra186_asrc.c
+++ b/sound/soc/tegra/tegra186_asrc.c
@@ -118,6 +118,7 @@ static void tegra186_asrc_cache_ratio(struct tegra186_asrc *asrc,
 {
 	asrc->lane[id].int_part = int_part;
 	asrc->lane[id].frac_part = frac_part;
+	asrc->lane[id].ratio_valid = true;
 }
 
 static int tegra186_asrc_apply_ratio(struct tegra186_asrc *asrc,
@@ -171,8 +172,15 @@ static int tegra186_asrc_apply_ratio(struct tegra186_asrc *asrc,
 static int tegra186_asrc_apply_cached_ratio(struct tegra186_asrc *asrc,
 					    unsigned int id)
 {
-	return tegra186_asrc_apply_ratio(asrc, id, asrc->lane[id].int_part,
-					asrc->lane[id].frac_part, false);
+	int ret;
+
+	ret = tegra186_asrc_apply_ratio(asrc, id, asrc->lane[id].int_part,
+					asrc->lane[id].frac_part,
+					!asrc->lane[id].ratio_valid);
+	if (!ret)
+		asrc->lane[id].ratio_valid = true;
+
+	return ret;
 }
 
 static bool tegra186_asrc_need_unlock(u64 old_ratio, u64 new_ratio)
@@ -375,19 +383,32 @@ static int tegra186_asrc_put_ratio_source(struct snd_kcontrol *kcontrol,
 	unsigned int new_source = ucontrol->value.enumerated.item[0];
 	unsigned int old_source, int_part = 0, frac_part = 0;
 	bool change = false;
-	int ret;
+	int pm_ret, ret;
 
 	mutex_lock(&asrc->ratio_lock);
 
 	old_source = asrc->lane[id].ratio_source;
 
+	pm_ret = pm_runtime_get_if_active(cmpnt->dev);
+	if (pm_ret < 0) {
+		mutex_unlock(&asrc->ratio_lock);
+		return pm_ret;
+	}
+
 	if (old_source == TEGRA186_ASRC_RATIO_SOURCE_ARAD &&
 	    new_source == TEGRA186_ASRC_RATIO_SOURCE_SW) {
-		ret = tegra186_asrc_read_ratio_pair(asrc, id, &int_part,
-						    &frac_part);
-		if (ret) {
-			mutex_unlock(&asrc->ratio_lock);
-			return ret;
+		if (pm_ret > 0) {
+			ret = tegra186_asrc_read_ratio_pair(asrc, id,
+							    &int_part,
+							    &frac_part);
+			if (ret) {
+				pm_runtime_put(cmpnt->dev);
+				asrc->lane[id].ratio_valid = false;
+				mutex_unlock(&asrc->ratio_lock);
+				return ret;
+			}
+		} else {
+			asrc->lane[id].ratio_valid = false;
 		}
 	}
 
@@ -395,15 +416,20 @@ static int tegra186_asrc_put_ratio_source(struct snd_kcontrol *kcontrol,
 				       TEGRA186_ASRC_STREAM_RATIO_TYPE_MASK,
 				       new_source, &change);
 	if (ret) {
+		if (pm_ret > 0)
+			pm_runtime_put(cmpnt->dev);
 		mutex_unlock(&asrc->ratio_lock);
 		return ret;
 	}
 
 	asrc->lane[id].ratio_source = new_source;
 	if (old_source == TEGRA186_ASRC_RATIO_SOURCE_ARAD &&
-	    new_source == TEGRA186_ASRC_RATIO_SOURCE_SW)
+	    new_source == TEGRA186_ASRC_RATIO_SOURCE_SW && pm_ret > 0)
 		tegra186_asrc_cache_ratio(asrc, id, int_part, frac_part);
 
+	if (pm_ret > 0)
+		pm_runtime_put(cmpnt->dev);
+
 	mutex_unlock(&asrc->ratio_lock);
 
 	return change ? 1 : 0;
@@ -422,18 +448,33 @@ static int tegra186_asrc_get_ratio(struct snd_kcontrol *kcontrol,
 
 	mutex_lock(&asrc->ratio_lock);
 
-	if (asrc->lane[id].ratio_source == TEGRA186_ASRC_RATIO_SOURCE_ARAD) {
+	int_part = asrc->lane[id].int_part;
+	frac_part = asrc->lane[id].frac_part;
+
+	if (asrc->lane[id].ratio_source != TEGRA186_ASRC_RATIO_SOURCE_ARAD)
+		goto done;
+
+	ret = pm_runtime_get_if_active(cmpnt->dev);
+	if (ret < 0) {
+		mutex_unlock(&asrc->ratio_lock);
+		return ret;
+	}
+
+	if (ret > 0) {
 		ret = tegra186_asrc_read_ratio_pair(asrc, id, &int_part,
 						    &frac_part);
-	} else {
-		int_part = asrc->lane[id].int_part;
-		frac_part = asrc->lane[id].frac_part;
-		ret = 0;
+		if (ret) {
+			pm_runtime_put(cmpnt->dev);
+			mutex_unlock(&asrc->ratio_lock);
+			return ret;
+		}
+		pm_runtime_put(cmpnt->dev);
+		asrc->lane[id].int_part = int_part;
+		asrc->lane[id].frac_part = frac_part;
 	}
 
+done:
 	mutex_unlock(&asrc->ratio_lock);
-	if (ret)
-		return ret;
 
 	ucontrol->value.integer.value[0] = int_part;
 	ucontrol->value.integer.value[1] = frac_part;
@@ -454,7 +495,7 @@ static int tegra186_asrc_put_ratio(struct snd_kcontrol *kcontrol,
 	long int_val = ucontrol->value.integer.value[0];
 	long frac_val = ucontrol->value.integer.value[1];
 	bool change = false, unlock = false;
-	int ret = 0;
+	int ret = 0, pm_ret;
 
 	if (int_val < 0 || int_val > TEGRA186_ASRC_STREAM_RATIO_INT_PART_MASK)
 		return -EINVAL;
@@ -488,12 +529,40 @@ static int tegra186_asrc_put_ratio(struct snd_kcontrol *kcontrol,
 	if (!change)
 		goto out_unlock;
 
-	unlock = tegra186_asrc_need_unlock(old_ratio, new_ratio);
+	unlock = !asrc->lane[id].ratio_valid ||
+		 tegra186_asrc_need_unlock(old_ratio, new_ratio);
+
+	pm_ret = pm_runtime_get_if_active(cmpnt->dev);
+	if (pm_ret < 0) {
+		ret = pm_ret;
+		goto out_unlock;
+	}
+
+	if (!pm_ret) {
+		asrc->lane[id].int_part = int_part;
+		asrc->lane[id].frac_part = frac_part;
+		ret = 1;
+		goto out_unlock;
+	}
+
+	ret = regmap_read(asrc->regmap, ASRC_STREAM_REG(TEGRA186_ASRC_STATUS, id),
+			  &pm_ret);
+	if (ret)
+		goto out_pm_put;
+
+	if (!(pm_ret & TEGRA186_ASRC_STREAM_EN)) {
+		asrc->lane[id].int_part = int_part;
+		asrc->lane[id].frac_part = frac_part;
+		ret = 1;
+		goto out_pm_put;
+	}
 
 	ret = tegra186_asrc_apply_ratio(asrc, id, int_part, frac_part, unlock);
 	if (!ret)
 		tegra186_asrc_cache_ratio(asrc, id, int_part, frac_part);
 
+out_pm_put:
+	pm_runtime_put(cmpnt->dev);
 out_unlock:
 	mutex_unlock(&asrc->ratio_lock);
 
@@ -1103,6 +1172,7 @@ static int tegra186_asrc_platform_probe(struct platform_device *pdev)
 		asrc->lane[i].ratio_source = TEGRA186_ASRC_RATIO_SOURCE_SW;
 		asrc->lane[i].int_part = 1;
 		asrc->lane[i].frac_part = 0;
+		asrc->lane[i].ratio_valid = true;
 		asrc->lane[i].hwcomp_disable = 0;
 		asrc->lane[i].input_thresh =
 			TEGRA186_ASRC_STREAM_DEFAULT_INPUT_HW_COMP_THRESH_CFG;
diff --git a/sound/soc/tegra/tegra186_asrc.h b/sound/soc/tegra/tegra186_asrc.h
index 9cc8cec6c204..dabfd2e2c904 100644
--- a/sound/soc/tegra/tegra186_asrc.h
+++ b/sound/soc/tegra/tegra186_asrc.h
@@ -99,6 +99,7 @@
 struct tegra186_asrc_lane {
 	unsigned int int_part;
 	unsigned int frac_part;
+	bool ratio_valid;
 	unsigned int ratio_source;
 	unsigned int hwcomp_disable;
 	unsigned int input_thresh;
-- 
2.43.0


  parent reply	other threads:[~2026-09-21  8:57 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-21  8:57 [RFC PATCH 0/3] ASoC: tegra: ASRC control fixes and ratio caching Sheetal
2026-09-21  8:57 ` [RFC PATCH 1/3] ASoC: tegra: Fix ASRC Stream6 input threshold control Sheetal
2026-09-21 11:38   ` Thierry Reding
2026-09-21  8:57 ` [RFC PATCH 2/3] ASoC: tegra: Update ASRC ratio controls Sheetal
2026-09-21 11:50   ` Thierry Reding
2026-09-21  8:57 ` Sheetal [this message]
2026-09-21 12:07 ` [RFC PATCH 0/3] ASoC: tegra: ASRC control fixes and ratio caching Thierry Reding
2026-09-21 12:51   ` 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=20260921085704.1248920-4-sheetal@nvidia.com \
    --to=sheetal@nvidia.com \
    --cc=broonie@kernel.org \
    --cc=jonathanh@nvidia.com \
    --cc=kuninori.morimoto.gx@renesas.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=mkumard@nvidia.com \
    --cc=perex@perex.cz \
    --cc=spujar@nvidia.com \
    --cc=thierry.reding@kernel.org \
    --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

all inboxes | Powered by JetHome®