Merge branch 'test/hda-vol-ofs' into next/hda
This commit is contained in:
commit
1eaf5c0716
|
@ -1119,6 +1119,7 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
|
||||||
u16 nid = get_amp_nid(kcontrol);
|
u16 nid = get_amp_nid(kcontrol);
|
||||||
u8 chs = get_amp_channels(kcontrol);
|
u8 chs = get_amp_channels(kcontrol);
|
||||||
int dir = get_amp_direction(kcontrol);
|
int dir = get_amp_direction(kcontrol);
|
||||||
|
unsigned int ofs = get_amp_offset(kcontrol);
|
||||||
u32 caps;
|
u32 caps;
|
||||||
|
|
||||||
caps = query_amp_caps(codec, nid, dir);
|
caps = query_amp_caps(codec, nid, dir);
|
||||||
|
@ -1130,6 +1131,8 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
|
||||||
kcontrol->id.name);
|
kcontrol->id.name);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
if (ofs < caps)
|
||||||
|
caps -= ofs;
|
||||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||||
uinfo->count = chs == 3 ? 2 : 1;
|
uinfo->count = chs == 3 ? 2 : 1;
|
||||||
uinfo->value.integer.min = 0;
|
uinfo->value.integer.min = 0;
|
||||||
|
@ -1138,6 +1141,32 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
|
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info);
|
||||||
|
|
||||||
|
|
||||||
|
static inline unsigned int
|
||||||
|
read_amp_value(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int ch, int dir, int idx, unsigned int ofs)
|
||||||
|
{
|
||||||
|
unsigned int val;
|
||||||
|
val = snd_hda_codec_amp_read(codec, nid, ch, dir, idx);
|
||||||
|
val &= HDA_AMP_VOLMASK;
|
||||||
|
if (val >= ofs)
|
||||||
|
val -= ofs;
|
||||||
|
else
|
||||||
|
val = 0;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
update_amp_value(struct hda_codec *codec, hda_nid_t nid,
|
||||||
|
int ch, int dir, int idx, unsigned int ofs,
|
||||||
|
unsigned int val)
|
||||||
|
{
|
||||||
|
if (val > 0)
|
||||||
|
val += ofs;
|
||||||
|
return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
|
||||||
|
HDA_AMP_VOLMASK, val);
|
||||||
|
}
|
||||||
|
|
||||||
int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
|
int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
|
||||||
struct snd_ctl_elem_value *ucontrol)
|
struct snd_ctl_elem_value *ucontrol)
|
||||||
{
|
{
|
||||||
|
@ -1146,14 +1175,13 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol,
|
||||||
int chs = get_amp_channels(kcontrol);
|
int chs = get_amp_channels(kcontrol);
|
||||||
int dir = get_amp_direction(kcontrol);
|
int dir = get_amp_direction(kcontrol);
|
||||||
int idx = get_amp_index(kcontrol);
|
int idx = get_amp_index(kcontrol);
|
||||||
|
unsigned int ofs = get_amp_offset(kcontrol);
|
||||||
long *valp = ucontrol->value.integer.value;
|
long *valp = ucontrol->value.integer.value;
|
||||||
|
|
||||||
if (chs & 1)
|
if (chs & 1)
|
||||||
*valp++ = snd_hda_codec_amp_read(codec, nid, 0, dir, idx)
|
*valp++ = read_amp_value(codec, nid, 0, dir, idx, ofs);
|
||||||
& HDA_AMP_VOLMASK;
|
|
||||||
if (chs & 2)
|
if (chs & 2)
|
||||||
*valp = snd_hda_codec_amp_read(codec, nid, 1, dir, idx)
|
*valp = read_amp_value(codec, nid, 1, dir, idx, ofs);
|
||||||
& HDA_AMP_VOLMASK;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get);
|
EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get);
|
||||||
|
@ -1166,18 +1194,17 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol,
|
||||||
int chs = get_amp_channels(kcontrol);
|
int chs = get_amp_channels(kcontrol);
|
||||||
int dir = get_amp_direction(kcontrol);
|
int dir = get_amp_direction(kcontrol);
|
||||||
int idx = get_amp_index(kcontrol);
|
int idx = get_amp_index(kcontrol);
|
||||||
|
unsigned int ofs = get_amp_offset(kcontrol);
|
||||||
long *valp = ucontrol->value.integer.value;
|
long *valp = ucontrol->value.integer.value;
|
||||||
int change = 0;
|
int change = 0;
|
||||||
|
|
||||||
snd_hda_power_up(codec);
|
snd_hda_power_up(codec);
|
||||||
if (chs & 1) {
|
if (chs & 1) {
|
||||||
change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
|
change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
|
||||||
0x7f, *valp);
|
|
||||||
valp++;
|
valp++;
|
||||||
}
|
}
|
||||||
if (chs & 2)
|
if (chs & 2)
|
||||||
change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
|
change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
|
||||||
0x7f, *valp);
|
|
||||||
snd_hda_power_down(codec);
|
snd_hda_power_down(codec);
|
||||||
return change;
|
return change;
|
||||||
}
|
}
|
||||||
|
@ -1189,6 +1216,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
||||||
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||||
hda_nid_t nid = get_amp_nid(kcontrol);
|
hda_nid_t nid = get_amp_nid(kcontrol);
|
||||||
int dir = get_amp_direction(kcontrol);
|
int dir = get_amp_direction(kcontrol);
|
||||||
|
unsigned int ofs = get_amp_offset(kcontrol);
|
||||||
u32 caps, val1, val2;
|
u32 caps, val1, val2;
|
||||||
|
|
||||||
if (size < 4 * sizeof(unsigned int))
|
if (size < 4 * sizeof(unsigned int))
|
||||||
|
@ -1197,6 +1225,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
|
||||||
val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
|
val2 = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT;
|
||||||
val2 = (val2 + 1) * 25;
|
val2 = (val2 + 1) * 25;
|
||||||
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
|
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
|
||||||
|
val1 += ofs;
|
||||||
val1 = ((int)val1) * ((int)val2);
|
val1 = ((int)val1) * ((int)val2);
|
||||||
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
|
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
|
@ -26,8 +26,10 @@
|
||||||
/*
|
/*
|
||||||
* for mixer controls
|
* for mixer controls
|
||||||
*/
|
*/
|
||||||
|
#define HDA_COMPOSE_AMP_VAL_OFS(nid,chs,idx,dir,ofs) \
|
||||||
|
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19) | ((ofs)<<23))
|
||||||
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
|
#define HDA_COMPOSE_AMP_VAL(nid,chs,idx,dir) \
|
||||||
((nid) | ((chs)<<16) | ((dir)<<18) | ((idx)<<19))
|
HDA_COMPOSE_AMP_VAL_OFS(nid, chs, idx, dir, 0)
|
||||||
/* mono volume with index (index=0,1,...) (channel=1,2) */
|
/* mono volume with index (index=0,1,...) (channel=1,2) */
|
||||||
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
#define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \
|
||||||
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \
|
||||||
|
@ -458,6 +460,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec,
|
||||||
#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
|
#define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3)
|
||||||
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
|
#define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1)
|
||||||
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
|
#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf)
|
||||||
|
#define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CEA Short Audio Descriptor data
|
* CEA Short Audio Descriptor data
|
||||||
|
|
|
@ -166,6 +166,7 @@ struct sigmatel_spec {
|
||||||
unsigned int alt_switch: 1;
|
unsigned int alt_switch: 1;
|
||||||
unsigned int hp_detect: 1;
|
unsigned int hp_detect: 1;
|
||||||
unsigned int spdif_mute: 1;
|
unsigned int spdif_mute: 1;
|
||||||
|
unsigned int check_volume_offset:1;
|
||||||
|
|
||||||
/* gpio lines */
|
/* gpio lines */
|
||||||
unsigned int eapd_mask;
|
unsigned int eapd_mask;
|
||||||
|
@ -202,6 +203,8 @@ struct sigmatel_spec {
|
||||||
hda_nid_t hp_dacs[5];
|
hda_nid_t hp_dacs[5];
|
||||||
hda_nid_t speaker_dacs[5];
|
hda_nid_t speaker_dacs[5];
|
||||||
|
|
||||||
|
int volume_offset;
|
||||||
|
|
||||||
/* capture */
|
/* capture */
|
||||||
hda_nid_t *adc_nids;
|
hda_nid_t *adc_nids;
|
||||||
unsigned int num_adcs;
|
unsigned int num_adcs;
|
||||||
|
@ -1293,6 +1296,8 @@ static int stac92xx_build_controls(struct hda_codec *codec)
|
||||||
unsigned int vmaster_tlv[4];
|
unsigned int vmaster_tlv[4];
|
||||||
snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
|
snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0],
|
||||||
HDA_OUTPUT, vmaster_tlv);
|
HDA_OUTPUT, vmaster_tlv);
|
||||||
|
/* correct volume offset */
|
||||||
|
vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset;
|
||||||
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
|
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
|
||||||
vmaster_tlv, slave_vols);
|
vmaster_tlv, slave_vols);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
|
@ -2976,14 +2981,34 @@ static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* create volume control/switch for the given prefx type */
|
/* create volume control/switch for the given prefx type */
|
||||||
static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_t nid, int chs)
|
static int create_controls(struct hda_codec *codec, const char *pfx,
|
||||||
|
hda_nid_t nid, int chs)
|
||||||
{
|
{
|
||||||
|
struct sigmatel_spec *spec = codec->spec;
|
||||||
char name[32];
|
char name[32];
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (!spec->check_volume_offset) {
|
||||||
|
unsigned int caps, step, nums, db_scale;
|
||||||
|
caps = query_amp_caps(codec, nid, HDA_OUTPUT);
|
||||||
|
step = (caps & AC_AMPCAP_STEP_SIZE) >>
|
||||||
|
AC_AMPCAP_STEP_SIZE_SHIFT;
|
||||||
|
step = (step + 1) * 25; /* in .01dB unit */
|
||||||
|
nums = (caps & AC_AMPCAP_NUM_STEPS) >>
|
||||||
|
AC_AMPCAP_NUM_STEPS_SHIFT;
|
||||||
|
db_scale = nums * step;
|
||||||
|
/* if dB scale is over -64dB, and finer enough,
|
||||||
|
* let's reduce it to half
|
||||||
|
*/
|
||||||
|
if (db_scale > 6400 && nums >= 0x1f)
|
||||||
|
spec->volume_offset = nums / 2;
|
||||||
|
spec->check_volume_offset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
sprintf(name, "%s Playback Volume", pfx);
|
sprintf(name, "%s Playback Volume", pfx);
|
||||||
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
|
err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, name,
|
||||||
HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT));
|
HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT,
|
||||||
|
spec->volume_offset));
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
sprintf(name, "%s Playback Switch", pfx);
|
sprintf(name, "%s Playback Switch", pfx);
|
||||||
|
@ -3049,10 +3074,10 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
|
||||||
nid = spec->multiout.dac_nids[i];
|
nid = spec->multiout.dac_nids[i];
|
||||||
if (i == 2) {
|
if (i == 2) {
|
||||||
/* Center/LFE */
|
/* Center/LFE */
|
||||||
err = create_controls(spec, "Center", nid, 1);
|
err = create_controls(codec, "Center", nid, 1);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
err = create_controls(spec, "LFE", nid, 2);
|
err = create_controls(codec, "LFE", nid, 2);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -3080,7 +3105,7 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = create_controls(spec, name, nid, 3);
|
err = create_controls(codec, name, nid, 3);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -3135,7 +3160,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
|
||||||
nid = spec->hp_dacs[i];
|
nid = spec->hp_dacs[i];
|
||||||
if (!nid)
|
if (!nid)
|
||||||
continue;
|
continue;
|
||||||
err = create_controls(spec, pfxs[nums++], nid, 3);
|
err = create_controls(codec, pfxs[nums++], nid, 3);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -3149,7 +3174,7 @@ static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec,
|
||||||
nid = spec->speaker_dacs[i];
|
nid = spec->speaker_dacs[i];
|
||||||
if (!nid)
|
if (!nid)
|
||||||
continue;
|
continue;
|
||||||
err = create_controls(spec, pfxs[nums++], nid, 3);
|
err = create_controls(codec, pfxs[nums++], nid, 3);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -3725,7 +3750,7 @@ static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lfe_pin) {
|
if (lfe_pin) {
|
||||||
err = create_controls(spec, "LFE", lfe_pin, 1);
|
err = create_controls(codec, "LFE", lfe_pin, 1);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue