diff --git a/asoc/qcs405.c b/asoc/qcs405.c index 18dfb82207be..982b1f278958 100644 --- a/asoc/qcs405.c +++ b/asoc/qcs405.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ #include #include @@ -148,6 +148,11 @@ enum { SPDIF_TX_MAX, }; +enum { + HDMI_RX_IDX = 0, + EXT_HDMI_RX_IDX_MAX, +}; + struct mi2s_conf { struct mutex lock; u32 ref_cnt; @@ -344,7 +349,9 @@ static struct dev_config tdm_tx_cfg[TDM_INTERFACE_MAX][TDM_PORT_MAX] = { {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 1}, /* TX_7 */ } }; - +static struct dev_config ext_hdmi_rx_cfg[] = { + [HDMI_RX_IDX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2}, +}; /* Default configuration of slimbus channels */ static struct dev_config slim_rx_cfg[] = { @@ -488,6 +495,12 @@ static char const *usb_sample_rate_text[] = {"KHZ_8", "KHZ_11P025", "KHZ_32", "KHZ_44P1", "KHZ_48", "KHZ_88P2", "KHZ_96", "KHZ_176P4", "KHZ_192", "KHZ_352P8", "KHZ_384"}; +static char const *ext_hdmi_sample_rate_text[] = {"KHZ_48", "KHZ_96", + "KHZ_192", "KHZ_32", "KHZ_44P1", + "KHZ_88P2", "KHZ_176P4"}; +static char const *ext_hdmi_bit_format_text[] = {"S16_LE", "S24_LE", + "S24_3LE"}; + static char const *tdm_ch_text[] = {"One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight"}; static char const *tdm_bit_format_text[] = {"S16_LE", "S24_LE", "S32_LE"}; @@ -539,6 +552,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_chs, slim_rx_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_chs, usb_ch_text); static SOC_ENUM_SINGLE_EXT_DECL(vi_feed_tx_chs, vi_feed_ch_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_hdmi_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(proxy_rx_chs, ch_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_format, bit_format_text); @@ -546,6 +560,7 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_format, bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_format, bit_format_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_hdmi_rx_format, ext_hdmi_bit_format_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_2_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_0_tx_sample_rate, slim_sample_rate_text); @@ -553,6 +568,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(slim_5_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(slim_6_rx_sample_rate, slim_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate, bt_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(bt_sample_rate_sink, bt_sample_rate_text); +static SOC_ENUM_SINGLE_EXT_DECL(ext_hdmi_rx_sample_rate, + ext_hdmi_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_rx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(usb_tx_sample_rate, usb_sample_rate_text); static SOC_ENUM_SINGLE_EXT_DECL(tdm_tx_chs, tdm_ch_text); @@ -2110,6 +2127,191 @@ static int usb_audio_tx_format_put(struct snd_kcontrol *kcontrol, return rc; } +static int ext_hdmi_get_port_idx(struct snd_kcontrol *kcontrol) +{ + int idx; + + if (strnstr(kcontrol->id.name, "HDMI_RX", + sizeof("HDMI_RX"))) { + idx = HDMI_RX_IDX; + } else { + pr_err("%s: unsupported BE: %s", + __func__, kcontrol->id.name); + idx = -EINVAL; + } + + return idx; +} + +static int ext_hdmi_rx_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ext_hdmi_rx_cfg[idx].bit_format) { + case SNDRV_PCM_FORMAT_S24_LE: + ucontrol->value.integer.value[0] = 1; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + default: + ucontrol->value.integer.value[0] = 0; + break; + } + + pr_debug("%s: ext_hdmi_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_hdmi_rx_cfg[idx].bit_format, + ucontrol->value.integer.value[0]); + return 0; +} + +static int ext_hdmi_rx_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ucontrol->value.integer.value[0]) { + case 1: + ext_hdmi_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE; + break; + case 0: + default: + ext_hdmi_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S16_LE; + break; + } + pr_debug("%s: ext_hdmi_rx[%d].format = %d, ucontrol value = %ld\n", + __func__, idx, ext_hdmi_rx_cfg[idx].bit_format, + ucontrol->value.integer.value[0]); + + return 0; +} + +static int ext_hdmi_rx_ch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ucontrol->value.integer.value[0] = + ext_hdmi_rx_cfg[idx].channels - 2; + + pr_debug("%s: ext_hdmi_rx[%d].ch = %d\n", __func__, + idx, ext_hdmi_rx_cfg[idx].channels); + + return 0; +} + +static int ext_hdmi_rx_ch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + ext_hdmi_rx_cfg[idx].channels = + ucontrol->value.integer.value[0] + 2; + + pr_debug("%s: ext_hdmi_rx[%d].ch = %d\n", __func__, + idx, ext_hdmi_rx_cfg[idx].channels); + return 0; +} + +static int ext_hdmi_rx_sample_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int sample_rate_val; + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ext_hdmi_rx_cfg[idx].sample_rate) { + case SAMPLING_RATE_176P4KHZ: + sample_rate_val = 6; + break; + + case SAMPLING_RATE_88P2KHZ: + sample_rate_val = 5; + break; + + case SAMPLING_RATE_44P1KHZ: + sample_rate_val = 4; + break; + + case SAMPLING_RATE_32KHZ: + sample_rate_val = 3; + break; + + case SAMPLING_RATE_192KHZ: + sample_rate_val = 2; + break; + + case SAMPLING_RATE_96KHZ: + sample_rate_val = 1; + break; + + case SAMPLING_RATE_48KHZ: + default: + sample_rate_val = 0; + break; + } + + ucontrol->value.integer.value[0] = sample_rate_val; + pr_debug("%s: ext_hdmi_rx[%d].sample_rate = %d\n", __func__, + idx, ext_hdmi_rx_cfg[idx].sample_rate); + + return 0; +} + + +static int ext_hdmi_rx_sample_rate_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int idx = ext_hdmi_get_port_idx(kcontrol); + + if (idx < 0) + return idx; + + switch (ucontrol->value.integer.value[0]) { + case 6: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_176P4KHZ; + break; + case 5: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_88P2KHZ; + break; + case 4: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_44P1KHZ; + break; + case 3: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_32KHZ; + break; + case 2: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_192KHZ; + break; + case 1: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_96KHZ; + break; + case 0: + default: + ext_hdmi_rx_cfg[idx].sample_rate = SAMPLING_RATE_48KHZ; + break; + } + + pr_debug("%s: control value = %ld, ext_hdmi_rx[%d].sample_rate = %d\n", + __func__, ucontrol->value.integer.value[0], idx, + ext_hdmi_rx_cfg[idx].sample_rate); + return 0; +} + static int proxy_rx_ch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -3842,6 +4044,14 @@ static const struct snd_kcontrol_new msm_snd_sb_controls[] = { slim_rx_bit_format_get, slim_rx_bit_format_put), SOC_ENUM_EXT("SLIM_0_TX Format", slim_0_tx_format, slim_tx_bit_format_get, slim_tx_bit_format_put), + SOC_ENUM_EXT("HDMI_RX Bit Format", ext_hdmi_rx_format, + ext_hdmi_rx_format_get, ext_hdmi_rx_format_put), + SOC_ENUM_EXT("HDMI_RX SampleRate", ext_hdmi_rx_sample_rate, + ext_hdmi_rx_sample_rate_get, + ext_hdmi_rx_sample_rate_put), + SOC_ENUM_EXT("HDMI_RX Channels", ext_hdmi_rx_chs, + ext_hdmi_rx_ch_get, + ext_hdmi_rx_ch_put), SOC_ENUM_EXT("SLIM_0_RX SampleRate", slim_0_rx_sample_rate, slim_rx_sample_rate_get, slim_rx_sample_rate_put), SOC_ENUM_EXT("SLIM_2_RX SampleRate", slim_2_rx_sample_rate, @@ -4506,6 +4716,23 @@ static int msm_slim_get_ch_from_beid(int32_t be_id) return ch_id; } +static int msm_ext_hdmi_get_idx_from_beid(int32_t be_id) +{ + int idx; + + switch (be_id) { + case MSM_BACKEND_DAI_HDMI_RX_MS: + idx = HDMI_RX_IDX; + break; + default: + pr_err("%s: Incorrect ext_hdmi BE id %d\n", __func__, be_id); + idx = -EINVAL; + break; + } + + return idx; +} + static int msm_cdc_dma_get_idx_from_beid(int32_t be_id) { int idx = 0; @@ -5040,11 +5267,27 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, channels->min = channels->max = afe_lb_tx_cfg.channels; break; + case MSM_BACKEND_DAI_HDMI_RX_MS: + idx = msm_ext_hdmi_get_idx_from_beid(dai_link->id); + + if (idx < 0) { + pr_err("%s: Incorrect ext hdmi idx %d\n", + __func__, idx); + rc = idx; + goto done; + } + + param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT, + ext_hdmi_rx_cfg[idx].bit_format); + rate->min = rate->max = ext_hdmi_rx_cfg[idx].sample_rate; + channels->min = channels->max = ext_hdmi_rx_cfg[idx].channels; + break; + default: rate->min = rate->max = SAMPLING_RATE_48KHZ; break; } - +done: return rc; } @@ -6104,7 +6347,6 @@ static struct snd_soc_ops msm_fe_qos_ops = { .prepare = msm_fe_qos_prepare, }; - static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) { int ret = 0; @@ -7298,6 +7540,24 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { }, }; +static struct snd_soc_dai_link ext_hdmi_be_dai_link[] = { + /* HDMI RX BACK END DAI Link */ + { + .name = LPASS_BE_HDMI_MS, + .stream_name = "HDMI MS Playback", + .cpu_dai_name = "msm-dai-q6-hdmi.24578", + .platform_name = "msm-pcm-routing", + .codec_name = "msm-ext-disp-audio-codec-rx", + .codec_dai_name = "msm_hdmi_ms_audio_codec_rx_dai", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_HDMI_RX_MS, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ignore_pmdown_time = 1, + .ignore_suspend = 1, + }, +}; + static struct snd_soc_dai_link msm_common_be_dai_links[] = { /* Backend AFE DAI Links */ { @@ -8305,7 +8565,8 @@ static struct snd_soc_dai_link msm_qcs405_dai_links[ ARRAY_SIZE(msm_wsa_cdc_dma_be_dai_links) + ARRAY_SIZE(msm_bolero_fe_dai_links) + ARRAY_SIZE(msm_spdif_be_dai_links) + - ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link)]; + ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link) + + ARRAY_SIZE(ext_hdmi_be_dai_link)]; static int msm_snd_card_tasha_late_probe(struct snd_soc_card *card) { @@ -8556,6 +8817,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) uint32_t va_bolero_codec = 0, wsa_bolero_codec = 0, mi2s_audio_intf = 0; uint32_t spdif_audio_intf = 0, wcn_audio_intf = 0; uint32_t afe_loopback_intf = 0, meta_mi2s_intf = 0; + uint32_t ext_disp_hdmi_rx = 0; const struct of_device_id *match; char __iomem *spdif_cfg, *spdif_pin_ctl; int rc = 0; @@ -8743,6 +9005,20 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) ARRAY_SIZE(msm_afe_rxtx_lb_be_dai_link); } } + rc = of_property_read_u32(dev->of_node, + "qcom,ext-disp-audio-rx", &ext_disp_hdmi_rx); + if (rc) { + dev_dbg(dev, "%s: No DT match ext disp hdmi rx\n", + __func__); + } else { + if (ext_disp_hdmi_rx) { + memcpy(msm_qcs405_dai_links + total_links, + ext_hdmi_be_dai_link, + sizeof(ext_hdmi_be_dai_link)); + total_links += ARRAY_SIZE(ext_hdmi_be_dai_link); + } + } + dailink = msm_qcs405_dai_links; } else if (!strcmp(match->data, "stub_codec")) { card = &snd_soc_card_stub_msm; @@ -8756,7 +9032,6 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) msm_stub_be_dai_links, sizeof(msm_stub_be_dai_links)); total_links += ARRAY_SIZE(msm_stub_be_dai_links); - dailink = msm_stub_dai_links; }