diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c index c0d8614559f1..6fb61da19536 100644 --- a/asoc/msm-compress-q6-v2.c +++ b/asoc/msm-compress-q6-v2.c @@ -540,7 +540,7 @@ static int msm_compr_read_buffer(struct msm_compr_audio *prtd) __func__, ret); return ret; } - prtd->bytes_read += buffer_length; + prtd->bytes_read += buffer_length + prtd->ts_header_offset; prtd->bytes_read_offset += buffer_length + prtd->ts_header_offset; if (prtd->bytes_read_offset >= prtd->buffer_size) prtd->bytes_read_offset -= prtd->buffer_size; @@ -676,9 +676,8 @@ static void compr_event_handler(uint32_t opcode, if (prtd->ts_header_offset) { /* Update the header for received buffer */ buff_addr = prtd->buffer + prtd->byte_offset; - /* Write the length of the buffer */ - *buff_addr = prtd->codec_param.buffer.fragment_size - - prtd->ts_header_offset; + /* Write the actual length of the received buffer */ + *buff_addr = payload[4]; buff_addr++; /* Write the offset */ *buff_addr = prtd->ts_header_offset; @@ -1457,28 +1456,54 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) break; } - pr_debug("%s: stream_id %d bits_per_sample %d\n", - __func__, ac->stream_id, bits_per_sample); + pr_debug("%s: stream_id %d bits_per_sample %d compr_passthr %d\n", + __func__, ac->stream_id, bits_per_sample, + prtd->compr_passthr); - if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) { - ret = q6asm_open_read_v4(prtd->audio_client, prtd->codec, - bits_per_sample, true, enc_cfg_id); + if (prtd->compr_passthr != LEGACY_PCM) { + ret = q6asm_open_read_compressed(prtd->audio_client, + prtd->codec, prtd->compr_passthr); + if (ret < 0) { + pr_err("%s:ASM open read err[%d] for compr_type[%d]\n", + __func__, ret, prtd->compr_passthr); + return ret; + } + + ret = msm_pcm_routing_reg_phy_compr_stream( + soc_prtd->dai_link->id, + ac->perf_mode, + prtd->session_id, + SNDRV_PCM_STREAM_CAPTURE, + prtd->compr_passthr); + if (ret) { + pr_err("%s: compr stream reg failed:%d\n", + __func__, ret); + return ret; + } } else { - ret = q6asm_open_read_v4(prtd->audio_client, prtd->codec, - bits_per_sample, false, enc_cfg_id); - } - if (ret < 0) { - pr_err("%s: q6asm_open_read failed:%d\n", __func__, ret); - return ret; - } + if (prtd->codec_param.codec.flags & COMPRESSED_TIMESTAMP_FLAG) { + ret = q6asm_open_read_v4(prtd->audio_client, + prtd->codec, + bits_per_sample, true, enc_cfg_id); + } else { + ret = q6asm_open_read_v4(prtd->audio_client, + prtd->codec, + bits_per_sample, false, enc_cfg_id); + } + if (ret < 0) { + pr_err("%s: q6asm_open_read failed:%d\n", + __func__, ret); + return ret; + } - ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id, - ac->perf_mode, - prtd->session_id, - SNDRV_PCM_STREAM_CAPTURE); - if (ret) { - pr_err("%s: stream reg failed:%d\n", __func__, ret); - return ret; + ret = msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->id, + ac->perf_mode, + prtd->session_id, + SNDRV_PCM_STREAM_CAPTURE); + if (ret) { + pr_err("%s: stream reg failed:%d\n", __func__, ret); + return ret; + } } ret = q6asm_set_io_mode(ac, (COMPRESSED_STREAM_IO | ASYNC_IO_MODE)); @@ -1533,7 +1558,7 @@ static int msm_compr_configure_dsp_for_capture(struct snd_compr_stream *cstream) ret = q6asm_enc_cfg_blk_custom(prtd->audio_client, prtd->sample_rate, prtd->num_channels, prtd->codec, (void *)&prtd->codec_param.codec.options.generic); - } else { + } else if (prtd->compr_passthr == LEGACY_PCM) { ret = q6asm_enc_cfg_blk_pcm_format_support_v4(prtd->audio_client, prtd->sample_rate, prtd->num_channels, bits_per_sample, sample_word_size, diff --git a/asoc/msm-dai-q6-v2.c b/asoc/msm-dai-q6-v2.c index 2c1eea17ff4a..ec6807a7964f 100644 --- a/asoc/msm-dai-q6-v2.c +++ b/asoc/msm-dai-q6-v2.c @@ -216,7 +216,14 @@ struct msm_dai_q6_spdif_dai_data { u32 rate; u32 channels; u32 bitwidth; + u16 port_id; struct afe_spdif_port_config spdif_port; + struct afe_event_fmt_update fmt_event; +}; + +struct msm_dai_q6_spdif_event_msg { + struct afe_port_mod_evt_rsp_hdr evt_hdr; + struct afe_event_fmt_update fmt_event; }; struct msm_dai_q6_mi2s_dai_config { @@ -1398,15 +1405,89 @@ static int msm_dai_q6_spdif_format_get(struct snd_kcontrol *kcontrol, return 0; } +static int msm_dai_q6_spdif_source_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct msm_dai_q6_spdif_dai_data *dai_data = kcontrol->private_data; + int value = ucontrol->value.integer.value[0]; + + dai_data->spdif_port.cfg.src_sel = value; + pr_debug("%s: value = %d\n", __func__, value); + return 0; +} + +static int msm_dai_q6_spdif_source_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct msm_dai_q6_spdif_dai_data *dai_data = kcontrol->private_data; + + ucontrol->value.integer.value[0] = + dai_data->spdif_port.cfg.src_sel; + return 0; +} + +static int msm_dai_q6_spdif_ext_state_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct msm_dai_q6_spdif_dai_data *dai_data = kcontrol->private_data; + + ucontrol->value.integer.value[0] = + dai_data->fmt_event.status & 0x3; + return 0; +} + +static int msm_dai_q6_spdif_ext_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct msm_dai_q6_spdif_dai_data *dai_data = kcontrol->private_data; + + ucontrol->value.integer.value[0] = + dai_data->fmt_event.data_format & 0x1; + return 0; +} + +static int msm_dai_q6_spdif_ext_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct msm_dai_q6_spdif_dai_data *dai_data = kcontrol->private_data; + + ucontrol->value.integer.value[0] = + dai_data->fmt_event.sample_rate; + return 0; +} + static const char * const spdif_format[] = { "LPCM", "Compr" }; -static const struct soc_enum spdif_config_enum[] = { - SOC_ENUM_SINGLE_EXT(2, spdif_format), +static const char * const spdif_source[] = { + "Optical", "EXT-ARC", "Coaxial", "VT-ARC" }; +static const char * const spdif_state[] = { + "Inactive", "Active", "EOS" +}; + +static const struct soc_enum spdif_rx_config_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spdif_format), spdif_format), +}; + +static const struct soc_enum spdif_tx_config_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spdif_source), spdif_source), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spdif_format), spdif_format), +}; + +static const struct soc_enum spdif_tx_status_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spdif_state), spdif_state), + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spdif_format), spdif_format), + }; + static int msm_dai_q6_spdif_chstatus_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1428,7 +1509,7 @@ static int msm_dai_q6_spdif_chstatus_put(struct snd_kcontrol *kcontrol, __func__); ret = afe_send_spdif_ch_status_cfg( &dai_data->spdif_port.ch_status, - AFE_PORT_ID_SPDIF_RX); + dai_data->port_id); } return ret; } @@ -1453,7 +1534,8 @@ static int msm_dai_q6_spdif_chstatus_info(struct snd_kcontrol *kcontrol, return 0; } -static const struct snd_kcontrol_new spdif_config_controls[] = { +static const struct snd_kcontrol_new spdif_rx_config_controls[] = { + /* Primary SPDIF output */ { .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE), @@ -1463,11 +1545,76 @@ static const struct snd_kcontrol_new spdif_config_controls[] = { .get = msm_dai_q6_spdif_chstatus_get, .put = msm_dai_q6_spdif_chstatus_put, }, - SOC_ENUM_EXT("SPDIF RX Format", spdif_config_enum[0], + SOC_ENUM_EXT("PRI SPDIF RX Format", spdif_rx_config_enum[0], + msm_dai_q6_spdif_format_get, + msm_dai_q6_spdif_format_put), + /* Secondary SPDIF output */ + { + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_INACTIVE), + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("SEC", PLAYBACK, PCM_STREAM), + .info = msm_dai_q6_spdif_chstatus_info, + .get = msm_dai_q6_spdif_chstatus_get, + .put = msm_dai_q6_spdif_chstatus_put, + }, + SOC_ENUM_EXT("SEC SPDIF RX Format", spdif_rx_config_enum[0], msm_dai_q6_spdif_format_get, msm_dai_q6_spdif_format_put) }; +static const struct snd_kcontrol_new spdif_tx_config_controls[] = { + SOC_ENUM_EXT("PRI SPDIF TX Source", spdif_tx_config_enum[0], + msm_dai_q6_spdif_source_get, + msm_dai_q6_spdif_source_put), + SOC_ENUM_EXT("PRI SPDIF TX Format", spdif_tx_config_enum[1], + msm_dai_q6_spdif_format_get, + msm_dai_q6_spdif_format_put), + SOC_ENUM_EXT("SEC SPDIF TX Source", spdif_tx_config_enum[0], + msm_dai_q6_spdif_source_get, + msm_dai_q6_spdif_source_put), + SOC_ENUM_EXT("SEC SPDIF TX Format", spdif_tx_config_enum[1], + msm_dai_q6_spdif_format_get, + msm_dai_q6_spdif_format_put) +}; + +static const struct snd_kcontrol_new spdif_tx_status_controls[] = { + SOC_ENUM_EXT("PRI SPDIF TX EXT State", spdif_tx_status_enum[0], + msm_dai_q6_spdif_ext_state_get, NULL), + SOC_ENUM_EXT("PRI SPDIF TX EXT Format", spdif_tx_status_enum[1], + msm_dai_q6_spdif_ext_format_get, NULL), + SOC_SINGLE_EXT("PRI SPDIF TX EXT Rate", 0, 0, 192000, 0, + msm_dai_q6_spdif_ext_rate_get, NULL), + SOC_ENUM_EXT("SEC SPDIF TX EXT State", spdif_tx_status_enum[0], + msm_dai_q6_spdif_ext_state_get, NULL), + SOC_ENUM_EXT("SEC SPDIF TX EXT Format", spdif_tx_status_enum[1], + msm_dai_q6_spdif_ext_format_get, NULL), + SOC_SINGLE_EXT("SEC SPDIF TX EXT Rate", 0, 0, 192000, 0, + msm_dai_q6_spdif_ext_rate_get, NULL) +}; + +static void msm_dai_q6_spdif_process_event(uint32_t opcode, uint32_t token, + uint32_t *payload, void *private_data) +{ + struct msm_dai_q6_spdif_event_msg *evt; + struct msm_dai_q6_spdif_dai_data *dai_data; + + evt = (struct msm_dai_q6_spdif_event_msg *)payload; + dai_data = (struct msm_dai_q6_spdif_dai_data *)private_data; + + pr_debug("%s: old state %d, fmt %d, rate %d\n", + __func__, dai_data->fmt_event.status, + dai_data->fmt_event.data_format, + dai_data->fmt_event.sample_rate); + pr_debug("%s: new state %d, fmt %d, rate %d\n", + __func__, evt->fmt_event.status, + evt->fmt_event.data_format, + evt->fmt_event.sample_rate); + + dai_data->fmt_event.status = evt->fmt_event.status; + dai_data->fmt_event.data_format = evt->fmt_event.data_format; + dai_data->fmt_event.sample_rate = evt->fmt_event.sample_rate; +} static int msm_dai_q6_spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, @@ -1475,7 +1622,6 @@ static int msm_dai_q6_spdif_hw_params(struct snd_pcm_substream *substream, { struct msm_dai_q6_spdif_dai_data *dai_data = dev_get_drvdata(dai->dev); - dai->id = AFE_PORT_ID_SPDIF_RX; dai_data->channels = params_channels(params); dai_data->spdif_port.cfg.num_channels = dai_data->channels; switch (params_format(params)) { @@ -1496,7 +1642,7 @@ static int msm_dai_q6_spdif_hw_params(struct snd_pcm_substream *substream, dai_data->bitwidth = dai_data->spdif_port.cfg.bit_width; dai_data->spdif_port.cfg.sample_rate = dai_data->rate; dai_data->spdif_port.cfg.spdif_cfg_minor_version = - AFE_API_VERSION_SPDIF_CONFIG; + AFE_API_VERSION_SPDIF_CONFIG_V2; dev_dbg(dai->dev, " channel %d sample rate %d bit width %d\n", dai_data->channels, dai_data->rate, dai_data->spdif_port.cfg.bit_width); @@ -1520,13 +1666,14 @@ static void msm_dai_q6_spdif_shutdown(struct snd_pcm_substream *substream, if (rc < 0) dev_err(dai->dev, "fail to close AFE port\n"); + dai_data->fmt_event.status = 0; /* report invalid line state */ + pr_debug("%s: dai_data->status_mask = %ld\n", __func__, *dai_data->status_mask); clear_bit(STATUS_PORT_STARTED, dai_data->status_mask); } - static int msm_dai_q6_spdif_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -1534,6 +1681,15 @@ static int msm_dai_q6_spdif_prepare(struct snd_pcm_substream *substream, int rc = 0; if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { + rc = afe_spdif_reg_event_cfg(dai->id, + AFE_MODULE_REGISTER_EVENT_FLAG, + msm_dai_q6_spdif_process_event, + dai_data); + if (rc < 0) + dev_err(dai->dev, + "fail to register event for port 0x%x\n", + dai->id); + rc = afe_spdif_port_start(dai->id, &dai_data->spdif_port, dai_data->rate); if (rc < 0) @@ -1550,7 +1706,6 @@ static int msm_dai_q6_spdif_prepare(struct snd_pcm_substream *substream, static int msm_dai_q6_spdif_dai_probe(struct snd_soc_dai *dai) { struct msm_dai_q6_spdif_dai_data *dai_data; - const struct snd_kcontrol_new *kcontrol; int rc = 0; struct snd_soc_dapm_route intercon; struct snd_soc_dapm_context *dapm; @@ -1563,17 +1718,67 @@ static int msm_dai_q6_spdif_dai_probe(struct snd_soc_dai *dai) GFP_KERNEL); if (!dai_data) { - dev_err(dai->dev, "DAI-%d: fail to allocate dai data\n", - AFE_PORT_ID_SPDIF_RX); rc = -ENOMEM; } else dev_set_drvdata(dai->dev, dai_data); - kcontrol = &spdif_config_controls[1]; - dapm = snd_soc_component_get_dapm(dai->component); + dai->id = dai->driver->id; + dai_data->port_id = dai->id; - rc = snd_ctl_add(dai->component->card->snd_card, - snd_ctl_new1(kcontrol, dai_data)); + switch (dai->id) { + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_rx_config_controls[1], + dai_data)); + break; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_rx_config_controls[3], + dai_data)); + break; + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_config_controls[0], + dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_config_controls[1], + dai_data)); + + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_status_controls[0], + dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_status_controls[1], + dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_status_controls[2], + dai_data)); + break; + case AFE_PORT_ID_SECONDARY_SPDIF_TX: + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_config_controls[2], + dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_config_controls[3], + dai_data)); + + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_status_controls[3], + dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_status_controls[4], + dai_data)); + rc = snd_ctl_add(dai->component->card->snd_card, + snd_ctl_new1(&spdif_tx_status_controls[5], + dai_data)); + break; + } + if (rc < 0) + dev_err(dai->dev, + "%s: err add config ctl, DAI = %s\n", + __func__, dai->name); + + dapm = snd_soc_component_get_dapm(dai->component); memset(&intercon, 0, sizeof(intercon)); if (!rc && dai && dai->driver) { @@ -1610,6 +1815,15 @@ static int msm_dai_q6_spdif_dai_remove(struct snd_soc_dai *dai) /* If AFE port is still up, close it */ if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) { + rc = afe_spdif_reg_event_cfg(dai->id, + AFE_MODULE_DEREGISTER_EVENT_FLAG, + NULL, + dai_data); + if (rc < 0) + dev_err(dai->dev, + "fail to deregister event for port 0x%x\n", + dai->id); + rc = afe_close(dai->id); /* can block */ if (rc < 0) dev_err(dai->dev, "fail to close AFE port\n"); @@ -1628,21 +1842,106 @@ static struct snd_soc_dai_ops msm_dai_q6_spdif_ops = { .shutdown = msm_dai_q6_spdif_shutdown, }; -static struct snd_soc_dai_driver msm_dai_q6_spdif_spdif_rx_dai = { - .playback = { - .stream_name = "SPDIF Playback", - .aif_name = "SPDIF_RX", - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | - SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .channels_min = 1, - .channels_max = 4, - .rate_min = 8000, - .rate_max = 48000, +static struct snd_soc_dai_driver msm_dai_q6_spdif_spdif_rx_dai[] = { + { + .playback = { + .stream_name = "Primary SPDIF Playback", + .aif_name = "PRI_SPDIF_RX", + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 32000, + .rate_max = 192000, + }, + .name = "PRI_SPDIF_RX", + .ops = &msm_dai_q6_spdif_ops, + .id = AFE_PORT_ID_PRIMARY_SPDIF_RX, + .probe = msm_dai_q6_spdif_dai_probe, + .remove = msm_dai_q6_spdif_dai_remove, + }, + { + .playback = { + .stream_name = "Secondary SPDIF Playback", + .aif_name = "SEC_SPDIF_RX", + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 32000, + .rate_max = 192000, + }, + .name = "SEC_SPDIF_RX", + .ops = &msm_dai_q6_spdif_ops, + .id = AFE_PORT_ID_SECONDARY_SPDIF_RX, + .probe = msm_dai_q6_spdif_dai_probe, + .remove = msm_dai_q6_spdif_dai_remove, + }, +}; + +static struct snd_soc_dai_driver msm_dai_q6_spdif_spdif_tx_dai[] = { + { + .capture = { + .stream_name = "Primary SPDIF Capture", + .aif_name = "PRI_SPDIF_TX", + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 32000, + .rate_max = 192000, + }, + .name = "PRI_SPDIF_TX", + .ops = &msm_dai_q6_spdif_ops, + .id = AFE_PORT_ID_PRIMARY_SPDIF_TX, + .probe = msm_dai_q6_spdif_dai_probe, + .remove = msm_dai_q6_spdif_dai_remove, + }, + { + .capture = { + .stream_name = "Secondary SPDIF Capture", + .aif_name = "SEC_SPDIF_TX", + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 32000, + .rate_max = 192000, + }, + .name = "SEC_SPDIF_TX", + .ops = &msm_dai_q6_spdif_ops, + .id = AFE_PORT_ID_SECONDARY_SPDIF_TX, + .probe = msm_dai_q6_spdif_dai_probe, + .remove = msm_dai_q6_spdif_dai_remove, }, - .ops = &msm_dai_q6_spdif_ops, - .probe = msm_dai_q6_spdif_dai_probe, - .remove = msm_dai_q6_spdif_dai_remove, }; static const struct snd_soc_component_driver msm_dai_spdif_q6_component = { @@ -5471,16 +5770,48 @@ static struct platform_driver msm_dai_q6_mi2s_driver = { static int msm_dai_q6_spdif_dev_probe(struct platform_device *pdev) { - int rc; + int rc, id; + const char *q6_dev_id = "qcom,msm-dai-q6-dev-id"; - pdev->id = AFE_PORT_ID_SPDIF_RX; + rc = of_property_read_u32(pdev->dev.of_node, q6_dev_id, &id); + if (rc) { + dev_err(&pdev->dev, + "%s: missing %s in dt node\n", __func__, q6_dev_id); + return rc; + } + + pdev->id = id; pr_debug("%s: dev name %s, id:%d\n", __func__, dev_name(&pdev->dev), pdev->id); - rc = snd_soc_register_component(&pdev->dev, + switch (pdev->id) { + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + rc = snd_soc_register_component(&pdev->dev, &msm_dai_spdif_q6_component, - &msm_dai_q6_spdif_spdif_rx_dai, 1); + &msm_dai_q6_spdif_spdif_rx_dai[0], 1); + break; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + rc = snd_soc_register_component(&pdev->dev, + &msm_dai_spdif_q6_component, + &msm_dai_q6_spdif_spdif_rx_dai[1], 1); + break; + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + rc = snd_soc_register_component(&pdev->dev, + &msm_dai_spdif_q6_component, + &msm_dai_q6_spdif_spdif_tx_dai[0], 1); + break; + case AFE_PORT_ID_SECONDARY_SPDIF_TX: + rc = snd_soc_register_component(&pdev->dev, + &msm_dai_spdif_q6_component, + &msm_dai_q6_spdif_spdif_tx_dai[1], 1); + break; + default: + dev_err(&pdev->dev, "invalid device ID %d\n", pdev->id); + rc = -ENODEV; + break; + } + return rc; } diff --git a/asoc/msm-pcm-routing-v2.c b/asoc/msm-pcm-routing-v2.c index bda838718855..7ad7460368a8 100644 --- a/asoc/msm-pcm-routing-v2.c +++ b/asoc/msm-pcm-routing-v2.c @@ -368,8 +368,8 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = { LPASS_BE_SEC_AUXPCM_RX}, { AFE_PORT_ID_SECONDARY_PCM_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SEC_AUXPCM_TX}, - { AFE_PORT_ID_SPDIF_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, - LPASS_BE_SPDIF_RX}, + { AFE_PORT_ID_PRIMARY_SPDIF_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, + LPASS_BE_PRI_SPDIF_RX}, { AFE_PORT_ID_SECONDARY_MI2S_RX_SD1, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_SEC_MI2S_RX_SD1}, { AFE_PORT_ID_QUINARY_MI2S_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, @@ -602,6 +602,12 @@ struct msm_pcm_routing_bdai_data msm_bedais[MSM_BACKEND_DAI_MAX] = { LPASS_BE_VA_CDC_DMA_TX_0}, { AFE_PORT_ID_VA_CODEC_DMA_TX_1, 0, {0}, {0}, 0, 0, 0, 0, {0}, LPASS_BE_VA_CDC_DMA_TX_1}, + { AFE_PORT_ID_PRIMARY_SPDIF_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, + LPASS_BE_PRI_SPDIF_TX}, + { AFE_PORT_ID_SECONDARY_SPDIF_RX, 0, {0}, {0}, 0, 0, 0, 0, {0}, + LPASS_BE_SEC_SPDIF_RX}, + { AFE_PORT_ID_SECONDARY_SPDIF_TX, 0, {0}, {0}, 0, 0, 0, 0, {0}, + LPASS_BE_SEC_SPDIF_TX}, }; /* Track ASM playback & capture sessions of DAI @@ -1337,7 +1343,9 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode, i); if ((passthr_mode == COMPRESSED_PASSTHROUGH_DSD) || (passthr_mode == - COMPRESSED_PASSTHROUGH_GEN)) + COMPRESSED_PASSTHROUGH_GEN) + || (passthr_mode == + COMPRESSED_PASSTHROUGH_IEC61937)) topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY; pr_debug("%s: Before adm open topology %d\n", __func__, topology); @@ -1389,12 +1397,12 @@ int msm_pcm_routing_reg_phy_compr_stream(int fe_id, int perf_mode, } } if (passthr_mode != COMPRESSED_PASSTHROUGH_DSD + && passthr_mode != COMPRESSED_PASSTHROUGH_GEN && passthr_mode != - COMPRESSED_PASSTHROUGH_GEN) { + COMPRESSED_PASSTHROUGH_IEC61937) msm_routing_send_device_pp_params( - msm_bedais[i].port_id, - copp_idx, fe_id); - } + msm_bedais[i].port_id, + copp_idx, fe_id); } } if (num_copps) { @@ -1758,7 +1766,7 @@ static void msm_pcm_routing_process_audio(u16 reg, u16 val, int set) path_type = ADM_PATH_PLAYBACK; } else { session_type = SESSION_TYPE_TX; - if (passthr_mode != LEGACY_PCM) + if ((passthr_mode != LEGACY_PCM) && (passthr_mode != LISTEN)) path_type = ADM_PATH_COMPRESSED_TX; else path_type = ADM_PATH_LIVE_REC; @@ -2999,7 +3007,7 @@ static const char *const be_name[] = { "SLIM_8_TX", "EXTPROC_RX", "EXTPROC_TX", "EXPROC_EC_TX", "QUAT_MI2S_RX", "QUAT_MI2S_TX", "SECOND_MI2S_RX", "SECOND_MI2S_TX", "PRI_MI2S_RX", "PRI_MI2S_TX", "TERT_MI2S_RX", "TERT_MI2S_TX", -"AUDIO_I2S_RX", "SEC_AUXPCM_RX", "SEC_AUXPCM_TX", "SPDIF_RX", +"AUDIO_I2S_RX", "SEC_AUXPCM_RX", "SEC_AUXPCM_TX", "PRI_SPDIF_RX", "SECOND_MI2S_RX_SD1", "QUIN_MI2S_RX", "QUIN_MI2S_TX", "SENARY_MI2S_TX", "PRI_TDM_RX_0", "PRI_TDM_TX_0", "PRI_TDM_RX_1", "PRI_TDM_TX_1", "PRI_TDM_RX_2", "PRI_TDM_TX_2", "PRI_TDM_RX_3", "PRI_TDM_TX_3", @@ -3029,7 +3037,8 @@ static const char *const be_name[] = { "INT4_MI2S_RX", "INT4_MI2S_TX", "INT5_MI2S_RX", "INT5_MI2S_TX", "INT6_MI2S_RX", "INT6_MI2S_TX", "WSA_CDC_DMA_RX_0", "WSA_CDC_DMA_TX_0", "WSA_CDC_DMA_RX_1", "WSA_CDC_DMA_TX_1", -"WSA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_1" +"WSA_CDC_DMA_TX_2", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_1", +"PRI_SPDIF_TX", "SEC_SPDIF_RX", "SEC_SPDIF_TX" }; static SOC_ENUM_SINGLE_DECL(mm1_channel_mux, @@ -4206,89 +4215,176 @@ static const struct snd_kcontrol_new sec_i2s_rx_mixer_controls[] = { msm_routing_put_audio_mixer), }; -static const struct snd_kcontrol_new spdif_rx_mixer_controls[] = { +static const struct snd_kcontrol_new pri_spdif_rx_mixer_controls[] = { SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new sec_spdif_rx_mixer_controls[] = { + SOC_DOUBLE_EXT("MultiMedia1", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia2", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia3", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia4", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia5", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia6", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia7", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia8", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia9", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia10", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia11", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA11, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia12", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA12, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia13", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA13, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia14", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA14, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia15", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA15, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia16", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia17", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia18", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia19", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia28", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("MultiMedia29", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_RX, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), }; @@ -8482,6 +8578,14 @@ static const struct snd_kcontrol_new mmul1_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul2_mixer_controls[] = { @@ -8641,6 +8745,14 @@ static const struct snd_kcontrol_new mmul2_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul3_mixer_controls[] = { @@ -8800,6 +8912,14 @@ static const struct snd_kcontrol_new mmul3_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul4_mixer_controls[] = { @@ -8955,6 +9075,14 @@ static const struct snd_kcontrol_new mmul4_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul5_mixer_controls[] = { @@ -9134,6 +9262,14 @@ static const struct snd_kcontrol_new mmul5_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul6_mixer_controls[] = { @@ -9293,6 +9429,14 @@ static const struct snd_kcontrol_new mmul6_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul8_mixer_controls[] = { @@ -9456,6 +9600,14 @@ static const struct snd_kcontrol_new mmul8_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul16_mixer_controls[] = { @@ -9619,6 +9771,14 @@ static const struct snd_kcontrol_new mmul16_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA16, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul9_mixer_controls[] = { @@ -9722,6 +9882,14 @@ static const struct snd_kcontrol_new mmul9_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA9, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul10_mixer_controls[] = { @@ -9849,6 +10017,14 @@ static const struct snd_kcontrol_new mmul10_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA10, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul17_mixer_controls[] = { SOC_DOUBLE_EXT("SLIM_0_TX", SND_SOC_NOPM, @@ -9911,6 +10087,14 @@ static const struct snd_kcontrol_new mmul17_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA17, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul18_mixer_controls[] = { @@ -9926,6 +10110,10 @@ static const struct snd_kcontrol_new mmul18_mixer_controls[] = { MSM_BACKEND_DAI_INT3_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_MI2S_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), SOC_DOUBLE_EXT("TERT_MI2S_TX", SND_SOC_NOPM, MSM_BACKEND_DAI_TERTIARY_MI2S_TX, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, @@ -9974,6 +10162,14 @@ static const struct snd_kcontrol_new mmul18_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA18, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul19_mixer_controls[] = { @@ -10037,6 +10233,14 @@ static const struct snd_kcontrol_new mmul19_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA19, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul20_mixer_controls[] = { @@ -10160,6 +10364,14 @@ static const struct snd_kcontrol_new mmul20_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA20, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul28_mixer_controls[] = { @@ -10223,6 +10435,14 @@ static const struct snd_kcontrol_new mmul28_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA28, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new mmul29_mixer_controls[] = { @@ -10286,6 +10506,14 @@ static const struct snd_kcontrol_new mmul29_mixer_controls[] = { MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("PRI_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_DOUBLE_EXT("SEC_SPDIF_TX", SND_SOC_NOPM, + MSM_BACKEND_DAI_SEC_SPDIF_TX, + MSM_FRONTEND_DAI_MULTIMEDIA29, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), }; static const struct snd_kcontrol_new pri_rx_voice_mixer_controls[] = { @@ -16125,7 +16353,14 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_AIF_OUT("PRI_I2S_RX", "Primary I2S Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("SEC_I2S_RX", "Secondary I2S Playback", 0, 0, 0, 0), - SND_SOC_DAPM_AIF_OUT("SPDIF_RX", "SPDIF Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("PRI_SPDIF_RX", "Primary SPDIF Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("PRI_SPDIF_TX", "Primary SPDIF Capture", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SEC_SPDIF_RX", "Secondary SPDIF Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("SEC_SPDIF_TX", "Secondary SPDIF Capture", + 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_RX", "Slimbus2 Playback", 0, 0, 0, 0), SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0), @@ -16495,8 +16730,10 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { display_port_mixer_controls, ARRAY_SIZE(display_port_mixer_controls)), SND_SOC_DAPM_MIXER("DISPLAY_PORT1 Mixer", SND_SOC_NOPM, 0, 0, display_port1_mixer_controls, ARRAY_SIZE(display_port1_mixer_controls)), - SND_SOC_DAPM_MIXER("SPDIF_RX Audio Mixer", SND_SOC_NOPM, 0, 0, - spdif_rx_mixer_controls, ARRAY_SIZE(spdif_rx_mixer_controls)), + SND_SOC_DAPM_MIXER("PRI_SPDIF_RX Audio Mixer", SND_SOC_NOPM, 0, 0, + pri_spdif_rx_mixer_controls, ARRAY_SIZE(pri_spdif_rx_mixer_controls)), + SND_SOC_DAPM_MIXER("SEC_SPDIF_RX Audio Mixer", SND_SOC_NOPM, 0, 0, + sec_spdif_rx_mixer_controls, ARRAY_SIZE(sec_spdif_rx_mixer_controls)), SND_SOC_DAPM_MIXER("MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, mi2s_rx_mixer_controls, ARRAY_SIZE(mi2s_rx_mixer_controls)), SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, @@ -17184,23 +17421,41 @@ static const struct snd_soc_dapm_route intercon[] = { {"DISPLAY_PORT1 Mixer", "MultiMedia16", "MM_DL16"}, {"DISPLAY_PORT1", NULL, "DISPLAY_PORT1 Mixer"}, - {"SPDIF_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, - {"SPDIF_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, - {"SPDIF_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, - {"SPDIF_RX Audio Mixer", "MultiMedia4", "MM_DL4"}, - {"SPDIF_RX Audio Mixer", "MultiMedia5", "MM_DL5"}, - {"SPDIF_RX Audio Mixer", "MultiMedia6", "MM_DL6"}, - {"SPDIF_RX Audio Mixer", "MultiMedia7", "MM_DL7"}, - {"SPDIF_RX Audio Mixer", "MultiMedia8", "MM_DL8"}, - {"SPDIF_RX Audio Mixer", "MultiMedia9", "MM_DL9"}, - {"SPDIF_RX Audio Mixer", "MultiMedia10", "MM_DL10"}, - {"SPDIF_RX Audio Mixer", "MultiMedia11", "MM_DL11"}, - {"SPDIF_RX Audio Mixer", "MultiMedia12", "MM_DL12"}, - {"SPDIF_RX Audio Mixer", "MultiMedia13", "MM_DL13"}, - {"SPDIF_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, - {"SPDIF_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, - {"SPDIF_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, - {"SPDIF_RX", NULL, "SPDIF_RX Audio Mixer"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia4", "MM_DL4"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia5", "MM_DL5"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia6", "MM_DL6"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia7", "MM_DL7"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia8", "MM_DL8"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia9", "MM_DL9"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia10", "MM_DL10"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia11", "MM_DL11"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia12", "MM_DL12"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia13", "MM_DL13"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, + {"PRI_SPDIF_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"PRI_SPDIF_RX", NULL, "PRI_SPDIF_RX Audio Mixer"}, + + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia4", "MM_DL4"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia5", "MM_DL5"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia6", "MM_DL6"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia7", "MM_DL7"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia8", "MM_DL8"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia9", "MM_DL9"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia10", "MM_DL10"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia11", "MM_DL11"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia12", "MM_DL12"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia13", "MM_DL13"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia14", "MM_DL14"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia15", "MM_DL15"}, + {"SEC_SPDIF_RX Audio Mixer", "MultiMedia16", "MM_DL16"}, + {"SEC_SPDIF_RX", NULL, "SEC_SPDIF_RX Audio Mixer"}, /* incall */ {"Incall_Music Audio Mixer", "MultiMedia1", "MM_DL1"}, @@ -17300,6 +17555,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia28 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia29 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia18 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, {"MultiMedia17 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"MultiMedia18 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, {"MultiMedia19 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, @@ -17318,6 +17574,9 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia5 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"}, {"MultiMedia5 Mixer", "SLIM_8_TX", "SLIMBUS_8_TX"}, {"MultiMedia10 Mixer", "SLIM_7_TX", "SLIMBUS_7_TX"}, + {"MultiMedia18 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia18 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, + {"MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, {"MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, @@ -18036,6 +18295,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia1 Mixer", "WSA_CDC_DMA_TX_2", "WSA_CDC_DMA_TX_2"}, {"MultiMedia1 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia1 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia1 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia1 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"MultiMedia2 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, {"MultiMedia2 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, @@ -18062,6 +18323,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia2 Mixer", "WSA_CDC_DMA_TX_2", "WSA_CDC_DMA_TX_2"}, {"MultiMedia2 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia2 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia2 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia2 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"MultiMedia3 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, {"MultiMedia3 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, @@ -18088,6 +18351,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia3 Mixer", "WSA_CDC_DMA_TX_2", "WSA_CDC_DMA_TX_2"}, {"MultiMedia3 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia3 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia3 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia3 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"MultiMedia4 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, {"MultiMedia4 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, @@ -18114,6 +18379,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia4 Mixer", "WSA_CDC_DMA_TX_2", "WSA_CDC_DMA_TX_2"}, {"MultiMedia4 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia4 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia4 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia4 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"MultiMedia5 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, {"MultiMedia5 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, @@ -18140,6 +18407,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia5 Mixer", "WSA_CDC_DMA_TX_2", "WSA_CDC_DMA_TX_2"}, {"MultiMedia5 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia5 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia5 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia5 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"MultiMedia6 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, {"MultiMedia6 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, @@ -18166,6 +18435,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia6 Mixer", "WSA_CDC_DMA_TX_2", "WSA_CDC_DMA_TX_2"}, {"MultiMedia6 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia6 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia6 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia6 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"MultiMedia8 Mixer", "PRI_TDM_TX_0", "PRI_TDM_TX_0"}, {"MultiMedia8 Mixer", "PRI_TDM_TX_1", "PRI_TDM_TX_1"}, @@ -18193,6 +18464,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia8 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia8 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, {"MultiMedia8 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia8 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia8 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"MultiMedia9 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, {"MultiMedia9 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, @@ -18212,6 +18485,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia9 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia9 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, {"MultiMedia9 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia9 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia9 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"MultiMedia10 Mixer", "TERT_TDM_TX_0", "TERT_TDM_TX_0"}, {"MultiMedia10 Mixer", "TERT_TDM_TX_1", "TERT_TDM_TX_1"}, @@ -18252,6 +18527,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia20 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia20 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, {"MultiMedia20 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia20 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia20 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"MultiMedia1 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, {"MultiMedia2 Mixer", "USB_AUDIO_TX", "USB_AUDIO_TX"}, @@ -18284,6 +18561,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"MultiMedia16 Mixer", "VA_CDC_DMA_TX_0", "VA_CDC_DMA_TX_0"}, {"MultiMedia16 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, {"MultiMedia16 Mixer", "VA_CDC_DMA_TX_1", "VA_CDC_DMA_TX_1"}, + {"MultiMedia16 Mixer", "PRI_SPDIF_TX", "PRI_SPDIF_TX"}, + {"MultiMedia16 Mixer", "SEC_SPDIF_TX", "SEC_SPDIF_TX"}, {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, {"INTERNAL_BT_SCO_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, @@ -19768,7 +20047,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"BE_OUT", NULL, "HDMI"}, {"BE_OUT", NULL, "DISPLAY_PORT"}, {"BE_OUT", NULL, "DISPLAY_PORT1"}, - {"BE_OUT", NULL, "SPDIF_RX"}, + {"BE_OUT", NULL, "PRI_SPDIF_RX"}, + {"BE_OUT", NULL, "SEC_SPDIF_RX"}, {"BE_OUT", NULL, "MI2S_RX"}, {"BE_OUT", NULL, "QUAT_MI2S_RX"}, {"BE_OUT", NULL, "QUIN_MI2S_RX"}, @@ -19897,6 +20177,8 @@ static const struct snd_soc_dapm_route intercon[] = { {"WSA_CDC_DMA_TX_2", NULL, "BE_IN"}, {"VA_CDC_DMA_TX_0", NULL, "BE_IN"}, {"VA_CDC_DMA_TX_1", NULL, "BE_IN"}, + {"PRI_SPDIF_TX", NULL, "BE_IN"}, + {"SEC_SPDIF_TX", NULL, "BE_IN"}, }; @@ -20036,7 +20318,11 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream) path_type = ADM_PATH_PLAYBACK; session_type = SESSION_TYPE_RX; } else { - path_type = ADM_PATH_LIVE_REC; + if ((bedai->passthr_mode[i] != LEGACY_PCM) && + (bedai->passthr_mode[i] != LISTEN)) + path_type = ADM_PATH_COMPRESSED_TX; + else + path_type = ADM_PATH_LIVE_REC; session_type = SESSION_TYPE_TX; } @@ -20094,6 +20380,15 @@ static int msm_pcm_routing_prepare(struct snd_pcm_substream *substream) fe_dai_app_type_cfg[i][session_type][be_id].acdb_dev_id; topology = msm_routing_get_adm_topology(i, session_type, be_id); + + if ((bedai->passthr_mode[i] == + COMPRESSED_PASSTHROUGH_DSD) + || (bedai->passthr_mode[i] == + COMPRESSED_PASSTHROUGH_GEN) + || (bedai->passthr_mode[i] == + COMPRESSED_PASSTHROUGH_IEC61937)) + topology = COMPRESSED_PASSTHROUGH_NONE_TOPOLOGY; + copp_idx = adm_open(bedai->port_id, path_type, sample_rate, channels, topology, fdai->perf_mode, bits_per_sample, diff --git a/asoc/msm-pcm-routing-v2.h b/asoc/msm-pcm-routing-v2.h index b8006bc13e6c..2a786af79eb1 100644 --- a/asoc/msm-pcm-routing-v2.h +++ b/asoc/msm-pcm-routing-v2.h @@ -48,7 +48,10 @@ #define LPASS_BE_INCALL_RECORD_RX "INCALL_RECORD_RX" #define LPASS_BE_INCALL_RECORD_TX "INCALL_RECORD_TX" #define LPASS_BE_SEC_I2S_RX "SECONDARY_I2S_RX" -#define LPASS_BE_SPDIF_RX "SPDIF_RX" +#define LPASS_BE_PRI_SPDIF_RX "PRI_SPDIF_RX" +#define LPASS_BE_PRI_SPDIF_TX "PRI_SPDIF_TX" +#define LPASS_BE_SEC_SPDIF_RX "SEC_SPDIF_RX" +#define LPASS_BE_SEC_SPDIF_TX "SEC_SPDIF_TX" #define LPASS_BE_MI2S_RX "MI2S_RX" #define LPASS_BE_MI2S_TX "MI2S_TX" @@ -299,7 +302,7 @@ enum { MSM_BACKEND_DAI_AUDIO_I2S_RX, MSM_BACKEND_DAI_SEC_AUXPCM_RX, MSM_BACKEND_DAI_SEC_AUXPCM_TX, - MSM_BACKEND_DAI_SPDIF_RX, + MSM_BACKEND_DAI_PRI_SPDIF_RX, MSM_BACKEND_DAI_SECONDARY_MI2S_RX_SD1, MSM_BACKEND_DAI_QUINARY_MI2S_RX, MSM_BACKEND_DAI_QUINARY_MI2S_TX, @@ -416,6 +419,9 @@ enum { MSM_BACKEND_DAI_WSA_CDC_DMA_TX_2, MSM_BACKEND_DAI_VA_CDC_DMA_TX_0, MSM_BACKEND_DAI_VA_CDC_DMA_TX_1, + MSM_BACKEND_DAI_PRI_SPDIF_TX, + MSM_BACKEND_DAI_SEC_SPDIF_RX, + MSM_BACKEND_DAI_SEC_SPDIF_TX, MSM_BACKEND_DAI_MAX, }; diff --git a/asoc/qcs405.c b/asoc/qcs405.c index be9ed2f0066a..a74bfe3efd43 100644 --- a/asoc/qcs405.c +++ b/asoc/qcs405.c @@ -61,6 +61,10 @@ #define SAMPLING_RATE_352P8KHZ 352800 #define SAMPLING_RATE_384KHZ 384000 +#define SPDIF_TX_CORE_CLK_204_P8_MHZ 204800000 +#define TLMM_EAST_SPARE 0x07BA0000 +#define TLMM_SPDIF_HDMI_ARC_CTL 0x07BA2000 + #define WSA8810_NAME_1 "wsa881x.20170211" #define WSA8810_NAME_2 "wsa881x.20170212" #define WCN_CDC_SLIM_RX_CH_MAX 2 @@ -128,6 +132,18 @@ enum { CDC_DMA_TX_MAX, }; +enum { + PRIM_SPDIF_RX = 0, + SEC_SPDIF_RX, + SPDIF_RX_MAX, +}; + +enum { + PRIM_SPDIF_TX = 0, + SEC_SPDIF_TX, + SPDIF_TX_MAX, +}; + struct mi2s_conf { struct mutex lock; u32 ref_cnt; @@ -396,6 +412,17 @@ static struct dev_config mi2s_rx_cfg[] = { [QUIN_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, }; +/* Default configuration of SPDIF channels */ +static struct dev_config spdif_rx_cfg[] = { + [PRIM_SPDIF_RX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [SEC_SPDIF_RX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + +static struct dev_config spdif_tx_cfg[] = { + [PRIM_SPDIF_TX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, + [SEC_SPDIF_TX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; + static struct dev_config mi2s_tx_cfg[] = { [PRIM_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, [SEC_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, @@ -470,6 +497,12 @@ static char const *cdc_dma_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_88P2", "KHZ_96", "KHZ_176P4", "KHZ_192", "KHZ_352P8", "KHZ_384"}; +static const char *spdif_rate_text[] = {"KHZ_32", "KHZ_44P1", "KHZ_48", + "KHZ_88P2", "KHZ_96", "KHZ_176P4", + "KHZ_192"}; +static const char *spdif_ch_text[] = {"One", "Two"}; +static const char *spdif_bit_format_text[] = {"S16_LE", "S24_LE"}; + static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_chs, slim_tx_ch_text); @@ -561,6 +594,12 @@ static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_0_sample_rate, cdc_dma_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(va_cdc_dma_tx_1_sample_rate, cdc_dma_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(spdif_rx_sample_rate, spdif_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(spdif_tx_sample_rate, spdif_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(spdif_rx_chs, spdif_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(spdif_tx_chs, spdif_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(spdif_rx_format, spdif_bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(spdif_tx_format, spdif_bit_format_text); static struct platform_device *spdev; @@ -2904,6 +2943,337 @@ static int msm_aux_pcm_tx_format_put(struct snd_kcontrol *kcontrol, return 0; } +static int spdif_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int idx; + + if (strnstr(kcontrol->id.name, "PRIM_SPDIF_RX", + sizeof("PRIM_SPDIF_RX"))) + idx = PRIM_SPDIF_RX; + else if (strnstr(kcontrol->id.name, "SEC_SPDIF_RX", + sizeof("SEC_SPDIF_RX"))) + idx = SEC_SPDIF_RX; + else if (strnstr(kcontrol->id.name, "PRIM_SPDIF_TX", + sizeof("PRIM_SPDIF_TX"))) + idx = PRIM_SPDIF_TX; + else if (strnstr(kcontrol->id.name, "SEC_SPDIF_TX", + sizeof("SEC_SPDIF_TX"))) + idx = SEC_SPDIF_TX; + else { + pr_err("%s: unsupported channel: %s", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} + +static int spdif_get_sample_rate_val(int sample_rate) +{ + int sample_rate_val; + + switch (sample_rate) { + case SAMPLING_RATE_32KHZ: + sample_rate_val = 0; + break; + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 1; + break; + case SAMPLING_RATE_48KHZ: + sample_rate_val = 2; + break; + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 3; + break; + case SAMPLING_RATE_96KHZ: + sample_rate_val = 4; + break; + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 5; + break; + case SAMPLING_RATE_192KHZ: + sample_rate_val = 6; + break; + default: + sample_rate_val = 2; + break; + } + return sample_rate_val; +} + +static int spdif_get_sample_rate(int value) +{ + int sample_rate; + + switch (value) { + case 0: + sample_rate = SAMPLING_RATE_32KHZ; + break; + case 1: + sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 2: + sample_rate = SAMPLING_RATE_48KHZ; + break; + case 3: + sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 4: + sample_rate = SAMPLING_RATE_96KHZ; + break; + case 5: + sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 6: + sample_rate = SAMPLING_RATE_192KHZ; + break; + default: + sample_rate = SAMPLING_RATE_48KHZ; + break; + } + return sample_rate; +} + +static int spdif_get_format(int value) +{ + int format; + + switch (value) { + case 0: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + case 1: + format = SNDRV_PCM_FORMAT_S24_LE; + break; + default: + format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + return format; +} + +static int spdif_get_format_value(int format) +{ + int value; + + switch (format) { + case SNDRV_PCM_FORMAT_S16_LE: + value = 0; + break; + case SNDRV_PCM_FORMAT_S24_LE: + value = 1; + break; + default: + value = 0; + break; + } + return value; +} + +static int msm_spdif_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + spdif_rx_cfg[idx].sample_rate = + spdif_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, spdif_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_spdif_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + spdif_get_sample_rate_val(spdif_rx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__, + idx, spdif_rx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_spdif_tx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + spdif_tx_cfg[idx].sample_rate = + spdif_get_sample_rate(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, spdif_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_spdif_tx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + spdif_get_sample_rate_val(spdif_tx_cfg[idx].sample_rate); + + pr_debug("%s: idx[%d]_tx_sample_rate = %d, item = %d\n", __func__, + idx, spdif_tx_cfg[idx].sample_rate, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_spdif_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + pr_debug("%s: msm_spdif_[%d]_rx_ch = %d\n", __func__, + idx, spdif_rx_cfg[idx].channels); + ucontrol->value.enumerated.item[0] = spdif_rx_cfg[idx].channels - 1; + + return 0; +} + +static int msm_spdif_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + spdif_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: msm_spdif_[%d]_rx_ch = %d\n", __func__, + idx, spdif_rx_cfg[idx].channels); + + return 1; +} + +static int msm_spdif_tx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + pr_debug("%s: msm_spdif_[%d]_tx_ch = %d\n", __func__, + idx, spdif_tx_cfg[idx].channels); + ucontrol->value.enumerated.item[0] = spdif_tx_cfg[idx].channels - 1; + + return 0; +} + +static int msm_spdif_tx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + spdif_tx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1; + pr_debug("%s: msm_spdif_[%d]_tx_ch = %d\n", __func__, + idx, spdif_tx_cfg[idx].channels); + + return 1; +} + +static int msm_spdif_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + spdif_get_format_value(spdif_rx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, spdif_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_spdif_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + spdif_rx_cfg[idx].bit_format = + spdif_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__, + idx, spdif_rx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_spdif_tx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.enumerated.item[0] = + spdif_get_format_value(spdif_tx_cfg[idx].bit_format); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, spdif_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + +static int msm_spdif_tx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = spdif_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + spdif_tx_cfg[idx].bit_format = + spdif_get_format(ucontrol->value.enumerated.item[0]); + + pr_debug("%s: idx[%d]_tx_format = %d, item = %d\n", __func__, + idx, spdif_tx_cfg[idx].bit_format, + ucontrol->value.enumerated.item[0]); + + return 0; +} + static const struct snd_kcontrol_new msm_snd_sb_controls[] = { SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs, slim_rx_ch_get, slim_rx_ch_put), @@ -3231,6 +3601,34 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { msm_aux_pcm_tx_format_get, msm_aux_pcm_tx_format_put), SOC_SINGLE_MULTI_EXT("VAD CFG", SND_SOC_NOPM, 0, 1000, 0, 3, NULL, msm_snd_vad_cfg_put), + SOC_ENUM_EXT("PRIM_SPDIF_RX SampleRate", spdif_rx_sample_rate, + msm_spdif_rx_sample_rate_get, + msm_spdif_rx_sample_rate_put), + SOC_ENUM_EXT("PRIM_SPDIF_TX SampleRate", spdif_tx_sample_rate, + msm_spdif_tx_sample_rate_get, + msm_spdif_tx_sample_rate_put), + SOC_ENUM_EXT("SEC_SPDIF_RX SampleRate", spdif_rx_sample_rate, + msm_spdif_rx_sample_rate_get, + msm_spdif_rx_sample_rate_put), + SOC_ENUM_EXT("SEC_SPDIF_TX SampleRate", spdif_tx_sample_rate, + msm_spdif_tx_sample_rate_get, + msm_spdif_tx_sample_rate_put), + SOC_ENUM_EXT("PRIM_SPDIF_RX Channels", spdif_rx_chs, + msm_spdif_rx_ch_get, msm_spdif_rx_ch_put), + SOC_ENUM_EXT("PRIM_SPDIF_TX Channels", spdif_tx_chs, + msm_spdif_tx_ch_get, msm_spdif_tx_ch_put), + SOC_ENUM_EXT("SEC_SPDIF_RX Channels", spdif_rx_chs, + msm_spdif_rx_ch_get, msm_spdif_rx_ch_put), + SOC_ENUM_EXT("SEC_SPDIF_TX Channels", spdif_tx_chs, + msm_spdif_tx_ch_get, msm_spdif_tx_ch_put), + SOC_ENUM_EXT("PRIM_SPDIF_RX Format", spdif_rx_format, + msm_spdif_rx_format_get, msm_spdif_rx_format_put), + SOC_ENUM_EXT("PRIM_SPDIF_TX Format", spdif_tx_format, + msm_spdif_tx_format_get, msm_spdif_tx_format_put), + SOC_ENUM_EXT("SEC_SPDIF_RX Format", spdif_rx_format, + msm_spdif_rx_format_get, msm_spdif_rx_format_put), + SOC_ENUM_EXT("SEC_SPDIF_TX Format", spdif_tx_format, + msm_spdif_tx_format_get, msm_spdif_tx_format_put), }; static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, @@ -3929,6 +4327,42 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = msm_vi_feed_tx_ch; break; + case MSM_BACKEND_DAI_PRI_SPDIF_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + spdif_rx_cfg[PRIM_SPDIF_RX].bit_format); + rate->min = rate->max = + spdif_rx_cfg[PRIM_SPDIF_RX].sample_rate; + channels->min = channels->max = + spdif_rx_cfg[PRIM_SPDIF_RX].channels; + break; + + case MSM_BACKEND_DAI_PRI_SPDIF_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + spdif_tx_cfg[PRIM_SPDIF_TX].bit_format); + rate->min = rate->max = + spdif_tx_cfg[PRIM_SPDIF_TX].sample_rate; + channels->min = channels->max = + spdif_tx_cfg[PRIM_SPDIF_TX].channels; + break; + + case MSM_BACKEND_DAI_SEC_SPDIF_RX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + spdif_rx_cfg[SEC_SPDIF_RX].bit_format); + rate->min = rate->max = + spdif_rx_cfg[SEC_SPDIF_RX].sample_rate; + channels->min = channels->max = + spdif_rx_cfg[SEC_SPDIF_RX].channels; + break; + + case MSM_BACKEND_DAI_SEC_SPDIF_TX: + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + spdif_tx_cfg[SEC_SPDIF_TX].bit_format); + rate->min = rate->max = + spdif_tx_cfg[SEC_SPDIF_TX].sample_rate; + channels->min = channels->max = + spdif_tx_cfg[SEC_SPDIF_TX].channels; + break; + default: rate->min = rate->max = SAMPLING_RATE_48KHZ; break; @@ -5115,6 +5549,136 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream) mutex_unlock(&mi2s_intf_conf[index].lock); } +static int msm_spdif_set_clk(struct snd_pcm_substream *substream, bool enable) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int port_id = cpu_dai->id; + struct afe_clk_set clk_cfg; + + clk_cfg.clk_set_minor_version = Q6AFE_LPASS_CLK_CONFIG_API_VERSION; + clk_cfg.clk_attri = Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO; + clk_cfg.clk_root = Q6AFE_LPASS_CLK_ROOT_DEFAULT; + clk_cfg.enable = enable; + + /* Set core clock (based on sample rate for RX, fixed for TX) */ + switch (port_id) { + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + clk_cfg.clk_id = AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_OUTPUT_CORE; + /* rate x 2ch x 2_for_biphase_coding x 32_bits_per_sample */ + clk_cfg.clk_freq_in_hz = + spdif_rx_cfg[PRIM_SPDIF_RX].sample_rate * 2 * 2 * 32; + break; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + clk_cfg.clk_id = AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_OUTPUT_CORE; + clk_cfg.clk_freq_in_hz = + spdif_rx_cfg[SEC_SPDIF_RX].sample_rate * 2 * 2 * 32; + break; + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + clk_cfg.clk_id = AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_INPUT_CORE; + clk_cfg.clk_freq_in_hz = SPDIF_TX_CORE_CLK_204_P8_MHZ; + break; + case AFE_PORT_ID_SECONDARY_SPDIF_TX: + clk_cfg.clk_id = AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_INPUT_CORE; + clk_cfg.clk_freq_in_hz = SPDIF_TX_CORE_CLK_204_P8_MHZ; + break; + } + + ret = afe_set_lpass_clock_v2(port_id, &clk_cfg); + if (ret < 0) { + dev_err(rtd->card->dev, + "%s: afe lpass clock failed for port 0x%x , err:%d\n", + __func__, port_id, ret); + goto err; + } + + /* Set NPL clock for RX in addition */ + switch (port_id) { + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + clk_cfg.clk_id = AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_OUTPUT_NPL; + + ret = afe_set_lpass_clock_v2(port_id, &clk_cfg); + if (ret < 0) { + dev_err(rtd->card->dev, + "%s: afe NPL failed port 0x%x, err:%d\n", + __func__, port_id, ret); + goto err; + } + break; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + clk_cfg.clk_id = AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_OUTPUT_NPL; + + ret = afe_set_lpass_clock_v2(port_id, &clk_cfg); + if (ret < 0) { + dev_err(rtd->card->dev, + "%s: afe NPL failed for port 0x%x, err:%d\n", + __func__, port_id, ret); + goto err; + } + break; + } + + if (enable) { + dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__, + clk_cfg.clk_freq_in_hz); + } + +err: + return ret; +} + +static int msm_spdif_snd_startup(struct snd_pcm_substream *substream) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + int port_id = cpu_dai->id; + + dev_dbg(rtd->card->dev, + "%s: substream = %s stream = %d, dai name %s, dai ID %d\n", + __func__, substream->name, substream->stream, + cpu_dai->name, cpu_dai->id); + + if (port_id < AFE_PORT_ID_PRIMARY_SPDIF_RX || + port_id > AFE_PORT_ID_SECONDARY_SPDIF_TX) { + ret = -EINVAL; + dev_err(rtd->card->dev, + "%s: CPU DAI id (%d) out of range\n", + __func__, cpu_dai->id); + goto err; + } + + ret = msm_spdif_set_clk(substream, true); + if (ret < 0) { + dev_err(rtd->card->dev, + "%s: afe lpass clock failed to enable (%d), err:%d\n", + __func__, port_id, ret); + } +err: + return ret; +} + +static void msm_spdif_snd_shutdown(struct snd_pcm_substream *substream) +{ + int ret; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + int port_id = rtd->cpu_dai->id; + + pr_debug("%s(): substream = %s stream = %d\n", __func__, + substream->name, substream->stream); + if (port_id < AFE_PORT_ID_PRIMARY_SPDIF_RX || + port_id > AFE_PORT_ID_SECONDARY_SPDIF_TX) { + pr_err("%s:invalid SPDIF DAI(%d)\n", __func__, port_id); + return; + } + + ret = msm_spdif_set_clk(substream, false); + if (ret < 0) + pr_err("%s:clock disable failed for SPDIF (%d); ret=%d\n", + __func__, port_id, ret); +} + static struct snd_soc_ops msm_mi2s_be_ops = { .startup = msm_mi2s_snd_startup, .shutdown = msm_mi2s_snd_shutdown, @@ -5132,6 +5696,11 @@ static struct snd_soc_ops msm_wcn_ops = { .hw_params = msm_wcn_hw_params, }; +static struct snd_soc_ops msm_spdif_be_ops = { + .startup = msm_spdif_snd_startup, + .shutdown = msm_spdif_snd_shutdown, +}; + /* Digital audio interface glue - connects codec <---> CPU */ static struct snd_soc_dai_link msm_common_dai_links[] = { @@ -5787,6 +6356,20 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { .codec_dai_name = "snd-soc-dummy-dai", .codec_name = "snd-soc-dummy", }, + { + .name = MSM_DAILINK_NAME(Compr Capture), + .stream_name = "Compr Capture", + .cpu_dai_name = "MultiMedia18", + .platform_name = "msm-compress-dsp", + .dynamic = 1, + .dpcm_capture = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .ignore_pmdown_time = 1, + .id = MSM_FRONTEND_DAI_MULTIMEDIA18, + }, }; static struct snd_soc_dai_link msm_common_be_dai_links[] = { @@ -6648,6 +7231,67 @@ static struct snd_soc_dai_link msm_va_cdc_dma_be_dai_links[] = { }, }; +static struct snd_soc_dai_link msm_spdif_be_dai_links[] = { + { + .name = LPASS_BE_PRI_SPDIF_RX, + .stream_name = "Primary SPDIF Playback", + .cpu_dai_name = "msm-dai-q6-spdif.20480", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_PRI_SPDIF_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_spdif_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_PRI_SPDIF_TX, + .stream_name = "Primary SPDIF Capture", + .cpu_dai_name = "msm-dai-q6-spdif.20481", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_PRI_SPDIF_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_spdif_be_ops, + .ignore_suspend = 1, + }, + { + .name = LPASS_BE_SEC_SPDIF_RX, + .stream_name = "Secondary SPDIF Playback", + .cpu_dai_name = "msm-dai-q6-spdif.20482", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-rx", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_SEC_SPDIF_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_spdif_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, + { + .name = LPASS_BE_SEC_SPDIF_TX, + .stream_name = "Secondary SPDIF Capture", + .cpu_dai_name = "msm-dai-q6-spdif.20483", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-stub-codec.1", + .codec_dai_name = "msm-stub-tx", + .no_pcm = 1, + .dpcm_capture = 1, + .id = MSM_BACKEND_DAI_SEC_SPDIF_TX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_spdif_be_ops, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_qcs405_dai_links[ ARRAY_SIZE(msm_common_dai_links) + ARRAY_SIZE(msm_common_misc_fe_dai_links) + @@ -6658,7 +7302,8 @@ static struct snd_soc_dai_link msm_qcs405_dai_links[ ARRAY_SIZE(msm_auxpcm_be_dai_links) + ARRAY_SIZE(msm_va_cdc_dma_be_dai_links) + ARRAY_SIZE(msm_wsa_cdc_dma_be_dai_links) + - ARRAY_SIZE(msm_bolero_fe_dai_links)]; + ARRAY_SIZE(msm_bolero_fe_dai_links) + + ARRAY_SIZE(msm_spdif_be_dai_links)]; static int msm_snd_card_tasha_late_probe(struct snd_soc_card *card) { @@ -6907,7 +7552,9 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) int total_links = 0; uint32_t tasha_codec = 0, auxpcm_audio_intf = 0; uint32_t va_bolero_codec = 0, wsa_bolero_codec = 0, mi2s_audio_intf = 0; + uint32_t spdif_audio_intf = 0; const struct of_device_id *match; + char __iomem *spdif_cfg, *spdif_pin_ctl; int rc = 0; match = of_match_node(qcs405_asoc_machine_of_match, dev->of_node); @@ -7028,6 +7675,27 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) ARRAY_SIZE(msm_auxpcm_be_dai_links); } } + rc = of_property_read_u32(dev->of_node, "qcom,spdif-audio-intf", + &spdif_audio_intf); + if (rc) { + dev_dbg(dev, "%s: No DT match SPDIF audio interface\n", + __func__); + } else { + if (spdif_audio_intf) { + memcpy(msm_qcs405_dai_links + total_links, + msm_spdif_be_dai_links, + sizeof(msm_spdif_be_dai_links)); + total_links += + ARRAY_SIZE(msm_spdif_be_dai_links); + + /* enable spdif coax pins */ + spdif_cfg = ioremap(TLMM_EAST_SPARE, 0x4); + spdif_pin_ctl = + ioremap(TLMM_SPDIF_HDMI_ARC_CTL, 0x4); + iowrite32(0xc0, spdif_cfg); + iowrite32(0x2220, spdif_pin_ctl); + } + } dailink = msm_qcs405_dai_links; } else if (!strcmp(match->data, "stub_codec")) { card = &snd_soc_card_stub_msm; diff --git a/dsp/q6afe.c b/dsp/q6afe.c index 03fbdb76dc19..7699a0181bfd 100644 --- a/dsp/q6afe.c +++ b/dsp/q6afe.c @@ -103,6 +103,19 @@ struct afe_ctl { void *rx_private_data; uint32_t mmap_handle; + void (*pri_spdif_tx_cb)(uint32_t opcode, + uint32_t token, uint32_t *payload, void *priv); + void (*sec_spdif_tx_cb)(uint32_t opcode, + uint32_t token, uint32_t *payload, void *priv); + void *pri_spdif_tx_private_data; + void *sec_spdif_tx_private_data; + struct afe_port_mod_evt_rsp_hdr pri_spdif_evt_pl; + struct afe_event_fmt_update pri_spdif_fmt_event; + struct afe_port_mod_evt_rsp_hdr sec_spdif_evt_pl; + struct afe_event_fmt_update sec_spdif_fmt_event; + struct work_struct afe_pri_spdif_work; + struct work_struct afe_sec_spdif_work; + int topology[AFE_MAX_PORTS]; struct cal_type_data *cal_data[MAX_AFE_CAL_TYPES]; @@ -354,6 +367,128 @@ static void afe_notify_dc_presence_work_fn(struct work_struct *work) __func__, event, ret); } + +static const char *const afe_event_port_text[] = { + "PORT=Primary", + "PORT=Secondary", +}; + +static const char * const afe_event_state_text[] = { + "STATE=Inactive", + "STATE=Active", + "STATE=EOS", +}; + +static const char *const afe_event_rate_text[] = { + "RATE=32000", + "RATE=44100", + "RATE=48000", + "RATE=88200", + "RATE=96000", + "RATE=176400", + "RATE=192000", +}; + +static const char *const afe_event_format_text[] = { + "FORMAT=LPCM", + "FORMAT=Compr", +}; + +static void afe_notify_spdif_fmt_update_common(void *payload) +{ + int ret = 0; + char *env[6]; + struct afe_port_mod_evt_rsp_hdr *evt_pl; + struct afe_event_fmt_update *fmt_event; + + evt_pl = (struct afe_port_mod_evt_rsp_hdr *)payload; + fmt_event = (struct afe_event_fmt_update *) + (payload + sizeof(struct afe_port_mod_evt_rsp_hdr)); + + env[0] = "SPDIF_FMT_UPDATE=TRUE"; + if (evt_pl->port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) + env[1] = (char *)afe_event_port_text[0]; + else + env[1] = (char *)afe_event_port_text[1]; + + switch (fmt_event->status) { + case AFE_PORT_STATUS_AUDIO_ACTIVE: + env[2] = (char *)afe_event_state_text[1]; + break; + case AFE_PORT_STATUS_AUDIO_EOS: + env[2] = (char *)afe_event_state_text[2]; + break; + default: + env[2] = (char *)afe_event_state_text[0]; + } + + switch (fmt_event->sample_rate) { + case 32000: + env[3] = (char *)afe_event_rate_text[0]; + break; + case 44100: + env[3] = (char *)afe_event_rate_text[1]; + break; + case 48000: + env[3] = (char *)afe_event_rate_text[2]; + break; + case 88200: + env[3] = (char *)afe_event_rate_text[3]; + break; + case 96000: + env[3] = (char *)afe_event_rate_text[4]; + break; + case 176400: + env[3] = (char *)afe_event_rate_text[5]; + break; + case 192000: + env[3] = (char *)afe_event_rate_text[6]; + break; + default: + env[3] = (char *)afe_event_rate_text[2]; + } + + if (fmt_event->data_format == AFE_NON_LINEAR_DATA) + env[4] = (char *)afe_event_format_text[1]; + else + env[4] = (char *)afe_event_format_text[0]; + + env[5] = NULL; + + ret = q6core_send_uevent_env(this_afe.uevent_data, env); + if (ret) + pr_err("%s: Send UEvent %s failed: %d\n", __func__, + env[0], ret); +} + +static void afe_notify_pri_spdif_fmt_update_work_fn(struct work_struct *work) +{ + afe_notify_spdif_fmt_update_common(&this_afe.pri_spdif_evt_pl); +} + +static void afe_notify_sec_spdif_fmt_update_work_fn(struct work_struct *work) +{ + afe_notify_spdif_fmt_update_common(&this_afe.sec_spdif_evt_pl); +} + +static void afe_notify_spdif_fmt_update(void *payload) +{ + struct afe_port_mod_evt_rsp_hdr *evt_pl; + + evt_pl = (struct afe_port_mod_evt_rsp_hdr *)payload; + if (evt_pl->port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) { + memcpy(&this_afe.pri_spdif_evt_pl, payload, + sizeof(struct afe_port_mod_evt_rsp_hdr) + + sizeof(struct afe_event_fmt_update)); + schedule_work(&this_afe.afe_pri_spdif_work); + } else { + memcpy(&this_afe.sec_spdif_evt_pl, payload, + sizeof(struct afe_port_mod_evt_rsp_hdr) + + sizeof(struct afe_event_fmt_update)); + schedule_work(&this_afe.afe_sec_spdif_work); + } +} + static int32_t afe_callback(struct apr_client_data *data, void *priv) { if (!data) { @@ -550,6 +685,20 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) flag_dc_presence[1] == 1) { afe_notify_dc_presence(); } + } else if (evt_pl->port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) { + if (this_afe.pri_spdif_tx_cb) { + this_afe.pri_spdif_tx_cb(data->opcode, + data->token, data->payload, + this_afe.pri_spdif_tx_private_data); + } + afe_notify_spdif_fmt_update(data->payload); + } else if (evt_pl->port_id == AFE_PORT_ID_SECONDARY_SPDIF_TX) { + if (this_afe.sec_spdif_tx_cb) { + this_afe.sec_spdif_tx_cb(data->opcode, + data->token, data->payload, + this_afe.sec_spdif_tx_private_data); + } + afe_notify_spdif_fmt_update(data->payload); } else { pr_debug("%s: mod ID = 0x%x event_id = 0x%x\n", __func__, evt_pl->module_id, @@ -640,6 +789,13 @@ int afe_sizeof_cfg_cmd(u16 port_id) ret_size = SIZEOF_CFG_CMD(afe_param_id_hdmi_multi_chan_audio_cfg); break; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: + ret_size = + SIZEOF_CFG_CMD(afe_param_id_spdif_cfg_v2); + break; case SLIMBUS_0_RX: case SLIMBUS_0_TX: case SLIMBUS_1_RX: @@ -2794,7 +2950,7 @@ int afe_spdif_port_start(u16 port_id, struct afe_spdif_port_config *spdif_port, param_hdr, (u8 *) spdif_port); if (ret) { pr_err("%s: AFE enable for port 0x%x failed ret = %d\n", - __func__, port_id, ret); + __func__, port_id, ret); goto fail_cmd; } @@ -2807,10 +2963,13 @@ int afe_spdif_port_start(u16 port_id, struct afe_spdif_port_config *spdif_port, goto fail_cmd; } - ret = afe_send_spdif_ch_status_cfg(&spdif_port->ch_status, port_id); - if (ret < 0) { - pr_err("%s: afe send failed %d\n", __func__, ret); - goto fail_cmd; + if (afe_get_port_type(port_id) == MSM_AFE_PORT_TYPE_RX) { + ret = afe_send_spdif_ch_status_cfg(&spdif_port->ch_status, + port_id); + if (ret < 0) { + pr_err("%s: afe send failed %d\n", __func__, ret); + goto fail_cmd; + } } return afe_send_cmd_port_start(port_id); @@ -2820,6 +2979,105 @@ fail_cmd: } EXPORT_SYMBOL(afe_spdif_port_start); +/** + * afe_spdif_reg_event_cfg - + * register for event from AFE spdif port + * + * @port_id: Port ID to register event + * @reg_flag: register or unregister + * @cb: callback function to invoke for events from module + * @private_data: private data to sent back in callback fn + * + * Returns 0 on success or error on failure + */ +int afe_spdif_reg_event_cfg(u16 port_id, u16 reg_flag, + void (*cb)(uint32_t opcode, + uint32_t token, uint32_t *payload, void *priv), + void *private_data) +{ + struct afe_port_cmd_event_cfg *config; + struct afe_port_cmd_mod_evt_cfg_payload pl; + int index; + int ret; + int num_events = 1; + int cmd_size = sizeof(struct afe_port_cmd_event_cfg) + + (num_events * sizeof(struct afe_port_cmd_mod_evt_cfg_payload)); + + config = kzalloc(cmd_size, GFP_KERNEL); + if (!config) + return -ENOMEM; + + if (port_id == AFE_PORT_ID_PRIMARY_SPDIF_TX) { + this_afe.pri_spdif_tx_cb = cb; + this_afe.pri_spdif_tx_private_data = private_data; + } else if (port_id == AFE_PORT_ID_SECONDARY_SPDIF_TX) { + this_afe.sec_spdif_tx_cb = cb; + this_afe.sec_spdif_tx_private_data = private_data; + } else { + pr_err("%s: wrong port id 0x%x\n", __func__, port_id); + ret = -EINVAL; + goto fail_idx; + } + + index = q6audio_get_port_index(port_id); + if (index < 0) { + pr_err("%s: Invalid index number: %d\n", __func__, index); + ret = -EINVAL; + goto fail_idx; + } + + memset(&pl, 0, sizeof(pl)); + pl.module_id = AFE_MODULE_CUSTOM_EVENTS; + pl.event_id = AFE_PORT_FMT_UPDATE_EVENT; + pl.reg_flag = reg_flag; + + config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + config->hdr.pkt_size = cmd_size; + config->hdr.src_port = 1; + config->hdr.dest_port = 1; + config->hdr.token = index; + + config->hdr.opcode = AFE_PORT_CMD_MOD_EVENT_CFG; + config->port_id = q6audio_get_port_id(port_id); + config->num_events = num_events; + config->version = 1; + memcpy(config->payload, &pl, sizeof(pl)); + atomic_set(&this_afe.state, 1); + atomic_set(&this_afe.status, 0); + ret = apr_send_pkt(this_afe.apr, (uint32_t *) config); + if (ret < 0) { + pr_err("%s: port = 0x%x failed %d\n", + __func__, port_id, ret); + goto fail_cmd; + } + ret = wait_event_timeout(this_afe.wait[index], + (atomic_read(&this_afe.state) == 0), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + pr_err("%s: wait_event timeout\n", __func__); + ret = -EINVAL; + goto fail_cmd; + } + if (atomic_read(&this_afe.status) > 0) { + pr_err("%s: config cmd failed [%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&this_afe.status))); + ret = adsp_err_get_lnx_err_code( + atomic_read(&this_afe.status)); + goto fail_idx; + } + ret = 0; +fail_cmd: + pr_debug("%s: config.opcode 0x%x status %d\n", + __func__, config->hdr.opcode, ret); + +fail_idx: + kfree(config); + return ret; +} +EXPORT_SYMBOL(afe_spdif_reg_event_cfg); + int afe_send_slot_mapping_cfg( struct afe_param_id_slot_mapping_cfg *slot_mapping_cfg, u16 port_id) @@ -3881,7 +4139,10 @@ int afe_get_port_index(u16 port_id) case MI2S_TX: return IDX_MI2S_TX; case HDMI_RX: return IDX_HDMI_RX; case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX; - case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: return IDX_PRIMARY_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_TX: return IDX_PRIMARY_SPDIF_TX; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: return IDX_SECONDARY_SPDIF_RX; + case AFE_PORT_ID_SECONDARY_SPDIF_TX: return IDX_SECONDARY_SPDIF_TX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; case DIGI_MIC_TX: return IDX_DIGI_MIC_TX; @@ -4260,6 +4521,12 @@ int afe_open(u16 port_id, case DISPLAY_PORT_RX: cfg_type = AFE_PARAM_ID_HDMI_CONFIG; break; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: + cfg_type = AFE_PARAM_ID_SPDIF_CONFIG; + break; case SLIMBUS_0_RX: case SLIMBUS_0_TX: case SLIMBUS_1_RX: @@ -6101,7 +6368,10 @@ int afe_validate_port(u16 port_id) case MI2S_TX: case HDMI_RX: case DISPLAY_PORT_RX: - case AFE_PORT_ID_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: case RSVD_2: case RSVD_3: case DIGI_MIC_TX: @@ -7696,6 +7966,10 @@ int __init afe_init(void) q6core_init_uevent_data(this_afe.uevent_data, "q6afe_uevent"); INIT_WORK(&this_afe.afe_dc_work, afe_notify_dc_presence_work_fn); + INIT_WORK(&this_afe.afe_pri_spdif_work, + afe_notify_pri_spdif_fmt_update_work_fn); + INIT_WORK(&this_afe.afe_sec_spdif_work, + afe_notify_sec_spdif_fmt_update_work_fn); return 0; } diff --git a/dsp/q6asm.c b/dsp/q6asm.c index db5b57b8947c..378279a5f18a 100644 --- a/dsp/q6asm.c +++ b/dsp/q6asm.c @@ -1963,6 +1963,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE: case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE: case ASM_SESSION_CMD_REGISTER_FOR_RX_UNDERFLOW_EVENTS: + case ASM_STREAM_CMD_OPEN_READ_COMPRESSED: case ASM_STREAM_CMD_OPEN_WRITE_COMPRESSED: pr_debug("%s: session %d opcode 0x%x token 0x%x Payload = [0x%x] stat 0x%x src %d dest %d\n", __func__, ac->session, @@ -2176,7 +2177,7 @@ static int32_t q6asm_callback(struct apr_client_data *data, void *priv) if (ac->io_mode & SYNC_IO_MODE) { if (port->buf == NULL) { - pr_err("%s: Unexpected Write Done\n", __func__); + pr_err("%s: Unexpected Read Done\n", __func__); spin_unlock_irqrestore( &(session[session_id].session_lock), flags); @@ -2843,6 +2844,85 @@ int q6asm_set_soft_volume_module_instance_ids(int instance, } EXPORT_SYMBOL(q6asm_set_soft_volume_module_instance_ids); +/** + * q6asm_open_read_compressed - + * command to open ASM in compressed read mode + * + * @ac: Audio client handle + * @format: capture format for ASM + * @passthrough_flag: flag to indicate passthrough option + * + * Returns 0 on success or error on failure + */ +int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format, + uint32_t passthrough_flag) +{ + int rc = 0; + struct asm_stream_cmd_open_read_compressed open; + + if (ac == NULL) { + pr_err("%s: ac[%pK] NULL\n", __func__, ac); + rc = -EINVAL; + goto fail_cmd; + } + + if (ac->apr == NULL) { + pr_err("%s: APR handle[%pK] NULL\n", __func__, ac->apr); + rc = -EINVAL; + goto fail_cmd; + } + pr_debug("%s: session[%d] wr_format[0x%x]\n", __func__, ac->session, + format); + + q6asm_add_hdr(ac, &open.hdr, sizeof(open), TRUE); + open.hdr.opcode = ASM_STREAM_CMD_OPEN_READ_COMPRESSED; + atomic_set(&ac->cmd_state, -1); + + /* + * Below flag indicates whether DSP shall keep IEC61937 packing or + * unpack to raw compressed format + */ + if (format == FORMAT_IEC61937) { + open.mode_flags = 0x1; + pr_debug("%s: Flag 1 IEC61937 output\n", __func__); + } else { + open.mode_flags = 0; + open.frames_per_buf = 1; + pr_debug("%s: Flag 0 RAW_COMPR output\n", __func__); + } + + rc = apr_send_pkt(ac->apr, (uint32_t *) &open); + if (rc < 0) { + pr_err("%s: open failed op[0x%x]rc[%d]\n", + __func__, open.hdr.opcode, rc); + rc = -EINVAL; + goto fail_cmd; + } + rc = wait_event_timeout(ac->cmd_wait, + (atomic_read(&ac->cmd_state) >= 0), 1*HZ); + if (!rc) { + pr_err("%s: timeout. waited for OPEN_READ_COMPR rc[%d]\n", + __func__, rc); + rc = -ETIMEDOUT; + goto fail_cmd; + } + + if (atomic_read(&ac->cmd_state) > 0) { + pr_err("%s: DSP returned error[%s]\n", + __func__, adsp_err_get_err_str( + atomic_read(&ac->cmd_state))); + rc = adsp_err_get_lnx_err_code( + atomic_read(&ac->cmd_state)); + goto fail_cmd; + } + + return 0; + +fail_cmd: + return rc; +} +EXPORT_SYMBOL(q6asm_open_read_compressed); + static int __q6asm_open_read(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, uint32_t pcm_format_block_ver, diff --git a/dsp/q6audio-v2.c b/dsp/q6audio-v2.c index a49632700c85..b48c9b69cf55 100644 --- a/dsp/q6audio-v2.c +++ b/dsp/q6audio-v2.c @@ -50,7 +50,10 @@ int q6audio_get_port_index(u16 port_id) case MI2S_TX: return IDX_MI2S_TX; case HDMI_RX: return IDX_HDMI_RX; case DISPLAY_PORT_RX: return IDX_DISPLAY_PORT_RX; - case AFE_PORT_ID_SPDIF_RX: return IDX_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: return IDX_PRIMARY_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_TX: return IDX_PRIMARY_SPDIF_TX; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: return IDX_SECONDARY_SPDIF_RX; + case AFE_PORT_ID_SECONDARY_SPDIF_TX: return IDX_SECONDARY_SPDIF_TX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; case DIGI_MIC_TX: return IDX_DIGI_MIC_TX; @@ -351,7 +354,14 @@ int q6audio_get_port_id(u16 port_id) case HDMI_RX: return AFE_PORT_ID_MULTICHAN_HDMI_RX; case DISPLAY_PORT_RX: return AFE_PORT_ID_HDMI_OVER_DP_RX; - case AFE_PORT_ID_SPDIF_RX: return AFE_PORT_ID_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + return AFE_PORT_ID_PRIMARY_SPDIF_RX; + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + return AFE_PORT_ID_PRIMARY_SPDIF_TX; + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + return AFE_PORT_ID_SECONDARY_SPDIF_RX; + case AFE_PORT_ID_SECONDARY_SPDIF_TX: + return AFE_PORT_ID_SECONDARY_SPDIF_TX; case RSVD_2: return IDX_RSVD_2; case RSVD_3: return IDX_RSVD_3; case DIGI_MIC_TX: return AFE_PORT_ID_DIGITAL_MIC_TX; @@ -777,6 +787,10 @@ int q6audio_is_digital_pcm_interface(u16 port_id) case AFE_PORT_ID_WSA_CODEC_DMA_TX_2: case AFE_PORT_ID_VA_CODEC_DMA_TX_0: case AFE_PORT_ID_VA_CODEC_DMA_TX_1: + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: break; default: ret = -EINVAL; @@ -854,7 +868,10 @@ int q6audio_validate_port(u16 port_id) case AFE_PORT_ID_QUATERNARY_MI2S_TX: case AFE_PORT_ID_SECONDARY_MI2S_RX: case AFE_PORT_ID_SECONDARY_MI2S_TX: - case AFE_PORT_ID_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_RX: + case AFE_PORT_ID_PRIMARY_SPDIF_TX: + case AFE_PORT_ID_SECONDARY_SPDIF_RX: + case AFE_PORT_ID_SECONDARY_SPDIF_TX: case AFE_PORT_ID_TERTIARY_MI2S_RX: case AFE_PORT_ID_TERTIARY_MI2S_TX: case AFE_PORT_ID_QUINARY_MI2S_RX: diff --git a/dsp/q6core.c b/dsp/q6core.c index 51b8ef0c4e9d..34f0dd091189 100644 --- a/dsp/q6core.c +++ b/dsp/q6core.c @@ -189,6 +189,23 @@ int q6core_send_uevent(struct audio_uevent_data *uevent_data, char *event) } EXPORT_SYMBOL(q6core_send_uevent); +/** + * q6core_send_uevent_env - send uevent with list of keys to userspace. + * + * @uevent_data: uevent data. + * @event: array of event keys to send. + * + * Returns 0 on success or error otherwise. + */ +int q6core_send_uevent_env(struct audio_uevent_data *uevent_data, char *env[]) +{ + if (!env || !uevent_data) + return -EINVAL; + + return kobject_uevent_env(&uevent_data->kobj, KOBJ_CHANGE, env); +} +EXPORT_SYMBOL(q6core_send_uevent_env); + static int parse_fwk_version_info(uint32_t *payload) { size_t ver_size; diff --git a/include/dsp/apr_audio-v2.h b/include/dsp/apr_audio-v2.h index 337f66f27b25..b9ae3f55843e 100644 --- a/include/dsp/apr_audio-v2.h +++ b/include/dsp/apr_audio-v2.h @@ -1236,7 +1236,11 @@ struct adm_cmd_connect_afe_port_v5 { #define AFE_PORT_ID_QUINARY_PCM_RX 0x103C #define AFE_PORT_ID_QUINARY_PCM_TX 0x103D -#define AFE_PORT_ID_SPDIF_RX 0x5000 +#define AFE_PORT_ID_PRIMARY_SPDIF_RX 0x5000 +#define AFE_PORT_ID_PRIMARY_SPDIF_TX 0x5001 +#define AFE_PORT_ID_SECONDARY_SPDIF_RX 0x5002 +#define AFE_PORT_ID_SECONDARY_SPDIF_TX 0x5003 + #define AFE_PORT_ID_RT_PROXY_PORT_001_RX 0x2000 #define AFE_PORT_ID_RT_PROXY_PORT_001_TX 0x2001 #define AFE_PORT_ID_INTERNAL_BT_SCO_RX 0x3000 @@ -2270,6 +2274,7 @@ struct afe_param_id_i2s_cfg { * This param id is used to configure PCM interface */ +#define AFE_API_VERSION_SPDIF_CONFIG_V2 0x2 #define AFE_API_VERSION_SPDIF_CONFIG 0x1 #define AFE_API_VERSION_SPDIF_CH_STATUS_CONFIG 0x1 #define AFE_API_VERSION_SPDIF_CLK_CONFIG 0x1 @@ -2283,10 +2288,20 @@ struct afe_param_id_i2s_cfg { #define AFE_PORT_CLK_ROOT_LPAPLL 0x3 #define AFE_PORT_CLK_ROOT_LPAQ6PLL 0x4 -struct afe_param_id_spdif_cfg { +#define AFE_MODULE_CUSTOM_EVENTS 0x00010251 + +#define AFE_PORT_FMT_UPDATE_EVENT 0x0001010E + +#define AFE_API_VERSION_EVENT_FMT_UPDATE 0x1 +#define AFE_PORT_STATUS_NO_SIGNAL 0 +#define AFE_PORT_STATUS_AUDIO_ACTIVE 1 +#define AFE_PORT_STATUS_AUDIO_EOS 2 + +struct afe_param_id_spdif_cfg_v2 { /* Minor version used for tracking the version of the SPDIF * configuration interface. - * Supported values: #AFE_API_VERSION_SPDIF_CONFIG + * Supported values: #AFE_API_VERSION_SPDIF_CONFIG, + * #AFE_API_VERSION_SPDIF_CONFIG_V2 */ u32 spdif_cfg_minor_version; @@ -2318,6 +2333,8 @@ struct afe_param_id_spdif_cfg { u16 bit_width; /* This field must be set to zero. */ u16 reserved; +/* Input select for spdif input, must be set to 0 for spdif output. */ + u32 src_sel; } __packed; struct afe_param_id_spdif_ch_status_cfg { @@ -2344,6 +2361,7 @@ struct afe_param_id_spdif_ch_status_cfg { */ } __packed; +/* deprecated */ struct afe_param_id_spdif_clk_cfg { u32 clk_cfg_minor_version; /* Minor version used for tracking the version of SPDIF @@ -2367,8 +2385,43 @@ struct afe_param_id_spdif_clk_cfg { */ } __packed; +struct afe_event_fmt_update { + /* Tracks the configuration of this event. */ + u32 minor_version; + + /* Detected port status. + * Supported values: + * - #AFE_PORT_STATUS_NO_SIGNAL + * - #AFE_PORT_STATUS_AUDIO_ACTIVE + * - #AFE_PORT_STATUS_AUDIO_EOS + */ + u32 status; + + /* Sampling rate of the port. + * Supported values: + * - #AFE_PORT_SAMPLE_RATE_32K + * - #AFE_PORT_SAMPLE_RATE_44_1K + * - #AFE_PORT_SAMPLE_RATE_48K + * - #AFE_PORT_SAMPLE_RATE_88_2K + * - #AFE_PORT_SAMPLE_RATE_96K + * - #AFE_PORT_SAMPLE_RATE_176_4K + * - #AFE_PORT_SAMPLE_RATE_192K + */ + u32 sample_rate; + + /* Data format of the port. + * Supported values: + * - #AFE_LINEAR_PCM_DATA + * - #AFE_NON_LINEAR_DATA + */ + u16 data_format; + + /* First 6 bytes of channel status bits */ + u8 channel_status[6]; +} __packed; + struct afe_spdif_port_config { - struct afe_param_id_spdif_cfg cfg; + struct afe_param_id_spdif_cfg_v2 cfg; struct afe_param_id_spdif_ch_status_cfg ch_status; } __packed; @@ -4093,7 +4146,7 @@ union afe_port_config { struct afe_param_id_internal_bt_fm_cfg int_bt_fm; struct afe_param_id_pseudo_port_cfg pseudo_port; struct afe_param_id_device_hw_delay_cfg hw_delay; - struct afe_param_id_spdif_cfg spdif; + struct afe_param_id_spdif_cfg_v2 spdif; struct afe_param_id_set_topology_cfg topology; struct afe_param_id_tdm_cfg tdm; struct afe_param_id_usb_audio_cfg usb_audio; @@ -4793,7 +4846,7 @@ struct asm_generic_compressed_fmt_blk_t { /* Command to send sample rate & channels for IEC61937 (compressed) or IEC60958 * (pcm) streams. Both audio standards use the same format and are used for - * HDMI or SPDIF. + * HDMI or SPDIF output. */ #define ASM_DATA_CMD_IEC_60958_MEDIA_FMT 0x0001321E @@ -7669,11 +7722,23 @@ struct asm_data_cmd_remove_silence { #define ASM_STREAM_CMD_OPEN_READ_COMPRESSED 0x00010D95 +/* Bitmask for the IEC 61937 to 61937 pass-through capture. */ +#define ASM_BIT_MASK_IEC_61937_PASS_THROUGH_FLAG (0x00000001UL) + +/* Shift value for the IEC 61937 to 61937 pass-through capture. */ +#define ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG 0 + struct asm_stream_cmd_open_read_compressed { struct apr_hdr hdr; u32 mode_flags; /* Mode flags that indicate whether meta information per encoded - * frame is to be provided. + * frame is to be provided and packaging. + * Supported values for bit 0: (IEC 61937 pass-through mode) + * - 0 -- Unpack the IEC 61937 format stream to RAW compressed format + * - 1 -- Pass-through transfer of the IEC 61937 format stream + * - Use #ASM_BIT_MASK_IEC_61937_PASS_THROUGH_FLAG to set the bitmask + * and #ASM_SHIFT_IEC_61937_PASS_THROUGH_FLAG to set the shift value + * for this bit. * Supported values for bit 4: * - 0 -- Return data buffer contains all encoded frames only; it does * not contain frame metadata. @@ -7687,7 +7752,9 @@ struct asm_stream_cmd_open_read_compressed { u32 frames_per_buf; /* Indicates the number of frames that need to be returned per * read buffer - * Supported values: should be greater than 0 + * Supported values: should be greater than 0 for IEC to RAW compressed + * unpack mode. + * Value is don't care for IEC 61937 pass-through mode. */ } __packed; @@ -10321,8 +10388,18 @@ enum afe_lpass_clk_mode { /* Clock ID for AHB HDMI input */ #define Q6AFE_LPASS_CLK_ID_AHB_HDMI_INPUT 0x400 -/* Clock ID for SPDIF core */ -#define Q6AFE_LPASS_CLK_ID_SPDIF_CORE 0x500 +/* Clock ID for the primary SPDIF output core. */ +#define AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_OUTPUT_CORE 0x500 +/* Clock ID for the secondary SPDIF output core. */ +#define AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_OUTPUT_CORE 0x501 +/* Clock ID for the primary SPDIF input core. */ +#define AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_INPUT_CORE 0x502 +/* Clock ID for the secondary SPDIF input core. */ +#define AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_INPUT_CORE 0x503 +/* Clock ID for the secondary SPDIF output NPL clk. */ +#define AFE_CLOCK_SET_CLOCK_ID_PRI_SPDIF_OUTPUT_NPL 0x504 +/* Clock ID for the primary SPDIF output NPL clk. */ +#define AFE_CLOCK_SET_CLOCK_ID_SEC_SPDIF_OUTPUT_NPL 0x505 /* Clock attribute for invalid use (reserved for internal usage) */ diff --git a/include/dsp/q6afe-v2.h b/include/dsp/q6afe-v2.h index e39d0b89d578..930682836f32 100644 --- a/include/dsp/q6afe-v2.h +++ b/include/dsp/q6afe-v2.h @@ -107,7 +107,7 @@ enum { /* IDX 45->49 */ IDX_SLIMBUS_6_RX, IDX_SLIMBUS_6_TX, - IDX_SPDIF_RX, + IDX_PRIMARY_SPDIF_RX, IDX_GLOBAL_CFG, IDX_AUDIO_PORT_ID_I2S_RX, /* IDX 50->53 */ @@ -229,7 +229,7 @@ enum { IDX_AFE_PORT_ID_QUINARY_TDM_TX_6, IDX_AFE_PORT_ID_QUINARY_TDM_RX_7, IDX_AFE_PORT_ID_QUINARY_TDM_TX_7, - /* IDX 161 to 166 */ + /* IDX 161 to 167 */ IDX_AFE_PORT_ID_WSA_CODEC_DMA_RX_0, IDX_AFE_PORT_ID_WSA_CODEC_DMA_TX_0, IDX_AFE_PORT_ID_WSA_CODEC_DMA_RX_1, @@ -237,6 +237,10 @@ enum { IDX_AFE_PORT_ID_WSA_CODEC_DMA_TX_2, IDX_AFE_PORT_ID_VA_CODEC_DMA_TX_0, IDX_AFE_PORT_ID_VA_CODEC_DMA_TX_1, + /* IDX 168 to 170 */ + IDX_SECONDARY_SPDIF_RX, + IDX_PRIMARY_SPDIF_TX, + IDX_SECONDARY_SPDIF_TX, AFE_MAX_PORTS }; @@ -389,6 +393,11 @@ int afe_send_spdif_ch_status_cfg(struct afe_param_id_spdif_ch_status_cfg int afe_spdif_port_start(u16 port_id, struct afe_spdif_port_config *spdif_port, u32 rate); +int afe_spdif_reg_event_cfg(u16 port_id, u16 reg_flag, + void (*cb)(uint32_t opcode, + uint32_t token, uint32_t *payload, void *priv), + void *private_data); + int afe_turn_onoff_hw_mad(u16 mad_type, u16 mad_enable); int afe_port_set_mad_type(u16 port_id, enum afe_mad_type mad_type); enum afe_mad_type afe_port_get_mad_type(u16 port_id); diff --git a/include/dsp/q6asm-v2.h b/include/dsp/q6asm-v2.h index e6f021db7e88..633e16c07e70 100644 --- a/include/dsp/q6asm-v2.h +++ b/include/dsp/q6asm-v2.h @@ -323,6 +323,9 @@ int q6asm_stream_open_write_v4(struct audio_client *ac, uint32_t format, uint16_t bits_per_sample, int32_t stream_id, bool is_gapless_mode); +int q6asm_open_read_compressed(struct audio_client *ac, uint32_t format, + uint32_t passthrough_flag); + int q6asm_open_write_compressed(struct audio_client *ac, uint32_t format, uint32_t passthrough_flag); diff --git a/include/dsp/q6core.h b/include/dsp/q6core.h index ac364511513a..cdee048c38bf 100644 --- a/include/dsp/q6core.h +++ b/include/dsp/q6core.h @@ -35,6 +35,7 @@ struct audio_uevent_data { int q6core_init_uevent_data(struct audio_uevent_data *uevent_data, char *name); void q6core_destroy_uevent_data(struct audio_uevent_data *uevent_data); int q6core_send_uevent(struct audio_uevent_data *uevent_data, char *name); +int q6core_send_uevent_env(struct audio_uevent_data *uevent_data, char *env[]); int q6core_get_avcs_api_version_per_service(uint32_t service_id); #define ADSP_CMD_SET_DTS_EAGLE_DATA_ID 0x00012919