1*c9b443d4STobin Davis /* 2*c9b443d4STobin Davis * HD audio interface patch for Conexant HDA audio codec 3*c9b443d4STobin Davis * 4*c9b443d4STobin Davis * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com> 5*c9b443d4STobin Davis * Takashi Iwai <tiwai@suse.de> 6*c9b443d4STobin Davis * Tobin Davis <tdavis@dsl-only.net> 7*c9b443d4STobin Davis * 8*c9b443d4STobin Davis * This driver is free software; you can redistribute it and/or modify 9*c9b443d4STobin Davis * it under the terms of the GNU General Public License as published by 10*c9b443d4STobin Davis * the Free Software Foundation; either version 2 of the License, or 11*c9b443d4STobin Davis * (at your option) any later version. 12*c9b443d4STobin Davis * 13*c9b443d4STobin Davis * This driver is distributed in the hope that it will be useful, 14*c9b443d4STobin Davis * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*c9b443d4STobin Davis * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*c9b443d4STobin Davis * GNU General Public License for more details. 17*c9b443d4STobin Davis * 18*c9b443d4STobin Davis * You should have received a copy of the GNU General Public License 19*c9b443d4STobin Davis * along with this program; if not, write to the Free Software 20*c9b443d4STobin Davis * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21*c9b443d4STobin Davis */ 22*c9b443d4STobin Davis 23*c9b443d4STobin Davis #include <sound/driver.h> 24*c9b443d4STobin Davis #include <linux/init.h> 25*c9b443d4STobin Davis #include <linux/delay.h> 26*c9b443d4STobin Davis #include <linux/slab.h> 27*c9b443d4STobin Davis #include <linux/pci.h> 28*c9b443d4STobin Davis #include <sound/core.h> 29*c9b443d4STobin Davis #include "hda_codec.h" 30*c9b443d4STobin Davis #include "hda_local.h" 31*c9b443d4STobin Davis 32*c9b443d4STobin Davis #define CXT_PIN_DIR_IN 0x00 33*c9b443d4STobin Davis #define CXT_PIN_DIR_OUT 0x01 34*c9b443d4STobin Davis #define CXT_PIN_DIR_INOUT 0x02 35*c9b443d4STobin Davis #define CXT_PIN_DIR_IN_NOMICBIAS 0x03 36*c9b443d4STobin Davis #define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04 37*c9b443d4STobin Davis 38*c9b443d4STobin Davis #define CONEXANT_HP_EVENT 0x37 39*c9b443d4STobin Davis #define CONEXANT_MIC_EVENT 0x38 40*c9b443d4STobin Davis 41*c9b443d4STobin Davis 42*c9b443d4STobin Davis 43*c9b443d4STobin Davis struct conexant_spec { 44*c9b443d4STobin Davis 45*c9b443d4STobin Davis struct snd_kcontrol_new *mixers[5]; 46*c9b443d4STobin Davis int num_mixers; 47*c9b443d4STobin Davis 48*c9b443d4STobin Davis const struct hda_verb *init_verbs[5]; /* initialization verbs 49*c9b443d4STobin Davis * don't forget NULL 50*c9b443d4STobin Davis * termination! 51*c9b443d4STobin Davis */ 52*c9b443d4STobin Davis unsigned int num_init_verbs; 53*c9b443d4STobin Davis 54*c9b443d4STobin Davis /* playback */ 55*c9b443d4STobin Davis struct hda_multi_out multiout; /* playback set-up 56*c9b443d4STobin Davis * max_channels, dacs must be set 57*c9b443d4STobin Davis * dig_out_nid and hp_nid are optional 58*c9b443d4STobin Davis */ 59*c9b443d4STobin Davis unsigned int cur_eapd; 60*c9b443d4STobin Davis unsigned int need_dac_fix; 61*c9b443d4STobin Davis 62*c9b443d4STobin Davis /* capture */ 63*c9b443d4STobin Davis unsigned int num_adc_nids; 64*c9b443d4STobin Davis hda_nid_t *adc_nids; 65*c9b443d4STobin Davis hda_nid_t dig_in_nid; /* digital-in NID; optional */ 66*c9b443d4STobin Davis 67*c9b443d4STobin Davis /* capture source */ 68*c9b443d4STobin Davis const struct hda_input_mux *input_mux; 69*c9b443d4STobin Davis hda_nid_t *capsrc_nids; 70*c9b443d4STobin Davis unsigned int cur_mux[3]; 71*c9b443d4STobin Davis 72*c9b443d4STobin Davis /* channel model */ 73*c9b443d4STobin Davis const struct hda_channel_mode *channel_mode; 74*c9b443d4STobin Davis int num_channel_mode; 75*c9b443d4STobin Davis 76*c9b443d4STobin Davis /* PCM information */ 77*c9b443d4STobin Davis struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ 78*c9b443d4STobin Davis 79*c9b443d4STobin Davis struct mutex amp_mutex; /* PCM volume/mute control mutex */ 80*c9b443d4STobin Davis unsigned int spdif_route; 81*c9b443d4STobin Davis 82*c9b443d4STobin Davis /* dynamic controls, init_verbs and input_mux */ 83*c9b443d4STobin Davis struct auto_pin_cfg autocfg; 84*c9b443d4STobin Davis unsigned int num_kctl_alloc, num_kctl_used; 85*c9b443d4STobin Davis struct snd_kcontrol_new *kctl_alloc; 86*c9b443d4STobin Davis struct hda_input_mux private_imux; 87*c9b443d4STobin Davis hda_nid_t private_dac_nids[4]; 88*c9b443d4STobin Davis 89*c9b443d4STobin Davis }; 90*c9b443d4STobin Davis 91*c9b443d4STobin Davis static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, 92*c9b443d4STobin Davis struct hda_codec *codec, 93*c9b443d4STobin Davis struct snd_pcm_substream *substream) 94*c9b443d4STobin Davis { 95*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 96*c9b443d4STobin Davis return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream); 97*c9b443d4STobin Davis } 98*c9b443d4STobin Davis 99*c9b443d4STobin Davis static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 100*c9b443d4STobin Davis struct hda_codec *codec, 101*c9b443d4STobin Davis unsigned int stream_tag, 102*c9b443d4STobin Davis unsigned int format, 103*c9b443d4STobin Davis struct snd_pcm_substream *substream) 104*c9b443d4STobin Davis { 105*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 106*c9b443d4STobin Davis return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 107*c9b443d4STobin Davis stream_tag, 108*c9b443d4STobin Davis format, substream); 109*c9b443d4STobin Davis } 110*c9b443d4STobin Davis 111*c9b443d4STobin Davis static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 112*c9b443d4STobin Davis struct hda_codec *codec, 113*c9b443d4STobin Davis struct snd_pcm_substream *substream) 114*c9b443d4STobin Davis { 115*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 116*c9b443d4STobin Davis return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 117*c9b443d4STobin Davis } 118*c9b443d4STobin Davis 119*c9b443d4STobin Davis /* 120*c9b443d4STobin Davis * Digital out 121*c9b443d4STobin Davis */ 122*c9b443d4STobin Davis static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 123*c9b443d4STobin Davis struct hda_codec *codec, 124*c9b443d4STobin Davis struct snd_pcm_substream *substream) 125*c9b443d4STobin Davis { 126*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 127*c9b443d4STobin Davis return snd_hda_multi_out_dig_open(codec, &spec->multiout); 128*c9b443d4STobin Davis } 129*c9b443d4STobin Davis 130*c9b443d4STobin Davis static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 131*c9b443d4STobin Davis struct hda_codec *codec, 132*c9b443d4STobin Davis struct snd_pcm_substream *substream) 133*c9b443d4STobin Davis { 134*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 135*c9b443d4STobin Davis return snd_hda_multi_out_dig_close(codec, &spec->multiout); 136*c9b443d4STobin Davis } 137*c9b443d4STobin Davis 138*c9b443d4STobin Davis /* 139*c9b443d4STobin Davis * Analog capture 140*c9b443d4STobin Davis */ 141*c9b443d4STobin Davis static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 142*c9b443d4STobin Davis struct hda_codec *codec, 143*c9b443d4STobin Davis unsigned int stream_tag, 144*c9b443d4STobin Davis unsigned int format, 145*c9b443d4STobin Davis struct snd_pcm_substream *substream) 146*c9b443d4STobin Davis { 147*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 148*c9b443d4STobin Davis snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 149*c9b443d4STobin Davis stream_tag, 0, format); 150*c9b443d4STobin Davis return 0; 151*c9b443d4STobin Davis } 152*c9b443d4STobin Davis 153*c9b443d4STobin Davis static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 154*c9b443d4STobin Davis struct hda_codec *codec, 155*c9b443d4STobin Davis struct snd_pcm_substream *substream) 156*c9b443d4STobin Davis { 157*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 158*c9b443d4STobin Davis snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 159*c9b443d4STobin Davis 0, 0, 0); 160*c9b443d4STobin Davis return 0; 161*c9b443d4STobin Davis } 162*c9b443d4STobin Davis 163*c9b443d4STobin Davis 164*c9b443d4STobin Davis 165*c9b443d4STobin Davis static struct hda_pcm_stream conexant_pcm_analog_playback = { 166*c9b443d4STobin Davis .substreams = 1, 167*c9b443d4STobin Davis .channels_min = 2, 168*c9b443d4STobin Davis .channels_max = 2, 169*c9b443d4STobin Davis .nid = 0, /* fill later */ 170*c9b443d4STobin Davis .ops = { 171*c9b443d4STobin Davis .open = conexant_playback_pcm_open, 172*c9b443d4STobin Davis .prepare = conexant_playback_pcm_prepare, 173*c9b443d4STobin Davis .cleanup = conexant_playback_pcm_cleanup 174*c9b443d4STobin Davis }, 175*c9b443d4STobin Davis }; 176*c9b443d4STobin Davis 177*c9b443d4STobin Davis static struct hda_pcm_stream conexant_pcm_analog_capture = { 178*c9b443d4STobin Davis .substreams = 1, 179*c9b443d4STobin Davis .channels_min = 2, 180*c9b443d4STobin Davis .channels_max = 2, 181*c9b443d4STobin Davis .nid = 0, /* fill later */ 182*c9b443d4STobin Davis .ops = { 183*c9b443d4STobin Davis .prepare = conexant_capture_pcm_prepare, 184*c9b443d4STobin Davis .cleanup = conexant_capture_pcm_cleanup 185*c9b443d4STobin Davis }, 186*c9b443d4STobin Davis }; 187*c9b443d4STobin Davis 188*c9b443d4STobin Davis 189*c9b443d4STobin Davis static struct hda_pcm_stream conexant_pcm_digital_playback = { 190*c9b443d4STobin Davis .substreams = 1, 191*c9b443d4STobin Davis .channels_min = 2, 192*c9b443d4STobin Davis .channels_max = 2, 193*c9b443d4STobin Davis .nid = 0, /* fill later */ 194*c9b443d4STobin Davis .ops = { 195*c9b443d4STobin Davis .open = conexant_dig_playback_pcm_open, 196*c9b443d4STobin Davis .close = conexant_dig_playback_pcm_close 197*c9b443d4STobin Davis }, 198*c9b443d4STobin Davis }; 199*c9b443d4STobin Davis 200*c9b443d4STobin Davis static struct hda_pcm_stream conexant_pcm_digital_capture = { 201*c9b443d4STobin Davis .substreams = 1, 202*c9b443d4STobin Davis .channels_min = 2, 203*c9b443d4STobin Davis .channels_max = 2, 204*c9b443d4STobin Davis /* NID is set in alc_build_pcms */ 205*c9b443d4STobin Davis }; 206*c9b443d4STobin Davis 207*c9b443d4STobin Davis static int conexant_build_pcms(struct hda_codec *codec) 208*c9b443d4STobin Davis { 209*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 210*c9b443d4STobin Davis struct hda_pcm *info = spec->pcm_rec; 211*c9b443d4STobin Davis 212*c9b443d4STobin Davis codec->num_pcms = 1; 213*c9b443d4STobin Davis codec->pcm_info = info; 214*c9b443d4STobin Davis 215*c9b443d4STobin Davis info->name = "CONEXANT Analog"; 216*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback; 217*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 218*c9b443d4STobin Davis spec->multiout.max_channels; 219*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 220*c9b443d4STobin Davis spec->multiout.dac_nids[0]; 221*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_CAPTURE] = conexant_pcm_analog_capture; 222*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; 223*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 224*c9b443d4STobin Davis 225*c9b443d4STobin Davis if (spec->multiout.dig_out_nid) { 226*c9b443d4STobin Davis info++; 227*c9b443d4STobin Davis codec->num_pcms++; 228*c9b443d4STobin Davis info->name = "Conexant Digital"; 229*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 230*c9b443d4STobin Davis conexant_pcm_digital_playback; 231*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 232*c9b443d4STobin Davis spec->multiout.dig_out_nid; 233*c9b443d4STobin Davis if (spec->dig_in_nid) { 234*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_CAPTURE] = 235*c9b443d4STobin Davis conexant_pcm_digital_capture; 236*c9b443d4STobin Davis info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 237*c9b443d4STobin Davis spec->dig_in_nid; 238*c9b443d4STobin Davis } 239*c9b443d4STobin Davis } 240*c9b443d4STobin Davis 241*c9b443d4STobin Davis return 0; 242*c9b443d4STobin Davis } 243*c9b443d4STobin Davis 244*c9b443d4STobin Davis static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol, 245*c9b443d4STobin Davis struct snd_ctl_elem_info *uinfo) 246*c9b443d4STobin Davis { 247*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 248*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 249*c9b443d4STobin Davis 250*c9b443d4STobin Davis return snd_hda_input_mux_info(spec->input_mux, uinfo); 251*c9b443d4STobin Davis } 252*c9b443d4STobin Davis 253*c9b443d4STobin Davis static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol, 254*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 255*c9b443d4STobin Davis { 256*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 257*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 258*c9b443d4STobin Davis unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 259*c9b443d4STobin Davis 260*c9b443d4STobin Davis ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 261*c9b443d4STobin Davis return 0; 262*c9b443d4STobin Davis } 263*c9b443d4STobin Davis 264*c9b443d4STobin Davis static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, 265*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 266*c9b443d4STobin Davis { 267*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 268*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 269*c9b443d4STobin Davis unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 270*c9b443d4STobin Davis 271*c9b443d4STobin Davis return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 272*c9b443d4STobin Davis spec->capsrc_nids[adc_idx], 273*c9b443d4STobin Davis &spec->cur_mux[adc_idx]); 274*c9b443d4STobin Davis } 275*c9b443d4STobin Davis 276*c9b443d4STobin Davis static int conexant_init(struct hda_codec *codec) 277*c9b443d4STobin Davis { 278*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 279*c9b443d4STobin Davis int i; 280*c9b443d4STobin Davis 281*c9b443d4STobin Davis for (i = 0; i < spec->num_init_verbs; i++) 282*c9b443d4STobin Davis snd_hda_sequence_write(codec, spec->init_verbs[i]); 283*c9b443d4STobin Davis return 0; 284*c9b443d4STobin Davis } 285*c9b443d4STobin Davis 286*c9b443d4STobin Davis static void conexant_free(struct hda_codec *codec) 287*c9b443d4STobin Davis { 288*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 289*c9b443d4STobin Davis unsigned int i; 290*c9b443d4STobin Davis 291*c9b443d4STobin Davis if (spec->kctl_alloc) { 292*c9b443d4STobin Davis for (i = 0; i < spec->num_kctl_used; i++) 293*c9b443d4STobin Davis kfree(spec->kctl_alloc[i].name); 294*c9b443d4STobin Davis kfree(spec->kctl_alloc); 295*c9b443d4STobin Davis } 296*c9b443d4STobin Davis 297*c9b443d4STobin Davis kfree(codec->spec); 298*c9b443d4STobin Davis } 299*c9b443d4STobin Davis 300*c9b443d4STobin Davis #ifdef CONFIG_PM 301*c9b443d4STobin Davis static int conexant_resume(struct hda_codec *codec) 302*c9b443d4STobin Davis { 303*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 304*c9b443d4STobin Davis int i; 305*c9b443d4STobin Davis 306*c9b443d4STobin Davis codec->patch_ops.init(codec); 307*c9b443d4STobin Davis for (i = 0; i < spec->num_mixers; i++) 308*c9b443d4STobin Davis snd_hda_resume_ctls(codec, spec->mixers[i]); 309*c9b443d4STobin Davis if (spec->multiout.dig_out_nid) 310*c9b443d4STobin Davis snd_hda_resume_spdif_out(codec); 311*c9b443d4STobin Davis if (spec->dig_in_nid) 312*c9b443d4STobin Davis snd_hda_resume_spdif_in(codec); 313*c9b443d4STobin Davis return 0; 314*c9b443d4STobin Davis } 315*c9b443d4STobin Davis #endif 316*c9b443d4STobin Davis 317*c9b443d4STobin Davis static int conexant_build_controls(struct hda_codec *codec) 318*c9b443d4STobin Davis { 319*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 320*c9b443d4STobin Davis unsigned int i; 321*c9b443d4STobin Davis int err; 322*c9b443d4STobin Davis 323*c9b443d4STobin Davis for (i = 0; i < spec->num_mixers; i++) { 324*c9b443d4STobin Davis err = snd_hda_add_new_ctls(codec, spec->mixers[i]); 325*c9b443d4STobin Davis if (err < 0) 326*c9b443d4STobin Davis return err; 327*c9b443d4STobin Davis } 328*c9b443d4STobin Davis if (spec->multiout.dig_out_nid) { 329*c9b443d4STobin Davis err = snd_hda_create_spdif_out_ctls(codec, 330*c9b443d4STobin Davis spec->multiout.dig_out_nid); 331*c9b443d4STobin Davis if (err < 0) 332*c9b443d4STobin Davis return err; 333*c9b443d4STobin Davis } 334*c9b443d4STobin Davis if (spec->dig_in_nid) { 335*c9b443d4STobin Davis err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); 336*c9b443d4STobin Davis if (err < 0) 337*c9b443d4STobin Davis return err; 338*c9b443d4STobin Davis } 339*c9b443d4STobin Davis return 0; 340*c9b443d4STobin Davis } 341*c9b443d4STobin Davis 342*c9b443d4STobin Davis static struct hda_codec_ops conexant_patch_ops = { 343*c9b443d4STobin Davis .build_controls = conexant_build_controls, 344*c9b443d4STobin Davis .build_pcms = conexant_build_pcms, 345*c9b443d4STobin Davis .init = conexant_init, 346*c9b443d4STobin Davis .free = conexant_free, 347*c9b443d4STobin Davis #ifdef CONFIG_PM 348*c9b443d4STobin Davis .resume = conexant_resume, 349*c9b443d4STobin Davis #endif 350*c9b443d4STobin Davis }; 351*c9b443d4STobin Davis 352*c9b443d4STobin Davis /* 353*c9b443d4STobin Davis * EAPD control 354*c9b443d4STobin Davis * the private value = nid | (invert << 8) 355*c9b443d4STobin Davis */ 356*c9b443d4STobin Davis 357*c9b443d4STobin Davis static int conexant_eapd_info(struct snd_kcontrol *kcontrol, 358*c9b443d4STobin Davis struct snd_ctl_elem_info *uinfo) 359*c9b443d4STobin Davis { 360*c9b443d4STobin Davis uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 361*c9b443d4STobin Davis uinfo->count = 1; 362*c9b443d4STobin Davis uinfo->value.integer.min = 0; 363*c9b443d4STobin Davis uinfo->value.integer.max = 1; 364*c9b443d4STobin Davis return 0; 365*c9b443d4STobin Davis } 366*c9b443d4STobin Davis 367*c9b443d4STobin Davis static int conexant_eapd_get(struct snd_kcontrol *kcontrol, 368*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 369*c9b443d4STobin Davis { 370*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 371*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 372*c9b443d4STobin Davis int invert = (kcontrol->private_value >> 8) & 1; 373*c9b443d4STobin Davis if (invert) 374*c9b443d4STobin Davis ucontrol->value.integer.value[0] = !spec->cur_eapd; 375*c9b443d4STobin Davis else 376*c9b443d4STobin Davis ucontrol->value.integer.value[0] = spec->cur_eapd; 377*c9b443d4STobin Davis return 0; 378*c9b443d4STobin Davis } 379*c9b443d4STobin Davis 380*c9b443d4STobin Davis static int conexant_eapd_put(struct snd_kcontrol *kcontrol, 381*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 382*c9b443d4STobin Davis { 383*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 384*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 385*c9b443d4STobin Davis int invert = (kcontrol->private_value >> 8) & 1; 386*c9b443d4STobin Davis hda_nid_t nid = kcontrol->private_value & 0xff; 387*c9b443d4STobin Davis unsigned int eapd; 388*c9b443d4STobin Davis eapd = ucontrol->value.integer.value[0]; 389*c9b443d4STobin Davis if (invert) 390*c9b443d4STobin Davis eapd = !eapd; 391*c9b443d4STobin Davis if (eapd == spec->cur_eapd && !codec->in_resume) 392*c9b443d4STobin Davis return 0; 393*c9b443d4STobin Davis spec->cur_eapd = eapd; 394*c9b443d4STobin Davis snd_hda_codec_write(codec, nid, 395*c9b443d4STobin Davis 0, AC_VERB_SET_EAPD_BTLENABLE, 396*c9b443d4STobin Davis eapd ? 0x02 : 0x00); 397*c9b443d4STobin Davis return 1; 398*c9b443d4STobin Davis } 399*c9b443d4STobin Davis 400*c9b443d4STobin Davis static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, 401*c9b443d4STobin Davis struct snd_ctl_elem_info *uinfo) 402*c9b443d4STobin Davis { 403*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 404*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 405*c9b443d4STobin Davis return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, 406*c9b443d4STobin Davis spec->num_channel_mode); 407*c9b443d4STobin Davis } 408*c9b443d4STobin Davis 409*c9b443d4STobin Davis static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol, 410*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 411*c9b443d4STobin Davis { 412*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 413*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 414*c9b443d4STobin Davis return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, 415*c9b443d4STobin Davis spec->num_channel_mode, 416*c9b443d4STobin Davis spec->multiout.max_channels); 417*c9b443d4STobin Davis } 418*c9b443d4STobin Davis 419*c9b443d4STobin Davis static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, 420*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 421*c9b443d4STobin Davis { 422*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 423*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 424*c9b443d4STobin Davis int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, 425*c9b443d4STobin Davis spec->num_channel_mode, 426*c9b443d4STobin Davis &spec->multiout.max_channels); 427*c9b443d4STobin Davis if (err >= 0 && spec->need_dac_fix) 428*c9b443d4STobin Davis spec->multiout.num_dacs = spec->multiout.max_channels / 2; 429*c9b443d4STobin Davis return err; 430*c9b443d4STobin Davis } 431*c9b443d4STobin Davis 432*c9b443d4STobin Davis #define CXT_PIN_MODE(xname, nid, dir) \ 433*c9b443d4STobin Davis { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ 434*c9b443d4STobin Davis .info = conexant_ch_mode_info, \ 435*c9b443d4STobin Davis .get = conexant_ch_mode_get, \ 436*c9b443d4STobin Davis .put = conexant_ch_mode_put, \ 437*c9b443d4STobin Davis .private_value = nid | (dir<<16) } 438*c9b443d4STobin Davis 439*c9b443d4STobin Davis static int cxt_gpio_data_info(struct snd_kcontrol *kcontrol, 440*c9b443d4STobin Davis struct snd_ctl_elem_info *uinfo) 441*c9b443d4STobin Davis { 442*c9b443d4STobin Davis uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 443*c9b443d4STobin Davis uinfo->count = 1; 444*c9b443d4STobin Davis uinfo->value.integer.min = 0; 445*c9b443d4STobin Davis uinfo->value.integer.max = 1; 446*c9b443d4STobin Davis return 0; 447*c9b443d4STobin Davis } 448*c9b443d4STobin Davis 449*c9b443d4STobin Davis static int cxt_gpio_data_get(struct snd_kcontrol *kcontrol, 450*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 451*c9b443d4STobin Davis { 452*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 453*c9b443d4STobin Davis hda_nid_t nid = kcontrol->private_value & 0xffff; 454*c9b443d4STobin Davis unsigned char mask = (kcontrol->private_value >> 16) & 0xff; 455*c9b443d4STobin Davis long *valp = ucontrol->value.integer.value; 456*c9b443d4STobin Davis unsigned int val = snd_hda_codec_read(codec, nid, 0, 457*c9b443d4STobin Davis AC_VERB_GET_GPIO_DATA, 0x00); 458*c9b443d4STobin Davis 459*c9b443d4STobin Davis *valp = (val & mask) != 0; 460*c9b443d4STobin Davis return 0; 461*c9b443d4STobin Davis } 462*c9b443d4STobin Davis 463*c9b443d4STobin Davis static int cxt_gpio_data_put(struct snd_kcontrol *kcontrol, 464*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 465*c9b443d4STobin Davis { 466*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 467*c9b443d4STobin Davis hda_nid_t nid = kcontrol->private_value & 0xffff; 468*c9b443d4STobin Davis unsigned char mask = (kcontrol->private_value >> 16) & 0xff; 469*c9b443d4STobin Davis long val = *ucontrol->value.integer.value; 470*c9b443d4STobin Davis unsigned int gpio_data = snd_hda_codec_read(codec, nid, 0, 471*c9b443d4STobin Davis AC_VERB_GET_GPIO_DATA, 472*c9b443d4STobin Davis 0x00); 473*c9b443d4STobin Davis unsigned int old_data = gpio_data; 474*c9b443d4STobin Davis 475*c9b443d4STobin Davis /* Set/unset the masked GPIO bit(s) as needed */ 476*c9b443d4STobin Davis if (val == 0) 477*c9b443d4STobin Davis gpio_data &= ~mask; 478*c9b443d4STobin Davis else 479*c9b443d4STobin Davis gpio_data |= mask; 480*c9b443d4STobin Davis if (gpio_data == old_data && !codec->in_resume) 481*c9b443d4STobin Davis return 0; 482*c9b443d4STobin Davis snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_GPIO_DATA, gpio_data); 483*c9b443d4STobin Davis return 1; 484*c9b443d4STobin Davis } 485*c9b443d4STobin Davis 486*c9b443d4STobin Davis #define CXT_GPIO_DATA_SWITCH(xname, nid, mask) \ 487*c9b443d4STobin Davis { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ 488*c9b443d4STobin Davis .info = cxt_gpio_data_info, \ 489*c9b443d4STobin Davis .get = cxt_gpio_data_get, \ 490*c9b443d4STobin Davis .put = cxt_gpio_data_put, \ 491*c9b443d4STobin Davis .private_value = nid | (mask<<16) } 492*c9b443d4STobin Davis 493*c9b443d4STobin Davis static int cxt_spdif_ctrl_info(struct snd_kcontrol *kcontrol, 494*c9b443d4STobin Davis struct snd_ctl_elem_info *uinfo) 495*c9b443d4STobin Davis { 496*c9b443d4STobin Davis uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 497*c9b443d4STobin Davis uinfo->count = 1; 498*c9b443d4STobin Davis uinfo->value.integer.min = 0; 499*c9b443d4STobin Davis uinfo->value.integer.max = 1; 500*c9b443d4STobin Davis return 0; 501*c9b443d4STobin Davis } 502*c9b443d4STobin Davis 503*c9b443d4STobin Davis static int cxt_spdif_ctrl_get(struct snd_kcontrol *kcontrol, 504*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 505*c9b443d4STobin Davis { 506*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 507*c9b443d4STobin Davis hda_nid_t nid = kcontrol->private_value & 0xffff; 508*c9b443d4STobin Davis unsigned char mask = (kcontrol->private_value >> 16) & 0xff; 509*c9b443d4STobin Davis long *valp = ucontrol->value.integer.value; 510*c9b443d4STobin Davis unsigned int val = snd_hda_codec_read(codec, nid, 0, 511*c9b443d4STobin Davis AC_VERB_GET_DIGI_CONVERT, 0x00); 512*c9b443d4STobin Davis 513*c9b443d4STobin Davis *valp = (val & mask) != 0; 514*c9b443d4STobin Davis return 0; 515*c9b443d4STobin Davis } 516*c9b443d4STobin Davis 517*c9b443d4STobin Davis static int cxt_spdif_ctrl_put(struct snd_kcontrol *kcontrol, 518*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 519*c9b443d4STobin Davis { 520*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 521*c9b443d4STobin Davis hda_nid_t nid = kcontrol->private_value & 0xffff; 522*c9b443d4STobin Davis unsigned char mask = (kcontrol->private_value >> 16) & 0xff; 523*c9b443d4STobin Davis long val = *ucontrol->value.integer.value; 524*c9b443d4STobin Davis unsigned int ctrl_data = snd_hda_codec_read(codec, nid, 0, 525*c9b443d4STobin Davis AC_VERB_GET_DIGI_CONVERT, 526*c9b443d4STobin Davis 0x00); 527*c9b443d4STobin Davis unsigned int old_data = ctrl_data; 528*c9b443d4STobin Davis 529*c9b443d4STobin Davis /* Set/unset the masked control bit(s) as needed */ 530*c9b443d4STobin Davis if (val == 0) 531*c9b443d4STobin Davis ctrl_data &= ~mask; 532*c9b443d4STobin Davis else 533*c9b443d4STobin Davis ctrl_data |= mask; 534*c9b443d4STobin Davis if (ctrl_data == old_data && !codec->in_resume) 535*c9b443d4STobin Davis return 0; 536*c9b443d4STobin Davis snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, 537*c9b443d4STobin Davis ctrl_data); 538*c9b443d4STobin Davis return 1; 539*c9b443d4STobin Davis } 540*c9b443d4STobin Davis 541*c9b443d4STobin Davis #define CXT_SPDIF_CTRL_SWITCH(xname, nid, mask) \ 542*c9b443d4STobin Davis { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ 543*c9b443d4STobin Davis .info = cxt_spdif_ctrl_info, \ 544*c9b443d4STobin Davis .get = cxt_spdif_ctrl_get, \ 545*c9b443d4STobin Davis .put = cxt_spdif_ctrl_put, \ 546*c9b443d4STobin Davis .private_value = nid | (mask<<16) } 547*c9b443d4STobin Davis 548*c9b443d4STobin Davis /* Conexant 5045 specific */ 549*c9b443d4STobin Davis 550*c9b443d4STobin Davis static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; 551*c9b443d4STobin Davis static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; 552*c9b443d4STobin Davis static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; 553*c9b443d4STobin Davis #define CXT5045_SPDIF_OUT 0x13 554*c9b443d4STobin Davis 555*c9b443d4STobin Davis 556*c9b443d4STobin Davis static struct hda_input_mux cxt5045_capture_source = { 557*c9b443d4STobin Davis .num_items = 2, 558*c9b443d4STobin Davis .items = { 559*c9b443d4STobin Davis { "ExtMic", 0x1 }, 560*c9b443d4STobin Davis { "LineIn", 0x2 }, 561*c9b443d4STobin Davis } 562*c9b443d4STobin Davis }; 563*c9b443d4STobin Davis 564*c9b443d4STobin Davis /* turn on/off EAPD (+ mute HP) as a master switch */ 565*c9b443d4STobin Davis static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, 566*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 567*c9b443d4STobin Davis { 568*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 569*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 570*c9b443d4STobin Davis 571*c9b443d4STobin Davis if (!conexant_eapd_put(kcontrol, ucontrol)) 572*c9b443d4STobin Davis return 0; 573*c9b443d4STobin Davis 574*c9b443d4STobin Davis /* toggle HP mute appropriately */ 575*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, 576*c9b443d4STobin Davis 0x80, spec->cur_eapd ? 0 : 0x80); 577*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, 578*c9b443d4STobin Davis 0x80, spec->cur_eapd ? 0 : 0x80); 579*c9b443d4STobin Davis return 1; 580*c9b443d4STobin Davis } 581*c9b443d4STobin Davis 582*c9b443d4STobin Davis /* bind volumes of both NID 0x10 and 0x11 */ 583*c9b443d4STobin Davis static int cxt5045_hp_master_vol_put(struct snd_kcontrol *kcontrol, 584*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 585*c9b443d4STobin Davis { 586*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 587*c9b443d4STobin Davis long *valp = ucontrol->value.integer.value; 588*c9b443d4STobin Davis int change; 589*c9b443d4STobin Davis 590*c9b443d4STobin Davis change = snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 591*c9b443d4STobin Davis 0x7f, valp[0] & 0x7f); 592*c9b443d4STobin Davis change |= snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 593*c9b443d4STobin Davis 0x7f, valp[1] & 0x7f); 594*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x11, 0, HDA_OUTPUT, 0, 595*c9b443d4STobin Davis 0x7f, valp[0] & 0x7f); 596*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x11, 1, HDA_OUTPUT, 0, 597*c9b443d4STobin Davis 0x7f, valp[1] & 0x7f); 598*c9b443d4STobin Davis return change; 599*c9b443d4STobin Davis } 600*c9b443d4STobin Davis 601*c9b443d4STobin Davis 602*c9b443d4STobin Davis /* mute internal speaker if HP is plugged */ 603*c9b443d4STobin Davis static void cxt5045_hp_automute(struct hda_codec *codec) 604*c9b443d4STobin Davis { 605*c9b443d4STobin Davis unsigned int present; 606*c9b443d4STobin Davis 607*c9b443d4STobin Davis present = snd_hda_codec_read(codec, 0x11, 0, 608*c9b443d4STobin Davis AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; 609*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x10, 0, HDA_OUTPUT, 0, 610*c9b443d4STobin Davis 0x80, present ? 0x80 : 0); 611*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x10, 1, HDA_OUTPUT, 0, 612*c9b443d4STobin Davis 0x80, present ? 0x80 : 0); 613*c9b443d4STobin Davis } 614*c9b443d4STobin Davis 615*c9b443d4STobin Davis /* unsolicited event for HP jack sensing */ 616*c9b443d4STobin Davis static void cxt5045_hp_unsol_event(struct hda_codec *codec, 617*c9b443d4STobin Davis unsigned int res) 618*c9b443d4STobin Davis { 619*c9b443d4STobin Davis res >>= 26; 620*c9b443d4STobin Davis switch (res) { 621*c9b443d4STobin Davis case CONEXANT_HP_EVENT: 622*c9b443d4STobin Davis cxt5045_hp_automute(codec); 623*c9b443d4STobin Davis break; 624*c9b443d4STobin Davis } 625*c9b443d4STobin Davis } 626*c9b443d4STobin Davis 627*c9b443d4STobin Davis static struct snd_kcontrol_new cxt5045_mixers[] = { 628*c9b443d4STobin Davis { 629*c9b443d4STobin Davis .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 630*c9b443d4STobin Davis .name = "Capture Source", 631*c9b443d4STobin Davis .info = conexant_mux_enum_info, 632*c9b443d4STobin Davis .get = conexant_mux_enum_get, 633*c9b443d4STobin Davis .put = conexant_mux_enum_put 634*c9b443d4STobin Davis }, 635*c9b443d4STobin Davis HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x17, 0x02, HDA_INPUT), 636*c9b443d4STobin Davis HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x17, 0x02, HDA_INPUT), 637*c9b443d4STobin Davis HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x02, HDA_INPUT), 638*c9b443d4STobin Davis HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x02, HDA_INPUT), 639*c9b443d4STobin Davis { 640*c9b443d4STobin Davis .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 641*c9b443d4STobin Davis .name = "Master Playback Volume", 642*c9b443d4STobin Davis .info = snd_hda_mixer_amp_volume_info, 643*c9b443d4STobin Davis .get = snd_hda_mixer_amp_volume_get, 644*c9b443d4STobin Davis .put = cxt5045_hp_master_vol_put, 645*c9b443d4STobin Davis .private_value = HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), 646*c9b443d4STobin Davis }, 647*c9b443d4STobin Davis { 648*c9b443d4STobin Davis .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 649*c9b443d4STobin Davis .name = "Master Playback Switch", 650*c9b443d4STobin Davis .info = conexant_eapd_info, 651*c9b443d4STobin Davis .get = conexant_eapd_get, 652*c9b443d4STobin Davis .put = cxt5045_hp_master_sw_put, 653*c9b443d4STobin Davis .private_value = 0x11, 654*c9b443d4STobin Davis }, 655*c9b443d4STobin Davis 656*c9b443d4STobin Davis {} 657*c9b443d4STobin Davis }; 658*c9b443d4STobin Davis 659*c9b443d4STobin Davis static struct hda_verb cxt5045_init_verbs[] = { 660*c9b443d4STobin Davis /* Line in, Mic */ 661*c9b443d4STobin Davis {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, 662*c9b443d4STobin Davis {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, 663*c9b443d4STobin Davis /* HP, Amp */ 664*c9b443d4STobin Davis {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 665*c9b443d4STobin Davis {0x1A, AC_VERB_SET_CONNECT_SEL,0x01}, 666*c9b443d4STobin Davis {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, 667*c9b443d4STobin Davis AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, 668*c9b443d4STobin Davis {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, 669*c9b443d4STobin Davis AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, 670*c9b443d4STobin Davis /* Record selector: Front mic */ 671*c9b443d4STobin Davis {0x14, AC_VERB_SET_CONNECT_SEL,0x03}, 672*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 673*c9b443d4STobin Davis AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, 674*c9b443d4STobin Davis /* SPDIF route: PCM */ 675*c9b443d4STobin Davis { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, 676*c9b443d4STobin Davis /* pin sensing on HP and Mic jacks */ 677*c9b443d4STobin Davis {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 678*c9b443d4STobin Davis /* EAPD */ 679*c9b443d4STobin Davis {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */ 680*c9b443d4STobin Davis { } /* end */ 681*c9b443d4STobin Davis }; 682*c9b443d4STobin Davis 683*c9b443d4STobin Davis #ifdef CONFIG_SND_DEBUG 684*c9b443d4STobin Davis /* Test configuration for debugging, modelled after the ALC260 test 685*c9b443d4STobin Davis * configuration. 686*c9b443d4STobin Davis */ 687*c9b443d4STobin Davis static struct hda_input_mux cxt5045_test_capture_source = { 688*c9b443d4STobin Davis .num_items = 5, 689*c9b443d4STobin Davis .items = { 690*c9b443d4STobin Davis { "MIXER", 0x0 }, 691*c9b443d4STobin Davis { "MIC1 pin", 0x1 }, 692*c9b443d4STobin Davis { "LINE1 pin", 0x2 }, 693*c9b443d4STobin Davis { "HP-OUT pin", 0x3 }, 694*c9b443d4STobin Davis { "CD pin", 0x4 }, 695*c9b443d4STobin Davis }, 696*c9b443d4STobin Davis }; 697*c9b443d4STobin Davis 698*c9b443d4STobin Davis static struct snd_kcontrol_new cxt5045_test_mixer[] = { 699*c9b443d4STobin Davis 700*c9b443d4STobin Davis /* Output controls */ 701*c9b443d4STobin Davis HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x19, 0x00, HDA_OUTPUT), 702*c9b443d4STobin Davis HDA_CODEC_MUTE("OutAmp-1 Switch", 0x19,0x00, HDA_OUTPUT), 703*c9b443d4STobin Davis HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), 704*c9b443d4STobin Davis HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), 705*c9b443d4STobin Davis 706*c9b443d4STobin Davis /* Modes for retasking pin widgets */ 707*c9b443d4STobin Davis CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), 708*c9b443d4STobin Davis CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), 709*c9b443d4STobin Davis 710*c9b443d4STobin Davis /* Loopback mixer controls */ 711*c9b443d4STobin Davis HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x17, 0x01, HDA_INPUT), 712*c9b443d4STobin Davis HDA_CODEC_MUTE("MIC1 Playback Switch", 0x17, 0x01, HDA_INPUT), 713*c9b443d4STobin Davis HDA_CODEC_VOLUME("LINE loopback Playback Volume", 0x17, 0x02, HDA_INPUT), 714*c9b443d4STobin Davis HDA_CODEC_MUTE("LINE loopback Playback Switch", 0x17, 0x02, HDA_INPUT), 715*c9b443d4STobin Davis HDA_CODEC_VOLUME("HP-OUT loopback Playback Volume", 0x17, 0x03, HDA_INPUT), 716*c9b443d4STobin Davis HDA_CODEC_MUTE("HP-OUT loopback Playback Switch", 0x17, 0x03, HDA_INPUT), 717*c9b443d4STobin Davis HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x04, HDA_INPUT), 718*c9b443d4STobin Davis HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x04, HDA_INPUT), 719*c9b443d4STobin Davis 720*c9b443d4STobin Davis /* Controls for GPIO pins, assuming they exist and are configured as outputs */ 721*c9b443d4STobin Davis CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), 722*c9b443d4STobin Davis #if 0 /* limit this to one GPIO pin for now */ 723*c9b443d4STobin Davis CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), 724*c9b443d4STobin Davis CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), 725*c9b443d4STobin Davis CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), 726*c9b443d4STobin Davis #endif 727*c9b443d4STobin Davis CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x13, 0x01), 728*c9b443d4STobin Davis 729*c9b443d4STobin Davis HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_OUTPUT), 730*c9b443d4STobin Davis HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_OUTPUT), 731*c9b443d4STobin Davis { 732*c9b443d4STobin Davis .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 733*c9b443d4STobin Davis .name = "Input Source", 734*c9b443d4STobin Davis .info = conexant_mux_enum_info, 735*c9b443d4STobin Davis .get = conexant_mux_enum_get, 736*c9b443d4STobin Davis .put = conexant_mux_enum_put, 737*c9b443d4STobin Davis }, 738*c9b443d4STobin Davis 739*c9b443d4STobin Davis { } /* end */ 740*c9b443d4STobin Davis }; 741*c9b443d4STobin Davis 742*c9b443d4STobin Davis static struct hda_verb cxt5045_test_init_verbs[] = { 743*c9b443d4STobin Davis /* Enable all GPIOs as outputs with an initial value of 0 */ 744*c9b443d4STobin Davis {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, 745*c9b443d4STobin Davis {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, 746*c9b443d4STobin Davis {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, 747*c9b443d4STobin Davis 748*c9b443d4STobin Davis /* Enable retasking pins as output, initially without power amp */ 749*c9b443d4STobin Davis {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 750*c9b443d4STobin Davis {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 751*c9b443d4STobin Davis 752*c9b443d4STobin Davis /* Disable digital (SPDIF) pins initially, but users can enable 753*c9b443d4STobin Davis * them via a mixer switch. In the case of SPDIF-out, this initverb 754*c9b443d4STobin Davis * payload also sets the generation to 0, output to be in "consumer" 755*c9b443d4STobin Davis * PCM format, copyright asserted, no pre-emphasis and no validity 756*c9b443d4STobin Davis * control. 757*c9b443d4STobin Davis */ 758*c9b443d4STobin Davis {0x13, AC_VERB_SET_DIGI_CONVERT_1, 0}, 759*c9b443d4STobin Davis 760*c9b443d4STobin Davis /* Start with output sum widgets muted and their output gains at min */ 761*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 762*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 763*c9b443d4STobin Davis 764*c9b443d4STobin Davis /* Unmute retasking pin widget output buffers since the default 765*c9b443d4STobin Davis * state appears to be output. As the pin mode is changed by the 766*c9b443d4STobin Davis * user the pin mode control will take care of enabling the pin's 767*c9b443d4STobin Davis * input/output buffers as needed. 768*c9b443d4STobin Davis */ 769*c9b443d4STobin Davis {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 770*c9b443d4STobin Davis {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 771*c9b443d4STobin Davis 772*c9b443d4STobin Davis /* Mute capture amp left and right */ 773*c9b443d4STobin Davis {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 774*c9b443d4STobin Davis 775*c9b443d4STobin Davis /* Set ADC connection select to match default mixer setting (mic1 776*c9b443d4STobin Davis * pin) 777*c9b443d4STobin Davis */ 778*c9b443d4STobin Davis {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, 779*c9b443d4STobin Davis 780*c9b443d4STobin Davis /* Mute all inputs to mixer widget (even unconnected ones) */ 781*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */ 782*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ 783*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ 784*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ 785*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ 786*c9b443d4STobin Davis 787*c9b443d4STobin Davis { } 788*c9b443d4STobin Davis }; 789*c9b443d4STobin Davis #endif 790*c9b443d4STobin Davis 791*c9b443d4STobin Davis 792*c9b443d4STobin Davis /* initialize jack-sensing, too */ 793*c9b443d4STobin Davis static int cxt5045_init(struct hda_codec *codec) 794*c9b443d4STobin Davis { 795*c9b443d4STobin Davis conexant_init(codec); 796*c9b443d4STobin Davis cxt5045_hp_automute(codec); 797*c9b443d4STobin Davis return 0; 798*c9b443d4STobin Davis } 799*c9b443d4STobin Davis 800*c9b443d4STobin Davis 801*c9b443d4STobin Davis enum { 802*c9b443d4STobin Davis CXT5045_LAPTOP, 803*c9b443d4STobin Davis #ifdef CONFIG_SND_DEBUG 804*c9b443d4STobin Davis CXT5045_TEST, 805*c9b443d4STobin Davis #endif 806*c9b443d4STobin Davis }; 807*c9b443d4STobin Davis 808*c9b443d4STobin Davis static struct hda_board_config cxt5045_cfg_tbl[] = { 809*c9b443d4STobin Davis /* Laptops w/ EAPD support */ 810*c9b443d4STobin Davis { .modelname = "laptop", .config = CXT5045_LAPTOP }, 811*c9b443d4STobin Davis /* HP DV6000Z */ 812*c9b443d4STobin Davis { .pci_subvendor = 0x103c, .pci_subdevice = 0x30b7, 813*c9b443d4STobin Davis .config = CXT5045_LAPTOP }, 814*c9b443d4STobin Davis #ifdef CONFIG_SND_DEBUG 815*c9b443d4STobin Davis { .modelname = "test", .config = CXT5045_TEST }, 816*c9b443d4STobin Davis #endif 817*c9b443d4STobin Davis 818*c9b443d4STobin Davis {} 819*c9b443d4STobin Davis }; 820*c9b443d4STobin Davis 821*c9b443d4STobin Davis static int patch_cxt5045(struct hda_codec *codec) 822*c9b443d4STobin Davis { 823*c9b443d4STobin Davis struct conexant_spec *spec; 824*c9b443d4STobin Davis int board_config; 825*c9b443d4STobin Davis 826*c9b443d4STobin Davis spec = kzalloc(sizeof(*spec), GFP_KERNEL); 827*c9b443d4STobin Davis if (!spec) 828*c9b443d4STobin Davis return -ENOMEM; 829*c9b443d4STobin Davis mutex_init(&spec->amp_mutex); 830*c9b443d4STobin Davis codec->spec = spec; 831*c9b443d4STobin Davis 832*c9b443d4STobin Davis spec->multiout.max_channels = 2; 833*c9b443d4STobin Davis spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); 834*c9b443d4STobin Davis spec->multiout.dac_nids = cxt5045_dac_nids; 835*c9b443d4STobin Davis spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT; 836*c9b443d4STobin Davis spec->num_adc_nids = 1; 837*c9b443d4STobin Davis spec->adc_nids = cxt5045_adc_nids; 838*c9b443d4STobin Davis spec->capsrc_nids = cxt5045_capsrc_nids; 839*c9b443d4STobin Davis spec->input_mux = &cxt5045_capture_source; 840*c9b443d4STobin Davis spec->num_mixers = 1; 841*c9b443d4STobin Davis spec->mixers[0] = cxt5045_mixers; 842*c9b443d4STobin Davis spec->num_init_verbs = 1; 843*c9b443d4STobin Davis spec->init_verbs[0] = cxt5045_init_verbs; 844*c9b443d4STobin Davis spec->spdif_route = 0; 845*c9b443d4STobin Davis 846*c9b443d4STobin Davis codec->patch_ops = conexant_patch_ops; 847*c9b443d4STobin Davis codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; 848*c9b443d4STobin Davis 849*c9b443d4STobin Davis board_config = snd_hda_check_board_config(codec, cxt5045_cfg_tbl); 850*c9b443d4STobin Davis switch (board_config) { 851*c9b443d4STobin Davis case CXT5045_LAPTOP: 852*c9b443d4STobin Davis spec->input_mux = &cxt5045_capture_source; 853*c9b443d4STobin Davis spec->num_init_verbs = 2; 854*c9b443d4STobin Davis spec->init_verbs[1] = cxt5045_init_verbs; 855*c9b443d4STobin Davis spec->mixers[0] = cxt5045_mixers; 856*c9b443d4STobin Davis codec->patch_ops.init = cxt5045_init; 857*c9b443d4STobin Davis break; 858*c9b443d4STobin Davis #ifdef CONFIG_SND_DEBUG 859*c9b443d4STobin Davis case CXT5045_TEST: 860*c9b443d4STobin Davis spec->input_mux = &cxt5045_test_capture_source; 861*c9b443d4STobin Davis spec->mixers[0] = cxt5045_test_mixer; 862*c9b443d4STobin Davis spec->init_verbs[0] = cxt5045_test_init_verbs; 863*c9b443d4STobin Davis #endif 864*c9b443d4STobin Davis } 865*c9b443d4STobin Davis return 0; 866*c9b443d4STobin Davis } 867*c9b443d4STobin Davis 868*c9b443d4STobin Davis 869*c9b443d4STobin Davis /* Conexant 5047 specific */ 870*c9b443d4STobin Davis 871*c9b443d4STobin Davis static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; 872*c9b443d4STobin Davis static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; 873*c9b443d4STobin Davis static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; 874*c9b443d4STobin Davis #define CXT5047_SPDIF_OUT 0x11 875*c9b443d4STobin Davis 876*c9b443d4STobin Davis 877*c9b443d4STobin Davis static struct hda_input_mux cxt5047_capture_source = { 878*c9b443d4STobin Davis .num_items = 2, 879*c9b443d4STobin Davis .items = { 880*c9b443d4STobin Davis { "ExtMic", 0x1 }, 881*c9b443d4STobin Davis { "IntMic", 0x2 }, 882*c9b443d4STobin Davis } 883*c9b443d4STobin Davis }; 884*c9b443d4STobin Davis 885*c9b443d4STobin Davis static struct hda_input_mux cxt5047_hp_capture_source = { 886*c9b443d4STobin Davis .num_items = 1, 887*c9b443d4STobin Davis .items = { 888*c9b443d4STobin Davis { "ExtMic", 0x1 }, 889*c9b443d4STobin Davis } 890*c9b443d4STobin Davis }; 891*c9b443d4STobin Davis 892*c9b443d4STobin Davis /* turn on/off EAPD (+ mute HP) as a master switch */ 893*c9b443d4STobin Davis static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, 894*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 895*c9b443d4STobin Davis { 896*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 897*c9b443d4STobin Davis struct conexant_spec *spec = codec->spec; 898*c9b443d4STobin Davis 899*c9b443d4STobin Davis if (!conexant_eapd_put(kcontrol, ucontrol)) 900*c9b443d4STobin Davis return 0; 901*c9b443d4STobin Davis 902*c9b443d4STobin Davis /* toggle HP mute appropriately */ 903*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, 904*c9b443d4STobin Davis 0x80, spec->cur_eapd ? 0 : 0x80); 905*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, 906*c9b443d4STobin Davis 0x80, spec->cur_eapd ? 0 : 0x80); 907*c9b443d4STobin Davis return 1; 908*c9b443d4STobin Davis } 909*c9b443d4STobin Davis 910*c9b443d4STobin Davis #if 0 911*c9b443d4STobin Davis /* bind volumes of both NID 0x13 and 0x1d */ 912*c9b443d4STobin Davis static int cxt5047_hp_master_vol_put(struct snd_kcontrol *kcontrol, 913*c9b443d4STobin Davis struct snd_ctl_elem_value *ucontrol) 914*c9b443d4STobin Davis { 915*c9b443d4STobin Davis struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 916*c9b443d4STobin Davis long *valp = ucontrol->value.integer.value; 917*c9b443d4STobin Davis int change; 918*c9b443d4STobin Davis 919*c9b443d4STobin Davis change = snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 920*c9b443d4STobin Davis 0x7f, valp[0] & 0x7f); 921*c9b443d4STobin Davis change |= snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 922*c9b443d4STobin Davis 0x7f, valp[1] & 0x7f); 923*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x13, 0, HDA_OUTPUT, 0, 924*c9b443d4STobin Davis 0x7f, valp[0] & 0x7f); 925*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x13, 1, HDA_OUTPUT, 0, 926*c9b443d4STobin Davis 0x7f, valp[1] & 0x7f); 927*c9b443d4STobin Davis return change; 928*c9b443d4STobin Davis } 929*c9b443d4STobin Davis #endif 930*c9b443d4STobin Davis 931*c9b443d4STobin Davis /* mute internal speaker if HP is plugged */ 932*c9b443d4STobin Davis static void cxt5047_hp_automute(struct hda_codec *codec) 933*c9b443d4STobin Davis { 934*c9b443d4STobin Davis unsigned int present; 935*c9b443d4STobin Davis 936*c9b443d4STobin Davis present = snd_hda_codec_read(codec, 0x13, 0, 937*c9b443d4STobin Davis AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; 938*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x1c, 0, HDA_OUTPUT, 0, 939*c9b443d4STobin Davis 0x80, present ? 0x80 : 0); 940*c9b443d4STobin Davis snd_hda_codec_amp_update(codec, 0x1c, 1, HDA_OUTPUT, 0, 941*c9b443d4STobin Davis 0x80, present ? 0x80 : 0); 942*c9b443d4STobin Davis } 943*c9b443d4STobin Davis 944*c9b443d4STobin Davis /* toggle input of built-in and mic jack appropriately */ 945*c9b443d4STobin Davis static void cxt5047_hp_automic(struct hda_codec *codec) 946*c9b443d4STobin Davis { 947*c9b443d4STobin Davis static struct hda_verb mic_jack_on[] = { 948*c9b443d4STobin Davis {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, 949*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, 950*c9b443d4STobin Davis {} 951*c9b443d4STobin Davis }; 952*c9b443d4STobin Davis static struct hda_verb mic_jack_off[] = { 953*c9b443d4STobin Davis {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, 954*c9b443d4STobin Davis {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, 955*c9b443d4STobin Davis {} 956*c9b443d4STobin Davis }; 957*c9b443d4STobin Davis unsigned int present; 958*c9b443d4STobin Davis 959*c9b443d4STobin Davis present = snd_hda_codec_read(codec, 0x08, 0, 960*c9b443d4STobin Davis AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; 961*c9b443d4STobin Davis if (present) 962*c9b443d4STobin Davis snd_hda_sequence_write(codec, mic_jack_on); 963*c9b443d4STobin Davis else 964*c9b443d4STobin Davis snd_hda_sequence_write(codec, mic_jack_off); 965*c9b443d4STobin Davis } 966*c9b443d4STobin Davis 967*c9b443d4STobin Davis /* unsolicited event for HP jack sensing */ 968*c9b443d4STobin Davis static void cxt5047_hp_unsol_event(struct hda_codec *codec, 969*c9b443d4STobin Davis unsigned int res) 970*c9b443d4STobin Davis { 971*c9b443d4STobin Davis res >>= 26; 972*c9b443d4STobin Davis switch (res) { 973*c9b443d4STobin Davis case CONEXANT_HP_EVENT: 974*c9b443d4STobin Davis cxt5047_hp_automute(codec); 975*c9b443d4STobin Davis break; 976*c9b443d4STobin Davis case CONEXANT_MIC_EVENT: 977*c9b443d4STobin Davis cxt5047_hp_automic(codec); 978*c9b443d4STobin Davis break; 979*c9b443d4STobin Davis } 980*c9b443d4STobin Davis } 981*c9b443d4STobin Davis 982*c9b443d4STobin Davis static struct snd_kcontrol_new cxt5047_mixers[] = { 983*c9b443d4STobin Davis { 984*c9b443d4STobin Davis .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 985*c9b443d4STobin Davis .name = "Capture Source", 986*c9b443d4STobin Davis .info = conexant_mux_enum_info, 987*c9b443d4STobin Davis .get = conexant_mux_enum_get, 988*c9b443d4STobin Davis .put = conexant_mux_enum_put 989*c9b443d4STobin Davis }, 990*c9b443d4STobin Davis HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), 991*c9b443d4STobin Davis HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19, 0x02, HDA_INPUT), 992*c9b443d4STobin Davis HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), 993*c9b443d4STobin Davis HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), 994*c9b443d4STobin Davis HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), 995*c9b443d4STobin Davis HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), 996*c9b443d4STobin Davis HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), 997*c9b443d4STobin Davis { 998*c9b443d4STobin Davis .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 999*c9b443d4STobin Davis .name = "Master Playback Switch", 1000*c9b443d4STobin Davis .info = conexant_eapd_info, 1001*c9b443d4STobin Davis .get = conexant_eapd_get, 1002*c9b443d4STobin Davis .put = cxt5047_hp_master_sw_put, 1003*c9b443d4STobin Davis .private_value = 0x13, 1004*c9b443d4STobin Davis }, 1005*c9b443d4STobin Davis 1006*c9b443d4STobin Davis {} 1007*c9b443d4STobin Davis }; 1008*c9b443d4STobin Davis 1009*c9b443d4STobin Davis static struct snd_kcontrol_new cxt5047_hp_mixers[] = { 1010*c9b443d4STobin Davis { 1011*c9b443d4STobin Davis .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1012*c9b443d4STobin Davis .name = "Capture Source", 1013*c9b443d4STobin Davis .info = conexant_mux_enum_info, 1014*c9b443d4STobin Davis .get = conexant_mux_enum_get, 1015*c9b443d4STobin Davis .put = conexant_mux_enum_put 1016*c9b443d4STobin Davis }, 1017*c9b443d4STobin Davis HDA_CODEC_VOLUME("Mic Bypass Capture Volume", 0x19, 0x02, HDA_INPUT), 1018*c9b443d4STobin Davis HDA_CODEC_MUTE("Mic Bypass Capture Switch", 0x19,0x02,HDA_INPUT), 1019*c9b443d4STobin Davis HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), 1020*c9b443d4STobin Davis HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), 1021*c9b443d4STobin Davis HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), 1022*c9b443d4STobin Davis HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), 1023*c9b443d4STobin Davis HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), 1024*c9b443d4STobin Davis { 1025*c9b443d4STobin Davis .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1026*c9b443d4STobin Davis .name = "Master Playback Switch", 1027*c9b443d4STobin Davis .info = conexant_eapd_info, 1028*c9b443d4STobin Davis .get = conexant_eapd_get, 1029*c9b443d4STobin Davis .put = cxt5047_hp_master_sw_put, 1030*c9b443d4STobin Davis .private_value = 0x13, 1031*c9b443d4STobin Davis }, 1032*c9b443d4STobin Davis { } /* end */ 1033*c9b443d4STobin Davis }; 1034*c9b443d4STobin Davis 1035*c9b443d4STobin Davis static struct hda_verb cxt5047_init_verbs[] = { 1036*c9b443d4STobin Davis /* Line in, Mic, Built-in Mic */ 1037*c9b443d4STobin Davis {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, 1038*c9b443d4STobin Davis {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, 1039*c9b443d4STobin Davis {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, 1040*c9b443d4STobin Davis /* HP, Amp */ 1041*c9b443d4STobin Davis {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, 1042*c9b443d4STobin Davis {0x1A, AC_VERB_SET_CONNECT_SEL,0x01}, 1043*c9b443d4STobin Davis {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, 1044*c9b443d4STobin Davis AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, 1045*c9b443d4STobin Davis {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, 1046*c9b443d4STobin Davis AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, 1047*c9b443d4STobin Davis /* Record selector: Front mic */ 1048*c9b443d4STobin Davis {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, 1049*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 1050*c9b443d4STobin Davis AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, 1051*c9b443d4STobin Davis /* SPDIF route: PCM */ 1052*c9b443d4STobin Davis { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, 1053*c9b443d4STobin Davis { } /* end */ 1054*c9b443d4STobin Davis }; 1055*c9b443d4STobin Davis 1056*c9b443d4STobin Davis /* configuration for Toshiba Laptops */ 1057*c9b443d4STobin Davis static struct hda_verb cxt5047_toshiba_init_verbs[] = { 1058*c9b443d4STobin Davis {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0 }, /* default on */ 1059*c9b443d4STobin Davis /* pin sensing on HP and Mic jacks */ 1060*c9b443d4STobin Davis {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 1061*c9b443d4STobin Davis {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 1062*c9b443d4STobin Davis {} 1063*c9b443d4STobin Davis }; 1064*c9b443d4STobin Davis 1065*c9b443d4STobin Davis /* configuration for HP Laptops */ 1066*c9b443d4STobin Davis static struct hda_verb cxt5047_hp_init_verbs[] = { 1067*c9b443d4STobin Davis /* pin sensing on HP and Mic jacks */ 1068*c9b443d4STobin Davis {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 1069*c9b443d4STobin Davis {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 1070*c9b443d4STobin Davis {} 1071*c9b443d4STobin Davis }; 1072*c9b443d4STobin Davis 1073*c9b443d4STobin Davis /* Test configuration for debugging, modelled after the ALC260 test 1074*c9b443d4STobin Davis * configuration. 1075*c9b443d4STobin Davis */ 1076*c9b443d4STobin Davis #ifdef CONFIG_SND_DEBUG 1077*c9b443d4STobin Davis static struct hda_input_mux cxt5047_test_capture_source = { 1078*c9b443d4STobin Davis .num_items = 5, 1079*c9b443d4STobin Davis .items = { 1080*c9b443d4STobin Davis { "MIXER", 0x0 }, 1081*c9b443d4STobin Davis { "LINE1 pin", 0x1 }, 1082*c9b443d4STobin Davis { "MIC1 pin", 0x2 }, 1083*c9b443d4STobin Davis { "MIC2 pin", 0x3 }, 1084*c9b443d4STobin Davis { "CD pin", 0x4 }, 1085*c9b443d4STobin Davis }, 1086*c9b443d4STobin Davis }; 1087*c9b443d4STobin Davis 1088*c9b443d4STobin Davis static struct snd_kcontrol_new cxt5047_test_mixer[] = { 1089*c9b443d4STobin Davis 1090*c9b443d4STobin Davis /* Output only controls */ 1091*c9b443d4STobin Davis HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x00, HDA_OUTPUT), 1092*c9b443d4STobin Davis HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x00, HDA_OUTPUT), 1093*c9b443d4STobin Davis HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x00, HDA_OUTPUT), 1094*c9b443d4STobin Davis HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x00, HDA_OUTPUT), 1095*c9b443d4STobin Davis HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), 1096*c9b443d4STobin Davis HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), 1097*c9b443d4STobin Davis HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), 1098*c9b443d4STobin Davis HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), 1099*c9b443d4STobin Davis 1100*c9b443d4STobin Davis /* Modes for retasking pin widgets */ 1101*c9b443d4STobin Davis CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), 1102*c9b443d4STobin Davis CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), 1103*c9b443d4STobin Davis 1104*c9b443d4STobin Davis /* Loopback mixer controls */ 1105*c9b443d4STobin Davis HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x19, 0x02, HDA_INPUT), 1106*c9b443d4STobin Davis HDA_CODEC_MUTE("MIC1 Playback Switch", 0x19, 0x02, HDA_INPUT), 1107*c9b443d4STobin Davis HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x19, 0x03, HDA_INPUT), 1108*c9b443d4STobin Davis HDA_CODEC_MUTE("MIC2 Playback Switch", 0x19, 0x03, HDA_INPUT), 1109*c9b443d4STobin Davis HDA_CODEC_VOLUME("LINE Playback Volume", 0x19, 0x01, HDA_INPUT), 1110*c9b443d4STobin Davis HDA_CODEC_MUTE("LINE Playback Switch", 0x19, 0x01, HDA_INPUT), 1111*c9b443d4STobin Davis HDA_CODEC_VOLUME("CD Playback Volume", 0x19, 0x04, HDA_INPUT), 1112*c9b443d4STobin Davis HDA_CODEC_MUTE("CD Playback Switch", 0x19, 0x04, HDA_INPUT), 1113*c9b443d4STobin Davis 1114*c9b443d4STobin Davis /* Controls for GPIO pins, assuming they exist and are configured as outputs */ 1115*c9b443d4STobin Davis CXT_GPIO_DATA_SWITCH("GPIO pin 0", 0x01, 0x01), 1116*c9b443d4STobin Davis #if 0 /* limit this to one GPIO pin for now */ 1117*c9b443d4STobin Davis CXT_GPIO_DATA_SWITCH("GPIO pin 1", 0x01, 0x02), 1118*c9b443d4STobin Davis CXT_GPIO_DATA_SWITCH("GPIO pin 2", 0x01, 0x04), 1119*c9b443d4STobin Davis CXT_GPIO_DATA_SWITCH("GPIO pin 3", 0x01, 0x08), 1120*c9b443d4STobin Davis #endif 1121*c9b443d4STobin Davis CXT_SPDIF_CTRL_SWITCH("SPDIF Playback Switch", 0x18, 0x01), 1122*c9b443d4STobin Davis 1123*c9b443d4STobin Davis HDA_CODEC_VOLUME("Capture Volume", 0x19, 0x0, HDA_OUTPUT), 1124*c9b443d4STobin Davis HDA_CODEC_MUTE("Capture Switch", 0x19, 0x0, HDA_OUTPUT), 1125*c9b443d4STobin Davis { 1126*c9b443d4STobin Davis .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1127*c9b443d4STobin Davis .name = "Input Source", 1128*c9b443d4STobin Davis .info = conexant_mux_enum_info, 1129*c9b443d4STobin Davis .get = conexant_mux_enum_get, 1130*c9b443d4STobin Davis .put = conexant_mux_enum_put, 1131*c9b443d4STobin Davis }, 1132*c9b443d4STobin Davis 1133*c9b443d4STobin Davis { } /* end */ 1134*c9b443d4STobin Davis }; 1135*c9b443d4STobin Davis 1136*c9b443d4STobin Davis static struct hda_verb cxt5047_test_init_verbs[] = { 1137*c9b443d4STobin Davis /* Enable all GPIOs as outputs with an initial value of 0 */ 1138*c9b443d4STobin Davis {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x0f}, 1139*c9b443d4STobin Davis {0x01, AC_VERB_SET_GPIO_DATA, 0x00}, 1140*c9b443d4STobin Davis {0x01, AC_VERB_SET_GPIO_MASK, 0x0f}, 1141*c9b443d4STobin Davis 1142*c9b443d4STobin Davis /* Enable retasking pins as output, initially without power amp */ 1143*c9b443d4STobin Davis {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1144*c9b443d4STobin Davis {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1145*c9b443d4STobin Davis {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1146*c9b443d4STobin Davis 1147*c9b443d4STobin Davis /* Disable digital (SPDIF) pins initially, but users can enable 1148*c9b443d4STobin Davis * them via a mixer switch. In the case of SPDIF-out, this initverb 1149*c9b443d4STobin Davis * payload also sets the generation to 0, output to be in "consumer" 1150*c9b443d4STobin Davis * PCM format, copyright asserted, no pre-emphasis and no validity 1151*c9b443d4STobin Davis * control. 1152*c9b443d4STobin Davis */ 1153*c9b443d4STobin Davis {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, 1154*c9b443d4STobin Davis 1155*c9b443d4STobin Davis /* Ensure mic1, mic2, line1 pin widgets take input from the 1156*c9b443d4STobin Davis * OUT1 sum bus when acting as an output. 1157*c9b443d4STobin Davis */ 1158*c9b443d4STobin Davis {0x1a, AC_VERB_SET_CONNECT_SEL, 0}, 1159*c9b443d4STobin Davis {0x1b, AC_VERB_SET_CONNECT_SEL, 0}, 1160*c9b443d4STobin Davis 1161*c9b443d4STobin Davis /* Start with output sum widgets muted and their output gains at min */ 1162*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1163*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 1164*c9b443d4STobin Davis 1165*c9b443d4STobin Davis /* Unmute retasking pin widget output buffers since the default 1166*c9b443d4STobin Davis * state appears to be output. As the pin mode is changed by the 1167*c9b443d4STobin Davis * user the pin mode control will take care of enabling the pin's 1168*c9b443d4STobin Davis * input/output buffers as needed. 1169*c9b443d4STobin Davis */ 1170*c9b443d4STobin Davis {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1171*c9b443d4STobin Davis {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1172*c9b443d4STobin Davis {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1173*c9b443d4STobin Davis 1174*c9b443d4STobin Davis /* Mute capture amp left and right */ 1175*c9b443d4STobin Davis {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1176*c9b443d4STobin Davis 1177*c9b443d4STobin Davis /* Set ADC connection select to match default mixer setting (mic1 1178*c9b443d4STobin Davis * pin) 1179*c9b443d4STobin Davis */ 1180*c9b443d4STobin Davis {0x12, AC_VERB_SET_CONNECT_SEL, 0x00}, 1181*c9b443d4STobin Davis 1182*c9b443d4STobin Davis /* Mute all inputs to mixer widget (even unconnected ones) */ 1183*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ 1184*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ 1185*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ 1186*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ 1187*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ 1188*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ 1189*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ 1190*c9b443d4STobin Davis {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ 1191*c9b443d4STobin Davis 1192*c9b443d4STobin Davis { } 1193*c9b443d4STobin Davis }; 1194*c9b443d4STobin Davis #endif 1195*c9b443d4STobin Davis 1196*c9b443d4STobin Davis 1197*c9b443d4STobin Davis /* initialize jack-sensing, too */ 1198*c9b443d4STobin Davis static int cxt5047_hp_init(struct hda_codec *codec) 1199*c9b443d4STobin Davis { 1200*c9b443d4STobin Davis conexant_init(codec); 1201*c9b443d4STobin Davis cxt5047_hp_automute(codec); 1202*c9b443d4STobin Davis cxt5047_hp_automic(codec); 1203*c9b443d4STobin Davis return 0; 1204*c9b443d4STobin Davis } 1205*c9b443d4STobin Davis 1206*c9b443d4STobin Davis 1207*c9b443d4STobin Davis enum { 1208*c9b443d4STobin Davis CXT5047_LAPTOP, 1209*c9b443d4STobin Davis #ifdef CONFIG_SND_DEBUG 1210*c9b443d4STobin Davis CXT5047_TEST, 1211*c9b443d4STobin Davis #endif 1212*c9b443d4STobin Davis CXT5047_LAPTOP_HP, 1213*c9b443d4STobin Davis CXT5047_LAPTOP_EAPD 1214*c9b443d4STobin Davis }; 1215*c9b443d4STobin Davis 1216*c9b443d4STobin Davis static struct hda_board_config cxt5047_cfg_tbl[] = { 1217*c9b443d4STobin Davis /* Laptops w/o EAPD support */ 1218*c9b443d4STobin Davis { .modelname = "laptop", .config = CXT5047_LAPTOP }, 1219*c9b443d4STobin Davis /*HP DV1000 */ 1220*c9b443d4STobin Davis { .pci_subvendor = 0x103c, .pci_subdevice = 0x30a0, 1221*c9b443d4STobin Davis .config = CXT5047_LAPTOP }, 1222*c9b443d4STobin Davis /*HP DV2000T/DV3000T */ 1223*c9b443d4STobin Davis { .pci_subvendor = 0x103c, .pci_subdevice = 0x30b2, 1224*c9b443d4STobin Davis .config = CXT5047_LAPTOP }, 1225*c9b443d4STobin Davis /* Not all HP's are created equal */ 1226*c9b443d4STobin Davis { .modelname = "laptop-hp", .config = CXT5047_LAPTOP_HP }, 1227*c9b443d4STobin Davis /*HP DV5200TX/DV8000T / Compaq V5209US/V5204NR */ 1228*c9b443d4STobin Davis { .pci_subvendor = 0x103c, .pci_subdevice = 0x30a5, 1229*c9b443d4STobin Davis .config = CXT5047_LAPTOP_HP }, 1230*c9b443d4STobin Davis /* Laptops with EAPD support */ 1231*c9b443d4STobin Davis { .modelname = "laptop-eapd", .config = CXT5047_LAPTOP_EAPD }, 1232*c9b443d4STobin Davis { .pci_subvendor = 0x1179, .pci_subdevice = 0xff31, 1233*c9b443d4STobin Davis .config = CXT5047_LAPTOP_EAPD }, /* Toshiba P100 */ 1234*c9b443d4STobin Davis #ifdef CONFIG_SND_DEBUG 1235*c9b443d4STobin Davis { .modelname = "test", .config = CXT5047_TEST }, 1236*c9b443d4STobin Davis #endif 1237*c9b443d4STobin Davis 1238*c9b443d4STobin Davis {} 1239*c9b443d4STobin Davis }; 1240*c9b443d4STobin Davis 1241*c9b443d4STobin Davis static int patch_cxt5047(struct hda_codec *codec) 1242*c9b443d4STobin Davis { 1243*c9b443d4STobin Davis struct conexant_spec *spec; 1244*c9b443d4STobin Davis int board_config; 1245*c9b443d4STobin Davis 1246*c9b443d4STobin Davis spec = kzalloc(sizeof(*spec), GFP_KERNEL); 1247*c9b443d4STobin Davis if (!spec) 1248*c9b443d4STobin Davis return -ENOMEM; 1249*c9b443d4STobin Davis mutex_init(&spec->amp_mutex); 1250*c9b443d4STobin Davis codec->spec = spec; 1251*c9b443d4STobin Davis 1252*c9b443d4STobin Davis spec->multiout.max_channels = 2; 1253*c9b443d4STobin Davis spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); 1254*c9b443d4STobin Davis spec->multiout.dac_nids = cxt5047_dac_nids; 1255*c9b443d4STobin Davis spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT; 1256*c9b443d4STobin Davis spec->num_adc_nids = 1; 1257*c9b443d4STobin Davis spec->adc_nids = cxt5047_adc_nids; 1258*c9b443d4STobin Davis spec->capsrc_nids = cxt5047_capsrc_nids; 1259*c9b443d4STobin Davis spec->input_mux = &cxt5047_capture_source; 1260*c9b443d4STobin Davis spec->num_mixers = 1; 1261*c9b443d4STobin Davis spec->mixers[0] = cxt5047_mixers; 1262*c9b443d4STobin Davis spec->num_init_verbs = 1; 1263*c9b443d4STobin Davis spec->init_verbs[0] = cxt5047_init_verbs; 1264*c9b443d4STobin Davis spec->spdif_route = 0; 1265*c9b443d4STobin Davis 1266*c9b443d4STobin Davis codec->patch_ops = conexant_patch_ops; 1267*c9b443d4STobin Davis codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; 1268*c9b443d4STobin Davis 1269*c9b443d4STobin Davis board_config = snd_hda_check_board_config(codec, cxt5047_cfg_tbl); 1270*c9b443d4STobin Davis switch (board_config) { 1271*c9b443d4STobin Davis case CXT5047_LAPTOP: 1272*c9b443d4STobin Davis break; 1273*c9b443d4STobin Davis case CXT5047_LAPTOP_HP: 1274*c9b443d4STobin Davis spec->input_mux = &cxt5047_hp_capture_source; 1275*c9b443d4STobin Davis spec->num_init_verbs = 2; 1276*c9b443d4STobin Davis spec->init_verbs[1] = cxt5047_hp_init_verbs; 1277*c9b443d4STobin Davis spec->mixers[0] = cxt5047_hp_mixers; 1278*c9b443d4STobin Davis codec->patch_ops.init = cxt5047_hp_init; 1279*c9b443d4STobin Davis break; 1280*c9b443d4STobin Davis case CXT5047_LAPTOP_EAPD: 1281*c9b443d4STobin Davis spec->num_init_verbs = 2; 1282*c9b443d4STobin Davis spec->init_verbs[1] = cxt5047_toshiba_init_verbs; 1283*c9b443d4STobin Davis break; 1284*c9b443d4STobin Davis #ifdef CONFIG_SND_DEBUG 1285*c9b443d4STobin Davis case CXT5047_TEST: 1286*c9b443d4STobin Davis spec->input_mux = &cxt5047_test_capture_source; 1287*c9b443d4STobin Davis spec->mixers[0] = cxt5047_test_mixer; 1288*c9b443d4STobin Davis spec->init_verbs[0] = cxt5047_test_init_verbs; 1289*c9b443d4STobin Davis #endif 1290*c9b443d4STobin Davis } 1291*c9b443d4STobin Davis return 0; 1292*c9b443d4STobin Davis } 1293*c9b443d4STobin Davis 1294*c9b443d4STobin Davis struct hda_codec_preset snd_hda_preset_conexant[] = { 1295*c9b443d4STobin Davis { .id = 0x14f15045, .name = "CXT5045", .patch = patch_cxt5045 }, 1296*c9b443d4STobin Davis { .id = 0x14f15047, .name = "CXT5047", .patch = patch_cxt5047 }, 1297*c9b443d4STobin Davis {} /* terminator */ 1298*c9b443d4STobin Davis }; 1299