[PATCH 3/5] ASoC: fsl-asoc-card: add channel and rate constraints for CS42888

Shengjiu Wang shengjiu.wang at nxp.com
Fri Apr 24 20:38:04 AEST 2026


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 at nxp.com>
---
 sound/soc/fsl/fsl-asoc-card.c | 67 +++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index e08e135886f7..50d7a5f2d79e 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -40,6 +40,18 @@
 /* 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,
+};
+
 /**
  * struct codec_priv - CODEC private data
  * @mclk: Main clock of the CODEC
@@ -93,6 +105,10 @@ struct cpu_priv {
  * @asrc_rate: ASRC sample rate used by Back-Ends
  * @asrc_format: ASRC sample format used by Back-Ends
  * @dai_fmt: DAI format between CPU and CODEC
+ * @support_rates: array of supported rates
+ * @support_channels: array of supported channels
+ * @num_rates: Number of entries in support_rates array
+ * @num_channels: Number of entries in support_channels array
  * @name: Card name
  */
 
@@ -110,6 +126,10 @@ struct fsl_asoc_card_priv {
 	u32 asrc_rate;
 	snd_pcm_format_t asrc_format;
 	u32 dai_fmt;
+	const u32 *support_rates;
+	const u32 *support_channels;
+	u32 num_rates;
+	u32 num_channels;
 	char name[32];
 };
 
@@ -291,7 +311,41 @@ 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;
+	static struct snd_pcm_hw_constraint_list constraint_rates;
+	static struct snd_pcm_hw_constraint_list constraint_channels;
+	int ret;
+
+	constraint_channels.list = priv->support_channels;
+	constraint_channels.count = priv->num_channels;
+	constraint_rates.list = priv->support_rates;
+	constraint_rates.count = priv->num_rates;
+
+	if (constraint_channels.count) {
+		ret = snd_pcm_hw_constraint_list(runtime, 0,
+						 SNDRV_PCM_HW_PARAM_CHANNELS,
+						 &constraint_channels);
+		if (ret)
+			return ret;
+	}
+
+	if (constraint_rates.count) {
+		ret = snd_pcm_hw_constraint_list(runtime, 0,
+						 SNDRV_PCM_HW_PARAM_RATE,
+						 &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 +807,19 @@ 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->support_channels = cs42888_channels;
+		priv->num_channels = ARRAY_SIZE(cs42888_channels);
+		if (priv->codec_priv[0].mclk_freq % 12288000 == 0) {
+			priv->support_rates = cs42888_rates_48k;
+			priv->num_rates = ARRAY_SIZE(cs42888_rates_48k);
+		} else if (priv->codec_priv[0].mclk_freq % 11289600 == 0) {
+			priv->support_rates = cs42888_rates_44k;
+			priv->num_rates = ARRAY_SIZE(cs42888_rates_44k);
+		} else {
+			/* Unknown MCLK, no rate constraints */
+			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



More information about the Linuxppc-dev mailing list