diff options
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 248 |
1 files changed, 200 insertions, 48 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 3fbbc8c01e70..c578c28f368e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -29,6 +29,7 @@ | |||
29 | 29 | ||
30 | #include "hda_codec.h" | 30 | #include "hda_codec.h" |
31 | #include "hda_local.h" | 31 | #include "hda_local.h" |
32 | #include "hda_beep.h" | ||
32 | 33 | ||
33 | #define CXT_PIN_DIR_IN 0x00 | 34 | #define CXT_PIN_DIR_IN 0x00 |
34 | #define CXT_PIN_DIR_OUT 0x01 | 35 | #define CXT_PIN_DIR_OUT 0x01 |
@@ -110,6 +111,8 @@ struct conexant_spec { | |||
110 | 111 | ||
111 | unsigned int dell_automute; | 112 | unsigned int dell_automute; |
112 | unsigned int port_d_mode; | 113 | unsigned int port_d_mode; |
114 | unsigned char ext_mic_bias; | ||
115 | unsigned int dell_vostro; | ||
113 | }; | 116 | }; |
114 | 117 | ||
115 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | 118 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -396,9 +399,7 @@ static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) | |||
396 | for (i = 0; i < spec->jacks.used; i++) { | 399 | for (i = 0; i < spec->jacks.used; i++) { |
397 | if (jacks->nid == nid) { | 400 | if (jacks->nid == nid) { |
398 | unsigned int present; | 401 | unsigned int present; |
399 | present = snd_hda_codec_read(codec, nid, 0, | 402 | present = snd_hda_jack_detect(codec, nid); |
400 | AC_VERB_GET_PIN_SENSE, 0) & | ||
401 | AC_PINSENSE_PRESENCE; | ||
402 | 403 | ||
403 | present = (present) ? jacks->type : 0 ; | 404 | present = (present) ? jacks->type : 0 ; |
404 | 405 | ||
@@ -477,6 +478,7 @@ static void conexant_free(struct hda_codec *codec) | |||
477 | snd_array_free(&spec->jacks); | 478 | snd_array_free(&spec->jacks); |
478 | } | 479 | } |
479 | #endif | 480 | #endif |
481 | snd_hda_detach_beep_device(codec); | ||
480 | kfree(codec->spec); | 482 | kfree(codec->spec); |
481 | } | 483 | } |
482 | 484 | ||
@@ -749,8 +751,7 @@ static void cxt5045_hp_automic(struct hda_codec *codec) | |||
749 | }; | 751 | }; |
750 | unsigned int present; | 752 | unsigned int present; |
751 | 753 | ||
752 | present = snd_hda_codec_read(codec, 0x12, 0, | 754 | present = snd_hda_jack_detect(codec, 0x12); |
753 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
754 | if (present) | 755 | if (present) |
755 | snd_hda_sequence_write(codec, mic_jack_on); | 756 | snd_hda_sequence_write(codec, mic_jack_on); |
756 | else | 757 | else |
@@ -764,8 +765,7 @@ static void cxt5045_hp_automute(struct hda_codec *codec) | |||
764 | struct conexant_spec *spec = codec->spec; | 765 | struct conexant_spec *spec = codec->spec; |
765 | unsigned int bits; | 766 | unsigned int bits; |
766 | 767 | ||
767 | spec->hp_present = snd_hda_codec_read(codec, 0x11, 0, | 768 | spec->hp_present = snd_hda_jack_detect(codec, 0x11); |
768 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
769 | 769 | ||
770 | bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; | 770 | bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; |
771 | snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, | 771 | snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, |
@@ -1174,9 +1174,10 @@ static int patch_cxt5045(struct hda_codec *codec) | |||
1174 | 1174 | ||
1175 | switch (codec->subsystem_id >> 16) { | 1175 | switch (codec->subsystem_id >> 16) { |
1176 | case 0x103c: | 1176 | case 0x103c: |
1177 | /* HP laptop has a really bad sound over 0dB on NID 0x17. | 1177 | case 0x1734: |
1178 | * Fix max PCM level to 0 dB | 1178 | /* HP & Fujitsu-Siemens laptops have really bad sound over 0dB |
1179 | * (originall it has 0x2b steps with 0dB offset 0x14) | 1179 | * on NID 0x17. Fix max PCM level to 0 dB |
1180 | * (originally it has 0x2b steps with 0dB offset 0x14) | ||
1180 | */ | 1181 | */ |
1181 | snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, | 1182 | snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, |
1182 | (0x14 << AC_AMPCAP_OFFSET_SHIFT) | | 1183 | (0x14 << AC_AMPCAP_OFFSET_SHIFT) | |
@@ -1242,8 +1243,7 @@ static void cxt5047_hp_automute(struct hda_codec *codec) | |||
1242 | struct conexant_spec *spec = codec->spec; | 1243 | struct conexant_spec *spec = codec->spec; |
1243 | unsigned int bits; | 1244 | unsigned int bits; |
1244 | 1245 | ||
1245 | spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, | 1246 | spec->hp_present = snd_hda_jack_detect(codec, 0x13); |
1246 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1247 | 1247 | ||
1248 | bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; | 1248 | bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; |
1249 | /* See the note in cxt5047_hp_master_sw_put */ | 1249 | /* See the note in cxt5047_hp_master_sw_put */ |
@@ -1266,8 +1266,7 @@ static void cxt5047_hp_automic(struct hda_codec *codec) | |||
1266 | }; | 1266 | }; |
1267 | unsigned int present; | 1267 | unsigned int present; |
1268 | 1268 | ||
1269 | present = snd_hda_codec_read(codec, 0x15, 0, | 1269 | present = snd_hda_jack_detect(codec, 0x15); |
1270 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
1271 | if (present) | 1270 | if (present) |
1272 | snd_hda_sequence_write(codec, mic_jack_on); | 1271 | snd_hda_sequence_write(codec, mic_jack_on); |
1273 | else | 1272 | else |
@@ -1414,16 +1413,7 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { | |||
1414 | .get = conexant_mux_enum_get, | 1413 | .get = conexant_mux_enum_get, |
1415 | .put = conexant_mux_enum_put, | 1414 | .put = conexant_mux_enum_put, |
1416 | }, | 1415 | }, |
1417 | HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT), | 1416 | HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), |
1418 | HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT), | ||
1419 | HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT), | ||
1420 | HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT), | ||
1421 | HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT), | ||
1422 | HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT), | ||
1423 | HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT), | ||
1424 | HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT), | ||
1425 | HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT), | ||
1426 | HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT), | ||
1427 | 1417 | ||
1428 | { } /* end */ | 1418 | { } /* end */ |
1429 | }; | 1419 | }; |
@@ -1620,9 +1610,7 @@ static void cxt5051_portb_automic(struct hda_codec *codec) | |||
1620 | 1610 | ||
1621 | if (spec->no_auto_mic) | 1611 | if (spec->no_auto_mic) |
1622 | return; | 1612 | return; |
1623 | present = snd_hda_codec_read(codec, 0x17, 0, | 1613 | present = snd_hda_jack_detect(codec, 0x17); |
1624 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1625 | AC_PINSENSE_PRESENCE; | ||
1626 | snd_hda_codec_write(codec, 0x14, 0, | 1614 | snd_hda_codec_write(codec, 0x14, 0, |
1627 | AC_VERB_SET_CONNECT_SEL, | 1615 | AC_VERB_SET_CONNECT_SEL, |
1628 | present ? 0x01 : 0x00); | 1616 | present ? 0x01 : 0x00); |
@@ -1637,9 +1625,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec) | |||
1637 | 1625 | ||
1638 | if (spec->no_auto_mic) | 1626 | if (spec->no_auto_mic) |
1639 | return; | 1627 | return; |
1640 | present = snd_hda_codec_read(codec, 0x18, 0, | 1628 | present = snd_hda_jack_detect(codec, 0x18); |
1641 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1642 | AC_PINSENSE_PRESENCE; | ||
1643 | if (present) | 1629 | if (present) |
1644 | spec->cur_adc_idx = 1; | 1630 | spec->cur_adc_idx = 1; |
1645 | else | 1631 | else |
@@ -1660,9 +1646,7 @@ static void cxt5051_hp_automute(struct hda_codec *codec) | |||
1660 | { | 1646 | { |
1661 | struct conexant_spec *spec = codec->spec; | 1647 | struct conexant_spec *spec = codec->spec; |
1662 | 1648 | ||
1663 | spec->hp_present = snd_hda_codec_read(codec, 0x16, 0, | 1649 | spec->hp_present = snd_hda_jack_detect(codec, 0x16); |
1664 | AC_VERB_GET_PIN_SENSE, 0) & | ||
1665 | AC_PINSENSE_PRESENCE; | ||
1666 | cxt5051_update_speaker(codec); | 1650 | cxt5051_update_speaker(codec); |
1667 | } | 1651 | } |
1668 | 1652 | ||
@@ -1927,6 +1911,11 @@ static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; | |||
1927 | static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; | 1911 | static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; |
1928 | #define CXT5066_SPDIF_OUT 0x21 | 1912 | #define CXT5066_SPDIF_OUT 0x21 |
1929 | 1913 | ||
1914 | /* OLPC's microphone port is DC coupled for use with external sensors, | ||
1915 | * therefore we use a 50% mic bias in order to center the input signal with | ||
1916 | * the DC input range of the codec. */ | ||
1917 | #define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 | ||
1918 | |||
1930 | static struct hda_channel_mode cxt5066_modes[1] = { | 1919 | static struct hda_channel_mode cxt5066_modes[1] = { |
1931 | { 2, NULL }, | 1920 | { 2, NULL }, |
1932 | }; | 1921 | }; |
@@ -1980,9 +1969,10 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
1980 | /* toggle input of built-in and mic jack appropriately */ | 1969 | /* toggle input of built-in and mic jack appropriately */ |
1981 | static void cxt5066_automic(struct hda_codec *codec) | 1970 | static void cxt5066_automic(struct hda_codec *codec) |
1982 | { | 1971 | { |
1983 | static struct hda_verb ext_mic_present[] = { | 1972 | struct conexant_spec *spec = codec->spec; |
1973 | struct hda_verb ext_mic_present[] = { | ||
1984 | /* enable external mic, port B */ | 1974 | /* enable external mic, port B */ |
1985 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 1975 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, |
1986 | 1976 | ||
1987 | /* switch to external mic input */ | 1977 | /* switch to external mic input */ |
1988 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 1978 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, |
@@ -2004,8 +1994,47 @@ static void cxt5066_automic(struct hda_codec *codec) | |||
2004 | }; | 1994 | }; |
2005 | unsigned int present; | 1995 | unsigned int present; |
2006 | 1996 | ||
2007 | present = snd_hda_codec_read(codec, 0x1a, 0, | 1997 | present = snd_hda_jack_detect(codec, 0x1a); |
2008 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1998 | if (present) { |
1999 | snd_printdd("CXT5066: external microphone detected\n"); | ||
2000 | snd_hda_sequence_write(codec, ext_mic_present); | ||
2001 | } else { | ||
2002 | snd_printdd("CXT5066: external microphone absent\n"); | ||
2003 | snd_hda_sequence_write(codec, ext_mic_absent); | ||
2004 | } | ||
2005 | } | ||
2006 | |||
2007 | /* toggle input of built-in digital mic and mic jack appropriately */ | ||
2008 | static void cxt5066_vostro_automic(struct hda_codec *codec) | ||
2009 | { | ||
2010 | struct conexant_spec *spec = codec->spec; | ||
2011 | unsigned int present; | ||
2012 | |||
2013 | struct hda_verb ext_mic_present[] = { | ||
2014 | /* enable external mic, port B */ | ||
2015 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, | ||
2016 | |||
2017 | /* switch to external mic input */ | ||
2018 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | ||
2019 | {0x14, AC_VERB_SET_CONNECT_SEL, 0}, | ||
2020 | |||
2021 | /* disable internal digital mic */ | ||
2022 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2023 | {} | ||
2024 | }; | ||
2025 | static struct hda_verb ext_mic_absent[] = { | ||
2026 | /* enable internal mic, port C */ | ||
2027 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2028 | |||
2029 | /* switch to internal mic input */ | ||
2030 | {0x14, AC_VERB_SET_CONNECT_SEL, 2}, | ||
2031 | |||
2032 | /* disable external mic, port B */ | ||
2033 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2034 | {} | ||
2035 | }; | ||
2036 | |||
2037 | present = snd_hda_jack_detect(codec, 0x1a); | ||
2009 | if (present) { | 2038 | if (present) { |
2010 | snd_printdd("CXT5066: external microphone detected\n"); | 2039 | snd_printdd("CXT5066: external microphone detected\n"); |
2011 | snd_hda_sequence_write(codec, ext_mic_present); | 2040 | snd_hda_sequence_write(codec, ext_mic_present); |
@@ -2022,12 +2051,10 @@ static void cxt5066_hp_automute(struct hda_codec *codec) | |||
2022 | unsigned int portA, portD; | 2051 | unsigned int portA, portD; |
2023 | 2052 | ||
2024 | /* Port A */ | 2053 | /* Port A */ |
2025 | portA = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0) | 2054 | portA = snd_hda_jack_detect(codec, 0x19); |
2026 | & AC_PINSENSE_PRESENCE; | ||
2027 | 2055 | ||
2028 | /* Port D */ | 2056 | /* Port D */ |
2029 | portD = (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) | 2057 | portD = snd_hda_jack_detect(codec, 0x1c); |
2030 | & AC_PINSENSE_PRESENCE) << 1; | ||
2031 | 2058 | ||
2032 | spec->hp_present = !!(portA | portD); | 2059 | spec->hp_present = !!(portA | portD); |
2033 | snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", | 2060 | snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", |
@@ -2049,6 +2076,20 @@ static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) | |||
2049 | } | 2076 | } |
2050 | } | 2077 | } |
2051 | 2078 | ||
2079 | /* unsolicited event for jack sensing */ | ||
2080 | static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res) | ||
2081 | { | ||
2082 | snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26); | ||
2083 | switch (res >> 26) { | ||
2084 | case CONEXANT_HP_EVENT: | ||
2085 | cxt5066_hp_automute(codec); | ||
2086 | break; | ||
2087 | case CONEXANT_MIC_EVENT: | ||
2088 | cxt5066_vostro_automic(codec); | ||
2089 | break; | ||
2090 | } | ||
2091 | } | ||
2092 | |||
2052 | static const struct hda_input_mux cxt5066_analog_mic_boost = { | 2093 | static const struct hda_input_mux cxt5066_analog_mic_boost = { |
2053 | .num_items = 5, | 2094 | .num_items = 5, |
2054 | .items = { | 2095 | .items = { |
@@ -2071,9 +2112,12 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, | |||
2071 | { | 2112 | { |
2072 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2113 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2073 | int val; | 2114 | int val; |
2115 | hda_nid_t nid = kcontrol->private_value & 0xff; | ||
2116 | int inout = (kcontrol->private_value & 0x100) ? | ||
2117 | AC_AMP_GET_INPUT : AC_AMP_GET_OUTPUT; | ||
2074 | 2118 | ||
2075 | val = snd_hda_codec_read(codec, 0x17, 0, | 2119 | val = snd_hda_codec_read(codec, nid, 0, |
2076 | AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_OUTPUT); | 2120 | AC_VERB_GET_AMP_GAIN_MUTE, inout); |
2077 | 2121 | ||
2078 | ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; | 2122 | ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; |
2079 | return 0; | 2123 | return 0; |
@@ -2085,6 +2129,9 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
2085 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2129 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2086 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | 2130 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; |
2087 | unsigned int idx; | 2131 | unsigned int idx; |
2132 | hda_nid_t nid = kcontrol->private_value & 0xff; | ||
2133 | int inout = (kcontrol->private_value & 0x100) ? | ||
2134 | AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT; | ||
2088 | 2135 | ||
2089 | if (!imux->num_items) | 2136 | if (!imux->num_items) |
2090 | return 0; | 2137 | return 0; |
@@ -2092,9 +2139,9 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
2092 | if (idx >= imux->num_items) | 2139 | if (idx >= imux->num_items) |
2093 | idx = imux->num_items - 1; | 2140 | idx = imux->num_items - 1; |
2094 | 2141 | ||
2095 | snd_hda_codec_write_cache(codec, 0x17, 0, | 2142 | snd_hda_codec_write_cache(codec, nid, 0, |
2096 | AC_VERB_SET_AMP_GAIN_MUTE, | 2143 | AC_VERB_SET_AMP_GAIN_MUTE, |
2097 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | | 2144 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout | |
2098 | imux->items[idx].index); | 2145 | imux->items[idx].index); |
2099 | 2146 | ||
2100 | return 1; | 2147 | return 1; |
@@ -2163,10 +2210,11 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { | |||
2163 | 2210 | ||
2164 | { | 2211 | { |
2165 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2212 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2166 | .name = "Analog Mic Boost Capture Enum", | 2213 | .name = "Ext Mic Boost Capture Enum", |
2167 | .info = cxt5066_mic_boost_mux_enum_info, | 2214 | .info = cxt5066_mic_boost_mux_enum_info, |
2168 | .get = cxt5066_mic_boost_mux_enum_get, | 2215 | .get = cxt5066_mic_boost_mux_enum_get, |
2169 | .put = cxt5066_mic_boost_mux_enum_put, | 2216 | .put = cxt5066_mic_boost_mux_enum_put, |
2217 | .private_value = 0x17, | ||
2170 | }, | 2218 | }, |
2171 | 2219 | ||
2172 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), | 2220 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), |
@@ -2174,6 +2222,19 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { | |||
2174 | {} | 2222 | {} |
2175 | }; | 2223 | }; |
2176 | 2224 | ||
2225 | static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { | ||
2226 | { | ||
2227 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2228 | .name = "Int Mic Boost Capture Enum", | ||
2229 | .info = cxt5066_mic_boost_mux_enum_info, | ||
2230 | .get = cxt5066_mic_boost_mux_enum_get, | ||
2231 | .put = cxt5066_mic_boost_mux_enum_put, | ||
2232 | .private_value = 0x23 | 0x100, | ||
2233 | }, | ||
2234 | HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), | ||
2235 | {} | ||
2236 | }; | ||
2237 | |||
2177 | static struct hda_verb cxt5066_init_verbs[] = { | 2238 | static struct hda_verb cxt5066_init_verbs[] = { |
2178 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ | 2239 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ |
2179 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ | 2240 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ |
@@ -2235,7 +2296,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2235 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2296 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
2236 | 2297 | ||
2237 | /* Port B: external microphone */ | 2298 | /* Port B: external microphone */ |
2238 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2299 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, |
2239 | 2300 | ||
2240 | /* Port C: internal microphone */ | 2301 | /* Port C: internal microphone */ |
2241 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2302 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
@@ -2290,6 +2351,67 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
2290 | { } /* end */ | 2351 | { } /* end */ |
2291 | }; | 2352 | }; |
2292 | 2353 | ||
2354 | static struct hda_verb cxt5066_init_verbs_vostro[] = { | ||
2355 | /* Port A: headphones */ | ||
2356 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2357 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2358 | |||
2359 | /* Port B: external microphone */ | ||
2360 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2361 | |||
2362 | /* Port C: unused */ | ||
2363 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2364 | |||
2365 | /* Port D: unused */ | ||
2366 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2367 | |||
2368 | /* Port E: unused, but has primary EAPD */ | ||
2369 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2370 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
2371 | |||
2372 | /* Port F: unused */ | ||
2373 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2374 | |||
2375 | /* Port G: internal speakers */ | ||
2376 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2377 | {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2378 | |||
2379 | /* DAC1 */ | ||
2380 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2381 | |||
2382 | /* DAC2: unused */ | ||
2383 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2384 | |||
2385 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2386 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2387 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2388 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2389 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2390 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2391 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2392 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2393 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2394 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2395 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2396 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2397 | |||
2398 | /* Digital microphone port */ | ||
2399 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
2400 | |||
2401 | /* Audio input selectors */ | ||
2402 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, | ||
2403 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2404 | |||
2405 | /* Disable SPDIF */ | ||
2406 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2407 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2408 | |||
2409 | /* enable unsolicited events for Port A and B */ | ||
2410 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
2411 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||
2412 | { } /* end */ | ||
2413 | }; | ||
2414 | |||
2293 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | 2415 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { |
2294 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 2416 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
2295 | { } /* end */ | 2417 | { } /* end */ |
@@ -2298,11 +2420,16 @@ static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | |||
2298 | /* initialize jack-sensing, too */ | 2420 | /* initialize jack-sensing, too */ |
2299 | static int cxt5066_init(struct hda_codec *codec) | 2421 | static int cxt5066_init(struct hda_codec *codec) |
2300 | { | 2422 | { |
2423 | struct conexant_spec *spec = codec->spec; | ||
2424 | |||
2301 | snd_printdd("CXT5066: init\n"); | 2425 | snd_printdd("CXT5066: init\n"); |
2302 | conexant_init(codec); | 2426 | conexant_init(codec); |
2303 | if (codec->patch_ops.unsol_event) { | 2427 | if (codec->patch_ops.unsol_event) { |
2304 | cxt5066_hp_automute(codec); | 2428 | cxt5066_hp_automute(codec); |
2305 | cxt5066_automic(codec); | 2429 | if (spec->dell_vostro) |
2430 | cxt5066_vostro_automic(codec); | ||
2431 | else | ||
2432 | cxt5066_automic(codec); | ||
2306 | } | 2433 | } |
2307 | return 0; | 2434 | return 0; |
2308 | } | 2435 | } |
@@ -2311,6 +2438,7 @@ enum { | |||
2311 | CXT5066_LAPTOP, /* Laptops w/ EAPD support */ | 2438 | CXT5066_LAPTOP, /* Laptops w/ EAPD support */ |
2312 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ | 2439 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ |
2313 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ | 2440 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ |
2441 | CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ | ||
2314 | CXT5066_MODELS | 2442 | CXT5066_MODELS |
2315 | }; | 2443 | }; |
2316 | 2444 | ||
@@ -2318,6 +2446,7 @@ static const char *cxt5066_models[CXT5066_MODELS] = { | |||
2318 | [CXT5066_LAPTOP] = "laptop", | 2446 | [CXT5066_LAPTOP] = "laptop", |
2319 | [CXT5066_DELL_LAPTOP] = "dell-laptop", | 2447 | [CXT5066_DELL_LAPTOP] = "dell-laptop", |
2320 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", | 2448 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", |
2449 | [CXT5066_DELL_VOSTO] = "dell-vostro" | ||
2321 | }; | 2450 | }; |
2322 | 2451 | ||
2323 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | 2452 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { |
@@ -2325,6 +2454,8 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | |||
2325 | CXT5066_LAPTOP), | 2454 | CXT5066_LAPTOP), |
2326 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", | 2455 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", |
2327 | CXT5066_DELL_LAPTOP), | 2456 | CXT5066_DELL_LAPTOP), |
2457 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), | ||
2458 | SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), | ||
2328 | {} | 2459 | {} |
2329 | }; | 2460 | }; |
2330 | 2461 | ||
@@ -2352,6 +2483,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2352 | spec->input_mux = &cxt5066_capture_source; | 2483 | spec->input_mux = &cxt5066_capture_source; |
2353 | 2484 | ||
2354 | spec->port_d_mode = PIN_HP; | 2485 | spec->port_d_mode = PIN_HP; |
2486 | spec->ext_mic_bias = PIN_VREF80; | ||
2355 | 2487 | ||
2356 | spec->num_init_verbs = 1; | 2488 | spec->num_init_verbs = 1; |
2357 | spec->init_verbs[0] = cxt5066_init_verbs; | 2489 | spec->init_verbs[0] = cxt5066_init_verbs; |
@@ -2383,6 +2515,23 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
2383 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2515 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
2384 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 2516 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
2385 | spec->port_d_mode = 0; | 2517 | spec->port_d_mode = 0; |
2518 | spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; | ||
2519 | |||
2520 | /* no S/PDIF out */ | ||
2521 | spec->multiout.dig_out_nid = 0; | ||
2522 | |||
2523 | /* input source automatically selected */ | ||
2524 | spec->input_mux = NULL; | ||
2525 | break; | ||
2526 | case CXT5066_DELL_VOSTO: | ||
2527 | codec->patch_ops.unsol_event = cxt5066_vostro_event; | ||
2528 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; | ||
2529 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | ||
2530 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | ||
2531 | spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; | ||
2532 | spec->port_d_mode = 0; | ||
2533 | spec->dell_vostro = 1; | ||
2534 | snd_hda_attach_beep_device(codec, 0x13); | ||
2386 | 2535 | ||
2387 | /* no S/PDIF out */ | 2536 | /* no S/PDIF out */ |
2388 | spec->multiout.dig_out_nid = 0; | 2537 | spec->multiout.dig_out_nid = 0; |
@@ -2407,6 +2556,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { | |||
2407 | .patch = patch_cxt5051 }, | 2556 | .patch = patch_cxt5051 }, |
2408 | { .id = 0x14f15066, .name = "CX20582 (Pebble)", | 2557 | { .id = 0x14f15066, .name = "CX20582 (Pebble)", |
2409 | .patch = patch_cxt5066 }, | 2558 | .patch = patch_cxt5066 }, |
2559 | { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", | ||
2560 | .patch = patch_cxt5066 }, | ||
2410 | {} /* terminator */ | 2561 | {} /* terminator */ |
2411 | }; | 2562 | }; |
2412 | 2563 | ||
@@ -2414,6 +2565,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15045"); | |||
2414 | MODULE_ALIAS("snd-hda-codec-id:14f15047"); | 2565 | MODULE_ALIAS("snd-hda-codec-id:14f15047"); |
2415 | MODULE_ALIAS("snd-hda-codec-id:14f15051"); | 2566 | MODULE_ALIAS("snd-hda-codec-id:14f15051"); |
2416 | MODULE_ALIAS("snd-hda-codec-id:14f15066"); | 2567 | MODULE_ALIAS("snd-hda-codec-id:14f15066"); |
2568 | MODULE_ALIAS("snd-hda-codec-id:14f15067"); | ||
2417 | 2569 | ||
2418 | MODULE_LICENSE("GPL"); | 2570 | MODULE_LICENSE("GPL"); |
2419 | MODULE_DESCRIPTION("Conexant HD-audio codec"); | 2571 | MODULE_DESCRIPTION("Conexant HD-audio codec"); |