sound/soc/sprd/sprd-pcm-compress.c

Source file repositories/reference/linux-study-clean/sound/soc/sprd/sprd-pcm-compress.c

File Facts

System
Linux kernel
Corpus path
sound/soc/sprd/sprd-pcm-compress.c
Extension
.c
Size
19310 bytes
Lines
672
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 sprd_compr_dma {
	struct dma_chan *chan;
	struct dma_async_tx_descriptor *desc;
	dma_cookie_t cookie;
	dma_addr_t phys;
	void *virt;
	int trans_len;
};

/*
 * The Spreadtrum Audio compress offload mode will use 2-stage DMA transfer to
 * save power. That means we can request 2 dma channels, one for source channel,
 * and another one for destination channel. Once the source channel's transaction
 * is done, it will trigger the destination channel's transaction automatically
 * by hardware signal.
 *
 * For 2-stage DMA transfer, we can allocate 2 buffers: IRAM buffer (always
 * power-on) and DDR buffer. The source channel will transfer data from IRAM
 * buffer to the DSP fifo to decoding/encoding, once IRAM buffer is empty by
 * transferring done, the destination channel will start to transfer data from
 * DDR buffer to IRAM buffer.
 *
 * Since the DSP fifo is only 512B, IRAM buffer is allocated by 32K, and DDR
 * buffer is larger to 2M. That means only the IRAM 32k data is transferred
 * done, we can wake up the AP system to transfer data from DDR to IRAM, and
 * other time the AP system can be suspended to save power.
 */
struct sprd_compr_stream {
	struct snd_compr_stream *cstream;
	struct sprd_compr_ops *compr_ops;
	struct sprd_compr_dma dma[SPRD_COMPR_DMA_CHANS];

	/* DMA engine channel number */
	int num_channels;

	/* Stage 0 IRAM buffer */
	struct snd_dma_buffer iram_buffer;
	/* Stage 1 DDR buffer */
	struct snd_dma_buffer compr_buffer;

	/* DSP play information IRAM buffer */
	dma_addr_t info_phys;
	void *info_area;
	int info_size;

	/* Data size copied to IRAM buffer */
	u64 copied_total;
	/* Total received data size from userspace */
	u64 received_total;
	/* Stage 0 IRAM buffer received data size */
	int received_stage0;
	/* Stage 1 DDR buffer received data size */
	int received_stage1;
	/* Stage 1 DDR buffer pointer */
	int stage1_pointer;
};

static int sprd_platform_compr_trigger(struct snd_soc_component *component,
				       struct snd_compr_stream *cstream,
				       int cmd);

static void sprd_platform_compr_drain_notify(void *arg)
{
	struct snd_compr_stream *cstream = arg;
	struct snd_compr_runtime *runtime = cstream->runtime;
	struct sprd_compr_stream *stream = runtime->private_data;

	memset(stream->info_area, 0, sizeof(struct sprd_compr_playinfo));

	snd_compr_drain_notify(cstream);
}

static void sprd_platform_compr_dma_complete(void *data)
{
	struct snd_compr_stream *cstream = data;
	struct snd_compr_runtime *runtime = cstream->runtime;
	struct sprd_compr_stream *stream = runtime->private_data;
	struct sprd_compr_dma *dma = &stream->dma[1];

	/* Update data size copied to IRAM buffer */
	stream->copied_total += dma->trans_len;
	if (stream->copied_total > stream->received_total)
		stream->copied_total = stream->received_total;

	snd_compr_fragment_elapsed(cstream);
}

static int sprd_platform_compr_dma_config(struct snd_soc_component *component,
					  struct snd_compr_stream *cstream,
					  struct snd_compr_params *params,

Annotation

Implementation Notes