sound/soc/codecs/wm8978.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
In previous WM8978 codec driver versions, wm8978_set_dai_clkdiv
might not have been called for BCLK, leaving the bit clock
divider unconfigured. This could cause incorrect or unstable audio
clocks depending on sample rate and word length.
This patch adds a check in wm8978_hw_params: if the BCLK divider
has not been set via wm8978_set_dai_clkdiv, it is dynamically
calculated and configured at runtime.
This ensures that BCLK is always correctly set, whether the
machine driver configures it explicitly or not.
Apart from this core patch, due to request from Mark Brown and
Charles Keepax. Overclock BCLK setup is applied, and dropped the
possible lowest error BCLK result. On top of the overclocking,
warning message is given to user as a reminding.
This patch author do not agree with this design nor
concept from first place!
Signed-off-by: Brian Sune <briansune@gmail.com>
---
sound/soc/codecs/wm8978.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index 8c45ba6fc4c3..d894d1cda326 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -99,6 +99,7 @@ struct wm8978_priv {
unsigned int f_mclk;
unsigned int f_256fs;
unsigned int f_opclk;
+ bool bclk_set;
int mclk_idx;
enum wm8978_sysclk_src sysclk;
};
@@ -590,6 +591,7 @@ static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
case WM8978_BCLKDIV:
if (div & ~0x1c)
return -EINVAL;
+ wm8978->bclk_set = true;
snd_soc_component_update_bits(component, WM8978_CLOCKING, 0x1c, div);
break;
default:
@@ -717,6 +719,11 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
+ unsigned int bclk, bclkdiv = 0, min_diff = UINT_MAX;
+ unsigned int target_bclk = params_rate(params) * params_width(params) * 2;
+ /* WM8978 supports divisors */
+ static const int bclk_divs[] = {1, 2, 4, 8, 16, 32};
+
struct snd_soc_component *component = dai->component;
struct wm8978_priv *wm8978 = snd_soc_component_get_drvdata(component);
/* Word length mask = 0x60 */
@@ -820,6 +827,31 @@ static int wm8978_hw_params(struct snd_pcm_substream *substream,
/* MCLK divisor mask = 0xe0 */
snd_soc_component_update_bits(component, WM8978_CLOCKING, 0xe0, best << 5);
+ if (!wm8978->bclk_set) {
+ for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
+ bclk = wm8978->f_256fs / bclk_divs[i];
+
+ if (bclk < target_bclk) {
+ dev_warn(component->dev,
+ "Auto BCLK cannot fit, BCLK using: #%u\n",
+ wm8978->f_256fs / bclk_divs[bclkdiv]);
+ break;
+ }
+
+ if (abs(bclk - target_bclk) < min_diff) {
+ min_diff = abs(bclk - target_bclk);
+ bclkdiv = i;
+ }
+ }
+
+ dev_dbg(component->dev, "%s: fs=%u width=%u -> target BCLK=%u, using div #%u\n",
+ __func__, params_rate(params), params_width(params), target_bclk,
+ bclk_divs[bclkdiv]);
+
+ /* BCLKDIV divisor mask = 0x1c */
+ snd_soc_component_update_bits(component, WM8978_CLOCKING, 0x1c, bclkdiv << 2);
+ }
+
snd_soc_component_write(component, WM8978_AUDIO_INTERFACE, iface_ctl);
snd_soc_component_write(component, WM8978_ADDITIONAL_CONTROL, add_ctl);
--
2.47.1.windows.1
On 08/10/2025 5:04 pm, Brian Sune wrote: > In previous WM8978 codec driver versions, wm8978_set_dai_clkdiv > might not have been called for BCLK, leaving the bit clock > divider unconfigured. This could cause incorrect or unstable audio > clocks depending on sample rate and word length. > > This patch adds a check in wm8978_hw_params: if the BCLK divider > has not been set via wm8978_set_dai_clkdiv, it is dynamically > calculated and configured at runtime. > This ensures that BCLK is always correctly set, whether the > machine driver configures it explicitly or not. > > Apart from this core patch, due to request from Mark Brown and > Charles Keepax. Overclock BCLK setup is applied, and dropped the > possible lowest error BCLK result. Selecting a lowest-error rate is not valid I2S. You must have enough BCLK cycles to send all the data. If number of BCLK cycles < number of sample bits you cannot send all the sample bits. So that would be an incorrect setup. > On top of the overclocking, Using a higher BCLK is valid I2S. In fact, it is exactly defined in the I2S specification that there can be more BCLK cycles than data bits and the RX end should ignore extra cycles. > warning message is given to user as a reminding. Warning the user that you selected the correct BCLK is strange. > This patch author do not agree with this design nor > concept from first place! For example if you are sending stereo 16-bit samples at 48 kHz you must have a BCLK at least 48000 * 16 * 2 = 1536000 Hz. If the _nearest_ BCLK is < 1536000 you don't have enough clock cycles to send all the sample bits.
Richard Fitzgerald <rf@opensource.cirrus.com> 於 2025年10月9日 週四 上午12:27寫道: > If the _nearest_ BCLK is < 1536000 you don't have enough clock > cycles to send all the sample bits. If the inherent design follows the original concept of i.e. IIS. Then the comment of not enough clock cycles to send all sample bits won't even exist. MCLK -> BCLK -> LRCLK. LRCLK is always subject to BCLK by channel # and data_bits. As for the BCLK is always subject to MCLK and oversample requirement or codec design. w/o MCLK rooms you cant do BCLK w/o BCLK rooms you cant do LRCLK. LRCLK itself is always subject to the original clock frequency. This is why there are no possible idea on not enough clock for bit load. BCLK divided by channel * data bits itself must be hold. Hence the result LRCLK aka final S.R. sample rate either is fasted or slowed is what it is. As there are no possible way to generate a incorrect divided result when mclk is not supported by some S.R. Then only result is S.R. is slowed or fasted based on the BCLK but not because you are targeting a S.R. aka LRCLK. Which result in BCLK is required to be faster.
Richard Fitzgerald <rf@opensource.cirrus.com> 於 2025年10月9日 週四 上午12:27寫道: > Selecting a lowest-error rate is not valid I2S. > You must have enough BCLK cycles to send all the data. If number > of BCLK cycles < number of sample bits you cannot send all the > sample bits. So that would be an incorrect setup. You had completely misunderstood my inherent idea. What Mark is arguing is about the same as you proposing. The idea from my side is that if you target 44.1K then the lowest error rate can only do 44k then both LRCLK and BCLK are follows. Both bit and clock are divided accordingly > > > On top of the overclocking, > > Using a higher BCLK is valid I2S. In fact, it is exactly defined in the > I2S specification that there can be more BCLK cycles than data bits > and the RX end should ignore extra cycles. Again, this idea is completely incorrect from first place. There are codec allow to do so doesn't mean this is IIS standard. Again if this idea holds then why not simply use a faster clock at anytime? Then this patch also make no sense from beginning. BCLK faster will always be okay, why setup the register then? > > warning message is given to user as a reminding. > > Warning the user that you selected the correct BCLK is strange. Warning message is based on what you are trying to setup on the codec. if the background is based on mclk is fixed and bclk and lrclk is divided from mclk. Where bclk is follows lrclk to commit the final closest audio S.R. I.E. 44k1 48k etc. other than that if the setup can only make closest result. BCLK is fasted and LRCLK = BCLK/32/2 then the result of cause is not fit. > > This patch author do not agree with this design nor > > concept from first place! > > For example if you are sending stereo 16-bit samples at 48 kHz you must > have a BCLK at least 48000 * 16 * 2 = 1536000 Hz. > > If the _nearest_ BCLK is < 1536000 you don't have enough clock > cycles to send all the sample bits. Again from the very beginning comment BCLK / channel / data_bits result in a slower S.R. aka LRCLK then of cause it is not fit. Brian
© 2016 - 2026 Red Hat, Inc.