aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_sigmatel.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-11-25 05:58:19 -0500
committerTakashi Iwai <tiwai@suse.de>2008-11-25 05:58:19 -0500
commitc6e4c66613c2bb040e53bb04006c277992cc8f4b (patch)
tree264d627e4e10ed8ea1ef2888ae38bed487eef33c /sound/pci/hda/patch_sigmatel.c
parent0e19e7d2bff0ec04fe4dc920c580d8a321afa07f (diff)
ALSA: hda - Assign unsol tags dynamically in patch_sigmatel.c
Since we need to handle many unsolicited events assigned to different widgets, allocate the event dynamically using the existing events array, and use the tag appropriately instead of combination of fixed number and widget nid. (Note that widget nid can be over 4 bits!) Also, replaced the call of unsol_event handler with a dedicated function to be more readable. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda/patch_sigmatel.c')
-rw-r--r--sound/pci/hda/patch_sigmatel.c159
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 39enum {
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
44enum { 46enum {
45 STAC_REF, 47 STAC_REF,
@@ -134,6 +136,8 @@ enum {
134 136
135struct sigmatel_event { 137struct 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
2556static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid,
2557 unsigned char type);
2558
2552static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, 2559static 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
3771static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, 3777static 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
3786static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid) 3794static 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
3799static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, 3808static 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
3822static 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
3809static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) 3842static 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
4062static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) 4094static 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
4217static 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
4185static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) 4226static 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;