Linux Sound subsystem development
 help / color / mirror / Atom feed
* [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues
       [not found] <CGME20261022074752eucas1p20373b227c271ff18c3207b7f67ff3c2c@eucas1p2.samsung.com>
@ 2026-10-22  7:47 ` Marek Szyprowski
  2026-10-22  7:47   ` [PATCH v2 1/4] ASoC: wm8994: fix MCLK gating for AIF clocks sourced from MCLK2 Marek Szyprowski
                     ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Marek Szyprowski @ 2026-10-22  7:47 UTC (permalink / raw)
  Cc: Marek Szyprowski, Liam Girdwood, Mark Brown, Sylwester Nawrocki,
	Charles Keepax, Krzysztof Kozlowski, Artur Weber, patches,
	linux-sound

Hi All,

This patchset fixes a few issues in the WM8994/WM1811 codec clocking
code, which show up on the Exynos4412 Trats2 board. On that board the
codec AIF1 and SYSCLK run from MCLK2 (the 32768Hz clock provided by the
PMIC) when idle, and from FLL1 (fed by MCLK1, a fixed 24MHz clock) when
a stream is active.

The symptoms are the codec flooding the kernel log with FIFO error
interrupts every 10ms once any digital path is powered up, for example
by the mixer state restored by alsactl, and FLL1 failing to lock:

 wm8994-codec wm8994-codec: Timed out waiting for FLL lock
 wm8994-codec wm8994-codec: FIFO error
 wm8994-codec wm8994-codec: FIFO error
 ...

Both issues disappear when booting with clk_ignore_unused, or after the
WLAN/Bluetooth drivers enable the shared 32kHz clock. This went
unnoticed during the initial Midas audio contribution probably because
the WLAN/Bluetooth drivers kept their clocks enabled that time. Several
bugs contribute to this:

1. aif_mclk_set() never enables MCLK2 for an AIF clocked from it, due
   to a missing shift of the AIFnCLK_SRC field value, so the codec runs
   from a stopped clock until another user enables it. The MCLK enable
   also doesn't follow the AIF clock source changes done while the AIF
   clock is running.

2. The AIFnCLK rate ratio saved when SYSCLK drops to 32kHz gets
   overwritten on each subsequent clock reconfiguration done in the low
   SYSCLK mode, so AIF1 ends up at 128fs instead of 256fs.

3. wm8994_set_dai_sysclk() passes the AIF index instead of the MCLK
   index to wm8994_set_mclk_rate(), so the rate of MCLK1 is reported for
   MCLK2 and the low SYSCLK handling is skipped.

4. The midas_wm1811 machine driver starts FLL1 at 11.2896MHz when no
   stream is active, while AIF1 keeps the configuration of the last
   stream (or the 48kHz reset default), which needs 12.288MHz.

Patches have been developed with LLM assistance and have been tested on
the real Trats2 board. The built-in speaker as well as headphones jack
provide proper audio now.

Best regards
Marek Szyprowski, PhD
Samsung R&D Institute Poland


Changelog:

v2:
- patch 1: move the MCLK enable to the newly selected MCLK when the AIF
  clock source is changed by configure_aif_clock()
- added collected Reviewed-by tags

v1: https://lore.kernel.org/all/20261021101750.3297770-1-m.szyprowski@samsung.com/
- initial version


Patch summary:

Marek Szyprowski (4):
  ASoC: wm8994: fix MCLK gating for AIF clocks sourced from MCLK2
  ASoC: wm8994: don't lose the AIF clock ratio when staying at 32kHz
    SYSCLK
  ASoC: wm8994: fix MCLK index used for setting MCLK rate
  ASoC: samsung: midas_wm1811: run FLL1 at the AIF1 configured rate when
    idle

 sound/soc/codecs/wm8994.c        | 153 ++++++++++++++++++-------------
 sound/soc/codecs/wm8994.h        |   2 +
 sound/soc/samsung/midas_wm1811.c |  14 ++-
 3 files changed, 99 insertions(+), 70 deletions(-)

-- 
2.43.0


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

* [PATCH v2 1/4] ASoC: wm8994: fix MCLK gating for AIF clocks sourced from MCLK2
  2026-10-22  7:47 ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Marek Szyprowski
@ 2026-10-22  7:47   ` Marek Szyprowski
  2026-10-22  9:38     ` Charles Keepax
  2026-10-22  7:47   ` [PATCH v2 2/4] ASoC: wm8994: don't lose the AIF clock ratio when staying at 32kHz SYSCLK Marek Szyprowski
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Marek Szyprowski @ 2026-10-22  7:47 UTC (permalink / raw)
  Cc: Marek Szyprowski, Liam Girdwood, Mark Brown, Sylwester Nawrocki,
	Charles Keepax, Krzysztof Kozlowski, Artur Weber, patches,
	linux-sound

aif_mclk_set() masks the AIFnCLK_SRC field of the AIFn clocking
register, but compares the result with unshifted field values. The
MCLK2 source (0x08) therefore never matches, so MCLK2 is never enabled
for an AIF clocked from it, and the AIF relies on other users of that
clock to keep it running.

On the Exynos4412 Trats2 board, AIF1 and SYSCLK run from MCLK2, the
32768Hz PMIC clock, while the codec is idle. That clock is shared with
the WLAN and Bluetooth chips, which enable it only once their drivers
are loaded. Until then the codec runs from a stopped clock: FLL1 fails
to lock when configured from that state, and the codec floods the
kernel log with FIFO error interrupts once a digital path is powered
up:

 wm8994-codec wm8994-codec: Timed out waiting for FLL lock
 wm8994-codec wm8994-codec: FIFO error

Booting with clk_ignore_unused, which keeps that clock running from
the bootloader, makes both issues disappear.

Fixing just the comparison is not enough. The AIF clock source can
be changed by configure_aif_clock() while the AIF clock is running,
for example the Midas machine driver switches AIF1 between MCLK2 and
FLL1 while AIF1CLK is kept enabled for jack detection. The MCLK
selected this way is never enabled, and looking up the clock again on
disable can release a different MCLK than the one enabled, leaking the
enable count of one clock and underflowing the other.

Shift the field value before decoding it, and remember which MCLK has
been enabled for each AIF, so that the same clock is released on
disable. When the AIF clock source is changed while the AIF clock is
running, enable the new MCLK before switching to it and release the
previous one afterwards. While at it, report the MCLK number 1-based
in the error message.

Fixes: 001b83d395ab ("ASoC: wm8994: Add support for MCLKn clock gating")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 sound/soc/codecs/wm8994.c | 55 ++++++++++++++++++++++++++++++++-------
 sound/soc/codecs/wm8994.h |  2 ++
 2 files changed, 47 insertions(+), 10 deletions(-)

diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index c65a7769a9d2..b5675eab2214 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -163,9 +163,12 @@ static void wm8958_micd_set_rate(struct snd_soc_component *component)
 static int configure_aif_clock(struct snd_soc_component *component, int aif)
 {
 	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct clk *mclk = NULL;
+	bool switch_mclk;
 	int rate;
 	int reg1 = 0;
 	int offset;
+	int ret;
 
 	if (aif)
 		offset = 4;
@@ -174,11 +177,13 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
 
 	switch (wm8994->sysclk[aif]) {
 	case WM8994_SYSCLK_MCLK1:
+		mclk = wm8994->mclk[WM8994_MCLK1].clk;
 		rate = wm8994->mclk_rate[0];
 		break;
 
 	case WM8994_SYSCLK_MCLK2:
 		reg1 |= 0x8;
+		mclk = wm8994->mclk[WM8994_MCLK2].clk;
 		rate = wm8994->mclk_rate[1];
 		break;
 
@@ -196,6 +201,20 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
 		return -EINVAL;
 	}
 
+	/*
+	 * If the AIF clock is running, enable the new MCLK before switching
+	 * to it and release the previous one afterwards.
+	 */
+	switch_mclk = wm8994->aif_clk_on[aif] && mclk != wm8994->aif_mclk[aif];
+	if (switch_mclk) {
+		ret = clk_prepare_enable(mclk);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to enable MCLK for AIF%d\n", aif + 1);
+			return ret;
+		}
+	}
+
 	if (rate >= 13500000) {
 		rate /= 2;
 		reg1 |= WM8994_AIF1CLK_DIV;
@@ -210,6 +229,11 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
 			    WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
 			    reg1);
 
+	if (switch_mclk) {
+		clk_disable_unprepare(wm8994->aif_mclk[aif]);
+		wm8994->aif_mclk[aif] = mclk;
+	}
+
 	return 0;
 }
 
@@ -1059,13 +1083,25 @@ static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enabl
 	unsigned int offset, val, clk_idx;
 	int ret;
 
+	/*
+	 * The AIF clock source may be changed while the AIF clock is
+	 * running, so release the MCLK which has been enabled for it
+	 * instead of the one currently selected.
+	 */
+	if (!enable) {
+		clk_disable_unprepare(wm8994->aif_mclk[aif]);
+		wm8994->aif_mclk[aif] = NULL;
+		wm8994->aif_clk_on[aif] = false;
+		return 0;
+	}
+
 	if (aif)
 		offset = 4;
 	else
 		offset = 0;
 
 	val = snd_soc_component_read(component, WM8994_AIF1_CLOCKING_1 + offset);
-	val &= WM8994_AIF1CLK_SRC_MASK;
+	val = (val & WM8994_AIF1CLK_SRC_MASK) >> WM8994_AIF1CLK_SRC_SHIFT;
 
 	switch (val) {
 	case 0:
@@ -1075,19 +1111,18 @@ static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enabl
 		clk_idx = WM8994_MCLK2;
 		break;
 	default:
+		wm8994->aif_clk_on[aif] = true;
 		return 0;
 	}
 
-	if (enable) {
-		ret = clk_prepare_enable(wm8994->mclk[clk_idx].clk);
-		if (ret < 0) {
-			dev_err(component->dev,	"Failed to enable MCLK%d\n",
-				clk_idx);
-			return ret;
-		}
-	} else {
-		clk_disable_unprepare(wm8994->mclk[clk_idx].clk);
+	ret = clk_prepare_enable(wm8994->mclk[clk_idx].clk);
+	if (ret < 0) {
+		dev_err(component->dev,	"Failed to enable MCLK%d\n",
+			clk_idx + 1);
+		return ret;
 	}
+	wm8994->aif_mclk[aif] = wm8994->mclk[clk_idx].clk;
+	wm8994->aif_clk_on[aif] = true;
 
 	return 0;
 }
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index b28398aa9e48..e7df0a1a2314 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -81,6 +81,8 @@ struct wm8994_priv {
 	struct wm_hubs_data hubs;
 	struct wm8994 *wm8994;
 	struct clk_bulk_data mclk[WM8994_NUM_MCLK];
+	struct clk *aif_mclk[2];
+	bool aif_clk_on[2];
 	int sysclk[2];
 	int sysclk_rate[2];
 	int mclk_rate[2];
-- 
2.43.0


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

* [PATCH v2 2/4] ASoC: wm8994: don't lose the AIF clock ratio when staying at 32kHz SYSCLK
  2026-10-22  7:47 ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Marek Szyprowski
  2026-10-22  7:47   ` [PATCH v2 1/4] ASoC: wm8994: fix MCLK gating for AIF clocks sourced from MCLK2 Marek Szyprowski
@ 2026-10-22  7:47   ` Marek Szyprowski
  2026-10-22  7:47   ` [PATCH v2 3/4] ASoC: wm8994: fix MCLK index used for setting MCLK rate Marek Szyprowski
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Marek Szyprowski @ 2026-10-22  7:47 UTC (permalink / raw)
  Cc: Marek Szyprowski, Liam Girdwood, Mark Brown, Sylwester Nawrocki,
	Charles Keepax, Krzysztof Kozlowski, Artur Weber, patches,
	linux-sound

When SYSCLK drops below 50kHz, the AIFnCLK rate ratio is saved and
temporarily lowered to 128fs for accessory detection, then restored
once SYSCLK gets fast enough again. The ratio is however saved again
on each clock reconfiguration done while SYSCLK is still slow, which
overwrites the original ratio with the 128fs one.

This happens on the Exynos4412 Trats2 board, which set MCLK2 as SYSCLK
twice during the card probe and then configure FLL1 while still running
from MCLK2. Once SYSCLK is switched to FLL1, the 128fs ratio is
"restored", so AIF1 is left configured for 48kHz at 128fs while being
clocked at 256fs. If any digital path is powered up before a stream
reconfigures the AIF, the codec raises FIFO error interrupts every
10ms, flooding the kernel log:

 wm8994-codec wm8994-codec: FIFO error

Save the original ratio only when entering the low SYSCLK mode. While
at it, move the code duplicated in _wm8994_set_fll() and
wm8994_set_dai_sysclk() to a common helper.

Fixes: 6730049a4763 ("ASoC: wm8994: Lower AIFnCLK divisor when dropping to 32kHz")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 sound/soc/codecs/wm8994.c | 94 +++++++++++++++++----------------------
 1 file changed, 40 insertions(+), 54 deletions(-)

diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index b5675eab2214..2cfc2f8a36b0 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -2234,6 +2234,44 @@ static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
 	return 0;
 }
 
