xref: /linux/sound/soc/sprd/sprd-pcm-dma.c (revision a87a5c6e)
142fea318SBaolin Wang // SPDX-License-Identifier: GPL-2.0
242fea318SBaolin Wang // Copyright (C) 2019 Spreadtrum Communications Inc.
342fea318SBaolin Wang 
442fea318SBaolin Wang #include <linux/dma-mapping.h>
542fea318SBaolin Wang #include <linux/dmaengine.h>
642fea318SBaolin Wang #include <linux/dma/sprd-dma.h>
742fea318SBaolin Wang #include <linux/kernel.h>
842fea318SBaolin Wang #include <linux/module.h>
91587a061SBaolin Wang #include <linux/of_reserved_mem.h>
1042fea318SBaolin Wang #include <linux/platform_device.h>
1142fea318SBaolin Wang #include <sound/pcm.h>
1242fea318SBaolin Wang #include <sound/pcm_params.h>
1342fea318SBaolin Wang #include <sound/soc.h>
1442fea318SBaolin Wang 
1542fea318SBaolin Wang #include "sprd-pcm-dma.h"
1642fea318SBaolin Wang 
1742fea318SBaolin Wang #define SPRD_PCM_DMA_LINKLIST_SIZE	64
1842fea318SBaolin Wang #define SPRD_PCM_DMA_BRUST_LEN		640
1942fea318SBaolin Wang 
2042fea318SBaolin Wang struct sprd_pcm_dma_data {
2142fea318SBaolin Wang 	struct dma_chan *chan;
2242fea318SBaolin Wang 	struct dma_async_tx_descriptor *desc;
2342fea318SBaolin Wang 	dma_cookie_t cookie;
2442fea318SBaolin Wang 	dma_addr_t phys;
2542fea318SBaolin Wang 	void *virt;
2642fea318SBaolin Wang 	int pre_pointer;
2742fea318SBaolin Wang };
2842fea318SBaolin Wang 
2942fea318SBaolin Wang struct sprd_pcm_dma_private {
3042fea318SBaolin Wang 	struct snd_pcm_substream *substream;
3142fea318SBaolin Wang 	struct sprd_pcm_dma_params *params;
3242fea318SBaolin Wang 	struct sprd_pcm_dma_data data[SPRD_PCM_CHANNEL_MAX];
3342fea318SBaolin Wang 	int hw_chan;
3442fea318SBaolin Wang 	int dma_addr_offset;
3542fea318SBaolin Wang };
3642fea318SBaolin Wang 
3742fea318SBaolin Wang static const struct snd_pcm_hardware sprd_pcm_hardware = {
3842fea318SBaolin Wang 	.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
3942fea318SBaolin Wang 		SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE |
4042fea318SBaolin Wang 		SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
4142fea318SBaolin Wang 	.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
4242fea318SBaolin Wang 	.period_bytes_min = 1,
4342fea318SBaolin Wang 	.period_bytes_max = 64 * 1024,
4442fea318SBaolin Wang 	.periods_min = 1,
4542fea318SBaolin Wang 	.periods_max = PAGE_SIZE / SPRD_PCM_DMA_LINKLIST_SIZE,
4642fea318SBaolin Wang 	.buffer_bytes_max = 64 * 1024,
4742fea318SBaolin Wang };
4842fea318SBaolin Wang 
sprd_pcm_open(struct snd_soc_component * component,struct snd_pcm_substream * substream)496702eed8SKuninori Morimoto static int sprd_pcm_open(struct snd_soc_component *component,
506702eed8SKuninori Morimoto 			 struct snd_pcm_substream *substream)
5142fea318SBaolin Wang {
5242fea318SBaolin Wang 	struct snd_pcm_runtime *runtime = substream->runtime;
5342fea318SBaolin Wang 	struct device *dev = component->dev;
5442fea318SBaolin Wang 	struct sprd_pcm_dma_private *dma_private;
5542fea318SBaolin Wang 	int hw_chan = SPRD_PCM_CHANNEL_MAX;
5642fea318SBaolin Wang 	int size, ret, i;
5742fea318SBaolin Wang 
5842fea318SBaolin Wang 	snd_soc_set_runtime_hwparams(substream, &sprd_pcm_hardware);
5942fea318SBaolin Wang 
6042fea318SBaolin Wang 	ret = snd_pcm_hw_constraint_step(runtime, 0,
6142fea318SBaolin Wang 					 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
6242fea318SBaolin Wang 					 SPRD_PCM_DMA_BRUST_LEN);
6342fea318SBaolin Wang 	if (ret < 0)
6442fea318SBaolin Wang 		return ret;
6542fea318SBaolin Wang 
6642fea318SBaolin Wang 	ret = snd_pcm_hw_constraint_step(runtime, 0,
6742fea318SBaolin Wang 					 SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
6842fea318SBaolin Wang 					 SPRD_PCM_DMA_BRUST_LEN);
6942fea318SBaolin Wang 	if (ret < 0)
7042fea318SBaolin Wang 		return ret;
7142fea318SBaolin Wang 
7242fea318SBaolin Wang 	ret = snd_pcm_hw_constraint_integer(runtime,
7342fea318SBaolin Wang 					    SNDRV_PCM_HW_PARAM_PERIODS);
7442fea318SBaolin Wang 	if (ret < 0)
7542fea318SBaolin Wang 		return ret;
7642fea318SBaolin Wang 
7742fea318SBaolin Wang 	dma_private = devm_kzalloc(dev, sizeof(*dma_private), GFP_KERNEL);
7842fea318SBaolin Wang 	if (!dma_private)
7942fea318SBaolin Wang 		return -ENOMEM;
8042fea318SBaolin Wang 
8142fea318SBaolin Wang 	size = runtime->hw.periods_max * SPRD_PCM_DMA_LINKLIST_SIZE;
8242fea318SBaolin Wang 
8342fea318SBaolin Wang 	for (i = 0; i < hw_chan; i++) {
8442fea318SBaolin Wang 		struct sprd_pcm_dma_data *data = &dma_private->data[i];
8542fea318SBaolin Wang 
8642fea318SBaolin Wang 		data->virt = dmam_alloc_coherent(dev, size, &data->phys,
8742fea318SBaolin Wang 						 GFP_KERNEL);
8842fea318SBaolin Wang 		if (!data->virt) {
8942fea318SBaolin Wang 			ret = -ENOMEM;
9042fea318SBaolin Wang 			goto error;
9142fea318SBaolin Wang 		}
9242fea318SBaolin Wang 	}
9342fea318SBaolin Wang 
9442fea318SBaolin Wang 	dma_private->hw_chan = hw_chan;
9542fea318SBaolin Wang 	runtime->private_data = dma_private;
9642fea318SBaolin Wang 	dma_private->substream = substream;
9742fea318SBaolin Wang 
9842fea318SBaolin Wang 	return 0;
9942fea318SBaolin Wang 
10042fea318SBaolin Wang error:
10142fea318SBaolin Wang 	for (i = 0; i < hw_chan; i++) {
10242fea318SBaolin Wang 		struct sprd_pcm_dma_data *data = &dma_private->data[i];
10342fea318SBaolin Wang 
10442fea318SBaolin Wang 		if (data->virt)
10542fea318SBaolin Wang 			dmam_free_coherent(dev, size, data->virt, data->phys);
10642fea318SBaolin Wang 	}
10742fea318SBaolin Wang 
10842fea318SBaolin Wang 	devm_kfree(dev, dma_private);
10942fea318SBaolin Wang 	return ret;
11042fea318SBaolin Wang }
11142fea318SBaolin Wang 
sprd_pcm_close(struct snd_soc_component * component,struct snd_pcm_substream * substream)1126702eed8SKuninori Morimoto static int sprd_pcm_close(struct snd_soc_component *component,
1136702eed8SKuninori Morimoto 			  struct snd_pcm_substream *substream)
11442fea318SBaolin Wang {
11542fea318SBaolin Wang 	struct snd_pcm_runtime *runtime = substream->runtime;
11642fea318SBaolin Wang 	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
11742fea318SBaolin Wang 	struct device *dev = component->dev;
11842fea318SBaolin Wang 	int size = runtime->hw.periods_max * SPRD_PCM_DMA_LINKLIST_SIZE;
11942fea318SBaolin Wang 	int i;
12042fea318SBaolin Wang 
12142fea318SBaolin Wang 	for (i = 0; i < dma_private->hw_chan; i++) {
12242fea318SBaolin Wang 		struct sprd_pcm_dma_data *data = &dma_private->data[i];
12342fea318SBaolin Wang 
12442fea318SBaolin Wang 		dmam_free_coherent(dev, size, data->virt, data->phys);
12542fea318SBaolin Wang 	}
12642fea318SBaolin Wang 
12742fea318SBaolin Wang 	devm_kfree(dev, dma_private);
12842fea318SBaolin Wang 
12942fea318SBaolin Wang 	return 0;
13042fea318SBaolin Wang }
13142fea318SBaolin Wang 
sprd_pcm_dma_complete(void * data)13242fea318SBaolin Wang static void sprd_pcm_dma_complete(void *data)
13342fea318SBaolin Wang {
13442fea318SBaolin Wang 	struct sprd_pcm_dma_private *dma_private = data;
13542fea318SBaolin Wang 	struct snd_pcm_substream *substream = dma_private->substream;
13642fea318SBaolin Wang 
13742fea318SBaolin Wang 	snd_pcm_period_elapsed(substream);
13842fea318SBaolin Wang }
13942fea318SBaolin Wang 
sprd_pcm_release_dma_channel(struct snd_pcm_substream * substream)14042fea318SBaolin Wang static void sprd_pcm_release_dma_channel(struct snd_pcm_substream *substream)
14142fea318SBaolin Wang {
14242fea318SBaolin Wang 	struct snd_pcm_runtime *runtime = substream->runtime;
14342fea318SBaolin Wang 	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
14442fea318SBaolin Wang 	int i;
14542fea318SBaolin Wang 
14642fea318SBaolin Wang 	for (i = 0; i < SPRD_PCM_CHANNEL_MAX; i++) {
14742fea318SBaolin Wang 		struct sprd_pcm_dma_data *data = &dma_private->data[i];
14842fea318SBaolin Wang 
14942fea318SBaolin Wang 		if (data->chan) {
15042fea318SBaolin Wang 			dma_release_channel(data->chan);
15142fea318SBaolin Wang 			data->chan = NULL;
15242fea318SBaolin Wang 		}
15342fea318SBaolin Wang 	}
15442fea318SBaolin Wang }
15542fea318SBaolin Wang 
sprd_pcm_request_dma_channel(struct snd_soc_component * component,struct snd_pcm_substream * substream,int channels)1566702eed8SKuninori Morimoto static int sprd_pcm_request_dma_channel(struct snd_soc_component *component,
1576702eed8SKuninori Morimoto 					struct snd_pcm_substream *substream,
15842fea318SBaolin Wang 					int channels)
15942fea318SBaolin Wang {
16042fea318SBaolin Wang 	struct snd_pcm_runtime *runtime = substream->runtime;
16142fea318SBaolin Wang 	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
16242fea318SBaolin Wang 	struct device *dev = component->dev;
16342fea318SBaolin Wang 	struct sprd_pcm_dma_params *dma_params = dma_private->params;
16442fea318SBaolin Wang 	int i;
16542fea318SBaolin Wang 
16642fea318SBaolin Wang 	if (channels > SPRD_PCM_CHANNEL_MAX) {
16742fea318SBaolin Wang 		dev_err(dev, "invalid dma channel number:%d\n", channels);
16842fea318SBaolin Wang 		return -EINVAL;
16942fea318SBaolin Wang 	}
17042fea318SBaolin Wang 
17142fea318SBaolin Wang 	for (i = 0; i < channels; i++) {
17242fea318SBaolin Wang 		struct sprd_pcm_dma_data *data = &dma_private->data[i];
17342fea318SBaolin Wang 
17442fea318SBaolin Wang 		data->chan = dma_request_slave_channel(dev,
17542fea318SBaolin Wang 						       dma_params->chan_name[i]);
17642fea318SBaolin Wang 		if (!data->chan) {
17742fea318SBaolin Wang 			dev_err(dev, "failed to request dma channel:%s\n",
17842fea318SBaolin Wang 				dma_params->chan_name[i]);
17942fea318SBaolin Wang 			sprd_pcm_release_dma_channel(substream);
18042fea318SBaolin Wang 			return -ENODEV;
18142fea318SBaolin Wang 		}
18242fea318SBaolin Wang 	}
18342fea318SBaolin Wang 
18442fea318SBaolin Wang 	return 0;
18542fea318SBaolin Wang }
18642fea318SBaolin Wang 
sprd_pcm_hw_params(struct snd_soc_component * component,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)1876702eed8SKuninori Morimoto static int sprd_pcm_hw_params(struct snd_soc_component *component,
1886702eed8SKuninori Morimoto 			      struct snd_pcm_substream *substream,
18942fea318SBaolin Wang 			      struct snd_pcm_hw_params *params)
19042fea318SBaolin Wang {
19142fea318SBaolin Wang 	struct snd_pcm_runtime *runtime = substream->runtime;
19242fea318SBaolin Wang 	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
193*a87a5c6eSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
19442fea318SBaolin Wang 	struct sprd_pcm_dma_params *dma_params;
19542fea318SBaolin Wang 	size_t totsize = params_buffer_bytes(params);
19642fea318SBaolin Wang 	size_t period = params_period_bytes(params);
19742fea318SBaolin Wang 	int channels = params_channels(params);
19842fea318SBaolin Wang 	int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
19942fea318SBaolin Wang 	struct scatterlist *sg;
20042fea318SBaolin Wang 	unsigned long flags;
20142fea318SBaolin Wang 	int ret, i, j, sg_num;
20242fea318SBaolin Wang 
203*a87a5c6eSKuninori Morimoto 	dma_params = snd_soc_dai_get_dma_data(snd_soc_rtd_to_cpu(rtd, 0), substream);
20442fea318SBaolin Wang 	if (!dma_params) {
20542fea318SBaolin Wang 		dev_warn(component->dev, "no dma parameters setting\n");
20642fea318SBaolin Wang 		dma_private->params = NULL;
20742fea318SBaolin Wang 		return 0;
20842fea318SBaolin Wang 	}
20942fea318SBaolin Wang 
21042fea318SBaolin Wang 	if (!dma_private->params) {
21142fea318SBaolin Wang 		dma_private->params = dma_params;
2126702eed8SKuninori Morimoto 		ret = sprd_pcm_request_dma_channel(component,
2136702eed8SKuninori Morimoto 						   substream, channels);
21442fea318SBaolin Wang 		if (ret)
21542fea318SBaolin Wang 			return ret;
21642fea318SBaolin Wang 	}
21742fea318SBaolin Wang 
21842fea318SBaolin Wang 	sg_num = totsize / period;
21942fea318SBaolin Wang 	dma_private->dma_addr_offset = totsize / channels;
22042fea318SBaolin Wang 
22142fea318SBaolin Wang 	sg = devm_kcalloc(component->dev, sg_num, sizeof(*sg), GFP_KERNEL);
22242fea318SBaolin Wang 	if (!sg) {
22342fea318SBaolin Wang 		ret = -ENOMEM;
22442fea318SBaolin Wang 		goto sg_err;
22542fea318SBaolin Wang 	}
22642fea318SBaolin Wang 
22742fea318SBaolin Wang 	for (i = 0; i < channels; i++) {
22842fea318SBaolin Wang 		struct sprd_pcm_dma_data *data = &dma_private->data[i];
22942fea318SBaolin Wang 		struct dma_chan *chan = data->chan;
23042fea318SBaolin Wang 		struct dma_slave_config config = { };
23142fea318SBaolin Wang 		struct sprd_dma_linklist link = { };
23242fea318SBaolin Wang 		enum dma_transfer_direction dir;
23342fea318SBaolin Wang 		struct scatterlist *sgt = sg;
23442fea318SBaolin Wang 
23542fea318SBaolin Wang 		config.src_maxburst = dma_params->fragment_len[i];
23642fea318SBaolin Wang 		config.src_addr_width = dma_params->datawidth[i];
23742fea318SBaolin Wang 		config.dst_addr_width = dma_params->datawidth[i];
23842fea318SBaolin Wang 		if (is_playback) {
23942fea318SBaolin Wang 			config.src_addr = runtime->dma_addr +
24042fea318SBaolin Wang 				i * dma_private->dma_addr_offset;
24142fea318SBaolin Wang 			config.dst_addr = dma_params->dev_phys[i];
24242fea318SBaolin Wang 			dir = DMA_MEM_TO_DEV;
24342fea318SBaolin Wang 		} else {
24442fea318SBaolin Wang 			config.src_addr = dma_params->dev_phys[i];
24542fea318SBaolin Wang 			config.dst_addr = runtime->dma_addr +
24642fea318SBaolin Wang 				i * dma_private->dma_addr_offset;
24742fea318SBaolin Wang 			dir = DMA_DEV_TO_MEM;
24842fea318SBaolin Wang 		}
24942fea318SBaolin Wang 
25042fea318SBaolin Wang 		sg_init_table(sgt, sg_num);
25142fea318SBaolin Wang 		for (j = 0; j < sg_num; j++, sgt++) {
25242fea318SBaolin Wang 			u32 sg_len = period / channels;
25342fea318SBaolin Wang 
25442fea318SBaolin Wang 			sg_dma_len(sgt) = sg_len;
25542fea318SBaolin Wang 			sg_dma_address(sgt) = runtime->dma_addr +
25642fea318SBaolin Wang 				i * dma_private->dma_addr_offset + sg_len * j;
25742fea318SBaolin Wang 		}
25842fea318SBaolin Wang 
25942fea318SBaolin Wang 		/*
26042fea318SBaolin Wang 		 * Configure the link-list address for the DMA engine link-list
26142fea318SBaolin Wang 		 * mode.
26242fea318SBaolin Wang 		 */
26342fea318SBaolin Wang 		link.virt_addr = (unsigned long)data->virt;
26442fea318SBaolin Wang 		link.phy_addr = data->phys;
26542fea318SBaolin Wang 
26642fea318SBaolin Wang 		ret = dmaengine_slave_config(chan, &config);
26742fea318SBaolin Wang 		if (ret) {
26842fea318SBaolin Wang 			dev_err(component->dev,
26942fea318SBaolin Wang 				"failed to set slave configuration: %d\n", ret);
27042fea318SBaolin Wang 			goto config_err;
27142fea318SBaolin Wang 		}
27242fea318SBaolin Wang 
27342fea318SBaolin Wang 		/*
27442fea318SBaolin Wang 		 * We configure the DMA request mode, interrupt mode, channel
27542fea318SBaolin Wang 		 * mode and channel trigger mode by the flags.
27642fea318SBaolin Wang 		 */
27742fea318SBaolin Wang 		flags = SPRD_DMA_FLAGS(SPRD_DMA_CHN_MODE_NONE, SPRD_DMA_NO_TRG,
27842fea318SBaolin Wang 				       SPRD_DMA_FRAG_REQ, SPRD_DMA_TRANS_INT);
27942fea318SBaolin Wang 		data->desc = chan->device->device_prep_slave_sg(chan, sg,
28042fea318SBaolin Wang 								sg_num, dir,
28142fea318SBaolin Wang 								flags, &link);
28242fea318SBaolin Wang 		if (!data->desc) {
28342fea318SBaolin Wang 			dev_err(component->dev, "failed to prepare slave sg\n");
28442fea318SBaolin Wang 			ret = -ENOMEM;
28542fea318SBaolin Wang 			goto config_err;
28642fea318SBaolin Wang 		}
28742fea318SBaolin Wang 
28842fea318SBaolin Wang 		if (!runtime->no_period_wakeup) {
28942fea318SBaolin Wang 			data->desc->callback = sprd_pcm_dma_complete;
29042fea318SBaolin Wang 			data->desc->callback_param = dma_private;
29142fea318SBaolin Wang 		}
29242fea318SBaolin Wang 	}
29342fea318SBaolin Wang 
29442fea318SBaolin Wang 	devm_kfree(component->dev, sg);
29542fea318SBaolin Wang 
29642fea318SBaolin Wang 	return 0;
29742fea318SBaolin Wang 
29842fea318SBaolin Wang config_err:
29942fea318SBaolin Wang 	devm_kfree(component->dev, sg);
30042fea318SBaolin Wang sg_err:
30142fea318SBaolin Wang 	sprd_pcm_release_dma_channel(substream);
30242fea318SBaolin Wang 	return ret;
30342fea318SBaolin Wang }
30442fea318SBaolin Wang 
sprd_pcm_hw_free(struct snd_soc_component * component,struct snd_pcm_substream * substream)3056702eed8SKuninori Morimoto static int sprd_pcm_hw_free(struct snd_soc_component *component,
3066702eed8SKuninori Morimoto 			    struct snd_pcm_substream *substream)
30742fea318SBaolin Wang {
30842fea318SBaolin Wang 	sprd_pcm_release_dma_channel(substream);
30942fea318SBaolin Wang 
31042fea318SBaolin Wang 	return 0;
31142fea318SBaolin Wang }
31242fea318SBaolin Wang 
sprd_pcm_trigger(struct snd_soc_component * component,struct snd_pcm_substream * substream,int cmd)3136702eed8SKuninori Morimoto static int sprd_pcm_trigger(struct snd_soc_component *component,
3146702eed8SKuninori Morimoto 			    struct snd_pcm_substream *substream, int cmd)
31542fea318SBaolin Wang {
31642fea318SBaolin Wang 	struct sprd_pcm_dma_private *dma_private =
31742fea318SBaolin Wang 		substream->runtime->private_data;
31842fea318SBaolin Wang 	int ret = 0, i;
31942fea318SBaolin Wang 
32042fea318SBaolin Wang 	switch (cmd) {
32142fea318SBaolin Wang 	case SNDRV_PCM_TRIGGER_START:
32242fea318SBaolin Wang 		for (i = 0; i < dma_private->hw_chan; i++) {
32342fea318SBaolin Wang 			struct sprd_pcm_dma_data *data = &dma_private->data[i];
32442fea318SBaolin Wang 
32542fea318SBaolin Wang 			if (!data->desc)
32642fea318SBaolin Wang 				continue;
32742fea318SBaolin Wang 
32842fea318SBaolin Wang 			data->cookie = dmaengine_submit(data->desc);
32942fea318SBaolin Wang 			ret = dma_submit_error(data->cookie);
33042fea318SBaolin Wang 			if (ret) {
33142fea318SBaolin Wang 				dev_err(component->dev,
33242fea318SBaolin Wang 					"failed to submit dma request: %d\n",
33342fea318SBaolin Wang 					ret);
33442fea318SBaolin Wang 				return ret;
33542fea318SBaolin Wang 			}
33642fea318SBaolin Wang 
33742fea318SBaolin Wang 			dma_async_issue_pending(data->chan);
33842fea318SBaolin Wang 		}
33942fea318SBaolin Wang 
34042fea318SBaolin Wang 		break;
34142fea318SBaolin Wang 	case SNDRV_PCM_TRIGGER_RESUME:
34242fea318SBaolin Wang 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
34342fea318SBaolin Wang 		for (i = 0; i < dma_private->hw_chan; i++) {
34442fea318SBaolin Wang 			struct sprd_pcm_dma_data *data = &dma_private->data[i];
34542fea318SBaolin Wang 
34642fea318SBaolin Wang 			if (data->chan)
34742fea318SBaolin Wang 				dmaengine_resume(data->chan);
34842fea318SBaolin Wang 		}
34942fea318SBaolin Wang 
35042fea318SBaolin Wang 		break;
35142fea318SBaolin Wang 	case SNDRV_PCM_TRIGGER_STOP:
35242fea318SBaolin Wang 		for (i = 0; i < dma_private->hw_chan; i++) {
35342fea318SBaolin Wang 			struct sprd_pcm_dma_data *data = &dma_private->data[i];
35442fea318SBaolin Wang 
35542fea318SBaolin Wang 			if (data->chan)
35642fea318SBaolin Wang 				dmaengine_terminate_async(data->chan);
35742fea318SBaolin Wang 		}
35842fea318SBaolin Wang 
35942fea318SBaolin Wang 		break;
36042fea318SBaolin Wang 	case SNDRV_PCM_TRIGGER_SUSPEND:
36142fea318SBaolin Wang 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
36242fea318SBaolin Wang 		for (i = 0; i < dma_private->hw_chan; i++) {
36342fea318SBaolin Wang 			struct sprd_pcm_dma_data *data = &dma_private->data[i];
36442fea318SBaolin Wang 
36542fea318SBaolin Wang 			if (data->chan)
36642fea318SBaolin Wang 				dmaengine_pause(data->chan);
36742fea318SBaolin Wang 		}
36842fea318SBaolin Wang 
36942fea318SBaolin Wang 		break;
37042fea318SBaolin Wang 	default:
37142fea318SBaolin Wang 		ret = -EINVAL;
37242fea318SBaolin Wang 	}
37342fea318SBaolin Wang 
37442fea318SBaolin Wang 	return ret;
37542fea318SBaolin Wang }
37642fea318SBaolin Wang 
sprd_pcm_pointer(struct snd_soc_component * component,struct snd_pcm_substream * substream)3776702eed8SKuninori Morimoto static snd_pcm_uframes_t sprd_pcm_pointer(struct snd_soc_component *component,
3786702eed8SKuninori Morimoto 					  struct snd_pcm_substream *substream)
37942fea318SBaolin Wang {
38042fea318SBaolin Wang 	struct snd_pcm_runtime *runtime = substream->runtime;
38142fea318SBaolin Wang 	struct sprd_pcm_dma_private *dma_private = runtime->private_data;
38242fea318SBaolin Wang 	int pointer[SPRD_PCM_CHANNEL_MAX];
38342fea318SBaolin Wang 	int bytes_of_pointer = 0, sel_max = 0, i;
38442fea318SBaolin Wang 	snd_pcm_uframes_t x;
38542fea318SBaolin Wang 	struct dma_tx_state state;
38642fea318SBaolin Wang 	enum dma_status status;
38742fea318SBaolin Wang 
38842fea318SBaolin Wang 	for (i = 0; i < dma_private->hw_chan; i++) {
38942fea318SBaolin Wang 		struct sprd_pcm_dma_data *data = &dma_private->data[i];
39042fea318SBaolin Wang 
39142fea318SBaolin Wang 		if (!data->chan)
39242fea318SBaolin Wang 			continue;
39342fea318SBaolin Wang 
39442fea318SBaolin Wang 		status = dmaengine_tx_status(data->chan, data->cookie, &state);
39542fea318SBaolin Wang 		if (status == DMA_ERROR) {
39642fea318SBaolin Wang 			dev_err(component->dev,
39742fea318SBaolin Wang 				"failed to get dma channel %d status\n", i);
39842fea318SBaolin Wang 			return 0;
39942fea318SBaolin Wang 		}
40042fea318SBaolin Wang 
40142fea318SBaolin Wang 		/*
40242fea318SBaolin Wang 		 * We just get current transfer address from the DMA engine, so
40342fea318SBaolin Wang 		 * we need convert to current pointer.
40442fea318SBaolin Wang 		 */
40542fea318SBaolin Wang 		pointer[i] = state.residue - runtime->dma_addr -
40642fea318SBaolin Wang 			i * dma_private->dma_addr_offset;
40742fea318SBaolin Wang 
40842fea318SBaolin Wang 		if (i == 0) {
40942fea318SBaolin Wang 			bytes_of_pointer = pointer[i];
41042fea318SBaolin Wang 			sel_max = pointer[i] < data->pre_pointer ? 1 : 0;
41142fea318SBaolin Wang 		} else {
41242fea318SBaolin Wang 			sel_max ^= pointer[i] < data->pre_pointer ? 1 : 0;
41342fea318SBaolin Wang 
41442fea318SBaolin Wang 			if (sel_max)
41542fea318SBaolin Wang 				bytes_of_pointer =
41642fea318SBaolin Wang 					max(pointer[i], pointer[i - 1]) << 1;
41742fea318SBaolin Wang 			else
41842fea318SBaolin Wang 				bytes_of_pointer =
41942fea318SBaolin Wang 					min(pointer[i], pointer[i - 1]) << 1;
42042fea318SBaolin Wang 		}
42142fea318SBaolin Wang 
42242fea318SBaolin Wang 		data->pre_pointer = pointer[i];
42342fea318SBaolin Wang 	}
42442fea318SBaolin Wang 
42542fea318SBaolin Wang 	x = bytes_to_frames(runtime, bytes_of_pointer);
42642fea318SBaolin Wang 	if (x == runtime->buffer_size)
42742fea318SBaolin Wang 		x = 0;
42842fea318SBaolin Wang 
42942fea318SBaolin Wang 	return x;
43042fea318SBaolin Wang }
43142fea318SBaolin Wang 
sprd_pcm_new(struct snd_soc_component * component,struct snd_soc_pcm_runtime * rtd)4326702eed8SKuninori Morimoto static int sprd_pcm_new(struct snd_soc_component *component,
4336702eed8SKuninori Morimoto 			struct snd_soc_pcm_runtime *rtd)
43442fea318SBaolin Wang {
43542fea318SBaolin Wang 	struct snd_card *card = rtd->card->snd_card;
43642fea318SBaolin Wang 	struct snd_pcm *pcm = rtd->pcm;
43742fea318SBaolin Wang 	int ret;
43842fea318SBaolin Wang 
43942fea318SBaolin Wang 	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
44042fea318SBaolin Wang 	if (ret)
44142fea318SBaolin Wang 		return ret;
44242fea318SBaolin Wang 
443ba447289STakashi Iwai 	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
444ba447289STakashi Iwai 					    card->dev,
445ba447289STakashi Iwai 					    sprd_pcm_hardware.buffer_bytes_max);
44642fea318SBaolin Wang }
44742fea318SBaolin Wang 
44842fea318SBaolin Wang static const struct snd_soc_component_driver sprd_soc_component = {
44942fea318SBaolin Wang 	.name		= DRV_NAME,
4506702eed8SKuninori Morimoto 	.open		= sprd_pcm_open,
4516702eed8SKuninori Morimoto 	.close		= sprd_pcm_close,
4526702eed8SKuninori Morimoto 	.hw_params	= sprd_pcm_hw_params,
4536702eed8SKuninori Morimoto 	.hw_free	= sprd_pcm_hw_free,
4546702eed8SKuninori Morimoto 	.trigger	= sprd_pcm_trigger,
4556702eed8SKuninori Morimoto 	.pointer	= sprd_pcm_pointer,
4566702eed8SKuninori Morimoto 	.pcm_construct	= sprd_pcm_new,
45727ecad21SKuninori Morimoto 	.compress_ops	= &sprd_platform_compress_ops,
45842fea318SBaolin Wang };
45942fea318SBaolin Wang 
sprd_soc_platform_probe(struct platform_device * pdev)46042fea318SBaolin Wang static int sprd_soc_platform_probe(struct platform_device *pdev)
46142fea318SBaolin Wang {
4621587a061SBaolin Wang 	struct device_node *np = pdev->dev.of_node;
46342fea318SBaolin Wang 	int ret;
46442fea318SBaolin Wang 
4651587a061SBaolin Wang 	ret = of_reserved_mem_device_init_by_idx(&pdev->dev, np, 0);
4661587a061SBaolin Wang 	if (ret)
4671587a061SBaolin Wang 		dev_warn(&pdev->dev,
4681587a061SBaolin Wang 			 "no reserved DMA memory for audio platform device\n");
4691587a061SBaolin Wang 
47042fea318SBaolin Wang 	ret = devm_snd_soc_register_component(&pdev->dev, &sprd_soc_component,
47142fea318SBaolin Wang 					      NULL, 0);
47242fea318SBaolin Wang 	if (ret)
47342fea318SBaolin Wang 		dev_err(&pdev->dev, "could not register platform:%d\n", ret);
47442fea318SBaolin Wang 
47542fea318SBaolin Wang 	return ret;
47642fea318SBaolin Wang }
47742fea318SBaolin Wang 
47842fea318SBaolin Wang static const struct of_device_id sprd_pcm_of_match[] = {
47942fea318SBaolin Wang 	{ .compatible = "sprd,pcm-platform", },
48042fea318SBaolin Wang 	{ },
48142fea318SBaolin Wang };
48242fea318SBaolin Wang MODULE_DEVICE_TABLE(of, sprd_pcm_of_match);
48342fea318SBaolin Wang 
48442fea318SBaolin Wang static struct platform_driver sprd_pcm_driver = {
48542fea318SBaolin Wang 	.driver = {
48642fea318SBaolin Wang 		.name = "sprd-pcm-audio",
48742fea318SBaolin Wang 		.of_match_table = sprd_pcm_of_match,
48842fea318SBaolin Wang 	},
48942fea318SBaolin Wang 
49042fea318SBaolin Wang 	.probe = sprd_soc_platform_probe,
49142fea318SBaolin Wang };
49242fea318SBaolin Wang 
49342fea318SBaolin Wang module_platform_driver(sprd_pcm_driver);
49442fea318SBaolin Wang 
49542fea318SBaolin Wang MODULE_DESCRIPTION("Spreadtrum ASoC PCM DMA");
49642fea318SBaolin Wang MODULE_LICENSE("GPL v2");
49742fea318SBaolin Wang MODULE_ALIAS("platform:sprd-audio");
498