Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/pci/hda/patch_conexant.c
10820 views
1
/*
2
* HD audio interface patch for Conexant HDA audio codec
3
*
4
* Copyright (c) 2006 Pototskiy Akex <[email protected]>
5
* Takashi Iwai <[email protected]>
6
* Tobin Davis <[email protected]>
7
*
8
* This driver is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
12
*
13
* This driver is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
*/
22
23
#include <linux/init.h>
24
#include <linux/delay.h>
25
#include <linux/slab.h>
26
#include <linux/pci.h>
27
#include <sound/core.h>
28
#include <sound/jack.h>
29
30
#include "hda_codec.h"
31
#include "hda_local.h"
32
#include "hda_beep.h"
33
34
#define CXT_PIN_DIR_IN 0x00
35
#define CXT_PIN_DIR_OUT 0x01
36
#define CXT_PIN_DIR_INOUT 0x02
37
#define CXT_PIN_DIR_IN_NOMICBIAS 0x03
38
#define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04
39
40
#define CONEXANT_HP_EVENT 0x37
41
#define CONEXANT_MIC_EVENT 0x38
42
#define CONEXANT_LINE_EVENT 0x39
43
44
/* Conexant 5051 specific */
45
46
#define CXT5051_SPDIF_OUT 0x12
47
#define CXT5051_PORTB_EVENT 0x38
48
#define CXT5051_PORTC_EVENT 0x39
49
50
#define AUTO_MIC_PORTB (1 << 1)
51
#define AUTO_MIC_PORTC (1 << 2)
52
53
struct pin_dac_pair {
54
hda_nid_t pin;
55
hda_nid_t dac;
56
int type;
57
};
58
59
struct imux_info {
60
hda_nid_t pin; /* input pin NID */
61
hda_nid_t adc; /* connected ADC NID */
62
hda_nid_t boost; /* optional boost volume NID */
63
int index; /* corresponding to autocfg.input */
64
};
65
66
struct conexant_spec {
67
68
const struct snd_kcontrol_new *mixers[5];
69
int num_mixers;
70
hda_nid_t vmaster_nid;
71
72
const struct hda_verb *init_verbs[5]; /* initialization verbs
73
* don't forget NULL
74
* termination!
75
*/
76
unsigned int num_init_verbs;
77
78
/* playback */
79
struct hda_multi_out multiout; /* playback set-up
80
* max_channels, dacs must be set
81
* dig_out_nid and hp_nid are optional
82
*/
83
unsigned int cur_eapd;
84
unsigned int hp_present;
85
unsigned int line_present;
86
unsigned int auto_mic;
87
int auto_mic_ext; /* imux_pins[] index for ext mic */
88
int auto_mic_dock; /* imux_pins[] index for dock mic */
89
int auto_mic_int; /* imux_pins[] index for int mic */
90
unsigned int need_dac_fix;
91
hda_nid_t slave_dig_outs[2];
92
93
/* capture */
94
unsigned int num_adc_nids;
95
const hda_nid_t *adc_nids;
96
hda_nid_t dig_in_nid; /* digital-in NID; optional */
97
98
unsigned int cur_adc_idx;
99
hda_nid_t cur_adc;
100
unsigned int cur_adc_stream_tag;
101
unsigned int cur_adc_format;
102
103
const struct hda_pcm_stream *capture_stream;
104
105
/* capture source */
106
const struct hda_input_mux *input_mux;
107
const hda_nid_t *capsrc_nids;
108
unsigned int cur_mux[3];
109
110
/* channel model */
111
const struct hda_channel_mode *channel_mode;
112
int num_channel_mode;
113
114
/* PCM information */
115
struct hda_pcm pcm_rec[2]; /* used in build_pcms() */
116
117
unsigned int spdif_route;
118
119
/* dynamic controls, init_verbs and input_mux */
120
struct auto_pin_cfg autocfg;
121
struct hda_input_mux private_imux;
122
struct imux_info imux_info[HDA_MAX_NUM_INPUTS];
123
hda_nid_t private_adc_nids[HDA_MAX_NUM_INPUTS];
124
hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
125
struct pin_dac_pair dac_info[8];
126
int dac_info_filled;
127
128
unsigned int port_d_mode;
129
unsigned int auto_mute:1; /* used in auto-parser */
130
unsigned int detect_line:1; /* Line-out detection enabled */
131
unsigned int automute_lines:1; /* automute line-out as well */
132
unsigned int automute_hp_lo:1; /* both HP and LO available */
133
unsigned int dell_automute:1;
134
unsigned int dell_vostro:1;
135
unsigned int ideapad:1;
136
unsigned int thinkpad:1;
137
unsigned int hp_laptop:1;
138
unsigned int asus:1;
139
140
unsigned int adc_switching:1;
141
142
unsigned int ext_mic_present;
143
unsigned int recording;
144
void (*capture_prepare)(struct hda_codec *codec);
145
void (*capture_cleanup)(struct hda_codec *codec);
146
147
/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
148
* through the microphone jack.
149
* When the user enables this through a mixer switch, both internal and
150
* external microphones are disabled. Gain is fixed at 0dB. In this mode,
151
* we also allow the bias to be configured through a separate mixer
152
* control. */
153
unsigned int dc_enable;
154
unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */
155
unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */
156
157
unsigned int beep_amp;
158
};
159
160
static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo,
161
struct hda_codec *codec,
162
struct snd_pcm_substream *substream)
163
{
164
struct conexant_spec *spec = codec->spec;
165
return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
166
hinfo);
167
}
168
169
static int conexant_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
170
struct hda_codec *codec,
171
unsigned int stream_tag,
172
unsigned int format,
173
struct snd_pcm_substream *substream)
174
{
175
struct conexant_spec *spec = codec->spec;
176
return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
177
stream_tag,
178
format, substream);
179
}
180
181
static int conexant_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
182
struct hda_codec *codec,
183
struct snd_pcm_substream *substream)
184
{
185
struct conexant_spec *spec = codec->spec;
186
return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
187
}
188
189
/*
190
* Digital out
191
*/
192
static int conexant_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
193
struct hda_codec *codec,
194
struct snd_pcm_substream *substream)
195
{
196
struct conexant_spec *spec = codec->spec;
197
return snd_hda_multi_out_dig_open(codec, &spec->multiout);
198
}
199
200
static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
201
struct hda_codec *codec,
202
struct snd_pcm_substream *substream)
203
{
204
struct conexant_spec *spec = codec->spec;
205
return snd_hda_multi_out_dig_close(codec, &spec->multiout);
206
}
207
208
static int conexant_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
209
struct hda_codec *codec,
210
unsigned int stream_tag,
211
unsigned int format,
212
struct snd_pcm_substream *substream)
213
{
214
struct conexant_spec *spec = codec->spec;
215
return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
216
stream_tag,
217
format, substream);
218
}
219
220
/*
221
* Analog capture
222
*/
223
static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
224
struct hda_codec *codec,
225
unsigned int stream_tag,
226
unsigned int format,
227
struct snd_pcm_substream *substream)
228
{
229
struct conexant_spec *spec = codec->spec;
230
if (spec->capture_prepare)
231
spec->capture_prepare(codec);
232
snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
233
stream_tag, 0, format);
234
return 0;
235
}
236
237
static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
238
struct hda_codec *codec,
239
struct snd_pcm_substream *substream)
240
{
241
struct conexant_spec *spec = codec->spec;
242
snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
243
if (spec->capture_cleanup)
244
spec->capture_cleanup(codec);
245
return 0;
246
}
247
248
249
250
static const struct hda_pcm_stream conexant_pcm_analog_playback = {
251
.substreams = 1,
252
.channels_min = 2,
253
.channels_max = 2,
254
.nid = 0, /* fill later */
255
.ops = {
256
.open = conexant_playback_pcm_open,
257
.prepare = conexant_playback_pcm_prepare,
258
.cleanup = conexant_playback_pcm_cleanup
259
},
260
};
261
262
static const struct hda_pcm_stream conexant_pcm_analog_capture = {
263
.substreams = 1,
264
.channels_min = 2,
265
.channels_max = 2,
266
.nid = 0, /* fill later */
267
.ops = {
268
.prepare = conexant_capture_pcm_prepare,
269
.cleanup = conexant_capture_pcm_cleanup
270
},
271
};
272
273
274
static const struct hda_pcm_stream conexant_pcm_digital_playback = {
275
.substreams = 1,
276
.channels_min = 2,
277
.channels_max = 2,
278
.nid = 0, /* fill later */
279
.ops = {
280
.open = conexant_dig_playback_pcm_open,
281
.close = conexant_dig_playback_pcm_close,
282
.prepare = conexant_dig_playback_pcm_prepare
283
},
284
};
285
286
static const struct hda_pcm_stream conexant_pcm_digital_capture = {
287
.substreams = 1,
288
.channels_min = 2,
289
.channels_max = 2,
290
/* NID is set in alc_build_pcms */
291
};
292
293
static int cx5051_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
294
struct hda_codec *codec,
295
unsigned int stream_tag,
296
unsigned int format,
297
struct snd_pcm_substream *substream)
298
{
299
struct conexant_spec *spec = codec->spec;
300
spec->cur_adc = spec->adc_nids[spec->cur_adc_idx];
301
spec->cur_adc_stream_tag = stream_tag;
302
spec->cur_adc_format = format;
303
snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
304
return 0;
305
}
306
307
static int cx5051_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
308
struct hda_codec *codec,
309
struct snd_pcm_substream *substream)
310
{
311
struct conexant_spec *spec = codec->spec;
312
snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
313
spec->cur_adc = 0;
314
return 0;
315
}
316
317
static const struct hda_pcm_stream cx5051_pcm_analog_capture = {
318
.substreams = 1,
319
.channels_min = 2,
320
.channels_max = 2,
321
.nid = 0, /* fill later */
322
.ops = {
323
.prepare = cx5051_capture_pcm_prepare,
324
.cleanup = cx5051_capture_pcm_cleanup
325
},
326
};
327
328
static int conexant_build_pcms(struct hda_codec *codec)
329
{
330
struct conexant_spec *spec = codec->spec;
331
struct hda_pcm *info = spec->pcm_rec;
332
333
codec->num_pcms = 1;
334
codec->pcm_info = info;
335
336
info->name = "CONEXANT Analog";
337
info->stream[SNDRV_PCM_STREAM_PLAYBACK] = conexant_pcm_analog_playback;
338
info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
339
spec->multiout.max_channels;
340
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
341
spec->multiout.dac_nids[0];
342
if (spec->capture_stream)
343
info->stream[SNDRV_PCM_STREAM_CAPTURE] = *spec->capture_stream;
344
else {
345
if (codec->vendor_id == 0x14f15051)
346
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
347
cx5051_pcm_analog_capture;
348
else {
349
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
350
conexant_pcm_analog_capture;
351
info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
352
spec->num_adc_nids;
353
}
354
}
355
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
356
357
if (spec->multiout.dig_out_nid) {
358
info++;
359
codec->num_pcms++;
360
info->name = "Conexant Digital";
361
info->pcm_type = HDA_PCM_TYPE_SPDIF;
362
info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
363
conexant_pcm_digital_playback;
364
info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
365
spec->multiout.dig_out_nid;
366
if (spec->dig_in_nid) {
367
info->stream[SNDRV_PCM_STREAM_CAPTURE] =
368
conexant_pcm_digital_capture;
369
info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
370
spec->dig_in_nid;
371
}
372
if (spec->slave_dig_outs[0])
373
codec->slave_dig_outs = spec->slave_dig_outs;
374
}
375
376
return 0;
377
}
378
379
static int conexant_mux_enum_info(struct snd_kcontrol *kcontrol,
380
struct snd_ctl_elem_info *uinfo)
381
{
382
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
383
struct conexant_spec *spec = codec->spec;
384
385
return snd_hda_input_mux_info(spec->input_mux, uinfo);
386
}
387
388
static int conexant_mux_enum_get(struct snd_kcontrol *kcontrol,
389
struct snd_ctl_elem_value *ucontrol)
390
{
391
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
392
struct conexant_spec *spec = codec->spec;
393
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
394
395
ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
396
return 0;
397
}
398
399
static int conexant_mux_enum_put(struct snd_kcontrol *kcontrol,
400
struct snd_ctl_elem_value *ucontrol)
401
{
402
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
403
struct conexant_spec *spec = codec->spec;
404
unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
405
406
return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
407
spec->capsrc_nids[adc_idx],
408
&spec->cur_mux[adc_idx]);
409
}
410
411
static int conexant_init_jacks(struct hda_codec *codec)
412
{
413
#ifdef CONFIG_SND_HDA_INPUT_JACK
414
struct conexant_spec *spec = codec->spec;
415
int i;
416
417
for (i = 0; i < spec->num_init_verbs; i++) {
418
const struct hda_verb *hv;
419
420
hv = spec->init_verbs[i];
421
while (hv->nid) {
422
int err = 0;
423
switch (hv->param ^ AC_USRSP_EN) {
424
case CONEXANT_HP_EVENT:
425
err = snd_hda_input_jack_add(codec, hv->nid,
426
SND_JACK_HEADPHONE, NULL);
427
snd_hda_input_jack_report(codec, hv->nid);
428
break;
429
case CXT5051_PORTC_EVENT:
430
case CONEXANT_MIC_EVENT:
431
err = snd_hda_input_jack_add(codec, hv->nid,
432
SND_JACK_MICROPHONE, NULL);
433
snd_hda_input_jack_report(codec, hv->nid);
434
break;
435
}
436
if (err < 0)
437
return err;
438
++hv;
439
}
440
}
441
#endif /* CONFIG_SND_HDA_INPUT_JACK */
442
return 0;
443
}
444
445
static int conexant_init(struct hda_codec *codec)
446
{
447
struct conexant_spec *spec = codec->spec;
448
int i;
449
450
for (i = 0; i < spec->num_init_verbs; i++)
451
snd_hda_sequence_write(codec, spec->init_verbs[i]);
452
return 0;
453
}
454
455
static void conexant_free(struct hda_codec *codec)
456
{
457
snd_hda_input_jack_free(codec);
458
snd_hda_detach_beep_device(codec);
459
kfree(codec->spec);
460
}
461
462
static const struct snd_kcontrol_new cxt_capture_mixers[] = {
463
{
464
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
465
.name = "Capture Source",
466
.info = conexant_mux_enum_info,
467
.get = conexant_mux_enum_get,
468
.put = conexant_mux_enum_put
469
},
470
{}
471
};
472
473
#ifdef CONFIG_SND_HDA_INPUT_BEEP
474
/* additional beep mixers; the actual parameters are overwritten at build */
475
static const struct snd_kcontrol_new cxt_beep_mixer[] = {
476
HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
477
HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
478
{ } /* end */
479
};
480
#endif
481
482
static const char * const slave_vols[] = {
483
"Headphone Playback Volume",
484
"Speaker Playback Volume",
485
"Front Playback Volume",
486
"Surround Playback Volume",
487
"CLFE Playback Volume",
488
NULL
489
};
490
491
static const char * const slave_sws[] = {
492
"Headphone Playback Switch",
493
"Speaker Playback Switch",
494
"Front Playback Switch",
495
"Surround Playback Switch",
496
"CLFE Playback Switch",
497
NULL
498
};
499
500
static int conexant_build_controls(struct hda_codec *codec)
501
{
502
struct conexant_spec *spec = codec->spec;
503
unsigned int i;
504
int err;
505
506
for (i = 0; i < spec->num_mixers; i++) {
507
err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
508
if (err < 0)
509
return err;
510
}
511
if (spec->multiout.dig_out_nid) {
512
err = snd_hda_create_spdif_out_ctls(codec,
513
spec->multiout.dig_out_nid);
514
if (err < 0)
515
return err;
516
err = snd_hda_create_spdif_share_sw(codec,
517
&spec->multiout);
518
if (err < 0)
519
return err;
520
spec->multiout.share_spdif = 1;
521
}
522
if (spec->dig_in_nid) {
523
err = snd_hda_create_spdif_in_ctls(codec,spec->dig_in_nid);
524
if (err < 0)
525
return err;
526
}
527
528
/* if we have no master control, let's create it */
529
if (spec->vmaster_nid &&
530
!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
531
unsigned int vmaster_tlv[4];
532
snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
533
HDA_OUTPUT, vmaster_tlv);
534
err = snd_hda_add_vmaster(codec, "Master Playback Volume",
535
vmaster_tlv, slave_vols);
536
if (err < 0)
537
return err;
538
}
539
if (spec->vmaster_nid &&
540
!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
541
err = snd_hda_add_vmaster(codec, "Master Playback Switch",
542
NULL, slave_sws);
543
if (err < 0)
544
return err;
545
}
546
547
if (spec->input_mux) {
548
err = snd_hda_add_new_ctls(codec, cxt_capture_mixers);
549
if (err < 0)
550
return err;
551
}
552
553
#ifdef CONFIG_SND_HDA_INPUT_BEEP
554
/* create beep controls if needed */
555
if (spec->beep_amp) {
556
const struct snd_kcontrol_new *knew;
557
for (knew = cxt_beep_mixer; knew->name; knew++) {
558
struct snd_kcontrol *kctl;
559
kctl = snd_ctl_new1(knew, codec);
560
if (!kctl)
561
return -ENOMEM;
562
kctl->private_value = spec->beep_amp;
563
err = snd_hda_ctl_add(codec, 0, kctl);
564
if (err < 0)
565
return err;
566
}
567
}
568
#endif
569
570
return 0;
571
}
572
573
#ifdef CONFIG_SND_HDA_POWER_SAVE
574
static int conexant_suspend(struct hda_codec *codec, pm_message_t state)
575
{
576
snd_hda_shutup_pins(codec);
577
return 0;
578
}
579
#endif
580
581
static const struct hda_codec_ops conexant_patch_ops = {
582
.build_controls = conexant_build_controls,
583
.build_pcms = conexant_build_pcms,
584
.init = conexant_init,
585
.free = conexant_free,
586
#ifdef CONFIG_SND_HDA_POWER_SAVE
587
.suspend = conexant_suspend,
588
#endif
589
.reboot_notify = snd_hda_shutup_pins,
590
};
591
592
#ifdef CONFIG_SND_HDA_INPUT_BEEP
593
#define set_beep_amp(spec, nid, idx, dir) \
594
((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
595
#else
596
#define set_beep_amp(spec, nid, idx, dir) /* NOP */
597
#endif
598
599
static int patch_conexant_auto(struct hda_codec *codec);
600
/*
601
* EAPD control
602
* the private value = nid | (invert << 8)
603
*/
604
605
#define cxt_eapd_info snd_ctl_boolean_mono_info
606
607
static int cxt_eapd_get(struct snd_kcontrol *kcontrol,
608
struct snd_ctl_elem_value *ucontrol)
609
{
610
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
611
struct conexant_spec *spec = codec->spec;
612
int invert = (kcontrol->private_value >> 8) & 1;
613
if (invert)
614
ucontrol->value.integer.value[0] = !spec->cur_eapd;
615
else
616
ucontrol->value.integer.value[0] = spec->cur_eapd;
617
return 0;
618
619
}
620
621
static int cxt_eapd_put(struct snd_kcontrol *kcontrol,
622
struct snd_ctl_elem_value *ucontrol)
623
{
624
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
625
struct conexant_spec *spec = codec->spec;
626
int invert = (kcontrol->private_value >> 8) & 1;
627
hda_nid_t nid = kcontrol->private_value & 0xff;
628
unsigned int eapd;
629
630
eapd = !!ucontrol->value.integer.value[0];
631
if (invert)
632
eapd = !eapd;
633
if (eapd == spec->cur_eapd)
634
return 0;
635
636
spec->cur_eapd = eapd;
637
snd_hda_codec_write_cache(codec, nid,
638
0, AC_VERB_SET_EAPD_BTLENABLE,
639
eapd ? 0x02 : 0x00);
640
return 1;
641
}
642
643
/* controls for test mode */
644
#ifdef CONFIG_SND_DEBUG
645
646
#define CXT_EAPD_SWITCH(xname, nid, mask) \
647
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
648
.info = cxt_eapd_info, \
649
.get = cxt_eapd_get, \
650
.put = cxt_eapd_put, \
651
.private_value = nid | (mask<<16) }
652
653
654
655
static int conexant_ch_mode_info(struct snd_kcontrol *kcontrol,
656
struct snd_ctl_elem_info *uinfo)
657
{
658
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
659
struct conexant_spec *spec = codec->spec;
660
return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
661
spec->num_channel_mode);
662
}
663
664
static int conexant_ch_mode_get(struct snd_kcontrol *kcontrol,
665
struct snd_ctl_elem_value *ucontrol)
666
{
667
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
668
struct conexant_spec *spec = codec->spec;
669
return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
670
spec->num_channel_mode,
671
spec->multiout.max_channels);
672
}
673
674
static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol,
675
struct snd_ctl_elem_value *ucontrol)
676
{
677
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
678
struct conexant_spec *spec = codec->spec;
679
int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
680
spec->num_channel_mode,
681
&spec->multiout.max_channels);
682
if (err >= 0 && spec->need_dac_fix)
683
spec->multiout.num_dacs = spec->multiout.max_channels / 2;
684
return err;
685
}
686
687
#define CXT_PIN_MODE(xname, nid, dir) \
688
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \
689
.info = conexant_ch_mode_info, \
690
.get = conexant_ch_mode_get, \
691
.put = conexant_ch_mode_put, \
692
.private_value = nid | (dir<<16) }
693
694
#endif /* CONFIG_SND_DEBUG */
695
696
/* Conexant 5045 specific */
697
698
static const hda_nid_t cxt5045_dac_nids[1] = { 0x19 };
699
static const hda_nid_t cxt5045_adc_nids[1] = { 0x1a };
700
static const hda_nid_t cxt5045_capsrc_nids[1] = { 0x1a };
701
#define CXT5045_SPDIF_OUT 0x18
702
703
static const struct hda_channel_mode cxt5045_modes[1] = {
704
{ 2, NULL },
705
};
706
707
static const struct hda_input_mux cxt5045_capture_source = {
708
.num_items = 2,
709
.items = {
710
{ "IntMic", 0x1 },
711
{ "ExtMic", 0x2 },
712
}
713
};
714
715
static const struct hda_input_mux cxt5045_capture_source_benq = {
716
.num_items = 5,
717
.items = {
718
{ "IntMic", 0x1 },
719
{ "ExtMic", 0x2 },
720
{ "LineIn", 0x3 },
721
{ "CD", 0x4 },
722
{ "Mixer", 0x0 },
723
}
724
};
725
726
static const struct hda_input_mux cxt5045_capture_source_hp530 = {
727
.num_items = 2,
728
.items = {
729
{ "ExtMic", 0x1 },
730
{ "IntMic", 0x2 },
731
}
732
};
733
734
/* turn on/off EAPD (+ mute HP) as a master switch */
735
static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol,
736
struct snd_ctl_elem_value *ucontrol)
737
{
738
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
739
struct conexant_spec *spec = codec->spec;
740
unsigned int bits;
741
742
if (!cxt_eapd_put(kcontrol, ucontrol))
743
return 0;
744
745
/* toggle internal speakers mute depending of presence of
746
* the headphone jack
747
*/
748
bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE;
749
snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0,
750
HDA_AMP_MUTE, bits);
751
752
bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE;
753
snd_hda_codec_amp_stereo(codec, 0x11, HDA_OUTPUT, 0,
754
HDA_AMP_MUTE, bits);
755
return 1;
756
}
757
758
/* bind volumes of both NID 0x10 and 0x11 */
759
static const struct hda_bind_ctls cxt5045_hp_bind_master_vol = {
760
.ops = &snd_hda_bind_vol,
761
.values = {
762
HDA_COMPOSE_AMP_VAL(0x10, 3, 0, HDA_OUTPUT),
763
HDA_COMPOSE_AMP_VAL(0x11, 3, 0, HDA_OUTPUT),
764
0
765
},
766
};
767
768
/* toggle input of built-in and mic jack appropriately */
769
static void cxt5045_hp_automic(struct hda_codec *codec)
770
{
771
static const struct hda_verb mic_jack_on[] = {
772
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
773
{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
774
{}
775
};
776
static const struct hda_verb mic_jack_off[] = {
777
{0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
778
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
779
{}
780
};
781
unsigned int present;
782
783
present = snd_hda_jack_detect(codec, 0x12);
784
if (present)
785
snd_hda_sequence_write(codec, mic_jack_on);
786
else
787
snd_hda_sequence_write(codec, mic_jack_off);
788
}
789
790
791
/* mute internal speaker if HP is plugged */
792
static void cxt5045_hp_automute(struct hda_codec *codec)
793
{
794
struct conexant_spec *spec = codec->spec;
795
unsigned int bits;
796
797
spec->hp_present = snd_hda_jack_detect(codec, 0x11);
798
799
bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0;
800
snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0,
801
HDA_AMP_MUTE, bits);
802
}
803
804
/* unsolicited event for HP jack sensing */
805
static void cxt5045_hp_unsol_event(struct hda_codec *codec,
806
unsigned int res)
807
{
808
res >>= 26;
809
switch (res) {
810
case CONEXANT_HP_EVENT:
811
cxt5045_hp_automute(codec);
812
break;
813
case CONEXANT_MIC_EVENT:
814
cxt5045_hp_automic(codec);
815
break;
816
817
}
818
}
819
820
static const struct snd_kcontrol_new cxt5045_mixers[] = {
821
HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
822
HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
823
HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
824
HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
825
HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
826
HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
827
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
828
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
829
HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
830
HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
831
HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
832
{
833
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
834
.name = "Master Playback Switch",
835
.info = cxt_eapd_info,
836
.get = cxt_eapd_get,
837
.put = cxt5045_hp_master_sw_put,
838
.private_value = 0x10,
839
},
840
841
{}
842
};
843
844
static const struct snd_kcontrol_new cxt5045_benq_mixers[] = {
845
HDA_CODEC_VOLUME("CD Capture Volume", 0x1a, 0x04, HDA_INPUT),
846
HDA_CODEC_MUTE("CD Capture Switch", 0x1a, 0x04, HDA_INPUT),
847
HDA_CODEC_VOLUME("CD Playback Volume", 0x17, 0x4, HDA_INPUT),
848
HDA_CODEC_MUTE("CD Playback Switch", 0x17, 0x4, HDA_INPUT),
849
850
HDA_CODEC_VOLUME("Line In Capture Volume", 0x1a, 0x03, HDA_INPUT),
851
HDA_CODEC_MUTE("Line In Capture Switch", 0x1a, 0x03, HDA_INPUT),
852
HDA_CODEC_VOLUME("Line In Playback Volume", 0x17, 0x3, HDA_INPUT),
853
HDA_CODEC_MUTE("Line In Playback Switch", 0x17, 0x3, HDA_INPUT),
854
855
HDA_CODEC_VOLUME("Mixer Capture Volume", 0x1a, 0x0, HDA_INPUT),
856
HDA_CODEC_MUTE("Mixer Capture Switch", 0x1a, 0x0, HDA_INPUT),
857
858
{}
859
};
860
861
static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = {
862
HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x1a, 0x02, HDA_INPUT),
863
HDA_CODEC_MUTE("Internal Mic Capture Switch", 0x1a, 0x02, HDA_INPUT),
864
HDA_CODEC_VOLUME("Mic Capture Volume", 0x1a, 0x01, HDA_INPUT),
865
HDA_CODEC_MUTE("Mic Capture Switch", 0x1a, 0x01, HDA_INPUT),
866
HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT),
867
HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT),
868
HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT),
869
HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT),
870
HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT),
871
HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT),
872
HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol),
873
{
874
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
875
.name = "Master Playback Switch",
876
.info = cxt_eapd_info,
877
.get = cxt_eapd_get,
878
.put = cxt5045_hp_master_sw_put,
879
.private_value = 0x10,
880
},
881
882
{}
883
};
884
885
static const struct hda_verb cxt5045_init_verbs[] = {
886
/* Line in, Mic */
887
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
888
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
889
/* HP, Amp */
890
{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
891
{0x10, AC_VERB_SET_CONNECT_SEL, 0x1},
892
{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
893
{0x11, AC_VERB_SET_CONNECT_SEL, 0x1},
894
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
895
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
896
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
897
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
898
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
899
/* Record selector: Internal mic */
900
{0x1a, AC_VERB_SET_CONNECT_SEL,0x1},
901
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
902
AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
903
/* SPDIF route: PCM */
904
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
905
{ 0x13, AC_VERB_SET_CONNECT_SEL, 0x0 },
906
/* EAPD */
907
{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2 }, /* default on */
908
{ } /* end */
909
};
910
911
static const struct hda_verb cxt5045_benq_init_verbs[] = {
912
/* Internal Mic, Mic */
913
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
914
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 },
915
/* Line In,HP, Amp */
916
{0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
917
{0x10, AC_VERB_SET_CONNECT_SEL, 0x1},
918
{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
919
{0x11, AC_VERB_SET_CONNECT_SEL, 0x1},
920
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
921
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
922
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
923
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
924
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
925
/* Record selector: Internal mic */
926
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x1},
927
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE,
928
AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
929
/* SPDIF route: PCM */
930
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
931
{0x13, AC_VERB_SET_CONNECT_SEL, 0x0},
932
/* EAPD */
933
{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
934
{ } /* end */
935
};
936
937
static const struct hda_verb cxt5045_hp_sense_init_verbs[] = {
938
/* pin sensing on HP jack */
939
{0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
940
{ } /* end */
941
};
942
943
static const struct hda_verb cxt5045_mic_sense_init_verbs[] = {
944
/* pin sensing on HP jack */
945
{0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
946
{ } /* end */
947
};
948
949
#ifdef CONFIG_SND_DEBUG
950
/* Test configuration for debugging, modelled after the ALC260 test
951
* configuration.
952
*/
953
static const struct hda_input_mux cxt5045_test_capture_source = {
954
.num_items = 5,
955
.items = {
956
{ "MIXER", 0x0 },
957
{ "MIC1 pin", 0x1 },
958
{ "LINE1 pin", 0x2 },
959
{ "HP-OUT pin", 0x3 },
960
{ "CD pin", 0x4 },
961
},
962
};
963
964
static const struct snd_kcontrol_new cxt5045_test_mixer[] = {
965
966
/* Output controls */
967
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x10, 0x0, HDA_OUTPUT),
968
HDA_CODEC_MUTE("Speaker Playback Switch", 0x10, 0x0, HDA_OUTPUT),
969
HDA_CODEC_VOLUME("Node 11 Playback Volume", 0x11, 0x0, HDA_OUTPUT),
970
HDA_CODEC_MUTE("Node 11 Playback Switch", 0x11, 0x0, HDA_OUTPUT),
971
HDA_CODEC_VOLUME("Node 12 Playback Volume", 0x12, 0x0, HDA_OUTPUT),
972
HDA_CODEC_MUTE("Node 12 Playback Switch", 0x12, 0x0, HDA_OUTPUT),
973
974
/* Modes for retasking pin widgets */
975
CXT_PIN_MODE("HP-OUT pin mode", 0x11, CXT_PIN_DIR_INOUT),
976
CXT_PIN_MODE("LINE1 pin mode", 0x12, CXT_PIN_DIR_INOUT),
977
978
/* EAPD Switch Control */
979
CXT_EAPD_SWITCH("External Amplifier", 0x10, 0x0),
980
981
/* Loopback mixer controls */
982
983
HDA_CODEC_VOLUME("Mixer-1 Volume", 0x17, 0x0, HDA_INPUT),
984
HDA_CODEC_MUTE("Mixer-1 Switch", 0x17, 0x0, HDA_INPUT),
985
HDA_CODEC_VOLUME("Mixer-2 Volume", 0x17, 0x1, HDA_INPUT),
986
HDA_CODEC_MUTE("Mixer-2 Switch", 0x17, 0x1, HDA_INPUT),
987
HDA_CODEC_VOLUME("Mixer-3 Volume", 0x17, 0x2, HDA_INPUT),
988
HDA_CODEC_MUTE("Mixer-3 Switch", 0x17, 0x2, HDA_INPUT),
989
HDA_CODEC_VOLUME("Mixer-4 Volume", 0x17, 0x3, HDA_INPUT),
990
HDA_CODEC_MUTE("Mixer-4 Switch", 0x17, 0x3, HDA_INPUT),
991
HDA_CODEC_VOLUME("Mixer-5 Volume", 0x17, 0x4, HDA_INPUT),
992
HDA_CODEC_MUTE("Mixer-5 Switch", 0x17, 0x4, HDA_INPUT),
993
{
994
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
995
.name = "Input Source",
996
.info = conexant_mux_enum_info,
997
.get = conexant_mux_enum_get,
998
.put = conexant_mux_enum_put,
999
},
1000
/* Audio input controls */
1001
HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT),
1002
HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT),
1003
HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT),
1004
HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT),
1005
HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT),
1006
HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT),
1007
HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT),
1008
HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT),
1009
HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT),
1010
HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT),
1011
{ } /* end */
1012
};
1013
1014
static const struct hda_verb cxt5045_test_init_verbs[] = {
1015
/* Set connections */
1016
{ 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1017
{ 0x11, AC_VERB_SET_CONNECT_SEL, 0x0 },
1018
{ 0x12, AC_VERB_SET_CONNECT_SEL, 0x0 },
1019
/* Enable retasking pins as output, initially without power amp */
1020
{0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1021
{0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1022
1023
/* Disable digital (SPDIF) pins initially, but users can enable
1024
* them via a mixer switch. In the case of SPDIF-out, this initverb
1025
* payload also sets the generation to 0, output to be in "consumer"
1026
* PCM format, copyright asserted, no pre-emphasis and no validity
1027
* control.
1028
*/
1029
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1030
{0x18, AC_VERB_SET_DIGI_CONVERT_1, 0},
1031
1032
/* Start with output sum widgets muted and their output gains at min */
1033
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1034
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1035
1036
/* Unmute retasking pin widget output buffers since the default
1037
* state appears to be output. As the pin mode is changed by the
1038
* user the pin mode control will take care of enabling the pin's
1039
* input/output buffers as needed.
1040
*/
1041
{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1042
{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1043
1044
/* Mute capture amp left and right */
1045
{0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1046
1047
/* Set ADC connection select to match default mixer setting (mic1
1048
* pin)
1049
*/
1050
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
1051
{0x17, AC_VERB_SET_CONNECT_SEL, 0x00},
1052
1053
/* Mute all inputs to mixer widget (even unconnected ones) */
1054
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* Mixer pin */
1055
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* Mic1 pin */
1056
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* Line pin */
1057
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* HP pin */
1058
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
1059
1060
{ }
1061
};
1062
#endif
1063
1064
1065
/* initialize jack-sensing, too */
1066
static int cxt5045_init(struct hda_codec *codec)
1067
{
1068
conexant_init(codec);
1069
cxt5045_hp_automute(codec);
1070
return 0;
1071
}
1072
1073
1074
enum {
1075
CXT5045_LAPTOP_HPSENSE,
1076
CXT5045_LAPTOP_MICSENSE,
1077
CXT5045_LAPTOP_HPMICSENSE,
1078
CXT5045_BENQ,
1079
CXT5045_LAPTOP_HP530,
1080
#ifdef CONFIG_SND_DEBUG
1081
CXT5045_TEST,
1082
#endif
1083
CXT5045_AUTO,
1084
CXT5045_MODELS
1085
};
1086
1087
static const char * const cxt5045_models[CXT5045_MODELS] = {
1088
[CXT5045_LAPTOP_HPSENSE] = "laptop-hpsense",
1089
[CXT5045_LAPTOP_MICSENSE] = "laptop-micsense",
1090
[CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense",
1091
[CXT5045_BENQ] = "benq",
1092
[CXT5045_LAPTOP_HP530] = "laptop-hp530",
1093
#ifdef CONFIG_SND_DEBUG
1094
[CXT5045_TEST] = "test",
1095
#endif
1096
[CXT5045_AUTO] = "auto",
1097
};
1098
1099
static const struct snd_pci_quirk cxt5045_cfg_tbl[] = {
1100
SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530),
1101
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
1102
CXT5045_LAPTOP_HPSENSE),
1103
SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE),
1104
SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ),
1105
SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE),
1106
SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE),
1107
SND_PCI_QUIRK(0x1734, 0x110e, "Fujitsu V5505",
1108
CXT5045_LAPTOP_HPMICSENSE),
1109
SND_PCI_QUIRK(0x1509, 0x1e40, "FIC", CXT5045_LAPTOP_HPMICSENSE),
1110
SND_PCI_QUIRK(0x1509, 0x2f05, "FIC", CXT5045_LAPTOP_HPMICSENSE),
1111
SND_PCI_QUIRK(0x1509, 0x2f06, "FIC", CXT5045_LAPTOP_HPMICSENSE),
1112
SND_PCI_QUIRK_MASK(0x1631, 0xff00, 0xc100, "Packard Bell",
1113
CXT5045_LAPTOP_HPMICSENSE),
1114
SND_PCI_QUIRK(0x8086, 0x2111, "Conexant Reference board", CXT5045_LAPTOP_HPSENSE),
1115
{}
1116
};
1117
1118
static int patch_cxt5045(struct hda_codec *codec)
1119
{
1120
struct conexant_spec *spec;
1121
int board_config;
1122
1123
board_config = snd_hda_check_board_config(codec, CXT5045_MODELS,
1124
cxt5045_models,
1125
cxt5045_cfg_tbl);
1126
#if 0 /* use the old method just for safety */
1127
if (board_config < 0)
1128
board_config = CXT5045_AUTO;
1129
#endif
1130
if (board_config == CXT5045_AUTO)
1131
return patch_conexant_auto(codec);
1132
1133
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1134
if (!spec)
1135
return -ENOMEM;
1136
codec->spec = spec;
1137
codec->pin_amp_workaround = 1;
1138
1139
spec->multiout.max_channels = 2;
1140
spec->multiout.num_dacs = ARRAY_SIZE(cxt5045_dac_nids);
1141
spec->multiout.dac_nids = cxt5045_dac_nids;
1142
spec->multiout.dig_out_nid = CXT5045_SPDIF_OUT;
1143
spec->num_adc_nids = 1;
1144
spec->adc_nids = cxt5045_adc_nids;
1145
spec->capsrc_nids = cxt5045_capsrc_nids;
1146
spec->input_mux = &cxt5045_capture_source;
1147
spec->num_mixers = 1;
1148
spec->mixers[0] = cxt5045_mixers;
1149
spec->num_init_verbs = 1;
1150
spec->init_verbs[0] = cxt5045_init_verbs;
1151
spec->spdif_route = 0;
1152
spec->num_channel_mode = ARRAY_SIZE(cxt5045_modes);
1153
spec->channel_mode = cxt5045_modes;
1154
1155
set_beep_amp(spec, 0x16, 0, 1);
1156
1157
codec->patch_ops = conexant_patch_ops;
1158
1159
switch (board_config) {
1160
case CXT5045_LAPTOP_HPSENSE:
1161
codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
1162
spec->input_mux = &cxt5045_capture_source;
1163
spec->num_init_verbs = 2;
1164
spec->init_verbs[1] = cxt5045_hp_sense_init_verbs;
1165
spec->mixers[0] = cxt5045_mixers;
1166
codec->patch_ops.init = cxt5045_init;
1167
break;
1168
case CXT5045_LAPTOP_MICSENSE:
1169
codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
1170
spec->input_mux = &cxt5045_capture_source;
1171
spec->num_init_verbs = 2;
1172
spec->init_verbs[1] = cxt5045_mic_sense_init_verbs;
1173
spec->mixers[0] = cxt5045_mixers;
1174
codec->patch_ops.init = cxt5045_init;
1175
break;
1176
default:
1177
case CXT5045_LAPTOP_HPMICSENSE:
1178
codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
1179
spec->input_mux = &cxt5045_capture_source;
1180
spec->num_init_verbs = 3;
1181
spec->init_verbs[1] = cxt5045_hp_sense_init_verbs;
1182
spec->init_verbs[2] = cxt5045_mic_sense_init_verbs;
1183
spec->mixers[0] = cxt5045_mixers;
1184
codec->patch_ops.init = cxt5045_init;
1185
break;
1186
case CXT5045_BENQ:
1187
codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
1188
spec->input_mux = &cxt5045_capture_source_benq;
1189
spec->num_init_verbs = 1;
1190
spec->init_verbs[0] = cxt5045_benq_init_verbs;
1191
spec->mixers[0] = cxt5045_mixers;
1192
spec->mixers[1] = cxt5045_benq_mixers;
1193
spec->num_mixers = 2;
1194
codec->patch_ops.init = cxt5045_init;
1195
break;
1196
case CXT5045_LAPTOP_HP530:
1197
codec->patch_ops.unsol_event = cxt5045_hp_unsol_event;
1198
spec->input_mux = &cxt5045_capture_source_hp530;
1199
spec->num_init_verbs = 2;
1200
spec->init_verbs[1] = cxt5045_hp_sense_init_verbs;
1201
spec->mixers[0] = cxt5045_mixers_hp530;
1202
codec->patch_ops.init = cxt5045_init;
1203
break;
1204
#ifdef CONFIG_SND_DEBUG
1205
case CXT5045_TEST:
1206
spec->input_mux = &cxt5045_test_capture_source;
1207
spec->mixers[0] = cxt5045_test_mixer;
1208
spec->init_verbs[0] = cxt5045_test_init_verbs;
1209
break;
1210
1211
#endif
1212
}
1213
1214
switch (codec->subsystem_id >> 16) {
1215
case 0x103c:
1216
case 0x1631:
1217
case 0x1734:
1218
case 0x17aa:
1219
/* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
1220
* really bad sound over 0dB on NID 0x17. Fix max PCM level to
1221
* 0 dB (originally it has 0x2b steps with 0dB offset 0x14)
1222
*/
1223
snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
1224
(0x14 << AC_AMPCAP_OFFSET_SHIFT) |
1225
(0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1226
(0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1227
(1 << AC_AMPCAP_MUTE_SHIFT));
1228
break;
1229
}
1230
1231
if (spec->beep_amp)
1232
snd_hda_attach_beep_device(codec, spec->beep_amp);
1233
1234
return 0;
1235
}
1236
1237
1238
/* Conexant 5047 specific */
1239
#define CXT5047_SPDIF_OUT 0x11
1240
1241
static const hda_nid_t cxt5047_dac_nids[1] = { 0x10 }; /* 0x1c */
1242
static const hda_nid_t cxt5047_adc_nids[1] = { 0x12 };
1243
static const hda_nid_t cxt5047_capsrc_nids[1] = { 0x1a };
1244
1245
static const struct hda_channel_mode cxt5047_modes[1] = {
1246
{ 2, NULL },
1247
};
1248
1249
static const struct hda_input_mux cxt5047_toshiba_capture_source = {
1250
.num_items = 2,
1251
.items = {
1252
{ "ExtMic", 0x2 },
1253
{ "Line-In", 0x1 },
1254
}
1255
};
1256
1257
/* turn on/off EAPD (+ mute HP) as a master switch */
1258
static int cxt5047_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1259
struct snd_ctl_elem_value *ucontrol)
1260
{
1261
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1262
struct conexant_spec *spec = codec->spec;
1263
unsigned int bits;
1264
1265
if (!cxt_eapd_put(kcontrol, ucontrol))
1266
return 0;
1267
1268
/* toggle internal speakers mute depending of presence of
1269
* the headphone jack
1270
*/
1271
bits = (!spec->hp_present && spec->cur_eapd) ? 0 : HDA_AMP_MUTE;
1272
/* NOTE: Conexat codec needs the index for *OUTPUT* amp of
1273
* pin widgets unlike other codecs. In this case, we need to
1274
* set index 0x01 for the volume from the mixer amp 0x19.
1275
*/
1276
snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01,
1277
HDA_AMP_MUTE, bits);
1278
bits = spec->cur_eapd ? 0 : HDA_AMP_MUTE;
1279
snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
1280
HDA_AMP_MUTE, bits);
1281
return 1;
1282
}
1283
1284
/* mute internal speaker if HP is plugged */
1285
static void cxt5047_hp_automute(struct hda_codec *codec)
1286
{
1287
struct conexant_spec *spec = codec->spec;
1288
unsigned int bits;
1289
1290
spec->hp_present = snd_hda_jack_detect(codec, 0x13);
1291
1292
bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0;
1293
/* See the note in cxt5047_hp_master_sw_put */
1294
snd_hda_codec_amp_stereo(codec, 0x1d, HDA_OUTPUT, 0x01,
1295
HDA_AMP_MUTE, bits);
1296
}
1297
1298
/* toggle input of built-in and mic jack appropriately */
1299
static void cxt5047_hp_automic(struct hda_codec *codec)
1300
{
1301
static const struct hda_verb mic_jack_on[] = {
1302
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1303
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1304
{}
1305
};
1306
static const struct hda_verb mic_jack_off[] = {
1307
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
1308
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1309
{}
1310
};
1311
unsigned int present;
1312
1313
present = snd_hda_jack_detect(codec, 0x15);
1314
if (present)
1315
snd_hda_sequence_write(codec, mic_jack_on);
1316
else
1317
snd_hda_sequence_write(codec, mic_jack_off);
1318
}
1319
1320
/* unsolicited event for HP jack sensing */
1321
static void cxt5047_hp_unsol_event(struct hda_codec *codec,
1322
unsigned int res)
1323
{
1324
switch (res >> 26) {
1325
case CONEXANT_HP_EVENT:
1326
cxt5047_hp_automute(codec);
1327
break;
1328
case CONEXANT_MIC_EVENT:
1329
cxt5047_hp_automic(codec);
1330
break;
1331
}
1332
}
1333
1334
static const struct snd_kcontrol_new cxt5047_base_mixers[] = {
1335
HDA_CODEC_VOLUME("Mic Playback Volume", 0x19, 0x02, HDA_INPUT),
1336
HDA_CODEC_MUTE("Mic Playback Switch", 0x19, 0x02, HDA_INPUT),
1337
HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT),
1338
HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x03, HDA_INPUT),
1339
HDA_CODEC_MUTE("Capture Switch", 0x12, 0x03, HDA_INPUT),
1340
HDA_CODEC_VOLUME("PCM Volume", 0x10, 0x00, HDA_OUTPUT),
1341
HDA_CODEC_MUTE("PCM Switch", 0x10, 0x00, HDA_OUTPUT),
1342
{
1343
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1344
.name = "Master Playback Switch",
1345
.info = cxt_eapd_info,
1346
.get = cxt_eapd_get,
1347
.put = cxt5047_hp_master_sw_put,
1348
.private_value = 0x13,
1349
},
1350
1351
{}
1352
};
1353
1354
static const struct snd_kcontrol_new cxt5047_hp_spk_mixers[] = {
1355
/* See the note in cxt5047_hp_master_sw_put */
1356
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x01, HDA_OUTPUT),
1357
HDA_CODEC_VOLUME("Headphone Playback Volume", 0x13, 0x00, HDA_OUTPUT),
1358
{}
1359
};
1360
1361
static const struct snd_kcontrol_new cxt5047_hp_only_mixers[] = {
1362
HDA_CODEC_VOLUME("Master Playback Volume", 0x13, 0x00, HDA_OUTPUT),
1363
{ } /* end */
1364
};
1365
1366
static const struct hda_verb cxt5047_init_verbs[] = {
1367
/* Line in, Mic, Built-in Mic */
1368
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1369
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
1370
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_50 },
1371
/* HP, Speaker */
1372
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP },
1373
{0x13, AC_VERB_SET_CONNECT_SEL, 0x0}, /* mixer(0x19) */
1374
{0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mixer(0x19) */
1375
/* Record selector: Mic */
1376
{0x12, AC_VERB_SET_CONNECT_SEL,0x03},
1377
{0x19, AC_VERB_SET_AMP_GAIN_MUTE,
1378
AC_AMP_SET_INPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x17},
1379
{0x1A, AC_VERB_SET_CONNECT_SEL,0x02},
1380
{0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
1381
AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x00},
1382
{0x1A, AC_VERB_SET_AMP_GAIN_MUTE,
1383
AC_AMP_SET_OUTPUT|AC_AMP_SET_RIGHT|AC_AMP_SET_LEFT|0x03},
1384
/* SPDIF route: PCM */
1385
{ 0x18, AC_VERB_SET_CONNECT_SEL, 0x0 },
1386
/* Enable unsolicited events */
1387
{0x13, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
1388
{0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
1389
{ } /* end */
1390
};
1391
1392
/* configuration for Toshiba Laptops */
1393
static const struct hda_verb cxt5047_toshiba_init_verbs[] = {
1394
{0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x0}, /* default off */
1395
{}
1396
};
1397
1398
/* Test configuration for debugging, modelled after the ALC260 test
1399
* configuration.
1400
*/
1401
#ifdef CONFIG_SND_DEBUG
1402
static const struct hda_input_mux cxt5047_test_capture_source = {
1403
.num_items = 4,
1404
.items = {
1405
{ "LINE1 pin", 0x0 },
1406
{ "MIC1 pin", 0x1 },
1407
{ "MIC2 pin", 0x2 },
1408
{ "CD pin", 0x3 },
1409
},
1410
};
1411
1412
static const struct snd_kcontrol_new cxt5047_test_mixer[] = {
1413
1414
/* Output only controls */
1415
HDA_CODEC_VOLUME("OutAmp-1 Volume", 0x10, 0x0, HDA_OUTPUT),
1416
HDA_CODEC_MUTE("OutAmp-1 Switch", 0x10,0x0, HDA_OUTPUT),
1417
HDA_CODEC_VOLUME("OutAmp-2 Volume", 0x1c, 0x0, HDA_OUTPUT),
1418
HDA_CODEC_MUTE("OutAmp-2 Switch", 0x1c, 0x0, HDA_OUTPUT),
1419
HDA_CODEC_VOLUME("Speaker Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1420
HDA_CODEC_MUTE("Speaker Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1421
HDA_CODEC_VOLUME("HeadPhone Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1422
HDA_CODEC_MUTE("HeadPhone Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1423
HDA_CODEC_VOLUME("Line1-Out Playback Volume", 0x14, 0x0, HDA_OUTPUT),
1424
HDA_CODEC_MUTE("Line1-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT),
1425
HDA_CODEC_VOLUME("Line2-Out Playback Volume", 0x15, 0x0, HDA_OUTPUT),
1426
HDA_CODEC_MUTE("Line2-Out Playback Switch", 0x15, 0x0, HDA_OUTPUT),
1427
1428
/* Modes for retasking pin widgets */
1429
CXT_PIN_MODE("LINE1 pin mode", 0x14, CXT_PIN_DIR_INOUT),
1430
CXT_PIN_MODE("MIC1 pin mode", 0x15, CXT_PIN_DIR_INOUT),
1431
1432
/* EAPD Switch Control */
1433
CXT_EAPD_SWITCH("External Amplifier", 0x13, 0x0),
1434
1435
/* Loopback mixer controls */
1436
HDA_CODEC_VOLUME("MIC1 Playback Volume", 0x12, 0x01, HDA_INPUT),
1437
HDA_CODEC_MUTE("MIC1 Playback Switch", 0x12, 0x01, HDA_INPUT),
1438
HDA_CODEC_VOLUME("MIC2 Playback Volume", 0x12, 0x02, HDA_INPUT),
1439
HDA_CODEC_MUTE("MIC2 Playback Switch", 0x12, 0x02, HDA_INPUT),
1440
HDA_CODEC_VOLUME("LINE Playback Volume", 0x12, 0x0, HDA_INPUT),
1441
HDA_CODEC_MUTE("LINE Playback Switch", 0x12, 0x0, HDA_INPUT),
1442
HDA_CODEC_VOLUME("CD Playback Volume", 0x12, 0x04, HDA_INPUT),
1443
HDA_CODEC_MUTE("CD Playback Switch", 0x12, 0x04, HDA_INPUT),
1444
1445
HDA_CODEC_VOLUME("Capture-1 Volume", 0x19, 0x0, HDA_INPUT),
1446
HDA_CODEC_MUTE("Capture-1 Switch", 0x19, 0x0, HDA_INPUT),
1447
HDA_CODEC_VOLUME("Capture-2 Volume", 0x19, 0x1, HDA_INPUT),
1448
HDA_CODEC_MUTE("Capture-2 Switch", 0x19, 0x1, HDA_INPUT),
1449
HDA_CODEC_VOLUME("Capture-3 Volume", 0x19, 0x2, HDA_INPUT),
1450
HDA_CODEC_MUTE("Capture-3 Switch", 0x19, 0x2, HDA_INPUT),
1451
HDA_CODEC_VOLUME("Capture-4 Volume", 0x19, 0x3, HDA_INPUT),
1452
HDA_CODEC_MUTE("Capture-4 Switch", 0x19, 0x3, HDA_INPUT),
1453
{
1454
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1455
.name = "Input Source",
1456
.info = conexant_mux_enum_info,
1457
.get = conexant_mux_enum_get,
1458
.put = conexant_mux_enum_put,
1459
},
1460
HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT),
1461
1462
{ } /* end */
1463
};
1464
1465
static const struct hda_verb cxt5047_test_init_verbs[] = {
1466
/* Enable retasking pins as output, initially without power amp */
1467
{0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1468
{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1469
{0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1470
1471
/* Disable digital (SPDIF) pins initially, but users can enable
1472
* them via a mixer switch. In the case of SPDIF-out, this initverb
1473
* payload also sets the generation to 0, output to be in "consumer"
1474
* PCM format, copyright asserted, no pre-emphasis and no validity
1475
* control.
1476
*/
1477
{0x18, AC_VERB_SET_DIGI_CONVERT_1, 0},
1478
1479
/* Ensure mic1, mic2, line1 pin widgets take input from the
1480
* OUT1 sum bus when acting as an output.
1481
*/
1482
{0x1a, AC_VERB_SET_CONNECT_SEL, 0},
1483
{0x1b, AC_VERB_SET_CONNECT_SEL, 0},
1484
1485
/* Start with output sum widgets muted and their output gains at min */
1486
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1487
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
1488
1489
/* Unmute retasking pin widget output buffers since the default
1490
* state appears to be output. As the pin mode is changed by the
1491
* user the pin mode control will take care of enabling the pin's
1492
* input/output buffers as needed.
1493
*/
1494
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1495
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1496
{0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1497
1498
/* Mute capture amp left and right */
1499
{0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
1500
1501
/* Set ADC connection select to match default mixer setting (mic1
1502
* pin)
1503
*/
1504
{0x12, AC_VERB_SET_CONNECT_SEL, 0x00},
1505
1506
/* Mute all inputs to mixer widget (even unconnected ones) */
1507
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, /* mic1 pin */
1508
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, /* mic2 pin */
1509
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, /* line1 pin */
1510
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, /* line2 pin */
1511
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* CD pin */
1512
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, /* Beep-gen pin */
1513
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, /* Line-out pin */
1514
{0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, /* HP-pin pin */
1515
1516
{ }
1517
};
1518
#endif
1519
1520
1521
/* initialize jack-sensing, too */
1522
static int cxt5047_hp_init(struct hda_codec *codec)
1523
{
1524
conexant_init(codec);
1525
cxt5047_hp_automute(codec);
1526
return 0;
1527
}
1528
1529
1530
enum {
1531
CXT5047_LAPTOP, /* Laptops w/o EAPD support */
1532
CXT5047_LAPTOP_HP, /* Some HP laptops */
1533
CXT5047_LAPTOP_EAPD, /* Laptops with EAPD support */
1534
#ifdef CONFIG_SND_DEBUG
1535
CXT5047_TEST,
1536
#endif
1537
CXT5047_AUTO,
1538
CXT5047_MODELS
1539
};
1540
1541
static const char * const cxt5047_models[CXT5047_MODELS] = {
1542
[CXT5047_LAPTOP] = "laptop",
1543
[CXT5047_LAPTOP_HP] = "laptop-hp",
1544
[CXT5047_LAPTOP_EAPD] = "laptop-eapd",
1545
#ifdef CONFIG_SND_DEBUG
1546
[CXT5047_TEST] = "test",
1547
#endif
1548
[CXT5047_AUTO] = "auto",
1549
};
1550
1551
static const struct snd_pci_quirk cxt5047_cfg_tbl[] = {
1552
SND_PCI_QUIRK(0x103c, 0x30a5, "HP DV5200T/DV8000T", CXT5047_LAPTOP_HP),
1553
SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP DV Series",
1554
CXT5047_LAPTOP),
1555
SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P100", CXT5047_LAPTOP_EAPD),
1556
{}
1557
};
1558
1559
static int patch_cxt5047(struct hda_codec *codec)
1560
{
1561
struct conexant_spec *spec;
1562
int board_config;
1563
1564
board_config = snd_hda_check_board_config(codec, CXT5047_MODELS,
1565
cxt5047_models,
1566
cxt5047_cfg_tbl);
1567
#if 0 /* not enabled as default, as BIOS often broken for this codec */
1568
if (board_config < 0)
1569
board_config = CXT5047_AUTO;
1570
#endif
1571
if (board_config == CXT5047_AUTO)
1572
return patch_conexant_auto(codec);
1573
1574
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1575
if (!spec)
1576
return -ENOMEM;
1577
codec->spec = spec;
1578
codec->pin_amp_workaround = 1;
1579
1580
spec->multiout.max_channels = 2;
1581
spec->multiout.num_dacs = ARRAY_SIZE(cxt5047_dac_nids);
1582
spec->multiout.dac_nids = cxt5047_dac_nids;
1583
spec->multiout.dig_out_nid = CXT5047_SPDIF_OUT;
1584
spec->num_adc_nids = 1;
1585
spec->adc_nids = cxt5047_adc_nids;
1586
spec->capsrc_nids = cxt5047_capsrc_nids;
1587
spec->num_mixers = 1;
1588
spec->mixers[0] = cxt5047_base_mixers;
1589
spec->num_init_verbs = 1;
1590
spec->init_verbs[0] = cxt5047_init_verbs;
1591
spec->spdif_route = 0;
1592
spec->num_channel_mode = ARRAY_SIZE(cxt5047_modes),
1593
spec->channel_mode = cxt5047_modes,
1594
1595
codec->patch_ops = conexant_patch_ops;
1596
1597
switch (board_config) {
1598
case CXT5047_LAPTOP:
1599
spec->num_mixers = 2;
1600
spec->mixers[1] = cxt5047_hp_spk_mixers;
1601
codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
1602
break;
1603
case CXT5047_LAPTOP_HP:
1604
spec->num_mixers = 2;
1605
spec->mixers[1] = cxt5047_hp_only_mixers;
1606
codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
1607
codec->patch_ops.init = cxt5047_hp_init;
1608
break;
1609
case CXT5047_LAPTOP_EAPD:
1610
spec->input_mux = &cxt5047_toshiba_capture_source;
1611
spec->num_mixers = 2;
1612
spec->mixers[1] = cxt5047_hp_spk_mixers;
1613
spec->num_init_verbs = 2;
1614
spec->init_verbs[1] = cxt5047_toshiba_init_verbs;
1615
codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
1616
break;
1617
#ifdef CONFIG_SND_DEBUG
1618
case CXT5047_TEST:
1619
spec->input_mux = &cxt5047_test_capture_source;
1620
spec->mixers[0] = cxt5047_test_mixer;
1621
spec->init_verbs[0] = cxt5047_test_init_verbs;
1622
codec->patch_ops.unsol_event = cxt5047_hp_unsol_event;
1623
#endif
1624
}
1625
spec->vmaster_nid = 0x13;
1626
1627
switch (codec->subsystem_id >> 16) {
1628
case 0x103c:
1629
/* HP laptops have really bad sound over 0 dB on NID 0x10.
1630
* Fix max PCM level to 0 dB (originally it has 0x1e steps
1631
* with 0 dB offset 0x17)
1632
*/
1633
snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT,
1634
(0x17 << AC_AMPCAP_OFFSET_SHIFT) |
1635
(0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1636
(0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1637
(1 << AC_AMPCAP_MUTE_SHIFT));
1638
break;
1639
}
1640
1641
return 0;
1642
}
1643
1644
/* Conexant 5051 specific */
1645
static const hda_nid_t cxt5051_dac_nids[1] = { 0x10 };
1646
static const hda_nid_t cxt5051_adc_nids[2] = { 0x14, 0x15 };
1647
1648
static const struct hda_channel_mode cxt5051_modes[1] = {
1649
{ 2, NULL },
1650
};
1651
1652
static void cxt5051_update_speaker(struct hda_codec *codec)
1653
{
1654
struct conexant_spec *spec = codec->spec;
1655
unsigned int pinctl;
1656
/* headphone pin */
1657
pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0;
1658
snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
1659
pinctl);
1660
/* speaker pin */
1661
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
1662
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
1663
pinctl);
1664
/* on ideapad there is an aditional speaker (subwoofer) to mute */
1665
if (spec->ideapad)
1666
snd_hda_codec_write(codec, 0x1b, 0,
1667
AC_VERB_SET_PIN_WIDGET_CONTROL,
1668
pinctl);
1669
}
1670
1671
/* turn on/off EAPD (+ mute HP) as a master switch */
1672
static int cxt5051_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1673
struct snd_ctl_elem_value *ucontrol)
1674
{
1675
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1676
1677
if (!cxt_eapd_put(kcontrol, ucontrol))
1678
return 0;
1679
cxt5051_update_speaker(codec);
1680
return 1;
1681
}
1682
1683
/* toggle input of built-in and mic jack appropriately */
1684
static void cxt5051_portb_automic(struct hda_codec *codec)
1685
{
1686
struct conexant_spec *spec = codec->spec;
1687
unsigned int present;
1688
1689
if (!(spec->auto_mic & AUTO_MIC_PORTB))
1690
return;
1691
present = snd_hda_jack_detect(codec, 0x17);
1692
snd_hda_codec_write(codec, 0x14, 0,
1693
AC_VERB_SET_CONNECT_SEL,
1694
present ? 0x01 : 0x00);
1695
}
1696
1697
/* switch the current ADC according to the jack state */
1698
static void cxt5051_portc_automic(struct hda_codec *codec)
1699
{
1700
struct conexant_spec *spec = codec->spec;
1701
unsigned int present;
1702
hda_nid_t new_adc;
1703
1704
if (!(spec->auto_mic & AUTO_MIC_PORTC))
1705
return;
1706
present = snd_hda_jack_detect(codec, 0x18);
1707
if (present)
1708
spec->cur_adc_idx = 1;
1709
else
1710
spec->cur_adc_idx = 0;
1711
new_adc = spec->adc_nids[spec->cur_adc_idx];
1712
if (spec->cur_adc && spec->cur_adc != new_adc) {
1713
/* stream is running, let's swap the current ADC */
1714
__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
1715
spec->cur_adc = new_adc;
1716
snd_hda_codec_setup_stream(codec, new_adc,
1717
spec->cur_adc_stream_tag, 0,
1718
spec->cur_adc_format);
1719
}
1720
}
1721
1722
/* mute internal speaker if HP is plugged */
1723
static void cxt5051_hp_automute(struct hda_codec *codec)
1724
{
1725
struct conexant_spec *spec = codec->spec;
1726
1727
spec->hp_present = snd_hda_jack_detect(codec, 0x16);
1728
cxt5051_update_speaker(codec);
1729
}
1730
1731
/* unsolicited event for HP jack sensing */
1732
static void cxt5051_hp_unsol_event(struct hda_codec *codec,
1733
unsigned int res)
1734
{
1735
int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
1736
switch (res >> 26) {
1737
case CONEXANT_HP_EVENT:
1738
cxt5051_hp_automute(codec);
1739
break;
1740
case CXT5051_PORTB_EVENT:
1741
cxt5051_portb_automic(codec);
1742
break;
1743
case CXT5051_PORTC_EVENT:
1744
cxt5051_portc_automic(codec);
1745
break;
1746
}
1747
snd_hda_input_jack_report(codec, nid);
1748
}
1749
1750
static const struct snd_kcontrol_new cxt5051_playback_mixers[] = {
1751
HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
1752
{
1753
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1754
.name = "Master Playback Switch",
1755
.info = cxt_eapd_info,
1756
.get = cxt_eapd_get,
1757
.put = cxt5051_hp_master_sw_put,
1758
.private_value = 0x1a,
1759
},
1760
{}
1761
};
1762
1763
static const struct snd_kcontrol_new cxt5051_capture_mixers[] = {
1764
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
1765
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
1766
HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
1767
HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
1768
HDA_CODEC_VOLUME("Docking Mic Volume", 0x15, 0x00, HDA_INPUT),
1769
HDA_CODEC_MUTE("Docking Mic Switch", 0x15, 0x00, HDA_INPUT),
1770
{}
1771
};
1772
1773
static const struct snd_kcontrol_new cxt5051_hp_mixers[] = {
1774
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
1775
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
1776
HDA_CODEC_VOLUME("Mic Volume", 0x15, 0x00, HDA_INPUT),
1777
HDA_CODEC_MUTE("Mic Switch", 0x15, 0x00, HDA_INPUT),
1778
{}
1779
};
1780
1781
static const struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = {
1782
HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x00, HDA_INPUT),
1783
HDA_CODEC_MUTE("Capture Switch", 0x14, 0x00, HDA_INPUT),
1784
{}
1785
};
1786
1787
static const struct snd_kcontrol_new cxt5051_f700_mixers[] = {
1788
HDA_CODEC_VOLUME("Capture Volume", 0x14, 0x01, HDA_INPUT),
1789
HDA_CODEC_MUTE("Capture Switch", 0x14, 0x01, HDA_INPUT),
1790
{}
1791
};
1792
1793
static const struct snd_kcontrol_new cxt5051_toshiba_mixers[] = {
1794
HDA_CODEC_VOLUME("Internal Mic Volume", 0x14, 0x00, HDA_INPUT),
1795
HDA_CODEC_MUTE("Internal Mic Switch", 0x14, 0x00, HDA_INPUT),
1796
HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT),
1797
HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT),
1798
{}
1799
};
1800
1801
static const struct hda_verb cxt5051_init_verbs[] = {
1802
/* Line in, Mic */
1803
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1804
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1805
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1806
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1807
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1808
{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1809
/* SPK */
1810
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1811
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
1812
/* HP, Amp */
1813
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1814
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
1815
/* DAC1 */
1816
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1817
/* Record selector: Internal mic */
1818
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
1819
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
1820
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
1821
/* SPDIF route: PCM */
1822
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1823
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
1824
/* EAPD */
1825
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1826
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
1827
{ } /* end */
1828
};
1829
1830
static const struct hda_verb cxt5051_hp_dv6736_init_verbs[] = {
1831
/* Line in, Mic */
1832
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1833
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1834
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
1835
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
1836
/* SPK */
1837
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1838
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
1839
/* HP, Amp */
1840
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1841
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
1842
/* DAC1 */
1843
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1844
/* Record selector: Internal mic */
1845
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
1846
{0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
1847
/* SPDIF route: PCM */
1848
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
1849
/* EAPD */
1850
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1851
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
1852
{ } /* end */
1853
};
1854
1855
static const struct hda_verb cxt5051_lenovo_x200_init_verbs[] = {
1856
/* Line in, Mic */
1857
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1858
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1859
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1860
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1861
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
1862
{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1863
/* SPK */
1864
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1865
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
1866
/* HP, Amp */
1867
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1868
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
1869
/* Docking HP */
1870
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1871
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00},
1872
/* DAC1 */
1873
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1874
/* Record selector: Internal mic */
1875
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
1876
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
1877
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x44},
1878
/* SPDIF route: PCM */
1879
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* needed for W500 Advanced Mini Dock 250410 */
1880
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
1881
/* EAPD */
1882
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1883
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
1884
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
1885
{ } /* end */
1886
};
1887
1888
static const struct hda_verb cxt5051_f700_init_verbs[] = {
1889
/* Line in, Mic */
1890
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03},
1891
{0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1892
{0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
1893
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0},
1894
/* SPK */
1895
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1896
{0x1a, AC_VERB_SET_CONNECT_SEL, 0x00},
1897
/* HP, Amp */
1898
{0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
1899
{0x16, AC_VERB_SET_CONNECT_SEL, 0x00},
1900
/* DAC1 */
1901
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
1902
/* Record selector: Internal mic */
1903
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44},
1904
{0x14, AC_VERB_SET_CONNECT_SEL, 0x1},
1905
/* SPDIF route: PCM */
1906
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x0},
1907
/* EAPD */
1908
{0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
1909
{0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT},
1910
{ } /* end */
1911
};
1912
1913
static void cxt5051_init_mic_port(struct hda_codec *codec, hda_nid_t nid,
1914
unsigned int event)
1915
{
1916
snd_hda_codec_write(codec, nid, 0,
1917
AC_VERB_SET_UNSOLICITED_ENABLE,
1918
AC_USRSP_EN | event);
1919
snd_hda_input_jack_add(codec, nid, SND_JACK_MICROPHONE, NULL);
1920
snd_hda_input_jack_report(codec, nid);
1921
}
1922
1923
static const struct hda_verb cxt5051_ideapad_init_verbs[] = {
1924
/* Subwoofer */
1925
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
1926
{0x1b, AC_VERB_SET_CONNECT_SEL, 0x00},
1927
{ } /* end */
1928
};
1929
1930
/* initialize jack-sensing, too */
1931
static int cxt5051_init(struct hda_codec *codec)
1932
{
1933
struct conexant_spec *spec = codec->spec;
1934
1935
conexant_init(codec);
1936
conexant_init_jacks(codec);
1937
1938
if (spec->auto_mic & AUTO_MIC_PORTB)
1939
cxt5051_init_mic_port(codec, 0x17, CXT5051_PORTB_EVENT);
1940
if (spec->auto_mic & AUTO_MIC_PORTC)
1941
cxt5051_init_mic_port(codec, 0x18, CXT5051_PORTC_EVENT);
1942
1943
if (codec->patch_ops.unsol_event) {
1944
cxt5051_hp_automute(codec);
1945
cxt5051_portb_automic(codec);
1946
cxt5051_portc_automic(codec);
1947
}
1948
return 0;
1949
}
1950
1951
1952
enum {
1953
CXT5051_LAPTOP, /* Laptops w/ EAPD support */
1954
CXT5051_HP, /* no docking */
1955
CXT5051_HP_DV6736, /* HP without mic switch */
1956
CXT5051_LENOVO_X200, /* Lenovo X200 laptop, also used for Advanced Mini Dock 250410 */
1957
CXT5051_F700, /* HP Compaq Presario F700 */
1958
CXT5051_TOSHIBA, /* Toshiba M300 & co */
1959
CXT5051_IDEAPAD, /* Lenovo IdeaPad Y430 */
1960
CXT5051_AUTO, /* auto-parser */
1961
CXT5051_MODELS
1962
};
1963
1964
static const char *const cxt5051_models[CXT5051_MODELS] = {
1965
[CXT5051_LAPTOP] = "laptop",
1966
[CXT5051_HP] = "hp",
1967
[CXT5051_HP_DV6736] = "hp-dv6736",
1968
[CXT5051_LENOVO_X200] = "lenovo-x200",
1969
[CXT5051_F700] = "hp-700",
1970
[CXT5051_TOSHIBA] = "toshiba",
1971
[CXT5051_IDEAPAD] = "ideapad",
1972
[CXT5051_AUTO] = "auto",
1973
};
1974
1975
static const struct snd_pci_quirk cxt5051_cfg_tbl[] = {
1976
SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736),
1977
SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP),
1978
SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700),
1979
SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba M30x", CXT5051_TOSHIBA),
1980
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
1981
CXT5051_LAPTOP),
1982
SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP),
1983
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200),
1984
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo IdeaPad", CXT5051_IDEAPAD),
1985
{}
1986
};
1987
1988
static int patch_cxt5051(struct hda_codec *codec)
1989
{
1990
struct conexant_spec *spec;
1991
int board_config;
1992
1993
board_config = snd_hda_check_board_config(codec, CXT5051_MODELS,
1994
cxt5051_models,
1995
cxt5051_cfg_tbl);
1996
#if 0 /* use the old method just for safety */
1997
if (board_config < 0)
1998
board_config = CXT5051_AUTO;
1999
#endif
2000
if (board_config == CXT5051_AUTO)
2001
return patch_conexant_auto(codec);
2002
2003
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2004
if (!spec)
2005
return -ENOMEM;
2006
codec->spec = spec;
2007
codec->pin_amp_workaround = 1;
2008
2009
codec->patch_ops = conexant_patch_ops;
2010
codec->patch_ops.init = cxt5051_init;
2011
2012
spec->multiout.max_channels = 2;
2013
spec->multiout.num_dacs = ARRAY_SIZE(cxt5051_dac_nids);
2014
spec->multiout.dac_nids = cxt5051_dac_nids;
2015
spec->multiout.dig_out_nid = CXT5051_SPDIF_OUT;
2016
spec->num_adc_nids = 1; /* not 2; via auto-mic switch */
2017
spec->adc_nids = cxt5051_adc_nids;
2018
spec->num_mixers = 2;
2019
spec->mixers[0] = cxt5051_capture_mixers;
2020
spec->mixers[1] = cxt5051_playback_mixers;
2021
spec->num_init_verbs = 1;
2022
spec->init_verbs[0] = cxt5051_init_verbs;
2023
spec->spdif_route = 0;
2024
spec->num_channel_mode = ARRAY_SIZE(cxt5051_modes);
2025
spec->channel_mode = cxt5051_modes;
2026
spec->cur_adc = 0;
2027
spec->cur_adc_idx = 0;
2028
2029
set_beep_amp(spec, 0x13, 0, HDA_OUTPUT);
2030
2031
codec->patch_ops.unsol_event = cxt5051_hp_unsol_event;
2032
2033
spec->auto_mic = AUTO_MIC_PORTB | AUTO_MIC_PORTC;
2034
switch (board_config) {
2035
case CXT5051_HP:
2036
spec->mixers[0] = cxt5051_hp_mixers;
2037
break;
2038
case CXT5051_HP_DV6736:
2039
spec->init_verbs[0] = cxt5051_hp_dv6736_init_verbs;
2040
spec->mixers[0] = cxt5051_hp_dv6736_mixers;
2041
spec->auto_mic = 0;
2042
break;
2043
case CXT5051_LENOVO_X200:
2044
spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs;
2045
/* Thinkpad X301 does not have S/PDIF wired and no ability
2046
to use a docking station. */
2047
if (codec->subsystem_id == 0x17aa211f)
2048
spec->multiout.dig_out_nid = 0;
2049
break;
2050
case CXT5051_F700:
2051
spec->init_verbs[0] = cxt5051_f700_init_verbs;
2052
spec->mixers[0] = cxt5051_f700_mixers;
2053
spec->auto_mic = 0;
2054
break;
2055
case CXT5051_TOSHIBA:
2056
spec->mixers[0] = cxt5051_toshiba_mixers;
2057
spec->auto_mic = AUTO_MIC_PORTB;
2058
break;
2059
case CXT5051_IDEAPAD:
2060
spec->init_verbs[spec->num_init_verbs++] =
2061
cxt5051_ideapad_init_verbs;
2062
spec->ideapad = 1;
2063
break;
2064
}
2065
2066
if (spec->beep_amp)
2067
snd_hda_attach_beep_device(codec, spec->beep_amp);
2068
2069
return 0;
2070
}
2071
2072
/* Conexant 5066 specific */
2073
2074
static const hda_nid_t cxt5066_dac_nids[1] = { 0x10 };
2075
static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 };
2076
static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 };
2077
static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 };
2078
2079
/* OLPC's microphone port is DC coupled for use with external sensors,
2080
* therefore we use a 50% mic bias in order to center the input signal with
2081
* the DC input range of the codec. */
2082
#define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50
2083
2084
static const struct hda_channel_mode cxt5066_modes[1] = {
2085
{ 2, NULL },
2086
};
2087
2088
#define HP_PRESENT_PORT_A (1 << 0)
2089
#define HP_PRESENT_PORT_D (1 << 1)
2090
#define hp_port_a_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_A)
2091
#define hp_port_d_present(spec) ((spec)->hp_present & HP_PRESENT_PORT_D)
2092
2093
static void cxt5066_update_speaker(struct hda_codec *codec)
2094
{
2095
struct conexant_spec *spec = codec->spec;
2096
unsigned int pinctl;
2097
2098
snd_printdd("CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n",
2099
spec->hp_present, spec->cur_eapd);
2100
2101
/* Port A (HP) */
2102
pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0;
2103
snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2104
pinctl);
2105
2106
/* Port D (HP/LO) */
2107
pinctl = spec->cur_eapd ? spec->port_d_mode : 0;
2108
if (spec->dell_automute || spec->thinkpad) {
2109
/* Mute if Port A is connected */
2110
if (hp_port_a_present(spec))
2111
pinctl = 0;
2112
} else {
2113
/* Thinkpad/Dell doesn't give pin-D status */
2114
if (!hp_port_d_present(spec))
2115
pinctl = 0;
2116
}
2117
snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2118
pinctl);
2119
2120
/* CLASS_D AMP */
2121
pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0;
2122
snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2123
pinctl);
2124
}
2125
2126
/* turn on/off EAPD (+ mute HP) as a master switch */
2127
static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol,
2128
struct snd_ctl_elem_value *ucontrol)
2129
{
2130
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2131
2132
if (!cxt_eapd_put(kcontrol, ucontrol))
2133
return 0;
2134
2135
cxt5066_update_speaker(codec);
2136
return 1;
2137
}
2138
2139
static const struct hda_input_mux cxt5066_olpc_dc_bias = {
2140
.num_items = 3,
2141
.items = {
2142
{ "Off", PIN_IN },
2143
{ "50%", PIN_VREF50 },
2144
{ "80%", PIN_VREF80 },
2145
},
2146
};
2147
2148
static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec)
2149
{
2150
struct conexant_spec *spec = codec->spec;
2151
/* Even though port F is the DC input, the bias is controlled on port B.
2152
* we also leave that port as an active input (but unselected) in DC mode
2153
* just in case that is necessary to make the bias setting take effect. */
2154
return snd_hda_codec_write_cache(codec, 0x1a, 0,
2155
AC_VERB_SET_PIN_WIDGET_CONTROL,
2156
cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index);
2157
}
2158
2159
/* OLPC defers mic widget control until when capture is started because the
2160
* microphone LED comes on as soon as these settings are put in place. if we
2161
* did this before recording, it would give the false indication that recording
2162
* is happening when it is not. */
2163
static void cxt5066_olpc_select_mic(struct hda_codec *codec)
2164
{
2165
struct conexant_spec *spec = codec->spec;
2166
if (!spec->recording)
2167
return;
2168
2169
if (spec->dc_enable) {
2170
/* in DC mode we ignore presence detection and just use the jack
2171
* through our special DC port */
2172
const struct hda_verb enable_dc_mode[] = {
2173
/* disble internal mic, port C */
2174
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2175
2176
/* enable DC capture, port F */
2177
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2178
{},
2179
};
2180
2181
snd_hda_sequence_write(codec, enable_dc_mode);
2182
/* port B input disabled (and bias set) through the following call */
2183
cxt5066_set_olpc_dc_bias(codec);
2184
return;
2185
}
2186
2187
/* disable DC (port F) */
2188
snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
2189
2190
/* external mic, port B */
2191
snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2192
spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0);
2193
2194
/* internal mic, port C */
2195
snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2196
spec->ext_mic_present ? 0 : PIN_VREF80);
2197
}
2198
2199
/* toggle input of built-in and mic jack appropriately */
2200
static void cxt5066_olpc_automic(struct hda_codec *codec)
2201
{
2202
struct conexant_spec *spec = codec->spec;
2203
unsigned int present;
2204
2205
if (spec->dc_enable) /* don't do presence detection in DC mode */
2206
return;
2207
2208
present = snd_hda_codec_read(codec, 0x1a, 0,
2209
AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
2210
if (present)
2211
snd_printdd("CXT5066: external microphone detected\n");
2212
else
2213
snd_printdd("CXT5066: external microphone absent\n");
2214
2215
snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
2216
present ? 0 : 1);
2217
spec->ext_mic_present = !!present;
2218
2219
cxt5066_olpc_select_mic(codec);
2220
}
2221
2222
/* toggle input of built-in digital mic and mic jack appropriately */
2223
static void cxt5066_vostro_automic(struct hda_codec *codec)
2224
{
2225
unsigned int present;
2226
2227
struct hda_verb ext_mic_present[] = {
2228
/* enable external mic, port B */
2229
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2230
2231
/* switch to external mic input */
2232
{0x17, AC_VERB_SET_CONNECT_SEL, 0},
2233
{0x14, AC_VERB_SET_CONNECT_SEL, 0},
2234
2235
/* disable internal digital mic */
2236
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2237
{}
2238
};
2239
static const struct hda_verb ext_mic_absent[] = {
2240
/* enable internal mic, port C */
2241
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2242
2243
/* switch to internal mic input */
2244
{0x14, AC_VERB_SET_CONNECT_SEL, 2},
2245
2246
/* disable external mic, port B */
2247
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2248
{}
2249
};
2250
2251
present = snd_hda_jack_detect(codec, 0x1a);
2252
if (present) {
2253
snd_printdd("CXT5066: external microphone detected\n");
2254
snd_hda_sequence_write(codec, ext_mic_present);
2255
} else {
2256
snd_printdd("CXT5066: external microphone absent\n");
2257
snd_hda_sequence_write(codec, ext_mic_absent);
2258
}
2259
}
2260
2261
/* toggle input of built-in digital mic and mic jack appropriately */
2262
static void cxt5066_ideapad_automic(struct hda_codec *codec)
2263
{
2264
unsigned int present;
2265
2266
struct hda_verb ext_mic_present[] = {
2267
{0x14, AC_VERB_SET_CONNECT_SEL, 0},
2268
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2269
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2270
{}
2271
};
2272
static const struct hda_verb ext_mic_absent[] = {
2273
{0x14, AC_VERB_SET_CONNECT_SEL, 2},
2274
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2275
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2276
{}
2277
};
2278
2279
present = snd_hda_jack_detect(codec, 0x1b);
2280
if (present) {
2281
snd_printdd("CXT5066: external microphone detected\n");
2282
snd_hda_sequence_write(codec, ext_mic_present);
2283
} else {
2284
snd_printdd("CXT5066: external microphone absent\n");
2285
snd_hda_sequence_write(codec, ext_mic_absent);
2286
}
2287
}
2288
2289
2290
/* toggle input of built-in digital mic and mic jack appropriately */
2291
static void cxt5066_asus_automic(struct hda_codec *codec)
2292
{
2293
unsigned int present;
2294
2295
present = snd_hda_jack_detect(codec, 0x1b);
2296
snd_printdd("CXT5066: external microphone present=%d\n", present);
2297
snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
2298
present ? 1 : 0);
2299
}
2300
2301
2302
/* toggle input of built-in digital mic and mic jack appropriately */
2303
static void cxt5066_hp_laptop_automic(struct hda_codec *codec)
2304
{
2305
unsigned int present;
2306
2307
present = snd_hda_jack_detect(codec, 0x1b);
2308
snd_printdd("CXT5066: external microphone present=%d\n", present);
2309
snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL,
2310
present ? 1 : 3);
2311
}
2312
2313
2314
/* toggle input of built-in digital mic and mic jack appropriately
2315
order is: external mic -> dock mic -> interal mic */
2316
static void cxt5066_thinkpad_automic(struct hda_codec *codec)
2317
{
2318
unsigned int ext_present, dock_present;
2319
2320
static const struct hda_verb ext_mic_present[] = {
2321
{0x14, AC_VERB_SET_CONNECT_SEL, 0},
2322
{0x17, AC_VERB_SET_CONNECT_SEL, 1},
2323
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2324
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2325
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2326
{}
2327
};
2328
static const struct hda_verb dock_mic_present[] = {
2329
{0x14, AC_VERB_SET_CONNECT_SEL, 0},
2330
{0x17, AC_VERB_SET_CONNECT_SEL, 0},
2331
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2332
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2333
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2334
{}
2335
};
2336
static const struct hda_verb ext_mic_absent[] = {
2337
{0x14, AC_VERB_SET_CONNECT_SEL, 2},
2338
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2339
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2340
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2341
{}
2342
};
2343
2344
ext_present = snd_hda_jack_detect(codec, 0x1b);
2345
dock_present = snd_hda_jack_detect(codec, 0x1a);
2346
if (ext_present) {
2347
snd_printdd("CXT5066: external microphone detected\n");
2348
snd_hda_sequence_write(codec, ext_mic_present);
2349
} else if (dock_present) {
2350
snd_printdd("CXT5066: dock microphone detected\n");
2351
snd_hda_sequence_write(codec, dock_mic_present);
2352
} else {
2353
snd_printdd("CXT5066: external microphone absent\n");
2354
snd_hda_sequence_write(codec, ext_mic_absent);
2355
}
2356
}
2357
2358
/* mute internal speaker if HP is plugged */
2359
static void cxt5066_hp_automute(struct hda_codec *codec)
2360
{
2361
struct conexant_spec *spec = codec->spec;
2362
unsigned int portA, portD;
2363
2364
/* Port A */
2365
portA = snd_hda_jack_detect(codec, 0x19);
2366
2367
/* Port D */
2368
portD = snd_hda_jack_detect(codec, 0x1c);
2369
2370
spec->hp_present = portA ? HP_PRESENT_PORT_A : 0;
2371
spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0;
2372
snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n",
2373
portA, portD, spec->hp_present);
2374
cxt5066_update_speaker(codec);
2375
}
2376
2377
/* Dispatch the right mic autoswitch function */
2378
static void cxt5066_automic(struct hda_codec *codec)
2379
{
2380
struct conexant_spec *spec = codec->spec;
2381
2382
if (spec->dell_vostro)
2383
cxt5066_vostro_automic(codec);
2384
else if (spec->ideapad)
2385
cxt5066_ideapad_automic(codec);
2386
else if (spec->thinkpad)
2387
cxt5066_thinkpad_automic(codec);
2388
else if (spec->hp_laptop)
2389
cxt5066_hp_laptop_automic(codec);
2390
else if (spec->asus)
2391
cxt5066_asus_automic(codec);
2392
}
2393
2394
/* unsolicited event for jack sensing */
2395
static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res)
2396
{
2397
struct conexant_spec *spec = codec->spec;
2398
snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
2399
switch (res >> 26) {
2400
case CONEXANT_HP_EVENT:
2401
cxt5066_hp_automute(codec);
2402
break;
2403
case CONEXANT_MIC_EVENT:
2404
/* ignore mic events in DC mode; we're always using the jack */
2405
if (!spec->dc_enable)
2406
cxt5066_olpc_automic(codec);
2407
break;
2408
}
2409
}
2410
2411
/* unsolicited event for jack sensing */
2412
static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res)
2413
{
2414
snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26);
2415
switch (res >> 26) {
2416
case CONEXANT_HP_EVENT:
2417
cxt5066_hp_automute(codec);
2418
break;
2419
case CONEXANT_MIC_EVENT:
2420
cxt5066_automic(codec);
2421
break;
2422
}
2423
}
2424
2425
2426
static const struct hda_input_mux cxt5066_analog_mic_boost = {
2427
.num_items = 5,
2428
.items = {
2429
{ "0dB", 0 },
2430
{ "10dB", 1 },
2431
{ "20dB", 2 },
2432
{ "30dB", 3 },
2433
{ "40dB", 4 },
2434
},
2435
};
2436
2437
static void cxt5066_set_mic_boost(struct hda_codec *codec)
2438
{
2439
struct conexant_spec *spec = codec->spec;
2440
snd_hda_codec_write_cache(codec, 0x17, 0,
2441
AC_VERB_SET_AMP_GAIN_MUTE,
2442
AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT |
2443
cxt5066_analog_mic_boost.items[spec->mic_boost].index);
2444
if (spec->ideapad || spec->thinkpad) {
2445
/* adjust the internal mic as well...it is not through 0x17 */
2446
snd_hda_codec_write_cache(codec, 0x23, 0,
2447
AC_VERB_SET_AMP_GAIN_MUTE,
2448
AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_INPUT |
2449
cxt5066_analog_mic_boost.
2450
items[spec->mic_boost].index);
2451
}
2452
}
2453
2454
static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol,
2455
struct snd_ctl_elem_info *uinfo)
2456
{
2457
return snd_hda_input_mux_info(&cxt5066_analog_mic_boost, uinfo);
2458
}
2459
2460
static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol,
2461
struct snd_ctl_elem_value *ucontrol)
2462
{
2463
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2464
struct conexant_spec *spec = codec->spec;
2465
ucontrol->value.enumerated.item[0] = spec->mic_boost;
2466
return 0;
2467
}
2468
2469
static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol,
2470
struct snd_ctl_elem_value *ucontrol)
2471
{
2472
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2473
struct conexant_spec *spec = codec->spec;
2474
const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
2475
unsigned int idx;
2476
idx = ucontrol->value.enumerated.item[0];
2477
if (idx >= imux->num_items)
2478
idx = imux->num_items - 1;
2479
2480
spec->mic_boost = idx;
2481
if (!spec->dc_enable)
2482
cxt5066_set_mic_boost(codec);
2483
return 1;
2484
}
2485
2486
static void cxt5066_enable_dc(struct hda_codec *codec)
2487
{
2488
const struct hda_verb enable_dc_mode[] = {
2489
/* disable gain */
2490
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2491
2492
/* switch to DC input */
2493
{0x17, AC_VERB_SET_CONNECT_SEL, 3},
2494
{}
2495
};
2496
2497
/* configure as input source */
2498
snd_hda_sequence_write(codec, enable_dc_mode);
2499
cxt5066_olpc_select_mic(codec); /* also sets configured bias */
2500
}
2501
2502
static void cxt5066_disable_dc(struct hda_codec *codec)
2503
{
2504
/* reconfigure input source */
2505
cxt5066_set_mic_boost(codec);
2506
/* automic also selects the right mic if we're recording */
2507
cxt5066_olpc_automic(codec);
2508
}
2509
2510
static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol,
2511
struct snd_ctl_elem_value *ucontrol)
2512
{
2513
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2514
struct conexant_spec *spec = codec->spec;
2515
ucontrol->value.integer.value[0] = spec->dc_enable;
2516
return 0;
2517
}
2518
2519
static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol,
2520
struct snd_ctl_elem_value *ucontrol)
2521
{
2522
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2523
struct conexant_spec *spec = codec->spec;
2524
int dc_enable = !!ucontrol->value.integer.value[0];
2525
2526
if (dc_enable == spec->dc_enable)
2527
return 0;
2528
2529
spec->dc_enable = dc_enable;
2530
if (dc_enable)
2531
cxt5066_enable_dc(codec);
2532
else
2533
cxt5066_disable_dc(codec);
2534
2535
return 1;
2536
}
2537
2538
static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
2539
struct snd_ctl_elem_info *uinfo)
2540
{
2541
return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo);
2542
}
2543
2544
static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
2545
struct snd_ctl_elem_value *ucontrol)
2546
{
2547
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2548
struct conexant_spec *spec = codec->spec;
2549
ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
2550
return 0;
2551
}
2552
2553
static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
2554
struct snd_ctl_elem_value *ucontrol)
2555
{
2556
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2557
struct conexant_spec *spec = codec->spec;
2558
const struct hda_input_mux *imux = &cxt5066_analog_mic_boost;
2559
unsigned int idx;
2560
2561
idx = ucontrol->value.enumerated.item[0];
2562
if (idx >= imux->num_items)
2563
idx = imux->num_items - 1;
2564
2565
spec->dc_input_bias = idx;
2566
if (spec->dc_enable)
2567
cxt5066_set_olpc_dc_bias(codec);
2568
return 1;
2569
}
2570
2571
static void cxt5066_olpc_capture_prepare(struct hda_codec *codec)
2572
{
2573
struct conexant_spec *spec = codec->spec;
2574
/* mark as recording and configure the microphone widget so that the
2575
* recording LED comes on. */
2576
spec->recording = 1;
2577
cxt5066_olpc_select_mic(codec);
2578
}
2579
2580
static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec)
2581
{
2582
struct conexant_spec *spec = codec->spec;
2583
const struct hda_verb disable_mics[] = {
2584
/* disable external mic, port B */
2585
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2586
2587
/* disble internal mic, port C */
2588
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2589
2590
/* disable DC capture, port F */
2591
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2592
{},
2593
};
2594
2595
snd_hda_sequence_write(codec, disable_mics);
2596
spec->recording = 0;
2597
}
2598
2599
static void conexant_check_dig_outs(struct hda_codec *codec,
2600
const hda_nid_t *dig_pins,
2601
int num_pins)
2602
{
2603
struct conexant_spec *spec = codec->spec;
2604
hda_nid_t *nid_loc = &spec->multiout.dig_out_nid;
2605
int i;
2606
2607
for (i = 0; i < num_pins; i++, dig_pins++) {
2608
unsigned int cfg = snd_hda_codec_get_pincfg(codec, *dig_pins);
2609
if (get_defcfg_connect(cfg) == AC_JACK_PORT_NONE)
2610
continue;
2611
if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1)
2612
continue;
2613
if (spec->slave_dig_outs[0])
2614
nid_loc++;
2615
else
2616
nid_loc = spec->slave_dig_outs;
2617
}
2618
}
2619
2620
static const struct hda_input_mux cxt5066_capture_source = {
2621
.num_items = 4,
2622
.items = {
2623
{ "Mic B", 0 },
2624
{ "Mic C", 1 },
2625
{ "Mic E", 2 },
2626
{ "Mic F", 3 },
2627
},
2628
};
2629
2630
static const struct hda_bind_ctls cxt5066_bind_capture_vol_others = {
2631
.ops = &snd_hda_bind_vol,
2632
.values = {
2633
HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
2634
HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT),
2635
0
2636
},
2637
};
2638
2639
static const struct hda_bind_ctls cxt5066_bind_capture_sw_others = {
2640
.ops = &snd_hda_bind_sw,
2641
.values = {
2642
HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_INPUT),
2643
HDA_COMPOSE_AMP_VAL(0x14, 3, 2, HDA_INPUT),
2644
0
2645
},
2646
};
2647
2648
static const struct snd_kcontrol_new cxt5066_mixer_master[] = {
2649
HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT),
2650
{}
2651
};
2652
2653
static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = {
2654
{
2655
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2656
.name = "Master Playback Volume",
2657
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
2658
SNDRV_CTL_ELEM_ACCESS_TLV_READ |
2659
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
2660
.subdevice = HDA_SUBDEV_AMP_FLAG,
2661
.info = snd_hda_mixer_amp_volume_info,
2662
.get = snd_hda_mixer_amp_volume_get,
2663
.put = snd_hda_mixer_amp_volume_put,
2664
.tlv = { .c = snd_hda_mixer_amp_tlv },
2665
/* offset by 28 volume steps to limit minimum gain to -46dB */
2666
.private_value =
2667
HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28),
2668
},
2669
{}
2670
};
2671
2672
static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = {
2673
{
2674
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2675
.name = "DC Mode Enable Switch",
2676
.info = snd_ctl_boolean_mono_info,
2677
.get = cxt5066_olpc_dc_get,
2678
.put = cxt5066_olpc_dc_put,
2679
},
2680
{
2681
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2682
.name = "DC Input Bias Enum",
2683
.info = cxt5066_olpc_dc_bias_enum_info,
2684
.get = cxt5066_olpc_dc_bias_enum_get,
2685
.put = cxt5066_olpc_dc_bias_enum_put,
2686
},
2687
{}
2688
};
2689
2690
static const struct snd_kcontrol_new cxt5066_mixers[] = {
2691
{
2692
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2693
.name = "Master Playback Switch",
2694
.info = cxt_eapd_info,
2695
.get = cxt_eapd_get,
2696
.put = cxt5066_hp_master_sw_put,
2697
.private_value = 0x1d,
2698
},
2699
2700
{
2701
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2702
.name = "Analog Mic Boost Capture Enum",
2703
.info = cxt5066_mic_boost_mux_enum_info,
2704
.get = cxt5066_mic_boost_mux_enum_get,
2705
.put = cxt5066_mic_boost_mux_enum_put,
2706
},
2707
2708
HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others),
2709
HDA_BIND_SW("Capture Switch", &cxt5066_bind_capture_sw_others),
2710
{}
2711
};
2712
2713
static const struct snd_kcontrol_new cxt5066_vostro_mixers[] = {
2714
{
2715
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2716
.name = "Internal Mic Boost Capture Enum",
2717
.info = cxt5066_mic_boost_mux_enum_info,
2718
.get = cxt5066_mic_boost_mux_enum_get,
2719
.put = cxt5066_mic_boost_mux_enum_put,
2720
.private_value = 0x23 | 0x100,
2721
},
2722
{}
2723
};
2724
2725
static const struct hda_verb cxt5066_init_verbs[] = {
2726
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
2727
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
2728
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
2729
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
2730
2731
/* Speakers */
2732
{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2733
{0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2734
2735
/* HP, Amp */
2736
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2737
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2738
2739
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2740
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2741
2742
/* DAC1 */
2743
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2744
2745
/* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
2746
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
2747
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2748
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
2749
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2750
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2751
2752
/* no digital microphone support yet */
2753
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2754
2755
/* Audio input selector */
2756
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
2757
2758
/* SPDIF route: PCM */
2759
{0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
2760
{0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
2761
2762
{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2763
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2764
2765
/* EAPD */
2766
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
2767
2768
/* not handling these yet */
2769
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
2770
{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
2771
{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
2772
{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
2773
{0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
2774
{0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
2775
{0x20, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
2776
{0x22, AC_VERB_SET_UNSOLICITED_ENABLE, 0},
2777
{ } /* end */
2778
};
2779
2780
static const struct hda_verb cxt5066_init_verbs_olpc[] = {
2781
/* Port A: headphones */
2782
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2783
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2784
2785
/* Port B: external microphone */
2786
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2787
2788
/* Port C: internal microphone */
2789
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2790
2791
/* Port D: unused */
2792
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2793
2794
/* Port E: unused, but has primary EAPD */
2795
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2796
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
2797
2798
/* Port F: external DC input through microphone port */
2799
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2800
2801
/* Port G: internal speakers */
2802
{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2803
{0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2804
2805
/* DAC1 */
2806
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2807
2808
/* DAC2: unused */
2809
{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2810
2811
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
2812
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2813
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2814
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2815
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2816
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2817
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2818
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2819
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2820
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2821
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2822
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2823
2824
/* Disable digital microphone port */
2825
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2826
2827
/* Audio input selectors */
2828
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
2829
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2830
2831
/* Disable SPDIF */
2832
{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2833
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2834
2835
/* enable unsolicited events for Port A and B */
2836
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
2837
{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
2838
{ } /* end */
2839
};
2840
2841
static const struct hda_verb cxt5066_init_verbs_vostro[] = {
2842
/* Port A: headphones */
2843
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2844
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2845
2846
/* Port B: external microphone */
2847
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2848
2849
/* Port C: unused */
2850
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2851
2852
/* Port D: unused */
2853
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2854
2855
/* Port E: unused, but has primary EAPD */
2856
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2857
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
2858
2859
/* Port F: unused */
2860
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2861
2862
/* Port G: internal speakers */
2863
{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2864
{0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2865
2866
/* DAC1 */
2867
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2868
2869
/* DAC2: unused */
2870
{0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2871
2872
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2873
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2874
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2875
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2876
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2877
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2878
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2879
{0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2880
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2881
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2882
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2883
{0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2884
2885
/* Digital microphone port */
2886
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2887
2888
/* Audio input selectors */
2889
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3},
2890
{0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2891
2892
/* Disable SPDIF */
2893
{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2894
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2895
2896
/* enable unsolicited events for Port A and B */
2897
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
2898
{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
2899
{ } /* end */
2900
};
2901
2902
static const struct hda_verb cxt5066_init_verbs_ideapad[] = {
2903
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */
2904
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */
2905
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
2906
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
2907
2908
/* Speakers */
2909
{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2910
{0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2911
2912
/* HP, Amp */
2913
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2914
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2915
2916
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2917
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2918
2919
/* DAC1 */
2920
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2921
2922
/* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
2923
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
2924
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2925
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
2926
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2927
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2928
{0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */
2929
2930
/* Audio input selector */
2931
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2},
2932
{0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */
2933
2934
/* SPDIF route: PCM */
2935
{0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
2936
{0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
2937
2938
{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2939
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2940
2941
/* internal microphone */
2942
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */
2943
2944
/* EAPD */
2945
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
2946
2947
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
2948
{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
2949
{ } /* end */
2950
};
2951
2952
static const struct hda_verb cxt5066_init_verbs_thinkpad[] = {
2953
{0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port F */
2954
{0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Port E */
2955
2956
/* Port G: internal speakers */
2957
{0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2958
{0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2959
2960
/* Port A: HP, Amp */
2961
{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2962
{0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2963
2964
/* Port B: Mic Dock */
2965
{0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2966
2967
/* Port C: Mic */
2968
{0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2969
2970
/* Port D: HP Dock, Amp */
2971
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
2972
{0x1c, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */
2973
2974
/* DAC1 */
2975
{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2976
2977
/* Node 14 connections: 0x17 0x18 0x23 0x24 0x27 */
2978
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50},
2979
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2980
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2) | 0x50},
2981
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2982
{0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2983
{0x14, AC_VERB_SET_CONNECT_SEL, 2}, /* default to internal mic */
2984
2985
/* Audio input selector */
2986
{0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x2},
2987
{0x17, AC_VERB_SET_CONNECT_SEL, 1}, /* route ext mic */
2988
2989
/* SPDIF route: PCM */
2990
{0x20, AC_VERB_SET_CONNECT_SEL, 0x0},
2991
{0x22, AC_VERB_SET_CONNECT_SEL, 0x0},
2992
2993
{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2994
{0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2995
2996
/* internal microphone */
2997
{0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* enable internal mic */
2998
2999
/* EAPD */
3000
{0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */
3001
3002
/* enable unsolicited events for Port A, B, C and D */
3003
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
3004
{0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
3005
{0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
3006
{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
3007
{ } /* end */
3008
};
3009
3010
static const struct hda_verb cxt5066_init_verbs_portd_lo[] = {
3011
{0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3012
{ } /* end */
3013
};
3014
3015
3016
static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = {
3017
{0x14, AC_VERB_SET_CONNECT_SEL, 0x0},
3018
{0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT},
3019
{0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT},
3020
{ } /* end */
3021
};
3022
3023
/* initialize jack-sensing, too */
3024
static int cxt5066_init(struct hda_codec *codec)
3025
{
3026
snd_printdd("CXT5066: init\n");
3027
conexant_init(codec);
3028
if (codec->patch_ops.unsol_event) {
3029
cxt5066_hp_automute(codec);
3030
cxt5066_automic(codec);
3031
}
3032
cxt5066_set_mic_boost(codec);
3033
return 0;
3034
}
3035
3036
static int cxt5066_olpc_init(struct hda_codec *codec)
3037
{
3038
struct conexant_spec *spec = codec->spec;
3039
snd_printdd("CXT5066: init\n");
3040
conexant_init(codec);
3041
cxt5066_hp_automute(codec);
3042
if (!spec->dc_enable) {
3043
cxt5066_set_mic_boost(codec);
3044
cxt5066_olpc_automic(codec);
3045
} else {
3046
cxt5066_enable_dc(codec);
3047
}
3048
return 0;
3049
}
3050
3051
enum {
3052
CXT5066_LAPTOP, /* Laptops w/ EAPD support */
3053
CXT5066_DELL_LAPTOP, /* Dell Laptop */
3054
CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */
3055
CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */
3056
CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */
3057
CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */
3058
CXT5066_ASUS, /* Asus K52JU, Lenovo G560 - Int mic at 0x1a and Ext mic at 0x1b */
3059
CXT5066_HP_LAPTOP, /* HP Laptop */
3060
CXT5066_AUTO, /* BIOS auto-parser */
3061
CXT5066_MODELS
3062
};
3063
3064
static const char * const cxt5066_models[CXT5066_MODELS] = {
3065
[CXT5066_LAPTOP] = "laptop",
3066
[CXT5066_DELL_LAPTOP] = "dell-laptop",
3067
[CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5",
3068
[CXT5066_DELL_VOSTRO] = "dell-vostro",
3069
[CXT5066_IDEAPAD] = "ideapad",
3070
[CXT5066_THINKPAD] = "thinkpad",
3071
[CXT5066_ASUS] = "asus",
3072
[CXT5066_HP_LAPTOP] = "hp-laptop",
3073
[CXT5066_AUTO] = "auto",
3074
};
3075
3076
static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
3077
SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT5066_AUTO),
3078
SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
3079
SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
3080
SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD),
3081
SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO),
3082
SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
3083
SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
3084
SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD),
3085
SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD),
3086
SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP),
3087
SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS),
3088
SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS),
3089
SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS),
3090
SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD),
3091
SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5),
3092
SND_PCI_QUIRK(0x1179, 0xffe0, "Toshiba Satellite Pro T130-15F", CXT5066_OLPC_XO_1_5),
3093
SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board",
3094
CXT5066_LAPTOP),
3095
SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5),
3096
SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
3097
SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
3098
SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
3099
SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo Thinkpad", CXT5066_THINKPAD),
3100
SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
3101
SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
3102
SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
3103
SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
3104
SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO),
3105
SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT5066_IDEAPAD), /* Fallback for Lenovos without dock mic */
3106
SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO),
3107
{}
3108
};
3109
3110
static int patch_cxt5066(struct hda_codec *codec)
3111
{
3112
struct conexant_spec *spec;
3113
int board_config;
3114
3115
board_config = snd_hda_check_board_config(codec, CXT5066_MODELS,
3116
cxt5066_models, cxt5066_cfg_tbl);
3117
#if 0 /* use the old method just for safety */
3118
if (board_config < 0)
3119
board_config = CXT5066_AUTO;
3120
#endif
3121
if (board_config == CXT5066_AUTO)
3122
return patch_conexant_auto(codec);
3123
3124
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3125
if (!spec)
3126
return -ENOMEM;
3127
codec->spec = spec;
3128
3129
codec->patch_ops = conexant_patch_ops;
3130
codec->patch_ops.init = conexant_init;
3131
3132
spec->dell_automute = 0;
3133
spec->multiout.max_channels = 2;
3134
spec->multiout.num_dacs = ARRAY_SIZE(cxt5066_dac_nids);
3135
spec->multiout.dac_nids = cxt5066_dac_nids;
3136
conexant_check_dig_outs(codec, cxt5066_digout_pin_nids,
3137
ARRAY_SIZE(cxt5066_digout_pin_nids));
3138
spec->num_adc_nids = 1;
3139
spec->adc_nids = cxt5066_adc_nids;
3140
spec->capsrc_nids = cxt5066_capsrc_nids;
3141
spec->input_mux = &cxt5066_capture_source;
3142
3143
spec->port_d_mode = PIN_HP;
3144
3145
spec->num_init_verbs = 1;
3146
spec->init_verbs[0] = cxt5066_init_verbs;
3147
spec->num_channel_mode = ARRAY_SIZE(cxt5066_modes);
3148
spec->channel_mode = cxt5066_modes;
3149
spec->cur_adc = 0;
3150
spec->cur_adc_idx = 0;
3151
3152
set_beep_amp(spec, 0x13, 0, HDA_OUTPUT);
3153
3154
switch (board_config) {
3155
default:
3156
case CXT5066_LAPTOP:
3157
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
3158
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3159
break;
3160
case CXT5066_DELL_LAPTOP:
3161
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
3162
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3163
3164
spec->port_d_mode = PIN_OUT;
3165
spec->init_verbs[spec->num_init_verbs] = cxt5066_init_verbs_portd_lo;
3166
spec->num_init_verbs++;
3167
spec->dell_automute = 1;
3168
break;
3169
case CXT5066_ASUS:
3170
case CXT5066_HP_LAPTOP:
3171
codec->patch_ops.init = cxt5066_init;
3172
codec->patch_ops.unsol_event = cxt5066_unsol_event;
3173
spec->init_verbs[spec->num_init_verbs] =
3174
cxt5066_init_verbs_hp_laptop;
3175
spec->num_init_verbs++;
3176
spec->hp_laptop = board_config == CXT5066_HP_LAPTOP;
3177
spec->asus = board_config == CXT5066_ASUS;
3178
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
3179
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3180
/* no S/PDIF out */
3181
if (board_config == CXT5066_HP_LAPTOP)
3182
spec->multiout.dig_out_nid = 0;
3183
/* input source automatically selected */
3184
spec->input_mux = NULL;
3185
spec->port_d_mode = 0;
3186
spec->mic_boost = 3; /* default 30dB gain */
3187
break;
3188
3189
case CXT5066_OLPC_XO_1_5:
3190
codec->patch_ops.init = cxt5066_olpc_init;
3191
codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event;
3192
spec->init_verbs[0] = cxt5066_init_verbs_olpc;
3193
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
3194
spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc;
3195
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3196
spec->port_d_mode = 0;
3197
spec->mic_boost = 3; /* default 30dB gain */
3198
3199
/* no S/PDIF out */
3200
spec->multiout.dig_out_nid = 0;
3201
3202
/* input source automatically selected */
3203
spec->input_mux = NULL;
3204
3205
/* our capture hooks which allow us to turn on the microphone LED
3206
* at the right time */
3207
spec->capture_prepare = cxt5066_olpc_capture_prepare;
3208
spec->capture_cleanup = cxt5066_olpc_capture_cleanup;
3209
break;
3210
case CXT5066_DELL_VOSTRO:
3211
codec->patch_ops.init = cxt5066_init;
3212
codec->patch_ops.unsol_event = cxt5066_unsol_event;
3213
spec->init_verbs[0] = cxt5066_init_verbs_vostro;
3214
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc;
3215
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3216
spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers;
3217
spec->port_d_mode = 0;
3218
spec->dell_vostro = 1;
3219
spec->mic_boost = 3; /* default 30dB gain */
3220
3221
/* no S/PDIF out */
3222
spec->multiout.dig_out_nid = 0;
3223
3224
/* input source automatically selected */
3225
spec->input_mux = NULL;
3226
break;
3227
case CXT5066_IDEAPAD:
3228
codec->patch_ops.init = cxt5066_init;
3229
codec->patch_ops.unsol_event = cxt5066_unsol_event;
3230
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
3231
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3232
spec->init_verbs[0] = cxt5066_init_verbs_ideapad;
3233
spec->port_d_mode = 0;
3234
spec->ideapad = 1;
3235
spec->mic_boost = 2; /* default 20dB gain */
3236
3237
/* no S/PDIF out */
3238
spec->multiout.dig_out_nid = 0;
3239
3240
/* input source automatically selected */
3241
spec->input_mux = NULL;
3242
break;
3243
case CXT5066_THINKPAD:
3244
codec->patch_ops.init = cxt5066_init;
3245
codec->patch_ops.unsol_event = cxt5066_unsol_event;
3246
spec->mixers[spec->num_mixers++] = cxt5066_mixer_master;
3247
spec->mixers[spec->num_mixers++] = cxt5066_mixers;
3248
spec->init_verbs[0] = cxt5066_init_verbs_thinkpad;
3249
spec->thinkpad = 1;
3250
spec->port_d_mode = PIN_OUT;
3251
spec->mic_boost = 2; /* default 20dB gain */
3252
3253
/* no S/PDIF out */
3254
spec->multiout.dig_out_nid = 0;
3255
3256
/* input source automatically selected */
3257
spec->input_mux = NULL;
3258
break;
3259
}
3260
3261
if (spec->beep_amp)
3262
snd_hda_attach_beep_device(codec, spec->beep_amp);
3263
3264
return 0;
3265
}
3266
3267
/*
3268
* Automatic parser for CX20641 & co
3269
*/
3270
3271
static int cx_auto_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
3272
struct hda_codec *codec,
3273
unsigned int stream_tag,
3274
unsigned int format,
3275
struct snd_pcm_substream *substream)
3276
{
3277
struct conexant_spec *spec = codec->spec;
3278
hda_nid_t adc = spec->imux_info[spec->cur_mux[0]].adc;
3279
if (spec->adc_switching) {
3280
spec->cur_adc = adc;
3281
spec->cur_adc_stream_tag = stream_tag;
3282
spec->cur_adc_format = format;
3283
}
3284
snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format);
3285
return 0;
3286
}
3287
3288
static int cx_auto_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
3289
struct hda_codec *codec,
3290
struct snd_pcm_substream *substream)
3291
{
3292
struct conexant_spec *spec = codec->spec;
3293
snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
3294
spec->cur_adc = 0;
3295
return 0;
3296
}
3297
3298
static const struct hda_pcm_stream cx_auto_pcm_analog_capture = {
3299
.substreams = 1,
3300
.channels_min = 2,
3301
.channels_max = 2,
3302
.nid = 0, /* fill later */
3303
.ops = {
3304
.prepare = cx_auto_capture_pcm_prepare,
3305
.cleanup = cx_auto_capture_pcm_cleanup
3306
},
3307
};
3308
3309
static const hda_nid_t cx_auto_adc_nids[] = { 0x14 };
3310
3311
/* get the connection index of @nid in the widget @mux */
3312
static int get_connection_index(struct hda_codec *codec, hda_nid_t mux,
3313
hda_nid_t nid)
3314
{
3315
hda_nid_t conn[HDA_MAX_NUM_INPUTS];
3316
int i, nums;
3317
3318
nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
3319
for (i = 0; i < nums; i++)
3320
if (conn[i] == nid)
3321
return i;
3322
return -1;
3323
}
3324
3325
/* get an unassigned DAC from the given list.
3326
* Return the nid if found and reduce the DAC list, or return zero if
3327
* not found
3328
*/
3329
static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin,
3330
hda_nid_t *dacs, int *num_dacs)
3331
{
3332
int i, nums = *num_dacs;
3333
hda_nid_t ret = 0;
3334
3335
for (i = 0; i < nums; i++) {
3336
if (get_connection_index(codec, pin, dacs[i]) >= 0) {
3337
ret = dacs[i];
3338
break;
3339
}
3340
}
3341
if (!ret)
3342
return 0;
3343
if (--nums > 0)
3344
memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t));
3345
*num_dacs = nums;
3346
return ret;
3347
}
3348
3349
#define MAX_AUTO_DACS 5
3350
3351
/* fill analog DAC list from the widget tree */
3352
static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
3353
{
3354
hda_nid_t nid, end_nid;
3355
int nums = 0;
3356
3357
end_nid = codec->start_nid + codec->num_nodes;
3358
for (nid = codec->start_nid; nid < end_nid; nid++) {
3359
unsigned int wcaps = get_wcaps(codec, nid);
3360
unsigned int type = get_wcaps_type(wcaps);
3361
if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) {
3362
dacs[nums++] = nid;
3363
if (nums >= MAX_AUTO_DACS)
3364
break;
3365
}
3366
}
3367
return nums;
3368
}
3369
3370
/* fill pin_dac_pair list from the pin and dac list */
3371
static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins,
3372
int num_pins, hda_nid_t *dacs, int *rest,
3373
struct pin_dac_pair *filled, int type)
3374
{
3375
int i, nums;
3376
3377
nums = 0;
3378
for (i = 0; i < num_pins; i++) {
3379
filled[nums].pin = pins[i];
3380
filled[nums].type = type;
3381
filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
3382
nums++;
3383
}
3384
return nums;
3385
}
3386
3387
/* parse analog output paths */
3388
static void cx_auto_parse_output(struct hda_codec *codec)
3389
{
3390
struct conexant_spec *spec = codec->spec;
3391
struct auto_pin_cfg *cfg = &spec->autocfg;
3392
hda_nid_t dacs[MAX_AUTO_DACS];
3393
int i, j, nums, rest;
3394
3395
rest = fill_cx_auto_dacs(codec, dacs);
3396
/* parse all analog output pins */
3397
nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs,
3398
dacs, &rest, spec->dac_info,
3399
AUTO_PIN_LINE_OUT);
3400
nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
3401
dacs, &rest, spec->dac_info + nums,
3402
AUTO_PIN_HP_OUT);
3403
nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
3404
dacs, &rest, spec->dac_info + nums,
3405
AUTO_PIN_SPEAKER_OUT);
3406
spec->dac_info_filled = nums;
3407
/* fill multiout struct */
3408
for (i = 0; i < nums; i++) {
3409
hda_nid_t dac = spec->dac_info[i].dac;
3410
if (!dac)
3411
continue;
3412
switch (spec->dac_info[i].type) {
3413
case AUTO_PIN_LINE_OUT:
3414
spec->private_dac_nids[spec->multiout.num_dacs] = dac;
3415
spec->multiout.num_dacs++;
3416
break;
3417
case AUTO_PIN_HP_OUT:
3418
case AUTO_PIN_SPEAKER_OUT:
3419
if (!spec->multiout.hp_nid) {
3420
spec->multiout.hp_nid = dac;
3421
break;
3422
}
3423
for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++)
3424
if (!spec->multiout.extra_out_nid[j]) {
3425
spec->multiout.extra_out_nid[j] = dac;
3426
break;
3427
}
3428
break;
3429
}
3430
}
3431
spec->multiout.dac_nids = spec->private_dac_nids;
3432
spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3433
3434
for (i = 0; i < cfg->hp_outs; i++) {
3435
if (is_jack_detectable(codec, cfg->hp_pins[i])) {
3436
spec->auto_mute = 1;
3437
break;
3438
}
3439
}
3440
if (spec->auto_mute &&
3441
cfg->line_out_pins[0] &&
3442
cfg->line_out_type != AUTO_PIN_SPEAKER_OUT &&
3443
cfg->line_out_pins[0] != cfg->hp_pins[0] &&
3444
cfg->line_out_pins[0] != cfg->speaker_pins[0]) {
3445
for (i = 0; i < cfg->line_outs; i++) {
3446
if (is_jack_detectable(codec, cfg->line_out_pins[i])) {
3447
spec->detect_line = 1;
3448
break;
3449
}
3450
}
3451
spec->automute_lines = spec->detect_line;
3452
}
3453
3454
spec->vmaster_nid = spec->private_dac_nids[0];
3455
}
3456
3457
static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
3458
hda_nid_t *pins, bool on);
3459
3460
static void do_automute(struct hda_codec *codec, int num_pins,
3461
hda_nid_t *pins, bool on)
3462
{
3463
int i;
3464
for (i = 0; i < num_pins; i++)
3465
snd_hda_codec_write(codec, pins[i], 0,
3466
AC_VERB_SET_PIN_WIDGET_CONTROL,
3467
on ? PIN_OUT : 0);
3468
cx_auto_turn_eapd(codec, num_pins, pins, on);
3469
}
3470
3471
static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
3472
{
3473
int i, present = 0;
3474
3475
for (i = 0; i < num_pins; i++) {
3476
hda_nid_t nid = pins[i];
3477
if (!nid || !is_jack_detectable(codec, nid))
3478
break;
3479
snd_hda_input_jack_report(codec, nid);
3480
present |= snd_hda_jack_detect(codec, nid);
3481
}
3482
return present;
3483
}
3484
3485
/* auto-mute/unmute speaker and line outs according to headphone jack */
3486
static void cx_auto_update_speakers(struct hda_codec *codec)
3487
{
3488
struct conexant_spec *spec = codec->spec;
3489
struct auto_pin_cfg *cfg = &spec->autocfg;
3490
int on = 1;
3491
3492
/* turn on HP EAPD when HP jacks are present */
3493
if (spec->auto_mute)
3494
on = spec->hp_present;
3495
cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on);
3496
/* mute speakers in auto-mode if HP or LO jacks are plugged */
3497
if (spec->auto_mute)
3498
on = !(spec->hp_present ||
3499
(spec->detect_line && spec->line_present));
3500
do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, on);
3501
3502
/* toggle line-out mutes if needed, too */
3503
/* if LO is a copy of either HP or Speaker, don't need to handle it */
3504
if (cfg->line_out_pins[0] == cfg->hp_pins[0] ||
3505
cfg->line_out_pins[0] == cfg->speaker_pins[0])
3506
return;
3507
if (spec->auto_mute) {
3508
/* mute LO in auto-mode when HP jack is present */
3509
if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ||
3510
spec->automute_lines)
3511
on = !spec->hp_present;
3512
else
3513
on = 1;
3514
}
3515
do_automute(codec, cfg->line_outs, cfg->line_out_pins, on);
3516
}
3517
3518
static void cx_auto_hp_automute(struct hda_codec *codec)
3519
{
3520
struct conexant_spec *spec = codec->spec;
3521
struct auto_pin_cfg *cfg = &spec->autocfg;
3522
3523
if (!spec->auto_mute)
3524
return;
3525
spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins);
3526
cx_auto_update_speakers(codec);
3527
}
3528
3529
static void cx_auto_line_automute(struct hda_codec *codec)
3530
{
3531
struct conexant_spec *spec = codec->spec;
3532
struct auto_pin_cfg *cfg = &spec->autocfg;
3533
3534
if (!spec->auto_mute || !spec->detect_line)
3535
return;
3536
spec->line_present = detect_jacks(codec, cfg->line_outs,
3537
cfg->line_out_pins);
3538
cx_auto_update_speakers(codec);
3539
}
3540
3541
static int cx_automute_mode_info(struct snd_kcontrol *kcontrol,
3542
struct snd_ctl_elem_info *uinfo)
3543
{
3544
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3545
struct conexant_spec *spec = codec->spec;
3546
static const char * const texts2[] = {
3547
"Disabled", "Enabled"
3548
};
3549
static const char * const texts3[] = {
3550
"Disabled", "Speaker Only", "Line-Out+Speaker"
3551
};
3552
const char * const *texts;
3553
3554
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
3555
uinfo->count = 1;
3556
if (spec->automute_hp_lo) {
3557
uinfo->value.enumerated.items = 3;
3558
texts = texts3;
3559
} else {
3560
uinfo->value.enumerated.items = 2;
3561
texts = texts2;
3562
}
3563
if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
3564
uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
3565
strcpy(uinfo->value.enumerated.name,
3566
texts[uinfo->value.enumerated.item]);
3567
return 0;
3568
}
3569
3570
static int cx_automute_mode_get(struct snd_kcontrol *kcontrol,
3571
struct snd_ctl_elem_value *ucontrol)
3572
{
3573
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3574
struct conexant_spec *spec = codec->spec;
3575
unsigned int val;
3576
if (!spec->auto_mute)
3577
val = 0;
3578
else if (!spec->automute_lines)
3579
val = 1;
3580
else
3581
val = 2;
3582
ucontrol->value.enumerated.item[0] = val;
3583
return 0;
3584
}
3585
3586
static int cx_automute_mode_put(struct snd_kcontrol *kcontrol,
3587
struct snd_ctl_elem_value *ucontrol)
3588
{
3589
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3590
struct conexant_spec *spec = codec->spec;
3591
3592
switch (ucontrol->value.enumerated.item[0]) {
3593
case 0:
3594
if (!spec->auto_mute)
3595
return 0;
3596
spec->auto_mute = 0;
3597
break;
3598
case 1:
3599
if (spec->auto_mute && !spec->automute_lines)
3600
return 0;
3601
spec->auto_mute = 1;
3602
spec->automute_lines = 0;
3603
break;
3604
case 2:
3605
if (!spec->automute_hp_lo)
3606
return -EINVAL;
3607
if (spec->auto_mute && spec->automute_lines)
3608
return 0;
3609
spec->auto_mute = 1;
3610
spec->automute_lines = 1;
3611
break;
3612
default:
3613
return -EINVAL;
3614
}
3615
cx_auto_update_speakers(codec);
3616
return 1;
3617
}
3618
3619
static const struct snd_kcontrol_new cx_automute_mode_enum[] = {
3620
{
3621
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3622
.name = "Auto-Mute Mode",
3623
.info = cx_automute_mode_info,
3624
.get = cx_automute_mode_get,
3625
.put = cx_automute_mode_put,
3626
},
3627
{ }
3628
};
3629
3630
static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol,
3631
struct snd_ctl_elem_info *uinfo)
3632
{
3633
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3634
struct conexant_spec *spec = codec->spec;
3635
3636
return snd_hda_input_mux_info(&spec->private_imux, uinfo);
3637
}
3638
3639
static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol,
3640
struct snd_ctl_elem_value *ucontrol)
3641
{
3642
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3643
struct conexant_spec *spec = codec->spec;
3644
3645
ucontrol->value.enumerated.item[0] = spec->cur_mux[0];
3646
return 0;
3647
}
3648
3649
/* look for the route the given pin from mux and return the index;
3650
* if do_select is set, actually select the route.
3651
*/
3652
static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux,
3653
hda_nid_t pin, hda_nid_t *srcp,
3654
bool do_select, int depth)
3655
{
3656
hda_nid_t conn[HDA_MAX_NUM_INPUTS];
3657
int i, nums;
3658
3659
switch (get_wcaps_type(get_wcaps(codec, mux))) {
3660
case AC_WID_AUD_IN:
3661
case AC_WID_AUD_SEL:
3662
case AC_WID_AUD_MIX:
3663
break;
3664
default:
3665
return -1;
3666
}
3667
3668
nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn));
3669
for (i = 0; i < nums; i++)
3670
if (conn[i] == pin) {
3671
if (do_select)
3672
snd_hda_codec_write(codec, mux, 0,
3673
AC_VERB_SET_CONNECT_SEL, i);
3674
if (srcp)
3675
*srcp = mux;
3676
return i;
3677
}
3678
depth++;
3679
if (depth == 2)
3680
return -1;
3681
for (i = 0; i < nums; i++) {
3682
int ret = __select_input_connection(codec, conn[i], pin, srcp,
3683
do_select, depth);
3684
if (ret >= 0) {
3685
if (do_select)
3686
snd_hda_codec_write(codec, mux, 0,
3687
AC_VERB_SET_CONNECT_SEL, i);
3688
return i;
3689
}
3690
}
3691
return -1;
3692
}
3693
3694
static void select_input_connection(struct hda_codec *codec, hda_nid_t mux,
3695
hda_nid_t pin)
3696
{
3697
__select_input_connection(codec, mux, pin, NULL, true, 0);
3698
}
3699
3700
static int get_input_connection(struct hda_codec *codec, hda_nid_t mux,
3701
hda_nid_t pin)
3702
{
3703
return __select_input_connection(codec, mux, pin, NULL, false, 0);
3704
}
3705
3706
static int cx_auto_mux_enum_update(struct hda_codec *codec,
3707
const struct hda_input_mux *imux,
3708
unsigned int idx)
3709
{
3710
struct conexant_spec *spec = codec->spec;
3711
hda_nid_t adc;
3712
int changed = 1;
3713
3714
if (!imux->num_items)
3715
return 0;
3716
if (idx >= imux->num_items)
3717
idx = imux->num_items - 1;
3718
if (spec->cur_mux[0] == idx)
3719
changed = 0;
3720
adc = spec->imux_info[idx].adc;
3721
select_input_connection(codec, spec->imux_info[idx].adc,
3722
spec->imux_info[idx].pin);
3723
if (spec->cur_adc && spec->cur_adc != adc) {
3724
/* stream is running, let's swap the current ADC */
3725
__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
3726
spec->cur_adc = adc;
3727
snd_hda_codec_setup_stream(codec, adc,
3728
spec->cur_adc_stream_tag, 0,
3729
spec->cur_adc_format);
3730
}
3731
spec->cur_mux[0] = idx;
3732
return changed;
3733
}
3734
3735
static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol,
3736
struct snd_ctl_elem_value *ucontrol)
3737
{
3738
struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3739
struct conexant_spec *spec = codec->spec;
3740
3741
return cx_auto_mux_enum_update(codec, &spec->private_imux,
3742
ucontrol->value.enumerated.item[0]);
3743
}
3744
3745
static const struct snd_kcontrol_new cx_auto_capture_mixers[] = {
3746
{
3747
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3748
.name = "Capture Source",
3749
.info = cx_auto_mux_enum_info,
3750
.get = cx_auto_mux_enum_get,
3751
.put = cx_auto_mux_enum_put
3752
},
3753
{}
3754
};
3755
3756
static bool select_automic(struct hda_codec *codec, int idx, bool detect)
3757
{
3758
struct conexant_spec *spec = codec->spec;
3759
if (idx < 0)
3760
return false;
3761
if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin))
3762
return false;
3763
cx_auto_mux_enum_update(codec, &spec->private_imux, idx);
3764
return true;
3765
}
3766
3767
/* automatic switch internal and external mic */
3768
static void cx_auto_automic(struct hda_codec *codec)
3769
{
3770
struct conexant_spec *spec = codec->spec;
3771
3772
if (!spec->auto_mic)
3773
return;
3774
if (!select_automic(codec, spec->auto_mic_ext, true))
3775
if (!select_automic(codec, spec->auto_mic_dock, true))
3776
select_automic(codec, spec->auto_mic_int, false);
3777
}
3778
3779
static void cx_auto_unsol_event(struct hda_codec *codec, unsigned int res)
3780
{
3781
int nid = (res & AC_UNSOL_RES_SUBTAG) >> 20;
3782
switch (res >> 26) {
3783
case CONEXANT_HP_EVENT:
3784
cx_auto_hp_automute(codec);
3785
break;
3786
case CONEXANT_LINE_EVENT:
3787
cx_auto_line_automute(codec);
3788
break;
3789
case CONEXANT_MIC_EVENT:
3790
cx_auto_automic(codec);
3791
snd_hda_input_jack_report(codec, nid);
3792
break;
3793
}
3794
}
3795
3796
/* check whether the pin config is suitable for auto-mic switching;
3797
* auto-mic is enabled only when one int-mic and one ext- and/or
3798
* one dock-mic exist
3799
*/
3800
static void cx_auto_check_auto_mic(struct hda_codec *codec)
3801
{
3802
struct conexant_spec *spec = codec->spec;
3803
int pset[INPUT_PIN_ATTR_NORMAL + 1];
3804
int i;
3805
3806
for (i = 0; i < ARRAY_SIZE(pset); i++)
3807
pset[i] = -1;
3808
for (i = 0; i < spec->private_imux.num_items; i++) {
3809
hda_nid_t pin = spec->imux_info[i].pin;
3810
unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin);
3811
int type, attr;
3812
attr = snd_hda_get_input_pin_attr(def_conf);
3813
if (attr == INPUT_PIN_ATTR_UNUSED)
3814
return; /* invalid entry */
3815
if (attr > INPUT_PIN_ATTR_NORMAL)
3816
attr = INPUT_PIN_ATTR_NORMAL;
3817
if (attr != INPUT_PIN_ATTR_INT &&
3818
!is_jack_detectable(codec, pin))
3819
return; /* non-detectable pin */
3820
type = get_defcfg_device(def_conf);
3821
if (type != AC_JACK_MIC_IN &&
3822
(attr != INPUT_PIN_ATTR_DOCK || type != AC_JACK_LINE_IN))
3823
return; /* no valid input type */
3824
if (pset[attr] >= 0)
3825
return; /* already occupied */
3826
pset[attr] = i;
3827
}
3828
if (pset[INPUT_PIN_ATTR_INT] < 0 ||
3829
(pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK]))
3830
return; /* no input to switch*/
3831
spec->auto_mic = 1;
3832
spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL];
3833
spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK];
3834
spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT];
3835
}
3836
3837
static void cx_auto_parse_input(struct hda_codec *codec)
3838
{
3839
struct conexant_spec *spec = codec->spec;
3840
struct auto_pin_cfg *cfg = &spec->autocfg;
3841
struct hda_input_mux *imux;
3842
int i, j;
3843
3844
imux = &spec->private_imux;
3845
for (i = 0; i < cfg->num_inputs; i++) {
3846
for (j = 0; j < spec->num_adc_nids; j++) {
3847
hda_nid_t adc = spec->adc_nids[j];
3848
int idx = get_input_connection(codec, adc,
3849
cfg->inputs[i].pin);
3850
if (idx >= 0) {
3851
const char *label;
3852
label = hda_get_autocfg_input_label(codec, cfg, i);
3853
spec->imux_info[imux->num_items].index = i;
3854
spec->imux_info[imux->num_items].boost = 0;
3855
spec->imux_info[imux->num_items].adc = adc;
3856
spec->imux_info[imux->num_items].pin =
3857
cfg->inputs[i].pin;
3858
snd_hda_add_imux_item(imux, label, idx, NULL);
3859
break;
3860
}
3861
}
3862
}
3863
if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items)
3864
cx_auto_check_auto_mic(codec);
3865
if (imux->num_items > 1 && !spec->auto_mic) {
3866
for (i = 1; i < imux->num_items; i++) {
3867
if (spec->imux_info[i].adc != spec->imux_info[0].adc) {
3868
spec->adc_switching = 1;
3869
break;
3870
}
3871
}
3872
}
3873
}
3874
3875
/* get digital-input audio widget corresponding to the given pin */
3876
static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin)
3877
{
3878
hda_nid_t nid, end_nid;
3879
3880
end_nid = codec->start_nid + codec->num_nodes;
3881
for (nid = codec->start_nid; nid < end_nid; nid++) {
3882
unsigned int wcaps = get_wcaps(codec, nid);
3883
unsigned int type = get_wcaps_type(wcaps);
3884
if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) {
3885
if (get_connection_index(codec, nid, pin) >= 0)
3886
return nid;
3887
}
3888
}
3889
return 0;
3890
}
3891
3892
static void cx_auto_parse_digital(struct hda_codec *codec)
3893
{
3894
struct conexant_spec *spec = codec->spec;
3895
struct auto_pin_cfg *cfg = &spec->autocfg;
3896
hda_nid_t nid;
3897
3898
if (cfg->dig_outs &&
3899
snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1)
3900
spec->multiout.dig_out_nid = nid;
3901
if (cfg->dig_in_pin)
3902
spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin);
3903
}
3904
3905
#ifdef CONFIG_SND_HDA_INPUT_BEEP
3906
static void cx_auto_parse_beep(struct hda_codec *codec)
3907
{
3908
struct conexant_spec *spec = codec->spec;
3909
hda_nid_t nid, end_nid;
3910
3911
end_nid = codec->start_nid + codec->num_nodes;
3912
for (nid = codec->start_nid; nid < end_nid; nid++)
3913
if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) {
3914
set_beep_amp(spec, nid, 0, HDA_OUTPUT);
3915
break;
3916
}
3917
}
3918
#else
3919
#define cx_auto_parse_beep(codec)
3920
#endif
3921
3922
static int cx_auto_parse_auto_config(struct hda_codec *codec)
3923
{
3924
struct conexant_spec *spec = codec->spec;
3925
int err;
3926
3927
err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
3928
if (err < 0)
3929
return err;
3930
3931
cx_auto_parse_output(codec);
3932
cx_auto_parse_input(codec);
3933
cx_auto_parse_digital(codec);
3934
cx_auto_parse_beep(codec);
3935
return 0;
3936
}
3937
3938
static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
3939
hda_nid_t *pins, bool on)
3940
{
3941
int i;
3942
for (i = 0; i < num_pins; i++) {
3943
if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
3944
snd_hda_codec_write(codec, pins[i], 0,
3945
AC_VERB_SET_EAPD_BTLENABLE,
3946
on ? 0x02 : 0);
3947
}
3948
}
3949
3950
static void select_connection(struct hda_codec *codec, hda_nid_t pin,
3951
hda_nid_t src)
3952
{
3953
int idx = get_connection_index(codec, pin, src);
3954
if (idx >= 0)
3955
snd_hda_codec_write(codec, pin, 0,
3956
AC_VERB_SET_CONNECT_SEL, idx);
3957
}
3958
3959
static void mute_outputs(struct hda_codec *codec, int num_nids,
3960
const hda_nid_t *nids)
3961
{
3962
int i, val;
3963
3964
for (i = 0; i < num_nids; i++) {
3965
hda_nid_t nid = nids[i];
3966
if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP))
3967
continue;
3968
if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE)
3969
val = AMP_OUT_MUTE;
3970
else
3971
val = AMP_OUT_ZERO;
3972
snd_hda_codec_write(codec, nid, 0,
3973
AC_VERB_SET_AMP_GAIN_MUTE, val);
3974
}
3975
}
3976
3977
static void enable_unsol_pins(struct hda_codec *codec, int num_pins,
3978
hda_nid_t *pins, unsigned int tag)
3979
{
3980
int i;
3981
for (i = 0; i < num_pins; i++)
3982
snd_hda_codec_write(codec, pins[i], 0,
3983
AC_VERB_SET_UNSOLICITED_ENABLE,
3984
AC_USRSP_EN | tag);
3985
}
3986
3987
static void cx_auto_init_output(struct hda_codec *codec)
3988
{
3989
struct conexant_spec *spec = codec->spec;
3990
struct auto_pin_cfg *cfg = &spec->autocfg;
3991
hda_nid_t nid;
3992
int i;
3993
3994
mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids);
3995
for (i = 0; i < cfg->hp_outs; i++)
3996
snd_hda_codec_write(codec, cfg->hp_pins[i], 0,
3997
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
3998
mute_outputs(codec, cfg->hp_outs, cfg->hp_pins);
3999
mute_outputs(codec, cfg->line_outs, cfg->line_out_pins);
4000
mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins);
4001
for (i = 0; i < spec->dac_info_filled; i++) {
4002
nid = spec->dac_info[i].dac;
4003
if (!nid)
4004
nid = spec->multiout.dac_nids[0];
4005
select_connection(codec, spec->dac_info[i].pin, nid);
4006
}
4007
if (spec->auto_mute) {
4008
enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins,
4009
CONEXANT_HP_EVENT);
4010
spec->hp_present = detect_jacks(codec, cfg->hp_outs,
4011
cfg->hp_pins);
4012
if (spec->detect_line) {
4013
enable_unsol_pins(codec, cfg->line_outs,
4014
cfg->line_out_pins,
4015
CONEXANT_LINE_EVENT);
4016
spec->line_present =
4017
detect_jacks(codec, cfg->line_outs,
4018
cfg->line_out_pins);
4019
}
4020
}
4021
cx_auto_update_speakers(codec);
4022
}
4023
4024
static void cx_auto_init_input(struct hda_codec *codec)
4025
{
4026
struct conexant_spec *spec = codec->spec;
4027
struct auto_pin_cfg *cfg = &spec->autocfg;
4028
int i, val;
4029
4030
for (i = 0; i < spec->num_adc_nids; i++) {
4031
hda_nid_t nid = spec->adc_nids[i];
4032
if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP))
4033
continue;
4034
if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)
4035
val = AMP_IN_MUTE(0);
4036
else
4037
val = AMP_IN_UNMUTE(0);
4038
snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
4039
val);
4040
}
4041
4042
for (i = 0; i < cfg->num_inputs; i++) {
4043
unsigned int type;
4044
if (cfg->inputs[i].type == AUTO_PIN_MIC)
4045
type = PIN_VREF80;
4046
else
4047
type = PIN_IN;
4048
snd_hda_codec_write(codec, cfg->inputs[i].pin, 0,
4049
AC_VERB_SET_PIN_WIDGET_CONTROL, type);
4050
}
4051
4052
if (spec->auto_mic) {
4053
if (spec->auto_mic_ext >= 0) {
4054
snd_hda_codec_write(codec,
4055
cfg->inputs[spec->auto_mic_ext].pin, 0,
4056
AC_VERB_SET_UNSOLICITED_ENABLE,
4057
AC_USRSP_EN | CONEXANT_MIC_EVENT);
4058
}
4059
if (spec->auto_mic_dock >= 0) {
4060
snd_hda_codec_write(codec,
4061
cfg->inputs[spec->auto_mic_dock].pin, 0,
4062
AC_VERB_SET_UNSOLICITED_ENABLE,
4063
AC_USRSP_EN | CONEXANT_MIC_EVENT);
4064
}
4065
cx_auto_automic(codec);
4066
} else {
4067
select_input_connection(codec, spec->imux_info[0].adc,
4068
spec->imux_info[0].pin);
4069
}
4070
}
4071
4072
static void cx_auto_init_digital(struct hda_codec *codec)
4073
{
4074
struct conexant_spec *spec = codec->spec;
4075
struct auto_pin_cfg *cfg = &spec->autocfg;
4076
4077
if (spec->multiout.dig_out_nid)
4078
snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0,
4079
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
4080
if (spec->dig_in_nid)
4081
snd_hda_codec_write(codec, cfg->dig_in_pin, 0,
4082
AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN);
4083
}
4084
4085
static int cx_auto_init(struct hda_codec *codec)
4086
{
4087
/*snd_hda_sequence_write(codec, cx_auto_init_verbs);*/
4088
cx_auto_init_output(codec);
4089
cx_auto_init_input(codec);
4090
cx_auto_init_digital(codec);
4091
return 0;
4092
}
4093
4094
static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename,
4095
const char *dir, int cidx,
4096
hda_nid_t nid, int hda_dir, int amp_idx)
4097
{
4098
static char name[32];
4099
static struct snd_kcontrol_new knew[] = {
4100
HDA_CODEC_VOLUME(name, 0, 0, 0),
4101
HDA_CODEC_MUTE(name, 0, 0, 0),
4102
};
4103
static const char * const sfx[2] = { "Volume", "Switch" };
4104
int i, err;
4105
4106
for (i = 0; i < 2; i++) {
4107
struct snd_kcontrol *kctl;
4108
knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx,
4109
hda_dir);
4110
knew[i].subdevice = HDA_SUBDEV_AMP_FLAG;
4111
knew[i].index = cidx;
4112
snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]);
4113
kctl = snd_ctl_new1(&knew[i], codec);
4114
if (!kctl)
4115
return -ENOMEM;
4116
err = snd_hda_ctl_add(codec, nid, kctl);
4117
if (err < 0)
4118
return err;
4119
if (!(query_amp_caps(codec, nid, hda_dir) & AC_AMPCAP_MUTE))
4120
break;
4121
}
4122
return 0;
4123
}
4124
4125
#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \
4126
cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0)
4127
4128
#define cx_auto_add_pb_volume(codec, nid, str, idx) \
4129
cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT)
4130
4131
static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac,
4132
hda_nid_t pin, const char *name, int idx)
4133
{
4134
unsigned int caps;
4135
caps = query_amp_caps(codec, dac, HDA_OUTPUT);
4136
if (caps & AC_AMPCAP_NUM_STEPS)
4137
return cx_auto_add_pb_volume(codec, dac, name, idx);
4138
caps = query_amp_caps(codec, pin, HDA_OUTPUT);
4139
if (caps & AC_AMPCAP_NUM_STEPS)
4140
return cx_auto_add_pb_volume(codec, pin, name, idx);
4141
return 0;
4142
}
4143
4144
static int cx_auto_build_output_controls(struct hda_codec *codec)
4145
{
4146
struct conexant_spec *spec = codec->spec;
4147
int i, err;
4148
int num_line = 0, num_hp = 0, num_spk = 0;
4149
static const char * const texts[3] = { "Front", "Surround", "CLFE" };
4150
4151
if (spec->dac_info_filled == 1)
4152
return try_add_pb_volume(codec, spec->dac_info[0].dac,
4153
spec->dac_info[0].pin,
4154
"Master", 0);
4155
4156
for (i = 0; i < spec->dac_info_filled; i++) {
4157
const char *label;
4158
int idx, type;
4159
if (!spec->dac_info[i].dac)
4160
continue;
4161
type = spec->dac_info[i].type;
4162
if (type == AUTO_PIN_LINE_OUT)
4163
type = spec->autocfg.line_out_type;
4164
switch (type) {
4165
case AUTO_PIN_LINE_OUT:
4166
default:
4167
label = texts[num_line++];
4168
idx = 0;
4169
break;
4170
case AUTO_PIN_HP_OUT:
4171
label = "Headphone";
4172
idx = num_hp++;
4173
break;
4174
case AUTO_PIN_SPEAKER_OUT:
4175
label = "Speaker";
4176
idx = num_spk++;
4177
break;
4178
}
4179
err = try_add_pb_volume(codec, spec->dac_info[i].dac,
4180
spec->dac_info[i].pin,
4181
label, idx);
4182
if (err < 0)
4183
return err;
4184
}
4185
4186
if (spec->auto_mute) {
4187
err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum);
4188
if (err < 0)
4189
return err;
4190
}
4191
4192
return 0;
4193
}
4194
4195
static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid,
4196
const char *label, const char *pfx,
4197
int cidx)
4198
{
4199
struct conexant_spec *spec = codec->spec;
4200
int i;
4201
4202
for (i = 0; i < spec->num_adc_nids; i++) {
4203
hda_nid_t adc_nid = spec->adc_nids[i];
4204
int idx = get_input_connection(codec, adc_nid, nid);
4205
if (idx < 0)
4206
continue;
4207
return cx_auto_add_volume_idx(codec, label, pfx,
4208
cidx, adc_nid, HDA_INPUT, idx);
4209
}
4210
return 0;
4211
}
4212
4213
static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx,
4214
const char *label, int cidx)
4215
{
4216
struct conexant_spec *spec = codec->spec;
4217
hda_nid_t mux, nid;
4218
int i, con;
4219
4220
nid = spec->imux_info[idx].pin;
4221
if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)
4222
return cx_auto_add_volume(codec, label, " Boost", cidx,
4223
nid, HDA_INPUT);
4224
con = __select_input_connection(codec, spec->imux_info[idx].adc, nid,
4225
&mux, false, 0);
4226
if (con < 0)
4227
return 0;
4228
for (i = 0; i < idx; i++) {
4229
if (spec->imux_info[i].boost == mux)
4230
return 0; /* already present */
4231
}
4232
4233
if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) {
4234
spec->imux_info[idx].boost = mux;
4235
return cx_auto_add_volume(codec, label, " Boost", 0,
4236
mux, HDA_OUTPUT);
4237
}
4238
return 0;
4239
}
4240
4241
static int cx_auto_build_input_controls(struct hda_codec *codec)
4242
{
4243
struct conexant_spec *spec = codec->spec;
4244
struct hda_input_mux *imux = &spec->private_imux;
4245
const char *prev_label;
4246
int input_conn[HDA_MAX_NUM_INPUTS];
4247
int i, err, cidx;
4248
int multi_connection;
4249
4250
multi_connection = 0;
4251
for (i = 0; i < imux->num_items; i++) {
4252
cidx = get_input_connection(codec, spec->imux_info[i].adc,
4253
spec->imux_info[i].pin);
4254
input_conn[i] = (spec->imux_info[i].adc << 8) | cidx;
4255
if (i > 0 && input_conn[i] != input_conn[0])
4256
multi_connection = 1;
4257
}
4258
4259
prev_label = NULL;
4260
cidx = 0;
4261
for (i = 0; i < imux->num_items; i++) {
4262
hda_nid_t nid = spec->imux_info[i].pin;
4263
const char *label;
4264
4265
label = hda_get_autocfg_input_label(codec, &spec->autocfg,
4266
spec->imux_info[i].index);
4267
if (label == prev_label)
4268
cidx++;
4269
else
4270
cidx = 0;
4271
prev_label = label;
4272
4273
err = cx_auto_add_boost_volume(codec, i, label, cidx);
4274
if (err < 0)
4275
return err;
4276
4277
if (!multi_connection) {
4278
if (i > 0)
4279
continue;
4280
err = cx_auto_add_capture_volume(codec, nid,
4281
"Capture", "", cidx);
4282
} else {
4283
err = cx_auto_add_capture_volume(codec, nid,
4284
label, " Capture", cidx);
4285
}
4286
if (err < 0)
4287
return err;
4288
}
4289
4290
if (spec->private_imux.num_items > 1 && !spec->auto_mic) {
4291
err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers);
4292
if (err < 0)
4293
return err;
4294
}
4295
4296
return 0;
4297
}
4298
4299
static int cx_auto_build_controls(struct hda_codec *codec)
4300
{
4301
int err;
4302
4303
err = cx_auto_build_output_controls(codec);
4304
if (err < 0)
4305
return err;
4306
err = cx_auto_build_input_controls(codec);
4307
if (err < 0)
4308
return err;
4309
return conexant_build_controls(codec);
4310
}
4311
4312
static int cx_auto_search_adcs(struct hda_codec *codec)
4313
{
4314
struct conexant_spec *spec = codec->spec;
4315
hda_nid_t nid, end_nid;
4316
4317
end_nid = codec->start_nid + codec->num_nodes;
4318
for (nid = codec->start_nid; nid < end_nid; nid++) {
4319
unsigned int caps = get_wcaps(codec, nid);
4320
if (get_wcaps_type(caps) != AC_WID_AUD_IN)
4321
continue;
4322
if (caps & AC_WCAP_DIGITAL)
4323
continue;
4324
if (snd_BUG_ON(spec->num_adc_nids >=
4325
ARRAY_SIZE(spec->private_adc_nids)))
4326
break;
4327
spec->private_adc_nids[spec->num_adc_nids++] = nid;
4328
}
4329
spec->adc_nids = spec->private_adc_nids;
4330
return 0;
4331
}
4332
4333
4334
static const struct hda_codec_ops cx_auto_patch_ops = {
4335
.build_controls = cx_auto_build_controls,
4336
.build_pcms = conexant_build_pcms,
4337
.init = cx_auto_init,
4338
.free = conexant_free,
4339
.unsol_event = cx_auto_unsol_event,
4340
#ifdef CONFIG_SND_HDA_POWER_SAVE
4341
.suspend = conexant_suspend,
4342
#endif
4343
.reboot_notify = snd_hda_shutup_pins,
4344
};
4345
4346
static int patch_conexant_auto(struct hda_codec *codec)
4347
{
4348
struct conexant_spec *spec;
4349
int err;
4350
4351
printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4352
codec->chip_name);
4353
4354
spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4355
if (!spec)
4356
return -ENOMEM;
4357
codec->spec = spec;
4358
codec->pin_amp_workaround = 1;
4359
err = cx_auto_search_adcs(codec);
4360
if (err < 0)
4361
return err;
4362
err = cx_auto_parse_auto_config(codec);
4363
if (err < 0) {
4364
kfree(codec->spec);
4365
codec->spec = NULL;
4366
return err;
4367
}
4368
spec->capture_stream = &cx_auto_pcm_analog_capture;
4369
codec->patch_ops = cx_auto_patch_ops;
4370
if (spec->beep_amp)
4371
snd_hda_attach_beep_device(codec, spec->beep_amp);
4372
return 0;
4373
}
4374
4375
/*
4376
*/
4377
4378
static const struct hda_codec_preset snd_hda_preset_conexant[] = {
4379
{ .id = 0x14f15045, .name = "CX20549 (Venice)",
4380
.patch = patch_cxt5045 },
4381
{ .id = 0x14f15047, .name = "CX20551 (Waikiki)",
4382
.patch = patch_cxt5047 },
4383
{ .id = 0x14f15051, .name = "CX20561 (Hermosa)",
4384
.patch = patch_cxt5051 },
4385
{ .id = 0x14f15066, .name = "CX20582 (Pebble)",
4386
.patch = patch_cxt5066 },
4387
{ .id = 0x14f15067, .name = "CX20583 (Pebble HSF)",
4388
.patch = patch_cxt5066 },
4389
{ .id = 0x14f15068, .name = "CX20584",
4390
.patch = patch_cxt5066 },
4391
{ .id = 0x14f15069, .name = "CX20585",
4392
.patch = patch_cxt5066 },
4393
{ .id = 0x14f1506c, .name = "CX20588",
4394
.patch = patch_cxt5066 },
4395
{ .id = 0x14f1506e, .name = "CX20590",
4396
.patch = patch_cxt5066 },
4397
{ .id = 0x14f15097, .name = "CX20631",
4398
.patch = patch_conexant_auto },
4399
{ .id = 0x14f15098, .name = "CX20632",
4400
.patch = patch_conexant_auto },
4401
{ .id = 0x14f150a1, .name = "CX20641",
4402
.patch = patch_conexant_auto },
4403
{ .id = 0x14f150a2, .name = "CX20642",
4404
.patch = patch_conexant_auto },
4405
{ .id = 0x14f150ab, .name = "CX20651",
4406
.patch = patch_conexant_auto },
4407
{ .id = 0x14f150ac, .name = "CX20652",
4408
.patch = patch_conexant_auto },
4409
{ .id = 0x14f150b8, .name = "CX20664",
4410
.patch = patch_conexant_auto },
4411
{ .id = 0x14f150b9, .name = "CX20665",
4412
.patch = patch_conexant_auto },
4413
{} /* terminator */
4414
};
4415
4416
MODULE_ALIAS("snd-hda-codec-id:14f15045");
4417
MODULE_ALIAS("snd-hda-codec-id:14f15047");
4418
MODULE_ALIAS("snd-hda-codec-id:14f15051");
4419
MODULE_ALIAS("snd-hda-codec-id:14f15066");
4420
MODULE_ALIAS("snd-hda-codec-id:14f15067");
4421
MODULE_ALIAS("snd-hda-codec-id:14f15068");
4422
MODULE_ALIAS("snd-hda-codec-id:14f15069");
4423
MODULE_ALIAS("snd-hda-codec-id:14f1506c");
4424
MODULE_ALIAS("snd-hda-codec-id:14f1506e");
4425
MODULE_ALIAS("snd-hda-codec-id:14f15097");
4426
MODULE_ALIAS("snd-hda-codec-id:14f15098");
4427
MODULE_ALIAS("snd-hda-codec-id:14f150a1");
4428
MODULE_ALIAS("snd-hda-codec-id:14f150a2");
4429
MODULE_ALIAS("snd-hda-codec-id:14f150ab");
4430
MODULE_ALIAS("snd-hda-codec-id:14f150ac");
4431
MODULE_ALIAS("snd-hda-codec-id:14f150b8");
4432
MODULE_ALIAS("snd-hda-codec-id:14f150b9");
4433
4434
MODULE_LICENSE("GPL");
4435
MODULE_DESCRIPTION("Conexant HD-audio codec");
4436
4437
static struct hda_codec_preset_list conexant_list = {
4438
.preset = snd_hda_preset_conexant,
4439
.owner = THIS_MODULE,
4440
};
4441
4442
static int __init patch_conexant_init(void)
4443
{
4444
return snd_hda_add_codec_preset(&conexant_list);
4445
}
4446
4447
static void __exit patch_conexant_exit(void)
4448
{
4449
snd_hda_delete_codec_preset(&conexant_list);
4450
}
4451
4452
module_init(patch_conexant_init)
4453
module_exit(patch_conexant_exit)
4454
4455