+/*
+ * If SYSCLK is less than 50kHz adjust AIFnCLK dividers for detection,
+ * restoring the original ones once SYSCLK is fast enough again.
+ */
+static void wm8994_update_aif_clk_rate(struct snd_soc_component *component)
+{
+	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+
+	if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
+		/* Don't overwrite the saved dividers with the 128fs ones */
+		if (!wm8994->aifdiv[0]) {
+			dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
+
+			wm8994->aifdiv[0] = snd_soc_component_read(component,
+								   WM8994_AIF1_RATE)
+				& WM8994_AIF1CLK_RATE_MASK;
+			wm8994->aifdiv[1] = snd_soc_component_read(component,
+								   WM8994_AIF2_RATE)
+				& WM8994_AIF1CLK_RATE_MASK;
+		}
+
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
+				    WM8994_AIF1CLK_RATE_MASK, 0x1);
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
+				    WM8994_AIF2CLK_RATE_MASK, 0x1);
+	} else if (wm8994->aifdiv[0]) {
+		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
+				    WM8994_AIF1CLK_RATE_MASK,
+				    wm8994->aifdiv[0]);
+		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
+				    WM8994_AIF2CLK_RATE_MASK,
+				    wm8994->aifdiv[1]);
+
+		wm8994->aifdiv[0] = 0;
+		wm8994->aifdiv[1] = 0;
+	}
+}
+
 static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
 			  unsigned int freq_in, unsigned int freq_out)
 {
@@ -2468,33 +2506,7 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
 
 	configure_clock(component);
 
-	/*
-	 * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
-	 * for detection.
-	 */
-	if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
-		dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
-
-		wm8994->aifdiv[0] = snd_soc_component_read(component, WM8994_AIF1_RATE)
-			& WM8994_AIF1CLK_RATE_MASK;
-		wm8994->aifdiv[1] = snd_soc_component_read(component, WM8994_AIF2_RATE)
-			& WM8994_AIF1CLK_RATE_MASK;
-
-		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
-				    WM8994_AIF1CLK_RATE_MASK, 0x1);
-		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
-				    WM8994_AIF2CLK_RATE_MASK, 0x1);
-	} else if (wm8994->aifdiv[0]) {
-		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
-				    WM8994_AIF1CLK_RATE_MASK,
-				    wm8994->aifdiv[0]);
-		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
-				    WM8994_AIF2CLK_RATE_MASK,
-				    wm8994->aifdiv[1]);
-
-		wm8994->aifdiv[0] = 0;
-		wm8994->aifdiv[1] = 0;
-	}
+	wm8994_update_aif_clk_rate(component);
 
 	return 0;
 }
