Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3d8d0bd0 authored by Mark Brown's avatar Mark Brown
Browse files

Merge branch 'topic/fsl-sai' of...

Merge branch 'topic/fsl-sai' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into asoc-fsl
parents f4faa29e c1df2964
Loading
Loading
Loading
Loading
+68 −8
Original line number Original line Diff line number Diff line
@@ -126,6 +126,17 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid)
		return IRQ_HANDLED;
		return IRQ_HANDLED;
}
}


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)
{
	struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);

	sai->slots = slots;
	sai->slot_width = slot_width;

	return 0;
}

static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
		int clk_id, unsigned int freq, int fsl_dir)
		int clk_id, unsigned int freq, int fsl_dir)
{
{
@@ -354,13 +365,25 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
		return -EINVAL;
		return -EINVAL;
	}
	}


	if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) {
	/*
	 * 1) For Asynchronous mode, we must set RCR2 register for capture, and
	 *    set TCR2 register for playback.
	 * 2) For Tx sync with Rx clock, we must set RCR2 register for playback
	 *    and capture.
	 * 3) For Rx sync with Tx clock, we must set TCR2 register for playback
	 *    and capture.
	 * 4) For Tx and Rx are both Synchronous with another SAI, we just
	 *    ignore it.
	 */
	if ((sai->synchronous[TX] && !sai->synchronous[RX]) ||
	    (!tx && !sai->synchronous[RX])) {
		regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
		regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
				   FSL_SAI_CR2_MSEL_MASK,
				   FSL_SAI_CR2_MSEL_MASK,
				   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
				   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
		regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
		regmap_update_bits(sai->regmap, FSL_SAI_RCR2,
				   FSL_SAI_CR2_DIV_MASK, savediv - 1);
				   FSL_SAI_CR2_DIV_MASK, savediv - 1);
	} else {
	} else if ((sai->synchronous[RX] && !sai->synchronous[TX]) ||
		   (tx && !sai->synchronous[TX])) {
		regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
		regmap_update_bits(sai->regmap, FSL_SAI_TCR2,
				   FSL_SAI_CR2_MSEL_MASK,
				   FSL_SAI_CR2_MSEL_MASK,
				   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
				   FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
@@ -383,11 +406,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
	unsigned int channels = params_channels(params);
	unsigned int channels = params_channels(params);
	u32 word_width = snd_pcm_format_width(params_format(params));
	u32 word_width = snd_pcm_format_width(params_format(params));
	u32 val_cr4 = 0, val_cr5 = 0;
	u32 val_cr4 = 0, val_cr5 = 0;
	u32 slots = (channels == 1) ? 2 : channels;
	u32 slot_width = word_width;
	int ret;
	int ret;


	if (sai->slots)
		slots = sai->slots;

	if (sai->slot_width)
		slot_width = sai->slot_width;

	if (!sai->is_slave_mode) {
	if (!sai->is_slave_mode) {
		ret = fsl_sai_set_bclk(cpu_dai, tx,
		ret = fsl_sai_set_bclk(cpu_dai, tx,
			2 * word_width * params_rate(params));
				slots * slot_width * params_rate(params));
		if (ret)
		if (ret)
			return ret;
			return ret;


@@ -399,21 +430,49 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream,


			sai->mclk_streams |= BIT(substream->stream);
			sai->mclk_streams |= BIT(substream->stream);
		}
		}

	}
	}


	if (!sai->is_dsp_mode)
	if (!sai->is_dsp_mode)
		val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
		val_cr4 |= FSL_SAI_CR4_SYWD(slot_width);


	val_cr5 |= FSL_SAI_CR5_WNW(word_width);
	val_cr5 |= FSL_SAI_CR5_WNW(slot_width);
	val_cr5 |= FSL_SAI_CR5_W0W(word_width);
	val_cr5 |= FSL_SAI_CR5_W0W(slot_width);


	if (sai->is_lsb_first)
	if (sai->is_lsb_first)
		val_cr5 |= FSL_SAI_CR5_FBT(0);
		val_cr5 |= FSL_SAI_CR5_FBT(0);
	else
	else
		val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);
		val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1);


	val_cr4 |= FSL_SAI_CR4_FRSZ(channels);
	val_cr4 |= FSL_SAI_CR4_FRSZ(slots);

	/*
	 * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will
	 * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4),
	 * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync
	 * error.
	 */

	if (!sai->is_slave_mode) {
		if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) {
			regmap_update_bits(sai->regmap, FSL_SAI_TCR4,
				FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
				val_cr4);
			regmap_update_bits(sai->regmap, FSL_SAI_TCR5,
				FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
				FSL_SAI_CR5_FBT_MASK, val_cr5);
			regmap_write(sai->regmap, FSL_SAI_TMR,
				~0UL - ((1 << channels) - 1));
		} else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) {
			regmap_update_bits(sai->regmap, FSL_SAI_RCR4,
				FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
				val_cr4);
			regmap_update_bits(sai->regmap, FSL_SAI_RCR5,
				FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK |
				FSL_SAI_CR5_FBT_MASK, val_cr5);
			regmap_write(sai->regmap, FSL_SAI_RMR,
				~0UL - ((1 << channels) - 1));
		}
	}


	regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
	regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx),
			   FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
			   FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK,
@@ -550,6 +609,7 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream,
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = {
	.set_sysclk	= fsl_sai_set_dai_sysclk,
	.set_sysclk	= fsl_sai_set_dai_sysclk,
	.set_fmt	= fsl_sai_set_dai_fmt,
	.set_fmt	= fsl_sai_set_dai_fmt,
	.set_tdm_slot	= fsl_sai_set_dai_tdm_slot,
	.hw_params	= fsl_sai_hw_params,
	.hw_params	= fsl_sai_hw_params,
	.hw_free	= fsl_sai_hw_free,
	.hw_free	= fsl_sai_hw_free,
	.trigger	= fsl_sai_trigger,
	.trigger	= fsl_sai_trigger,
+3 −0
Original line number Original line Diff line number Diff line
@@ -143,6 +143,9 @@ struct fsl_sai {


	unsigned int mclk_id[2];
	unsigned int mclk_id[2];
	unsigned int mclk_streams;
	unsigned int mclk_streams;
	unsigned int slots;
	unsigned int slot_width;

	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;
};
};