ASoC: codecs: rk_codec_digital: Fix digital gain for ADC/DAC

Change-Id: Id39ab0485c33aead08c8f143fd092902d2c46886
Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
This commit is contained in:
Sugar Zhang
2020-11-19 17:57:59 +08:00
committed by Tao Huang
parent 3def46f561
commit 69fd5f5410
2 changed files with 175 additions and 24 deletions

View File

@@ -66,13 +66,163 @@ static const char * const dac_hpf_cutoff_text[] = {
static SOC_ENUM_SINGLE_DECL(dac_hpf_cutoff_enum, DACHPF, 4,
dac_hpf_cutoff_text);
static int rk_codec_digital_adc_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int val = snd_soc_component_read32(component, mc->reg);
unsigned int sign = snd_soc_component_read32(component, ADCVOGP);
unsigned int mask = (1 << fls(mc->max)) - 1;
unsigned int shift = mc->shift;
int mid = mc->max / 2;
int uv;
switch (mc->reg) {
case ADCVOLL0:
sign &= ACDCDIG_ADCVOGP_VOLGPL0_MASK;
break;
case ADCVOLL1:
sign &= ACDCDIG_ADCVOGP_VOLGPL1_MASK;
break;
case ADCVOLR0:
sign &= ACDCDIG_ADCVOGP_VOLGPR0_MASK;
break;
default:
return -EINVAL;
}
uv = (val >> shift) & mask;
if (sign)
uv = mid + uv;
else
uv = mid - uv;
ucontrol->value.integer.value[0] = uv;
return 0;
}
static int rk_codec_digital_adc_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int mask = (1 << fls(mc->max)) - 1;
unsigned int val, val_mask, sign, sign_mask;
int uv = ucontrol->value.integer.value[0];
int min = mc->min;
int mid = mc->max / 2;
bool pos = (uv > mid);
switch (mc->reg) {
case ADCVOLL0:
sign_mask = ACDCDIG_ADCVOGP_VOLGPL0_MASK;
sign = pos ? ACDCDIG_ADCVOGP_VOLGPL0_POS : ACDCDIG_ADCVOGP_VOLGPL0_NEG;
break;
case ADCVOLL1:
sign_mask = ACDCDIG_ADCVOGP_VOLGPL1_MASK;
sign = pos ? ACDCDIG_ADCVOGP_VOLGPL1_POS : ACDCDIG_ADCVOGP_VOLGPL1_NEG;
break;
case ADCVOLR0:
sign_mask = ACDCDIG_ADCVOGP_VOLGPR0_MASK;
sign = pos ? ACDCDIG_ADCVOGP_VOLGPR0_POS : ACDCDIG_ADCVOGP_VOLGPR0_NEG;
break;
default:
return -EINVAL;
}
uv = pos ? (uv - mid) : (mid - uv);
val = ((uv + min) & mask);
val_mask = mask << shift;
val = val << shift;
snd_soc_component_update_bits(component, reg, val_mask, val);
snd_soc_component_update_bits(component, ADCVOGP, sign_mask, sign);
return 0;
}
static int rk_codec_digital_dac_vol_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int val = snd_soc_component_read32(component, mc->reg);
unsigned int sign = snd_soc_component_read32(component, DACVOGP);
unsigned int mask = (1 << fls(mc->max)) - 1;
unsigned int shift = mc->shift;
int mid = mc->max / 2;
int uv;
uv = (val >> shift) & mask;
if (sign)
uv = mid + uv;
else
uv = mid - uv;
ucontrol->value.integer.value[0] = uv;
ucontrol->value.integer.value[1] = uv;
return 0;
}
static int rk_codec_digital_dac_vol_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
unsigned int reg = mc->reg;
unsigned int rreg = mc->rreg;
unsigned int shift = mc->shift;
unsigned int mask = (1 << fls(mc->max)) - 1;
unsigned int val, val_mask, sign;
int uv = ucontrol->value.integer.value[0];
int min = mc->min;
int mid = mc->max / 2;
if (uv > mid) {
sign = ACDCDIG_DACVOGP_VOLGPL0_POS | ACDCDIG_DACVOGP_VOLGPR0_POS;
uv = uv - mid;
} else {
sign = ACDCDIG_DACVOGP_VOLGPL0_NEG | ACDCDIG_DACVOGP_VOLGPR0_NEG;
uv = mid - uv;
}
val = ((uv + min) & mask);
val_mask = mask << shift;
val = val << shift;
snd_soc_component_update_bits(component, reg, val_mask, val);
snd_soc_component_update_bits(component, rreg, val_mask, val);
snd_soc_component_write(component, DACVOGP, sign);
return 0;
}
static const struct snd_kcontrol_new rk_codec_digital_snd_controls[] = {
SOC_SINGLE_TLV("ADCL0 Digital Volume",
ADCVOLL0, 0, 0Xff, 1, adc_tlv),
SOC_SINGLE_TLV("ADCL1 Digital Volume",
ADCVOLL1, 0, 0xff, 1, adc_tlv),
SOC_SINGLE_TLV("ADCR0 Digital Volume",
ADCVOLR0, 0, 0xff, 1, adc_tlv),
SOC_SINGLE_EXT_TLV("ADCL0 Digital Volume",
ADCVOLL0, 0, 0X1fe, 0,
rk_codec_digital_adc_vol_get,
rk_codec_digital_adc_vol_put,
adc_tlv),
SOC_SINGLE_EXT_TLV("ADCL1 Digital Volume",
ADCVOLL1, 0, 0x1fe, 0,
rk_codec_digital_adc_vol_get,
rk_codec_digital_adc_vol_put,
adc_tlv),
SOC_SINGLE_EXT_TLV("ADCR0 Digital Volume",
ADCVOLR0, 0, 0x1fe, 0,
rk_codec_digital_adc_vol_get,
rk_codec_digital_adc_vol_put,
adc_tlv),
SOC_SINGLE_TLV("ADCL0 PGA Gain",
ADCPGL0, 0, 0Xf, 0, pga_tlv),
@@ -81,10 +231,11 @@ static const struct snd_kcontrol_new rk_codec_digital_snd_controls[] = {
SOC_SINGLE_TLV("ADCR0 PGA Gain",
ADCPGR0, 0, 0xf, 0, pga_tlv),
SOC_SINGLE_TLV("DACL Digital Volume",
DACVOLL0, 0, 0xff, 1, dac_tlv),
SOC_SINGLE_TLV("DACR Digital Volume",
DACVOLR0, 0, 0xff, 1, dac_tlv),
SOC_DOUBLE_R_EXT_TLV("DAC Digital Volume",
DACVOLL0, DACVOLR0, 0, 0x1fe, 0,
rk_codec_digital_dac_vol_get,
rk_codec_digital_dac_vol_put,
dac_tlv),
SOC_ENUM("ADC HPF Cutoff", adc_hpf_cutoff_enum),
SOC_SINGLE("ADC L0 HPF Switch", ADCHPFEN, 0, 1, 0),

View File

@@ -143,19 +143,19 @@
#define ACDCDIG_ADCVOGP_VOLGPL0_MASK BIT(0)
#define ACDCDIG_ADCVOGP_VOLGPL0_POS BIT(0)
#define ACDCDIG_ADCVOGP_VOLGPL0_NEG 0
#define ACDCDIG_ADCVOGP_VOLGPR1_MASK BIT(1)
#define ACDCDIG_ADCVOGP_VOLGPR1_POS BIT(1)
#define ACDCDIG_ADCVOGP_VOLGPR1_NEG 0
#define ACDCDIG_ADCVOGP_VOLGPL2_MASK BIT(2)
#define ACDCDIG_ADCVOGP_VOLGPL2_POS BIT(2)
#define ACDCDIG_ADCVOGP_VOLGPL2_NEG 0
#define ACDCDIG_ADCVOGP_VOLGPR0_MASK BIT(1)
#define ACDCDIG_ADCVOGP_VOLGPR0_POS BIT(1)
#define ACDCDIG_ADCVOGP_VOLGPR0_NEG 0
#define ACDCDIG_ADCVOGP_VOLGPL1_MASK BIT(2)
#define ACDCDIG_ADCVOGP_VOLGPL1_POS BIT(2)
#define ACDCDIG_ADCVOGP_VOLGPL1_NEG 0
/* ADCALC0 */
#define ACDCDIG_ADCALC0_ALCL0_MASK BIT(0)
#define ACDCDIG_ADCALC0_ALCL0_EN BIT(0)
#define ACDCDIG_ADCALC0_ALCR1_MASK BIT(1)
#define ACDCDIG_ADCALC0_ALCR1_EN BIT(1)
#define ACDCDIG_ADCALC0_ALCL2_MASK BIT(2)
#define ACDCDIG_ADCALC0_ALCL2_EN BIT(2)
#define ACDCDIG_ADCALC0_ALCR0_MASK BIT(1)
#define ACDCDIG_ADCALC0_ALCR0_EN BIT(1)
#define ACDCDIG_ADCALC0_ALCL1_MASK BIT(2)
#define ACDCDIG_ADCALC0_ALCL1_EN BIT(2)
/* ADCALC1 */
#define ACDCDIG_ADCALC1_ALCRRATE_MASK GENMASK(3, 0)
#define ACDCDIG_ADCALC1_ALCRRATE(x) ((x) & 0xf)
@@ -169,10 +169,10 @@
/* ADCHPFEN */
#define ACDCDIG_ADCHPFEN_HPFEN_L0_MASK BIT(0)
#define ACDCDIG_ADCHPFEN_HPFEN_L0_EN BIT(0)
#define ACDCDIG_ADCHPFEN_HPFEN_R1_MASK BIT(1)
#define ACDCDIG_ADCHPFEN_HPFEN_R1_EN BIT(1)
#define ACDCDIG_ADCHPFEN_HPFEN_L2_MASK BIT(2)
#define ACDCDIG_ADCHPFEN_HPFEN_L2_EN BIT(2)
#define ACDCDIG_ADCHPFEN_HPFEN_R0_MASK BIT(1)
#define ACDCDIG_ADCHPFEN_HPFEN_R0_EN BIT(1)
#define ACDCDIG_ADCHPFEN_HPFEN_L1_MASK BIT(2)
#define ACDCDIG_ADCHPFEN_HPFEN_L1_EN BIT(2)
/* ADCHPFCF */
#define ACDCDIG_ADCHPFCF_HPFCF_MASK GENMASK(1, 0)
#define ACDCDIG_ADCHPFCF_HPFCF_493HZ 3