@@ -2612,33 +2624,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 
 	configure_clock(component);
 
-	/*
-	 * If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
-	 * for detection.
-	 */
-	if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
-		dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
-
-		wm8994->aifdiv[0] = snd_soc_component_read(component, WM8994_AIF1_RATE)
-			& WM8994_AIF1CLK_RATE_MASK;
-		wm8994->aifdiv[1] = snd_soc_component_read(component, WM8994_AIF2_RATE)
-			& WM8994_AIF1CLK_RATE_MASK;
-
-		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
-				    WM8994_AIF1CLK_RATE_MASK, 0x1);
-		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
-				    WM8994_AIF2CLK_RATE_MASK, 0x1);
-	} else if (wm8994->aifdiv[0]) {
-		snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
-				    WM8994_AIF1CLK_RATE_MASK,
-				    wm8994->aifdiv[0]);
-		snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
-				    WM8994_AIF2CLK_RATE_MASK,
-				    wm8994->aifdiv[1]);
-
-		wm8994->aifdiv[0] = 0;
-		wm8994->aifdiv[1] = 0;
-	}
+	wm8994_update_aif_clk_rate(component);
 
 	return 0;
 }
-- 
2.43.0


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

* [PATCH v2 3/4] ASoC: wm8994: fix MCLK index used for setting MCLK rate
  2026-10-22  7:47 ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Marek Szyprowski
  2026-10-22  7:47   ` [PATCH v2 1/4] ASoC: wm8994: fix MCLK gating for AIF clocks sourced from MCLK2 Marek Szyprowski
  2026-10-22  7:47   ` [PATCH v2 2/4] ASoC: wm8994: don't lose the AIF clock ratio when staying at 32kHz SYSCLK Marek Szyprowski
