Unverified Commit 3b7961a3 authored by Codrin Ciubotariu's avatar Codrin Ciubotariu Committed by Mark Brown
Browse files

ASoC: atmel-i2s: Fix usage of capture and playback at the same time



For both capture and playback streams to work at the same time, only the
needed values from a register need to be updated. Also, clocks should be
enabled only when the first stream is started and stopped when there is no
running stream.

Fixes: b543e467 ("ASoC: atmel-i2s: add driver for the new Atmel I2S controller")
Signed-off-by: default avatarCodrin Ciubotariu <codrin.ciubotariu@microchip.com>
Link: https://lore.kernel.org/r/20210618150741.401739-2-codrin.ciubotariu@microchip.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 489a830a
Loading
Loading
Loading
Loading
+26 −8
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ struct atmel_i2s_dev {
	unsigned int				fmt;
	const struct atmel_i2s_gck_param	*gck_param;
	const struct atmel_i2s_caps		*caps;
	int					clk_use_no;
};

static irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id)
@@ -321,9 +322,16 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
{
	struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
	bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
	unsigned int mr = 0;
	unsigned int mr = 0, mr_mask;
	int ret;

	mr_mask = ATMEL_I2SC_MR_FORMAT_MASK | ATMEL_I2SC_MR_MODE_MASK |
		ATMEL_I2SC_MR_DATALENGTH_MASK;
	if (is_playback)
		mr_mask |= ATMEL_I2SC_MR_TXMONO;
	else
		mr_mask |= ATMEL_I2SC_MR_RXMONO;

	switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		mr |= ATMEL_I2SC_MR_FORMAT_I2S;
@@ -402,7 +410,7 @@ static int atmel_i2s_hw_params(struct snd_pcm_substream *substream,
		return -EINVAL;
	}

	return regmap_write(dev->regmap, ATMEL_I2SC_MR, mr);
	return regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr);
}

static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev,
@@ -495,18 +503,28 @@ static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
	is_master = (mr & ATMEL_I2SC_MR_MODE_MASK) == ATMEL_I2SC_MR_MODE_MASTER;

	/* If master starts, enable the audio clock. */
	if (is_master && mck_enabled)
	if (is_master && mck_enabled) {
		if (!dev->clk_use_no) {
			err = atmel_i2s_switch_mck_generator(dev, true);
			if (err)
				return err;
		}
		dev->clk_use_no++;
	}

	err = regmap_write(dev->regmap, ATMEL_I2SC_CR, cr);
	if (err)
		return err;

	/* If master stops, disable the audio clock. */
	if (is_master && !mck_enabled)
	if (is_master && !mck_enabled) {
		if (dev->clk_use_no == 1) {
			err = atmel_i2s_switch_mck_generator(dev, false);
			if (err)
				return err;
		}
		dev->clk_use_no--;
	}

	return err;
}