sound/soc/google/chv3-i2s.c

Source file repositories/reference/linux-study-clean/sound/soc/google/chv3-i2s.c

File Facts

System
Linux kernel
Corpus path
sound/soc/google/chv3-i2s.c
Extension
.c
Size
9957 bytes
Lines
340
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 chv3_i2s_dev {
	struct device *dev;
	void __iomem *iobase;
	void __iomem *iobase_irq;
	struct snd_pcm_substream *rx_substream;
	struct snd_pcm_substream *tx_substream;
	int tx_bytes_to_fetch;
};

static struct snd_soc_dai_driver chv3_i2s_dai = {
	.name = "chv3-i2s",
	.capture = {
		.channels_min = 1,
		.channels_max = 128,
		.rates = SNDRV_PCM_RATE_CONTINUOUS,
		.rate_min = 8000,
		.rate_max = 96000,
		.formats = SNDRV_PCM_FMTBIT_S32_LE,
	},
	.playback = {
		.channels_min = 1,
		.channels_max = 128,
		.rates = SNDRV_PCM_RATE_CONTINUOUS,
		.rate_min = 8000,
		.rate_max = 96000,
		.formats = SNDRV_PCM_FMTBIT_S32_LE,
	},
};

static const struct snd_pcm_hardware chv3_dma_hw = {
	.info = SNDRV_PCM_INFO_INTERLEAVED |
		SNDRV_PCM_INFO_MMAP |
		SNDRV_PCM_INFO_MMAP_VALID |
		SNDRV_PCM_INFO_BLOCK_TRANSFER,
	.buffer_bytes_max = I2S_MAX_BUFFER_SIZE,
	.period_bytes_min = 64,
	.period_bytes_max = 8192,
	.periods_min = 4,
	.periods_max = 256,
};

static inline void chv3_i2s_wr(struct chv3_i2s_dev *i2s, int offset, u32 val)
{
	writel(val, i2s->iobase + offset);
}

static inline u32 chv3_i2s_rd(struct chv3_i2s_dev *i2s, int offset)
{
	return readl(i2s->iobase + offset);
}

static irqreturn_t chv3_i2s_isr(int irq, void *data)
{
	struct chv3_i2s_dev *i2s = data;
	u32 reg;

	reg = readl(i2s->iobase_irq + I2S_IRQ_CLR);
	if (!reg)
		return IRQ_NONE;

	if (reg & I2S_IRQ_RX_BIT)
		snd_pcm_period_elapsed(i2s->rx_substream);

	if (reg & I2S_IRQ_TX_BIT)
		snd_pcm_period_elapsed(i2s->tx_substream);

	writel(reg, i2s->iobase_irq + I2S_IRQ_CLR);

	return IRQ_HANDLED;
}

static int chv3_dma_open(struct snd_soc_component *component,
			 struct snd_pcm_substream *substream)
{
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct chv3_i2s_dev *i2s = snd_soc_dai_get_drvdata(snd_soc_rtd_to_cpu(rtd, 0));
	int res;

	snd_soc_set_runtime_hwparams(substream, &chv3_dma_hw);

	res = snd_pcm_hw_constraint_pow2(substream->runtime, 0,
			SNDRV_PCM_HW_PARAM_BUFFER_BYTES);
	if (res)
		return res;

	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
		i2s->rx_substream = substream;
	else
		i2s->tx_substream = substream;

Annotation

Implementation Notes