Commit 15c95839 authored by Shengjiu Wang's avatar Shengjiu Wang Committed by Mark Brown

ASoC: fsl_sai: Add separate DAI for transmitter and receiver

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: default avatarShengjiu Wang <shengjiu.wang@nxp.com>
Link: https://patch.msgid.link/1718174452-17596-2-git-send-email-shengjiu.wang@nxp.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 727de4fb
...@@ -357,18 +357,18 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, ...@@ -357,18 +357,18 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
case SND_SOC_DAIFMT_BP_FP: case SND_SOC_DAIFMT_BP_FP:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR; val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
val_cr4 |= FSL_SAI_CR4_FSD_MSTR; val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
sai->is_consumer_mode = false; sai->is_consumer_mode[tx] = false;
break; break;
case SND_SOC_DAIFMT_BC_FC: case SND_SOC_DAIFMT_BC_FC:
sai->is_consumer_mode = true; sai->is_consumer_mode[tx] = true;
break; break;
case SND_SOC_DAIFMT_BP_FC: case SND_SOC_DAIFMT_BP_FC:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR; val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
sai->is_consumer_mode = false; sai->is_consumer_mode[tx] = false;
break; break;
case SND_SOC_DAIFMT_BC_FP: case SND_SOC_DAIFMT_BC_FP:
val_cr4 |= FSL_SAI_CR4_FSD_MSTR; val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
sai->is_consumer_mode = true; sai->is_consumer_mode[tx] = true;
break; break;
default: default:
return -EINVAL; return -EINVAL;
...@@ -400,6 +400,16 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) ...@@ -400,6 +400,16 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
return ret; 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) 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); struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
...@@ -412,7 +422,7 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) ...@@ -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; bool support_1_1_ratio = sai->verid.version >= 0x0301;
/* Don't apply to consumer mode */ /* Don't apply to consumer mode */
if (sai->is_consumer_mode) if (sai->is_consumer_mode[tx])
return 0; return 0;
/* /*
...@@ -575,7 +585,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, ...@@ -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); ret = fsl_sai_set_bclk(cpu_dai, tx, bclk);
if (ret) if (ret)
return ret; return ret;
...@@ -613,7 +623,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, ...@@ -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. * 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), regmap_update_bits(sai->regmap, FSL_SAI_xCR4(!tx, ofs),
FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK |
FSL_SAI_CR4_CHMOD_MASK, FSL_SAI_CR4_CHMOD_MASK,
...@@ -683,7 +693,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, ...@@ -683,7 +693,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
* FSD_MSTR bit for this specific case. * FSD_MSTR bit for this specific case.
*/ */
if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && 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), regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
FSL_SAI_CR4_FSD_MSTR, 0); FSL_SAI_CR4_FSD_MSTR, 0);
...@@ -697,7 +707,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, ...@@ -697,7 +707,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
/* Enable FSD_MSTR after configuring word width */ /* Enable FSD_MSTR after configuring word width */
if (sai->soc_data->mclk_with_tere && sai->mclk_direction_output && 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), regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs),
FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR); FSL_SAI_CR4_FSD_MSTR, FSL_SAI_CR4_FSD_MSTR);
...@@ -720,8 +730,8 @@ static int fsl_sai_hw_free(struct snd_pcm_substream *substream, ...@@ -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), regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs),
FSL_SAI_CR3_TRCE_MASK, 0); FSL_SAI_CR3_TRCE_MASK, 0);
if (!sai->is_consumer_mode && if (!sai->is_consumer_mode[tx] &&
sai->mclk_streams & BIT(substream->stream)) { sai->mclk_streams & BIT(substream->stream)) {
clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]); clk_disable_unprepare(sai->mclk_clk[sai->mclk_id[tx]]);
sai->mclk_streams &= ~BIT(substream->stream); sai->mclk_streams &= ~BIT(substream->stream);
} }
...@@ -759,7 +769,7 @@ static void fsl_sai_config_disable(struct fsl_sai *sai, int dir) ...@@ -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 * This is a hardware bug, and will be fix in the
* next sai version. * next sai version.
*/ */
if (!sai->is_consumer_mode) { if (!sai->is_consumer_mode[tx]) {
/* Software Reset */ /* Software Reset */
regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR); regmap_write(sai->regmap, FSL_SAI_xCSR(tx, ofs), FSL_SAI_CSR_SR);
/* Clear SR bit to finish the reset */ /* Clear SR bit to finish the reset */
...@@ -914,6 +924,30 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { ...@@ -914,6 +924,30 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
.startup = fsl_sai_startup, .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) static int fsl_sai_dai_resume(struct snd_soc_component *component)
{ {
struct fsl_sai *sai = snd_soc_component_get_drvdata(component); struct fsl_sai *sai = snd_soc_component_get_drvdata(component);
...@@ -931,26 +965,55 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component) ...@@ -931,26 +965,55 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component)
return 0; return 0;
} }
static struct snd_soc_dai_driver fsl_sai_dai_template = { static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
.playback = { {
.stream_name = "CPU-Playback", .name = "sai-tx-rx",
.channels_min = 1, .playback = {
.channels_max = 32, .stream_name = "CPU-Playback",
.rate_min = 8000, .channels_min = 1,
.rate_max = 2822400, .channels_max = 32,
.rates = SNDRV_PCM_RATE_KNOT, .rate_min = 8000,
.formats = FSL_SAI_FORMATS, .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", .name = "sai-rx",
.channels_min = 1, .capture = {
.channels_max = 32, .stream_name = "CPU-Capture",
.rate_min = 8000, .channels_min = 1,
.rate_max = 2822400, .channels_max = 32,
.rates = SNDRV_PCM_RATE_KNOT, .rate_min = 8000,
.formats = FSL_SAI_FORMATS, .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 = { static const struct snd_soc_component_driver fsl_component = {
...@@ -1399,15 +1462,15 @@ static int fsl_sai_probe(struct platform_device *pdev) ...@@ -1399,15 +1462,15 @@ static int fsl_sai_probe(struct platform_device *pdev)
return ret; return ret;
} }
memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template, memcpy(&sai->cpu_dai_drv, fsl_sai_dai_template,
sizeof(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 */ /* Sync Tx with Rx as default by following old DT binding */
sai->synchronous[RX] = true; sai->synchronous[RX] = true;
sai->synchronous[TX] = false; sai->synchronous[TX] = false;
sai->cpu_dai_drv.symmetric_rate = 1; sai->cpu_dai_drv[0].symmetric_rate = 1;
sai->cpu_dai_drv.symmetric_channels = 1; sai->cpu_dai_drv[0].symmetric_channels = 1;
sai->cpu_dai_drv.symmetric_sample_bits = 1; sai->cpu_dai_drv[0].symmetric_sample_bits = 1;
if (of_property_read_bool(np, "fsl,sai-synchronous-rx") && if (of_property_read_bool(np, "fsl,sai-synchronous-rx") &&
of_property_read_bool(np, "fsl,sai-asynchronous")) { of_property_read_bool(np, "fsl,sai-asynchronous")) {
...@@ -1424,9 +1487,9 @@ static int fsl_sai_probe(struct platform_device *pdev) ...@@ -1424,9 +1487,9 @@ static int fsl_sai_probe(struct platform_device *pdev)
/* Discard all settings for asynchronous mode */ /* Discard all settings for asynchronous mode */
sai->synchronous[RX] = false; sai->synchronous[RX] = false;
sai->synchronous[TX] = false; sai->synchronous[TX] = false;
sai->cpu_dai_drv.symmetric_rate = 0; sai->cpu_dai_drv[0].symmetric_rate = 0;
sai->cpu_dai_drv.symmetric_channels = 0; sai->cpu_dai_drv[0].symmetric_channels = 0;
sai->cpu_dai_drv.symmetric_sample_bits = 0; sai->cpu_dai_drv[0].symmetric_sample_bits = 0;
} }
sai->mclk_direction_output = of_property_read_bool(np, "fsl,sai-mclk-direction-output"); sai->mclk_direction_output = of_property_read_bool(np, "fsl,sai-mclk-direction-output");
...@@ -1505,7 +1568,7 @@ static int fsl_sai_probe(struct platform_device *pdev) ...@@ -1505,7 +1568,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
} }
ret = devm_snd_soc_register_component(dev, &fsl_component, 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) if (ret)
goto err_pm_get_sync; goto err_pm_get_sync;
......
...@@ -282,7 +282,7 @@ struct fsl_sai { ...@@ -282,7 +282,7 @@ struct fsl_sai {
struct clk *pll11k_clk; struct clk *pll11k_clk;
struct resource *res; struct resource *res;
bool is_consumer_mode; bool is_consumer_mode[2];
bool is_lsb_first; bool is_lsb_first;
bool is_dsp_mode; bool is_dsp_mode;
bool is_pdm_mode; bool is_pdm_mode;
...@@ -299,7 +299,7 @@ struct fsl_sai { ...@@ -299,7 +299,7 @@ struct fsl_sai {
unsigned int bclk_ratio; unsigned int bclk_ratio;
const struct fsl_sai_soc_data *soc_data; 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_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_tx;
struct fsl_sai_verid verid; struct fsl_sai_verid verid;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment