aboutsummaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2011-09-15 19:47:48 -0700
committerColin Cross <ccross@android.com>2011-09-15 19:47:48 -0700
commita475c08e4ed22e996f32475aeb02aee600772e35 (patch)
tree13a78d3f3305c965bf4517f5370633b3a5c8a118 /sound
parent3049d563f3d6ce046279160adef2069e1dcadb8b (diff)
parent919cf0ce816b626f1d836d050a31463650f54526 (diff)
downloadkernel_samsung_tuna-a475c08e4ed22e996f32475aeb02aee600772e35.zip
kernel_samsung_tuna-a475c08e4ed22e996f32475aeb02aee600772e35.tar.gz
kernel_samsung_tuna-a475c08e4ed22e996f32475aeb02aee600772e35.tar.bz2
Merge branch 'linux-omap-3.0' into android-omap-3.0
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/twl6040.c72
-rw-r--r--sound/soc/omap/omap-abe-dsp.c89
-rw-r--r--sound/soc/omap/omap-abe.c354
-rw-r--r--sound/soc/soc-dsp.c8
4 files changed, 367 insertions, 156 deletions
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 508a122..06908dd 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -811,7 +811,23 @@ static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
+static int twl6040_hf_dac_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ priv->non_lp++;
+ else
+ priv->non_lp--;
+
+ msleep(1);
+
+ return 0;
+}
+
+static int twl6040_ep_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec = w->codec;
@@ -820,21 +836,15 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w,
if (SND_SOC_DAPM_EVENT_ON(event)) {
priv->non_lp++;
- if (!strcmp(w->name, "Earphone Enable")) {
- /* Earphone doesn't support low power mode */
- priv->power_mode_forced = 1;
- ret = headset_power_mode(codec, 1);
- }
+ /* Earphone doesn't support low power mode */
+ priv->power_mode_forced = 1;
+ ret = headset_power_mode(codec, 1);
} else {
priv->non_lp--;
- if (!strcmp(w->name, "Earphone Enable")) {
- priv->power_mode_forced = 0;
- ret = headset_power_mode(codec, priv->headset_mode);
- }
+ priv->power_mode_forced = 0;
+ ret = headset_power_mode(codec, priv->headset_mode);
}
- msleep(1);
-
return ret;
}
@@ -1096,6 +1106,11 @@ static const struct soc_enum twl6040_hf_enum[] = {
twl6040_hf_texts),
};
+static const char *twl6040_ep_texts[] = {"Off", "HS DAC"};
+
+static const struct soc_enum twl6040_virt_enum =
+ SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, twl6040_ep_texts);
+
static const struct snd_kcontrol_new amicl_control =
SOC_DAPM_ENUM("Route", twl6040_enum[0]);
@@ -1109,6 +1124,10 @@ static const struct snd_kcontrol_new hsl_mux_controls =
static const struct snd_kcontrol_new hsr_mux_controls =
SOC_DAPM_ENUM("Route", twl6040_hs_enum[1]);
+/* EP playback virtual mux */
+static const struct snd_kcontrol_new ep_virt_mux_controls =
+ SOC_DAPM_ENUM_VIRT("Route", twl6040_virt_enum);
+
/* Handsfree DAC playback switches */
static const struct snd_kcontrol_new hfl_mux_controls =
SOC_DAPM_ENUM("Route", twl6040_hf_enum[0]);
@@ -1116,9 +1135,6 @@ static const struct snd_kcontrol_new hfl_mux_controls =
static const struct snd_kcontrol_new hfr_mux_controls =
SOC_DAPM_ENUM("Route", twl6040_hf_enum[1]);
-static const struct snd_kcontrol_new ep_driver_switch_controls =
- SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0);
-
/* Headset power mode */
static const char *twl6040_headset_power_texts[] = {
"Low-Power", "High-Performance",
@@ -1244,11 +1260,11 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback",
TWL6040_REG_HFLCTL, 0, 0,
- twl6040_power_mode_event,
+ twl6040_hf_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_DAC_E("HFDAC Right", "Handsfree Playback",
TWL6040_REG_HFRCTL, 0, 0,
- twl6040_power_mode_event,
+ twl6040_hf_dac_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MUX("HF Left Playback",
@@ -1260,6 +1276,8 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
SND_SOC_NOPM, 0, 0, &hsl_mux_controls),
SND_SOC_DAPM_MUX("HS Right Playback",
SND_SOC_NOPM, 0, 0, &hsr_mux_controls),
+ SND_SOC_DAPM_MUX("Earphone Playback",
+ SND_SOC_NOPM, 0, 0, &ep_virt_mux_controls),
/* Analog playback drivers */
SND_SOC_DAPM_OUT_DRV_E("Handsfree Left Driver",
@@ -1278,15 +1296,16 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = {
TWL6040_REG_HSRCTL, 2, 0, NULL, 0,
pga_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
- SND_SOC_DAPM_SWITCH_E("Earphone Enable",
- SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls,
- twl6040_power_mode_event,
- SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_OUT_DRV_E("Earphone Driver",
- SND_SOC_NOPM, 0, 0, NULL, 0,
+ TWL6040_REG_EARCTL, 0, 0, NULL, 0,
pga_event,
SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+ /* Earphone virtual PGA (HS power mode) */
+ SND_SOC_DAPM_PGA_E("Earphone Power Mode", SND_SOC_NOPM,
+ 0, 0, NULL, 0, twl6040_ep_event,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
+
/* Analog playback PGAs */
SND_SOC_DAPM_PGA("HFDAC Left PGA",
TWL6040_REG_HFLCTL, 1, 0, NULL, 0),
@@ -1328,8 +1347,9 @@ static const struct snd_soc_dapm_route intercon[] = {
{"HSOR", NULL, "Headset Right Driver"},
/* Earphone playback path */
- {"Earphone Enable", "Switch", "HSDAC Left"},
- {"Earphone Driver", NULL, "Earphone Enable"},
+ {"Earphone Playback", "HS DAC", "HSDAC Left"},
+ {"Earphone Power Mode", NULL, "Earphone Playback"},
+ {"Earphone Driver", NULL, "Earphone Power Mode"},
{"EP", NULL, "Earphone Driver"},
{"HF Left Playback", "HF DAC", "HFDAC Left"},
@@ -1684,8 +1704,10 @@ static int twl6040_probe(struct snd_soc_codec *codec)
else
priv->ep_step = 1;
- /* default is low-power mode */
+ /* default headset power mode is high-performance */
priv->headset_mode = 1;
+
+ /* default is low-power mode */
priv->sysclk_constraints = &lp_constraints;
priv->workqueue = create_singlethread_workqueue("twl6040-codec");
diff --git a/sound/soc/omap/omap-abe-dsp.c b/sound/soc/omap/omap-abe-dsp.c
index fa6964c..c4c8e45 100644
--- a/sound/soc/omap/omap-abe-dsp.c
+++ b/sound/soc/omap/omap-abe-dsp.c
@@ -2057,41 +2057,74 @@ static int aess_set_runtime_opp_level(struct abe_data *abe)
return 0;
}
-static int aess_save_context(struct abe_data *abe)
+static void abe_dsp_init_gains(struct abe_data *abe)
{
- /* TODO: Find a better way to save/retore gains after OFF mode */
-
- abe_mute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
- abe_mute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
+ /* Uplink gains */
abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL);
abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES);
abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL);
+
abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES);
abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL);
abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL);
abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL);
- abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
- abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2);
- abe_mute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
- abe_mute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
- abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
- abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
- abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
- abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2);
- abe_mute_gain(MIXECHO, MIX_ECHO_DL1);
- abe_mute_gain(MIXECHO, MIX_ECHO_DL2);
+
abe_mute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
abe_mute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
abe_mute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
abe_mute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
abe_mute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
abe_mute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
+
abe_mute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
abe_mute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
+
abe_mute_gain(GAINS_BTUL, GAIN_LEFT_OFFSET);
abe_mute_gain(GAINS_BTUL, GAIN_RIGHT_OFFSET);
+ /* Downlink gains */
+ abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_5MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL1, GAIN_0dB, RAMP_5MS, GAIN_RIGHT_OFFSET);
+ abe_mute_gain(GAINS_DL1, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DL1, GAIN_RIGHT_OFFSET);
+
+ abe_write_gain(GAINS_DL2, GAIN_M7dB, RAMP_5MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL2, GAIN_M7dB, RAMP_5MS, GAIN_RIGHT_OFFSET);
+ abe_mute_gain(GAINS_DL2, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DL2, GAIN_RIGHT_OFFSET);
+
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2);
+
+ abe_mute_gain(MIXECHO, MIX_ECHO_DL1);
+ abe_mute_gain(MIXECHO, MIX_ECHO_DL2);
+
+ /* Sidetone gains */
+ abe_mute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
+ abe_mute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
+}
+
+static int aess_save_context(struct abe_data *abe)
+{
+ /* mute gains not associated with FEs/BEs */
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL);
+ abe_mute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL);
+ abe_mute_gain(MIXECHO, MIX_ECHO_DL1);
+ abe_mute_gain(MIXECHO, MIX_ECHO_DL2);
+
return 0;
}
@@ -2112,37 +2145,16 @@ static int aess_restore_context(struct abe_data *abe)
if (pdata->was_context_lost && pdata->was_context_lost(abe->dev))
abe_reload_fw(abe->firmware);
- /* TODO: Find a better way to save/retore gains after dor OFF mode */
- abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
- abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
+ /* unmute gains not associated with FEs/BEs */
abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_MM_DL);
abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_TONES);
- abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_VX_DL);
abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_TONES);
abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_DL);
abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_MM_DL);
abe_unmute_gain(MIXVXREC, MIX_VXREC_INPUT_VX_UL);
- abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
- abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2);
- abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
- abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
- abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
- abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
- abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
- abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2);
abe_unmute_gain(MIXECHO, MIX_ECHO_DL1);
abe_unmute_gain(MIXECHO, MIX_ECHO_DL2);
- abe_unmute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
- abe_unmute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
- abe_unmute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
- abe_unmute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
- abe_unmute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
- abe_unmute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
- abe_unmute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
- abe_unmute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
- abe_unmute_gain(GAINS_BTUL, GAIN_LEFT_OFFSET);
- abe_unmute_gain(GAINS_BTUL, GAIN_RIGHT_OFFSET);
abe_set_router_configuration(UPROUTE, 0, (u32 *)abe->router);
@@ -2692,6 +2704,9 @@ static int abe_probe(struct snd_soc_platform *platform)
/* "tick" of the audio engine */
abe_write_event_generator(EVENT_TIMER);
+
+ abe_dsp_init_gains(abe);
+
/* Stop the engine */
abe_stop_event_generator();
abe_disable_irq();
diff --git a/sound/soc/omap/omap-abe.c b/sound/soc/omap/omap-abe.c
index 6cb7d9f..95cfe86 100644
--- a/sound/soc/omap/omap-abe.c
+++ b/sound/soc/omap/omap-abe.c
@@ -61,8 +61,6 @@ struct omap_abe_data {
int suspended_dais;
};
-static int dl1_gain; /* dynamically set by machine drivers */
-
/*
* Stream DMA parameters
*/
@@ -152,7 +150,7 @@ static int modem_get_dai(struct snd_pcm_substream *substream,
abe_priv->modem_substream[substream->stream] =
snd_soc_get_dai_substream(rtd->card,
- OMAP_ABE_BE_MM_EXT1, substream->stream);
+ OMAP_ABE_BE_MM_EXT1, !substream->stream);
if (abe_priv->modem_substream[substream->stream] == NULL)
return -ENODEV;
@@ -166,64 +164,106 @@ static int modem_get_dai(struct snd_pcm_substream *substream,
int omap_abe_set_dl1_output(int output)
{
+ int gain;
+
/*
* the output itself is not important, but the DL1 gain
* to use when each output is active
*/
switch (output) {
case OMAP_ABE_DL1_HEADSET_LP:
- dl1_gain = GAIN_M8dB;
+ gain = GAIN_M8dB;
break;
case OMAP_ABE_DL1_HEADSET_HP:
case OMAP_ABE_DL1_EARPIECE:
- dl1_gain = GAIN_M1dB;
+ gain = GAIN_M1dB;
break;
case OMAP_ABE_DL1_NO_PDM:
- dl1_gain = GAIN_0dB;
+ gain = GAIN_0dB;
break;
default:
return -EINVAL;
}
+ abe_write_gain(GAINS_DL1, gain, RAMP_5MS, GAIN_LEFT_OFFSET);
+ abe_write_gain(GAINS_DL1, gain, RAMP_5MS, GAIN_RIGHT_OFFSET);
+
return 0;
}
EXPORT_SYMBOL(omap_abe_set_dl1_output);
+static int omap_abe_dl1_enabled(struct omap_abe_data *abe_priv)
+{
+ /* DL1 path is common for PDM_DL1, BT_VX_DL and MM_EXT_DL */
+ return omap_abe_port_is_enabled(abe_priv->abe,
+ abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]) +
+ omap_abe_port_is_enabled(abe_priv->abe,
+ abe_priv->port[OMAP_ABE_BE_PORT_BT_VX_DL]) +
+ omap_abe_port_is_enabled(abe_priv->abe,
+ abe_priv->port[OMAP_ABE_BE_PORT_MM_EXT_DL]);
+}
+
+static int omap_abe_dl2_enabled(struct omap_abe_data *abe_priv)
+{
+ return omap_abe_port_is_enabled(abe_priv->abe,
+ abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]);
+}
+
static void mute_be(struct snd_soc_pcm_runtime *be,
struct snd_soc_dai *dai, int stream)
{
+ struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
+
dev_dbg(&be->dev, "%s: %s %d\n", __func__, be->cpu_dai->name, stream);
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (be->dai_link->be_id) {
case OMAP_ABE_DAI_PDM_DL1:
- abe_write_gain(GAINS_DL1, MUTE_GAIN, RAMP_5MS,
- GAIN_LEFT_OFFSET);
- abe_write_gain(GAINS_DL1, MUTE_GAIN, RAMP_5MS,
- GAIN_RIGHT_OFFSET);
+ case OMAP_ABE_DAI_BT_VX:
+ case OMAP_ABE_DAI_MM_FM:
+ /*
+ * DL1 Mixer->SDT Mixer and DL1 gain are common for
+ * PDM_DL1, BT_VX_DL and MM_EXT_DL, mute those gains
+ * only if the last active BE
+ */
+ if (omap_abe_dl1_enabled(abe_priv) == 1) {
+ abe_mute_gain(GAINS_DL1, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DL1, GAIN_RIGHT_OFFSET);
+ abe_mute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
+ }
break;
case OMAP_ABE_DAI_PDM_DL2:
- abe_write_gain(GAINS_DL2, MUTE_GAIN, RAMP_5MS,
- GAIN_LEFT_OFFSET);
- abe_write_gain(GAINS_DL2, MUTE_GAIN, RAMP_5MS,
- GAIN_RIGHT_OFFSET);
+ abe_mute_gain(GAINS_DL2, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DL2, GAIN_RIGHT_OFFSET);
break;
case OMAP_ABE_DAI_PDM_VIB:
- case OMAP_ABE_DAI_BT_VX:
- case OMAP_ABE_DAI_MM_FM:
case OMAP_ABE_DAI_MODEM:
break;
}
} else {
switch (be->dai_link->be_id) {
case OMAP_ABE_DAI_PDM_UL:
+ abe_mute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
break;
case OMAP_ABE_DAI_BT_VX:
+ abe_mute_gain(GAINS_BTUL, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_BTUL, GAIN_RIGHT_OFFSET);
+ break;
case OMAP_ABE_DAI_MM_FM:
case OMAP_ABE_DAI_MODEM:
+ break;
case OMAP_ABE_DAI_DMIC0:
+ abe_mute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
+ break;
case OMAP_ABE_DAI_DMIC1:
+ abe_mute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
+ break;
case OMAP_ABE_DAI_DMIC2:
+ abe_mute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
+ abe_mute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
break;
}
}
@@ -239,20 +279,22 @@ static void unmute_be(struct snd_soc_pcm_runtime *be,
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
switch (be->dai_link->be_id) {
case OMAP_ABE_DAI_PDM_DL1:
- abe_write_gain(GAINS_DL1, dl1_gain, RAMP_5MS,
- GAIN_LEFT_OFFSET);
- abe_write_gain(GAINS_DL1, dl1_gain, RAMP_5MS,
- GAIN_RIGHT_OFFSET);
+ case OMAP_ABE_DAI_BT_VX:
+ case OMAP_ABE_DAI_MM_FM:
+ /*
+ * DL1 Mixer->SDT Mixer and DL1 gain are common for
+ * PDM_DL1, BT_VX_DL and MM_EXT_DL, unmute when any
+ * of them becomes active
+ */
+ abe_unmute_gain(GAINS_DL1, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DL1, GAIN_RIGHT_OFFSET);
+ abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_DL1_MIXER);
break;
case OMAP_ABE_DAI_PDM_DL2:
- abe_write_gain(GAINS_DL2, GAIN_M7dB, RAMP_5MS,
- GAIN_LEFT_OFFSET);
- abe_write_gain(GAINS_DL2, GAIN_M7dB, RAMP_5MS,
- GAIN_RIGHT_OFFSET);
+ abe_unmute_gain(GAINS_DL2, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DL2, GAIN_RIGHT_OFFSET);
break;
case OMAP_ABE_DAI_PDM_VIB:
- case OMAP_ABE_DAI_BT_VX:
- case OMAP_ABE_DAI_MM_FM:
break;
case OMAP_ABE_DAI_MODEM:
if (omap_abe_port_is_enabled(abe_priv->abe,
@@ -270,14 +312,32 @@ static void unmute_be(struct snd_soc_pcm_runtime *be,
switch (be->dai_link->be_id) {
case OMAP_ABE_DAI_PDM_UL:
+ abe_unmute_gain(GAINS_AMIC, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_AMIC, GAIN_RIGHT_OFFSET);
break;
case OMAP_ABE_DAI_BT_VX:
+ abe_reset_mic_ul_src_filters();
+ abe_unmute_gain(GAINS_BTUL, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_BTUL, GAIN_RIGHT_OFFSET);
+ break;
case OMAP_ABE_DAI_MM_FM:
case OMAP_ABE_DAI_MODEM:
+ abe_reset_mic_ul_src_filters();
+ break;
case OMAP_ABE_DAI_DMIC0:
+ abe_reset_mic_ul_src_filters();
+ abe_unmute_gain(GAINS_DMIC1, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC1, GAIN_RIGHT_OFFSET);
+ break;
case OMAP_ABE_DAI_DMIC1:
+ abe_reset_mic_ul_src_filters();
+ abe_unmute_gain(GAINS_DMIC2, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC2, GAIN_RIGHT_OFFSET);
+ break;
case OMAP_ABE_DAI_DMIC2:
abe_reset_mic_ul_src_filters();
+ abe_unmute_gain(GAINS_DMIC3, GAIN_LEFT_OFFSET);
+ abe_unmute_gain(GAINS_DMIC3, GAIN_RIGHT_OFFSET);
break;
}
}
@@ -511,88 +571,184 @@ static void disable_fe_port(struct snd_pcm_substream *substream,
}
}
-static void mute_fe_port(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai, int stream)
+static void mute_fe_port_capture(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int mute)
{
- struct snd_soc_pcm_runtime *fe = substream->private_data;
- struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
+ struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(fe->cpu_dai);
- dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream);
+ dev_dbg(&fe->dev, "%s: %s FE %s BE %s\n",
+ __func__, mute ? "mute" : "unmute",
+ fe->dai_link->name, be->dai_link->name);
- switch(dai->id) {
- case ABE_FRONTEND_DAI_MEDIA:
- case ABE_FRONTEND_DAI_LP_MEDIA:
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
- abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
- abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ switch (fe->cpu_dai->id) {
+ case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
+ if (omap_abe_dl1_enabled(abe_priv)) {
+ if (mute)
+ abe_mute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2);
+ else
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_UL2);
+ }
+ if (omap_abe_dl2_enabled(abe_priv)) {
+ if (mute)
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2);
+ else
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_UL2);
+ }
break;
- case ABE_FRONTEND_DAI_VOICE:
case ABE_FRONTEND_DAI_MODEM:
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
- abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
- abe_mute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
- break;
- case ABE_FRONTEND_DAI_TONES:
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
- abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
- abe_mute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+ case ABE_FRONTEND_DAI_VOICE:
+ if (mute) {
+ abe_mute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
+ abe_mute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
+ } else {
+ abe_unmute_gain(MIXSDT, MIX_SDT_INPUT_UP_MIXER);
+ abe_unmute_gain(MIXAUDUL, MIX_AUDUL_INPUT_UPLINK);
+ }
break;
- case ABE_FRONTEND_DAI_VIBRA:
- case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
+ case ABE_FRONTEND_DAI_MEDIA:
+ default:
break;
}
}
-static void unmute_fe_port(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai, int stream)
+static void mute_fe_port_playback(struct snd_soc_pcm_runtime *fe,
+ struct snd_soc_pcm_runtime *be, int mute)
{
- struct snd_soc_pcm_runtime *fe = substream->private_data;
- struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
+ struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(fe->cpu_dai);
- dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream);
+ dev_dbg(&fe->dev, "%s: %s FE %s BE %s\n",
+ __func__, mute ? "mute" : "unmute",
+ fe->dai_link->name, be->dai_link->name);
- switch(dai->id) {
+ switch (fe->cpu_dai->id) {
case ABE_FRONTEND_DAI_MEDIA:
case ABE_FRONTEND_DAI_LP_MEDIA:
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
- abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
- abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ switch (be->dai_link->be_id) {
+ case OMAP_ABE_DAI_PDM_DL1:
+ case OMAP_ABE_DAI_BT_VX:
+ case OMAP_ABE_DAI_MM_FM:
+ if (mute) {
+ /* mute if last running DL1-related BE */
+ if (omap_abe_dl1_enabled(abe_priv) == 1)
+ abe_mute_gain(MIXDL1,
+ MIX_DL1_INPUT_MM_DL);
+ } else {
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_MM_DL);
+ }
+ break;
+ case OMAP_ABE_DAI_PDM_DL2:
+ if (mute)
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ else
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_MM_DL);
+ break;
+ case OMAP_ABE_DAI_MODEM:
+ case OMAP_ABE_DAI_PDM_VIB:
+ default:
+ break;
+ }
break;
case ABE_FRONTEND_DAI_VOICE:
case ABE_FRONTEND_DAI_MODEM:
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
- abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
- abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ switch (be->dai_link->be_id) {
+ case OMAP_ABE_DAI_PDM_DL1:
+ case OMAP_ABE_DAI_BT_VX:
+ case OMAP_ABE_DAI_MM_FM:
+ if (mute) {
+ /* mute if last running DL1-related BE */
+ if (omap_abe_dl1_enabled(abe_priv) == 1)
+ abe_mute_gain(MIXDL1,
+ MIX_DL1_INPUT_VX_DL);
+ } else {
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_VX_DL);
+ }
+ break;
+ case OMAP_ABE_DAI_PDM_DL2:
+ if (mute)
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ else
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_VX_DL);
+ break;
+ case OMAP_ABE_DAI_MODEM:
+ case OMAP_ABE_DAI_PDM_VIB:
+ default:
+ break;
+ }
break;
case ABE_FRONTEND_DAI_TONES:
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL2]))
- abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
- if (omap_abe_port_is_enabled(abe_priv->abe,
- abe_priv->port[OMAP_ABE_BE_PORT_PDM_DL1]))
- abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+ switch (be->dai_link->be_id) {
+ case OMAP_ABE_DAI_PDM_DL1:
+ case OMAP_ABE_DAI_BT_VX:
+ case OMAP_ABE_DAI_MM_FM:
+ if (mute) {
+ /* mute if last running DL1-related BE */
+ if (omap_abe_dl1_enabled(abe_priv) == 1)
+ abe_mute_gain(MIXDL1,
+ MIX_DL1_INPUT_TONES);
+ } else{
+ abe_unmute_gain(MIXDL1, MIX_DL1_INPUT_TONES);
+ }
+ break;
+ case OMAP_ABE_DAI_PDM_DL2:
+ if (mute)
+ abe_mute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
+ else
+ abe_unmute_gain(MIXDL2, MIX_DL2_INPUT_TONES);
+ break;
+ case OMAP_ABE_DAI_MODEM:
+ case OMAP_ABE_DAI_PDM_VIB:
+ default:
+ break;
+ }
break;
case ABE_FRONTEND_DAI_VIBRA:
- case ABE_FRONTEND_DAI_MEDIA_CAPTURE:
+ default:
break;
}
}
+static void mute_fe_port(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai, int stream)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ struct snd_soc_dsp_params *dsp_params;
+
+ dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream);
+
+ list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dsp_params->be;
+
+ if (!snd_soc_dsp_is_op_for_be(fe, be, stream))
+ continue;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mute_fe_port_playback(fe, be, 1);
+ else
+ mute_fe_port_capture(fe, be, 1);
+ }
+}
+
+static void unmute_fe_port(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai, int stream)
+{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
+ struct snd_soc_dsp_params *dsp_params;
+
+ dev_dbg(&fe->dev, "%s: %s %d\n", __func__, dai->name, stream);
+
+ list_for_each_entry(dsp_params, &fe->dsp[stream].be_clients, list_be) {
+ struct snd_soc_pcm_runtime *be = dsp_params->be;
+
+ if (!snd_soc_dsp_is_op_for_be(fe, be, stream))
+ continue;
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+ mute_fe_port_playback(fe, be, 0);
+ else
+ mute_fe_port_capture(fe, be, 0);
+ }
+}
+
static void capture_trigger(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai, int cmd)
{
@@ -640,6 +796,9 @@ static void capture_trigger(struct snd_pcm_substream *substream,
/* Enable Frontend sDMA */
snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
enable_fe_port(substream, dai, stream);
+
+ /* unmute FE port */
+ unmute_fe_port(substream, dai, stream);
}
/* Restore ABE GAINS AMIC */
@@ -665,9 +824,11 @@ static void capture_trigger(struct snd_pcm_substream *substream,
snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
break;
case SNDRV_PCM_TRIGGER_STOP:
-
/* does this trigger() apply to the FE ? */
if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) {
+ /* mute FE port */
+ mute_fe_port(substream, dai, stream);
+
/* Disable sDMA */
disable_fe_port(substream, dai, stream);
snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
@@ -691,6 +852,9 @@ static void capture_trigger(struct snd_pcm_substream *substream,
be_substream = snd_soc_dsp_get_substream(be, stream);
+ /* mute the BE port */
+ mute_be(be, dai, stream);
+
/* disable the BE port */
disable_be_port(be, dai, stream);
@@ -756,14 +920,14 @@ static void playback_trigger(struct snd_pcm_substream *substream,
/* does this trigger() apply to the FE ? */
if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) {
-
/* Enable Frontend sDMA */
snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
enable_fe_port(substream, dai, stream);
-
- /* unmute FE port */
- unmute_fe_port(substream, dai, stream);
}
+
+ /* unmute FE port (sensitive to runtime udpates) */
+ unmute_fe_port(substream, dai, stream);
+
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/* Enable Frontend sDMA */
@@ -784,11 +948,11 @@ static void playback_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
+ /* mute FE port (sensitive to runtime udpates) */
+ mute_fe_port(substream, dai, stream);
+
/* does this trigger() apply to the FE ? */
if (snd_soc_dsp_is_trigger_for_fe(fe, stream)) {
- /* mute FE port */
- mute_fe_port(substream, dai, stream);
-
/* disable the transfer */
disable_fe_port(substream, dai, stream);
snd_soc_dsp_platform_trigger(substream, cmd, fe->platform);
@@ -812,6 +976,9 @@ static void playback_trigger(struct snd_pcm_substream *substream,
be_substream = snd_soc_dsp_get_substream(be, stream);
+ /* mute the BE port */
+ mute_be(be, dai, stream);
+
/* disable the BE */
disable_be_port(be, dai, stream);
@@ -1061,12 +1228,14 @@ static int omap_abe_dai_trigger(struct snd_pcm_substream *substream,
static int omap_abe_dai_bespoke_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai)
{
+ struct snd_soc_pcm_runtime *fe = substream->private_data;
struct omap_abe_data *abe_priv = snd_soc_dai_get_drvdata(dai);
int ret = 0;
dev_dbg(dai->dev, "%s: %s cmd %d\n", __func__, dai->name, cmd);
- if (dai->id == ABE_FRONTEND_DAI_MODEM) {
+ if ((dai->id == ABE_FRONTEND_DAI_MODEM) &&
+ snd_soc_dsp_is_trigger_for_fe(fe, substream->stream)) {
dev_dbg(abe_priv->modem_dai->dev, "%s: MODEM stream %d cmd %d\n",
__func__, substream->stream, cmd);
@@ -1235,9 +1404,6 @@ static int omap_abe_dai_probe(struct snd_soc_dai *dai)
}
snd_soc_dai_set_drvdata(dai, abe_priv);
-
- dl1_gain = GAIN_0dB;
-
return 0;
err_port:
diff --git a/sound/soc/soc-dsp.c b/sound/soc/soc-dsp.c
index ebb3dd7..24c8e5e 100644
--- a/sound/soc/soc-dsp.c
+++ b/sound/soc/soc-dsp.c
@@ -1124,6 +1124,10 @@ int soc_dsp_runtime_update(struct snd_soc_dapm_widget *widget)
/* DAPM sync will call this to update DSP paths */
dev_dbg(card->dev, "DSP runtime update for FE %s\n", fe->dai_link->name);
+ /* skip if FE doesn't have playback capability */
+ if (!fe->cpu_dai->driver->playback.channels_min)
+ goto capture;
+
/* update any playback paths */
start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1);
stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_PLAYBACK, 1);
@@ -1142,6 +1146,10 @@ int soc_dsp_runtime_update(struct snd_soc_dapm_widget *widget)
fe_clear_pending(fe, SNDRV_PCM_STREAM_PLAYBACK);
capture:
+ /* skip if FE doesn't have capture capability */
+ if (!fe->cpu_dai->driver->capture.channels_min)
+ continue;
+
/* update any capture paths */
start = dsp_add_new_paths(fe, SNDRV_PCM_STREAM_CAPTURE, 1);
stop = dsp_prune_old_paths(fe, SNDRV_PCM_STREAM_CAPTURE, 1);