sound/soc/fsl/fsl_qmc_audio.c

Source file repositories/reference/linux-study-clean/sound/soc/fsl/fsl_qmc_audio.c

File Facts

System
Linux kernel
Corpus path
sound/soc/fsl/fsl_qmc_audio.c
Extension
.c
Size
26101 bytes
Lines
972
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 qmc_dai {
	char *name;
	int id;
	struct device *dev;
	unsigned int nb_tx_ts;
	unsigned int nb_rx_ts;

	unsigned int nb_chans_avail;
	unsigned int nb_chans_used_tx;
	unsigned int nb_chans_used_rx;
	struct qmc_chan **qmc_chans;
};

struct qmc_audio {
	struct device *dev;
	unsigned int num_dais;
	struct qmc_dai *dais;
	struct snd_soc_dai_driver *dai_drivers;
};

struct qmc_dai_prtd {
	struct qmc_dai *qmc_dai;

	snd_pcm_uframes_t buffer_ended;
	snd_pcm_uframes_t buffer_size;
	snd_pcm_uframes_t period_size;

	dma_addr_t ch_dma_addr_start;
	dma_addr_t ch_dma_addr_current;
	dma_addr_t ch_dma_addr_end;
	size_t ch_dma_size;
	size_t ch_dma_offset;

	unsigned int channels;
	struct snd_pcm_substream *substream;
};

static int qmc_audio_pcm_new(struct snd_soc_component *component,
			     struct snd_soc_pcm_runtime *rtd)
{
	struct snd_card *card = rtd->card->snd_card;
	int ret;

	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
	if (ret)
		return ret;

	snd_pcm_set_managed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, card->dev,
				       64 * 1024, 64 * 1024);
	return 0;
}

static bool qmc_audio_access_is_interleaved(snd_pcm_access_t access)
{
	switch (access) {
	case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
	case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
		return true;
	default:
		break;
	}
	return false;
}

static int qmc_audio_pcm_hw_params(struct snd_soc_component *component,
				   struct snd_pcm_substream *substream,
				   struct snd_pcm_hw_params *params)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct qmc_dai_prtd *prtd = substream->runtime->private_data;

	/*
	 * In interleaved mode, the driver uses one QMC channel for all audio
	 * channels whereas in non-interleaved mode, it uses one QMC channel per
	 * audio channel.
	 */
	prtd->channels = qmc_audio_access_is_interleaved(params_access(params)) ?
				1 : params_channels(params);

	prtd->substream = substream;

	prtd->buffer_ended = 0;
	prtd->buffer_size = params_buffer_size(params);
	prtd->period_size = params_period_size(params);

	prtd->ch_dma_addr_start = runtime->dma_addr;
	prtd->ch_dma_offset = params_buffer_bytes(params) / prtd->channels;
	prtd->ch_dma_addr_end = runtime->dma_addr + prtd->ch_dma_offset;
	prtd->ch_dma_addr_current = prtd->ch_dma_addr_start;
	prtd->ch_dma_size = params_period_bytes(params) / prtd->channels;

Annotation

Implementation Notes