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

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.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent bfdca489
Loading
Loading
Loading
Loading
+56 −20
Original line number Diff line number Diff line
@@ -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,23 +276,35 @@ 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
	 */
	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)
	}
	if (idra || idrb)
		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))) {
	     (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)) &&
	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))) {
	     (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);
	}
	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");
			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,6 +759,10 @@ 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");
			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,6 +815,9 @@ 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
			 */
			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;
@@ -797,6 +826,9 @@ 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
			 */
			if (dev->soc->has_fifo)
				ierb = MCHP_I2SMCC_INT_RXFFRDY;
			else
				iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels);
		}
		break;
@@ -815,6 +847,9 @@ static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd,
		}
	}

	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);

@@ -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[] = {