diff options
author | Codrin Ciubotariu <codrin.ciubotariu@microchip.com> | 2021-03-01 20:09:04 +0300 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2021-03-10 16:08:39 +0300 |
commit | 16135d66309a5ca67e05cd7d0b1b038597a0b0a3 (patch) | |
tree | 6876377579e0d4c79c6b33af3e71dd9f7dc10268 /sound/soc/atmel/mchp-i2s-mcc.c | |
parent | bfdca489751ff765ee606c85bda1680040dedd8e (diff) | |
download | linux-16135d66309a5ca67e05cd7d0b1b038597a0b0a3.tar.xz |
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>
Diffstat (limited to 'sound/soc/atmel/mchp-i2s-mcc.c')
-rw-r--r-- | sound/soc/atmel/mchp-i2s-mcc.c | 76 |
1 files changed, 56 insertions, 20 deletions
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c index 515ba3634fdd..673bc16cb46a 100644 --- a/sound/soc/atmel/mchp-i2s-mcc.c +++ b/sound/soc/atmel/mchp-i2s-mcc.c @@ -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[] = { |