@ 2026-10-22  7:47   ` Marek Szyprowski
  2026-10-22  7:47   ` [PATCH v2 4/4] ASoC: samsung: midas_wm1811: run FLL1 at the AIF1 configured rate when idle Marek Szyprowski
  2026-10-22 10:03   ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Mark Brown
  4 siblings, 0 replies; 11+ messages in thread
From: Marek Szyprowski @ 2026-10-22  7:47 UTC (permalink / raw)
  Cc: Marek Szyprowski, Liam Girdwood, Mark Brown, Sylwester Nawrocki,
	Charles Keepax, Krzysztof Kozlowski, Artur Weber, patches,
	linux-sound

wm8994_set_dai_sysclk() passes the AIF index (dai->id - 1) to
wm8994_set_mclk_rate(), which uses it to index the MCLK clocks and
their cached rates. As a result, selecting MCLK2 as the AIF1 clock
source sets and reads back the rate of MCLK1 instead, and the rate
of MCLK1 is then stored as the MCLK2 rate.

On the Exynos4412 Trats2 board, where MCLK1 is a fixed 24MHz clock and
MCLK2 a 32768Hz clock used when the codec is idle, this gives:

 wm8994-codec wm8994-codec: AIF1 using MCLK2 at 24000000Hz

so the driver assumes a 12MHz SYSCLK while it actually runs at 32kHz.
This skips the 128fs AIF clock ratio setup for low SYSCLK rates and
makes the mic detection rate configuration use the wrong clock rate.

