Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
0003 // Copyright (c) 2018, Linaro Limited
0004 
0005 #include <linux/err.h>
0006 #include <linux/init.h>
0007 #include <linux/module.h>
0008 #include <linux/device.h>
0009 #include <linux/platform_device.h>
0010 #include <linux/slab.h>
0011 #include <sound/pcm.h>
0012 #include <sound/soc.h>
0013 #include <sound/pcm_params.h>
0014 #include "q6dsp-lpass-ports.h"
0015 #include "q6afe.h"
0016 
0017 
0018 struct q6afe_dai_priv_data {
0019     uint32_t sd_line_mask;
0020     uint32_t sync_mode;
0021     uint32_t sync_src;
0022     uint32_t data_out_enable;
0023     uint32_t invert_sync;
0024     uint32_t data_delay;
0025     uint32_t data_align;
0026 };
0027 
0028 struct q6afe_dai_data {
0029     struct q6afe_port *port[AFE_PORT_MAX];
0030     struct q6afe_port_config port_config[AFE_PORT_MAX];
0031     bool is_port_started[AFE_PORT_MAX];
0032     struct q6afe_dai_priv_data priv[AFE_PORT_MAX];
0033 };
0034 
0035 static int q6slim_hw_params(struct snd_pcm_substream *substream,
0036                 struct snd_pcm_hw_params *params,
0037                 struct snd_soc_dai *dai)
0038 {
0039 
0040     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0041     struct q6afe_slim_cfg *slim = &dai_data->port_config[dai->id].slim;
0042 
0043     slim->sample_rate = params_rate(params);
0044 
0045     switch (params_format(params)) {
0046     case SNDRV_PCM_FORMAT_S16_LE:
0047     case SNDRV_PCM_FORMAT_SPECIAL:
0048         slim->bit_width = 16;
0049         break;
0050     case SNDRV_PCM_FORMAT_S24_LE:
0051         slim->bit_width = 24;
0052         break;
0053     case SNDRV_PCM_FORMAT_S32_LE:
0054         slim->bit_width = 32;
0055         break;
0056     default:
0057         pr_err("%s: format %d\n",
0058             __func__, params_format(params));
0059         return -EINVAL;
0060     }
0061 
0062     return 0;
0063 }
0064 
0065 static int q6hdmi_hw_params(struct snd_pcm_substream *substream,
0066                 struct snd_pcm_hw_params *params,
0067                 struct snd_soc_dai *dai)
0068 {
0069     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0070     int channels = params_channels(params);
0071     struct q6afe_hdmi_cfg *hdmi = &dai_data->port_config[dai->id].hdmi;
0072 
0073     hdmi->sample_rate = params_rate(params);
0074     switch (params_format(params)) {
0075     case SNDRV_PCM_FORMAT_S16_LE:
0076         hdmi->bit_width = 16;
0077         break;
0078     case SNDRV_PCM_FORMAT_S24_LE:
0079         hdmi->bit_width = 24;
0080         break;
0081     }
0082 
0083     /* HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4 */
0084     switch (channels) {
0085     case 2:
0086         hdmi->channel_allocation = 0;
0087         break;
0088     case 3:
0089         hdmi->channel_allocation = 0x02;
0090         break;
0091     case 4:
0092         hdmi->channel_allocation = 0x06;
0093         break;
0094     case 5:
0095         hdmi->channel_allocation = 0x0A;
0096         break;
0097     case 6:
0098         hdmi->channel_allocation = 0x0B;
0099         break;
0100     case 7:
0101         hdmi->channel_allocation = 0x12;
0102         break;
0103     case 8:
0104         hdmi->channel_allocation = 0x13;
0105         break;
0106     default:
0107         dev_err(dai->dev, "invalid Channels = %u\n", channels);
0108         return -EINVAL;
0109     }
0110 
0111     return 0;
0112 }
0113 
0114 static int q6i2s_hw_params(struct snd_pcm_substream *substream,
0115                struct snd_pcm_hw_params *params,
0116                struct snd_soc_dai *dai)
0117 {
0118     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0119     struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg;
0120 
0121     i2s->sample_rate = params_rate(params);
0122     i2s->bit_width = params_width(params);
0123     i2s->num_channels = params_channels(params);
0124     i2s->sd_line_mask = dai_data->priv[dai->id].sd_line_mask;
0125 
0126     return 0;
0127 }
0128 
0129 static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
0130 {
0131     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0132     struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg;
0133 
0134     i2s->fmt = fmt;
0135 
0136     return 0;
0137 }
0138 
0139 static int q6tdm_set_tdm_slot(struct snd_soc_dai *dai,
0140                 unsigned int tx_mask,
0141                 unsigned int rx_mask,
0142                 int slots, int slot_width)
0143 {
0144 
0145     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0146     struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
0147     unsigned int cap_mask;
0148     int rc = 0;
0149 
0150     /* HW only supports 16 and 32 bit slot width configuration */
0151     if ((slot_width != 16) && (slot_width != 32)) {
0152         dev_err(dai->dev, "%s: invalid slot_width %d\n",
0153             __func__, slot_width);
0154         return -EINVAL;
0155     }
0156 
0157     /* HW supports 1-32 slots configuration. Typical: 1, 2, 4, 8, 16, 32 */
0158     switch (slots) {
0159     case 2:
0160         cap_mask = 0x03;
0161         break;
0162     case 4:
0163         cap_mask = 0x0F;
0164         break;
0165     case 8:
0166         cap_mask = 0xFF;
0167         break;
0168     case 16:
0169         cap_mask = 0xFFFF;
0170         break;
0171     default:
0172         dev_err(dai->dev, "%s: invalid slots %d\n",
0173             __func__, slots);
0174         return -EINVAL;
0175     }
0176 
0177     switch (dai->id) {
0178     case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
0179         tdm->nslots_per_frame = slots;
0180         tdm->slot_width = slot_width;
0181         /* TDM RX dais ids are even and tx are odd */
0182         tdm->slot_mask = ((dai->id & 0x1) ? tx_mask : rx_mask) & cap_mask;
0183         break;
0184     default:
0185         dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
0186             __func__, dai->id);
0187         return -EINVAL;
0188     }
0189 
0190     return rc;
0191 }
0192 
0193 static int q6tdm_set_channel_map(struct snd_soc_dai *dai,
0194                 unsigned int tx_num, unsigned int *tx_slot,
0195                 unsigned int rx_num, unsigned int *rx_slot)
0196 {
0197 
0198     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0199     struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
0200     int rc = 0;
0201     int i = 0;
0202 
0203     switch (dai->id) {
0204     case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
0205         if (dai->id & 0x1) {
0206             if (!tx_slot) {
0207                 dev_err(dai->dev, "tx slot not found\n");
0208                 return -EINVAL;
0209             }
0210             if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
0211                 dev_err(dai->dev, "invalid tx num %d\n",
0212                     tx_num);
0213                 return -EINVAL;
0214             }
0215 
0216             for (i = 0; i < tx_num; i++)
0217                 tdm->ch_mapping[i] = tx_slot[i];
0218 
0219             for (i = tx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
0220                 tdm->ch_mapping[i] = Q6AFE_CMAP_INVALID;
0221 
0222             tdm->num_channels = tx_num;
0223         } else {
0224             /* rx */
0225             if (!rx_slot) {
0226                 dev_err(dai->dev, "rx slot not found\n");
0227                 return -EINVAL;
0228             }
0229             if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
0230                 dev_err(dai->dev, "invalid rx num %d\n",
0231                     rx_num);
0232                 return -EINVAL;
0233             }
0234 
0235             for (i = 0; i < rx_num; i++)
0236                 tdm->ch_mapping[i] = rx_slot[i];
0237 
0238             for (i = rx_num; i < AFE_PORT_MAX_AUDIO_CHAN_CNT; i++)
0239                 tdm->ch_mapping[i] = Q6AFE_CMAP_INVALID;
0240 
0241             tdm->num_channels = rx_num;
0242         }
0243 
0244         break;
0245     default:
0246         dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
0247             __func__, dai->id);
0248         return -EINVAL;
0249     }
0250 
0251     return rc;
0252 }
0253 
0254 static int q6tdm_hw_params(struct snd_pcm_substream *substream,
0255                struct snd_pcm_hw_params *params,
0256                struct snd_soc_dai *dai)
0257 {
0258     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0259     struct q6afe_tdm_cfg *tdm = &dai_data->port_config[dai->id].tdm;
0260 
0261     tdm->bit_width = params_width(params);
0262     tdm->sample_rate = params_rate(params);
0263     tdm->num_channels = params_channels(params);
0264     tdm->data_align_type = dai_data->priv[dai->id].data_align;
0265     tdm->sync_src = dai_data->priv[dai->id].sync_src;
0266     tdm->sync_mode = dai_data->priv[dai->id].sync_mode;
0267 
0268     return 0;
0269 }
0270 
0271 static int q6dma_set_channel_map(struct snd_soc_dai *dai,
0272                  unsigned int tx_num, unsigned int *tx_ch_mask,
0273                  unsigned int rx_num, unsigned int *rx_ch_mask)
0274 {
0275 
0276     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0277     struct q6afe_cdc_dma_cfg *cfg = &dai_data->port_config[dai->id].dma_cfg;
0278     int ch_mask;
0279     int rc = 0;
0280 
0281     switch (dai->id) {
0282     case WSA_CODEC_DMA_TX_0:
0283     case WSA_CODEC_DMA_TX_1:
0284     case WSA_CODEC_DMA_TX_2:
0285     case VA_CODEC_DMA_TX_0:
0286     case VA_CODEC_DMA_TX_1:
0287     case VA_CODEC_DMA_TX_2:
0288     case TX_CODEC_DMA_TX_0:
0289     case TX_CODEC_DMA_TX_1:
0290     case TX_CODEC_DMA_TX_2:
0291     case TX_CODEC_DMA_TX_3:
0292     case TX_CODEC_DMA_TX_4:
0293     case TX_CODEC_DMA_TX_5:
0294         if (!tx_ch_mask) {
0295             dev_err(dai->dev, "tx slot not found\n");
0296             return -EINVAL;
0297         }
0298 
0299         if (tx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
0300             dev_err(dai->dev, "invalid tx num %d\n",
0301                 tx_num);
0302             return -EINVAL;
0303         }
0304         ch_mask = *tx_ch_mask;
0305 
0306         break;
0307     case WSA_CODEC_DMA_RX_0:
0308     case WSA_CODEC_DMA_RX_1:
0309     case RX_CODEC_DMA_RX_0:
0310     case RX_CODEC_DMA_RX_1:
0311     case RX_CODEC_DMA_RX_2:
0312     case RX_CODEC_DMA_RX_3:
0313     case RX_CODEC_DMA_RX_4:
0314     case RX_CODEC_DMA_RX_5:
0315     case RX_CODEC_DMA_RX_6:
0316     case RX_CODEC_DMA_RX_7:
0317         /* rx */
0318         if (!rx_ch_mask) {
0319             dev_err(dai->dev, "rx slot not found\n");
0320             return -EINVAL;
0321         }
0322         if (rx_num > AFE_PORT_MAX_AUDIO_CHAN_CNT) {
0323             dev_err(dai->dev, "invalid rx num %d\n",
0324                 rx_num);
0325             return -EINVAL;
0326         }
0327         ch_mask = *rx_ch_mask;
0328 
0329         break;
0330     default:
0331         dev_err(dai->dev, "%s: invalid dai id 0x%x\n",
0332             __func__, dai->id);
0333         return -EINVAL;
0334     }
0335 
0336     cfg->active_channels_mask = ch_mask;
0337 
0338     return rc;
0339 }
0340 
0341 static int q6dma_hw_params(struct snd_pcm_substream *substream,
0342                struct snd_pcm_hw_params *params,
0343                struct snd_soc_dai *dai)
0344 {
0345     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0346     struct q6afe_cdc_dma_cfg *cfg = &dai_data->port_config[dai->id].dma_cfg;
0347 
0348     cfg->bit_width = params_width(params);
0349     cfg->sample_rate = params_rate(params);
0350     cfg->num_channels = params_channels(params);
0351 
0352     return 0;
0353 }
0354 static void q6afe_dai_shutdown(struct snd_pcm_substream *substream,
0355                 struct snd_soc_dai *dai)
0356 {
0357     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0358     int rc;
0359 
0360     if (!dai_data->is_port_started[dai->id])
0361         return;
0362 
0363     rc = q6afe_port_stop(dai_data->port[dai->id]);
0364     if (rc < 0)
0365         dev_err(dai->dev, "fail to close AFE port (%d)\n", rc);
0366 
0367     dai_data->is_port_started[dai->id] = false;
0368 
0369 }
0370 
0371 static int q6afe_dai_prepare(struct snd_pcm_substream *substream,
0372         struct snd_soc_dai *dai)
0373 {
0374     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0375     int rc;
0376 
0377     if (dai_data->is_port_started[dai->id]) {
0378         /* stop the port and restart with new port config */
0379         rc = q6afe_port_stop(dai_data->port[dai->id]);
0380         if (rc < 0) {
0381             dev_err(dai->dev, "fail to close AFE port (%d)\n", rc);
0382             return rc;
0383         }
0384     }
0385 
0386     switch (dai->id) {
0387     case HDMI_RX:
0388     case DISPLAY_PORT_RX:
0389         q6afe_hdmi_port_prepare(dai_data->port[dai->id],
0390                     &dai_data->port_config[dai->id].hdmi);
0391         break;
0392     case SLIMBUS_0_RX ... SLIMBUS_6_TX:
0393         q6afe_slim_port_prepare(dai_data->port[dai->id],
0394                     &dai_data->port_config[dai->id].slim);
0395         break;
0396     case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
0397     case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
0398         rc = q6afe_i2s_port_prepare(dai_data->port[dai->id],
0399                    &dai_data->port_config[dai->id].i2s_cfg);
0400         if (rc < 0) {
0401             dev_err(dai->dev, "fail to prepare AFE port %x\n",
0402                 dai->id);
0403             return rc;
0404         }
0405         break;
0406     case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
0407         q6afe_tdm_port_prepare(dai_data->port[dai->id],
0408                     &dai_data->port_config[dai->id].tdm);
0409         break;
0410     case WSA_CODEC_DMA_RX_0 ... RX_CODEC_DMA_RX_7:
0411         q6afe_cdc_dma_port_prepare(dai_data->port[dai->id],
0412                        &dai_data->port_config[dai->id].dma_cfg);
0413         break;
0414     default:
0415         return -EINVAL;
0416     }
0417 
0418     rc = q6afe_port_start(dai_data->port[dai->id]);
0419     if (rc < 0) {
0420         dev_err(dai->dev, "fail to start AFE port %x\n", dai->id);
0421         return rc;
0422     }
0423     dai_data->is_port_started[dai->id] = true;
0424 
0425     return 0;
0426 }
0427 
0428 static int q6slim_set_channel_map(struct snd_soc_dai *dai,
0429                 unsigned int tx_num, unsigned int *tx_slot,
0430                 unsigned int rx_num, unsigned int *rx_slot)
0431 {
0432     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0433     struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id];
0434     int i;
0435 
0436     if (dai->id & 0x1) {
0437         /* TX */
0438         if (!tx_slot) {
0439             pr_err("%s: tx slot not found\n", __func__);
0440             return -EINVAL;
0441         }
0442 
0443         for (i = 0; i < tx_num; i++)
0444             pcfg->slim.ch_mapping[i] = tx_slot[i];
0445 
0446         pcfg->slim.num_channels = tx_num;
0447 
0448 
0449     } else {
0450         if (!rx_slot) {
0451             pr_err("%s: rx slot not found\n", __func__);
0452             return -EINVAL;
0453         }
0454 
0455         for (i = 0; i < rx_num; i++)
0456             pcfg->slim.ch_mapping[i] =   rx_slot[i];
0457 
0458         pcfg->slim.num_channels = rx_num;
0459 
0460     }
0461 
0462     return 0;
0463 }
0464 
0465 static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai,
0466         int clk_id, unsigned int freq, int dir)
0467 {
0468     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0469     struct q6afe_port *port = dai_data->port[dai->id];
0470 
0471     switch (clk_id) {
0472     case LPAIF_DIG_CLK:
0473         return q6afe_port_set_sysclk(port, clk_id, 0, 5, freq, dir);
0474     case LPAIF_BIT_CLK:
0475     case LPAIF_OSR_CLK:
0476         return q6afe_port_set_sysclk(port, clk_id,
0477                          Q6AFE_LPASS_CLK_SRC_INTERNAL,
0478                          Q6AFE_LPASS_CLK_ROOT_DEFAULT,
0479                          freq, dir);
0480     case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR:
0481     case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1:
0482     case Q6AFE_LPASS_CLK_ID_WSA_CORE_MCLK ... Q6AFE_LPASS_CLK_ID_VA_CORE_2X_MCLK:
0483         return q6afe_port_set_sysclk(port, clk_id,
0484                          Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO,
0485                          Q6AFE_LPASS_CLK_ROOT_DEFAULT,
0486                          freq, dir);
0487     case Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT ... Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT:
0488         return q6afe_port_set_sysclk(port, clk_id,
0489                          Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO,
0490                          Q6AFE_LPASS_CLK_ROOT_DEFAULT,
0491                          freq, dir);
0492     }
0493 
0494     return 0;
0495 }
0496 
0497 static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
0498     {"HDMI Playback", NULL, "HDMI_RX"},
0499     {"Display Port Playback", NULL, "DISPLAY_PORT_RX"},
0500     {"Slimbus Playback", NULL, "SLIMBUS_0_RX"},
0501     {"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"},
0502     {"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"},
0503     {"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"},
0504     {"Slimbus4 Playback", NULL, "SLIMBUS_4_RX"},
0505     {"Slimbus5 Playback", NULL, "SLIMBUS_5_RX"},
0506     {"Slimbus6 Playback", NULL, "SLIMBUS_6_RX"},
0507 
0508     {"SLIMBUS_0_TX", NULL, "Slimbus Capture"},
0509     {"SLIMBUS_1_TX", NULL, "Slimbus1 Capture"},
0510     {"SLIMBUS_2_TX", NULL, "Slimbus2 Capture"},
0511     {"SLIMBUS_3_TX", NULL, "Slimbus3 Capture"},
0512     {"SLIMBUS_4_TX", NULL, "Slimbus4 Capture"},
0513     {"SLIMBUS_5_TX", NULL, "Slimbus5 Capture"},
0514     {"SLIMBUS_6_TX", NULL, "Slimbus6 Capture"},
0515 
0516     {"Primary MI2S Playback", NULL, "PRI_MI2S_RX"},
0517     {"Secondary MI2S Playback", NULL, "SEC_MI2S_RX"},
0518     {"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"},
0519     {"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"},
0520     {"Quinary MI2S Playback", NULL, "QUIN_MI2S_RX"},
0521 
0522     {"Primary TDM0 Playback", NULL, "PRIMARY_TDM_RX_0"},
0523     {"Primary TDM1 Playback", NULL, "PRIMARY_TDM_RX_1"},
0524     {"Primary TDM2 Playback", NULL, "PRIMARY_TDM_RX_2"},
0525     {"Primary TDM3 Playback", NULL, "PRIMARY_TDM_RX_3"},
0526     {"Primary TDM4 Playback", NULL, "PRIMARY_TDM_RX_4"},
0527     {"Primary TDM5 Playback", NULL, "PRIMARY_TDM_RX_5"},
0528     {"Primary TDM6 Playback", NULL, "PRIMARY_TDM_RX_6"},
0529     {"Primary TDM7 Playback", NULL, "PRIMARY_TDM_RX_7"},
0530 
0531     {"Secondary TDM0 Playback", NULL, "SEC_TDM_RX_0"},
0532     {"Secondary TDM1 Playback", NULL, "SEC_TDM_RX_1"},
0533     {"Secondary TDM2 Playback", NULL, "SEC_TDM_RX_2"},
0534     {"Secondary TDM3 Playback", NULL, "SEC_TDM_RX_3"},
0535     {"Secondary TDM4 Playback", NULL, "SEC_TDM_RX_4"},
0536     {"Secondary TDM5 Playback", NULL, "SEC_TDM_RX_5"},
0537     {"Secondary TDM6 Playback", NULL, "SEC_TDM_RX_6"},
0538     {"Secondary TDM7 Playback", NULL, "SEC_TDM_RX_7"},
0539 
0540     {"Tertiary TDM0 Playback", NULL, "TERT_TDM_RX_0"},
0541     {"Tertiary TDM1 Playback", NULL, "TERT_TDM_RX_1"},
0542     {"Tertiary TDM2 Playback", NULL, "TERT_TDM_RX_2"},
0543     {"Tertiary TDM3 Playback", NULL, "TERT_TDM_RX_3"},
0544     {"Tertiary TDM4 Playback", NULL, "TERT_TDM_RX_4"},
0545     {"Tertiary TDM5 Playback", NULL, "TERT_TDM_RX_5"},
0546     {"Tertiary TDM6 Playback", NULL, "TERT_TDM_RX_6"},
0547     {"Tertiary TDM7 Playback", NULL, "TERT_TDM_RX_7"},
0548 
0549     {"Quaternary TDM0 Playback", NULL, "QUAT_TDM_RX_0"},
0550     {"Quaternary TDM1 Playback", NULL, "QUAT_TDM_RX_1"},
0551     {"Quaternary TDM2 Playback", NULL, "QUAT_TDM_RX_2"},
0552     {"Quaternary TDM3 Playback", NULL, "QUAT_TDM_RX_3"},
0553     {"Quaternary TDM4 Playback", NULL, "QUAT_TDM_RX_4"},
0554     {"Quaternary TDM5 Playback", NULL, "QUAT_TDM_RX_5"},
0555     {"Quaternary TDM6 Playback", NULL, "QUAT_TDM_RX_6"},
0556     {"Quaternary TDM7 Playback", NULL, "QUAT_TDM_RX_7"},
0557 
0558     {"Quinary TDM0 Playback", NULL, "QUIN_TDM_RX_0"},
0559     {"Quinary TDM1 Playback", NULL, "QUIN_TDM_RX_1"},
0560     {"Quinary TDM2 Playback", NULL, "QUIN_TDM_RX_2"},
0561     {"Quinary TDM3 Playback", NULL, "QUIN_TDM_RX_3"},
0562     {"Quinary TDM4 Playback", NULL, "QUIN_TDM_RX_4"},
0563     {"Quinary TDM5 Playback", NULL, "QUIN_TDM_RX_5"},
0564     {"Quinary TDM6 Playback", NULL, "QUIN_TDM_RX_6"},
0565     {"Quinary TDM7 Playback", NULL, "QUIN_TDM_RX_7"},
0566 
0567     {"PRIMARY_TDM_TX_0", NULL, "Primary TDM0 Capture"},
0568     {"PRIMARY_TDM_TX_1", NULL, "Primary TDM1 Capture"},
0569     {"PRIMARY_TDM_TX_2", NULL, "Primary TDM2 Capture"},
0570     {"PRIMARY_TDM_TX_3", NULL, "Primary TDM3 Capture"},
0571     {"PRIMARY_TDM_TX_4", NULL, "Primary TDM4 Capture"},
0572     {"PRIMARY_TDM_TX_5", NULL, "Primary TDM5 Capture"},
0573     {"PRIMARY_TDM_TX_6", NULL, "Primary TDM6 Capture"},
0574     {"PRIMARY_TDM_TX_7", NULL, "Primary TDM7 Capture"},
0575 
0576     {"SEC_TDM_TX_0", NULL, "Secondary TDM0 Capture"},
0577     {"SEC_TDM_TX_1", NULL, "Secondary TDM1 Capture"},
0578     {"SEC_TDM_TX_2", NULL, "Secondary TDM2 Capture"},
0579     {"SEC_TDM_TX_3", NULL, "Secondary TDM3 Capture"},
0580     {"SEC_TDM_TX_4", NULL, "Secondary TDM4 Capture"},
0581     {"SEC_TDM_TX_5", NULL, "Secondary TDM5 Capture"},
0582     {"SEC_TDM_TX_6", NULL, "Secondary TDM6 Capture"},
0583     {"SEC_TDM_TX_7", NULL, "Secondary TDM7 Capture"},
0584 
0585     {"TERT_TDM_TX_0", NULL, "Tertiary TDM0 Capture"},
0586     {"TERT_TDM_TX_1", NULL, "Tertiary TDM1 Capture"},
0587     {"TERT_TDM_TX_2", NULL, "Tertiary TDM2 Capture"},
0588     {"TERT_TDM_TX_3", NULL, "Tertiary TDM3 Capture"},
0589     {"TERT_TDM_TX_4", NULL, "Tertiary TDM4 Capture"},
0590     {"TERT_TDM_TX_5", NULL, "Tertiary TDM5 Capture"},
0591     {"TERT_TDM_TX_6", NULL, "Tertiary TDM6 Capture"},
0592     {"TERT_TDM_TX_7", NULL, "Tertiary TDM7 Capture"},
0593 
0594     {"QUAT_TDM_TX_0", NULL, "Quaternary TDM0 Capture"},
0595     {"QUAT_TDM_TX_1", NULL, "Quaternary TDM1 Capture"},
0596     {"QUAT_TDM_TX_2", NULL, "Quaternary TDM2 Capture"},
0597     {"QUAT_TDM_TX_3", NULL, "Quaternary TDM3 Capture"},
0598     {"QUAT_TDM_TX_4", NULL, "Quaternary TDM4 Capture"},
0599     {"QUAT_TDM_TX_5", NULL, "Quaternary TDM5 Capture"},
0600     {"QUAT_TDM_TX_6", NULL, "Quaternary TDM6 Capture"},
0601     {"QUAT_TDM_TX_7", NULL, "Quaternary TDM7 Capture"},
0602 
0603     {"QUIN_TDM_TX_0", NULL, "Quinary TDM0 Capture"},
0604     {"QUIN_TDM_TX_1", NULL, "Quinary TDM1 Capture"},
0605     {"QUIN_TDM_TX_2", NULL, "Quinary TDM2 Capture"},
0606     {"QUIN_TDM_TX_3", NULL, "Quinary TDM3 Capture"},
0607     {"QUIN_TDM_TX_4", NULL, "Quinary TDM4 Capture"},
0608     {"QUIN_TDM_TX_5", NULL, "Quinary TDM5 Capture"},
0609     {"QUIN_TDM_TX_6", NULL, "Quinary TDM6 Capture"},
0610     {"QUIN_TDM_TX_7", NULL, "Quinary TDM7 Capture"},
0611 
0612     {"TERT_MI2S_TX", NULL, "Tertiary MI2S Capture"},
0613     {"PRI_MI2S_TX", NULL, "Primary MI2S Capture"},
0614     {"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"},
0615     {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"},
0616     {"QUIN_MI2S_TX", NULL, "Quinary MI2S Capture"},
0617 
0618     {"WSA_CODEC_DMA_RX_0 Playback", NULL, "WSA_CODEC_DMA_RX_0"},
0619     {"WSA_CODEC_DMA_TX_0", NULL, "WSA_CODEC_DMA_TX_0 Capture"},
0620     {"WSA_CODEC_DMA_RX_1 Playback", NULL, "WSA_CODEC_DMA_RX_1"},
0621     {"WSA_CODEC_DMA_TX_1", NULL, "WSA_CODEC_DMA_TX_1 Capture"},
0622     {"WSA_CODEC_DMA_TX_2", NULL, "WSA_CODEC_DMA_TX_2 Capture"},
0623     {"VA_CODEC_DMA_TX_0", NULL, "VA_CODEC_DMA_TX_0 Capture"},
0624     {"VA_CODEC_DMA_TX_1", NULL, "VA_CODEC_DMA_TX_1 Capture"},
0625     {"VA_CODEC_DMA_TX_2", NULL, "VA_CODEC_DMA_TX_2 Capture"},
0626     {"RX_CODEC_DMA_RX_0 Playback", NULL, "RX_CODEC_DMA_RX_0"},
0627     {"TX_CODEC_DMA_TX_0", NULL, "TX_CODEC_DMA_TX_0 Capture"},
0628     {"RX_CODEC_DMA_RX_1 Playback", NULL, "RX_CODEC_DMA_RX_1"},
0629     {"TX_CODEC_DMA_TX_1", NULL, "TX_CODEC_DMA_TX_1 Capture"},
0630     {"RX_CODEC_DMA_RX_2 Playback", NULL, "RX_CODEC_DMA_RX_2"},
0631     {"TX_CODEC_DMA_TX_2", NULL, "TX_CODEC_DMA_TX_2 Capture"},
0632     {"RX_CODEC_DMA_RX_3 Playback", NULL, "RX_CODEC_DMA_RX_3"},
0633     {"TX_CODEC_DMA_TX_3", NULL, "TX_CODEC_DMA_TX_3 Capture"},
0634     {"RX_CODEC_DMA_RX_4 Playback", NULL, "RX_CODEC_DMA_RX_4"},
0635     {"TX_CODEC_DMA_TX_4", NULL, "TX_CODEC_DMA_TX_4 Capture"},
0636     {"RX_CODEC_DMA_RX_5 Playback", NULL, "RX_CODEC_DMA_RX_5"},
0637     {"TX_CODEC_DMA_TX_5", NULL, "TX_CODEC_DMA_TX_5 Capture"},
0638     {"RX_CODEC_DMA_RX_6 Playback", NULL, "RX_CODEC_DMA_RX_6"},
0639     {"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"},
0640 };
0641 
0642 static const struct snd_soc_dai_ops q6hdmi_ops = {
0643     .prepare    = q6afe_dai_prepare,
0644     .hw_params  = q6hdmi_hw_params,
0645     .shutdown   = q6afe_dai_shutdown,
0646 };
0647 
0648 static const struct snd_soc_dai_ops q6i2s_ops = {
0649     .prepare    = q6afe_dai_prepare,
0650     .hw_params  = q6i2s_hw_params,
0651     .set_fmt    = q6i2s_set_fmt,
0652     .shutdown   = q6afe_dai_shutdown,
0653     .set_sysclk = q6afe_mi2s_set_sysclk,
0654 };
0655 
0656 static const struct snd_soc_dai_ops q6slim_ops = {
0657     .prepare    = q6afe_dai_prepare,
0658     .hw_params  = q6slim_hw_params,
0659     .shutdown   = q6afe_dai_shutdown,
0660     .set_channel_map = q6slim_set_channel_map,
0661 };
0662 
0663 static const struct snd_soc_dai_ops q6tdm_ops = {
0664     .prepare    = q6afe_dai_prepare,
0665     .shutdown   = q6afe_dai_shutdown,
0666     .set_sysclk = q6afe_mi2s_set_sysclk,
0667     .set_tdm_slot     = q6tdm_set_tdm_slot,
0668     .set_channel_map  = q6tdm_set_channel_map,
0669     .hw_params        = q6tdm_hw_params,
0670 };
0671 
0672 static const struct snd_soc_dai_ops q6dma_ops = {
0673     .prepare    = q6afe_dai_prepare,
0674     .shutdown   = q6afe_dai_shutdown,
0675     .set_sysclk = q6afe_mi2s_set_sysclk,
0676     .set_channel_map  = q6dma_set_channel_map,
0677     .hw_params        = q6dma_hw_params,
0678 };
0679 
0680 static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai)
0681 {
0682     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0683     struct q6afe_port *port;
0684 
0685     port = q6afe_port_get_from_id(dai->dev, dai->id);
0686     if (IS_ERR(port)) {
0687         dev_err(dai->dev, "Unable to get afe port\n");
0688         return -EINVAL;
0689     }
0690     dai_data->port[dai->id] = port;
0691 
0692     return 0;
0693 }
0694 
0695 static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai)
0696 {
0697     struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev);
0698 
0699     q6afe_port_put(dai_data->port[dai->id]);
0700     dai_data->port[dai->id] = NULL;
0701 
0702     return 0;
0703 }
0704 
0705 static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = {
0706     SND_SOC_DAPM_AIF_IN("HDMI_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0707     SND_SOC_DAPM_AIF_IN("SLIMBUS_0_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0708     SND_SOC_DAPM_AIF_IN("SLIMBUS_1_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0709     SND_SOC_DAPM_AIF_IN("SLIMBUS_2_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0710     SND_SOC_DAPM_AIF_IN("SLIMBUS_3_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0711     SND_SOC_DAPM_AIF_IN("SLIMBUS_4_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0712     SND_SOC_DAPM_AIF_IN("SLIMBUS_5_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0713     SND_SOC_DAPM_AIF_IN("SLIMBUS_6_RX", NULL, 0, SND_SOC_NOPM, 0, 0),
0714     SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
0715     SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
0716     SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
0717     SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
0718     SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
0719     SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
0720     SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_TX", NULL, 0, SND_SOC_NOPM, 0, 0),
0721     SND_SOC_DAPM_AIF_IN("QUIN_MI2S_RX", NULL,
0722                         0, SND_SOC_NOPM, 0, 0),
0723     SND_SOC_DAPM_AIF_OUT("QUIN_MI2S_TX", NULL,
0724                         0, SND_SOC_NOPM, 0, 0),
0725     SND_SOC_DAPM_AIF_IN("QUAT_MI2S_RX", NULL,
0726                         0, SND_SOC_NOPM, 0, 0),
0727     SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_TX", NULL,
0728                         0, SND_SOC_NOPM, 0, 0),
0729     SND_SOC_DAPM_AIF_IN("TERT_MI2S_RX", NULL,
0730                         0, SND_SOC_NOPM, 0, 0),
0731     SND_SOC_DAPM_AIF_OUT("TERT_MI2S_TX", NULL,
0732                         0, SND_SOC_NOPM, 0, 0),
0733     SND_SOC_DAPM_AIF_IN("SEC_MI2S_RX", NULL,
0734                  0, SND_SOC_NOPM, 0, 0),
0735     SND_SOC_DAPM_AIF_OUT("SEC_MI2S_TX", NULL,
0736                         0, SND_SOC_NOPM, 0, 0),
0737     SND_SOC_DAPM_AIF_IN("SEC_MI2S_RX_SD1",
0738             "Secondary MI2S Playback SD1",
0739             0, SND_SOC_NOPM, 0, 0),
0740     SND_SOC_DAPM_AIF_IN("PRI_MI2S_RX", NULL,
0741                  0, SND_SOC_NOPM, 0, 0),
0742     SND_SOC_DAPM_AIF_OUT("PRI_MI2S_TX", NULL,
0743                         0, SND_SOC_NOPM, 0, 0),
0744 
0745     SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_0", NULL,
0746                  0, SND_SOC_NOPM, 0, 0),
0747     SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_1", NULL,
0748                  0, SND_SOC_NOPM, 0, 0),
0749     SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_2", NULL,
0750                  0, SND_SOC_NOPM, 0, 0),
0751     SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_3", NULL,
0752                  0, SND_SOC_NOPM, 0, 0),
0753     SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_4", NULL,
0754                  0, SND_SOC_NOPM, 0, 0),
0755     SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_5", NULL,
0756                  0, SND_SOC_NOPM, 0, 0),
0757     SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_6", NULL,
0758                  0, SND_SOC_NOPM, 0, 0),
0759     SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_7", NULL,
0760                  0, SND_SOC_NOPM, 0, 0),
0761     SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_0", NULL,
0762                         0, SND_SOC_NOPM, 0, 0),
0763     SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_1", NULL,
0764                         0, SND_SOC_NOPM, 0, 0),
0765     SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_2", NULL,
0766                         0, SND_SOC_NOPM, 0, 0),
0767     SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_3", NULL,
0768                         0, SND_SOC_NOPM, 0, 0),
0769     SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_4", NULL,
0770                         0, SND_SOC_NOPM, 0, 0),
0771     SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_5", NULL,
0772                         0, SND_SOC_NOPM, 0, 0),
0773     SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_6", NULL,
0774                         0, SND_SOC_NOPM, 0, 0),
0775     SND_SOC_DAPM_AIF_OUT("PRIMARY_TDM_TX_7", NULL,
0776                         0, SND_SOC_NOPM, 0, 0),
0777 
0778     SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_0", NULL,
0779                  0, SND_SOC_NOPM, 0, 0),
0780     SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_1", NULL,
0781                  0, SND_SOC_NOPM, 0, 0),
0782     SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_2", NULL,
0783                  0, SND_SOC_NOPM, 0, 0),
0784     SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_3", NULL,
0785                  0, SND_SOC_NOPM, 0, 0),
0786     SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_4", NULL,
0787                  0, SND_SOC_NOPM, 0, 0),
0788     SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_5", NULL,
0789                  0, SND_SOC_NOPM, 0, 0),
0790     SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_6", NULL,
0791                  0, SND_SOC_NOPM, 0, 0),
0792     SND_SOC_DAPM_AIF_IN("SEC_TDM_RX_7", NULL,
0793                  0, SND_SOC_NOPM, 0, 0),
0794     SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_0", NULL,
0795                         0, SND_SOC_NOPM, 0, 0),
0796     SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_1", NULL,
0797                         0, SND_SOC_NOPM, 0, 0),
0798     SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_2", NULL,
0799                         0, SND_SOC_NOPM, 0, 0),
0800     SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_3", NULL,
0801                         0, SND_SOC_NOPM, 0, 0),
0802     SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_4", NULL,
0803                         0, SND_SOC_NOPM, 0, 0),
0804     SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_5", NULL,
0805                         0, SND_SOC_NOPM, 0, 0),
0806     SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_6", NULL,
0807                         0, SND_SOC_NOPM, 0, 0),
0808     SND_SOC_DAPM_AIF_OUT("SEC_TDM_TX_7", NULL,
0809                         0, SND_SOC_NOPM, 0, 0),
0810 
0811     SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_0", NULL,
0812                  0, SND_SOC_NOPM, 0, 0),
0813     SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_1", NULL,
0814                  0, SND_SOC_NOPM, 0, 0),
0815     SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_2", NULL,
0816                  0, SND_SOC_NOPM, 0, 0),
0817     SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_3", NULL,
0818                  0, SND_SOC_NOPM, 0, 0),
0819     SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_4", NULL,
0820                  0, SND_SOC_NOPM, 0, 0),
0821     SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_5", NULL,
0822                  0, SND_SOC_NOPM, 0, 0),
0823     SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_6", NULL,
0824                  0, SND_SOC_NOPM, 0, 0),
0825     SND_SOC_DAPM_AIF_IN("TERT_TDM_RX_7", NULL,
0826                  0, SND_SOC_NOPM, 0, 0),
0827     SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_0", NULL,
0828                         0, SND_SOC_NOPM, 0, 0),
0829     SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_1", NULL,
0830                         0, SND_SOC_NOPM, 0, 0),
0831     SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_2", NULL,
0832                         0, SND_SOC_NOPM, 0, 0),
0833     SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_3", NULL,
0834                         0, SND_SOC_NOPM, 0, 0),
0835     SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_4", NULL,
0836                         0, SND_SOC_NOPM, 0, 0),
0837     SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_5", NULL,
0838                         0, SND_SOC_NOPM, 0, 0),
0839     SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_6", NULL,
0840                         0, SND_SOC_NOPM, 0, 0),
0841     SND_SOC_DAPM_AIF_OUT("TERT_TDM_TX_7", NULL,
0842                         0, SND_SOC_NOPM, 0, 0),
0843 
0844     SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_0", NULL,
0845                  0, SND_SOC_NOPM, 0, 0),
0846     SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_1", NULL,
0847                  0, SND_SOC_NOPM, 0, 0),
0848     SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_2", NULL,
0849                  0, SND_SOC_NOPM, 0, 0),
0850     SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_3", NULL,
0851                  0, SND_SOC_NOPM, 0, 0),
0852     SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_4", NULL,
0853                  0, SND_SOC_NOPM, 0, 0),
0854     SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_5", NULL,
0855                  0, SND_SOC_NOPM, 0, 0),
0856     SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_6", NULL,
0857                  0, SND_SOC_NOPM, 0, 0),
0858     SND_SOC_DAPM_AIF_IN("QUAT_TDM_RX_7", NULL,
0859                  0, SND_SOC_NOPM, 0, 0),
0860     SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_0", NULL,
0861                         0, SND_SOC_NOPM, 0, 0),
0862     SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_1", NULL,
0863                         0, SND_SOC_NOPM, 0, 0),
0864     SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_2", NULL,
0865                         0, SND_SOC_NOPM, 0, 0),
0866     SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_3", NULL,
0867                         0, SND_SOC_NOPM, 0, 0),
0868     SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_4", NULL,
0869                         0, SND_SOC_NOPM, 0, 0),
0870     SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_5", NULL,
0871                         0, SND_SOC_NOPM, 0, 0),
0872     SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_6", NULL,
0873                         0, SND_SOC_NOPM, 0, 0),
0874     SND_SOC_DAPM_AIF_OUT("QUAT_TDM_TX_7", NULL,
0875                         0, SND_SOC_NOPM, 0, 0),
0876 
0877     SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_0", NULL,
0878                  0, SND_SOC_NOPM, 0, 0),
0879     SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_1", NULL,
0880                  0, SND_SOC_NOPM, 0, 0),
0881     SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_2", NULL,
0882                  0, SND_SOC_NOPM, 0, 0),
0883     SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_3", NULL,
0884                  0, SND_SOC_NOPM, 0, 0),
0885     SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_4", NULL,
0886                  0, SND_SOC_NOPM, 0, 0),
0887     SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_5", NULL,
0888                  0, SND_SOC_NOPM, 0, 0),
0889     SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_6", NULL,
0890                  0, SND_SOC_NOPM, 0, 0),
0891     SND_SOC_DAPM_AIF_IN("QUIN_TDM_RX_7", NULL,
0892                  0, SND_SOC_NOPM, 0, 0),
0893     SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_0", NULL,
0894                         0, SND_SOC_NOPM, 0, 0),
0895     SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_1", NULL,
0896                         0, SND_SOC_NOPM, 0, 0),
0897     SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_2", NULL,
0898                         0, SND_SOC_NOPM, 0, 0),
0899     SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_3", NULL,
0900                         0, SND_SOC_NOPM, 0, 0),
0901     SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_4", NULL,
0902                         0, SND_SOC_NOPM, 0, 0),
0903     SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_5", NULL,
0904                         0, SND_SOC_NOPM, 0, 0),
0905     SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_6", NULL,
0906                         0, SND_SOC_NOPM, 0, 0),
0907     SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL,
0908                         0, SND_SOC_NOPM, 0, 0),
0909     SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, SND_SOC_NOPM, 0, 0),
0910 
0911     SND_SOC_DAPM_AIF_IN("WSA_CODEC_DMA_RX_0", "NULL",
0912         0, SND_SOC_NOPM, 0, 0),
0913     SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_0", "NULL",
0914          0, SND_SOC_NOPM, 0, 0),
0915     SND_SOC_DAPM_AIF_IN("WSA_CODEC_DMA_RX_1", "NULL",
0916         0, SND_SOC_NOPM, 0, 0),
0917     SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_1", "NULL",
0918          0, SND_SOC_NOPM, 0, 0),
0919     SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_2", "NULL",
0920          0, SND_SOC_NOPM, 0, 0),
0921     SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_0", "NULL",
0922          0, SND_SOC_NOPM, 0, 0),
0923     SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_1", "NULL",
0924          0, SND_SOC_NOPM, 0, 0),
0925     SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_2", "NULL",
0926          0, SND_SOC_NOPM, 0, 0),
0927     SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_0", "NULL",
0928         0, SND_SOC_NOPM, 0, 0),
0929     SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_0", "NULL",
0930          0, SND_SOC_NOPM, 0, 0),
0931     SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_1", "NULL",
0932         0, SND_SOC_NOPM, 0, 0),
0933     SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_1", "NULL",
0934          0, SND_SOC_NOPM, 0, 0),
0935     SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_2", "NULL",
0936         0, SND_SOC_NOPM, 0, 0),
0937     SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_2", "NULL",
0938          0, SND_SOC_NOPM, 0, 0),
0939     SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_3", "NULL",
0940         0, SND_SOC_NOPM, 0, 0),
0941     SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_3", "NULL",
0942          0, SND_SOC_NOPM, 0, 0),
0943     SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_4", "NULL",
0944         0, SND_SOC_NOPM, 0, 0),
0945     SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_4", "NULL",
0946          0, SND_SOC_NOPM, 0, 0),
0947     SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_5", "NULL",
0948         0, SND_SOC_NOPM, 0, 0),
0949     SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_5", "NULL",
0950          0, SND_SOC_NOPM, 0, 0),
0951     SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_6", "NULL",
0952         0, SND_SOC_NOPM, 0, 0),
0953     SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_7", "NULL",
0954         0, SND_SOC_NOPM, 0, 0),
0955 };
0956 
0957 static const struct snd_soc_component_driver q6afe_dai_component = {
0958     .name       = "q6afe-dai-component",
0959     .dapm_widgets = q6afe_dai_widgets,
0960     .num_dapm_widgets = ARRAY_SIZE(q6afe_dai_widgets),
0961     .dapm_routes = q6afe_dapm_routes,
0962     .num_dapm_routes = ARRAY_SIZE(q6afe_dapm_routes),
0963     .of_xlate_dai_name = q6dsp_audio_ports_of_xlate_dai_name,
0964 
0965 };
0966 
0967 static void of_q6afe_parse_dai_data(struct device *dev,
0968                     struct q6afe_dai_data *data)
0969 {
0970     struct device_node *node;
0971     int ret;
0972 
0973     for_each_child_of_node(dev->of_node, node) {
0974         unsigned int lines[Q6AFE_MAX_MI2S_LINES];
0975         struct q6afe_dai_priv_data *priv;
0976         int id, i, num_lines;
0977 
0978         ret = of_property_read_u32(node, "reg", &id);
0979         if (ret || id < 0 || id >= AFE_PORT_MAX) {
0980             dev_err(dev, "valid dai id not found:%d\n", ret);
0981             continue;
0982         }
0983 
0984         switch (id) {
0985         /* MI2S specific properties */
0986         case QUINARY_MI2S_RX ... QUINARY_MI2S_TX:
0987         case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX:
0988             priv = &data->priv[id];
0989             ret = of_property_read_variable_u32_array(node,
0990                             "qcom,sd-lines",
0991                             lines, 0,
0992                             Q6AFE_MAX_MI2S_LINES);
0993             if (ret < 0)
0994                 num_lines = 0;
0995             else
0996                 num_lines = ret;
0997 
0998             priv->sd_line_mask = 0;
0999 
1000             for (i = 0; i < num_lines; i++)
1001                 priv->sd_line_mask |= BIT(lines[i]);
1002 
1003             break;
1004         case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7:
1005             priv = &data->priv[id];
1006             ret = of_property_read_u32(node, "qcom,tdm-sync-mode",
1007                            &priv->sync_mode);
1008             if (ret) {
1009                 dev_err(dev, "No Sync mode from DT\n");
1010                 break;
1011             }
1012             ret = of_property_read_u32(node, "qcom,tdm-sync-src",
1013                            &priv->sync_src);
1014             if (ret) {
1015                 dev_err(dev, "No Sync Src from DT\n");
1016                 break;
1017             }
1018             ret = of_property_read_u32(node, "qcom,tdm-data-out",
1019                            &priv->data_out_enable);
1020             if (ret) {
1021                 dev_err(dev, "No Data out enable from DT\n");
1022                 break;
1023             }
1024             ret = of_property_read_u32(node, "qcom,tdm-invert-sync",
1025                            &priv->invert_sync);
1026             if (ret) {
1027                 dev_err(dev, "No Invert sync from DT\n");
1028                 break;
1029             }
1030             ret = of_property_read_u32(node, "qcom,tdm-data-delay",
1031                            &priv->data_delay);
1032             if (ret) {
1033                 dev_err(dev, "No Data Delay from DT\n");
1034                 break;
1035             }
1036             ret = of_property_read_u32(node, "qcom,tdm-data-align",
1037                            &priv->data_align);
1038             if (ret) {
1039                 dev_err(dev, "No Data align from DT\n");
1040                 break;
1041             }
1042             break;
1043         default:
1044             break;
1045         }
1046     }
1047 }
1048 
1049 static int q6afe_dai_dev_probe(struct platform_device *pdev)
1050 {
1051     struct q6dsp_audio_port_dai_driver_config cfg;
1052     struct snd_soc_dai_driver *dais;
1053     struct q6afe_dai_data *dai_data;
1054     struct device *dev = &pdev->dev;
1055     int num_dais;
1056 
1057     dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL);
1058     if (!dai_data)
1059         return -ENOMEM;
1060 
1061     dev_set_drvdata(dev, dai_data);
1062     of_q6afe_parse_dai_data(dev, dai_data);
1063 
1064     cfg.probe = msm_dai_q6_dai_probe;
1065     cfg.remove = msm_dai_q6_dai_remove;
1066     cfg.q6hdmi_ops = &q6hdmi_ops;
1067     cfg.q6slim_ops = &q6slim_ops;
1068     cfg.q6i2s_ops = &q6i2s_ops;
1069     cfg.q6tdm_ops = &q6tdm_ops;
1070     cfg.q6dma_ops = &q6dma_ops;
1071     dais = q6dsp_audio_ports_set_config(dev, &cfg, &num_dais);
1072 
1073     return devm_snd_soc_register_component(dev, &q6afe_dai_component, dais, num_dais);
1074 }
1075 
1076 #ifdef CONFIG_OF
1077 static const struct of_device_id q6afe_dai_device_id[] = {
1078     { .compatible = "qcom,q6afe-dais" },
1079     {},
1080 };
1081 MODULE_DEVICE_TABLE(of, q6afe_dai_device_id);
1082 #endif
1083 
1084 static struct platform_driver q6afe_dai_platform_driver = {
1085     .driver = {
1086         .name = "q6afe-dai",
1087         .of_match_table = of_match_ptr(q6afe_dai_device_id),
1088     },
1089     .probe = q6afe_dai_dev_probe,
1090 };
1091 module_platform_driver(q6afe_dai_platform_driver);
1092 
1093 MODULE_DESCRIPTION("Q6 Audio Frontend dai driver");
1094 MODULE_LICENSE("GPL v2");