brintos

brintos / linux-shallow public Read only

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