Skip to content

Commit

Permalink
ASoC: fsl_sai: Add separate DAI for transmitter and receiver
Browse files Browse the repository at this point in the history
The transmitter and receiver part of the SAI interface need to be
configured with different master/slave mode, especially to work
with the audiomix module.

+-------+               +-----------+
| SAI1  |   --TX-->     |           |
|       |   <--RX--     |           |
+-------+               |           |
                        | AUDIOMIX  |
+-------+               |           |
| SAI2  |   --TX-->     |           |
+-------+               +-----------+

The SAI1 TX is in master mode, but SAI1 RX is in slave mode.
So add another two DAIs for TX and RX separately. but only
defined fsl_sai_set_dai_fmt_tx() and fsl_sai_set_dai_fmt_rx()
ops function for current case, in the future, the other ops
function for TX and RX can be defined if required.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Link: https://patch.msgid.link/1718174452-17596-2-git-send-email-shengjiu.wang@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
Shengjiu Wang authored and Mark Brown committed Jun 26, 2024
1 parent 727de4f commit 15c9583
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 41 deletions.
141 changes: 102 additions & 39 deletions sound/soc/fsl/fsl_sai.c
Original file line number Diff line number Diff line change
Expand Up @@ -357,18 +357,18 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
case SND_SOC_DAIFMT_BP_FP:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
sai->is_consumer_mode = false;
sai->is_consumer_mode[tx] = false;
break;
case SND_SOC_DAIFMT_BC_FC:
sai->is_consumer_mode = true;
sai->is_consumer_mode[tx] = true;
break;
case SND_SOC_DAIFMT_BP_FC:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
sai->is_consumer_mode = false;
sai->is_consumer_mode[tx] = false;
break;
case SND_SOC_DAIFMT_BC_FP:
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
sai->is_consumer_mode = true;
sai->is_consumer_mode[tx] = true;
break;
default:
return -EINVAL;
Expand Down Expand Up @@ -400,6 +400,16 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
return ret;
}

static int fsl_sai_set_dai_fmt_tx(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, true);
}

static int fsl_sai_set_dai_fmt_rx(struct snd_soc_dai *cpu_dai, unsigned int fmt)
{
return fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, false);
}

static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
Expand All @@ -412,7 +422,7 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
bool support_1_1_ratio = sai->verid.version >= 0x0301;

/* Don't apply to consumer mode */
if (sai->is_consumer_mode)
if (sai->is_consumer_mode[tx])
return 0;

/*
Expand Down Expand Up @@ -575,7 +585,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
}
}

if (!sai->is_consumer_mode) {
if (!sai->is_consumer_mode[tx]) {
ret = fsl_sai_set_bclk(cpu_dai, tx, bclk);
if (ret)
return ret;
Expand Down Expand Up @@ -613,7 +623,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
* RCR5(TCR5) for playback(capture), or there will be sync error.
*/

if (!sai->is_consumer_mode && fsl_sai_dir_is_synced(sai, adir)) {
if (!sai->is_consumer_mode[tx] && fsl_sai_dir_is_synced(sai, adir)) {
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs),
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
FSL_SAI_CR4_CHMOD_MASK,
Expand Down Expand Up @@ -683,7 +693,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
* FSD_MSTR bit for this specific case.
*/
if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output &&
!sai->is_consumer_mode)
!sai->is_consumer_mode[tx])
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
FSL_SAI_CR4_FSD_MSTR, 0);

Expand All @@ -697,7 +707,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,

/* Enable FSD_MSTR after configuring word width */
if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output &&
!sai->is_consumer_mode)
!sai->is_consumer_mode[tx])
regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR);

Expand All @@ -720,8 +730,8 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
FSL_SAI_CR3_TRCE_MASK, 0);

if (!sai->is_consumer_mode &&
sai->mclk_streams & BIT(substream->stream)) {
if (!sai->is_consumer_mode[tx] &&
sai->mclk_streams & BIT(substream->stream)) {
clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]);
sai->mclk_streams &= ~BIT(substream->stream);
}
Expand Down Expand Up @@ -759,7 +769,7 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir)
* This is a hardware bug, and will be fix in the
* next sai version.
*/
if (!sai->is_consumer_mode) {
if (!sai->is_consumer_mode[tx]) {
/* Software Reset */
regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR);
/* Clear SR bit to finish the reset */
Expand Down Expand Up @@ -914,6 +924,30 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
.startup = fsl_sai_startup,
};

static const struct snd_soc_dai_ops fsl_sai_pcm_dai_tx_ops = {
.probe = fsl_sai_dai_probe,
.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,
.hw_params = fsl_sai_hw_params,
.hw_free = fsl_sai_hw_free,
.trigger = fsl_sai_trigger,
.startup = fsl_sai_startup,
};

