sound/soc/intel/keembay/kmb_platform.c

Source file repositories/reference/linux-study-clean/sound/soc/intel/keembay/kmb_platform.c

File Facts

System
Linux kernel
Corpus path
sound/soc/intel/keembay/kmb_platform.c
Extension
.c
Size
23885 bytes
Lines
929
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

if (kmb_i2s->config.data_width == 16) {
			writel(((u16(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
			writel(((u16(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
		} else {
			writel(((u32(*)[2])buf)[tx_ptr][0], i2s_base + LRBR_LTHR(0));
			writel(((u32(*)[2])buf)[tx_ptr][1], i2s_base + RRBR_RTHR(0));
		}

		period_pos++;

		if (++tx_ptr >= runtime->buffer_size)
			tx_ptr = 0;
	}

	*period_elapsed = period_pos >= runtime->period_size;

	return tx_ptr;
}

static unsigned int kmb_pcm_rx_fn(struct kmb_i2s_info *kmb_i2s,
				  struct snd_pcm_runtime *runtime,
				  unsigned int rx_ptr, bool *period_elapsed)
{
	unsigned int period_pos = rx_ptr % runtime->period_size;
	void __iomem *i2s_base = kmb_i2s->i2s_base;
	int chan = kmb_i2s->config.chan_nr;
	void *buf = runtime->dma_area;
	int i, j;

	/* KMB i2s uses two separate L/R FIFO */
	for (i = 0; i < kmb_i2s->fifo_th; i++) {
		for (j = 0; j < chan / 2; j++) {
			if (kmb_i2s->config.data_width == 16) {
				((u16 *)buf)[rx_ptr * chan + (j * 2)] =
						readl(i2s_base + LRBR_LTHR(j));
				((u16 *)buf)[rx_ptr * chan + ((j * 2) + 1)] =
						readl(i2s_base + RRBR_RTHR(j));
			} else {
				((u32 *)buf)[rx_ptr * chan + (j * 2)] =
						readl(i2s_base + LRBR_LTHR(j));
				((u32 *)buf)[rx_ptr * chan + ((j * 2) + 1)] =
						readl(i2s_base + RRBR_RTHR(j));
			}
		}
		period_pos++;

		if (++rx_ptr >= runtime->buffer_size)
			rx_ptr = 0;
	}

	*period_elapsed = period_pos >= runtime->period_size;

	return rx_ptr;
}

static inline void kmb_i2s_disable_channels(struct kmb_i2s_info *kmb_i2s,
					    u32 stream)
{
	u32 i;

	/* Disable all channels regardless of configuration*/
	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
		for (i = 0; i < MAX_ISR; i++)
			writel(0, kmb_i2s->i2s_base + TER(i));
	} else {
		for (i = 0; i < MAX_ISR; i++)
			writel(0, kmb_i2s->i2s_base + RER(i));
	}
}

static inline void kmb_i2s_clear_irqs(struct kmb_i2s_info *kmb_i2s, u32 stream)
{
	struct i2s_clk_config_data *config = &kmb_i2s->config;
	u32 i;

	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
		for (i = 0; i < config->chan_nr / 2; i++)
			readl(kmb_i2s->i2s_base + TOR(i));
	} else {
		for (i = 0; i < config->chan_nr / 2; i++)
			readl(kmb_i2s->i2s_base + ROR(i));
	}
}

static inline void kmb_i2s_irq_trigger(struct kmb_i2s_info *kmb_i2s,
				       u32 stream, int chan_nr, bool trigger)
{
	u32 i, irq;
	u32 flag;

Annotation

Implementation Notes