diff options
author | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-10-06 11:01:27 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2009-10-06 11:01:27 -0400 |
commit | 907bc6c7fc7071b00083fc11e510e47dd93df45d (patch) | |
tree | 0697a608561522c00da9e1814974a2eb051bb96d /sound/pci/hda/patch_conexant.c | |
parent | d2b247a8be57647d1745535acd58169fbcbe431a (diff) | |
parent | 2a0f5cb32772e9a9560209e241a80bfbbc31dbc3 (diff) |
Merge branch 'for-2.6.32' into for-2.6.33
Diffstat (limited to 'sound/pci/hda/patch_conexant.c')
-rw-r--r-- | sound/pci/hda/patch_conexant.c | 491 |
1 files changed, 490 insertions, 1 deletions
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ac868c59f9e3..3fbbc8c01e70 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -108,6 +108,8 @@ struct conexant_spec { | |||
108 | struct hda_input_mux private_imux; | 108 | struct hda_input_mux private_imux; |
109 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; | 109 | hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; |
110 | 110 | ||
111 | unsigned int dell_automute; | ||
112 | unsigned int port_d_mode; | ||
111 | }; | 113 | }; |
112 | 114 | ||
113 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | 115 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, |
@@ -680,11 +682,13 @@ static struct hda_input_mux cxt5045_capture_source = { | |||
680 | }; | 682 | }; |
681 | 683 | ||
682 | static struct hda_input_mux cxt5045_capture_source_benq = { | 684 | static struct hda_input_mux cxt5045_capture_source_benq = { |
683 | .num_items = 3, | 685 | .num_items = 5, |
684 | .items = { | 686 | .items = { |
685 | { "IntMic", 0x1 }, | 687 | { "IntMic", 0x1 }, |
686 | { "ExtMic", 0x2 }, | 688 | { "ExtMic", 0x2 }, |
687 | { "LineIn", 0x3 }, | 689 | { "LineIn", 0x3 }, |
690 | { "CD", 0x4 }, | ||
691 | { "Mixer", 0x0 }, | ||
688 | } | 692 | } |
689 | }; | 693 | }; |
690 | 694 | ||
@@ -809,11 +813,19 @@ static struct snd_kcontrol_new cxt5045_mixers[] = { | |||
809 | }; | 813 | }; |
810 | 814 | ||
811 | static struct snd_kcontrol_new cxt5045_benq_mixers[] = { | 815 | static struct snd_kcontrol_new cxt5045_benq_mixers[] = { |
816 | HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT), | ||
817 | HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT), | ||
818 | HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), | ||
819 | HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x4, HDA_INPUT), | ||
820 | |||
812 | HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT), | 821 | HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT), |
813 | HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT), | 822 | HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT), |
814 | HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT), | 823 | HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT), |
815 | HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT), | 824 | HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT), |
816 | 825 | ||
826 | HDA_CODEC_VOLUME("Mixer Capture Volume", 0x1a, 0x0, HDA_INPUT), | ||
827 | HDA_CODEC_MUTE("Mixer Capture Switch", 0x1a, 0x0, HDA_INPUT), | ||
828 | |||
817 | {} | 829 | {} |
818 | }; | 830 | }; |
819 | 831 | ||
@@ -1908,6 +1920,480 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
1908 | return 0; | 1920 | return 0; |
1909 | } | 1921 | } |
1910 | 1922 | ||
1923 | /* Conexant 5066 specific */ | ||
1924 | |||
1925 | static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; | ||
1926 | static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; | ||
1927 | static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; | ||
1928 | #define CXT5066_SPDIF_OUT 0x21 | ||
1929 | |||
1930 | static struct hda_channel_mode cxt5066_modes[1] = { | ||
1931 | { 2, NULL }, | ||
1932 | }; | ||
1933 | |||
1934 | static void cxt5066_update_speaker(struct hda_codec *codec) | ||
1935 | { | ||
1936 | struct conexant_spec *spec = codec->spec; | ||
1937 | unsigned int pinctl; | ||
1938 | |||
1939 | snd_printdd("CXT5066: update speaker, hp_present=%d\n", | ||
1940 | spec->hp_present); | ||
1941 | |||
1942 | /* Port A (HP) */ | ||
1943 | pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0; | ||
1944 | snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1945 | pinctl); | ||
1946 | |||
1947 | /* Port D (HP/LO) */ | ||
1948 | pinctl = ((spec->hp_present & 2) && spec->cur_eapd) | ||
1949 | ? spec->port_d_mode : 0; | ||
1950 | snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1951 | pinctl); | ||
1952 | |||
1953 | /* CLASS_D AMP */ | ||
1954 | pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; | ||
1955 | snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
1956 | pinctl); | ||
1957 | |||
1958 | if (spec->dell_automute) { | ||
1959 | /* DELL AIO Port Rule: PortA > PortD > IntSpk */ | ||
1960 | pinctl = (!(spec->hp_present & 1) && spec->cur_eapd) | ||
1961 | ? PIN_OUT : 0; | ||
1962 | snd_hda_codec_write(codec, 0x1c, 0, | ||
1963 | AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); | ||
1964 | } | ||
1965 | } | ||
1966 | |||
1967 | /* turn on/off EAPD (+ mute HP) as a master switch */ | ||
1968 | static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, | ||
1969 | struct snd_ctl_elem_value *ucontrol) | ||
1970 | { | ||
1971 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1972 | |||
1973 | if (!cxt_eapd_put(kcontrol, ucontrol)) | ||
1974 | return 0; | ||
1975 | |||
1976 | cxt5066_update_speaker(codec); | ||
1977 | return 1; | ||
1978 | } | ||
1979 | |||
1980 | /* toggle input of built-in and mic jack appropriately */ | ||
1981 | static void cxt5066_automic(struct hda_codec *codec) | ||
1982 | { | ||
1983 | static struct hda_verb ext_mic_present[] = { | ||
1984 | /* enable external mic, port B */ | ||
1985 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1986 | |||
1987 | /* switch to external mic input */ | ||
1988 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | ||
1989 | |||
1990 | /* disable internal mic, port C */ | ||
1991 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
1992 | {} | ||
1993 | }; | ||
1994 | static struct hda_verb ext_mic_absent[] = { | ||
1995 | /* enable internal mic, port C */ | ||
1996 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
1997 | |||
1998 | /* switch to internal mic input */ | ||
1999 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, | ||
2000 | |||
2001 | /* disable external mic, port B */ | ||
2002 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2003 | {} | ||
2004 | }; | ||
2005 | unsigned int present; | ||
2006 | |||
2007 | present = snd_hda_codec_read(codec, 0x1a, 0, | ||
2008 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
2009 | if (present) { | ||
2010 | snd_printdd("CXT5066: external microphone detected\n"); | ||
2011 | snd_hda_sequence_write(codec, ext_mic_present); | ||
2012 | } else { | ||
2013 | snd_printdd("CXT5066: external microphone absent\n"); | ||
2014 | snd_hda_sequence_write(codec, ext_mic_absent); | ||
2015 | } | ||
2016 | } | ||
2017 | |||
2018 | /* mute internal speaker if HP is plugged */ | ||
2019 | static void cxt5066_hp_automute(struct hda_codec *codec) | ||
2020 | { | ||
2021 | struct conexant_spec *spec = codec->spec; | ||
2022 | unsigned int portA, portD; | ||
2023 | |||
2024 | /* Port A */ | ||
2025 | portA = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0) | ||
2026 | & AC_PINSENSE_PRESENCE; | ||
2027 | |||
2028 | /* Port D */ | ||
2029 | portD = (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) | ||
2030 | & AC_PINSENSE_PRESENCE) << 1; | ||
2031 | |||
2032 | spec->hp_present = !!(portA | portD); | ||
2033 | snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", | ||
2034 | portA, portD, spec->hp_present); | ||
2035 | cxt5066_update_speaker(codec); | ||
2036 | } | ||
2037 | |||
2038 | /* unsolicited event for jack sensing */ | ||
2039 | static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) | ||
2040 | { | ||
2041 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); | ||
2042 | switch (res >> 26) { | ||
2043 | case CONEXANT_HP_EVENT: | ||
2044 | cxt5066_hp_automute(codec); | ||
2045 | break; | ||
2046 | case CONEXANT_MIC_EVENT: | ||
2047 | cxt5066_automic(codec); | ||
2048 | break; | ||
2049 | } | ||
2050 | } | ||
2051 | |||
2052 | static const struct hda_input_mux cxt5066_analog_mic_boost = { | ||
2053 | .num_items = 5, | ||
2054 | .items = { | ||
2055 | { "0dB", 0 }, | ||
2056 | { "10dB", 1 }, | ||
2057 | { "20dB", 2 }, | ||
2058 | { "30dB", 3 }, | ||
2059 | { "40dB", 4 }, | ||
2060 | }, | ||
2061 | }; | ||
2062 | |||
2063 | static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, | ||
2064 | struct snd_ctl_elem_info *uinfo) | ||
2065 | { | ||
2066 | return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo); | ||
2067 | } | ||
2068 | |||
2069 | static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, | ||
2070 | struct snd_ctl_elem_value *ucontrol) | ||
2071 | { | ||
2072 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2073 | int val; | ||
2074 | |||
2075 | val = snd_hda_codec_read(codec, 0x17, 0, | ||
2076 | AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_OUTPUT); | ||
2077 | |||
2078 | ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; | ||
2079 | return 0; | ||
2080 | } | ||
2081 | |||
2082 | static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, | ||
2083 | struct snd_ctl_elem_value *ucontrol) | ||
2084 | { | ||
2085 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2086 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | ||
2087 | unsigned int idx; | ||
2088 | |||
2089 | if (!imux->num_items) | ||
2090 | return 0; | ||
2091 | idx = ucontrol->value.enumerated.item[0]; | ||
2092 | if (idx >= imux->num_items) | ||
2093 | idx = imux->num_items - 1; | ||
2094 | |||
2095 | snd_hda_codec_write_cache(codec, 0x17, 0, | ||
2096 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
2097 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | | ||
2098 | imux->items[idx].index); | ||
2099 | |||
2100 | return 1; | ||
2101 | } | ||
2102 | |||
2103 | static struct hda_input_mux cxt5066_capture_source = { | ||
2104 | .num_items = 4, | ||
2105 | .items = { | ||
2106 | { "Mic B", 0 }, | ||
2107 | { "Mic C", 1 }, | ||
2108 | { "Mic E", 2 }, | ||
2109 | { "Mic F", 3 }, | ||
2110 | }, | ||
2111 | }; | ||
2112 | |||
2113 | static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { | ||
2114 | .ops = &snd_hda_bind_vol, | ||
2115 | .values = { | ||
2116 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), | ||
2117 | HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), | ||
2118 | 0 | ||
2119 | }, | ||
2120 | }; | ||
2121 | |||
2122 | static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { | ||
2123 | .ops = &snd_hda_bind_sw, | ||
2124 | .values = { | ||
2125 | HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), | ||
2126 | HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), | ||
2127 | 0 | ||
2128 | }, | ||
2129 | }; | ||
2130 | |||
2131 | static struct snd_kcontrol_new cxt5066_mixer_master[] = { | ||
2132 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
2133 | {} | ||
2134 | }; | ||
2135 | |||
2136 | static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | ||
2137 | { | ||
2138 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2139 | .name = "Master Playback Volume", | ||
2140 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
2141 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | ||
2142 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | ||
2143 | .info = snd_hda_mixer_amp_volume_info, | ||
2144 | .get = snd_hda_mixer_amp_volume_get, | ||
2145 | .put = snd_hda_mixer_amp_volume_put, | ||
2146 | .tlv = { .c = snd_hda_mixer_amp_tlv }, | ||
2147 | /* offset by 28 volume steps to limit minimum gain to -46dB */ | ||
2148 | .private_value = | ||
2149 | HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28), | ||
2150 | }, | ||
2151 | {} | ||
2152 | }; | ||
2153 | |||
2154 | static struct snd_kcontrol_new cxt5066_mixers[] = { | ||
2155 | { | ||
2156 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2157 | .name = "Master Playback Switch", | ||
2158 | .info = cxt_eapd_info, | ||
2159 | .get = cxt_eapd_get, | ||
2160 | .put = cxt5066_hp_master_sw_put, | ||
2161 | .private_value = 0x1d, | ||
2162 | }, | ||
2163 | |||
2164 | { | ||
2165 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
2166 | .name = "Analog Mic Boost Capture Enum", | ||
2167 | .info = cxt5066_mic_boost_mux_enum_info, | ||
2168 | .get = cxt5066_mic_boost_mux_enum_get, | ||
2169 | .put = cxt5066_mic_boost_mux_enum_put, | ||
2170 | }, | ||
2171 | |||
2172 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), | ||
2173 | HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others), | ||
2174 | {} | ||
2175 | }; | ||
2176 | |||
2177 | static struct hda_verb cxt5066_init_verbs[] = { | ||
2178 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ | ||
2179 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ | ||
2180 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ | ||
2181 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ | ||
2182 | |||
2183 | /* Speakers */ | ||
2184 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2185 | {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2186 | |||
2187 | /* HP, Amp */ | ||
2188 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2189 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2190 | |||
2191 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2192 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2193 | |||
2194 | /* DAC1 */ | ||
2195 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2196 | |||
2197 | /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ | ||
2198 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, | ||
2199 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2200 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, | ||
2201 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2202 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
2203 | |||
2204 | /* no digital microphone support yet */ | ||
2205 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2206 | |||
2207 | /* Audio input selector */ | ||
2208 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, | ||
2209 | |||
2210 | /* SPDIF route: PCM */ | ||
2211 | {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2212 | {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
2213 | |||
2214 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2215 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2216 | |||
2217 | /* EAPD */ | ||
2218 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
2219 | |||
2220 | /* not handling these yet */ | ||
2221 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, | ||
2222 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, | ||
2223 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, | ||
2224 | {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, | ||
2225 | {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, | ||
2226 | {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, | ||
2227 | {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, | ||
2228 | {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, | ||
2229 | { } /* end */ | ||
2230 | }; | ||
2231 | |||
2232 | static struct hda_verb cxt5066_init_verbs_olpc[] = { | ||
2233 | /* Port A: headphones */ | ||
2234 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
2235 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2236 | |||
2237 | /* Port B: external microphone */ | ||
2238 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2239 | |||
2240 | /* Port C: internal microphone */ | ||
2241 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
2242 | |||
2243 | /* Port D: unused */ | ||
2244 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2245 | |||
2246 | /* Port E: unused, but has primary EAPD */ | ||
2247 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2248 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
2249 | |||
2250 | /* Port F: unused */ | ||
2251 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2252 | |||
2253 | /* Port G: internal speakers */ | ||
2254 | {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2255 | {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | ||
2256 | |||
2257 | /* DAC1 */ | ||
2258 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
2259 | |||
2260 | /* DAC2: unused */ | ||
2261 | {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
2262 | |||
2263 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, | ||
2264 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2265 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2266 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2267 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2268 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2269 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2270 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2271 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
2272 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
2273 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
2274 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
2275 | |||
2276 | /* Disable digital microphone port */ | ||
2277 | {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2278 | |||
2279 | /* Audio input selectors */ | ||
2280 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, | ||
2281 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
2282 | |||
2283 | /* Disable SPDIF */ | ||
2284 | {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2285 | {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
2286 | |||
2287 | /* enable unsolicited events for Port A and B */ | ||
2288 | {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, | ||
2289 | {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, | ||
2290 | { } /* end */ | ||
2291 | }; | ||
2292 | |||
2293 | static struct hda_verb cxt5066_init_verbs_portd_lo[] = { | ||
2294 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
2295 | { } /* end */ | ||
2296 | }; | ||
2297 | |||
2298 | /* initialize jack-sensing, too */ | ||
2299 | static int cxt5066_init(struct hda_codec *codec) | ||
2300 | { | ||
2301 | snd_printdd("CXT5066: init\n"); | ||
2302 | conexant_init(codec); | ||
2303 | if (codec->patch_ops.unsol_event) { | ||
2304 | cxt5066_hp_automute(codec); | ||
2305 | cxt5066_automic(codec); | ||
2306 | } | ||
2307 | return 0; | ||
2308 | } | ||
2309 | |||
2310 | enum { | ||
2311 | CXT5066_LAPTOP, /* Laptops w/ EAPD support */ | ||
2312 | CXT5066_DELL_LAPTOP, /* Dell Laptop */ | ||
2313 | CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ | ||
2314 | CXT5066_MODELS | ||
2315 | }; | ||
2316 | |||
2317 | static const char *cxt5066_models[CXT5066_MODELS] = { | ||
2318 | [CXT5066_LAPTOP] = "laptop", | ||
2319 | [CXT5066_DELL_LAPTOP] = "dell-laptop", | ||
2320 | [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", | ||
2321 | }; | ||
2322 | |||
2323 | static struct snd_pci_quirk cxt5066_cfg_tbl[] = { | ||
2324 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | ||
2325 | CXT5066_LAPTOP), | ||
2326 | SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", | ||
2327 | CXT5066_DELL_LAPTOP), | ||
2328 | {} | ||
2329 | }; | ||
2330 | |||
2331 | static int patch_cxt5066(struct hda_codec *codec) | ||
2332 | { | ||
2333 | struct conexant_spec *spec; | ||
2334 | int board_config; | ||
2335 | |||
2336 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
2337 | if (!spec) | ||
2338 | return -ENOMEM; | ||
2339 | codec->spec = spec; | ||
2340 | |||
2341 | codec->patch_ops = conexant_patch_ops; | ||
2342 | codec->patch_ops.init = cxt5066_init; | ||
2343 | |||
2344 | spec->dell_automute = 0; | ||
2345 | spec->multiout.max_channels = 2; | ||
2346 | spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); | ||
2347 | spec->multiout.dac_nids = cxt5066_dac_nids; | ||
2348 | spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT; | ||
2349 | spec->num_adc_nids = 1; | ||
2350 | spec->adc_nids = cxt5066_adc_nids; | ||
2351 | spec->capsrc_nids = cxt5066_capsrc_nids; | ||
2352 | spec->input_mux = &cxt5066_capture_source; | ||
2353 | |||
2354 | spec->port_d_mode = PIN_HP; | ||
2355 | |||
2356 | spec->num_init_verbs = 1; | ||
2357 | spec->init_verbs[0] = cxt5066_init_verbs; | ||
2358 | spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes); | ||
2359 | spec->channel_mode = cxt5066_modes; | ||
2360 | spec->cur_adc = 0; | ||
2361 | spec->cur_adc_idx = 0; | ||
2362 | |||
2363 | board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, | ||
2364 | cxt5066_models, cxt5066_cfg_tbl); | ||
2365 | switch (board_config) { | ||
2366 | default: | ||
2367 | case CXT5066_LAPTOP: | ||
2368 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | ||
2369 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | ||
2370 | break; | ||
2371 | case CXT5066_DELL_LAPTOP: | ||
2372 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; | ||
2373 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | ||
2374 | |||
2375 | spec->port_d_mode = PIN_OUT; | ||
2376 | spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo; | ||
2377 | spec->num_init_verbs++; | ||
2378 | spec->dell_automute = 1; | ||
2379 | break; | ||
2380 | case CXT5066_OLPC_XO_1_5: | ||
2381 | codec->patch_ops.unsol_event = cxt5066_unsol_event; | ||
2382 | spec->init_verbs[0] = cxt5066_init_verbs_olpc; | ||
2383 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | ||
2384 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | ||
2385 | spec->port_d_mode = 0; | ||
2386 | |||
2387 | /* no S/PDIF out */ | ||
2388 | spec->multiout.dig_out_nid = 0; | ||
2389 | |||
2390 | /* input source automatically selected */ | ||
2391 | spec->input_mux = NULL; | ||
2392 | break; | ||
2393 | } | ||
2394 | |||
2395 | return 0; | ||
2396 | } | ||
1911 | 2397 | ||
1912 | /* | 2398 | /* |
1913 | */ | 2399 | */ |
@@ -1919,12 +2405,15 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { | |||
1919 | .patch = patch_cxt5047 }, | 2405 | .patch = patch_cxt5047 }, |
1920 | { .id = 0x14f15051, .name = "CX20561 (Hermosa)", | 2406 | { .id = 0x14f15051, .name = "CX20561 (Hermosa)", |
1921 | .patch = patch_cxt5051 }, | 2407 | .patch = patch_cxt5051 }, |
2408 | { .id = 0x14f15066, .name = "CX20582 (Pebble)", | ||
2409 | .patch = patch_cxt5066 }, | ||
1922 | {} /* terminator */ | 2410 | {} /* terminator */ |
1923 | }; | 2411 | }; |
1924 | 2412 | ||
1925 | MODULE_ALIAS("snd-hda-codec-id:14f15045"); | 2413 | MODULE_ALIAS("snd-hda-codec-id:14f15045"); |
1926 | MODULE_ALIAS("snd-hda-codec-id:14f15047"); | 2414 | MODULE_ALIAS("snd-hda-codec-id:14f15047"); |
1927 | MODULE_ALIAS("snd-hda-codec-id:14f15051"); | 2415 | MODULE_ALIAS("snd-hda-codec-id:14f15051"); |
2416 | MODULE_ALIAS("snd-hda-codec-id:14f15066"); | ||
1928 | 2417 | ||
1929 | MODULE_LICENSE("GPL"); | 2418 | MODULE_LICENSE("GPL"); |
1930 | MODULE_DESCRIPTION("Conexant HD-audio codec"); | 2419 | MODULE_DESCRIPTION("Conexant HD-audio codec"); |