static const struct snd_soc_dai_ops fsl_sai_pcm_dai_rx_ops = {
.probe = fsl_sai_dai_probe,
.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,
.hw_params = fsl_sai_hw_params,
.hw_free = fsl_sai_hw_free,
.trigger = fsl_sai_trigger,
.startup = fsl_sai_startup,
};

static int fsl_sai_dai_resume(struct snd_soc_component *component)
{
struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
Expand All @@ -931,26 +965,55 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component)
return 0;
}

static struct snd_soc_dai_driver fsl_sai_dai_template = {
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
.channels_max = 32,
.rate_min = 8000,
.rate_max = 2822400,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_SAI_FORMATS,
static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
{
.name = "sai-tx-rx",
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
.channels_max = 32,
.rate_min = 8000,
.rate_max = 2822400,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_SAI_FORMATS,
},
.capture = {
.stream_name = "CPU-Capture",
.channels_min = 1,
.channels_max = 32,
.rate_min = 8000,
.rate_max = 2822400,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_SAI_FORMATS,
},
.ops = &fsl_sai_pcm_dai_ops,
},
{
.name = "sai-tx",
.playback = {
.stream_name = "CPU-Playback",
.channels_min = 1,
.channels_max = 32,
.rate_min = 8000,
.rate_max = 2822400,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_SAI_FORMATS,
},
.ops = &fsl_sai_pcm_dai_tx_ops,
},
.capture = {
.stream_name = "CPU-Capture",
.channels_min = 1,
.channels_max = 32,
.rate_min = 8000,
.rate_max = 2822400,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_SAI_FORMATS,
{
.name = "sai-rx",
.capture = {
.stream_name = "CPU-Capture",
.channels_min = 1,
.channels_max = 32,
.rate_min = 8000,
.rate_max = 2822400,
.rates = SNDRV_PCM_RATE_KNOT,
.formats = FSL_SAI_FORMATS,
},
.ops = &fsl_sai_pcm_dai_rx_ops,
},
.ops = &fsl_sai_pcm_dai_ops,
};

static const struct snd_soc_component_driver fsl_component = {
Expand Down Expand Up @@ -1399,15 +1462,15 @@ static int fsl_sai_probe(struct platform_device *pdev)
return ret;
}

memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template,
sizeof(fsl_sai_dai_template));
memcpy(&sai->cpu_dai_drv, fsl_sai_dai_template,
sizeof(*fsl_sai_dai_template) * ARRAY_SIZE(fsl_sai_dai_template));

/* Sync Tx with Rx as default by following old DT binding */
sai->synchronous[RX] = true;
sai->synchronous[TX] = false;
sai->cpu_dai_drv.symmetric_rate = 1;
sai->cpu_dai_drv.symmetric_channels = 1;
sai->cpu_dai_drv.symmetric_sample_bits = 1;
sai->cpu_dai_drv[0].symmetric_rate = 1;
sai->cpu_dai_drv[0].symmetric_channels = 1;
sai->cpu_dai_drv[0].symmetric_sample_bits = 1;

if (of_property_read_bool(np, "fsl,sai-synchronous-rx") &&
of_property_read_bool(np, "fsl,sai-asynchronous")) {
Expand All @@ -1424,9 +1487,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
/* Discard all settings for asynchronous mode */
sai->synchronous[RX] = false;
sai->synchronous[TX] = false;
sai->cpu_dai_drv.symmetric_rate = 0;
sai->cpu_dai_drv.symmetric_channels = 0;
sai->cpu_dai_drv.symmetric_sample_bits = 0;
sai->cpu_dai_drv[0].symmetric_rate = 0;
sai->cpu_dai_drv[0].symmetric_channels = 0;
sai->cpu_dai_drv[0].symmetric_sample_bits = 0;
}

sai->mclk_direction_output = of_property_read_bool(np, "fsl,sai-mclk-direction-output");
Expand Down Expand Up @@ -1505,7 +1568,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
}

ret = devm_snd_soc_register_component(dev, &fsl_component,
&sai->cpu_dai_drv, 1);
sai->cpu_dai_drv, ARRAY_SIZE(fsl_sai_dai_template));
if (ret)
goto err_pm_get_sync;

Expand Down
4 changes: 2 additions & 2 deletions sound/soc/fsl/fsl_sai.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ struct fsl_sai {
struct clk *pll11k_clk;
struct resource *res;

bool is_consumer_mode;
bool is_consumer_mode[2];
bool is_lsb_first;
bool is_dsp_mode;
bool is_pdm_mode;
Expand All @@ -299,7 +299,7 @@ struct fsl_sai {
unsigned int bclk_ratio;

const struct fsl_sai_soc_data *soc_data;
struct snd_soc_dai_driver cpu_dai_drv;
struct snd_soc_dai_driver cpu_dai_drv[3];
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
struct fsl_sai_verid verid;
Expand Down

0 comments on commit 15c9583

Please sign in to comment.