diff options
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 186 |
1 files changed, 116 insertions, 70 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index d906c5b74cf0..3acb5824ad39 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #include "hda_codec.h" | 31 | #include "hda_codec.h" |
32 | #include "hda_local.h" | 32 | #include "hda_local.h" |
33 | #include "hda_auto_parser.h" | ||
33 | #include "hda_beep.h" | 34 | #include "hda_beep.h" |
34 | #include "hda_jack.h" | 35 | #include "hda_jack.h" |
35 | 36 | ||
@@ -66,6 +67,7 @@ struct imux_info { | |||
66 | }; | 67 | }; |
67 | 68 | ||
68 | struct conexant_spec { | 69 | struct conexant_spec { |
70 | struct hda_gen_spec gen; | ||
69 | 71 | ||
70 | const struct snd_kcontrol_new *mixers[5]; | 72 | const struct snd_kcontrol_new *mixers[5]; |
71 | int num_mixers; | 73 | int num_mixers; |
@@ -141,6 +143,7 @@ struct conexant_spec { | |||
141 | unsigned int hp_laptop:1; | 143 | unsigned int hp_laptop:1; |
142 | unsigned int asus:1; | 144 | unsigned int asus:1; |
143 | unsigned int pin_eapd_ctrls:1; | 145 | unsigned int pin_eapd_ctrls:1; |
146 | unsigned int fixup_stereo_dmic:1; | ||
144 | 147 | ||
145 | unsigned int adc_switching:1; | 148 | unsigned int adc_switching:1; |
146 | 149 | ||
@@ -1601,17 +1604,13 @@ static void cxt5051_update_speaker(struct hda_codec *codec) | |||
1601 | unsigned int pinctl; | 1604 | unsigned int pinctl; |
1602 | /* headphone pin */ | 1605 | /* headphone pin */ |
1603 | pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; | 1606 | pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; |
1604 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 1607 | snd_hda_set_pin_ctl(codec, 0x16, pinctl); |
1605 | pinctl); | ||
1606 | /* speaker pin */ | 1608 | /* speaker pin */ |
1607 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | 1609 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; |
1608 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 1610 | snd_hda_set_pin_ctl(codec, 0x1a, pinctl); |
1609 | pinctl); | ||
1610 | /* on ideapad there is an additional speaker (subwoofer) to mute */ | 1611 | /* on ideapad there is an additional speaker (subwoofer) to mute */ |
1611 | if (spec->ideapad) | 1612 | if (spec->ideapad) |
1612 | snd_hda_codec_write(codec, 0x1b, 0, | 1613 | snd_hda_set_pin_ctl(codec, 0x1b, pinctl); |
1613 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1614 | pinctl); | ||
1615 | } | 1614 | } |
1616 | 1615 | ||
1617 | /* turn on/off EAPD (+ mute HP) as a master switch */ | 1616 | /* turn on/off EAPD (+ mute HP) as a master switch */ |
@@ -1996,8 +1995,7 @@ static void cxt5066_update_speaker(struct hda_codec *codec) | |||
1996 | 1995 | ||
1997 | /* Port A (HP) */ | 1996 | /* Port A (HP) */ |
1998 | pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0; | 1997 | pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0; |
1999 | snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 1998 | snd_hda_set_pin_ctl(codec, 0x19, pinctl); |
2000 | pinctl); | ||
2001 | 1999 | ||
2002 | /* Port D (HP/LO) */ | 2000 | /* Port D (HP/LO) */ |
2003 | pinctl = spec->cur_eapd ? spec->port_d_mode : 0; | 2001 | pinctl = spec->cur_eapd ? spec->port_d_mode : 0; |
@@ -2010,13 +2008,11 @@ static void cxt5066_update_speaker(struct hda_codec *codec) | |||
2010 | if (!hp_port_d_present(spec)) | 2008 | if (!hp_port_d_present(spec)) |
2011 | pinctl = 0; | 2009 | pinctl = 0; |
2012 | } | 2010 | } |
2013 | snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 2011 | snd_hda_set_pin_ctl(codec, 0x1c, pinctl); |
2014 | pinctl); | ||
2015 | 2012 | ||
2016 | /* CLASS_D AMP */ | 2013 | /* CLASS_D AMP */ |
2017 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | 2014 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; |
2018 | snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 2015 | snd_hda_set_pin_ctl(codec, 0x1f, pinctl); |
2019 | pinctl); | ||
2020 | } | 2016 | } |
2021 | 2017 | ||
2022 | /* turn on/off EAPD (+ mute HP) as a master switch */ | 2018 | /* turn on/off EAPD (+ mute HP) as a master switch */ |
@@ -2047,8 +2043,7 @@ static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) | |||
2047 | /* Even though port F is the DC input, the bias is controlled on port B. | 2043 | /* Even though port F is the DC input, the bias is controlled on port B. |
2048 | * we also leave that port as an active input (but unselected) in DC mode | 2044 | * we also leave that port as an active input (but unselected) in DC mode |
2049 | * just in case that is necessary to make the bias setting take effect. */ | 2045 | * just in case that is necessary to make the bias setting take effect. */ |
2050 | return snd_hda_codec_write_cache(codec, 0x1a, 0, | 2046 | return snd_hda_set_pin_ctl_cache(codec, 0x1a, |
2051 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
2052 | cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); | 2047 | cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); |
2053 | } | 2048 | } |
2054 | 2049 | ||
@@ -2081,14 +2076,14 @@ static void cxt5066_olpc_select_mic(struct hda_codec *codec) | |||
2081 | } | 2076 | } |
2082 | 2077 | ||
2083 | /* disable DC (port F) */ | 2078 | /* disable DC (port F) */ |
2084 | snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | 2079 | snd_hda_set_pin_ctl(codec, 0x1e, 0); |
2085 | 2080 | ||
2086 | /* external mic, port B */ | 2081 | /* external mic, port B */ |
2087 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 2082 | snd_hda_set_pin_ctl(codec, 0x1a, |
2088 | spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); | 2083 | spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); |
2089 | 2084 | ||
2090 | /* internal mic, port C */ | 2085 | /* internal mic, port C */ |
2091 | snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 2086 | snd_hda_set_pin_ctl(codec, 0x1b, |
2092 | spec->ext_mic_present ? 0 : PIN_VREF80); | 2087 | spec->ext_mic_present ? 0 : PIN_VREF80); |
2093 | } | 2088 | } |
2094 | 2089 | ||
@@ -3357,9 +3352,7 @@ static void do_automute(struct hda_codec *codec, int num_pins, | |||
3357 | struct conexant_spec *spec = codec->spec; | 3352 | struct conexant_spec *spec = codec->spec; |
3358 | int i; | 3353 | int i; |
3359 | for (i = 0; i < num_pins; i++) | 3354 | for (i = 0; i < num_pins; i++) |
3360 | snd_hda_codec_write(codec, pins[i], 0, | 3355 | snd_hda_set_pin_ctl(codec, pins[i], on ? PIN_OUT : 0); |
3361 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
3362 | on ? PIN_OUT : 0); | ||
3363 | if (spec->pin_eapd_ctrls) | 3356 | if (spec->pin_eapd_ctrls) |
3364 | cx_auto_turn_eapd(codec, num_pins, pins, on); | 3357 | cx_auto_turn_eapd(codec, num_pins, pins, on); |
3365 | } | 3358 | } |
@@ -3976,8 +3969,7 @@ static void cx_auto_init_output(struct hda_codec *codec) | |||
3976 | if (snd_hda_query_pin_caps(codec, cfg->hp_pins[i]) & | 3969 | if (snd_hda_query_pin_caps(codec, cfg->hp_pins[i]) & |
3977 | AC_PINCAP_HP_DRV) | 3970 | AC_PINCAP_HP_DRV) |
3978 | val |= AC_PINCTL_HP_EN; | 3971 | val |= AC_PINCTL_HP_EN; |
3979 | snd_hda_codec_write(codec, cfg->hp_pins[i], 0, | 3972 | snd_hda_set_pin_ctl(codec, cfg->hp_pins[i], val); |
3980 | AC_VERB_SET_PIN_WIDGET_CONTROL, val); | ||
3981 | } | 3973 | } |
3982 | mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); | 3974 | mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); |
3983 | mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); | 3975 | mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); |
@@ -4030,13 +4022,11 @@ static void cx_auto_init_input(struct hda_codec *codec) | |||
4030 | } | 4022 | } |
4031 | 4023 | ||
4032 | for (i = 0; i < cfg->num_inputs; i++) { | 4024 | for (i = 0; i < cfg->num_inputs; i++) { |
4033 | unsigned int type; | 4025 | hda_nid_t pin = cfg->inputs[i].pin; |
4026 | unsigned int type = PIN_IN; | ||
4034 | if (cfg->inputs[i].type == AUTO_PIN_MIC) | 4027 | if (cfg->inputs[i].type == AUTO_PIN_MIC) |
4035 | type = PIN_VREF80; | 4028 | type |= snd_hda_get_default_vref(codec, pin); |
4036 | else | 4029 | snd_hda_set_pin_ctl(codec, pin, type); |
4037 | type = PIN_IN; | ||
4038 | snd_hda_codec_write(codec, cfg->inputs[i].pin, 0, | ||
4039 | AC_VERB_SET_PIN_WIDGET_CONTROL, type); | ||
4040 | } | 4030 | } |
4041 | 4031 | ||
4042 | if (spec->auto_mic) { | 4032 | if (spec->auto_mic) { |
@@ -4063,11 +4053,9 @@ static void cx_auto_init_digital(struct hda_codec *codec) | |||
4063 | struct auto_pin_cfg *cfg = &spec->autocfg; | 4053 | struct auto_pin_cfg *cfg = &spec->autocfg; |
4064 | 4054 | ||
4065 | if (spec->multiout.dig_out_nid) | 4055 | if (spec->multiout.dig_out_nid) |
4066 | snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0, | 4056 | snd_hda_set_pin_ctl(codec, cfg->dig_out_pins[0], PIN_OUT); |
4067 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); | ||
4068 | if (spec->dig_in_nid) | 4057 | if (spec->dig_in_nid) |
4069 | snd_hda_codec_write(codec, cfg->dig_in_pin, 0, | 4058 | snd_hda_set_pin_ctl(codec, cfg->dig_in_pin, PIN_IN); |
4070 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); | ||
4071 | } | 4059 | } |
4072 | 4060 | ||
4073 | static int cx_auto_init(struct hda_codec *codec) | 4061 | static int cx_auto_init(struct hda_codec *codec) |
@@ -4084,9 +4072,9 @@ static int cx_auto_init(struct hda_codec *codec) | |||
4084 | 4072 | ||
4085 | static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, | 4073 | static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, |
4086 | const char *dir, int cidx, | 4074 | const char *dir, int cidx, |
4087 | hda_nid_t nid, int hda_dir, int amp_idx) | 4075 | hda_nid_t nid, int hda_dir, int amp_idx, int chs) |
4088 | { | 4076 | { |
4089 | static char name[32]; | 4077 | static char name[44]; |
4090 | static struct snd_kcontrol_new knew[] = { | 4078 | static struct snd_kcontrol_new knew[] = { |
4091 | HDA_CODEC_VOLUME(name, 0, 0, 0), | 4079 | HDA_CODEC_VOLUME(name, 0, 0, 0), |
4092 | HDA_CODEC_MUTE(name, 0, 0, 0), | 4080 | HDA_CODEC_MUTE(name, 0, 0, 0), |
@@ -4096,7 +4084,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, | |||
4096 | 4084 | ||
4097 | for (i = 0; i < 2; i++) { | 4085 | for (i = 0; i < 2; i++) { |
4098 | struct snd_kcontrol *kctl; | 4086 | struct snd_kcontrol *kctl; |
4099 | knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx, | 4087 | knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx, |
4100 | hda_dir); | 4088 | hda_dir); |
4101 | knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; | 4089 | knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; |
4102 | knew[i].index = cidx; | 4090 | knew[i].index = cidx; |
@@ -4115,7 +4103,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, | |||
4115 | } | 4103 | } |
4116 | 4104 | ||
4117 | #define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \ | 4105 | #define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \ |
4118 | cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0) | 4106 | cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3) |
4119 | 4107 | ||
4120 | #define cx_auto_add_pb_volume(codec, nid, str, idx) \ | 4108 | #define cx_auto_add_pb_volume(codec, nid, str, idx) \ |
4121 | cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) | 4109 | cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) |
@@ -4185,6 +4173,36 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) | |||
4185 | return 0; | 4173 | return 0; |
4186 | } | 4174 | } |
4187 | 4175 | ||
4176 | /* Returns zero if this is a normal stereo channel, and non-zero if it should | ||
4177 | be split in two independent channels. | ||
4178 | dest_label must be at least 44 characters. */ | ||
4179 | static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label, | ||
4180 | char *dest_label, int nid) | ||
4181 | { | ||
4182 | struct conexant_spec *spec = codec->spec; | ||
4183 | int i; | ||
4184 | |||
4185 | if (!spec->fixup_stereo_dmic) | ||
4186 | return 0; | ||
4187 | |||
4188 | for (i = 0; i < AUTO_CFG_MAX_INS; i++) { | ||
4189 | int def_conf; | ||
4190 | if (spec->autocfg.inputs[i].pin != nid) | ||
4191 | continue; | ||
4192 | |||
4193 | if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC) | ||
4194 | return 0; | ||
4195 | def_conf = snd_hda_codec_get_pincfg(codec, nid); | ||
4196 | if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) | ||
4197 | return 0; | ||
4198 | |||
4199 | /* Finally found the inverted internal mic! */ | ||
4200 | snprintf(dest_label, 44, "Inverted %s", label); | ||
4201 | return 1; | ||
4202 | } | ||
4203 | return 0; | ||
4204 | } | ||
4205 | |||
4188 | static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, | 4206 | static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, |
4189 | const char *label, const char *pfx, | 4207 | const char *label, const char *pfx, |
4190 | int cidx) | 4208 | int cidx) |
@@ -4193,14 +4211,25 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, | |||
4193 | int i; | 4211 | int i; |
4194 | 4212 | ||
4195 | for (i = 0; i < spec->num_adc_nids; i++) { | 4213 | for (i = 0; i < spec->num_adc_nids; i++) { |
4214 | char rightch_label[44]; | ||
4196 | hda_nid_t adc_nid = spec->adc_nids[i]; | 4215 | hda_nid_t adc_nid = spec->adc_nids[i]; |
4197 | int idx = get_input_connection(codec, adc_nid, nid); | 4216 | int idx = get_input_connection(codec, adc_nid, nid); |
4198 | if (idx < 0) | 4217 | if (idx < 0) |
4199 | continue; | 4218 | continue; |
4200 | if (codec->single_adc_amp) | 4219 | if (codec->single_adc_amp) |
4201 | idx = 0; | 4220 | idx = 0; |
4221 | |||
4222 | if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) { | ||
4223 | /* Make two independent kcontrols for left and right */ | ||
4224 | int err = cx_auto_add_volume_idx(codec, label, pfx, | ||
4225 | cidx, adc_nid, HDA_INPUT, idx, 1); | ||
4226 | if (err < 0) | ||
4227 | return err; | ||
4228 | return cx_auto_add_volume_idx(codec, rightch_label, pfx, | ||
4229 | cidx, adc_nid, HDA_INPUT, idx, 2); | ||
4230 | } | ||
4202 | return cx_auto_add_volume_idx(codec, label, pfx, | 4231 | return cx_auto_add_volume_idx(codec, label, pfx, |
4203 | cidx, adc_nid, HDA_INPUT, idx); | 4232 | cidx, adc_nid, HDA_INPUT, idx, 3); |
4204 | } | 4233 | } |
4205 | return 0; | 4234 | return 0; |
4206 | } | 4235 | } |
@@ -4213,9 +4242,19 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx, | |||
4213 | int i, con; | 4242 | int i, con; |
4214 | 4243 | ||
4215 | nid = spec->imux_info[idx].pin; | 4244 | nid = spec->imux_info[idx].pin; |
4216 | if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) | 4245 | if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { |
4246 | char rightch_label[44]; | ||
4247 | if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) { | ||
4248 | int err = cx_auto_add_volume_idx(codec, label, " Boost", | ||
4249 | cidx, nid, HDA_INPUT, 0, 1); | ||
4250 | if (err < 0) | ||
4251 | return err; | ||
4252 | return cx_auto_add_volume_idx(codec, rightch_label, " Boost", | ||
4253 | cidx, nid, HDA_INPUT, 0, 2); | ||
4254 | } | ||
4217 | return cx_auto_add_volume(codec, label, " Boost", cidx, | 4255 | return cx_auto_add_volume(codec, label, " Boost", cidx, |
4218 | nid, HDA_INPUT); | 4256 | nid, HDA_INPUT); |
4257 | } | ||
4219 | con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, | 4258 | con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, |
4220 | &mux, false, 0); | 4259 | &mux, false, 0); |
4221 | if (con < 0) | 4260 | if (con < 0) |
@@ -4370,37 +4409,21 @@ static const struct hda_codec_ops cx_auto_patch_ops = { | |||
4370 | /* | 4409 | /* |
4371 | * pin fix-up | 4410 | * pin fix-up |
4372 | */ | 4411 | */ |
4373 | struct cxt_pincfg { | ||
4374 | hda_nid_t nid; | ||
4375 | u32 val; | ||
4376 | }; | ||
4377 | |||
4378 | static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg) | ||
4379 | { | ||
4380 | for (; cfg->nid; cfg++) | ||
4381 | snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); | ||
4382 | |||
4383 | } | ||
4384 | |||
4385 | static void apply_pin_fixup(struct hda_codec *codec, | ||
4386 | const struct snd_pci_quirk *quirk, | ||
4387 | const struct cxt_pincfg **table) | ||
4388 | { | ||
4389 | quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk); | ||
4390 | if (quirk) { | ||
4391 | snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n", | ||
4392 | quirk->name); | ||
4393 | apply_pincfg(codec, table[quirk->value]); | ||
4394 | } | ||
4395 | } | ||
4396 | |||
4397 | enum { | 4412 | enum { |
4398 | CXT_PINCFG_LENOVO_X200, | 4413 | CXT_PINCFG_LENOVO_X200, |
4399 | CXT_PINCFG_LENOVO_TP410, | 4414 | CXT_PINCFG_LENOVO_TP410, |
4415 | CXT_FIXUP_STEREO_DMIC, | ||
4400 | }; | 4416 | }; |
4401 | 4417 | ||
4418 | static void cxt_fixup_stereo_dmic(struct hda_codec *codec, | ||
4419 | const struct hda_fixup *fix, int action) | ||
4420 | { | ||
4421 | struct conexant_spec *spec = codec->spec; | ||
4422 | spec->fixup_stereo_dmic = 1; | ||
4423 | } | ||
4424 | |||
4402 | /* ThinkPad X200 & co with cxt5051 */ | 4425 | /* ThinkPad X200 & co with cxt5051 */ |
4403 | static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = { | 4426 | static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { |
4404 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ | 4427 | { 0x16, 0x042140ff }, /* HP (seq# overridden) */ |
4405 | { 0x17, 0x21a11000 }, /* dock-mic */ | 4428 | { 0x17, 0x21a11000 }, /* dock-mic */ |
4406 | { 0x19, 0x2121103f }, /* dock-HP */ | 4429 | { 0x19, 0x2121103f }, /* dock-HP */ |
@@ -4409,16 +4432,26 @@ static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = { | |||
4409 | }; | 4432 | }; |
4410 | 4433 | ||
4411 | /* ThinkPad 410/420/510/520, X201 & co with cxt5066 */ | 4434 | /* ThinkPad 410/420/510/520, X201 & co with cxt5066 */ |
4412 | static const struct cxt_pincfg cxt_pincfg_lenovo_tp410[] = { | 4435 | static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = { |
4413 | { 0x19, 0x042110ff }, /* HP (seq# overridden) */ | 4436 | { 0x19, 0x042110ff }, /* HP (seq# overridden) */ |
4414 | { 0x1a, 0x21a190f0 }, /* dock-mic */ | 4437 | { 0x1a, 0x21a190f0 }, /* dock-mic */ |
4415 | { 0x1c, 0x212140ff }, /* dock-HP */ | 4438 | { 0x1c, 0x212140ff }, /* dock-HP */ |
4416 | {} | 4439 | {} |
4417 | }; | 4440 | }; |
4418 | 4441 | ||
4419 | static const struct cxt_pincfg *cxt_pincfg_tbl[] = { | 4442 | static const struct hda_fixup cxt_fixups[] = { |
4420 | [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200, | 4443 | [CXT_PINCFG_LENOVO_X200] = { |
4421 | [CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410, | 4444 | .type = HDA_FIXUP_PINS, |
4445 | .v.pins = cxt_pincfg_lenovo_x200, | ||
4446 | }, | ||
4447 | [CXT_PINCFG_LENOVO_TP410] = { | ||
4448 | .type = HDA_FIXUP_PINS, | ||
4449 | .v.pins = cxt_pincfg_lenovo_tp410, | ||
4450 | }, | ||
4451 | [CXT_FIXUP_STEREO_DMIC] = { | ||
4452 | .type = HDA_FIXUP_FUNC, | ||
4453 | .v.func = cxt_fixup_stereo_dmic, | ||
4454 | }, | ||
4422 | }; | 4455 | }; |
4423 | 4456 | ||
4424 | static const struct snd_pci_quirk cxt5051_fixups[] = { | 4457 | static const struct snd_pci_quirk cxt5051_fixups[] = { |
@@ -4432,6 +4465,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { | |||
4432 | SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), | 4465 | SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), |
4433 | SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410), | 4466 | SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410), |
4434 | SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410), | 4467 | SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410), |
4468 | SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), | ||
4435 | {} | 4469 | {} |
4436 | }; | 4470 | }; |
4437 | 4471 | ||
@@ -4471,13 +4505,16 @@ static int patch_conexant_auto(struct hda_codec *codec) | |||
4471 | case 0x14f15051: | 4505 | case 0x14f15051: |
4472 | add_cx5051_fake_mutes(codec); | 4506 | add_cx5051_fake_mutes(codec); |
4473 | codec->pin_amp_workaround = 1; | 4507 | codec->pin_amp_workaround = 1; |
4474 | apply_pin_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl); | 4508 | snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups); |
4475 | break; | 4509 | break; |
4476 | default: | 4510 | default: |
4477 | codec->pin_amp_workaround = 1; | 4511 | codec->pin_amp_workaround = 1; |
4478 | apply_pin_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl); | 4512 | snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups); |
4513 | break; | ||
4479 | } | 4514 | } |
4480 | 4515 | ||
4516 | snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); | ||
4517 | |||
4481 | /* Show mute-led control only on HP laptops | 4518 | /* Show mute-led control only on HP laptops |
4482 | * This is a sort of white-list: on HP laptops, EAPD corresponds | 4519 | * This is a sort of white-list: on HP laptops, EAPD corresponds |
4483 | * only to the mute-LED without actualy amp function. Meanwhile, | 4520 | * only to the mute-LED without actualy amp function. Meanwhile, |
@@ -4556,6 +4593,12 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = { | |||
4556 | .patch = patch_conexant_auto }, | 4593 | .patch = patch_conexant_auto }, |
4557 | { .id = 0x14f150b9, .name = "CX20665", | 4594 | { .id = 0x14f150b9, .name = "CX20665", |
4558 | .patch = patch_conexant_auto }, | 4595 | .patch = patch_conexant_auto }, |
4596 | { .id = 0x14f1510f, .name = "CX20751/2", | ||
4597 | .patch = patch_conexant_auto }, | ||
4598 | { .id = 0x14f15110, .name = "CX20751/2", | ||
4599 | .patch = patch_conexant_auto }, | ||
4600 | { .id = 0x14f15111, .name = "CX20753/4", | ||
4601 | .patch = patch_conexant_auto }, | ||
4559 | {} /* terminator */ | 4602 | {} /* terminator */ |
4560 | }; | 4603 | }; |
4561 | 4604 | ||
@@ -4576,6 +4619,9 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab"); | |||
4576 | MODULE_ALIAS("snd-hda-codec-id:14f150ac"); | 4619 | MODULE_ALIAS("snd-hda-codec-id:14f150ac"); |
4577 | MODULE_ALIAS("snd-hda-codec-id:14f150b8"); | 4620 | MODULE_ALIAS("snd-hda-codec-id:14f150b8"); |
4578 | MODULE_ALIAS("snd-hda-codec-id:14f150b9"); | 4621 | MODULE_ALIAS("snd-hda-codec-id:14f150b9"); |
4622 | MODULE_ALIAS("snd-hda-codec-id:14f1510f"); | ||
4623 | MODULE_ALIAS("snd-hda-codec-id:14f15110"); | ||
4624 | MODULE_ALIAS("snd-hda-codec-id:14f15111"); | ||
4579 | 4625 | ||
4580 | MODULE_LICENSE("GPL"); | 4626 | MODULE_LICENSE("GPL"); |
4581 | MODULE_DESCRIPTION("Conexant HD-audio codec"); | 4627 | MODULE_DESCRIPTION("Conexant HD-audio codec"); |