File Index
Files and directories
Sign in
FILE

q6afe-dai.c

File preview with syntax highlighting.

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