diff options
Diffstat (limited to 'sound/pci/hda/patch_cirrus.c')
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 94 |
1 files changed, 70 insertions, 24 deletions
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 488fd9ade1ba..460fb2ef7e39 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -65,6 +65,7 @@ struct cs_spec { | |||
65 | 65 | ||
66 | /* available models */ | 66 | /* available models */ |
67 | enum { | 67 | enum { |
68 | CS420X_MBP53, | ||
68 | CS420X_MBP55, | 69 | CS420X_MBP55, |
69 | CS420X_IMAC27, | 70 | CS420X_IMAC27, |
70 | CS420X_AUTO, | 71 | CS420X_AUTO, |
@@ -329,12 +330,12 @@ static int is_ext_mic(struct hda_codec *codec, unsigned int idx) | |||
329 | { | 330 | { |
330 | struct cs_spec *spec = codec->spec; | 331 | struct cs_spec *spec = codec->spec; |
331 | struct auto_pin_cfg *cfg = &spec->autocfg; | 332 | struct auto_pin_cfg *cfg = &spec->autocfg; |
332 | hda_nid_t pin = cfg->input_pins[idx]; | 333 | hda_nid_t pin = cfg->inputs[idx].pin; |
333 | unsigned int val = snd_hda_query_pin_caps(codec, pin); | 334 | unsigned int val = snd_hda_query_pin_caps(codec, pin); |
334 | if (!(val & AC_PINCAP_PRES_DETECT)) | 335 | if (!(val & AC_PINCAP_PRES_DETECT)) |
335 | return 0; | 336 | return 0; |
336 | val = snd_hda_codec_get_pincfg(codec, pin); | 337 | val = snd_hda_codec_get_pincfg(codec, pin); |
337 | return (get_defcfg_connect(val) == AC_JACK_PORT_COMPLEX); | 338 | return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT); |
338 | } | 339 | } |
339 | 340 | ||
340 | static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, | 341 | static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, |
@@ -424,10 +425,8 @@ static int parse_input(struct hda_codec *codec) | |||
424 | struct auto_pin_cfg *cfg = &spec->autocfg; | 425 | struct auto_pin_cfg *cfg = &spec->autocfg; |
425 | int i; | 426 | int i; |
426 | 427 | ||
427 | for (i = 0; i < AUTO_PIN_LAST; i++) { | 428 | for (i = 0; i < cfg->num_inputs; i++) { |
428 | hda_nid_t pin = cfg->input_pins[i]; | 429 | hda_nid_t pin = cfg->inputs[i].pin; |
429 | if (!pin) | ||
430 | continue; | ||
431 | spec->input_idx[spec->num_inputs] = i; | 430 | spec->input_idx[spec->num_inputs] = i; |
432 | spec->capsrc_idx[i] = spec->num_inputs++; | 431 | spec->capsrc_idx[i] = spec->num_inputs++; |
433 | spec->cur_input = i; | 432 | spec->cur_input = i; |
@@ -438,16 +437,17 @@ static int parse_input(struct hda_codec *codec) | |||
438 | 437 | ||
439 | /* check whether the automatic mic switch is available */ | 438 | /* check whether the automatic mic switch is available */ |
440 | if (spec->num_inputs == 2 && | 439 | if (spec->num_inputs == 2 && |
441 | spec->adc_nid[AUTO_PIN_MIC] && spec->adc_nid[AUTO_PIN_FRONT_MIC]) { | 440 | cfg->inputs[0].type == AUTO_PIN_MIC && |
442 | if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_FRONT_MIC])) { | 441 | cfg->inputs[1].type == AUTO_PIN_MIC) { |
443 | if (!is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { | 442 | if (is_ext_mic(codec, cfg->inputs[0].pin)) { |
443 | if (!is_ext_mic(codec, cfg->inputs[1].pin)) { | ||
444 | spec->mic_detect = 1; | 444 | spec->mic_detect = 1; |
445 | spec->automic_idx = AUTO_PIN_FRONT_MIC; | 445 | spec->automic_idx = 0; |
446 | } | 446 | } |
447 | } else { | 447 | } else { |
448 | if (is_ext_mic(codec, cfg->input_pins[AUTO_PIN_MIC])) { | 448 | if (is_ext_mic(codec, cfg->inputs[1].pin)) { |
449 | spec->mic_detect = 1; | 449 | spec->mic_detect = 1; |
450 | spec->automic_idx = AUTO_PIN_MIC; | 450 | spec->automic_idx = 1; |
451 | } | 451 | } |
452 | } | 452 | } |
453 | } | 453 | } |
@@ -674,6 +674,7 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol, | |||
674 | { | 674 | { |
675 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 675 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
676 | struct cs_spec *spec = codec->spec; | 676 | struct cs_spec *spec = codec->spec; |
677 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
677 | unsigned int idx; | 678 | unsigned int idx; |
678 | 679 | ||
679 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 680 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
@@ -682,7 +683,8 @@ static int cs_capture_source_info(struct snd_kcontrol *kcontrol, | |||
682 | if (uinfo->value.enumerated.item >= spec->num_inputs) | 683 | if (uinfo->value.enumerated.item >= spec->num_inputs) |
683 | uinfo->value.enumerated.item = spec->num_inputs - 1; | 684 | uinfo->value.enumerated.item = spec->num_inputs - 1; |
684 | idx = spec->input_idx[uinfo->value.enumerated.item]; | 685 | idx = spec->input_idx[uinfo->value.enumerated.item]; |
685 | strcpy(uinfo->value.enumerated.name, auto_pin_cfg_labels[idx]); | 686 | strcpy(uinfo->value.enumerated.name, |
687 | hda_get_input_pin_label(codec, cfg->inputs[idx].pin, 1)); | ||
686 | return 0; | 688 | return 0; |
687 | } | 689 | } |
688 | 690 | ||
@@ -740,6 +742,27 @@ static struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, | |||
740 | return bind; | 742 | return bind; |
741 | } | 743 | } |
742 | 744 | ||
745 | /* add a (input-boost) volume control to the given input pin */ | ||
746 | static int add_input_volume_control(struct hda_codec *codec, | ||
747 | struct auto_pin_cfg *cfg, | ||
748 | int item) | ||
749 | { | ||
750 | hda_nid_t pin = cfg->inputs[item].pin; | ||
751 | u32 caps; | ||
752 | const char *label; | ||
753 | struct snd_kcontrol *kctl; | ||
754 | |||
755 | if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP)) | ||
756 | return 0; | ||
757 | caps = query_amp_caps(codec, pin, HDA_INPUT); | ||
758 | caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | ||
759 | if (caps <= 1) | ||
760 | return 0; | ||
761 | label = hda_get_autocfg_input_label(codec, cfg, item); | ||
762 | return add_volume(codec, label, 0, | ||
763 | HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl); | ||
764 | } | ||
765 | |||
743 | static int build_input(struct hda_codec *codec) | 766 | static int build_input(struct hda_codec *codec) |
744 | { | 767 | { |
745 | struct cs_spec *spec = codec->spec; | 768 | struct cs_spec *spec = codec->spec; |
@@ -779,6 +802,12 @@ static int build_input(struct hda_codec *codec) | |||
779 | return err; | 802 | return err; |
780 | } | 803 | } |
781 | 804 | ||
805 | for (i = 0; i < spec->num_inputs; i++) { | ||
806 | err = add_input_volume_control(codec, &spec->autocfg, i); | ||
807 | if (err < 0) | ||
808 | return err; | ||
809 | } | ||
810 | |||
782 | return 0; | 811 | return 0; |
783 | } | 812 | } |
784 | 813 | ||
@@ -838,7 +867,8 @@ static void cs_automute(struct hda_codec *codec) | |||
838 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 867 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
839 | hp_present ? 0 : PIN_OUT); | 868 | hp_present ? 0 : PIN_OUT); |
840 | } | 869 | } |
841 | if (spec->board_config == CS420X_MBP55 || | 870 | if (spec->board_config == CS420X_MBP53 || |
871 | spec->board_config == CS420X_MBP55 || | ||
842 | spec->board_config == CS420X_IMAC27) { | 872 | spec->board_config == CS420X_IMAC27) { |
843 | unsigned int gpio = hp_present ? 0x02 : 0x08; | 873 | unsigned int gpio = hp_present ? 0x02 : 0x08; |
844 | snd_hda_codec_write(codec, 0x01, 0, | 874 | snd_hda_codec_write(codec, 0x01, 0, |
@@ -853,15 +883,12 @@ static void cs_automic(struct hda_codec *codec) | |||
853 | hda_nid_t nid; | 883 | hda_nid_t nid; |
854 | unsigned int present; | 884 | unsigned int present; |
855 | 885 | ||
856 | nid = cfg->input_pins[spec->automic_idx]; | 886 | nid = cfg->inputs[spec->automic_idx].pin; |
857 | present = snd_hda_jack_detect(codec, nid); | 887 | present = snd_hda_jack_detect(codec, nid); |
858 | if (present) | 888 | if (present) |
859 | change_cur_input(codec, spec->automic_idx, 0); | 889 | change_cur_input(codec, spec->automic_idx, 0); |
860 | else { | 890 | else |
861 | unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ? | 891 | change_cur_input(codec, !spec->automic_idx, 0); |
862 | AUTO_PIN_FRONT_MIC : AUTO_PIN_MIC; | ||
863 | change_cur_input(codec, imic, 0); | ||
864 | } | ||
865 | } | 892 | } |
866 | 893 | ||
867 | /* | 894 | /* |
@@ -918,14 +945,14 @@ static void init_input(struct hda_codec *codec) | |||
918 | unsigned int coef; | 945 | unsigned int coef; |
919 | int i; | 946 | int i; |
920 | 947 | ||
921 | for (i = 0; i < AUTO_PIN_LAST; i++) { | 948 | for (i = 0; i < cfg->num_inputs; i++) { |
922 | unsigned int ctl; | 949 | unsigned int ctl; |
923 | hda_nid_t pin = cfg->input_pins[i]; | 950 | hda_nid_t pin = cfg->inputs[i].pin; |
924 | if (!pin || !spec->adc_nid[i]) | 951 | if (!spec->adc_nid[i]) |
925 | continue; | 952 | continue; |
926 | /* set appropriate pin control and mute first */ | 953 | /* set appropriate pin control and mute first */ |
927 | ctl = PIN_IN; | 954 | ctl = PIN_IN; |
928 | if (i <= AUTO_PIN_FRONT_MIC) { | 955 | if (cfg->inputs[i].type == AUTO_PIN_MIC) { |
929 | unsigned int caps = snd_hda_query_pin_caps(codec, pin); | 956 | unsigned int caps = snd_hda_query_pin_caps(codec, pin); |
930 | caps >>= AC_PINCAP_VREF_SHIFT; | 957 | caps >>= AC_PINCAP_VREF_SHIFT; |
931 | if (caps & AC_PINCAP_VREF_80) | 958 | if (caps & AC_PINCAP_VREF_80) |
@@ -1130,6 +1157,7 @@ static int cs_parse_auto_config(struct hda_codec *codec) | |||
1130 | } | 1157 | } |
1131 | 1158 | ||
1132 | static const char *cs420x_models[CS420X_MODELS] = { | 1159 | static const char *cs420x_models[CS420X_MODELS] = { |
1160 | [CS420X_MBP53] = "mbp53", | ||
1133 | [CS420X_MBP55] = "mbp55", | 1161 | [CS420X_MBP55] = "mbp55", |
1134 | [CS420X_IMAC27] = "imac27", | 1162 | [CS420X_IMAC27] = "imac27", |
1135 | [CS420X_AUTO] = "auto", | 1163 | [CS420X_AUTO] = "auto", |
@@ -1137,7 +1165,9 @@ static const char *cs420x_models[CS420X_MODELS] = { | |||
1137 | 1165 | ||
1138 | 1166 | ||
1139 | static struct snd_pci_quirk cs420x_cfg_tbl[] = { | 1167 | static struct snd_pci_quirk cs420x_cfg_tbl[] = { |
1168 | SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53), | ||
1140 | SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), | 1169 | SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), |
1170 | SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55), | ||
1141 | SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27), | 1171 | SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27), |
1142 | {} /* terminator */ | 1172 | {} /* terminator */ |
1143 | }; | 1173 | }; |
@@ -1147,6 +1177,20 @@ struct cs_pincfg { | |||
1147 | u32 val; | 1177 | u32 val; |
1148 | }; | 1178 | }; |
1149 | 1179 | ||
1180 | static struct cs_pincfg mbp53_pincfgs[] = { | ||
1181 | { 0x09, 0x012b4050 }, | ||
1182 | { 0x0a, 0x90100141 }, | ||
1183 | { 0x0b, 0x90100140 }, | ||
1184 | { 0x0c, 0x018b3020 }, | ||
1185 | { 0x0d, 0x90a00110 }, | ||
1186 | { 0x0e, 0x400000f0 }, | ||
1187 | { 0x0f, 0x01cbe030 }, | ||
1188 | { 0x10, 0x014be060 }, | ||
1189 | { 0x12, 0x400000f0 }, | ||
1190 | { 0x15, 0x400000f0 }, | ||
1191 | {} /* terminator */ | ||
1192 | }; | ||
1193 | |||
1150 | static struct cs_pincfg mbp55_pincfgs[] = { | 1194 | static struct cs_pincfg mbp55_pincfgs[] = { |
1151 | { 0x09, 0x012b4030 }, | 1195 | { 0x09, 0x012b4030 }, |
1152 | { 0x0a, 0x90100121 }, | 1196 | { 0x0a, 0x90100121 }, |
@@ -1176,6 +1220,7 @@ static struct cs_pincfg imac27_pincfgs[] = { | |||
1176 | }; | 1220 | }; |
1177 | 1221 | ||
1178 | static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { | 1222 | static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { |
1223 | [CS420X_MBP53] = mbp53_pincfgs, | ||
1179 | [CS420X_MBP55] = mbp55_pincfgs, | 1224 | [CS420X_MBP55] = mbp55_pincfgs, |
1180 | [CS420X_IMAC27] = imac27_pincfgs, | 1225 | [CS420X_IMAC27] = imac27_pincfgs, |
1181 | }; | 1226 | }; |
@@ -1208,6 +1253,7 @@ static int patch_cs420x(struct hda_codec *codec) | |||
1208 | 1253 | ||
1209 | switch (spec->board_config) { | 1254 | switch (spec->board_config) { |
1210 | case CS420X_IMAC27: | 1255 | case CS420X_IMAC27: |
1256 | case CS420X_MBP53: | ||
1211 | case CS420X_MBP55: | 1257 | case CS420X_MBP55: |
1212 | /* GPIO1 = headphones */ | 1258 | /* GPIO1 = headphones */ |
1213 | /* GPIO3 = speakers */ | 1259 | /* GPIO3 = speakers */ |