|
@@ -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 <linux/clk.h>
|
|
|
#include <linux/delay.h>
|
|
@@ -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;
|
|
|
}
|
|
|
|