1*c577b8a1SJoseph Chan /* 2*c577b8a1SJoseph Chan * Universal Interface for Intel High Definition Audio Codec 3*c577b8a1SJoseph Chan * 4*c577b8a1SJoseph Chan * HD audio interface patch for VIA VT1708 codec 5*c577b8a1SJoseph Chan * 6*c577b8a1SJoseph Chan * Copyright (c) 2006 Lydia Wang <lydiawang@viatech.com> 7*c577b8a1SJoseph Chan * Takashi Iwai <tiwai@suse.de> 8*c577b8a1SJoseph Chan * 9*c577b8a1SJoseph Chan * This driver is free software; you can redistribute it and/or modify 10*c577b8a1SJoseph Chan * it under the terms of the GNU General Public License as published by 11*c577b8a1SJoseph Chan * the Free Software Foundation; either version 2 of the License, or 12*c577b8a1SJoseph Chan * (at your option) any later version. 13*c577b8a1SJoseph Chan * 14*c577b8a1SJoseph Chan * This driver is distributed in the hope that it will be useful, 15*c577b8a1SJoseph Chan * but WITHOUT ANY WARRANTY; without even the implied warranty of 16*c577b8a1SJoseph Chan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17*c577b8a1SJoseph Chan * GNU General Public License for more details. 18*c577b8a1SJoseph Chan * 19*c577b8a1SJoseph Chan * You should have received a copy of the GNU General Public License 20*c577b8a1SJoseph Chan * along with this program; if not, write to the Free Software 21*c577b8a1SJoseph Chan * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22*c577b8a1SJoseph Chan */ 23*c577b8a1SJoseph Chan 24*c577b8a1SJoseph Chan /* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */ 25*c577b8a1SJoseph Chan /* */ 26*c577b8a1SJoseph Chan /* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */ 27*c577b8a1SJoseph Chan /* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ 28*c577b8a1SJoseph Chan /* 2006-08-02 Lydia Wang Add support to VT1709 codec */ 29*c577b8a1SJoseph Chan /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ 30*c577b8a1SJoseph Chan /* */ 31*c577b8a1SJoseph Chan /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 32*c577b8a1SJoseph Chan 33*c577b8a1SJoseph Chan 34*c577b8a1SJoseph Chan #include <sound/driver.h> 35*c577b8a1SJoseph Chan #include <linux/init.h> 36*c577b8a1SJoseph Chan #include <linux/delay.h> 37*c577b8a1SJoseph Chan #include <linux/slab.h> 38*c577b8a1SJoseph Chan #include <linux/pci.h> 39*c577b8a1SJoseph Chan #include <sound/core.h> 40*c577b8a1SJoseph Chan #include "hda_codec.h" 41*c577b8a1SJoseph Chan #include "hda_local.h" 42*c577b8a1SJoseph Chan 43*c577b8a1SJoseph Chan 44*c577b8a1SJoseph Chan /* amp values */ 45*c577b8a1SJoseph Chan #define AMP_VAL_IDX_SHIFT 19 46*c577b8a1SJoseph Chan #define AMP_VAL_IDX_MASK (0x0f<<19) 47*c577b8a1SJoseph Chan 48*c577b8a1SJoseph Chan #define NUM_CONTROL_ALLOC 32 49*c577b8a1SJoseph Chan #define NUM_VERB_ALLOC 32 50*c577b8a1SJoseph Chan 51*c577b8a1SJoseph Chan /* Pin Widget NID */ 52*c577b8a1SJoseph Chan #define VT1708_HP_NID 0x13 53*c577b8a1SJoseph Chan #define VT1708_DIGOUT_NID 0x14 54*c577b8a1SJoseph Chan #define VT1708_DIGIN_NID 0x16 55*c577b8a1SJoseph Chan 56*c577b8a1SJoseph Chan #define VT1709_HP_DAC_NID 0x28 57*c577b8a1SJoseph Chan #define VT1709_DIGOUT_NID 0x13 58*c577b8a1SJoseph Chan #define VT1709_DIGIN_NID 0x17 59*c577b8a1SJoseph Chan 60*c577b8a1SJoseph Chan #define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) 61*c577b8a1SJoseph Chan #define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) 62*c577b8a1SJoseph Chan #define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) 63*c577b8a1SJoseph Chan 64*c577b8a1SJoseph Chan 65*c577b8a1SJoseph Chan enum { 66*c577b8a1SJoseph Chan VIA_CTL_WIDGET_VOL, 67*c577b8a1SJoseph Chan VIA_CTL_WIDGET_MUTE, 68*c577b8a1SJoseph Chan }; 69*c577b8a1SJoseph Chan 70*c577b8a1SJoseph Chan enum { 71*c577b8a1SJoseph Chan AUTO_SEQ_FRONT, 72*c577b8a1SJoseph Chan AUTO_SEQ_SURROUND, 73*c577b8a1SJoseph Chan AUTO_SEQ_CENLFE, 74*c577b8a1SJoseph Chan AUTO_SEQ_SIDE 75*c577b8a1SJoseph Chan }; 76*c577b8a1SJoseph Chan 77*c577b8a1SJoseph Chan static struct snd_kcontrol_new vt1708_control_templates[] = { 78*c577b8a1SJoseph Chan HDA_CODEC_VOLUME(NULL, 0, 0, 0), 79*c577b8a1SJoseph Chan HDA_CODEC_MUTE(NULL, 0, 0, 0), 80*c577b8a1SJoseph Chan }; 81*c577b8a1SJoseph Chan 82*c577b8a1SJoseph Chan 83*c577b8a1SJoseph Chan struct via_spec { 84*c577b8a1SJoseph Chan /* codec parameterization */ 85*c577b8a1SJoseph Chan struct snd_kcontrol_new *mixers[3]; 86*c577b8a1SJoseph Chan unsigned int num_mixers; 87*c577b8a1SJoseph Chan 88*c577b8a1SJoseph Chan struct hda_verb *init_verbs; 89*c577b8a1SJoseph Chan 90*c577b8a1SJoseph Chan char *stream_name_analog; 91*c577b8a1SJoseph Chan struct hda_pcm_stream *stream_analog_playback; 92*c577b8a1SJoseph Chan struct hda_pcm_stream *stream_analog_capture; 93*c577b8a1SJoseph Chan 94*c577b8a1SJoseph Chan char *stream_name_digital; 95*c577b8a1SJoseph Chan struct hda_pcm_stream *stream_digital_playback; 96*c577b8a1SJoseph Chan struct hda_pcm_stream *stream_digital_capture; 97*c577b8a1SJoseph Chan 98*c577b8a1SJoseph Chan /* playback */ 99*c577b8a1SJoseph Chan struct hda_multi_out multiout; 100*c577b8a1SJoseph Chan 101*c577b8a1SJoseph Chan /* capture */ 102*c577b8a1SJoseph Chan unsigned int num_adc_nids; 103*c577b8a1SJoseph Chan hda_nid_t *adc_nids; 104*c577b8a1SJoseph Chan hda_nid_t dig_in_nid; 105*c577b8a1SJoseph Chan 106*c577b8a1SJoseph Chan /* capture source */ 107*c577b8a1SJoseph Chan const struct hda_input_mux *input_mux; 108*c577b8a1SJoseph Chan unsigned int cur_mux[3]; 109*c577b8a1SJoseph Chan 110*c577b8a1SJoseph Chan /* PCM information */ 111*c577b8a1SJoseph Chan struct hda_pcm pcm_rec[2]; 112*c577b8a1SJoseph Chan 113*c577b8a1SJoseph Chan /* dynamic controls, init_verbs and input_mux */ 114*c577b8a1SJoseph Chan struct auto_pin_cfg autocfg; 115*c577b8a1SJoseph Chan unsigned int num_kctl_alloc, num_kctl_used; 116*c577b8a1SJoseph Chan struct snd_kcontrol_new *kctl_alloc; 117*c577b8a1SJoseph Chan struct hda_input_mux private_imux; 118*c577b8a1SJoseph Chan hda_nid_t private_dac_nids[4]; 119*c577b8a1SJoseph Chan }; 120*c577b8a1SJoseph Chan 121*c577b8a1SJoseph Chan static hda_nid_t vt1708_adc_nids[2] = { 122*c577b8a1SJoseph Chan /* ADC1-2 */ 123*c577b8a1SJoseph Chan 0x15, 0x27 124*c577b8a1SJoseph Chan }; 125*c577b8a1SJoseph Chan 126*c577b8a1SJoseph Chan static hda_nid_t vt1709_adc_nids[3] = { 127*c577b8a1SJoseph Chan /* ADC1-2 */ 128*c577b8a1SJoseph Chan 0x14, 0x15, 0x16 129*c577b8a1SJoseph Chan }; 130*c577b8a1SJoseph Chan 131*c577b8a1SJoseph Chan /* add dynamic controls */ 132*c577b8a1SJoseph Chan static int via_add_control(struct via_spec *spec, int type, const char *name, 133*c577b8a1SJoseph Chan unsigned long val) 134*c577b8a1SJoseph Chan { 135*c577b8a1SJoseph Chan struct snd_kcontrol_new *knew; 136*c577b8a1SJoseph Chan 137*c577b8a1SJoseph Chan if (spec->num_kctl_used >= spec->num_kctl_alloc) { 138*c577b8a1SJoseph Chan int num = spec->num_kctl_alloc + NUM_CONTROL_ALLOC; 139*c577b8a1SJoseph Chan 140*c577b8a1SJoseph Chan /* array + terminator */ 141*c577b8a1SJoseph Chan knew = kcalloc(num + 1, sizeof(*knew), GFP_KERNEL); 142*c577b8a1SJoseph Chan if (!knew) 143*c577b8a1SJoseph Chan return -ENOMEM; 144*c577b8a1SJoseph Chan if (spec->kctl_alloc) { 145*c577b8a1SJoseph Chan memcpy(knew, spec->kctl_alloc, 146*c577b8a1SJoseph Chan sizeof(*knew) * spec->num_kctl_alloc); 147*c577b8a1SJoseph Chan kfree(spec->kctl_alloc); 148*c577b8a1SJoseph Chan } 149*c577b8a1SJoseph Chan spec->kctl_alloc = knew; 150*c577b8a1SJoseph Chan spec->num_kctl_alloc = num; 151*c577b8a1SJoseph Chan } 152*c577b8a1SJoseph Chan 153*c577b8a1SJoseph Chan knew = &spec->kctl_alloc[spec->num_kctl_used]; 154*c577b8a1SJoseph Chan *knew = vt1708_control_templates[type]; 155*c577b8a1SJoseph Chan knew->name = kstrdup(name, GFP_KERNEL); 156*c577b8a1SJoseph Chan 157*c577b8a1SJoseph Chan if (!knew->name) 158*c577b8a1SJoseph Chan return -ENOMEM; 159*c577b8a1SJoseph Chan knew->private_value = val; 160*c577b8a1SJoseph Chan spec->num_kctl_used++; 161*c577b8a1SJoseph Chan return 0; 162*c577b8a1SJoseph Chan } 163*c577b8a1SJoseph Chan 164*c577b8a1SJoseph Chan /* create input playback/capture controls for the given pin */ 165*c577b8a1SJoseph Chan static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, 166*c577b8a1SJoseph Chan const char *ctlname, int idx, int mix_nid) 167*c577b8a1SJoseph Chan { 168*c577b8a1SJoseph Chan char name[32]; 169*c577b8a1SJoseph Chan int err; 170*c577b8a1SJoseph Chan 171*c577b8a1SJoseph Chan sprintf(name, "%s Playback Volume", ctlname); 172*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, 173*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); 174*c577b8a1SJoseph Chan if (err < 0) 175*c577b8a1SJoseph Chan return err; 176*c577b8a1SJoseph Chan sprintf(name, "%s Playback Switch", ctlname); 177*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, 178*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); 179*c577b8a1SJoseph Chan if (err < 0) 180*c577b8a1SJoseph Chan return err; 181*c577b8a1SJoseph Chan return 0; 182*c577b8a1SJoseph Chan } 183*c577b8a1SJoseph Chan 184*c577b8a1SJoseph Chan static void via_auto_set_output_and_unmute(struct hda_codec *codec, 185*c577b8a1SJoseph Chan hda_nid_t nid, int pin_type, 186*c577b8a1SJoseph Chan int dac_idx) 187*c577b8a1SJoseph Chan { 188*c577b8a1SJoseph Chan /* set as output */ 189*c577b8a1SJoseph Chan snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 190*c577b8a1SJoseph Chan pin_type); 191*c577b8a1SJoseph Chan snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 192*c577b8a1SJoseph Chan AMP_OUT_UNMUTE); 193*c577b8a1SJoseph Chan } 194*c577b8a1SJoseph Chan 195*c577b8a1SJoseph Chan 196*c577b8a1SJoseph Chan static void via_auto_init_multi_out(struct hda_codec *codec) 197*c577b8a1SJoseph Chan { 198*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 199*c577b8a1SJoseph Chan int i; 200*c577b8a1SJoseph Chan 201*c577b8a1SJoseph Chan for (i = 0; i <= AUTO_SEQ_SIDE; i++) { 202*c577b8a1SJoseph Chan hda_nid_t nid = spec->autocfg.line_out_pins[i]; 203*c577b8a1SJoseph Chan if (nid) 204*c577b8a1SJoseph Chan via_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); 205*c577b8a1SJoseph Chan } 206*c577b8a1SJoseph Chan } 207*c577b8a1SJoseph Chan 208*c577b8a1SJoseph Chan static void via_auto_init_hp_out(struct hda_codec *codec) 209*c577b8a1SJoseph Chan { 210*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 211*c577b8a1SJoseph Chan hda_nid_t pin; 212*c577b8a1SJoseph Chan 213*c577b8a1SJoseph Chan pin = spec->autocfg.hp_pins[0]; 214*c577b8a1SJoseph Chan if (pin) /* connect to front */ 215*c577b8a1SJoseph Chan via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); 216*c577b8a1SJoseph Chan } 217*c577b8a1SJoseph Chan 218*c577b8a1SJoseph Chan static void via_auto_init_analog_input(struct hda_codec *codec) 219*c577b8a1SJoseph Chan { 220*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 221*c577b8a1SJoseph Chan int i; 222*c577b8a1SJoseph Chan 223*c577b8a1SJoseph Chan for (i = 0; i < AUTO_PIN_LAST; i++) { 224*c577b8a1SJoseph Chan hda_nid_t nid = spec->autocfg.input_pins[i]; 225*c577b8a1SJoseph Chan 226*c577b8a1SJoseph Chan snd_hda_codec_write(codec, nid, 0, 227*c577b8a1SJoseph Chan AC_VERB_SET_PIN_WIDGET_CONTROL, 228*c577b8a1SJoseph Chan (i <= AUTO_PIN_FRONT_MIC ? 229*c577b8a1SJoseph Chan PIN_VREF50 : PIN_IN)); 230*c577b8a1SJoseph Chan 231*c577b8a1SJoseph Chan } 232*c577b8a1SJoseph Chan } 233*c577b8a1SJoseph Chan /* 234*c577b8a1SJoseph Chan * input MUX handling 235*c577b8a1SJoseph Chan */ 236*c577b8a1SJoseph Chan static int via_mux_enum_info(struct snd_kcontrol *kcontrol, 237*c577b8a1SJoseph Chan struct snd_ctl_elem_info *uinfo) 238*c577b8a1SJoseph Chan { 239*c577b8a1SJoseph Chan struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 240*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 241*c577b8a1SJoseph Chan return snd_hda_input_mux_info(spec->input_mux, uinfo); 242*c577b8a1SJoseph Chan } 243*c577b8a1SJoseph Chan 244*c577b8a1SJoseph Chan static int via_mux_enum_get(struct snd_kcontrol *kcontrol, 245*c577b8a1SJoseph Chan struct snd_ctl_elem_value *ucontrol) 246*c577b8a1SJoseph Chan { 247*c577b8a1SJoseph Chan struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 248*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 249*c577b8a1SJoseph Chan unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 250*c577b8a1SJoseph Chan 251*c577b8a1SJoseph Chan ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 252*c577b8a1SJoseph Chan return 0; 253*c577b8a1SJoseph Chan } 254*c577b8a1SJoseph Chan 255*c577b8a1SJoseph Chan static int via_mux_enum_put(struct snd_kcontrol *kcontrol, 256*c577b8a1SJoseph Chan struct snd_ctl_elem_value *ucontrol) 257*c577b8a1SJoseph Chan { 258*c577b8a1SJoseph Chan struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 259*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 260*c577b8a1SJoseph Chan unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 261*c577b8a1SJoseph Chan unsigned int vendor_id = codec->vendor_id; 262*c577b8a1SJoseph Chan 263*c577b8a1SJoseph Chan /* AIW0 lydia 060801 add for correct sw0 input select */ 264*c577b8a1SJoseph Chan if (IS_VT1708_VENDORID(vendor_id) && (adc_idx == 0)) 265*c577b8a1SJoseph Chan return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 266*c577b8a1SJoseph Chan 0x18, &spec->cur_mux[adc_idx]); 267*c577b8a1SJoseph Chan else if ((IS_VT1709_10CH_VENDORID(vendor_id) || 268*c577b8a1SJoseph Chan IS_VT1709_6CH_VENDORID(vendor_id)) && (adc_idx == 0) ) 269*c577b8a1SJoseph Chan return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 270*c577b8a1SJoseph Chan 0x19, &spec->cur_mux[adc_idx]); 271*c577b8a1SJoseph Chan else 272*c577b8a1SJoseph Chan return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 273*c577b8a1SJoseph Chan spec->adc_nids[adc_idx], 274*c577b8a1SJoseph Chan &spec->cur_mux[adc_idx]); 275*c577b8a1SJoseph Chan } 276*c577b8a1SJoseph Chan 277*c577b8a1SJoseph Chan /* capture mixer elements */ 278*c577b8a1SJoseph Chan static struct snd_kcontrol_new vt1708_capture_mixer[] = { 279*c577b8a1SJoseph Chan HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), 280*c577b8a1SJoseph Chan HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_INPUT), 281*c577b8a1SJoseph Chan HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x27, 0x0, HDA_INPUT), 282*c577b8a1SJoseph Chan HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x27, 0x0, HDA_INPUT), 283*c577b8a1SJoseph Chan { 284*c577b8a1SJoseph Chan .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 285*c577b8a1SJoseph Chan /* The multiple "Capture Source" controls confuse alsamixer 286*c577b8a1SJoseph Chan * So call somewhat different.. 287*c577b8a1SJoseph Chan * FIXME: the controls appear in the "playback" view! 288*c577b8a1SJoseph Chan */ 289*c577b8a1SJoseph Chan /* .name = "Capture Source", */ 290*c577b8a1SJoseph Chan .name = "Input Source", 291*c577b8a1SJoseph Chan .count = 1, 292*c577b8a1SJoseph Chan .info = via_mux_enum_info, 293*c577b8a1SJoseph Chan .get = via_mux_enum_get, 294*c577b8a1SJoseph Chan .put = via_mux_enum_put, 295*c577b8a1SJoseph Chan }, 296*c577b8a1SJoseph Chan { } /* end */ 297*c577b8a1SJoseph Chan }; 298*c577b8a1SJoseph Chan /* 299*c577b8a1SJoseph Chan * generic initialization of ADC, input mixers and output mixers 300*c577b8a1SJoseph Chan */ 301*c577b8a1SJoseph Chan static struct hda_verb vt1708_volume_init_verbs[] = { 302*c577b8a1SJoseph Chan /* 303*c577b8a1SJoseph Chan * Unmute ADC0-1 and set the default input to mic-in 304*c577b8a1SJoseph Chan */ 305*c577b8a1SJoseph Chan {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 306*c577b8a1SJoseph Chan {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 307*c577b8a1SJoseph Chan 308*c577b8a1SJoseph Chan 309*c577b8a1SJoseph Chan /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 310*c577b8a1SJoseph Chan * mixer widget 311*c577b8a1SJoseph Chan */ 312*c577b8a1SJoseph Chan /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ 313*c577b8a1SJoseph Chan {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 314*c577b8a1SJoseph Chan {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 315*c577b8a1SJoseph Chan {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 316*c577b8a1SJoseph Chan {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 317*c577b8a1SJoseph Chan {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 318*c577b8a1SJoseph Chan 319*c577b8a1SJoseph Chan /* 320*c577b8a1SJoseph Chan * Set up output mixers (0x19 - 0x1b) 321*c577b8a1SJoseph Chan */ 322*c577b8a1SJoseph Chan /* set vol=0 to output mixers */ 323*c577b8a1SJoseph Chan {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 324*c577b8a1SJoseph Chan {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 325*c577b8a1SJoseph Chan {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 326*c577b8a1SJoseph Chan 327*c577b8a1SJoseph Chan /* Setup default input to PW4 */ 328*c577b8a1SJoseph Chan {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, 329*c577b8a1SJoseph Chan /* Set mic as default input of sw0 */ 330*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_CONNECT_SEL, 0x2}, 331*c577b8a1SJoseph Chan /* PW9 Output enable */ 332*c577b8a1SJoseph Chan {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 333*c577b8a1SJoseph Chan }; 334*c577b8a1SJoseph Chan 335*c577b8a1SJoseph Chan static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, 336*c577b8a1SJoseph Chan struct hda_codec *codec, 337*c577b8a1SJoseph Chan struct snd_pcm_substream *substream) 338*c577b8a1SJoseph Chan { 339*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 340*c577b8a1SJoseph Chan return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 341*c577b8a1SJoseph Chan } 342*c577b8a1SJoseph Chan 343*c577b8a1SJoseph Chan static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 344*c577b8a1SJoseph Chan struct hda_codec *codec, 345*c577b8a1SJoseph Chan unsigned int stream_tag, 346*c577b8a1SJoseph Chan unsigned int format, 347*c577b8a1SJoseph Chan struct snd_pcm_substream *substream) 348*c577b8a1SJoseph Chan { 349*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 350*c577b8a1SJoseph Chan return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 351*c577b8a1SJoseph Chan stream_tag, format, substream); 352*c577b8a1SJoseph Chan } 353*c577b8a1SJoseph Chan 354*c577b8a1SJoseph Chan static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 355*c577b8a1SJoseph Chan struct hda_codec *codec, 356*c577b8a1SJoseph Chan struct snd_pcm_substream *substream) 357*c577b8a1SJoseph Chan { 358*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 359*c577b8a1SJoseph Chan return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 360*c577b8a1SJoseph Chan } 361*c577b8a1SJoseph Chan 362*c577b8a1SJoseph Chan /* 363*c577b8a1SJoseph Chan * Digital out 364*c577b8a1SJoseph Chan */ 365*c577b8a1SJoseph Chan static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 366*c577b8a1SJoseph Chan struct hda_codec *codec, 367*c577b8a1SJoseph Chan struct snd_pcm_substream *substream) 368*c577b8a1SJoseph Chan { 369*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 370*c577b8a1SJoseph Chan return snd_hda_multi_out_dig_open(codec, &spec->multiout); 371*c577b8a1SJoseph Chan } 372*c577b8a1SJoseph Chan 373*c577b8a1SJoseph Chan static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 374*c577b8a1SJoseph Chan struct hda_codec *codec, 375*c577b8a1SJoseph Chan struct snd_pcm_substream *substream) 376*c577b8a1SJoseph Chan { 377*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 378*c577b8a1SJoseph Chan return snd_hda_multi_out_dig_close(codec, &spec->multiout); 379*c577b8a1SJoseph Chan } 380*c577b8a1SJoseph Chan 381*c577b8a1SJoseph Chan /* 382*c577b8a1SJoseph Chan * Analog capture 383*c577b8a1SJoseph Chan */ 384*c577b8a1SJoseph Chan static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 385*c577b8a1SJoseph Chan struct hda_codec *codec, 386*c577b8a1SJoseph Chan unsigned int stream_tag, 387*c577b8a1SJoseph Chan unsigned int format, 388*c577b8a1SJoseph Chan struct snd_pcm_substream *substream) 389*c577b8a1SJoseph Chan { 390*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 391*c577b8a1SJoseph Chan 392*c577b8a1SJoseph Chan snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 393*c577b8a1SJoseph Chan stream_tag, 0, format); 394*c577b8a1SJoseph Chan return 0; 395*c577b8a1SJoseph Chan } 396*c577b8a1SJoseph Chan 397*c577b8a1SJoseph Chan static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 398*c577b8a1SJoseph Chan struct hda_codec *codec, 399*c577b8a1SJoseph Chan struct snd_pcm_substream *substream) 400*c577b8a1SJoseph Chan { 401*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 402*c577b8a1SJoseph Chan snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 403*c577b8a1SJoseph Chan 0, 0, 0); 404*c577b8a1SJoseph Chan return 0; 405*c577b8a1SJoseph Chan } 406*c577b8a1SJoseph Chan 407*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1708_pcm_analog_playback = { 408*c577b8a1SJoseph Chan .substreams = 1, 409*c577b8a1SJoseph Chan .channels_min = 2, 410*c577b8a1SJoseph Chan .channels_max = 8, 411*c577b8a1SJoseph Chan .nid = 0x10, /* NID to query formats and rates */ 412*c577b8a1SJoseph Chan .ops = { 413*c577b8a1SJoseph Chan .open = via_playback_pcm_open, 414*c577b8a1SJoseph Chan .prepare = via_playback_pcm_prepare, 415*c577b8a1SJoseph Chan .cleanup = via_playback_pcm_cleanup 416*c577b8a1SJoseph Chan }, 417*c577b8a1SJoseph Chan }; 418*c577b8a1SJoseph Chan 419*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1708_pcm_analog_capture = { 420*c577b8a1SJoseph Chan .substreams = 2, 421*c577b8a1SJoseph Chan .channels_min = 2, 422*c577b8a1SJoseph Chan .channels_max = 2, 423*c577b8a1SJoseph Chan .nid = 0x15, /* NID to query formats and rates */ 424*c577b8a1SJoseph Chan .ops = { 425*c577b8a1SJoseph Chan .prepare = via_capture_pcm_prepare, 426*c577b8a1SJoseph Chan .cleanup = via_capture_pcm_cleanup 427*c577b8a1SJoseph Chan }, 428*c577b8a1SJoseph Chan }; 429*c577b8a1SJoseph Chan 430*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1708_pcm_digital_playback = { 431*c577b8a1SJoseph Chan .substreams = 1, 432*c577b8a1SJoseph Chan .channels_min = 2, 433*c577b8a1SJoseph Chan .channels_max = 2, 434*c577b8a1SJoseph Chan /* NID is set in via_build_pcms */ 435*c577b8a1SJoseph Chan .ops = { 436*c577b8a1SJoseph Chan .open = via_dig_playback_pcm_open, 437*c577b8a1SJoseph Chan .close = via_dig_playback_pcm_close 438*c577b8a1SJoseph Chan }, 439*c577b8a1SJoseph Chan }; 440*c577b8a1SJoseph Chan 441*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1708_pcm_digital_capture = { 442*c577b8a1SJoseph Chan .substreams = 1, 443*c577b8a1SJoseph Chan .channels_min = 2, 444*c577b8a1SJoseph Chan .channels_max = 2, 445*c577b8a1SJoseph Chan }; 446*c577b8a1SJoseph Chan 447*c577b8a1SJoseph Chan static int via_build_controls(struct hda_codec *codec) 448*c577b8a1SJoseph Chan { 449*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 450*c577b8a1SJoseph Chan int err; 451*c577b8a1SJoseph Chan int i; 452*c577b8a1SJoseph Chan 453*c577b8a1SJoseph Chan for (i = 0; i < spec->num_mixers; i++) { 454*c577b8a1SJoseph Chan err = snd_hda_add_new_ctls(codec, spec->mixers[i]); 455*c577b8a1SJoseph Chan if (err < 0) 456*c577b8a1SJoseph Chan return err; 457*c577b8a1SJoseph Chan } 458*c577b8a1SJoseph Chan 459*c577b8a1SJoseph Chan if (spec->multiout.dig_out_nid) { 460*c577b8a1SJoseph Chan err = snd_hda_create_spdif_out_ctls(codec, 461*c577b8a1SJoseph Chan spec->multiout.dig_out_nid); 462*c577b8a1SJoseph Chan if (err < 0) 463*c577b8a1SJoseph Chan return err; 464*c577b8a1SJoseph Chan } 465*c577b8a1SJoseph Chan if (spec->dig_in_nid) { 466*c577b8a1SJoseph Chan err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); 467*c577b8a1SJoseph Chan if (err < 0) 468*c577b8a1SJoseph Chan return err; 469*c577b8a1SJoseph Chan } 470*c577b8a1SJoseph Chan return 0; 471*c577b8a1SJoseph Chan } 472*c577b8a1SJoseph Chan 473*c577b8a1SJoseph Chan static int via_build_pcms(struct hda_codec *codec) 474*c577b8a1SJoseph Chan { 475*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 476*c577b8a1SJoseph Chan struct hda_pcm *info = spec->pcm_rec; 477*c577b8a1SJoseph Chan 478*c577b8a1SJoseph Chan codec->num_pcms = 1; 479*c577b8a1SJoseph Chan codec->pcm_info = info; 480*c577b8a1SJoseph Chan 481*c577b8a1SJoseph Chan info->name = spec->stream_name_analog; 482*c577b8a1SJoseph Chan info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *(spec->stream_analog_playback); 483*c577b8a1SJoseph Chan info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; 484*c577b8a1SJoseph Chan info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); 485*c577b8a1SJoseph Chan info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 486*c577b8a1SJoseph Chan 487*c577b8a1SJoseph Chan info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 488*c577b8a1SJoseph Chan spec->multiout.max_channels; 489*c577b8a1SJoseph Chan 490*c577b8a1SJoseph Chan if (spec->multiout.dig_out_nid || spec->dig_in_nid) { 491*c577b8a1SJoseph Chan codec->num_pcms++; 492*c577b8a1SJoseph Chan info++; 493*c577b8a1SJoseph Chan info->name = spec->stream_name_digital; 494*c577b8a1SJoseph Chan if (spec->multiout.dig_out_nid) { 495*c577b8a1SJoseph Chan info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 496*c577b8a1SJoseph Chan *(spec->stream_digital_playback); 497*c577b8a1SJoseph Chan info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 498*c577b8a1SJoseph Chan spec->multiout.dig_out_nid; 499*c577b8a1SJoseph Chan } 500*c577b8a1SJoseph Chan if (spec->dig_in_nid) { 501*c577b8a1SJoseph Chan info->stream[SNDRV_PCM_STREAM_CAPTURE] = 502*c577b8a1SJoseph Chan *(spec->stream_digital_capture); 503*c577b8a1SJoseph Chan info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 504*c577b8a1SJoseph Chan spec->dig_in_nid; 505*c577b8a1SJoseph Chan } 506*c577b8a1SJoseph Chan } 507*c577b8a1SJoseph Chan 508*c577b8a1SJoseph Chan return 0; 509*c577b8a1SJoseph Chan } 510*c577b8a1SJoseph Chan 511*c577b8a1SJoseph Chan static void via_free(struct hda_codec *codec) 512*c577b8a1SJoseph Chan { 513*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 514*c577b8a1SJoseph Chan unsigned int i; 515*c577b8a1SJoseph Chan 516*c577b8a1SJoseph Chan if (!spec) 517*c577b8a1SJoseph Chan return; 518*c577b8a1SJoseph Chan 519*c577b8a1SJoseph Chan if (spec->kctl_alloc) { 520*c577b8a1SJoseph Chan for (i = 0; i < spec->num_kctl_used; i++) 521*c577b8a1SJoseph Chan kfree(spec->kctl_alloc[i].name); 522*c577b8a1SJoseph Chan kfree(spec->kctl_alloc); 523*c577b8a1SJoseph Chan } 524*c577b8a1SJoseph Chan 525*c577b8a1SJoseph Chan kfree(codec->spec); 526*c577b8a1SJoseph Chan } 527*c577b8a1SJoseph Chan 528*c577b8a1SJoseph Chan static int via_init(struct hda_codec *codec) 529*c577b8a1SJoseph Chan { 530*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 531*c577b8a1SJoseph Chan snd_hda_sequence_write(codec, spec->init_verbs); 532*c577b8a1SJoseph Chan return 0; 533*c577b8a1SJoseph Chan } 534*c577b8a1SJoseph Chan 535*c577b8a1SJoseph Chan #ifdef CONFIG_PM 536*c577b8a1SJoseph Chan /* 537*c577b8a1SJoseph Chan * resume 538*c577b8a1SJoseph Chan */ 539*c577b8a1SJoseph Chan static int via_resume(struct hda_codec *codec) 540*c577b8a1SJoseph Chan { 541*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 542*c577b8a1SJoseph Chan int i; 543*c577b8a1SJoseph Chan 544*c577b8a1SJoseph Chan via_init(codec); 545*c577b8a1SJoseph Chan for (i = 0; i < spec->num_mixers; i++) 546*c577b8a1SJoseph Chan snd_hda_resume_ctls(codec, spec->mixers[i]); 547*c577b8a1SJoseph Chan if (spec->multiout.dig_out_nid) 548*c577b8a1SJoseph Chan snd_hda_resume_spdif_out(codec); 549*c577b8a1SJoseph Chan if (spec->dig_in_nid) 550*c577b8a1SJoseph Chan snd_hda_resume_spdif_in(codec); 551*c577b8a1SJoseph Chan 552*c577b8a1SJoseph Chan return 0; 553*c577b8a1SJoseph Chan } 554*c577b8a1SJoseph Chan #endif 555*c577b8a1SJoseph Chan 556*c577b8a1SJoseph Chan /* 557*c577b8a1SJoseph Chan */ 558*c577b8a1SJoseph Chan static struct hda_codec_ops via_patch_ops = { 559*c577b8a1SJoseph Chan .build_controls = via_build_controls, 560*c577b8a1SJoseph Chan .build_pcms = via_build_pcms, 561*c577b8a1SJoseph Chan .init = via_init, 562*c577b8a1SJoseph Chan .free = via_free, 563*c577b8a1SJoseph Chan #ifdef CONFIG_PM 564*c577b8a1SJoseph Chan .resume = via_resume, 565*c577b8a1SJoseph Chan #endif 566*c577b8a1SJoseph Chan }; 567*c577b8a1SJoseph Chan 568*c577b8a1SJoseph Chan /* fill in the dac_nids table from the parsed pin configuration */ 569*c577b8a1SJoseph Chan static int vt1708_auto_fill_dac_nids(struct via_spec *spec, 570*c577b8a1SJoseph Chan const struct auto_pin_cfg *cfg) 571*c577b8a1SJoseph Chan { 572*c577b8a1SJoseph Chan int i; 573*c577b8a1SJoseph Chan hda_nid_t nid; 574*c577b8a1SJoseph Chan 575*c577b8a1SJoseph Chan spec->multiout.num_dacs = cfg->line_outs; 576*c577b8a1SJoseph Chan 577*c577b8a1SJoseph Chan spec->multiout.dac_nids = spec->private_dac_nids; 578*c577b8a1SJoseph Chan 579*c577b8a1SJoseph Chan for(i = 0; i < 4; i++) { 580*c577b8a1SJoseph Chan nid = cfg->line_out_pins[i]; 581*c577b8a1SJoseph Chan if (nid) { 582*c577b8a1SJoseph Chan /* config dac list */ 583*c577b8a1SJoseph Chan switch (i) { 584*c577b8a1SJoseph Chan case AUTO_SEQ_FRONT: 585*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x10; 586*c577b8a1SJoseph Chan break; 587*c577b8a1SJoseph Chan case AUTO_SEQ_CENLFE: 588*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x12; 589*c577b8a1SJoseph Chan break; 590*c577b8a1SJoseph Chan case AUTO_SEQ_SURROUND: 591*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x13; 592*c577b8a1SJoseph Chan break; 593*c577b8a1SJoseph Chan case AUTO_SEQ_SIDE: 594*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x11; 595*c577b8a1SJoseph Chan break; 596*c577b8a1SJoseph Chan } 597*c577b8a1SJoseph Chan } 598*c577b8a1SJoseph Chan } 599*c577b8a1SJoseph Chan 600*c577b8a1SJoseph Chan return 0; 601*c577b8a1SJoseph Chan } 602*c577b8a1SJoseph Chan 603*c577b8a1SJoseph Chan /* add playback controls from the parsed DAC table */ 604*c577b8a1SJoseph Chan static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, 605*c577b8a1SJoseph Chan const struct auto_pin_cfg *cfg) 606*c577b8a1SJoseph Chan { 607*c577b8a1SJoseph Chan char name[32]; 608*c577b8a1SJoseph Chan static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; 609*c577b8a1SJoseph Chan hda_nid_t nid, nid_vol = 0; 610*c577b8a1SJoseph Chan int i, err; 611*c577b8a1SJoseph Chan 612*c577b8a1SJoseph Chan for (i = 0; i <= AUTO_SEQ_SIDE; i++) { 613*c577b8a1SJoseph Chan nid = cfg->line_out_pins[i]; 614*c577b8a1SJoseph Chan 615*c577b8a1SJoseph Chan if (!nid) 616*c577b8a1SJoseph Chan continue; 617*c577b8a1SJoseph Chan 618*c577b8a1SJoseph Chan if (i != AUTO_SEQ_FRONT) 619*c577b8a1SJoseph Chan nid_vol = 0x1b - i + 1; 620*c577b8a1SJoseph Chan 621*c577b8a1SJoseph Chan if (i == AUTO_SEQ_CENLFE) { 622*c577b8a1SJoseph Chan /* Center/LFE */ 623*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, 624*c577b8a1SJoseph Chan "Center Playback Volume", 625*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); 626*c577b8a1SJoseph Chan if (err < 0) 627*c577b8a1SJoseph Chan return err; 628*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, 629*c577b8a1SJoseph Chan "LFE Playback Volume", 630*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); 631*c577b8a1SJoseph Chan if (err < 0) 632*c577b8a1SJoseph Chan return err; 633*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, 634*c577b8a1SJoseph Chan "Center Playback Switch", 635*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); 636*c577b8a1SJoseph Chan if (err < 0) 637*c577b8a1SJoseph Chan return err; 638*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, 639*c577b8a1SJoseph Chan "LFE Playback Switch", 640*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); 641*c577b8a1SJoseph Chan if (err < 0) 642*c577b8a1SJoseph Chan return err; 643*c577b8a1SJoseph Chan } else if (i == AUTO_SEQ_FRONT){ 644*c577b8a1SJoseph Chan /* add control to mixer index 0 */ 645*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, 646*c577b8a1SJoseph Chan "Master Front Playback Volume", 647*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); 648*c577b8a1SJoseph Chan if (err < 0) 649*c577b8a1SJoseph Chan return err; 650*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, 651*c577b8a1SJoseph Chan "Master Front Playback Switch", 652*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT)); 653*c577b8a1SJoseph Chan if (err < 0) 654*c577b8a1SJoseph Chan return err; 655*c577b8a1SJoseph Chan 656*c577b8a1SJoseph Chan /* add control to PW3 */ 657*c577b8a1SJoseph Chan sprintf(name, "%s Playback Volume", chname[i]); 658*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, 659*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); 660*c577b8a1SJoseph Chan if (err < 0) 661*c577b8a1SJoseph Chan return err; 662*c577b8a1SJoseph Chan sprintf(name, "%s Playback Switch", chname[i]); 663*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, 664*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); 665*c577b8a1SJoseph Chan if (err < 0) 666*c577b8a1SJoseph Chan return err; 667*c577b8a1SJoseph Chan } else { 668*c577b8a1SJoseph Chan sprintf(name, "%s Playback Volume", chname[i]); 669*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, 670*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); 671*c577b8a1SJoseph Chan if (err < 0) 672*c577b8a1SJoseph Chan return err; 673*c577b8a1SJoseph Chan sprintf(name, "%s Playback Switch", chname[i]); 674*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, 675*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); 676*c577b8a1SJoseph Chan if (err < 0) 677*c577b8a1SJoseph Chan return err; 678*c577b8a1SJoseph Chan } 679*c577b8a1SJoseph Chan } 680*c577b8a1SJoseph Chan 681*c577b8a1SJoseph Chan return 0; 682*c577b8a1SJoseph Chan } 683*c577b8a1SJoseph Chan 684*c577b8a1SJoseph Chan static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) 685*c577b8a1SJoseph Chan { 686*c577b8a1SJoseph Chan int err; 687*c577b8a1SJoseph Chan 688*c577b8a1SJoseph Chan if (!pin) 689*c577b8a1SJoseph Chan return 0; 690*c577b8a1SJoseph Chan 691*c577b8a1SJoseph Chan spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */ 692*c577b8a1SJoseph Chan 693*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, 694*c577b8a1SJoseph Chan "Headphone Playback Volume", 695*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); 696*c577b8a1SJoseph Chan if (err < 0) 697*c577b8a1SJoseph Chan return err; 698*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, 699*c577b8a1SJoseph Chan "Headphone Playback Switch", 700*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); 701*c577b8a1SJoseph Chan if (err < 0) 702*c577b8a1SJoseph Chan return err; 703*c577b8a1SJoseph Chan 704*c577b8a1SJoseph Chan return 0; 705*c577b8a1SJoseph Chan } 706*c577b8a1SJoseph Chan 707*c577b8a1SJoseph Chan /* create playback/capture controls for input pins */ 708*c577b8a1SJoseph Chan static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, 709*c577b8a1SJoseph Chan const struct auto_pin_cfg *cfg) 710*c577b8a1SJoseph Chan { 711*c577b8a1SJoseph Chan static char *labels[] = { 712*c577b8a1SJoseph Chan "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL 713*c577b8a1SJoseph Chan }; 714*c577b8a1SJoseph Chan struct hda_input_mux *imux = &spec->private_imux; 715*c577b8a1SJoseph Chan int i, err, idx = 0; 716*c577b8a1SJoseph Chan 717*c577b8a1SJoseph Chan /* for internal loopback recording select */ 718*c577b8a1SJoseph Chan imux->items[imux->num_items].label = "Stereo Mixer"; 719*c577b8a1SJoseph Chan imux->items[imux->num_items].index = idx; 720*c577b8a1SJoseph Chan imux->num_items++; 721*c577b8a1SJoseph Chan 722*c577b8a1SJoseph Chan for (i = 0; i < AUTO_PIN_LAST; i++) { 723*c577b8a1SJoseph Chan if (!cfg->input_pins[i]) 724*c577b8a1SJoseph Chan continue; 725*c577b8a1SJoseph Chan 726*c577b8a1SJoseph Chan switch (cfg->input_pins[i]) { 727*c577b8a1SJoseph Chan case 0x1d: /* Mic */ 728*c577b8a1SJoseph Chan idx = 2; 729*c577b8a1SJoseph Chan break; 730*c577b8a1SJoseph Chan 731*c577b8a1SJoseph Chan case 0x1e: /* Line In */ 732*c577b8a1SJoseph Chan idx = 3; 733*c577b8a1SJoseph Chan break; 734*c577b8a1SJoseph Chan 735*c577b8a1SJoseph Chan case 0x21: /* Front Mic */ 736*c577b8a1SJoseph Chan idx = 4; 737*c577b8a1SJoseph Chan break; 738*c577b8a1SJoseph Chan 739*c577b8a1SJoseph Chan case 0x24: /* CD */ 740*c577b8a1SJoseph Chan idx = 1; 741*c577b8a1SJoseph Chan break; 742*c577b8a1SJoseph Chan } 743*c577b8a1SJoseph Chan err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], 744*c577b8a1SJoseph Chan idx, 0x17); 745*c577b8a1SJoseph Chan if (err < 0) 746*c577b8a1SJoseph Chan return err; 747*c577b8a1SJoseph Chan imux->items[imux->num_items].label = labels[i]; 748*c577b8a1SJoseph Chan imux->items[imux->num_items].index = idx; 749*c577b8a1SJoseph Chan imux->num_items++; 750*c577b8a1SJoseph Chan } 751*c577b8a1SJoseph Chan return 0; 752*c577b8a1SJoseph Chan } 753*c577b8a1SJoseph Chan 754*c577b8a1SJoseph Chan static int vt1708_parse_auto_config(struct hda_codec *codec) 755*c577b8a1SJoseph Chan { 756*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 757*c577b8a1SJoseph Chan int err; 758*c577b8a1SJoseph Chan 759*c577b8a1SJoseph Chan err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); 760*c577b8a1SJoseph Chan if (err < 0) 761*c577b8a1SJoseph Chan return err; 762*c577b8a1SJoseph Chan err = vt1708_auto_fill_dac_nids(spec, &spec->autocfg); 763*c577b8a1SJoseph Chan if (err < 0) 764*c577b8a1SJoseph Chan return err; 765*c577b8a1SJoseph Chan if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) 766*c577b8a1SJoseph Chan return 0; /* can't find valid BIOS pin config */ 767*c577b8a1SJoseph Chan 768*c577b8a1SJoseph Chan err = vt1708_auto_create_multi_out_ctls(spec, &spec->autocfg); 769*c577b8a1SJoseph Chan if (err < 0) 770*c577b8a1SJoseph Chan return err; 771*c577b8a1SJoseph Chan err = vt1708_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); 772*c577b8a1SJoseph Chan if (err < 0) 773*c577b8a1SJoseph Chan return err; 774*c577b8a1SJoseph Chan err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); 775*c577b8a1SJoseph Chan if (err < 0) 776*c577b8a1SJoseph Chan return err; 777*c577b8a1SJoseph Chan 778*c577b8a1SJoseph Chan spec->multiout.max_channels = spec->multiout.num_dacs * 2; 779*c577b8a1SJoseph Chan 780*c577b8a1SJoseph Chan if (spec->autocfg.dig_out_pin) 781*c577b8a1SJoseph Chan spec->multiout.dig_out_nid = VT1708_DIGOUT_NID; 782*c577b8a1SJoseph Chan if (spec->autocfg.dig_in_pin) 783*c577b8a1SJoseph Chan spec->dig_in_nid = VT1708_DIGIN_NID; 784*c577b8a1SJoseph Chan 785*c577b8a1SJoseph Chan if (spec->kctl_alloc) 786*c577b8a1SJoseph Chan spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 787*c577b8a1SJoseph Chan 788*c577b8a1SJoseph Chan spec->init_verbs = vt1708_volume_init_verbs; 789*c577b8a1SJoseph Chan 790*c577b8a1SJoseph Chan spec->input_mux = &spec->private_imux; 791*c577b8a1SJoseph Chan 792*c577b8a1SJoseph Chan return 1; 793*c577b8a1SJoseph Chan } 794*c577b8a1SJoseph Chan 795*c577b8a1SJoseph Chan /* init callback for auto-configuration model -- overriding the default init */ 796*c577b8a1SJoseph Chan static int via_auto_init(struct hda_codec *codec) 797*c577b8a1SJoseph Chan { 798*c577b8a1SJoseph Chan via_init(codec); 799*c577b8a1SJoseph Chan via_auto_init_multi_out(codec); 800*c577b8a1SJoseph Chan via_auto_init_hp_out(codec); 801*c577b8a1SJoseph Chan via_auto_init_analog_input(codec); 802*c577b8a1SJoseph Chan return 0; 803*c577b8a1SJoseph Chan } 804*c577b8a1SJoseph Chan 805*c577b8a1SJoseph Chan static int patch_vt1708(struct hda_codec *codec) 806*c577b8a1SJoseph Chan { 807*c577b8a1SJoseph Chan struct via_spec *spec; 808*c577b8a1SJoseph Chan int err; 809*c577b8a1SJoseph Chan 810*c577b8a1SJoseph Chan /* create a codec specific record */ 811*c577b8a1SJoseph Chan spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 812*c577b8a1SJoseph Chan if (spec == NULL) 813*c577b8a1SJoseph Chan return -ENOMEM; 814*c577b8a1SJoseph Chan 815*c577b8a1SJoseph Chan codec->spec = spec; 816*c577b8a1SJoseph Chan 817*c577b8a1SJoseph Chan /* automatic parse from the BIOS config */ 818*c577b8a1SJoseph Chan err = vt1708_parse_auto_config(codec); 819*c577b8a1SJoseph Chan if (err < 0) { 820*c577b8a1SJoseph Chan via_free(codec); 821*c577b8a1SJoseph Chan return err; 822*c577b8a1SJoseph Chan } else if (!err) { 823*c577b8a1SJoseph Chan printk(KERN_INFO "hda_codec: Cannot set up configuration " 824*c577b8a1SJoseph Chan "from BIOS. Using genenic mode...\n"); 825*c577b8a1SJoseph Chan } 826*c577b8a1SJoseph Chan 827*c577b8a1SJoseph Chan 828*c577b8a1SJoseph Chan spec->stream_name_analog = "VT1708 Analog"; 829*c577b8a1SJoseph Chan spec->stream_analog_playback = &vt1708_pcm_analog_playback; 830*c577b8a1SJoseph Chan spec->stream_analog_capture = &vt1708_pcm_analog_capture; 831*c577b8a1SJoseph Chan 832*c577b8a1SJoseph Chan spec->stream_name_digital = "VT1708 Digital"; 833*c577b8a1SJoseph Chan spec->stream_digital_playback = &vt1708_pcm_digital_playback; 834*c577b8a1SJoseph Chan spec->stream_digital_capture = &vt1708_pcm_digital_capture; 835*c577b8a1SJoseph Chan 836*c577b8a1SJoseph Chan 837*c577b8a1SJoseph Chan if (!spec->adc_nids && spec->input_mux) { 838*c577b8a1SJoseph Chan spec->adc_nids = vt1708_adc_nids; 839*c577b8a1SJoseph Chan spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids); 840*c577b8a1SJoseph Chan spec->mixers[spec->num_mixers] = vt1708_capture_mixer; 841*c577b8a1SJoseph Chan spec->num_mixers++; 842*c577b8a1SJoseph Chan } 843*c577b8a1SJoseph Chan 844*c577b8a1SJoseph Chan codec->patch_ops = via_patch_ops; 845*c577b8a1SJoseph Chan 846*c577b8a1SJoseph Chan codec->patch_ops.init = via_auto_init; 847*c577b8a1SJoseph Chan 848*c577b8a1SJoseph Chan return 0; 849*c577b8a1SJoseph Chan } 850*c577b8a1SJoseph Chan 851*c577b8a1SJoseph Chan /* capture mixer elements */ 852*c577b8a1SJoseph Chan static struct snd_kcontrol_new vt1709_capture_mixer[] = { 853*c577b8a1SJoseph Chan HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x0, HDA_INPUT), 854*c577b8a1SJoseph Chan HDA_CODEC_MUTE("Capture Switch", 0x14, 0x0, HDA_INPUT), 855*c577b8a1SJoseph Chan HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x15, 0x0, HDA_INPUT), 856*c577b8a1SJoseph Chan HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x15, 0x0, HDA_INPUT), 857*c577b8a1SJoseph Chan HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x16, 0x0, HDA_INPUT), 858*c577b8a1SJoseph Chan HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x16, 0x0, HDA_INPUT), 859*c577b8a1SJoseph Chan { 860*c577b8a1SJoseph Chan .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 861*c577b8a1SJoseph Chan /* The multiple "Capture Source" controls confuse alsamixer 862*c577b8a1SJoseph Chan * So call somewhat different.. 863*c577b8a1SJoseph Chan * FIXME: the controls appear in the "playback" view! 864*c577b8a1SJoseph Chan */ 865*c577b8a1SJoseph Chan /* .name = "Capture Source", */ 866*c577b8a1SJoseph Chan .name = "Input Source", 867*c577b8a1SJoseph Chan .count = 1, 868*c577b8a1SJoseph Chan .info = via_mux_enum_info, 869*c577b8a1SJoseph Chan .get = via_mux_enum_get, 870*c577b8a1SJoseph Chan .put = via_mux_enum_put, 871*c577b8a1SJoseph Chan }, 872*c577b8a1SJoseph Chan { } /* end */ 873*c577b8a1SJoseph Chan }; 874*c577b8a1SJoseph Chan 875*c577b8a1SJoseph Chan /* 876*c577b8a1SJoseph Chan * generic initialization of ADC, input mixers and output mixers 877*c577b8a1SJoseph Chan */ 878*c577b8a1SJoseph Chan static struct hda_verb vt1709_10ch_volume_init_verbs[] = { 879*c577b8a1SJoseph Chan /* 880*c577b8a1SJoseph Chan * Unmute ADC0-2 and set the default input to mic-in 881*c577b8a1SJoseph Chan */ 882*c577b8a1SJoseph Chan {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 883*c577b8a1SJoseph Chan {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 884*c577b8a1SJoseph Chan {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 885*c577b8a1SJoseph Chan 886*c577b8a1SJoseph Chan 887*c577b8a1SJoseph Chan /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 888*c577b8a1SJoseph Chan * mixer widget 889*c577b8a1SJoseph Chan */ 890*c577b8a1SJoseph Chan /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ 891*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 892*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 893*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 894*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 895*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 896*c577b8a1SJoseph Chan 897*c577b8a1SJoseph Chan /* 898*c577b8a1SJoseph Chan * Set up output selector (0x1a, 0x1b, 0x29) 899*c577b8a1SJoseph Chan */ 900*c577b8a1SJoseph Chan /* set vol=0 to output mixers */ 901*c577b8a1SJoseph Chan {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 902*c577b8a1SJoseph Chan {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 903*c577b8a1SJoseph Chan {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 904*c577b8a1SJoseph Chan 905*c577b8a1SJoseph Chan /* 906*c577b8a1SJoseph Chan * Unmute PW3 and PW4 907*c577b8a1SJoseph Chan */ 908*c577b8a1SJoseph Chan {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 909*c577b8a1SJoseph Chan {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 910*c577b8a1SJoseph Chan 911*c577b8a1SJoseph Chan /* Set input of PW4 as AOW4 */ 912*c577b8a1SJoseph Chan {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, 913*c577b8a1SJoseph Chan /* Set mic as default input of sw0 */ 914*c577b8a1SJoseph Chan {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, 915*c577b8a1SJoseph Chan /* PW9 Output enable */ 916*c577b8a1SJoseph Chan {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 917*c577b8a1SJoseph Chan { } 918*c577b8a1SJoseph Chan }; 919*c577b8a1SJoseph Chan 920*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { 921*c577b8a1SJoseph Chan .substreams = 1, 922*c577b8a1SJoseph Chan .channels_min = 2, 923*c577b8a1SJoseph Chan .channels_max = 10, 924*c577b8a1SJoseph Chan .nid = 0x10, /* NID to query formats and rates */ 925*c577b8a1SJoseph Chan .ops = { 926*c577b8a1SJoseph Chan .open = via_playback_pcm_open, 927*c577b8a1SJoseph Chan .prepare = via_playback_pcm_prepare, 928*c577b8a1SJoseph Chan .cleanup = via_playback_pcm_cleanup 929*c577b8a1SJoseph Chan }, 930*c577b8a1SJoseph Chan }; 931*c577b8a1SJoseph Chan 932*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { 933*c577b8a1SJoseph Chan .substreams = 1, 934*c577b8a1SJoseph Chan .channels_min = 2, 935*c577b8a1SJoseph Chan .channels_max = 6, 936*c577b8a1SJoseph Chan .nid = 0x10, /* NID to query formats and rates */ 937*c577b8a1SJoseph Chan .ops = { 938*c577b8a1SJoseph Chan .open = via_playback_pcm_open, 939*c577b8a1SJoseph Chan .prepare = via_playback_pcm_prepare, 940*c577b8a1SJoseph Chan .cleanup = via_playback_pcm_cleanup 941*c577b8a1SJoseph Chan }, 942*c577b8a1SJoseph Chan }; 943*c577b8a1SJoseph Chan 944*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_pcm_analog_capture = { 945*c577b8a1SJoseph Chan .substreams = 2, 946*c577b8a1SJoseph Chan .channels_min = 2, 947*c577b8a1SJoseph Chan .channels_max = 2, 948*c577b8a1SJoseph Chan .nid = 0x14, /* NID to query formats and rates */ 949*c577b8a1SJoseph Chan .ops = { 950*c577b8a1SJoseph Chan .prepare = via_capture_pcm_prepare, 951*c577b8a1SJoseph Chan .cleanup = via_capture_pcm_cleanup 952*c577b8a1SJoseph Chan }, 953*c577b8a1SJoseph Chan }; 954*c577b8a1SJoseph Chan 955*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_pcm_digital_playback = { 956*c577b8a1SJoseph Chan .substreams = 1, 957*c577b8a1SJoseph Chan .channels_min = 2, 958*c577b8a1SJoseph Chan .channels_max = 2, 959*c577b8a1SJoseph Chan /* NID is set in via_build_pcms */ 960*c577b8a1SJoseph Chan .ops = { 961*c577b8a1SJoseph Chan .open = via_dig_playback_pcm_open, 962*c577b8a1SJoseph Chan .close = via_dig_playback_pcm_close 963*c577b8a1SJoseph Chan }, 964*c577b8a1SJoseph Chan }; 965*c577b8a1SJoseph Chan 966*c577b8a1SJoseph Chan static struct hda_pcm_stream vt1709_pcm_digital_capture = { 967*c577b8a1SJoseph Chan .substreams = 1, 968*c577b8a1SJoseph Chan .channels_min = 2, 969*c577b8a1SJoseph Chan .channels_max = 2, 970*c577b8a1SJoseph Chan }; 971*c577b8a1SJoseph Chan 972*c577b8a1SJoseph Chan static int vt1709_auto_fill_dac_nids(struct via_spec *spec, 973*c577b8a1SJoseph Chan const struct auto_pin_cfg *cfg) 974*c577b8a1SJoseph Chan { 975*c577b8a1SJoseph Chan int i; 976*c577b8a1SJoseph Chan hda_nid_t nid; 977*c577b8a1SJoseph Chan 978*c577b8a1SJoseph Chan if (cfg->line_outs == 4) /* 10 channels */ 979*c577b8a1SJoseph Chan spec->multiout.num_dacs = cfg->line_outs+1; /* AOW0~AOW4 */ 980*c577b8a1SJoseph Chan else if (cfg->line_outs == 3) /* 6 channels */ 981*c577b8a1SJoseph Chan spec->multiout.num_dacs = cfg->line_outs; /* AOW0~AOW2 */ 982*c577b8a1SJoseph Chan 983*c577b8a1SJoseph Chan spec->multiout.dac_nids = spec->private_dac_nids; 984*c577b8a1SJoseph Chan 985*c577b8a1SJoseph Chan if (cfg->line_outs == 4) { /* 10 channels */ 986*c577b8a1SJoseph Chan for (i = 0; i < cfg->line_outs; i++) { 987*c577b8a1SJoseph Chan nid = cfg->line_out_pins[i]; 988*c577b8a1SJoseph Chan if (nid) { 989*c577b8a1SJoseph Chan /* config dac list */ 990*c577b8a1SJoseph Chan switch (i) { 991*c577b8a1SJoseph Chan case AUTO_SEQ_FRONT: 992*c577b8a1SJoseph Chan /* AOW0 */ 993*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x10; 994*c577b8a1SJoseph Chan break; 995*c577b8a1SJoseph Chan case AUTO_SEQ_CENLFE: 996*c577b8a1SJoseph Chan /* AOW2 */ 997*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x12; 998*c577b8a1SJoseph Chan break; 999*c577b8a1SJoseph Chan case AUTO_SEQ_SURROUND: 1000*c577b8a1SJoseph Chan /* AOW3 */ 1001*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x27; 1002*c577b8a1SJoseph Chan break; 1003*c577b8a1SJoseph Chan case AUTO_SEQ_SIDE: 1004*c577b8a1SJoseph Chan /* AOW1 */ 1005*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x11; 1006*c577b8a1SJoseph Chan break; 1007*c577b8a1SJoseph Chan default: 1008*c577b8a1SJoseph Chan break; 1009*c577b8a1SJoseph Chan } 1010*c577b8a1SJoseph Chan } 1011*c577b8a1SJoseph Chan } 1012*c577b8a1SJoseph Chan spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ 1013*c577b8a1SJoseph Chan 1014*c577b8a1SJoseph Chan } else if (cfg->line_outs == 3) { /* 6 channels */ 1015*c577b8a1SJoseph Chan for(i = 0; i < cfg->line_outs; i++) { 1016*c577b8a1SJoseph Chan nid = cfg->line_out_pins[i]; 1017*c577b8a1SJoseph Chan if (nid) { 1018*c577b8a1SJoseph Chan /* config dac list */ 1019*c577b8a1SJoseph Chan switch(i) { 1020*c577b8a1SJoseph Chan case AUTO_SEQ_FRONT: 1021*c577b8a1SJoseph Chan /* AOW0 */ 1022*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x10; 1023*c577b8a1SJoseph Chan break; 1024*c577b8a1SJoseph Chan case AUTO_SEQ_CENLFE: 1025*c577b8a1SJoseph Chan /* AOW2 */ 1026*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x12; 1027*c577b8a1SJoseph Chan break; 1028*c577b8a1SJoseph Chan case AUTO_SEQ_SURROUND: 1029*c577b8a1SJoseph Chan /* AOW1 */ 1030*c577b8a1SJoseph Chan spec->multiout.dac_nids[i] = 0x11; 1031*c577b8a1SJoseph Chan break; 1032*c577b8a1SJoseph Chan default: 1033*c577b8a1SJoseph Chan break; 1034*c577b8a1SJoseph Chan } 1035*c577b8a1SJoseph Chan } 1036*c577b8a1SJoseph Chan } 1037*c577b8a1SJoseph Chan } 1038*c577b8a1SJoseph Chan 1039*c577b8a1SJoseph Chan return 0; 1040*c577b8a1SJoseph Chan } 1041*c577b8a1SJoseph Chan 1042*c577b8a1SJoseph Chan /* add playback controls from the parsed DAC table */ 1043*c577b8a1SJoseph Chan static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, 1044*c577b8a1SJoseph Chan const struct auto_pin_cfg *cfg) 1045*c577b8a1SJoseph Chan { 1046*c577b8a1SJoseph Chan char name[32]; 1047*c577b8a1SJoseph Chan static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; 1048*c577b8a1SJoseph Chan hda_nid_t nid = 0; 1049*c577b8a1SJoseph Chan int i, err; 1050*c577b8a1SJoseph Chan 1051*c577b8a1SJoseph Chan for (i = 0; i <= AUTO_SEQ_SIDE; i++) { 1052*c577b8a1SJoseph Chan nid = cfg->line_out_pins[i]; 1053*c577b8a1SJoseph Chan 1054*c577b8a1SJoseph Chan if (!nid) 1055*c577b8a1SJoseph Chan continue; 1056*c577b8a1SJoseph Chan 1057*c577b8a1SJoseph Chan if (i == AUTO_SEQ_CENLFE) { 1058*c577b8a1SJoseph Chan /* Center/LFE */ 1059*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, 1060*c577b8a1SJoseph Chan "Center Playback Volume", 1061*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); 1062*c577b8a1SJoseph Chan if (err < 0) 1063*c577b8a1SJoseph Chan return err; 1064*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, 1065*c577b8a1SJoseph Chan "LFE Playback Volume", 1066*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); 1067*c577b8a1SJoseph Chan if (err < 0) 1068*c577b8a1SJoseph Chan return err; 1069*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, 1070*c577b8a1SJoseph Chan "Center Playback Switch", 1071*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, HDA_OUTPUT)); 1072*c577b8a1SJoseph Chan if (err < 0) 1073*c577b8a1SJoseph Chan return err; 1074*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, 1075*c577b8a1SJoseph Chan "LFE Playback Switch", 1076*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, HDA_OUTPUT)); 1077*c577b8a1SJoseph Chan if (err < 0) 1078*c577b8a1SJoseph Chan return err; 1079*c577b8a1SJoseph Chan } else if (i == AUTO_SEQ_FRONT){ 1080*c577b8a1SJoseph Chan /* add control to mixer index 0 */ 1081*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, 1082*c577b8a1SJoseph Chan "Master Front Playback Volume", 1083*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); 1084*c577b8a1SJoseph Chan if (err < 0) 1085*c577b8a1SJoseph Chan return err; 1086*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, 1087*c577b8a1SJoseph Chan "Master Front Playback Switch", 1088*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT)); 1089*c577b8a1SJoseph Chan if (err < 0) 1090*c577b8a1SJoseph Chan return err; 1091*c577b8a1SJoseph Chan 1092*c577b8a1SJoseph Chan /* add control to PW3 */ 1093*c577b8a1SJoseph Chan sprintf(name, "%s Playback Volume", chname[i]); 1094*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, 1095*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); 1096*c577b8a1SJoseph Chan if (err < 0) 1097*c577b8a1SJoseph Chan return err; 1098*c577b8a1SJoseph Chan sprintf(name, "%s Playback Switch", chname[i]); 1099*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, 1100*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); 1101*c577b8a1SJoseph Chan if (err < 0) 1102*c577b8a1SJoseph Chan return err; 1103*c577b8a1SJoseph Chan } else if (i == AUTO_SEQ_SURROUND) { 1104*c577b8a1SJoseph Chan sprintf(name, "%s Playback Volume", chname[i]); 1105*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, 1106*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); 1107*c577b8a1SJoseph Chan if (err < 0) 1108*c577b8a1SJoseph Chan return err; 1109*c577b8a1SJoseph Chan sprintf(name, "%s Playback Switch", chname[i]); 1110*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, 1111*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x29, 3, 0, HDA_OUTPUT)); 1112*c577b8a1SJoseph Chan if (err < 0) 1113*c577b8a1SJoseph Chan return err; 1114*c577b8a1SJoseph Chan } else if (i == AUTO_SEQ_SIDE) { 1115*c577b8a1SJoseph Chan sprintf(name, "%s Playback Volume", chname[i]); 1116*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, 1117*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); 1118*c577b8a1SJoseph Chan if (err < 0) 1119*c577b8a1SJoseph Chan return err; 1120*c577b8a1SJoseph Chan sprintf(name, "%s Playback Switch", chname[i]); 1121*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, 1122*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT)); 1123*c577b8a1SJoseph Chan if (err < 0) 1124*c577b8a1SJoseph Chan return err; 1125*c577b8a1SJoseph Chan } 1126*c577b8a1SJoseph Chan } 1127*c577b8a1SJoseph Chan 1128*c577b8a1SJoseph Chan return 0; 1129*c577b8a1SJoseph Chan } 1130*c577b8a1SJoseph Chan 1131*c577b8a1SJoseph Chan static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) 1132*c577b8a1SJoseph Chan { 1133*c577b8a1SJoseph Chan int err; 1134*c577b8a1SJoseph Chan 1135*c577b8a1SJoseph Chan if (!pin) 1136*c577b8a1SJoseph Chan return 0; 1137*c577b8a1SJoseph Chan 1138*c577b8a1SJoseph Chan if (spec->multiout.num_dacs == 5) /* 10 channels */ 1139*c577b8a1SJoseph Chan spec->multiout.hp_nid = VT1709_HP_DAC_NID; 1140*c577b8a1SJoseph Chan else if (spec->multiout.num_dacs == 3) /* 6 channels */ 1141*c577b8a1SJoseph Chan spec->multiout.hp_nid = 0; 1142*c577b8a1SJoseph Chan 1143*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_VOL, 1144*c577b8a1SJoseph Chan "Headphone Playback Volume", 1145*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); 1146*c577b8a1SJoseph Chan if (err < 0) 1147*c577b8a1SJoseph Chan return err; 1148*c577b8a1SJoseph Chan err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, 1149*c577b8a1SJoseph Chan "Headphone Playback Switch", 1150*c577b8a1SJoseph Chan HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); 1151*c577b8a1SJoseph Chan if (err < 0) 1152*c577b8a1SJoseph Chan return err; 1153*c577b8a1SJoseph Chan 1154*c577b8a1SJoseph Chan return 0; 1155*c577b8a1SJoseph Chan } 1156*c577b8a1SJoseph Chan 1157*c577b8a1SJoseph Chan /* create playback/capture controls for input pins */ 1158*c577b8a1SJoseph Chan static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, 1159*c577b8a1SJoseph Chan const struct auto_pin_cfg *cfg) 1160*c577b8a1SJoseph Chan { 1161*c577b8a1SJoseph Chan static char *labels[] = { 1162*c577b8a1SJoseph Chan "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL 1163*c577b8a1SJoseph Chan }; 1164*c577b8a1SJoseph Chan struct hda_input_mux *imux = &spec->private_imux; 1165*c577b8a1SJoseph Chan int i, err, idx = 0; 1166*c577b8a1SJoseph Chan 1167*c577b8a1SJoseph Chan /* for internal loopback recording select */ 1168*c577b8a1SJoseph Chan imux->items[imux->num_items].label = "Stereo Mixer"; 1169*c577b8a1SJoseph Chan imux->items[imux->num_items].index = idx; 1170*c577b8a1SJoseph Chan imux->num_items++; 1171*c577b8a1SJoseph Chan 1172*c577b8a1SJoseph Chan for (i = 0; i < AUTO_PIN_LAST; i++) { 1173*c577b8a1SJoseph Chan if (!cfg->input_pins[i]) 1174*c577b8a1SJoseph Chan continue; 1175*c577b8a1SJoseph Chan 1176*c577b8a1SJoseph Chan switch (cfg->input_pins[i]) { 1177*c577b8a1SJoseph Chan case 0x1d: /* Mic */ 1178*c577b8a1SJoseph Chan idx = 2; 1179*c577b8a1SJoseph Chan break; 1180*c577b8a1SJoseph Chan 1181*c577b8a1SJoseph Chan case 0x1e: /* Line In */ 1182*c577b8a1SJoseph Chan idx = 3; 1183*c577b8a1SJoseph Chan break; 1184*c577b8a1SJoseph Chan 1185*c577b8a1SJoseph Chan case 0x21: /* Front Mic */ 1186*c577b8a1SJoseph Chan idx = 4; 1187*c577b8a1SJoseph Chan break; 1188*c577b8a1SJoseph Chan 1189*c577b8a1SJoseph Chan case 0x23: /* CD */ 1190*c577b8a1SJoseph Chan idx = 1; 1191*c577b8a1SJoseph Chan break; 1192*c577b8a1SJoseph Chan } 1193*c577b8a1SJoseph Chan err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], 1194*c577b8a1SJoseph Chan idx, 0x18); 1195*c577b8a1SJoseph Chan if (err < 0) 1196*c577b8a1SJoseph Chan return err; 1197*c577b8a1SJoseph Chan imux->items[imux->num_items].label = labels[i]; 1198*c577b8a1SJoseph Chan imux->items[imux->num_items].index = idx; 1199*c577b8a1SJoseph Chan imux->num_items++; 1200*c577b8a1SJoseph Chan } 1201*c577b8a1SJoseph Chan return 0; 1202*c577b8a1SJoseph Chan } 1203*c577b8a1SJoseph Chan 1204*c577b8a1SJoseph Chan static int vt1709_parse_auto_config(struct hda_codec *codec) 1205*c577b8a1SJoseph Chan { 1206*c577b8a1SJoseph Chan struct via_spec *spec = codec->spec; 1207*c577b8a1SJoseph Chan int err; 1208*c577b8a1SJoseph Chan 1209*c577b8a1SJoseph Chan err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); 1210*c577b8a1SJoseph Chan if (err < 0) 1211*c577b8a1SJoseph Chan return err; 1212*c577b8a1SJoseph Chan err = vt1709_auto_fill_dac_nids(spec, &spec->autocfg); 1213*c577b8a1SJoseph Chan if (err < 0) 1214*c577b8a1SJoseph Chan return err; 1215*c577b8a1SJoseph Chan if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) 1216*c577b8a1SJoseph Chan return 0; /* can't find valid BIOS pin config */ 1217*c577b8a1SJoseph Chan 1218*c577b8a1SJoseph Chan err = vt1709_auto_create_multi_out_ctls(spec, &spec->autocfg); 1219*c577b8a1SJoseph Chan if (err < 0) 1220*c577b8a1SJoseph Chan return err; 1221*c577b8a1SJoseph Chan err = vt1709_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); 1222*c577b8a1SJoseph Chan if (err < 0) 1223*c577b8a1SJoseph Chan return err; 1224*c577b8a1SJoseph Chan err = vt1709_auto_create_analog_input_ctls(spec, &spec->autocfg); 1225*c577b8a1SJoseph Chan if (err < 0) 1226*c577b8a1SJoseph Chan return err; 1227*c577b8a1SJoseph Chan 1228*c577b8a1SJoseph Chan spec->multiout.max_channels = spec->multiout.num_dacs * 2; 1229*c577b8a1SJoseph Chan 1230*c577b8a1SJoseph Chan if (spec->autocfg.dig_out_pin) 1231*c577b8a1SJoseph Chan spec->multiout.dig_out_nid = VT1709_DIGOUT_NID; 1232*c577b8a1SJoseph Chan if (spec->autocfg.dig_in_pin) 1233*c577b8a1SJoseph Chan spec->dig_in_nid = VT1709_DIGIN_NID; 1234*c577b8a1SJoseph Chan 1235*c577b8a1SJoseph Chan if (spec->kctl_alloc) 1236*c577b8a1SJoseph Chan spec->mixers[spec->num_mixers++] = spec->kctl_alloc; 1237*c577b8a1SJoseph Chan 1238*c577b8a1SJoseph Chan spec->input_mux = &spec->private_imux; 1239*c577b8a1SJoseph Chan 1240*c577b8a1SJoseph Chan return 1; 1241*c577b8a1SJoseph Chan } 1242*c577b8a1SJoseph Chan 1243*c577b8a1SJoseph Chan static int patch_vt1709_10ch(struct hda_codec *codec) 1244*c577b8a1SJoseph Chan { 1245*c577b8a1SJoseph Chan struct via_spec *spec; 1246*c577b8a1SJoseph Chan int err; 1247*c577b8a1SJoseph Chan 1248*c577b8a1SJoseph Chan /* create a codec specific record */ 1249*c577b8a1SJoseph Chan spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 1250*c577b8a1SJoseph Chan if (spec == NULL) 1251*c577b8a1SJoseph Chan return -ENOMEM; 1252*c577b8a1SJoseph Chan 1253*c577b8a1SJoseph Chan codec->spec = spec; 1254*c577b8a1SJoseph Chan 1255*c577b8a1SJoseph Chan err = vt1709_parse_auto_config(codec); 1256*c577b8a1SJoseph Chan if (err < 0) { 1257*c577b8a1SJoseph Chan via_free(codec); 1258*c577b8a1SJoseph Chan return err; 1259*c577b8a1SJoseph Chan } else if (!err) { 1260*c577b8a1SJoseph Chan printk(KERN_INFO "hda_codec: Cannot set up configuration. " 1261*c577b8a1SJoseph Chan "Using genenic mode...\n"); 1262*c577b8a1SJoseph Chan } 1263*c577b8a1SJoseph Chan 1264*c577b8a1SJoseph Chan spec->init_verbs = vt1709_10ch_volume_init_verbs; 1265*c577b8a1SJoseph Chan 1266*c577b8a1SJoseph Chan spec->stream_name_analog = "VT1709 Analog"; 1267*c577b8a1SJoseph Chan spec->stream_analog_playback = &vt1709_10ch_pcm_analog_playback; 1268*c577b8a1SJoseph Chan spec->stream_analog_capture = &vt1709_pcm_analog_capture; 1269*c577b8a1SJoseph Chan 1270*c577b8a1SJoseph Chan spec->stream_name_digital = "VT1709 Digital"; 1271*c577b8a1SJoseph Chan spec->stream_digital_playback = &vt1709_pcm_digital_playback; 1272*c577b8a1SJoseph Chan spec->stream_digital_capture = &vt1709_pcm_digital_capture; 1273*c577b8a1SJoseph Chan 1274*c577b8a1SJoseph Chan 1275*c577b8a1SJoseph Chan if (!spec->adc_nids && spec->input_mux) { 1276*c577b8a1SJoseph Chan spec->adc_nids = vt1709_adc_nids; 1277*c577b8a1SJoseph Chan spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); 1278*c577b8a1SJoseph Chan spec->mixers[spec->num_mixers] = vt1709_capture_mixer; 1279*c577b8a1SJoseph Chan spec->num_mixers++; 1280*c577b8a1SJoseph Chan } 1281*c577b8a1SJoseph Chan 1282*c577b8a1SJoseph Chan codec->patch_ops = via_patch_ops; 1283*c577b8a1SJoseph Chan 1284*c577b8a1SJoseph Chan codec->patch_ops.init = via_auto_init; 1285*c577b8a1SJoseph Chan 1286*c577b8a1SJoseph Chan return 0; 1287*c577b8a1SJoseph Chan } 1288*c577b8a1SJoseph Chan /* 1289*c577b8a1SJoseph Chan * generic initialization of ADC, input mixers and output mixers 1290*c577b8a1SJoseph Chan */ 1291*c577b8a1SJoseph Chan static struct hda_verb vt1709_6ch_volume_init_verbs[] = { 1292*c577b8a1SJoseph Chan /* 1293*c577b8a1SJoseph Chan * Unmute ADC0-2 and set the default input to mic-in 1294*c577b8a1SJoseph Chan */ 1295*c577b8a1SJoseph Chan {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1296*c577b8a1SJoseph Chan {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1297*c577b8a1SJoseph Chan {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1298*c577b8a1SJoseph Chan 1299*c577b8a1SJoseph Chan 1300*c577b8a1SJoseph Chan /* Unmute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback 1301*c577b8a1SJoseph Chan * mixer widget 1302*c577b8a1SJoseph Chan */ 1303*c577b8a1SJoseph Chan /* Amp Indices: AOW0=0, CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ 1304*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, 1305*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, 1306*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, 1307*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, 1308*c577b8a1SJoseph Chan {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, 1309*c577b8a1SJoseph Chan 1310*c577b8a1SJoseph Chan /* 1311*c577b8a1SJoseph Chan * Set up output selector (0x1a, 0x1b, 0x29) 1312*c577b8a1SJoseph Chan */ 1313*c577b8a1SJoseph Chan /* set vol=0 to output mixers */ 1314*c577b8a1SJoseph Chan {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1315*c577b8a1SJoseph Chan {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1316*c577b8a1SJoseph Chan {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1317*c577b8a1SJoseph Chan 1318*c577b8a1SJoseph Chan /* 1319*c577b8a1SJoseph Chan * Unmute PW3 and PW4 1320*c577b8a1SJoseph Chan */ 1321*c577b8a1SJoseph Chan {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1322*c577b8a1SJoseph Chan {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, 1323*c577b8a1SJoseph Chan 1324*c577b8a1SJoseph Chan /* Set input of PW4 as MW0 */ 1325*c577b8a1SJoseph Chan {0x20, AC_VERB_SET_CONNECT_SEL, 0}, 1326*c577b8a1SJoseph Chan /* Set mic as default input of sw0 */ 1327*c577b8a1SJoseph Chan {0x19, AC_VERB_SET_CONNECT_SEL, 0x2}, 1328*c577b8a1SJoseph Chan /* PW9 Output enable */ 1329*c577b8a1SJoseph Chan {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, 1330*c577b8a1SJoseph Chan { } 1331*c577b8a1SJoseph Chan }; 1332*c577b8a1SJoseph Chan 1333*c577b8a1SJoseph Chan static int patch_vt1709_6ch(struct hda_codec *codec) 1334*c577b8a1SJoseph Chan { 1335*c577b8a1SJoseph Chan struct via_spec *spec; 1336*c577b8a1SJoseph Chan int err; 1337*c577b8a1SJoseph Chan 1338*c577b8a1SJoseph Chan /* create a codec specific record */ 1339*c577b8a1SJoseph Chan spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); 1340*c577b8a1SJoseph Chan if (spec == NULL) 1341*c577b8a1SJoseph Chan return -ENOMEM; 1342*c577b8a1SJoseph Chan 1343*c577b8a1SJoseph Chan codec->spec = spec; 1344*c577b8a1SJoseph Chan 1345*c577b8a1SJoseph Chan err = vt1709_parse_auto_config(codec); 1346*c577b8a1SJoseph Chan if (err < 0) { 1347*c577b8a1SJoseph Chan via_free(codec); 1348*c577b8a1SJoseph Chan return err; 1349*c577b8a1SJoseph Chan } else if (!err) { 1350*c577b8a1SJoseph Chan printk(KERN_INFO "hda_codec: Cannot set up configuration. " 1351*c577b8a1SJoseph Chan "Using genenic mode...\n"); 1352*c577b8a1SJoseph Chan } 1353*c577b8a1SJoseph Chan 1354*c577b8a1SJoseph Chan spec->init_verbs = vt1709_6ch_volume_init_verbs; 1355*c577b8a1SJoseph Chan 1356*c577b8a1SJoseph Chan spec->stream_name_analog = "VT1709 Analog"; 1357*c577b8a1SJoseph Chan spec->stream_analog_playback = &vt1709_6ch_pcm_analog_playback; 1358*c577b8a1SJoseph Chan spec->stream_analog_capture = &vt1709_pcm_analog_capture; 1359*c577b8a1SJoseph Chan 1360*c577b8a1SJoseph Chan spec->stream_name_digital = "VT1709 Digital"; 1361*c577b8a1SJoseph Chan spec->stream_digital_playback = &vt1709_pcm_digital_playback; 1362*c577b8a1SJoseph Chan spec->stream_digital_capture = &vt1709_pcm_digital_capture; 1363*c577b8a1SJoseph Chan 1364*c577b8a1SJoseph Chan 1365*c577b8a1SJoseph Chan if (!spec->adc_nids && spec->input_mux) { 1366*c577b8a1SJoseph Chan spec->adc_nids = vt1709_adc_nids; 1367*c577b8a1SJoseph Chan spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); 1368*c577b8a1SJoseph Chan spec->mixers[spec->num_mixers] = vt1709_capture_mixer; 1369*c577b8a1SJoseph Chan spec->num_mixers++; 1370*c577b8a1SJoseph Chan } 1371*c577b8a1SJoseph Chan 1372*c577b8a1SJoseph Chan codec->patch_ops = via_patch_ops; 1373*c577b8a1SJoseph Chan 1374*c577b8a1SJoseph Chan codec->patch_ops.init = via_auto_init; 1375*c577b8a1SJoseph Chan 1376*c577b8a1SJoseph Chan return 0; 1377*c577b8a1SJoseph Chan } 1378*c577b8a1SJoseph Chan 1379*c577b8a1SJoseph Chan /* 1380*c577b8a1SJoseph Chan * patch entries 1381*c577b8a1SJoseph Chan */ 1382*c577b8a1SJoseph Chan struct hda_codec_preset snd_hda_preset_via[] = { 1383*c577b8a1SJoseph Chan { .id = 0x11061708, .name = "VIA VT1708", .patch = patch_vt1708}, 1384*c577b8a1SJoseph Chan { .id = 0x11061709, .name = "VIA VT1708", .patch = patch_vt1708}, 1385*c577b8a1SJoseph Chan { .id = 0x1106170A, .name = "VIA VT1708", .patch = patch_vt1708}, 1386*c577b8a1SJoseph Chan { .id = 0x1106170B, .name = "VIA VT1708", .patch = patch_vt1708}, 1387*c577b8a1SJoseph Chan { .id = 0x1106E710, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, 1388*c577b8a1SJoseph Chan { .id = 0x1106E711, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, 1389*c577b8a1SJoseph Chan { .id = 0x1106E712, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, 1390*c577b8a1SJoseph Chan { .id = 0x1106E713, .name = "VIA VT1709 10-Ch", .patch = patch_vt1709_10ch}, 1391*c577b8a1SJoseph Chan { .id = 0x1106E714, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, 1392*c577b8a1SJoseph Chan { .id = 0x1106E715, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, 1393*c577b8a1SJoseph Chan { .id = 0x1106E716, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, 1394*c577b8a1SJoseph Chan { .id = 0x1106E717, .name = "VIA VT1709 6-Ch", .patch = patch_vt1709_6ch}, 1395*c577b8a1SJoseph Chan {} /* terminator */ 1396*c577b8a1SJoseph Chan }; 1397