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