aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/hda_intel.c1
-rw-r--r--sound/pci/hda/patch_cirrus.c89
-rw-r--r--sound/pci/hda/patch_hdmi.c50
-rw-r--r--sound/pci/hda/patch_realtek.c56
4 files changed, 156 insertions, 40 deletions
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index e54ebd5..6e61a01 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -3428,6 +3428,7 @@ static struct snd_pci_quirk msi_black_list[] = {
SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */
SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */
SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */
+ SND_PCI_QUIRK(0x1179, 0xfb44, "Toshiba Satellite C870", 0), /* AMD Hudson */
SND_PCI_QUIRK(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */
SND_PCI_QUIRK(0xa0a0, 0x0575, "Aopen MZ915-M", 0), /* ICH6 */
{}
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
index cccaf9c..b524f89 100644
--- a/sound/pci/hda/patch_cirrus.c
+++ b/sound/pci/hda/patch_cirrus.c
@@ -169,7 +169,7 @@ static void cs_automute(struct hda_codec *codec)
snd_hda_gen_update_outputs(codec);
- if (spec->gpio_eapd_hp) {
+ if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
spec->gpio_data = spec->gen.hp_jack_present ?
spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
snd_hda_codec_write(codec, 0x01, 0,
@@ -291,10 +291,11 @@ static int cs_init(struct hda_codec *codec)
{
struct cs_spec *spec = codec->spec;
- /* init_verb sequence for C0/C1/C2 errata*/
- snd_hda_sequence_write(codec, cs_errata_init_verbs);
-
- snd_hda_sequence_write(codec, cs_coef_init_verbs);
+ if (spec->vendor_nid == CS420X_VENDOR_NID) {
+ /* init_verb sequence for C0/C1/C2 errata*/
+ snd_hda_sequence_write(codec, cs_errata_init_verbs);
+ snd_hda_sequence_write(codec, cs_coef_init_verbs);
+ }
snd_hda_gen_init(codec);
@@ -307,8 +308,10 @@ static int cs_init(struct hda_codec *codec)
spec->gpio_data);
}
- init_input_coef(codec);
- init_digital_coef(codec);
+ if (spec->vendor_nid == CS420X_VENDOR_NID) {
+ init_input_coef(codec);
+ init_digital_coef(codec);
+ }
return 0;
}
@@ -552,6 +555,76 @@ static int patch_cs420x(struct hda_codec *codec)
}
/*
+ * CS4208 support:
+ * Its layout is no longer compatible with CS4206/CS4207, and the generic
+ * parser seems working fairly well, except for trivial fixups.
+ */
+enum {
+ CS4208_GPIO0,
+};
+
+static const struct hda_model_fixup cs4208_models[] = {
+ { .id = CS4208_GPIO0, .name = "gpio0" },
+ {}
+};
+
+static const struct snd_pci_quirk cs4208_fixup_tbl[] = {
+ /* codec SSID */
+ SND_PCI_QUIRK(0x106b, 0x7100, "MacBookPro 6,1", CS4208_GPIO0),
+ SND_PCI_QUIRK(0x106b, 0x7200, "MacBookPro 6,2", CS4208_GPIO0),
+ {} /* terminator */
+};
+
+static void cs4208_fixup_gpio0(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ struct cs_spec *spec = codec->spec;
+ spec->gpio_eapd_hp = 0;
+ spec->gpio_eapd_speaker = 1;
+ spec->gpio_mask = spec->gpio_dir =
+ spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+ }
+}
+
+static const struct hda_fixup cs4208_fixups[] = {
+ [CS4208_GPIO0] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs4208_fixup_gpio0,
+ },
+};
+
+static int patch_cs4208(struct hda_codec *codec)
+{
+ struct cs_spec *spec;
+ int err;
+
+ spec = cs_alloc_spec(codec, 0); /* no specific w/a */
+ if (!spec)
+ return -ENOMEM;
+
+ spec->gen.automute_hook = cs_automute;
+
+ snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl,
+ cs4208_fixups);
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+ err = cs_parse_auto_config(codec);
+ if (err < 0)
+ goto error;
+
+ codec->patch_ops = cs_patch_ops;
+
+ snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+ return 0;
+
+ error:
+ cs_free(codec);
+ return err;
+}
+
+/*
* Cirrus Logic CS4210
*
* 1 DAC => HP(sense) / Speakers,
@@ -991,6 +1064,7 @@ static int patch_cs4213(struct hda_codec *codec)
static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
{ .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
{ .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
+ { .id = 0x10134208, .name = "CS4208", .patch = patch_cs4208 },
{ .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 },
{ .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 },
{} /* terminator */
@@ -998,6 +1072,7 @@ static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
MODULE_ALIAS("snd-hda-codec-id:10134206");
MODULE_ALIAS("snd-hda-codec-id:10134207");
+MODULE_ALIAS("snd-hda-codec-id:10134208");
MODULE_ALIAS("snd-hda-codec-id:10134210");
MODULE_ALIAS("snd-hda-codec-id:10134213");
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 9a58893..3d8cd044 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -44,6 +44,8 @@ static bool static_hdmi_pcm;
module_param(static_hdmi_pcm, bool, 0644);
MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
+#define is_haswell(codec) ((codec)->vendor_id == 0x80862807)
+
struct hdmi_spec_per_cvt {
hda_nid_t cvt_nid;
int assigned;
@@ -894,6 +896,11 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
if (!channels)
return;
+ if (is_haswell(codec))
+ snd_hda_codec_write(codec, pin_nid, 0,
+ AC_VERB_SET_AMP_GAIN_MUTE,
+ AMP_OUT_UNMUTE);
+
eld = &per_pin->sink_eld;
if (!eld->monitor_present)
return;
@@ -1033,10 +1040,10 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
hdmi_non_intrinsic_event(codec, res);
}
-static void haswell_verify_pin_D0(struct hda_codec *codec,
+static void haswell_verify_D0(struct hda_codec *codec,
hda_nid_t cvt_nid, hda_nid_t nid)
{
- int pwr, lamp, ramp;
+ int pwr;
/* For Haswell, the converter 1/2 may keep in D3 state after bootup,
* thus pins could only choose converter 0 for use. Make sure the
@@ -1052,25 +1059,6 @@ static void haswell_verify_pin_D0(struct hda_codec *codec,
pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
snd_printd("Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr);
}
-
- lamp = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_AMP_GAIN_MUTE,
- AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT);
- ramp = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_AMP_GAIN_MUTE,
- AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT);
- if (lamp != ramp) {
- snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
- AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT | lamp);
-
- lamp = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_AMP_GAIN_MUTE,
- AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT);
- ramp = snd_hda_codec_read(codec, nid, 0,
- AC_VERB_GET_AMP_GAIN_MUTE,
- AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT);
- snd_printd("Haswell HDMI audio: Mute after set on pin 0x%x: [0x%x 0x%x]\n", nid, lamp, ramp);
- }
}
/*
@@ -1087,8 +1075,8 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
int pinctl;
int new_pinctl = 0;
- if (codec->vendor_id == 0x80862807)
- haswell_verify_pin_D0(codec, cvt_nid, pin_nid);
+ if (is_haswell(codec))
+ haswell_verify_D0(codec, cvt_nid, pin_nid);
if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
pinctl = snd_hda_codec_read(codec, pin_nid, 0,
@@ -1227,7 +1215,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
mux_idx);
/* configure unused pins to choose other converters */
- if (codec->vendor_id == 0x80862807)
+ if (is_haswell(codec))
haswell_config_cvts(codec, pin_idx, mux_idx);
snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
@@ -1358,14 +1346,10 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
/* Haswell-specific workaround: re-setup when the transcoder is
* changed during the stream playback
*/
- if (codec->vendor_id == 0x80862807 &&
- eld->eld_valid && !old_eld_valid && per_pin->setup) {
- snd_hda_codec_write(codec, pin_nid, 0,
- AC_VERB_SET_AMP_GAIN_MUTE,
- AMP_OUT_UNMUTE);
+ if (is_haswell(codec) &&
+ eld->eld_valid && !old_eld_valid && per_pin->setup)
hdmi_setup_audio_infoframe(codec, per_pin,
per_pin->non_pcm);
- }
}
mutex_unlock(&pin_eld->lock);
@@ -1405,7 +1389,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
return 0;
- if (codec->vendor_id == 0x80862807)
+ if (is_haswell(codec))
intel_haswell_fixup_connect_list(codec, pin_nid);
pin_idx = spec->num_pins;
@@ -2014,7 +1998,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
codec->spec = spec;
hdmi_array_init(spec, 4);
- if (codec->vendor_id == 0x80862807) {
+ if (is_haswell(codec)) {
intel_haswell_enable_all_pins(codec, true);
intel_haswell_fixup_enable_dp12(codec);
}
@@ -2025,7 +2009,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
return -EINVAL;
}
codec->patch_ops = generic_hdmi_patch_ops;
- if (codec->vendor_id == 0x80862807) {
+ if (is_haswell(codec)) {
codec->patch_ops.set_power_state = haswell_set_power_state;
codec->dp_mst = true;
}
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 9e9378c..bc07d36 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -3443,6 +3443,56 @@ static void alc283_fixup_chromebook(struct hda_codec *codec,
}
}
+/* mute tablet speaker pin (0x14) via dock plugging in addition */
+static void asus_tx300_automute(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ snd_hda_gen_update_outputs(codec);
+ if (snd_hda_jack_detect(codec, 0x1b))
+ spec->gen.mute_bits |= (1ULL << 0x14);
+}
+
+static void alc282_fixup_asus_tx300(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ /* TX300 needs to set up GPIO2 for the speaker amp */
+ static const struct hda_verb gpio2_verbs[] = {
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
+ { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 },
+ {}
+ };
+ static const struct hda_pintbl dock_pins[] = {
+ { 0x1b, 0x21114000 }, /* dock speaker pin */
+ {}
+ };
+ struct snd_kcontrol *kctl;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PRE_PROBE:
+ snd_hda_add_verbs(codec, gpio2_verbs);
+ snd_hda_apply_pincfgs(codec, dock_pins);
+ spec->gen.auto_mute_via_amp = 1;
+ spec->gen.automute_hook = asus_tx300_automute;
+ snd_hda_jack_detect_enable_callback(codec, 0x1b,
+ HDA_GEN_HP_EVENT,
+ snd_hda_gen_hp_automute);
+ break;
+ case HDA_FIXUP_ACT_BUILD:
+ /* this is a bit tricky; give more sane names for the main
+ * (tablet) speaker and the dock speaker, respectively
+ */
+ kctl = snd_hda_find_mixer_ctl(codec, "Speaker Playback Switch");
+ if (kctl)
+ strcpy(kctl->id.name, "Dock Speaker Playback Switch");
+ kctl = snd_hda_find_mixer_ctl(codec, "Bass Speaker Playback Switch");
+ if (kctl)
+ strcpy(kctl->id.name, "Speaker Playback Switch");
+ break;
+ }
+}
+
enum {
ALC269_FIXUP_SONY_VAIO,
ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -3480,6 +3530,7 @@ enum {
ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
ALC269VB_FIXUP_ORDISSIMO_EVE2,
ALC283_FIXUP_CHROME_BOOK,
+ ALC282_FIXUP_ASUS_TX300,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -3735,6 +3786,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc283_fixup_chromebook,
},
+ [ALC282_FIXUP_ASUS_TX300] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc282_fixup_asus_tx300,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -3784,6 +3839,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x21ed, "HP Falco Chromebook", ALC283_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
+ SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),