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