Timur,
On 03/23/16 17:21, Timur Karaldin wrote:
Hi Peter! Here is my patch v2. It works only for aic3106, but I don't have any others. Also patch contains some debug output, I would clean it. I like behaviour of this improvements and I didn't know any issue right now for these add-ons except debug output and that it's correct only for aic3106 (didn't check for others even on datasheet level). Thank you for all your help!
sorry for the delay, I was dragged away for a bit.
Can you send these as separated patches per new functionality? Please use git format-patch to create the patches and try to clean them up so it is going to be easier to understand them.
Can you check your mail client to wrap lines correctly? You have very long lines, for example: http://www.spinics.net/lists/alsa-devel/msg47793.html http://www.spinics.net/lists/alsa-devel/msg48199.html
While they should be something like: http://www.spinics.net/lists/alsa-devel/msg47797.html
Couple of comments, but it would be more beneficial to see a series...
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index d7349bc..2c06e21 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -89,6 +89,7 @@ struct aic3x_priv {
/* Selects the micbias voltage */ enum aic3x_micbias_voltage micbias_vg;
unsigned char cached_gain[LINE1L_2_RADC_CTRL-MIC3LR_2_LADC_CTRL+1];
spaces around '+' '-' '='
See: Documentation/CodingStyle
Also, make sure that tabs are not replaced by spaces and check the patch for long lines also.
Run scripts/checkpatch.pl --strict on the patches.
};
static const struct reg_default aic3x_reg[] = { @@ -134,16 +135,175 @@ static const struct regmap_config aic3x_regmap = {
#define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ SOC_SINGLE_EXT(xname, reg, shift, mask, invert, \
snd_soc_dapm_get_volsw, snd_soc_dapm_put_volsw_aic3x)
snd_soc_dapm_get_volsw_aic3x, snd_soc_dapm_put_volsw_aic3x)
+#define SOC_DOUBLE_R_AIC3X_TLV(xname, reg, rreg, shift, mask, invert) \
SOC_DOUBLE_R_EXT_TLV(xname, reg, rreg, shift, mask, invert, \
snd_soc_get_gain_aic3x, snd_soc_put_gain_aic3x, gain_stage_tlv)
+#define SOC_SINGLE_AIC3X_TLV(xname, reg, shift, mask, invert) \
SOC_SINGLE_EXT_TLV(xname, reg, shift, mask, invert, \
snd_soc_get_gain_aic3x, snd_soc_put_gain_aic3x, gain_stage_tlv)
+#define SOC_SINGLE_EXT_VOL(xname, reg, shift, mask, invert) \
SOC_SINGLE_EXT(xname, reg, shift, mask, invert, \
snd_soc_get_volsw_uncached, snd_soc_put_volsw)
+/*
- Headset detect flag, button press detect flag and headset type flag is
read only register,
- but we could not declare these regs as volatile because other bits are RW,
so we use
- unchached get hanler for these regs.
+*/ +static int snd_soc_get_volsw_uncached( struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value * ucontrol)
+{
int ret;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
regcache_cache_bypass(aic3x->regmap, true);
ret = snd_soc_get_volsw(kcontrol, ucontrol);
regcache_cache_bypass(aic3x->regmap, false);
return ret;
+}
+/*
- All input lines have additional gain controls which can be controled by
volume control.
- 0x0 - means 0dB and 0x8 - means -12 dB. It's a litlle bit tricky because
value 0xF means mute.
- value 0x9-0xE reserverd, so in case of switch muted we should store value
in cache and should
- not set up it to register
+*/ +static int snd_soc_put_gain_aic3x(struct snd_kcontrol* kcontrol,
struct snd_ctl_elem_value* ucontrol)
Please keep the parameter indentation uniform.
+{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
struct soc_mixer_control *mc = (struct soc_mixer_control
*)kcontrol->private_value;
unsigned int reg;
unsigned int shift = mc->shift;
int max = mc->max;
unsigned int mask = (1<<fls(max))-1;
unsigned int invert = mc->invert;
u8 regdata, newval, regval;
u8 loop = 0;
//First of all we need to cache value. Then we need to test each value
on mute in register
//If not muted, we should setup new value
reg = mc->reg;
newval = ( ucontrol->value.integer.value[0] & mask );
printk(KERN_INFO "set gain control reg:%d val:%0X mask:%0X shift:%0X
invert %d\n", reg,newval, mask, shift,invert);
do
{
It would be better to do this w/o do {}while loop, see snd_soc_put_volsw() for example.
if(invert)
{
newval = ( 8 - newval ) & mask;
printk(KERN_INFO "inverted val %0X\n", newval);
}
//read, test and update if first reg if needs
regdata = snd_soc_read(codec, reg);
regval = ( regdata >> shift) & mask;
if( reg >= MIC3LR_2_LADC_CTRL && reg <= LINE1L_2_RADC_CTRL )
{
printk(KERN_INFO "cached_gain before
%0X\n",aic3x->cached_gain[reg-MIC3LR_2_LADC_CTRL]);
- aic3x->cached_gain[reg-MIC3LR_2_LADC_CTRL]&=~(mask<<shift);
- aic3x->cached_gain[reg-MIC3LR_2_LADC_CTRL]|=(newval<<shift);
printk(KERN_INFO "cached_gain after
%0X\n",aic3x->cached_gain[reg-MIC3LR_2_LADC_CTRL]);
}
if ( regval!=0xf && regval!=newval )
snd_soc_update_bits( codec, reg, mask<<shift,
newval<<shift );
if(snd_soc_volsw_is_stereo(mc))
{
loop=!loop; //switch loop, so for first time loop
will be true after and for second time it will be false, so we will finish loop
if(loop) //if first time
{
reg=mc->rreg;
newval = (ucontrol->value.integer.value[1] &
mask);
printk(KERN_INFO "control is stereo second
reg:%d val:%0X\n", reg,newval);
continue;
}
}
}while(loop);
return 0;
+}
+/*
- All input lines have additional gain controls which can be controled by
volume control.
- 0x0 - means 0dB and 0x8 - means -12 dB. It's a litlle bit tricky because
value 0xF means mute.
- value 0x9-0xE reserverd, so in case of switch muted we should read value
from cache in aic3x_priv
- and should not read it from regcache or register
+*/ +static int snd_soc_get_gain_aic3x( struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
struct soc_mixer_control *mc = (struct soc_mixer_control
*)kcontrol->private_value;
unsigned int reg;
unsigned int shift = mc->shift;
int max = mc->max;
unsigned int mask = (1<<fls(max))-1;
unsigned int invert = mc->invert;
u8 regdata, regval;
u8 loop = 0;
//First of all we need to cache value. Then we need to test each value
on mute in register
//If not muted, we should set up new value
reg = mc->reg;
printk(KERN_INFO "get gain control reg:%d mask:%0X shift:%0X invert
%d\n", reg, mask, shift,invert);
do
{
same here, please remove the loop.
regdata = snd_soc_read(codec, reg);
regval = ( regdata >> shift) & mask;
printk(KERN_INFO "regval:%0X\n", regval);
//check if register is muted then return cached value
if( regval == 0xf )
{
if( reg >=MIC3LR_2_LADC_CTRL && reg <=
LINE1L_2_RADC_CTRL )
regval =
(aic3x->cached_gain[reg-MIC3LR_2_LADC_CTRL]>>shift) & mask;
printk(KERN_INFO "regval from cache:%0X\n", regval);
}
if( invert )
{
regval = (8 - regval) & mask;
printk(KERN_INFO "regval after invert:%0X\n", regval);
}
ucontrol->value.integer.value[loop] = regval;
if(snd_soc_volsw_is_stereo(mc))
{
loop=loop?0:1; //switch loop, so for first time loop
will be 1 after and for second time it will be 0, so we will exit from while-loop
if(loop) //if first time
{
reg=mc->rreg;
printk(KERN_INFO "control is stereo second
reg:%d\n", reg);
continue;
}
}
}while(loop);
return 0;
+}
/*
- All input lines are connected when !0xf and disconnected with 0xf bit field,
- so we have to use specific dapm_put call for input mixer
- so we have to use specific dapm_put call for input mixer. In case of unmute
*/
- we should set up register value from cached values from aic3x_priv struct.
static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int reg = mc->reg;
@@ -151,20 +311,32 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, int max = mc->max; unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert;
unsigned short val;
unsigned int val; struct snd_soc_dapm_update update; int connect, change; val = (ucontrol->value.integer.value[0] & mask);
printk(KERN_INFO "dapm put volsw val:%X reg:%X mask:%X shift:%X
invert:%X\n", val, reg, mask, shift, invert);
mask = 0xf; if (val)
{ val = mask;
printk(KERN_INFO "new val:%X\n", val);
} connect = !!val; if (invert)
{ val = mask - val;
printk(KERN_INFO "val after invert:%X\n", val);
}
if (!val)
{
if( reg>=MIC3LR_2_LADC_CTRL && reg<=LINE1L_2_RADC_CTRL )
val =
(aic3x->cached_gain[reg-MIC3LR_2_LADC_CTRL]>>shift) & mask;
printk(KERN_INFO "cached val:%X\n", val);
}
this generally looks good, but please clean up the patch.
mask <<= shift; val <<= shift;
@@ -183,6 +355,36 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, return change; }
+/*
- Based on standart handler snd_soc_dapm_get_volsw, but changing mask to 0xF
- */
+static int snd_soc_dapm_get_volsw_aic3x(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
int ret;
//register contains 4 bits, so we change max temoprally to read
register by original handler, then return it back
mc->max = 15;
ret = snd_soc_dapm_get_volsw( kcontrol, ucontrol);
printk(KERN_INFO "soc_dapm_get_volsw_aic3x:%ld reg:%X shift:%X max:%X
newmax:%X\n", ucontrol->value.integer.value[0], reg, shift, max, mc->max );
mc->max = max;
//all gains except mute (0xf) after invertion is not equl to 0, so we
need to set 1(on)
//for all values except 0. 0 is mute, so we do not need to change it
if(ucontrol->value.integer.value[0]!=0)
ucontrol->value.integer.value[0]=1;
printk(KERN_INFO "new value:%ld\n", ucontrol->value.integer.value[0]);
return ret;
+}
/*
- mic bias power on/off share the same register bits with
- output voltage of mic bias. when power on mic bias, we
@@ -270,6 +472,14 @@ static const struct soc_enum aic3x_agc_decay_enum[] = { SOC_ENUM_SINGLE(RAGC_CTRL_A, 0, 4, aic3x_agc_decay), };
+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
*/ @@ -287,6 +497,9 @@ static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 50, 0); */ static DECLARE_TLV_DB_SCALE(output_stage_tlv, -5900, 50, 1);
+static DECLARE_TLV_DB_SCALE(gain_stage_tlv, -1200, 150, 0);
static const struct snd_kcontrol_new aic3x_snd_controls[] = { /* Output */ SOC_DOUBLE_R_TLV("PCM Playback Volume", @@ -399,6 +612,24 @@ 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_DOUBLE_R_AIC3X_TLV("Mic3L Volume", MIC3LR_2_LADC_CTRL,
MIC3LR_2_RADC_CTRL, 4, 8, 1),
SOC_DOUBLE_R_AIC3X_TLV("Mic3R Volume", MIC3LR_2_LADC_CTRL,
MIC3LR_2_RADC_CTRL, 0, 8, 1),
SOC_DOUBLE_R_AIC3X_TLV("Line1L Volume", LINE1L_2_LADC_CTRL,
LINE1L_2_RADC_CTRL, 3, 8, 1),
SOC_DOUBLE_R_AIC3X_TLV("Line1R Volume", LINE1R_2_LADC_CTRL,
LINE1R_2_RADC_CTRL, 3, 8, 1),
SOC_SINGLE_AIC3X_TLV("Line2L Volume", LINE2L_2_LADC_CTRL, 3, 8, 1),
SOC_SINGLE_AIC3X_TLV("Line2R Volume", LINE2R_2_RADC_CTRL, 3, 8, 1),
SOC_ENUM("Headset Jack Debounce", aic3x_headset_debounce_enum ),
SOC_ENUM("Button Press Debounce", aic3x_button_debounce_enum ),
SOC_SINGLE("Headset Detect Enable", AIC3X_HEADSET_DETECT_CTRL_A, 7, 1,
0),
SOC_SINGLE_EXT_VOL("Headset Detect Type", AIC3X_HEADSET_DETECT_CTRL_A,
AIC3X_HEADSET_DETECT_A_SHIFT, AIC3X_HEADSET_DETECT_A_MASK, 0),
SOC_SINGLE_EXT_VOL("Button Detect Flag", AIC3X_HEADSET_DETECT_CTRL_B,
AIC3X_BUTTON_DETECT_SHIFT, AIC3X_BUTTON_DETECT_MASK, 0),
SOC_SINGLE_EXT_VOL("Headset Detect Flag", AIC3X_HEADSET_DETECT_CTRL_B,
AIC3X_HEADSET_DETECT_B_SHIFT, AIC3X_HEADSET_DETECT_B_MASK, 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[] = {
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index e521ac3..bcac87f 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h @@ -271,9 +271,20 @@ 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 +#define AIC3X_HEADSET_DETECT_A_SHIFT 5 +#define AIC3X_HEADSET_DETECT_A_MASK 3
+#define AIC3X_BUTTON_DETECT_SHIFT 5 +#define AIC3X_BUTTON_DETECT_MASK 1 +#define AIC3X_HEADSET_DETECT_B_SHIFT 4 +#define AIC3X_HEADSET_DETECT_B_MASK 1 #define AIC3X_HEADSET_DEBOUNCE_SHIFT 2 #define AIC3X_HEADSET_DEBOUNCE_MASK 7
#define AIC3X_BUTTON_DEBOUNCE_SHIFT 0
It would be great if you could clean this up, have separate patches in order to be able to review the changes and also to be able to test it. It looks promising ;)