aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_conexant.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r--sound/pci/hda/patch_conexant.c169
1 files changed, 161 insertions, 8 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 61682e1d09da..e863649d31f5 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -115,6 +115,7 @@ struct conexant_spec {
115 unsigned int port_d_mode; 115 unsigned int port_d_mode;
116 unsigned int dell_vostro:1; 116 unsigned int dell_vostro:1;
117 unsigned int ideapad:1; 117 unsigned int ideapad:1;
118 unsigned int thinkpad:1;
118 119
119 unsigned int ext_mic_present; 120 unsigned int ext_mic_present;
120 unsigned int recording; 121 unsigned int recording;
@@ -1195,10 +1196,12 @@ static int patch_cxt5045(struct hda_codec *codec)
1195 1196
1196 switch (codec->subsystem_id >> 16) { 1197 switch (codec->subsystem_id >> 16) {
1197 case 0x103c: 1198 case 0x103c:
1199 case 0x1631:
1198 case 0x1734: 1200 case 0x1734:
1199 /* HP & Fujitsu-Siemens laptops have really bad sound over 0dB 1201 case 0x17aa:
1200 * on NID 0x17. Fix max PCM level to 0 dB 1202 /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
1201 * (originally it has 0x2b steps with 0dB offset 0x14) 1203 * really bad sound over 0dB on NID 0x17. Fix max PCM level to
1204 * 0 dB (originally it has 0x2b steps with 0dB offset 0x14)
1202 */ 1205 */
1203 snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, 1206 snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
1204 (0x14 << AC_AMPCAP_OFFSET_SHIFT) | 1207 (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
@@ -1782,6 +1785,7 @@ static struct hda_verb cxt5051_init_verbs[] = {
1782 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, 1785 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
1783 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, 1786 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
1784 /* SPDIF route: PCM */ 1787 /* SPDIF route: PCM */
1788 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1785 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, 1789 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
1786 /* EAPD */ 1790 /* EAPD */
1787 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1791 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
@@ -1838,6 +1842,7 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
1838 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, 1842 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
1839 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, 1843 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
1840 /* SPDIF route: PCM */ 1844 /* SPDIF route: PCM */
1845 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* needed for W500 Advanced Mini Dock 250410 */
1841 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, 1846 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
1842 /* EAPD */ 1847 /* EAPD */
1843 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1848 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
@@ -1909,7 +1914,7 @@ enum {
1909 CXT5051_LAPTOP, /* Laptops w/ EAPD support */ 1914 CXT5051_LAPTOP, /* Laptops w/ EAPD support */
1910 CXT5051_HP, /* no docking */ 1915 CXT5051_HP, /* no docking */
1911 CXT5051_HP_DV6736, /* HP without mic switch */ 1916 CXT5051_HP_DV6736, /* HP without mic switch */
1912 CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ 1917 CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */
1913 CXT5051_F700, /* HP Compaq Presario F700 */ 1918 CXT5051_F700, /* HP Compaq Presario F700 */
1914 CXT5051_TOSHIBA, /* Toshiba M300 & co */ 1919 CXT5051_TOSHIBA, /* Toshiba M300 & co */
1915 CXT5051_MODELS 1920 CXT5051_MODELS
@@ -2031,6 +2036,9 @@ static void cxt5066_update_speaker(struct hda_codec *codec)
2031 /* Port D (HP/LO) */ 2036 /* Port D (HP/LO) */
2032 pinctl = ((spec->hp_present & 2) && spec->cur_eapd) 2037 pinctl = ((spec->hp_present & 2) && spec->cur_eapd)
2033 ? spec->port_d_mode : 0; 2038 ? spec->port_d_mode : 0;
2039 /* Mute if Port A is connected on Thinkpad */
2040 if (spec->thinkpad && (spec->hp_present & 1))
2041 pinctl = 0;
2034 snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2042 snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2035 pinctl); 2043 pinctl);
2036 2044
@@ -2211,6 +2219,50 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec)
2211 } 2219 }
2212} 2220}
2213 2221
2222/* toggle input of built-in digital mic and mic jack appropriately
2223 order is: external mic -> dock mic -> interal mic */
2224static void cxt5066_thinkpad_automic(struct hda_codec *codec)
2225{
2226 unsigned int ext_present, dock_present;
2227
2228 static struct hda_verb ext_mic_present[] = {
2229 {0x14, AC_VERB_SET_CONNECT_SEL, 0},
2230 {0x17, AC_VERB_SET_CONNECT_SEL, 1},
2231 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2232 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2233 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2234 {}
2235 };
2236 static struct hda_verb dock_mic_present[] = {
2237 {0x14, AC_VERB_SET_CONNECT_SEL, 0},
2238 {0x17, AC_VERB_SET_CONNECT_SEL, 0},
2239 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2240 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2241 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2242 {}
2243 };
2244 static struct hda_verb ext_mic_absent[] = {
2245 {0x14, AC_VERB_SET_CONNECT_SEL, 2},
2246 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2247 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2248 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2249 {}
2250 };
2251
2252 ext_present = snd_hda_jack_detect(codec, 0x1b);
2253 dock_present = snd_hda_jack_detect(codec, 0x1a);
2254 if (ext_present) {
2255 snd_printdd("CXT5066: external microphone detected\n");
2256 snd_hda_sequence_write(codec, ext_mic_present);
2257 } else if (dock_present) {
2258 snd_printdd("CXT5066: dock microphone detected\n");
2259 snd_hda_sequence_write(codec, dock_mic_present);
2260 } else {
2261 snd_printdd("CXT5066: external microphone absent\n");
2262 snd_hda_sequence_write(codec, ext_mic_absent);
2263 }
2264}
2265
2214/* mute internal speaker if HP is plugged */ 2266/* mute internal speaker if HP is plugged */
2215static void cxt5066_hp_automute(struct hda_codec *codec) 2267static void cxt5066_hp_automute(struct hda_codec *codec)
2216{ 2268{
@@ -2223,7 +2275,8 @@ static void cxt5066_hp_automute(struct hda_codec *codec)
2223 /* Port D */ 2275 /* Port D */
2224 portD = snd_hda_jack_detect(codec, 0x1c); 2276 portD = snd_hda_jack_detect(codec, 0x1c);
2225 2277
2226 spec->hp_present = !!(portA | portD); 2278 spec->hp_present = !!(portA);
2279 spec->hp_present |= portD ? 2 : 0;
2227 snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", 2280 snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
2228 portA, portD, spec->hp_present); 2281 portA, portD, spec->hp_present);
2229 cxt5066_update_speaker(codec); 2282 cxt5066_update_speaker(codec);
@@ -2274,6 +2327,20 @@ static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res)
2274 } 2327 }
2275} 2328}
2276 2329
2330/* unsolicited event for jack sensing */
2331static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res)
2332{
2333 snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26);
2334 switch (res >> 26) {
2335 case CONEXANT_HP_EVENT:
2336 cxt5066_hp_automute(codec);
2337 break;
2338 case CONEXANT_MIC_EVENT:
2339 cxt5066_thinkpad_automic(codec);
2340 break;
2341 }
2342}
2343
2277static const struct hda_input_mux cxt5066_analog_mic_boost = { 2344static const struct hda_input_mux cxt5066_analog_mic_boost = {
2278 .num_items = 5, 2345 .num_items = 5,
2279 .items = { 2346 .items = {
@@ -2292,7 +2359,7 @@ static void cxt5066_set_mic_boost(struct hda_codec *codec)
2292 AC_VERB_SET_AMP_GAIN_MUTE, 2359 AC_VERB_SET_AMP_GAIN_MUTE,
2293 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | 2360 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
2294 cxt5066_analog_mic_boost.items[spec->mic_boost].index); 2361 cxt5066_analog_mic_boost.items[spec->mic_boost].index);
2295 if (spec->ideapad) { 2362 if (spec->ideapad || spec->thinkpad) {
2296 /* adjust the internal mic as well...it is not through 0x17 */ 2363 /* adjust the internal mic as well...it is not through 0x17 */
2297 snd_hda_codec_write_cache(codec, 0x23, 0, 2364 snd_hda_codec_write_cache(codec, 0x23, 0,
2298 AC_VERB_SET_AMP_GAIN_MUTE, 2365 AC_VERB_SET_AMP_GAIN_MUTE,
@@ -2780,6 +2847,64 @@ static struct hda_verb cxt5066_init_verbs_ideapad[] = {
2780 { } /* end */ 2847 { } /* end */
2781}; 2848};
2782 2849
2850static struct hda_verb cxt5066_init_verbs_thinkpad[] = {
2851 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
2852 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
2853
2854 /* Port G: internal speakers */
2855 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2856 {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2857
2858 /* Port A: HP, Amp */
2859 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2860 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2861
2862 /* Port B: Mic Dock */
2863 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2864
2865 /* Port C: Mic */
2866 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2867
2868 /* Port D: HP Dock, Amp */
2869 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2870 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2871
2872 /* DAC1 */
2873 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2874
2875 /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
2876 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
2877 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2878 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
2879 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2880 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2881 {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */
2882
2883 /* Audio input selector */
2884 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2},
2885 {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */
2886
2887 /* SPDIF route: PCM */
2888 {0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
2889 {0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
2890
2891 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2892 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2893
2894 /* internal microphone */
2895 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
2896
2897 /* EAPD */
2898 {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
2899
2900 /* enable unsolicited events for Port A, B, C and D */
2901 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
2902 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
2903 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
2904 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
2905 { } /* end */
2906};
2907
2783static struct hda_verb cxt5066_init_verbs_portd_lo[] = { 2908static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
2784 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2909 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2785 { } /* end */ 2910 { } /* end */
@@ -2798,6 +2923,8 @@ static int cxt5066_init(struct hda_codec *codec)
2798 cxt5066_vostro_automic(codec); 2923 cxt5066_vostro_automic(codec);
2799 else if (spec->ideapad) 2924 else if (spec->ideapad)
2800 cxt5066_ideapad_automic(codec); 2925 cxt5066_ideapad_automic(codec);
2926 else if (spec->thinkpad)
2927 cxt5066_thinkpad_automic(codec);
2801 } 2928 }
2802 cxt5066_set_mic_boost(codec); 2929 cxt5066_set_mic_boost(codec);
2803 return 0; 2930 return 0;
@@ -2819,20 +2946,22 @@ static int cxt5066_olpc_init(struct hda_codec *codec)
2819} 2946}
2820 2947
2821enum { 2948enum {
2822 CXT5066_LAPTOP, /* Laptops w/ EAPD support */ 2949 CXT5066_LAPTOP, /* Laptops w/ EAPD support */
2823 CXT5066_DELL_LAPTOP, /* Dell Laptop */ 2950 CXT5066_DELL_LAPTOP, /* Dell Laptop */
2824 CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ 2951 CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
2825 CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ 2952 CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */
2826 CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ 2953 CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
2954 CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */
2827 CXT5066_MODELS 2955 CXT5066_MODELS
2828}; 2956};
2829 2957
2830static const char *cxt5066_models[CXT5066_MODELS] = { 2958static const char *cxt5066_models[CXT5066_MODELS] = {
2831 [CXT5066_LAPTOP] = "laptop", 2959 [CXT5066_LAPTOP] = "laptop",
2832 [CXT5066_DELL_LAPTOP] = "dell-laptop", 2960 [CXT5066_DELL_LAPTOP] = "dell-laptop",
2833 [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", 2961 [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
2834 [CXT5066_DELL_VOSTO] = "dell-vostro", 2962 [CXT5066_DELL_VOSTO] = "dell-vostro",
2835 [CXT5066_IDEAPAD] = "ideapad", 2963 [CXT5066_IDEAPAD] = "ideapad",
2964 [CXT5066_THINKPAD] = "thinkpad",
2836}; 2965};
2837 2966
2838static struct snd_pci_quirk cxt5066_cfg_tbl[] = { 2967static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
@@ -2842,7 +2971,12 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
2842 CXT5066_DELL_LAPTOP), 2971 CXT5066_DELL_LAPTOP),
2843 SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), 2972 SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
2844 SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), 2973 SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
2974 SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
2975 SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
2976 SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
2977 SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD),
2845 SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), 2978 SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
2979 SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
2846 {} 2980 {}
2847}; 2981};
2848 2982
@@ -2950,6 +3084,22 @@ static int patch_cxt5066(struct hda_codec *codec)
2950 /* input source automatically selected */ 3084 /* input source automatically selected */
2951 spec->input_mux = NULL; 3085 spec->input_mux = NULL;
2952 break; 3086 break;
3087 case CXT5066_THINKPAD:
3088 codec->patch_ops.init = cxt5066_init;
3089 codec->patch_ops.unsol_event = cxt5066_thinkpad_event;
3090 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
3091 spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3092 spec->init_verbs[0] = cxt5066_init_verbs_thinkpad;
3093 spec->thinkpad = 1;
3094 spec->port_d_mode = PIN_OUT;
3095 spec->mic_boost = 2; /* default 20dB gain */
3096
3097 /* no S/PDIF out */
3098 spec->multiout.dig_out_nid = 0;
3099
3100 /* input source automatically selected */
3101 spec->input_mux = NULL;
3102 break;
2953 } 3103 }
2954 3104
2955 return 0; 3105 return 0;
@@ -2969,6 +3119,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = {
2969 .patch = patch_cxt5066 }, 3119 .patch = patch_cxt5066 },
2970 { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", 3120 { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)",
2971 .patch = patch_cxt5066 }, 3121 .patch = patch_cxt5066 },
3122 { .id = 0x14f15069, .name = "CX20585",
3123 .patch = patch_cxt5066 },
2972 {} /* terminator */ 3124 {} /* terminator */
2973}; 3125};
2974 3126
@@ -2977,6 +3129,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15047");
2977MODULE_ALIAS("snd-hda-codec-id:14f15051"); 3129MODULE_ALIAS("snd-hda-codec-id:14f15051");
2978MODULE_ALIAS("snd-hda-codec-id:14f15066"); 3130MODULE_ALIAS("snd-hda-codec-id:14f15066");
2979MODULE_ALIAS("snd-hda-codec-id:14f15067"); 3131MODULE_ALIAS("snd-hda-codec-id:14f15067");
3132MODULE_ALIAS("snd-hda-codec-id:14f15069");
2980 3133
2981MODULE_LICENSE("GPL"); 3134MODULE_LICENSE("GPL");
2982MODULE_DESCRIPTION("Conexant HD-audio codec"); 3135MODULE_DESCRIPTION("Conexant HD-audio codec");