aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2011-05-13 10:52:25 -0400
committerTakashi Iwai <tiwai@suse.de>2011-05-13 10:52:25 -0400
commit6764bcef4cb964456615565ff974ed917de3c12d (patch)
tree0fdb4a24b9a3cbb38c69dd4bacc96e5178e1ed50 /sound/pci
parent0ad1b5b619e4f053dfdcef9dfc68cc5142d86961 (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.c279
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
578static 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
1922static const struct snd_pci_quirk cxt5051_cfg_tbl[] = { 1936static 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
3220static 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
3237static 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
3247static 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
3198static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; 3258static 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
3274static 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
3434static 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
3443static 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
3453static 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
3483static 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
3493static 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 */
3366static void cx_auto_automic(struct hda_codec *codec) 3505static 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
3386static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res) 3519static 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
3883static 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
3739static int cx_auto_build_input_controls(struct hda_codec *codec) 3901static 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);