mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-17 01:04:19 +08:00
ASoC: mchp-i2s-mcc: Add FIFOs support
I2S-MCC found on SAMA7G5 includes 2 FIFOs (capture and playback). When FIFOs are enabled, bits I2SMCC_ISRA.TXLRDYx and I2SMCC_ISRA.TXRRDYx must not be used. Bits I2SMCC_ISRB.TXFFRDY and I2SMCC_ISRB.RXFFRDY must be used instead. Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com> Link: https://lore.kernel.org/r/20210301170905.835091-7-codrin.ciubotariu@microchip.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
bfdca48975
commit
16135d6630
@ -176,7 +176,7 @@
|
||||
*/
|
||||
#define MCHP_I2SMCC_MRB_CRAMODE_REGULAR (1 << 0)
|
||||
|
||||
#define MCHP_I2SMCC_MRB_FIFOEN BIT(1)
|
||||
#define MCHP_I2SMCC_MRB_FIFOEN BIT(4)
|
||||
|
||||
#define MCHP_I2SMCC_MRB_DMACHUNK_MASK GENMASK(9, 8)
|
||||
#define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \
|
||||
@ -230,6 +230,7 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = {
|
||||
|
||||
struct mchp_i2s_mcc_soc_data {
|
||||
unsigned int data_pin_pair_num;
|
||||
bool has_fifo;
|
||||
};
|
||||
|
||||
struct mchp_i2s_mcc_dev {
|
||||
@ -257,7 +258,7 @@ struct mchp_i2s_mcc_dev {
|
||||
static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct mchp_i2s_mcc_dev *dev = dev_id;
|
||||
u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0;
|
||||
u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0, idrb = 0;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
|
||||
regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra);
|
||||
@ -275,24 +276,36 @@ static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
|
||||
* Tx/Rx ready interrupts are enabled when stopping only, to assure
|
||||
* availability and to disable clocks if necessary
|
||||
*/
|
||||
idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) |
|
||||
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
|
||||
if (idra)
|
||||
if (dev->soc->has_fifo) {
|
||||
idrb |= pendingb & (MCHP_I2SMCC_INT_TXFFRDY |
|
||||
MCHP_I2SMCC_INT_RXFFRDY);
|
||||
} else {
|
||||
idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) |
|
||||
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
|
||||
}
|
||||
if (idra || idrb)
|
||||
ret = IRQ_HANDLED;
|
||||
|
||||
if ((imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) &&
|
||||
(imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) ==
|
||||
(idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) {
|
||||
if ((!dev->soc->has_fifo &&
|
||||
(imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) &&
|
||||
(imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) ==
|
||||
(idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) ||
|
||||
(dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_TXFFRDY)) {
|
||||
dev->tx_rdy = 1;
|
||||
wake_up_interruptible(&dev->wq_txrdy);
|
||||
}
|
||||
if ((imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) &&
|
||||
(imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) ==
|
||||
(idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) {
|
||||
if ((!dev->soc->has_fifo &&
|
||||
(imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) &&
|
||||
(imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) ==
|
||||
(idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) ||
|
||||
(dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_RXFFRDY)) {
|
||||
dev->rx_rdy = 1;
|
||||
wake_up_interruptible(&dev->wq_rxrdy);
|
||||
}
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);
|
||||
if (dev->soc->has_fifo)
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, idrb);
|
||||
else
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -664,6 +677,10 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
|
||||
}
|
||||
}
|
||||
|
||||
/* enable FIFO if available */
|
||||
if (dev->soc->has_fifo)
|
||||
mrb |= MCHP_I2SMCC_MRB_FIFOEN;
|
||||
|
||||
/*
|
||||
* If we are already running, the wanted setup must be
|
||||
* the same with the one that's currently ongoing
|
||||
@ -726,8 +743,13 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
|
||||
if (err == 0) {
|
||||
dev_warn_once(dev->dev,
|
||||
"Timeout waiting for Tx ready\n");
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
|
||||
MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels));
|
||||
if (dev->soc->has_fifo)
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IDRB,
|
||||
MCHP_I2SMCC_INT_TXFFRDY);
|
||||
else
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
|
||||
MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels));
|
||||
|
||||
dev->tx_rdy = 1;
|
||||
}
|
||||
} else {
|
||||
@ -737,8 +759,12 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
|
||||
if (err == 0) {
|
||||
dev_warn_once(dev->dev,
|
||||
"Timeout waiting for Rx ready\n");
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
|
||||
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
|
||||
if (dev->soc->has_fifo)
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IDRB,
|
||||
MCHP_I2SMCC_INT_RXFFRDY);
|
||||
else
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA,
|
||||
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels));
|
||||
dev->rx_rdy = 1;
|
||||
}
|
||||
}
|
||||
@ -765,7 +791,7 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
|
||||
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
|
||||
u32 cr = 0;
|
||||
u32 iera = 0;
|
||||
u32 iera = 0, ierb = 0;
|
||||
u32 sr;
|
||||
int err;
|
||||
|
||||
@ -789,7 +815,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
* Enable Tx Ready interrupts on all channels
|
||||
* to assure all data is sent
|
||||
*/
|
||||
iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels);
|
||||
if (dev->soc->has_fifo)
|
||||
ierb = MCHP_I2SMCC_INT_TXFFRDY;
|
||||
else
|
||||
iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels);
|
||||
} else if (!is_playback && (sr & MCHP_I2SMCC_SR_RXEN)) {
|
||||
cr = MCHP_I2SMCC_CR_RXDIS;
|
||||
dev->rx_rdy = 0;
|
||||
@ -797,7 +826,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
* Enable Rx Ready interrupts on all channels
|
||||
* to assure all data is received
|
||||
*/
|
||||
iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
|
||||
if (dev->soc->has_fifo)
|
||||
ierb = MCHP_I2SMCC_INT_RXFFRDY;
|
||||
else
|
||||
iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -815,7 +847,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
}
|
||||
}
|
||||
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera);
|
||||
if (dev->soc->has_fifo)
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IERB, ierb);
|
||||
else
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_IERA, iera);
|
||||
regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr);
|
||||
|
||||
return 0;
|
||||
@ -903,6 +938,7 @@ static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sam9x60 = {
|
||||
|
||||
static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sama7g5 = {
|
||||
.data_pin_pair_num = 4,
|
||||
.has_fifo = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id mchp_i2s_mcc_dt_ids[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user