Skip to content

Commit 476c02e

Browse files
jason77-wangtiwai
authored andcommitted
ALSA: hda/realtek - a fake key event is triggered by running shutup
On the Lenovo X1C7 machines, after we plug the headset, the rt_resume() and rt_suspend() of the codec driver will be called periodically, the driver can't stay in the rt_suspend state even users doen't use the sound card. Through debugging, I found when running rt_suspend(), it will call alc225_shutup(), in this function, it will change 3k pull down control by alc_update_coef_idx(codec, 0x4a, 0, 3 << 10), this will trigger a fake key event and that event will resume the codec, when codec suspend agin, it will trigger the fake key event one more time, this process will repeat. If disable the key event before changing the pull down control, it will not trigger fake key event. It also needs to restore the pull down control and re-enable the key event, otherwise the system can't get key event when codec is in rt_suspend state. Also move some functions ahead of alc225_shutup(), this can save the function declaration. Fixes: 76f7dec (ALSA: hda/realtek - Add Headset Button supported for ThinkPad X1) Cc: Kailang Yang <[email protected]> Cc: <[email protected]> Signed-off-by: Hui Wang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent f5a88b0 commit 476c02e

File tree

1 file changed

+107
-63
lines changed

1 file changed

+107
-63
lines changed

sound/pci/hda/patch_realtek.c

Lines changed: 107 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct alc_spec {
107107
unsigned int done_hp_init:1;
108108
unsigned int no_shutup_pins:1;
109109
unsigned int ultra_low_power:1;
110+
unsigned int has_hs_key:1;
110111

111112
/* for PLL fix */
112113
hda_nid_t pll_nid;
@@ -2982,6 +2983,107 @@ static int alc269_parse_auto_config(struct hda_codec *codec)
29822983
return alc_parse_auto_config(codec, alc269_ignore, ssids);
29832984
}
29842985

2986+
static const struct hda_jack_keymap alc_headset_btn_keymap[] = {
2987+
{ SND_JACK_BTN_0, KEY_PLAYPAUSE },
2988+
{ SND_JACK_BTN_1, KEY_VOICECOMMAND },
2989+
{ SND_JACK_BTN_2, KEY_VOLUMEUP },
2990+
{ SND_JACK_BTN_3, KEY_VOLUMEDOWN },
2991+
{}
2992+
};
2993+
2994+
static void alc_headset_btn_callback(struct hda_codec *codec,
2995+
struct hda_jack_callback *jack)
2996+
{
2997+
int report = 0;
2998+
2999+
if (jack->unsol_res & (7 << 13))
3000+
report |= SND_JACK_BTN_0;
3001+
3002+
if (jack->unsol_res & (1 << 16 | 3 << 8))
3003+
report |= SND_JACK_BTN_1;
3004+
3005+
/* Volume up key */
3006+
if (jack->unsol_res & (7 << 23))
3007+
report |= SND_JACK_BTN_2;
3008+
3009+
/* Volume down key */
3010+
if (jack->unsol_res & (7 << 10))
3011+
report |= SND_JACK_BTN_3;
3012+
3013+
jack->jack->button_state = report;
3014+
}
3015+
3016+
static void alc_disable_headset_jack_key(struct hda_codec *codec)
3017+
{
3018+
struct alc_spec *spec = codec->spec;
3019+
3020+
if (!spec->has_hs_key)
3021+
return;
3022+
3023+
switch (codec->core.vendor_id) {
3024+
case 0x10ec0215:
3025+
case 0x10ec0225:
3026+
case 0x10ec0285:
3027+
case 0x10ec0295:
3028+
case 0x10ec0289:
3029+
case 0x10ec0299:
3030+
alc_write_coef_idx(codec, 0x48, 0x0);
3031+
alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
3032+
alc_update_coef_idx(codec, 0x44, 0x0045 << 8, 0x0);
3033+
break;
3034+
case 0x10ec0236:
3035+
case 0x10ec0256:
3036+
alc_write_coef_idx(codec, 0x48, 0x0);
3037+
alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
3038+
break;
3039+
}
3040+
}
3041+
3042+
static void alc_enable_headset_jack_key(struct hda_codec *codec)
3043+
{
3044+
struct alc_spec *spec = codec->spec;
3045+
3046+
if (!spec->has_hs_key)
3047+
return;
3048+
3049+
switch (codec->core.vendor_id) {
3050+
case 0x10ec0215:
3051+
case 0x10ec0225:
3052+
case 0x10ec0285:
3053+
case 0x10ec0295:
3054+
case 0x10ec0289:
3055+
case 0x10ec0299:
3056+
alc_write_coef_idx(codec, 0x48, 0xd011);
3057+
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
3058+
alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8);
3059+
break;
3060+
case 0x10ec0236:
3061+
case 0x10ec0256:
3062+
alc_write_coef_idx(codec, 0x48, 0xd011);
3063+
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
3064+
break;
3065+
}
3066+
}
3067+
3068+
static void alc_fixup_headset_jack(struct hda_codec *codec,
3069+
const struct hda_fixup *fix, int action)
3070+
{
3071+
struct alc_spec *spec = codec->spec;
3072+
3073+
switch (action) {
3074+
case HDA_FIXUP_ACT_PRE_PROBE:
3075+
spec->has_hs_key = 1;
3076+
snd_hda_jack_detect_enable_callback(codec, 0x55,
3077+
alc_headset_btn_callback);
3078+
snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", false,
3079+
SND_JACK_HEADSET, alc_headset_btn_keymap);
3080+
break;
3081+
case HDA_FIXUP_ACT_INIT:
3082+
alc_enable_headset_jack_key(codec);
3083+
break;
3084+
}
3085+
}
3086+
29853087
static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
29863088
{
29873089
alc_update_coef_idx(codec, 0x04, 1 << 11, power_up ? (1 << 11) : 0);
@@ -3372,6 +3474,8 @@ static void alc225_shutup(struct hda_codec *codec)
33723474

33733475
if (!hp_pin)
33743476
hp_pin = 0x21;
3477+
3478+
alc_disable_headset_jack_key(codec);
33753479
/* 3k pull low control for Headset jack. */
33763480
alc_update_coef_idx(codec, 0x4a, 0, 3 << 10);
33773481

@@ -3411,6 +3515,9 @@ static void alc225_shutup(struct hda_codec *codec)
34113515
alc_update_coef_idx(codec, 0x4a, 3<<4, 2<<4);
34123516
msleep(30);
34133517
}
3518+
3519+
alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
3520+
alc_enable_headset_jack_key(codec);
34143521
}
34153522

