diff --git a/include/dt-bindings/sound/qcom,q6voice.h b/include/dt-bindings/sound/qcom,q6voice.h index fe5aa3a3fce49b..825bf7d47fe316 100644 --- a/include/dt-bindings/sound/qcom,q6voice.h +++ b/include/dt-bindings/sound/qcom,q6voice.h @@ -3,5 +3,6 @@ #define __DT_BINDINGS_Q6_VOICE_H__ #define CS_VOICE 0 +#define VOICEMMODE1 1 #endif /* __DT_BINDINGS_Q6_VOICE_H__ */ diff --git a/sound/soc/qcom/qdsp6/q6mvm.c b/sound/soc/qcom/qdsp6/q6mvm.c index 8240a7270f4702..fce5318300a75c 100644 --- a/sound/soc/qcom/qdsp6/q6mvm.c +++ b/sound/soc/qcom/qdsp6/q6mvm.c @@ -51,6 +51,20 @@ static inline const char *q6mvm_session_name(enum q6voice_path_type path) switch (path) { case Q6VOICE_PATH_VOICE: return "default modem voice"; + case Q6VOICE_PATH_VOIP: + return "10004000"; + case Q6VOICE_PATH_VOLTE: + return "10C02000"; + case Q6VOICE_PATH_VOICE2: + return "10DC1000"; + case Q6VOICE_PATH_QCHAT: + return "10803000"; + case Q6VOICE_PATH_VOWLAN: + return "10002000"; + case Q6VOICE_PATH_VOICEMMODE1: + return "11C05000"; + case Q6VOICE_PATH_VOICEMMODE2: + return "11DC5000"; default: return NULL; } diff --git a/sound/soc/qcom/qdsp6/q6voice-dai.c b/sound/soc/qcom/qdsp6/q6voice-dai.c index f3ae9d75f82b7a..93318d10e14542 100644 --- a/sound/soc/qcom/qdsp6/q6voice-dai.c +++ b/sound/soc/qcom/qdsp6/q6voice-dai.c @@ -11,20 +11,44 @@ #define DRV_NAME "q6voice-dai" +static enum q6voice_path_type q6voice_get_path(unsigned int dai_id) +{ + switch (dai_id) { + case CS_VOICE: + return Q6VOICE_PATH_VOICE; + case VOICEMMODE1: + return Q6VOICE_PATH_VOICEMMODE1; + } + + return Q6VOICE_PATH_COUNT; +} + static int q6voice_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct q6voice *v = snd_soc_dai_get_drvdata(dai); + enum q6voice_path_type path = q6voice_get_path(dai->driver->id); - return q6voice_start(v, Q6VOICE_PATH_VOICE, substream->stream); + if (path == Q6VOICE_PATH_COUNT) { + dev_err(dai->dev, "Invalid DAI ID %u\n", dai->driver->id); + return -EINVAL; + } + + return q6voice_start(v, path, substream->stream); } static void q6voice_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct q6voice *v = snd_soc_dai_get_drvdata(dai); + enum q6voice_path_type path = q6voice_get_path(dai->driver->id); + + if (path == Q6VOICE_PATH_COUNT) { + dev_err(dai->dev, "Invalid DAI ID %u\n", dai->driver->id); + return; + } - q6voice_stop(v, Q6VOICE_PATH_VOICE, substream->stream); + q6voice_stop(v, path, substream->stream); } static struct snd_soc_dai_ops q6voice_dai_ops = { @@ -57,6 +81,29 @@ static struct snd_soc_dai_driver q6voice_dais[] = { }, .ops = &q6voice_dai_ops, }, + { + .id = VOICEMMODE1, + .name = "VOICEMMODE1", + .playback = { + .stream_name = "VOICEMMODE1 Playback", + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .capture = { + .stream_name = "VOICEMMODE1 Capture", + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_8000, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 1, + .channels_max = 1, + }, + .ops = &q6voice_dai_ops, + }, }; /* FIXME: Use codec2codec instead */ @@ -77,21 +124,26 @@ static int q6voice_dai_open(struct snd_soc_component *component, return 0; } -static int q6voice_get_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int q6voice_get_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, bool capture) { struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct q6voice *v = snd_soc_component_get_drvdata(c); - bool capture = !!mc->shift; + enum q6voice_path_type path = q6voice_get_path(mc->shift); + + if (path == Q6VOICE_PATH_COUNT) { + dev_err(c->dev, "Invalid DAI ID %u\n", mc->shift); + return -EINVAL; + } ucontrol->value.integer.value[0] = - q6voice_get_port(v, Q6VOICE_PATH_VOICE, capture) == mc->reg; + q6voice_get_port(v, path, capture) == mc->reg; return 0; } -static int q6voice_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int q6voice_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol, bool capture) { struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); @@ -99,61 +151,114 @@ static int q6voice_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_ (struct soc_mixer_control *)kcontrol->private_value; struct q6voice *v = snd_soc_component_get_drvdata(c); bool val = !!ucontrol->value.integer.value[0]; - bool capture = !!mc->shift; + enum q6voice_path_type path = q6voice_get_path(mc->shift); + + if (path == Q6VOICE_PATH_COUNT) { + dev_err(c->dev, "Invalid DAI ID %u\n", mc->shift); + return -EINVAL; + } if (val) - q6voice_set_port(v, Q6VOICE_PATH_VOICE, capture, mc->reg); - else if (q6voice_get_port(v, Q6VOICE_PATH_VOICE, capture) == mc->reg) - q6voice_set_port(v, Q6VOICE_PATH_VOICE, capture, 0); + q6voice_set_port(v, path, capture, mc->reg); + else if (q6voice_get_port(v, path, capture) == mc->reg) + q6voice_set_port(v, path, capture, 0); snd_soc_dapm_mixer_update_power(dapm, kcontrol, val, NULL); return 1; } -static const struct snd_kcontrol_new voice_tx_mixer_controls[] = { - SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, 1, 1, 0, - q6voice_get_mixer, q6voice_put_mixer), - SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, 1, 1, 0, - q6voice_get_mixer, q6voice_put_mixer), - SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, 1, 1, 0, - q6voice_get_mixer, q6voice_put_mixer), - SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, 1, 1, 0, - q6voice_get_mixer, q6voice_put_mixer), - SOC_SINGLE_EXT("QUIN_MI2S_TX", QUINARY_MI2S_TX, 1, 1, 0, - q6voice_get_mixer, q6voice_put_mixer), +static int q6voice_get_mixer_capture(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + return q6voice_get_mixer(kcontrol, ucontrol, true); +} + +static int q6voice_get_mixer_playback(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + return q6voice_get_mixer(kcontrol, ucontrol, false); +} + +static int q6voice_put_mixer_capture(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + return q6voice_put_mixer(kcontrol, ucontrol, true); +} + +static int q6voice_put_mixer_playback(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +{ + return q6voice_put_mixer(kcontrol, ucontrol, false); +} + +static const struct snd_kcontrol_new cs_voice_tx_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, CS_VOICE, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, CS_VOICE, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, CS_VOICE, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, CS_VOICE, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), + SOC_SINGLE_EXT("QUIN_MI2S_TX", QUINARY_MI2S_TX, CS_VOICE, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), +}; + +static const struct snd_kcontrol_new voicemmode1_tx_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), + SOC_SINGLE_EXT("QUIN_MI2S_TX", QUINARY_MI2S_TX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_capture, q6voice_put_mixer_capture), }; static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("CS-Voice", PRIMARY_MI2S_RX, 0, 1, 0, - q6voice_get_mixer, q6voice_put_mixer) + SOC_SINGLE_EXT("CS-Voice", PRIMARY_MI2S_RX, CS_VOICE, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), + SOC_SINGLE_EXT("VoiceMMode1", PRIMARY_MI2S_RX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), }; static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("CS-Voice", SECONDARY_MI2S_RX, 0, 1, 0, - q6voice_get_mixer, q6voice_put_mixer) + SOC_SINGLE_EXT("CS-Voice", SECONDARY_MI2S_RX, CS_VOICE, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), + SOC_SINGLE_EXT("VoiceMMode1", SECONDARY_MI2S_RX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), }; static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("CS-Voice", TERTIARY_MI2S_RX, 0, 1, 0, - q6voice_get_mixer, q6voice_put_mixer) + SOC_SINGLE_EXT("CS-Voice", TERTIARY_MI2S_RX, CS_VOICE, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), + SOC_SINGLE_EXT("VoiceMMode1", TERTIARY_MI2S_RX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), }; static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("CS-Voice", QUATERNARY_MI2S_RX, 0, 1, 0, - q6voice_get_mixer, q6voice_put_mixer) + SOC_SINGLE_EXT("CS-Voice", QUATERNARY_MI2S_RX, CS_VOICE, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), + SOC_SINGLE_EXT("VoiceMMode1", QUATERNARY_MI2S_RX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), }; static const struct snd_kcontrol_new quinary_mi2s_rx_mixer_controls[] = { - SOC_SINGLE_EXT("CS-Voice", QUINARY_MI2S_RX, 0, 1, 0, - q6voice_get_mixer, q6voice_put_mixer) + SOC_SINGLE_EXT("CS-Voice", QUINARY_MI2S_RX, CS_VOICE, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), + SOC_SINGLE_EXT("VoiceMMode1", QUINARY_MI2S_RX, VOICEMMODE1, 1, 0, + q6voice_get_mixer_playback, q6voice_put_mixer_playback), }; static const struct snd_soc_dapm_widget q6voice_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("CS-VOICE_DL1", "CS-VOICE Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("CS-VOICE_UL1", "CS-VOICE Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MIXER("CS-Voice Capture Mixer", SND_SOC_NOPM, 0, 0, - voice_tx_mixer_controls, - ARRAY_SIZE(voice_tx_mixer_controls)), + cs_voice_tx_mixer_controls, + ARRAY_SIZE(cs_voice_tx_mixer_controls)), + SND_SOC_DAPM_AIF_IN("VOICEMMODE1_DL1", "VOICEMMODE1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("VOICEMMODE1_UL1", "VOICEMMODE1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_MIXER("VoiceMMode1 Capture Mixer", SND_SOC_NOPM, 0, 0, + voicemmode1_tx_mixer_controls, + ARRAY_SIZE(voicemmode1_tx_mixer_controls)), SND_SOC_DAPM_MIXER("PRI_MI2S_RX Voice Mixer", SND_SOC_NOPM, 0, 0, primary_mi2s_rx_mixer_controls, ARRAY_SIZE(primary_mi2s_rx_mixer_controls)), @@ -178,12 +283,24 @@ static const struct snd_soc_dapm_route q6voice_dapm_routes[] = { { "CS-Voice Capture Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX" }, { "CS-Voice Capture Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX" }, { "CS-VOICE_UL1", NULL, "CS-Voice Capture Mixer" }, + { "VoiceMMode1 Capture Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX" }, + { "VoiceMMode1 Capture Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX" }, + { "VoiceMMode1 Capture Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX" }, + { "VoiceMMode1 Capture Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX" }, + { "VoiceMMode1 Capture Mixer", "QUIN_MI2S_TX", "QUIN_MI2S_TX" }, + { "VOICEMMODE1_UL1", NULL, "VoiceMMode1 Capture Mixer" }, { "PRI_MI2S_RX Voice Mixer", "CS-Voice", "CS-VOICE_DL1" }, { "SEC_MI2S_RX Voice Mixer", "CS-Voice", "CS-VOICE_DL1" }, { "TERT_MI2S_RX Voice Mixer", "CS-Voice", "CS-VOICE_DL1" }, { "QUAT_MI2S_RX Voice Mixer", "CS-Voice", "CS-VOICE_DL1" }, { "QUIN_MI2S_RX Voice Mixer", "CS-Voice", "CS-VOICE_DL1" }, + { "PRI_MI2S_RX Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL1" }, + { "SEC_MI2S_RX Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL1" }, + { "TERT_MI2S_RX Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL1" }, + { "QUAT_MI2S_RX Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL1" }, + { "QUIN_MI2S_RX Voice Mixer", "VoiceMMode1", "VOICEMMODE1_DL1" }, + { "PRI_MI2S_RX", NULL, "PRI_MI2S_RX Voice Mixer" }, { "SEC_MI2S_RX", NULL, "SEC_MI2S_RX Voice Mixer" }, { "TERT_MI2S_RX", NULL, "TERT_MI2S_RX Voice Mixer" }, diff --git a/sound/soc/qcom/qdsp6/q6voice.h b/sound/soc/qcom/qdsp6/q6voice.h index 5b2d2dd679b34d..13b058c7303ac9 100644 --- a/sound/soc/qcom/qdsp6/q6voice.h +++ b/sound/soc/qcom/qdsp6/q6voice.h @@ -3,14 +3,14 @@ #define _Q6_VOICE_H enum q6voice_path_type { - Q6VOICE_PATH_VOICE = 0, - /* TODO: Q6VOICE_PATH_VOIP = 1, */ - /* TODO: Q6VOICE_PATH_VOLTE = 2, */ - /* TODO: Q6VOICE_PATH_VOICE2 = 3, */ - /* TODO: Q6VOICE_PATH_QCHAT = 4, */ - /* TODO: Q6VOICE_PATH_VOWLAN = 5, */ - /* TODO: Q6VOICE_PATH_VOICEMMODE1 = 6, */ - /* TODO: Q6VOICE_PATH_VOICEMMODE2 = 7, */ + Q6VOICE_PATH_VOICE = 0, + Q6VOICE_PATH_VOIP = 1, + Q6VOICE_PATH_VOLTE = 2, + Q6VOICE_PATH_VOICE2 = 3, + Q6VOICE_PATH_QCHAT = 4, + Q6VOICE_PATH_VOWLAN = 5, + Q6VOICE_PATH_VOICEMMODE1 = 6, + Q6VOICE_PATH_VOICEMMODE2 = 7, Q6VOICE_PATH_COUNT };