aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_conexant.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-01-31 18:16:28 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-01-31 18:16:28 -0500
commite1a9c9872dd004617555dff079b357a6ffd945e9 (patch)
treec34779e59712ff345f8e4ee97e74086a85b34974 /sound/pci/hda/patch_conexant.c
parentfcc3ff4f9d695a80dc6e6058e0d631a3026ed4c3 (diff)
parent2ecba4ffbbc6c85fce8c3878514be415edace413 (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.c445
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
225static 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
239static 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
249static 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
221static int conexant_build_pcms(struct hda_codec *codec) 260static 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
505static 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
633static 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
580static struct hda_verb cxt5045_init_verbs[] = { 642static 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
667static 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
606static struct hda_verb cxt5045_hp_sense_init_verbs[] = { 692static 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
742enum { 828enum {
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
751static const char *cxt5045_models[CXT5045_MODELS] = { 839static 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
759static struct snd_pci_quirk cxt5045_cfg_tbl[] = { 849static 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)
933static void cxt5047_hp_automic(struct hda_codec *codec) 1066static 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)
956static void cxt5047_hp_unsol_event(struct hda_codec *codec, 1089static 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
1256static struct snd_pci_quirk cxt5047_cfg_tbl[] = { 1399static 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 */
1471static hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
1472static 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
1477static struct hda_channel_mode cxt5051_modes[1] = {
1478 { 2, NULL },
1479};
1480
1481static 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 */
1491static 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 */
1503static 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 */
1516static 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 */
1541static 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 */
1552static 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
1568static 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
1588static 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
1606static 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 */
1637static 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
1649enum {
1650 CXT5051_LAPTOP, /* Laptops w/ EAPD support */
1651 CXT5051_HP, /* no docking */
1652 CXT5051_MODELS
1653};
1654
1655static const char *cxt5051_models[CXT5051_MODELS] = {
1656 [CXT5051_LAPTOP] = "laptop",
1657 [CXT5051_HP] = "hp",
1658};
1659
1660static 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
1667static 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
1327struct hda_codec_preset snd_hda_preset_conexant[] = { 1718struct 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};