Linux Audio

Check our new training course

Loading...
v5.9
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * HD audio interface patch for Conexant HDA audio codec
   4 *
   5 * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
   6 * 		      Takashi Iwai <tiwai@suse.de>
   7 * 		      Tobin Davis  <tdavis@dsl-only.net>
   8 */
   9
  10#include <linux/init.h>
  11#include <linux/delay.h>
  12#include <linux/slab.h>
  13#include <linux/module.h>
  14#include <sound/core.h>
  15#include <sound/jack.h>
  16
  17#include <sound/hda_codec.h>
  18#include "hda_local.h"
  19#include "hda_auto_parser.h"
  20#include "hda_beep.h"
  21#include "hda_jack.h"
  22#include "hda_generic.h"
  23
 
 
 
 
 
 
  24struct conexant_spec {
  25	struct hda_gen_spec gen;
  26
  27	/* extra EAPD pins */
  28	unsigned int num_eapds;
  29	hda_nid_t eapds[4];
  30	bool dynamic_eapd;
  31	hda_nid_t mute_led_eapd;
  32
  33	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
  34
  35	/* OPLC XO specific */
  36	bool recording;
  37	bool dc_enable;
  38	unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
  39	struct nid_path *dc_mode_path;
  40
  41	int mute_led_polarity;
  42	unsigned int gpio_led;
  43	unsigned int gpio_mute_led_mask;
  44	unsigned int gpio_mic_led_mask;
  45
 
  46};
  47
  48
  49#ifdef CONFIG_SND_HDA_INPUT_BEEP
  50/* additional beep mixers; private_value will be overwritten */
  51static const struct snd_kcontrol_new cxt_beep_mixer[] = {
  52	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
  53	HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
  54};
  55
  56static int set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
  57			int idx, int dir)
  58{
  59	struct snd_kcontrol_new *knew;
  60	unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
  61	int i;
  62
  63	spec->gen.beep_nid = nid;
  64	for (i = 0; i < ARRAY_SIZE(cxt_beep_mixer); i++) {
  65		knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
  66					    &cxt_beep_mixer[i]);
  67		if (!knew)
  68			return -ENOMEM;
  69		knew->private_value = beep_amp;
  70	}
  71	return 0;
  72}
  73
  74static int cx_auto_parse_beep(struct hda_codec *codec)
  75{
  76	struct conexant_spec *spec = codec->spec;
  77	hda_nid_t nid;
  78
  79	for_each_hda_codec_node(nid, codec)
  80		if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
  81			return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
  82	return 0;
  83}
  84#else
  85#define cx_auto_parse_beep(codec)	0
  86#endif
  87
  88/*
  89 * Automatic parser for CX20641 & co
  90 */
  91
  92/* parse EAPDs */
  93static void cx_auto_parse_eapd(struct hda_codec *codec)
  94{
  95	struct conexant_spec *spec = codec->spec;
  96	hda_nid_t nid;
  97
  98	for_each_hda_codec_node(nid, codec) {
  99		if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
 100			continue;
 101		if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
 102			continue;
 103		spec->eapds[spec->num_eapds++] = nid;
 104		if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
 105			break;
 106	}
 107
 108	/* NOTE: below is a wild guess; if we have more than two EAPDs,
 109	 * it's a new chip, where EAPDs are supposed to be associated to
 110	 * pins, and we can control EAPD per pin.
 111	 * OTOH, if only one or two EAPDs are found, it's an old chip,
 112	 * thus it might control over all pins.
 113	 */
 114	if (spec->num_eapds > 2)
 115		spec->dynamic_eapd = 1;
 116}
 117
 118static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
 119			      const hda_nid_t *pins, bool on)
 120{
 121	int i;
 122	for (i = 0; i < num_pins; i++) {
 123		if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
 124			snd_hda_codec_write(codec, pins[i], 0,
 125					    AC_VERB_SET_EAPD_BTLENABLE,
 126					    on ? 0x02 : 0);
 127	}
 128}
 129
 130/* turn on/off EAPD according to Master switch */
 131static void cx_auto_vmaster_hook(void *private_data, int enabled)
 132{
 133	struct hda_codec *codec = private_data;
 134	struct conexant_spec *spec = codec->spec;
 135
 136	cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled);
 137}
 138
 139/* turn on/off EAPD according to Master switch (inversely!) for mute LED */
 140static int cx_auto_vmaster_mute_led(struct led_classdev *led_cdev,
 141				    enum led_brightness brightness)
 142{
 143	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
 144	struct conexant_spec *spec = codec->spec;
 145
 146	snd_hda_codec_write(codec, spec->mute_led_eapd, 0,
 147			    AC_VERB_SET_EAPD_BTLENABLE,
 148			    brightness ? 0x02 : 0x00);
 149	return 0;
 150}
 151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 152static int cx_auto_init(struct hda_codec *codec)
 153{
 154	struct conexant_spec *spec = codec->spec;
 155	snd_hda_gen_init(codec);
 156	if (!spec->dynamic_eapd)
 157		cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
 158
 
 159	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
 160
 
 
 
 161	return 0;
 162}
 163
 164static void cx_auto_reboot_notify(struct hda_codec *codec)
 165{
 166	struct conexant_spec *spec = codec->spec;
 167
 168	/* Turn the problematic codec into D3 to avoid spurious noises
 169	   from the internal speaker during (and after) reboot */
 170	cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
 171	snd_hda_gen_reboot_notify(codec);
 172}
 173
 174static void cx_auto_free(struct hda_codec *codec)
 175{
 176	cx_auto_reboot_notify(codec);
 177	snd_hda_gen_free(codec);
 178}
 179
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 180static const struct hda_codec_ops cx_auto_patch_ops = {
 181	.build_controls = snd_hda_gen_build_controls,
 182	.build_pcms = snd_hda_gen_build_pcms,
 183	.init = cx_auto_init,
 184	.reboot_notify = cx_auto_reboot_notify,
 185	.free = cx_auto_free,
 186	.unsol_event = snd_hda_jack_unsol_event,
 187#ifdef CONFIG_PM
 
 188	.check_power_status = snd_hda_gen_check_power_status,
 189#endif
 190};
 191
 192/*
 193 * pin fix-up
 194 */
 195enum {
 196	CXT_PINCFG_LENOVO_X200,
 197	CXT_PINCFG_LENOVO_TP410,
 198	CXT_PINCFG_LEMOTE_A1004,
 199	CXT_PINCFG_LEMOTE_A1205,
 200	CXT_PINCFG_COMPAQ_CQ60,
 201	CXT_FIXUP_STEREO_DMIC,
 
 202	CXT_FIXUP_INC_MIC_BOOST,
 203	CXT_FIXUP_HEADPHONE_MIC_PIN,
 204	CXT_FIXUP_HEADPHONE_MIC,
 205	CXT_FIXUP_GPIO1,
 206	CXT_FIXUP_ASPIRE_DMIC,
 207	CXT_FIXUP_THINKPAD_ACPI,
 208	CXT_FIXUP_OLPC_XO,
 209	CXT_FIXUP_CAP_MIX_AMP,
 210	CXT_FIXUP_TOSHIBA_P105,
 211	CXT_FIXUP_HP_530,
 212	CXT_FIXUP_CAP_MIX_AMP_5047,
 213	CXT_FIXUP_MUTE_LED_EAPD,
 214	CXT_FIXUP_HP_DOCK,
 215	CXT_FIXUP_HP_SPECTRE,
 216	CXT_FIXUP_HP_GATE_MIC,
 217	CXT_FIXUP_MUTE_LED_GPIO,
 
 218	CXT_FIXUP_HEADSET_MIC,
 219	CXT_FIXUP_HP_MIC_NO_PRESENCE,
 
 220};
 221
 222/* for hda_fixup_thinkpad_acpi() */
 223#include "thinkpad_helper.c"
 224
 225static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
 226				  const struct hda_fixup *fix, int action)
 227{
 228	struct conexant_spec *spec = codec->spec;
 229	spec->gen.inv_dmic_split = 1;
 230}
 231
 232static void cxt5066_increase_mic_boost(struct hda_codec *codec,
 233				   const struct hda_fixup *fix, int action)
 234{
 235	if (action != HDA_FIXUP_ACT_PRE_PROBE)
 236		return;
 237
 238	snd_hda_override_amp_caps(codec, 0x17, HDA_OUTPUT,
 239				  (0x3 << AC_AMPCAP_OFFSET_SHIFT) |
 240				  (0x4 << AC_AMPCAP_NUM_STEPS_SHIFT) |
 241				  (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
 242				  (0 << AC_AMPCAP_MUTE_SHIFT));
 243}
 244
 245static void cxt_update_headset_mode(struct hda_codec *codec)
 246{
 247	/* The verbs used in this function were tested on a Conexant CX20751/2 codec. */
 248	int i;
 249	bool mic_mode = false;
 250	struct conexant_spec *spec = codec->spec;
 251	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
 252
 253	hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
 254
 255	for (i = 0; i < cfg->num_inputs; i++)
 256		if (cfg->inputs[i].pin == mux_pin) {
 257			mic_mode = !!cfg->inputs[i].is_headphone_mic;
 258			break;
 259		}
 260
 261	if (mic_mode) {
 262		snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */
 263		spec->gen.hp_jack_present = false;
 264	} else {
 265		snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */
 266		spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]);
 267	}
 268
 269	snd_hda_gen_update_outputs(codec);
 270}
 271
 272static void cxt_update_headset_mode_hook(struct hda_codec *codec,
 273					 struct snd_kcontrol *kcontrol,
 274					 struct snd_ctl_elem_value *ucontrol)
 275{
 276	cxt_update_headset_mode(codec);
 277}
 278
 279static void cxt_fixup_headphone_mic(struct hda_codec *codec,
 280				    const struct hda_fixup *fix, int action)
 281{
 282	struct conexant_spec *spec = codec->spec;
 283
 284	switch (action) {
 285	case HDA_FIXUP_ACT_PRE_PROBE:
 286		spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
 287		snd_hdac_regmap_add_vendor_verb(&codec->core, 0x410);
 288		break;
 289	case HDA_FIXUP_ACT_PROBE:
 290		WARN_ON(spec->gen.cap_sync_hook);
 291		spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
 292		spec->gen.automute_hook = cxt_update_headset_mode;
 293		break;
 294	case HDA_FIXUP_ACT_INIT:
 295		cxt_update_headset_mode(codec);
 296		break;
 297	}
 298}
 299
 300static void cxt_fixup_headset_mic(struct hda_codec *codec,
 301				    const struct hda_fixup *fix, int action)
 302{
 303	struct conexant_spec *spec = codec->spec;
 304
 305	switch (action) {
 306	case HDA_FIXUP_ACT_PRE_PROBE:
 307		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
 308		break;
 309	}
 310}
 311
 312/* OPLC XO 1.5 fixup */
 313
 314/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
 315 * through the microphone jack.
 316 * When the user enables this through a mixer switch, both internal and
 317 * external microphones are disabled. Gain is fixed at 0dB. In this mode,
 318 * we also allow the bias to be configured through a separate mixer
 319 * control. */
 320
 321#define update_mic_pin(codec, nid, val)					\
 322	snd_hda_codec_write_cache(codec, nid, 0,			\
 323				   AC_VERB_SET_PIN_WIDGET_CONTROL, val)
 324
 325static const struct hda_input_mux olpc_xo_dc_bias = {
 326	.num_items = 3,
 327	.items = {
 328		{ "Off", PIN_IN },
 329		{ "50%", PIN_VREF50 },
 330		{ "80%", PIN_VREF80 },
 331	},
 332};
 333
 334static void olpc_xo_update_mic_boost(struct hda_codec *codec)
 335{
 336	struct conexant_spec *spec = codec->spec;
 337	int ch, val;
 338
 339	for (ch = 0; ch < 2; ch++) {
 340		val = AC_AMP_SET_OUTPUT |
 341			(ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT);
 342		if (!spec->dc_enable)
 343			val |= snd_hda_codec_amp_read(codec, 0x17, ch, HDA_OUTPUT, 0);
 344		snd_hda_codec_write(codec, 0x17, 0,
 345				    AC_VERB_SET_AMP_GAIN_MUTE, val);
 346	}
 347}
 348
 349static void olpc_xo_update_mic_pins(struct hda_codec *codec)
 350{
 351	struct conexant_spec *spec = codec->spec;
 352	int cur_input, val;
 353	struct nid_path *path;
 354
 355	cur_input = spec->gen.input_paths[0][spec->gen.cur_mux[0]];
 356
 357	/* Set up mic pins for port-B, C and F dynamically as the recording
 358	 * LED is turned on/off by these pin controls
 359	 */
 360	if (!spec->dc_enable) {
 361		/* disable DC bias path and pin for port F */
 362		update_mic_pin(codec, 0x1e, 0);
 363		snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
 364
 365		/* update port B (ext mic) and C (int mic) */
 366		/* OLPC defers mic widget control until when capture is
 367		 * started because the microphone LED comes on as soon as
 368		 * these settings are put in place. if we did this before
 369		 * recording, it would give the false indication that
 370		 * recording is happening when it is not.
 371		 */
 372		update_mic_pin(codec, 0x1a, spec->recording ?
 373			       snd_hda_codec_get_pin_target(codec, 0x1a) : 0);
 374		update_mic_pin(codec, 0x1b, spec->recording ?
 375			       snd_hda_codec_get_pin_target(codec, 0x1b) : 0);
 376		/* enable normal mic path */
 377		path = snd_hda_get_path_from_idx(codec, cur_input);
 378		if (path)
 379			snd_hda_activate_path(codec, path, true, false);
 380	} else {
 381		/* disable normal mic path */
 382		path = snd_hda_get_path_from_idx(codec, cur_input);
 383		if (path)
 384			snd_hda_activate_path(codec, path, false, false);
 385
 386		/* Even though port F is the DC input, the bias is controlled
 387		 * on port B.  We also leave that port as an active input (but
 388		 * unselected) in DC mode just in case that is necessary to
 389		 * make the bias setting take effect.
 390		 */
 391		if (spec->recording)
 392			val = olpc_xo_dc_bias.items[spec->dc_input_bias].index;
 393		else
 394			val = 0;
 395		update_mic_pin(codec, 0x1a, val);
 396		update_mic_pin(codec, 0x1b, 0);
 397		/* enable DC bias path and pin */
 398		update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
 399		snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
 400	}
 401}
 402
 403/* mic_autoswitch hook */
 404static void olpc_xo_automic(struct hda_codec *codec,
 405			    struct hda_jack_callback *jack)
 406{
 407	struct conexant_spec *spec = codec->spec;
 408
 409	/* in DC mode, we don't handle automic */
 410	if (!spec->dc_enable)
 411		snd_hda_gen_mic_autoswitch(codec, jack);
 412	olpc_xo_update_mic_pins(codec);
 413	if (spec->dc_enable)
 414		olpc_xo_update_mic_boost(codec);
 415}
 416
 417/* pcm_capture hook */
 418static void olpc_xo_capture_hook(struct hda_pcm_stream *hinfo,
 419				 struct hda_codec *codec,
 420				 struct snd_pcm_substream *substream,
 421				 int action)
 422{
 423	struct conexant_spec *spec = codec->spec;
 424
 425	/* toggle spec->recording flag and update mic pins accordingly
 426	 * for turning on/off LED
 427	 */
 428	switch (action) {
 429	case HDA_GEN_PCM_ACT_PREPARE:
 430		spec->recording = 1;
 431		olpc_xo_update_mic_pins(codec);
 432		break;
 433	case HDA_GEN_PCM_ACT_CLEANUP:
 434		spec->recording = 0;
 435		olpc_xo_update_mic_pins(codec);
 436		break;
 437	}
 438}
 439
 440static int olpc_xo_dc_mode_get(struct snd_kcontrol *kcontrol,
 441			       struct snd_ctl_elem_value *ucontrol)
 442{
 443	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 444	struct conexant_spec *spec = codec->spec;
 445	ucontrol->value.integer.value[0] = spec->dc_enable;
 446	return 0;
 447}
 448
 449static int olpc_xo_dc_mode_put(struct snd_kcontrol *kcontrol,
 450			       struct snd_ctl_elem_value *ucontrol)
 451{
 452	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 453	struct conexant_spec *spec = codec->spec;
 454	int dc_enable = !!ucontrol->value.integer.value[0];
 455
 456	if (dc_enable == spec->dc_enable)
 457		return 0;
 458
 459	spec->dc_enable = dc_enable;
 460	olpc_xo_update_mic_pins(codec);
 461	olpc_xo_update_mic_boost(codec);
 462	return 1;
 463}
 464
 465static int olpc_xo_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
 466				    struct snd_ctl_elem_value *ucontrol)
 467{
 468	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 469	struct conexant_spec *spec = codec->spec;
 470	ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
 471	return 0;
 472}
 473
 474static int olpc_xo_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
 475				     struct snd_ctl_elem_info *uinfo)
 476{
 477	return snd_hda_input_mux_info(&olpc_xo_dc_bias, uinfo);
 478}
 479
 480static int olpc_xo_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
 481				    struct snd_ctl_elem_value *ucontrol)
 482{
 483	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 484	struct conexant_spec *spec = codec->spec;
 485	const struct hda_input_mux *imux = &olpc_xo_dc_bias;
 486	unsigned int idx;
 487
 488	idx = ucontrol->value.enumerated.item[0];
 489	if (idx >= imux->num_items)
 490		idx = imux->num_items - 1;
 491	if (spec->dc_input_bias == idx)
 492		return 0;
 493
 494	spec->dc_input_bias = idx;
 495	if (spec->dc_enable)
 496		olpc_xo_update_mic_pins(codec);
 497	return 1;
 498}
 499
 500static const struct snd_kcontrol_new olpc_xo_mixers[] = {
 501	{
 502		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 503		.name = "DC Mode Enable Switch",
 504		.info = snd_ctl_boolean_mono_info,
 505		.get = olpc_xo_dc_mode_get,
 506		.put = olpc_xo_dc_mode_put,
 507	},
 508	{
 509		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 510		.name = "DC Input Bias Enum",
 511		.info = olpc_xo_dc_bias_enum_info,
 512		.get = olpc_xo_dc_bias_enum_get,
 513		.put = olpc_xo_dc_bias_enum_put,
 514	},
 515	{}
 516};
 517
 518/* overriding mic boost put callback; update mic boost volume only when
 519 * DC mode is disabled
 520 */
 521static int olpc_xo_mic_boost_put(struct snd_kcontrol *kcontrol,
 522				 struct snd_ctl_elem_value *ucontrol)
 523{
 524	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 525	struct conexant_spec *spec = codec->spec;
 526	int ret = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
 527	if (ret > 0 && spec->dc_enable)
 528		olpc_xo_update_mic_boost(codec);
 529	return ret;
 530}
 531
 532static void cxt_fixup_olpc_xo(struct hda_codec *codec,
 533				    const struct hda_fixup *fix, int action)
 534{
 535	struct conexant_spec *spec = codec->spec;
 536	struct snd_kcontrol_new *kctl;
 537	int i;
 538
 539	if (action != HDA_FIXUP_ACT_PROBE)
 540		return;
 541
 542	spec->gen.mic_autoswitch_hook = olpc_xo_automic;
 543	spec->gen.pcm_capture_hook = olpc_xo_capture_hook;
 544	spec->dc_mode_path = snd_hda_add_new_path(codec, 0x1e, 0x14, 0);
 545
 546	snd_hda_add_new_ctls(codec, olpc_xo_mixers);
 547
 548	/* OLPC's microphone port is DC coupled for use with external sensors,
 549	 * therefore we use a 50% mic bias in order to center the input signal
 550	 * with the DC input range of the codec.
 551	 */
 552	snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50);
 553
 554	/* override mic boost control */
 555	snd_array_for_each(&spec->gen.kctls, i, kctl) {
 556		if (!strcmp(kctl->name, "Mic Boost Volume")) {
 557			kctl->put = olpc_xo_mic_boost_put;
 558			break;
 559		}
 560	}
 561}
 562
 563static void cxt_fixup_mute_led_eapd(struct hda_codec *codec,
 564				    const struct hda_fixup *fix, int action)
 565{
 566	struct conexant_spec *spec = codec->spec;
 567
 568	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
 569		spec->mute_led_eapd = 0x1b;
 570		spec->dynamic_eapd = 1;
 571		snd_hda_gen_add_mute_led_cdev(codec, cx_auto_vmaster_mute_led);
 572	}
 573}
 574
 575/*
 576 * Fix max input level on mixer widget to 0dB
 577 * (originally it has 0x2b steps with 0dB offset 0x14)
 578 */
 579static void cxt_fixup_cap_mix_amp(struct hda_codec *codec,
 580				  const struct hda_fixup *fix, int action)
 581{
 582	snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
 583				  (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
 584				  (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
 585				  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
 586				  (1 << AC_AMPCAP_MUTE_SHIFT));
 587}
 588
 589/*
 590 * Fix max input level on mixer widget to 0dB
 591 * (originally it has 0x1e steps with 0 dB offset 0x17)
 592 */
 593static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec,
 594				  const struct hda_fixup *fix, int action)
 595{
 596	snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT,
 597				  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
 598				  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
 599				  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
 600				  (1 << AC_AMPCAP_MUTE_SHIFT));
 601}
 602
 603static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
 604				       const struct hda_fixup *fix,
 605				       int action)
 606{
 607	/* the mic pin (0x19) doesn't give an unsolicited event;
 608	 * probe the mic pin together with the headphone pin (0x16)
 609	 */
 610	if (action == HDA_FIXUP_ACT_PROBE)
 611		snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
 612}
 613
 614/* update LED status via GPIO */
 615static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
 616				bool led_on)
 617{
 618	struct conexant_spec *spec = codec->spec;
 619	unsigned int oldval = spec->gpio_led;
 620
 621	if (spec->mute_led_polarity)
 622		led_on = !led_on;
 623
 624	if (led_on)
 625		spec->gpio_led |= mask;
 626	else
 627		spec->gpio_led &= ~mask;
 628	codec_dbg(codec, "mask:%d enabled:%d gpio_led:%d\n",
 629			mask, led_on, spec->gpio_led);
 630	if (spec->gpio_led != oldval)
 631		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
 632				    spec->gpio_led);
 633}
 634
 635/* turn on/off mute LED via GPIO per vmaster hook */
 636static int cxt_gpio_mute_update(struct led_classdev *led_cdev,
 637				enum led_brightness brightness)
 638{
 639	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
 640	struct conexant_spec *spec = codec->spec;
 641
 642	cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, brightness);
 643	return 0;
 644}
 645
 646/* turn on/off mic-mute LED via GPIO per capture hook */
 647static int cxt_gpio_micmute_update(struct led_classdev *led_cdev,
 648				   enum led_brightness brightness)
 649{
 650	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
 651	struct conexant_spec *spec = codec->spec;
 652
 653	cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, brightness);
 654	return 0;
 655}
 656
 657
 658static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
 659				const struct hda_fixup *fix, int action)
 660{
 661	struct conexant_spec *spec = codec->spec;
 662	static const struct hda_verb gpio_init[] = {
 663		{ 0x01, AC_VERB_SET_GPIO_MASK, 0x03 },
 664		{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03 },
 665		{}
 666	};
 667
 668	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
 
 
 669		snd_hda_gen_add_mute_led_cdev(codec, cxt_gpio_mute_update);
 670		spec->gpio_led = 0;
 671		spec->mute_led_polarity = 0;
 672		spec->gpio_mute_led_mask = 0x01;
 673		spec->gpio_mic_led_mask = 0x02;
 674		snd_hda_gen_add_micmute_led_cdev(codec, cxt_gpio_micmute_update);
 
 675	}
 676	snd_hda_add_verbs(codec, gpio_init);
 677	if (spec->gpio_led)
 678		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
 679				    spec->gpio_led);
 680}
 681
 
 
 
 
 
 
 
 
 
 
 
 
 
 682
 683/* ThinkPad X200 & co with cxt5051 */
 684static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
 685	{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
 686	{ 0x17, 0x21a11000 }, /* dock-mic */
 687	{ 0x19, 0x2121103f }, /* dock-HP */
 688	{ 0x1c, 0x21440100 }, /* dock SPDIF out */
 689	{}
 690};
 691
 692/* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
 693static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = {
 694	{ 0x19, 0x042110ff }, /* HP (seq# overridden) */
 695	{ 0x1a, 0x21a190f0 }, /* dock-mic */
 696	{ 0x1c, 0x212140ff }, /* dock-HP */
 697	{}
 698};
 699
 700/* Lemote A1004/A1205 with cxt5066 */
 701static const struct hda_pintbl cxt_pincfg_lemote[] = {
 702	{ 0x1a, 0x90a10020 }, /* Internal mic */
 703	{ 0x1b, 0x03a11020 }, /* External mic */
 704	{ 0x1d, 0x400101f0 }, /* Not used */
 705	{ 0x1e, 0x40a701f0 }, /* Not used */
 706	{ 0x20, 0x404501f0 }, /* Not used */
 707	{ 0x22, 0x404401f0 }, /* Not used */
 708	{ 0x23, 0x40a701f0 }, /* Not used */
 709	{}
 710};
 711
 
 
 
 
 
 
 
 
 
 
 
 712static const struct hda_fixup cxt_fixups[] = {
 713	[CXT_PINCFG_LENOVO_X200] = {
 714		.type = HDA_FIXUP_PINS,
 715		.v.pins = cxt_pincfg_lenovo_x200,
 716	},
 717	[CXT_PINCFG_LENOVO_TP410] = {
 718		.type = HDA_FIXUP_PINS,
 719		.v.pins = cxt_pincfg_lenovo_tp410,
 720		.chained = true,
 721		.chain_id = CXT_FIXUP_THINKPAD_ACPI,
 722	},
 723	[CXT_PINCFG_LEMOTE_A1004] = {
 724		.type = HDA_FIXUP_PINS,
 725		.chained = true,
 726		.chain_id = CXT_FIXUP_INC_MIC_BOOST,
 727		.v.pins = cxt_pincfg_lemote,
 728	},
 729	[CXT_PINCFG_LEMOTE_A1205] = {
 730		.type = HDA_FIXUP_PINS,
 731		.v.pins = cxt_pincfg_lemote,
 732	},
 733	[CXT_PINCFG_COMPAQ_CQ60] = {
 734		.type = HDA_FIXUP_PINS,
 735		.v.pins = (const struct hda_pintbl[]) {
 736			/* 0x17 was falsely set up as a mic, it should 0x1d */
 737			{ 0x17, 0x400001f0 },
 738			{ 0x1d, 0x97a70120 },
 739			{ }
 740		}
 741	},
 742	[CXT_FIXUP_STEREO_DMIC] = {
 743		.type = HDA_FIXUP_FUNC,
 744		.v.func = cxt_fixup_stereo_dmic,
 745	},
 
 
 
 
 
 
 
 
 746	[CXT_FIXUP_INC_MIC_BOOST] = {
 747		.type = HDA_FIXUP_FUNC,
 748		.v.func = cxt5066_increase_mic_boost,
 749	},
 750	[CXT_FIXUP_HEADPHONE_MIC_PIN] = {
 751		.type = HDA_FIXUP_PINS,
 752		.chained = true,
 753		.chain_id = CXT_FIXUP_HEADPHONE_MIC,
 754		.v.pins = (const struct hda_pintbl[]) {
 755			{ 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
 756			{ }
 757		}
 758	},
 759	[CXT_FIXUP_HEADPHONE_MIC] = {
 760		.type = HDA_FIXUP_FUNC,
 761		.v.func = cxt_fixup_headphone_mic,
 762	},
 763	[CXT_FIXUP_GPIO1] = {
 764		.type = HDA_FIXUP_VERBS,
 765		.v.verbs = (const struct hda_verb[]) {
 766			{ 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
 767			{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
 768			{ 0x01, AC_VERB_SET_GPIO_DATA, 0x01 },
 769			{ }
 770		},
 771	},
 772	[CXT_FIXUP_ASPIRE_DMIC] = {
 773		.type = HDA_FIXUP_FUNC,
 774		.v.func = cxt_fixup_stereo_dmic,
 775		.chained = true,
 776		.chain_id = CXT_FIXUP_GPIO1,
 777	},
 778	[CXT_FIXUP_THINKPAD_ACPI] = {
 779		.type = HDA_FIXUP_FUNC,
 780		.v.func = hda_fixup_thinkpad_acpi,
 781	},
 782	[CXT_FIXUP_OLPC_XO] = {
 783		.type = HDA_FIXUP_FUNC,
 784		.v.func = cxt_fixup_olpc_xo,
 785	},
 786	[CXT_FIXUP_CAP_MIX_AMP] = {
 787		.type = HDA_FIXUP_FUNC,
 788		.v.func = cxt_fixup_cap_mix_amp,
 789	},
 790	[CXT_FIXUP_TOSHIBA_P105] = {
 791		.type = HDA_FIXUP_PINS,
 792		.v.pins = (const struct hda_pintbl[]) {
 793			{ 0x10, 0x961701f0 }, /* speaker/hp */
 794			{ 0x12, 0x02a1901e }, /* ext mic */
 795			{ 0x14, 0x95a70110 }, /* int mic */
 796			{}
 797		},
 798	},
 799	[CXT_FIXUP_HP_530] = {
 800		.type = HDA_FIXUP_PINS,
 801		.v.pins = (const struct hda_pintbl[]) {
 802			{ 0x12, 0x90a60160 }, /* int mic */
 803			{}
 804		},
 805		.chained = true,
 806		.chain_id = CXT_FIXUP_CAP_MIX_AMP,
 807	},
 808	[CXT_FIXUP_CAP_MIX_AMP_5047] = {
 809		.type = HDA_FIXUP_FUNC,
 810		.v.func = cxt_fixup_cap_mix_amp_5047,
 811	},
 812	[CXT_FIXUP_MUTE_LED_EAPD] = {
 813		.type = HDA_FIXUP_FUNC,
 814		.v.func = cxt_fixup_mute_led_eapd,
 815	},
 816	[CXT_FIXUP_HP_DOCK] = {
 817		.type = HDA_FIXUP_PINS,
 818		.v.pins = (const struct hda_pintbl[]) {
 819			{ 0x16, 0x21011020 }, /* line-out */
 820			{ 0x18, 0x2181103f }, /* line-in */
 821			{ }
 822		},
 823		.chained = true,
 824		.chain_id = CXT_FIXUP_MUTE_LED_GPIO,
 825	},
 826	[CXT_FIXUP_HP_SPECTRE] = {
 827		.type = HDA_FIXUP_PINS,
 828		.v.pins = (const struct hda_pintbl[]) {
 829			/* enable NID 0x1d for the speaker on top */
 830			{ 0x1d, 0x91170111 },
 831			{ }
 832		}
 833	},
 834	[CXT_FIXUP_HP_GATE_MIC] = {
 835		.type = HDA_FIXUP_FUNC,
 836		.v.func = cxt_fixup_hp_gate_mic_jack,
 837	},
 838	[CXT_FIXUP_MUTE_LED_GPIO] = {
 839		.type = HDA_FIXUP_FUNC,
 840		.v.func = cxt_fixup_mute_led_gpio,
 841	},
 
 
 
 
 842	[CXT_FIXUP_HEADSET_MIC] = {
 843		.type = HDA_FIXUP_FUNC,
 844		.v.func = cxt_fixup_headset_mic,
 845	},
 846	[CXT_FIXUP_HP_MIC_NO_PRESENCE] = {
 847		.type = HDA_FIXUP_PINS,
 848		.v.pins = (const struct hda_pintbl[]) {
 849			{ 0x1a, 0x02a1113c },
 850			{ }
 851		},
 852		.chained = true,
 853		.chain_id = CXT_FIXUP_HEADSET_MIC,
 854	},
 
 
 
 
 855};
 856
 857static const struct snd_pci_quirk cxt5045_fixups[] = {
 858	SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530),
 859	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105),
 860	/* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
 861	 * really bad sound over 0dB on NID 0x17.
 862	 */
 863	SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP),
 864	SND_PCI_QUIRK_VENDOR(0x1631, "Packard Bell", CXT_FIXUP_CAP_MIX_AMP),
 865	SND_PCI_QUIRK_VENDOR(0x1734, "Fujitsu", CXT_FIXUP_CAP_MIX_AMP),
 866	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT_FIXUP_CAP_MIX_AMP),
 867	{}
 868};
 869
 870static const struct hda_model_fixup cxt5045_fixup_models[] = {
 871	{ .id = CXT_FIXUP_CAP_MIX_AMP, .name = "cap-mix-amp" },
 872	{ .id = CXT_FIXUP_TOSHIBA_P105, .name = "toshiba-p105" },
 873	{ .id = CXT_FIXUP_HP_530, .name = "hp-530" },
 874	{}
 875};
 876
 877static const struct snd_pci_quirk cxt5047_fixups[] = {
 878	/* HP laptops have really bad sound over 0 dB on NID 0x10.
 879	 */
 880	SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047),
 881	{}
 882};
 883
 884static const struct hda_model_fixup cxt5047_fixup_models[] = {
 885	{ .id = CXT_FIXUP_CAP_MIX_AMP_5047, .name = "cap-mix-amp" },
 886	{}
 887};
 888
 889static const struct snd_pci_quirk cxt5051_fixups[] = {
 890	SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60),
 891	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
 892	{}
 893};
 894
 895static const struct hda_model_fixup cxt5051_fixup_models[] = {
 896	{ .id = CXT_PINCFG_LENOVO_X200, .name = "lenovo-x200" },
 897	{}
 898};
 899
 900static const struct snd_pci_quirk cxt5066_fixups[] = {
 901	SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
 902	SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
 903	SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
 904	SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
 905	SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
 906	SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
 907	SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
 908	SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
 909	SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
 910	SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
 911	SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
 912	SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
 913	SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
 
 914	SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
 915	SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
 916	SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
 917	SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
 918	SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
 
 
 
 
 
 
 919	SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO),
 
 
 920	SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE),
 921	SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
 922	SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE),
 923	SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE),
 924	SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
 
 925	SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
 926	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
 927	SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
 928	SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
 929	SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
 930	SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
 931	SND_PCI_QUIRK(0x17aa, 0x21d2, "Lenovo T420s", CXT_PINCFG_LENOVO_TP410),
 932	SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
 933	SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
 934	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
 935	SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
 936	SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
 937	SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
 
 
 
 938	SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
 939	SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
 940	SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
 941	SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI),
 942	SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
 943	SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205),
 944	{}
 945};
 946
 947static const struct hda_model_fixup cxt5066_fixup_models[] = {
 948	{ .id = CXT_FIXUP_STEREO_DMIC, .name = "stereo-dmic" },
 949	{ .id = CXT_FIXUP_GPIO1, .name = "gpio1" },
 950	{ .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" },
 951	{ .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" },
 952	{ .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" },
 953	{ .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" },
 954	{ .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" },
 955	{ .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
 956	{ .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
 957	{ .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
 958	{ .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
 
 959	{ .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
 
 
 960	{}
 961};
 962
 963/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
 964 * can be created (bko#42825)
 965 */
 966static void add_cx5051_fake_mutes(struct hda_codec *codec)
 967{
 968	struct conexant_spec *spec = codec->spec;
 969	static const hda_nid_t out_nids[] = {
 970		0x10, 0x11, 0
 971	};
 972	const hda_nid_t *p;
 973
 974	for (p = out_nids; *p; p++)
 975		snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT,
 976					  AC_AMPCAP_MIN_MUTE |
 977					  query_amp_caps(codec, *p, HDA_OUTPUT));
 978	spec->gen.dac_min_mute = true;
 979}
 980
 981static int patch_conexant_auto(struct hda_codec *codec)
 982{
 983	struct conexant_spec *spec;
 984	int err;
 985
 986	codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
 987
 988	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 989	if (!spec)
 990		return -ENOMEM;
 991	snd_hda_gen_spec_init(&spec->gen);
 992	codec->spec = spec;
 993	codec->patch_ops = cx_auto_patch_ops;
 994
 
 
 
 
 
 
 
 
 
 995	cx_auto_parse_eapd(codec);
 996	spec->gen.own_eapd_ctl = 1;
 997
 998	switch (codec->core.vendor_id) {
 999	case 0x14f15045:
1000		codec->single_adc_amp = 1;
1001		spec->gen.mixer_nid = 0x17;
1002		spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
1003		snd_hda_pick_fixup(codec, cxt5045_fixup_models,
1004				   cxt5045_fixups, cxt_fixups);
1005		break;
1006	case 0x14f15047:
1007		codec->pin_amp_workaround = 1;
1008		spec->gen.mixer_nid = 0x19;
1009		spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
1010		snd_hda_pick_fixup(codec, cxt5047_fixup_models,
1011				   cxt5047_fixups, cxt_fixups);
1012		break;
1013	case 0x14f15051:
1014		add_cx5051_fake_mutes(codec);
1015		codec->pin_amp_workaround = 1;
1016		snd_hda_pick_fixup(codec, cxt5051_fixup_models,
1017				   cxt5051_fixups, cxt_fixups);
1018		break;
 
 
 
 
 
 
 
1019	case 0x14f150f2:
1020		codec->power_save_node = 1;
1021		fallthrough;
1022	default:
1023		codec->pin_amp_workaround = 1;
1024		snd_hda_pick_fixup(codec, cxt5066_fixup_models,
1025				   cxt5066_fixups, cxt_fixups);
1026		break;
1027	}
1028
1029	if (!spec->gen.vmaster_mute.hook && spec->dynamic_eapd)
1030		spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook;
1031
1032	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1033
1034	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
1035				       spec->parse_flags);
1036	if (err < 0)
1037		goto error;
1038
1039	err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
1040	if (err < 0)
1041		goto error;
1042
1043	err = cx_auto_parse_beep(codec);
1044	if (err < 0)
1045		goto error;
1046
1047	/* Some laptops with Conexant chips show stalls in S3 resume,
1048	 * which falls into the single-cmd mode.
1049	 * Better to make reset, then.
1050	 */
1051	if (!codec->bus->core.sync_write) {
1052		codec_info(codec,
1053			   "Enable sync_write for stable communication\n");
1054		codec->bus->core.sync_write = 1;
1055		codec->bus->allow_bus_reset = 1;
1056	}
1057
1058	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
1059
1060	return 0;
1061
1062 error:
1063	cx_auto_free(codec);
1064	return err;
1065}
1066
1067/*
1068 */
1069
1070static const struct hda_device_id snd_hda_id_conexant[] = {
1071	HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto),
 
1072	HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
 
 
1073	HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
1074	HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
1075	HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
1076	HDA_CODEC_ENTRY(0x14f15066, "CX20582 (Pebble)", patch_conexant_auto),
1077	HDA_CODEC_ENTRY(0x14f15067, "CX20583 (Pebble HSF)", patch_conexant_auto),
1078	HDA_CODEC_ENTRY(0x14f15068, "CX20584", patch_conexant_auto),
1079	HDA_CODEC_ENTRY(0x14f15069, "CX20585", patch_conexant_auto),
1080	HDA_CODEC_ENTRY(0x14f1506c, "CX20588", patch_conexant_auto),
1081	HDA_CODEC_ENTRY(0x14f1506e, "CX20590", patch_conexant_auto),
1082	HDA_CODEC_ENTRY(0x14f15097, "CX20631", patch_conexant_auto),
1083	HDA_CODEC_ENTRY(0x14f15098, "CX20632", patch_conexant_auto),
1084	HDA_CODEC_ENTRY(0x14f150a1, "CX20641", patch_conexant_auto),
1085	HDA_CODEC_ENTRY(0x14f150a2, "CX20642", patch_conexant_auto),
1086	HDA_CODEC_ENTRY(0x14f150ab, "CX20651", patch_conexant_auto),
1087	HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto),
1088	HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto),
1089	HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto),
1090	HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto),
1091	HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto),
1092	HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto),
1093	HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto),
1094	HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto),
1095	HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto),
1096	HDA_CODEC_ENTRY(0x14f15111, "CX20753/4", patch_conexant_auto),
1097	HDA_CODEC_ENTRY(0x14f15113, "CX20755", patch_conexant_auto),
1098	HDA_CODEC_ENTRY(0x14f15114, "CX20756", patch_conexant_auto),
1099	HDA_CODEC_ENTRY(0x14f15115, "CX20757", patch_conexant_auto),
1100	HDA_CODEC_ENTRY(0x14f151d7, "CX20952", patch_conexant_auto),
1101	{} /* terminator */
1102};
1103MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_conexant);
1104
1105MODULE_LICENSE("GPL");
1106MODULE_DESCRIPTION("Conexant HD-audio codec");
1107
1108static struct hda_codec_driver conexant_driver = {
1109	.id = snd_hda_id_conexant,
1110};
1111
1112module_hda_codec_driver(conexant_driver);
v6.8
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * HD audio interface patch for Conexant HDA audio codec
   4 *
   5 * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
   6 * 		      Takashi Iwai <tiwai@suse.de>
   7 * 		      Tobin Davis  <tdavis@dsl-only.net>
   8 */
   9
  10#include <linux/init.h>
  11#include <linux/delay.h>
  12#include <linux/slab.h>
  13#include <linux/module.h>
  14#include <sound/core.h>
  15#include <sound/jack.h>
  16
  17#include <sound/hda_codec.h>
  18#include "hda_local.h"
  19#include "hda_auto_parser.h"
  20#include "hda_beep.h"
  21#include "hda_jack.h"
  22#include "hda_generic.h"
  23
  24enum {
  25	CX_HEADSET_NOPRESENT = 0,
  26	CX_HEADSET_PARTPRESENT,
  27	CX_HEADSET_ALLPRESENT,
  28};
  29
  30struct conexant_spec {
  31	struct hda_gen_spec gen;
  32
  33	/* extra EAPD pins */
  34	unsigned int num_eapds;
  35	hda_nid_t eapds[4];
  36	bool dynamic_eapd;
  37	hda_nid_t mute_led_eapd;
  38
  39	unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
  40
  41	/* OPLC XO specific */
  42	bool recording;
  43	bool dc_enable;
  44	unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
  45	struct nid_path *dc_mode_path;
  46
  47	int mute_led_polarity;
  48	unsigned int gpio_led;
  49	unsigned int gpio_mute_led_mask;
  50	unsigned int gpio_mic_led_mask;
  51	unsigned int headset_present_flag;
  52	bool is_cx8070_sn6140;
  53};
  54
  55
  56#ifdef CONFIG_SND_HDA_INPUT_BEEP
  57/* additional beep mixers; private_value will be overwritten */
  58static const struct snd_kcontrol_new cxt_beep_mixer[] = {
  59	HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
  60	HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
  61};
  62
  63static int set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
  64			int idx, int dir)
  65{
  66	struct snd_kcontrol_new *knew;
  67	unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
  68	int i;
  69
  70	spec->gen.beep_nid = nid;
  71	for (i = 0; i < ARRAY_SIZE(cxt_beep_mixer); i++) {
  72		knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
  73					    &cxt_beep_mixer[i]);
  74		if (!knew)
  75			return -ENOMEM;
  76		knew->private_value = beep_amp;
  77	}
  78	return 0;
  79}
  80
  81static int cx_auto_parse_beep(struct hda_codec *codec)
  82{
  83	struct conexant_spec *spec = codec->spec;
  84	hda_nid_t nid;
  85
  86	for_each_hda_codec_node(nid, codec)
  87		if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
  88			return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
  89	return 0;
  90}
  91#else
  92#define cx_auto_parse_beep(codec)	0
  93#endif
  94
  95/*
  96 * Automatic parser for CX20641 & co
  97 */
  98
  99/* parse EAPDs */
 100static void cx_auto_parse_eapd(struct hda_codec *codec)
 101{
 102	struct conexant_spec *spec = codec->spec;
 103	hda_nid_t nid;
 104
 105	for_each_hda_codec_node(nid, codec) {
 106		if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
 107			continue;
 108		if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
 109			continue;
 110		spec->eapds[spec->num_eapds++] = nid;
 111		if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
 112			break;
 113	}
 114
 115	/* NOTE: below is a wild guess; if we have more than two EAPDs,
 116	 * it's a new chip, where EAPDs are supposed to be associated to
 117	 * pins, and we can control EAPD per pin.
 118	 * OTOH, if only one or two EAPDs are found, it's an old chip,
 119	 * thus it might control over all pins.
 120	 */
 121	if (spec->num_eapds > 2)
 122		spec->dynamic_eapd = 1;
 123}
 124
 125static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
 126			      const hda_nid_t *pins, bool on)
 127{
 128	int i;
 129	for (i = 0; i < num_pins; i++) {
 130		if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
 131			snd_hda_codec_write(codec, pins[i], 0,
 132					    AC_VERB_SET_EAPD_BTLENABLE,
 133					    on ? 0x02 : 0);
 134	}
 135}
 136
 137/* turn on/off EAPD according to Master switch */
 138static void cx_auto_vmaster_hook(void *private_data, int enabled)
 139{
 140	struct hda_codec *codec = private_data;
 141	struct conexant_spec *spec = codec->spec;
 142
 143	cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled);
 144}
 145
 146/* turn on/off EAPD according to Master switch (inversely!) for mute LED */
 147static int cx_auto_vmaster_mute_led(struct led_classdev *led_cdev,
 148				    enum led_brightness brightness)
 149{
 150	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
 151	struct conexant_spec *spec = codec->spec;
 152
 153	snd_hda_codec_write(codec, spec->mute_led_eapd, 0,
 154			    AC_VERB_SET_EAPD_BTLENABLE,
 155			    brightness ? 0x02 : 0x00);
 156	return 0;
 157}
 158
 159static void cxt_init_gpio_led(struct hda_codec *codec)
 160{
 161	struct conexant_spec *spec = codec->spec;
 162	unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
 163
 164	if (mask) {
 165		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
 166				    mask);
 167		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
 168				    mask);
 169		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
 170				    spec->gpio_led);
 171	}
 172}
 173
 174static void cx_fixup_headset_recog(struct hda_codec *codec)
 175{
 176	unsigned int mic_persent;
 177
 178	/* fix some headset type recognize fail issue, such as EDIFIER headset */
 179	/* set micbiasd output current comparator threshold from 66% to 55%. */
 180	snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010);
 181	/* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias registor
 182	 * value adjustment trim from 2.2K ohms to 2.0K ohms.
 183	 */
 184	snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10);
 185	/* fix reboot headset type recognize fail issue */
 186	mic_persent = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0);
 187	if (mic_persent & AC_PINSENSE_PRESENCE)
 188		/* enable headset mic VREF */
 189		snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
 190	else
 191		/* disable headset mic VREF */
 192		snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
 193}
 194
 195static int cx_auto_init(struct hda_codec *codec)
 196{
 197	struct conexant_spec *spec = codec->spec;
 198	snd_hda_gen_init(codec);
 199	if (!spec->dynamic_eapd)
 200		cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
 201
 202	cxt_init_gpio_led(codec);
 203	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
 204
 205	if (spec->is_cx8070_sn6140)
 206		cx_fixup_headset_recog(codec);
 207
 208	return 0;
 209}
 210
 211static void cx_auto_shutdown(struct hda_codec *codec)
 212{
 213	struct conexant_spec *spec = codec->spec;
 214
 215	/* Turn the problematic codec into D3 to avoid spurious noises
 216	   from the internal speaker during (and after) reboot */
 217	cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
 
 218}
 219
 220static void cx_auto_free(struct hda_codec *codec)
 221{
 222	cx_auto_shutdown(codec);
 223	snd_hda_gen_free(codec);
 224}
 225
 226static void cx_process_headset_plugin(struct hda_codec *codec)
 227{
 228	unsigned int val;
 229	unsigned int count = 0;
 230
 231	/* Wait headset detect done. */
 232	do {
 233		val = snd_hda_codec_read(codec, 0x1c, 0, 0xca0, 0x0);
 234		if (val & 0x080) {
 235			codec_dbg(codec, "headset type detect done!\n");
 236			break;
 237		}
 238		msleep(20);
 239		count++;
 240	} while (count < 3);
 241	val = snd_hda_codec_read(codec, 0x1c, 0, 0xcb0, 0x0);
 242	if (val & 0x800) {
 243		codec_dbg(codec, "headset plugin, type is CTIA\n");
 244		snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
 245	} else if (val & 0x400) {
 246		codec_dbg(codec, "headset plugin, type is OMTP\n");
 247		snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
 248	} else {
 249		codec_dbg(codec, "headphone plugin\n");
 250	}
 251}
 252
 253static void cx_update_headset_mic_vref(struct hda_codec *codec, unsigned int res)
 254{
 255	unsigned int phone_present, mic_persent, phone_tag, mic_tag;
 256	struct conexant_spec *spec = codec->spec;
 257
 258	/* In cx8070 and sn6140, the node 16 can only be config to headphone or disabled,
 259	 * the node 19 can only be config to microphone or disabled.
 260	 * Check hp&mic tag to process headset pulgin&plugout.
 261	 */
 262	phone_tag = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0);
 263	mic_tag = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_UNSOLICITED_RESPONSE, 0x0);
 264	if ((phone_tag & (res >> AC_UNSOL_RES_TAG_SHIFT)) ||
 265	    (mic_tag & (res >> AC_UNSOL_RES_TAG_SHIFT))) {
 266		phone_present = snd_hda_codec_read(codec, 0x16, 0, AC_VERB_GET_PIN_SENSE, 0x0);
 267		if (!(phone_present & AC_PINSENSE_PRESENCE)) {/* headphone plugout */
 268			spec->headset_present_flag = CX_HEADSET_NOPRESENT;
 269			snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
 270			return;
 271		}
 272		if (spec->headset_present_flag == CX_HEADSET_NOPRESENT) {
 273			spec->headset_present_flag = CX_HEADSET_PARTPRESENT;
 274		} else if (spec->headset_present_flag == CX_HEADSET_PARTPRESENT) {
 275			mic_persent = snd_hda_codec_read(codec, 0x19, 0,
 276							 AC_VERB_GET_PIN_SENSE, 0x0);
 277			/* headset is present */
 278			if ((phone_present & AC_PINSENSE_PRESENCE) &&
 279			    (mic_persent & AC_PINSENSE_PRESENCE)) {
 280				cx_process_headset_plugin(codec);
 281				spec->headset_present_flag = CX_HEADSET_ALLPRESENT;
 282			}
 283		}
 284	}
 285}
 286
 287static void cx_jack_unsol_event(struct hda_codec *codec, unsigned int res)
 288{
 289	struct conexant_spec *spec = codec->spec;
 290
 291	if (spec->is_cx8070_sn6140)
 292		cx_update_headset_mic_vref(codec, res);
 293
 294	snd_hda_jack_unsol_event(codec, res);
 295}
 296
 297#ifdef CONFIG_PM
 298static int cx_auto_suspend(struct hda_codec *codec)
 299{
 300	cx_auto_shutdown(codec);
 301	return 0;
 302}
 303#endif
 304
 305static const struct hda_codec_ops cx_auto_patch_ops = {
 306	.build_controls = snd_hda_gen_build_controls,
 307	.build_pcms = snd_hda_gen_build_pcms,
 308	.init = cx_auto_init,
 
 309	.free = cx_auto_free,
 310	.unsol_event = cx_jack_unsol_event,
 311#ifdef CONFIG_PM
 312	.suspend = cx_auto_suspend,
 313	.check_power_status = snd_hda_gen_check_power_status,
 314#endif
 315};
 316
 317/*
 318 * pin fix-up
 319 */
 320enum {
 321	CXT_PINCFG_LENOVO_X200,
 322	CXT_PINCFG_LENOVO_TP410,
 323	CXT_PINCFG_LEMOTE_A1004,
 324	CXT_PINCFG_LEMOTE_A1205,
 325	CXT_PINCFG_COMPAQ_CQ60,
 326	CXT_FIXUP_STEREO_DMIC,
 327	CXT_PINCFG_LENOVO_NOTEBOOK,
 328	CXT_FIXUP_INC_MIC_BOOST,
 329	CXT_FIXUP_HEADPHONE_MIC_PIN,
 330	CXT_FIXUP_HEADPHONE_MIC,
 331	CXT_FIXUP_GPIO1,
 332	CXT_FIXUP_ASPIRE_DMIC,
 333	CXT_FIXUP_THINKPAD_ACPI,
 334	CXT_FIXUP_OLPC_XO,
 335	CXT_FIXUP_CAP_MIX_AMP,
 336	CXT_FIXUP_TOSHIBA_P105,
 337	CXT_FIXUP_HP_530,
 338	CXT_FIXUP_CAP_MIX_AMP_5047,
 339	CXT_FIXUP_MUTE_LED_EAPD,
 340	CXT_FIXUP_HP_DOCK,
 341	CXT_FIXUP_HP_SPECTRE,
 342	CXT_FIXUP_HP_GATE_MIC,
 343	CXT_FIXUP_MUTE_LED_GPIO,
 344	CXT_FIXUP_HP_ZBOOK_MUTE_LED,
 345	CXT_FIXUP_HEADSET_MIC,
 346	CXT_FIXUP_HP_MIC_NO_PRESENCE,
 347	CXT_PINCFG_SWS_JS201D,
 348};
 349
 350/* for hda_fixup_thinkpad_acpi() */
 351#include "thinkpad_helper.c"
 352
 353static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
 354				  const struct hda_fixup *fix, int action)
 355{
 356	struct conexant_spec *spec = codec->spec;
 357	spec->gen.inv_dmic_split = 1;
 358}
 359
 360static void cxt5066_increase_mic_boost(struct hda_codec *codec,
 361				   const struct hda_fixup *fix, int action)
 362{
 363	if (action != HDA_FIXUP_ACT_PRE_PROBE)
 364		return;
 365
 366	snd_hda_override_amp_caps(codec, 0x17, HDA_OUTPUT,
 367				  (0x3 << AC_AMPCAP_OFFSET_SHIFT) |
 368				  (0x4 << AC_AMPCAP_NUM_STEPS_SHIFT) |
 369				  (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
 370				  (0 << AC_AMPCAP_MUTE_SHIFT));
 371}
 372
 373static void cxt_update_headset_mode(struct hda_codec *codec)
 374{
 375	/* The verbs used in this function were tested on a Conexant CX20751/2 codec. */
 376	int i;
 377	bool mic_mode = false;
 378	struct conexant_spec *spec = codec->spec;
 379	struct auto_pin_cfg *cfg = &spec->gen.autocfg;
 380
 381	hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
 382
 383	for (i = 0; i < cfg->num_inputs; i++)
 384		if (cfg->inputs[i].pin == mux_pin) {
 385			mic_mode = !!cfg->inputs[i].is_headphone_mic;
 386			break;
 387		}
 388
 389	if (mic_mode) {
 390		snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */
 391		spec->gen.hp_jack_present = false;
 392	} else {
 393		snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */
 394		spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]);
 395	}
 396
 397	snd_hda_gen_update_outputs(codec);
 398}
 399
 400static void cxt_update_headset_mode_hook(struct hda_codec *codec,
 401					 struct snd_kcontrol *kcontrol,
 402					 struct snd_ctl_elem_value *ucontrol)
 403{
 404	cxt_update_headset_mode(codec);
 405}
 406
 407static void cxt_fixup_headphone_mic(struct hda_codec *codec,
 408				    const struct hda_fixup *fix, int action)
 409{
 410	struct conexant_spec *spec = codec->spec;
 411
 412	switch (action) {
 413	case HDA_FIXUP_ACT_PRE_PROBE:
 414		spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
 415		snd_hdac_regmap_add_vendor_verb(&codec->core, 0x410);
 416		break;
 417	case HDA_FIXUP_ACT_PROBE:
 418		WARN_ON(spec->gen.cap_sync_hook);
 419		spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
 420		spec->gen.automute_hook = cxt_update_headset_mode;
 421		break;
 422	case HDA_FIXUP_ACT_INIT:
 423		cxt_update_headset_mode(codec);
 424		break;
 425	}
 426}
 427
 428static void cxt_fixup_headset_mic(struct hda_codec *codec,
 429				    const struct hda_fixup *fix, int action)
 430{
 431	struct conexant_spec *spec = codec->spec;
 432
 433	switch (action) {
 434	case HDA_FIXUP_ACT_PRE_PROBE:
 435		spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
 436		break;
 437	}
 438}
 439
 440/* OPLC XO 1.5 fixup */
 441
 442/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
 443 * through the microphone jack.
 444 * When the user enables this through a mixer switch, both internal and
 445 * external microphones are disabled. Gain is fixed at 0dB. In this mode,
 446 * we also allow the bias to be configured through a separate mixer
 447 * control. */
 448
 449#define update_mic_pin(codec, nid, val)					\
 450	snd_hda_codec_write_cache(codec, nid, 0,			\
 451				   AC_VERB_SET_PIN_WIDGET_CONTROL, val)
 452
 453static const struct hda_input_mux olpc_xo_dc_bias = {
 454	.num_items = 3,
 455	.items = {
 456		{ "Off", PIN_IN },
 457		{ "50%", PIN_VREF50 },
 458		{ "80%", PIN_VREF80 },
 459	},
 460};
 461
 462static void olpc_xo_update_mic_boost(struct hda_codec *codec)
 463{
 464	struct conexant_spec *spec = codec->spec;
 465	int ch, val;
 466
 467	for (ch = 0; ch < 2; ch++) {
 468		val = AC_AMP_SET_OUTPUT |
 469			(ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT);
 470		if (!spec->dc_enable)
 471			val |= snd_hda_codec_amp_read(codec, 0x17, ch, HDA_OUTPUT, 0);
 472		snd_hda_codec_write(codec, 0x17, 0,
 473				    AC_VERB_SET_AMP_GAIN_MUTE, val);
 474	}
 475}
 476
 477static void olpc_xo_update_mic_pins(struct hda_codec *codec)
 478{
 479	struct conexant_spec *spec = codec->spec;
 480	int cur_input, val;
 481	struct nid_path *path;
 482
 483	cur_input = spec->gen.input_paths[0][spec->gen.cur_mux[0]];
 484
 485	/* Set up mic pins for port-B, C and F dynamically as the recording
 486	 * LED is turned on/off by these pin controls
 487	 */
 488	if (!spec->dc_enable) {
 489		/* disable DC bias path and pin for port F */
 490		update_mic_pin(codec, 0x1e, 0);
 491		snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
 492
 493		/* update port B (ext mic) and C (int mic) */
 494		/* OLPC defers mic widget control until when capture is
 495		 * started because the microphone LED comes on as soon as
 496		 * these settings are put in place. if we did this before
 497		 * recording, it would give the false indication that
 498		 * recording is happening when it is not.
 499		 */
 500		update_mic_pin(codec, 0x1a, spec->recording ?
 501			       snd_hda_codec_get_pin_target(codec, 0x1a) : 0);
 502		update_mic_pin(codec, 0x1b, spec->recording ?
 503			       snd_hda_codec_get_pin_target(codec, 0x1b) : 0);
 504		/* enable normal mic path */
 505		path = snd_hda_get_path_from_idx(codec, cur_input);
 506		if (path)
 507			snd_hda_activate_path(codec, path, true, false);
 508	} else {
 509		/* disable normal mic path */
 510		path = snd_hda_get_path_from_idx(codec, cur_input);
 511		if (path)
 512			snd_hda_activate_path(codec, path, false, false);
 513
 514		/* Even though port F is the DC input, the bias is controlled
 515		 * on port B.  We also leave that port as an active input (but
 516		 * unselected) in DC mode just in case that is necessary to
 517		 * make the bias setting take effect.
 518		 */
 519		if (spec->recording)
 520			val = olpc_xo_dc_bias.items[spec->dc_input_bias].index;
 521		else
 522			val = 0;
 523		update_mic_pin(codec, 0x1a, val);
 524		update_mic_pin(codec, 0x1b, 0);
 525		/* enable DC bias path and pin */
 526		update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
 527		snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
 528	}
 529}
 530
 531/* mic_autoswitch hook */
 532static void olpc_xo_automic(struct hda_codec *codec,
 533			    struct hda_jack_callback *jack)
 534{
 535	struct conexant_spec *spec = codec->spec;
 536
 537	/* in DC mode, we don't handle automic */
 538	if (!spec->dc_enable)
 539		snd_hda_gen_mic_autoswitch(codec, jack);
 540	olpc_xo_update_mic_pins(codec);
 541	if (spec->dc_enable)
 542		olpc_xo_update_mic_boost(codec);
 543}
 544
 545/* pcm_capture hook */
 546static void olpc_xo_capture_hook(struct hda_pcm_stream *hinfo,
 547				 struct hda_codec *codec,
 548				 struct snd_pcm_substream *substream,
 549				 int action)
 550{
 551	struct conexant_spec *spec = codec->spec;
 552
 553	/* toggle spec->recording flag and update mic pins accordingly
 554	 * for turning on/off LED
 555	 */
 556	switch (action) {
 557	case HDA_GEN_PCM_ACT_PREPARE:
 558		spec->recording = 1;
 559		olpc_xo_update_mic_pins(codec);
 560		break;
 561	case HDA_GEN_PCM_ACT_CLEANUP:
 562		spec->recording = 0;
 563		olpc_xo_update_mic_pins(codec);
 564		break;
 565	}
 566}
 567
 568static int olpc_xo_dc_mode_get(struct snd_kcontrol *kcontrol,
 569			       struct snd_ctl_elem_value *ucontrol)
 570{
 571	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 572	struct conexant_spec *spec = codec->spec;
 573	ucontrol->value.integer.value[0] = spec->dc_enable;
 574	return 0;
 575}
 576
 577static int olpc_xo_dc_mode_put(struct snd_kcontrol *kcontrol,
 578			       struct snd_ctl_elem_value *ucontrol)
 579{
 580	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 581	struct conexant_spec *spec = codec->spec;
 582	int dc_enable = !!ucontrol->value.integer.value[0];
 583
 584	if (dc_enable == spec->dc_enable)
 585		return 0;
 586
 587	spec->dc_enable = dc_enable;
 588	olpc_xo_update_mic_pins(codec);
 589	olpc_xo_update_mic_boost(codec);
 590	return 1;
 591}
 592
 593static int olpc_xo_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
 594				    struct snd_ctl_elem_value *ucontrol)
 595{
 596	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 597	struct conexant_spec *spec = codec->spec;
 598	ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
 599	return 0;
 600}
 601
 602static int olpc_xo_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
 603				     struct snd_ctl_elem_info *uinfo)
 604{
 605	return snd_hda_input_mux_info(&olpc_xo_dc_bias, uinfo);
 606}
 607
 608static int olpc_xo_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
 609				    struct snd_ctl_elem_value *ucontrol)
 610{
 611	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 612	struct conexant_spec *spec = codec->spec;
 613	const struct hda_input_mux *imux = &olpc_xo_dc_bias;
 614	unsigned int idx;
 615
 616	idx = ucontrol->value.enumerated.item[0];
 617	if (idx >= imux->num_items)
 618		idx = imux->num_items - 1;
 619	if (spec->dc_input_bias == idx)
 620		return 0;
 621
 622	spec->dc_input_bias = idx;
 623	if (spec->dc_enable)
 624		olpc_xo_update_mic_pins(codec);
 625	return 1;
 626}
 627
 628static const struct snd_kcontrol_new olpc_xo_mixers[] = {
 629	{
 630		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 631		.name = "DC Mode Enable Switch",
 632		.info = snd_ctl_boolean_mono_info,
 633		.get = olpc_xo_dc_mode_get,
 634		.put = olpc_xo_dc_mode_put,
 635	},
 636	{
 637		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 638		.name = "DC Input Bias Enum",
 639		.info = olpc_xo_dc_bias_enum_info,
 640		.get = olpc_xo_dc_bias_enum_get,
 641		.put = olpc_xo_dc_bias_enum_put,
 642	},
 643	{}
 644};
 645
 646/* overriding mic boost put callback; update mic boost volume only when
 647 * DC mode is disabled
 648 */
 649static int olpc_xo_mic_boost_put(struct snd_kcontrol *kcontrol,
 650				 struct snd_ctl_elem_value *ucontrol)
 651{
 652	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
 653	struct conexant_spec *spec = codec->spec;
 654	int ret = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
 655	if (ret > 0 && spec->dc_enable)
 656		olpc_xo_update_mic_boost(codec);
 657	return ret;
 658}
 659
 660static void cxt_fixup_olpc_xo(struct hda_codec *codec,
 661				    const struct hda_fixup *fix, int action)
 662{
 663	struct conexant_spec *spec = codec->spec;
 664	struct snd_kcontrol_new *kctl;
 665	int i;
 666
 667	if (action != HDA_FIXUP_ACT_PROBE)
 668		return;
 669
 670	spec->gen.mic_autoswitch_hook = olpc_xo_automic;
 671	spec->gen.pcm_capture_hook = olpc_xo_capture_hook;
 672	spec->dc_mode_path = snd_hda_add_new_path(codec, 0x1e, 0x14, 0);
 673
 674	snd_hda_add_new_ctls(codec, olpc_xo_mixers);
 675
 676	/* OLPC's microphone port is DC coupled for use with external sensors,
 677	 * therefore we use a 50% mic bias in order to center the input signal
 678	 * with the DC input range of the codec.
 679	 */
 680	snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50);
 681
 682	/* override mic boost control */
 683	snd_array_for_each(&spec->gen.kctls, i, kctl) {
 684		if (!strcmp(kctl->name, "Mic Boost Volume")) {
 685			kctl->put = olpc_xo_mic_boost_put;
 686			break;
 687		}
 688	}
 689}
 690
 691static void cxt_fixup_mute_led_eapd(struct hda_codec *codec,
 692				    const struct hda_fixup *fix, int action)
 693{
 694	struct conexant_spec *spec = codec->spec;
 695
 696	if (action == HDA_FIXUP_ACT_PRE_PROBE) {
 697		spec->mute_led_eapd = 0x1b;
 698		spec->dynamic_eapd = true;
 699		snd_hda_gen_add_mute_led_cdev(codec, cx_auto_vmaster_mute_led);
 700	}
 701}
 702
 703/*
 704 * Fix max input level on mixer widget to 0dB
 705 * (originally it has 0x2b steps with 0dB offset 0x14)
 706 */
 707static void cxt_fixup_cap_mix_amp(struct hda_codec *codec,
 708				  const struct hda_fixup *fix, int action)
 709{
 710	snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
 711				  (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
 712				  (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
 713				  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
 714				  (1 << AC_AMPCAP_MUTE_SHIFT));
 715}
 716
 717/*
 718 * Fix max input level on mixer widget to 0dB
 719 * (originally it has 0x1e steps with 0 dB offset 0x17)
 720 */
 721static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec,
 722				  const struct hda_fixup *fix, int action)
 723{
 724	snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT,
 725				  (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
 726				  (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
 727				  (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
 728				  (1 << AC_AMPCAP_MUTE_SHIFT));
 729}
 730
 731static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
 732				       const struct hda_fixup *fix,
 733				       int action)
 734{
 735	/* the mic pin (0x19) doesn't give an unsolicited event;
 736	 * probe the mic pin together with the headphone pin (0x16)
 737	 */
 738	if (action == HDA_FIXUP_ACT_PROBE)
 739		snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
 740}
 741
 742/* update LED status via GPIO */
 743static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
 744				bool led_on)
 745{
 746	struct conexant_spec *spec = codec->spec;
 747	unsigned int oldval = spec->gpio_led;
 748
 749	if (spec->mute_led_polarity)
 750		led_on = !led_on;
 751
 752	if (led_on)
 753		spec->gpio_led |= mask;
 754	else
 755		spec->gpio_led &= ~mask;
 756	codec_dbg(codec, "mask:%d enabled:%d gpio_led:%d\n",
 757			mask, led_on, spec->gpio_led);
 758	if (spec->gpio_led != oldval)
 759		snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
 760				    spec->gpio_led);
 761}
 762
 763/* turn on/off mute LED via GPIO per vmaster hook */
 764static int cxt_gpio_mute_update(struct led_classdev *led_cdev,
 765				enum led_brightness brightness)
 766{
 767	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
 768	struct conexant_spec *spec = codec->spec;
 769
 770	cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, brightness);
 771	return 0;
 772}
 773
 774/* turn on/off mic-mute LED via GPIO per capture hook */
 775static int cxt_gpio_micmute_update(struct led_classdev *led_cdev,
 776				   enum led_brightness brightness)
 777{
 778	struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
 779	struct conexant_spec *spec = codec->spec;
 780
 781	cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, brightness);
 782	return 0;
 783}
 784
 785static void cxt_setup_mute_led(struct hda_codec *codec,
 786			       unsigned int mute, unsigned int mic_mute)
 
 787{
 788	struct conexant_spec *spec = codec->spec;
 
 
 
 
 
 789
 790	spec->gpio_led = 0;
 791	spec->mute_led_polarity = 0;
 792	if (mute) {
 793		snd_hda_gen_add_mute_led_cdev(codec, cxt_gpio_mute_update);
 794		spec->gpio_mute_led_mask = mute;
 795	}
 796	if (mic_mute) {
 
 797		snd_hda_gen_add_micmute_led_cdev(codec, cxt_gpio_micmute_update);
 798		spec->gpio_mic_led_mask = mic_mute;
 799	}
 
 
 
 
 800}
 801
 802static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
 803				const struct hda_fixup *fix, int action)
 804{
 805	if (action == HDA_FIXUP_ACT_PRE_PROBE)
 806		cxt_setup_mute_led(codec, 0x01, 0x02);
 807}
 808
 809static void cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec,
 810					const struct hda_fixup *fix, int action)
 811{
 812	if (action == HDA_FIXUP_ACT_PRE_PROBE)
 813		cxt_setup_mute_led(codec, 0x10, 0x20);
 814}
 815
 816/* ThinkPad X200 & co with cxt5051 */
 817static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
 818	{ 0x16, 0x042140ff }, /* HP (seq# overridden) */
 819	{ 0x17, 0x21a11000 }, /* dock-mic */
 820	{ 0x19, 0x2121103f }, /* dock-HP */
 821	{ 0x1c, 0x21440100 }, /* dock SPDIF out */
 822	{}
 823};
 824
 825/* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
 826static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = {
 827	{ 0x19, 0x042110ff }, /* HP (seq# overridden) */
 828	{ 0x1a, 0x21a190f0 }, /* dock-mic */
 829	{ 0x1c, 0x212140ff }, /* dock-HP */
 830	{}
 831};
 832
 833/* Lemote A1004/A1205 with cxt5066 */
 834static const struct hda_pintbl cxt_pincfg_lemote[] = {
 835	{ 0x1a, 0x90a10020 }, /* Internal mic */
 836	{ 0x1b, 0x03a11020 }, /* External mic */
 837	{ 0x1d, 0x400101f0 }, /* Not used */
 838	{ 0x1e, 0x40a701f0 }, /* Not used */
 839	{ 0x20, 0x404501f0 }, /* Not used */
 840	{ 0x22, 0x404401f0 }, /* Not used */
 841	{ 0x23, 0x40a701f0 }, /* Not used */
 842	{}
 843};
 844
 845/* SuoWoSi/South-holding JS201D with sn6140 */
 846static const struct hda_pintbl cxt_pincfg_sws_js201d[] = {
 847	{ 0x16, 0x03211040 }, /* hp out */
 848	{ 0x17, 0x91170110 }, /* SPK/Class_D */
 849	{ 0x18, 0x95a70130 }, /* Internal mic */
 850	{ 0x19, 0x03a11020 }, /* Headset Mic */
 851	{ 0x1a, 0x40f001f0 }, /* Not used */
 852	{ 0x21, 0x40f001f0 }, /* Not used */
 853	{}
 854};
 855
 856static const struct hda_fixup cxt_fixups[] = {
 857	[CXT_PINCFG_LENOVO_X200] = {
 858		.type = HDA_FIXUP_PINS,
 859		.v.pins = cxt_pincfg_lenovo_x200,
 860	},
 861	[CXT_PINCFG_LENOVO_TP410] = {
 862		.type = HDA_FIXUP_PINS,
 863		.v.pins = cxt_pincfg_lenovo_tp410,
 864		.chained = true,
 865		.chain_id = CXT_FIXUP_THINKPAD_ACPI,
 866	},
 867	[CXT_PINCFG_LEMOTE_A1004] = {
 868		.type = HDA_FIXUP_PINS,
 869		.chained = true,
 870		.chain_id = CXT_FIXUP_INC_MIC_BOOST,
 871		.v.pins = cxt_pincfg_lemote,
 872	},
 873	[CXT_PINCFG_LEMOTE_A1205] = {
 874		.type = HDA_FIXUP_PINS,
 875		.v.pins = cxt_pincfg_lemote,
 876	},
 877	[CXT_PINCFG_COMPAQ_CQ60] = {
 878		.type = HDA_FIXUP_PINS,
 879		.v.pins = (const struct hda_pintbl[]) {
 880			/* 0x17 was falsely set up as a mic, it should 0x1d */
 881			{ 0x17, 0x400001f0 },
 882			{ 0x1d, 0x97a70120 },
 883			{ }
 884		}
 885	},
 886	[CXT_FIXUP_STEREO_DMIC] = {
 887		.type = HDA_FIXUP_FUNC,
 888		.v.func = cxt_fixup_stereo_dmic,
 889	},
 890	[CXT_PINCFG_LENOVO_NOTEBOOK] = {
 891		.type = HDA_FIXUP_PINS,
 892		.v.pins = (const struct hda_pintbl[]) {
 893			{ 0x1a, 0x05d71030 },
 894			{ }
 895		},
 896		.chain_id = CXT_FIXUP_STEREO_DMIC,
 897	},
 898	[CXT_FIXUP_INC_MIC_BOOST] = {
 899		.type = HDA_FIXUP_FUNC,
 900		.v.func = cxt5066_increase_mic_boost,
 901	},
 902	[CXT_FIXUP_HEADPHONE_MIC_PIN] = {
 903		.type = HDA_FIXUP_PINS,
 904		.chained = true,
 905		.chain_id = CXT_FIXUP_HEADPHONE_MIC,
 906		.v.pins = (const struct hda_pintbl[]) {
 907			{ 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
 908			{ }
 909		}
 910	},
 911	[CXT_FIXUP_HEADPHONE_MIC] = {
 912		.type = HDA_FIXUP_FUNC,
 913		.v.func = cxt_fixup_headphone_mic,
 914	},
 915	[CXT_FIXUP_GPIO1] = {
 916		.type = HDA_FIXUP_VERBS,
 917		.v.verbs = (const struct hda_verb[]) {
 918			{ 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
 919			{ 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
 920			{ 0x01, AC_VERB_SET_GPIO_DATA, 0x01 },
 921			{ }
 922		},
 923	},
 924	[CXT_FIXUP_ASPIRE_DMIC] = {
 925		.type = HDA_FIXUP_FUNC,
 926		.v.func = cxt_fixup_stereo_dmic,
 927		.chained = true,
 928		.chain_id = CXT_FIXUP_GPIO1,
 929	},
 930	[CXT_FIXUP_THINKPAD_ACPI] = {
 931		.type = HDA_FIXUP_FUNC,
 932		.v.func = hda_fixup_thinkpad_acpi,
 933	},
 934	[CXT_FIXUP_OLPC_XO] = {
 935		.type = HDA_FIXUP_FUNC,
 936		.v.func = cxt_fixup_olpc_xo,
 937	},
 938	[CXT_FIXUP_CAP_MIX_AMP] = {
 939		.type = HDA_FIXUP_FUNC,
 940		.v.func = cxt_fixup_cap_mix_amp,
 941	},
 942	[CXT_FIXUP_TOSHIBA_P105] = {
 943		.type = HDA_FIXUP_PINS,
 944		.v.pins = (const struct hda_pintbl[]) {
 945			{ 0x10, 0x961701f0 }, /* speaker/hp */
 946			{ 0x12, 0x02a1901e }, /* ext mic */
 947			{ 0x14, 0x95a70110 }, /* int mic */
 948			{}
 949		},
 950	},
 951	[CXT_FIXUP_HP_530] = {
 952		.type = HDA_FIXUP_PINS,
 953		.v.pins = (const struct hda_pintbl[]) {
 954			{ 0x12, 0x90a60160 }, /* int mic */
 955			{}
 956		},
 957		.chained = true,
 958		.chain_id = CXT_FIXUP_CAP_MIX_AMP,
 959	},
 960	[CXT_FIXUP_CAP_MIX_AMP_5047] = {
 961		.type = HDA_FIXUP_FUNC,
 962		.v.func = cxt_fixup_cap_mix_amp_5047,
 963	},
 964	[CXT_FIXUP_MUTE_LED_EAPD] = {
 965		.type = HDA_FIXUP_FUNC,
 966		.v.func = cxt_fixup_mute_led_eapd,
 967	},
 968	[CXT_FIXUP_HP_DOCK] = {
 969		.type = HDA_FIXUP_PINS,
 970		.v.pins = (const struct hda_pintbl[]) {
 971			{ 0x16, 0x21011020 }, /* line-out */
 972			{ 0x18, 0x2181103f }, /* line-in */
 973			{ }
 974		},
 975		.chained = true,
 976		.chain_id = CXT_FIXUP_MUTE_LED_GPIO,
 977	},
 978	[CXT_FIXUP_HP_SPECTRE] = {
 979		.type = HDA_FIXUP_PINS,
 980		.v.pins = (const struct hda_pintbl[]) {
 981			/* enable NID 0x1d for the speaker on top */
 982			{ 0x1d, 0x91170111 },
 983			{ }
 984		}
 985	},
 986	[CXT_FIXUP_HP_GATE_MIC] = {
 987		.type = HDA_FIXUP_FUNC,
 988		.v.func = cxt_fixup_hp_gate_mic_jack,
 989	},
 990	[CXT_FIXUP_MUTE_LED_GPIO] = {
 991		.type = HDA_FIXUP_FUNC,
 992		.v.func = cxt_fixup_mute_led_gpio,
 993	},
 994	[CXT_FIXUP_HP_ZBOOK_MUTE_LED] = {
 995		.type = HDA_FIXUP_FUNC,
 996		.v.func = cxt_fixup_hp_zbook_mute_led,
 997	},
 998	[CXT_FIXUP_HEADSET_MIC] = {
 999		.type = HDA_FIXUP_FUNC,
1000		.v.func = cxt_fixup_headset_mic,
1001	},
1002	[CXT_FIXUP_HP_MIC_NO_PRESENCE] = {
1003		.type = HDA_FIXUP_PINS,
1004		.v.pins = (const struct hda_pintbl[]) {
1005			{ 0x1a, 0x02a1113c },
1006			{ }
1007		},
1008		.chained = true,
1009		.chain_id = CXT_FIXUP_HEADSET_MIC,
1010	},
1011	[CXT_PINCFG_SWS_JS201D] = {
1012		.type = HDA_FIXUP_PINS,
1013		.v.pins = cxt_pincfg_sws_js201d,
1014	},
1015};
1016
1017static const struct snd_pci_quirk cxt5045_fixups[] = {
1018	SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530),
1019	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105),
1020	/* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
1021	 * really bad sound over 0dB on NID 0x17.
1022	 */
1023	SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP),
1024	SND_PCI_QUIRK_VENDOR(0x1631, "Packard Bell", CXT_FIXUP_CAP_MIX_AMP),
1025	SND_PCI_QUIRK_VENDOR(0x1734, "Fujitsu", CXT_FIXUP_CAP_MIX_AMP),
1026	SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT_FIXUP_CAP_MIX_AMP),
1027	{}
1028};
1029
1030static const struct hda_model_fixup cxt5045_fixup_models[] = {
1031	{ .id = CXT_FIXUP_CAP_MIX_AMP, .name = "cap-mix-amp" },
1032	{ .id = CXT_FIXUP_TOSHIBA_P105, .name = "toshiba-p105" },
1033	{ .id = CXT_FIXUP_HP_530, .name = "hp-530" },
1034	{}
1035};
1036
1037static const struct snd_pci_quirk cxt5047_fixups[] = {
1038	/* HP laptops have really bad sound over 0 dB on NID 0x10.
1039	 */
1040	SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047),
1041	{}
1042};
1043
1044static const struct hda_model_fixup cxt5047_fixup_models[] = {
1045	{ .id = CXT_FIXUP_CAP_MIX_AMP_5047, .name = "cap-mix-amp" },
1046	{}
1047};
1048
1049static const struct snd_pci_quirk cxt5051_fixups[] = {
1050	SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60),
1051	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
1052	{}
1053};
1054
1055static const struct hda_model_fixup cxt5051_fixup_models[] = {
1056	{ .id = CXT_PINCFG_LENOVO_X200, .name = "lenovo-x200" },
1057	{}
1058};
1059
1060static const struct snd_pci_quirk cxt5066_fixups[] = {
1061	SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
1062	SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
1063	SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
1064	SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
1065	SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
1066	SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
 
 
 
 
 
1067	SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
1068	SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
1069	SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
1070	SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
1071	SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
 
1072	SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
1073	SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
1074	SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE),
1075	SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
1076	SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
1077	SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
1078	SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
1079	SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
1080	SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO),
1081	SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
1082	SND_PCI_QUIRK(0x103c, 0x844f, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
1083	SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE),
1084	SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
1085	SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE),
1086	SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE),
1087	SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
1088	SND_PCI_QUIRK(0x14f1, 0x0265, "SWS JS201D", CXT_PINCFG_SWS_JS201D),
1089	SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
1090	SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
1091	SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
1092	SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
1093	SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
1094	SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
1095	SND_PCI_QUIRK(0x17aa, 0x21d2, "Lenovo T420s", CXT_PINCFG_LENOVO_TP410),
1096	SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
1097	SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
1098	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
1099	SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
1100	SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
1101	SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
1102	/* NOTE: we'd need to extend the quirk for 17aa:3977 as the same
1103	 * PCI SSID is used on multiple Lenovo models
1104	 */
1105	SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
1106	SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
1107	SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
1108	SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI),
1109	SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
1110	SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205),
1111	{}
1112};
1113
1114static const struct hda_model_fixup cxt5066_fixup_models[] = {
1115	{ .id = CXT_FIXUP_STEREO_DMIC, .name = "stereo-dmic" },
1116	{ .id = CXT_FIXUP_GPIO1, .name = "gpio1" },
1117	{ .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" },
1118	{ .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" },
1119	{ .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" },
1120	{ .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" },
1121	{ .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" },
1122	{ .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
1123	{ .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
1124	{ .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
1125	{ .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
1126	{ .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" },
1127	{ .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
1128	{ .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" },
1129	{ .id = CXT_PINCFG_SWS_JS201D, .name = "sws-js201d" },
1130	{}
1131};
1132
1133/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
1134 * can be created (bko#42825)
1135 */
1136static void add_cx5051_fake_mutes(struct hda_codec *codec)
1137{
1138	struct conexant_spec *spec = codec->spec;
1139	static const hda_nid_t out_nids[] = {
1140		0x10, 0x11, 0
1141	};
1142	const hda_nid_t *p;
1143
1144	for (p = out_nids; *p; p++)
1145		snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT,
1146					  AC_AMPCAP_MIN_MUTE |
1147					  query_amp_caps(codec, *p, HDA_OUTPUT));
1148	spec->gen.dac_min_mute = true;
1149}
1150
1151static int patch_conexant_auto(struct hda_codec *codec)
1152{
1153	struct conexant_spec *spec;
1154	int err;
1155
1156	codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
1157
1158	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1159	if (!spec)
1160		return -ENOMEM;
1161	snd_hda_gen_spec_init(&spec->gen);
1162	codec->spec = spec;
1163	codec->patch_ops = cx_auto_patch_ops;
1164
1165	/* init cx8070/sn6140 flag and reset headset_present_flag */
1166	switch (codec->core.vendor_id) {
1167	case 0x14f11f86:
1168	case 0x14f11f87:
1169		spec->is_cx8070_sn6140 = true;
1170		spec->headset_present_flag = CX_HEADSET_NOPRESENT;
1171		break;
1172	}
1173
1174	cx_auto_parse_eapd(codec);
1175	spec->gen.own_eapd_ctl = 1;
1176
1177	switch (codec->core.vendor_id) {
1178	case 0x14f15045:
1179		codec->single_adc_amp = 1;
1180		spec->gen.mixer_nid = 0x17;
1181		spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
1182		snd_hda_pick_fixup(codec, cxt5045_fixup_models,
1183				   cxt5045_fixups, cxt_fixups);
1184		break;
1185	case 0x14f15047:
1186		codec->pin_amp_workaround = 1;
1187		spec->gen.mixer_nid = 0x19;
1188		spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
1189		snd_hda_pick_fixup(codec, cxt5047_fixup_models,
1190				   cxt5047_fixups, cxt_fixups);
1191		break;
1192	case 0x14f15051:
1193		add_cx5051_fake_mutes(codec);
1194		codec->pin_amp_workaround = 1;
1195		snd_hda_pick_fixup(codec, cxt5051_fixup_models,
1196				   cxt5051_fixups, cxt_fixups);
1197		break;
1198	case 0x14f15098:
1199		codec->pin_amp_workaround = 1;
1200		spec->gen.mixer_nid = 0x22;
1201		spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
1202		snd_hda_pick_fixup(codec, cxt5066_fixup_models,
1203				   cxt5066_fixups, cxt_fixups);
1204		break;
1205	case 0x14f150f2:
1206		codec->power_save_node = 1;
1207		fallthrough;
1208	default:
1209		codec->pin_amp_workaround = 1;
1210		snd_hda_pick_fixup(codec, cxt5066_fixup_models,
1211				   cxt5066_fixups, cxt_fixups);
1212		break;
1213	}
1214
1215	if (!spec->gen.vmaster_mute.hook && spec->dynamic_eapd)
1216		spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook;
1217
1218	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1219
1220	err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
1221				       spec->parse_flags);
1222	if (err < 0)
1223		goto error;
1224
1225	err = cx_auto_parse_beep(codec);
1226	if (err < 0)
1227		goto error;
1228
1229	err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
1230	if (err < 0)
1231		goto error;
1232
1233	/* Some laptops with Conexant chips show stalls in S3 resume,
1234	 * which falls into the single-cmd mode.
1235	 * Better to make reset, then.
1236	 */
1237	if (!codec->bus->core.sync_write) {
1238		codec_info(codec,
1239			   "Enable sync_write for stable communication\n");
1240		codec->bus->core.sync_write = 1;
1241		codec->bus->allow_bus_reset = 1;
1242	}
1243
1244	snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
1245
1246	return 0;
1247
1248 error:
1249	cx_auto_free(codec);
1250	return err;
1251}
1252
1253/*
1254 */
1255
1256static const struct hda_device_id snd_hda_id_conexant[] = {
1257	HDA_CODEC_ENTRY(0x14f11f86, "CX8070", patch_conexant_auto),
1258	HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto),
1259	HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
1260	HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto),
1261	HDA_CODEC_ENTRY(0x14f120d1, "SN6180", patch_conexant_auto),
1262	HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
1263	HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
1264	HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
1265	HDA_CODEC_ENTRY(0x14f15066, "CX20582 (Pebble)", patch_conexant_auto),
1266	HDA_CODEC_ENTRY(0x14f15067, "CX20583 (Pebble HSF)", patch_conexant_auto),
1267	HDA_CODEC_ENTRY(0x14f15068, "CX20584", patch_conexant_auto),
1268	HDA_CODEC_ENTRY(0x14f15069, "CX20585", patch_conexant_auto),
1269	HDA_CODEC_ENTRY(0x14f1506c, "CX20588", patch_conexant_auto),
1270	HDA_CODEC_ENTRY(0x14f1506e, "CX20590", patch_conexant_auto),
1271	HDA_CODEC_ENTRY(0x14f15097, "CX20631", patch_conexant_auto),
1272	HDA_CODEC_ENTRY(0x14f15098, "CX20632", patch_conexant_auto),
1273	HDA_CODEC_ENTRY(0x14f150a1, "CX20641", patch_conexant_auto),
1274	HDA_CODEC_ENTRY(0x14f150a2, "CX20642", patch_conexant_auto),
1275	HDA_CODEC_ENTRY(0x14f150ab, "CX20651", patch_conexant_auto),
1276	HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto),
1277	HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto),
1278	HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto),
1279	HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto),
1280	HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto),
1281	HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto),
1282	HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto),
1283	HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto),
1284	HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto),
1285	HDA_CODEC_ENTRY(0x14f15111, "CX20753/4", patch_conexant_auto),
1286	HDA_CODEC_ENTRY(0x14f15113, "CX20755", patch_conexant_auto),
1287	HDA_CODEC_ENTRY(0x14f15114, "CX20756", patch_conexant_auto),
1288	HDA_CODEC_ENTRY(0x14f15115, "CX20757", patch_conexant_auto),
1289	HDA_CODEC_ENTRY(0x14f151d7, "CX20952", patch_conexant_auto),
1290	{} /* terminator */
1291};
1292MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_conexant);
1293
1294MODULE_LICENSE("GPL");
1295MODULE_DESCRIPTION("Conexant HD-audio codec");
1296
1297static struct hda_codec_driver conexant_driver = {
1298	.id = snd_hda_id_conexant,
1299};
1300
1301module_hda_codec_driver(conexant_driver);