• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/sound/pci/hda/
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