diff options
-rw-r--r-- | sound/soc/codecs/ab8500_audio.c | 137 | ||||
-rw-r--r-- | sound/soc/codecs/ab8500_audio.h | 4 | ||||
-rw-r--r-- | sound/soc/ux500/ux500_ab8500.c | 203 |
3 files changed, 199 insertions, 145 deletions
diff --git a/sound/soc/codecs/ab8500_audio.c b/sound/soc/codecs/ab8500_audio.c index 5d51727ab76..3665e3815ce 100644 --- a/sound/soc/codecs/ab8500_audio.c +++ b/sound/soc/codecs/ab8500_audio.c @@ -668,44 +668,69 @@ static const struct snd_kcontrol_new dapm_pwm2vib2[] = { SOC_DAPM_ENUM("Vibra 2 Controller", dapm_enum_pwm2vib2), }; -/* DAPM-widgets */ - static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { - /* Headset path */ - SND_SOC_DAPM_AIF_IN("DA_IN1", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("DA_IN2", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + /* DA/AD */ - /* XXX SwapDA12_34 */ + SND_SOC_DAPM_INPUT("ADC Input"), + SND_SOC_DAPM_DAC("ADC", "ab8500_0c", SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_MIXER("DA1 Channel Gain", REG_DAPATHENA, - REG_DAPATHENA_ENDA1, 0, NULL, 0), - SND_SOC_DAPM_MIXER("DA2 Channel Gain", REG_DAPATHENA, - REG_DAPATHENA_ENDA2, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC", "ab8500_0p", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("DAC Output"), - SND_SOC_DAPM_MIXER("HSL Digital Gain", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MIXER("HSR Digital Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_AIF_IN("DA_IN1", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DA_IN2", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DA_IN3", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DA_IN4", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DA_IN5", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DA_IN6", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AD_OUT1", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AD_OUT2", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AD_OUT3", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AD_OUT4", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AD_OUT57", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AD_OUT68", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), + + /* Headset path */ - SND_SOC_DAPM_MIXER("HSL DAC", REG_DAPATHCONF, - REG_DAPATHCONF_ENDACHSL, 0, NULL, 0), - SND_SOC_DAPM_MIXER("HSR DAC", REG_DAPATHCONF, - REG_DAPATHCONF_ENDACHSR, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Charge Pump", REG_ANACONF5, REG_ANACONF5_ENCPHS, 0, NULL, 0), - SND_SOC_DAPM_MIXER("HSL DAC Driver", REG_ANACONF3, - REG_ANACONF3_ENDRVHSL, 0, NULL, 0), - SND_SOC_DAPM_MIXER("HSR DAC Driver", REG_ANACONF3, - REG_ANACONF3_ENDRVHSR, 0, NULL, 0), + SND_SOC_DAPM_DAC("DA1 Enable", "ab8500_0c", + REG_DAPATHENA, REG_DAPATHENA_ENDA1, 0), + SND_SOC_DAPM_DAC("DA2 Enable", "ab8500_0c", + REG_DAPATHENA, REG_DAPATHENA_ENDA2, 0), SND_SOC_DAPM_SWITCH("Headset Left", SND_SOC_NOPM, 0, 0, dapm_hsl_mute), SND_SOC_DAPM_SWITCH("Headset Right", SND_SOC_NOPM, 0, 0, dapm_hsr_mute), - SND_SOC_DAPM_MIXER("HSL Enable", REG_ANACONF4, - REG_ANACONF4_ENHSL, 0, NULL, 0), - SND_SOC_DAPM_MIXER("HSR Enable", REG_ANACONF4, - REG_ANACONF4_ENHSR, 0, NULL, 0), - - SND_SOC_DAPM_MIXER("Charge Pump", REG_ANACONF5, - REG_ANACONF5_ENCPHS, 0, NULL, 0), + SND_SOC_DAPM_PGA("HSL Digital Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("HSR Digital Gain", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_DAC("HSL DAC", "ab8500_0c", + REG_DAPATHCONF, REG_DAPATHCONF_ENDACHSL, 0), + SND_SOC_DAPM_DAC("HSR DAC", "ab8500_0c", + REG_DAPATHCONF, REG_DAPATHCONF_ENDACHSR, 0), + SND_SOC_DAPM_MIXER("HSL DAC Mute", REG_MUTECONF, REG_MUTECONF_MUTDACHSL, + INVERT, NULL, 0), + SND_SOC_DAPM_MIXER("HSR DAC Mute", REG_MUTECONF, REG_MUTECONF_MUTDACHSR, + INVERT, NULL, 0), + SND_SOC_DAPM_DAC("HSL DAC Driver", "ab8500_0c", + REG_ANACONF3, REG_ANACONF3_ENDRVHSL, 0), + SND_SOC_DAPM_DAC("HSR DAC Driver", "ab8500_0c", + REG_ANACONF3, REG_ANACONF3_ENDRVHSR, 0), + + SND_SOC_DAPM_MIXER("HSL Mute", REG_MUTECONF, REG_MUTECONF_MUTHSL, + INVERT, NULL, 0), + SND_SOC_DAPM_MIXER("HSR Mute", REG_MUTECONF, REG_MUTECONF_MUTHSR, + INVERT, NULL, 0), + SND_SOC_DAPM_MIXER("HSL Enable", REG_ANACONF4, REG_ANACONF4_ENHSL, + NORMAL, NULL, 0), + SND_SOC_DAPM_MIXER("HSR Enable", REG_ANACONF4, REG_ANACONF4_ENHSR, + NORMAL, NULL, 0), + SND_SOC_DAPM_PGA("HSL Gain", SND_SOC_NOPM, 0, + 0, NULL, 0), + SND_SOC_DAPM_PGA("HSR Gain", SND_SOC_NOPM, 0, + 0, NULL, 0), SND_SOC_DAPM_OUTPUT("HSL"), SND_SOC_DAPM_OUTPUT("HSR"), @@ -743,11 +768,6 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { /* Handsfree path */ - SND_SOC_DAPM_AIF_IN("DA_IN3", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("DA_IN4", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), - - /* XXX SwapDA12_34 */ - SND_SOC_DAPM_MIXER("DA3 Channel Gain", REG_DAPATHENA, REG_DAPATHENA_ENDA3, 0, NULL, 0), SND_SOC_DAPM_MIXER("DA4 Channel Gain", REG_DAPATHENA, @@ -784,8 +804,6 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { /* Vibrator path */ - SND_SOC_DAPM_AIF_IN("DA_IN5", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_IN("DA_IN6", "ab8500_0p", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_MUX("Vibra 1", SND_SOC_NOPM, 0, 0, &dapm_vibra1_mux), SND_SOC_DAPM_MUX("Vibra 2", SND_SOC_NOPM, 0, 0, &dapm_vibra2_mux), SND_SOC_DAPM_MIXER("DA5 Channel Gain", REG_DAPATHENA, @@ -850,9 +868,6 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { SND_SOC_DAPM_MIXER("AD12 Enable", REG_ADPATHENA, REG_ADPATHENA_ENAD12, 0, NULL, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT1", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT2", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), - /* Microphone 1 path */ SND_SOC_DAPM_INPUT("MIC1 Input"), @@ -876,8 +891,6 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { SND_SOC_DAPM_MIXER("AD3 Enable", REG_ADPATHENA, REG_ADPATHENA_ENAD34, 0, NULL, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT3", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), - /* HD Capture path */ SND_SOC_DAPM_MUX("AD 5 Select Capture Route", @@ -893,9 +906,6 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { SND_SOC_DAPM_MIXER("AD68 Enable", REG_ADPATHENA, REG_ADPATHENA_ENAD5768, 0, NULL, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT57", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), - SND_SOC_DAPM_AIF_OUT("AD_OUT68", "ab8500_0c", 0, SND_SOC_NOPM, 0, 0), - /* Digital Microphone path */ SND_SOC_DAPM_INPUT("DMIC Input"), @@ -947,31 +957,45 @@ static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { /* DAPM-routes */ static const struct snd_soc_dapm_route dapm_routes[] = { + /* AD/DA */ + {"ADC", NULL, "ADC Input"}, + {"DAC Output", NULL, "DAC"}, + + /* Powerup charge pump if DA1/2 is in use */ + {"DA_IN1", NULL, "Charge Pump"}, + {"DA_IN2", NULL, "Charge Pump"}, + /* Headset path */ - {"DA1 Channel Gain", NULL, "DA_IN1"}, - {"DA2 Channel Gain", NULL, "DA_IN2"}, + {"DA1 Enable", NULL, "DA_IN1"}, + {"DA2 Enable", NULL, "DA_IN2"}, - {"HSL Digital Gain", NULL, "DA1 Channel Gain"}, - {"HSR Digital Gain", NULL, "DA2 Channel Gain"}, + {"HSL Digital Gain", NULL, "DA1 Enable"}, + {"HSR Digital Gain", NULL, "DA2 Enable"}, {"HSL DAC", NULL, "HSL Digital Gain"}, {"HSR DAC", NULL, "HSR Digital Gain"}, - {"HSL DAC Driver", NULL, "HSL DAC"}, - {"HSR DAC Driver", NULL, "HSR DAC"}, + {"HSL DAC Mute", NULL, "HSL DAC"}, + {"HSR DAC Mute", NULL, "HSR DAC"}, + + {"HSL DAC Driver", NULL, "HSL DAC Mute"}, + {"HSR DAC Driver", NULL, "HSR DAC Mute"}, - {"Headset Left", "Playback Switch", "HSL DAC Driver"}, - {"Headset Right", "Playback Switch", "HSR DAC Driver"}, + {"HSL Mute", NULL, "HSL DAC Driver"}, + {"HSR Mute", NULL, "HSR DAC Driver"}, + + {"Headset Left", "Playback Switch", "HSL Mute"}, + {"Headset Right", "Playback Switch", "HSR Mute"}, {"HSL Enable", NULL, "Headset Left"}, {"HSR Enable", NULL, "Headset Right"}, - {"Charge Pump", NULL, "HSL Enable"}, - {"Charge Pump", NULL, "HSR Enable"}, + {"HSL Gain", NULL, "HSL Enable"}, + {"HSR Gain", NULL, "HSR Enable"}, - {"HSL", NULL, "Charge Pump"}, - {"HSR", NULL, "Charge Pump"}, + {"HSL", NULL, "HSL Gain"}, + {"HSR", NULL, "HSR Gain"}, /* IHF or Lineout path */ @@ -1036,7 +1060,6 @@ static const struct snd_soc_dapm_route dapm_routes[] = { {"IHFL", NULL, "IHF or Lineout Select"}, {"IHFR", NULL, "IHF or Lineout Select"}, - /* Vibrator path */ {"DA5 Channel Gain", NULL, "DA_IN5"}, @@ -1179,8 +1202,8 @@ static const struct snd_soc_dapm_route dapm_routes[] = { {"STFIR1 Gain", NULL, "STFIR1 Control"}, {"STFIR2 Gain", NULL, "STFIR2 Control"}, - {"DA1 Channel Gain", NULL, "STFIR1 Gain"}, - {"DA2 Channel Gain", NULL, "STFIR2 Gain"}, + {"DA1 Enable", NULL, "STFIR1 Gain"}, + {"DA2 Enable", NULL, "STFIR2 Gain"}, }; /* Controls - Non-DAPM ASoC */ diff --git a/sound/soc/codecs/ab8500_audio.h b/sound/soc/codecs/ab8500_audio.h index 4ac8220d8d6..bfdd2eb2ec8 100644 --- a/sound/soc/codecs/ab8500_audio.h +++ b/sound/soc/codecs/ab8500_audio.h @@ -246,6 +246,10 @@ bool ab8500_audio_dapm_path_active(enum ab8500_audio_dapm_path dapm_path); #define REG_MUTECONF_MUTEAR 6 #define REG_MUTECONF_MUTHSL 5 #define REG_MUTECONF_MUTHSR 4 +#define REG_MUTECONF_MUTDACEAR 2 +#define REG_MUTECONF_MUTDACHSL 1 +#define REG_MUTECONF_MUTDACHSR 0 + /* REG_SHORTCIRCONF */ diff --git a/sound/soc/ux500/ux500_ab8500.c b/sound/soc/ux500/ux500_ab8500.c index c7799c3415b..a85b7215ff0 100644 --- a/sound/soc/ux500/ux500_ab8500.c +++ b/sound/soc/ux500/ux500_ab8500.c @@ -161,6 +161,81 @@ err_get: return status; } +/* Power/clock control */ + +static int ux500_ab8500_power_control_inc(void) +{ + int ret; + + mutex_lock(&power_lock); + + ab8500_power_count++; + pr_debug("%s: ab8500_power_count changed from %d to %d", + __func__, + ab8500_power_count-1, + ab8500_power_count); + + if (ab8500_power_count == 1) { + /* Turn on audio-regulator */ + ret = enable_regulator(REGULATOR_AUDIO); + + /* Enable audio-clock */ + ret = clk_set_parent(clk_ptr_intclk, + (master_clock_sel == 0) ? clk_ptr_sysclk : clk_ptr_ulpclk); + if (ret) { + pr_err("%s: ERROR: Setting master-clock to %s failed (ret = %d)!", + __func__, + (master_clock_sel == 0) ? "SYSCLK" : "ULPCLK", + ret); + return ret; + } + pr_debug("%s: Enabling master-clock (%s).", + __func__, + (master_clock_sel == 0) ? "SYSCLK" : "ULPCLK"); + ret = clk_enable(clk_ptr_audioclk); + if (ret) { + pr_err("%s: ERROR: clk_enable failed (ret = %d)!", __func__, ret); + ab8500_power_count = 0; + return ret; + } + + /* Power on audio-parts of AB8500 */ + ab8500_audio_power_control(true); + } + + mutex_unlock(&power_lock); + + return 0; +} + +static void ux500_ab8500_power_control_dec(void) +{ + mutex_lock(&power_lock); + + ab8500_power_count--; + + pr_debug("%s: ab8500_power_count changed from %d to %d", + __func__, + ab8500_power_count+1, + ab8500_power_count); + + if (ab8500_power_count == 0) { + /* Power off audio-parts of AB8500 */ + ab8500_audio_power_control(false); + + /* Disable audio-clock */ + pr_debug("%s: Disabling master-clock (%s).", + __func__, + (master_clock_sel == 0) ? "SYSCLK" : "ULPCLK"); + clk_disable(clk_ptr_audioclk); + + /* Turn off audio-regulator */ + disable_regulator(REGULATOR_AUDIO); + } + + mutex_unlock(&power_lock); +} + /* Controls - Non-DAPM Non-ASoC */ static int mclk_input_control_info(struct snd_kcontrol *kcontrol, @@ -212,6 +287,18 @@ static const struct snd_kcontrol_new mclk_input_control = { /* DAPM-events */ +static int dapm_audioreg_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) + ux500_ab8500_power_control_inc(); + else + ux500_ab8500_power_control_dec(); + + return 0; +} + + static int dapm_mic1reg_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { @@ -254,19 +341,40 @@ static int dapm_dmicreg_event(struct snd_soc_dapm_widget *w, /* DAPM-widgets */ static const struct snd_soc_dapm_widget ux500_ab8500_dapm_widgets[] = { - SND_SOC_DAPM_MIC("MIC1 Regulator", dapm_mic1reg_event), - SND_SOC_DAPM_MIC("MIC2 Regulator", dapm_mic2reg_event), - SND_SOC_DAPM_MIC("DMIC Regulator", dapm_dmicreg_event), + SND_SOC_DAPM_SUPPLY("AUDIO Regulator", SND_SOC_NOPM, 0, 0, dapm_audioreg_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("AMIC1 Regulator", SND_SOC_NOPM, 0, 0, dapm_mic1reg_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("AMIC2 Regulator", SND_SOC_NOPM, 0, 0, dapm_mic2reg_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("DMIC Regulator", SND_SOC_NOPM, 0, 0, dapm_dmicreg_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), }; /* DAPM-routes */ static const struct snd_soc_dapm_route ux500_ab8500_dapm_intercon[] = { - {"MIC1 Input", NULL, "MIC1 Regulator"}, - {"MIC2 Input", NULL, "MIC2 Regulator"}, - {"DMIC Input", NULL, "DMIC Regulator"}, + + /* Power AB8500 audio-block when AD/DA is active */ + {"DAC", NULL, "AUDIO Regulator"}, + {"ADC", NULL, "AUDIO Regulator"}, + + /* Power AMIC1-regulator when MIC1 is enabled */ + {"MIC1 Enable", NULL, "AMIC1 Regulator"}, + + /* Power AMIC2-regulator when MIC1 is enabled */ + {"MIC2 Enable", NULL, "AMIC2 Regulator"}, + + /* Power DMIC-regulator when any digital mic is enabled */ + {"DMic 1", NULL, "DMIC Regulator"}, + {"DMic 2", NULL, "DMIC Regulator"}, + {"DMic 3", NULL, "DMIC Regulator"}, + {"DMic 4", NULL, "DMIC Regulator"}, + {"DMic 5", NULL, "DMIC Regulator"}, + {"DMic 6", NULL, "DMIC Regulator"}, }; + static int add_widgets(struct snd_soc_codec *codec) { int ret; @@ -292,84 +400,6 @@ static int add_widgets(struct snd_soc_codec *codec) return 0; } -/* Power/clock control */ - -static int ux500_ab8500_power_control_inc(void) -{ - int ret; - - mutex_lock(&power_lock); - - ab8500_power_count++; - pr_debug("%s: ab8500_power_count changed from %d to %d", - __func__, - ab8500_power_count-1, - ab8500_power_count); - - if (ab8500_power_count == 1) { - ret = clk_set_parent(clk_ptr_intclk, - (master_clock_sel == 0) ? clk_ptr_sysclk : clk_ptr_ulpclk); - if (ret) { - pr_err("%s: ERROR: Setting master-clock to %s failed (ret = %d)!", - __func__, - (master_clock_sel == 0) ? "SYSCLK" : "ULPCLK", - ret); - return ret; - } - - pr_debug("%s: Enabling master-clock (%s).", - __func__, - (master_clock_sel == 0) ? "SYSCLK" : "ULPCLK"); - - /* Enable audio-clock */ - ret = clk_enable(clk_ptr_audioclk); - if (ret) { - pr_err("%s: ERROR: clk_enable failed (ret = %d)!", __func__, ret); - ab8500_power_count = 0; - return ret; - } - - /* Power on audio-parts of AB8500 */ - ab8500_audio_power_control(true); - - /* Turn on audio-regulator */ - ret = enable_regulator(REGULATOR_AUDIO); - } - - mutex_unlock(&power_lock); - - return 0; -} - -static void ux500_ab8500_power_control_dec(void) -{ - mutex_lock(&power_lock); - - ab8500_power_count--; - - pr_debug("%s: ab8500_power_count changed from %d to %d", - __func__, - ab8500_power_count+1, - ab8500_power_count); - - if (ab8500_power_count == 0) { - pr_debug("%s: Disabling master-clock (%s).", - __func__, - (master_clock_sel == 0) ? "SYSCLK" : "ULPCLK"); - - /* Disable audio-clock */ - clk_disable(clk_ptr_audioclk); - - /* Power off audio-parts of AB8500 */ - ab8500_audio_power_control(false); - - /* Turn off audio-regulator */ - disable_regulator(REGULATOR_AUDIO); - } - - mutex_unlock(&power_lock); -} - /* ASoC */ int ux500_ab8500_startup(struct snd_pcm_substream *substream) @@ -385,7 +415,7 @@ int ux500_ab8500_startup(struct snd_pcm_substream *substream) return ret; } - return ux500_ab8500_power_control_inc(); + return 0; } void ux500_ab8500_shutdown(struct snd_pcm_substream *substream) @@ -399,7 +429,6 @@ void ux500_ab8500_shutdown(struct snd_pcm_substream *substream) rx_slots = DEF_RX_SLOTS; clk_disable(clk_ptr_gpio1); - ux500_ab8500_power_control_dec(); } int ux500_ab8500_hw_params(struct snd_pcm_substream *substream, @@ -528,8 +557,6 @@ int ux500_ab8500_machine_codec_init(struct snd_soc_pcm_runtime *rtd) pr_debug("%s Enter.\n", __func__); - /* TODO: Add required DAPM routes to control regulators on demand */ - ret = snd_soc_jack_new(codec, "AB8500 Hs Status", SND_JACK_HEADPHONE | |