diff options
Diffstat (limited to 'sound/pci/hda/patch_cirrus.c')
-rw-r--r-- | sound/pci/hda/patch_cirrus.c | 55 |
1 files changed, 36 insertions, 19 deletions
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 2a2d8645ba09..70a7abda7e22 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
@@ -58,6 +58,8 @@ struct cs_spec { | |||
58 | unsigned int gpio_mask; | 58 | unsigned int gpio_mask; |
59 | unsigned int gpio_dir; | 59 | unsigned int gpio_dir; |
60 | unsigned int gpio_data; | 60 | unsigned int gpio_data; |
61 | unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */ | ||
62 | unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */ | ||
61 | 63 | ||
62 | struct hda_pcm pcm_rec[2]; /* PCM information */ | 64 | struct hda_pcm pcm_rec[2]; /* PCM information */ |
63 | 65 | ||
@@ -76,6 +78,7 @@ enum { | |||
76 | CS420X_MBP53, | 78 | CS420X_MBP53, |
77 | CS420X_MBP55, | 79 | CS420X_MBP55, |
78 | CS420X_IMAC27, | 80 | CS420X_IMAC27, |
81 | CS420X_APPLE, | ||
79 | CS420X_AUTO, | 82 | CS420X_AUTO, |
80 | CS420X_MODELS | 83 | CS420X_MODELS |
81 | }; | 84 | }; |
@@ -237,6 +240,15 @@ static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
237 | return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); | 240 | return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); |
238 | } | 241 | } |
239 | 242 | ||
243 | static void cs_update_input_select(struct hda_codec *codec) | ||
244 | { | ||
245 | struct cs_spec *spec = codec->spec; | ||
246 | if (spec->cur_adc) | ||
247 | snd_hda_codec_write(codec, spec->cur_adc, 0, | ||
248 | AC_VERB_SET_CONNECT_SEL, | ||
249 | spec->adc_idx[spec->cur_input]); | ||
250 | } | ||
251 | |||
240 | /* | 252 | /* |
241 | * Analog capture | 253 | * Analog capture |
242 | */ | 254 | */ |
@@ -250,6 +262,7 @@ static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
250 | spec->cur_adc = spec->adc_nid[spec->cur_input]; | 262 | spec->cur_adc = spec->adc_nid[spec->cur_input]; |
251 | spec->cur_adc_stream_tag = stream_tag; | 263 | spec->cur_adc_stream_tag = stream_tag; |
252 | spec->cur_adc_format = format; | 264 | spec->cur_adc_format = format; |
265 | cs_update_input_select(codec); | ||
253 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); | 266 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); |
254 | return 0; | 267 | return 0; |
255 | } | 268 | } |
@@ -689,10 +702,8 @@ static int change_cur_input(struct hda_codec *codec, unsigned int idx, | |||
689 | spec->cur_adc_stream_tag, 0, | 702 | spec->cur_adc_stream_tag, 0, |
690 | spec->cur_adc_format); | 703 | spec->cur_adc_format); |
691 | } | 704 | } |
692 | snd_hda_codec_write(codec, spec->cur_adc, 0, | ||
693 | AC_VERB_SET_CONNECT_SEL, | ||
694 | spec->adc_idx[idx]); | ||
695 | spec->cur_input = idx; | 705 | spec->cur_input = idx; |
706 | cs_update_input_select(codec); | ||
696 | return 1; | 707 | return 1; |
697 | } | 708 | } |
698 | 709 | ||
@@ -920,10 +931,9 @@ static void cs_automute(struct hda_codec *codec) | |||
920 | spdif_present ? 0 : PIN_OUT); | 931 | spdif_present ? 0 : PIN_OUT); |
921 | } | 932 | } |
922 | } | 933 | } |
923 | if (spec->board_config == CS420X_MBP53 || | 934 | if (spec->gpio_eapd_hp) { |
924 | spec->board_config == CS420X_MBP55 || | 935 | unsigned int gpio = hp_present ? |
925 | spec->board_config == CS420X_IMAC27) { | 936 | spec->gpio_eapd_hp : spec->gpio_eapd_speaker; |
926 | unsigned int gpio = hp_present ? 0x02 : 0x08; | ||
927 | snd_hda_codec_write(codec, 0x01, 0, | 937 | snd_hda_codec_write(codec, 0x01, 0, |
928 | AC_VERB_SET_GPIO_DATA, gpio); | 938 | AC_VERB_SET_GPIO_DATA, gpio); |
929 | } | 939 | } |
@@ -973,10 +983,7 @@ static void cs_automic(struct hda_codec *codec) | |||
973 | } else { | 983 | } else { |
974 | spec->cur_input = spec->last_input; | 984 | spec->cur_input = spec->last_input; |
975 | } | 985 | } |
976 | 986 | cs_update_input_select(codec); | |
977 | snd_hda_codec_write_cache(codec, spec->cur_adc, 0, | ||
978 | AC_VERB_SET_CONNECT_SEL, | ||
979 | spec->adc_idx[spec->cur_input]); | ||
980 | } else { | 987 | } else { |
981 | if (present) | 988 | if (present) |
982 | change_cur_input(codec, spec->automic_idx, 0); | 989 | change_cur_input(codec, spec->automic_idx, 0); |
@@ -1073,9 +1080,7 @@ static void init_input(struct hda_codec *codec) | |||
1073 | cs_automic(codec); | 1080 | cs_automic(codec); |
1074 | else { | 1081 | else { |
1075 | spec->cur_adc = spec->adc_nid[spec->cur_input]; | 1082 | spec->cur_adc = spec->adc_nid[spec->cur_input]; |
1076 | snd_hda_codec_write(codec, spec->cur_adc, 0, | 1083 | cs_update_input_select(codec); |
1077 | AC_VERB_SET_CONNECT_SEL, | ||
1078 | spec->adc_idx[spec->cur_input]); | ||
1079 | } | 1084 | } |
1080 | } else { | 1085 | } else { |
1081 | change_cur_input(codec, spec->cur_input, 1); | 1086 | change_cur_input(codec, spec->cur_input, 1); |
@@ -1273,6 +1278,7 @@ static const char * const cs420x_models[CS420X_MODELS] = { | |||
1273 | [CS420X_MBP53] = "mbp53", | 1278 | [CS420X_MBP53] = "mbp53", |
1274 | [CS420X_MBP55] = "mbp55", | 1279 | [CS420X_MBP55] = "mbp55", |
1275 | [CS420X_IMAC27] = "imac27", | 1280 | [CS420X_IMAC27] = "imac27", |
1281 | [CS420X_APPLE] = "apple", | ||
1276 | [CS420X_AUTO] = "auto", | 1282 | [CS420X_AUTO] = "auto", |
1277 | }; | 1283 | }; |
1278 | 1284 | ||
@@ -1282,7 +1288,13 @@ static const struct snd_pci_quirk cs420x_cfg_tbl[] = { | |||
1282 | SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), | 1288 | SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55), |
1283 | SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), | 1289 | SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), |
1284 | SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55), | 1290 | SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55), |
1285 | SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27), | 1291 | /* this conflicts with too many other models */ |
1292 | /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/ | ||
1293 | {} /* terminator */ | ||
1294 | }; | ||
1295 | |||
1296 | static const struct snd_pci_quirk cs420x_codec_cfg_tbl[] = { | ||
1297 | SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), | ||
1286 | {} /* terminator */ | 1298 | {} /* terminator */ |
1287 | }; | 1299 | }; |
1288 | 1300 | ||
@@ -1364,6 +1376,10 @@ static int patch_cs420x(struct hda_codec *codec) | |||
1364 | spec->board_config = | 1376 | spec->board_config = |
1365 | snd_hda_check_board_config(codec, CS420X_MODELS, | 1377 | snd_hda_check_board_config(codec, CS420X_MODELS, |
1366 | cs420x_models, cs420x_cfg_tbl); | 1378 | cs420x_models, cs420x_cfg_tbl); |
1379 | if (spec->board_config < 0) | ||
1380 | spec->board_config = | ||
1381 | snd_hda_check_board_codec_sid_config(codec, | ||
1382 | CS420X_MODELS, NULL, cs420x_codec_cfg_tbl); | ||
1367 | if (spec->board_config >= 0) | 1383 | if (spec->board_config >= 0) |
1368 | fix_pincfg(codec, spec->board_config, cs_pincfgs); | 1384 | fix_pincfg(codec, spec->board_config, cs_pincfgs); |
1369 | 1385 | ||
@@ -1371,10 +1387,11 @@ static int patch_cs420x(struct hda_codec *codec) | |||
1371 | case CS420X_IMAC27: | 1387 | case CS420X_IMAC27: |
1372 | case CS420X_MBP53: | 1388 | case CS420X_MBP53: |
1373 | case CS420X_MBP55: | 1389 | case CS420X_MBP55: |
1374 | /* GPIO1 = headphones */ | 1390 | case CS420X_APPLE: |
1375 | /* GPIO3 = speakers */ | 1391 | spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */ |
1376 | spec->gpio_mask = 0x0a; | 1392 | spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */ |
1377 | spec->gpio_dir = 0x0a; | 1393 | spec->gpio_mask = spec->gpio_dir = |
1394 | spec->gpio_eapd_hp | spec->gpio_eapd_speaker; | ||
1378 | break; | 1395 | break; |
1379 | } | 1396 | } |
1380 | 1397 | ||