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/err.h>
6#include <linux/init.h>
7#include <linux/module.h>
8#include <linux/device.h>
9#include <linux/platform_device.h>
10#include <linux/slab.h>
11#include <sound/pcm.h>
12#include <sound/soc.h>
13#include <sound/pcm_params.h>
14#include "q6dsp-lpass-ports.h"
15#include "q6dsp-common.h"
16#include "q6afe.h"
17
18
19struct q6afe_dai_priv_data {
20	uint32_t sd_line_mask;
21	uint32_t sync_mode;
22	uint32_t sync_src;
23	uint32_t data_out_enable;
24	uint32_t invert_sync;
25	uint32_t data_delay;
26	uint32_t data_align;
27};
28
29struct q6afe_dai_data {
30	struct q6afe_port *port[AFE_PORT_MAX];
31	struct q6afe_port_config port_config[AFE_PORT_MAX];
32	bool is_port_started[AFE_PORT_MAX];
33	struct q6afe_dai_priv_data priv[AFE_PORT_MAX];
34};
35
36static int q6slim_hw_params(struct snd_pcm_substream *substream,
37			    struct snd_pcm_hw_params *params,
38			    struct snd_soc_dai *dai)
39{
40
41	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
42	struct q6afe_slim_cfg *slim = &dai_data->port_config[dai->id].slim;
43
44	slim->sample_rate = params_rate(params);
45
46	switch (params_format(params)) {
47	case SNDRV_PCM_FORMAT_S16_LE:
48	case SNDRV_PCM_FORMAT_SPECIAL:
49		slim->bit_width = 16;
50		break;
51	case SNDRV_PCM_FORMAT_S24_LE:
52		slim->bit_width = 24;
53		break;
54	case SNDRV_PCM_FORMAT_S32_LE:
55		slim->bit_width = 32;
56		break;
57	default:
58		pr_err("%s: format %d\n",
59			__func__, params_format(params));
60		return -EINVAL;
61	}
62
63	return 0;
64}
65
66static int q6hdmi_hw_params(struct snd_pcm_substream *substream,
67				struct snd_pcm_hw_params *params,
68				struct snd_soc_dai *dai)
69{
70	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
71	int channels = params_channels(params);
72	struct q6afe_hdmi_cfg *hdmi = &dai_data->port_config[dai->id].hdmi;
73	int ret;
74
75	hdmi->sample_rate = params_rate(params);
76	switch (params_format(params)) {
77	case SNDRV_PCM_FORMAT_S16_LE:
78		hdmi->bit_width = 16;
79		break;
80	case SNDRV_PCM_FORMAT_S24_LE:
81		hdmi->bit_width = 24;
82		break;
83	}
84
85	ret = q6dsp_get_channel_allocation(channels);
86	if (ret < 0)
87		return ret;
88
89	hdmi->channel_allocation = (u16) ret;
90
91	return 0;
92}
93
94static int q6i2s_hw_params(struct snd_pcm_substream *substream,
95			   struct snd_pcm_hw_params *params,
96			   struct snd_soc_dai *dai)
97{
98	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
99	struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg;
100
101	i2s->sample_rate = params_rate(params);
102	i2s->bit_width = params_width(params);
103	i2s->num_channels = params_channels(params);
104	i2s->sd_line_mask = dai_data->priv[dai->id].sd_line_mask;
105
106	return 0;
107}
108
109static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
110{
111	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
112	struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg;
113
114	i2s->fmt = fmt;
115
116	return 0;
117}
118
119static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai,
120				unsigned int tx_mask,
121				unsigned int rx_mask,
122				int slots, int slot_width)
123{
124
125	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
126	struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
127	unsigned int cap_mask;
128	int rc = 0;
129
130	/* HW only supports 16 and 32 bit slot width configuration */
131	if ((slot_width != 16) && (slot_width != 32)) {
132		dev_err(dai->dev, "%s: invalid slot_width %d\n",
133			__func__, slot_width);
134		return -EINVAL;
135	}
136
137	/* HW supports 1-32 slots configuration. Typical: 1, 2, 4, 8, 16, 32 */
138	switch (slots) {
139	case 2:
140		cap_mask = 0x03;
141		break;
142	case 4:
143		cap_mask = 0x0F;
144		break;
145	case 8:
146		cap_mask = 0xFF;
147		break;
148	case 16:
149		cap_mask = 0xFFFF;
150		break;
151	default:
152		dev_err(dai->dev, "%s: invalid slots %d\n",
153			__func__, slots);
154		return -EINVAL;
155	}
156
157	switch (dai->id) {
158	case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
159		tdm->nslots_per_frame = slots;
160		tdm->slot_width = slot_width;
161		/* TDM RX dais ids are even and tx are odd */
162		tdm->slot_mask = ((dai->id & 0x1) ? tx_mask : rx_mask) & cap_mask;
163		break;
164	default:
165		dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
166			__func__, dai->id);
167		return -EINVAL;
168	}
169
170	return rc;
171}
172
173static int q6tdm_set_channel_map(struct snd_soc_dai *dai,
174				unsigned int tx_num, unsigned int *tx_slot,
175				unsigned int rx_num, unsigned int *rx_slot)
176{
177
178	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
179	struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
180	int rc = 0;
181	int i = 0;
182
183	switch (dai->id) {
184	case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
185		if (dai->id & 0x1) {
186			if (!tx_slot) {
187				dev_err(dai->dev, "tx slot not found\n");
188				return -EINVAL;
189			}
190			if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
191				dev_err(dai->dev, "invalid tx num %d\n",
192					tx_num);
193				return -EINVAL;
194			}
195
196			for (i = 0; i < tx_num; i++)
197				tdm->ch_mapping[i] = tx_slot[i];
198
199			for (i = tx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
200				tdm->ch_mapping[i] = Q6AFE_CMAP_INVALID;
201
202			tdm->num_channels = tx_num;
203		} else {
204			/* rx */
205			if (!rx_slot) {
206				dev_err(dai->dev, "rx slot not found\n");
207				return -EINVAL;
208			}
209			if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
210				dev_err(dai->dev, "invalid rx num %d\n",
211					rx_num);
212				return -EINVAL;
213			}
214
215			for (i = 0; i < rx_num; i++)
216				tdm->ch_mapping[i] = rx_slot[i];
217
218			for (i = rx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
219				tdm->ch_mapping[i] = Q6AFE_CMAP_INVALID;
220
221			tdm->num_channels = rx_num;
222		}
223
224		break;
225	default:
226		dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
227			__func__, dai->id);
228		return -EINVAL;
229	}
230
231	return rc;
232}
233
234static int q6tdm_hw_params(struct snd_pcm_substream *substream,
235			   struct snd_pcm_hw_params *params,
236			   struct snd_soc_dai *dai)
237{
238	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
239	struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
240
241	tdm->bit_width = params_width(params);
242	tdm->sample_rate = params_rate(params);
243	tdm->num_channels = params_channels(params);
244	tdm->data_align_type = dai_data->priv[dai->id].data_align;
245	tdm->sync_src = dai_data->priv[dai->id].sync_src;
246	tdm->sync_mode = dai_data->priv[dai->id].sync_mode;
247
248	return 0;
249}
250
251static int q6dma_set_channel_map(struct snd_soc_dai *dai,
252				 unsigned int tx_num, unsigned int *tx_ch_mask,
253				 unsigned int rx_num, unsigned int *rx_ch_mask)
254{
255
256	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
257	struct q6afe_cdc_dma_cfg *cfg = &dai_data->port_config[dai->id].dma_cfg;
258	int ch_mask;
259	int rc = 0;
260
261	switch (dai->id) {
262	case WSA_CODEC_DMA_TX_0:
263	case WSA_CODEC_DMA_TX_1:
264	case WSA_CODEC_DMA_TX_2:
265	case VA_CODEC_DMA_TX_0:
266	case VA_CODEC_DMA_TX_1:
267	case VA_CODEC_DMA_TX_2:
268	case TX_CODEC_DMA_TX_0:
269	case TX_CODEC_DMA_TX_1:
270	case TX_CODEC_DMA_TX_2:
271	case TX_CODEC_DMA_TX_3:
272	case TX_CODEC_DMA_TX_4:
273	case TX_CODEC_DMA_TX_5:
274		if (!tx_ch_mask) {
275			dev_err(dai->dev, "tx slot not found\n");
276			return -EINVAL;
277		}
278
279		if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
280			dev_err(dai->dev, "invalid tx num %d\n",
281				tx_num);
282			return -EINVAL;
283		}
284		ch_mask = *tx_ch_mask;
285
286		break;
287	case WSA_CODEC_DMA_RX_0:
288	case WSA_CODEC_DMA_RX_1:
289	case RX_CODEC_DMA_RX_0:
290	case RX_CODEC_DMA_RX_1:
291	case RX_CODEC_DMA_RX_2:
292	case RX_CODEC_DMA_RX_3:
293	case RX_CODEC_DMA_RX_4:
294	case RX_CODEC_DMA_RX_5:
295	case RX_CODEC_DMA_RX_6:
296	case RX_CODEC_DMA_RX_7:
297		/* rx */
298		if (!rx_ch_mask) {
299			dev_err(dai->dev, "rx slot not found\n");
300			return -EINVAL;
301		}
302		if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
303			dev_err(dai->dev, "invalid rx num %d\n",
304				rx_num);
305			return -EINVAL;
306		}
307		ch_mask = *rx_ch_mask;
308
309		break;
310	default:
311		dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
312			__func__, dai->id);
313		return -EINVAL;
314	}
315
316	cfg->active_channels_mask = ch_mask;
317
318	return rc;
319}
320
321static int q6dma_hw_params(struct snd_pcm_substream *substream,
322			   struct snd_pcm_hw_params *params,
323			   struct snd_soc_dai *dai)
324{
325	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
326	struct q6afe_cdc_dma_cfg *cfg = &dai_data->port_config[dai->id].dma_cfg;
327
328	cfg->bit_width = params_width(params);
329	cfg->sample_rate = params_rate(params);
330	cfg->num_channels = params_channels(params);
331
332	return 0;
333}
334static void q6afe_dai_shutdown(struct snd_pcm_substream *substream,
335				struct snd_soc_dai *dai)
336{
337	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
338	int rc;
339
340	if (!dai_data->is_port_started[dai->id])
341		return;
342
343	rc = q6afe_port_stop(dai_data->port[dai->id]);
344	if (rc < 0)
345		dev_err(dai->dev, "fail to close AFE port (%d)\n", rc);
346
347	dai_data->is_port_started[dai->id] = false;
348
349}
350
351static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
352		struct snd_soc_dai *dai)
353{
354	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
355	int rc;
356
357	if (dai_data->is_port_started[dai->id]) {
358		/* stop the port and restart with new port config */
359		rc = q6afe_port_stop(dai_data->port[dai->id]);
360		if (rc < 0) {
361			dev_err(dai->dev, "fail to close AFE port (%d)\n", rc);
362			return rc;
363		}
364	}
365
366	switch (dai->id) {
367	case HDMI_RX:
368	case DISPLAY_PORT_RX:
369		q6afe_hdmi_port_prepare(dai_data->port[dai->id],
370					&dai_data->port_config[dai->id].hdmi);
371		break;
372	case SLIMBUS_0_RX ... SLIMBUS_6_TX:
373		q6afe_slim_port_prepare(dai_data->port[dai->id],
374					&dai_data->port_config[dai->id].slim);
375		break;
376	case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
377	case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
378		rc = q6afe_i2s_port_prepare(dai_data->port[dai->id],
379			       &dai_data->port_config[dai->id].i2s_cfg);
380		if (rc < 0) {
381			dev_err(dai->dev, "fail to prepare AFE port %x\n",
382				dai->id);
383			return rc;
384		}
385		break;
386	case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
387		q6afe_tdm_port_prepare(dai_data->port[dai->id],
388					&dai_data->port_config[dai->id].tdm);
389		break;
390	case WSA_CODEC_DMA_RX_0 ... RX_CODEC_DMA_RX_7:
391		q6afe_cdc_dma_port_prepare(dai_data->port[dai->id],
392					   &dai_data->port_config[dai->id].dma_cfg);
393		break;
394	default:
395		return -EINVAL;
396	}
397
398	rc = q6afe_port_start(dai_data->port[dai->id]);
399	if (rc < 0) {
400		dev_err(dai->dev, "fail to start AFE port %x\n", dai->id);
401		return rc;
402	}
403	dai_data->is_port_started[dai->id] = true;
404
405	return 0;
406}
407
408static int q6slim_set_channel_map(struct snd_soc_dai *dai,
409				unsigned int tx_num, unsigned int *tx_slot,
410				unsigned int rx_num, unsigned int *rx_slot)
411{
412	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
413	struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id];
414	int i;
415
416	if (dai->id & 0x1) {
417		/* TX */
418		if (!tx_slot) {
419			pr_err("%s: tx slot not found\n", __func__);
420			return -EINVAL;
421		}
422
423		for (i = 0; i < tx_num; i++)
424			pcfg->slim.ch_mapping[i] = tx_slot[i];
425
426		pcfg->slim.num_channels = tx_num;
427
428
429	} else {
430		if (!rx_slot) {
431			pr_err("%s: rx slot not found\n", __func__);
432			return -EINVAL;
433		}
434
435		for (i = 0; i < rx_num; i++)
436			pcfg->slim.ch_mapping[i] =   rx_slot[i];
437
438		pcfg->slim.num_channels = rx_num;
439
440	}
441
442	return 0;
443}
444
445static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai,
446		int clk_id, unsigned int freq, int dir)
447{
448	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
449	struct q6afe_port *port = dai_data->port[dai->id];
450
451	switch (clk_id) {
452	case LPAIF_DIG_CLK:
453		return q6afe_port_set_sysclk(port, clk_id, 0, 5, freq, dir);
454	case LPAIF_BIT_CLK:
455	case LPAIF_OSR_CLK:
456		return q6afe_port_set_sysclk(port, clk_id,
457					     Q6AFE_LPASS_CLK_SRC_INTERNAL,
458					     Q6AFE_LPASS_CLK_ROOT_DEFAULT,
459					     freq, dir);
460	case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR:
461	case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
462	case Q6AFE_LPASS_CLK_ID_WSA_CORE_MCLK ... Q6AFE_LPASS_CLK_ID_VA_CORE_2X_MCLK:
463		return q6afe_port_set_sysclk(port, clk_id,
464					     Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
465					     Q6AFE_LPASS_CLK_ROOT_DEFAULT,
466					     freq, dir);
467	case Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT ... Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT:
468		return q6afe_port_set_sysclk(port, clk_id,
469					     Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO,
470					     Q6AFE_LPASS_CLK_ROOT_DEFAULT,
471					     freq, dir);
472	}
473
474	return 0;
475}
476
477static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
478	{"HDMI Playback", NULL, "HDMI_RX"},
479	{"DISPLAY_PORT_RX_0 Playback", NULL, "DISPLAY_PORT_RX"},
480	{"Slimbus Playback", NULL, "SLIMBUS_0_RX"},
481	{"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"},
482	{"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"},
483	{"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"},
484	{"Slimbus4 Playback", NULL, "SLIMBUS_4_RX"},
485	{"Slimbus5 Playback", NULL, "SLIMBUS_5_RX"},
486	{"Slimbus6 Playback", NULL, "SLIMBUS_6_RX"},
487
488	{"SLIMBUS_0_TX", NULL, "Slimbus Capture"},
489	{"SLIMBUS_1_TX", NULL, "Slimbus1 Capture"},
490	{"SLIMBUS_2_TX", NULL, "Slimbus2 Capture"},
491	{"SLIMBUS_3_TX", NULL, "Slimbus3 Capture"},
492	{"SLIMBUS_4_TX", NULL, "Slimbus4 Capture"},
493	{"SLIMBUS_5_TX", NULL, "Slimbus5 Capture"},
494	{"SLIMBUS_6_TX", NULL, "Slimbus6 Capture"},
495
496	{"Primary MI2S Playback", NULL, "PRI_MI2S_RX"},
497	{"Secondary MI2S Playback", NULL, "SEC_MI2S_RX"},
498	{"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"},
499	{"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"},
500	{"Quinary MI2S Playback", NULL, "QUIN_MI2S_RX"},
501
502	{"Primary TDM0 Playback", NULL, "PRIMARY_TDM_RX_0"},
503	{"Primary TDM1 Playback", NULL, "PRIMARY_TDM_RX_1"},
504	{"Primary TDM2 Playback", NULL, "PRIMARY_TDM_RX_2"},
505	{"Primary TDM3 Playback", NULL, "PRIMARY_TDM_RX_3"},
506	{"Primary TDM4 Playback", NULL, "PRIMARY_TDM_RX_4"},
507	{"Primary TDM5 Playback", NULL, "PRIMARY_TDM_RX_5"},
508	{"Primary TDM6 Playback", NULL, "PRIMARY_TDM_RX_6"},
509	{"Primary TDM7 Playback", NULL, "PRIMARY_TDM_RX_7"},
510
511	{"Secondary TDM0 Playback", NULL, "SEC_TDM_RX_0"},
512	{"Secondary TDM1 Playback", NULL, "SEC_TDM_RX_1"},
513	{"Secondary TDM2 Playback", NULL, "SEC_TDM_RX_2"},
514	{"Secondary TDM3 Playback", NULL, "SEC_TDM_RX_3"},
515	{"Secondary TDM4 Playback", NULL, "SEC_TDM_RX_4"},
516	{"Secondary TDM5 Playback", NULL, "SEC_TDM_RX_5"},
517	{"Secondary TDM6 Playback", NULL, "SEC_TDM_RX_6"},
518	{"Secondary TDM7 Playback", NULL, "SEC_TDM_RX_7"},
519
520	{"Tertiary TDM0 Playback", NULL, "TERT_TDM_RX_0"},
521	{"Tertiary TDM1 Playback", NULL, "TERT_TDM_RX_1"},
522	{"Tertiary TDM2 Playback", NULL, "TERT_TDM_RX_2"},
523	{"Tertiary TDM3 Playback", NULL, "TERT_TDM_RX_3"},
524	{"Tertiary TDM4 Playback", NULL, "TERT_TDM_RX_4"},
525	{"Tertiary TDM5 Playback", NULL, "TERT_TDM_RX_5"},
526	{"Tertiary TDM6 Playback", NULL, "TERT_TDM_RX_6"},
527	{"Tertiary TDM7 Playback", NULL, "TERT_TDM_RX_7"},
528
529	{"Quaternary TDM0 Playback", NULL, "QUAT_TDM_RX_0"},
530	{"Quaternary TDM1 Playback", NULL, "QUAT_TDM_RX_1"},
531	{"Quaternary TDM2 Playback", NULL, "QUAT_TDM_RX_2"},
532	{"Quaternary TDM3 Playback", NULL, "QUAT_TDM_RX_3"},
533	{"Quaternary TDM4 Playback", NULL, "QUAT_TDM_RX_4"},
534	{"Quaternary TDM5 Playback", NULL, "QUAT_TDM_RX_5"},
535	{"Quaternary TDM6 Playback", NULL, "QUAT_TDM_RX_6"},
536	{"Quaternary TDM7 Playback", NULL, "QUAT_TDM_RX_7"},
537
538	{"Quinary TDM0 Playback", NULL, "QUIN_TDM_RX_0"},
539	{"Quinary TDM1 Playback", NULL, "QUIN_TDM_RX_1"},
540	{"Quinary TDM2 Playback", NULL, "QUIN_TDM_RX_2"},
541	{"Quinary TDM3 Playback", NULL, "QUIN_TDM_RX_3"},
542	{"Quinary TDM4 Playback", NULL, "QUIN_TDM_RX_4"},
543	{"Quinary TDM5 Playback", NULL, "QUIN_TDM_RX_5"},
544	{"Quinary TDM6 Playback", NULL, "QUIN_TDM_RX_6"},
545	{"Quinary TDM7 Playback", NULL, "QUIN_TDM_RX_7"},
546
547	{"PRIMARY_TDM_TX_0", NULL, "Primary TDM0 Capture"},
548	{"PRIMARY_TDM_TX_1", NULL, "Primary TDM1 Capture"},
549	{"PRIMARY_TDM_TX_2", NULL, "Primary TDM2 Capture"},
550	{"PRIMARY_TDM_TX_3", NULL, "Primary TDM3 Capture"},
551	{"PRIMARY_TDM_TX_4", NULL, "Primary TDM4 Capture"},
552	{"PRIMARY_TDM_TX_5", NULL, "Primary TDM5 Capture"},
553	{"PRIMARY_TDM_TX_6", NULL, "Primary TDM6 Capture"},
554	{"PRIMARY_TDM_TX_7", NULL, "Primary TDM7 Capture"},
555
556	{"SEC_TDM_TX_0", NULL, "Secondary TDM0 Capture"},
557	{"SEC_TDM_TX_1", NULL, "Secondary TDM1 Capture"},
558	{"SEC_TDM_TX_2", NULL, "Secondary TDM2 Capture"},
559	{"SEC_TDM_TX_3", NULL, "Secondary TDM3 Capture"},
560	{"SEC_TDM_TX_4", NULL, "Secondary TDM4 Capture"},
561	{"SEC_TDM_TX_5", NULL, "Secondary TDM5 Capture"},
562	{"SEC_TDM_TX_6", NULL, "Secondary TDM6 Capture"},
563	{"SEC_TDM_TX_7", NULL, "Secondary TDM7 Capture"},
564
565	{"TERT_TDM_TX_0", NULL, "Tertiary TDM0 Capture"},
566	{"TERT_TDM_TX_1", NULL, "Tertiary TDM1 Capture"},
567	{"TERT_TDM_TX_2", NULL, "Tertiary TDM2 Capture"},
568	{"TERT_TDM_TX_3", NULL, "Tertiary TDM3 Capture"},
569	{"TERT_TDM_TX_4", NULL, "Tertiary TDM4 Capture"},
570	{"TERT_TDM_TX_5", NULL, "Tertiary TDM5 Capture"},
571	{"TERT_TDM_TX_6", NULL, "Tertiary TDM6 Capture"},
572	{"TERT_TDM_TX_7", NULL, "Tertiary TDM7 Capture"},
573
574	{"QUAT_TDM_TX_0", NULL, "Quaternary TDM0 Capture"},
575	{"QUAT_TDM_TX_1", NULL, "Quaternary TDM1 Capture"},
576	{"QUAT_TDM_TX_2", NULL, "Quaternary TDM2 Capture"},
577	{"QUAT_TDM_TX_3", NULL, "Quaternary TDM3 Capture"},
578	{"QUAT_TDM_TX_4", NULL, "Quaternary TDM4 Capture"},
579	{"QUAT_TDM_TX_5", NULL, "Quaternary TDM5 Capture"},
580	{"QUAT_TDM_TX_6", NULL, "Quaternary TDM6 Capture"},
581	{"QUAT_TDM_TX_7", NULL, "Quaternary TDM7 Capture"},
582
583	{"QUIN_TDM_TX_0", NULL, "Quinary TDM0 Capture"},
584	{"QUIN_TDM_TX_1", NULL, "Quinary TDM1 Capture"},
585	{"QUIN_TDM_TX_2", NULL, "Quinary TDM2 Capture"},
586	{"QUIN_TDM_TX_3", NULL, "Quinary TDM3 Capture"},
587	{"QUIN_TDM_TX_4", NULL, "Quinary TDM4 Capture"},
588	{"QUIN_TDM_TX_5", NULL, "Quinary TDM5 Capture"},
589	{"QUIN_TDM_TX_6", NULL, "Quinary TDM6 Capture"},
590	{"QUIN_TDM_TX_7", NULL, "Quinary TDM7 Capture"},
591
592	{"TERT_MI2S_TX", NULL, "Tertiary MI2S Capture"},
593	{"PRI_MI2S_TX", NULL, "Primary MI2S Capture"},
594	{"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"},
595	{"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"},
596	{"QUIN_MI2S_TX", NULL, "Quinary MI2S Capture"},
597
598	{"WSA_CODEC_DMA_RX_0 Playback", NULL, "WSA_CODEC_DMA_RX_0"},
599	{"WSA_CODEC_DMA_TX_0", NULL, "WSA_CODEC_DMA_TX_0 Capture"},
600	{"WSA_CODEC_DMA_RX_1 Playback", NULL, "WSA_CODEC_DMA_RX_1"},
601	{"WSA_CODEC_DMA_TX_1", NULL, "WSA_CODEC_DMA_TX_1 Capture"},
602	{"WSA_CODEC_DMA_TX_2", NULL, "WSA_CODEC_DMA_TX_2 Capture"},
603	{"VA_CODEC_DMA_TX_0", NULL, "VA_CODEC_DMA_TX_0 Capture"},
604	{"VA_CODEC_DMA_TX_1", NULL, "VA_CODEC_DMA_TX_1 Capture"},
605	{"VA_CODEC_DMA_TX_2", NULL, "VA_CODEC_DMA_TX_2 Capture"},
606	{"RX_CODEC_DMA_RX_0 Playback", NULL, "RX_CODEC_DMA_RX_0"},
607	{"TX_CODEC_DMA_TX_0", NULL, "TX_CODEC_DMA_TX_0 Capture"},
608	{"RX_CODEC_DMA_RX_1 Playback", NULL, "RX_CODEC_DMA_RX_1"},
609	{"TX_CODEC_DMA_TX_1", NULL, "TX_CODEC_DMA_TX_1 Capture"},
610	{"RX_CODEC_DMA_RX_2 Playback", NULL, "RX_CODEC_DMA_RX_2"},
611	{"TX_CODEC_DMA_TX_2", NULL, "TX_CODEC_DMA_TX_2 Capture"},
612	{"RX_CODEC_DMA_RX_3 Playback", NULL, "RX_CODEC_DMA_RX_3"},
613	{"TX_CODEC_DMA_TX_3", NULL, "TX_CODEC_DMA_TX_3 Capture"},
614	{"RX_CODEC_DMA_RX_4 Playback", NULL, "RX_CODEC_DMA_RX_4"},
615	{"TX_CODEC_DMA_TX_4", NULL, "TX_CODEC_DMA_TX_4 Capture"},
616	{"RX_CODEC_DMA_RX_5 Playback", NULL, "RX_CODEC_DMA_RX_5"},
617	{"TX_CODEC_DMA_TX_5", NULL, "TX_CODEC_DMA_TX_5 Capture"},
618	{"RX_CODEC_DMA_RX_6 Playback", NULL, "RX_CODEC_DMA_RX_6"},
619	{"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"},
620};
621
622static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
623{
624	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
625	struct q6afe_port *port;
626
627	port = q6afe_port_get_from_id(dai->dev, dai->id);
628	if (IS_ERR(port)) {
629		dev_err(dai->dev, "Unable to get afe port\n");
630		return -EINVAL;
631	}
632	dai_data->port[dai->id] = port;
633
634	return 0;
635}
636
637static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
638{
639	struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
640
641	q6afe_port_put(dai_data->port[dai->id]);
642	dai_data->port[dai->id] = NULL;
643
644	return 0;
645}
646
647static const struct snd_soc_dai_ops q6hdmi_ops = {
648	.probe			= msm_dai_q6_dai_probe,
649	.remove			= msm_dai_q6_dai_remove,
650	.prepare		= q6afe_dai_prepare,
651	.hw_params		= q6hdmi_hw_params,
652	.shutdown		= q6afe_dai_shutdown,
653};
654
655static const struct snd_soc_dai_ops q6i2s_ops = {
656	.probe			= msm_dai_q6_dai_probe,
657	.remove			= msm_dai_q6_dai_remove,
658	.prepare		= q6afe_dai_prepare,
659	.hw_params		= q6i2s_hw_params,
660	.set_fmt		= q6i2s_set_fmt,
661	.shutdown		= q6afe_dai_shutdown,
662	.set_sysclk		= q6afe_mi2s_set_sysclk,
663};
664
665static const struct snd_soc_dai_ops q6slim_ops = {
666	.probe			= msm_dai_q6_dai_probe,
667	.remove			= msm_dai_q6_dai_remove,
668	.prepare		= q6afe_dai_prepare,
669	.hw_params		= q6slim_hw_params,
670	.shutdown		= q6afe_dai_shutdown,
671	.set_channel_map	= q6slim_set_channel_map,
672};
673
674static const struct snd_soc_dai_ops q6tdm_ops = {
675	.probe			= msm_dai_q6_dai_probe,
676	.remove			= msm_dai_q6_dai_remove,
677	.prepare		= q6afe_dai_prepare,
678	.shutdown		= q6afe_dai_shutdown,
679	.set_sysclk		= q6afe_mi2s_set_sysclk,
680	.set_tdm_slot		= q6tdm_set_tdm_slot,
681	.set_channel_map	= q6tdm_set_channel_map,
682	.hw_params		= q6tdm_hw_params,
683};
684
685static const struct snd_soc_dai_ops q6dma_ops = {
686	.probe			= msm_dai_q6_dai_probe,
687	.remove			= msm_dai_q6_dai_remove,
688	.prepare		= q6afe_dai_prepare,
689	.shutdown		= q6afe_dai_shutdown,
690	.set_sysclk		= q6afe_mi2s_set_sysclk,
691	.set_channel_map	= q6dma_set_channel_map,
692	.hw_params		= q6dma_hw_params,
693};
694
695static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
696	SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
697	SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
698	SND_SOC_DAPM_AIF_IN("SLIMBUS_1_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
699	SND_SOC_DAPM_AIF_IN("SLIMBUS_2_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
700	SND_SOC_DAPM_AIF_IN("SLIMBUS_3_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
701	SND_SOC_DAPM_AIF_IN("SLIMBUS_4_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
702	SND_SOC_DAPM_AIF_IN("SLIMBUS_5_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
703	SND_SOC_DAPM_AIF_IN("SLIMBUS_6_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
704	SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
705	SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
706	SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
707	SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
708	SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
709	SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
710	SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
711	SND_SOC_DAPM_AIF_IN("QUIN_MI2S_RX", NULL,
712						0, SND_SOC_NOPM, 0, 0),
713	SND_SOC_DAPM_AIF_OUT("QUIN_MI2S_TX", NULL,
714						0, SND_SOC_NOPM, 0, 0),
715	SND_SOC_DAPM_AIF_IN("QUAT_MI2S_RX", NULL,
716						0, SND_SOC_NOPM, 0, 0),
717	SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_TX", NULL,
718						0, SND_SOC_NOPM, 0, 0),
719	SND_SOC_DAPM_AIF_IN("TERT_MI2S_RX", NULL,
720						0, SND_SOC_NOPM, 0, 0),
721	SND_SOC_DAPM_AIF_OUT("TERT_MI2S_TX", NULL,
722						0, SND_SOC_NOPM, 0, 0),
723	SND_SOC_DAPM_AIF_IN("SEC_MI2S_RX", NULL,
724			     0, SND_SOC_NOPM, 0, 0),
725	SND_SOC_DAPM_AIF_OUT("SEC_MI2S_TX", NULL,
726						0, SND_SOC_NOPM, 0, 0),
727	SND_SOC_DAPM_AIF_IN("SEC_MI2S_RX_SD1",
728			"Secondary MI2S Playback SD1",
729			0, SND_SOC_NOPM, 0, 0),
730	SND_SOC_DAPM_AIF_IN("PRI_MI2S_RX", NULL,
731			     0, SND_SOC_NOPM, 0, 0),
732	SND_SOC_DAPM_AIF_OUT("PRI_MI2S_TX", NULL,
733						0, SND_SOC_NOPM, 0, 0),
734
735	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_0", NULL,
736			     0, SND_SOC_NOPM, 0, 0),
737	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_1", NULL,
738			     0, SND_SOC_NOPM, 0, 0),
739	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_2", NULL,
740			     0, SND_SOC_NOPM, 0, 0),
741	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_3", NULL,
742			     0, SND_SOC_NOPM, 0, 0),
743	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_4", NULL,
744			     0, SND_SOC_NOPM, 0, 0),
745	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_5", NULL,
746			     0, SND_SOC_NOPM, 0, 0),
747	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_6", NULL,
748			     0, SND_SOC_NOPM, 0, 0),
749	SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_7", NULL,
750			     0, SND_SOC_NOPM, 0, 0),
751	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_0", NULL,
752						0, SND_SOC_NOPM, 0, 0),
753	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_1", NULL,
754						0, SND_SOC_NOPM, 0, 0),
755	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_2", NULL,
756						0, SND_SOC_NOPM, 0, 0),
757	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_3", NULL,
758						0, SND_SOC_NOPM, 0, 0),
759	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_4", NULL,
760						0, SND_SOC_NOPM, 0, 0),
761	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_5", NULL,
762						0, SND_SOC_NOPM, 0, 0),
763	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_6", NULL,
764						0, SND_SOC_NOPM, 0, 0),
765	SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_7", NULL,
766						0, SND_SOC_NOPM, 0, 0),
767
768	SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_0", NULL,
769			     0, SND_SOC_NOPM, 0, 0),
770	SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_1", NULL,
771			     0, SND_SOC_NOPM, 0, 0),
772	SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_2", NULL,
773			     0, SND_SOC_NOPM, 0, 0),
774	SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_3", NULL,
775			     0, SND_SOC_NOPM, 0, 0),
776	SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_4", NULL,
777			     0, SND_SOC_NOPM, 0, 0),
778	SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_5", NULL,
779			     0, SND_SOC_NOPM, 0, 0),
780	SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_6", NULL,
781			     0, SND_SOC_NOPM, 0, 0),
782	SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_7", NULL,
783			     0, SND_SOC_NOPM, 0, 0),
784	SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_0", NULL,
785						0, SND_SOC_NOPM, 0, 0),
786	SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_1", NULL,
787						0, SND_SOC_NOPM, 0, 0),
788	SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_2", NULL,
789						0, SND_SOC_NOPM, 0, 0),
790	SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_3", NULL,
791						0, SND_SOC_NOPM, 0, 0),
792	SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_4", NULL,
793						0, SND_SOC_NOPM, 0, 0),
794	SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_5", NULL,
795						0, SND_SOC_NOPM, 0, 0),
796	SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_6", NULL,
797						0, SND_SOC_NOPM, 0, 0),
798	SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_7", NULL,
799						0, SND_SOC_NOPM, 0, 0),
800
801	SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_0", NULL,
802			     0, SND_SOC_NOPM, 0, 0),
803	SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_1", NULL,
804			     0, SND_SOC_NOPM, 0, 0),
805	SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_2", NULL,
806			     0, SND_SOC_NOPM, 0, 0),
807	SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_3", NULL,
808			     0, SND_SOC_NOPM, 0, 0),
809	SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_4", NULL,
810			     0, SND_SOC_NOPM, 0, 0),
811	SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_5", NULL,
812			     0, SND_SOC_NOPM, 0, 0),
813	SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_6", NULL,
814			     0, SND_SOC_NOPM, 0, 0),
815	SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_7", NULL,
816			     0, SND_SOC_NOPM, 0, 0),
817	SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_0", NULL,
818						0, SND_SOC_NOPM, 0, 0),
819	SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_1", NULL,
820						0, SND_SOC_NOPM, 0, 0),
821	SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_2", NULL,
822						0, SND_SOC_NOPM, 0, 0),
823	SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_3", NULL,
824						0, SND_SOC_NOPM, 0, 0),
825	SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_4", NULL,
826						0, SND_SOC_NOPM, 0, 0),
827	SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_5", NULL,
828						0, SND_SOC_NOPM, 0, 0),
829	SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_6", NULL,
830						0, SND_SOC_NOPM, 0, 0),
831	SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_7", NULL,
832						0, SND_SOC_NOPM, 0, 0),
833
834	SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_0", NULL,
835			     0, SND_SOC_NOPM, 0, 0),
836	SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_1", NULL,
837			     0, SND_SOC_NOPM, 0, 0),
838	SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_2", NULL,
839			     0, SND_SOC_NOPM, 0, 0),
840	SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_3", NULL,
841			     0, SND_SOC_NOPM, 0, 0),
842	SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_4", NULL,
843			     0, SND_SOC_NOPM, 0, 0),
844	SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_5", NULL,
845			     0, SND_SOC_NOPM, 0, 0),
846	SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_6", NULL,
847			     0, SND_SOC_NOPM, 0, 0),
848	SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_7", NULL,
849			     0, SND_SOC_NOPM, 0, 0),
850	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_0", NULL,
851						0, SND_SOC_NOPM, 0, 0),
852	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_1", NULL,
853						0, SND_SOC_NOPM, 0, 0),
854	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_2", NULL,
855						0, SND_SOC_NOPM, 0, 0),
856	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_3", NULL,
857						0, SND_SOC_NOPM, 0, 0),
858	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_4", NULL,
859						0, SND_SOC_NOPM, 0, 0),
860	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_5", NULL,
861						0, SND_SOC_NOPM, 0, 0),
862	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_6", NULL,
863						0, SND_SOC_NOPM, 0, 0),
864	SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_7", NULL,
865						0, SND_SOC_NOPM, 0, 0),
866
867	SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_0", NULL,
868			     0, SND_SOC_NOPM, 0, 0),
869	SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_1", NULL,
870			     0, SND_SOC_NOPM, 0, 0),
871	SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_2", NULL,
872			     0, SND_SOC_NOPM, 0, 0),
873	SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_3", NULL,
874			     0, SND_SOC_NOPM, 0, 0),
875	SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_4", NULL,
876			     0, SND_SOC_NOPM, 0, 0),
877	SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_5", NULL,
878			     0, SND_SOC_NOPM, 0, 0),
879	SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_6", NULL,
880			     0, SND_SOC_NOPM, 0, 0),
881	SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_7", NULL,
882			     0, SND_SOC_NOPM, 0, 0),
883	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_0", NULL,
884						0, SND_SOC_NOPM, 0, 0),
885	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_1", NULL,
886						0, SND_SOC_NOPM, 0, 0),
887	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_2", NULL,
888						0, SND_SOC_NOPM, 0, 0),
889	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_3", NULL,
890						0, SND_SOC_NOPM, 0, 0),
891	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_4", NULL,
892						0, SND_SOC_NOPM, 0, 0),
893	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_5", NULL,
894						0, SND_SOC_NOPM, 0, 0),
895	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_6", NULL,
896						0, SND_SOC_NOPM, 0, 0),
897	SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL,
898						0, SND_SOC_NOPM, 0, 0),
899	SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, SND_SOC_NOPM, 0, 0),
900
901	SND_SOC_DAPM_AIF_IN("WSA_CODEC_DMA_RX_0", "NULL",
902		0, SND_SOC_NOPM, 0, 0),
903	SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_0", "NULL",
904		 0, SND_SOC_NOPM, 0, 0),
905	SND_SOC_DAPM_AIF_IN("WSA_CODEC_DMA_RX_1", "NULL",
906		0, SND_SOC_NOPM, 0, 0),
907	SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_1", "NULL",
908		 0, SND_SOC_NOPM, 0, 0),
909	SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_2", "NULL",
910		 0, SND_SOC_NOPM, 0, 0),
911	SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_0", "NULL",
912		 0, SND_SOC_NOPM, 0, 0),
913	SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_1", "NULL",
914		 0, SND_SOC_NOPM, 0, 0),
915	SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_2", "NULL",
916		 0, SND_SOC_NOPM, 0, 0),
917	SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_0", "NULL",
918		0, SND_SOC_NOPM, 0, 0),
919	SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_0", "NULL",
920		 0, SND_SOC_NOPM, 0, 0),
921	SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_1", "NULL",
922		0, SND_SOC_NOPM, 0, 0),
923	SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_1", "NULL",
924		 0, SND_SOC_NOPM, 0, 0),
925	SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_2", "NULL",
926		0, SND_SOC_NOPM, 0, 0),
927	SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_2", "NULL",
928		 0, SND_SOC_NOPM, 0, 0),
929	SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_3", "NULL",
930		0, SND_SOC_NOPM, 0, 0),
931	SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_3", "NULL",
932		 0, SND_SOC_NOPM, 0, 0),
933	SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_4", "NULL",
934		0, SND_SOC_NOPM, 0, 0),
935	SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_4", "NULL",
936		 0, SND_SOC_NOPM, 0, 0),
937	SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_5", "NULL",
938		0, SND_SOC_NOPM, 0, 0),
939	SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_5", "NULL",
940		 0, SND_SOC_NOPM, 0, 0),
941	SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_6", "NULL",
942		0, SND_SOC_NOPM, 0, 0),
943	SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_7", "NULL",
944		0, SND_SOC_NOPM, 0, 0),
945};
946
947static const struct snd_soc_component_driver q6afe_dai_component = {
948	.name		= "q6afe-dai-component",
949	.dapm_widgets = q6afe_dai_widgets,
950	.num_dapm_widgets = ARRAY_SIZE(q6afe_dai_widgets),
951	.dapm_routes = q6afe_dapm_routes,
952	.num_dapm_routes = ARRAY_SIZE(q6afe_dapm_routes),
953	.of_xlate_dai_name = q6dsp_audio_ports_of_xlate_dai_name,
954
955};
956
957static void of_q6afe_parse_dai_data(struct device *dev,
958				    struct q6afe_dai_data *data)
959{
960	struct device_node *node;
961	int ret;
962
963	for_each_child_of_node(dev->of_node, node) {
964		unsigned int lines[Q6AFE_MAX_MI2S_LINES];
965		struct q6afe_dai_priv_data *priv;
966		int id, i, num_lines;
967
968		ret = of_property_read_u32(node, "reg", &id);
969		if (ret || id < 0 || id >= AFE_PORT_MAX) {
970			dev_err(dev, "valid dai id not found:%d\n", ret);
971			continue;
972		}
973
974		switch (id) {
975		/* MI2S specific properties */
976		case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
977		case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
978			priv = &data->priv[id];
979			ret = of_property_read_variable_u32_array(node,
980							"qcom,sd-lines",
981							lines, 0,
982							Q6AFE_MAX_MI2S_LINES);
983			if (ret < 0)
984				num_lines = 0;
985			else
986				num_lines = ret;
987
988			priv->sd_line_mask = 0;
989
990			for (i = 0; i < num_lines; i++)
991				priv->sd_line_mask |= BIT(lines[i]);
992
993			break;
994		case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
995			priv = &data->priv[id];
996			ret = of_property_read_u32(node, "qcom,tdm-sync-mode",
997						   &priv->sync_mode);
998			if (ret) {
999				dev_err(dev, "No Sync mode from DT\n");
1000				break;
1001			}
1002			ret = of_property_read_u32(node, "qcom,tdm-sync-src",
1003						   &priv->sync_src);
1004			if (ret) {
1005				dev_err(dev, "No Sync Src from DT\n");
1006				break;
1007			}
1008			ret = of_property_read_u32(node, "qcom,tdm-data-out",
1009						   &priv->data_out_enable);
1010			if (ret) {
1011				dev_err(dev, "No Data out enable from DT\n");
1012				break;
1013			}
1014			ret = of_property_read_u32(node, "qcom,tdm-invert-sync",
1015						   &priv->invert_sync);
1016			if (ret) {
1017				dev_err(dev, "No Invert sync from DT\n");
1018				break;
1019			}
1020			ret = of_property_read_u32(node, "qcom,tdm-data-delay",
1021						   &priv->data_delay);
1022			if (ret) {
1023				dev_err(dev, "No Data Delay from DT\n");
1024				break;
1025			}
1026			ret = of_property_read_u32(node, "qcom,tdm-data-align",
1027						   &priv->data_align);
1028			if (ret) {
1029				dev_err(dev, "No Data align from DT\n");
1030				break;
1031			}
1032			break;
1033		default:
1034			break;
1035		}
1036	}
1037}
1038
1039static int q6afe_dai_dev_probe(struct platform_device *pdev)
1040{
1041	struct q6dsp_audio_port_dai_driver_config cfg;
1042	struct snd_soc_dai_driver *dais;
1043	struct q6afe_dai_data *dai_data;
1044	struct device *dev = &pdev->dev;
1045	int num_dais;
1046
1047	dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL);
1048	if (!dai_data)
1049		return -ENOMEM;
1050
1051	dev_set_drvdata(dev, dai_data);
1052	of_q6afe_parse_dai_data(dev, dai_data);
1053
1054	cfg.q6hdmi_ops = &q6hdmi_ops;
1055	cfg.q6slim_ops = &q6slim_ops;
1056	cfg.q6i2s_ops = &q6i2s_ops;
1057	cfg.q6tdm_ops = &q6tdm_ops;
1058	cfg.q6dma_ops = &q6dma_ops;
1059	dais = q6dsp_audio_ports_set_config(dev, &cfg, &num_dais);
1060
1061	return devm_snd_soc_register_component(dev, &q6afe_dai_component, dais, num_dais);
1062}
1063
1064#ifdef CONFIG_OF
1065static const struct of_device_id q6afe_dai_device_id[] = {
1066	{ .compatible = "qcom,q6afe-dais" },
1067	{},
1068};
1069MODULE_DEVICE_TABLE(of, q6afe_dai_device_id);
1070#endif
1071
1072static struct platform_driver q6afe_dai_platform_driver = {
1073	.driver = {
1074		.name = "q6afe-dai",
1075		.of_match_table = of_match_ptr(q6afe_dai_device_id),
1076	},
1077	.probe = q6afe_dai_dev_probe,
1078};
1079module_platform_driver(q6afe_dai_platform_driver);
1080
1081MODULE_DESCRIPTION("Q6 Audio Frontend dai driver");
1082MODULE_LICENSE("GPL v2");
1083