cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

q6asm-dai.c (37689B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
      3// Copyright (c) 2018, Linaro Limited
      4
      5#include <linux/init.h>
      6#include <linux/err.h>
      7#include <linux/module.h>
      8#include <linux/platform_device.h>
      9#include <linux/slab.h>
     10#include <sound/soc.h>
     11#include <sound/soc-dapm.h>
     12#include <sound/pcm.h>
     13#include <linux/spinlock.h>
     14#include <sound/compress_driver.h>
     15#include <asm/dma.h>
     16#include <linux/dma-mapping.h>
     17#include <linux/of_device.h>
     18#include <sound/pcm_params.h>
     19#include "q6asm.h"
     20#include "q6routing.h"
     21#include "q6dsp-errno.h"
     22
     23#define DRV_NAME	"q6asm-fe-dai"
     24
     25#define PLAYBACK_MIN_NUM_PERIODS    2
     26#define PLAYBACK_MAX_NUM_PERIODS   8
     27#define PLAYBACK_MAX_PERIOD_SIZE    65536
     28#define PLAYBACK_MIN_PERIOD_SIZE    128
     29#define CAPTURE_MIN_NUM_PERIODS     2
     30#define CAPTURE_MAX_NUM_PERIODS     8
     31#define CAPTURE_MAX_PERIOD_SIZE     4096
     32#define CAPTURE_MIN_PERIOD_SIZE     320
     33#define SID_MASK_DEFAULT	0xF
     34
     35/* Default values used if user space does not set */
     36#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
     37#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
     38#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
     39#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
     40
     41#define ALAC_CH_LAYOUT_MONO   ((101 << 16) | 1)
     42#define ALAC_CH_LAYOUT_STEREO ((101 << 16) | 2)
     43
     44enum stream_state {
     45	Q6ASM_STREAM_IDLE = 0,
     46	Q6ASM_STREAM_STOPPED,
     47	Q6ASM_STREAM_RUNNING,
     48};
     49
     50struct q6asm_dai_rtd {
     51	struct snd_pcm_substream *substream;
     52	struct snd_compr_stream *cstream;
     53	struct snd_codec codec;
     54	struct snd_dma_buffer dma_buffer;
     55	spinlock_t lock;
     56	phys_addr_t phys;
     57	unsigned int pcm_size;
     58	unsigned int pcm_count;
     59	unsigned int pcm_irq_pos;       /* IRQ position */
     60	unsigned int periods;
     61	unsigned int bytes_sent;
     62	unsigned int bytes_received;
     63	unsigned int copied_total;
     64	uint16_t bits_per_sample;
     65	uint16_t source; /* Encoding source bit mask */
     66	struct audio_client *audio_client;
     67	uint32_t next_track_stream_id;
     68	bool next_track;
     69	uint32_t stream_id;
     70	uint16_t session_id;
     71	enum stream_state state;
     72	uint32_t initial_samples_drop;
     73	uint32_t trailing_samples_drop;
     74	bool notify_on_drain;
     75};
     76
     77struct q6asm_dai_data {
     78	struct snd_soc_dai_driver *dais;
     79	int num_dais;
     80	long long int sid;
     81};
     82
     83static const struct snd_pcm_hardware q6asm_dai_hardware_capture = {
     84	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
     85				SNDRV_PCM_INFO_BLOCK_TRANSFER |
     86				SNDRV_PCM_INFO_MMAP_VALID |
     87				SNDRV_PCM_INFO_INTERLEAVED |
     88				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
     89	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
     90				SNDRV_PCM_FMTBIT_S24_LE),
     91	.rates =                SNDRV_PCM_RATE_8000_48000,
     92	.rate_min =             8000,
     93	.rate_max =             48000,
     94	.channels_min =         1,
     95	.channels_max =         4,
     96	.buffer_bytes_max =     CAPTURE_MAX_NUM_PERIODS *
     97				CAPTURE_MAX_PERIOD_SIZE,
     98	.period_bytes_min =	CAPTURE_MIN_PERIOD_SIZE,
     99	.period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
    100	.periods_min =          CAPTURE_MIN_NUM_PERIODS,
    101	.periods_max =          CAPTURE_MAX_NUM_PERIODS,
    102	.fifo_size =            0,
    103};
    104
    105static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
    106	.info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BATCH |
    107				SNDRV_PCM_INFO_BLOCK_TRANSFER |
    108				SNDRV_PCM_INFO_MMAP_VALID |
    109				SNDRV_PCM_INFO_INTERLEAVED |
    110				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
    111	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
    112				SNDRV_PCM_FMTBIT_S24_LE),
    113	.rates =                SNDRV_PCM_RATE_8000_192000,
    114	.rate_min =             8000,
    115	.rate_max =             192000,
    116	.channels_min =         1,
    117	.channels_max =         8,
    118	.buffer_bytes_max =     (PLAYBACK_MAX_NUM_PERIODS *
    119				PLAYBACK_MAX_PERIOD_SIZE),
    120	.period_bytes_min =	PLAYBACK_MIN_PERIOD_SIZE,
    121	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
    122	.periods_min =          PLAYBACK_MIN_NUM_PERIODS,
    123	.periods_max =          PLAYBACK_MAX_NUM_PERIODS,
    124	.fifo_size =            0,
    125};
    126
    127#define Q6ASM_FEDAI_DRIVER(num) { \
    128		.playback = {						\
    129			.stream_name = "MultiMedia"#num" Playback",	\
    130			.rates = (SNDRV_PCM_RATE_8000_192000|		\
    131					SNDRV_PCM_RATE_KNOT),		\
    132			.formats = (SNDRV_PCM_FMTBIT_S16_LE |		\
    133					SNDRV_PCM_FMTBIT_S24_LE),	\
    134			.channels_min = 1,				\
    135			.channels_max = 8,				\
    136			.rate_min =     8000,				\
    137			.rate_max =	192000,				\
    138		},							\
    139		.capture = {						\
    140			.stream_name = "MultiMedia"#num" Capture",	\
    141			.rates = (SNDRV_PCM_RATE_8000_48000|		\
    142					SNDRV_PCM_RATE_KNOT),		\
    143			.formats = (SNDRV_PCM_FMTBIT_S16_LE |		\
    144				    SNDRV_PCM_FMTBIT_S24_LE),		\
    145			.channels_min = 1,				\
    146			.channels_max = 4,				\
    147			.rate_min =     8000,				\
    148			.rate_max =	48000,				\
    149		},							\
    150		.name = "MultiMedia"#num,				\
    151		.id = MSM_FRONTEND_DAI_MULTIMEDIA##num,			\
    152	}
    153
    154/* Conventional and unconventional sample rate supported */
    155static unsigned int supported_sample_rates[] = {
    156	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
    157	88200, 96000, 176400, 192000
    158};
    159
    160static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
    161	.count = ARRAY_SIZE(supported_sample_rates),
    162	.list = supported_sample_rates,
    163	.mask = 0,
    164};
    165
    166static const struct snd_compr_codec_caps q6asm_compr_caps = {
    167	.num_descriptors = 1,
    168	.descriptor[0].max_ch = 2,
    169	.descriptor[0].sample_rates = {	8000, 11025, 12000, 16000, 22050,
    170					24000, 32000, 44100, 48000, 88200,
    171					96000, 176400, 192000 },
    172	.descriptor[0].num_sample_rates = 13,
    173	.descriptor[0].bit_rate[0] = 320,
    174	.descriptor[0].bit_rate[1] = 128,
    175	.descriptor[0].num_bitrates = 2,
    176	.descriptor[0].profiles = 0,
    177	.descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
    178	.descriptor[0].formats = 0,
    179};
    180
    181static void event_handler(uint32_t opcode, uint32_t token,
    182			  void *payload, void *priv)
    183{
    184	struct q6asm_dai_rtd *prtd = priv;
    185	struct snd_pcm_substream *substream = prtd->substream;
    186
    187	switch (opcode) {
    188	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
    189		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    190			q6asm_write_async(prtd->audio_client, prtd->stream_id,
    191				   prtd->pcm_count, 0, 0, 0);
    192		break;
    193	case ASM_CLIENT_EVENT_CMD_EOS_DONE:
    194		prtd->state = Q6ASM_STREAM_STOPPED;
    195		break;
    196	case ASM_CLIENT_EVENT_DATA_WRITE_DONE: {
    197		prtd->pcm_irq_pos += prtd->pcm_count;
    198		snd_pcm_period_elapsed(substream);
    199		if (prtd->state == Q6ASM_STREAM_RUNNING)
    200			q6asm_write_async(prtd->audio_client, prtd->stream_id,
    201					   prtd->pcm_count, 0, 0, 0);
    202
    203		break;
    204		}
    205	case ASM_CLIENT_EVENT_DATA_READ_DONE:
    206		prtd->pcm_irq_pos += prtd->pcm_count;
    207		snd_pcm_period_elapsed(substream);
    208		if (prtd->state == Q6ASM_STREAM_RUNNING)
    209			q6asm_read(prtd->audio_client, prtd->stream_id);
    210
    211		break;
    212	default:
    213		break;
    214	}
    215}
    216
    217static int q6asm_dai_prepare(struct snd_soc_component *component,
    218			     struct snd_pcm_substream *substream)
    219{
    220	struct snd_pcm_runtime *runtime = substream->runtime;
    221	struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
    222	struct q6asm_dai_rtd *prtd = runtime->private_data;
    223	struct q6asm_dai_data *pdata;
    224	struct device *dev = component->dev;
    225	int ret, i;
    226
    227	pdata = snd_soc_component_get_drvdata(component);
    228	if (!pdata)
    229		return -EINVAL;
    230
    231	if (!prtd || !prtd->audio_client) {
    232		dev_err(dev, "%s: private data null or audio client freed\n",
    233			__func__);
    234		return -EINVAL;
    235	}
    236
    237	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
    238	prtd->pcm_irq_pos = 0;
    239	/* rate and channels are sent to audio driver */
    240	if (prtd->state) {
    241		/* clear the previous setup if any  */
    242		q6asm_cmd(prtd->audio_client, prtd->stream_id, CMD_CLOSE);
    243		q6asm_unmap_memory_regions(substream->stream,
    244					   prtd->audio_client);
    245		q6routing_stream_close(soc_prtd->dai_link->id,
    246					 substream->stream);
    247	}
    248
    249	ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client,
    250				       prtd->phys,
    251				       (prtd->pcm_size / prtd->periods),
    252				       prtd->periods);
    253
    254	if (ret < 0) {
    255		dev_err(dev, "Audio Start: Buffer Allocation failed rc = %d\n",
    256							ret);
    257		return -ENOMEM;
    258	}
    259
    260	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    261		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id,
    262				       FORMAT_LINEAR_PCM,
    263				       0, prtd->bits_per_sample, false);
    264	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
    265		ret = q6asm_open_read(prtd->audio_client, prtd->stream_id,
    266				      FORMAT_LINEAR_PCM,
    267				      prtd->bits_per_sample);
    268	}
    269
    270	if (ret < 0) {
    271		dev_err(dev, "%s: q6asm_open_write failed\n", __func__);
    272		goto open_err;
    273	}
    274
    275	prtd->session_id = q6asm_get_session_id(prtd->audio_client);
    276	ret = q6routing_stream_open(soc_prtd->dai_link->id, LEGACY_PCM_MODE,
    277			      prtd->session_id, substream->stream);
    278	if (ret) {
    279		dev_err(dev, "%s: stream reg failed ret:%d\n", __func__, ret);
    280		goto routing_err;
    281	}
    282
    283	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    284		ret = q6asm_media_format_block_multi_ch_pcm(
    285				prtd->audio_client, prtd->stream_id,
    286				runtime->rate, runtime->channels, NULL,
    287				prtd->bits_per_sample);
    288	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
    289		ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
    290							   prtd->stream_id,
    291							   runtime->rate,
    292							   runtime->channels,
    293							   prtd->bits_per_sample);
    294
    295		/* Queue the buffers */
    296		for (i = 0; i < runtime->periods; i++)
    297			q6asm_read(prtd->audio_client, prtd->stream_id);
    298
    299	}
    300	if (ret < 0)
    301		dev_info(dev, "%s: CMD Format block failed\n", __func__);
    302	else
    303		prtd->state = Q6ASM_STREAM_RUNNING;
    304
    305	return ret;
    306
    307routing_err:
    308	q6asm_cmd(prtd->audio_client, prtd->stream_id,  CMD_CLOSE);
    309open_err:
    310	q6asm_unmap_memory_regions(substream->stream, prtd->audio_client);
    311	q6asm_audio_client_free(prtd->audio_client);
    312	prtd->audio_client = NULL;
    313
    314	return ret;
    315}
    316
    317static int q6asm_dai_trigger(struct snd_soc_component *component,
    318			     struct snd_pcm_substream *substream, int cmd)
    319{
    320	int ret = 0;
    321	struct snd_pcm_runtime *runtime = substream->runtime;
    322	struct q6asm_dai_rtd *prtd = runtime->private_data;
    323
    324	switch (cmd) {
    325	case SNDRV_PCM_TRIGGER_START:
    326	case SNDRV_PCM_TRIGGER_RESUME:
    327	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    328		ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
    329				       0, 0, 0);
    330		break;
    331	case SNDRV_PCM_TRIGGER_STOP:
    332		prtd->state = Q6ASM_STREAM_STOPPED;
    333		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
    334				       CMD_EOS);
    335		break;
    336	case SNDRV_PCM_TRIGGER_SUSPEND:
    337	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    338		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
    339				       CMD_PAUSE);
    340		break;
    341	default:
    342		ret = -EINVAL;
    343		break;
    344	}
    345
    346	return ret;
    347}
    348
    349static int q6asm_dai_open(struct snd_soc_component *component,
    350			  struct snd_pcm_substream *substream)
    351{
    352	struct snd_pcm_runtime *runtime = substream->runtime;
    353	struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
    354	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_prtd, 0);
    355	struct q6asm_dai_rtd *prtd;
    356	struct q6asm_dai_data *pdata;
    357	struct device *dev = component->dev;
    358	int ret = 0;
    359	int stream_id;
    360
    361	stream_id = cpu_dai->driver->id;
    362
    363	pdata = snd_soc_component_get_drvdata(component);
    364	if (!pdata) {
    365		dev_err(dev, "Drv data not found ..\n");
    366		return -EINVAL;
    367	}
    368
    369	prtd = kzalloc(sizeof(struct q6asm_dai_rtd), GFP_KERNEL);
    370	if (prtd == NULL)
    371		return -ENOMEM;
    372
    373	prtd->substream = substream;
    374	prtd->audio_client = q6asm_audio_client_alloc(dev,
    375				(q6asm_cb)event_handler, prtd, stream_id,
    376				LEGACY_PCM_MODE);
    377	if (IS_ERR(prtd->audio_client)) {
    378		dev_info(dev, "%s: Could not allocate memory\n", __func__);
    379		ret = PTR_ERR(prtd->audio_client);
    380		kfree(prtd);
    381		return ret;
    382	}
    383
    384	/* DSP expects stream id from 1 */
    385	prtd->stream_id = 1;
    386
    387	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    388		runtime->hw = q6asm_dai_hardware_playback;
    389	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
    390		runtime->hw = q6asm_dai_hardware_capture;
    391
    392	ret = snd_pcm_hw_constraint_list(runtime, 0,
    393				SNDRV_PCM_HW_PARAM_RATE,
    394				&constraints_sample_rates);
    395	if (ret < 0)
    396		dev_info(dev, "snd_pcm_hw_constraint_list failed\n");
    397	/* Ensure that buffer size is a multiple of period size */
    398	ret = snd_pcm_hw_constraint_integer(runtime,
    399					    SNDRV_PCM_HW_PARAM_PERIODS);
    400	if (ret < 0)
    401		dev_info(dev, "snd_pcm_hw_constraint_integer failed\n");
    402
    403	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    404		ret = snd_pcm_hw_constraint_minmax(runtime,
    405			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
    406			PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
    407			PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
    408		if (ret < 0) {
    409			dev_err(dev, "constraint for buffer bytes min max ret = %d\n",
    410				ret);
    411		}
    412	}
    413
    414	ret = snd_pcm_hw_constraint_step(runtime, 0,
    415		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
    416	if (ret < 0) {
    417		dev_err(dev, "constraint for period bytes step ret = %d\n",
    418								ret);
    419	}
    420	ret = snd_pcm_hw_constraint_step(runtime, 0,
    421		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
    422	if (ret < 0) {
    423		dev_err(dev, "constraint for buffer bytes step ret = %d\n",
    424								ret);
    425	}
    426
    427	runtime->private_data = prtd;
    428
    429	snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_playback);
    430
    431	runtime->dma_bytes = q6asm_dai_hardware_playback.buffer_bytes_max;
    432
    433
    434	if (pdata->sid < 0)
    435		prtd->phys = substream->dma_buffer.addr;
    436	else
    437		prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32);
    438
    439	return 0;
    440}
    441
    442static int q6asm_dai_close(struct snd_soc_component *component,
    443			   struct snd_pcm_substream *substream)
    444{
    445	struct snd_pcm_runtime *runtime = substream->runtime;
    446	struct snd_soc_pcm_runtime *soc_prtd = asoc_substream_to_rtd(substream);
    447	struct q6asm_dai_rtd *prtd = runtime->private_data;
    448
    449	if (prtd->audio_client) {
    450		if (prtd->state)
    451			q6asm_cmd(prtd->audio_client, prtd->stream_id,
    452				  CMD_CLOSE);
    453
    454		q6asm_unmap_memory_regions(substream->stream,
    455					   prtd->audio_client);
    456		q6asm_audio_client_free(prtd->audio_client);
    457		prtd->audio_client = NULL;
    458	}
    459	q6routing_stream_close(soc_prtd->dai_link->id,
    460						substream->stream);
    461	kfree(prtd);
    462	return 0;
    463}
    464
    465static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_soc_component *component,
    466					   struct snd_pcm_substream *substream)
    467{
    468
    469	struct snd_pcm_runtime *runtime = substream->runtime;
    470	struct q6asm_dai_rtd *prtd = runtime->private_data;
    471
    472	if (prtd->pcm_irq_pos >= prtd->pcm_size)
    473		prtd->pcm_irq_pos = 0;
    474
    475	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
    476}
    477
    478static int q6asm_dai_hw_params(struct snd_soc_component *component,
    479			       struct snd_pcm_substream *substream,
    480			       struct snd_pcm_hw_params *params)
    481{
    482	struct snd_pcm_runtime *runtime = substream->runtime;
    483	struct q6asm_dai_rtd *prtd = runtime->private_data;
    484
    485	prtd->pcm_size = params_buffer_bytes(params);
    486	prtd->periods = params_periods(params);
    487
    488	switch (params_format(params)) {
    489	case SNDRV_PCM_FORMAT_S16_LE:
    490		prtd->bits_per_sample = 16;
    491		break;
    492	case SNDRV_PCM_FORMAT_S24_LE:
    493		prtd->bits_per_sample = 24;
    494		break;
    495	}
    496
    497	return 0;
    498}
    499
    500static void compress_event_handler(uint32_t opcode, uint32_t token,
    501				   void *payload, void *priv)
    502{
    503	struct q6asm_dai_rtd *prtd = priv;
    504	struct snd_compr_stream *substream = prtd->cstream;
    505	unsigned long flags;
    506	u32 wflags = 0;
    507	uint64_t avail;
    508	uint32_t bytes_written, bytes_to_write;
    509	bool is_last_buffer = false;
    510
    511	switch (opcode) {
    512	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
    513		spin_lock_irqsave(&prtd->lock, flags);
    514		if (!prtd->bytes_sent) {
    515			q6asm_stream_remove_initial_silence(prtd->audio_client,
    516						    prtd->stream_id,
    517						    prtd->initial_samples_drop);
    518
    519			q6asm_write_async(prtd->audio_client, prtd->stream_id,
    520					  prtd->pcm_count, 0, 0, 0);
    521			prtd->bytes_sent += prtd->pcm_count;
    522		}
    523
    524		spin_unlock_irqrestore(&prtd->lock, flags);
    525		break;
    526
    527	case ASM_CLIENT_EVENT_CMD_EOS_DONE:
    528		spin_lock_irqsave(&prtd->lock, flags);
    529		if (prtd->notify_on_drain) {
    530			if (substream->partial_drain) {
    531				/*
    532				 * Close old stream and make it stale, switch
    533				 * the active stream now!
    534				 */
    535				q6asm_cmd_nowait(prtd->audio_client,
    536						 prtd->stream_id,
    537						 CMD_CLOSE);
    538				/*
    539				 * vaild stream ids start from 1, So we are
    540				 * toggling this between 1 and 2.
    541				 */
    542				prtd->stream_id = (prtd->stream_id == 1 ? 2 : 1);
    543			}
    544
    545			snd_compr_drain_notify(prtd->cstream);
    546			prtd->notify_on_drain = false;
    547
    548		} else {
    549			prtd->state = Q6ASM_STREAM_STOPPED;
    550		}
    551		spin_unlock_irqrestore(&prtd->lock, flags);
    552		break;
    553
    554	case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
    555		spin_lock_irqsave(&prtd->lock, flags);
    556
    557		bytes_written = token >> ASM_WRITE_TOKEN_LEN_SHIFT;
    558		prtd->copied_total += bytes_written;
    559		snd_compr_fragment_elapsed(substream);
    560
    561		if (prtd->state != Q6ASM_STREAM_RUNNING) {
    562			spin_unlock_irqrestore(&prtd->lock, flags);
    563			break;
    564		}
    565
    566		avail = prtd->bytes_received - prtd->bytes_sent;
    567		if (avail > prtd->pcm_count) {
    568			bytes_to_write = prtd->pcm_count;
    569		} else {
    570			if (substream->partial_drain || prtd->notify_on_drain)
    571				is_last_buffer = true;
    572			bytes_to_write = avail;
    573		}
    574
    575		if (bytes_to_write) {
    576			if (substream->partial_drain && is_last_buffer) {
    577				wflags |= ASM_LAST_BUFFER_FLAG;
    578				q6asm_stream_remove_trailing_silence(prtd->audio_client,
    579						     prtd->stream_id,
    580						     prtd->trailing_samples_drop);
    581			}
    582
    583			q6asm_write_async(prtd->audio_client, prtd->stream_id,
    584					  bytes_to_write, 0, 0, wflags);
    585
    586			prtd->bytes_sent += bytes_to_write;
    587		}
    588
    589		if (prtd->notify_on_drain && is_last_buffer)
    590			q6asm_cmd_nowait(prtd->audio_client,
    591					 prtd->stream_id, CMD_EOS);
    592
    593		spin_unlock_irqrestore(&prtd->lock, flags);
    594		break;
    595
    596	default:
    597		break;
    598	}
    599}
    600
    601static int q6asm_dai_compr_open(struct snd_soc_component *component,
    602				struct snd_compr_stream *stream)
    603{
    604	struct snd_soc_pcm_runtime *rtd = stream->private_data;
    605	struct snd_compr_runtime *runtime = stream->runtime;
    606	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    607	struct q6asm_dai_data *pdata;
    608	struct device *dev = component->dev;
    609	struct q6asm_dai_rtd *prtd;
    610	int stream_id, size, ret;
    611
    612	stream_id = cpu_dai->driver->id;
    613	pdata = snd_soc_component_get_drvdata(component);
    614	if (!pdata) {
    615		dev_err(dev, "Drv data not found ..\n");
    616		return -EINVAL;
    617	}
    618
    619	prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
    620	if (!prtd)
    621		return -ENOMEM;
    622
    623	/* DSP expects stream id from 1 */
    624	prtd->stream_id = 1;
    625
    626	prtd->cstream = stream;
    627	prtd->audio_client = q6asm_audio_client_alloc(dev,
    628					(q6asm_cb)compress_event_handler,
    629					prtd, stream_id, LEGACY_PCM_MODE);
    630	if (IS_ERR(prtd->audio_client)) {
    631		dev_err(dev, "Could not allocate memory\n");
    632		ret = PTR_ERR(prtd->audio_client);
    633		goto free_prtd;
    634	}
    635
    636	size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
    637			COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
    638	ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
    639				  &prtd->dma_buffer);
    640	if (ret) {
    641		dev_err(dev, "Cannot allocate buffer(s)\n");
    642		goto free_client;
    643	}
    644
    645	if (pdata->sid < 0)
    646		prtd->phys = prtd->dma_buffer.addr;
    647	else
    648		prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
    649
    650	snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
    651	spin_lock_init(&prtd->lock);
    652	runtime->private_data = prtd;
    653
    654	return 0;
    655
    656free_client:
    657	q6asm_audio_client_free(prtd->audio_client);
    658free_prtd:
    659	kfree(prtd);
    660
    661	return ret;
    662}
    663
    664static int q6asm_dai_compr_free(struct snd_soc_component *component,
    665				struct snd_compr_stream *stream)
    666{
    667	struct snd_compr_runtime *runtime = stream->runtime;
    668	struct q6asm_dai_rtd *prtd = runtime->private_data;
    669	struct snd_soc_pcm_runtime *rtd = stream->private_data;
    670
    671	if (prtd->audio_client) {
    672		if (prtd->state) {
    673			q6asm_cmd(prtd->audio_client, prtd->stream_id,
    674				  CMD_CLOSE);
    675			if (prtd->next_track_stream_id) {
    676				q6asm_cmd(prtd->audio_client,
    677					  prtd->next_track_stream_id,
    678					  CMD_CLOSE);
    679			}
    680		}
    681
    682		snd_dma_free_pages(&prtd->dma_buffer);
    683		q6asm_unmap_memory_regions(stream->direction,
    684					   prtd->audio_client);
    685		q6asm_audio_client_free(prtd->audio_client);
    686		prtd->audio_client = NULL;
    687	}
    688	q6routing_stream_close(rtd->dai_link->id, stream->direction);
    689	kfree(prtd);
    690
    691	return 0;
    692}
    693
    694static int __q6asm_dai_compr_set_codec_params(struct snd_soc_component *component,
    695					      struct snd_compr_stream *stream,
    696					      struct snd_codec *codec,
    697					      int stream_id)
    698{
    699	struct snd_compr_runtime *runtime = stream->runtime;
    700	struct q6asm_dai_rtd *prtd = runtime->private_data;
    701	struct q6asm_flac_cfg flac_cfg;
    702	struct q6asm_wma_cfg wma_cfg;
    703	struct q6asm_alac_cfg alac_cfg;
    704	struct q6asm_ape_cfg ape_cfg;
    705	unsigned int wma_v9 = 0;
    706	struct device *dev = component->dev;
    707	int ret;
    708	union snd_codec_options *codec_options;
    709	struct snd_dec_flac *flac;
    710	struct snd_dec_wma *wma;
    711	struct snd_dec_alac *alac;
    712	struct snd_dec_ape *ape;
    713
    714	codec_options = &(prtd->codec.options);
    715
    716	memcpy(&prtd->codec, codec, sizeof(*codec));
    717
    718	switch (codec->id) {
    719	case SND_AUDIOCODEC_FLAC:
    720
    721		memset(&flac_cfg, 0x0, sizeof(struct q6asm_flac_cfg));
    722		flac = &codec_options->flac_d;
    723
    724		flac_cfg.ch_cfg = codec->ch_in;
    725		flac_cfg.sample_rate = codec->sample_rate;
    726		flac_cfg.stream_info_present = 1;
    727		flac_cfg.sample_size = flac->sample_size;
    728		flac_cfg.min_blk_size = flac->min_blk_size;
    729		flac_cfg.max_blk_size = flac->max_blk_size;
    730		flac_cfg.max_frame_size = flac->max_frame_size;
    731		flac_cfg.min_frame_size = flac->min_frame_size;
    732
    733		ret = q6asm_stream_media_format_block_flac(prtd->audio_client,
    734							   stream_id,
    735							   &flac_cfg);
    736		if (ret < 0) {
    737			dev_err(dev, "FLAC CMD Format block failed:%d\n", ret);
    738			return -EIO;
    739		}
    740		break;
    741
    742	case SND_AUDIOCODEC_WMA:
    743		wma = &codec_options->wma_d;
    744
    745		memset(&wma_cfg, 0x0, sizeof(struct q6asm_wma_cfg));
    746
    747		wma_cfg.sample_rate =  codec->sample_rate;
    748		wma_cfg.num_channels = codec->ch_in;
    749		wma_cfg.bytes_per_sec = codec->bit_rate / 8;
    750		wma_cfg.block_align = codec->align;
    751		wma_cfg.bits_per_sample = prtd->bits_per_sample;
    752		wma_cfg.enc_options = wma->encoder_option;
    753		wma_cfg.adv_enc_options = wma->adv_encoder_option;
    754		wma_cfg.adv_enc_options2 = wma->adv_encoder_option2;
    755
    756		if (wma_cfg.num_channels == 1)
    757			wma_cfg.channel_mask = 4; /* Mono Center */
    758		else if (wma_cfg.num_channels == 2)
    759			wma_cfg.channel_mask = 3; /* Stereo FL/FR */
    760		else
    761			return -EINVAL;
    762
    763		/* check the codec profile */
    764		switch (codec->profile) {
    765		case SND_AUDIOPROFILE_WMA9:
    766			wma_cfg.fmtag = 0x161;
    767			wma_v9 = 1;
    768			break;
    769
    770		case SND_AUDIOPROFILE_WMA10:
    771			wma_cfg.fmtag = 0x166;
    772			break;
    773
    774		case SND_AUDIOPROFILE_WMA9_PRO:
    775			wma_cfg.fmtag = 0x162;
    776			break;
    777
    778		case SND_AUDIOPROFILE_WMA9_LOSSLESS:
    779			wma_cfg.fmtag = 0x163;
    780			break;
    781
    782		case SND_AUDIOPROFILE_WMA10_LOSSLESS:
    783			wma_cfg.fmtag = 0x167;
    784			break;
    785
    786		default:
    787			dev_err(dev, "Unknown WMA profile:%x\n",
    788				codec->profile);
    789			return -EIO;
    790		}
    791
    792		if (wma_v9)
    793			ret = q6asm_stream_media_format_block_wma_v9(
    794					prtd->audio_client, stream_id,
    795					&wma_cfg);
    796		else
    797			ret = q6asm_stream_media_format_block_wma_v10(
    798					prtd->audio_client, stream_id,
    799					&wma_cfg);
    800		if (ret < 0) {
    801			dev_err(dev, "WMA9 CMD failed:%d\n", ret);
    802			return -EIO;
    803		}
    804		break;
    805
    806	case SND_AUDIOCODEC_ALAC:
    807		memset(&alac_cfg, 0x0, sizeof(alac_cfg));
    808		alac = &codec_options->alac_d;
    809
    810		alac_cfg.sample_rate = codec->sample_rate;
    811		alac_cfg.avg_bit_rate = codec->bit_rate;
    812		alac_cfg.bit_depth = prtd->bits_per_sample;
    813		alac_cfg.num_channels = codec->ch_in;
    814
    815		alac_cfg.frame_length = alac->frame_length;
    816		alac_cfg.pb = alac->pb;
    817		alac_cfg.mb = alac->mb;
    818		alac_cfg.kb = alac->kb;
    819		alac_cfg.max_run = alac->max_run;
    820		alac_cfg.compatible_version = alac->compatible_version;
    821		alac_cfg.max_frame_bytes = alac->max_frame_bytes;
    822
    823		switch (codec->ch_in) {
    824		case 1:
    825			alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_MONO;
    826			break;
    827		case 2:
    828			alac_cfg.channel_layout_tag = ALAC_CH_LAYOUT_STEREO;
    829			break;
    830		}
    831		ret = q6asm_stream_media_format_block_alac(prtd->audio_client,
    832							   stream_id,
    833							   &alac_cfg);
    834		if (ret < 0) {
    835			dev_err(dev, "ALAC CMD Format block failed:%d\n", ret);
    836			return -EIO;
    837		}
    838		break;
    839
    840	case SND_AUDIOCODEC_APE:
    841		memset(&ape_cfg, 0x0, sizeof(ape_cfg));
    842		ape = &codec_options->ape_d;
    843
    844		ape_cfg.sample_rate = codec->sample_rate;
    845		ape_cfg.num_channels = codec->ch_in;
    846		ape_cfg.bits_per_sample = prtd->bits_per_sample;
    847
    848		ape_cfg.compatible_version = ape->compatible_version;
    849		ape_cfg.compression_level = ape->compression_level;
    850		ape_cfg.format_flags = ape->format_flags;
    851		ape_cfg.blocks_per_frame = ape->blocks_per_frame;
    852		ape_cfg.final_frame_blocks = ape->final_frame_blocks;
    853		ape_cfg.total_frames = ape->total_frames;
    854		ape_cfg.seek_table_present = ape->seek_table_present;
    855
    856		ret = q6asm_stream_media_format_block_ape(prtd->audio_client,
    857							  stream_id,
    858							  &ape_cfg);
    859		if (ret < 0) {
    860			dev_err(dev, "APE CMD Format block failed:%d\n", ret);
    861			return -EIO;
    862		}
    863		break;
    864
    865	default:
    866		break;
    867	}
    868
    869	return 0;
    870}
    871
    872static int q6asm_dai_compr_set_params(struct snd_soc_component *component,
    873				      struct snd_compr_stream *stream,
    874				      struct snd_compr_params *params)
    875{
    876	struct snd_compr_runtime *runtime = stream->runtime;
    877	struct q6asm_dai_rtd *prtd = runtime->private_data;
    878	struct snd_soc_pcm_runtime *rtd = stream->private_data;
    879	int dir = stream->direction;
    880	struct q6asm_dai_data *pdata;
    881	struct device *dev = component->dev;
    882	int ret;
    883
    884	pdata = snd_soc_component_get_drvdata(component);
    885	if (!pdata)
    886		return -EINVAL;
    887
    888	if (!prtd || !prtd->audio_client) {
    889		dev_err(dev, "private data null or audio client freed\n");
    890		return -EINVAL;
    891	}
    892
    893	prtd->periods = runtime->fragments;
    894	prtd->pcm_count = runtime->fragment_size;
    895	prtd->pcm_size = runtime->fragments * runtime->fragment_size;
    896	prtd->bits_per_sample = 16;
    897
    898	if (dir == SND_COMPRESS_PLAYBACK) {
    899		ret = q6asm_open_write(prtd->audio_client, prtd->stream_id, params->codec.id,
    900				params->codec.profile, prtd->bits_per_sample,
    901				true);
    902
    903		if (ret < 0) {
    904			dev_err(dev, "q6asm_open_write failed\n");
    905			q6asm_audio_client_free(prtd->audio_client);
    906			prtd->audio_client = NULL;
    907			return ret;
    908		}
    909	}
    910
    911	prtd->session_id = q6asm_get_session_id(prtd->audio_client);
    912	ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
    913			      prtd->session_id, dir);
    914	if (ret) {
    915		dev_err(dev, "Stream reg failed ret:%d\n", ret);
    916		return ret;
    917	}
    918
    919	ret = __q6asm_dai_compr_set_codec_params(component, stream,
    920						 &params->codec,
    921						 prtd->stream_id);
    922	if (ret) {
    923		dev_err(dev, "codec param setup failed ret:%d\n", ret);
    924		return ret;
    925	}
    926
    927	ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
    928				       (prtd->pcm_size / prtd->periods),
    929				       prtd->periods);
    930
    931	if (ret < 0) {
    932		dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
    933		return -ENOMEM;
    934	}
    935
    936	prtd->state = Q6ASM_STREAM_RUNNING;
    937
    938	return 0;
    939}
    940
    941static int q6asm_dai_compr_set_metadata(struct snd_soc_component *component,
    942					struct snd_compr_stream *stream,
    943					struct snd_compr_metadata *metadata)
    944{
    945	struct snd_compr_runtime *runtime = stream->runtime;
    946	struct q6asm_dai_rtd *prtd = runtime->private_data;
    947	int ret = 0;
    948
    949	switch (metadata->key) {
    950	case SNDRV_COMPRESS_ENCODER_PADDING:
    951		prtd->trailing_samples_drop = metadata->value[0];
    952		break;
    953	case SNDRV_COMPRESS_ENCODER_DELAY:
    954		prtd->initial_samples_drop = metadata->value[0];
    955		if (prtd->next_track_stream_id) {
    956			ret = q6asm_open_write(prtd->audio_client,
    957					       prtd->next_track_stream_id,
    958					       prtd->codec.id,
    959					       prtd->codec.profile,
    960					       prtd->bits_per_sample,
    961				       true);
    962			if (ret < 0) {
    963				dev_err(component->dev, "q6asm_open_write failed\n");
    964				return ret;
    965			}
    966			ret = __q6asm_dai_compr_set_codec_params(component, stream,
    967								 &prtd->codec,
    968								 prtd->next_track_stream_id);
    969			if (ret < 0) {
    970				dev_err(component->dev, "q6asm_open_write failed\n");
    971				return ret;
    972			}
    973
    974			ret = q6asm_stream_remove_initial_silence(prtd->audio_client,
    975						    prtd->next_track_stream_id,
    976						    prtd->initial_samples_drop);
    977			prtd->next_track_stream_id = 0;
    978
    979		}
    980
    981		break;
    982	default:
    983		ret = -EINVAL;
    984		break;
    985	}
    986
    987	return ret;
    988}
    989
    990static int q6asm_dai_compr_trigger(struct snd_soc_component *component,
    991				   struct snd_compr_stream *stream, int cmd)
    992{
    993	struct snd_compr_runtime *runtime = stream->runtime;
    994	struct q6asm_dai_rtd *prtd = runtime->private_data;
    995	int ret = 0;
    996
    997	switch (cmd) {
    998	case SNDRV_PCM_TRIGGER_START:
    999	case SNDRV_PCM_TRIGGER_RESUME:
   1000	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
   1001		ret = q6asm_run_nowait(prtd->audio_client, prtd->stream_id,
   1002				       0, 0, 0);
   1003		break;
   1004	case SNDRV_PCM_TRIGGER_STOP:
   1005		prtd->state = Q6ASM_STREAM_STOPPED;
   1006		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
   1007				       CMD_EOS);
   1008		break;
   1009	case SNDRV_PCM_TRIGGER_SUSPEND:
   1010	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
   1011		ret = q6asm_cmd_nowait(prtd->audio_client, prtd->stream_id,
   1012				       CMD_PAUSE);
   1013		break;
   1014	case SND_COMPR_TRIGGER_NEXT_TRACK:
   1015		prtd->next_track = true;
   1016		prtd->next_track_stream_id = (prtd->stream_id == 1 ? 2 : 1);
   1017		break;
   1018	case SND_COMPR_TRIGGER_DRAIN:
   1019	case SND_COMPR_TRIGGER_PARTIAL_DRAIN:
   1020		prtd->notify_on_drain = true;
   1021		break;
   1022	default:
   1023		ret = -EINVAL;
   1024		break;
   1025	}
   1026
   1027	return ret;
   1028}
   1029
   1030static int q6asm_dai_compr_pointer(struct snd_soc_component *component,
   1031				   struct snd_compr_stream *stream,
   1032				   struct snd_compr_tstamp *tstamp)
   1033{
   1034	struct snd_compr_runtime *runtime = stream->runtime;
   1035	struct q6asm_dai_rtd *prtd = runtime->private_data;
   1036	unsigned long flags;
   1037
   1038	spin_lock_irqsave(&prtd->lock, flags);
   1039
   1040	tstamp->copied_total = prtd->copied_total;
   1041	tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
   1042
   1043	spin_unlock_irqrestore(&prtd->lock, flags);
   1044
   1045	return 0;
   1046}
   1047
   1048static int q6asm_compr_copy(struct snd_soc_component *component,
   1049			    struct snd_compr_stream *stream, char __user *buf,
   1050			    size_t count)
   1051{
   1052	struct snd_compr_runtime *runtime = stream->runtime;
   1053	struct q6asm_dai_rtd *prtd = runtime->private_data;
   1054	unsigned long flags;
   1055	u32 wflags = 0;
   1056	int avail, bytes_in_flight = 0;
   1057	void *dstn;
   1058	size_t copy;
   1059	u32 app_pointer;
   1060	u32 bytes_received;
   1061
   1062	bytes_received = prtd->bytes_received;
   1063
   1064	/**
   1065	 * Make sure that next track data pointer is aligned at 32 bit boundary
   1066	 * This is a Mandatory requirement from DSP data buffers alignment
   1067	 */
   1068	if (prtd->next_track)
   1069		bytes_received = ALIGN(prtd->bytes_received, prtd->pcm_count);
   1070
   1071	app_pointer = bytes_received/prtd->pcm_size;
   1072	app_pointer = bytes_received -  (app_pointer * prtd->pcm_size);
   1073	dstn = prtd->dma_buffer.area + app_pointer;
   1074
   1075	if (count < prtd->pcm_size - app_pointer) {
   1076		if (copy_from_user(dstn, buf, count))
   1077			return -EFAULT;
   1078	} else {
   1079		copy = prtd->pcm_size - app_pointer;
   1080		if (copy_from_user(dstn, buf, copy))
   1081			return -EFAULT;
   1082		if (copy_from_user(prtd->dma_buffer.area, buf + copy,
   1083				   count - copy))
   1084			return -EFAULT;
   1085	}
   1086
   1087	spin_lock_irqsave(&prtd->lock, flags);
   1088
   1089	bytes_in_flight = prtd->bytes_received - prtd->copied_total;
   1090
   1091	if (prtd->next_track) {
   1092		prtd->next_track = false;
   1093		prtd->copied_total = ALIGN(prtd->copied_total, prtd->pcm_count);
   1094		prtd->bytes_sent = ALIGN(prtd->bytes_sent, prtd->pcm_count);
   1095	}
   1096
   1097	prtd->bytes_received = bytes_received + count;
   1098
   1099	/* Kick off the data to dsp if its starving!! */
   1100	if (prtd->state == Q6ASM_STREAM_RUNNING && (bytes_in_flight == 0)) {
   1101		uint32_t bytes_to_write = prtd->pcm_count;
   1102
   1103		avail = prtd->bytes_received - prtd->bytes_sent;
   1104
   1105		if (avail < prtd->pcm_count)
   1106			bytes_to_write = avail;
   1107
   1108		q6asm_write_async(prtd->audio_client, prtd->stream_id,
   1109				  bytes_to_write, 0, 0, wflags);
   1110		prtd->bytes_sent += bytes_to_write;
   1111	}
   1112
   1113	spin_unlock_irqrestore(&prtd->lock, flags);
   1114
   1115	return count;
   1116}
   1117
   1118static int q6asm_dai_compr_mmap(struct snd_soc_component *component,
   1119				struct snd_compr_stream *stream,
   1120				struct vm_area_struct *vma)
   1121{
   1122	struct snd_compr_runtime *runtime = stream->runtime;
   1123	struct q6asm_dai_rtd *prtd = runtime->private_data;
   1124	struct device *dev = component->dev;
   1125
   1126	return dma_mmap_coherent(dev, vma,
   1127			prtd->dma_buffer.area, prtd->dma_buffer.addr,
   1128			prtd->dma_buffer.bytes);
   1129}
   1130
   1131static int q6asm_dai_compr_get_caps(struct snd_soc_component *component,
   1132				    struct snd_compr_stream *stream,
   1133				    struct snd_compr_caps *caps)
   1134{
   1135	caps->direction = SND_COMPRESS_PLAYBACK;
   1136	caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
   1137	caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
   1138	caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
   1139	caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
   1140	caps->num_codecs = 5;
   1141	caps->codecs[0] = SND_AUDIOCODEC_MP3;
   1142	caps->codecs[1] = SND_AUDIOCODEC_FLAC;
   1143	caps->codecs[2] = SND_AUDIOCODEC_WMA;
   1144	caps->codecs[3] = SND_AUDIOCODEC_ALAC;
   1145	caps->codecs[4] = SND_AUDIOCODEC_APE;
   1146
   1147	return 0;
   1148}
   1149
   1150static int q6asm_dai_compr_get_codec_caps(struct snd_soc_component *component,
   1151					  struct snd_compr_stream *stream,
   1152					  struct snd_compr_codec_caps *codec)
   1153{
   1154	switch (codec->codec) {
   1155	case SND_AUDIOCODEC_MP3:
   1156		*codec = q6asm_compr_caps;
   1157		break;
   1158	default:
   1159		break;
   1160	}
   1161
   1162	return 0;
   1163}
   1164
   1165static const struct snd_compress_ops q6asm_dai_compress_ops = {
   1166	.open		= q6asm_dai_compr_open,
   1167	.free		= q6asm_dai_compr_free,
   1168	.set_params	= q6asm_dai_compr_set_params,
   1169	.set_metadata	= q6asm_dai_compr_set_metadata,
   1170	.pointer	= q6asm_dai_compr_pointer,
   1171	.trigger	= q6asm_dai_compr_trigger,
   1172	.get_caps	= q6asm_dai_compr_get_caps,
   1173	.get_codec_caps	= q6asm_dai_compr_get_codec_caps,
   1174	.mmap		= q6asm_dai_compr_mmap,
   1175	.copy		= q6asm_compr_copy,
   1176};
   1177
   1178static int q6asm_dai_pcm_new(struct snd_soc_component *component,
   1179			     struct snd_soc_pcm_runtime *rtd)
   1180{
   1181	struct snd_pcm *pcm = rtd->pcm;
   1182	size_t size = q6asm_dai_hardware_playback.buffer_bytes_max;
   1183
   1184	return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
   1185					    component->dev, size);
   1186}
   1187
   1188static const struct snd_soc_dapm_widget q6asm_dapm_widgets[] = {
   1189	SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, SND_SOC_NOPM, 0, 0),
   1190	SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, SND_SOC_NOPM, 0, 0),
   1191	SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, SND_SOC_NOPM, 0, 0),
   1192	SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, SND_SOC_NOPM, 0, 0),
   1193	SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, SND_SOC_NOPM, 0, 0),
   1194	SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, SND_SOC_NOPM, 0, 0),
   1195	SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, SND_SOC_NOPM, 0, 0),
   1196	SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, SND_SOC_NOPM, 0, 0),
   1197	SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, SND_SOC_NOPM, 0, 0),
   1198	SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, SND_SOC_NOPM, 0, 0),
   1199	SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, SND_SOC_NOPM, 0, 0),
   1200	SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, SND_SOC_NOPM, 0, 0),
   1201	SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, SND_SOC_NOPM, 0, 0),
   1202	SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, SND_SOC_NOPM, 0, 0),
   1203	SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, SND_SOC_NOPM, 0, 0),
   1204	SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, SND_SOC_NOPM, 0, 0),
   1205};
   1206
   1207static const struct snd_soc_component_driver q6asm_fe_dai_component = {
   1208	.name		= DRV_NAME,
   1209	.open		= q6asm_dai_open,
   1210	.hw_params	= q6asm_dai_hw_params,
   1211	.close		= q6asm_dai_close,
   1212	.prepare	= q6asm_dai_prepare,
   1213	.trigger	= q6asm_dai_trigger,
   1214	.pointer	= q6asm_dai_pointer,
   1215	.pcm_construct	= q6asm_dai_pcm_new,
   1216	.compress_ops	= &q6asm_dai_compress_ops,
   1217	.dapm_widgets	= q6asm_dapm_widgets,
   1218	.num_dapm_widgets = ARRAY_SIZE(q6asm_dapm_widgets),
   1219};
   1220
   1221static struct snd_soc_dai_driver q6asm_fe_dais_template[] = {
   1222	Q6ASM_FEDAI_DRIVER(1),
   1223	Q6ASM_FEDAI_DRIVER(2),
   1224	Q6ASM_FEDAI_DRIVER(3),
   1225	Q6ASM_FEDAI_DRIVER(4),
   1226	Q6ASM_FEDAI_DRIVER(5),
   1227	Q6ASM_FEDAI_DRIVER(6),
   1228	Q6ASM_FEDAI_DRIVER(7),
   1229	Q6ASM_FEDAI_DRIVER(8),
   1230};
   1231
   1232static int of_q6asm_parse_dai_data(struct device *dev,
   1233				    struct q6asm_dai_data *pdata)
   1234{
   1235	struct snd_soc_dai_driver *dai_drv;
   1236	struct snd_soc_pcm_stream empty_stream;
   1237	struct device_node *node;
   1238	int ret, id, dir, idx = 0;
   1239
   1240
   1241	pdata->num_dais = of_get_child_count(dev->of_node);
   1242	if (!pdata->num_dais) {
   1243		dev_err(dev, "No dais found in DT\n");
   1244		return -EINVAL;
   1245	}
   1246
   1247	pdata->dais = devm_kcalloc(dev, pdata->num_dais, sizeof(*dai_drv),
   1248				   GFP_KERNEL);
   1249	if (!pdata->dais)
   1250		return -ENOMEM;
   1251
   1252	memset(&empty_stream, 0, sizeof(empty_stream));
   1253
   1254	for_each_child_of_node(dev->of_node, node) {
   1255		ret = of_property_read_u32(node, "reg", &id);
   1256		if (ret || id >= MAX_SESSIONS || id < 0) {
   1257			dev_err(dev, "valid dai id not found:%d\n", ret);
   1258			continue;
   1259		}
   1260
   1261		dai_drv = &pdata->dais[idx++];
   1262		*dai_drv = q6asm_fe_dais_template[id];
   1263
   1264		ret = of_property_read_u32(node, "direction", &dir);
   1265		if (ret)
   1266			continue;
   1267
   1268		if (dir == Q6ASM_DAI_RX)
   1269			dai_drv->capture = empty_stream;
   1270		else if (dir == Q6ASM_DAI_TX)
   1271			dai_drv->playback = empty_stream;
   1272
   1273		if (of_property_read_bool(node, "is-compress-dai"))
   1274			dai_drv->compress_new = snd_soc_new_compress;
   1275	}
   1276
   1277	return 0;
   1278}
   1279
   1280static int q6asm_dai_probe(struct platform_device *pdev)
   1281{
   1282	struct device *dev = &pdev->dev;
   1283	struct device_node *node = dev->of_node;
   1284	struct of_phandle_args args;
   1285	struct q6asm_dai_data *pdata;
   1286	int rc;
   1287
   1288	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
   1289	if (!pdata)
   1290		return -ENOMEM;
   1291
   1292	rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
   1293	if (rc < 0)
   1294		pdata->sid = -1;
   1295	else
   1296		pdata->sid = args.args[0] & SID_MASK_DEFAULT;
   1297
   1298	dev_set_drvdata(dev, pdata);
   1299
   1300	rc = of_q6asm_parse_dai_data(dev, pdata);
   1301	if (rc)
   1302		return rc;
   1303
   1304	return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
   1305					       pdata->dais, pdata->num_dais);
   1306}
   1307
   1308#ifdef CONFIG_OF
   1309static const struct of_device_id q6asm_dai_device_id[] = {
   1310	{ .compatible = "qcom,q6asm-dais" },
   1311	{},
   1312};
   1313MODULE_DEVICE_TABLE(of, q6asm_dai_device_id);
   1314#endif
   1315
   1316static struct platform_driver q6asm_dai_platform_driver = {
   1317	.driver = {
   1318		.name = "q6asm-dai",
   1319		.of_match_table = of_match_ptr(q6asm_dai_device_id),
   1320	},
   1321	.probe = q6asm_dai_probe,
   1322};
   1323module_platform_driver(q6asm_dai_platform_driver);
   1324
   1325MODULE_DESCRIPTION("Q6ASM dai driver");
   1326MODULE_LICENSE("GPL v2");