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

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.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 727de4fb
Loading
Loading
Loading
Loading
+102 −39
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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;

	/*
@@ -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;
@@ -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,
@@ -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);

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

@@ -720,7 +730,7 @@ 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 &&
	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);
@@ -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 */
@@ -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);
@@ -931,7 +965,9 @@ static int fsl_sai_dai_resume(struct snd_soc_component *component)
	return 0;
}

static struct snd_soc_dai_driver fsl_sai_dai_template = {
static struct snd_soc_dai_driver fsl_sai_dai_template[] = {
	{
		.name = "sai-tx-rx",
		.playback = {
			.stream_name = "CPU-Playback",
			.channels_min = 1,
@@ -951,6 +987,33 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = {
			.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,
	},
	{
		.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,
	},
};

static const struct snd_soc_component_driver fsl_component = {
@@ -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")) {
@@ -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");
@@ -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;

+2 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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;