diff options
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
| -rw-r--r-- | sound/pci/hda/patch_conexant.c | 217 |
1 files changed, 139 insertions, 78 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 9bb030a469cd..4d5004e693f0 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
| @@ -85,6 +85,7 @@ struct conexant_spec { | |||
| 85 | unsigned int auto_mic; | 85 | unsigned int auto_mic; |
| 86 | int auto_mic_ext; /* autocfg.inputs[] index for ext mic */ | 86 | int auto_mic_ext; /* autocfg.inputs[] index for ext mic */ |
| 87 | unsigned int need_dac_fix; | 87 | unsigned int need_dac_fix; |
| 88 | hda_nid_t slave_dig_outs[2]; | ||
| 88 | 89 | ||
| 89 | /* capture */ | 90 | /* capture */ |
| 90 | unsigned int num_adc_nids; | 91 | unsigned int num_adc_nids; |
| @@ -127,6 +128,7 @@ struct conexant_spec { | |||
| 127 | unsigned int ideapad:1; | 128 | unsigned int ideapad:1; |
| 128 | unsigned int thinkpad:1; | 129 | unsigned int thinkpad:1; |
| 129 | unsigned int hp_laptop:1; | 130 | unsigned int hp_laptop:1; |
| 131 | unsigned int asus:1; | ||
| 130 | 132 | ||
| 131 | unsigned int ext_mic_present; | 133 | unsigned int ext_mic_present; |
| 132 | unsigned int recording; | 134 | unsigned int recording; |
| @@ -352,6 +354,8 @@ static int conexant_build_pcms(struct hda_codec *codec) | |||
| 352 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = | 354 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = |
| 353 | spec->dig_in_nid; | 355 | spec->dig_in_nid; |
| 354 | } | 356 | } |
| 357 | if (spec->slave_dig_outs[0]) | ||
| 358 | codec->slave_dig_outs = spec->slave_dig_outs; | ||
| 355 | } | 359 | } |
| 356 | 360 | ||
| 357 | return 0; | 361 | return 0; |
| @@ -403,10 +407,16 @@ static int conexant_add_jack(struct hda_codec *codec, | |||
| 403 | struct conexant_spec *spec; | 407 | struct conexant_spec *spec; |
| 404 | struct conexant_jack *jack; | 408 | struct conexant_jack *jack; |
| 405 | const char *name; | 409 | const char *name; |
| 406 | int err; | 410 | int i, err; |
| 407 | 411 | ||
| 408 | spec = codec->spec; | 412 | spec = codec->spec; |
| 409 | snd_array_init(&spec->jacks, sizeof(*jack), 32); | 413 | snd_array_init(&spec->jacks, sizeof(*jack), 32); |
| 414 | |||
| 415 | jack = spec->jacks.list; | ||
| 416 | for (i = 0; i < spec->jacks.used; i++, jack++) | ||
| 417 | if (jack->nid == nid) | ||
| 418 | return 0 ; /* already present */ | ||
| 419 | |||
| 410 | jack = snd_array_new(&spec->jacks); | 420 | jack = snd_array_new(&spec->jacks); |
| 411 | name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; | 421 | name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; |
| 412 | 422 | ||
| @@ -2100,7 +2110,7 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
| 2100 | static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; | 2110 | static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; |
| 2101 | static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; | 2111 | static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; |
| 2102 | static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; | 2112 | static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; |
| 2103 | #define CXT5066_SPDIF_OUT 0x21 | 2113 | static hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; |
| 2104 | 2114 | ||
| 2105 | /* OLPC's microphone port is DC coupled for use with external sensors, | 2115 | /* OLPC's microphone port is DC coupled for use with external sensors, |
| 2106 | * therefore we use a 50% mic bias in order to center the input signal with | 2116 | * therefore we use a 50% mic bias in order to center the input signal with |
| @@ -2312,6 +2322,19 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) | |||
| 2312 | } | 2322 | } |
| 2313 | } | 2323 | } |
| 2314 | 2324 | ||
| 2325 | |||
| 2326 | /* toggle input of built-in digital mic and mic jack appropriately */ | ||
| 2327 | static void cxt5066_asus_automic(struct hda_codec *codec) | ||
| 2328 | { | ||
| 2329 | unsigned int present; | ||
| 2330 | |||
| 2331 | present = snd_hda_jack_detect(codec, 0x1b); | ||
| 2332 | snd_printdd("CXT5066: external microphone present=%d\n", present); | ||
| 2333 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, | ||
| 2334 | present ? 1 : 0); | ||
| 2335 | } | ||
| 2336 | |||
| 2337 | |||
| 2315 | /* toggle input of built-in digital mic and mic jack appropriately */ | 2338 | /* toggle input of built-in digital mic and mic jack appropriately */ |
| 2316 | static void cxt5066_hp_laptop_automic(struct hda_codec *codec) | 2339 | static void cxt5066_hp_laptop_automic(struct hda_codec *codec) |
| 2317 | { | 2340 | { |
| @@ -2387,79 +2410,55 @@ static void cxt5066_hp_automute(struct hda_codec *codec) | |||
| 2387 | cxt5066_update_speaker(codec); | 2410 | cxt5066_update_speaker(codec); |
| 2388 | } | 2411 | } |
| 2389 | 2412 | ||
| 2390 | /* unsolicited event for jack sensing */ | 2413 | /* Dispatch the right mic autoswitch function */ |
| 2391 | static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) | 2414 | static void cxt5066_automic(struct hda_codec *codec) |
| 2392 | { | 2415 | { |
| 2393 | struct conexant_spec *spec = codec->spec; | 2416 | struct conexant_spec *spec = codec->spec; |
| 2394 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); | ||
| 2395 | switch (res >> 26) { | ||
| 2396 | case CONEXANT_HP_EVENT: | ||
| 2397 | cxt5066_hp_automute(codec); | ||
| 2398 | break; | ||
| 2399 | case CONEXANT_MIC_EVENT: | ||
| 2400 | /* ignore mic events in DC mode; we're always using the jack */ | ||
| 2401 | if (!spec->dc_enable) | ||
| 2402 | cxt5066_olpc_automic(codec); | ||
| 2403 | break; | ||
| 2404 | } | ||
| 2405 | } | ||
| 2406 | 2417 | ||
| 2407 | /* unsolicited event for jack sensing */ | 2418 | if (spec->dell_vostro) |
| 2408 | static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res) | ||
| 2409 | { | ||
| 2410 | snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26); | ||
| 2411 | switch (res >> 26) { | ||
| 2412 | case CONEXANT_HP_EVENT: | ||
| 2413 | cxt5066_hp_automute(codec); | ||
| 2414 | break; | ||
| 2415 | case CONEXANT_MIC_EVENT: | ||
| 2416 | cxt5066_vostro_automic(codec); | 2419 | cxt5066_vostro_automic(codec); |
| 2417 | break; | 2420 | else if (spec->ideapad) |
| 2418 | } | ||
| 2419 | } | ||
| 2420 | |||
| 2421 | /* unsolicited event for jack sensing */ | ||
| 2422 | static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) | ||
| 2423 | { | ||
| 2424 | snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26); | ||
| 2425 | switch (res >> 26) { | ||
| 2426 | case CONEXANT_HP_EVENT: | ||
| 2427 | cxt5066_hp_automute(codec); | ||
| 2428 | break; | ||
| 2429 | case CONEXANT_MIC_EVENT: | ||
| 2430 | cxt5066_ideapad_automic(codec); | 2421 | cxt5066_ideapad_automic(codec); |
| 2431 | break; | 2422 | else if (spec->thinkpad) |
| 2432 | } | 2423 | cxt5066_thinkpad_automic(codec); |
| 2424 | else if (spec->hp_laptop) | ||
| 2425 | cxt5066_hp_laptop_automic(codec); | ||
| 2426 | else if (spec->asus) | ||
| 2427 | cxt5066_asus_automic(codec); | ||
| 2433 | } | 2428 | } |
| 2434 | 2429 | ||
| 2435 | /* unsolicited event for jack sensing */ | 2430 | /* unsolicited event for jack sensing */ |
| 2436 | static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res) | 2431 | static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) |
| 2437 | { | 2432 | { |
| 2438 | snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26); | 2433 | struct conexant_spec *spec = codec->spec; |
| 2434 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); | ||
| 2439 | switch (res >> 26) { | 2435 | switch (res >> 26) { |
| 2440 | case CONEXANT_HP_EVENT: | 2436 | case CONEXANT_HP_EVENT: |
| 2441 | cxt5066_hp_automute(codec); | 2437 | cxt5066_hp_automute(codec); |
| 2442 | break; | 2438 | break; |
| 2443 | case CONEXANT_MIC_EVENT: | 2439 | case CONEXANT_MIC_EVENT: |
| 2444 | cxt5066_hp_laptop_automic(codec); | 2440 | /* ignore mic events in DC mode; we're always using the jack */ |
| 2441 | if (!spec->dc_enable) | ||
| 2442 | cxt5066_olpc_automic(codec); | ||
| 2445 | break; | 2443 | break; |
| 2446 | } | 2444 | } |
| 2447 | } | 2445 | } |
| 2448 | 2446 | ||
| 2449 | /* unsolicited event for jack sensing */ | 2447 | /* unsolicited event for jack sensing */ |
| 2450 | static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) | 2448 | static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) |
| 2451 | { | 2449 | { |
| 2452 | snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26); | 2450 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); |
| 2453 | switch (res >> 26) { | 2451 | switch (res >> 26) { |
| 2454 | case CONEXANT_HP_EVENT: | 2452 | case CONEXANT_HP_EVENT: |
| 2455 | cxt5066_hp_automute(codec); | 2453 | cxt5066_hp_automute(codec); |
| 2456 | break; | 2454 | break; |
| 2457 | case CONEXANT_MIC_EVENT: | 2455 | case CONEXANT_MIC_EVENT: |
| 2458 | cxt5066_thinkpad_automic(codec); | 2456 | cxt5066_automic(codec); |
| 2459 | break; | 2457 | break; |
| 2460 | } | 2458 | } |
| 2461 | } | 2459 | } |
| 2462 | 2460 | ||
| 2461 | |||
| 2463 | static const struct hda_input_mux cxt5066_analog_mic_boost = { | 2462 | static const struct hda_input_mux cxt5066_analog_mic_boost = { |
| 2464 | .num_items = 5, | 2463 | .num_items = 5, |
| 2465 | .items = { | 2464 | .items = { |
| @@ -2633,6 +2632,27 @@ static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) | |||
| 2633 | spec->recording = 0; | 2632 | spec->recording = 0; |
| 2634 | } | 2633 | } |
| 2635 | 2634 | ||
| 2635 | static void conexant_check_dig_outs(struct hda_codec *codec, | ||
| 2636 | hda_nid_t *dig_pins, | ||
| 2637 | int num_pins) | ||
| 2638 | { | ||
| 2639 | struct conexant_spec *spec = codec->spec; | ||
| 2640 | hda_nid_t *nid_loc = &spec->multiout.dig_out_nid; | ||
| 2641 | int i; | ||
| 2642 | |||
| 2643 | for (i = 0; i < num_pins; i++, dig_pins++) { | ||
| 2644 | unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins); | ||
| 2645 | if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE) | ||
| 2646 | continue; | ||
| 2647 | if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1) | ||
| 2648 | continue; | ||
| 2649 | if (spec->slave_dig_outs[0]) | ||
| 2650 | nid_loc++; | ||
| 2651 | else | ||
| 2652 | nid_loc = spec->slave_dig_outs; | ||
| 2653 | } | ||
| 2654 | } | ||
| 2655 | |||
| 2636 | static struct hda_input_mux cxt5066_capture_source = { | 2656 | static struct hda_input_mux cxt5066_capture_source = { |
| 2637 | .num_items = 4, | 2657 | .num_items = 4, |
| 2638 | .items = { | 2658 | .items = { |
| @@ -3039,20 +3059,11 @@ static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { | |||
| 3039 | /* initialize jack-sensing, too */ | 3059 | /* initialize jack-sensing, too */ |
| 3040 | static int cxt5066_init(struct hda_codec *codec) | 3060 | static int cxt5066_init(struct hda_codec *codec) |
| 3041 | { | 3061 | { |
| 3042 | struct conexant_spec *spec = codec->spec; | ||
| 3043 | |||
| 3044 | snd_printdd("CXT5066: init\n"); | 3062 | snd_printdd("CXT5066: init\n"); |
| 3045 | conexant_init(codec); | 3063 | conexant_init(codec); |
| 3046 | if (codec->patch_ops.unsol_event) { | 3064 | if (codec->patch_ops.unsol_event) { |
| 3047 | cxt5066_hp_automute(codec); | 3065 | cxt5066_hp_automute(codec); |
| 3048 | if (spec->dell_vostro) | 3066 | cxt5066_automic(codec); |
| 3049 | cxt5066_vostro_automic(codec); | ||
| 3050 | else if (spec->ideapad) | ||
| 3051 | cxt5066_ideapad_automic(codec); | ||
| 3052 | else if (spec->thinkpad) | ||
| 3053 | cxt5066_thinkpad_automic(codec); | ||
| 3054 | else if (spec->hp_laptop) | ||
| 3055 | cxt5066_hp_laptop_automic(codec); | ||
| 3056 | } | 3067 | } |
| 3057 | cxt5066_set_mic_boost(codec); | 3068 | cxt5066_set_mic_boost(codec); |
| 3058 | return 0; | 3069 | return 0; |
| @@ -3080,6 +3091,7 @@ enum { | |||
| 3080 | CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ | 3091 | CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ |
| 3081 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ | 3092 | CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ |
| 3082 | CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ | 3093 | CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ |
| 3094 | CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */ | ||
| 3083 | CXT5066_HP_LAPTOP, /* HP Laptop */ | 3095 | CXT5066_HP_LAPTOP, /* HP Laptop */ |
| 3084 | CXT5066_MODELS | 3096 | CXT5066_MODELS |
| 3085 | }; | 3097 | }; |
| @@ -3091,6 +3103,7 @@ static const char * const cxt5066_models[CXT5066_MODELS] = { | |||
| 3091 | [CXT5066_DELL_VOSTRO] = "dell-vostro", | 3103 | [CXT5066_DELL_VOSTRO] = "dell-vostro", |
| 3092 | [CXT5066_IDEAPAD] = "ideapad", | 3104 | [CXT5066_IDEAPAD] = "ideapad", |
| 3093 | [CXT5066_THINKPAD] = "thinkpad", | 3105 | [CXT5066_THINKPAD] = "thinkpad", |
| 3106 | [CXT5066_ASUS] = "asus", | ||
| 3094 | [CXT5066_HP_LAPTOP] = "hp-laptop", | 3107 | [CXT5066_HP_LAPTOP] = "hp-laptop", |
| 3095 | }; | 3108 | }; |
| 3096 | 3109 | ||
| @@ -3101,8 +3114,12 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | |||
| 3101 | SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), | 3114 | SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), |
| 3102 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), | 3115 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO), |
| 3103 | SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), | 3116 | SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), |
| 3117 | SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), | ||
| 3118 | SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD), | ||
| 3104 | SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), | 3119 | SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), |
| 3105 | SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP), | 3120 | SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS), |
| 3121 | SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS), | ||
| 3122 | SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), | ||
| 3106 | SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), | 3123 | SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), |
| 3107 | SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), | 3124 | SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), |
| 3108 | SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), | 3125 | SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), |
| @@ -3111,7 +3128,9 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | |||
| 3111 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), | 3128 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), |
| 3112 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), | 3129 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), |
| 3113 | SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), | 3130 | SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), |
| 3131 | SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), | ||
| 3114 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), | 3132 | SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), |
| 3133 | SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), | ||
| 3115 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */ | 3134 | SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */ |
| 3116 | {} | 3135 | {} |
| 3117 | }; | 3136 | }; |
| @@ -3133,7 +3152,8 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
| 3133 | spec->multiout.max_channels = 2; | 3152 | spec->multiout.max_channels = 2; |
| 3134 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); | 3153 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); |
| 3135 | spec->multiout.dac_nids = cxt5066_dac_nids; | 3154 | spec->multiout.dac_nids = cxt5066_dac_nids; |
| 3136 | spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT; | 3155 | conexant_check_dig_outs(codec, cxt5066_digout_pin_nids, |
| 3156 | ARRAY_SIZE(cxt5066_digout_pin_nids)); | ||
| 3137 | spec->num_adc_nids = 1; | 3157 | spec->num_adc_nids = 1; |
| 3138 | spec->adc_nids = cxt5066_adc_nids; | 3158 | spec->adc_nids = cxt5066_adc_nids; |
| 3139 | spec->capsrc_nids = cxt5066_capsrc_nids; | 3159 | spec->capsrc_nids = cxt5066_capsrc_nids; |
| @@ -3167,17 +3187,20 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
| 3167 | spec->num_init_verbs++; | 3187 | spec->num_init_verbs++; |
| 3168 | spec->dell_automute = 1; | 3188 | spec->dell_automute = 1; |
| 3169 | break; | 3189 | break; |
| 3190 | case CXT5066_ASUS: | ||
| 3170 | case CXT5066_HP_LAPTOP: | 3191 | case CXT5066_HP_LAPTOP: |
| 3171 | codec->patch_ops.init = cxt5066_init; | 3192 | codec->patch_ops.init = cxt5066_init; |
| 3172 | codec->patch_ops.unsol_event = cxt5066_hp_laptop_event; | 3193 | codec->patch_ops.unsol_event = cxt5066_unsol_event; |
| 3173 | spec->init_verbs[spec->num_init_verbs] = | 3194 | spec->init_verbs[spec->num_init_verbs] = |
| 3174 | cxt5066_init_verbs_hp_laptop; | 3195 | cxt5066_init_verbs_hp_laptop; |
| 3175 | spec->num_init_verbs++; | 3196 | spec->num_init_verbs++; |
| 3176 | spec->hp_laptop = 1; | 3197 | spec->hp_laptop = board_config == CXT5066_HP_LAPTOP; |
| 3198 | spec->asus = board_config == CXT5066_ASUS; | ||
| 3177 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | 3199 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; |
| 3178 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 3200 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
| 3179 | /* no S/PDIF out */ | 3201 | /* no S/PDIF out */ |
| 3180 | spec->multiout.dig_out_nid = 0; | 3202 | if (board_config == CXT5066_HP_LAPTOP) |
| 3203 | spec->multiout.dig_out_nid = 0; | ||
| 3181 | /* input source automatically selected */ | 3204 | /* input source automatically selected */ |
| 3182 | spec->input_mux = NULL; | 3205 | spec->input_mux = NULL; |
| 3183 | spec->port_d_mode = 0; | 3206 | spec->port_d_mode = 0; |
| @@ -3207,7 +3230,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
| 3207 | break; | 3230 | break; |
| 3208 | case CXT5066_DELL_VOSTRO: | 3231 | case CXT5066_DELL_VOSTRO: |
| 3209 | codec->patch_ops.init = cxt5066_init; | 3232 | codec->patch_ops.init = cxt5066_init; |
| 3210 | codec->patch_ops.unsol_event = cxt5066_vostro_event; | 3233 | codec->patch_ops.unsol_event = cxt5066_unsol_event; |
| 3211 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; | 3234 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; |
| 3212 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 3235 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
| 3213 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 3236 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
| @@ -3224,7 +3247,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
| 3224 | break; | 3247 | break; |
| 3225 | case CXT5066_IDEAPAD: | 3248 | case CXT5066_IDEAPAD: |
| 3226 | codec->patch_ops.init = cxt5066_init; | 3249 | codec->patch_ops.init = cxt5066_init; |
| 3227 | codec->patch_ops.unsol_event = cxt5066_ideapad_event; | 3250 | codec->patch_ops.unsol_event = cxt5066_unsol_event; |
| 3228 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | 3251 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; |
| 3229 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 3252 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
| 3230 | spec->init_verbs[0] = cxt5066_init_verbs_ideapad; | 3253 | spec->init_verbs[0] = cxt5066_init_verbs_ideapad; |
| @@ -3240,7 +3263,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
| 3240 | break; | 3263 | break; |
| 3241 | case CXT5066_THINKPAD: | 3264 | case CXT5066_THINKPAD: |
| 3242 | codec->patch_ops.init = cxt5066_init; | 3265 | codec->patch_ops.init = cxt5066_init; |
| 3243 | codec->patch_ops.unsol_event = cxt5066_thinkpad_event; | 3266 | codec->patch_ops.unsol_event = cxt5066_unsol_event; |
| 3244 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | 3267 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; |
| 3245 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 3268 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
| 3246 | spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; | 3269 | spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; |
| @@ -3389,7 +3412,7 @@ static void cx_auto_parse_output(struct hda_codec *codec) | |||
| 3389 | } | 3412 | } |
| 3390 | } | 3413 | } |
| 3391 | spec->multiout.dac_nids = spec->private_dac_nids; | 3414 | spec->multiout.dac_nids = spec->private_dac_nids; |
| 3392 | spec->multiout.max_channels = nums * 2; | 3415 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
| 3393 | 3416 | ||
| 3394 | if (cfg->hp_outs > 0) | 3417 | if (cfg->hp_outs > 0) |
| 3395 | spec->auto_mute = 1; | 3418 | spec->auto_mute = 1; |
| @@ -3708,9 +3731,9 @@ static int cx_auto_init(struct hda_codec *codec) | |||
| 3708 | return 0; | 3731 | return 0; |
| 3709 | } | 3732 | } |
| 3710 | 3733 | ||
| 3711 | static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, | 3734 | static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, |
| 3712 | const char *dir, int cidx, | 3735 | const char *dir, int cidx, |
| 3713 | hda_nid_t nid, int hda_dir) | 3736 | hda_nid_t nid, int hda_dir, int amp_idx) |
| 3714 | { | 3737 | { |
| 3715 | static char name[32]; | 3738 | static char name[32]; |
| 3716 | static struct snd_kcontrol_new knew[] = { | 3739 | static struct snd_kcontrol_new knew[] = { |
| @@ -3722,7 +3745,8 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, | |||
| 3722 | 3745 | ||
| 3723 | for (i = 0; i < 2; i++) { | 3746 | for (i = 0; i < 2; i++) { |
| 3724 | struct snd_kcontrol *kctl; | 3747 | struct snd_kcontrol *kctl; |
| 3725 | knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, hda_dir); | 3748 | knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx, |
| 3749 | hda_dir); | ||
| 3726 | knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; | 3750 | knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; |
| 3727 | knew[i].index = cidx; | 3751 | knew[i].index = cidx; |
| 3728 | snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]); | 3752 | snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]); |
| @@ -3738,6 +3762,9 @@ static int cx_auto_add_volume(struct hda_codec *codec, const char *basename, | |||
| 3738 | return 0; | 3762 | return 0; |
| 3739 | } | 3763 | } |
| 3740 | 3764 | ||
| 3765 | #define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \ | ||
| 3766 | cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0) | ||
| 3767 | |||
| 3741 | #define cx_auto_add_pb_volume(codec, nid, str, idx) \ | 3768 | #define cx_auto_add_pb_volume(codec, nid, str, idx) \ |
| 3742 | cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) | 3769 | cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) |
| 3743 | 3770 | ||
| @@ -3787,29 +3814,60 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) | |||
| 3787 | struct conexant_spec *spec = codec->spec; | 3814 | struct conexant_spec *spec = codec->spec; |
| 3788 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3815 | struct auto_pin_cfg *cfg = &spec->autocfg; |
| 3789 | static const char *prev_label; | 3816 | static const char *prev_label; |
| 3790 | int i, err, cidx; | 3817 | int i, err, cidx, conn_len; |
| 3818 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | ||
| 3819 | |||
| 3820 | int multi_adc_volume = 0; /* If the ADC nid has several input volumes */ | ||
| 3821 | int adc_nid = spec->adc_nids[0]; | ||
| 3822 | |||
| 3823 | conn_len = snd_hda_get_connections(codec, adc_nid, conn, | ||
| 3824 | HDA_MAX_CONNECTIONS); | ||
| 3825 | if (conn_len < 0) | ||
| 3826 | return conn_len; | ||
| 3827 | |||
| 3828 | multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1; | ||
| 3829 | if (!multi_adc_volume) { | ||
| 3830 | err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid, | ||
| 3831 | HDA_INPUT); | ||
| 3832 | if (err < 0) | ||
| 3833 | return err; | ||
| 3834 | } | ||
| 3791 | 3835 | ||
| 3792 | err = cx_auto_add_volume(codec, "Capture", "", 0, spec->adc_nids[0], | ||
| 3793 | HDA_INPUT); | ||
| 3794 | if (err < 0) | ||
| 3795 | return err; | ||
| 3796 | prev_label = NULL; | 3836 | prev_label = NULL; |
| 3797 | cidx = 0; | 3837 | cidx = 0; |
| 3798 | for (i = 0; i < cfg->num_inputs; i++) { | 3838 | for (i = 0; i < cfg->num_inputs; i++) { |
| 3799 | hda_nid_t nid = cfg->inputs[i].pin; | 3839 | hda_nid_t nid = cfg->inputs[i].pin; |
| 3800 | const char *label; | 3840 | const char *label; |
| 3801 | if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) | 3841 | int j; |
| 3842 | int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP; | ||
| 3843 | if (!pin_amp && !multi_adc_volume) | ||
| 3802 | continue; | 3844 | continue; |
| 3845 | |||
| 3803 | label = hda_get_autocfg_input_label(codec, cfg, i); | 3846 | label = hda_get_autocfg_input_label(codec, cfg, i); |
| 3804 | if (label == prev_label) | 3847 | if (label == prev_label) |
| 3805 | cidx++; | 3848 | cidx++; |
| 3806 | else | 3849 | else |
| 3807 | cidx = 0; | 3850 | cidx = 0; |
| 3808 | prev_label = label; | 3851 | prev_label = label; |
| 3809 | err = cx_auto_add_volume(codec, label, " Capture", cidx, | 3852 | |
| 3810 | nid, HDA_INPUT); | 3853 | if (pin_amp) { |
| 3811 | if (err < 0) | 3854 | err = cx_auto_add_volume(codec, label, " Boost", cidx, |
| 3812 | return err; | 3855 | nid, HDA_INPUT); |
| 3856 | if (err < 0) | ||
| 3857 | return err; | ||
| 3858 | } | ||
| 3859 | |||
| 3860 | if (!multi_adc_volume) | ||
| 3861 | continue; | ||
| 3862 | for (j = 0; j < conn_len; j++) { | ||
| 3863 | if (conn[j] == nid) { | ||
| 3864 | err = cx_auto_add_volume_idx(codec, label, | ||
| 3865 | " Capture", cidx, adc_nid, HDA_INPUT, j); | ||
| 3866 | if (err < 0) | ||
| 3867 | return err; | ||
| 3868 | break; | ||
| 3869 | } | ||
| 3870 | } | ||
| 3813 | } | 3871 | } |
| 3814 | return 0; | 3872 | return 0; |
| 3815 | } | 3873 | } |
| @@ -3881,6 +3939,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { | |||
| 3881 | .patch = patch_cxt5066 }, | 3939 | .patch = patch_cxt5066 }, |
| 3882 | { .id = 0x14f15069, .name = "CX20585", | 3940 | { .id = 0x14f15069, .name = "CX20585", |
| 3883 | .patch = patch_cxt5066 }, | 3941 | .patch = patch_cxt5066 }, |
| 3942 | { .id = 0x14f1506e, .name = "CX20590", | ||
| 3943 | .patch = patch_cxt5066 }, | ||
| 3884 | { .id = 0x14f15097, .name = "CX20631", | 3944 | { .id = 0x14f15097, .name = "CX20631", |
| 3885 | .patch = patch_conexant_auto }, | 3945 | .patch = patch_conexant_auto }, |
| 3886 | { .id = 0x14f15098, .name = "CX20632", | 3946 | { .id = 0x14f15098, .name = "CX20632", |
| @@ -3907,6 +3967,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15066"); | |||
| 3907 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); | 3967 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); |
| 3908 | MODULE_ALIAS("snd-hda-codec-id:14f15068"); | 3968 | MODULE_ALIAS("snd-hda-codec-id:14f15068"); |
| 3909 | MODULE_ALIAS("snd-hda-codec-id:14f15069"); | 3969 | MODULE_ALIAS("snd-hda-codec-id:14f15069"); |
| 3970 | MODULE_ALIAS("snd-hda-codec-id:14f1506e"); | ||
| 3910 | MODULE_ALIAS("snd-hda-codec-id:14f15097"); | 3971 | MODULE_ALIAS("snd-hda-codec-id:14f15097"); |
| 3911 | MODULE_ALIAS("snd-hda-codec-id:14f15098"); | 3972 | MODULE_ALIAS("snd-hda-codec-id:14f15098"); |
| 3912 | MODULE_ALIAS("snd-hda-codec-id:14f150a1"); | 3973 | MODULE_ALIAS("snd-hda-codec-id:14f150a1"); |
