Skip to content

Commit

Permalink
ASoC: atmel-i2s: Fix usage of capture and playback at the same time
Browse files Browse the repository at this point in the history
[ Upstream commit 3b7961a ]

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: b543e46 ("ASoC: atmel-i2s: add driver for the new Atmel I2S controller")
Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
Link: https://lore.kernel.org/r/20210618150741.401739-2-codrin.ciubotariu@microchip.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
codrin989 authored and gregkh committed Jul 14, 2021
1 parent 49d0c57 commit b509efd
Showing 1 changed file with 26 additions and 8 deletions.
34 changes: 26 additions & 8 deletions sound/soc/atmel/atmel-i2s.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
err = atmel_i2s_switch_mck_generator(dev, true);
if (err)
return err;
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)
err = atmel_i2s_switch_mck_generator(dev, false);
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;
}
Expand Down

0 comments on commit b509efd

Please sign in to comment.