Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/dt-bindings/sound/qcom,q6voice.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
#define __DT_BINDINGS_Q6_VOICE_H__

#define CS_VOICE 0
#define VOICEMMODE1 1

#endif /* __DT_BINDINGS_Q6_VOICE_H__ */
14 changes: 14 additions & 0 deletions sound/soc/qcom/qdsp6/q6mvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
183 changes: 150 additions & 33 deletions sound/soc/qcom/qdsp6/q6voice-dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 */
Expand All @@ -77,83 +124,141 @@ 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);
struct soc_mixer_control *mc =
(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)),
Expand All @@ -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" },
Expand Down
16 changes: 8 additions & 8 deletions sound/soc/qcom/qdsp6/q6voice.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
};

Expand Down