xref: /linux/sound/soc/qcom/qdsp6/q6apm-dai.c (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
19b4fe0f1SSrinivas Kandagatla // SPDX-License-Identifier: GPL-2.0
29b4fe0f1SSrinivas Kandagatla // Copyright (c) 2021, Linaro Limited
39b4fe0f1SSrinivas Kandagatla 
49b4fe0f1SSrinivas Kandagatla #include <linux/init.h>
59b4fe0f1SSrinivas Kandagatla #include <linux/err.h>
69b4fe0f1SSrinivas Kandagatla #include <linux/module.h>
7340d79a1SRob Herring #include <linux/of.h>
89b4fe0f1SSrinivas Kandagatla #include <linux/platform_device.h>
99b4fe0f1SSrinivas Kandagatla #include <linux/slab.h>
109b4fe0f1SSrinivas Kandagatla #include <sound/soc.h>
119b4fe0f1SSrinivas Kandagatla #include <sound/soc-dapm.h>
1284222ef5SSrinivas Kandagatla #include <linux/spinlock.h>
139b4fe0f1SSrinivas Kandagatla #include <sound/pcm.h>
149b4fe0f1SSrinivas Kandagatla #include <asm/dma.h>
159b4fe0f1SSrinivas Kandagatla #include <linux/dma-mapping.h>
169b4fe0f1SSrinivas Kandagatla #include <sound/pcm_params.h>
179b4fe0f1SSrinivas Kandagatla #include "q6apm.h"
189b4fe0f1SSrinivas Kandagatla 
199b4fe0f1SSrinivas Kandagatla #define DRV_NAME "q6apm-dai"
209b4fe0f1SSrinivas Kandagatla 
219b4fe0f1SSrinivas Kandagatla #define PLAYBACK_MIN_NUM_PERIODS	2
229b4fe0f1SSrinivas Kandagatla #define PLAYBACK_MAX_NUM_PERIODS	8
239b4fe0f1SSrinivas Kandagatla #define PLAYBACK_MAX_PERIOD_SIZE	65536
249b4fe0f1SSrinivas Kandagatla #define PLAYBACK_MIN_PERIOD_SIZE	128
259b4fe0f1SSrinivas Kandagatla #define CAPTURE_MIN_NUM_PERIODS		2
269b4fe0f1SSrinivas Kandagatla #define CAPTURE_MAX_NUM_PERIODS		8
275d01ed9bSSrinivas Kandagatla #define CAPTURE_MAX_PERIOD_SIZE		65536
285d01ed9bSSrinivas Kandagatla #define CAPTURE_MIN_PERIOD_SIZE		6144
299b4fe0f1SSrinivas Kandagatla #define BUFFER_BYTES_MAX (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE)
309b4fe0f1SSrinivas Kandagatla #define BUFFER_BYTES_MIN (PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE)
3188b60bf0SSrinivas Kandagatla #define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
3288b60bf0SSrinivas Kandagatla #define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
33c0c87738SSrinivas Kandagatla #define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
34c0c87738SSrinivas Kandagatla #define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
359b4fe0f1SSrinivas Kandagatla #define SID_MASK_DEFAULT	0xF
369b4fe0f1SSrinivas Kandagatla 
37c0c87738SSrinivas Kandagatla static const struct snd_compr_codec_caps q6apm_compr_caps = {
38c0c87738SSrinivas Kandagatla 	.num_descriptors = 1,
39c0c87738SSrinivas Kandagatla 	.descriptor[0].max_ch = 2,
40c0c87738SSrinivas Kandagatla 	.descriptor[0].sample_rates = {	8000, 11025, 12000, 16000, 22050,
41c0c87738SSrinivas Kandagatla 					24000, 32000, 44100, 48000, 88200,
42c0c87738SSrinivas Kandagatla 					96000, 176400, 192000 },
43c0c87738SSrinivas Kandagatla 	.descriptor[0].num_sample_rates = 13,
44c0c87738SSrinivas Kandagatla 	.descriptor[0].bit_rate[0] = 320,
45c0c87738SSrinivas Kandagatla 	.descriptor[0].bit_rate[1] = 128,
46c0c87738SSrinivas Kandagatla 	.descriptor[0].num_bitrates = 2,
47c0c87738SSrinivas Kandagatla 	.descriptor[0].profiles = 0,
48c0c87738SSrinivas Kandagatla 	.descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
49c0c87738SSrinivas Kandagatla 	.descriptor[0].formats = 0,
50c0c87738SSrinivas Kandagatla };
51c0c87738SSrinivas Kandagatla 
529b4fe0f1SSrinivas Kandagatla enum stream_state {
539b4fe0f1SSrinivas Kandagatla 	Q6APM_STREAM_IDLE = 0,
549b4fe0f1SSrinivas Kandagatla 	Q6APM_STREAM_STOPPED,
559b4fe0f1SSrinivas Kandagatla 	Q6APM_STREAM_RUNNING,
569b4fe0f1SSrinivas Kandagatla };
579b4fe0f1SSrinivas Kandagatla 
589b4fe0f1SSrinivas Kandagatla struct q6apm_dai_rtd {
599b4fe0f1SSrinivas Kandagatla 	struct snd_pcm_substream *substream;
609b4fe0f1SSrinivas Kandagatla 	struct snd_compr_stream *cstream;
61c0c87738SSrinivas Kandagatla 	struct snd_codec codec;
629b4fe0f1SSrinivas Kandagatla 	struct snd_compr_params codec_param;
639b4fe0f1SSrinivas Kandagatla 	struct snd_dma_buffer dma_buffer;
649b4fe0f1SSrinivas Kandagatla 	phys_addr_t phys;
659b4fe0f1SSrinivas Kandagatla 	unsigned int pcm_size;
669b4fe0f1SSrinivas Kandagatla 	unsigned int pcm_count;
679b4fe0f1SSrinivas Kandagatla 	unsigned int periods;
689b4fe0f1SSrinivas Kandagatla 	unsigned int bytes_sent;
699b4fe0f1SSrinivas Kandagatla 	unsigned int bytes_received;
709b4fe0f1SSrinivas Kandagatla 	unsigned int copied_total;
719b4fe0f1SSrinivas Kandagatla 	uint16_t bits_per_sample;
723d4a4411SSrinivas Kandagatla 	snd_pcm_uframes_t queue_ptr;
73c0c87738SSrinivas Kandagatla 	bool next_track;
749b4fe0f1SSrinivas Kandagatla 	enum stream_state state;
759b4fe0f1SSrinivas Kandagatla 	struct q6apm_graph *graph;
7684222ef5SSrinivas Kandagatla 	spinlock_t lock;
7788b60bf0SSrinivas Kandagatla 	bool notify_on_drain;
789b4fe0f1SSrinivas Kandagatla };
799b4fe0f1SSrinivas Kandagatla 
809b4fe0f1SSrinivas Kandagatla struct q6apm_dai_data {
819b4fe0f1SSrinivas Kandagatla 	long long sid;
829b4fe0f1SSrinivas Kandagatla };
839b4fe0f1SSrinivas Kandagatla 
84e6fa3509SKrzysztof Kozlowski static const struct snd_pcm_hardware q6apm_dai_hardware_capture = {
859b4fe0f1SSrinivas Kandagatla 	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER |
869b4fe0f1SSrinivas Kandagatla 				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED |
87aa759f3fSSrinivas Kandagatla 				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
88aa759f3fSSrinivas Kandagatla 				 SNDRV_PCM_INFO_BATCH),
899b4fe0f1SSrinivas Kandagatla 	.formats =              (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE),
909b4fe0f1SSrinivas Kandagatla 	.rates =                SNDRV_PCM_RATE_8000_48000,
919b4fe0f1SSrinivas Kandagatla 	.rate_min =             8000,
929b4fe0f1SSrinivas Kandagatla 	.rate_max =             48000,
939b4fe0f1SSrinivas Kandagatla 	.channels_min =         2,
949b4fe0f1SSrinivas Kandagatla 	.channels_max =         4,
959b4fe0f1SSrinivas Kandagatla 	.buffer_bytes_max =     CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE,
969b4fe0f1SSrinivas Kandagatla 	.period_bytes_min =	CAPTURE_MIN_PERIOD_SIZE,
979b4fe0f1SSrinivas Kandagatla 	.period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
989b4fe0f1SSrinivas Kandagatla 	.periods_min =          CAPTURE_MIN_NUM_PERIODS,
999b4fe0f1SSrinivas Kandagatla 	.periods_max =          CAPTURE_MAX_NUM_PERIODS,
1009b4fe0f1SSrinivas Kandagatla 	.fifo_size =            0,
1019b4fe0f1SSrinivas Kandagatla };
1029b4fe0f1SSrinivas Kandagatla 
103e6fa3509SKrzysztof Kozlowski static const struct snd_pcm_hardware q6apm_dai_hardware_playback = {
1049b4fe0f1SSrinivas Kandagatla 	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER |
1059b4fe0f1SSrinivas Kandagatla 				 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED |
106aa759f3fSSrinivas Kandagatla 				 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME |
107aa759f3fSSrinivas Kandagatla 				 SNDRV_PCM_INFO_BATCH),
1089b4fe0f1SSrinivas Kandagatla 	.formats =              (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE),
1099b4fe0f1SSrinivas Kandagatla 	.rates =                SNDRV_PCM_RATE_8000_192000,
1109b4fe0f1SSrinivas Kandagatla 	.rate_min =             8000,
1119b4fe0f1SSrinivas Kandagatla 	.rate_max =             192000,
1129b4fe0f1SSrinivas Kandagatla 	.channels_min =         2,
1139b4fe0f1SSrinivas Kandagatla 	.channels_max =         8,
1149b4fe0f1SSrinivas Kandagatla 	.buffer_bytes_max =     (PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE),
1159b4fe0f1SSrinivas Kandagatla 	.period_bytes_min =	PLAYBACK_MIN_PERIOD_SIZE,
1169b4fe0f1SSrinivas Kandagatla 	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
1179b4fe0f1SSrinivas Kandagatla 	.periods_min =          PLAYBACK_MIN_NUM_PERIODS,
1189b4fe0f1SSrinivas Kandagatla 	.periods_max =          PLAYBACK_MAX_NUM_PERIODS,
1199b4fe0f1SSrinivas Kandagatla 	.fifo_size =            0,
1209b4fe0f1SSrinivas Kandagatla };
1219b4fe0f1SSrinivas Kandagatla 
event_handler(uint32_t opcode,uint32_t token,void * payload,void * priv)1225b5089e2SArnd Bergmann static void event_handler(uint32_t opcode, uint32_t token, void *payload, void *priv)
1239b4fe0f1SSrinivas Kandagatla {
1249b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = priv;
1259b4fe0f1SSrinivas Kandagatla 	struct snd_pcm_substream *substream = prtd->substream;
1269b4fe0f1SSrinivas Kandagatla 
1279b4fe0f1SSrinivas Kandagatla 	switch (opcode) {
1289b4fe0f1SSrinivas Kandagatla 	case APM_CLIENT_EVENT_CMD_EOS_DONE:
1299b4fe0f1SSrinivas Kandagatla 		prtd->state = Q6APM_STREAM_STOPPED;
1309b4fe0f1SSrinivas Kandagatla 		break;
1319b4fe0f1SSrinivas Kandagatla 	case APM_CLIENT_EVENT_DATA_WRITE_DONE:
1329b4fe0f1SSrinivas Kandagatla 		snd_pcm_period_elapsed(substream);
1339b4fe0f1SSrinivas Kandagatla 
1349b4fe0f1SSrinivas Kandagatla 		break;
1359b4fe0f1SSrinivas Kandagatla 	case APM_CLIENT_EVENT_DATA_READ_DONE:
1369b4fe0f1SSrinivas Kandagatla 		snd_pcm_period_elapsed(substream);
1379b4fe0f1SSrinivas Kandagatla 		if (prtd->state == Q6APM_STREAM_RUNNING)
1389b4fe0f1SSrinivas Kandagatla 			q6apm_read(prtd->graph);
1399b4fe0f1SSrinivas Kandagatla 
1409b4fe0f1SSrinivas Kandagatla 		break;
1419b4fe0f1SSrinivas Kandagatla 	default:
1429b4fe0f1SSrinivas Kandagatla 		break;
1439b4fe0f1SSrinivas Kandagatla 	}
1449b4fe0f1SSrinivas Kandagatla }
1459b4fe0f1SSrinivas Kandagatla 
event_handler_compr(uint32_t opcode,uint32_t token,void * payload,void * priv)14688b60bf0SSrinivas Kandagatla static void event_handler_compr(uint32_t opcode, uint32_t token,
1475b5089e2SArnd Bergmann 				void *payload, void *priv)
14888b60bf0SSrinivas Kandagatla {
14988b60bf0SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = priv;
15088b60bf0SSrinivas Kandagatla 	struct snd_compr_stream *substream = prtd->cstream;
15188b60bf0SSrinivas Kandagatla 	unsigned long flags;
15288b60bf0SSrinivas Kandagatla 	uint32_t wflags = 0;
15388b60bf0SSrinivas Kandagatla 	uint64_t avail;
15488b60bf0SSrinivas Kandagatla 	uint32_t bytes_written, bytes_to_write;
15588b60bf0SSrinivas Kandagatla 	bool is_last_buffer = false;
15688b60bf0SSrinivas Kandagatla 
15788b60bf0SSrinivas Kandagatla 	switch (opcode) {
15888b60bf0SSrinivas Kandagatla 	case APM_CLIENT_EVENT_CMD_EOS_DONE:
15988b60bf0SSrinivas Kandagatla 		spin_lock_irqsave(&prtd->lock, flags);
16088b60bf0SSrinivas Kandagatla 		if (prtd->notify_on_drain) {
16188b60bf0SSrinivas Kandagatla 			snd_compr_drain_notify(prtd->cstream);
16288b60bf0SSrinivas Kandagatla 			prtd->notify_on_drain = false;
16388b60bf0SSrinivas Kandagatla 		} else {
16488b60bf0SSrinivas Kandagatla 			prtd->state = Q6APM_STREAM_STOPPED;
16588b60bf0SSrinivas Kandagatla 		}
16688b60bf0SSrinivas Kandagatla 		spin_unlock_irqrestore(&prtd->lock, flags);
16788b60bf0SSrinivas Kandagatla 		break;
16888b60bf0SSrinivas Kandagatla 	case APM_CLIENT_EVENT_DATA_WRITE_DONE:
16988b60bf0SSrinivas Kandagatla 		spin_lock_irqsave(&prtd->lock, flags);
17088b60bf0SSrinivas Kandagatla 		bytes_written = token >> APM_WRITE_TOKEN_LEN_SHIFT;
17188b60bf0SSrinivas Kandagatla 		prtd->copied_total += bytes_written;
17288b60bf0SSrinivas Kandagatla 		snd_compr_fragment_elapsed(substream);
17388b60bf0SSrinivas Kandagatla 
17488b60bf0SSrinivas Kandagatla 		if (prtd->state != Q6APM_STREAM_RUNNING) {
17588b60bf0SSrinivas Kandagatla 			spin_unlock_irqrestore(&prtd->lock, flags);
17688b60bf0SSrinivas Kandagatla 			break;
17788b60bf0SSrinivas Kandagatla 		}
17888b60bf0SSrinivas Kandagatla 
17988b60bf0SSrinivas Kandagatla 		avail = prtd->bytes_received - prtd->bytes_sent;
18088b60bf0SSrinivas Kandagatla 
18188b60bf0SSrinivas Kandagatla 		if (avail > prtd->pcm_count) {
18288b60bf0SSrinivas Kandagatla 			bytes_to_write = prtd->pcm_count;
18388b60bf0SSrinivas Kandagatla 		} else {
18488b60bf0SSrinivas Kandagatla 			if (substream->partial_drain || prtd->notify_on_drain)
18588b60bf0SSrinivas Kandagatla 				is_last_buffer = true;
18688b60bf0SSrinivas Kandagatla 			bytes_to_write = avail;
18788b60bf0SSrinivas Kandagatla 		}
18888b60bf0SSrinivas Kandagatla 
18988b60bf0SSrinivas Kandagatla 		if (bytes_to_write) {
19088b60bf0SSrinivas Kandagatla 			if (substream->partial_drain && is_last_buffer)
19188b60bf0SSrinivas Kandagatla 				wflags |= APM_LAST_BUFFER_FLAG;
19288b60bf0SSrinivas Kandagatla 
19388b60bf0SSrinivas Kandagatla 			q6apm_write_async(prtd->graph,
19488b60bf0SSrinivas Kandagatla 						bytes_to_write, 0, 0, wflags);
19588b60bf0SSrinivas Kandagatla 
19688b60bf0SSrinivas Kandagatla 			prtd->bytes_sent += bytes_to_write;
19788b60bf0SSrinivas Kandagatla 
19888b60bf0SSrinivas Kandagatla 			if (prtd->notify_on_drain && is_last_buffer)
19988b60bf0SSrinivas Kandagatla 				audioreach_shared_memory_send_eos(prtd->graph);
20088b60bf0SSrinivas Kandagatla 		}
20188b60bf0SSrinivas Kandagatla 
20288b60bf0SSrinivas Kandagatla 		spin_unlock_irqrestore(&prtd->lock, flags);
20388b60bf0SSrinivas Kandagatla 		break;
20488b60bf0SSrinivas Kandagatla 	default:
20588b60bf0SSrinivas Kandagatla 		break;
20688b60bf0SSrinivas Kandagatla 	}
20788b60bf0SSrinivas Kandagatla }
20888b60bf0SSrinivas Kandagatla 
q6apm_dai_prepare(struct snd_soc_component * component,struct snd_pcm_substream * substream)2099b4fe0f1SSrinivas Kandagatla static int q6apm_dai_prepare(struct snd_soc_component *component,
2109b4fe0f1SSrinivas Kandagatla 			     struct snd_pcm_substream *substream)
2119b4fe0f1SSrinivas Kandagatla {
2129b4fe0f1SSrinivas Kandagatla 	struct snd_pcm_runtime *runtime = substream->runtime;
2139b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
2149b4fe0f1SSrinivas Kandagatla 	struct audioreach_module_config cfg;
2159b4fe0f1SSrinivas Kandagatla 	struct device *dev = component->dev;
2169b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_data *pdata;
2179b4fe0f1SSrinivas Kandagatla 	int ret;
2189b4fe0f1SSrinivas Kandagatla 
2199b4fe0f1SSrinivas Kandagatla 	pdata = snd_soc_component_get_drvdata(component);
2209b4fe0f1SSrinivas Kandagatla 	if (!pdata)
2219b4fe0f1SSrinivas Kandagatla 		return -EINVAL;
2229b4fe0f1SSrinivas Kandagatla 
2239b4fe0f1SSrinivas Kandagatla 	if (!prtd || !prtd->graph) {
2249b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "%s: private data null or audio client freed\n", __func__);
2259b4fe0f1SSrinivas Kandagatla 		return -EINVAL;
2269b4fe0f1SSrinivas Kandagatla 	}
2279b4fe0f1SSrinivas Kandagatla 
2289b4fe0f1SSrinivas Kandagatla 	cfg.direction = substream->stream;
2299b4fe0f1SSrinivas Kandagatla 	cfg.sample_rate = runtime->rate;
2309b4fe0f1SSrinivas Kandagatla 	cfg.num_channels = runtime->channels;
2319b4fe0f1SSrinivas Kandagatla 	cfg.bit_width = prtd->bits_per_sample;
232e41521b6SMohammad Rafi Shaik 	cfg.fmt = SND_AUDIOCODEC_PCM;
2335d5dd9bbSKrzysztof Kozlowski 	audioreach_set_default_channel_mapping(cfg.channel_map, runtime->channels);
2349b4fe0f1SSrinivas Kandagatla 
23558136d93SSrinivas Kandagatla 	if (prtd->state) {
23658136d93SSrinivas Kandagatla 		/* clear the previous setup if any  */
23758136d93SSrinivas Kandagatla 		q6apm_graph_stop(prtd->graph);
23858136d93SSrinivas Kandagatla 		q6apm_unmap_memory_regions(prtd->graph, substream->stream);
23958136d93SSrinivas Kandagatla 	}
24058136d93SSrinivas Kandagatla 
2419b4fe0f1SSrinivas Kandagatla 	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
2429b4fe0f1SSrinivas Kandagatla 	/* rate and channels are sent to audio driver */
2439b4fe0f1SSrinivas Kandagatla 	ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg);
2449b4fe0f1SSrinivas Kandagatla 	if (ret < 0) {
2459b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "%s: q6apm_open_write failed\n", __func__);
2469b4fe0f1SSrinivas Kandagatla 		return ret;
2479b4fe0f1SSrinivas Kandagatla 	}
2489b4fe0f1SSrinivas Kandagatla 
2499b4fe0f1SSrinivas Kandagatla 	ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg);
2509b4fe0f1SSrinivas Kandagatla 	if (ret < 0)
2519b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "%s: CMD Format block failed\n", __func__);
2529b4fe0f1SSrinivas Kandagatla 
2539b4fe0f1SSrinivas Kandagatla 	ret = q6apm_map_memory_regions(prtd->graph, substream->stream, prtd->phys,
2549b4fe0f1SSrinivas Kandagatla 				       (prtd->pcm_size / prtd->periods), prtd->periods);
2559b4fe0f1SSrinivas Kandagatla 
2569b4fe0f1SSrinivas Kandagatla 	if (ret < 0) {
2579b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n",	ret);
2589b4fe0f1SSrinivas Kandagatla 		return -ENOMEM;
2599b4fe0f1SSrinivas Kandagatla 	}
2609b4fe0f1SSrinivas Kandagatla 
2619b4fe0f1SSrinivas Kandagatla 	ret = q6apm_graph_prepare(prtd->graph);
2629b4fe0f1SSrinivas Kandagatla 	if (ret) {
2639b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "Failed to prepare Graph %d\n", ret);
2649b4fe0f1SSrinivas Kandagatla 		return ret;
2659b4fe0f1SSrinivas Kandagatla 	}
2669b4fe0f1SSrinivas Kandagatla 
2679b4fe0f1SSrinivas Kandagatla 	ret = q6apm_graph_start(prtd->graph);
2689b4fe0f1SSrinivas Kandagatla 	if (ret) {
2699b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "Failed to Start Graph %d\n", ret);
2709b4fe0f1SSrinivas Kandagatla 		return ret;
2719b4fe0f1SSrinivas Kandagatla 	}
2729b4fe0f1SSrinivas Kandagatla 
2739b4fe0f1SSrinivas Kandagatla 	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
2749b4fe0f1SSrinivas Kandagatla 		int i;
2759b4fe0f1SSrinivas Kandagatla 		/* Queue the buffers for Capture ONLY after graph is started */
2769b4fe0f1SSrinivas Kandagatla 		for (i = 0; i < runtime->periods; i++)
2779b4fe0f1SSrinivas Kandagatla 			q6apm_read(prtd->graph);
2789b4fe0f1SSrinivas Kandagatla 
2799b4fe0f1SSrinivas Kandagatla 	}
2809b4fe0f1SSrinivas Kandagatla 
2819b4fe0f1SSrinivas Kandagatla 	/* Now that graph as been prepared and started update the internal state accordingly */
2829b4fe0f1SSrinivas Kandagatla 	prtd->state = Q6APM_STREAM_RUNNING;
2839b4fe0f1SSrinivas Kandagatla 
2849b4fe0f1SSrinivas Kandagatla 	return 0;
2859b4fe0f1SSrinivas Kandagatla }
2869b4fe0f1SSrinivas Kandagatla 
q6apm_dai_ack(struct snd_soc_component * component,struct snd_pcm_substream * substream)2873d4a4411SSrinivas Kandagatla static int q6apm_dai_ack(struct snd_soc_component *component, struct snd_pcm_substream *substream)
2883d4a4411SSrinivas Kandagatla {
2893d4a4411SSrinivas Kandagatla 	struct snd_pcm_runtime *runtime = substream->runtime;
2903d4a4411SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
2913d4a4411SSrinivas Kandagatla 	int i, ret = 0, avail_periods;
2923d4a4411SSrinivas Kandagatla 
2933d4a4411SSrinivas Kandagatla 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
2943d4a4411SSrinivas Kandagatla 		avail_periods = (runtime->control->appl_ptr - prtd->queue_ptr)/runtime->period_size;
2953d4a4411SSrinivas Kandagatla 		for (i = 0; i < avail_periods; i++) {
2963d4a4411SSrinivas Kandagatla 			ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP);
2973d4a4411SSrinivas Kandagatla 			if (ret < 0) {
2983d4a4411SSrinivas Kandagatla 				dev_err(component->dev, "Error queuing playback buffer %d\n", ret);
2993d4a4411SSrinivas Kandagatla 				return ret;
3003d4a4411SSrinivas Kandagatla 			}
3013d4a4411SSrinivas Kandagatla 			prtd->queue_ptr += runtime->period_size;
3023d4a4411SSrinivas Kandagatla 		}
3033d4a4411SSrinivas Kandagatla 	}
3043d4a4411SSrinivas Kandagatla 
3053d4a4411SSrinivas Kandagatla 	return ret;
3063d4a4411SSrinivas Kandagatla }
3073d4a4411SSrinivas Kandagatla 
q6apm_dai_trigger(struct snd_soc_component * component,struct snd_pcm_substream * substream,int cmd)3089b4fe0f1SSrinivas Kandagatla static int q6apm_dai_trigger(struct snd_soc_component *component,
3099b4fe0f1SSrinivas Kandagatla 			     struct snd_pcm_substream *substream, int cmd)
3109b4fe0f1SSrinivas Kandagatla {
3119b4fe0f1SSrinivas Kandagatla 	struct snd_pcm_runtime *runtime = substream->runtime;
3129b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
3139b4fe0f1SSrinivas Kandagatla 	int ret = 0;
3149b4fe0f1SSrinivas Kandagatla 
3159b4fe0f1SSrinivas Kandagatla 	switch (cmd) {
3169b4fe0f1SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_START:
3179b4fe0f1SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_RESUME:
3189b4fe0f1SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
3199b4fe0f1SSrinivas Kandagatla 		break;
3209b4fe0f1SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_STOP:
3219b4fe0f1SSrinivas Kandagatla 		/* TODO support be handled via SoftPause Module */
3229b4fe0f1SSrinivas Kandagatla 		prtd->state = Q6APM_STREAM_STOPPED;
3239b4fe0f1SSrinivas Kandagatla 		break;
3249b4fe0f1SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_SUSPEND:
3259b4fe0f1SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
3269b4fe0f1SSrinivas Kandagatla 		break;
3279b4fe0f1SSrinivas Kandagatla 	default:
3289b4fe0f1SSrinivas Kandagatla 		ret = -EINVAL;
3299b4fe0f1SSrinivas Kandagatla 		break;
3309b4fe0f1SSrinivas Kandagatla 	}
3319b4fe0f1SSrinivas Kandagatla 
3329b4fe0f1SSrinivas Kandagatla 	return ret;
3339b4fe0f1SSrinivas Kandagatla }
3349b4fe0f1SSrinivas Kandagatla 
q6apm_dai_open(struct snd_soc_component * component,struct snd_pcm_substream * substream)3359b4fe0f1SSrinivas Kandagatla static int q6apm_dai_open(struct snd_soc_component *component,
3369b4fe0f1SSrinivas Kandagatla 			  struct snd_pcm_substream *substream)
3379b4fe0f1SSrinivas Kandagatla {
3389b4fe0f1SSrinivas Kandagatla 	struct snd_pcm_runtime *runtime = substream->runtime;
33977678a25SKrzysztof Kozlowski 	struct snd_soc_pcm_runtime *soc_prtd = snd_soc_substream_to_rtd(substream);
3409b1a2dfaSKuninori Morimoto 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(soc_prtd, 0);
3419b4fe0f1SSrinivas Kandagatla 	struct device *dev = component->dev;
3429b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_data *pdata;
3439b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd;
3449b4fe0f1SSrinivas Kandagatla 	int graph_id, ret;
3459b4fe0f1SSrinivas Kandagatla 
3469b4fe0f1SSrinivas Kandagatla 	graph_id = cpu_dai->driver->id;
3479b4fe0f1SSrinivas Kandagatla 
3489b4fe0f1SSrinivas Kandagatla 	pdata = snd_soc_component_get_drvdata(component);
3499b4fe0f1SSrinivas Kandagatla 	if (!pdata) {
3509b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "Drv data not found ..\n");
3519b4fe0f1SSrinivas Kandagatla 		return -EINVAL;
3529b4fe0f1SSrinivas Kandagatla 	}
3539b4fe0f1SSrinivas Kandagatla 
3549b4fe0f1SSrinivas Kandagatla 	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
3559b4fe0f1SSrinivas Kandagatla 	if (prtd == NULL)
3569b4fe0f1SSrinivas Kandagatla 		return -ENOMEM;
3579b4fe0f1SSrinivas Kandagatla 
35884222ef5SSrinivas Kandagatla 	spin_lock_init(&prtd->lock);
3599b4fe0f1SSrinivas Kandagatla 	prtd->substream = substream;
3605b5089e2SArnd Bergmann 	prtd->graph = q6apm_graph_open(dev, event_handler, prtd, graph_id);
3619b4fe0f1SSrinivas Kandagatla 	if (IS_ERR(prtd->graph)) {
3629b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "%s: Could not allocate memory\n", __func__);
3639b4fe0f1SSrinivas Kandagatla 		ret = PTR_ERR(prtd->graph);
3649b4fe0f1SSrinivas Kandagatla 		goto err;
3659b4fe0f1SSrinivas Kandagatla 	}
3669b4fe0f1SSrinivas Kandagatla 
3679b4fe0f1SSrinivas Kandagatla 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
3689b4fe0f1SSrinivas Kandagatla 		runtime->hw = q6apm_dai_hardware_playback;
3699b4fe0f1SSrinivas Kandagatla 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
3709b4fe0f1SSrinivas Kandagatla 		runtime->hw = q6apm_dai_hardware_capture;
3719b4fe0f1SSrinivas Kandagatla 
3729b4fe0f1SSrinivas Kandagatla 	/* Ensure that buffer size is a multiple of period size */
3739b4fe0f1SSrinivas Kandagatla 	ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
3749b4fe0f1SSrinivas Kandagatla 	if (ret < 0) {
3759b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "snd_pcm_hw_constraint_integer failed\n");
3769b4fe0f1SSrinivas Kandagatla 		goto err;
3779b4fe0f1SSrinivas Kandagatla 	}
3789b4fe0f1SSrinivas Kandagatla 
3799b4fe0f1SSrinivas Kandagatla 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
3809b4fe0f1SSrinivas Kandagatla 		ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
3819b4fe0f1SSrinivas Kandagatla 						   BUFFER_BYTES_MIN, BUFFER_BYTES_MAX);
3829b4fe0f1SSrinivas Kandagatla 		if (ret < 0) {
3839b4fe0f1SSrinivas Kandagatla 			dev_err(dev, "constraint for buffer bytes min max ret = %d\n", ret);
3849b4fe0f1SSrinivas Kandagatla 			goto err;
3859b4fe0f1SSrinivas Kandagatla 		}
3869b4fe0f1SSrinivas Kandagatla 	}
3879b4fe0f1SSrinivas Kandagatla 
38831070195SSrinivas Kandagatla 	/* setup 10ms latency to accommodate DSP restrictions */
38931070195SSrinivas Kandagatla 	ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 480);
3909b4fe0f1SSrinivas Kandagatla 	if (ret < 0) {
3919b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "constraint for period bytes step ret = %d\n", ret);
3929b4fe0f1SSrinivas Kandagatla 		goto err;
3939b4fe0f1SSrinivas Kandagatla 	}
3949b4fe0f1SSrinivas Kandagatla 
39531070195SSrinivas Kandagatla 	ret = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 480);
3969b4fe0f1SSrinivas Kandagatla 	if (ret < 0) {
3979b4fe0f1SSrinivas Kandagatla 		dev_err(dev, "constraint for buffer bytes step ret = %d\n", ret);
3989b4fe0f1SSrinivas Kandagatla 		goto err;
3999b4fe0f1SSrinivas Kandagatla 	}
4009b4fe0f1SSrinivas Kandagatla 
4019b4fe0f1SSrinivas Kandagatla 	runtime->private_data = prtd;
4029b4fe0f1SSrinivas Kandagatla 	runtime->dma_bytes = BUFFER_BYTES_MAX;
4039b4fe0f1SSrinivas Kandagatla 	if (pdata->sid < 0)
4049b4fe0f1SSrinivas Kandagatla 		prtd->phys = substream->dma_buffer.addr;
4059b4fe0f1SSrinivas Kandagatla 	else
4069b4fe0f1SSrinivas Kandagatla 		prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32);
4079b4fe0f1SSrinivas Kandagatla 
4089b4fe0f1SSrinivas Kandagatla 	return 0;
4099b4fe0f1SSrinivas Kandagatla err:
4109b4fe0f1SSrinivas Kandagatla 	kfree(prtd);
4119b4fe0f1SSrinivas Kandagatla 
4129b4fe0f1SSrinivas Kandagatla 	return ret;
4139b4fe0f1SSrinivas Kandagatla }
4149b4fe0f1SSrinivas Kandagatla 
q6apm_dai_close(struct snd_soc_component * component,struct snd_pcm_substream * substream)4159b4fe0f1SSrinivas Kandagatla static int q6apm_dai_close(struct snd_soc_component *component,
4169b4fe0f1SSrinivas Kandagatla 			   struct snd_pcm_substream *substream)
4179b4fe0f1SSrinivas Kandagatla {
4189b4fe0f1SSrinivas Kandagatla 	struct snd_pcm_runtime *runtime = substream->runtime;
4199b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
4209b4fe0f1SSrinivas Kandagatla 
4218f2e5c65SSrinivas Kandagatla 	if (prtd->state) { /* only stop graph that is started */
4229b4fe0f1SSrinivas Kandagatla 		q6apm_graph_stop(prtd->graph);
4239b4fe0f1SSrinivas Kandagatla 		q6apm_unmap_memory_regions(prtd->graph, substream->stream);
4248f2e5c65SSrinivas Kandagatla 	}
4258f2e5c65SSrinivas Kandagatla 
4269b4fe0f1SSrinivas Kandagatla 	q6apm_graph_close(prtd->graph);
4279b4fe0f1SSrinivas Kandagatla 	prtd->graph = NULL;
4289b4fe0f1SSrinivas Kandagatla 	kfree(prtd);
4299b4fe0f1SSrinivas Kandagatla 	runtime->private_data = NULL;
4309b4fe0f1SSrinivas Kandagatla 
4319b4fe0f1SSrinivas Kandagatla 	return 0;
4329b4fe0f1SSrinivas Kandagatla }
4339b4fe0f1SSrinivas Kandagatla 
q6apm_dai_pointer(struct snd_soc_component * component,struct snd_pcm_substream * substream)4349b4fe0f1SSrinivas Kandagatla static snd_pcm_uframes_t q6apm_dai_pointer(struct snd_soc_component *component,
4359b4fe0f1SSrinivas Kandagatla 					   struct snd_pcm_substream *substream)
4369b4fe0f1SSrinivas Kandagatla {
4379b4fe0f1SSrinivas Kandagatla 	struct snd_pcm_runtime *runtime = substream->runtime;
4389b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
43984222ef5SSrinivas Kandagatla 	snd_pcm_uframes_t ptr;
4409b4fe0f1SSrinivas Kandagatla 
441*a93dad6fSSrinivas Kandagatla 	ptr = q6apm_get_hw_pointer(prtd->graph, substream->stream) * runtime->period_size;
442*a93dad6fSSrinivas Kandagatla 	if (ptr)
443*a93dad6fSSrinivas Kandagatla 		return ptr - 1;
4449b4fe0f1SSrinivas Kandagatla 
445*a93dad6fSSrinivas Kandagatla 	return 0;
4469b4fe0f1SSrinivas Kandagatla }
4479b4fe0f1SSrinivas Kandagatla 
q6apm_dai_hw_params(struct snd_soc_component * component,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)4489b4fe0f1SSrinivas Kandagatla static int q6apm_dai_hw_params(struct snd_soc_component *component,
4499b4fe0f1SSrinivas Kandagatla 			       struct snd_pcm_substream *substream,
4509b4fe0f1SSrinivas Kandagatla 			       struct snd_pcm_hw_params *params)
4519b4fe0f1SSrinivas Kandagatla {
4529b4fe0f1SSrinivas Kandagatla 	struct snd_pcm_runtime *runtime = substream->runtime;
4539b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
4549b4fe0f1SSrinivas Kandagatla 
4559b4fe0f1SSrinivas Kandagatla 	prtd->pcm_size = params_buffer_bytes(params);
4569b4fe0f1SSrinivas Kandagatla 	prtd->periods = params_periods(params);
4579b4fe0f1SSrinivas Kandagatla 
4589b4fe0f1SSrinivas Kandagatla 	switch (params_format(params)) {
4599b4fe0f1SSrinivas Kandagatla 	case SNDRV_PCM_FORMAT_S16_LE:
4609b4fe0f1SSrinivas Kandagatla 		prtd->bits_per_sample = 16;
4619b4fe0f1SSrinivas Kandagatla 		break;
4629b4fe0f1SSrinivas Kandagatla 	case SNDRV_PCM_FORMAT_S24_LE:
4639b4fe0f1SSrinivas Kandagatla 		prtd->bits_per_sample = 24;
4649b4fe0f1SSrinivas Kandagatla 		break;
4659b4fe0f1SSrinivas Kandagatla 	default:
4669b4fe0f1SSrinivas Kandagatla 		return -EINVAL;
4679b4fe0f1SSrinivas Kandagatla 	}
4689b4fe0f1SSrinivas Kandagatla 
4699b4fe0f1SSrinivas Kandagatla 	return 0;
4709b4fe0f1SSrinivas Kandagatla }
4719b4fe0f1SSrinivas Kandagatla 
q6apm_dai_pcm_new(struct snd_soc_component * component,struct snd_soc_pcm_runtime * rtd)4729b4fe0f1SSrinivas Kandagatla static int q6apm_dai_pcm_new(struct snd_soc_component *component, struct snd_soc_pcm_runtime *rtd)
4739b4fe0f1SSrinivas Kandagatla {
4749b4fe0f1SSrinivas Kandagatla 	int size = BUFFER_BYTES_MAX;
4759b4fe0f1SSrinivas Kandagatla 
4769b4fe0f1SSrinivas Kandagatla 	return snd_pcm_set_fixed_buffer_all(rtd->pcm, SNDRV_DMA_TYPE_DEV, component->dev, size);
4779b4fe0f1SSrinivas Kandagatla }
4789b4fe0f1SSrinivas Kandagatla 
q6apm_dai_compr_open(struct snd_soc_component * component,struct snd_compr_stream * stream)47988b60bf0SSrinivas Kandagatla static int q6apm_dai_compr_open(struct snd_soc_component *component,
48088b60bf0SSrinivas Kandagatla 				struct snd_compr_stream *stream)
48188b60bf0SSrinivas Kandagatla {
48288b60bf0SSrinivas Kandagatla 	struct snd_soc_pcm_runtime *rtd = stream->private_data;
4839b1a2dfaSKuninori Morimoto 	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
48488b60bf0SSrinivas Kandagatla 	struct snd_compr_runtime *runtime = stream->runtime;
48588b60bf0SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd;
48688b60bf0SSrinivas Kandagatla 	struct q6apm_dai_data *pdata;
48788b60bf0SSrinivas Kandagatla 	struct device *dev = component->dev;
48888b60bf0SSrinivas Kandagatla 	int ret, size;
48988b60bf0SSrinivas Kandagatla 	int graph_id;
49088b60bf0SSrinivas Kandagatla 
49188b60bf0SSrinivas Kandagatla 	graph_id = cpu_dai->driver->id;
49288b60bf0SSrinivas Kandagatla 	pdata = snd_soc_component_get_drvdata(component);
49388b60bf0SSrinivas Kandagatla 	if (!pdata)
49488b60bf0SSrinivas Kandagatla 		return -EINVAL;
49588b60bf0SSrinivas Kandagatla 
49688b60bf0SSrinivas Kandagatla 	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
49788b60bf0SSrinivas Kandagatla 	if (prtd == NULL)
49888b60bf0SSrinivas Kandagatla 		return -ENOMEM;
49988b60bf0SSrinivas Kandagatla 
50088b60bf0SSrinivas Kandagatla 	prtd->cstream = stream;
5015b5089e2SArnd Bergmann 	prtd->graph = q6apm_graph_open(dev, event_handler_compr, prtd, graph_id);
50288b60bf0SSrinivas Kandagatla 	if (IS_ERR(prtd->graph)) {
50388b60bf0SSrinivas Kandagatla 		ret = PTR_ERR(prtd->graph);
50488b60bf0SSrinivas Kandagatla 		kfree(prtd);
50588b60bf0SSrinivas Kandagatla 		return ret;
50688b60bf0SSrinivas Kandagatla 	}
50788b60bf0SSrinivas Kandagatla 
50888b60bf0SSrinivas Kandagatla 	runtime->private_data = prtd;
50988b60bf0SSrinivas Kandagatla 	runtime->dma_bytes = BUFFER_BYTES_MAX;
51088b60bf0SSrinivas Kandagatla 	size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE * COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
51188b60bf0SSrinivas Kandagatla 	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, &prtd->dma_buffer);
51288b60bf0SSrinivas Kandagatla 	if (ret)
51388b60bf0SSrinivas Kandagatla 		return ret;
51488b60bf0SSrinivas Kandagatla 
51588b60bf0SSrinivas Kandagatla 	if (pdata->sid < 0)
51688b60bf0SSrinivas Kandagatla 		prtd->phys = prtd->dma_buffer.addr;
51788b60bf0SSrinivas Kandagatla 	else
51888b60bf0SSrinivas Kandagatla 		prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
51988b60bf0SSrinivas Kandagatla 
52088b60bf0SSrinivas Kandagatla 	snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
52188b60bf0SSrinivas Kandagatla 	spin_lock_init(&prtd->lock);
52288b60bf0SSrinivas Kandagatla 
52388b60bf0SSrinivas Kandagatla 	q6apm_enable_compress_module(dev, prtd->graph, true);
52488b60bf0SSrinivas Kandagatla 	return 0;
52588b60bf0SSrinivas Kandagatla }
52688b60bf0SSrinivas Kandagatla 
q6apm_dai_compr_free(struct snd_soc_component * component,struct snd_compr_stream * stream)52788b60bf0SSrinivas Kandagatla static int q6apm_dai_compr_free(struct snd_soc_component *component,
52888b60bf0SSrinivas Kandagatla 				struct snd_compr_stream *stream)
52988b60bf0SSrinivas Kandagatla {
53088b60bf0SSrinivas Kandagatla 	struct snd_compr_runtime *runtime = stream->runtime;
53188b60bf0SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
53288b60bf0SSrinivas Kandagatla 
53388b60bf0SSrinivas Kandagatla 	q6apm_graph_stop(prtd->graph);
53488b60bf0SSrinivas Kandagatla 	q6apm_unmap_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK);
53588b60bf0SSrinivas Kandagatla 	q6apm_graph_close(prtd->graph);
53688b60bf0SSrinivas Kandagatla 	snd_dma_free_pages(&prtd->dma_buffer);
53788b60bf0SSrinivas Kandagatla 	prtd->graph = NULL;
53888b60bf0SSrinivas Kandagatla 	kfree(prtd);
53988b60bf0SSrinivas Kandagatla 	runtime->private_data = NULL;
54088b60bf0SSrinivas Kandagatla 
54188b60bf0SSrinivas Kandagatla 	return 0;
54288b60bf0SSrinivas Kandagatla }
543c0c87738SSrinivas Kandagatla 
q6apm_dai_compr_get_caps(struct snd_soc_component * component,struct snd_compr_stream * stream,struct snd_compr_caps * caps)544c0c87738SSrinivas Kandagatla static int q6apm_dai_compr_get_caps(struct snd_soc_component *component,
545c0c87738SSrinivas Kandagatla 				    struct snd_compr_stream *stream,
546c0c87738SSrinivas Kandagatla 				    struct snd_compr_caps *caps)
547c0c87738SSrinivas Kandagatla {
548c0c87738SSrinivas Kandagatla 	caps->direction = SND_COMPRESS_PLAYBACK;
549c0c87738SSrinivas Kandagatla 	caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
550c0c87738SSrinivas Kandagatla 	caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
551c0c87738SSrinivas Kandagatla 	caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
552c0c87738SSrinivas Kandagatla 	caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
553c0c87738SSrinivas Kandagatla 	caps->num_codecs = 3;
554c0c87738SSrinivas Kandagatla 	caps->codecs[0] = SND_AUDIOCODEC_MP3;
555c0c87738SSrinivas Kandagatla 	caps->codecs[1] = SND_AUDIOCODEC_AAC;
556c0c87738SSrinivas Kandagatla 	caps->codecs[2] = SND_AUDIOCODEC_FLAC;
557c0c87738SSrinivas Kandagatla 
558c0c87738SSrinivas Kandagatla 	return 0;
559c0c87738SSrinivas Kandagatla }
560c0c87738SSrinivas Kandagatla 
q6apm_dai_compr_get_codec_caps(struct snd_soc_component * component,struct snd_compr_stream * stream,struct snd_compr_codec_caps * codec)561c0c87738SSrinivas Kandagatla static int q6apm_dai_compr_get_codec_caps(struct snd_soc_component *component,
562c0c87738SSrinivas Kandagatla 					  struct snd_compr_stream *stream,
563c0c87738SSrinivas Kandagatla 					  struct snd_compr_codec_caps *codec)
564c0c87738SSrinivas Kandagatla {
565c0c87738SSrinivas Kandagatla 	switch (codec->codec) {
566c0c87738SSrinivas Kandagatla 	case SND_AUDIOCODEC_MP3:
567c0c87738SSrinivas Kandagatla 		*codec = q6apm_compr_caps;
568c0c87738SSrinivas Kandagatla 		break;
569c0c87738SSrinivas Kandagatla 	default:
570c0c87738SSrinivas Kandagatla 		break;
571c0c87738SSrinivas Kandagatla 	}
572c0c87738SSrinivas Kandagatla 
573c0c87738SSrinivas Kandagatla 	return 0;
574c0c87738SSrinivas Kandagatla }
575c337bf33SSrinivas Kandagatla 
q6apm_dai_compr_pointer(struct snd_soc_component * component,struct snd_compr_stream * stream,struct snd_compr_tstamp * tstamp)576c337bf33SSrinivas Kandagatla static int q6apm_dai_compr_pointer(struct snd_soc_component *component,
577c337bf33SSrinivas Kandagatla 				   struct snd_compr_stream *stream,
578c337bf33SSrinivas Kandagatla 				   struct snd_compr_tstamp *tstamp)
579c337bf33SSrinivas Kandagatla {
580c337bf33SSrinivas Kandagatla 	struct snd_compr_runtime *runtime = stream->runtime;
581c337bf33SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
582c337bf33SSrinivas Kandagatla 	unsigned long flags;
583c337bf33SSrinivas Kandagatla 
584c337bf33SSrinivas Kandagatla 	spin_lock_irqsave(&prtd->lock, flags);
585c337bf33SSrinivas Kandagatla 	tstamp->copied_total = prtd->copied_total;
586c337bf33SSrinivas Kandagatla 	tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
587c337bf33SSrinivas Kandagatla 	spin_unlock_irqrestore(&prtd->lock, flags);
588c337bf33SSrinivas Kandagatla 
589c337bf33SSrinivas Kandagatla 	return 0;
590c337bf33SSrinivas Kandagatla }
591c337bf33SSrinivas Kandagatla 
q6apm_dai_compr_trigger(struct snd_soc_component * component,struct snd_compr_stream * stream,int cmd)592c337bf33SSrinivas Kandagatla static int q6apm_dai_compr_trigger(struct snd_soc_component *component,
593c337bf33SSrinivas Kandagatla 			    struct snd_compr_stream *stream, int cmd)
594c337bf33SSrinivas Kandagatla {
595c337bf33SSrinivas Kandagatla 	struct snd_compr_runtime *runtime = stream->runtime;
596c337bf33SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
597c337bf33SSrinivas Kandagatla 	int ret = 0;
598c337bf33SSrinivas Kandagatla 
599c337bf33SSrinivas Kandagatla 	switch (cmd) {
600c337bf33SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_START:
601c337bf33SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_RESUME:
602c337bf33SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
603c337bf33SSrinivas Kandagatla 		ret = q6apm_write_async(prtd->graph, prtd->pcm_count, 0, 0, NO_TIMESTAMP);
604c337bf33SSrinivas Kandagatla 		break;
605c337bf33SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_STOP:
606c337bf33SSrinivas Kandagatla 		break;
607c337bf33SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_SUSPEND:
608c337bf33SSrinivas Kandagatla 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
609c337bf33SSrinivas Kandagatla 		break;
610c337bf33SSrinivas Kandagatla 	case SND_COMPR_TRIGGER_NEXT_TRACK:
611c337bf33SSrinivas Kandagatla 		prtd->next_track = true;
612c337bf33SSrinivas Kandagatla 		break;
613c337bf33SSrinivas Kandagatla 	case SND_COMPR_TRIGGER_DRAIN:
614c337bf33SSrinivas Kandagatla 	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
615c337bf33SSrinivas Kandagatla 		prtd->notify_on_drain = true;
616c337bf33SSrinivas Kandagatla 		break;
617c337bf33SSrinivas Kandagatla 	default:
618c337bf33SSrinivas Kandagatla 		ret = -EINVAL;
619c337bf33SSrinivas Kandagatla 		break;
620c337bf33SSrinivas Kandagatla 	}
621c337bf33SSrinivas Kandagatla 
622c337bf33SSrinivas Kandagatla 	return ret;
623c337bf33SSrinivas Kandagatla }
624c337bf33SSrinivas Kandagatla 
q6apm_dai_compr_ack(struct snd_soc_component * component,struct snd_compr_stream * stream,size_t count)625c337bf33SSrinivas Kandagatla static int q6apm_dai_compr_ack(struct snd_soc_component *component, struct snd_compr_stream *stream,
626c337bf33SSrinivas Kandagatla 			size_t count)
627c337bf33SSrinivas Kandagatla {
628c337bf33SSrinivas Kandagatla 	struct snd_compr_runtime *runtime = stream->runtime;
629c337bf33SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
630c337bf33SSrinivas Kandagatla 	unsigned long flags;
631c337bf33SSrinivas Kandagatla 
632c337bf33SSrinivas Kandagatla 	spin_lock_irqsave(&prtd->lock, flags);
633c337bf33SSrinivas Kandagatla 	prtd->bytes_received += count;
634c337bf33SSrinivas Kandagatla 	spin_unlock_irqrestore(&prtd->lock, flags);
635c337bf33SSrinivas Kandagatla 
636c337bf33SSrinivas Kandagatla 	return count;
637c337bf33SSrinivas Kandagatla }
638c337bf33SSrinivas Kandagatla 
q6apm_dai_compr_set_params(struct snd_soc_component * component,struct snd_compr_stream * stream,struct snd_compr_params * params)639b3f736d1SSrinivas Kandagatla static int q6apm_dai_compr_set_params(struct snd_soc_component *component,
640b3f736d1SSrinivas Kandagatla 				      struct snd_compr_stream *stream,
641b3f736d1SSrinivas Kandagatla 				      struct snd_compr_params *params)
642b3f736d1SSrinivas Kandagatla {
643b3f736d1SSrinivas Kandagatla 	struct snd_compr_runtime *runtime = stream->runtime;
644b3f736d1SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
645b3f736d1SSrinivas Kandagatla 	struct q6apm_dai_data *pdata;
646b3f736d1SSrinivas Kandagatla 	struct audioreach_module_config cfg;
647b3f736d1SSrinivas Kandagatla 	struct snd_codec *codec = &params->codec;
648b3f736d1SSrinivas Kandagatla 	int dir = stream->direction;
649b3f736d1SSrinivas Kandagatla 	int ret;
650b3f736d1SSrinivas Kandagatla 
651b3f736d1SSrinivas Kandagatla 	pdata = snd_soc_component_get_drvdata(component);
652b3f736d1SSrinivas Kandagatla 	if (!pdata)
653b3f736d1SSrinivas Kandagatla 		return -EINVAL;
654b3f736d1SSrinivas Kandagatla 
655b3f736d1SSrinivas Kandagatla 	prtd->periods = runtime->fragments;
656b3f736d1SSrinivas Kandagatla 	prtd->pcm_count = runtime->fragment_size;
657b3f736d1SSrinivas Kandagatla 	prtd->pcm_size = runtime->fragments * runtime->fragment_size;
658b3f736d1SSrinivas Kandagatla 	prtd->bits_per_sample = 16;
659b3f736d1SSrinivas Kandagatla 
660b3f736d1SSrinivas Kandagatla 	if (prtd->next_track != true) {
661b3f736d1SSrinivas Kandagatla 		memcpy(&prtd->codec, codec, sizeof(*codec));
662b3f736d1SSrinivas Kandagatla 
663b3f736d1SSrinivas Kandagatla 		ret = q6apm_set_real_module_id(component->dev, prtd->graph, codec->id);
664b3f736d1SSrinivas Kandagatla 		if (ret)
665b3f736d1SSrinivas Kandagatla 			return ret;
666b3f736d1SSrinivas Kandagatla 
667b3f736d1SSrinivas Kandagatla 		cfg.direction = dir;
668b3f736d1SSrinivas Kandagatla 		cfg.sample_rate = codec->sample_rate;
669b3f736d1SSrinivas Kandagatla 		cfg.num_channels = 2;
670b3f736d1SSrinivas Kandagatla 		cfg.bit_width = prtd->bits_per_sample;
671b3f736d1SSrinivas Kandagatla 		cfg.fmt = codec->id;
6725d5dd9bbSKrzysztof Kozlowski 		audioreach_set_default_channel_mapping(cfg.channel_map,
6735d5dd9bbSKrzysztof Kozlowski 						       cfg.num_channels);
674b3f736d1SSrinivas Kandagatla 		memcpy(&cfg.codec, codec, sizeof(*codec));
675b3f736d1SSrinivas Kandagatla 
676b3f736d1SSrinivas Kandagatla 		ret = q6apm_graph_media_format_shmem(prtd->graph, &cfg);
677b3f736d1SSrinivas Kandagatla 		if (ret < 0)
678b3f736d1SSrinivas Kandagatla 			return ret;
679b3f736d1SSrinivas Kandagatla 
680b3f736d1SSrinivas Kandagatla 		ret = q6apm_graph_media_format_pcm(prtd->graph, &cfg);
681b3f736d1SSrinivas Kandagatla 		if (ret)
682b3f736d1SSrinivas Kandagatla 			return ret;
683b3f736d1SSrinivas Kandagatla 
684b3f736d1SSrinivas Kandagatla 		ret = q6apm_map_memory_regions(prtd->graph, SNDRV_PCM_STREAM_PLAYBACK,
685b3f736d1SSrinivas Kandagatla 					       prtd->phys, (prtd->pcm_size / prtd->periods),
686b3f736d1SSrinivas Kandagatla 					       prtd->periods);
687b3f736d1SSrinivas Kandagatla 		if (ret < 0)
688b3f736d1SSrinivas Kandagatla 			return -ENOMEM;
689b3f736d1SSrinivas Kandagatla 
690b3f736d1SSrinivas Kandagatla 		ret = q6apm_graph_prepare(prtd->graph);
691b3f736d1SSrinivas Kandagatla 		if (ret)
692b3f736d1SSrinivas Kandagatla 			return ret;
693b3f736d1SSrinivas Kandagatla 
694b3f736d1SSrinivas Kandagatla 		ret = q6apm_graph_start(prtd->graph);
695b3f736d1SSrinivas Kandagatla 		if (ret)
696b3f736d1SSrinivas Kandagatla 			return ret;
697b3f736d1SSrinivas Kandagatla 
698b3f736d1SSrinivas Kandagatla 	} else {
699b3f736d1SSrinivas Kandagatla 		cfg.direction = dir;
700b3f736d1SSrinivas Kandagatla 		cfg.sample_rate = codec->sample_rate;
701b3f736d1SSrinivas Kandagatla 		cfg.num_channels = 2;
702b3f736d1SSrinivas Kandagatla 		cfg.bit_width = prtd->bits_per_sample;
703b3f736d1SSrinivas Kandagatla 		cfg.fmt = codec->id;
704b3f736d1SSrinivas Kandagatla 		memcpy(&cfg.codec, codec, sizeof(*codec));
705b3f736d1SSrinivas Kandagatla 
706b3f736d1SSrinivas Kandagatla 		ret = audioreach_compr_set_param(prtd->graph,  &cfg);
707b3f736d1SSrinivas Kandagatla 		if (ret < 0)
708b3f736d1SSrinivas Kandagatla 			return ret;
709b3f736d1SSrinivas Kandagatla 	}
710b3f736d1SSrinivas Kandagatla 	prtd->state = Q6APM_STREAM_RUNNING;
711b3f736d1SSrinivas Kandagatla 
712b3f736d1SSrinivas Kandagatla 	return 0;
713b3f736d1SSrinivas Kandagatla }
714b3f736d1SSrinivas Kandagatla 
q6apm_dai_compr_set_metadata(struct snd_soc_component * component,struct snd_compr_stream * stream,struct snd_compr_metadata * metadata)715b3f736d1SSrinivas Kandagatla static int q6apm_dai_compr_set_metadata(struct snd_soc_component *component,
716b3f736d1SSrinivas Kandagatla 					struct snd_compr_stream *stream,
717b3f736d1SSrinivas Kandagatla 					struct snd_compr_metadata *metadata)
718b3f736d1SSrinivas Kandagatla {
719b3f736d1SSrinivas Kandagatla 	struct snd_compr_runtime *runtime = stream->runtime;
720b3f736d1SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
721b3f736d1SSrinivas Kandagatla 	int ret = 0;
722b3f736d1SSrinivas Kandagatla 
723b3f736d1SSrinivas Kandagatla 	switch (metadata->key) {
724b3f736d1SSrinivas Kandagatla 	case SNDRV_COMPRESS_ENCODER_PADDING:
725b3f736d1SSrinivas Kandagatla 		q6apm_remove_trailing_silence(component->dev, prtd->graph,
726bd381c9dSKrzysztof Kozlowski 					      metadata->value[0]);
727b3f736d1SSrinivas Kandagatla 		break;
728b3f736d1SSrinivas Kandagatla 	case SNDRV_COMPRESS_ENCODER_DELAY:
729b3f736d1SSrinivas Kandagatla 		q6apm_remove_initial_silence(component->dev, prtd->graph,
730bd381c9dSKrzysztof Kozlowski 					     metadata->value[0]);
731b3f736d1SSrinivas Kandagatla 		break;
732b3f736d1SSrinivas Kandagatla 	default:
733b3f736d1SSrinivas Kandagatla 		ret = -EINVAL;
734b3f736d1SSrinivas Kandagatla 		break;
735b3f736d1SSrinivas Kandagatla 	}
736b3f736d1SSrinivas Kandagatla 
737b3f736d1SSrinivas Kandagatla 	return ret;
738b3f736d1SSrinivas Kandagatla }
739b3f736d1SSrinivas Kandagatla 
q6apm_dai_compr_mmap(struct snd_soc_component * component,struct snd_compr_stream * stream,struct vm_area_struct * vma)740c317d148SSrinivas Kandagatla static int q6apm_dai_compr_mmap(struct snd_soc_component *component,
741c317d148SSrinivas Kandagatla 				struct snd_compr_stream *stream,
742c317d148SSrinivas Kandagatla 				struct vm_area_struct *vma)
743c317d148SSrinivas Kandagatla {
744c317d148SSrinivas Kandagatla 	struct snd_compr_runtime *runtime = stream->runtime;
745c317d148SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
746c317d148SSrinivas Kandagatla 	struct device *dev = component->dev;
747c317d148SSrinivas Kandagatla 
748c317d148SSrinivas Kandagatla 	return dma_mmap_coherent(dev, vma, prtd->dma_buffer.area, prtd->dma_buffer.addr,
749c317d148SSrinivas Kandagatla 				 prtd->dma_buffer.bytes);
750c317d148SSrinivas Kandagatla }
751c317d148SSrinivas Kandagatla 
q6apm_compr_copy(struct snd_soc_component * component,struct snd_compr_stream * stream,char __user * buf,size_t count)752c317d148SSrinivas Kandagatla static int q6apm_compr_copy(struct snd_soc_component *component,
753c317d148SSrinivas Kandagatla 			    struct snd_compr_stream *stream, char __user *buf,
754c317d148SSrinivas Kandagatla 			    size_t count)
755c317d148SSrinivas Kandagatla {
756c317d148SSrinivas Kandagatla 	struct snd_compr_runtime *runtime = stream->runtime;
757c317d148SSrinivas Kandagatla 	struct q6apm_dai_rtd *prtd = runtime->private_data;
758c317d148SSrinivas Kandagatla 	void *dstn;
759c317d148SSrinivas Kandagatla 	unsigned long flags;
760c317d148SSrinivas Kandagatla 	size_t copy;
761c317d148SSrinivas Kandagatla 	u32 wflags = 0;
762c317d148SSrinivas Kandagatla 	u32 app_pointer;
763c317d148SSrinivas Kandagatla 	u32 bytes_received;
764c317d148SSrinivas Kandagatla 	uint32_t bytes_to_write;
765c317d148SSrinivas Kandagatla 	int avail, bytes_in_flight = 0;
766c317d148SSrinivas Kandagatla 
767c317d148SSrinivas Kandagatla 	bytes_received = prtd->bytes_received;
768c317d148SSrinivas Kandagatla 
769c317d148SSrinivas Kandagatla 	/**
770c317d148SSrinivas Kandagatla 	 * Make sure that next track data pointer is aligned at 32 bit boundary
771c317d148SSrinivas Kandagatla 	 * This is a Mandatory requirement from DSP data buffers alignment
772c317d148SSrinivas Kandagatla 	 */
773c317d148SSrinivas Kandagatla 	if (prtd->next_track)
774c317d148SSrinivas Kandagatla 		bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
775c317d148SSrinivas Kandagatla 
776c317d148SSrinivas Kandagatla 	app_pointer = bytes_received/prtd->pcm_size;
777c317d148SSrinivas Kandagatla 	app_pointer = bytes_received -  (app_pointer * prtd->pcm_size);
778c317d148SSrinivas Kandagatla 	dstn = prtd->dma_buffer.area + app_pointer;
779c317d148SSrinivas Kandagatla 
780c317d148SSrinivas Kandagatla 	if (count < prtd->pcm_size - app_pointer) {
781c317d148SSrinivas Kandagatla 		if (copy_from_user(dstn, buf, count))
782c317d148SSrinivas Kandagatla 			return -EFAULT;
783c317d148SSrinivas Kandagatla 	} else {
784c317d148SSrinivas Kandagatla 		copy = prtd->pcm_size - app_pointer;
785c317d148SSrinivas Kandagatla 		if (copy_from_user(dstn, buf, copy))
786c317d148SSrinivas Kandagatla 			return -EFAULT;
787c317d148SSrinivas Kandagatla 		if (copy_from_user(prtd->dma_buffer.area, buf + copy, count - copy))
788c317d148SSrinivas Kandagatla 			return -EFAULT;
789c317d148SSrinivas Kandagatla 	}
790c317d148SSrinivas Kandagatla 
791c317d148SSrinivas Kandagatla 	spin_lock_irqsave(&prtd->lock, flags);
792c317d148SSrinivas Kandagatla 	bytes_in_flight = prtd->bytes_received - prtd->copied_total;
793c317d148SSrinivas Kandagatla 
794c317d148SSrinivas Kandagatla 	if (prtd->next_track) {
795c317d148SSrinivas Kandagatla 		prtd->next_track = false;
796c317d148SSrinivas Kandagatla 		prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
797c317d148SSrinivas Kandagatla 		prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
798c317d148SSrinivas Kandagatla 	}
799c317d148SSrinivas Kandagatla 
800c317d148SSrinivas Kandagatla 	prtd->bytes_received = bytes_received + count;
801c317d148SSrinivas Kandagatla 
802c317d148SSrinivas Kandagatla 	/* Kick off the data to dsp if its starving!! */
803c317d148SSrinivas Kandagatla 	if (prtd->state == Q6APM_STREAM_RUNNING && (bytes_in_flight == 0)) {
804c317d148SSrinivas Kandagatla 		bytes_to_write = prtd->pcm_count;
805c317d148SSrinivas Kandagatla 		avail = prtd->bytes_received - prtd->bytes_sent;
806c317d148SSrinivas Kandagatla 
807c317d148SSrinivas Kandagatla 		if (avail < prtd->pcm_count)
808c317d148SSrinivas Kandagatla 			bytes_to_write = avail;
809c317d148SSrinivas Kandagatla 
810c317d148SSrinivas Kandagatla 		q6apm_write_async(prtd->graph, bytes_to_write, 0, 0, wflags);
811c317d148SSrinivas Kandagatla 		prtd->bytes_sent += bytes_to_write;
812c317d148SSrinivas Kandagatla 	}
813c317d148SSrinivas Kandagatla 
814c317d148SSrinivas Kandagatla 	spin_unlock_irqrestore(&prtd->lock, flags);
815c317d148SSrinivas Kandagatla 
816c317d148SSrinivas Kandagatla 	return count;
817c317d148SSrinivas Kandagatla }
818c317d148SSrinivas Kandagatla 
81988b60bf0SSrinivas Kandagatla static const struct snd_compress_ops q6apm_dai_compress_ops = {
82088b60bf0SSrinivas Kandagatla 	.open		= q6apm_dai_compr_open,
82188b60bf0SSrinivas Kandagatla 	.free		= q6apm_dai_compr_free,
822c0c87738SSrinivas Kandagatla 	.get_caps	= q6apm_dai_compr_get_caps,
823c0c87738SSrinivas Kandagatla 	.get_codec_caps	= q6apm_dai_compr_get_codec_caps,
824c337bf33SSrinivas Kandagatla 	.pointer	= q6apm_dai_compr_pointer,
825c337bf33SSrinivas Kandagatla 	.trigger	= q6apm_dai_compr_trigger,
826c337bf33SSrinivas Kandagatla 	.ack		= q6apm_dai_compr_ack,
827b3f736d1SSrinivas Kandagatla 	.set_params	= q6apm_dai_compr_set_params,
828b3f736d1SSrinivas Kandagatla 	.set_metadata	= q6apm_dai_compr_set_metadata,
829c317d148SSrinivas Kandagatla 	.mmap		= q6apm_dai_compr_mmap,
830c317d148SSrinivas Kandagatla 	.copy		= q6apm_compr_copy,
83188b60bf0SSrinivas Kandagatla };
83288b60bf0SSrinivas Kandagatla 
8339b4fe0f1SSrinivas Kandagatla static const struct snd_soc_component_driver q6apm_fe_dai_component = {
8349b4fe0f1SSrinivas Kandagatla 	.name		= DRV_NAME,
8359b4fe0f1SSrinivas Kandagatla 	.open		= q6apm_dai_open,
8369b4fe0f1SSrinivas Kandagatla 	.close		= q6apm_dai_close,
8379b4fe0f1SSrinivas Kandagatla 	.prepare	= q6apm_dai_prepare,
8389b4fe0f1SSrinivas Kandagatla 	.pcm_construct	= q6apm_dai_pcm_new,
8399b4fe0f1SSrinivas Kandagatla 	.hw_params	= q6apm_dai_hw_params,
8409b4fe0f1SSrinivas Kandagatla 	.pointer	= q6apm_dai_pointer,
8419b4fe0f1SSrinivas Kandagatla 	.trigger	= q6apm_dai_trigger,
8423d4a4411SSrinivas Kandagatla 	.ack		= q6apm_dai_ack,
84388b60bf0SSrinivas Kandagatla 	.compress_ops	= &q6apm_dai_compress_ops,
844ac192c1aSSrinivas Kandagatla 	.use_dai_pcm_id = true,
8459b4fe0f1SSrinivas Kandagatla };
8469b4fe0f1SSrinivas Kandagatla 
q6apm_dai_probe(struct platform_device * pdev)8479b4fe0f1SSrinivas Kandagatla static int q6apm_dai_probe(struct platform_device *pdev)
8489b4fe0f1SSrinivas Kandagatla {
8499b4fe0f1SSrinivas Kandagatla 	struct device *dev = &pdev->dev;
8509b4fe0f1SSrinivas Kandagatla 	struct device_node *node = dev->of_node;
8519b4fe0f1SSrinivas Kandagatla 	struct q6apm_dai_data *pdata;
8529b4fe0f1SSrinivas Kandagatla 	struct of_phandle_args args;
8539b4fe0f1SSrinivas Kandagatla 	int rc;
8549b4fe0f1SSrinivas Kandagatla 
8559b4fe0f1SSrinivas Kandagatla 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
8569b4fe0f1SSrinivas Kandagatla 	if (!pdata)
8579b4fe0f1SSrinivas Kandagatla 		return -ENOMEM;
8589b4fe0f1SSrinivas Kandagatla 
8599b4fe0f1SSrinivas Kandagatla 	rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
8609b4fe0f1SSrinivas Kandagatla 	if (rc < 0)
8619b4fe0f1SSrinivas Kandagatla 		pdata->sid = -1;
8629b4fe0f1SSrinivas Kandagatla 	else
8639b4fe0f1SSrinivas Kandagatla 		pdata->sid = args.args[0] & SID_MASK_DEFAULT;
8649b4fe0f1SSrinivas Kandagatla 
8659b4fe0f1SSrinivas Kandagatla 	dev_set_drvdata(dev, pdata);
8669b4fe0f1SSrinivas Kandagatla 
8679b4fe0f1SSrinivas Kandagatla 	return devm_snd_soc_register_component(dev, &q6apm_fe_dai_component, NULL, 0);
8689b4fe0f1SSrinivas Kandagatla }
8699b4fe0f1SSrinivas Kandagatla 
8709b4fe0f1SSrinivas Kandagatla #ifdef CONFIG_OF
8719b4fe0f1SSrinivas Kandagatla static const struct of_device_id q6apm_dai_device_id[] = {
8729b4fe0f1SSrinivas Kandagatla 	{ .compatible = "qcom,q6apm-dais" },
8739b4fe0f1SSrinivas Kandagatla 	{},
8749b4fe0f1SSrinivas Kandagatla };
8759b4fe0f1SSrinivas Kandagatla MODULE_DEVICE_TABLE(of, q6apm_dai_device_id);
8769b4fe0f1SSrinivas Kandagatla #endif
8779b4fe0f1SSrinivas Kandagatla 
8789b4fe0f1SSrinivas Kandagatla static struct platform_driver q6apm_dai_platform_driver = {
8799b4fe0f1SSrinivas Kandagatla 	.driver = {
8809b4fe0f1SSrinivas Kandagatla 		.name = "q6apm-dai",
8819b4fe0f1SSrinivas Kandagatla 		.of_match_table = of_match_ptr(q6apm_dai_device_id),
8829b4fe0f1SSrinivas Kandagatla 	},
8839b4fe0f1SSrinivas Kandagatla 	.probe = q6apm_dai_probe,
8849b4fe0f1SSrinivas Kandagatla };
8859b4fe0f1SSrinivas Kandagatla module_platform_driver(q6apm_dai_platform_driver);
8869b4fe0f1SSrinivas Kandagatla 
8879b4fe0f1SSrinivas Kandagatla MODULE_DESCRIPTION("Q6APM dai driver");
8889b4fe0f1SSrinivas Kandagatla MODULE_LICENSE("GPL");
889