aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_sigmatel.c
diff options
context:
space:
mode:
authorMatthew Ranostay <mranostay@embeddedalley.com>2008-10-25 01:06:04 -0400
committerTakashi Iwai <tiwai@suse.de>2008-10-27 03:15:15 -0400
commit74aeaabc3e452b29bc1b9eac5aa48923569f8a4e (patch)
treee9d9ecc7e98560fc8e1093419c3d9a4bf204b7cd /sound/pci/hda/patch_sigmatel.c
parent50a9f7905fb3e6ae25e80ba443a14d878caef0c9 (diff)
ALSA: hda: add support for jack detection on IDT codecs.
This patch adds support to the IDT codec families to report jack status to the jack abstraction layer. This required some reorganization in the stac92xx_unsol_event function in which the index value is changed to reporting the nid with the event. Also adds an sigmatel_jack struct to keep track of the nid relation to the jack abstraction layer instance. Also adds functions to set and retrieve data values for each nid, this is used in stac92xx_unsol_event to retrieve the GPIO mask for STAC_VREF_EVENT. Signed-off-by: Matthew Ranostay <mranostay@embeddedalley.com> 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.c203
1 files changed, 170 insertions, 33 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index d106ea52a90d..c24d22fddd09 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -36,6 +36,7 @@
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_INSERT_EVENT 0x10
39#define STAC_PWR_EVENT 0x20 40#define STAC_PWR_EVENT 0x20
40#define STAC_HP_EVENT 0x30 41#define STAC_HP_EVENT 0x30
41#define STAC_VREF_EVENT 0x40 42#define STAC_VREF_EVENT 0x40
@@ -129,6 +130,17 @@ enum {
129 STAC_927X_MODELS 130 STAC_927X_MODELS
130}; 131};
131 132
133struct sigmatel_event {
134 hda_nid_t nid;
135 int data;
136};
137
138struct sigmatel_jack {
139 hda_nid_t nid;
140 int type;
141 struct snd_jack *jack;
142};
143
132struct sigmatel_spec { 144struct sigmatel_spec {
133 struct snd_kcontrol_new *mixers[4]; 145 struct snd_kcontrol_new *mixers[4];
134 unsigned int num_mixers; 146 unsigned int num_mixers;
@@ -161,6 +173,12 @@ struct sigmatel_spec {
161 hda_nid_t *pwr_nids; 173 hda_nid_t *pwr_nids;
162 hda_nid_t *dac_list; 174 hda_nid_t *dac_list;
163 175
176 /* jack detection */
177 struct snd_array jacks;
178
179 /* events */
180 struct snd_array events;
181
164 /* playback */ 182 /* playback */
165 struct hda_input_mux *mono_mux; 183 struct hda_input_mux *mono_mux;
166 struct hda_input_mux *amp_mux; 184 struct hda_input_mux *amp_mux;
@@ -216,9 +234,6 @@ struct sigmatel_spec {
216 234
217 struct hda_pcm pcm_rec[2]; /* PCM information */ 235 struct hda_pcm pcm_rec[2]; /* PCM information */
218 236
219 /* jack detection */
220 struct snd_jack *jack;
221
222 /* dynamic controls and input_mux */ 237 /* dynamic controls and input_mux */
223 struct auto_pin_cfg autocfg; 238 struct auto_pin_cfg autocfg;
224 struct snd_array kctls; 239 struct snd_array kctls;
@@ -2458,13 +2473,15 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol,
2458{ 2473{
2459 struct hda_codec *codec = snd_kcontrol_chip(kcontrol); 2474 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2460 struct sigmatel_spec *spec = codec->spec; 2475 struct sigmatel_spec *spec = codec->spec;
2476 struct auto_pin_cfg *cfg = &spec->autocfg;
2477 int nid = cfg->hp_pins[cfg->hp_outs - 1];
2461 2478
2462 spec->hp_switch = ucontrol->value.integer.value[0]; 2479 spec->hp_switch = ucontrol->value.integer.value[0];
2463 2480
2464 /* check to be sure that the ports are upto date with 2481 /* check to be sure that the ports are upto date with
2465 * switch changes 2482 * switch changes
2466 */ 2483 */
2467 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); 2484 codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26);
2468 2485
2469 return 1; 2486 return 1;
2470} 2487}
@@ -2504,7 +2521,8 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_
2504 * appropriately according to the pin direction 2521 * appropriately according to the pin direction
2505 */ 2522 */
2506 if (spec->hp_detect) 2523 if (spec->hp_detect)
2507 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); 2524 codec->patch_ops.unsol_event(codec,
2525 (STAC_HP_EVENT | nid) << 26);
2508 2526
2509 return 1; 2527 return 1;
2510} 2528}
@@ -3574,13 +3592,70 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
3574 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ 3592 AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
3575} 3593}
3576 3594
3595static int stac92xx_add_jack(struct hda_codec *codec,
3596 hda_nid_t nid, int type)
3597{
3598 struct sigmatel_spec *spec = codec->spec;
3599 struct sigmatel_jack *jack;
3600 int def_conf = snd_hda_codec_read(codec, nid,
3601 0, AC_VERB_GET_CONFIG_DEFAULT, 0);
3602 int connectivity = get_defcfg_connect(def_conf);
3603 char name[32];
3604
3605 if (connectivity && connectivity != AC_JACK_PORT_FIXED)
3606 return 0;
3607
3608 snd_array_init(&spec->jacks, sizeof(*jack), 32);
3609 jack = snd_array_new(&spec->jacks);
3610 if (!jack)
3611 return -ENOMEM;
3612 jack->nid = nid;
3613 jack->type = type;
3614
3615 sprintf(name, "%s at %s %s Jack",
3616 snd_hda_get_jack_type(def_conf),
3617 snd_hda_get_jack_connectivity(def_conf),
3618 snd_hda_get_jack_location(def_conf));
3619
3620 return snd_jack_new(codec->bus->card, name, type, &jack->jack);
3621}
3622
3623static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid,
3624 int data)
3625{
3626 struct sigmatel_event *event;
3627
3628 snd_array_init(&spec->events, sizeof(*event), 32);
3629 event = snd_array_new(&spec->events);
3630 if (!event)
3631 return -ENOMEM;
3632 event->nid = nid;
3633 event->data = data;
3634
3635 return 0;
3636}
3637
3638static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid)
3639{
3640 struct sigmatel_spec *spec = codec->spec;
3641 struct sigmatel_event *events = spec->events.list;
3642 if (events) {
3643 int i;
3644 for (i = 0; i < spec->events.used; i++)
3645 if (events[i].nid == nid)
3646 return events[i].data;
3647 }
3648 return 0;
3649}
3650
3577static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, 3651static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid,
3578 unsigned int event) 3652 unsigned int event)
3579{ 3653{
3580 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) 3654 if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
3581 snd_hda_codec_write_cache(codec, nid, 0, 3655 snd_hda_codec_write_cache(codec, nid, 0,
3582 AC_VERB_SET_UNSOLICITED_ENABLE, 3656 AC_VERB_SET_UNSOLICITED_ENABLE,
3583 (AC_USRSP_EN | event)); 3657 (AC_USRSP_EN | event | nid));
3658 }
3584} 3659}
3585 3660
3586static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) 3661static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid)
@@ -3623,27 +3698,36 @@ static int stac92xx_init(struct hda_codec *codec)
3623 /* set up pins */ 3698 /* set up pins */
3624 if (spec->hp_detect) { 3699 if (spec->hp_detect) {
3625 /* Enable unsolicited responses on the HP widget */ 3700 /* Enable unsolicited responses on the HP widget */
3626 for (i = 0; i < cfg->hp_outs; i++) 3701 for (i = 0; i < cfg->hp_outs; i++) {
3627 enable_pin_detect(codec, cfg->hp_pins[i], 3702 int type = SND_JACK_HEADPHONE;
3628 STAC_HP_EVENT); 3703 hda_nid_t nid = cfg->hp_pins[i];
3704 enable_pin_detect(codec, nid, STAC_HP_EVENT | nid);
3705 /* jack detection */
3706 if (cfg->hp_outs == i)
3707 type |= SND_JACK_LINEOUT;
3708 err = stac92xx_add_jack(codec, nid, type);
3709 if (err < 0)
3710 return err;
3711
3712 }
3629 /* force to enable the first line-out; the others are set up 3713 /* force to enable the first line-out; the others are set up
3630 * in unsol_event 3714 * in unsol_event
3631 */ 3715 */
3632 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], 3716 stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0],
3633 AC_PINCTL_OUT_EN); 3717 AC_PINCTL_OUT_EN);
3634 stac92xx_auto_init_hp_out(codec);
3635 /* jack detection */
3636 err = snd_jack_new(codec->bus->card,
3637 "Headphone Jack",
3638 SND_JACK_HEADPHONE, &spec->jack);
3639 if (err < 0)
3640 return err;
3641 /* fake event to set up pins */ 3718 /* fake event to set up pins */
3642 codec->patch_ops.unsol_event(codec, STAC_HP_EVENT << 26); 3719 codec->patch_ops.unsol_event(codec,
3720 (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26);
3643 } else { 3721 } else {
3644 stac92xx_auto_init_multi_out(codec); 3722 stac92xx_auto_init_multi_out(codec);
3645 stac92xx_auto_init_hp_out(codec); 3723 stac92xx_auto_init_hp_out(codec);
3646 } 3724 }
3725 for (i = 0; i < cfg->line_outs; i++) {
3726 err = stac92xx_add_jack(codec,
3727 cfg->line_out_pins[i], SND_JACK_LINEOUT);
3728 if (err < 0)
3729 return err;
3730 }
3647 for (i = 0; i < AUTO_PIN_LAST; i++) { 3731 for (i = 0; i < AUTO_PIN_LAST; i++) {
3648 hda_nid_t nid = cfg->input_pins[i]; 3732 hda_nid_t nid = cfg->input_pins[i];
3649 if (nid) { 3733 if (nid) {
@@ -3656,6 +3740,11 @@ static int stac92xx_init(struct hda_codec *codec)
3656 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) 3740 if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC)
3657 pinctl |= stac92xx_get_vref(codec, nid); 3741 pinctl |= stac92xx_get_vref(codec, nid);
3658 stac92xx_auto_set_pinctl(codec, nid, pinctl); 3742 stac92xx_auto_set_pinctl(codec, nid, pinctl);
3743 err = stac92xx_add_jack(codec, nid,
3744 SND_JACK_MICROPHONE);
3745 if (err < 0)
3746 return err;
3747 enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid);
3659 } 3748 }
3660 } 3749 }
3661 for (i = 0; i < spec->num_dmics; i++) 3750 for (i = 0; i < spec->num_dmics; i++)
@@ -3697,6 +3786,18 @@ static int stac92xx_init(struct hda_codec *codec)
3697 return 0; 3786 return 0;
3698} 3787}
3699 3788
3789static void stac92xx_free_jacks(struct hda_codec *codec)
3790{
3791 struct sigmatel_spec *spec = codec->spec;
3792 if (spec->jacks.list) {
3793 struct sigmatel_jack *jacks = spec->jacks.list;
3794 int i;
3795 for (i = 0; i < spec->jacks.used; i++)
3796 snd_device_free(codec->bus->card, &jacks[i].jack);
3797 }
3798 snd_array_free(&spec->jacks);
3799}
3800
3700static void stac92xx_free_kctls(struct hda_codec *codec) 3801static void stac92xx_free_kctls(struct hda_codec *codec)
3701{ 3802{
3702 struct sigmatel_spec *spec = codec->spec; 3803 struct sigmatel_spec *spec = codec->spec;
@@ -3717,11 +3818,10 @@ static void stac92xx_free(struct hda_codec *codec)
3717 if (! spec) 3818 if (! spec)
3718 return; 3819 return;
3719 3820
3720 if (spec->jack)
3721 snd_device_free(codec->bus->card, spec->jack);
3722
3723 if (spec->bios_pin_configs) 3821 if (spec->bios_pin_configs)
3724 kfree(spec->bios_pin_configs); 3822 kfree(spec->bios_pin_configs);
3823 stac92xx_free_jacks(codec);
3824 snd_array_free(&spec->events);
3725 3825
3726 kfree(spec); 3826 kfree(spec);
3727 snd_hda_detach_beep_device(codec); 3827 snd_hda_detach_beep_device(codec);
@@ -3804,8 +3904,6 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res)
3804 break; 3904 break;
3805 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]); 3905 presence = get_hp_pin_presence(codec, cfg->hp_pins[i]);
3806 } 3906 }
3807 snd_jack_report(spec->jack,
3808 presence ? SND_JACK_HEADPHONE : 0);
3809 3907
3810 if (presence) { 3908 if (presence) {
3811 /* disable lineouts, enable hp */ 3909 /* disable lineouts, enable hp */
@@ -3862,24 +3960,57 @@ static void stac92xx_pin_sense(struct hda_codec *codec, int idx)
3862 3960
3863 /* power down unused output ports */ 3961 /* power down unused output ports */
3864 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val); 3962 snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val);
3865}; 3963}
3964
3965static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid)
3966{
3967 struct sigmatel_spec *spec = codec->spec;
3968 struct sigmatel_jack *jacks = spec->jacks.list;
3969
3970 if (jacks) {
3971 int i;
3972 for (i = 0; i < spec->jacks.used; i++) {
3973 if (jacks->nid == nid) {
3974 unsigned int pin_ctl =
3975 snd_hda_codec_read(codec, nid,
3976 0, AC_VERB_GET_PIN_WIDGET_CONTROL,
3977 0x00);
3978 int type = jacks->type;
3979 if (type == (SND_JACK_LINEOUT
3980 | SND_JACK_HEADPHONE))
3981 type = (pin_ctl & AC_PINCTL_HP_EN)
3982 ? SND_JACK_HEADPHONE : SND_JACK_LINEOUT;
3983 snd_jack_report(jacks->jack,
3984 get_hp_pin_presence(codec, nid)
3985 ? type : 0);
3986 }
3987 jacks++;
3988 }
3989 }
3990}
3866 3991
3867static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) 3992static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res)
3868{ 3993{
3869 struct sigmatel_spec *spec = codec->spec; 3994 struct sigmatel_spec *spec = codec->spec;
3870 int idx = res >> 26 & 0x0f; 3995 int event = (res >> 26) & 0x70;
3996 int nid = res >> 26 & 0x0f;
3871 3997
3872 switch ((res >> 26) & 0x70) { 3998 switch (event) {
3873 case STAC_HP_EVENT: 3999 case STAC_HP_EVENT:
3874 stac92xx_hp_detect(codec, res); 4000 stac92xx_hp_detect(codec, res);
3875 /* fallthru */ 4001 /* fallthru */
4002 case STAC_INSERT_EVENT:
3876 case STAC_PWR_EVENT: 4003 case STAC_PWR_EVENT:
3877 if (spec->num_pwrs > 0) 4004 if (nid) {
3878 stac92xx_pin_sense(codec, idx); 4005 if (spec->num_pwrs > 0)
4006 stac92xx_pin_sense(codec, nid);
4007 stac92xx_report_jack(codec, nid);
4008 }
3879 break; 4009 break;
3880 case STAC_VREF_EVENT: { 4010 case STAC_VREF_EVENT: {
3881 int data = snd_hda_codec_read(codec, codec->afg, 0, 4011 int data = snd_hda_codec_read(codec, codec->afg, 0,
3882 AC_VERB_GET_GPIO_DATA, 0); 4012 AC_VERB_GET_GPIO_DATA, 0);
4013 int idx = stac92xx_event_data(codec, nid);
3883 /* toggle VREF state based on GPIOx status */ 4014 /* toggle VREF state based on GPIOx status */
3884 snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, 4015 snd_hda_codec_write(codec, codec->afg, 0, 0x7e0,
3885 !!(data & (1 << idx))); 4016 !!(data & (1 << idx)));
@@ -4402,8 +4533,11 @@ again:
4402 snd_hda_codec_write(codec, codec->afg, 0, 4533 snd_hda_codec_write(codec, codec->afg, 0,
4403 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); 4534 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
4404 snd_hda_codec_write_cache(codec, codec->afg, 0, 4535 snd_hda_codec_write_cache(codec, codec->afg, 0,
4405 AC_VERB_SET_UNSOLICITED_ENABLE, 4536 AC_VERB_SET_UNSOLICITED_ENABLE,
4406 (AC_USRSP_EN | STAC_VREF_EVENT | 0x01)); 4537 (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
4538 err = stac92xx_add_event(spec, codec->afg, 0x02);
4539 if (err < 0)
4540 return err;
4407 spec->gpio_mask |= 0x02; 4541 spec->gpio_mask |= 0x02;
4408 break; 4542 break;
4409 } 4543 }
@@ -4802,8 +4936,11 @@ static int patch_stac9205(struct hda_codec *codec)
4802 snd_hda_codec_write(codec, codec->afg, 0, 4936 snd_hda_codec_write(codec, codec->afg, 0,
4803 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); 4937 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
4804 snd_hda_codec_write_cache(codec, codec->afg, 0, 4938 snd_hda_codec_write_cache(codec, codec->afg, 0,
4805 AC_VERB_SET_UNSOLICITED_ENABLE, 4939 AC_VERB_SET_UNSOLICITED_ENABLE,
4806 (AC_USRSP_EN | STAC_HP_EVENT)); 4940 (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg));
4941 err = stac92xx_add_event(spec, codec->afg, 0x01);
4942 if (err < 0)
4943 return err;
4807 4944
4808 spec->gpio_dir = 0x0b; 4945 spec->gpio_dir = 0x0b;
4809 spec->eapd_mask = 0x01; 4946 spec->eapd_mask = 0x01;