Commit 16135d66 authored by Codrin Ciubotariu's avatar Codrin Ciubotariu Committed by Mark Brown

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: default avatarCodrin Ciubotariu <codrin.ciubotariu@microchip.com>
Link: https://lore.kernel.org/r/20210301170905.835091-7-codrin.ciubotariu@microchip.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent bfdca489
...@@ -176,7 +176,7 @@ ...@@ -176,7 +176,7 @@
*/ */
#define MCHP_I2SMCC_MRB_CRAMODE_REGULAR (1 << 0) #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_MASK GENMASK(9, 8)
#define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \ #define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \
...@@ -230,6 +230,7 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = { ...@@ -230,6 +230,7 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = {
struct mchp_i2s_mcc_soc_data { struct mchp_i2s_mcc_soc_data {
unsigned int data_pin_pair_num; unsigned int data_pin_pair_num;
bool has_fifo;
}; };
struct mchp_i2s_mcc_dev { struct mchp_i2s_mcc_dev {
...@@ -257,7 +258,7 @@ 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) static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id)
{ {
struct mchp_i2s_mcc_dev *dev = 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; irqreturn_t ret = IRQ_NONE;
regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra); regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra);
...@@ -275,24 +276,36 @@ static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id) ...@@ -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 * Tx/Rx ready interrupts are enabled when stopping only, to assure
* availability and to disable clocks if necessary * availability and to disable clocks if necessary
*/ */
idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) | if (dev->soc->has_fifo) {
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); idrb |= pendingb & (MCHP_I2SMCC_INT_TXFFRDY |
if (idra) 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; ret = IRQ_HANDLED;
if ((imra & 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))) { (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; dev->tx_rdy = 1;
wake_up_interruptible(&dev->wq_txrdy); wake_up_interruptible(&dev->wq_txrdy);
} }
if ((imra & 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))) { (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; dev->rx_rdy = 1;
wake_up_interruptible(&dev->wq_rxrdy); 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; return ret;
} }
...@@ -664,6 +677,10 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, ...@@ -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 * If we are already running, the wanted setup must be
* the same with the one that's currently ongoing * 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, ...@@ -726,8 +743,13 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
if (err == 0) { if (err == 0) {
dev_warn_once(dev->dev, dev_warn_once(dev->dev,
"Timeout waiting for Tx ready\n"); "Timeout waiting for Tx ready\n");
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, if (dev->soc->has_fifo)
MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)); 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; dev->tx_rdy = 1;
} }
} else { } else {
...@@ -737,8 +759,12 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream, ...@@ -737,8 +759,12 @@ static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream,
if (err == 0) { if (err == 0) {
dev_warn_once(dev->dev, dev_warn_once(dev->dev,
"Timeout waiting for Rx ready\n"); "Timeout waiting for Rx ready\n");
regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, if (dev->soc->has_fifo)
MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); 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; dev->rx_rdy = 1;
} }
} }
...@@ -765,7 +791,7 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -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); struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
u32 cr = 0; u32 cr = 0;
u32 iera = 0; u32 iera = 0, ierb = 0;
u32 sr; u32 sr;
int err; int err;
...@@ -789,7 +815,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -789,7 +815,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
* Enable Tx Ready interrupts on all channels * Enable Tx Ready interrupts on all channels
* to assure all data is sent * 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)) { } else if (!is_playback && (sr & MCHP_I2SMCC_SR_RXEN)) {
cr = MCHP_I2SMCC_CR_RXDIS; cr = MCHP_I2SMCC_CR_RXDIS;
dev->rx_rdy = 0; dev->rx_rdy = 0;
...@@ -797,7 +826,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -797,7 +826,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
* Enable Rx Ready interrupts on all channels * Enable Rx Ready interrupts on all channels
* to assure all data is received * 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; break;
default: default:
...@@ -815,7 +847,10 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, ...@@ -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); regmap_write(dev->regmap, MCHP_I2SMCC_CR, cr);
return 0; return 0;
...@@ -903,6 +938,7 @@ static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sam9x60 = { ...@@ -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 = { static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sama7g5 = {
.data_pin_pair_num = 4, .data_pin_pair_num = 4,
.has_fifo = true,
}; };
static const struct of_device_id mchp_i2s_mcc_dt_ids[] = { static const struct of_device_id mchp_i2s_mcc_dt_ids[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment