sound/soc/fsl/fsl_asrc_dma.c

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

File Facts

System
Linux kernel
Corpus path
sound/soc/fsl/fsl_asrc_dma.c
Extension
.c
Size
14844 bytes
Lines
515
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 (IS_ERR(tmp_chan)) {
			dev_err(dev, "failed to request DMA channel for Back-End\n");
			return -EINVAL;
		}
	}

	/*
	 * An EDMA DEV_TO_DEV channel is fixed and bound with DMA event of each
	 * peripheral, unlike SDMA channel that is allocated dynamically. So no
	 * need to configure dma_request and dma_request2, but get dma_chan of
	 * Back-End device directly via dma_request_chan.
	 */
	if (!asrc->use_edma) {
		/* Get DMA request of Back-End */
		tmp_data = tmp_chan->private;
		pair->dma_data.dma_request = tmp_data->dma_request;
		be_peripheral_type = tmp_data->peripheral_type;
		if (!be_chan)
			dma_release_channel(tmp_chan);

		/* Get DMA request of Front-End */
		tmp_chan = asrc->get_dma_channel(pair, dir);
		tmp_data = tmp_chan->private;
		pair->dma_data.dma_request2 = tmp_data->dma_request;
		pair->dma_data.peripheral_type = tmp_data->peripheral_type;
		pair->dma_data.priority = tmp_data->priority;
		dma_release_channel(tmp_chan);

		of_dma_node = pair->dma_chan[!dir]->device->dev->of_node;
		pair->dma_chan[dir] =
			__dma_request_channel(&mask, filter, &pair->dma_data,
					      of_dma_node);
		pair->req_dma_chan = true;
	} else {
		pair->dma_chan[dir] = tmp_chan;
		/* Do not flag to release if we are reusing the Back-End one */
		pair->req_dma_chan = !be_chan;
	}

	if (!pair->dma_chan[dir]) {
		dev_err(dev, "failed to request DMA channel for Back-End\n");
		return -EINVAL;
	}

	width = snd_pcm_format_physical_width(asrc->asrc_format);
	if (width < 8 || width > 64)
		return -EINVAL;
	else if (width == 8)
		buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
	else if (width == 16)
		buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
	else if (width == 24)
		buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES;
	else if (width <= 32)
		buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
	else
		buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES;

	config_be.direction = DMA_DEV_TO_DEV;
	config_be.src_addr_width = buswidth;
	config_be.src_maxburst = dma_params_be->maxburst;
	config_be.dst_addr_width = buswidth;
	config_be.dst_maxburst = dma_params_be->maxburst;

	memset(&audio_config, 0, sizeof(audio_config));
	config_be.peripheral_config = &audio_config;
	config_be.peripheral_size  = sizeof(audio_config);

	if (tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL ||
		   be_peripheral_type == IMX_DMATYPE_SPDIF))
		audio_config.n_fifos_dst = 2;
	if (!tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL ||
		    be_peripheral_type == IMX_DMATYPE_SPDIF))
		audio_config.n_fifos_src = 2;

	if (tx) {
		config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index);
		config_be.dst_addr = dma_params_be->addr;
	} else {
		config_be.dst_addr = asrc->paddr + asrc->get_fifo_addr(IN, index);
		config_be.src_addr = dma_params_be->addr;
	}

	ret = dmaengine_slave_config(pair->dma_chan[dir], &config_be);
	if (ret) {
		dev_err(dev, "failed to config DMA channel for Back-End\n");
		if (pair->req_dma_chan)
			dma_release_channel(pair->dma_chan[dir]);
		return ret;
	}

Annotation

Implementation Notes