aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorGreg Alexander <greigs@galexander.org>2010-02-13 02:02:25 -0500
committerTakashi Iwai <tiwai@suse.de>2010-02-13 04:16:05 -0500
commitcfd3d8dcf7b4fc783db0806ac3936a7b44735bf7 (patch)
treeed8d1b1af1d83f4cb18384e6d36ad2c135e3a64f /sound/pci
parentb2d6efe7fa18ad14ee6e9964c90643095b6ac7e2 (diff)
ALSA: hda - Add support for Lenovo IdeaPad U150
Add patch for the Conexant 5066 HDA codec to support the Lenovo IdeaPad U150 Signed-off-by: Greg Alexander <greigs@galexander.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/hda/patch_conexant.c130
1 files changed, 126 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 745e35992144..194a28c54992 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -113,7 +113,8 @@ struct conexant_spec {
113 113
114 unsigned int dell_automute; 114 unsigned int dell_automute;
115 unsigned int port_d_mode; 115 unsigned int port_d_mode;
116 unsigned int dell_vostro; 116 unsigned int dell_vostro:1;
117 unsigned int ideapad:1;
117 118
118 unsigned int ext_mic_present; 119 unsigned int ext_mic_present;
119 unsigned int recording; 120 unsigned int recording;
@@ -2167,6 +2168,34 @@ static void cxt5066_vostro_automic(struct hda_codec *codec)
2167 } 2168 }
2168} 2169}
2169 2170
2171/* toggle input of built-in digital mic and mic jack appropriately */
2172static void cxt5066_ideapad_automic(struct hda_codec *codec)
2173{
2174 unsigned int present;
2175
2176 struct hda_verb ext_mic_present[] = {
2177 {0x14, AC_VERB_SET_CONNECT_SEL, 0},
2178 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2179 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2180 {}
2181 };
2182 static struct hda_verb ext_mic_absent[] = {
2183 {0x14, AC_VERB_SET_CONNECT_SEL, 2},
2184 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2185 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2186 {}
2187 };
2188
2189 present = snd_hda_jack_detect(codec, 0x1b);
2190 if (present) {
2191 snd_printdd("CXT5066: external microphone detected\n");
2192 snd_hda_sequence_write(codec, ext_mic_present);
2193 } else {
2194 snd_printdd("CXT5066: external microphone absent\n");
2195 snd_hda_sequence_write(codec, ext_mic_absent);
2196 }
2197}
2198
2170/* mute internal speaker if HP is plugged */ 2199/* mute internal speaker if HP is plugged */
2171static void cxt5066_hp_automute(struct hda_codec *codec) 2200static void cxt5066_hp_automute(struct hda_codec *codec)
2172{ 2201{
@@ -2216,6 +2245,20 @@ static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res)
2216 } 2245 }
2217} 2246}
2218 2247
2248/* unsolicited event for jack sensing */
2249static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res)
2250{
2251 snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26);
2252 switch (res >> 26) {
2253 case CONEXANT_HP_EVENT:
2254 cxt5066_hp_automute(codec);
2255 break;
2256 case CONEXANT_MIC_EVENT:
2257 cxt5066_ideapad_automic(codec);
2258 break;
2259 }
2260}
2261
2219static const struct hda_input_mux cxt5066_analog_mic_boost = { 2262static const struct hda_input_mux cxt5066_analog_mic_boost = {
2220 .num_items = 5, 2263 .num_items = 5,
2221 .items = { 2264 .items = {
@@ -2227,13 +2270,21 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = {
2227 }, 2270 },
2228}; 2271};
2229 2272
2230static int cxt5066_set_mic_boost(struct hda_codec *codec) 2273static void cxt5066_set_mic_boost(struct hda_codec *codec)
2231{ 2274{
2232 struct conexant_spec *spec = codec->spec; 2275 struct conexant_spec *spec = codec->spec;
2233 return snd_hda_codec_write_cache(codec, 0x17, 0, 2276 snd_hda_codec_write_cache(codec, 0x17, 0,
2234 AC_VERB_SET_AMP_GAIN_MUTE, 2277 AC_VERB_SET_AMP_GAIN_MUTE,
2235 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | 2278 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
2236 cxt5066_analog_mic_boost.items[spec->mic_boost].index); 2279 cxt5066_analog_mic_boost.items[spec->mic_boost].index);
2280 if (spec->ideapad) {
2281 /* adjust the internal mic as well...it is not through 0x17 */
2282 snd_hda_codec_write_cache(codec, 0x23, 0,
2283 AC_VERB_SET_AMP_GAIN_MUTE,
2284 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT |
2285 cxt5066_analog_mic_boost.
2286 items[spec->mic_boost].index);
2287 }
2237} 2288}
2238 2289
2239static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, 2290static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
@@ -2664,6 +2715,56 @@ static struct hda_verb cxt5066_init_verbs_vostro[] = {
2664 { } /* end */ 2715 { } /* end */
2665}; 2716};
2666 2717
2718static struct hda_verb cxt5066_init_verbs_ideapad[] = {
2719 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
2720 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
2721 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
2722 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
2723
2724 /* Speakers */
2725 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2726 {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2727
2728 /* HP, Amp */
2729 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2730 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2731
2732 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2733 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2734
2735 /* DAC1 */
2736 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2737
2738 /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
2739 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
2740 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2741 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
2742 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2743 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2744 {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */
2745
2746 /* Audio input selector */
2747 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2},
2748 {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */
2749
2750 /* SPDIF route: PCM */
2751 {0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
2752 {0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
2753
2754 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2755 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2756
2757 /* internal microphone */
2758 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */
2759
2760 /* EAPD */
2761 {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
2762
2763 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
2764 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
2765 { } /* end */
2766};
2767
2667static struct hda_verb cxt5066_init_verbs_portd_lo[] = { 2768static struct hda_verb cxt5066_init_verbs_portd_lo[] = {
2668 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2769 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2669 { } /* end */ 2770 { } /* end */
@@ -2680,6 +2781,8 @@ static int cxt5066_init(struct hda_codec *codec)
2680 cxt5066_hp_automute(codec); 2781 cxt5066_hp_automute(codec);
2681 if (spec->dell_vostro) 2782 if (spec->dell_vostro)
2682 cxt5066_vostro_automic(codec); 2783 cxt5066_vostro_automic(codec);
2784 else if (spec->ideapad)
2785 cxt5066_ideapad_automic(codec);
2683 } 2786 }
2684 cxt5066_set_mic_boost(codec); 2787 cxt5066_set_mic_boost(codec);
2685 return 0; 2788 return 0;
@@ -2705,6 +2808,7 @@ enum {
2705 CXT5066_DELL_LAPTOP, /* Dell Laptop */ 2808 CXT5066_DELL_LAPTOP, /* Dell Laptop */
2706 CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ 2809 CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
2707 CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ 2810 CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */
2811 CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
2708 CXT5066_MODELS 2812 CXT5066_MODELS
2709}; 2813};
2710 2814
@@ -2712,7 +2816,8 @@ static const char *cxt5066_models[CXT5066_MODELS] = {
2712 [CXT5066_LAPTOP] = "laptop", 2816 [CXT5066_LAPTOP] = "laptop",
2713 [CXT5066_DELL_LAPTOP] = "dell-laptop", 2817 [CXT5066_DELL_LAPTOP] = "dell-laptop",
2714 [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", 2818 [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
2715 [CXT5066_DELL_VOSTO] = "dell-vostro" 2819 [CXT5066_DELL_VOSTO] = "dell-vostro",
2820 [CXT5066_IDEAPAD] = "ideapad",
2716}; 2821};
2717 2822
2718static struct snd_pci_quirk cxt5066_cfg_tbl[] = { 2823static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
@@ -2722,6 +2827,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = {
2722 CXT5066_DELL_LAPTOP), 2827 CXT5066_DELL_LAPTOP),
2723 SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), 2828 SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
2724 SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), 2829 SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO),
2830 SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD),
2725 {} 2831 {}
2726}; 2832};
2727 2833
@@ -2813,6 +2919,22 @@ static int patch_cxt5066(struct hda_codec *codec)
2813 /* input source automatically selected */ 2919 /* input source automatically selected */
2814 spec->input_mux = NULL; 2920 spec->input_mux = NULL;
2815 break; 2921 break;
2922 case CXT5066_IDEAPAD:
2923 codec->patch_ops.init = cxt5066_init;
2924 codec->patch_ops.unsol_event = cxt5066_ideapad_event;
2925 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
2926 spec->mixers[spec->num_mixers++] = cxt5066_mixers;
2927 spec->init_verbs[0] = cxt5066_init_verbs_ideapad;
2928 spec->port_d_mode = 0;
2929 spec->ideapad = 1;
2930 spec->mic_boost = 2; /* default 20dB gain */
2931
2932 /* no S/PDIF out */
2933 spec->multiout.dig_out_nid = 0;
2934
2935 /* input source automatically selected */
2936 spec->input_mux = NULL;
2937 break;
2816 } 2938 }
2817 2939
2818 return 0; 2940 return 0;