sound/soc/atmel/mchp-i2s-mcc.c

Source file repositories/reference/linux-study-clean/sound/soc/atmel/mchp-i2s-mcc.c

File Facts

System
Linux kernel
Corpus path
sound/soc/atmel/mchp-i2s-mcc.c
Extension
.c
Size
32191 bytes
Lines
1139
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct mchp_i2s_mcc_soc_data {
	unsigned int	data_pin_pair_num;
	bool		has_fifo;
};

struct mchp_i2s_mcc_dev {
	struct wait_queue_head			wq_txrdy;
	struct wait_queue_head			wq_rxrdy;
	struct device				*dev;
	struct regmap				*regmap;
	struct clk				*pclk;
	struct clk				*gclk;
	const struct mchp_i2s_mcc_soc_data	*soc;
	struct snd_dmaengine_dai_dma_data	playback;
	struct snd_dmaengine_dai_dma_data	capture;
	unsigned int				fmt;
	unsigned int				sysclk;
	unsigned int				frame_length;
	int					tdm_slots;
	int					channels;
	u8					tdm_data_pair;
	unsigned int				gclk_use:1;
	unsigned int				gclk_running:1;
	unsigned int				tx_rdy:1;
	unsigned int				rx_rdy:1;
};

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, idrb = 0;
	irqreturn_t ret = IRQ_NONE;

	regmap_read(dev->regmap, MCHP_I2SMCC_IMRA, &imra);
	regmap_read(dev->regmap, MCHP_I2SMCC_ISRA, &sra);
	pendinga = imra & sra;

	regmap_read(dev->regmap, MCHP_I2SMCC_IMRB, &imrb);
	regmap_read(dev->regmap, MCHP_I2SMCC_ISRB, &srb);
	pendingb = imrb & srb;

	if (!pendinga && !pendingb)
		return IRQ_NONE;

	/*
	 * 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 || idrb)
		ret = IRQ_HANDLED;

	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 ((!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);
	}
	if (dev->soc->has_fifo)
		regmap_write(dev->regmap, MCHP_I2SMCC_IDRB, idrb);
	else
		regmap_write(dev->regmap, MCHP_I2SMCC_IDRA, idra);

	return ret;
}

static int mchp_i2s_mcc_set_sysclk(struct snd_soc_dai *dai,
				   int clk_id, unsigned int freq, int dir)
{
	struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);

	dev_dbg(dev->dev, "%s() clk_id=%d freq=%u dir=%d\n",
		__func__, clk_id, freq, dir);

Annotation

Implementation Notes