1/* 2 * HD audio interface patch for Conexant HDA audio codec 3 * 4 * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com> 5 * Takashi Iwai <tiwai@suse.de> 6 * Tobin Davis <tdavis@dsl-only.net> 7 * 8 * This driver is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This driver is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 */ 22 23#include <linux/init.h> 24#include <linux/delay.h> 25#include <linux/slab.h> 26#include <linux/pci.h> 27#include <sound/core.h> 28#include <sound/jack.h> 29 30#include "hda_codec.h" 31#include "hda_local.h" 32#include "hda_beep.h" 33 34#define CXT_PIN_DIR_IN 0x00 35#define CXT_PIN_DIR_OUT 0x01 36#define CXT_PIN_DIR_INOUT 0x02 37#define CXT_PIN_DIR_IN_NOMICBIAS 0x03 38#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04 39 40#define CONEXANT_HP_EVENT 0x37 41#define CONEXANT_MIC_EVENT 0x38 42 43/* Conexant 5051 specific */ 44 45#define CXT5051_SPDIF_OUT 0x12 46#define CXT5051_PORTB_EVENT 0x38 47#define CXT5051_PORTC_EVENT 0x39 48 49#define AUTO_MIC_PORTB (1 << 1) 50#define AUTO_MIC_PORTC (1 << 2) 51 52struct conexant_jack { 53 54 hda_nid_t nid; 55 int type; 56 struct snd_jack *jack; 57 58}; 59 60struct conexant_spec { 61 62 struct snd_kcontrol_new *mixers[5]; 63 int num_mixers; 64 hda_nid_t vmaster_nid; 65 66 const struct hda_verb *init_verbs[5]; /* initialization verbs 67 * don't forget NULL 68 * termination! 69 */ 70 unsigned int num_init_verbs; 71 72 /* playback */ 73 struct hda_multi_out multiout; /* playback set-up 74 * max_channels, dacs must be set 75 * dig_out_nid and hp_nid are optional 76 */ 77 unsigned int cur_eapd; 78 unsigned int hp_present; 79 unsigned int auto_mic; 80 unsigned int need_dac_fix; 81 82 /* capture */ 83 unsigned int num_adc_nids; 84 hda_nid_t *adc_nids; 85 hda_nid_t dig_in_nid; /* digital-in NID; optional */ 86 87 unsigned int cur_adc_idx; 88 hda_nid_t cur_adc; 89 unsigned int cur_adc_stream_tag; 90 unsigned int cur_adc_format; 91 92 /* capture source */ 93 const struct hda_input_mux *input_mux; 94 hda_nid_t *capsrc_nids; 95 unsigned int cur_mux[3]; 96 97 /* channel model */ 98 const struct hda_channel_mode *channel_mode; 99 int num_channel_mode; 100 101 /* PCM information */ 102 struct hda_pcm pcm_rec[2]; /* used in build_pcms() */ 103 104 unsigned int spdif_route; 105 106 /* jack detection */ 107 struct snd_array jacks; 108 109 /* dynamic controls, init_verbs and input_mux */ 110 struct auto_pin_cfg autocfg; 111 struct hda_input_mux private_imux; 112 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; 113 114 unsigned int dell_automute; 115 unsigned int port_d_mode; 116 unsigned int dell_vostro:1; 117 unsigned int ideapad:1; 118 unsigned int thinkpad:1; 119 unsigned int hp_laptop:1; 120 121 unsigned int ext_mic_present; 122 unsigned int recording; 123 void (*capture_prepare)(struct hda_codec *codec); 124 void (*capture_cleanup)(struct hda_codec *codec); 125 126 /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) 127 * through the microphone jack. 128 * When the user enables this through a mixer switch, both internal and 129 * external microphones are disabled. Gain is fixed at 0dB. In this mode, 130 * we also allow the bias to be configured through a separate mixer 131 * control. */ 132 unsigned int dc_enable; 133 unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ 134 unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ 135 136 unsigned int beep_amp; 137}; 138 139static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, 140 struct hda_codec *codec, 141 struct snd_pcm_substream *substream) 142{ 143 struct conexant_spec *spec = codec->spec; 144 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, 145 hinfo); 146} 147 148static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 149 struct hda_codec *codec, 150 unsigned int stream_tag, 151 unsigned int format, 152 struct snd_pcm_substream *substream) 153{ 154 struct conexant_spec *spec = codec->spec; 155 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, 156 stream_tag, 157 format, substream); 158} 159 160static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, 161 struct hda_codec *codec, 162 struct snd_pcm_substream *substream) 163{ 164 struct conexant_spec *spec = codec->spec; 165 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); 166} 167 168/* 169 * Digital out 170 */ 171static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, 172 struct hda_codec *codec, 173 struct snd_pcm_substream *substream) 174{ 175 struct conexant_spec *spec = codec->spec; 176 return snd_hda_multi_out_dig_open(codec, &spec->multiout); 177} 178 179static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 180 struct hda_codec *codec, 181 struct snd_pcm_substream *substream) 182{ 183 struct conexant_spec *spec = codec->spec; 184 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 185} 186 187static int conexant_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, 188 struct hda_codec *codec, 189 unsigned int stream_tag, 190 unsigned int format, 191 struct snd_pcm_substream *substream) 192{ 193 struct conexant_spec *spec = codec->spec; 194 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, 195 stream_tag, 196 format, substream); 197} 198 199/* 200 * Analog capture 201 */ 202static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 203 struct hda_codec *codec, 204 unsigned int stream_tag, 205 unsigned int format, 206 struct snd_pcm_substream *substream) 207{ 208 struct conexant_spec *spec = codec->spec; 209 if (spec->capture_prepare) 210 spec->capture_prepare(codec); 211 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], 212 stream_tag, 0, format); 213 return 0; 214} 215 216static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 217 struct hda_codec *codec, 218 struct snd_pcm_substream *substream) 219{ 220 struct conexant_spec *spec = codec->spec; 221 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); 222 if (spec->capture_cleanup) 223 spec->capture_cleanup(codec); 224 return 0; 225} 226 227 228 229static struct hda_pcm_stream conexant_pcm_analog_playback = { 230 .substreams = 1, 231 .channels_min = 2, 232 .channels_max = 2, 233 .nid = 0, /* fill later */ 234 .ops = { 235 .open = conexant_playback_pcm_open, 236 .prepare = conexant_playback_pcm_prepare, 237 .cleanup = conexant_playback_pcm_cleanup 238 }, 239}; 240 241static struct hda_pcm_stream conexant_pcm_analog_capture = { 242 .substreams = 1, 243 .channels_min = 2, 244 .channels_max = 2, 245 .nid = 0, /* fill later */ 246 .ops = { 247 .prepare = conexant_capture_pcm_prepare, 248 .cleanup = conexant_capture_pcm_cleanup 249 }, 250}; 251 252 253static struct hda_pcm_stream conexant_pcm_digital_playback = { 254 .substreams = 1, 255 .channels_min = 2, 256 .channels_max = 2, 257 .nid = 0, /* fill later */ 258 .ops = { 259 .open = conexant_dig_playback_pcm_open, 260 .close = conexant_dig_playback_pcm_close, 261 .prepare = conexant_dig_playback_pcm_prepare 262 }, 263}; 264 265static struct hda_pcm_stream conexant_pcm_digital_capture = { 266 .substreams = 1, 267 .channels_min = 2, 268 .channels_max = 2, 269 /* NID is set in alc_build_pcms */ 270}; 271 272static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo, 273 struct hda_codec *codec, 274 unsigned int stream_tag, 275 unsigned int format, 276 struct snd_pcm_substream *substream) 277{ 278 struct conexant_spec *spec = codec->spec; 279 spec->cur_adc = spec->adc_nids[spec->cur_adc_idx]; 280 spec->cur_adc_stream_tag = stream_tag; 281 spec->cur_adc_format = format; 282 snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); 283 return 0; 284} 285 286static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, 287 struct hda_codec *codec, 288 struct snd_pcm_substream *substream) 289{ 290 struct conexant_spec *spec = codec->spec; 291 snd_hda_codec_cleanup_stream(codec, spec->cur_adc); 292 spec->cur_adc = 0; 293 return 0; 294} 295 296static struct hda_pcm_stream cx5051_pcm_analog_capture = { 297 .substreams = 1, 298 .channels_min = 2, 299 .channels_max = 2, 300 .nid = 0, /* fill later */ 301 .ops = { 302 .prepare = cx5051_capture_pcm_prepare, 303 .cleanup = cx5051_capture_pcm_cleanup 304 }, 305}; 306 307static int conexant_build_pcms(struct hda_codec *codec) 308{ 309 struct conexant_spec *spec = codec->spec; 310 struct hda_pcm *info = spec->pcm_rec; 311 312 codec->num_pcms = 1; 313 codec->pcm_info = info; 314 315 info->name = "CONEXANT Analog"; 316 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback; 317 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 318 spec->multiout.max_channels; 319 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 320 spec->multiout.dac_nids[0]; 321 if (codec->vendor_id == 0x14f15051) 322 info->stream[SNDRV_PCM_STREAM_CAPTURE] = 323 cx5051_pcm_analog_capture; 324 else 325 info->stream[SNDRV_PCM_STREAM_CAPTURE] = 326 conexant_pcm_analog_capture; 327 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; 328 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; 329 330 if (spec->multiout.dig_out_nid) { 331 info++; 332 codec->num_pcms++; 333 info->name = "Conexant Digital"; 334 info->pcm_type = HDA_PCM_TYPE_SPDIF; 335 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = 336 conexant_pcm_digital_playback; 337 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 338 spec->multiout.dig_out_nid; 339 if (spec->dig_in_nid) { 340 info->stream[SNDRV_PCM_STREAM_CAPTURE] = 341 conexant_pcm_digital_capture; 342 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 343 spec->dig_in_nid; 344 } 345 } 346 347 return 0; 348} 349 350static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol, 351 struct snd_ctl_elem_info *uinfo) 352{ 353 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 354 struct conexant_spec *spec = codec->spec; 355 356 return snd_hda_input_mux_info(spec->input_mux, uinfo); 357} 358 359static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol, 360 struct snd_ctl_elem_value *ucontrol) 361{ 362 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 363 struct conexant_spec *spec = codec->spec; 364 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 365 366 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; 367 return 0; 368} 369 370static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol, 371 struct snd_ctl_elem_value *ucontrol) 372{ 373 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 374 struct conexant_spec *spec = codec->spec; 375 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 376 377 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, 378 spec->capsrc_nids[adc_idx], 379 &spec->cur_mux[adc_idx]); 380} 381 382#ifdef CONFIG_SND_HDA_INPUT_JACK 383static void conexant_free_jack_priv(struct snd_jack *jack) 384{ 385 struct conexant_jack *jacks = jack->private_data; 386 jacks->nid = 0; 387 jacks->jack = NULL; 388} 389 390static int conexant_add_jack(struct hda_codec *codec, 391 hda_nid_t nid, int type) 392{ 393 struct conexant_spec *spec; 394 struct conexant_jack *jack; 395 const char *name; 396 int i, err; 397 398 spec = codec->spec; 399 snd_array_init(&spec->jacks, sizeof(*jack), 32); 400 401 jack = spec->jacks.list; 402 for (i = 0; i < spec->jacks.used; i++, jack++) 403 if (jack->nid == nid) 404 return 0 ; /* already present */ 405 406 jack = snd_array_new(&spec->jacks); 407 name = (type == SND_JACK_HEADPHONE) ? "Headphone" : "Mic" ; 408 409 if (!jack) 410 return -ENOMEM; 411 412 jack->nid = nid; 413 jack->type = type; 414 415 err = snd_jack_new(codec->bus->card, name, type, &jack->jack); 416 if (err < 0) 417 return err; 418 jack->jack->private_data = jack; 419 jack->jack->private_free = conexant_free_jack_priv; 420 return 0; 421} 422 423static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) 424{ 425 struct conexant_spec *spec = codec->spec; 426 struct conexant_jack *jacks = spec->jacks.list; 427 428 if (jacks) { 429 int i; 430 for (i = 0; i < spec->jacks.used; i++) { 431 if (jacks->nid == nid) { 432 unsigned int present; 433 present = snd_hda_jack_detect(codec, nid); 434 435 present = (present) ? jacks->type : 0 ; 436 437 snd_jack_report(jacks->jack, 438 present); 439 } 440 jacks++; 441 } 442 } 443} 444 445static int conexant_init_jacks(struct hda_codec *codec) 446{ 447 struct conexant_spec *spec = codec->spec; 448 int i; 449 450 for (i = 0; i < spec->num_init_verbs; i++) { 451 const struct hda_verb *hv; 452 453 hv = spec->init_verbs[i]; 454 while (hv->nid) { 455 int err = 0; 456 switch (hv->param ^ AC_USRSP_EN) { 457 case CONEXANT_HP_EVENT: 458 err = conexant_add_jack(codec, hv->nid, 459 SND_JACK_HEADPHONE); 460 conexant_report_jack(codec, hv->nid); 461 break; 462 case CXT5051_PORTC_EVENT: 463 case CONEXANT_MIC_EVENT: 464 err = conexant_add_jack(codec, hv->nid, 465 SND_JACK_MICROPHONE); 466 conexant_report_jack(codec, hv->nid); 467 break; 468 } 469 if (err < 0) 470 return err; 471 ++hv; 472 } 473 } 474 return 0; 475 476} 477#else 478static inline void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) 479{ 480} 481 482static inline int conexant_init_jacks(struct hda_codec *codec) 483{ 484 return 0; 485} 486#endif 487 488static int conexant_init(struct hda_codec *codec) 489{ 490 struct conexant_spec *spec = codec->spec; 491 int i; 492 493 for (i = 0; i < spec->num_init_verbs; i++) 494 snd_hda_sequence_write(codec, spec->init_verbs[i]); 495 return 0; 496} 497 498static void conexant_free(struct hda_codec *codec) 499{ 500#ifdef CONFIG_SND_HDA_INPUT_JACK 501 struct conexant_spec *spec = codec->spec; 502 if (spec->jacks.list) { 503 struct conexant_jack *jacks = spec->jacks.list; 504 int i; 505 for (i = 0; i < spec->jacks.used; i++, jacks++) { 506 if (jacks->jack) 507 snd_device_free(codec->bus->card, jacks->jack); 508 } 509 snd_array_free(&spec->jacks); 510 } 511#endif 512 snd_hda_detach_beep_device(codec); 513 kfree(codec->spec); 514} 515 516static struct snd_kcontrol_new cxt_capture_mixers[] = { 517 { 518 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 519 .name = "Capture Source", 520 .info = conexant_mux_enum_info, 521 .get = conexant_mux_enum_get, 522 .put = conexant_mux_enum_put 523 }, 524 {} 525}; 526 527#ifdef CONFIG_SND_HDA_INPUT_BEEP 528/* additional beep mixers; the actual parameters are overwritten at build */ 529static struct snd_kcontrol_new cxt_beep_mixer[] = { 530 HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), 531 HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), 532 { } /* end */ 533}; 534#endif 535 536static const char *slave_vols[] = { 537 "Headphone Playback Volume", 538 "Speaker Playback Volume", 539 NULL 540}; 541 542static const char *slave_sws[] = { 543 "Headphone Playback Switch", 544 "Speaker Playback Switch", 545 NULL 546}; 547 548static int conexant_build_controls(struct hda_codec *codec) 549{ 550 struct conexant_spec *spec = codec->spec; 551 unsigned int i; 552 int err; 553 554 for (i = 0; i < spec->num_mixers; i++) { 555 err = snd_hda_add_new_ctls(codec, spec->mixers[i]); 556 if (err < 0) 557 return err; 558 } 559 if (spec->multiout.dig_out_nid) { 560 err = snd_hda_create_spdif_out_ctls(codec, 561 spec->multiout.dig_out_nid); 562 if (err < 0) 563 return err; 564 err = snd_hda_create_spdif_share_sw(codec, 565 &spec->multiout); 566 if (err < 0) 567 return err; 568 spec->multiout.share_spdif = 1; 569 } 570 if (spec->dig_in_nid) { 571 err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid); 572 if (err < 0) 573 return err; 574 } 575 576 /* if we have no master control, let's create it */ 577 if (spec->vmaster_nid && 578 !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { 579 unsigned int vmaster_tlv[4]; 580 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, 581 HDA_OUTPUT, vmaster_tlv); 582 err = snd_hda_add_vmaster(codec, "Master Playback Volume", 583 vmaster_tlv, slave_vols); 584 if (err < 0) 585 return err; 586 } 587 if (spec->vmaster_nid && 588 !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { 589 err = snd_hda_add_vmaster(codec, "Master Playback Switch", 590 NULL, slave_sws); 591 if (err < 0) 592 return err; 593 } 594 595 if (spec->input_mux) { 596 err = snd_hda_add_new_ctls(codec, cxt_capture_mixers); 597 if (err < 0) 598 return err; 599 } 600 601#ifdef CONFIG_SND_HDA_INPUT_BEEP 602 /* create beep controls if needed */ 603 if (spec->beep_amp) { 604 struct snd_kcontrol_new *knew; 605 for (knew = cxt_beep_mixer; knew->name; knew++) { 606 struct snd_kcontrol *kctl; 607 kctl = snd_ctl_new1(knew, codec); 608 if (!kctl) 609 return -ENOMEM; 610 kctl->private_value = spec->beep_amp; 611 err = snd_hda_ctl_add(codec, 0, kctl); 612 if (err < 0) 613 return err; 614 } 615 } 616#endif 617 618 return 0; 619} 620 621#ifdef CONFIG_SND_HDA_POWER_SAVE 622static int conexant_suspend(struct hda_codec *codec, pm_message_t state) 623{ 624 snd_hda_shutup_pins(codec); 625 return 0; 626} 627#endif 628 629static struct hda_codec_ops conexant_patch_ops = { 630 .build_controls = conexant_build_controls, 631 .build_pcms = conexant_build_pcms, 632 .init = conexant_init, 633 .free = conexant_free, 634#ifdef CONFIG_SND_HDA_POWER_SAVE 635 .suspend = conexant_suspend, 636#endif 637 .reboot_notify = snd_hda_shutup_pins, 638}; 639 640#ifdef CONFIG_SND_HDA_INPUT_BEEP 641#define set_beep_amp(spec, nid, idx, dir) \ 642 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) 643#else 644#define set_beep_amp(spec, nid, idx, dir) /* NOP */ 645#endif 646 647/* 648 * EAPD control 649 * the private value = nid | (invert << 8) 650 */ 651 652#define cxt_eapd_info snd_ctl_boolean_mono_info 653 654static int cxt_eapd_get(struct snd_kcontrol *kcontrol, 655 struct snd_ctl_elem_value *ucontrol) 656{ 657 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 658 struct conexant_spec *spec = codec->spec; 659 int invert = (kcontrol->private_value >> 8) & 1; 660 if (invert) 661 ucontrol->value.integer.value[0] = !spec->cur_eapd; 662 else 663 ucontrol->value.integer.value[0] = spec->cur_eapd; 664 return 0; 665 666} 667 668static int cxt_eapd_put(struct snd_kcontrol *kcontrol, 669 struct snd_ctl_elem_value *ucontrol) 670{ 671 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 672 struct conexant_spec *spec = codec->spec; 673 int invert = (kcontrol->private_value >> 8) & 1; 674 hda_nid_t nid = kcontrol->private_value & 0xff; 675 unsigned int eapd; 676 677 eapd = !!ucontrol->value.integer.value[0]; 678 if (invert) 679 eapd = !eapd; 680 if (eapd == spec->cur_eapd) 681 return 0; 682 683 spec->cur_eapd = eapd; 684 snd_hda_codec_write_cache(codec, nid, 685 0, AC_VERB_SET_EAPD_BTLENABLE, 686 eapd ? 0x02 : 0x00); 687 return 1; 688} 689 690/* controls for test mode */ 691#ifdef CONFIG_SND_DEBUG 692 693#define CXT_EAPD_SWITCH(xname, nid, mask) \ 694 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ 695 .info = cxt_eapd_info, \ 696 .get = cxt_eapd_get, \ 697 .put = cxt_eapd_put, \ 698 .private_value = nid | (mask<<16) } 699 700 701 702static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol, 703 struct snd_ctl_elem_info *uinfo) 704{ 705 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 706 struct conexant_spec *spec = codec->spec; 707 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode, 708 spec->num_channel_mode); 709} 710 711static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol, 712 struct snd_ctl_elem_value *ucontrol) 713{ 714 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 715 struct conexant_spec *spec = codec->spec; 716 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, 717 spec->num_channel_mode, 718 spec->multiout.max_channels); 719} 720 721static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, 722 struct snd_ctl_elem_value *ucontrol) 723{ 724 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 725 struct conexant_spec *spec = codec->spec; 726 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, 727 spec->num_channel_mode, 728 &spec->multiout.max_channels); 729 if (err >= 0 && spec->need_dac_fix) 730 spec->multiout.num_dacs = spec->multiout.max_channels / 2; 731 return err; 732} 733 734#define CXT_PIN_MODE(xname, nid, dir) \ 735 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ 736 .info = conexant_ch_mode_info, \ 737 .get = conexant_ch_mode_get, \ 738 .put = conexant_ch_mode_put, \ 739 .private_value = nid | (dir<<16) } 740 741#endif /* CONFIG_SND_DEBUG */ 742 743/* Conexant 5045 specific */ 744 745static hda_nid_t cxt5045_dac_nids[1] = { 0x19 }; 746static hda_nid_t cxt5045_adc_nids[1] = { 0x1a }; 747static hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a }; 748#define CXT5045_SPDIF_OUT 0x18 749 750static struct hda_channel_mode cxt5045_modes[1] = { 751 { 2, NULL }, 752}; 753 754static struct hda_input_mux cxt5045_capture_source = { 755 .num_items = 2, 756 .items = { 757 { "IntMic", 0x1 }, 758 { "ExtMic", 0x2 }, 759 } 760}; 761 762static struct hda_input_mux cxt5045_capture_source_benq = { 763 .num_items = 5, 764 .items = { 765 { "IntMic", 0x1 }, 766 { "ExtMic", 0x2 }, 767 { "LineIn", 0x3 }, 768 { "CD", 0x4 }, 769 { "Mixer", 0x0 }, 770 } 771}; 772 773static struct hda_input_mux cxt5045_capture_source_hp530 = { 774 .num_items = 2, 775 .items = { 776 { "ExtMic", 0x1 }, 777 { "IntMic", 0x2 }, 778 } 779}; 780 781/* turn on/off EAPD (+ mute HP) as a master switch */ 782static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, 783 struct snd_ctl_elem_value *ucontrol) 784{ 785 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 786 struct conexant_spec *spec = codec->spec; 787 unsigned int bits; 788 789 if (!cxt_eapd_put(kcontrol, ucontrol)) 790 return 0; 791 792 /* toggle internal speakers mute depending of presence of 793 * the headphone jack 794 */ 795 bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; 796 snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, 797 HDA_AMP_MUTE, bits); 798 799 bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; 800 snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0, 801 HDA_AMP_MUTE, bits); 802 return 1; 803} 804 805/* bind volumes of both NID 0x10 and 0x11 */ 806static struct hda_bind_ctls cxt5045_hp_bind_master_vol = { 807 .ops = &snd_hda_bind_vol, 808 .values = { 809 HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT), 810 HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT), 811 0 812 }, 813}; 814 815/* toggle input of built-in and mic jack appropriately */ 816static void cxt5045_hp_automic(struct hda_codec *codec) 817{ 818 static struct hda_verb mic_jack_on[] = { 819 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, 820 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, 821 {} 822 }; 823 static struct hda_verb mic_jack_off[] = { 824 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, 825 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, 826 {} 827 }; 828 unsigned int present; 829 830 present = snd_hda_jack_detect(codec, 0x12); 831 if (present) 832 snd_hda_sequence_write(codec, mic_jack_on); 833 else 834 snd_hda_sequence_write(codec, mic_jack_off); 835} 836 837 838/* mute internal speaker if HP is plugged */ 839static void cxt5045_hp_automute(struct hda_codec *codec) 840{ 841 struct conexant_spec *spec = codec->spec; 842 unsigned int bits; 843 844 spec->hp_present = snd_hda_jack_detect(codec, 0x11); 845 846 bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; 847 snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, 848 HDA_AMP_MUTE, bits); 849} 850 851/* unsolicited event for HP jack sensing */ 852static void cxt5045_hp_unsol_event(struct hda_codec *codec, 853 unsigned int res) 854{ 855 res >>= 26; 856 switch (res) { 857 case CONEXANT_HP_EVENT: 858 cxt5045_hp_automute(codec); 859 break; 860 case CONEXANT_MIC_EVENT: 861 cxt5045_hp_automic(codec); 862 break; 863 864 } 865} 866 867static struct snd_kcontrol_new cxt5045_mixers[] = { 868 HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), 869 HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), 870 HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), 871 HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), 872 HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), 873 HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), 874 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x1, HDA_INPUT), 875 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x1, HDA_INPUT), 876 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x2, HDA_INPUT), 877 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x2, HDA_INPUT), 878 HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), 879 { 880 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 881 .name = "Master Playback Switch", 882 .info = cxt_eapd_info, 883 .get = cxt_eapd_get, 884 .put = cxt5045_hp_master_sw_put, 885 .private_value = 0x10, 886 }, 887 888 {} 889}; 890 891static struct snd_kcontrol_new cxt5045_benq_mixers[] = { 892 HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT), 893 HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT), 894 HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT), 895 HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x4, HDA_INPUT), 896 897 HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT), 898 HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT), 899 HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT), 900 HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT), 901 902 HDA_CODEC_VOLUME("Mixer Capture Volume", 0x1a, 0x0, HDA_INPUT), 903 HDA_CODEC_MUTE("Mixer Capture Switch", 0x1a, 0x0, HDA_INPUT), 904 905 {} 906}; 907 908static struct snd_kcontrol_new cxt5045_mixers_hp530[] = { 909 HDA_CODEC_VOLUME("Int Mic Capture Volume", 0x1a, 0x02, HDA_INPUT), 910 HDA_CODEC_MUTE("Int Mic Capture Switch", 0x1a, 0x02, HDA_INPUT), 911 HDA_CODEC_VOLUME("Ext Mic Capture Volume", 0x1a, 0x01, HDA_INPUT), 912 HDA_CODEC_MUTE("Ext Mic Capture Switch", 0x1a, 0x01, HDA_INPUT), 913 HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), 914 HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), 915 HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x17, 0x2, HDA_INPUT), 916 HDA_CODEC_MUTE("Int Mic Playback Switch", 0x17, 0x2, HDA_INPUT), 917 HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x17, 0x1, HDA_INPUT), 918 HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x17, 0x1, HDA_INPUT), 919 HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), 920 { 921 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 922 .name = "Master Playback Switch", 923 .info = cxt_eapd_info, 924 .get = cxt_eapd_get, 925 .put = cxt5045_hp_master_sw_put, 926 .private_value = 0x10, 927 }, 928 929 {} 930}; 931 932static struct hda_verb cxt5045_init_verbs[] = { 933 /* Line in, Mic */ 934 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, 935 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, 936 /* HP, Amp */ 937 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 938 {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, 939 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 940 {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, 941 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 942 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 943 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 944 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 945 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 946 /* Record selector: Int mic */ 947 {0x1a, AC_VERB_SET_CONNECT_SEL,0x1}, 948 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 949 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, 950 /* SPDIF route: PCM */ 951 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 952 { 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 }, 953 /* EAPD */ 954 {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2 }, /* default on */ 955 { } /* end */ 956}; 957 958static struct hda_verb cxt5045_benq_init_verbs[] = { 959 /* Int Mic, Mic */ 960 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, 961 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, 962 /* Line In,HP, Amp */ 963 {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 964 {0x10, AC_VERB_SET_CONNECT_SEL, 0x1}, 965 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 966 {0x11, AC_VERB_SET_CONNECT_SEL, 0x1}, 967 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 968 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 969 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 970 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 971 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 972 /* Record selector: Int mic */ 973 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x1}, 974 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 975 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, 976 /* SPDIF route: PCM */ 977 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 978 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, 979 /* EAPD */ 980 {0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 981 { } /* end */ 982}; 983 984static struct hda_verb cxt5045_hp_sense_init_verbs[] = { 985 /* pin sensing on HP jack */ 986 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 987 { } /* end */ 988}; 989 990static struct hda_verb cxt5045_mic_sense_init_verbs[] = { 991 /* pin sensing on HP jack */ 992 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 993 { } /* end */ 994}; 995 996#ifdef CONFIG_SND_DEBUG 997/* Test configuration for debugging, modelled after the ALC260 test 998 * configuration. 999 */ 1000static struct hda_input_mux cxt5045_test_capture_source = { 1001 .num_items = 5, 1002 .items = { 1003 { "MIXER", 0x0 }, 1004 { "MIC1 pin", 0x1 }, 1005 { "LINE1 pin", 0x2 }, 1006 { "HP-OUT pin", 0x3 }, 1007 { "CD pin", 0x4 }, 1008 }, 1009}; 1010 1011static struct snd_kcontrol_new cxt5045_test_mixer[] = { 1012 1013 /* Output controls */ 1014 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT), 1015 HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT), 1016 HDA_CODEC_VOLUME("Node 11 Playback Volume", 0x11, 0x0, HDA_OUTPUT), 1017 HDA_CODEC_MUTE("Node 11 Playback Switch", 0x11, 0x0, HDA_OUTPUT), 1018 HDA_CODEC_VOLUME("Node 12 Playback Volume", 0x12, 0x0, HDA_OUTPUT), 1019 HDA_CODEC_MUTE("Node 12 Playback Switch", 0x12, 0x0, HDA_OUTPUT), 1020 1021 /* Modes for retasking pin widgets */ 1022 CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT), 1023 CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT), 1024 1025 /* EAPD Switch Control */ 1026 CXT_EAPD_SWITCH("External Amplifier", 0x10, 0x0), 1027 1028 /* Loopback mixer controls */ 1029 1030 HDA_CODEC_VOLUME("Mixer-1 Volume", 0x17, 0x0, HDA_INPUT), 1031 HDA_CODEC_MUTE("Mixer-1 Switch", 0x17, 0x0, HDA_INPUT), 1032 HDA_CODEC_VOLUME("Mixer-2 Volume", 0x17, 0x1, HDA_INPUT), 1033 HDA_CODEC_MUTE("Mixer-2 Switch", 0x17, 0x1, HDA_INPUT), 1034 HDA_CODEC_VOLUME("Mixer-3 Volume", 0x17, 0x2, HDA_INPUT), 1035 HDA_CODEC_MUTE("Mixer-3 Switch", 0x17, 0x2, HDA_INPUT), 1036 HDA_CODEC_VOLUME("Mixer-4 Volume", 0x17, 0x3, HDA_INPUT), 1037 HDA_CODEC_MUTE("Mixer-4 Switch", 0x17, 0x3, HDA_INPUT), 1038 HDA_CODEC_VOLUME("Mixer-5 Volume", 0x17, 0x4, HDA_INPUT), 1039 HDA_CODEC_MUTE("Mixer-5 Switch", 0x17, 0x4, HDA_INPUT), 1040 { 1041 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1042 .name = "Input Source", 1043 .info = conexant_mux_enum_info, 1044 .get = conexant_mux_enum_get, 1045 .put = conexant_mux_enum_put, 1046 }, 1047 /* Audio input controls */ 1048 HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT), 1049 HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT), 1050 HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT), 1051 HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT), 1052 HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT), 1053 HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT), 1054 HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT), 1055 HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT), 1056 HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT), 1057 HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT), 1058 { } /* end */ 1059}; 1060 1061static struct hda_verb cxt5045_test_init_verbs[] = { 1062 /* Set connections */ 1063 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, 1064 { 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 }, 1065 { 0x12, AC_VERB_SET_CONNECT_SEL, 0x0 }, 1066 /* Enable retasking pins as output, initially without power amp */ 1067 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1068 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1069 1070 /* Disable digital (SPDIF) pins initially, but users can enable 1071 * them via a mixer switch. In the case of SPDIF-out, this initverb 1072 * payload also sets the generation to 0, output to be in "consumer" 1073 * PCM format, copyright asserted, no pre-emphasis and no validity 1074 * control. 1075 */ 1076 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1077 {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, 1078 1079 /* Start with output sum widgets muted and their output gains at min */ 1080 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1081 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 1082 1083 /* Unmute retasking pin widget output buffers since the default 1084 * state appears to be output. As the pin mode is changed by the 1085 * user the pin mode control will take care of enabling the pin's 1086 * input/output buffers as needed. 1087 */ 1088 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1089 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1090 1091 /* Mute capture amp left and right */ 1092 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1093 1094 /* Set ADC connection select to match default mixer setting (mic1 1095 * pin) 1096 */ 1097 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, 1098 {0x17, AC_VERB_SET_CONNECT_SEL, 0x00}, 1099 1100 /* Mute all inputs to mixer widget (even unconnected ones) */ 1101 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */ 1102 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */ 1103 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */ 1104 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */ 1105 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ 1106 1107 { } 1108}; 1109#endif 1110 1111 1112/* initialize jack-sensing, too */ 1113static int cxt5045_init(struct hda_codec *codec) 1114{ 1115 conexant_init(codec); 1116 cxt5045_hp_automute(codec); 1117 return 0; 1118} 1119 1120 1121enum { 1122 CXT5045_LAPTOP_HPSENSE, 1123 CXT5045_LAPTOP_MICSENSE, 1124 CXT5045_LAPTOP_HPMICSENSE, 1125 CXT5045_BENQ, 1126 CXT5045_LAPTOP_HP530, 1127#ifdef CONFIG_SND_DEBUG 1128 CXT5045_TEST, 1129#endif 1130 CXT5045_MODELS 1131}; 1132 1133static const char *cxt5045_models[CXT5045_MODELS] = { 1134 [CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense", 1135 [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", 1136 [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", 1137 [CXT5045_BENQ] = "benq", 1138 [CXT5045_LAPTOP_HP530] = "laptop-hp530", 1139#ifdef CONFIG_SND_DEBUG 1140 [CXT5045_TEST] = "test", 1141#endif 1142}; 1143 1144static struct snd_pci_quirk cxt5045_cfg_tbl[] = { 1145 SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), 1146 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", 1147 CXT5045_LAPTOP_HPSENSE), 1148 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE), 1149 SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), 1150 SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), 1151 SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), 1152 SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505", 1153 CXT5045_LAPTOP_HPMICSENSE), 1154 SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE), 1155 SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE), 1156 SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE), 1157 SND_PCI_QUIRK_MASK(0x1631, 0xff00, 0xc100, "Packard Bell", 1158 CXT5045_LAPTOP_HPMICSENSE), 1159 SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE), 1160 {} 1161}; 1162 1163static int patch_cxt5045(struct hda_codec *codec) 1164{ 1165 struct conexant_spec *spec; 1166 int board_config; 1167 1168 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 1169 if (!spec) 1170 return -ENOMEM; 1171 codec->spec = spec; 1172 codec->pin_amp_workaround = 1; 1173 1174 spec->multiout.max_channels = 2; 1175 spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids); 1176 spec->multiout.dac_nids = cxt5045_dac_nids; 1177 spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT; 1178 spec->num_adc_nids = 1; 1179 spec->adc_nids = cxt5045_adc_nids; 1180 spec->capsrc_nids = cxt5045_capsrc_nids; 1181 spec->input_mux = &cxt5045_capture_source; 1182 spec->num_mixers = 1; 1183 spec->mixers[0] = cxt5045_mixers; 1184 spec->num_init_verbs = 1; 1185 spec->init_verbs[0] = cxt5045_init_verbs; 1186 spec->spdif_route = 0; 1187 spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes); 1188 spec->channel_mode = cxt5045_modes; 1189 1190 set_beep_amp(spec, 0x16, 0, 1); 1191 1192 codec->patch_ops = conexant_patch_ops; 1193 1194 board_config = snd_hda_check_board_config(codec, CXT5045_MODELS, 1195 cxt5045_models, 1196 cxt5045_cfg_tbl); 1197 switch (board_config) { 1198 case CXT5045_LAPTOP_HPSENSE: 1199 codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; 1200 spec->input_mux = &cxt5045_capture_source; 1201 spec->num_init_verbs = 2; 1202 spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; 1203 spec->mixers[0] = cxt5045_mixers; 1204 codec->patch_ops.init = cxt5045_init; 1205 break; 1206 case CXT5045_LAPTOP_MICSENSE: 1207 codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; 1208 spec->input_mux = &cxt5045_capture_source; 1209 spec->num_init_verbs = 2; 1210 spec->init_verbs[1] = cxt5045_mic_sense_init_verbs; 1211 spec->mixers[0] = cxt5045_mixers; 1212 codec->patch_ops.init = cxt5045_init; 1213 break; 1214 default: 1215 case CXT5045_LAPTOP_HPMICSENSE: 1216 codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; 1217 spec->input_mux = &cxt5045_capture_source; 1218 spec->num_init_verbs = 3; 1219 spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; 1220 spec->init_verbs[2] = cxt5045_mic_sense_init_verbs; 1221 spec->mixers[0] = cxt5045_mixers; 1222 codec->patch_ops.init = cxt5045_init; 1223 break; 1224 case CXT5045_BENQ: 1225 codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; 1226 spec->input_mux = &cxt5045_capture_source_benq; 1227 spec->num_init_verbs = 1; 1228 spec->init_verbs[0] = cxt5045_benq_init_verbs; 1229 spec->mixers[0] = cxt5045_mixers; 1230 spec->mixers[1] = cxt5045_benq_mixers; 1231 spec->num_mixers = 2; 1232 codec->patch_ops.init = cxt5045_init; 1233 break; 1234 case CXT5045_LAPTOP_HP530: 1235 codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; 1236 spec->input_mux = &cxt5045_capture_source_hp530; 1237 spec->num_init_verbs = 2; 1238 spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; 1239 spec->mixers[0] = cxt5045_mixers_hp530; 1240 codec->patch_ops.init = cxt5045_init; 1241 break; 1242#ifdef CONFIG_SND_DEBUG 1243 case CXT5045_TEST: 1244 spec->input_mux = &cxt5045_test_capture_source; 1245 spec->mixers[0] = cxt5045_test_mixer; 1246 spec->init_verbs[0] = cxt5045_test_init_verbs; 1247 break; 1248 1249#endif 1250 } 1251 1252 switch (codec->subsystem_id >> 16) { 1253 case 0x103c: 1254 case 0x1631: 1255 case 0x1734: 1256 case 0x17aa: 1257 /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have 1258 * really bad sound over 0dB on NID 0x17. Fix max PCM level to 1259 * 0 dB (originally it has 0x2b steps with 0dB offset 0x14) 1260 */ 1261 snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, 1262 (0x14 << AC_AMPCAP_OFFSET_SHIFT) | 1263 (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | 1264 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | 1265 (1 << AC_AMPCAP_MUTE_SHIFT)); 1266 break; 1267 } 1268 1269 if (spec->beep_amp) 1270 snd_hda_attach_beep_device(codec, spec->beep_amp); 1271 1272 return 0; 1273} 1274 1275 1276/* Conexant 5047 specific */ 1277#define CXT5047_SPDIF_OUT 0x11 1278 1279static hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */ 1280static hda_nid_t cxt5047_adc_nids[1] = { 0x12 }; 1281static hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a }; 1282 1283static struct hda_channel_mode cxt5047_modes[1] = { 1284 { 2, NULL }, 1285}; 1286 1287static struct hda_input_mux cxt5047_toshiba_capture_source = { 1288 .num_items = 2, 1289 .items = { 1290 { "ExtMic", 0x2 }, 1291 { "Line-In", 0x1 }, 1292 } 1293}; 1294 1295/* turn on/off EAPD (+ mute HP) as a master switch */ 1296static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol, 1297 struct snd_ctl_elem_value *ucontrol) 1298{ 1299 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1300 struct conexant_spec *spec = codec->spec; 1301 unsigned int bits; 1302 1303 if (!cxt_eapd_put(kcontrol, ucontrol)) 1304 return 0; 1305 1306 /* toggle internal speakers mute depending of presence of 1307 * the headphone jack 1308 */ 1309 bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE; 1310 /* NOTE: Conexat codec needs the index for *OUTPUT* amp of 1311 * pin widgets unlike other codecs. In this case, we need to 1312 * set index 0x01 for the volume from the mixer amp 0x19. 1313 */ 1314 snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, 1315 HDA_AMP_MUTE, bits); 1316 bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE; 1317 snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, 1318 HDA_AMP_MUTE, bits); 1319 return 1; 1320} 1321 1322/* mute internal speaker if HP is plugged */ 1323static void cxt5047_hp_automute(struct hda_codec *codec) 1324{ 1325 struct conexant_spec *spec = codec->spec; 1326 unsigned int bits; 1327 1328 spec->hp_present = snd_hda_jack_detect(codec, 0x13); 1329 1330 bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; 1331 /* See the note in cxt5047_hp_master_sw_put */ 1332 snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01, 1333 HDA_AMP_MUTE, bits); 1334} 1335 1336/* toggle input of built-in and mic jack appropriately */ 1337static void cxt5047_hp_automic(struct hda_codec *codec) 1338{ 1339 static struct hda_verb mic_jack_on[] = { 1340 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1341 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1342 {} 1343 }; 1344 static struct hda_verb mic_jack_off[] = { 1345 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 1346 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1347 {} 1348 }; 1349 unsigned int present; 1350 1351 present = snd_hda_jack_detect(codec, 0x15); 1352 if (present) 1353 snd_hda_sequence_write(codec, mic_jack_on); 1354 else 1355 snd_hda_sequence_write(codec, mic_jack_off); 1356} 1357 1358/* unsolicited event for HP jack sensing */ 1359static void cxt5047_hp_unsol_event(struct hda_codec *codec, 1360 unsigned int res) 1361{ 1362 switch (res >> 26) { 1363 case CONEXANT_HP_EVENT: 1364 cxt5047_hp_automute(codec); 1365 break; 1366 case CONEXANT_MIC_EVENT: 1367 cxt5047_hp_automic(codec); 1368 break; 1369 } 1370} 1371 1372static struct snd_kcontrol_new cxt5047_base_mixers[] = { 1373 HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT), 1374 HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT), 1375 HDA_CODEC_VOLUME("Mic Boost", 0x1a, 0x0, HDA_OUTPUT), 1376 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT), 1377 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT), 1378 HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT), 1379 HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT), 1380 { 1381 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1382 .name = "Master Playback Switch", 1383 .info = cxt_eapd_info, 1384 .get = cxt_eapd_get, 1385 .put = cxt5047_hp_master_sw_put, 1386 .private_value = 0x13, 1387 }, 1388 1389 {} 1390}; 1391 1392static struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = { 1393 /* See the note in cxt5047_hp_master_sw_put */ 1394 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT), 1395 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT), 1396 {} 1397}; 1398 1399static struct snd_kcontrol_new cxt5047_hp_only_mixers[] = { 1400 HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT), 1401 { } /* end */ 1402}; 1403 1404static struct hda_verb cxt5047_init_verbs[] = { 1405 /* Line in, Mic, Built-in Mic */ 1406 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, 1407 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, 1408 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 }, 1409 /* HP, Speaker */ 1410 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, 1411 {0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* mixer(0x19) */ 1412 {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mixer(0x19) */ 1413 /* Record selector: Mic */ 1414 {0x12, AC_VERB_SET_CONNECT_SEL,0x03}, 1415 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 1416 AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17}, 1417 {0x1A, AC_VERB_SET_CONNECT_SEL,0x02}, 1418 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, 1419 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00}, 1420 {0x1A, AC_VERB_SET_AMP_GAIN_MUTE, 1421 AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03}, 1422 /* SPDIF route: PCM */ 1423 { 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 }, 1424 /* Enable unsolicited events */ 1425 {0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 1426 {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 1427 { } /* end */ 1428}; 1429 1430/* configuration for Toshiba Laptops */ 1431static struct hda_verb cxt5047_toshiba_init_verbs[] = { 1432 {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */ 1433 {} 1434}; 1435 1436/* Test configuration for debugging, modelled after the ALC260 test 1437 * configuration. 1438 */ 1439#ifdef CONFIG_SND_DEBUG 1440static struct hda_input_mux cxt5047_test_capture_source = { 1441 .num_items = 4, 1442 .items = { 1443 { "LINE1 pin", 0x0 }, 1444 { "MIC1 pin", 0x1 }, 1445 { "MIC2 pin", 0x2 }, 1446 { "CD pin", 0x3 }, 1447 }, 1448}; 1449 1450static struct snd_kcontrol_new cxt5047_test_mixer[] = { 1451 1452 /* Output only controls */ 1453 HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT), 1454 HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x0, HDA_OUTPUT), 1455 HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x0, HDA_OUTPUT), 1456 HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x0, HDA_OUTPUT), 1457 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT), 1458 HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT), 1459 HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT), 1460 HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT), 1461 HDA_CODEC_VOLUME("Line1-Out Playback Volume", 0x14, 0x0, HDA_OUTPUT), 1462 HDA_CODEC_MUTE("Line1-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), 1463 HDA_CODEC_VOLUME("Line2-Out Playback Volume", 0x15, 0x0, HDA_OUTPUT), 1464 HDA_CODEC_MUTE("Line2-Out Playback Switch", 0x15, 0x0, HDA_OUTPUT), 1465 1466 /* Modes for retasking pin widgets */ 1467 CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT), 1468 CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT), 1469 1470 /* EAPD Switch Control */ 1471 CXT_EAPD_SWITCH("External Amplifier", 0x13, 0x0), 1472 1473 /* Loopback mixer controls */ 1474 HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x12, 0x01, HDA_INPUT), 1475 HDA_CODEC_MUTE("MIC1 Playback Switch", 0x12, 0x01, HDA_INPUT), 1476 HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x12, 0x02, HDA_INPUT), 1477 HDA_CODEC_MUTE("MIC2 Playback Switch", 0x12, 0x02, HDA_INPUT), 1478 HDA_CODEC_VOLUME("LINE Playback Volume", 0x12, 0x0, HDA_INPUT), 1479 HDA_CODEC_MUTE("LINE Playback Switch", 0x12, 0x0, HDA_INPUT), 1480 HDA_CODEC_VOLUME("CD Playback Volume", 0x12, 0x04, HDA_INPUT), 1481 HDA_CODEC_MUTE("CD Playback Switch", 0x12, 0x04, HDA_INPUT), 1482 1483 HDA_CODEC_VOLUME("Capture-1 Volume", 0x19, 0x0, HDA_INPUT), 1484 HDA_CODEC_MUTE("Capture-1 Switch", 0x19, 0x0, HDA_INPUT), 1485 HDA_CODEC_VOLUME("Capture-2 Volume", 0x19, 0x1, HDA_INPUT), 1486 HDA_CODEC_MUTE("Capture-2 Switch", 0x19, 0x1, HDA_INPUT), 1487 HDA_CODEC_VOLUME("Capture-3 Volume", 0x19, 0x2, HDA_INPUT), 1488 HDA_CODEC_MUTE("Capture-3 Switch", 0x19, 0x2, HDA_INPUT), 1489 HDA_CODEC_VOLUME("Capture-4 Volume", 0x19, 0x3, HDA_INPUT), 1490 HDA_CODEC_MUTE("Capture-4 Switch", 0x19, 0x3, HDA_INPUT), 1491 { 1492 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1493 .name = "Input Source", 1494 .info = conexant_mux_enum_info, 1495 .get = conexant_mux_enum_get, 1496 .put = conexant_mux_enum_put, 1497 }, 1498 HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), 1499 1500 { } /* end */ 1501}; 1502 1503static struct hda_verb cxt5047_test_init_verbs[] = { 1504 /* Enable retasking pins as output, initially without power amp */ 1505 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1506 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1507 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1508 1509 /* Disable digital (SPDIF) pins initially, but users can enable 1510 * them via a mixer switch. In the case of SPDIF-out, this initverb 1511 * payload also sets the generation to 0, output to be in "consumer" 1512 * PCM format, copyright asserted, no pre-emphasis and no validity 1513 * control. 1514 */ 1515 {0x18, AC_VERB_SET_DIGI_CONVERT_1, 0}, 1516 1517 /* Ensure mic1, mic2, line1 pin widgets take input from the 1518 * OUT1 sum bus when acting as an output. 1519 */ 1520 {0x1a, AC_VERB_SET_CONNECT_SEL, 0}, 1521 {0x1b, AC_VERB_SET_CONNECT_SEL, 0}, 1522 1523 /* Start with output sum widgets muted and their output gains at min */ 1524 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1525 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 1526 1527 /* Unmute retasking pin widget output buffers since the default 1528 * state appears to be output. As the pin mode is changed by the 1529 * user the pin mode control will take care of enabling the pin's 1530 * input/output buffers as needed. 1531 */ 1532 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1533 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1534 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1535 1536 /* Mute capture amp left and right */ 1537 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 1538 1539 /* Set ADC connection select to match default mixer setting (mic1 1540 * pin) 1541 */ 1542 {0x12, AC_VERB_SET_CONNECT_SEL, 0x00}, 1543 1544 /* Mute all inputs to mixer widget (even unconnected ones) */ 1545 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */ 1546 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */ 1547 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */ 1548 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */ 1549 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */ 1550 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */ 1551 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */ 1552 {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */ 1553 1554 { } 1555}; 1556#endif 1557 1558 1559/* initialize jack-sensing, too */ 1560static int cxt5047_hp_init(struct hda_codec *codec) 1561{ 1562 conexant_init(codec); 1563 cxt5047_hp_automute(codec); 1564 return 0; 1565} 1566 1567 1568enum { 1569 CXT5047_LAPTOP, /* Laptops w/o EAPD support */ 1570 CXT5047_LAPTOP_HP, /* Some HP laptops */ 1571 CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */ 1572#ifdef CONFIG_SND_DEBUG 1573 CXT5047_TEST, 1574#endif 1575 CXT5047_MODELS 1576}; 1577 1578static const char *cxt5047_models[CXT5047_MODELS] = { 1579 [CXT5047_LAPTOP] = "laptop", 1580 [CXT5047_LAPTOP_HP] = "laptop-hp", 1581 [CXT5047_LAPTOP_EAPD] = "laptop-eapd", 1582#ifdef CONFIG_SND_DEBUG 1583 [CXT5047_TEST] = "test", 1584#endif 1585}; 1586 1587static struct snd_pci_quirk cxt5047_cfg_tbl[] = { 1588 SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP), 1589 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series", 1590 CXT5047_LAPTOP), 1591 SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD), 1592 {} 1593}; 1594 1595static int patch_cxt5047(struct hda_codec *codec) 1596{ 1597 struct conexant_spec *spec; 1598 int board_config; 1599 1600 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 1601 if (!spec) 1602 return -ENOMEM; 1603 codec->spec = spec; 1604 codec->pin_amp_workaround = 1; 1605 1606 spec->multiout.max_channels = 2; 1607 spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids); 1608 spec->multiout.dac_nids = cxt5047_dac_nids; 1609 spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT; 1610 spec->num_adc_nids = 1; 1611 spec->adc_nids = cxt5047_adc_nids; 1612 spec->capsrc_nids = cxt5047_capsrc_nids; 1613 spec->num_mixers = 1; 1614 spec->mixers[0] = cxt5047_base_mixers; 1615 spec->num_init_verbs = 1; 1616 spec->init_verbs[0] = cxt5047_init_verbs; 1617 spec->spdif_route = 0; 1618 spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes), 1619 spec->channel_mode = cxt5047_modes, 1620 1621 codec->patch_ops = conexant_patch_ops; 1622 1623 board_config = snd_hda_check_board_config(codec, CXT5047_MODELS, 1624 cxt5047_models, 1625 cxt5047_cfg_tbl); 1626 switch (board_config) { 1627 case CXT5047_LAPTOP: 1628 spec->num_mixers = 2; 1629 spec->mixers[1] = cxt5047_hp_spk_mixers; 1630 codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; 1631 break; 1632 case CXT5047_LAPTOP_HP: 1633 spec->num_mixers = 2; 1634 spec->mixers[1] = cxt5047_hp_only_mixers; 1635 codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; 1636 codec->patch_ops.init = cxt5047_hp_init; 1637 break; 1638 case CXT5047_LAPTOP_EAPD: 1639 spec->input_mux = &cxt5047_toshiba_capture_source; 1640 spec->num_mixers = 2; 1641 spec->mixers[1] = cxt5047_hp_spk_mixers; 1642 spec->num_init_verbs = 2; 1643 spec->init_verbs[1] = cxt5047_toshiba_init_verbs; 1644 codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; 1645 break; 1646#ifdef CONFIG_SND_DEBUG 1647 case CXT5047_TEST: 1648 spec->input_mux = &cxt5047_test_capture_source; 1649 spec->mixers[0] = cxt5047_test_mixer; 1650 spec->init_verbs[0] = cxt5047_test_init_verbs; 1651 codec->patch_ops.unsol_event = cxt5047_hp_unsol_event; 1652#endif 1653 } 1654 spec->vmaster_nid = 0x13; 1655 1656 switch (codec->subsystem_id >> 16) { 1657 case 0x103c: 1658 /* HP laptops have really bad sound over 0 dB on NID 0x10. 1659 * Fix max PCM level to 0 dB (originally it has 0x1e steps 1660 * with 0 dB offset 0x17) 1661 */ 1662 snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, 1663 (0x17 << AC_AMPCAP_OFFSET_SHIFT) | 1664 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | 1665 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | 1666 (1 << AC_AMPCAP_MUTE_SHIFT)); 1667 break; 1668 } 1669 1670 return 0; 1671} 1672 1673/* Conexant 5051 specific */ 1674static hda_nid_t cxt5051_dac_nids[1] = { 0x10 }; 1675static hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 }; 1676 1677static struct hda_channel_mode cxt5051_modes[1] = { 1678 { 2, NULL }, 1679}; 1680 1681static void cxt5051_update_speaker(struct hda_codec *codec) 1682{ 1683 struct conexant_spec *spec = codec->spec; 1684 unsigned int pinctl; 1685 /* headphone pin */ 1686 pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; 1687 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 1688 pinctl); 1689 /* speaker pin */ 1690 pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; 1691 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 1692 pinctl); 1693 /* on ideapad there is an aditional speaker (subwoofer) to mute */ 1694 if (spec->ideapad) 1695 snd_hda_codec_write(codec, 0x1b, 0, 1696 AC_VERB_SET_PIN_WIDGET_CONTROL, 1697 pinctl); 1698} 1699 1700/* turn on/off EAPD (+ mute HP) as a master switch */ 1701static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol, 1702 struct snd_ctl_elem_value *ucontrol) 1703{ 1704 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 1705 1706 if (!cxt_eapd_put(kcontrol, ucontrol)) 1707 return 0; 1708 cxt5051_update_speaker(codec); 1709 return 1; 1710} 1711 1712/* toggle input of built-in and mic jack appropriately */ 1713static void cxt5051_portb_automic(struct hda_codec *codec) 1714{ 1715 struct conexant_spec *spec = codec->spec; 1716 unsigned int present; 1717 1718 if (!(spec->auto_mic & AUTO_MIC_PORTB)) 1719 return; 1720 present = snd_hda_jack_detect(codec, 0x17); 1721 snd_hda_codec_write(codec, 0x14, 0, 1722 AC_VERB_SET_CONNECT_SEL, 1723 present ? 0x01 : 0x00); 1724} 1725 1726/* switch the current ADC according to the jack state */ 1727static void cxt5051_portc_automic(struct hda_codec *codec) 1728{ 1729 struct conexant_spec *spec = codec->spec; 1730 unsigned int present; 1731 hda_nid_t new_adc; 1732 1733 if (!(spec->auto_mic & AUTO_MIC_PORTC)) 1734 return; 1735 present = snd_hda_jack_detect(codec, 0x18); 1736 if (present) 1737 spec->cur_adc_idx = 1; 1738 else 1739 spec->cur_adc_idx = 0; 1740 new_adc = spec->adc_nids[spec->cur_adc_idx]; 1741 if (spec->cur_adc && spec->cur_adc != new_adc) { 1742 /* stream is running, let's swap the current ADC */ 1743 __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); 1744 spec->cur_adc = new_adc; 1745 snd_hda_codec_setup_stream(codec, new_adc, 1746 spec->cur_adc_stream_tag, 0, 1747 spec->cur_adc_format); 1748 } 1749} 1750 1751/* mute internal speaker if HP is plugged */ 1752static void cxt5051_hp_automute(struct hda_codec *codec) 1753{ 1754 struct conexant_spec *spec = codec->spec; 1755 1756 spec->hp_present = snd_hda_jack_detect(codec, 0x16); 1757 cxt5051_update_speaker(codec); 1758} 1759 1760/* unsolicited event for HP jack sensing */ 1761static void cxt5051_hp_unsol_event(struct hda_codec *codec, 1762 unsigned int res) 1763{ 1764 int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20; 1765 switch (res >> 26) { 1766 case CONEXANT_HP_EVENT: 1767 cxt5051_hp_automute(codec); 1768 break; 1769 case CXT5051_PORTB_EVENT: 1770 cxt5051_portb_automic(codec); 1771 break; 1772 case CXT5051_PORTC_EVENT: 1773 cxt5051_portc_automic(codec); 1774 break; 1775 } 1776 conexant_report_jack(codec, nid); 1777} 1778 1779static struct snd_kcontrol_new cxt5051_playback_mixers[] = { 1780 HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), 1781 { 1782 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 1783 .name = "Master Playback Switch", 1784 .info = cxt_eapd_info, 1785 .get = cxt_eapd_get, 1786 .put = cxt5051_hp_master_sw_put, 1787 .private_value = 0x1a, 1788 }, 1789 {} 1790}; 1791 1792static struct snd_kcontrol_new cxt5051_capture_mixers[] = { 1793 HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), 1794 HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), 1795 HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), 1796 HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), 1797 HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT), 1798 HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT), 1799 {} 1800}; 1801 1802static struct snd_kcontrol_new cxt5051_hp_mixers[] = { 1803 HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), 1804 HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), 1805 HDA_CODEC_VOLUME("External Mic Volume", 0x15, 0x00, HDA_INPUT), 1806 HDA_CODEC_MUTE("External Mic Switch", 0x15, 0x00, HDA_INPUT), 1807 {} 1808}; 1809 1810static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { 1811 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT), 1812 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT), 1813 {} 1814}; 1815 1816static struct snd_kcontrol_new cxt5051_f700_mixers[] = { 1817 HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT), 1818 HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT), 1819 {} 1820}; 1821 1822static struct snd_kcontrol_new cxt5051_toshiba_mixers[] = { 1823 HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT), 1824 HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT), 1825 HDA_CODEC_VOLUME("External Mic Volume", 0x14, 0x01, HDA_INPUT), 1826 HDA_CODEC_MUTE("External Mic Switch", 0x14, 0x01, HDA_INPUT), 1827 {} 1828}; 1829 1830static struct hda_verb cxt5051_init_verbs[] = { 1831 /* Line in, Mic */ 1832 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1833 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1834 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1835 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1836 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1837 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1838 /* SPK */ 1839 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1840 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, 1841 /* HP, Amp */ 1842 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 1843 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, 1844 /* DAC1 */ 1845 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1846 /* Record selector: Int mic */ 1847 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, 1848 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, 1849 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, 1850 /* SPDIF route: PCM */ 1851 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1852 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, 1853 /* EAPD */ 1854 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1855 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, 1856 { } /* end */ 1857}; 1858 1859static struct hda_verb cxt5051_hp_dv6736_init_verbs[] = { 1860 /* Line in, Mic */ 1861 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1862 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1863 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, 1864 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, 1865 /* SPK */ 1866 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1867 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, 1868 /* HP, Amp */ 1869 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 1870 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, 1871 /* DAC1 */ 1872 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1873 /* Record selector: Int mic */ 1874 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, 1875 {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, 1876 /* SPDIF route: PCM */ 1877 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, 1878 /* EAPD */ 1879 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1880 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, 1881 { } /* end */ 1882}; 1883 1884static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { 1885 /* Line in, Mic */ 1886 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1887 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1888 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1889 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1890 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 1891 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1892 /* SPK */ 1893 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1894 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, 1895 /* HP, Amp */ 1896 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 1897 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, 1898 /* Docking HP */ 1899 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 1900 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, 1901 /* DAC1 */ 1902 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1903 /* Record selector: Int mic */ 1904 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, 1905 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, 1906 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44}, 1907 /* SPDIF route: PCM */ 1908 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* needed for W500 Advanced Mini Dock 250410 */ 1909 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, 1910 /* EAPD */ 1911 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1912 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, 1913 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, 1914 { } /* end */ 1915}; 1916 1917static struct hda_verb cxt5051_f700_init_verbs[] = { 1918 /* Line in, Mic */ 1919 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, 1920 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 1921 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, 1922 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, 1923 /* SPK */ 1924 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1925 {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, 1926 /* HP, Amp */ 1927 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 1928 {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, 1929 /* DAC1 */ 1930 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 1931 /* Record selector: Int mic */ 1932 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, 1933 {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, 1934 /* SPDIF route: PCM */ 1935 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, 1936 /* EAPD */ 1937 {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 1938 {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, 1939 { } /* end */ 1940}; 1941 1942static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid, 1943 unsigned int event) 1944{ 1945 snd_hda_codec_write(codec, nid, 0, 1946 AC_VERB_SET_UNSOLICITED_ENABLE, 1947 AC_USRSP_EN | event); 1948#ifdef CONFIG_SND_HDA_INPUT_JACK 1949 conexant_add_jack(codec, nid, SND_JACK_MICROPHONE); 1950 conexant_report_jack(codec, nid); 1951#endif 1952} 1953 1954static struct hda_verb cxt5051_ideapad_init_verbs[] = { 1955 /* Subwoofer */ 1956 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 1957 {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, 1958 { } /* end */ 1959}; 1960 1961/* initialize jack-sensing, too */ 1962static int cxt5051_init(struct hda_codec *codec) 1963{ 1964 struct conexant_spec *spec = codec->spec; 1965 1966 conexant_init(codec); 1967 conexant_init_jacks(codec); 1968 1969 if (spec->auto_mic & AUTO_MIC_PORTB) 1970 cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT); 1971 if (spec->auto_mic & AUTO_MIC_PORTC) 1972 cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT); 1973 1974 if (codec->patch_ops.unsol_event) { 1975 cxt5051_hp_automute(codec); 1976 cxt5051_portb_automic(codec); 1977 cxt5051_portc_automic(codec); 1978 } 1979 return 0; 1980} 1981 1982 1983enum { 1984 CXT5051_LAPTOP, /* Laptops w/ EAPD support */ 1985 CXT5051_HP, /* no docking */ 1986 CXT5051_HP_DV6736, /* HP without mic switch */ 1987 CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */ 1988 CXT5051_F700, /* HP Compaq Presario F700 */ 1989 CXT5051_TOSHIBA, /* Toshiba M300 & co */ 1990 CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */ 1991 CXT5051_MODELS 1992}; 1993 1994static const char *cxt5051_models[CXT5051_MODELS] = { 1995 [CXT5051_LAPTOP] = "laptop", 1996 [CXT5051_HP] = "hp", 1997 [CXT5051_HP_DV6736] = "hp-dv6736", 1998 [CXT5051_LENOVO_X200] = "lenovo-x200", 1999 [CXT5051_F700] = "hp-700", 2000 [CXT5051_TOSHIBA] = "toshiba", 2001 [CXT5051_IDEAPAD] = "ideapad", 2002}; 2003 2004static struct snd_pci_quirk cxt5051_cfg_tbl[] = { 2005 SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), 2006 SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), 2007 SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), 2008 SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA), 2009 SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", 2010 CXT5051_LAPTOP), 2011 SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), 2012 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), 2013 SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD), 2014 {} 2015}; 2016 2017static int patch_cxt5051(struct hda_codec *codec) 2018{ 2019 struct conexant_spec *spec; 2020 int board_config; 2021 2022 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 2023 if (!spec) 2024 return -ENOMEM; 2025 codec->spec = spec; 2026 codec->pin_amp_workaround = 1; 2027 2028 codec->patch_ops = conexant_patch_ops; 2029 codec->patch_ops.init = cxt5051_init; 2030 2031 spec->multiout.max_channels = 2; 2032 spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids); 2033 spec->multiout.dac_nids = cxt5051_dac_nids; 2034 spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT; 2035 spec->num_adc_nids = 1; /* not 2; via auto-mic switch */ 2036 spec->adc_nids = cxt5051_adc_nids; 2037 spec->num_mixers = 2; 2038 spec->mixers[0] = cxt5051_capture_mixers; 2039 spec->mixers[1] = cxt5051_playback_mixers; 2040 spec->num_init_verbs = 1; 2041 spec->init_verbs[0] = cxt5051_init_verbs; 2042 spec->spdif_route = 0; 2043 spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes); 2044 spec->channel_mode = cxt5051_modes; 2045 spec->cur_adc = 0; 2046 spec->cur_adc_idx = 0; 2047 2048 set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); 2049 2050 codec->patch_ops.unsol_event = cxt5051_hp_unsol_event; 2051 2052 board_config = snd_hda_check_board_config(codec, CXT5051_MODELS, 2053 cxt5051_models, 2054 cxt5051_cfg_tbl); 2055 spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC; 2056 switch (board_config) { 2057 case CXT5051_HP: 2058 spec->mixers[0] = cxt5051_hp_mixers; 2059 break; 2060 case CXT5051_HP_DV6736: 2061 spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs; 2062 spec->mixers[0] = cxt5051_hp_dv6736_mixers; 2063 spec->auto_mic = 0; 2064 break; 2065 case CXT5051_LENOVO_X200: 2066 spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; 2067 /* Thinkpad X301 does not have S/PDIF wired and no ability 2068 to use a docking station. */ 2069 if (codec->subsystem_id == 0x17aa211f) 2070 spec->multiout.dig_out_nid = 0; 2071 break; 2072 case CXT5051_F700: 2073 spec->init_verbs[0] = cxt5051_f700_init_verbs; 2074 spec->mixers[0] = cxt5051_f700_mixers; 2075 spec->auto_mic = 0; 2076 break; 2077 case CXT5051_TOSHIBA: 2078 spec->mixers[0] = cxt5051_toshiba_mixers; 2079 spec->auto_mic = AUTO_MIC_PORTB; 2080 break; 2081 case CXT5051_IDEAPAD: 2082 spec->init_verbs[spec->num_init_verbs++] = 2083 cxt5051_ideapad_init_verbs; 2084 spec->ideapad = 1; 2085 break; 2086 } 2087 2088 if (spec->beep_amp) 2089 snd_hda_attach_beep_device(codec, spec->beep_amp); 2090 2091 return 0; 2092} 2093 2094/* Conexant 5066 specific */ 2095 2096static hda_nid_t cxt5066_dac_nids[1] = { 0x10 }; 2097static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; 2098static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; 2099#define CXT5066_SPDIF_OUT 0x21 2100 2101/* OLPC's microphone port is DC coupled for use with external sensors, 2102 * therefore we use a 50% mic bias in order to center the input signal with 2103 * the DC input range of the codec. */ 2104#define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 2105 2106static struct hda_channel_mode cxt5066_modes[1] = { 2107 { 2, NULL }, 2108}; 2109 2110static void cxt5066_update_speaker(struct hda_codec *codec) 2111{ 2112 struct conexant_spec *spec = codec->spec; 2113 unsigned int pinctl; 2114 2115 snd_printdd("CXT5066: update speaker, hp_present=%d\n", 2116 spec->hp_present); 2117 2118 /* Port A (HP) */ 2119 pinctl = ((spec->hp_present & 1) && spec->cur_eapd) ? PIN_HP : 0; 2120 snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2121 pinctl); 2122 2123 /* Port D (HP/LO) */ 2124 pinctl = ((spec->hp_present & 2) && spec->cur_eapd) 2125 ? spec->port_d_mode : 0; 2126 /* Mute if Port A is connected on Thinkpad */ 2127 if (spec->thinkpad && (spec->hp_present & 1)) 2128 pinctl = 0; 2129 snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2130 pinctl); 2131 2132 /* CLASS_D AMP */ 2133 pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; 2134 snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2135 pinctl); 2136 2137 if (spec->dell_automute) { 2138 /* DELL AIO Port Rule: PortA > PortD > IntSpk */ 2139 pinctl = (!(spec->hp_present & 1) && spec->cur_eapd) 2140 ? PIN_OUT : 0; 2141 snd_hda_codec_write(codec, 0x1c, 0, 2142 AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); 2143 } 2144} 2145 2146/* turn on/off EAPD (+ mute HP) as a master switch */ 2147static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, 2148 struct snd_ctl_elem_value *ucontrol) 2149{ 2150 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2151 2152 if (!cxt_eapd_put(kcontrol, ucontrol)) 2153 return 0; 2154 2155 cxt5066_update_speaker(codec); 2156 return 1; 2157} 2158 2159static const struct hda_input_mux cxt5066_olpc_dc_bias = { 2160 .num_items = 3, 2161 .items = { 2162 { "Off", PIN_IN }, 2163 { "50%", PIN_VREF50 }, 2164 { "80%", PIN_VREF80 }, 2165 }, 2166}; 2167 2168static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) 2169{ 2170 struct conexant_spec *spec = codec->spec; 2171 /* Even though port F is the DC input, the bias is controlled on port B. 2172 * we also leave that port as an active input (but unselected) in DC mode 2173 * just in case that is necessary to make the bias setting take effect. */ 2174 return snd_hda_codec_write_cache(codec, 0x1a, 0, 2175 AC_VERB_SET_PIN_WIDGET_CONTROL, 2176 cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); 2177} 2178 2179/* OLPC defers mic widget control until when capture is started because the 2180 * microphone LED comes on as soon as these settings are put in place. if we 2181 * did this before recording, it would give the false indication that recording 2182 * is happening when it is not. */ 2183static void cxt5066_olpc_select_mic(struct hda_codec *codec) 2184{ 2185 struct conexant_spec *spec = codec->spec; 2186 if (!spec->recording) 2187 return; 2188 2189 if (spec->dc_enable) { 2190 /* in DC mode we ignore presence detection and just use the jack 2191 * through our special DC port */ 2192 const struct hda_verb enable_dc_mode[] = { 2193 /* disble internal mic, port C */ 2194 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2195 2196 /* enable DC capture, port F */ 2197 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2198 {}, 2199 }; 2200 2201 snd_hda_sequence_write(codec, enable_dc_mode); 2202 /* port B input disabled (and bias set) through the following call */ 2203 cxt5066_set_olpc_dc_bias(codec); 2204 return; 2205 } 2206 2207 /* disable DC (port F) */ 2208 snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); 2209 2210 /* external mic, port B */ 2211 snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2212 spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); 2213 2214 /* internal mic, port C */ 2215 snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 2216 spec->ext_mic_present ? 0 : PIN_VREF80); 2217} 2218 2219/* toggle input of built-in and mic jack appropriately */ 2220static void cxt5066_olpc_automic(struct hda_codec *codec) 2221{ 2222 struct conexant_spec *spec = codec->spec; 2223 unsigned int present; 2224 2225 if (spec->dc_enable) /* don't do presence detection in DC mode */ 2226 return; 2227 2228 present = snd_hda_codec_read(codec, 0x1a, 0, 2229 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; 2230 if (present) 2231 snd_printdd("CXT5066: external microphone detected\n"); 2232 else 2233 snd_printdd("CXT5066: external microphone absent\n"); 2234 2235 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, 2236 present ? 0 : 1); 2237 spec->ext_mic_present = !!present; 2238 2239 cxt5066_olpc_select_mic(codec); 2240} 2241 2242/* toggle input of built-in digital mic and mic jack appropriately */ 2243static void cxt5066_vostro_automic(struct hda_codec *codec) 2244{ 2245 unsigned int present; 2246 2247 struct hda_verb ext_mic_present[] = { 2248 /* enable external mic, port B */ 2249 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2250 2251 /* switch to external mic input */ 2252 {0x17, AC_VERB_SET_CONNECT_SEL, 0}, 2253 {0x14, AC_VERB_SET_CONNECT_SEL, 0}, 2254 2255 /* disable internal digital mic */ 2256 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2257 {} 2258 }; 2259 static struct hda_verb ext_mic_absent[] = { 2260 /* enable internal mic, port C */ 2261 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2262 2263 /* switch to internal mic input */ 2264 {0x14, AC_VERB_SET_CONNECT_SEL, 2}, 2265 2266 /* disable external mic, port B */ 2267 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2268 {} 2269 }; 2270 2271 present = snd_hda_jack_detect(codec, 0x1a); 2272 if (present) { 2273 snd_printdd("CXT5066: external microphone detected\n"); 2274 snd_hda_sequence_write(codec, ext_mic_present); 2275 } else { 2276 snd_printdd("CXT5066: external microphone absent\n"); 2277 snd_hda_sequence_write(codec, ext_mic_absent); 2278 } 2279} 2280 2281/* toggle input of built-in digital mic and mic jack appropriately */ 2282static void cxt5066_ideapad_automic(struct hda_codec *codec) 2283{ 2284 unsigned int present; 2285 2286 struct hda_verb ext_mic_present[] = { 2287 {0x14, AC_VERB_SET_CONNECT_SEL, 0}, 2288 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2289 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2290 {} 2291 }; 2292 static struct hda_verb ext_mic_absent[] = { 2293 {0x14, AC_VERB_SET_CONNECT_SEL, 2}, 2294 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2295 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2296 {} 2297 }; 2298 2299 present = snd_hda_jack_detect(codec, 0x1b); 2300 if (present) { 2301 snd_printdd("CXT5066: external microphone detected\n"); 2302 snd_hda_sequence_write(codec, ext_mic_present); 2303 } else { 2304 snd_printdd("CXT5066: external microphone absent\n"); 2305 snd_hda_sequence_write(codec, ext_mic_absent); 2306 } 2307} 2308 2309/* toggle input of built-in digital mic and mic jack appropriately */ 2310static void cxt5066_hp_laptop_automic(struct hda_codec *codec) 2311{ 2312 unsigned int present; 2313 2314 present = snd_hda_jack_detect(codec, 0x1b); 2315 snd_printdd("CXT5066: external microphone present=%d\n", present); 2316 snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, 2317 present ? 1 : 3); 2318} 2319 2320 2321/* toggle input of built-in digital mic and mic jack appropriately 2322 order is: external mic -> dock mic -> interal mic */ 2323static void cxt5066_thinkpad_automic(struct hda_codec *codec) 2324{ 2325 unsigned int ext_present, dock_present; 2326 2327 static struct hda_verb ext_mic_present[] = { 2328 {0x14, AC_VERB_SET_CONNECT_SEL, 0}, 2329 {0x17, AC_VERB_SET_CONNECT_SEL, 1}, 2330 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2331 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2332 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2333 {} 2334 }; 2335 static struct hda_verb dock_mic_present[] = { 2336 {0x14, AC_VERB_SET_CONNECT_SEL, 0}, 2337 {0x17, AC_VERB_SET_CONNECT_SEL, 0}, 2338 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, 2339 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2340 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2341 {} 2342 }; 2343 static struct hda_verb ext_mic_absent[] = { 2344 {0x14, AC_VERB_SET_CONNECT_SEL, 2}, 2345 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2346 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2347 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2348 {} 2349 }; 2350 2351 ext_present = snd_hda_jack_detect(codec, 0x1b); 2352 dock_present = snd_hda_jack_detect(codec, 0x1a); 2353 if (ext_present) { 2354 snd_printdd("CXT5066: external microphone detected\n"); 2355 snd_hda_sequence_write(codec, ext_mic_present); 2356 } else if (dock_present) { 2357 snd_printdd("CXT5066: dock microphone detected\n"); 2358 snd_hda_sequence_write(codec, dock_mic_present); 2359 } else { 2360 snd_printdd("CXT5066: external microphone absent\n"); 2361 snd_hda_sequence_write(codec, ext_mic_absent); 2362 } 2363} 2364 2365/* mute internal speaker if HP is plugged */ 2366static void cxt5066_hp_automute(struct hda_codec *codec) 2367{ 2368 struct conexant_spec *spec = codec->spec; 2369 unsigned int portA, portD; 2370 2371 /* Port A */ 2372 portA = snd_hda_jack_detect(codec, 0x19); 2373 2374 /* Port D */ 2375 portD = snd_hda_jack_detect(codec, 0x1c); 2376 2377 spec->hp_present = !!(portA); 2378 spec->hp_present |= portD ? 2 : 0; 2379 snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", 2380 portA, portD, spec->hp_present); 2381 cxt5066_update_speaker(codec); 2382} 2383 2384/* unsolicited event for jack sensing */ 2385static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) 2386{ 2387 struct conexant_spec *spec = codec->spec; 2388 snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); 2389 switch (res >> 26) { 2390 case CONEXANT_HP_EVENT: 2391 cxt5066_hp_automute(codec); 2392 break; 2393 case CONEXANT_MIC_EVENT: 2394 /* ignore mic events in DC mode; we're always using the jack */ 2395 if (!spec->dc_enable) 2396 cxt5066_olpc_automic(codec); 2397 break; 2398 } 2399} 2400 2401/* unsolicited event for jack sensing */ 2402static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res) 2403{ 2404 snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26); 2405 switch (res >> 26) { 2406 case CONEXANT_HP_EVENT: 2407 cxt5066_hp_automute(codec); 2408 break; 2409 case CONEXANT_MIC_EVENT: 2410 cxt5066_vostro_automic(codec); 2411 break; 2412 } 2413} 2414 2415/* unsolicited event for jack sensing */ 2416static void cxt5066_ideapad_event(struct hda_codec *codec, unsigned int res) 2417{ 2418 snd_printdd("CXT5066_ideapad: unsol event %x (%x)\n", res, res >> 26); 2419 switch (res >> 26) { 2420 case CONEXANT_HP_EVENT: 2421 cxt5066_hp_automute(codec); 2422 break; 2423 case CONEXANT_MIC_EVENT: 2424 cxt5066_ideapad_automic(codec); 2425 break; 2426 } 2427} 2428 2429/* unsolicited event for jack sensing */ 2430static void cxt5066_hp_laptop_event(struct hda_codec *codec, unsigned int res) 2431{ 2432 snd_printdd("CXT5066_hp_laptop: unsol event %x (%x)\n", res, res >> 26); 2433 switch (res >> 26) { 2434 case CONEXANT_HP_EVENT: 2435 cxt5066_hp_automute(codec); 2436 break; 2437 case CONEXANT_MIC_EVENT: 2438 cxt5066_hp_laptop_automic(codec); 2439 break; 2440 } 2441} 2442 2443/* unsolicited event for jack sensing */ 2444static void cxt5066_thinkpad_event(struct hda_codec *codec, unsigned int res) 2445{ 2446 snd_printdd("CXT5066_thinkpad: unsol event %x (%x)\n", res, res >> 26); 2447 switch (res >> 26) { 2448 case CONEXANT_HP_EVENT: 2449 cxt5066_hp_automute(codec); 2450 break; 2451 case CONEXANT_MIC_EVENT: 2452 cxt5066_thinkpad_automic(codec); 2453 break; 2454 } 2455} 2456 2457static const struct hda_input_mux cxt5066_analog_mic_boost = { 2458 .num_items = 5, 2459 .items = { 2460 { "0dB", 0 }, 2461 { "10dB", 1 }, 2462 { "20dB", 2 }, 2463 { "30dB", 3 }, 2464 { "40dB", 4 }, 2465 }, 2466}; 2467 2468static void cxt5066_set_mic_boost(struct hda_codec *codec) 2469{ 2470 struct conexant_spec *spec = codec->spec; 2471 snd_hda_codec_write_cache(codec, 0x17, 0, 2472 AC_VERB_SET_AMP_GAIN_MUTE, 2473 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | 2474 cxt5066_analog_mic_boost.items[spec->mic_boost].index); 2475 if (spec->ideapad || spec->thinkpad) { 2476 /* adjust the internal mic as well...it is not through 0x17 */ 2477 snd_hda_codec_write_cache(codec, 0x23, 0, 2478 AC_VERB_SET_AMP_GAIN_MUTE, 2479 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT | 2480 cxt5066_analog_mic_boost. 2481 items[spec->mic_boost].index); 2482 } 2483} 2484 2485static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, 2486 struct snd_ctl_elem_info *uinfo) 2487{ 2488 return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo); 2489} 2490 2491static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, 2492 struct snd_ctl_elem_value *ucontrol) 2493{ 2494 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2495 struct conexant_spec *spec = codec->spec; 2496 ucontrol->value.enumerated.item[0] = spec->mic_boost; 2497 return 0; 2498} 2499 2500static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, 2501 struct snd_ctl_elem_value *ucontrol) 2502{ 2503 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2504 struct conexant_spec *spec = codec->spec; 2505 const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; 2506 unsigned int idx; 2507 idx = ucontrol->value.enumerated.item[0]; 2508 if (idx >= imux->num_items) 2509 idx = imux->num_items - 1; 2510 2511 spec->mic_boost = idx; 2512 if (!spec->dc_enable) 2513 cxt5066_set_mic_boost(codec); 2514 return 1; 2515} 2516 2517static void cxt5066_enable_dc(struct hda_codec *codec) 2518{ 2519 const struct hda_verb enable_dc_mode[] = { 2520 /* disable gain */ 2521 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2522 2523 /* switch to DC input */ 2524 {0x17, AC_VERB_SET_CONNECT_SEL, 3}, 2525 {} 2526 }; 2527 2528 /* configure as input source */ 2529 snd_hda_sequence_write(codec, enable_dc_mode); 2530 cxt5066_olpc_select_mic(codec); /* also sets configured bias */ 2531} 2532 2533static void cxt5066_disable_dc(struct hda_codec *codec) 2534{ 2535 /* reconfigure input source */ 2536 cxt5066_set_mic_boost(codec); 2537 /* automic also selects the right mic if we're recording */ 2538 cxt5066_olpc_automic(codec); 2539} 2540 2541static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol, 2542 struct snd_ctl_elem_value *ucontrol) 2543{ 2544 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2545 struct conexant_spec *spec = codec->spec; 2546 ucontrol->value.integer.value[0] = spec->dc_enable; 2547 return 0; 2548} 2549 2550static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol, 2551 struct snd_ctl_elem_value *ucontrol) 2552{ 2553 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2554 struct conexant_spec *spec = codec->spec; 2555 int dc_enable = !!ucontrol->value.integer.value[0]; 2556 2557 if (dc_enable == spec->dc_enable) 2558 return 0; 2559 2560 spec->dc_enable = dc_enable; 2561 if (dc_enable) 2562 cxt5066_enable_dc(codec); 2563 else 2564 cxt5066_disable_dc(codec); 2565 2566 return 1; 2567} 2568 2569static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol, 2570 struct snd_ctl_elem_info *uinfo) 2571{ 2572 return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo); 2573} 2574 2575static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol, 2576 struct snd_ctl_elem_value *ucontrol) 2577{ 2578 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2579 struct conexant_spec *spec = codec->spec; 2580 ucontrol->value.enumerated.item[0] = spec->dc_input_bias; 2581 return 0; 2582} 2583 2584static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol, 2585 struct snd_ctl_elem_value *ucontrol) 2586{ 2587 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2588 struct conexant_spec *spec = codec->spec; 2589 const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; 2590 unsigned int idx; 2591 2592 idx = ucontrol->value.enumerated.item[0]; 2593 if (idx >= imux->num_items) 2594 idx = imux->num_items - 1; 2595 2596 spec->dc_input_bias = idx; 2597 if (spec->dc_enable) 2598 cxt5066_set_olpc_dc_bias(codec); 2599 return 1; 2600} 2601 2602static void cxt5066_olpc_capture_prepare(struct hda_codec *codec) 2603{ 2604 struct conexant_spec *spec = codec->spec; 2605 /* mark as recording and configure the microphone widget so that the 2606 * recording LED comes on. */ 2607 spec->recording = 1; 2608 cxt5066_olpc_select_mic(codec); 2609} 2610 2611static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) 2612{ 2613 struct conexant_spec *spec = codec->spec; 2614 const struct hda_verb disable_mics[] = { 2615 /* disable external mic, port B */ 2616 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2617 2618 /* disble internal mic, port C */ 2619 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2620 2621 /* disable DC capture, port F */ 2622 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2623 {}, 2624 }; 2625 2626 snd_hda_sequence_write(codec, disable_mics); 2627 spec->recording = 0; 2628} 2629 2630static struct hda_input_mux cxt5066_capture_source = { 2631 .num_items = 4, 2632 .items = { 2633 { "Mic B", 0 }, 2634 { "Mic C", 1 }, 2635 { "Mic E", 2 }, 2636 { "Mic F", 3 }, 2637 }, 2638}; 2639 2640static struct hda_bind_ctls cxt5066_bind_capture_vol_others = { 2641 .ops = &snd_hda_bind_vol, 2642 .values = { 2643 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), 2644 HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), 2645 0 2646 }, 2647}; 2648 2649static struct hda_bind_ctls cxt5066_bind_capture_sw_others = { 2650 .ops = &snd_hda_bind_sw, 2651 .values = { 2652 HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT), 2653 HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT), 2654 0 2655 }, 2656}; 2657 2658static struct snd_kcontrol_new cxt5066_mixer_master[] = { 2659 HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), 2660 {} 2661}; 2662 2663static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { 2664 { 2665 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2666 .name = "Master Playback Volume", 2667 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 2668 SNDRV_CTL_ELEM_ACCESS_TLV_READ | 2669 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, 2670 .subdevice = HDA_SUBDEV_AMP_FLAG, 2671 .info = snd_hda_mixer_amp_volume_info, 2672 .get = snd_hda_mixer_amp_volume_get, 2673 .put = snd_hda_mixer_amp_volume_put, 2674 .tlv = { .c = snd_hda_mixer_amp_tlv }, 2675 /* offset by 28 volume steps to limit minimum gain to -46dB */ 2676 .private_value = 2677 HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28), 2678 }, 2679 {} 2680}; 2681 2682static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { 2683 { 2684 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2685 .name = "DC Mode Enable Switch", 2686 .info = snd_ctl_boolean_mono_info, 2687 .get = cxt5066_olpc_dc_get, 2688 .put = cxt5066_olpc_dc_put, 2689 }, 2690 { 2691 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2692 .name = "DC Input Bias Enum", 2693 .info = cxt5066_olpc_dc_bias_enum_info, 2694 .get = cxt5066_olpc_dc_bias_enum_get, 2695 .put = cxt5066_olpc_dc_bias_enum_put, 2696 }, 2697 {} 2698}; 2699 2700static struct snd_kcontrol_new cxt5066_mixers[] = { 2701 { 2702 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2703 .name = "Master Playback Switch", 2704 .info = cxt_eapd_info, 2705 .get = cxt_eapd_get, 2706 .put = cxt5066_hp_master_sw_put, 2707 .private_value = 0x1d, 2708 }, 2709 2710 { 2711 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2712 .name = "Analog Mic Boost Capture Enum", 2713 .info = cxt5066_mic_boost_mux_enum_info, 2714 .get = cxt5066_mic_boost_mux_enum_get, 2715 .put = cxt5066_mic_boost_mux_enum_put, 2716 }, 2717 2718 HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), 2719 HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others), 2720 {} 2721}; 2722 2723static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { 2724 { 2725 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 2726 .name = "Int Mic Boost Capture Enum", 2727 .info = cxt5066_mic_boost_mux_enum_info, 2728 .get = cxt5066_mic_boost_mux_enum_get, 2729 .put = cxt5066_mic_boost_mux_enum_put, 2730 .private_value = 0x23 | 0x100, 2731 }, 2732 {} 2733}; 2734 2735static struct hda_verb cxt5066_init_verbs[] = { 2736 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ 2737 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ 2738 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ 2739 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ 2740 2741 /* Speakers */ 2742 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2743 {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2744 2745 /* HP, Amp */ 2746 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2747 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2748 2749 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2750 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2751 2752 /* DAC1 */ 2753 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2754 2755 /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ 2756 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, 2757 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2758 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, 2759 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2760 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 2761 2762 /* no digital microphone support yet */ 2763 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2764 2765 /* Audio input selector */ 2766 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, 2767 2768 /* SPDIF route: PCM */ 2769 {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, 2770 {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, 2771 2772 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2773 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2774 2775 /* EAPD */ 2776 {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 2777 2778 /* not handling these yet */ 2779 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, 2780 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, 2781 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, 2782 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, 2783 {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, 2784 {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, 2785 {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, 2786 {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0}, 2787 { } /* end */ 2788}; 2789 2790static struct hda_verb cxt5066_init_verbs_olpc[] = { 2791 /* Port A: headphones */ 2792 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2793 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2794 2795 /* Port B: external microphone */ 2796 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2797 2798 /* Port C: internal microphone */ 2799 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2800 2801 /* Port D: unused */ 2802 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2803 2804 /* Port E: unused, but has primary EAPD */ 2805 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2806 {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 2807 2808 /* Port F: external DC input through microphone port */ 2809 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2810 2811 /* Port G: internal speakers */ 2812 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2813 {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2814 2815 /* DAC1 */ 2816 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2817 2818 /* DAC2: unused */ 2819 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2820 2821 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, 2822 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2823 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2824 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2825 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2826 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2827 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2828 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2829 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2830 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2831 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2832 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2833 2834 /* Disable digital microphone port */ 2835 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2836 2837 /* Audio input selectors */ 2838 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, 2839 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, 2840 2841 /* Disable SPDIF */ 2842 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2843 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2844 2845 /* enable unsolicited events for Port A and B */ 2846 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 2847 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 2848 { } /* end */ 2849}; 2850 2851static struct hda_verb cxt5066_init_verbs_vostro[] = { 2852 /* Port A: headphones */ 2853 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2854 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2855 2856 /* Port B: external microphone */ 2857 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2858 2859 /* Port C: unused */ 2860 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2861 2862 /* Port D: unused */ 2863 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2864 2865 /* Port E: unused, but has primary EAPD */ 2866 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2867 {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 2868 2869 /* Port F: unused */ 2870 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2871 2872 /* Port G: internal speakers */ 2873 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2874 {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2875 2876 /* DAC1 */ 2877 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2878 2879 /* DAC2: unused */ 2880 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, 2881 2882 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2883 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2884 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2885 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2886 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2887 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2888 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2889 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2890 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, 2891 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2892 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, 2893 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2894 2895 /* Digital microphone port */ 2896 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, 2897 2898 /* Audio input selectors */ 2899 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, 2900 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, 2901 2902 /* Disable SPDIF */ 2903 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2904 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2905 2906 /* enable unsolicited events for Port A and B */ 2907 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 2908 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 2909 { } /* end */ 2910}; 2911 2912static struct hda_verb cxt5066_init_verbs_ideapad[] = { 2913 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ 2914 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ 2915 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ 2916 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ 2917 2918 /* Speakers */ 2919 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2920 {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2921 2922 /* HP, Amp */ 2923 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2924 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2925 2926 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, 2927 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2928 2929 /* DAC1 */ 2930 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2931 2932 /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ 2933 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, 2934 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2935 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, 2936 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2937 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 2938 {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ 2939 2940 /* Audio input selector */ 2941 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, 2942 {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ 2943 2944 /* SPDIF route: PCM */ 2945 {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, 2946 {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, 2947 2948 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2949 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2950 2951 /* internal microphone */ 2952 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ 2953 2954 /* EAPD */ 2955 {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 2956 2957 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 2958 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 2959 { } /* end */ 2960}; 2961 2962static struct hda_verb cxt5066_init_verbs_thinkpad[] = { 2963 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */ 2964 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */ 2965 2966 /* Port G: internal speakers */ 2967 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 2968 {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2969 2970 /* Port A: HP, Amp */ 2971 {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2972 {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2973 2974 /* Port B: Mic Dock */ 2975 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2976 2977 /* Port C: Mic */ 2978 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2979 2980 /* Port D: HP Dock, Amp */ 2981 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, 2982 {0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ 2983 2984 /* DAC1 */ 2985 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, 2986 2987 /* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */ 2988 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, 2989 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, 2990 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50}, 2991 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, 2992 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, 2993 {0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */ 2994 2995 /* Audio input selector */ 2996 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2}, 2997 {0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */ 2998 2999 /* SPDIF route: PCM */ 3000 {0x20, AC_VERB_SET_CONNECT_SEL, 0x0}, 3001 {0x22, AC_VERB_SET_CONNECT_SEL, 0x0}, 3002 3003 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3004 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3005 3006 /* internal microphone */ 3007 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable int mic */ 3008 3009 /* EAPD */ 3010 {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ 3011 3012 /* enable unsolicited events for Port A, B, C and D */ 3013 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 3014 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 3015 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 3016 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 3017 { } /* end */ 3018}; 3019 3020static struct hda_verb cxt5066_init_verbs_portd_lo[] = { 3021 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, 3022 { } /* end */ 3023}; 3024 3025 3026static struct hda_verb cxt5066_init_verbs_hp_laptop[] = { 3027 {0x14, AC_VERB_SET_CONNECT_SEL, 0x0}, 3028 {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, 3029 {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, 3030 { } /* end */ 3031}; 3032 3033/* initialize jack-sensing, too */ 3034static int cxt5066_init(struct hda_codec *codec) 3035{ 3036 struct conexant_spec *spec = codec->spec; 3037 3038 snd_printdd("CXT5066: init\n"); 3039 conexant_init(codec); 3040 if (codec->patch_ops.unsol_event) { 3041 cxt5066_hp_automute(codec); 3042 if (spec->dell_vostro) 3043 cxt5066_vostro_automic(codec); 3044 else if (spec->ideapad) 3045 cxt5066_ideapad_automic(codec); 3046 else if (spec->thinkpad) 3047 cxt5066_thinkpad_automic(codec); 3048 else if (spec->hp_laptop) 3049 cxt5066_hp_laptop_automic(codec); 3050 } 3051 cxt5066_set_mic_boost(codec); 3052 return 0; 3053} 3054 3055static int cxt5066_olpc_init(struct hda_codec *codec) 3056{ 3057 struct conexant_spec *spec = codec->spec; 3058 snd_printdd("CXT5066: init\n"); 3059 conexant_init(codec); 3060 cxt5066_hp_automute(codec); 3061 if (!spec->dc_enable) { 3062 cxt5066_set_mic_boost(codec); 3063 cxt5066_olpc_automic(codec); 3064 } else { 3065 cxt5066_enable_dc(codec); 3066 } 3067 return 0; 3068} 3069 3070enum { 3071 CXT5066_LAPTOP, /* Laptops w/ EAPD support */ 3072 CXT5066_DELL_LAPTOP, /* Dell Laptop */ 3073 CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ 3074 CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ 3075 CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ 3076 CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ 3077 CXT5066_HP_LAPTOP, /* HP Laptop */ 3078 CXT5066_MODELS 3079}; 3080 3081static const char *cxt5066_models[CXT5066_MODELS] = { 3082 [CXT5066_LAPTOP] = "laptop", 3083 [CXT5066_DELL_LAPTOP] = "dell-laptop", 3084 [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", 3085 [CXT5066_DELL_VOSTO] = "dell-vostro", 3086 [CXT5066_IDEAPAD] = "ideapad", 3087 [CXT5066_THINKPAD] = "thinkpad", 3088 [CXT5066_HP_LAPTOP] = "hp-laptop", 3089}; 3090 3091static struct snd_pci_quirk cxt5066_cfg_tbl[] = { 3092 SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", 3093 CXT5066_LAPTOP), 3094 SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD), 3095 SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), 3096 SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTO), 3097 SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), 3098 SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), 3099 SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), 3100 SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_HP_LAPTOP), 3101 SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), 3102 SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), 3103 SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5), 3104 SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), 3105 SND_PCI_QUIRK(0x17aa, 0x21b2, "Thinkpad X100e", CXT5066_IDEAPAD), 3106 SND_PCI_QUIRK(0x17aa, 0x21b3, "Thinkpad Edge 13 (197)", CXT5066_IDEAPAD), 3107 SND_PCI_QUIRK(0x17aa, 0x21b4, "Thinkpad Edge", CXT5066_IDEAPAD), 3108 SND_PCI_QUIRK(0x17aa, 0x21c8, "Thinkpad Edge 11", CXT5066_IDEAPAD), 3109 SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD), 3110 SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G series", CXT5066_IDEAPAD), 3111 SND_PCI_QUIRK(0x17aa, 0x390a, "Lenovo S10-3t", CXT5066_IDEAPAD), 3112 SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G series (AMD)", CXT5066_IDEAPAD), 3113 SND_PCI_QUIRK(0x17aa, 0x3a0d, "ideapad", CXT5066_IDEAPAD), 3114 {} 3115}; 3116 3117static int patch_cxt5066(struct hda_codec *codec) 3118{ 3119 struct conexant_spec *spec; 3120 int board_config; 3121 3122 spec = kzalloc(sizeof(*spec), GFP_KERNEL); 3123 if (!spec) 3124 return -ENOMEM; 3125 codec->spec = spec; 3126 3127 codec->patch_ops = conexant_patch_ops; 3128 codec->patch_ops.init = conexant_init; 3129 3130 spec->dell_automute = 0; 3131 spec->multiout.max_channels = 2; 3132 spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids); 3133 spec->multiout.dac_nids = cxt5066_dac_nids; 3134 spec->multiout.dig_out_nid = CXT5066_SPDIF_OUT; 3135 spec->num_adc_nids = 1; 3136 spec->adc_nids = cxt5066_adc_nids; 3137 spec->capsrc_nids = cxt5066_capsrc_nids; 3138 spec->input_mux = &cxt5066_capture_source; 3139 3140 spec->port_d_mode = PIN_HP; 3141 3142 spec->num_init_verbs = 1; 3143 spec->init_verbs[0] = cxt5066_init_verbs; 3144 spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes); 3145 spec->channel_mode = cxt5066_modes; 3146 spec->cur_adc = 0; 3147 spec->cur_adc_idx = 0; 3148 3149 set_beep_amp(spec, 0x13, 0, HDA_OUTPUT); 3150 3151 board_config = snd_hda_check_board_config(codec, CXT5066_MODELS, 3152 cxt5066_models, cxt5066_cfg_tbl); 3153 switch (board_config) { 3154 default: 3155 case CXT5066_LAPTOP: 3156 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; 3157 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3158 break; 3159 case CXT5066_DELL_LAPTOP: 3160 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; 3161 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3162 3163 spec->port_d_mode = PIN_OUT; 3164 spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo; 3165 spec->num_init_verbs++; 3166 spec->dell_automute = 1; 3167 break; 3168 case CXT5066_HP_LAPTOP: 3169 codec->patch_ops.init = cxt5066_init; 3170 codec->patch_ops.unsol_event = cxt5066_hp_laptop_event; 3171 spec->init_verbs[spec->num_init_verbs] = 3172 cxt5066_init_verbs_hp_laptop; 3173 spec->num_init_verbs++; 3174 spec->hp_laptop = 1; 3175 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; 3176 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3177 /* no S/PDIF out */ 3178 spec->multiout.dig_out_nid = 0; 3179 /* input source automatically selected */ 3180 spec->input_mux = NULL; 3181 spec->port_d_mode = 0; 3182 spec->mic_boost = 3; /* default 30dB gain */ 3183 break; 3184 3185 case CXT5066_OLPC_XO_1_5: 3186 codec->patch_ops.init = cxt5066_olpc_init; 3187 codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; 3188 spec->init_verbs[0] = cxt5066_init_verbs_olpc; 3189 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; 3190 spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc; 3191 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3192 spec->port_d_mode = 0; 3193 spec->mic_boost = 3; /* default 30dB gain */ 3194 3195 /* no S/PDIF out */ 3196 spec->multiout.dig_out_nid = 0; 3197 3198 /* input source automatically selected */ 3199 spec->input_mux = NULL; 3200 3201 /* our capture hooks which allow us to turn on the microphone LED 3202 * at the right time */ 3203 spec->capture_prepare = cxt5066_olpc_capture_prepare; 3204 spec->capture_cleanup = cxt5066_olpc_capture_cleanup; 3205 break; 3206 case CXT5066_DELL_VOSTO: 3207 codec->patch_ops.init = cxt5066_init; 3208 codec->patch_ops.unsol_event = cxt5066_vostro_event; 3209 spec->init_verbs[0] = cxt5066_init_verbs_vostro; 3210 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; 3211 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3212 spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; 3213 spec->port_d_mode = 0; 3214 spec->dell_vostro = 1; 3215 spec->mic_boost = 3; /* default 30dB gain */ 3216 3217 /* no S/PDIF out */ 3218 spec->multiout.dig_out_nid = 0; 3219 3220 /* input source automatically selected */ 3221 spec->input_mux = NULL; 3222 break; 3223 case CXT5066_IDEAPAD: 3224 codec->patch_ops.init = cxt5066_init; 3225 codec->patch_ops.unsol_event = cxt5066_ideapad_event; 3226 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; 3227 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3228 spec->init_verbs[0] = cxt5066_init_verbs_ideapad; 3229 spec->port_d_mode = 0; 3230 spec->ideapad = 1; 3231 spec->mic_boost = 2; /* default 20dB gain */ 3232 3233 /* no S/PDIF out */ 3234 spec->multiout.dig_out_nid = 0; 3235 3236 /* input source automatically selected */ 3237 spec->input_mux = NULL; 3238 break; 3239 case CXT5066_THINKPAD: 3240 codec->patch_ops.init = cxt5066_init; 3241 codec->patch_ops.unsol_event = cxt5066_thinkpad_event; 3242 spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; 3243 spec->mixers[spec->num_mixers++] = cxt5066_mixers; 3244 spec->init_verbs[0] = cxt5066_init_verbs_thinkpad; 3245 spec->thinkpad = 1; 3246 spec->port_d_mode = PIN_OUT; 3247 spec->mic_boost = 2; /* default 20dB gain */ 3248 3249 /* no S/PDIF out */ 3250 spec->multiout.dig_out_nid = 0; 3251 3252 /* input source automatically selected */ 3253 spec->input_mux = NULL; 3254 break; 3255 } 3256 3257 if (spec->beep_amp) 3258 snd_hda_attach_beep_device(codec, spec->beep_amp); 3259 3260 return 0; 3261} 3262 3263/* 3264 */ 3265 3266static struct hda_codec_preset snd_hda_preset_conexant[] = { 3267 { .id = 0x14f15045, .name = "CX20549 (Venice)", 3268 .patch = patch_cxt5045 }, 3269 { .id = 0x14f15047, .name = "CX20551 (Waikiki)", 3270 .patch = patch_cxt5047 }, 3271 { .id = 0x14f15051, .name = "CX20561 (Hermosa)", 3272 .patch = patch_cxt5051 }, 3273 { .id = 0x14f15066, .name = "CX20582 (Pebble)", 3274 .patch = patch_cxt5066 }, 3275 { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", 3276 .patch = patch_cxt5066 }, 3277 { .id = 0x14f15068, .name = "CX20584", 3278 .patch = patch_cxt5066 }, 3279 { .id = 0x14f15069, .name = "CX20585", 3280 .patch = patch_cxt5066 }, 3281 {} /* terminator */ 3282}; 3283 3284MODULE_ALIAS("snd-hda-codec-id:14f15045"); 3285MODULE_ALIAS("snd-hda-codec-id:14f15047"); 3286MODULE_ALIAS("snd-hda-codec-id:14f15051"); 3287MODULE_ALIAS("snd-hda-codec-id:14f15066"); 3288MODULE_ALIAS("snd-hda-codec-id:14f15067"); 3289MODULE_ALIAS("snd-hda-codec-id:14f15068"); 3290MODULE_ALIAS("snd-hda-codec-id:14f15069"); 3291 3292MODULE_LICENSE("GPL"); 3293MODULE_DESCRIPTION("Conexant HD-audio codec"); 3294 3295static struct hda_codec_preset_list conexant_list = { 3296 .preset = snd_hda_preset_conexant, 3297 .owner = THIS_MODULE, 3298}; 3299 3300static int __init patch_conexant_init(void) 3301{ 3302 return snd_hda_add_codec_preset(&conexant_list); 3303} 3304 3305static void __exit patch_conexant_exit(void) 3306{ 3307 snd_hda_delete_codec_preset(&conexant_list); 3308} 3309 3310module_init(patch_conexant_init) 3311module_exit(patch_conexant_exit) 3312