aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_via.c
diff options
context:
space:
mode:
authorHarald Welte <HaraldWelte@viatech.com>2008-09-09 03:56:01 -0400
committerJaroslav Kysela <perex@perex.cz>2008-09-09 12:52:01 -0400
commitd949cac1ea8596f61942437ad741a3fbb412846f (patch)
treee00ff87b5310f19164e253afc60c668e82dbcfa1 /sound/pci/hda/patch_via.c
parentfb4cb772c0b22f7bce0b151ef5712e80d434bc97 (diff)
ALSA: HDA patch_via.c: Add VT1708S and VT1702 support
The VT1702 and VT1708S codecs are new HDA codecs by VIA. This patch adds support for them to the patch_via.c file for HDA Signed-off-by: Harald Welte <HaraldWelte@viatech.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/hda/patch_via.c')
-rw-r--r--sound/pci/hda/patch_via.c762
1 files changed, 758 insertions, 4 deletions
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index bae6273eeb1a..91b72add1a8d 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Universal Interface for Intel High Definition Audio Codec 2 * Universal Interface for Intel High Definition Audio Codec
3 * 3 *
4 * HD audio interface patch for VIA VT1708 codec 4 * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec
5 * 5 *
6 * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com> 6 * Copyright (c) 2006-2008 Lydia Wang <lydiawang@viatech.com>
7 * Takashi Iwai <tiwai@suse.de> 7 * Takashi Iwai <tiwai@suse.de>
@@ -31,6 +31,7 @@
31/* 2007-09-17 Lydia Wang Add VT1708B codec support */ 31/* 2007-09-17 Lydia Wang Add VT1708B codec support */
32/* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ 32/* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */
33/* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ 33/* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */
34/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */
34/* */ 35/* */
35/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 36/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
36 37
@@ -55,8 +56,8 @@
55#define VT1708_DIGOUT_NID 0x14 56#define VT1708_DIGOUT_NID 0x14
56#define VT1708_DIGIN_NID 0x16 57#define VT1708_DIGIN_NID 0x16
57#define VT1708_DIGIN_PIN 0x26 58#define VT1708_DIGIN_PIN 0x26
58#define VT1708_HP_PIN_NID 0x20 59#define VT1708_HP_PIN_NID 0x20
59#define VT1708_CD_PIN_NID 0x24 60#define VT1708_CD_PIN_NID 0x24
60 61
61#define VT1709_HP_DAC_NID 0x28 62#define VT1709_HP_DAC_NID 0x28
62#define VT1709_DIGOUT_NID 0x13 63#define VT1709_DIGOUT_NID 0x13
@@ -68,12 +69,19 @@
68#define VT1708B_DIGIN_NID 0x15 69#define VT1708B_DIGIN_NID 0x15
69#define VT1708B_DIGIN_PIN 0x21 70#define VT1708B_DIGIN_PIN 0x21
70 71
72#define VT1708S_HP_NID 0x25
73#define VT1708S_DIGOUT_NID 0x12
74
75#define VT1702_HP_NID 0x17
76#define VT1702_DIGOUT_NID 0x11
77
71#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) 78#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b)
72#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) 79#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713)
73#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) 80#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717)
74#define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723) 81#define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723)
75#define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727) 82#define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727)
76 83#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397)
84#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398)
77 85
78enum { 86enum {
79 VIA_CTL_WIDGET_VOL, 87 VIA_CTL_WIDGET_VOL,
@@ -150,6 +158,16 @@ static hda_nid_t vt1708B_adc_nids[2] = {
150 0x13, 0x14 158 0x13, 0x14
151}; 159};
152 160
161static hda_nid_t vt1708S_adc_nids[2] = {
162 /* ADC1-2 */
163 0x13, 0x14
164};
165
166static hda_nid_t vt1702_adc_nids[3] = {
167 /* ADC1-2 */
168 0x12, 0x20, 0x1F
169};
170
153/* add dynamic controls */ 171/* add dynamic controls */
154static int via_add_control(struct via_spec *spec, int type, const char *name, 172static int via_add_control(struct via_spec *spec, int type, const char *name,
155 unsigned long val) 173 unsigned long val)
@@ -294,6 +312,9 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol,
294 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0)) 312 IS_VT1708B_4CH_VENDORID(vendor_id)) && (adc_idx == 0))
295 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 313 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
296 0x17, &spec->cur_mux[adc_idx]); 314 0x17, &spec->cur_mux[adc_idx]);
315 else if (IS_VT1702_VENDORID(vendor_id) && (adc_idx == 0))
316 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
317 0x13, &spec->cur_mux[adc_idx]);
297 else 318 else
298 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 319 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
299 spec->adc_nids[adc_idx], 320 spec->adc_nids[adc_idx],
@@ -2011,6 +2032,707 @@ static int patch_vt1708B_4ch(struct hda_codec *codec)
2011 return 0; 2032 return 0;
2012} 2033}
2013 2034
2035/* Patch for VT1708S */
2036
2037/* capture mixer elements */
2038static struct snd_kcontrol_new vt1708S_capture_mixer[] = {
2039 HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT),
2040 HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT),
2041 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT),
2042 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT),
2043 HDA_CODEC_VOLUME("Mic Boost", 0x1A, 0x0, HDA_INPUT),
2044 HDA_CODEC_VOLUME("Front Mic Boost", 0x1E, 0x0, HDA_INPUT),
2045 {
2046 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2047 /* The multiple "Capture Source" controls confuse alsamixer
2048 * So call somewhat different..
2049 */
2050 /* .name = "Capture Source", */
2051 .name = "Input Source",
2052 .count = 1,
2053 .info = via_mux_enum_info,
2054 .get = via_mux_enum_get,
2055 .put = via_mux_enum_put,
2056 },
2057 { } /* end */
2058};
2059
2060static struct hda_verb vt1708S_volume_init_verbs[] = {
2061 /* Unmute ADC0-1 and set the default input to mic-in */
2062 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2063 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2064
2065 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the
2066 * analog-loopback mixer widget */
2067 /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */
2068 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2069 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2070 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2071 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2072 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
2073
2074 /* Setup default input of PW4 to MW0 */
2075 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0},
2076 /* PW9 Output enable */
2077 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2078 { }
2079};
2080
2081static struct hda_pcm_stream vt1708S_pcm_analog_playback = {
2082 .substreams = 2,
2083 .channels_min = 2,
2084 .channels_max = 8,
2085 .nid = 0x10, /* NID to query formats and rates */
2086 .ops = {
2087 .open = via_playback_pcm_open,
2088 .prepare = via_playback_pcm_prepare,
2089 .cleanup = via_playback_pcm_cleanup
2090 },
2091};
2092
2093static struct hda_pcm_stream vt1708S_pcm_analog_capture = {
2094 .substreams = 2,
2095 .channels_min = 2,
2096 .channels_max = 2,
2097 .nid = 0x13, /* NID to query formats and rates */
2098 .ops = {
2099 .prepare = via_capture_pcm_prepare,
2100 .cleanup = via_capture_pcm_cleanup
2101 },
2102};
2103
2104static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
2105 .substreams = 1,
2106 .channels_min = 2,
2107 .channels_max = 2,
2108 /* NID is set in via_build_pcms */
2109 .ops = {
2110 .open = via_dig_playback_pcm_open,
2111 .close = via_dig_playback_pcm_close,
2112 .prepare = via_dig_playback_pcm_prepare
2113 },
2114};
2115
2116/* fill in the dac_nids table from the parsed pin configuration */
2117static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
2118 const struct auto_pin_cfg *cfg)
2119{
2120 int i;
2121 hda_nid_t nid;
2122
2123 spec->multiout.num_dacs = cfg->line_outs;
2124
2125 spec->multiout.dac_nids = spec->private_dac_nids;
2126
2127 for (i = 0; i < 4; i++) {
2128 nid = cfg->line_out_pins[i];
2129 if (nid) {
2130 /* config dac list */
2131 switch (i) {
2132 case AUTO_SEQ_FRONT:
2133 spec->multiout.dac_nids[i] = 0x10;
2134 break;
2135 case AUTO_SEQ_CENLFE:
2136 spec->multiout.dac_nids[i] = 0x24;
2137 break;
2138 case AUTO_SEQ_SURROUND:
2139 spec->multiout.dac_nids[i] = 0x11;
2140 break;
2141 case AUTO_SEQ_SIDE:
2142 spec->multiout.dac_nids[i] = 0x25;
2143 break;
2144 }
2145 }
2146 }
2147
2148 return 0;
2149}
2150
2151/* add playback controls from the parsed DAC table */
2152static int vt1708S_auto_create_multi_out_ctls(struct via_spec *spec,
2153 const struct auto_pin_cfg *cfg)
2154{
2155 char name[32];
2156 static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" };
2157 hda_nid_t nid_vols[] = {0x10, 0x11, 0x24, 0x25};
2158 hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x26, 0x27};
2159 hda_nid_t nid, nid_vol, nid_mute;
2160 int i, err;
2161
2162 for (i = 0; i <= AUTO_SEQ_SIDE; i++) {
2163 nid = cfg->line_out_pins[i];
2164
2165 if (!nid)
2166 continue;
2167
2168 nid_vol = nid_vols[i];
2169 nid_mute = nid_mutes[i];
2170
2171 if (i == AUTO_SEQ_CENLFE) {
2172 /* Center/LFE */
2173 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2174 "Center Playback Volume",
2175 HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0,
2176 HDA_OUTPUT));
2177 if (err < 0)
2178 return err;
2179 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2180 "LFE Playback Volume",
2181 HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0,
2182 HDA_OUTPUT));
2183 if (err < 0)
2184 return err;
2185 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2186 "Center Playback Switch",
2187 HDA_COMPOSE_AMP_VAL(nid_mute,
2188 1, 0,
2189 HDA_OUTPUT));
2190 if (err < 0)
2191 return err;
2192 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2193 "LFE Playback Switch",
2194 HDA_COMPOSE_AMP_VAL(nid_mute,
2195 2, 0,
2196 HDA_OUTPUT));
2197 if (err < 0)
2198 return err;
2199 } else if (i == AUTO_SEQ_FRONT) {
2200 /* add control to mixer index 0 */
2201 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2202 "Master Front Playback Volume",
2203 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2204 HDA_INPUT));
2205 if (err < 0)
2206 return err;
2207 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2208 "Master Front Playback Switch",
2209 HDA_COMPOSE_AMP_VAL(0x16, 3, 0,
2210 HDA_INPUT));
2211 if (err < 0)
2212 return err;
2213
2214 /* Front */
2215 sprintf(name, "%s Playback Volume", chname[i]);
2216 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2217 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2218 HDA_OUTPUT));
2219 if (err < 0)
2220 return err;
2221 sprintf(name, "%s Playback Switch", chname[i]);
2222 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2223 HDA_COMPOSE_AMP_VAL(nid_mute,
2224 3, 0,
2225 HDA_OUTPUT));
2226 if (err < 0)
2227 return err;
2228 } else {
2229 sprintf(name, "%s Playback Volume", chname[i]);
2230 err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name,
2231 HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0,
2232 HDA_OUTPUT));
2233 if (err < 0)
2234 return err;
2235 sprintf(name, "%s Playback Switch", chname[i]);
2236 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name,
2237 HDA_COMPOSE_AMP_VAL(nid_mute,
2238 3, 0,
2239 HDA_OUTPUT));
2240 if (err < 0)
2241 return err;
2242 }
2243 }
2244
2245 return 0;
2246}
2247
2248static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2249{
2250 int err;
2251
2252 if (!pin)
2253 return 0;
2254
2255 spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */
2256
2257 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2258 "Headphone Playback Volume",
2259 HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT));
2260 if (err < 0)
2261 return err;
2262
2263 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2264 "Headphone Playback Switch",
2265 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2266 if (err < 0)
2267 return err;
2268
2269 return 0;
2270}
2271
2272/* create playback/capture controls for input pins */
2273static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec,
2274 const struct auto_pin_cfg *cfg)
2275{
2276 static char *labels[] = {
2277 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2278 };
2279 struct hda_input_mux *imux = &spec->private_imux;
2280 int i, err, idx = 0;
2281
2282 /* for internal loopback recording select */
2283 imux->items[imux->num_items].label = "Stereo Mixer";
2284 imux->items[imux->num_items].index = 5;
2285 imux->num_items++;
2286
2287 for (i = 0; i < AUTO_PIN_LAST; i++) {
2288 if (!cfg->input_pins[i])
2289 continue;
2290
2291 switch (cfg->input_pins[i]) {
2292 case 0x1a: /* Mic */
2293 idx = 2;
2294 break;
2295
2296 case 0x1b: /* Line In */
2297 idx = 3;
2298 break;
2299
2300 case 0x1e: /* Front Mic */
2301 idx = 4;
2302 break;
2303
2304 case 0x1f: /* CD */
2305 idx = 1;
2306 break;
2307 }
2308 err = via_new_analog_input(spec, cfg->input_pins[i], labels[i],
2309 idx, 0x16);
2310 if (err < 0)
2311 return err;
2312 imux->items[imux->num_items].label = labels[i];
2313 imux->items[imux->num_items].index = idx-1;
2314 imux->num_items++;
2315 }
2316 return 0;
2317}
2318
2319static int vt1708S_parse_auto_config(struct hda_codec *codec)
2320{
2321 struct via_spec *spec = codec->spec;
2322 int err;
2323 static hda_nid_t vt1708s_ignore[] = {0x21, 0};
2324
2325 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2326 vt1708s_ignore);
2327 if (err < 0)
2328 return err;
2329 err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg);
2330 if (err < 0)
2331 return err;
2332 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2333 return 0; /* can't find valid BIOS pin config */
2334
2335 err = vt1708S_auto_create_multi_out_ctls(spec, &spec->autocfg);
2336 if (err < 0)
2337 return err;
2338 err = vt1708S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2339 if (err < 0)
2340 return err;
2341 err = vt1708S_auto_create_analog_input_ctls(spec, &spec->autocfg);
2342 if (err < 0)
2343 return err;
2344
2345 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2346
2347 if (spec->autocfg.dig_out_pin)
2348 spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
2349
2350 if (spec->kctl_alloc)
2351 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2352
2353 spec->input_mux = &spec->private_imux;
2354
2355 return 1;
2356}
2357
2358#ifdef CONFIG_SND_HDA_POWER_SAVE
2359static struct hda_amp_list vt1708S_loopbacks[] = {
2360 { 0x16, HDA_INPUT, 1 },
2361 { 0x16, HDA_INPUT, 2 },
2362 { 0x16, HDA_INPUT, 3 },
2363 { 0x16, HDA_INPUT, 4 },
2364 { } /* end */
2365};
2366#endif
2367
2368static int patch_vt1708S(struct hda_codec *codec)
2369{
2370 struct via_spec *spec;
2371 int err;
2372
2373 /* create a codec specific record */
2374 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2375 if (spec == NULL)
2376 return -ENOMEM;
2377
2378 codec->spec = spec;
2379
2380 /* automatic parse from the BIOS config */
2381 err = vt1708S_parse_auto_config(codec);
2382 if (err < 0) {
2383 via_free(codec);
2384 return err;
2385 } else if (!err) {
2386 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2387 "from BIOS. Using genenic mode...\n");
2388 }
2389
2390 spec->init_verbs = vt1708S_volume_init_verbs;
2391
2392 spec->stream_name_analog = "VT1708S Analog";
2393 spec->stream_analog_playback = &vt1708S_pcm_analog_playback;
2394 spec->stream_analog_capture = &vt1708S_pcm_analog_capture;
2395
2396 spec->stream_name_digital = "VT1708S Digital";
2397 spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
2398
2399 if (!spec->adc_nids && spec->input_mux) {
2400 spec->adc_nids = vt1708S_adc_nids;
2401 spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids);
2402 spec->mixers[spec->num_mixers] = vt1708S_capture_mixer;
2403 spec->num_mixers++;
2404 }
2405
2406 codec->patch_ops = via_patch_ops;
2407
2408 codec->patch_ops.init = via_auto_init;
2409
2410#ifdef CONFIG_SND_HDA_POWER_SAVE
2411 spec->loopback.amplist = vt1708S_loopbacks;
2412#endif
2413
2414 return 0;
2415}
2416
2417/* Patch for VT1702 */
2418
2419/* capture mixer elements */
2420static struct snd_kcontrol_new vt1702_capture_mixer[] = {
2421 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_INPUT),
2422 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_INPUT),
2423 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x20, 0x0, HDA_INPUT),
2424 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x20, 0x0, HDA_INPUT),
2425 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x1F, 0x0, HDA_INPUT),
2426 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x1F, 0x0, HDA_INPUT),
2427 HDA_CODEC_VOLUME("Digital Mic Boost Capture Volume", 0x1E, 0x0,
2428 HDA_INPUT),
2429 {
2430 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2431 /* The multiple "Capture Source" controls confuse alsamixer
2432 * So call somewhat different..
2433 */
2434 /* .name = "Capture Source", */
2435 .name = "Input Source",
2436 .count = 1,
2437 .info = via_mux_enum_info,
2438 .get = via_mux_enum_get,
2439 .put = via_mux_enum_put,
2440 },
2441 { } /* end */
2442};
2443
2444static struct hda_verb vt1702_volume_init_verbs[] = {
2445 /*
2446 * Unmute ADC0-1 and set the default input to mic-in
2447 */
2448 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2449 {0x1F, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2450 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2451
2452
2453 /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback
2454 * mixer widget
2455 */
2456 /* Amp Indices: Mic1 = 1, Line = 1, Mic2 = 3 */
2457 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2458 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
2459 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)},
2460 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)},
2461 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2462
2463 /* Setup default input of PW4 to MW0 */
2464 {0x17, AC_VERB_SET_CONNECT_SEL, 0x1},
2465 /* PW6 PW7 Output enable */
2466 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2467 {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},
2468 { }
2469};
2470
2471static struct hda_pcm_stream vt1702_pcm_analog_playback = {
2472 .substreams = 1,
2473 .channels_min = 2,
2474 .channels_max = 2,
2475 .nid = 0x10, /* NID to query formats and rates */
2476 .ops = {
2477 .open = via_playback_pcm_open,
2478 .prepare = via_playback_pcm_prepare,
2479 .cleanup = via_playback_pcm_cleanup
2480 },
2481};
2482
2483static struct hda_pcm_stream vt1702_pcm_analog_capture = {
2484 .substreams = 3,
2485 .channels_min = 2,
2486 .channels_max = 2,
2487 .nid = 0x12, /* NID to query formats and rates */
2488 .ops = {
2489 .prepare = via_capture_pcm_prepare,
2490 .cleanup = via_capture_pcm_cleanup
2491 },
2492};
2493
2494static struct hda_pcm_stream vt1702_pcm_digital_playback = {
2495 .substreams = 1,
2496 .channels_min = 2,
2497 .channels_max = 2,
2498 /* NID is set in via_build_pcms */
2499 .ops = {
2500 .open = via_dig_playback_pcm_open,
2501 .close = via_dig_playback_pcm_close,
2502 .prepare = via_dig_playback_pcm_prepare
2503 },
2504};
2505
2506/* fill in the dac_nids table from the parsed pin configuration */
2507static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
2508 const struct auto_pin_cfg *cfg)
2509{
2510 spec->multiout.num_dacs = 1;
2511 spec->multiout.dac_nids = spec->private_dac_nids;
2512
2513 if (cfg->line_out_pins[0]) {
2514 /* config dac list */
2515 spec->multiout.dac_nids[0] = 0x10;
2516 }
2517
2518 return 0;
2519}
2520
2521/* add playback controls from the parsed DAC table */
2522static int vt1702_auto_create_line_out_ctls(struct via_spec *spec,
2523 const struct auto_pin_cfg *cfg)
2524{
2525 int err;
2526
2527 if (!cfg->line_out_pins[0])
2528 return -1;
2529
2530 /* add control to mixer index 0 */
2531 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2532 "Master Front Playback Volume",
2533 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
2534 if (err < 0)
2535 return err;
2536 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2537 "Master Front Playback Switch",
2538 HDA_COMPOSE_AMP_VAL(0x1A, 3, 0, HDA_INPUT));
2539 if (err < 0)
2540 return err;
2541
2542 /* Front */
2543 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2544 "Front Playback Volume",
2545 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT));
2546 if (err < 0)
2547 return err;
2548 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2549 "Front Playback Switch",
2550 HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_OUTPUT));
2551 if (err < 0)
2552 return err;
2553
2554 return 0;
2555}
2556
2557static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin)
2558{
2559 int err;
2560
2561 if (!pin)
2562 return 0;
2563
2564 spec->multiout.hp_nid = 0x1D;
2565
2566 err = via_add_control(spec, VIA_CTL_WIDGET_VOL,
2567 "Headphone Playback Volume",
2568 HDA_COMPOSE_AMP_VAL(0x1D, 3, 0, HDA_OUTPUT));
2569 if (err < 0)
2570 return err;
2571
2572 err = via_add_control(spec, VIA_CTL_WIDGET_MUTE,
2573 "Headphone Playback Switch",
2574 HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT));
2575 if (err < 0)
2576 return err;
2577
2578 return 0;
2579}
2580
2581/* create playback/capture controls for input pins */
2582static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec,
2583 const struct auto_pin_cfg *cfg)
2584{
2585 static char *labels[] = {
2586 "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL
2587 };
2588 struct hda_input_mux *imux = &spec->private_imux;
2589 int i, err, idx = 0;
2590
2591 /* for internal loopback recording select */
2592 imux->items[imux->num_items].label = "Stereo Mixer";
2593 imux->items[imux->num_items].index = 3;
2594 imux->num_items++;
2595
2596 for (i = 0; i < AUTO_PIN_LAST; i++) {
2597 if (!cfg->input_pins[i])
2598 continue;
2599
2600 switch (cfg->input_pins[i]) {
2601 case 0x14: /* Mic */
2602 idx = 1;
2603 break;
2604
2605 case 0x15: /* Line In */
2606 idx = 2;
2607 break;
2608
2609 case 0x18: /* Front Mic */
2610 idx = 3;
2611 break;
2612 }
2613 err = via_new_analog_input(spec, cfg->input_pins[i],
2614 labels[i], idx, 0x1A);
2615 if (err < 0)
2616 return err;
2617 imux->items[imux->num_items].label = labels[i];
2618 imux->items[imux->num_items].index = idx-1;
2619 imux->num_items++;
2620 }
2621 return 0;
2622}
2623
2624static int vt1702_parse_auto_config(struct hda_codec *codec)
2625{
2626 struct via_spec *spec = codec->spec;
2627 int err;
2628 static hda_nid_t vt1702_ignore[] = {0x1C, 0};
2629
2630 err = snd_hda_parse_pin_def_config(codec, &spec->autocfg,
2631 vt1702_ignore);
2632 if (err < 0)
2633 return err;
2634 err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg);
2635 if (err < 0)
2636 return err;
2637 if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0])
2638 return 0; /* can't find valid BIOS pin config */
2639
2640 err = vt1702_auto_create_line_out_ctls(spec, &spec->autocfg);
2641 if (err < 0)
2642 return err;
2643 err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]);
2644 if (err < 0)
2645 return err;
2646 err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg);
2647 if (err < 0)
2648 return err;
2649
2650 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2651
2652 if (spec->autocfg.dig_out_pin)
2653 spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
2654
2655 if (spec->kctl_alloc)
2656 spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
2657
2658 spec->input_mux = &spec->private_imux;
2659
2660 return 1;
2661}
2662
2663#ifdef CONFIG_SND_HDA_POWER_SAVE
2664static struct hda_amp_list vt1702_loopbacks[] = {
2665 { 0x1A, HDA_INPUT, 1 },
2666 { 0x1A, HDA_INPUT, 2 },
2667 { 0x1A, HDA_INPUT, 3 },
2668 { 0x1A, HDA_INPUT, 4 },
2669 { } /* end */
2670};
2671#endif
2672
2673static int patch_vt1702(struct hda_codec *codec)
2674{
2675 struct via_spec *spec;
2676 int err;
2677 unsigned int response;
2678 unsigned char control;
2679
2680 /* create a codec specific record */
2681 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2682 if (spec == NULL)
2683 return -ENOMEM;
2684
2685 codec->spec = spec;
2686
2687 /* automatic parse from the BIOS config */
2688 err = vt1702_parse_auto_config(codec);
2689 if (err < 0) {
2690 via_free(codec);
2691 return err;
2692 } else if (!err) {
2693 printk(KERN_INFO "hda_codec: Cannot set up configuration "
2694 "from BIOS. Using genenic mode...\n");
2695 }
2696
2697 spec->init_verbs = vt1702_volume_init_verbs;
2698
2699 spec->stream_name_analog = "VT1702 Analog";
2700 spec->stream_analog_playback = &vt1702_pcm_analog_playback;
2701 spec->stream_analog_capture = &vt1702_pcm_analog_capture;
2702
2703 spec->stream_name_digital = "VT1702 Digital";
2704 spec->stream_digital_playback = &vt1702_pcm_digital_playback;
2705
2706 if (!spec->adc_nids && spec->input_mux) {
2707 spec->adc_nids = vt1702_adc_nids;
2708 spec->num_adc_nids = ARRAY_SIZE(vt1702_adc_nids);
2709 spec->mixers[spec->num_mixers] = vt1702_capture_mixer;
2710 spec->num_mixers++;
2711 }
2712
2713 codec->patch_ops = via_patch_ops;
2714
2715 codec->patch_ops.init = via_auto_init;
2716
2717#ifdef CONFIG_SND_HDA_POWER_SAVE
2718 spec->loopback.amplist = vt1702_loopbacks;
2719#endif
2720
2721 /* Open backdoor */
2722 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0);
2723 control = (unsigned char)(response & 0xff);
2724 control |= 0x3;
2725 snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control);
2726
2727 /* Enable GPIO 0&1 for volume&mute control */
2728 /* Enable GPIO 2 for DMIC-DATA */
2729 response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0);
2730 control = (unsigned char)((response >> 16) & 0x3f);
2731 snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control);
2732
2733 return 0;
2734}
2735
2014/* 2736/*
2015 * patch entries 2737 * patch entries
2016 */ 2738 */
@@ -2051,5 +2773,37 @@ struct hda_codec_preset snd_hda_preset_via[] = {
2051 .patch = patch_vt1708B_4ch}, 2773 .patch = patch_vt1708B_4ch},
2052 { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch", 2774 { .id = 0x1106E727, .name = "VIA VT1708B 4-Ch",
2053 .patch = patch_vt1708B_4ch}, 2775 .patch = patch_vt1708B_4ch},
2776 { .id = 0x11060397, .name = "VIA VT1708S",
2777 .patch = patch_vt1708S},
2778 { .id = 0x11061397, .name = "VIA VT1708S",
2779 .patch = patch_vt1708S},
2780 { .id = 0x11062397, .name = "VIA VT1708S",
2781 .patch = patch_vt1708S},
2782 { .id = 0x11063397, .name = "VIA VT1708S",
2783 .patch = patch_vt1708S},
2784 { .id = 0x11064397, .name = "VIA VT1708S",
2785 .patch = patch_vt1708S},
2786 { .id = 0x11065397, .name = "VIA VT1708S",
2787 .patch = patch_vt1708S},
2788 { .id = 0x11066397, .name = "VIA VT1708S",
2789 .patch = patch_vt1708S},
2790 { .id = 0x11067397, .name = "VIA VT1708S",
2791 .patch = patch_vt1708S},
2792 { .id = 0x11060398, .name = "VIA VT1702",
2793 .patch = patch_vt1702},
2794 { .id = 0x11061398, .name = "VIA VT1702",
2795 .patch = patch_vt1702},
2796 { .id = 0x11062398, .name = "VIA VT1702",
2797 .patch = patch_vt1702},
2798 { .id = 0x11063398, .name = "VIA VT1702",
2799 .patch = patch_vt1702},
2800 { .id = 0x11064398, .name = "VIA VT1702",
2801 .patch = patch_vt1702},
2802 { .id = 0x11065398, .name = "VIA VT1702",
2803 .patch = patch_vt1702},
2804 { .id = 0x11066398, .name = "VIA VT1702",
2805 .patch = patch_vt1702},
2806 { .id = 0x11067398, .name = "VIA VT1702",
2807 .patch = patch_vt1702},
2054 {} /* terminator */ 2808 {} /* terminator */
2055}; 2809};