34163523
static void alc_default_init(struct hda_codec *codec)
@@ -5668,69 +5775,6 @@ static void alc285_fixup_invalidate_dacs(struct hda_codec *codec,
56685775
snd_hda_override_wcaps(codec, 0x03, 0);
56695776
}
56705777

5671-
static const struct hda_jack_keymap alc_headset_btn_keymap[] = {
5672-
{ SND_JACK_BTN_0, KEY_PLAYPAUSE },
5673-
{ SND_JACK_BTN_1, KEY_VOICECOMMAND },
5674-
{ SND_JACK_BTN_2, KEY_VOLUMEUP },
5675-
{ SND_JACK_BTN_3, KEY_VOLUMEDOWN },
5676-
{}
5677-
};
5678-
5679-
static void alc_headset_btn_callback(struct hda_codec *codec,
5680-
struct hda_jack_callback *jack)
5681-
{
5682-
int report = 0;
5683-
5684-
if (jack->unsol_res & (7 << 13))
5685-
report |= SND_JACK_BTN_0;
5686-
5687-
if (jack->unsol_res & (1 << 16 | 3 << 8))
5688-
report |= SND_JACK_BTN_1;
5689-
5690-
/* Volume up key */
5691-
if (jack->unsol_res & (7 << 23))
5692-
report |= SND_JACK_BTN_2;
5693-
5694-
/* Volume down key */
5695-
if (jack->unsol_res & (7 << 10))
5696-
report |= SND_JACK_BTN_3;
5697-
5698-
jack->jack->button_state = report;
5699-
}
5700-
5701-
static void alc_fixup_headset_jack(struct hda_codec *codec,
5702-
const struct hda_fixup *fix, int action)
5703-
{
5704-
5705-
switch (action) {
5706-
case HDA_FIXUP_ACT_PRE_PROBE:
5707-
snd_hda_jack_detect_enable_callback(codec, 0x55,
5708-
alc_headset_btn_callback);
5709-
snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack", false,
5710-
SND_JACK_HEADSET, alc_headset_btn_keymap);
5711-
break;
5712-
case HDA_FIXUP_ACT_INIT:
5713-
switch (codec->core.vendor_id) {
5714-
case 0x10ec0215:
5715-
case 0x10ec0225:
5716-
case 0x10ec0285:
5717-
case 0x10ec0295:
5718-
case 0x10ec0289:
5719-
case 0x10ec0299:
5720-
alc_write_coef_idx(codec, 0x48, 0xd011);
5721-
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
5722-
alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8);
5723-
break;
5724-
case 0x10ec0236:
5725-
case 0x10ec0256:
5726-
alc_write_coef_idx(codec, 0x48, 0xd011);
5727-
alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
5728-
break;
5729-
}
5730-
break;
5731-
}
5732-
}
5733-
57345778
static void alc295_fixup_chromebook(struct hda_codec *codec,
57355779
const struct hda_fixup *fix, int action)
57365780
{

0 commit comments

Comments
 (0)