diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/soc/codecs/twl6040.c | 72 | ||||
-rw-r--r-- | sound/soc/omap/omap-abe-dsp.c | 89 | ||||
-rw-r--r-- | sound/soc/omap/omap-abe.c | 354 | ||||
-rw-r--r-- | sound/soc/soc-dsp.c | 8 |
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); |