Commit 187d333edc0a8e1bb507900ce89853ffe3bd2c84
1 parent
92bb43e6aa
Exists in
master
and in
6 other branches
ALSA: hda - Fix jack-detection control of VT1708
VT1708 has no support for unsolicited events per jack-plug, the driver implements the workq for polling the jack-detection. The mixer element "Jack Detect" was supposed to control this behavior on/off, but this doesn't work properly as is now. The workq is always started and the HP automute is always enabled. This patch fixes the jack-detect control behavior by triggering / stopping the work appropriately at the state change. Also the work checks the internal state to continue scheduling or not. Cc: <stable@kernel.org> [v3.1] Signed-off-by: Takashi Iwai <tiwai@suse.de>
Showing 1 changed file with 43 additions and 33 deletions Side-by-side Diff
sound/pci/hda/patch_via.c
... | ... | @@ -208,6 +208,7 @@ |
208 | 208 | /* work to check hp jack state */ |
209 | 209 | struct hda_codec *codec; |
210 | 210 | struct delayed_work vt1708_hp_work; |
211 | + int hp_work_active; | |
211 | 212 | int vt1708_jack_detect; |
212 | 213 | int vt1708_hp_present; |
213 | 214 | |
214 | 215 | |
215 | 216 | |
216 | 217 | |
... | ... | @@ -305,27 +306,35 @@ |
305 | 306 | static void analog_low_current_mode(struct hda_codec *codec); |
306 | 307 | static bool is_aa_path_mute(struct hda_codec *codec); |
307 | 308 | |
308 | -static void vt1708_start_hp_work(struct via_spec *spec) | |
309 | +#define hp_detect_with_aa(codec) \ | |
310 | + (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1 && \ | |
311 | + !is_aa_path_mute(codec)) | |
312 | + | |
313 | +static void vt1708_stop_hp_work(struct via_spec *spec) | |
309 | 314 | { |
310 | 315 | if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) |
311 | 316 | return; |
312 | - snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, | |
313 | - !spec->vt1708_jack_detect); | |
314 | - if (!delayed_work_pending(&spec->vt1708_hp_work)) | |
315 | - schedule_delayed_work(&spec->vt1708_hp_work, | |
316 | - msecs_to_jiffies(100)); | |
317 | + if (spec->hp_work_active) { | |
318 | + snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 1); | |
319 | + cancel_delayed_work_sync(&spec->vt1708_hp_work); | |
320 | + spec->hp_work_active = 0; | |
321 | + } | |
317 | 322 | } |
318 | 323 | |
319 | -static void vt1708_stop_hp_work(struct via_spec *spec) | |
324 | +static void vt1708_update_hp_work(struct via_spec *spec) | |
320 | 325 | { |
321 | 326 | if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) |
322 | 327 | return; |
323 | - if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1 | |
324 | - && !is_aa_path_mute(spec->codec)) | |
325 | - return; | |
326 | - snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, | |
327 | - !spec->vt1708_jack_detect); | |
328 | - cancel_delayed_work_sync(&spec->vt1708_hp_work); | |
328 | + if (spec->vt1708_jack_detect && | |
329 | + (spec->active_streams || hp_detect_with_aa(spec->codec))) { | |
330 | + if (!spec->hp_work_active) { | |
331 | + snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 0); | |
332 | + schedule_delayed_work(&spec->vt1708_hp_work, | |
333 | + msecs_to_jiffies(100)); | |
334 | + spec->hp_work_active = 1; | |
335 | + } | |
336 | + } else if (!hp_detect_with_aa(spec->codec)) | |
337 | + vt1708_stop_hp_work(spec); | |
329 | 338 | } |
330 | 339 | |
331 | 340 | static void set_widgets_power_state(struct hda_codec *codec) |
... | ... | @@ -343,12 +352,7 @@ |
343 | 352 | |
344 | 353 | set_widgets_power_state(codec); |
345 | 354 | analog_low_current_mode(snd_kcontrol_chip(kcontrol)); |
346 | - if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { | |
347 | - if (is_aa_path_mute(codec)) | |
348 | - vt1708_start_hp_work(codec->spec); | |
349 | - else | |
350 | - vt1708_stop_hp_work(codec->spec); | |
351 | - } | |
355 | + vt1708_update_hp_work(codec->spec); | |
352 | 356 | return change; |
353 | 357 | } |
354 | 358 | |
... | ... | @@ -1154,7 +1158,7 @@ |
1154 | 1158 | spec->cur_dac_stream_tag = stream_tag; |
1155 | 1159 | spec->cur_dac_format = format; |
1156 | 1160 | mutex_unlock(&spec->config_mutex); |
1157 | - vt1708_start_hp_work(spec); | |
1161 | + vt1708_update_hp_work(spec); | |
1158 | 1162 | return 0; |
1159 | 1163 | } |
1160 | 1164 | |
... | ... | @@ -1174,7 +1178,7 @@ |
1174 | 1178 | spec->cur_hp_stream_tag = stream_tag; |
1175 | 1179 | spec->cur_hp_format = format; |
1176 | 1180 | mutex_unlock(&spec->config_mutex); |
1177 | - vt1708_start_hp_work(spec); | |
1181 | + vt1708_update_hp_work(spec); | |
1178 | 1182 | return 0; |
1179 | 1183 | } |
1180 | 1184 | |
... | ... | @@ -1188,7 +1192,7 @@ |
1188 | 1192 | snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); |
1189 | 1193 | spec->active_streams &= ~STREAM_MULTI_OUT; |
1190 | 1194 | mutex_unlock(&spec->config_mutex); |
1191 | - vt1708_stop_hp_work(spec); | |
1195 | + vt1708_update_hp_work(spec); | |
1192 | 1196 | return 0; |
1193 | 1197 | } |
1194 | 1198 | |
... | ... | @@ -1203,7 +1207,7 @@ |
1203 | 1207 | snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0); |
1204 | 1208 | spec->active_streams &= ~STREAM_INDEP_HP; |
1205 | 1209 | mutex_unlock(&spec->config_mutex); |
1206 | - vt1708_stop_hp_work(spec); | |
1210 | + vt1708_update_hp_work(spec); | |
1207 | 1211 | return 0; |
1208 | 1212 | } |
1209 | 1213 | |
... | ... | @@ -1645,7 +1649,8 @@ |
1645 | 1649 | int nums; |
1646 | 1650 | struct via_spec *spec = codec->spec; |
1647 | 1651 | |
1648 | - if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0]) | |
1652 | + if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0] && | |
1653 | + (spec->codec_type != VT1708 || spec->vt1708_jack_detect)) | |
1649 | 1654 | present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); |
1650 | 1655 | |
1651 | 1656 | if (spec->smart51_enabled) |
... | ... | @@ -2612,8 +2617,6 @@ |
2612 | 2617 | |
2613 | 2618 | if (spec->codec_type != VT1708) |
2614 | 2619 | return 0; |
2615 | - spec->vt1708_jack_detect = | |
2616 | - !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1); | |
2617 | 2620 | ucontrol->value.integer.value[0] = spec->vt1708_jack_detect; |
2618 | 2621 | return 0; |
2619 | 2622 | } |
2620 | 2623 | |
2621 | 2624 | |
... | ... | @@ -2623,18 +2626,22 @@ |
2623 | 2626 | { |
2624 | 2627 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2625 | 2628 | struct via_spec *spec = codec->spec; |
2626 | - int change; | |
2629 | + int val; | |
2627 | 2630 | |
2628 | 2631 | if (spec->codec_type != VT1708) |
2629 | 2632 | return 0; |
2630 | - spec->vt1708_jack_detect = ucontrol->value.integer.value[0]; | |
2631 | - change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8)) | |
2632 | - == !spec->vt1708_jack_detect; | |
2633 | - if (spec->vt1708_jack_detect) { | |
2633 | + val = !!ucontrol->value.integer.value[0]; | |
2634 | + if (spec->vt1708_jack_detect == val) | |
2635 | + return 0; | |
2636 | + spec->vt1708_jack_detect = val; | |
2637 | + if (spec->vt1708_jack_detect && | |
2638 | + snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") != 1) { | |
2634 | 2639 | mute_aa_path(codec, 1); |
2635 | 2640 | notify_aa_path_ctls(codec); |
2636 | 2641 | } |
2637 | - return change; | |
2642 | + via_hp_automute(codec); | |
2643 | + vt1708_update_hp_work(spec); | |
2644 | + return 1; | |
2638 | 2645 | } |
2639 | 2646 | |
2640 | 2647 | static const struct snd_kcontrol_new vt1708_jack_detect_ctl = { |
... | ... | @@ -2771,6 +2778,7 @@ |
2771 | 2778 | via_auto_init_unsol_event(codec); |
2772 | 2779 | |
2773 | 2780 | via_hp_automute(codec); |
2781 | + vt1708_update_hp_work(spec); | |
2774 | 2782 | |
2775 | 2783 | return 0; |
2776 | 2784 | } |
... | ... | @@ -2787,7 +2795,9 @@ |
2787 | 2795 | spec->vt1708_hp_present ^= 1; |
2788 | 2796 | via_hp_automute(spec->codec); |
2789 | 2797 | } |
2790 | - vt1708_start_hp_work(spec); | |
2798 | + if (spec->vt1708_jack_detect) | |
2799 | + schedule_delayed_work(&spec->vt1708_hp_work, | |
2800 | + msecs_to_jiffies(100)); | |
2791 | 2801 | } |
2792 | 2802 | |
2793 | 2803 | static int get_mux_nids(struct hda_codec *codec) |