From 78b3bcfd5697f486946f559f56dbf78c30e22f27 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 28 Mar 2025 16:57:41 +0800 Subject: [PATCH 1/4] ASoC: fsl_sai: allow to set mclk rate with zero clk_id If clk_id is zero, it means FSL_SAI_CLK_BUS in fsl_sai_set_dai_sysclk(), as the clk[FSL_SAI_CLK_BUS]'s rate can't be changed, there is no rate changed for mclk. But with audio-graph-card, the clk_id is always zero, in order to allow to set mclk rate with zero clk_id, update the condition to be if clk_id is zero, then set the FSL_SAI_CLK_MAST1's rate. This would not change the original function for master mode. Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20250328085744.1893434-2-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index ed2b4780c470..bcb46a0b5e68 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -238,22 +238,22 @@ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, if (dir == SND_SOC_CLOCK_IN) return 0; - if (freq > 0 && clk_id != FSL_SAI_CLK_BUS) { - if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) { - dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id); - return -EINVAL; - } + if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) { + dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id); + return -EINVAL; + } - if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) { - dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id); - return -EINVAL; - } + if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) { + dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id); + return -EINVAL; + } - if (sai->mclk_streams == 0) { - ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq); - if (ret < 0) - return ret; - } + if (sai->mclk_streams == 0 && freq > 0) { + ret = fsl_sai_set_mclk_rate(cpu_dai, + clk_id ? clk_id : FSL_SAI_CLK_MAST1, + freq); + if (ret < 0) + return ret; } ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, true); From 4fe9d03b48cce3edb679ce1f404f19d242537a66 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 28 Mar 2025 16:57:42 +0800 Subject: [PATCH 2/4] ASoC: fsl_sai: add xlate_tdm_slot_mask() callback With DPCM case, for example ASRC->SAI->AMIX, the SAI can be codec dai device in backend, but __soc_pcm_hw_params() will get the tdm_mask for channel constraint, tdm_mask is set by snd_soc_dai_set_tdm_slot() from slot number, but SAI supports flexible channel number with fixed slot number, so add an empty xlate_tdm_slot_mask() callback to avoid the channel constraint in __soc_pcm_hw_params(). Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20250328085744.1893434-3-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index bcb46a0b5e68..9a450fc86dba 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -174,6 +174,13 @@ static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, return 0; } +static int fsl_sai_xlate_tdm_slot_mask(unsigned int slots, + unsigned int *tx_mask, unsigned int *rx_mask) +{ + /* Leave it empty, don't change the value of tx_mask and rx_mask */ + return 0; +} + static int fsl_sai_set_dai_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) { @@ -933,6 +940,7 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_tx_ops = { .set_sysclk = fsl_sai_set_dai_sysclk, .set_fmt = fsl_sai_set_dai_fmt_tx, .set_tdm_slot = fsl_sai_set_dai_tdm_slot, + .xlate_tdm_slot_mask = fsl_sai_xlate_tdm_slot_mask, .hw_params = fsl_sai_hw_params, .hw_free = fsl_sai_hw_free, .trigger = fsl_sai_trigger, @@ -945,6 +953,7 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_rx_ops = { .set_sysclk = fsl_sai_set_dai_sysclk, .set_fmt = fsl_sai_set_dai_fmt_rx, .set_tdm_slot = fsl_sai_set_dai_tdm_slot, + .xlate_tdm_slot_mask = fsl_sai_xlate_tdm_slot_mask, .hw_params = fsl_sai_hw_params, .hw_free = fsl_sai_hw_free, .trigger = fsl_sai_trigger, From e4b543d51ef1e723bde12d160121b7358a005b4f Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 28 Mar 2025 16:57:43 +0800 Subject: [PATCH 3/4] ASoC: fsl_sai: separate 'is_dsp_mode' for tx and rx The transmitter and receiver of SAI can be used for different dsp modes, then 'is_dsp_mode' needs to be separated. Expand 'is_dsp_mode' to array 'is_dsp_mode[]' to support different configuration of tx and rx. Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20250328085744.1893434-4-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 8 ++++---- sound/soc/fsl/fsl_sai.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 9a450fc86dba..09054e339b31 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -287,7 +287,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, val_cr4 |= FSL_SAI_CR4_MF; sai->is_pdm_mode = false; - sai->is_dsp_mode = false; + sai->is_dsp_mode[tx] = false; /* DAI mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -316,7 +316,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, */ val_cr2 |= FSL_SAI_CR2_BCP; val_cr4 |= FSL_SAI_CR4_FSE; - sai->is_dsp_mode = true; + sai->is_dsp_mode[tx] = true; break; case SND_SOC_DAIFMT_DSP_B: /* @@ -324,7 +324,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, * frame sync asserts with the first bit of the frame. */ val_cr2 |= FSL_SAI_CR2_BCP; - sai->is_dsp_mode = true; + sai->is_dsp_mode[tx] = true; break; case SND_SOC_DAIFMT_PDM: val_cr2 |= FSL_SAI_CR2_BCP; @@ -607,7 +607,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, } } - if (!sai->is_dsp_mode && !sai->is_pdm_mode) + if (!sai->is_dsp_mode[tx] && !sai->is_pdm_mode) val_cr4 |= FSL_SAI_CR4_SYWD(slot_width); val_cr5 |= FSL_SAI_CR5_WNW(slot_width); diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 0e25e2fc7ce0..3f9357da0d8f 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -286,7 +286,7 @@ struct fsl_sai { bool is_consumer_mode[2]; bool is_lsb_first; - bool is_dsp_mode; + bool is_dsp_mode[2]; bool is_pdm_mode; bool is_multi_fifo_dma; bool synchronous[2]; From 1d9119794c10023ebd7c901aa9aa2c74eb833177 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 28 Mar 2025 16:57:44 +0800 Subject: [PATCH 4/4] ASoC: fsl_sai: separate set_tdm_slot() for tx and rx The transmitter and receiver of SAI can be used for different slot number and slot width configuration, so refine fsl_sai_set_dai_tdm_slot(), add fsl_sai_set_dai_tdm_slot_tx() for tx and fsl_sai_set_dai_tdm_slot_rx() for rx. Signed-off-by: Shengjiu Wang Link: https://patch.msgid.link/20250328085744.1893434-5-shengjiu.wang@nxp.com Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_sai.c | 45 ++++++++++++++++++++++++++++++++--------- sound/soc/fsl/fsl_sai.h | 4 ++-- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 09054e339b31..af1a168d35e3 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -163,17 +163,42 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) return iret; } -static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, - u32 rx_mask, int slots, int slot_width) +static int fsl_sai_set_dai_tdm_slot_tx(struct snd_soc_dai *cpu_dai, u32 tx_mask, + u32 rx_mask, int slots, int slot_width) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + bool tx = true; - sai->slots = slots; - sai->slot_width = slot_width; + sai->slots[tx] = slots; + sai->slot_width[tx] = slot_width; return 0; } +static int fsl_sai_set_dai_tdm_slot_rx(struct snd_soc_dai *cpu_dai, u32 tx_mask, + u32 rx_mask, int slots, int slot_width) +{ + struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + bool tx = false; + + sai->slots[tx] = slots; + sai->slot_width[tx] = slot_width; + + return 0; +} + +static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, + u32 rx_mask, int slots, int slot_width) +{ + int ret; + + ret = fsl_sai_set_dai_tdm_slot_tx(cpu_dai, tx_mask, rx_mask, slots, slot_width); + if (ret) + return ret; + + return fsl_sai_set_dai_tdm_slot_rx(cpu_dai, tx_mask, rx_mask, slots, slot_width); +} + static int fsl_sai_xlate_tdm_slot_mask(unsigned int slots, unsigned int *tx_mask, unsigned int *rx_mask) { @@ -548,11 +573,11 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, u32 watermark; int ret, i; - if (sai->slot_width) - slot_width = sai->slot_width; + if (sai->slot_width[tx]) + slot_width = sai->slot_width[tx]; - if (sai->slots) - slots = sai->slots; + if (sai->slots[tx]) + slots = sai->slots[tx]; else if (sai->bclk_ratio) slots = sai->bclk_ratio / slot_width; @@ -939,7 +964,7 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_tx_ops = { .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, .set_sysclk = fsl_sai_set_dai_sysclk, .set_fmt = fsl_sai_set_dai_fmt_tx, - .set_tdm_slot = fsl_sai_set_dai_tdm_slot, + .set_tdm_slot = fsl_sai_set_dai_tdm_slot_tx, .xlate_tdm_slot_mask = fsl_sai_xlate_tdm_slot_mask, .hw_params = fsl_sai_hw_params, .hw_free = fsl_sai_hw_free, @@ -952,7 +977,7 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_rx_ops = { .set_bclk_ratio = fsl_sai_set_dai_bclk_ratio, .set_sysclk = fsl_sai_set_dai_sysclk, .set_fmt = fsl_sai_set_dai_fmt_rx, - .set_tdm_slot = fsl_sai_set_dai_tdm_slot, + .set_tdm_slot = fsl_sai_set_dai_tdm_slot_rx, .xlate_tdm_slot_mask = fsl_sai_xlate_tdm_slot_mask, .hw_params = fsl_sai_hw_params, .hw_free = fsl_sai_hw_free, diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 3f9357da0d8f..6c917f79c6b0 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -296,8 +296,8 @@ struct fsl_sai { unsigned int mclk_id[2]; unsigned int mclk_streams; - unsigned int slots; - unsigned int slot_width; + unsigned int slots[2]; + unsigned int slot_width[2]; unsigned int bclk_ratio; const struct fsl_sai_soc_data *soc_data;