diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-05-13 10:52:25 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-05-13 10:52:25 -0400 |
commit | 6764bcef4cb964456615565ff974ed917de3c12d (patch) | |
tree | 0fdb4a24b9a3cbb38c69dd4bacc96e5178e1ed50 /sound/pci | |
parent | 0ad1b5b619e4f053dfdcef9dfc68cc5142d86961 (diff) |
ALSA: hda - Add auto-parser support to cxt5051 / CX20561 Hermosa
Extend the existing auto-parser for CX2064x for cxt5051 codec.
Now the auto-parser supports ADC-switching for this codec.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 279 |
1 files changed, 217 insertions, 62 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 19416e305be6..cdb9f499d7f1 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -89,6 +89,8 @@ struct conexant_spec { | |||
89 | unsigned int cur_adc_stream_tag; | 89 | unsigned int cur_adc_stream_tag; |
90 | unsigned int cur_adc_format; | 90 | unsigned int cur_adc_format; |
91 | 91 | ||
92 | const struct hda_pcm_stream *capture_stream; | ||
93 | |||
92 | /* capture source */ | 94 | /* capture source */ |
93 | const struct hda_input_mux *input_mux; | 95 | const struct hda_input_mux *input_mux; |
94 | const hda_nid_t *capsrc_nids; | 96 | const hda_nid_t *capsrc_nids; |
@@ -106,6 +108,7 @@ struct conexant_spec { | |||
106 | /* dynamic controls, init_verbs and input_mux */ | 108 | /* dynamic controls, init_verbs and input_mux */ |
107 | struct auto_pin_cfg autocfg; | 109 | struct auto_pin_cfg autocfg; |
108 | struct hda_input_mux private_imux; | 110 | struct hda_input_mux private_imux; |
111 | hda_nid_t imux_adcs[HDA_MAX_NUM_INPUTS]; | ||
109 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 112 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
110 | struct pin_dac_pair dac_info[8]; | 113 | struct pin_dac_pair dac_info[8]; |
111 | int dac_info_filled; | 114 | int dac_info_filled; |
@@ -119,6 +122,8 @@ struct conexant_spec { | |||
119 | unsigned int hp_laptop:1; | 122 | unsigned int hp_laptop:1; |
120 | unsigned int asus:1; | 123 | unsigned int asus:1; |
121 | 124 | ||
125 | unsigned int adc_switching:1; | ||
126 | |||
122 | unsigned int ext_mic_present; | 127 | unsigned int ext_mic_present; |
123 | unsigned int recording; | 128 | unsigned int recording; |
124 | void (*capture_prepare)(struct hda_codec *codec); | 129 | void (*capture_prepare)(struct hda_codec *codec); |
@@ -319,13 +324,19 @@ static int conexant_build_pcms(struct hda_codec *codec) | |||
319 | spec->multiout.max_channels; | 324 | spec->multiout.max_channels; |
320 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | 325 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
321 | spec->multiout.dac_nids[0]; | 326 | spec->multiout.dac_nids[0]; |
322 | if (codec->vendor_id == 0x14f15051) | 327 | if (spec->capture_stream) |
323 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | 328 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream; |
324 | cx5051_pcm_analog_capture; | 329 | else { |
325 | else | 330 | if (codec->vendor_id == 0x14f15051) |
326 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | 331 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = |
327 | conexant_pcm_analog_capture; | 332 | cx5051_pcm_analog_capture; |
328 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; | 333 | else { |
334 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
335 | conexant_pcm_analog_capture; | ||
336 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = | ||
337 | spec->num_adc_nids; | ||
338 | } | ||
339 | } | ||
329 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | 340 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; |
330 | 341 | ||
331 | if (spec->multiout.dig_out_nid) { | 342 | if (spec->multiout.dig_out_nid) { |
@@ -564,6 +575,7 @@ static const struct hda_codec_ops conexant_patch_ops = { | |||
564 | #define set_beep_amp(spec, nid, idx, dir) /* NOP */ | 575 | #define set_beep_amp(spec, nid, idx, dir) /* NOP */ |
565 | #endif | 576 | #endif |
566 | 577 | ||
578 | static int patch_conexant_auto(struct hda_codec *codec); | ||
567 | /* | 579 | /* |
568 | * EAPD control | 580 | * EAPD control |
569 | * the private value = nid | (invert << 8) | 581 | * the private value = nid | (invert << 8) |
@@ -1906,6 +1918,7 @@ enum { | |||
1906 | CXT5051_F700, /* HP Compaq Presario F700 */ | 1918 | CXT5051_F700, /* HP Compaq Presario F700 */ |
1907 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ | 1919 | CXT5051_TOSHIBA, /* Toshiba M300 & co */ |
1908 | CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ | 1920 | CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ |
1921 | CXT5051_AUTO, /* auto-parser */ | ||
1909 | CXT5051_MODELS | 1922 | CXT5051_MODELS |
1910 | }; | 1923 | }; |
1911 | 1924 | ||
@@ -1917,6 +1930,7 @@ static const char *const cxt5051_models[CXT5051_MODELS] = { | |||
1917 | [CXT5051_F700] = "hp-700", | 1930 | [CXT5051_F700] = "hp-700", |
1918 | [CXT5051_TOSHIBA] = "toshiba", | 1931 | [CXT5051_TOSHIBA] = "toshiba", |
1919 | [CXT5051_IDEAPAD] = "ideapad", | 1932 | [CXT5051_IDEAPAD] = "ideapad", |
1933 | [CXT5051_AUTO] = "auto", | ||
1920 | }; | 1934 | }; |
1921 | 1935 | ||
1922 | static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1936 | static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
@@ -1937,6 +1951,17 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1937 | struct conexant_spec *spec; | 1951 | struct conexant_spec *spec; |
1938 | int board_config; | 1952 | int board_config; |
1939 | 1953 | ||
1954 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | ||
1955 | cxt5051_models, | ||
1956 | cxt5051_cfg_tbl); | ||
1957 | if (board_config < 0) | ||
1958 | board_config = CXT5051_AUTO; | ||
1959 | if (board_config == CXT5051_AUTO) { | ||
1960 | printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", | ||
1961 | codec->chip_name); | ||
1962 | return patch_conexant_auto(codec); | ||
1963 | } | ||
1964 | |||
1940 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 1965 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); |
1941 | if (!spec) | 1966 | if (!spec) |
1942 | return -ENOMEM; | 1967 | return -ENOMEM; |
@@ -1967,9 +1992,6 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1967 | 1992 | ||
1968 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | 1993 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; |
1969 | 1994 | ||
1970 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | ||
1971 | cxt5051_models, | ||
1972 | cxt5051_cfg_tbl); | ||
1973 | spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; | 1995 | spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; |
1974 | switch (board_config) { | 1996 | switch (board_config) { |
1975 | case CXT5051_HP: | 1997 | case CXT5051_HP: |
@@ -3195,6 +3217,44 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
3195 | * Automatic parser for CX20641 & co | 3217 | * Automatic parser for CX20641 & co |
3196 | */ | 3218 | */ |
3197 | 3219 | ||
3220 | static int cx_auto_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
3221 | struct hda_codec *codec, | ||
3222 | unsigned int stream_tag, | ||
3223 | unsigned int format, | ||
3224 | struct snd_pcm_substream *substream) | ||
3225 | { | ||
3226 | struct conexant_spec *spec = codec->spec; | ||
3227 | hda_nid_t adc = spec->imux_adcs[spec->cur_mux[0]]; | ||
3228 | if (spec->adc_switching) { | ||
3229 | spec->cur_adc = adc; | ||
3230 | spec->cur_adc_stream_tag = stream_tag; | ||
3231 | spec->cur_adc_format = format; | ||
3232 | } | ||
3233 | snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format); | ||
3234 | return 0; | ||
3235 | } | ||
3236 | |||
3237 | static int cx_auto_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
3238 | struct hda_codec *codec, | ||
3239 | struct snd_pcm_substream *substream) | ||
3240 | { | ||
3241 | struct conexant_spec *spec = codec->spec; | ||
3242 | snd_hda_codec_cleanup_stream(codec, spec->cur_adc); | ||
3243 | spec->cur_adc = 0; | ||
3244 | return 0; | ||
3245 | } | ||
3246 | |||
3247 | static const struct hda_pcm_stream cx_auto_pcm_analog_capture = { | ||
3248 | .substreams = 1, | ||
3249 | .channels_min = 2, | ||
3250 | .channels_max = 2, | ||
3251 | .nid = 0, /* fill later */ | ||
3252 | .ops = { | ||
3253 | .prepare = cx_auto_capture_pcm_prepare, | ||
3254 | .cleanup = cx_auto_capture_pcm_cleanup | ||
3255 | }, | ||
3256 | }; | ||
3257 | |||
3198 | static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; | 3258 | static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; |
3199 | 3259 | ||
3200 | /* get the connection index of @nid in the widget @mux */ | 3260 | /* get the connection index of @nid in the widget @mux */ |
@@ -3211,6 +3271,15 @@ static int get_connection_index(struct hda_codec *codec, hda_nid_t mux, | |||
3211 | return -1; | 3271 | return -1; |
3212 | } | 3272 | } |
3213 | 3273 | ||
3274 | static int has_multi_connection(struct hda_codec *codec, hda_nid_t mux) | ||
3275 | { | ||
3276 | hda_nid_t conn[HDA_MAX_NUM_INPUTS]; | ||
3277 | int nums; | ||
3278 | |||
3279 | nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); | ||
3280 | return nums > 1; | ||
3281 | } | ||
3282 | |||
3214 | /* get an unassigned DAC from the given list. | 3283 | /* get an unassigned DAC from the given list. |
3215 | * Return the nid if found and reduce the DAC list, or return zero if | 3284 | * Return the nid if found and reduce the DAC list, or return zero if |
3216 | * not found | 3285 | * not found |
@@ -3362,25 +3431,89 @@ static void cx_auto_hp_automute(struct hda_codec *codec) | |||
3362 | cx_auto_turn_eapd(codec, cfg->speaker_outs, cfg->speaker_pins, !present); | 3431 | cx_auto_turn_eapd(codec, cfg->speaker_outs, cfg->speaker_pins, !present); |
3363 | } | 3432 | } |
3364 | 3433 | ||
3434 | static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
3435 | struct snd_ctl_elem_info *uinfo) | ||
3436 | { | ||
3437 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3438 | struct conexant_spec *spec = codec->spec; | ||
3439 | |||
3440 | return snd_hda_input_mux_info(&spec->private_imux, uinfo); | ||
3441 | } | ||
3442 | |||
3443 | static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
3444 | struct snd_ctl_elem_value *ucontrol) | ||
3445 | { | ||
3446 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3447 | struct conexant_spec *spec = codec->spec; | ||
3448 | |||
3449 | ucontrol->value.enumerated.item[0] = spec->cur_mux[0]; | ||
3450 | return 0; | ||
3451 | } | ||
3452 | |||
3453 | static int cx_auto_mux_enum_update(struct hda_codec *codec, | ||
3454 | const struct hda_input_mux *imux, | ||
3455 | unsigned int idx) | ||
3456 | { | ||
3457 | struct conexant_spec *spec = codec->spec; | ||
3458 | hda_nid_t adc; | ||
3459 | |||
3460 | if (!imux->num_items) | ||
3461 | return 0; | ||
3462 | if (idx >= imux->num_items) | ||
3463 | idx = imux->num_items - 1; | ||
3464 | if (spec->cur_mux[0] == idx) | ||
3465 | return 0; | ||
3466 | adc = spec->imux_adcs[idx]; | ||
3467 | if (has_multi_connection(codec, adc)) | ||
3468 | snd_hda_codec_write(codec, adc, 0, | ||
3469 | AC_VERB_SET_CONNECT_SEL, | ||
3470 | imux->items[idx].index); | ||
3471 | if (spec->cur_adc && spec->cur_adc != adc) { | ||
3472 | /* stream is running, let's swap the current ADC */ | ||
3473 | __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); | ||
3474 | spec->cur_adc = adc; | ||
3475 | snd_hda_codec_setup_stream(codec, adc, | ||
3476 | spec->cur_adc_stream_tag, 0, | ||
3477 | spec->cur_adc_format); | ||
3478 | } | ||
3479 | spec->cur_mux[0] = idx; | ||
3480 | return 1; | ||
3481 | } | ||
3482 | |||
3483 | static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
3484 | struct snd_ctl_elem_value *ucontrol) | ||
3485 | { | ||
3486 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
3487 | struct conexant_spec *spec = codec->spec; | ||
3488 | |||
3489 | return cx_auto_mux_enum_update(codec, &spec->private_imux, | ||
3490 | ucontrol->value.enumerated.item[0]); | ||
3491 | } | ||
3492 | |||
3493 | static const struct snd_kcontrol_new cx_auto_capture_mixers[] = { | ||
3494 | { | ||
3495 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
3496 | .name = "Capture Source", | ||
3497 | .info = cx_auto_mux_enum_info, | ||
3498 | .get = cx_auto_mux_enum_get, | ||
3499 | .put = cx_auto_mux_enum_put | ||
3500 | }, | ||
3501 | {} | ||
3502 | }; | ||
3503 | |||
3365 | /* automatic switch internal and external mic */ | 3504 | /* automatic switch internal and external mic */ |
3366 | static void cx_auto_automic(struct hda_codec *codec) | 3505 | static void cx_auto_automic(struct hda_codec *codec) |
3367 | { | 3506 | { |
3368 | struct conexant_spec *spec = codec->spec; | 3507 | struct conexant_spec *spec = codec->spec; |
3369 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3508 | struct auto_pin_cfg *cfg = &spec->autocfg; |
3370 | struct hda_input_mux *imux = &spec->private_imux; | ||
3371 | int ext_idx = spec->auto_mic_ext; | 3509 | int ext_idx = spec->auto_mic_ext; |
3372 | 3510 | ||
3373 | if (!spec->auto_mic) | 3511 | if (!spec->auto_mic) |
3374 | return; | 3512 | return; |
3375 | if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) { | 3513 | if (snd_hda_jack_detect(codec, cfg->inputs[ext_idx].pin)) |
3376 | snd_hda_codec_write(codec, spec->adc_nids[0], 0, | 3514 | cx_auto_mux_enum_update(codec, &spec->private_imux, ext_idx); |
3377 | AC_VERB_SET_CONNECT_SEL, | 3515 | else |
3378 | imux->items[ext_idx].index); | 3516 | cx_auto_mux_enum_update(codec, &spec->private_imux, !ext_idx); |
3379 | } else { | ||
3380 | snd_hda_codec_write(codec, spec->adc_nids[0], 0, | ||
3381 | AC_VERB_SET_CONNECT_SEL, | ||
3382 | imux->items[!ext_idx].index); | ||
3383 | } | ||
3384 | } | 3517 | } |
3385 | 3518 | ||
3386 | static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) | 3519 | static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) |
@@ -3442,22 +3575,33 @@ static void cx_auto_parse_input(struct hda_codec *codec) | |||
3442 | struct conexant_spec *spec = codec->spec; | 3575 | struct conexant_spec *spec = codec->spec; |
3443 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3576 | struct auto_pin_cfg *cfg = &spec->autocfg; |
3444 | struct hda_input_mux *imux; | 3577 | struct hda_input_mux *imux; |
3445 | int i; | 3578 | int i, j; |
3446 | 3579 | ||
3447 | imux = &spec->private_imux; | 3580 | imux = &spec->private_imux; |
3448 | for (i = 0; i < cfg->num_inputs; i++) { | 3581 | for (i = 0; i < cfg->num_inputs; i++) { |
3449 | int idx = get_connection_index(codec, spec->adc_nids[0], | 3582 | for (j = 0; j < spec->num_adc_nids; j++) { |
3583 | hda_nid_t adc = spec->adc_nids[j]; | ||
3584 | int idx = get_connection_index(codec, adc, | ||
3450 | cfg->inputs[i].pin); | 3585 | cfg->inputs[i].pin); |
3451 | if (idx >= 0) { | 3586 | if (idx >= 0) { |
3452 | const char *label; | 3587 | const char *label; |
3453 | label = hda_get_autocfg_input_label(codec, cfg, i); | 3588 | label = hda_get_autocfg_input_label(codec, cfg, i); |
3454 | snd_hda_add_imux_item(imux, label, idx, NULL); | 3589 | snd_hda_add_imux_item(imux, label, idx, NULL); |
3590 | spec->imux_adcs[i] = adc; | ||
3591 | break; | ||
3592 | } | ||
3455 | } | 3593 | } |
3456 | } | 3594 | } |
3457 | if (imux->num_items == 2 && cfg->num_inputs == 2) | 3595 | if (imux->num_items == 2 && cfg->num_inputs == 2) |
3458 | cx_auto_check_auto_mic(codec); | 3596 | cx_auto_check_auto_mic(codec); |
3459 | if (imux->num_items > 1 && !spec->auto_mic) | 3597 | if (imux->num_items > 1 && !spec->auto_mic) { |
3460 | spec->input_mux = imux; | 3598 | for (i = 1; i < imux->num_items; i++) { |
3599 | if (spec->imux_adcs[i] != spec->imux_adcs[0]) { | ||
3600 | spec->adc_switching = 1; | ||
3601 | break; | ||
3602 | } | ||
3603 | } | ||
3604 | } | ||
3461 | } | 3605 | } |
3462 | 3606 | ||
3463 | /* get digital-input audio widget corresponding to the given pin */ | 3607 | /* get digital-input audio widget corresponding to the given pin */ |
@@ -3736,39 +3880,37 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) | |||
3736 | return 0; | 3880 | return 0; |
3737 | } | 3881 | } |
3738 | 3882 | ||
3883 | static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, | ||
3884 | const char *label, const char *pfx, | ||
3885 | int cidx) | ||
3886 | { | ||
3887 | struct conexant_spec *spec = codec->spec; | ||
3888 | int i; | ||
3889 | |||
3890 | for (i = 0; i < spec->num_adc_nids; i++) { | ||
3891 | hda_nid_t adc_nid = spec->adc_nids[i]; | ||
3892 | int idx = get_connection_index(codec, adc_nid, nid); | ||
3893 | if (idx < 0) | ||
3894 | continue; | ||
3895 | return cx_auto_add_volume_idx(codec, label, pfx, | ||
3896 | cidx, adc_nid, HDA_INPUT, idx); | ||
3897 | } | ||
3898 | return 0; | ||
3899 | } | ||
3900 | |||
3739 | static int cx_auto_build_input_controls(struct hda_codec *codec) | 3901 | static int cx_auto_build_input_controls(struct hda_codec *codec) |
3740 | { | 3902 | { |
3741 | struct conexant_spec *spec = codec->spec; | 3903 | struct conexant_spec *spec = codec->spec; |
3742 | struct auto_pin_cfg *cfg = &spec->autocfg; | 3904 | struct auto_pin_cfg *cfg = &spec->autocfg; |
3743 | static const char *prev_label; | 3905 | static const char *prev_label; |
3744 | int i, err, cidx, conn_len; | 3906 | int i, err, cidx; |
3745 | hda_nid_t conn[HDA_MAX_CONNECTIONS]; | ||
3746 | |||
3747 | int multi_adc_volume = 0; /* If the ADC nid has several input volumes */ | ||
3748 | int adc_nid = spec->adc_nids[0]; | ||
3749 | |||
3750 | conn_len = snd_hda_get_connections(codec, adc_nid, conn, | ||
3751 | HDA_MAX_CONNECTIONS); | ||
3752 | if (conn_len < 0) | ||
3753 | return conn_len; | ||
3754 | |||
3755 | multi_adc_volume = cfg->num_inputs > 1 && conn_len > 1; | ||
3756 | if (!multi_adc_volume) { | ||
3757 | err = cx_auto_add_volume(codec, "Capture", "", 0, adc_nid, | ||
3758 | HDA_INPUT); | ||
3759 | if (err < 0) | ||
3760 | return err; | ||
3761 | } | ||
3762 | 3907 | ||
3763 | prev_label = NULL; | 3908 | prev_label = NULL; |
3764 | cidx = 0; | 3909 | cidx = 0; |
3765 | for (i = 0; i < cfg->num_inputs; i++) { | 3910 | for (i = 0; i < cfg->num_inputs; i++) { |
3766 | hda_nid_t nid = cfg->inputs[i].pin; | 3911 | hda_nid_t nid = cfg->inputs[i].pin; |
3767 | const char *label; | 3912 | const char *label; |
3768 | int j; | ||
3769 | int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP; | 3913 | int pin_amp = get_wcaps(codec, nid) & AC_WCAP_IN_AMP; |
3770 | if (!pin_amp && !multi_adc_volume) | ||
3771 | continue; | ||
3772 | 3914 | ||
3773 | label = hda_get_autocfg_input_label(codec, cfg, i); | 3915 | label = hda_get_autocfg_input_label(codec, cfg, i); |
3774 | if (label == prev_label) | 3916 | if (label == prev_label) |
@@ -3784,18 +3926,23 @@ static int cx_auto_build_input_controls(struct hda_codec *codec) | |||
3784 | return err; | 3926 | return err; |
3785 | } | 3927 | } |
3786 | 3928 | ||
3787 | if (!multi_adc_volume) | 3929 | if (cfg->num_inputs == 1) { |
3788 | continue; | 3930 | err = cx_auto_add_capture_volume(codec, nid, |
3789 | for (j = 0; j < conn_len; j++) { | 3931 | "Capture", "", cidx); |
3790 | if (conn[j] == nid) { | 3932 | } else { |
3791 | err = cx_auto_add_volume_idx(codec, label, | 3933 | err = cx_auto_add_capture_volume(codec, nid, |
3792 | " Capture", cidx, adc_nid, HDA_INPUT, j); | 3934 | label, " Capture", cidx); |
3793 | if (err < 0) | ||
3794 | return err; | ||
3795 | break; | ||
3796 | } | ||
3797 | } | 3935 | } |
3936 | if (err < 0) | ||
3937 | return err; | ||
3938 | } | ||
3939 | |||
3940 | if (spec->private_imux.num_items > 1 && !spec->auto_mic) { | ||
3941 | err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers); | ||
3942 | if (err < 0) | ||
3943 | return err; | ||
3798 | } | 3944 | } |
3945 | |||
3799 | return 0; | 3946 | return 0; |
3800 | } | 3947 | } |
3801 | 3948 | ||
@@ -3833,15 +3980,23 @@ static int patch_conexant_auto(struct hda_codec *codec) | |||
3833 | if (!spec) | 3980 | if (!spec) |
3834 | return -ENOMEM; | 3981 | return -ENOMEM; |
3835 | codec->spec = spec; | 3982 | codec->spec = spec; |
3836 | spec->adc_nids = cx_auto_adc_nids; | 3983 | if (codec->vendor_id == 0x14f15051) { |
3837 | spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids); | 3984 | codec->pin_amp_workaround = 1; |
3838 | spec->capsrc_nids = spec->adc_nids; | 3985 | spec->adc_nids = cxt5051_adc_nids; |
3986 | spec->num_adc_nids = ARRAY_SIZE(cxt5051_adc_nids); | ||
3987 | spec->capsrc_nids = spec->adc_nids; | ||
3988 | } else { | ||
3989 | spec->adc_nids = cx_auto_adc_nids; | ||
3990 | spec->num_adc_nids = ARRAY_SIZE(cx_auto_adc_nids); | ||
3991 | spec->capsrc_nids = spec->adc_nids; | ||
3992 | } | ||
3839 | err = cx_auto_parse_auto_config(codec); | 3993 | err = cx_auto_parse_auto_config(codec); |
3840 | if (err < 0) { | 3994 | if (err < 0) { |
3841 | kfree(codec->spec); | 3995 | kfree(codec->spec); |
3842 | codec->spec = NULL; | 3996 | codec->spec = NULL; |
3843 | return err; | 3997 | return err; |
3844 | } | 3998 | } |
3999 | spec->capture_stream = &cx_auto_pcm_analog_capture; | ||
3845 | codec->patch_ops = cx_auto_patch_ops; | 4000 | codec->patch_ops = cx_auto_patch_ops; |
3846 | if (spec->beep_amp) | 4001 | if (spec->beep_amp) |
3847 | snd_hda_attach_beep_device(codec, spec->beep_amp); | 4002 | snd_hda_attach_beep_device(codec, spec->beep_amp); |