162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci *  Copyright (C) 2012, Analog Devices Inc.
462306a36Sopenharmony_ci *	Author: Lars-Peter Clausen <lars@metafoo.de>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifndef __SOUND_DMAENGINE_PCM_H__
862306a36Sopenharmony_ci#define __SOUND_DMAENGINE_PCM_H__
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <sound/pcm.h>
1162306a36Sopenharmony_ci#include <sound/soc.h>
1262306a36Sopenharmony_ci#include <linux/dmaengine.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/**
1562306a36Sopenharmony_ci * snd_pcm_substream_to_dma_direction - Get dma_transfer_direction for a PCM
1662306a36Sopenharmony_ci *   substream
1762306a36Sopenharmony_ci * @substream: PCM substream
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci * Return: DMA transfer direction
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_cistatic inline enum dma_transfer_direction
2262306a36Sopenharmony_cisnd_pcm_substream_to_dma_direction(const struct snd_pcm_substream *substream)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2562306a36Sopenharmony_ci		return DMA_MEM_TO_DEV;
2662306a36Sopenharmony_ci	else
2762306a36Sopenharmony_ci		return DMA_DEV_TO_MEM;
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ciint snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
3162306a36Sopenharmony_ci	const struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config);
3262306a36Sopenharmony_ciint snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd);
3362306a36Sopenharmony_cisnd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream);
3462306a36Sopenharmony_cisnd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciint snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
3762306a36Sopenharmony_ci	struct dma_chan *chan);
3862306a36Sopenharmony_ciint snd_dmaengine_pcm_close(struct snd_pcm_substream *substream);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ciint snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
4162306a36Sopenharmony_ci	dma_filter_fn filter_fn, void *filter_data);
4262306a36Sopenharmony_ciint snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
4562306a36Sopenharmony_ci	void *filter_data);
4662306a36Sopenharmony_cistruct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/*
4962306a36Sopenharmony_ci * The DAI supports packed transfers, eg 2 16-bit samples in a 32-bit word.
5062306a36Sopenharmony_ci * If this flag is set the dmaengine driver won't put any restriction on
5162306a36Sopenharmony_ci * the supported sample formats and set the DMA transfer size to undefined.
5262306a36Sopenharmony_ci * The DAI driver is responsible to disable any unsupported formats in it's
5362306a36Sopenharmony_ci * configuration and catch corner cases that are not already handled in
5462306a36Sopenharmony_ci * the ALSA core.
5562306a36Sopenharmony_ci */
5662306a36Sopenharmony_ci#define SND_DMAENGINE_PCM_DAI_FLAG_PACK BIT(0)
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/**
5962306a36Sopenharmony_ci * struct snd_dmaengine_dai_dma_data - DAI DMA configuration data
6062306a36Sopenharmony_ci * @addr: Address of the DAI data source or destination register.
6162306a36Sopenharmony_ci * @addr_width: Width of the DAI data source or destination register.
6262306a36Sopenharmony_ci * @maxburst: Maximum number of words(note: words, as in units of the
6362306a36Sopenharmony_ci * src_addr_width member, not bytes) that can be send to or received from the
6462306a36Sopenharmony_ci * DAI in one burst.
6562306a36Sopenharmony_ci * @filter_data: Custom DMA channel filter data, this will usually be used when
6662306a36Sopenharmony_ci * requesting the DMA channel.
6762306a36Sopenharmony_ci * @chan_name: Custom channel name to use when requesting DMA channel.
6862306a36Sopenharmony_ci * @fifo_size: FIFO size of the DAI controller in bytes
6962306a36Sopenharmony_ci * @flags: PCM_DAI flags, only SND_DMAENGINE_PCM_DAI_FLAG_PACK for now
7062306a36Sopenharmony_ci * @peripheral_config: peripheral configuration for programming peripheral
7162306a36Sopenharmony_ci * for dmaengine transfer
7262306a36Sopenharmony_ci * @peripheral_size: peripheral configuration buffer size
7362306a36Sopenharmony_ci */
7462306a36Sopenharmony_cistruct snd_dmaengine_dai_dma_data {
7562306a36Sopenharmony_ci	dma_addr_t addr;
7662306a36Sopenharmony_ci	enum dma_slave_buswidth addr_width;
7762306a36Sopenharmony_ci	u32 maxburst;
7862306a36Sopenharmony_ci	void *filter_data;
7962306a36Sopenharmony_ci	const char *chan_name;
8062306a36Sopenharmony_ci	unsigned int fifo_size;
8162306a36Sopenharmony_ci	unsigned int flags;
8262306a36Sopenharmony_ci	void *peripheral_config;
8362306a36Sopenharmony_ci	size_t peripheral_size;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_civoid snd_dmaengine_pcm_set_config_from_dai_data(
8762306a36Sopenharmony_ci	const struct snd_pcm_substream *substream,
8862306a36Sopenharmony_ci	const struct snd_dmaengine_dai_dma_data *dma_data,
8962306a36Sopenharmony_ci	struct dma_slave_config *config);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciint snd_dmaengine_pcm_refine_runtime_hwparams(
9262306a36Sopenharmony_ci	struct snd_pcm_substream *substream,
9362306a36Sopenharmony_ci	struct snd_dmaengine_dai_dma_data *dma_data,
9462306a36Sopenharmony_ci	struct snd_pcm_hardware *hw,
9562306a36Sopenharmony_ci	struct dma_chan *chan);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci/*
9862306a36Sopenharmony_ci * Try to request the DMA channel using compat_request_channel or
9962306a36Sopenharmony_ci * compat_filter_fn if it couldn't be requested through devicetree.
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_ci#define SND_DMAENGINE_PCM_FLAG_COMPAT BIT(0)
10262306a36Sopenharmony_ci/*
10362306a36Sopenharmony_ci * Don't try to request the DMA channels through devicetree. This flag only
10462306a36Sopenharmony_ci * makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well.
10562306a36Sopenharmony_ci */
10662306a36Sopenharmony_ci#define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1)
10762306a36Sopenharmony_ci/*
10862306a36Sopenharmony_ci * The PCM is half duplex and the DMA channel is shared between capture and
10962306a36Sopenharmony_ci * playback.
11062306a36Sopenharmony_ci */
11162306a36Sopenharmony_ci#define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3)
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci/**
11462306a36Sopenharmony_ci * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM
11562306a36Sopenharmony_ci * @prepare_slave_config: Callback used to fill in the DMA slave_config for a
11662306a36Sopenharmony_ci *   PCM substream. Will be called from the PCM drivers hwparams callback.
11762306a36Sopenharmony_ci * @compat_request_channel: Callback to request a DMA channel for platforms
11862306a36Sopenharmony_ci *   which do not use devicetree.
11962306a36Sopenharmony_ci * @process: Callback used to apply processing on samples transferred from/to
12062306a36Sopenharmony_ci *   user space.
12162306a36Sopenharmony_ci * @compat_filter_fn: Will be used as the filter function when requesting a
12262306a36Sopenharmony_ci *  channel for platforms which do not use devicetree. The filter parameter
12362306a36Sopenharmony_ci *  will be the DAI's DMA data.
12462306a36Sopenharmony_ci * @dma_dev: If set, request DMA channel on this device rather than the DAI
12562306a36Sopenharmony_ci *  device.
12662306a36Sopenharmony_ci * @chan_names: If set, these custom DMA channel names will be requested at
12762306a36Sopenharmony_ci *  registration time.
12862306a36Sopenharmony_ci * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM.
12962306a36Sopenharmony_ci * @prealloc_buffer_size: Size of the preallocated audio buffer.
13062306a36Sopenharmony_ci *
13162306a36Sopenharmony_ci * Note: If both compat_request_channel and compat_filter_fn are set
13262306a36Sopenharmony_ci * compat_request_channel will be used to request the channel and
13362306a36Sopenharmony_ci * compat_filter_fn will be ignored. Otherwise the channel will be requested
13462306a36Sopenharmony_ci * using dma_request_channel with compat_filter_fn as the filter function.
13562306a36Sopenharmony_ci */
13662306a36Sopenharmony_cistruct snd_dmaengine_pcm_config {
13762306a36Sopenharmony_ci	int (*prepare_slave_config)(struct snd_pcm_substream *substream,
13862306a36Sopenharmony_ci			struct snd_pcm_hw_params *params,
13962306a36Sopenharmony_ci			struct dma_slave_config *slave_config);
14062306a36Sopenharmony_ci	struct dma_chan *(*compat_request_channel)(
14162306a36Sopenharmony_ci			struct snd_soc_pcm_runtime *rtd,
14262306a36Sopenharmony_ci			struct snd_pcm_substream *substream);
14362306a36Sopenharmony_ci	int (*process)(struct snd_pcm_substream *substream,
14462306a36Sopenharmony_ci		       int channel, unsigned long hwoff,
14562306a36Sopenharmony_ci		       unsigned long bytes);
14662306a36Sopenharmony_ci	dma_filter_fn compat_filter_fn;
14762306a36Sopenharmony_ci	struct device *dma_dev;
14862306a36Sopenharmony_ci	const char *chan_names[SNDRV_PCM_STREAM_LAST + 1];
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	const struct snd_pcm_hardware *pcm_hardware;
15162306a36Sopenharmony_ci	unsigned int prealloc_buffer_size;
15262306a36Sopenharmony_ci};
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciint snd_dmaengine_pcm_register(struct device *dev,
15562306a36Sopenharmony_ci	const struct snd_dmaengine_pcm_config *config,
15662306a36Sopenharmony_ci	unsigned int flags);
15762306a36Sopenharmony_civoid snd_dmaengine_pcm_unregister(struct device *dev);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ciint devm_snd_dmaengine_pcm_register(struct device *dev,
16062306a36Sopenharmony_ci	const struct snd_dmaengine_pcm_config *config,
16162306a36Sopenharmony_ci	unsigned int flags);
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ciint snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
16462306a36Sopenharmony_ci	struct snd_pcm_hw_params *params,
16562306a36Sopenharmony_ci	struct dma_slave_config *slave_config);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci#define SND_DMAENGINE_PCM_DRV_NAME "snd_dmaengine_pcm"
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_cistruct dmaengine_pcm {
17062306a36Sopenharmony_ci	struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1];
17162306a36Sopenharmony_ci	const struct snd_dmaengine_pcm_config *config;
17262306a36Sopenharmony_ci	struct snd_soc_component component;
17362306a36Sopenharmony_ci	unsigned int flags;
17462306a36Sopenharmony_ci};
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic inline struct dmaengine_pcm *soc_component_to_pcm(struct snd_soc_component *p)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	return container_of(p, struct dmaengine_pcm, component);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci#endif
181