ASoC: fsl_sai: add several improvements

Merge series from Shengjiu Wang <shengjiu.wang@nxp.com>:

Add several improvements for the sai interface.
1.allow to set mclk rate with zero clk_id for master mode
2.add xlate_tdm_slot_mask() callback to avoid channel constrain
3.separate 'is_dsp_mode' for tx and rx
4.separate set_tdm_slot() for tx and rx
This commit is contained in:
Mark Brown
2025-04-08 10:25:16 +01:00
2 changed files with 65 additions and 31 deletions

View File

@@ -163,17 +163,49 @@ 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)
{
/* 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)
{
@@ -238,22 +270,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);
@@ -280,7 +312,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:
@@ -309,7 +341,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:
/*
@@ -317,7 +349,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;
@@ -541,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;
@@ -600,7 +632,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);
@@ -932,7 +964,8 @@ 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,
.trigger = fsl_sai_trigger,
@@ -944,7 +977,8 @@ 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,
.trigger = fsl_sai_trigger,

View File

@@ -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];
@@ -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;