LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Shengjiu Wang <shengjiu.wang@nxp.com>
To: shengjiu.wang@gmail.com, Xiubo.Lee@gmail.com, festevam@gmail.com,
	nicoleotsuka@gmail.com, lgirdwood@gmail.com, broonie@kernel.org,
	perex@perex.cz, tiwai@suse.com, linux-sound@vger.kernel.org,
	linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org
Subject: [PATCH v2 3/5] ASoC: fsl-asoc-card: add channel and rate constraints for CS42888
Date: Wed, 29 Apr 2026 18:00:25 +0800	[thread overview]
Message-ID: <20260429100028.2739711-4-shengjiu.wang@nxp.com> (raw)
In-Reply-To: <20260429100028.2739711-1-shengjiu.wang@nxp.com>

The CS42888 codec has 4 I2S lanes with 2 channels per lane. Using odd
channel counts (3, 5, 7) causes data misalignment in the I2S frame,
resulting in incorrect channel mapping. Only mono and even channel
counts (1, 2, 4, 6, 8) work correctly.

Additionally, the fixed system clock on i.MX platforms limits supported
sample rates. With 12.288 MHz MCLK, only 48kHz family rates (48k, 96k,
192k) achieve valid MCLK:LRCK ratios. With 11.2896 MHz MCLK, only 44k
family rates are supported.

Add a startup callback to apply PCM constraints for both channels and
rates, preventing userspace from requesting unsupported configurations.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
---
 sound/soc/fsl/fsl-asoc-card.c | 71 +++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index e08e135886f7..90414ac10032 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -40,6 +40,33 @@
 /* Default DAI format without Master and Slave flag */
 #define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF)
 
+static const u32 cs42888_rates_48k[] = {
+	48000, 96000, 192000,
+};
+
+static const u32 cs42888_rates_44k[] = {
+	44100, 88200, 176400,
+};
+
+static const u32 cs42888_channels[] = {
+	1, 2, 4, 6, 8,
+};
+
+static const struct snd_pcm_hw_constraint_list cs42888_rate_48k_constraints = {
+	.list = cs42888_rates_48k,
+	.count = ARRAY_SIZE(cs42888_rates_48k),
+};
+
+static const struct snd_pcm_hw_constraint_list cs42888_rate_44k_constraints = {
+	.list = cs42888_rates_44k,
+	.count = ARRAY_SIZE(cs42888_rates_44k),
+};
+
+static const struct snd_pcm_hw_constraint_list cs42888_channel_constraints = {
+	.list = cs42888_channels,
+	.count = ARRAY_SIZE(cs42888_channels),
+};
+
 /**
  * struct codec_priv - CODEC private data
  * @mclk: Main clock of the CODEC
@@ -87,6 +114,8 @@ struct cpu_priv {
  * @codec_priv: CODEC private data
  * @cpu_priv: CPU private data
  * @card: ASoC card structure
+ * @constraint_rates: array of supported rates
+ * @constraint_channels: array of supported channels
  * @streams: Mask of current active streams
  * @sample_rate: Current sample rate
  * @sample_format: Current sample format
@@ -104,6 +133,8 @@ struct fsl_asoc_card_priv {
 	struct codec_priv codec_priv[2];
 	struct cpu_priv cpu_priv;
 	struct snd_soc_card card;
+	const struct snd_pcm_hw_constraint_list *constraint_rates;
+	const struct snd_pcm_hw_constraint_list *constraint_channels;
 	u8 streams;
 	u32 sample_rate;
 	snd_pcm_format_t sample_format;
@@ -291,7 +322,39 @@ static int fsl_asoc_card_hw_free(struct snd_pcm_substream *substream)
 	return 0;
 }
 
+static int fsl_asoc_card_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int ret;
+
+	if (priv->constraint_channels) {
+		ret = snd_pcm_hw_constraint_list(runtime, 0,
+						 SNDRV_PCM_HW_PARAM_CHANNELS,
+						 priv->constraint_channels);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * Apply rate constraints only to frontend DAI links (no_pcm = 0).
+	 * Skip DPCM backend (no_pcm = 1) as rate is fixed by be_hw_params_fixup()
+	 * and ASRC frontend handles rate conversion.
+	 */
+	if (priv->constraint_rates && !rtd->dai_link->no_pcm) {
+		ret = snd_pcm_hw_constraint_list(runtime, 0,
+						 SNDRV_PCM_HW_PARAM_RATE,
+						 priv->constraint_rates);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static const struct snd_soc_ops fsl_asoc_card_ops = {
+	.startup = fsl_asoc_card_startup,
 	.hw_params = fsl_asoc_card_hw_params,
 	.hw_free = fsl_asoc_card_hw_free,
 };
@@ -753,6 +816,14 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
 		priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
 		priv->cpu_priv.slot_width = 32;
 		priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC;
+		priv->constraint_channels = &cs42888_channel_constraints;
+		if (priv->codec_priv[0].mclk_freq % 12288000 == 0)
+			priv->constraint_rates  = &cs42888_rate_48k_constraints;
+		else if (priv->codec_priv[0].mclk_freq % 11289600 == 0)
+			priv->constraint_rates = &cs42888_rate_44k_constraints;
+		else
+			dev_warn(&pdev->dev, "Unknown MCLK frequency %lu, no rate constraints\n",
+				 priv->codec_priv[0].mclk_freq);
 	} else if (of_device_is_compatible(np, "fsl,imx-audio-cs427x")) {
 		codec_dai_name[0] = "cs4271-hifi";
 		priv->codec_priv[0].mclk_id = CS427x_SYSCLK_MCLK;
-- 
2.34.1



  parent reply	other threads:[~2026-04-29  9:59 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-29 10:00 [PATCH v2 0/5] ASoC: fsl-asoc-card: Add some improvements Shengjiu Wang
2026-04-29 10:00 ` [PATCH v2 1/5] ASoC: fsl-asoc-card: enable dpcm_merged_chan flag for ASRC frontend Shengjiu Wang
2026-04-29 10:00 ` [PATCH v2 2/5] ASoC: fsl-asoc-card: enable ignore_pmdown_time for ASRC case Shengjiu Wang
2026-04-29 10:00 ` Shengjiu Wang [this message]
2026-04-29 10:00 ` [PATCH v2 4/5] ASoC: fsl-asoc-card: exclude S20_3LE format for WM8960/WM8962 + SAI Shengjiu Wang
2026-04-29 10:00 ` [PATCH v2 5/5] ASoC: fsl-asoc-card: reduce WM8904 PLL ratio to meet frequency limit Shengjiu Wang
2026-04-30 12:08 ` [PATCH v2 0/5] ASoC: fsl-asoc-card: Add some improvements 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=20260429100028.2739711-4-shengjiu.wang@nxp.com \
    --to=shengjiu.wang@nxp.com \
    --cc=Xiubo.Lee@gmail.com \
    --cc=broonie@kernel.org \
    --cc=festevam@gmail.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=nicoleotsuka@gmail.com \
    --cc=perex@perex.cz \
    --cc=shengjiu.wang@gmail.com \
    --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