ALC888_ACER_ASPIRE_8930G,
ALC888_ACER_ASPIRE_7730G,
ALC883_MEDION,
- ALC883_MEDION_MD2,
ALC883_MEDION_WIM2160,
ALC883_LAPTOP_EAPD,
ALC883_LENOVO_101E_2ch,
spec->init_amp = ALC_INIT_GPIO3;
break;
case 5:
+ default:
spec->init_amp = ALC_INIT_DEFAULT;
break;
}
u32 val;
};
+struct alc_model_fixup {
+ const int id;
+ const char *name;
+};
+
struct alc_fixup {
unsigned int sku;
const struct alc_pincfg *pins;
const struct hda_verb *verbs;
+ void (*func)(struct hda_codec *codec, const struct alc_fixup *fix,
+ int pre_init);
};
-static void alc_pick_fixup(struct hda_codec *codec,
- const struct snd_pci_quirk *quirk,
- const struct alc_fixup *fix,
- int pre_init)
+static void __alc_pick_fixup(struct hda_codec *codec,
+ const struct alc_fixup *fix,
+ const char *modelname,
+ int pre_init)
{
const struct alc_pincfg *cfg;
struct alc_spec *spec;
- quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
- if (!quirk)
- return;
- fix += quirk->value;
cfg = fix->pins;
if (pre_init && fix->sku) {
#ifdef CONFIG_SND_DEBUG_VERBOSE
snd_printdd(KERN_INFO "hda_codec: %s: Apply sku override for %s\n",
- codec->chip_name, quirk->name);
+ codec->chip_name, modelname);
#endif
spec = codec->spec;
spec->cdefine.sku_cfg = fix->sku;
if (pre_init && cfg) {
#ifdef CONFIG_SND_DEBUG_VERBOSE
snd_printdd(KERN_INFO "hda_codec: %s: Apply pincfg for %s\n",
- codec->chip_name, quirk->name);
+ codec->chip_name, modelname);
#endif
for (; cfg->nid; cfg++)
snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
if (!pre_init && fix->verbs) {
#ifdef CONFIG_SND_DEBUG_VERBOSE
snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-verbs for %s\n",
- codec->chip_name, quirk->name);
+ codec->chip_name, modelname);
#endif
add_verb(codec->spec, fix->verbs);
}
+ if (fix->func) {
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ snd_printdd(KERN_INFO "hda_codec: %s: Apply fix-func for %s\n",
+ codec->chip_name, modelname);
+#endif
+ fix->func(codec, fix, pre_init);
+ }
+}
+
+static void alc_pick_fixup(struct hda_codec *codec,
+ const struct snd_pci_quirk *quirk,
+ const struct alc_fixup *fix,
+ int pre_init)
+{
+ quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
+ if (quirk) {
+ fix += quirk->value;
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+ __alc_pick_fixup(codec, fix, quirk->name, pre_init);
+#else
+ __alc_pick_fixup(codec, fix, NULL, pre_init);
+#endif
+ }
+}
+
+static void alc_pick_fixup_model(struct hda_codec *codec,
+ const struct alc_model_fixup *models,
+ const struct snd_pci_quirk *quirk,
+ const struct alc_fixup *fix,
+ int pre_init)
+{
+ if (codec->modelname && models) {
+ while (models->name) {
+ if (!strcmp(codec->modelname, models->name)) {
+ fix += models->id;
+ break;
+ }
+ models++;
+ }
+ __alc_pick_fixup(codec, fix, codec->modelname, pre_init);
+ } else {
+ alc_pick_fixup(codec, quirk, fix, pre_init);
+ }
}
static int alc_read_coef_idx(struct hda_codec *codec,
{ }
};
+/*
+ *ALC888 Acer Aspire 7730G model
+ */
+
+static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
+/* Bias voltage on for external mic port */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN | PIN_VREF80},
+/* Front Mic: set to PIN_IN (empty by default) */
+ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
+/* Unselect Front Mic by default in input mixer 3 */
+ {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)},
+/* Enable unsolicited event for HP jack */
+ {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
+/* Enable speaker output */
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/* Enable headphone output */
+ {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP},
+ {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
+ {0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
+/*Enable internal subwoofer */
+ {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+ {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
+ {0x17, AC_VERB_SET_EAPD_BTLENABLE, 2},
+ { }
+};
+
/*
* ALC889 Acer Aspire 8930G model
*/
spec->autocfg.speaker_pins[2] = 0x17;
}
+static void alc888_acer_aspire_7730g_setup(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ spec->autocfg.hp_pins[0] = 0x15;
+ spec->autocfg.speaker_pins[0] = 0x14;
+ spec->autocfg.speaker_pins[1] = 0x16;
+ spec->autocfg.speaker_pins[2] = 0x17;
+}
+
static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
};
/* auto-toggle front mic */
-static void alc880_uniwill_mic_automute(struct hda_codec *codec)
+static void alc88x_simple_mic_automute(struct hda_codec *codec)
{
unsigned int present;
unsigned char bits;
static void alc880_uniwill_init_hook(struct hda_codec *codec)
{
alc_automute_amp(codec);
- alc880_uniwill_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
}
static void alc880_uniwill_unsol_event(struct hda_codec *codec,
*/
switch (res >> 28) {
case ALC880_MIC_EVENT:
- alc880_uniwill_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
break;
default:
alc_automute_amp_unsol_event(codec, res);
SND_PCI_QUIRK(0x1734, 0x10b0, "Fujitsu", ALC880_FUJITSU),
SND_PCI_QUIRK(0x1854, 0x0018, "LG LW20", ALC880_LG_LW),
SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_LG),
+ SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_LG),
SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_LG),
SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_LG_LW),
SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_TCL_S700),
{ } /* end */
};
-static struct snd_kcontrol_new alc883_medion_md2_mixer[] = {
- HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Headphone Playback Switch", 0x14, 0x0, HDA_OUTPUT),
- HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT),
- HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT),
- HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
- HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT),
- HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT),
- { } /* end */
-};
-
static struct snd_kcontrol_new alc883_medion_wim2160_mixer[] = {
HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT),
alc888_lenovo_ms7195_rca_automute(codec);
}
-static struct hda_verb alc883_medion_md2_verbs[] = {
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
- {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
-
- {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
-
- {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
/* toggle speaker-output according to the hp-jack state */
-static void alc883_medion_md2_setup(struct hda_codec *codec)
+static void alc883_lenovo_nb0763_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
#define alc883_targa_init_hook alc882_targa_init_hook
#define alc883_targa_unsol_event alc882_targa_unsol_event
-static void alc883_clevo_m720_mic_automute(struct hda_codec *codec)
-{
- unsigned int present;
-
- present = snd_hda_jack_detect(codec, 0x18);
- snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
- HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
-}
-
static void alc883_clevo_m720_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
static void alc883_clevo_m720_init_hook(struct hda_codec *codec)
{
alc_automute_amp(codec);
- alc883_clevo_m720_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
}
static void alc883_clevo_m720_unsol_event(struct hda_codec *codec,
{
switch (res >> 26) {
case ALC880_MIC_EVENT:
- alc883_clevo_m720_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
break;
default:
alc_automute_amp_unsol_event(codec, res);
{ }
};
-static struct hda_verb alc888_acer_aspire_7730G_verbs[] = {
- {0x15, AC_VERB_SET_CONNECT_SEL, 0x00},
- {0x17, AC_VERB_SET_CONNECT_SEL, 0x02},
- {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN},
- { } /* end */
-};
-
static void alc888_6st_dell_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
[ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g",
[ALC888_ACER_ASPIRE_7730G] = "acer-aspire-7730g",
[ALC883_MEDION] = "medion",
- [ALC883_MEDION_MD2] = "medion-md2",
[ALC883_MEDION_WIM2160] = "medion-wim2160",
[ALC883_LAPTOP_EAPD] = "laptop-eapd",
[ALC883_LENOVO_101E_2ch] = "lenovo-101e",
SND_PCI_QUIRK(0x17aa, 0x3bfc, "Lenovo NB0763", ALC883_LENOVO_NB0763),
SND_PCI_QUIRK(0x17aa, 0x3bfd, "Lenovo NB0763", ALC883_LENOVO_NB0763),
SND_PCI_QUIRK(0x17aa, 0x101d, "Lenovo Sky", ALC888_LENOVO_SKY),
- SND_PCI_QUIRK(0x17c0, 0x4071, "MEDION MD2", ALC883_MEDION_MD2),
SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG),
SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG),
SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66),
.const_channel_count = 6,
.input_mux = &alc883_capture_source,
.unsol_event = alc_automute_amp_unsol_event,
- .setup = alc888_acer_aspire_6530g_setup,
+ .setup = alc888_acer_aspire_7730g_setup,
.init_hook = alc_automute_amp,
},
[ALC883_MEDION] = {
.channel_mode = alc883_sixstack_modes,
.input_mux = &alc883_capture_source,
},
- [ALC883_MEDION_MD2] = {
- .mixers = { alc883_medion_md2_mixer},
- .init_verbs = { alc883_init_verbs, alc883_medion_md2_verbs},
- .num_dacs = ARRAY_SIZE(alc883_dac_nids),
- .dac_nids = alc883_dac_nids,
- .dig_out_nid = ALC883_DIGOUT_NID,
- .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes),
- .channel_mode = alc883_3ST_2ch_modes,
- .input_mux = &alc883_capture_source,
- .unsol_event = alc_automute_amp_unsol_event,
- .setup = alc883_medion_md2_setup,
- .init_hook = alc_automute_amp,
- },
[ALC883_MEDION_WIM2160] = {
.mixers = { alc883_medion_wim2160_mixer },
.init_verbs = { alc883_init_verbs, alc883_medion_wim2160_verbs },
.need_dac_fix = 1,
.input_mux = &alc883_lenovo_nb0763_capture_source,
.unsol_event = alc_automute_amp_unsol_event,
- .setup = alc883_medion_md2_setup,
+ .setup = alc883_lenovo_nb0763_setup,
.init_hook = alc_automute_amp,
},
[ALC888_LENOVO_MS7195_DIG] = {
/* different alc269-variants */
enum {
ALC269_TYPE_NORMAL,
+ ALC269_TYPE_ALC258,
ALC269_TYPE_ALC259,
+ ALC269_TYPE_ALC269VB,
+ ALC269_TYPE_ALC270,
ALC269_TYPE_ALC271X,
};
static int patch_alc269(struct hda_codec *codec)
{
struct alc_spec *spec;
- int board_config;
+ int board_config, coef;
int err;
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
alc_auto_parse_customize_define(codec);
- if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){
+ coef = alc_read_coef_idx(codec, 0);
+ if ((coef & 0x00f0) == 0x0010) {
if (codec->bus->pci->subsystem_vendor == 0x1025 &&
spec->cdefine.platform_type == 1) {
alc_codec_rename(codec, "ALC271X");
spec->codec_variant = ALC269_TYPE_ALC271X;
- } else {
+ } else if ((coef & 0xf000) == 0x1000) {
+ spec->codec_variant = ALC269_TYPE_ALC270;
+ } else if ((coef & 0xf000) == 0x2000) {
alc_codec_rename(codec, "ALC259");
spec->codec_variant = ALC269_TYPE_ALC259;
+ } else if ((coef & 0xf000) == 0x3000) {
+ alc_codec_rename(codec, "ALC258");
+ spec->codec_variant = ALC269_TYPE_ALC258;
+ } else {
+ alc_codec_rename(codec, "ALC269VB");
+ spec->codec_variant = ALC269_TYPE_ALC269VB;
}
} else
alc_fix_pll_init(codec, 0x20, 0x04, 15);
spec->stream_digital_capture = &alc269_pcm_digital_capture;
if (!spec->adc_nids) { /* wasn't filled automatically? use default */
- if (spec->codec_variant != ALC269_TYPE_NORMAL) {
+ if (spec->codec_variant == ALC269_TYPE_NORMAL) {
spec->adc_nids = alc269_adc_nids;
spec->num_adc_nids = ARRAY_SIZE(alc269_adc_nids);
spec->capsrc_nids = alc269_capsrc_nids;
{}
};
-static void alc861vd_lenovo_mic_automute(struct hda_codec *codec)
-{
- unsigned int present;
- unsigned char bits;
-
- present = snd_hda_jack_detect(codec, 0x18);
- bits = present ? HDA_AMP_MUTE : 0;
-
- snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1,
- HDA_AMP_MUTE, bits);
-}
-
static void alc861vd_lenovo_setup(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
static void alc861vd_lenovo_init_hook(struct hda_codec *codec)
{
alc_automute_amp(codec);
- alc861vd_lenovo_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
}
static void alc861vd_lenovo_unsol_event(struct hda_codec *codec,
{
switch (res >> 26) {
case ALC880_MIC_EVENT:
- alc861vd_lenovo_mic_automute(codec);
+ alc88x_simple_mic_automute(codec);
break;
default:
alc_automute_amp_unsol_event(codec, res);
static int alc861vd_auto_create_input_ctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
{
- return alc_auto_create_input_ctls(codec, cfg, 0x15, 0x09, 0);
+ return alc_auto_create_input_ctls(codec, cfg, 0x0b, 0x22, 0);
}
return 0x02;
else if (nid >= 0x0c && nid <= 0x0e)
return nid - 0x0c + 0x02;
+ else if (nid == 0x26) /* ALC887-VD has this DAC too */
+ return 0x25;
else
return 0;
}
static hda_nid_t alc662_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
hda_nid_t dac)
{
- hda_nid_t mix[4];
+ hda_nid_t mix[5];
int i, num;
num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
alc_inithook(codec);
}
+static void alc272_fixup_mario(struct hda_codec *codec,
+ const struct alc_fixup *fix, int pre_init) {
+ if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
+ (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
+ (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
+ (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+ (0 << AC_AMPCAP_MUTE_SHIFT)))
+ printk(KERN_WARNING
+ "hda_codec: failed to override amp caps for NID 0x2\n");
+}
+
enum {
ALC662_FIXUP_ASPIRE,
ALC662_FIXUP_IDEAPAD,
+ ALC272_FIXUP_MARIO,
};
static const struct alc_fixup alc662_fixups[] = {
{ }
}
},
+ [ALC272_FIXUP_MARIO] = {
+ .func = alc272_fixup_mario,
+ }
};
static struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+ SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
{}
};
+static const struct alc_model_fixup alc662_fixup_models[] = {
+ {.id = ALC272_FIXUP_MARIO, .name = "mario"},
+ {}
+};
static int patch_alc662(struct hda_codec *codec)
codec->patch_ops = alc_patch_ops;
if (board_config == ALC662_AUTO) {
spec->init_hook = alc662_auto_init;
- alc_pick_fixup(codec, alc662_fixup_tbl, alc662_fixups, 0);
+ alc_pick_fixup_model(codec, alc662_fixup_models,
+ alc662_fixup_tbl, alc662_fixups, 0);
}
alc_init_jacks(codec);
{
if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){
kfree(codec->chip_name);
- codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
+ if (codec->vendor_id == 0x10ec0887)
+ codec->chip_name = kstrdup("ALC887-VD", GFP_KERNEL);
+ else
+ codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL);
if (!codec->chip_name) {
alc_free(codec);
return -ENOMEM;
{ .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
.patch = patch_alc882 },
{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
- { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
+ { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc888 },
{ .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
.patch = patch_alc882 },
{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 },