Hi, colleagues!
I'm newbie with ALSA devel. I need to get extra functionality from codec through ALSA mixer. Task: 1. making possibility to set-up gain for each input (XXX_2_LADCCTRL and XXX_2_RADCCTRL registers) 2. making possibility to set-up debounce for button and headset detection ( HEADSET_DETECT_CTRL_A register) 3. making possibility to enable high-power AC-coupled output (HEADSET_DETECT_CTRL_A register) 4. making possibility to enable stereo pseudo differential output (HEADSET_DETECT_CTRL_B register) 5. enable headset detection (HEADSET_DETECT_CTRL_A) 6. getting headset detect status (HEADSET_DETECT_CTRL_A)
Well, my patch works in generally, but I don't like it very much, because: 1. All controls for input amplifiers' gain are shown in Alsamixer-Playback section. But not only mine, capture controls from base codec's version are shown in playback section too, for example (Right or Left) PGA Mixer Line1(L or R)/2(L or R)/MIC3(L or R), which is definitely capture settings. Should I worried about it? because, as I understand, it could not be setted correctly during changing playback/capture mode for power-saving reason. 2. "Right PGA Mixer Line1R" control (and similar) using the same bits in LINE1R_2_RADCCTRL register as my "Line1R RADC Gain" control (and similar) and put there b"1111" when user switch disconnect it from ADC. So my control is not shown when user disconnect it from ADC. 3. When I start/stop arecord some of my options were reset (debounces, headset enable, high-power AC-coupled, pseudo differential output). When I set up it in shell and then start arecord, it's reset again. Is it the reason because of displaying controls in playback mixer section?
I will be very pleased for any advise, thank you!
here is my patch for tlv320aic3x.c --- sound/soc/codecs/tlv320aic3x.c | 55 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index d7349bc..27d031e 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -122,11 +122,24 @@ static const struct reg_default aic3x_reg[] = { { 108, 0x00 }, { 109, 0x00 }, };
+static bool aic3106_volatile(struct device *dev, unsigned int reg) +{ + switch(reg) + { + case AIC3X_HEADSET_DETECT_CTRL_A: + case AIC3X_HEADSET_DETECT_CTRL_B: + return true; + default: + return false; + } +} + static const struct regmap_config aic3x_regmap = { .reg_bits = 8, .val_bits = 8,
.max_register = DAC_ICC_ADJ, + .volatile_reg = aic3106_volatile, .reg_defaults = aic3x_reg, .num_reg_defaults = ARRAY_SIZE(aic3x_reg), .cache_type = REGCACHE_RBTREE, @@ -196,7 +209,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); + struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -270,6 +283,26 @@ static const struct soc_enum aic3x_agc_decay_enum[] = { SOC_ENUM_SINGLE(RAGC_CTRL_A, 0, 4, aic3x_agc_decay), };
+static const char *aic3x_adc_gain[] = { "0dB", "-1.5dB", "-3dB", "-4.5dB", "-6dB", "-7.5dB", "-9dB", "-10.5dB", "-12dB" }; +static const struct soc_enum aic3x_adc_gain_enum[] = { + SOC_ENUM_SINGLE(MIC3LR_2_LADC_CTRL, 4, 9, aic3x_adc_gain), + SOC_ENUM_SINGLE(MIC3LR_2_RADC_CTRL, 0, 9, aic3x_adc_gain), + SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 3, 9, aic3x_adc_gain), + SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 3, 9, aic3x_adc_gain), + SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 3, 9, aic3x_adc_gain), + SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 3, 9, aic3x_adc_gain), +}; +static const char *aic3x_headset_debounce[] = { "16ms", "32ms", "64ms", "128ms", "256ms", "512ms" }; +static const struct soc_enum aic3x_headset_debounce_enum[] = { + SOC_ENUM_SINGLE(AIC3X_HEADSET_DETECT_CTRL_A, 2, 6, aic3x_headset_debounce), +}; +static const char *aic3x_button_debounce[] = { "0ms", "8ms", "16ms", "32ms" }; +static const struct soc_enum aic3x_button_debounce_enum[] = { + SOC_ENUM_SINGLE(AIC3X_HEADSET_DETECT_CTRL_A, 0, 4, aic3x_button_debounce), +}; + + + /* * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps */ @@ -399,6 +432,19 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), + /* Additional controls */ + SOC_ENUM("Mic3L LADC Gain", aic3x_adc_gain_enum[0]), + SOC_ENUM("Mic3R RADC Gain", aic3x_adc_gain_enum[1]), + SOC_ENUM("Line1L LADC Gain", aic3x_adc_gain_enum[2]), + SOC_ENUM("Line1R RADC Gain", aic3x_adc_gain_enum[3]), + SOC_ENUM("Line2L LADC Gain", aic3x_adc_gain_enum[4]), + SOC_ENUM("Line2R RADC Gain", aic3x_adc_gain_enum[5]), + SOC_ENUM("Headset Debounce", aic3x_headset_debounce_enum), + SOC_ENUM("Button Debounce", aic3x_button_debounce_enum), + SOC_SINGLE("Headset Detected", AIC3X_HEADSET_DETECT_CTRL_A, AIC3X_HEADSET_DETECT_SHIFT, AIC3X_HEADSET_DETECT_MASK, 0), + SOC_SINGLE("Headset Detect Enable", AIC3X_HEADSET_DETECT_CTRL_A, 7, 1, 0), + SOC_SINGLE("High power output Ac-coupled", AIC3X_HEADSET_DETECT_CTRL_B, 7, 1, 0), + SOC_SINGLE("Stereo pseudodifferential output", AIC3X_HEADSET_DETECT_CTRL_B, 3, 1, 0), };
static const struct snd_kcontrol_new aic3x_mono_controls[] = { @@ -614,7 +660,7 @@ static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { SND_SOC_DAPM_REG(snd_soc_dapm_micbias, "DMic Rate 32", AIC3X_ASD_INTF_CTRLA, 0, 3, 3, 0),
- /* Mic Bias */ + /* Mic Bias */ SND_SOC_DAPM_SUPPLY("Mic Bias", MICBIAS_CTRL, 6, 0, mic_bias_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), @@ -692,7 +738,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"Left Line2L Mux", "single-ended", "LINE2L"}, {"Left Line2L Mux", "differential", "LINE2L"},
- {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, + {"Left PGA Mixer", "Line1L Switch", "Left Line1L Mux"}, {"Left PGA Mixer", "Line1R Switch", "Left Line1R Mux"}, {"Left PGA Mixer", "Line2L Switch", "Left Line2L Mux"}, {"Left PGA Mixer", "Mic3L Switch", "MIC3L"}, @@ -814,6 +860,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"Right HPCOM Mux", "external feedback", "Right HPCOM Mixer"}, {"Right HP Com", NULL, "Right HPCOM Mux"}, {"HPRCOM", NULL, "Right HP Com"}, + };
static const struct snd_soc_dapm_route intercon_mono[] = { @@ -918,7 +965,9 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, data = (LDAC2LCH | RDAC2RCH); data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; if (params_rate(params) >= 64000) + { data |= DUAL_RATE_MODE; + } snd_soc_write(codec, AIC3X_CODEC_DATAPATH_REG, data);
/* codec sample rate select */ -- and tlv320aic3x.h --- sound/soc/codecs/tlv320aic3x.h | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index e521ac3..8ff42d2 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -271,6 +271,12 @@ enum { AIC3X_BUTTON_DEBOUNCE_32MS = 3 };
+typedef struct { + struct platform_device* pdev; + struct proc_dir_entry *proc_value; + struct snd_soc_codec *codec; +} aic3106_detect_t; + #define AIC3X_HEADSET_DETECT_ENABLED 0x80 #define AIC3X_HEADSET_DETECT_SHIFT 5 #define AIC3X_HEADSET_DETECT_MASK 3 --