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