diff options
Diffstat (limited to 'sound/pci')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 159 |
1 files changed, 101 insertions, 58 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 09b3f4b1db4d..4b7dda57c0e9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -36,10 +36,12 @@ | |||
36 | #include "hda_patch.h" | 36 | #include "hda_patch.h" |
37 | #include "hda_beep.h" | 37 | #include "hda_beep.h" |
38 | 38 | ||
39 | #define STAC_VREF_EVENT 0x00 | 39 | enum { |
40 | #define STAC_INSERT_EVENT 0x10 | 40 | STAC_VREF_EVENT = 1, |
41 | #define STAC_PWR_EVENT 0x20 | 41 | STAC_INSERT_EVENT, |
42 | #define STAC_HP_EVENT 0x30 | 42 | STAC_PWR_EVENT, |
43 | STAC_HP_EVENT, | ||
44 | }; | ||
43 | 45 | ||
44 | enum { | 46 | enum { |
45 | STAC_REF, | 47 | STAC_REF, |
@@ -134,6 +136,8 @@ enum { | |||
134 | 136 | ||
135 | struct sigmatel_event { | 137 | struct sigmatel_event { |
136 | hda_nid_t nid; | 138 | hda_nid_t nid; |
139 | unsigned char type; | ||
140 | unsigned char tag; | ||
137 | int data; | 141 | int data; |
138 | }; | 142 | }; |
139 | 143 | ||
@@ -2549,6 +2553,9 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol, | |||
2549 | return 0; | 2553 | return 0; |
2550 | } | 2554 | } |
2551 | 2555 | ||
2556 | static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, | ||
2557 | unsigned char type); | ||
2558 | |||
2552 | static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, | 2559 | static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, |
2553 | struct snd_ctl_elem_value *ucontrol) | 2560 | struct snd_ctl_elem_value *ucontrol) |
2554 | { | 2561 | { |
@@ -2561,7 +2568,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, | |||
2561 | /* check to be sure that the ports are upto date with | 2568 | /* check to be sure that the ports are upto date with |
2562 | * switch changes | 2569 | * switch changes |
2563 | */ | 2570 | */ |
2564 | codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26); | 2571 | stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); |
2565 | 2572 | ||
2566 | return 1; | 2573 | return 1; |
2567 | } | 2574 | } |
@@ -2601,8 +2608,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
2601 | * appropriately according to the pin direction | 2608 | * appropriately according to the pin direction |
2602 | */ | 2609 | */ |
2603 | if (spec->hp_detect) | 2610 | if (spec->hp_detect) |
2604 | codec->patch_ops.unsol_event(codec, | 2611 | stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); |
2605 | (STAC_HP_EVENT | nid) << 26); | ||
2606 | 2612 | ||
2607 | return 1; | 2613 | return 1; |
2608 | } | 2614 | } |
@@ -3768,8 +3774,8 @@ static int stac92xx_add_jack(struct hda_codec *codec, | |||
3768 | #endif | 3774 | #endif |
3769 | } | 3775 | } |
3770 | 3776 | ||
3771 | static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, | 3777 | static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, |
3772 | int data) | 3778 | unsigned char type, int data) |
3773 | { | 3779 | { |
3774 | struct sigmatel_event *event; | 3780 | struct sigmatel_event *event; |
3775 | 3781 | ||
@@ -3778,32 +3784,59 @@ static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, | |||
3778 | if (!event) | 3784 | if (!event) |
3779 | return -ENOMEM; | 3785 | return -ENOMEM; |
3780 | event->nid = nid; | 3786 | event->nid = nid; |
3787 | event->type = type; | ||
3788 | event->tag = spec->events.used; | ||
3781 | event->data = data; | 3789 | event->data = data; |
3782 | 3790 | ||
3783 | return 0; | 3791 | return event->tag; |
3784 | } | 3792 | } |
3785 | 3793 | ||
3786 | static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid) | 3794 | static struct sigmatel_event *stac_get_event(struct hda_codec *codec, |
3795 | hda_nid_t nid, unsigned char type) | ||
3787 | { | 3796 | { |
3788 | struct sigmatel_spec *spec = codec->spec; | 3797 | struct sigmatel_spec *spec = codec->spec; |
3789 | struct sigmatel_event *events = spec->events.list; | 3798 | struct sigmatel_event *event = spec->events.list; |
3790 | if (events) { | 3799 | int i; |
3791 | int i; | 3800 | |
3792 | for (i = 0; i < spec->events.used; i++) | 3801 | for (i = 0; i < spec->events.used; i++, event++) { |
3793 | if (events[i].nid == nid) | 3802 | if (event->nid == nid && event->type == type) |
3794 | return events[i].data; | 3803 | return event; |
3795 | } | 3804 | } |
3796 | return 0; | 3805 | return NULL; |
3797 | } | 3806 | } |
3798 | 3807 | ||
3799 | static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | 3808 | static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec, |
3800 | unsigned int event) | 3809 | unsigned char tag) |
3801 | { | 3810 | { |
3802 | if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { | 3811 | struct sigmatel_spec *spec = codec->spec; |
3803 | snd_hda_codec_write_cache(codec, nid, 0, | 3812 | struct sigmatel_event *event = spec->events.list; |
3804 | AC_VERB_SET_UNSOLICITED_ENABLE, | 3813 | int i; |
3805 | (AC_USRSP_EN | event | nid)); | 3814 | |
3815 | for (i = 0; i < spec->events.used; i++, event++) { | ||
3816 | if (event->tag == tag) | ||
3817 | return event; | ||
3806 | } | 3818 | } |
3819 | return NULL; | ||
3820 | } | ||
3821 | |||
3822 | static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, | ||
3823 | unsigned int type) | ||
3824 | { | ||
3825 | struct sigmatel_event *event; | ||
3826 | int tag; | ||
3827 | |||
3828 | if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) | ||
3829 | return; | ||
3830 | event = stac_get_event(codec, nid, type); | ||
3831 | if (event) | ||
3832 | tag = event->tag; | ||
3833 | else | ||
3834 | tag = stac_add_event(codec->spec, nid, type, 0); | ||
3835 | if (tag < 0) | ||
3836 | return; | ||
3837 | snd_hda_codec_write_cache(codec, nid, 0, | ||
3838 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
3839 | AC_USRSP_EN | tag); | ||
3807 | } | 3840 | } |
3808 | 3841 | ||
3809 | static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) | 3842 | static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) |
@@ -3862,7 +3895,7 @@ static int stac92xx_init(struct hda_codec *codec) | |||
3862 | /* Enable unsolicited responses on the HP widget */ | 3895 | /* Enable unsolicited responses on the HP widget */ |
3863 | for (i = 0; i < cfg->hp_outs; i++) { | 3896 | for (i = 0; i < cfg->hp_outs; i++) { |
3864 | hda_nid_t nid = cfg->hp_pins[i]; | 3897 | hda_nid_t nid = cfg->hp_pins[i]; |
3865 | enable_pin_detect(codec, nid, STAC_HP_EVENT | nid); | 3898 | enable_pin_detect(codec, nid, STAC_HP_EVENT); |
3866 | } | 3899 | } |
3867 | /* force to enable the first line-out; the others are set up | 3900 | /* force to enable the first line-out; the others are set up |
3868 | * in unsol_event | 3901 | * in unsol_event |
@@ -3870,8 +3903,8 @@ static int stac92xx_init(struct hda_codec *codec) | |||
3870 | stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], | 3903 | stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], |
3871 | AC_PINCTL_OUT_EN); | 3904 | AC_PINCTL_OUT_EN); |
3872 | /* fake event to set up pins */ | 3905 | /* fake event to set up pins */ |
3873 | codec->patch_ops.unsol_event(codec, | 3906 | stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], |
3874 | (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); | 3907 | STAC_HP_EVENT); |
3875 | } else { | 3908 | } else { |
3876 | stac92xx_auto_init_multi_out(codec); | 3909 | stac92xx_auto_init_multi_out(codec); |
3877 | stac92xx_auto_init_hp_out(codec); | 3910 | stac92xx_auto_init_hp_out(codec); |
@@ -3892,7 +3925,7 @@ static int stac92xx_init(struct hda_codec *codec) | |||
3892 | } | 3925 | } |
3893 | pinctl |= AC_PINCTL_IN_EN; | 3926 | pinctl |= AC_PINCTL_IN_EN; |
3894 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 3927 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
3895 | enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid); | 3928 | enable_pin_detect(codec, nid, STAC_INSERT_EVENT); |
3896 | } | 3929 | } |
3897 | } | 3930 | } |
3898 | for (i = 0; i < spec->num_dmics; i++) | 3931 | for (i = 0; i < spec->num_dmics; i++) |
@@ -3907,7 +3940,6 @@ static int stac92xx_init(struct hda_codec *codec) | |||
3907 | for (i = 0; i < spec->num_pwrs; i++) { | 3940 | for (i = 0; i < spec->num_pwrs; i++) { |
3908 | hda_nid_t nid = spec->pwr_nids[i]; | 3941 | hda_nid_t nid = spec->pwr_nids[i]; |
3909 | int pinctl, def_conf; | 3942 | int pinctl, def_conf; |
3910 | int event = STAC_PWR_EVENT; | ||
3911 | 3943 | ||
3912 | if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) | 3944 | if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) |
3913 | continue; /* already has an unsol event */ | 3945 | continue; /* already has an unsol event */ |
@@ -3930,8 +3962,8 @@ static int stac92xx_init(struct hda_codec *codec) | |||
3930 | stac_toggle_power_map(codec, nid, 1); | 3962 | stac_toggle_power_map(codec, nid, 1); |
3931 | continue; | 3963 | continue; |
3932 | } | 3964 | } |
3933 | enable_pin_detect(codec, spec->pwr_nids[i], event | i); | 3965 | enable_pin_detect(codec, nid, STAC_PWR_EVENT); |
3934 | codec->patch_ops.unsol_event(codec, (event | i) << 26); | 3966 | stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); |
3935 | } | 3967 | } |
3936 | if (spec->dac_list) | 3968 | if (spec->dac_list) |
3937 | stac92xx_power_down(codec); | 3969 | stac92xx_power_down(codec); |
@@ -4059,7 +4091,7 @@ static int no_hp_sensing(struct sigmatel_spec *spec, int i) | |||
4059 | return 0; | 4091 | return 0; |
4060 | } | 4092 | } |
4061 | 4093 | ||
4062 | static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) | 4094 | static void stac92xx_hp_detect(struct hda_codec *codec) |
4063 | { | 4095 | { |
4064 | struct sigmatel_spec *spec = codec->spec; | 4096 | struct sigmatel_spec *spec = codec->spec; |
4065 | struct auto_pin_cfg *cfg = &spec->autocfg; | 4097 | struct auto_pin_cfg *cfg = &spec->autocfg; |
@@ -4182,33 +4214,43 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) | |||
4182 | } | 4214 | } |
4183 | } | 4215 | } |
4184 | 4216 | ||
4217 | static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, | ||
4218 | unsigned char type) | ||
4219 | { | ||
4220 | struct sigmatel_event *event = stac_get_event(codec, nid, type); | ||
4221 | if (!event) | ||
4222 | return; | ||
4223 | codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26); | ||
4224 | } | ||
4225 | |||
4185 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) | 4226 | static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) |
4186 | { | 4227 | { |
4187 | struct sigmatel_spec *spec = codec->spec; | 4228 | struct sigmatel_spec *spec = codec->spec; |
4188 | int event = (res >> 26) & 0x70; | 4229 | struct sigmatel_event *event; |
4189 | int nid = res >> 26 & 0x0f; | 4230 | int tag, data; |
4190 | 4231 | ||
4191 | switch (event) { | 4232 | tag = (res >> 26) & 0x7f; |
4233 | event = stac_get_event_from_tag(codec, tag); | ||
4234 | if (!event) | ||
4235 | return; | ||
4236 | |||
4237 | switch (event->type) { | ||
4192 | case STAC_HP_EVENT: | 4238 | case STAC_HP_EVENT: |
4193 | stac92xx_hp_detect(codec, res); | 4239 | stac92xx_hp_detect(codec); |
4194 | /* fallthru */ | 4240 | /* fallthru */ |
4195 | case STAC_INSERT_EVENT: | 4241 | case STAC_INSERT_EVENT: |
4196 | case STAC_PWR_EVENT: | 4242 | case STAC_PWR_EVENT: |
4197 | if (nid) { | 4243 | if (spec->num_pwrs > 0) |
4198 | if (spec->num_pwrs > 0) | 4244 | stac92xx_pin_sense(codec, event->nid); |
4199 | stac92xx_pin_sense(codec, nid); | 4245 | stac92xx_report_jack(codec, event->nid); |
4200 | stac92xx_report_jack(codec, nid); | ||
4201 | } | ||
4202 | break; | 4246 | break; |
4203 | case STAC_VREF_EVENT: { | 4247 | case STAC_VREF_EVENT: |
4204 | int data = snd_hda_codec_read(codec, codec->afg, 0, | 4248 | data = snd_hda_codec_read(codec, codec->afg, 0, |
4205 | AC_VERB_GET_GPIO_DATA, 0); | 4249 | AC_VERB_GET_GPIO_DATA, 0); |
4206 | int idx = stac92xx_event_data(codec, nid); | ||
4207 | /* toggle VREF state based on GPIOx status */ | 4250 | /* toggle VREF state based on GPIOx status */ |
4208 | snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, | 4251 | snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, |
4209 | !!(data & (1 << idx))); | 4252 | !!(data & (1 << event->data))); |
4210 | break; | 4253 | break; |
4211 | } | ||
4212 | } | 4254 | } |
4213 | } | 4255 | } |
4214 | 4256 | ||
@@ -4223,8 +4265,8 @@ static int stac92xx_resume(struct hda_codec *codec) | |||
4223 | snd_hda_codec_resume_cache(codec); | 4265 | snd_hda_codec_resume_cache(codec); |
4224 | /* fake event to set up pins again to override cached values */ | 4266 | /* fake event to set up pins again to override cached values */ |
4225 | if (spec->hp_detect) | 4267 | if (spec->hp_detect) |
4226 | codec->patch_ops.unsol_event(codec, | 4268 | stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], |
4227 | (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); | 4269 | STAC_HP_EVENT); |
4228 | return 0; | 4270 | return 0; |
4229 | } | 4271 | } |
4230 | 4272 | ||
@@ -4732,14 +4774,15 @@ again: | |||
4732 | switch (spec->board_config) { | 4774 | switch (spec->board_config) { |
4733 | case STAC_HP_M4: | 4775 | case STAC_HP_M4: |
4734 | /* Enable VREF power saving on GPIO1 detect */ | 4776 | /* Enable VREF power saving on GPIO1 detect */ |
4777 | err = stac_add_event(spec, codec->afg, | ||
4778 | STAC_VREF_EVENT, 0x02); | ||
4779 | if (err < 0) | ||
4780 | return err; | ||
4735 | snd_hda_codec_write_cache(codec, codec->afg, 0, | 4781 | snd_hda_codec_write_cache(codec, codec->afg, 0, |
4736 | AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); | 4782 | AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); |
4737 | snd_hda_codec_write_cache(codec, codec->afg, 0, | 4783 | snd_hda_codec_write_cache(codec, codec->afg, 0, |
4738 | AC_VERB_SET_UNSOLICITED_ENABLE, | 4784 | AC_VERB_SET_UNSOLICITED_ENABLE, |
4739 | (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); | 4785 | AC_USRSP_EN | err); |
4740 | err = stac92xx_add_event(spec, codec->afg, 0x02); | ||
4741 | if (err < 0) | ||
4742 | return err; | ||
4743 | spec->gpio_mask |= 0x02; | 4786 | spec->gpio_mask |= 0x02; |
4744 | break; | 4787 | break; |
4745 | } | 4788 | } |
@@ -5131,14 +5174,14 @@ static int patch_stac9205(struct hda_codec *codec) | |||
5131 | stac_change_pin_config(codec, 0x20, 0x1c410030); | 5174 | stac_change_pin_config(codec, 0x20, 0x1c410030); |
5132 | 5175 | ||
5133 | /* Enable unsol response for GPIO4/Dock HP connection */ | 5176 | /* Enable unsol response for GPIO4/Dock HP connection */ |
5177 | err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01); | ||
5178 | if (err < 0) | ||
5179 | return err; | ||
5134 | snd_hda_codec_write_cache(codec, codec->afg, 0, | 5180 | snd_hda_codec_write_cache(codec, codec->afg, 0, |
5135 | AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); | 5181 | AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); |
5136 | snd_hda_codec_write_cache(codec, codec->afg, 0, | 5182 | snd_hda_codec_write_cache(codec, codec->afg, 0, |
5137 | AC_VERB_SET_UNSOLICITED_ENABLE, | 5183 | AC_VERB_SET_UNSOLICITED_ENABLE, |
5138 | (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); | 5184 | AC_USRSP_EN | err); |
5139 | err = stac92xx_add_event(spec, codec->afg, 0x01); | ||
5140 | if (err < 0) | ||
5141 | return err; | ||
5142 | 5185 | ||
5143 | spec->gpio_dir = 0x0b; | 5186 | spec->gpio_dir = 0x0b; |
5144 | spec->eapd_mask = 0x01; | 5187 | spec->eapd_mask = 0x01; |