xref: /openbmc/linux/sound/soc/qcom/qdsp6/q6asm-dai.c (revision 036b9e7c)
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 <asm/dma.h>
14 #include <linux/dma-mapping.h>
15 #include <linux/of_device.h>
16 #include <sound/pcm_params.h>
17 #include "q6asm.h"
18 #include "q6routing.h"
19 #include "q6dsp-errno.h"
20 
21 #define DRV_NAME	"q6asm-fe-dai"
22 
23 #define PLAYBACK_MIN_NUM_PERIODS    2
24 #define PLAYBACK_MAX_NUM_PERIODS   8
25 #define PLAYBACK_MAX_PERIOD_SIZE    65536
26 #define PLAYBACK_MIN_PERIOD_SIZE    128
27 #define CAPTURE_MIN_NUM_PERIODS     2
28 #define CAPTURE_MAX_NUM_PERIODS     8
29 #define CAPTURE_MAX_PERIOD_SIZE     4096
30 #define CAPTURE_MIN_PERIOD_SIZE     320
31 #define SID_MASK_DEFAULT	0xF
32 
33 enum stream_state {
34 	Q6ASM_STREAM_IDLE = 0,
35 	Q6ASM_STREAM_STOPPED,
36 	Q6ASM_STREAM_RUNNING,
37 };
38 
39 struct q6asm_dai_rtd {
40 	struct snd_pcm_substream *substream;
41 	phys_addr_t phys;
42 	unsigned int pcm_size;
43 	unsigned int pcm_count;
44 	unsigned int pcm_irq_pos;       /* IRQ position */
45 	unsigned int periods;
46 	uint16_t bits_per_sample;
47 	uint16_t source; /* Encoding source bit mask */
48 	struct audio_client *audio_client;
49 	uint16_t session_id;
50 	enum stream_state state;
51 };
52 
53 struct q6asm_dai_data {
54 	long long int sid;
55 };
56 
57 static struct snd_pcm_hardware q6asm_dai_hardware_capture = {
58 	.info =                 (SNDRV_PCM_INFO_MMAP |
59 				SNDRV_PCM_INFO_BLOCK_TRANSFER |
60 				SNDRV_PCM_INFO_MMAP_VALID |
61 				SNDRV_PCM_INFO_INTERLEAVED |
62 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
63 	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
64 				SNDRV_PCM_FMTBIT_S24_LE),
65 	.rates =                SNDRV_PCM_RATE_8000_48000,
66 	.rate_min =             8000,
67 	.rate_max =             48000,
68 	.channels_min =         1,
69 	.channels_max =         4,
70 	.buffer_bytes_max =     CAPTURE_MAX_NUM_PERIODS *
71 				CAPTURE_MAX_PERIOD_SIZE,
72 	.period_bytes_min =	CAPTURE_MIN_PERIOD_SIZE,
73 	.period_bytes_max =     CAPTURE_MAX_PERIOD_SIZE,
74 	.periods_min =          CAPTURE_MIN_NUM_PERIODS,
75 	.periods_max =          CAPTURE_MAX_NUM_PERIODS,
76 	.fifo_size =            0,
77 };
78 
79 static struct snd_pcm_hardware q6asm_dai_hardware_playback = {
80 	.info =                 (SNDRV_PCM_INFO_MMAP |
81 				SNDRV_PCM_INFO_BLOCK_TRANSFER |
82 				SNDRV_PCM_INFO_MMAP_VALID |
83 				SNDRV_PCM_INFO_INTERLEAVED |
84 				SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
85 	.formats =              (SNDRV_PCM_FMTBIT_S16_LE |
86 				SNDRV_PCM_FMTBIT_S24_LE),
87 	.rates =                SNDRV_PCM_RATE_8000_192000,
88 	.rate_min =             8000,
89 	.rate_max =             192000,
90 	.channels_min =         1,
91 	.channels_max =         8,
92 	.buffer_bytes_max =     (PLAYBACK_MAX_NUM_PERIODS *
93 				PLAYBACK_MAX_PERIOD_SIZE),
94 	.period_bytes_min =	PLAYBACK_MIN_PERIOD_SIZE,
95 	.period_bytes_max =     PLAYBACK_MAX_PERIOD_SIZE,
96 	.periods_min =          PLAYBACK_MIN_NUM_PERIODS,
97 	.periods_max =          PLAYBACK_MAX_NUM_PERIODS,
98 	.fifo_size =            0,
99 };
100 
101 #define Q6ASM_FEDAI_DRIVER(num) { \
102 		.playback = {						\
103 			.stream_name = "MultiMedia"#num" Playback",	\
104 			.rates = (SNDRV_PCM_RATE_8000_192000|		\
105 					SNDRV_PCM_RATE_KNOT),		\
106 			.formats = (SNDRV_PCM_FMTBIT_S16_LE |		\
107 					SNDRV_PCM_FMTBIT_S24_LE),	\
108 			.channels_min = 1,				\
109 			.channels_max = 8,				\
110 			.rate_min =     8000,				\
111 			.rate_max =	192000,				\
112 		},							\
113 		.capture = {						\
114 			.stream_name = "MultiMedia"#num" Capture",	\
115 			.rates = (SNDRV_PCM_RATE_8000_48000|		\
116 					SNDRV_PCM_RATE_KNOT),		\
117 			.formats = (SNDRV_PCM_FMTBIT_S16_LE |		\
118 				    SNDRV_PCM_FMTBIT_S24_LE),		\
119 			.channels_min = 1,				\
120 			.channels_max = 4,				\
121 			.rate_min =     8000,				\
122 			.rate_max =	48000,				\
123 		},							\
124 		.name = "MultiMedia"#num,				\
125 		.id = MSM_FRONTEND_DAI_MULTIMEDIA##num,			\
126 	}
127 
128 /* Conventional and unconventional sample rate supported */
129 static unsigned int supported_sample_rates[] = {
130 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000,
131 	88200, 96000, 176400, 192000
132 };
133 
134 static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
135 	.count = ARRAY_SIZE(supported_sample_rates),
136 	.list = supported_sample_rates,
137 	.mask = 0,
138 };
139 
140 static void event_handler(uint32_t opcode, uint32_t token,
141 			  uint32_t *payload, void *priv)
142 {
143 	struct q6asm_dai_rtd *prtd = priv;
144 	struct snd_pcm_substream *substream = prtd->substream;
145 
146 	switch (opcode) {
147 	case ASM_CLIENT_EVENT_CMD_RUN_DONE:
148 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
149 			q6asm_write_async(prtd->audio_client,
150 				   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
151 		break;
152 	case ASM_CLIENT_EVENT_CMD_EOS_DONE:
153 		prtd->state = Q6ASM_STREAM_STOPPED;
154 		break;
155 	case ASM_CLIENT_EVENT_DATA_WRITE_DONE: {
156 		prtd->pcm_irq_pos += prtd->pcm_count;
157 		snd_pcm_period_elapsed(substream);
158 		if (prtd->state == Q6ASM_STREAM_RUNNING)
159 			q6asm_write_async(prtd->audio_client,
160 					   prtd->pcm_count, 0, 0, NO_TIMESTAMP);
161 
162 		break;
163 		}
164 	case ASM_CLIENT_EVENT_DATA_READ_DONE:
165 		prtd->pcm_irq_pos += prtd->pcm_count;
166 		snd_pcm_period_elapsed(substream);
167 		if (prtd->state == Q6ASM_STREAM_RUNNING)
168 			q6asm_read(prtd->audio_client);
169 
170 		break;
171 	default:
172 		break;
173 	}
174 }
175 
176 static int q6asm_dai_prepare(struct snd_pcm_substream *substream)
177 {
178 	struct snd_pcm_runtime *runtime = substream->runtime;
179 	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
180 	struct q6asm_dai_rtd *prtd = runtime->private_data;
181 	struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
182 	struct q6asm_dai_data *pdata;
183 	int ret, i;
184 
185 	pdata = snd_soc_component_get_drvdata(c);
186 	if (!pdata)
187 		return -EINVAL;
188 
189 	if (!prtd || !prtd->audio_client) {
190 		pr_err("%s: private data null or audio client freed\n",
191 			__func__);
192 		return -EINVAL;
193 	}
194 
195 	prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
196 	prtd->pcm_irq_pos = 0;
197 	/* rate and channels are sent to audio driver */
198 	if (prtd->state) {
199 		/* clear the previous setup if any  */
200 		q6asm_cmd(prtd->audio_client, CMD_CLOSE);
201 		q6asm_unmap_memory_regions(substream->stream,
202 					   prtd->audio_client);
203 		q6routing_stream_close(soc_prtd->dai_link->id,
204 					 substream->stream);
205 	}
206 
207 	ret = q6asm_map_memory_regions(substream->stream, prtd->audio_client,
208 				       prtd->phys,
209 				       (prtd->pcm_size / prtd->periods),
210 				       prtd->periods);
211 
212 	if (ret < 0) {
213 		pr_err("Audio Start: Buffer Allocation failed rc = %d\n",
214 							ret);
215 		return -ENOMEM;
216 	}
217 
218 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
219 		ret = q6asm_open_write(prtd->audio_client, FORMAT_LINEAR_PCM,
220 				       prtd->bits_per_sample);
221 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
222 		ret = q6asm_open_read(prtd->audio_client, FORMAT_LINEAR_PCM,
223 				       prtd->bits_per_sample);
224 	}
225 
226 	if (ret < 0) {
227 		pr_err("%s: q6asm_open_write failed\n", __func__);
228 		q6asm_audio_client_free(prtd->audio_client);
229 		prtd->audio_client = NULL;
230 		return -ENOMEM;
231 	}
232 
233 	prtd->session_id = q6asm_get_session_id(prtd->audio_client);
234 	ret = q6routing_stream_open(soc_prtd->dai_link->id, LEGACY_PCM_MODE,
235 			      prtd->session_id, substream->stream);
236 	if (ret) {
237 		pr_err("%s: stream reg failed ret:%d\n", __func__, ret);
238 		return ret;
239 	}
240 
241 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
242 		ret = q6asm_media_format_block_multi_ch_pcm(
243 				prtd->audio_client, runtime->rate,
244 				runtime->channels, NULL,
245 				prtd->bits_per_sample);
246 	} else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
247 		ret = q6asm_enc_cfg_blk_pcm_format_support(prtd->audio_client,
248 					runtime->rate, runtime->channels,
249 					prtd->bits_per_sample);
250 
251 		/* Queue the buffers */
252 		for (i = 0; i < runtime->periods; i++)
253 			q6asm_read(prtd->audio_client);
254 
255 	}
256 	if (ret < 0)
257 		pr_info("%s: CMD Format block failed\n", __func__);
258 
259 	prtd->state = Q6ASM_STREAM_RUNNING;
260 
261 	return 0;
262 }
263 
264 static int q6asm_dai_trigger(struct snd_pcm_substream *substream, int cmd)
265 {
266 	int ret = 0;
267 	struct snd_pcm_runtime *runtime = substream->runtime;
268 	struct q6asm_dai_rtd *prtd = runtime->private_data;
269 
270 	switch (cmd) {
271 	case SNDRV_PCM_TRIGGER_START:
272 	case SNDRV_PCM_TRIGGER_RESUME:
273 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
274 		ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
275 		break;
276 	case SNDRV_PCM_TRIGGER_STOP:
277 		prtd->state = Q6ASM_STREAM_STOPPED;
278 		ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
279 		break;
280 	case SNDRV_PCM_TRIGGER_SUSPEND:
281 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
282 		ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
283 		break;
284 	default:
285 		ret = -EINVAL;
286 		break;
287 	}
288 
289 	return ret;
290 }
291 
292 static int q6asm_dai_open(struct snd_pcm_substream *substream)
293 {
294 	struct snd_pcm_runtime *runtime = substream->runtime;
295 	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
296 	struct snd_soc_dai *cpu_dai = soc_prtd->cpu_dai;
297 	struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
298 	struct q6asm_dai_rtd *prtd;
299 	struct q6asm_dai_data *pdata;
300 	struct device *dev = c->dev;
301 	int ret = 0;
302 	int stream_id;
303 
304 	stream_id = cpu_dai->driver->id;
305 
306 	pdata = snd_soc_component_get_drvdata(c);
307 	if (!pdata) {
308 		pr_err("Drv data not found ..\n");
309 		return -EINVAL;
310 	}
311 
312 	prtd = kzalloc(sizeof(struct q6asm_dai_rtd), GFP_KERNEL);
313 	if (prtd == NULL)
314 		return -ENOMEM;
315 
316 	prtd->substream = substream;
317 	prtd->audio_client = q6asm_audio_client_alloc(dev,
318 				(q6asm_cb)event_handler, prtd, stream_id,
319 				LEGACY_PCM_MODE);
320 	if (IS_ERR(prtd->audio_client)) {
321 		pr_info("%s: Could not allocate memory\n", __func__);
322 		ret = PTR_ERR(prtd->audio_client);
323 		kfree(prtd);
324 		return ret;
325 	}
326 
327 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
328 		runtime->hw = q6asm_dai_hardware_playback;
329 	else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
330 		runtime->hw = q6asm_dai_hardware_capture;
331 
332 	ret = snd_pcm_hw_constraint_list(runtime, 0,
333 				SNDRV_PCM_HW_PARAM_RATE,
334 				&constraints_sample_rates);
335 	if (ret < 0)
336 		pr_info("snd_pcm_hw_constraint_list failed\n");
337 	/* Ensure that buffer size is a multiple of period size */
338 	ret = snd_pcm_hw_constraint_integer(runtime,
339 					    SNDRV_PCM_HW_PARAM_PERIODS);
340 	if (ret < 0)
341 		pr_info("snd_pcm_hw_constraint_integer failed\n");
342 
343 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
344 		ret = snd_pcm_hw_constraint_minmax(runtime,
345 			SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
346 			PLAYBACK_MIN_NUM_PERIODS * PLAYBACK_MIN_PERIOD_SIZE,
347 			PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE);
348 		if (ret < 0) {
349 			pr_err("constraint for buffer bytes min max ret = %d\n",
350 									ret);
351 		}
352 	}
353 
354 	ret = snd_pcm_hw_constraint_step(runtime, 0,
355 		SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
356 	if (ret < 0) {
357 		pr_err("constraint for period bytes step ret = %d\n",
358 								ret);
359 	}
360 	ret = snd_pcm_hw_constraint_step(runtime, 0,
361 		SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
362 	if (ret < 0) {
363 		pr_err("constraint for buffer bytes step ret = %d\n",
364 								ret);
365 	}
366 
367 	runtime->private_data = prtd;
368 
369 	snd_soc_set_runtime_hwparams(substream, &q6asm_dai_hardware_playback);
370 
371 	runtime->dma_bytes = q6asm_dai_hardware_playback.buffer_bytes_max;
372 
373 
374 	if (pdata->sid < 0)
375 		prtd->phys = substream->dma_buffer.addr;
376 	else
377 		prtd->phys = substream->dma_buffer.addr | (pdata->sid << 32);
378 
379 	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
380 
381 	return 0;
382 }
383 
384 static int q6asm_dai_close(struct snd_pcm_substream *substream)
385 {
386 	struct snd_pcm_runtime *runtime = substream->runtime;
387 	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
388 	struct q6asm_dai_rtd *prtd = runtime->private_data;
389 
390 	if (prtd->audio_client) {
391 		if (prtd->state)
392 			q6asm_cmd(prtd->audio_client, CMD_CLOSE);
393 
394 		q6asm_unmap_memory_regions(substream->stream,
395 					   prtd->audio_client);
396 		q6asm_audio_client_free(prtd->audio_client);
397 		prtd->audio_client = NULL;
398 	}
399 	q6routing_stream_close(soc_prtd->dai_link->id,
400 						substream->stream);
401 	kfree(prtd);
402 	return 0;
403 }
404 
405 static snd_pcm_uframes_t q6asm_dai_pointer(struct snd_pcm_substream *substream)
406 {
407 
408 	struct snd_pcm_runtime *runtime = substream->runtime;
409 	struct q6asm_dai_rtd *prtd = runtime->private_data;
410 
411 	if (prtd->pcm_irq_pos >= prtd->pcm_size)
412 		prtd->pcm_irq_pos = 0;
413 
414 	return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
415 }
416 
417 static int q6asm_dai_mmap(struct snd_pcm_substream *substream,
418 				struct vm_area_struct *vma)
419 {
420 
421 	struct snd_pcm_runtime *runtime = substream->runtime;
422 	struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
423 	struct snd_soc_component *c = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
424 	struct device *dev = c->dev;
425 
426 	return dma_mmap_coherent(dev, vma,
427 			runtime->dma_area, runtime->dma_addr,
428 			runtime->dma_bytes);
429 }
430 
431 static int q6asm_dai_hw_params(struct snd_pcm_substream *substream,
432 				struct snd_pcm_hw_params *params)
433 {
434 	struct snd_pcm_runtime *runtime = substream->runtime;
435 	struct q6asm_dai_rtd *prtd = runtime->private_data;
436 
437 	prtd->pcm_size = params_buffer_bytes(params);
438 	prtd->periods = params_periods(params);
439 
440 	switch (params_format(params)) {
441 	case SNDRV_PCM_FORMAT_S16_LE:
442 		prtd->bits_per_sample = 16;
443 		break;
444 	case SNDRV_PCM_FORMAT_S24_LE:
445 		prtd->bits_per_sample = 24;
446 		break;
447 	}
448 
449 	return 0;
450 }
451 
452 static struct snd_pcm_ops q6asm_dai_ops = {
453 	.open           = q6asm_dai_open,
454 	.hw_params	= q6asm_dai_hw_params,
455 	.close          = q6asm_dai_close,
456 	.ioctl          = snd_pcm_lib_ioctl,
457 	.prepare        = q6asm_dai_prepare,
458 	.trigger        = q6asm_dai_trigger,
459 	.pointer        = q6asm_dai_pointer,
460 	.mmap		= q6asm_dai_mmap,
461 };
462 
463 static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
464 {
465 	struct snd_pcm_substream *psubstream, *csubstream;
466 	struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
467 	struct snd_pcm *pcm = rtd->pcm;
468 	struct device *dev;
469 	int size, ret;
470 
471 	dev = c->dev;
472 	size = q6asm_dai_hardware_playback.buffer_bytes_max;
473 	psubstream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
474 	if (psubstream) {
475 		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
476 					  &psubstream->dma_buffer);
477 		if (ret) {
478 			dev_err(dev, "Cannot allocate buffer(s)\n");
479 			return ret;
480 		}
481 	}
482 
483 	csubstream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
484 	if (csubstream) {
485 		ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
486 					  &csubstream->dma_buffer);
487 		if (ret) {
488 			dev_err(dev, "Cannot allocate buffer(s)\n");
489 			if (psubstream)
490 				snd_dma_free_pages(&psubstream->dma_buffer);
491 			return ret;
492 		}
493 	}
494 
495 	return 0;
496 }
497 
498 static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
499 {
500 	struct snd_pcm_substream *substream;
501 	int i;
502 
503 	for (i = 0; i < ARRAY_SIZE(pcm->streams); i++) {
504 		substream = pcm->streams[i].substream;
505 		if (substream) {
506 			snd_dma_free_pages(&substream->dma_buffer);
507 			substream->dma_buffer.area = NULL;
508 			substream->dma_buffer.addr = 0;
509 		}
510 	}
511 }
512 
513 static const struct snd_soc_component_driver q6asm_fe_dai_component = {
514 	.name		= DRV_NAME,
515 	.ops		= &q6asm_dai_ops,
516 	.pcm_new	= q6asm_dai_pcm_new,
517 	.pcm_free	= q6asm_dai_pcm_free,
518 
519 };
520 
521 static struct snd_soc_dai_driver q6asm_fe_dais[] = {
522 	Q6ASM_FEDAI_DRIVER(1),
523 	Q6ASM_FEDAI_DRIVER(2),
524 	Q6ASM_FEDAI_DRIVER(3),
525 	Q6ASM_FEDAI_DRIVER(4),
526 	Q6ASM_FEDAI_DRIVER(5),
527 	Q6ASM_FEDAI_DRIVER(6),
528 	Q6ASM_FEDAI_DRIVER(7),
529 	Q6ASM_FEDAI_DRIVER(8),
530 };
531 
532 static int q6asm_dai_probe(struct platform_device *pdev)
533 {
534 	struct device *dev = &pdev->dev;
535 	struct device_node *node = dev->of_node;
536 	struct of_phandle_args args;
537 	struct q6asm_dai_data *pdata;
538 	int rc;
539 
540 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
541 	if (!pdata)
542 		return -ENOMEM;
543 
544 	rc = of_parse_phandle_with_fixed_args(node, "iommus", 1, 0, &args);
545 	if (rc < 0)
546 		pdata->sid = -1;
547 	else
548 		pdata->sid = args.args[0] & SID_MASK_DEFAULT;
549 
550 	dev_set_drvdata(dev, pdata);
551 
552 	return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
553 					q6asm_fe_dais,
554 					ARRAY_SIZE(q6asm_fe_dais));
555 }
556 
557 static const struct of_device_id q6asm_dai_device_id[] = {
558 	{ .compatible = "qcom,q6asm-dais" },
559 	{},
560 };
561 MODULE_DEVICE_TABLE(of, q6asm_dai_device_id);
562 
563 static struct platform_driver q6asm_dai_platform_driver = {
564 	.driver = {
565 		.name = "q6asm-dai",
566 		.of_match_table = of_match_ptr(q6asm_dai_device_id),
567 	},
568 	.probe = q6asm_dai_probe,
569 };
570 module_platform_driver(q6asm_dai_platform_driver);
571 
572 MODULE_DESCRIPTION("Q6ASM dai driver");
573 MODULE_LICENSE("GPL v2");
574