[ALSA] hda: add sigmatel hp detect support

HDA Codec driver
Adds support for detecting hp insertion/removal and enable/disable of
lineouts based on unsolicited events.

Signed-off-by: Matt <matt@embeddedalley.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by Matt and committed by Jaroslav Kysela 4e55096e 41e2fce4

+63 -2
+3
sound/pci/hda/hda_codec.h
··· 262 262 #define AC_PINCTL_OUT_EN (1<<6) 263 263 #define AC_PINCTL_HP_EN (1<<7) 264 264 265 + /* Unsolicited response - 8bit */ 266 + #define AC_USRSP_EN (1<<7) 267 + 265 268 /* configuration default - 32bit */ 266 269 #define AC_DEFCFG_SEQUENCE (0xf<<0) 267 270 #define AC_DEFCFG_DEF_ASSOC (0xf<<4)
+60 -2
sound/pci/hda/patch_sigmatel.c
··· 36 36 37 37 #undef STAC_TEST 38 38 39 + #define NUM_CONTROL_ALLOC 32 40 + #define STAC_HP_EVENT 0x37 41 + #define STAC_UNSOL_ENABLE (AC_USRSP_EN | STAC_HP_EVENT) 42 + 39 43 struct sigmatel_spec { 40 44 snd_kcontrol_new_t *mixers[4]; 41 45 unsigned int num_mixers; ··· 511 507 return 0; 512 508 } 513 509 514 - #define NUM_CONTROL_ALLOC 32 515 - 516 510 enum { 517 511 STAC_CTL_WIDGET_VOL, 518 512 STAC_CTL_WIDGET_MUTE, ··· 619 617 hda_nid_t pin = cfg->hp_pin; 620 618 hda_nid_t nid; 621 619 int i, err; 620 + unsigned int wid_caps; 622 621 623 622 if (! pin) 624 623 return 0; 624 + 625 + wid_caps = snd_hda_param_read(codec, pin, AC_PAR_AUDIO_WIDGET_CAP); 626 + if (wid_caps & AC_WCAP_UNSOL_CAP) 627 + /* Enable unsolicited responses on the HP widget */ 628 + snd_hda_codec_write(codec, pin, 0, 629 + AC_VERB_SET_UNSOLICITED_ENABLE, 630 + STAC_UNSOL_ENABLE); 625 631 626 632 nid = snd_hda_codec_read(codec, pin, 0, AC_VERB_GET_CONNECT_LIST, 0) & 0xff; 627 633 for (i = 0; i < cfg->line_outs; i++) { ··· 838 828 kfree(spec); 839 829 } 840 830 831 + static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, 832 + unsigned int flag) 833 + { 834 + unsigned int pin_ctl = snd_hda_codec_read(codec, nid, 835 + 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); 836 + snd_hda_codec_write(codec, nid, 0, 837 + AC_VERB_SET_PIN_WIDGET_CONTROL, 838 + pin_ctl | flag); 839 + } 840 + 841 + static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, 842 + unsigned int flag) 843 + { 844 + unsigned int pin_ctl = snd_hda_codec_read(codec, nid, 845 + 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); 846 + snd_hda_codec_write(codec, nid, 0, 847 + AC_VERB_SET_PIN_WIDGET_CONTROL, 848 + pin_ctl & ~flag); 849 + } 850 + 851 + static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) 852 + { 853 + struct sigmatel_spec *spec = codec->spec; 854 + struct auto_pin_cfg *cfg = &spec->autocfg; 855 + int i, presence; 856 + 857 + if ((res >> 26) != STAC_HP_EVENT) 858 + return; 859 + 860 + presence = snd_hda_codec_read(codec, cfg->hp_pin, 0, 861 + AC_VERB_GET_PIN_SENSE, 0x00) >> 31; 862 + 863 + if (presence) { 864 + /* disable lineouts, enable hp */ 865 + for (i = 0; i < cfg->line_outs; i++) 866 + stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], 867 + AC_PINCTL_OUT_EN); 868 + stac92xx_set_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); 869 + } else { 870 + /* enable lineouts, disable hp */ 871 + for (i = 0; i < cfg->line_outs; i++) 872 + stac92xx_set_pinctl(codec, cfg->line_out_pins[i], 873 + AC_PINCTL_OUT_EN); 874 + stac92xx_reset_pinctl(codec, cfg->hp_pin, AC_PINCTL_OUT_EN); 875 + } 876 + } 877 + 841 878 #ifdef CONFIG_PM 842 879 static int stac92xx_resume(struct hda_codec *codec) 843 880 { ··· 908 851 .build_pcms = stac92xx_build_pcms, 909 852 .init = stac92xx_init, 910 853 .free = stac92xx_free, 854 + .unsol_event = stac92xx_unsol_event, 911 855 #ifdef CONFIG_PM 912 856 .resume = stac92xx_resume, 913 857 #endif