mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination
@ 2026-05-22 13:33 Troy Mitchell
  2026-05-22 13:33 ` [PATCH v4 1/3] ASoC: soc-dai: add shared BCLK clock for cross-DAI rate constraints Troy Mitchell
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Troy Mitchell @ 2026-05-22 13:33 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai, Yixun Lan
  Cc: linux-sound, linux-kernel, linux-riscv, spacemit, jinmei.wei,
	Troy Mitchell

On some SoCs (e.g. SpacemiT K3), multiple I2S controllers share the
same physical BCLK. When one controller is already streaming, the
others must use hw_params that result in the same BCLK rate, otherwise
the shared clock would be reconfigured and corrupt the active stream.

This series adds framework-level support for this constraint:

Patch 1 adds the dt-bindings for the spacemit,k3-i2s compatible.
The K3 SoC uses the same I2S IP as K1 but requires additional clocks:
a dedicated sysclk_div, along with c_sysclk and c_bclk which are
shared across multiple I2S controllers.

Patch 2 adds a DEFINE_GUARD wrapping snd_soc_card_mutex_lock() and
snd_soc_card_mutex_unlock() so that scope-based locking picks up the
SND_SOC_CARD_CLASS_RUNTIME lockdep subclass.

Patch 3 adds the constraint logic in soc-pcm.c. During PCM open,
every DAI that has a bclk clock pointer gets a hw_rule registered
unconditionally. The rule callback runs at hw_refine time: it scans
the card for an active peer sharing the same physical BCLK (via
clk_is_match()) that has already completed hw_params, then constrains
the current stream's rate to match the established BCLK rate. The
first DAI to complete hw_params is unconstrained; subsequent DAIs
must match. Two modes are supported:

  - Default (I2S): BCLK = rate * channels * sample_bits. The rule
    derives the valid rate range from the current channel and
    sample_bits intervals.

  - Explicit ratio (TDM): if the driver sets dai->bclk_ratio
    (e.g. slots * slot_width), the rule computes the single valid
    rate as active_bclk_rate / bclk_ratio.

This series was prompted by review feedback on the SpacemiT K3 I2S
series, where a vendor-specific fixed-sample-rate property was rejected
in favor of a generic framework solution:
https://lore.kernel.org/all/afFqgF6ZRwYdfUmL@sirena.co.uk/

Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
Changes in v4:
- Use snd_soc_card_mutex_lock()/snd_soc_card_mutex_unlock() via a local
  DEFINE_GUARD for lockdep subclass consistency
- Add DEFINE_GUARD(snd_soc_card_mutex) as a separate patch
- Link to v3: https://patch.msgid.link/20260518-i2s-same-blk-v3-0-2ba1c4f41db9@linux.spacemit.com

- Drop the SpacemiT K1/K3 I2S driver patch (previously patch 3) which
  depends on the not-yet-merged K3 I2S series; it will be sent as a
  standalone patch once that series lands
- Link to v2: https://patch.msgid.link/20260507-i2s-same-blk-v2-0-ede05a22f732@linux.spacemit.com

Changes in v2:
- Only store bclk_ratio when set_bclk_ratio op succeeds, avoiding stale
  ratio on real errors
- Hold card->mutex during rtd list traversal in hw_rule callback
- Link to v1: https://patch.msgid.link/20260430-i2s-same-blk-v1-0-3a1f04eb6159@linux.spacemit.com

To: Liam Girdwood <lgirdwood@gmail.com>
To: Mark Brown <broonie@kernel.org>
To: Jaroslav Kysela <perex@perex.cz>
To: Takashi Iwai <tiwai@suse.com>
To: Yixun Lan <dlan@kernel.org>
Cc: linux-sound@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: linux-riscv@lists.infradead.org
Cc: spacemit@lists.linux.dev

---
Troy Mitchell (3):
      ASoC: soc-dai: add shared BCLK clock for cross-DAI rate constraints
      ASoC: soc-pcm: add DEFINE_GUARD for snd_soc_card_mutex
      ASoC: soc-pcm: constrain hw_params when DAIs share the same BCLK

 include/sound/soc-dai.h |   7 +++
 sound/soc/soc-dai.c     |  18 ++++++++
 sound/soc/soc-pcm.c     | 119 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 144 insertions(+)
---
base-commit: db490fe819ac280fe608b23d98c54a5467ef2948
change-id: 20260429-i2s-same-blk-fe102b18c5ac

Best regards,
--  
Troy Mitchell <troy.mitchell@linux.spacemit.com>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 1/3] ASoC: soc-dai: add shared BCLK clock for cross-DAI rate constraints
  2026-05-22 13:33 [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination Troy Mitchell
@ 2026-05-22 13:33 ` Troy Mitchell
  2026-05-22 13:33 ` [PATCH v4 2/3] ASoC: soc-pcm: add DEFINE_GUARD for snd_soc_card_mutex Troy Mitchell
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Troy Mitchell @ 2026-05-22 13:33 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai, Yixun Lan
  Cc: linux-sound, linux-kernel, linux-riscv, spacemit, jinmei.wei,
	Troy Mitchell

Add a bclk field to struct snd_soc_dai and a helper function
snd_soc_dai_set_bclk_clk() that platform drivers can use to declare
which clock is their BCLK.

Also cache the bclk_ratio in snd_soc_dai_set_bclk_ratio() so that
the framework can use it later in hw_rule evaluation for TDM
configurations where BCLK = rate * slots * slot_width.

When multiple DAIs on the same card share the same physical BCLK
(detected via clk_is_match()), the ASoC core can automatically
constrain their hw_params so that the resulting BCLK rates are
compatible. This commit adds the data structure support; the actual
constraint logic follows in the next patch.

Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
 include/sound/soc-dai.h |  7 +++++++
 sound/soc/soc-dai.c     | 18 ++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 6a42812bba8c..df010a91b350 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -17,6 +17,7 @@
 struct snd_pcm_substream;
 struct snd_soc_dapm_widget;
 struct snd_compr_stream;
+struct clk;
 
 /*
  * DAI hardware audio formats.
@@ -188,6 +189,8 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
 
 int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio);
 
+void snd_soc_dai_set_bclk_clk(struct snd_soc_dai *dai, struct clk *bclk);
+
 /* Digital Audio interface formatting */
 int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd);
 u64 snd_soc_dai_get_fmt(const struct snd_soc_dai *dai, int priority);
@@ -473,6 +476,10 @@ struct snd_soc_dai {
 	unsigned int symmetric_channels;
 	unsigned int symmetric_sample_bits;
 
+	/* shared BCLK clock for cross-DAI rate constraints */
+	struct clk *bclk;
+	unsigned int bclk_ratio; /* BCLK = rate * bclk_ratio (0 = use channels * sample_bits) */
+
 	/* parent platform/codec */
 	struct snd_soc_component *component;
 
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 2f370fda1266..1719ddcefa4b 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -116,10 +116,28 @@ int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
 	    dai->driver->ops->set_bclk_ratio)
 		ret = dai->driver->ops->set_bclk_ratio(dai, ratio);
 
+	if (!ret)
+		dai->bclk_ratio = ratio;
+
 	return soc_dai_ret(dai, ret);
 }
 EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
 
+/**
+ * snd_soc_dai_set_bclk_clk - set the BCLK clock for shared clock detection
+ * @dai: DAI
+ * @bclk: BCLK clock pointer (or NULL to clear)
+ *
+ * When multiple DAIs share the same physical BCLK (detected via
+ * clk_is_match()), the ASoC core will automatically constrain their
+ * hw_params so that the resulting BCLK rates are compatible.
+ */
+void snd_soc_dai_set_bclk_clk(struct snd_soc_dai *dai, struct clk *bclk)
+{
+	dai->bclk = bclk;
+}
+EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_clk);
+
 int snd_soc_dai_get_fmt_max_priority(const struct snd_soc_pcm_runtime *rtd)
 {
 	struct snd_soc_dai *dai;

-- 
2.54.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 2/3] ASoC: soc-pcm: add DEFINE_GUARD for snd_soc_card_mutex
  2026-05-22 13:33 [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination Troy Mitchell
  2026-05-22 13:33 ` [PATCH v4 1/3] ASoC: soc-dai: add shared BCLK clock for cross-DAI rate constraints Troy Mitchell
@ 2026-05-22 13:33 ` Troy Mitchell
  2026-05-22 13:33 ` [PATCH v4 3/3] ASoC: soc-pcm: constrain hw_params when DAIs share the same BCLK Troy Mitchell
  2026-05-25 10:42 ` [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination Mark Brown
  3 siblings, 0 replies; 5+ messages in thread
From: Troy Mitchell @ 2026-05-22 13:33 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai, Yixun Lan
  Cc: linux-sound, linux-kernel, linux-riscv, spacemit, jinmei.wei,
	Troy Mitchell

Define a guard class wrapping snd_soc_card_mutex_lock() and
snd_soc_card_mutex_unlock() so that scope-based locking can be used
while still picking up the SND_SOC_CARD_CLASS_RUNTIME lockdep subclass.

Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
 sound/soc/soc-pcm.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 9b12eedb77c3..25e494c4ed81 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -26,6 +26,9 @@
 #include <sound/soc-link.h>
 #include <sound/initval.h>
 
+
+DEFINE_GUARD(snd_soc_card_mutex, struct snd_soc_card *,
+	     snd_soc_card_mutex_lock(_T), snd_soc_card_mutex_unlock(_T))
 #define soc_pcm_ret(rtd, ret) _soc_pcm_ret(rtd, __func__, ret)
 static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd,
 			       const char *func, int ret)

-- 
2.54.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v4 3/3] ASoC: soc-pcm: constrain hw_params when DAIs share the same BCLK
  2026-05-22 13:33 [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination Troy Mitchell
  2026-05-22 13:33 ` [PATCH v4 1/3] ASoC: soc-dai: add shared BCLK clock for cross-DAI rate constraints Troy Mitchell
  2026-05-22 13:33 ` [PATCH v4 2/3] ASoC: soc-pcm: add DEFINE_GUARD for snd_soc_card_mutex Troy Mitchell
@ 2026-05-22 13:33 ` Troy Mitchell
  2026-05-25 10:42 ` [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination Mark Brown
  3 siblings, 0 replies; 5+ messages in thread
From: Troy Mitchell @ 2026-05-22 13:33 UTC (permalink / raw)
  To: Liam Girdwood, Mark Brown, Jaroslav Kysela, Takashi Iwai, Yixun Lan
  Cc: linux-sound, linux-kernel, linux-riscv, spacemit, jinmei.wei,
	Troy Mitchell

When multiple CPU DAIs on the same sound card share the same physical
BCLK, add a hw_rule during PCM open that constrains the sample rate so
the resulting BCLK rate stays consistent across all sharing DAIs.

The rule callback scans all DAIs on the card at hw_refine time, looking
for an active peer that shares the same physical BCLK (via
clk_is_match()) and has already completed hw_params (checked via
dai->symmetric_rate != 0). This ensures the constraint uses the real
BCLK rate established by the peer's clk_set_rate() in hw_params, not a
stale boot-time default.

The first DAI to complete hw_params is unconstrained (no active peer
yet); subsequent DAIs are constrained to match.

The rule supports two modes:
- If the DAI has an explicit bclk_ratio set (e.g. for TDM where
  BCLK = rate * slots * slot_width), the rate is constrained to
  active_bclk_rate / bclk_ratio.
- Otherwise, the default formula BCLK = rate * channels * sample_bits
  is used to derive the valid rate range.

The constraint is purely additive: DAIs that do not set a bclk clock
pointer are completely unaffected.

Signed-off-by: Troy Mitchell <troy.mitchell@linux.spacemit.com>
---
 sound/soc/soc-pcm.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)

diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 25e494c4ed81..0e49290a8c90 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -12,6 +12,7 @@
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/slab.h>
@@ -470,6 +471,114 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream,
 	return 0;
 }
 
+/*
+ * Shared BCLK constraint: when multiple DAIs share the same physical BCLK,
+ * constrain hw_params so that the BCLK rate (rate * channels * sample_bits,
+ * or rate * slots * slot_width for TDM) remains consistent.
+ */
+
+static int soc_pcm_shared_bclk_rule_rate(struct snd_pcm_hw_params *params,
+					 struct snd_pcm_hw_rule *rule)
+{
+	struct snd_soc_dai *dai = rule->private;
+	struct snd_soc_card *card = dai->component->card;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_dai *other_dai;
+	unsigned long active_bclk_rate = 0;
+	struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+	struct snd_interval constraint = { .empty = 1 };
+	unsigned int target_rate;
+	int i;
+
+	/* Protect the rtd list traversal with the ASoC card mutex helper. */
+	guard(snd_soc_card_mutex)(card);
+
+	/* Scan all DAIs on the card for an active peer sharing the same BCLK */
+	for_each_card_rtds(card, rtd) {
+		for_each_rtd_cpu_dais(rtd, i, other_dai) {
+			if (other_dai == dai)
+				continue;
+			if (!other_dai->bclk)
+				continue;
+			if (!snd_soc_dai_active(other_dai))
+				continue;
+			/*
+			 * Skip peers whose hw_params hasn't run yet.
+			 * symmetric_rate is set by soc_pcm_set_dai_params()
+			 * after snd_soc_dai_hw_params(), so non-zero means
+			 * the DAI's clk_set_rate() has already executed.
+			 */
+			if (!other_dai->symmetric_rate)
+				continue;
+			if (!clk_is_match(dai->bclk, other_dai->bclk))
+				continue;
+
+			active_bclk_rate = clk_get_rate(other_dai->bclk);
+			if (active_bclk_rate)
+				goto found;
+		}
+	}
+
+	return 0;
+
+found:
+	if (dai->bclk_ratio) {
+		/*
+		 * Driver has set an explicit BCLK ratio (e.g. for TDM where
+		 * BCLK = rate * slots * slot_width). The only valid rate is
+		 * active_bclk_rate / bclk_ratio.
+		 */
+		target_rate = active_bclk_rate / dai->bclk_ratio;
+
+		constraint.min = target_rate;
+		constraint.max = target_rate;
+	} else {
+		struct snd_interval *channels = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_CHANNELS);
+		struct snd_interval *sample_bits = hw_param_interval(params,
+						SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
+
+		/*
+		 * Default: BCLK = rate * channels * sample_bits.
+		 * Calculate the range of valid rates given the current
+		 * channel and sample_bits intervals.
+		 */
+		if (!channels->min || !sample_bits->min)
+			return 0;
+
+		constraint.max = active_bclk_rate /
+				 ((unsigned long)channels->min * sample_bits->min);
+
+		if (channels->max && sample_bits->max)
+			constraint.min = active_bclk_rate /
+					 ((unsigned long)channels->max * sample_bits->max);
+		else
+			constraint.min = constraint.max;
+	}
+
+	constraint.integer = 1;
+	constraint.empty = 0;
+
+	return snd_interval_refine(rate, &constraint);
+}
+
+static int soc_pcm_apply_shared_bclk(struct snd_pcm_substream *substream,
+				     struct snd_soc_dai *dai)
+{
+	if (!dai->bclk)
+		return 0;
+
+	dev_dbg(dai->dev,
+		"ASoC: registering shared BCLK rate constraint\n");
+
+	return snd_pcm_hw_rule_add(substream->runtime, 0,
+		SNDRV_PCM_HW_PARAM_RATE,
+		soc_pcm_shared_bclk_rule_rate, dai,
+		SNDRV_PCM_HW_PARAM_CHANNELS,
+		SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
+		-1);
+}
+
 static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
@@ -906,6 +1015,13 @@ static int __soc_pcm_open(struct snd_soc_pcm_runtime *rtd,
 		if (ret != 0)
 			goto err;
 	}
+
+	/* Shared BCLK constraint across DAIs on the same card */
+	for_each_rtd_cpu_dais(rtd, i, dai) {
+		ret = soc_pcm_apply_shared_bclk(substream, dai);
+		if (ret != 0)
+			goto err;
+	}
 dynamic:
 	snd_soc_runtime_activate(rtd, substream->stream);
 	ret = 0;

-- 
2.54.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination
  2026-05-22 13:33 [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination Troy Mitchell
                   ` (2 preceding siblings ...)
  2026-05-22 13:33 ` [PATCH v4 3/3] ASoC: soc-pcm: constrain hw_params when DAIs share the same BCLK Troy Mitchell
@ 2026-05-25 10:42 ` Mark Brown
  3 siblings, 0 replies; 5+ messages in thread
From: Mark Brown @ 2026-05-25 10:42 UTC (permalink / raw)
  To: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Yixun Lan, Troy Mitchell
  Cc: linux-sound, linux-kernel, linux-riscv, spacemit, jinmei.wei

On Fri, 22 May 2026 21:33:56 +0800, Troy Mitchell wrote:
> ASoC: add shared BCLK rate constraint for cross-DAI coordination
> 
> On some SoCs (e.g. SpacemiT K3), multiple I2S controllers share the
> same physical BCLK. When one controller is already streaming, the
> others must use hw_params that result in the same BCLK rate, otherwise
> the shared clock would be reconfigured and corrupt the active stream.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.2

Thanks!

[1/3] ASoC: soc-dai: add shared BCLK clock for cross-DAI rate constraints
      https://git.kernel.org/broonie/sound/c/94bdfad3a665
[2/3] ASoC: soc-pcm: add DEFINE_GUARD for snd_soc_card_mutex
      https://git.kernel.org/broonie/sound/c/2555c62275a1
[3/3] ASoC: soc-pcm: constrain hw_params when DAIs share the same BCLK
      https://git.kernel.org/broonie/sound/c/c8c2ffd722a6

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-05-25 12:32 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-22 13:33 [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination Troy Mitchell
2026-05-22 13:33 ` [PATCH v4 1/3] ASoC: soc-dai: add shared BCLK clock for cross-DAI rate constraints Troy Mitchell
2026-05-22 13:33 ` [PATCH v4 2/3] ASoC: soc-pcm: add DEFINE_GUARD for snd_soc_card_mutex Troy Mitchell
2026-05-22 13:33 ` [PATCH v4 3/3] ASoC: soc-pcm: constrain hw_params when DAIs share the same BCLK Troy Mitchell
2026-05-25 10:42 ` [PATCH v4 0/3] ASoC: add shared BCLK rate constraint for cross-DAI coordination Mark Brown

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®