aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_conexant.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r--sound/pci/hda/patch_conexant.c165
1 files changed, 99 insertions, 66 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 76752d8ea73..0c8b5a1993e 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -136,6 +136,8 @@ struct conexant_spec {
136 unsigned int thinkpad:1; 136 unsigned int thinkpad:1;
137 unsigned int hp_laptop:1; 137 unsigned int hp_laptop:1;
138 unsigned int asus:1; 138 unsigned int asus:1;
139 unsigned int pin_eapd_ctrls:1;
140 unsigned int single_adc_amp:1;
139 141
140 unsigned int adc_switching:1; 142 unsigned int adc_switching:1;
141 143
@@ -1867,39 +1869,6 @@ static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
1867 { } /* end */ 1869 { } /* end */
1868}; 1870};
1869 1871
1870static const struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
1871 /* Line in, Mic */
1872 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1873 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1874 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1875 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1876 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1877 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1878 /* SPK */
1879 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1880 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
1881 /* HP, Amp */
1882 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1883 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
1884 /* Docking HP */
1885 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1886 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00},
1887 /* DAC1 */
1888 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1889 /* Record selector: Internal mic */
1890 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
1891 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
1892 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
1893 /* SPDIF route: PCM */
1894 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* needed for W500 Advanced Mini Dock 250410 */
1895 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
1896 /* EAPD */
1897 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1898 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
1899 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
1900 { } /* end */
1901};
1902
1903static const struct hda_verb cxt5051_f700_init_verbs[] = { 1872static const struct hda_verb cxt5051_f700_init_verbs[] = {
1904 /* Line in, Mic */ 1873 /* Line in, Mic */
1905 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1874 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
@@ -1968,7 +1937,6 @@ enum {
1968 CXT5051_LAPTOP, /* Laptops w/ EAPD support */ 1937 CXT5051_LAPTOP, /* Laptops w/ EAPD support */
1969 CXT5051_HP, /* no docking */ 1938 CXT5051_HP, /* no docking */
1970 CXT5051_HP_DV6736, /* HP without mic switch */ 1939 CXT5051_HP_DV6736, /* HP without mic switch */
1971 CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */
1972 CXT5051_F700, /* HP Compaq Presario F700 */ 1940 CXT5051_F700, /* HP Compaq Presario F700 */
1973 CXT5051_TOSHIBA, /* Toshiba M300 & co */ 1941 CXT5051_TOSHIBA, /* Toshiba M300 & co */
1974 CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ 1942 CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */
@@ -1980,7 +1948,6 @@ static const char *const cxt5051_models[CXT5051_MODELS] = {
1980 [CXT5051_LAPTOP] = "laptop", 1948 [CXT5051_LAPTOP] = "laptop",
1981 [CXT5051_HP] = "hp", 1949 [CXT5051_HP] = "hp",
1982 [CXT5051_HP_DV6736] = "hp-dv6736", 1950 [CXT5051_HP_DV6736] = "hp-dv6736",
1983 [CXT5051_LENOVO_X200] = "lenovo-x200",
1984 [CXT5051_F700] = "hp-700", 1951 [CXT5051_F700] = "hp-700",
1985 [CXT5051_TOSHIBA] = "toshiba", 1952 [CXT5051_TOSHIBA] = "toshiba",
1986 [CXT5051_IDEAPAD] = "ideapad", 1953 [CXT5051_IDEAPAD] = "ideapad",
@@ -1995,7 +1962,6 @@ static const struct snd_pci_quirk cxt5051_cfg_tbl[] = {
1995 SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", 1962 SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
1996 CXT5051_LAPTOP), 1963 CXT5051_LAPTOP),
1997 SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), 1964 SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
1998 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
1999 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), 1965 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD),
2000 {} 1966 {}
2001}; 1967};
@@ -2053,13 +2019,6 @@ static int patch_cxt5051(struct hda_codec *codec)
2053 spec->mixers[0] = cxt5051_hp_dv6736_mixers; 2019 spec->mixers[0] = cxt5051_hp_dv6736_mixers;
2054 spec->auto_mic = 0; 2020 spec->auto_mic = 0;
2055 break; 2021 break;
2056 case CXT5051_LENOVO_X200:
2057 spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
2058 /* Thinkpad X301 does not have S/PDIF wired and no ability
2059 to use a docking station. */
2060 if (codec->subsystem_id == 0x17aa211f)
2061 spec->multiout.dig_out_nid = 0;
2062 break;
2063 case CXT5051_F700: 2022 case CXT5051_F700:
2064 spec->init_verbs[0] = cxt5051_f700_init_verbs; 2023 spec->init_verbs[0] = cxt5051_f700_init_verbs;
2065 spec->mixers[0] = cxt5051_f700_mixers; 2024 spec->mixers[0] = cxt5051_f700_mixers;
@@ -3473,12 +3432,14 @@ static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
3473static void do_automute(struct hda_codec *codec, int num_pins, 3432static void do_automute(struct hda_codec *codec, int num_pins,
3474 hda_nid_t *pins, bool on) 3433 hda_nid_t *pins, bool on)
3475{ 3434{
3435 struct conexant_spec *spec = codec->spec;
3476 int i; 3436 int i;
3477 for (i = 0; i < num_pins; i++) 3437 for (i = 0; i < num_pins; i++)
3478 snd_hda_codec_write(codec, pins[i], 0, 3438 snd_hda_codec_write(codec, pins[i], 0,
3479 AC_VERB_SET_PIN_WIDGET_CONTROL, 3439 AC_VERB_SET_PIN_WIDGET_CONTROL,
3480 on ? PIN_OUT : 0); 3440 on ? PIN_OUT : 0);
3481 cx_auto_turn_eapd(codec, num_pins, pins, on); 3441 if (spec->pin_eapd_ctrls)
3442 cx_auto_turn_eapd(codec, num_pins, pins, on);
3482} 3443}
3483 3444
3484static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) 3445static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
@@ -3503,9 +3464,12 @@ static void cx_auto_update_speakers(struct hda_codec *codec)
3503 int on = 1; 3464 int on = 1;
3504 3465
3505 /* turn on HP EAPD when HP jacks are present */ 3466 /* turn on HP EAPD when HP jacks are present */
3506 if (spec->auto_mute) 3467 if (spec->pin_eapd_ctrls) {
3507 on = spec->hp_present; 3468 if (spec->auto_mute)
3508 cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); 3469 on = spec->hp_present;
3470 cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
3471 }
3472
3509 /* mute speakers in auto-mode if HP or LO jacks are plugged */ 3473 /* mute speakers in auto-mode if HP or LO jacks are plugged */
3510 if (spec->auto_mute) 3474 if (spec->auto_mute)
3511 on = !(spec->hp_present || 3475 on = !(spec->hp_present ||
@@ -3932,20 +3896,10 @@ static void cx_auto_parse_beep(struct hda_codec *codec)
3932#define cx_auto_parse_beep(codec) 3896#define cx_auto_parse_beep(codec)
3933#endif 3897#endif
3934 3898
3935static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) 3899/* parse EAPDs */
3936{
3937 int i;
3938 for (i = 0; i < nums; i++)
3939 if (list[i] == nid)
3940 return true;
3941 return false;
3942}
3943
3944/* parse extra-EAPD that aren't assigned to any pins */
3945static void cx_auto_parse_eapd(struct hda_codec *codec) 3900static void cx_auto_parse_eapd(struct hda_codec *codec)
3946{ 3901{
3947 struct conexant_spec *spec = codec->spec; 3902 struct conexant_spec *spec = codec->spec;
3948 struct auto_pin_cfg *cfg = &spec->autocfg;
3949 hda_nid_t nid, end_nid; 3903 hda_nid_t nid, end_nid;
3950 3904
3951 end_nid = codec->start_nid + codec->num_nodes; 3905 end_nid = codec->start_nid + codec->num_nodes;
@@ -3954,14 +3908,18 @@ static void cx_auto_parse_eapd(struct hda_codec *codec)
3954 continue; 3908 continue;
3955 if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) 3909 if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
3956 continue; 3910 continue;
3957 if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) ||
3958 found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) ||
3959 found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs))
3960 continue;
3961 spec->eapds[spec->num_eapds++] = nid; 3911 spec->eapds[spec->num_eapds++] = nid;
3962 if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) 3912 if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
3963 break; 3913 break;
3964 } 3914 }
3915
3916 /* NOTE: below is a wild guess; if we have more than two EAPDs,
3917 * it's a new chip, where EAPDs are supposed to be associated to
3918 * pins, and we can control EAPD per pin.
3919 * OTOH, if only one or two EAPDs are found, it's an old chip,
3920 * thus it might control over all pins.
3921 */
3922 spec->pin_eapd_ctrls = spec->num_eapds > 2;
3965} 3923}
3966 3924
3967static int cx_auto_parse_auto_config(struct hda_codec *codec) 3925static int cx_auto_parse_auto_config(struct hda_codec *codec)
@@ -4067,8 +4025,9 @@ static void cx_auto_init_output(struct hda_codec *codec)
4067 } 4025 }
4068 } 4026 }
4069 cx_auto_update_speakers(codec); 4027 cx_auto_update_speakers(codec);
4070 /* turn on/off extra EAPDs, too */ 4028 /* turn on all EAPDs if no individual EAPD control is available */
4071 cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); 4029 if (!spec->pin_eapd_ctrls)
4030 cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
4072} 4031}
4073 4032
4074static void cx_auto_init_input(struct hda_codec *codec) 4033static void cx_auto_init_input(struct hda_codec *codec)
@@ -4255,6 +4214,8 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
4255 int idx = get_input_connection(codec, adc_nid, nid); 4214 int idx = get_input_connection(codec, adc_nid, nid);
4256 if (idx < 0) 4215 if (idx < 0)
4257 continue; 4216 continue;
4217 if (spec->single_adc_amp)
4218 idx = 0;
4258 return cx_auto_add_volume_idx(codec, label, pfx, 4219 return cx_auto_add_volume_idx(codec, label, pfx,
4259 cidx, adc_nid, HDA_INPUT, idx); 4220 cidx, adc_nid, HDA_INPUT, idx);
4260 } 4221 }
@@ -4295,14 +4256,21 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
4295 struct hda_input_mux *imux = &spec->private_imux; 4256 struct hda_input_mux *imux = &spec->private_imux;
4296 const char *prev_label; 4257 const char *prev_label;
4297 int input_conn[HDA_MAX_NUM_INPUTS]; 4258 int input_conn[HDA_MAX_NUM_INPUTS];
4298 int i, err, cidx; 4259 int i, j, err, cidx;
4299 int multi_connection; 4260 int multi_connection;
4300 4261
4262 if (!imux->num_items)
4263 return 0;
4264
4301 multi_connection = 0; 4265 multi_connection = 0;
4302 for (i = 0; i < imux->num_items; i++) { 4266 for (i = 0; i < imux->num_items; i++) {
4303 cidx = get_input_connection(codec, spec->imux_info[i].adc, 4267 cidx = get_input_connection(codec, spec->imux_info[i].adc,
4304 spec->imux_info[i].pin); 4268 spec->imux_info[i].pin);
4305 input_conn[i] = (spec->imux_info[i].adc << 8) | cidx; 4269 if (cidx < 0)
4270 continue;
4271 input_conn[i] = spec->imux_info[i].adc;
4272 if (!spec->single_adc_amp)
4273 input_conn[i] |= cidx << 8;
4306 if (i > 0 && input_conn[i] != input_conn[0]) 4274 if (i > 0 && input_conn[i] != input_conn[0])
4307 multi_connection = 1; 4275 multi_connection = 1;
4308 } 4276 }
@@ -4331,6 +4299,15 @@ static int cx_auto_build_input_controls(struct hda_codec *codec)
4331 err = cx_auto_add_capture_volume(codec, nid, 4299 err = cx_auto_add_capture_volume(codec, nid,
4332 "Capture", "", cidx); 4300 "Capture", "", cidx);
4333 } else { 4301 } else {
4302 bool dup_found = false;
4303 for (j = 0; j < i; j++) {
4304 if (input_conn[j] == input_conn[i]) {
4305 dup_found = true;
4306 break;
4307 }
4308 }
4309 if (dup_found)
4310 continue;
4334 err = cx_auto_add_capture_volume(codec, nid, 4311 err = cx_auto_add_capture_volume(codec, nid,
4335 label, " Capture", cidx); 4312 label, " Capture", cidx);
4336 } 4313 }
@@ -4394,6 +4371,53 @@ static const struct hda_codec_ops cx_auto_patch_ops = {
4394 .reboot_notify = snd_hda_shutup_pins, 4371 .reboot_notify = snd_hda_shutup_pins,
4395}; 4372};
4396 4373
4374/*
4375 * pin fix-up
4376 */
4377struct cxt_pincfg {
4378 hda_nid_t nid;
4379 u32 val;
4380};
4381
4382static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg)
4383{
4384 for (; cfg->nid; cfg++)
4385 snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
4386
4387}
4388
4389static void apply_pin_fixup(struct hda_codec *codec,
4390 const struct snd_pci_quirk *quirk,
4391 const struct cxt_pincfg **table)
4392{
4393 quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk);
4394 if (quirk) {
4395 snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n",
4396 quirk->name);
4397 apply_pincfg(codec, table[quirk->value]);
4398 }
4399}
4400
4401enum {
4402 CXT_PINCFG_LENOVO_X200,
4403};
4404
4405static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = {
4406 { 0x16, 0x042140ff }, /* HP (seq# overridden) */
4407 { 0x17, 0x21a11000 }, /* dock-mic */
4408 { 0x19, 0x2121103f }, /* dock-HP */
4409 {}
4410};
4411
4412static const struct cxt_pincfg *cxt_pincfg_tbl[] = {
4413 [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200,
4414};
4415
4416static const struct snd_pci_quirk cxt_fixups[] = {
4417 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
4418 {}
4419};
4420
4397static int patch_conexant_auto(struct hda_codec *codec) 4421static int patch_conexant_auto(struct hda_codec *codec)
4398{ 4422{
4399 struct conexant_spec *spec; 4423 struct conexant_spec *spec;
@@ -4407,6 +4431,15 @@ static int patch_conexant_auto(struct hda_codec *codec)
4407 return -ENOMEM; 4431 return -ENOMEM;
4408 codec->spec = spec; 4432 codec->spec = spec;
4409 codec->pin_amp_workaround = 1; 4433 codec->pin_amp_workaround = 1;
4434
4435 switch (codec->vendor_id) {
4436 case 0x14f15045:
4437 spec->single_adc_amp = 1;
4438 break;
4439 }
4440
4441 apply_pin_fixup(codec, cxt_fixups, cxt_pincfg_tbl);
4442
4410 err = cx_auto_search_adcs(codec); 4443 err = cx_auto_search_adcs(codec);
4411 if (err < 0) 4444 if (err < 0)
4412 return err; 4445 return err;