diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-31 18:16:28 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-31 18:16:28 -0500 |
commit | e1a9c9872dd004617555dff079b357a6ffd945e9 (patch) | |
tree | c34779e59712ff345f8e4ee97e74086a85b34974 /sound/pci/hda/patch_conexant.c | |
parent | fcc3ff4f9d695a80dc6e6058e0d631a3026ed4c3 (diff) | |
parent | 2ecba4ffbbc6c85fce8c3878514be415edace413 (diff) |
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/perex/alsa
* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/perex/alsa: (299 commits)
[ALSA] version 1.0.16rc2
[ALSA] hda: fix Mic in as output
[ALSA] emu10k1 - Another EMU0404 Board ID
[ALSA] emu10k1 - Fix kthread handling at resume
[ALSA] emu10k1: General cleanup, add new locks, fix alsa bug#3501, kernel bug#9304.
[ALSA] emu10k1 - Use enum for emu_model types
[ALSA] emu10k1 - Don't create emu1010 controls for non-emu boards
[ALSA] emu10k1 - 1616(M) cardbus improvements
[ALSA] snd:emu10k1: E-Mu updates. Fixes to firmware loading and support for 0404.
[ALSA] emu10k1: Add comments regarding E-Mu ins and outs.
[ALSA] oxygen: revert SPI clock frequency change for AK4396/WM8785
[ALSA] es1938 - improve capture hw pointer reads
[ALSA] HDA-Intel - Add support for Intel SCH
[ALSA] hda: Add GPIO mute support to STAC9205
[ALSA] hda-codec - Add Dell T3400 support
[ALSA] hda-codec - Add model for HP DV9553EG laptop
[ALSA] hda-codec - Control SPDIF as slave
[ALSA] hda_intel: ALSA HD Audio patch for Intel ICH10 DeviceID's
[ALSA] Fix Oops with PCM OSS sync
[ALSA] hda-codec - Add speaker automute to ALC262 HP models
...
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 445 |
1 files changed, 419 insertions, 26 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6aa073986747..f6dd51cda7b2 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -20,7 +20,6 @@ | |||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <sound/driver.h> | ||
24 | #include <linux/init.h> | 23 | #include <linux/init.h> |
25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
26 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
@@ -65,6 +64,11 @@ struct conexant_spec { | |||
65 | hda_nid_t *adc_nids; | 64 | hda_nid_t *adc_nids; |
66 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ | 65 | hda_nid_t dig_in_nid; /* digital-in NID; optional */ |
67 | 66 | ||
67 | unsigned int cur_adc_idx; | ||
68 | hda_nid_t cur_adc; | ||
69 | unsigned int cur_adc_stream_tag; | ||
70 | unsigned int cur_adc_format; | ||
71 | |||
68 | /* capture source */ | 72 | /* capture source */ |
69 | const struct hda_input_mux *input_mux; | 73 | const struct hda_input_mux *input_mux; |
70 | hda_nid_t *capsrc_nids; | 74 | hda_nid_t *capsrc_nids; |
@@ -218,6 +222,41 @@ static struct hda_pcm_stream conexant_pcm_digital_capture = { | |||
218 | /* NID is set in alc_build_pcms */ | 222 | /* NID is set in alc_build_pcms */ |
219 | }; | 223 | }; |
220 | 224 | ||
225 | static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
226 | struct hda_codec *codec, | ||
227 | unsigned int stream_tag, | ||
228 | unsigned int format, | ||
229 | struct snd_pcm_substream *substream) | ||
230 | { | ||
231 | struct conexant_spec *spec = codec->spec; | ||
232 | spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
233 | spec->cur_adc_stream_tag = stream_tag; | ||
234 | spec->cur_adc_format = format; | ||
235 | snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
240 | struct hda_codec *codec, | ||
241 | struct snd_pcm_substream *substream) | ||
242 | { | ||
243 | struct conexant_spec *spec = codec->spec; | ||
244 | snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0); | ||
245 | spec->cur_adc = 0; | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static struct hda_pcm_stream cx5051_pcm_analog_capture = { | ||
250 | .substreams = 1, | ||
251 | .channels_min = 2, | ||
252 | .channels_max = 2, | ||
253 | .nid = 0, /* fill later */ | ||
254 | .ops = { | ||
255 | .prepare = cx5051_capture_pcm_prepare, | ||
256 | .cleanup = cx5051_capture_pcm_cleanup | ||
257 | }, | ||
258 | }; | ||
259 | |||
221 | static int conexant_build_pcms(struct hda_codec *codec) | 260 | static int conexant_build_pcms(struct hda_codec *codec) |
222 | { | 261 | { |
223 | struct conexant_spec *spec = codec->spec; | 262 | struct conexant_spec *spec = codec->spec; |
@@ -232,7 +271,12 @@ static int conexant_build_pcms(struct hda_codec *codec) | |||
232 | spec->multiout.max_channels; | 271 | spec->multiout.max_channels; |
233 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = | 272 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = |
234 | spec->multiout.dac_nids[0]; | 273 | spec->multiout.dac_nids[0]; |
235 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture; | 274 | if (codec->vendor_id == 0x14f15051) |
275 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
276 | cx5051_pcm_analog_capture; | ||
277 | else | ||
278 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
279 | conexant_pcm_analog_capture; | ||
236 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; | 280 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; |
237 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; | 281 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; |
238 | 282 | ||
@@ -373,7 +417,7 @@ static int cxt_eapd_put(struct snd_kcontrol *kcontrol, | |||
373 | hda_nid_t nid = kcontrol->private_value & 0xff; | 417 | hda_nid_t nid = kcontrol->private_value & 0xff; |
374 | unsigned int eapd; | 418 | unsigned int eapd; |
375 | 419 | ||
376 | eapd = ucontrol->value.integer.value[0]; | 420 | eapd = !!ucontrol->value.integer.value[0]; |
377 | if (invert) | 421 | if (invert) |
378 | eapd = !eapd; | 422 | eapd = !eapd; |
379 | if (eapd == spec->cur_eapd) | 423 | if (eapd == spec->cur_eapd) |
@@ -454,7 +498,16 @@ static struct hda_input_mux cxt5045_capture_source = { | |||
454 | .num_items = 2, | 498 | .num_items = 2, |
455 | .items = { | 499 | .items = { |
456 | { "IntMic", 0x1 }, | 500 | { "IntMic", 0x1 }, |
457 | { "LineIn", 0x2 }, | 501 | { "ExtMic", 0x2 }, |
502 | } | ||
503 | }; | ||
504 | |||
505 | static struct hda_input_mux cxt5045_capture_source_benq = { | ||
506 | .num_items = 3, | ||
507 | .items = { | ||
508 | { "IntMic", 0x1 }, | ||
509 | { "ExtMic", 0x2 }, | ||
510 | { "LineIn", 0x3 }, | ||
458 | } | 511 | } |
459 | }; | 512 | }; |
460 | 513 | ||
@@ -577,6 +630,15 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { | |||
577 | {} | 630 | {} |
578 | }; | 631 | }; |
579 | 632 | ||
633 | static struct snd_kcontrol_new cxt5045_benq_mixers[] = { | ||
634 | HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT), | ||
635 | HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT), | ||
636 | HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT), | ||
637 | HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT), | ||
638 | |||
639 | {} | ||
640 | }; | ||
641 | |||
580 | static struct hda_verb cxt5045_init_verbs[] = { | 642 | static struct hda_verb cxt5045_init_verbs[] = { |
581 | /* Line in, Mic */ | 643 | /* Line in, Mic */ |
582 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | 644 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, |
@@ -602,6 +664,30 @@ static struct hda_verb cxt5045_init_verbs[] = { | |||
602 | { } /* end */ | 664 | { } /* end */ |
603 | }; | 665 | }; |
604 | 666 | ||
667 | static struct hda_verb cxt5045_benq_init_verbs[] = { | ||
668 | /* Int Mic, Mic */ | ||
669 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | ||
670 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, | ||
671 | /* Line In,HP, Amp */ | ||
672 | {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
673 | {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
674 | {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
675 | {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
676 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
677 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
678 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
679 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
680 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
681 | /* Record selector: Int mic */ | ||
682 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
683 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, | ||
684 | AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, | ||
685 | /* SPDIF route: PCM */ | ||
686 | {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
687 | /* EAPD */ | ||
688 | {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
689 | { } /* end */ | ||
690 | }; | ||
605 | 691 | ||
606 | static struct hda_verb cxt5045_hp_sense_init_verbs[] = { | 692 | static struct hda_verb cxt5045_hp_sense_init_verbs[] = { |
607 | /* pin sensing on HP jack */ | 693 | /* pin sensing on HP jack */ |
@@ -740,8 +826,10 @@ static int cxt5045_init(struct hda_codec *codec) | |||
740 | 826 | ||
741 | 827 | ||
742 | enum { | 828 | enum { |
743 | CXT5045_LAPTOP, /* Laptops w/ EAPD support */ | 829 | CXT5045_LAPTOP_HPSENSE, |
744 | CXT5045_FUJITSU, /* Laptops w/ EAPD support */ | 830 | CXT5045_LAPTOP_MICSENSE, |
831 | CXT5045_LAPTOP_HPMICSENSE, | ||
832 | CXT5045_BENQ, | ||
745 | #ifdef CONFIG_SND_DEBUG | 833 | #ifdef CONFIG_SND_DEBUG |
746 | CXT5045_TEST, | 834 | CXT5045_TEST, |
747 | #endif | 835 | #endif |
@@ -749,23 +837,35 @@ enum { | |||
749 | }; | 837 | }; |
750 | 838 | ||
751 | static const char *cxt5045_models[CXT5045_MODELS] = { | 839 | static const char *cxt5045_models[CXT5045_MODELS] = { |
752 | [CXT5045_LAPTOP] = "laptop", | 840 | [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", |
753 | [CXT5045_FUJITSU] = "fujitsu", | 841 | [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", |
842 | [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", | ||
843 | [CXT5045_BENQ] = "benq", | ||
754 | #ifdef CONFIG_SND_DEBUG | 844 | #ifdef CONFIG_SND_DEBUG |
755 | [CXT5045_TEST] = "test", | 845 | [CXT5045_TEST] = "test", |
756 | #endif | 846 | #endif |
757 | }; | 847 | }; |
758 | 848 | ||
759 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { | 849 | static struct snd_pci_quirk cxt5045_cfg_tbl[] = { |
760 | SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP), | 850 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP", CXT5045_LAPTOP_HPSENSE), |
761 | SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP), | 851 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP_HPSENSE), |
762 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV Series", CXT5045_LAPTOP), | 852 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP_HPSENSE), |
763 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2120", CXT5045_LAPTOP), | 853 | SND_PCI_QUIRK(0x103c, 0x30b7, "HP DV6000Z", CXT5045_LAPTOP_HPSENSE), |
764 | SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP), | 854 | SND_PCI_QUIRK(0x103c, 0x30bb, "HP DV8000", CXT5045_LAPTOP_HPSENSE), |
765 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP), | 855 | SND_PCI_QUIRK(0x103c, 0x30cd, "HP DV Series", CXT5045_LAPTOP_HPSENSE), |
766 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_FUJITSU), | 856 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV9533EG", CXT5045_LAPTOP_HPSENSE), |
767 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP), | 857 | SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HPSENSE), |
768 | SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP), | 858 | SND_PCI_QUIRK(0x103c, 0x30d9, "HP Spartan", CXT5045_LAPTOP_HPSENSE), |
859 | SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), | ||
860 | SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), | ||
861 | SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), | ||
862 | SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", CXT5045_LAPTOP_HPSENSE), | ||
863 | SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||
864 | SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||
865 | SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), | ||
866 | SND_PCI_QUIRK(0x1631, 0xc106, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), | ||
867 | SND_PCI_QUIRK(0x1631, 0xc107, "Packard Bell", CXT5045_LAPTOP_HPMICSENSE), | ||
868 | SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), | ||
769 | {} | 869 | {} |
770 | }; | 870 | }; |
771 | 871 | ||
@@ -803,7 +903,7 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
803 | cxt5045_models, | 903 | cxt5045_models, |
804 | cxt5045_cfg_tbl); | 904 | cxt5045_cfg_tbl); |
805 | switch (board_config) { | 905 | switch (board_config) { |
806 | case CXT5045_LAPTOP: | 906 | case CXT5045_LAPTOP_HPSENSE: |
807 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | 907 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; |
808 | spec->input_mux = &cxt5045_capture_source; | 908 | spec->input_mux = &cxt5045_capture_source; |
809 | spec->num_init_verbs = 2; | 909 | spec->num_init_verbs = 2; |
@@ -811,20 +911,53 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
811 | spec->mixers[0] = cxt5045_mixers; | 911 | spec->mixers[0] = cxt5045_mixers; |
812 | codec->patch_ops.init = cxt5045_init; | 912 | codec->patch_ops.init = cxt5045_init; |
813 | break; | 913 | break; |
814 | case CXT5045_FUJITSU: | 914 | case CXT5045_LAPTOP_MICSENSE: |
815 | spec->input_mux = &cxt5045_capture_source; | 915 | spec->input_mux = &cxt5045_capture_source; |
816 | spec->num_init_verbs = 2; | 916 | spec->num_init_verbs = 2; |
817 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; | 917 | spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; |
818 | spec->mixers[0] = cxt5045_mixers; | 918 | spec->mixers[0] = cxt5045_mixers; |
819 | codec->patch_ops.init = cxt5045_init; | 919 | codec->patch_ops.init = cxt5045_init; |
820 | break; | 920 | break; |
921 | default: | ||
922 | case CXT5045_LAPTOP_HPMICSENSE: | ||
923 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | ||
924 | spec->input_mux = &cxt5045_capture_source; | ||
925 | spec->num_init_verbs = 3; | ||
926 | spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; | ||
927 | spec->init_verbs[2] = cxt5045_mic_sense_init_verbs; | ||
928 | spec->mixers[0] = cxt5045_mixers; | ||
929 | codec->patch_ops.init = cxt5045_init; | ||
930 | break; | ||
931 | case CXT5045_BENQ: | ||
932 | codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; | ||
933 | spec->input_mux = &cxt5045_capture_source_benq; | ||
934 | spec->num_init_verbs = 1; | ||
935 | spec->init_verbs[0] = cxt5045_benq_init_verbs; | ||
936 | spec->mixers[0] = cxt5045_mixers; | ||
937 | spec->mixers[1] = cxt5045_benq_mixers; | ||
938 | spec->num_mixers = 2; | ||
939 | codec->patch_ops.init = cxt5045_init; | ||
940 | break; | ||
821 | #ifdef CONFIG_SND_DEBUG | 941 | #ifdef CONFIG_SND_DEBUG |
822 | case CXT5045_TEST: | 942 | case CXT5045_TEST: |
823 | spec->input_mux = &cxt5045_test_capture_source; | 943 | spec->input_mux = &cxt5045_test_capture_source; |
824 | spec->mixers[0] = cxt5045_test_mixer; | 944 | spec->mixers[0] = cxt5045_test_mixer; |
825 | spec->init_verbs[0] = cxt5045_test_init_verbs; | 945 | spec->init_verbs[0] = cxt5045_test_init_verbs; |
946 | break; | ||
947 | |||
826 | #endif | 948 | #endif |
827 | } | 949 | } |
950 | |||
951 | /* | ||
952 | * Fix max PCM level to 0 dB | ||
953 | * (originall it has 0x2b steps with 0dB offset 0x14) | ||
954 | */ | ||
955 | snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, | ||
956 | (0x14 << AC_AMPCAP_OFFSET_SHIFT) | | ||
957 | (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | | ||
958 | (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | | ||
959 | (1 << AC_AMPCAP_MUTE_SHIFT)); | ||
960 | |||
828 | return 0; | 961 | return 0; |
829 | } | 962 | } |
830 | 963 | ||
@@ -933,13 +1066,13 @@ static void cxt5047_hp2_automute(struct hda_codec *codec) | |||
933 | static void cxt5047_hp_automic(struct hda_codec *codec) | 1066 | static void cxt5047_hp_automic(struct hda_codec *codec) |
934 | { | 1067 | { |
935 | static struct hda_verb mic_jack_on[] = { | 1068 | static struct hda_verb mic_jack_on[] = { |
936 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 1069 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
937 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 1070 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
938 | {} | 1071 | {} |
939 | }; | 1072 | }; |
940 | static struct hda_verb mic_jack_off[] = { | 1073 | static struct hda_verb mic_jack_off[] = { |
941 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, | 1074 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, |
942 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, | 1075 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
943 | {} | 1076 | {} |
944 | }; | 1077 | }; |
945 | unsigned int present; | 1078 | unsigned int present; |
@@ -956,8 +1089,7 @@ static void cxt5047_hp_automic(struct hda_codec *codec) | |||
956 | static void cxt5047_hp_unsol_event(struct hda_codec *codec, | 1089 | static void cxt5047_hp_unsol_event(struct hda_codec *codec, |
957 | unsigned int res) | 1090 | unsigned int res) |
958 | { | 1091 | { |
959 | res >>= 26; | 1092 | switch (res >> 26) { |
960 | switch (res) { | ||
961 | case CONEXANT_HP_EVENT: | 1093 | case CONEXANT_HP_EVENT: |
962 | cxt5047_hp_automute(codec); | 1094 | cxt5047_hp_automute(codec); |
963 | break; | 1095 | break; |
@@ -1166,6 +1298,17 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { | |||
1166 | .get = conexant_mux_enum_get, | 1298 | .get = conexant_mux_enum_get, |
1167 | .put = conexant_mux_enum_put, | 1299 | .put = conexant_mux_enum_put, |
1168 | }, | 1300 | }, |
1301 | HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT), | ||
1302 | HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT), | ||
1303 | HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT), | ||
1304 | HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT), | ||
1305 | HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT), | ||
1306 | HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT), | ||
1307 | HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT), | ||
1308 | HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT), | ||
1309 | HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT), | ||
1310 | HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT), | ||
1311 | |||
1169 | { } /* end */ | 1312 | { } /* end */ |
1170 | }; | 1313 | }; |
1171 | 1314 | ||
@@ -1255,9 +1398,9 @@ static const char *cxt5047_models[CXT5047_MODELS] = { | |||
1255 | 1398 | ||
1256 | static struct snd_pci_quirk cxt5047_cfg_tbl[] = { | 1399 | static struct snd_pci_quirk cxt5047_cfg_tbl[] = { |
1257 | SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), | 1400 | SND_PCI_QUIRK(0x103c, 0x30a0, "HP DV1000", CXT5047_LAPTOP), |
1401 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | ||
1258 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), | 1402 | SND_PCI_QUIRK(0x103c, 0x30b2, "HP DV2000T/DV3000T", CXT5047_LAPTOP), |
1259 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), | 1403 | SND_PCI_QUIRK(0x103c, 0x30b5, "HP DV2000Z", CXT5047_LAPTOP), |
1260 | SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), | ||
1261 | SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), | 1404 | SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), |
1262 | {} | 1405 | {} |
1263 | }; | 1406 | }; |
@@ -1324,10 +1467,260 @@ static int patch_cxt5047(struct hda_codec *codec) | |||
1324 | return 0; | 1467 | return 0; |
1325 | } | 1468 | } |
1326 | 1469 | ||
1470 | /* Conexant 5051 specific */ | ||
1471 | static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; | ||
1472 | static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; | ||
1473 | #define CXT5051_SPDIF_OUT 0x1C | ||
1474 | #define CXT5051_PORTB_EVENT 0x38 | ||
1475 | #define CXT5051_PORTC_EVENT 0x39 | ||
1476 | |||
1477 | static struct hda_channel_mode cxt5051_modes[1] = { | ||
1478 | { 2, NULL }, | ||
1479 | }; | ||
1480 | |||
1481 | static void cxt5051_update_speaker(struct hda_codec *codec) | ||
1482 | { | ||
1483 | struct conexant_spec *spec = codec->spec; | ||
1484 | unsigned int pinctl; | ||
1485 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | ||
1486 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1487 | pinctl); | ||
1488 | } | ||
1489 | |||
1490 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
1491 | static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
1492 | struct snd_ctl_elem_value *ucontrol) | ||
1493 | { | ||
1494 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1495 | |||
1496 | if (!cxt_eapd_put(kcontrol, ucontrol)) | ||
1497 | return 0; | ||
1498 | cxt5051_update_speaker(codec); | ||
1499 | return 1; | ||
1500 | } | ||
1501 | |||
1502 | /* toggle input of built-in and mic jack appropriately */ | ||
1503 | static void cxt5051_portb_automic(struct hda_codec *codec) | ||
1504 | { | ||
1505 | unsigned int present; | ||
1506 | |||
1507 | present = snd_hda_codec_read(codec, 0x17, 0, | ||
1508 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1509 | AC_PINSENSE_PRESENCE; | ||
1510 | snd_hda_codec_write(codec, 0x14, 0, | ||
1511 | AC_VERB_SET_CONNECT_SEL, | ||
1512 | present ? 0x01 : 0x00); | ||
1513 | } | ||
1514 | |||
1515 | /* switch the current ADC according to the jack state */ | ||
1516 | static void cxt5051_portc_automic(struct hda_codec *codec) | ||
1517 | { | ||
1518 | struct conexant_spec *spec = codec->spec; | ||
1519 | unsigned int present; | ||
1520 | hda_nid_t new_adc; | ||
1521 | |||
1522 | present = snd_hda_codec_read(codec, 0x18, 0, | ||
1523 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1524 | AC_PINSENSE_PRESENCE; | ||
1525 | if (present) | ||
1526 | spec->cur_adc_idx = 1; | ||
1527 | else | ||
1528 | spec->cur_adc_idx = 0; | ||
1529 | new_adc = spec->adc_nids[spec->cur_adc_idx]; | ||
1530 | if (spec->cur_adc && spec->cur_adc != new_adc) { | ||
1531 | /* stream is running, let's swap the current ADC */ | ||
1532 | snd_hda_codec_setup_stream(codec, spec->cur_adc, 0, 0, 0); | ||
1533 | spec->cur_adc = new_adc; | ||
1534 | snd_hda_codec_setup_stream(codec, new_adc, | ||
1535 | spec->cur_adc_stream_tag, 0, | ||
1536 | spec->cur_adc_format); | ||
1537 | } | ||
1538 | } | ||
1539 | |||
1540 | /* mute internal speaker if HP is plugged */ | ||
1541 | static void cxt5051_hp_automute(struct hda_codec *codec) | ||
1542 | { | ||
1543 | struct conexant_spec *spec = codec->spec; | ||
1544 | |||
1545 | spec->hp_present = snd_hda_codec_read(codec, 0x16, 0, | ||
1546 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1547 | AC_PINSENSE_PRESENCE; | ||
1548 | cxt5051_update_speaker(codec); | ||
1549 | } | ||
1550 | |||
1551 | /* unsolicited event for HP jack sensing */ | ||
1552 | static void cxt5051_hp_unsol_event(struct hda_codec *codec, | ||
1553 | unsigned int res) | ||
1554 | { | ||
1555 | switch (res >> 26) { | ||
1556 | case CONEXANT_HP_EVENT: | ||
1557 | cxt5051_hp_automute(codec); | ||
1558 | break; | ||
1559 | case CXT5051_PORTB_EVENT: | ||
1560 | cxt5051_portb_automic(codec); | ||
1561 | break; | ||
1562 | case CXT5051_PORTC_EVENT: | ||
1563 | cxt5051_portc_automic(codec); | ||
1564 | break; | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1568 | static struct snd_kcontrol_new cxt5051_mixers[] = { | ||
1569 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1570 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1571 | HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
1572 | HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
1573 | HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1574 | HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1575 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1576 | { | ||
1577 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1578 | .name = "Master Playback Switch", | ||
1579 | .info = cxt_eapd_info, | ||
1580 | .get = cxt_eapd_get, | ||
1581 | .put = cxt5051_hp_master_sw_put, | ||
1582 | .private_value = 0x1a, | ||
1583 | }, | ||
1584 | |||
1585 | {} | ||
1586 | }; | ||
1587 | |||
1588 | static struct snd_kcontrol_new cxt5051_hp_mixers[] = { | ||
1589 | HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), | ||
1590 | HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), | ||
1591 | HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), | ||
1592 | HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), | ||
1593 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
1594 | { | ||
1595 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1596 | .name = "Master Playback Switch", | ||
1597 | .info = cxt_eapd_info, | ||
1598 | .get = cxt_eapd_get, | ||
1599 | .put = cxt5051_hp_master_sw_put, | ||
1600 | .private_value = 0x1a, | ||
1601 | }, | ||
1602 | |||
1603 | {} | ||
1604 | }; | ||
1605 | |||
1606 | static struct hda_verb cxt5051_init_verbs[] = { | ||
1607 | /* Line in, Mic */ | ||
1608 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1609 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1610 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1611 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1612 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1613 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | ||
1614 | /* SPK */ | ||
1615 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1616 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1617 | /* HP, Amp */ | ||
1618 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
1619 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1620 | /* DAC1 */ | ||
1621 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1622 | /* Record selector: Int mic */ | ||
1623 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | ||
1624 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | ||
1625 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, | ||
1626 | /* SPDIF route: PCM */ | ||
1627 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
1628 | /* EAPD */ | ||
1629 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
1630 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||
1631 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
1632 | {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTC_EVENT}, | ||
1633 | { } /* end */ | ||
1634 | }; | ||
1635 | |||
1636 | /* initialize jack-sensing, too */ | ||
1637 | static int cxt5051_init(struct hda_codec *codec) | ||
1638 | { | ||
1639 | conexant_init(codec); | ||
1640 | if (codec->patch_ops.unsol_event) { | ||
1641 | cxt5051_hp_automute(codec); | ||
1642 | cxt5051_portb_automic(codec); | ||
1643 | cxt5051_portc_automic(codec); | ||
1644 | } | ||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | |||
1649 | enum { | ||
1650 | CXT5051_LAPTOP, /* Laptops w/ EAPD support */ | ||
1651 | CXT5051_HP, /* no docking */ | ||
1652 | CXT5051_MODELS | ||
1653 | }; | ||
1654 | |||
1655 | static const char *cxt5051_models[CXT5051_MODELS] = { | ||
1656 | [CXT5051_LAPTOP] = "laptop", | ||
1657 | [CXT5051_HP] = "hp", | ||
1658 | }; | ||
1659 | |||
1660 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | ||
1661 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | ||
1662 | CXT5051_LAPTOP), | ||
1663 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | ||
1664 | {} | ||
1665 | }; | ||
1666 | |||
1667 | static int patch_cxt5051(struct hda_codec *codec) | ||
1668 | { | ||
1669 | struct conexant_spec *spec; | ||
1670 | int board_config; | ||
1671 | |||
1672 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
1673 | if (!spec) | ||
1674 | return -ENOMEM; | ||
1675 | mutex_init(&spec->amp_mutex); | ||
1676 | codec->spec = spec; | ||
1677 | |||
1678 | codec->patch_ops = conexant_patch_ops; | ||
1679 | codec->patch_ops.init = cxt5051_init; | ||
1680 | |||
1681 | spec->multiout.max_channels = 2; | ||
1682 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids); | ||
1683 | spec->multiout.dac_nids = cxt5051_dac_nids; | ||
1684 | spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; | ||
1685 | spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ | ||
1686 | spec->adc_nids = cxt5051_adc_nids; | ||
1687 | spec->num_mixers = 1; | ||
1688 | spec->mixers[0] = cxt5051_mixers; | ||
1689 | spec->num_init_verbs = 1; | ||
1690 | spec->init_verbs[0] = cxt5051_init_verbs; | ||
1691 | spec->spdif_route = 0; | ||
1692 | spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes); | ||
1693 | spec->channel_mode = cxt5051_modes; | ||
1694 | spec->cur_adc = 0; | ||
1695 | spec->cur_adc_idx = 0; | ||
1696 | |||
1697 | board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, | ||
1698 | cxt5051_models, | ||
1699 | cxt5051_cfg_tbl); | ||
1700 | switch (board_config) { | ||
1701 | case CXT5051_HP: | ||
1702 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | ||
1703 | spec->mixers[0] = cxt5051_hp_mixers; | ||
1704 | break; | ||
1705 | default: | ||
1706 | case CXT5051_LAPTOP: | ||
1707 | codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; | ||
1708 | break; | ||
1709 | } | ||
1710 | |||
1711 | return 0; | ||
1712 | } | ||
1713 | |||
1714 | |||
1715 | /* | ||
1716 | */ | ||
1717 | |||
1327 | struct hda_codec_preset snd_hda_preset_conexant[] = { | 1718 | struct hda_codec_preset snd_hda_preset_conexant[] = { |
1328 | { .id = 0x14f15045, .name = "CX20549 (Venice)", | 1719 | { .id = 0x14f15045, .name = "CX20549 (Venice)", |
1329 | .patch = patch_cxt5045 }, | 1720 | .patch = patch_cxt5045 }, |
1330 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", | 1721 | { .id = 0x14f15047, .name = "CX20551 (Waikiki)", |
1331 | .patch = patch_cxt5047 }, | 1722 | .patch = patch_cxt5047 }, |
1723 | { .id = 0x14f15051, .name = "CX20561 (Hermosa)", | ||
1724 | .patch = patch_cxt5051 }, | ||
1332 | {} /* terminator */ | 1725 | {} /* terminator */ |
1333 | }; | 1726 | }; |