Pass the MCLK index matching the selected clock source instead.

Fixes: 419e2f508336 ("ASoC: wm8994: Add support for setting MCLK clock rate")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 sound/soc/codecs/wm8994.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 2cfc2f8a36b0..6b91e02f130b 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -2566,7 +2566,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 	case WM8994_SYSCLK_MCLK1:
 		wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1;
 
-		ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
+		ret = wm8994_set_mclk_rate(wm8994, WM8994_MCLK1, &freq);
 		if (ret < 0)
 			return ret;
 
@@ -2579,7 +2579,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
 		/* TODO: Set GPIO AF */
 		wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2;
 
-		ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
+		ret = wm8994_set_mclk_rate(wm8994, WM8994_MCLK2, &freq);
 		if (ret < 0)
 			return ret;
 
-- 
2.43.0


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

* [PATCH v2 4/4] ASoC: samsung: midas_wm1811: run FLL1 at the AIF1 configured rate when idle
  2026-10-22  7:47 ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Marek Szyprowski
                     ` (2 preceding siblings ...)
  2026-10-22  7:47   ` [PATCH v2 3/4] ASoC: wm8994: fix MCLK index used for setting MCLK rate Marek Szyprowski
@ 2026-10-22  7:47   ` Marek Szyprowski
  2026-10-22 10:03   ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Mark Brown
  4 siblings, 0 replies; 11+ messages in thread
From: Marek Szyprowski @ 2026-10-22  7:47 UTC (permalink / raw)
  Cc: Marek Szyprowski, Liam Girdwood, Mark Brown, Sylwester Nawrocki,
	Charles Keepax, Krzysztof Kozlowski, Artur Weber, patches,
	linux-sound

When the codec is brought up without an active stream, for example
because the mixer state restored by alsactl powers up a digital path,
midas_start_fll1() sets FLL1 to the default 11.2896MHz rate. The
codec's AIF1 however keeps the configuration of the last stream, or its
reset default of 48kHz at 256fs before the first stream, which needs
a 12.288MHz AIF1 clock. The digital paths then run with AIF1 clocked
at a rate not matching its configuration.

Remember the FLL1 rate requested by the last hw_params() call, which
matches the AIF1 configuration kept in the codec, and use it when no
specific rate is requested. Change the default rate used before the
first stream to 12.288MHz, matching the codec's default AIF1
configuration.

Fixes: fd0ea9cd9698 ("ASoC: samsung: Add sound support for Midas boards")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
---
 sound/soc/samsung/midas_wm1811.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c
index d43af5069baf..11466dd3539e 100644
--- a/sound/soc/samsung/midas_wm1811.c
+++ b/sound/soc/samsung/midas_wm1811.c
@@ -25,7 +25,8 @@
  */
 #define MCLK1_RATE 24000000U
 #define MCLK2_RATE 32768U
-#define DEFAULT_FLL1_RATE 11289600U
+/* Matches the codec's default AIF1 configuration: 48kHz, 256fs */
+#define DEFAULT_FLL1_RATE 12288000U
 
 struct midas_priv {
 	struct gpio_desc *gpio_fm_sel;
@@ -34,6 +35,7 @@ struct midas_priv {
 	struct gpio_desc *gpio_headset_key;
 	struct iio_channel *adc_headset_detect;
 	unsigned int fll1_rate;
+	unsigned int aif1clk_rate;
 
 	struct snd_soc_jack headset_jack;
 };
@@ -171,11 +173,12 @@ static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
 	if (!rate)
 		rate = priv->fll1_rate;
 	/*
-	 * If no new rate is requested, set FLL1 to a sane default for jack
-	 * detection.
+	 * If no new rate is requested, set FLL1 to the rate the codec's AIF1
+	 * is currently configured for, as its digital paths can be powered
+	 * up without an active stream.
 	 */
 	if (!rate)
-		rate = DEFAULT_FLL1_RATE;
+		rate = priv->aif1clk_rate ?: DEFAULT_FLL1_RATE;
 
 	if (rate != priv->fll1_rate && priv->fll1_rate) {
 		/* while reconfiguring, switch to MCLK2 for SYSCLK */
@@ -241,6 +244,7 @@ static int midas_aif1_hw_params(struct snd_pcm_substream *substream,
 				struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+	struct midas_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 	unsigned int pll_out;
 
 	/* AIF1CLK should be at least 3MHz for "optimal performance" */
@@ -249,6 +253,8 @@ static int midas_aif1_hw_params(struct snd_pcm_substream *substream,
 	else
 		pll_out = params_rate(params) * 256;
 
+	priv->aif1clk_rate = pll_out;
+
 	return midas_start_fll1(rtd, pll_out);
 }
 
-- 
2.43.0


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

* Re: [PATCH v2 1/4] ASoC: wm8994: fix MCLK gating for AIF clocks sourced from MCLK2
  2026-10-22  7:47   ` [PATCH v2 1/4] ASoC: wm8994: fix MCLK gating for AIF clocks sourced from MCLK2 Marek Szyprowski
