mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-23 23:50:51 +07:00
ASoC: atmel-i2s: Fix usage of capture and playback at the same time
[ Upstream commit 3b7961a326f8a7e03f54a19f02fedae8d488b80f ]
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: b543e467d1
("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>
This commit is contained in:
parent
af497961ab
commit
e30e636447
@ -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)
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user