summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2012-02-27 15:00:58 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-03-12 10:32:40 -0700
commit9c2143082d8e7797f6a63720100d06bec7586fd5 (patch)
treeb5563dc3c7d7b3a5e98a74f499e85911e9d75f60 /sound
parenta8e161f4c38c371974319359165d544604e06b78 (diff)
ALSA: hda - Add a fake mute feature
commit 3868137ea41866773e75d9ac4b9988dcc361ff1d upstream. Some codecs don't supply the mute amp-capabilities although the lowest volume gives the mute. It'd be handy if the parser provides the mute mixers in such a case. This patch adds an extension amp-cap bit (which is used only in the driver) to represent the min volume = mute state. Also modified the amp cache code to support the fake mute feature when this bit is set but the real mute bit is unset. In addition, conexant cx5051 parser uses this new feature to implement the missing mute controls. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=42825 Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/hda_codec.c8
-rw-r--r--sound/pci/hda/hda_codec.h3
-rw-r--r--sound/pci/hda/patch_conexant.c22
3 files changed, 30 insertions, 3 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 67d341fa7d10..39e1a6a3ede8 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1651,7 +1651,11 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info,
parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT;
parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT;
parm |= index << AC_AMP_SET_INDEX_SHIFT;
- parm |= val;
+ if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) &&
+ (info->amp_caps & AC_AMPCAP_MIN_MUTE))
+ ; /* set the zero value as a fake mute */
+ else
+ parm |= val;
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm);
info->vol[ch] = val;
}
@@ -1918,7 +1922,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag,
val1 = -((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT);
val1 += ofs;
val1 = ((int)val1) * ((int)val2);
- if (min_mute)
+ if (min_mute || (caps & AC_AMPCAP_MIN_MUTE))
val2 |= TLV_DB_SCALE_MUTE;
if (put_user(SNDRV_CTL_TLVT_DB_SCALE, _tlv))
return -EFAULT;
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h
index 59c97306c1de..eff1fc54e56c 100644
--- a/sound/pci/hda/hda_codec.h
+++ b/sound/pci/hda/hda_codec.h
@@ -302,6 +302,9 @@ enum {
#define AC_AMPCAP_MUTE (1<<31) /* mute capable */
#define AC_AMPCAP_MUTE_SHIFT 31
+/* driver-specific amp-caps: using bits 24-30 */
+#define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */
+
/* Connection list */
#define AC_CLIST_LENGTH (0x7f<<0)
#define AC_CLIST_LONG (1<<7)
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 81ecd6c03217..4ad20a61531e 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -4127,7 +4127,8 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
err = snd_hda_ctl_add(codec, nid, kctl);
if (err < 0)
return err;
- if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE))
+ if (!(query_amp_caps(codec, nid, hda_dir) &
+ (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)))
break;
}
return 0;
@@ -4372,6 +4373,22 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
.reboot_notify = snd_hda_shutup_pins,
};
+/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
+ * can be created (bko#42825)
+ */
+static void add_cx5051_fake_mutes(struct hda_codec *codec)
+{
+ static hda_nid_t out_nids[] = {
+ 0x10, 0x11, 0
+ };
+ hda_nid_t *p;
+
+ for (p = out_nids; *p; p++)
+ snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT,
+ AC_AMPCAP_MIN_MUTE |
+ query_amp_caps(codec, *p, HDA_OUTPUT));
+}
+
static int patch_conexant_auto(struct hda_codec *codec)
{
struct conexant_spec *spec;
@@ -4390,6 +4407,9 @@ static int patch_conexant_auto(struct hda_codec *codec)
case 0x14f15045:
spec->single_adc_amp = 1;
break;
+ case 0x14f15051:
+ add_cx5051_fake_mutes(codec);
+ break;
}
err = cx_auto_search_adcs(codec);