@ 2026-10-22  9:38     ` Charles Keepax
  0 siblings, 0 replies; 11+ messages in thread
From: Charles Keepax @ 2026-10-22  9:38 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: Liam Girdwood, Mark Brown, Sylwester Nawrocki,
	Krzysztof Kozlowski, Artur Weber, patches, linux-sound

On Thu, Oct 22, 2026 at 09:47:39AM +0200, Marek Szyprowski wrote:
> aif_mclk_set() masks the AIFnCLK_SRC field of the AIFn clocking
> register, but compares the result with unshifted field values. The
> MCLK2 source (0x08) therefore never matches, so MCLK2 is never enabled
> for an AIF clocked from it, and the AIF relies on other users of that
> clock to keep it running.
> 
> On the Exynos4412 Trats2 board, AIF1 and SYSCLK run from MCLK2, the
> 32768Hz PMIC clock, while the codec is idle. That clock is shared with
> the WLAN and Bluetooth chips, which enable it only once their drivers
> are loaded. Until then the codec runs from a stopped clock: FLL1 fails
> to lock when configured from that state, and the codec floods the
> kernel log with FIFO error interrupts once a digital path is powered
> up:
> 
>  wm8994-codec wm8994-codec: Timed out waiting for FLL lock
>  wm8994-codec wm8994-codec: FIFO error
> 
> Booting with clk_ignore_unused, which keeps that clock running from
> the bootloader, makes both issues disappear.
> 
> Fixing just the comparison is not enough. The AIF clock source can
> be changed by configure_aif_clock() while the AIF clock is running,
> for example the Midas machine driver switches AIF1 between MCLK2 and
> FLL1 while AIF1CLK is kept enabled for jack detection. The MCLK
> selected this way is never enabled, and looking up the clock again on
> disable can release a different MCLK than the one enabled, leaking the
> enable count of one clock and underflowing the other.
> 
> Shift the field value before decoding it, and remember which MCLK has
> been enabled for each AIF, so that the same clock is released on
> disable. When the AIF clock source is changed while the AIF clock is
> running, enable the new MCLK before switching to it and release the
> previous one afterwards. While at it, report the MCLK number 1-based
> in the error message.
> 
> Fixes: 001b83d395ab ("ASoC: wm8994: Add support for MCLKn clock gating")
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---

Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>

Thanks,
Charles

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

* Re: [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues
  2026-10-22  7:47 ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Marek Szyprowski
                     ` (3 preceding siblings ...)
  2026-10-22  7:47   ` [PATCH v2 4/4] ASoC: samsung: midas_wm1811: run FLL1 at the AIF1 configured rate when idle Marek Szyprowski
@ 2026-10-22 10:03   ` Mark Brown
  2026-10-22 10:15     ` [PATCH] ASoC: wm8994: follow AIF clock source changes in MCLK gating Marek Szyprowski
  2026-10-22 10:17     ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Marek Szyprowski
  4 siblings, 2 replies; 11+ messages in thread
From: Mark Brown @ 2026-10-22 10:03 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: Liam Girdwood, Sylwester Nawrocki, Charles Keepax,
	Krzysztof Kozlowski, Artur Weber, patches, linux-sound

[-- Attachment #1: Type: text/plain, Size: 382 bytes --]

On Thu, Oct 22, 2026 at 09:47:38AM +0200, Marek Szyprowski wrote:

> v2:
> - patch 1: move the MCLK enable to the newly selected MCLK when the AIF
>   clock source is changed by configure_aif_clock()
> - added collected Reviewed-by tags

v1 was already in my CI queue with other things stacked on top of it,
could you please send an incremental change with the differences from
v2?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* [PATCH] ASoC: wm8994: follow AIF clock source changes in MCLK gating
  2026-10-22 10:03   ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Mark Brown
@ 2026-10-22 10:15     ` Marek Szyprowski
  2026-10-22 13:10       ` Mark Brown
  2026-10-22 13:20       ` Mark Brown
  2026-10-22 10:17     ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Marek Szyprowski
  1 sibling, 2 replies; 11+ messages in thread
From: Marek Szyprowski @ 2026-10-22 10:15 UTC (permalink / raw)
  To: patches, linux-sound
  Cc: Marek Szyprowski, Liam Girdwood, Mark Brown, Sylwester Nawrocki,
	Charles Keepax, Krzysztof Kozlowski, Artur Weber

The AIF clock source can be changed by configure_aif_clock() while the
AIF clock is running, for example the Midas machine driver switches
AIF1 between MCLK2 and FLL1 while AIF1CLK is kept enabled for jack
detection. aif_mclk_set() only enables the MCLK selected at the time
the AIF clock is turned on, so an MCLK selected later this way is never
enabled, and the codec may run from a stopped clock.

Track whether the AIF clock is running and, if so, enable the newly
selected MCLK in configure_aif_clock() before switching to it, then
release the previously enabled one.

Fixes: 001b83d395ab ("ASoC: wm8994: Add support for MCLKn clock gating")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
 sound/soc/codecs/wm8994.c | 27 +++++++++++++++++++++++++++
 sound/soc/codecs/wm8994.h |  1 +
 2 files changed, 28 insertions(+)

diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 8adb3de546dd..6b91e02f130b 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -163,9 +163,12 @@ static void wm8958_micd_set_rate(struct snd_soc_component *component)
 static int configure_aif_clock(struct snd_soc_component *component, int aif)
 {
 	struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
+	struct clk *mclk = NULL;
+	bool switch_mclk;
 	int rate;
 	int reg1 = 0;
 	int offset;
+	int ret;
 
 	if (aif)
 		offset = 4;
@@ -174,11 +177,13 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
 
 	switch (wm8994->sysclk[aif]) {
 	case WM8994_SYSCLK_MCLK1:
+		mclk = wm8994->mclk[WM8994_MCLK1].clk;
 		rate = wm8994->mclk_rate[0];
 		break;
 
 	case WM8994_SYSCLK_MCLK2:
 		reg1 |= 0x8;
+		mclk = wm8994->mclk[WM8994_MCLK2].clk;
 		rate = wm8994->mclk_rate[1];
 		break;
 
@@ -196,6 +201,20 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
 		return -EINVAL;
 	}
 
+	/*
+	 * If the AIF clock is running, enable the new MCLK before switching
+	 * to it and release the previous one afterwards.
+	 */
+	switch_mclk = wm8994->aif_clk_on[aif] && mclk != wm8994->aif_mclk[aif];
+	if (switch_mclk) {
+		ret = clk_prepare_enable(mclk);
+		if (ret < 0) {
+			dev_err(component->dev,
+				"Failed to enable MCLK for AIF%d\n", aif + 1);
+			return ret;
+		}
+	}
+
 	if (rate >= 13500000) {
 		rate /= 2;
 		reg1 |= WM8994_AIF1CLK_DIV;
@@ -210,6 +229,11 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
 			    WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
 			    reg1);
 
+	if (switch_mclk) {
+		clk_disable_unprepare(wm8994->aif_mclk[aif]);
+		wm8994->aif_mclk[aif] = mclk;
+	}
+
 	return 0;
 }
 
@@ -1067,6 +1091,7 @@ static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enabl
 	if (!enable) {
 		clk_disable_unprepare(wm8994->aif_mclk[aif]);
 		wm8994->aif_mclk[aif] = NULL;
+		wm8994->aif_clk_on[aif] = false;
 		return 0;
 	}
 
@@ -1086,6 +1111,7 @@ static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enabl
 		clk_idx = WM8994_MCLK2;
 		break;
 	default:
+		wm8994->aif_clk_on[aif] = true;
 		return 0;
 	}
 
@@ -1096,6 +1122,7 @@ static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enabl
 		return ret;
 	}
 	wm8994->aif_mclk[aif] = wm8994->mclk[clk_idx].clk;
+	wm8994->aif_clk_on[aif] = true;
 
 	return 0;
 }
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 5b22cfab317e..e7df0a1a2314 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -82,6 +82,7 @@ struct wm8994_priv {
 	struct wm8994 *wm8994;
 	struct clk_bulk_data mclk[WM8994_NUM_MCLK];
 	struct clk *aif_mclk[2];
+	bool aif_clk_on[2];
 	int sysclk[2];
 	int sysclk_rate[2];
 	int mclk_rate[2];
-- 
2.43.0


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

* Re: [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues
  2026-10-22 10:03   ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Mark Brown
  2026-10-22 10:15     ` [PATCH] ASoC: wm8994: follow AIF clock source changes in MCLK gating Marek Szyprowski
@ 2026-10-22 10:17     ` Marek Szyprowski
  1 sibling, 0 replies; 11+ messages in thread
From: Marek Szyprowski @ 2026-10-22 10:17 UTC (permalink / raw)
  To: Mark Brown
  Cc: Liam Girdwood, Sylwester Nawrocki, Charles Keepax,
	Krzysztof Kozlowski, Artur Weber, patches, linux-sound

On 22.10.2026 12:03, Mark Brown wrote:
> On Thu, Oct 22, 2026 at 09:47:38AM +0200, Marek Szyprowski wrote:
>
>> v2:
>> - patch 1: move the MCLK enable to the newly selected MCLK when the AIF
>>   clock source is changed by configure_aif_clock()
>> - added collected Reviewed-by tags
> v1 was already in my CI queue with other things stacked on top of it,
> could you please send an incremental change with the differences from
> v2?

Sure:

https://lore.kernel.org/all/20261022101531.775891-1-m.szyprowski@samsung.com/

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


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

* Re: [PATCH] ASoC: wm8994: follow AIF clock source changes in MCLK gating
  2026-10-22 10:15     ` [PATCH] ASoC: wm8994: follow AIF clock source changes in MCLK gating Marek Szyprowski
@ 2026-10-22 13:10       ` Mark Brown
  2026-10-22 13:20       ` Mark Brown
  1 sibling, 0 replies; 11+ messages in thread
From: Mark Brown @ 2026-10-22 13:10 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: patches, linux-sound, Liam Girdwood, Sylwester Nawrocki,
	Charles Keepax, Krzysztof Kozlowski, Artur Weber

[-- Attachment #1: Type: text/plain, Size: 566 bytes --]

On Thu, Oct 22, 2026 at 12:15:28PM +0200, Marek Szyprowski wrote:
> The AIF clock source can be changed by configure_aif_clock() while the
> AIF clock is running, for example the Midas machine driver switches
> AIF1 between MCLK2 and FLL1 while AIF1CLK is kept enabled for jack

Please don't send new patches in reply to old patches or serieses, this
makes it harder for both people and tools to understand what is going
on - it can bury things in mailboxes and make it difficult to keep track
of what current patches are, both for the new patches and the old ones.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

* Re: [PATCH] ASoC: wm8994: follow AIF clock source changes in MCLK gating
  2026-10-22 10:15     ` [PATCH] ASoC: wm8994: follow AIF clock source changes in MCLK gating Marek Szyprowski
  2026-10-22 13:10       ` Mark Brown
@ 2026-10-22 13:20       ` Mark Brown
  1 sibling, 0 replies; 11+ messages in thread
From: Mark Brown @ 2026-10-22 13:20 UTC (permalink / raw)
  To: patches, linux-sound, Marek Szyprowski
  Cc: Liam Girdwood, Sylwester Nawrocki, Charles Keepax,
	Krzysztof Kozlowski, Artur Weber

On Thu, 22 Oct 2026 12:15:28 +0200, Marek Szyprowski wrote:
> ASoC: wm8994: follow AIF clock source changes in MCLK gating

Applied to

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

Thanks!

[1/1] ASoC: wm8994: follow AIF clock source changes in MCLK gating
      https://git.kernel.org/broonie/sound/c/8731e33a3b98

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] 11+ messages in thread

end of thread, other threads:[~2026-10-22 15:00 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <CGME20261022074752eucas1p20373b227c271ff18c3207b7f67ff3c2c@eucas1p2.samsung.com>
2026-10-22  7:47 ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Marek Szyprowski
2026-10-22  7:47   ` [PATCH v2 1/4] ASoC: wm8994: fix MCLK gating for AIF clocks sourced from MCLK2 Marek Szyprowski
2026-10-22  9:38     ` Charles Keepax
2026-10-22  7:47   ` [PATCH v2 2/4] ASoC: wm8994: don't lose the AIF clock ratio when staying at 32kHz SYSCLK Marek Szyprowski
2026-10-22  7:47   ` [PATCH v2 3/4] ASoC: wm8994: fix MCLK index used for setting MCLK rate Marek Szyprowski
2026-10-22  7:47   ` [PATCH v2 4/4] ASoC: samsung: midas_wm1811: run FLL1 at the AIF1 configured rate when idle Marek Szyprowski
2026-10-22 10:03   ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Mark Brown
2026-10-22 10:15     ` [PATCH] ASoC: wm8994: follow AIF clock source changes in MCLK gating Marek Szyprowski
2026-10-22 13:10       ` Mark Brown
2026-10-22 13:20       ` Mark Brown
2026-10-22 10:17     ` [PATCH v2 0/4] ASoC: wm8994/midas_wm1811: fix codec clocking issues Marek Szyprowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox