diff options
author | Takashi Iwai <tiwai@suse.de> | 2008-11-25 12:01:58 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2008-11-25 12:01:58 +0100 |
commit | 3de78ef5c743f4963f4374a3deb236e4cc0393fa (patch) | |
tree | eafd1c73897fd7ddba6ba500d675b8f21c7e5915 /sound | |
parent | 799834ec1a74e464f0039cb344faa3608f19fec2 (diff) | |
parent | c6e4c66613c2bb040e53bb04006c277992cc8f4b (diff) |
Merge branch 'topic/hda' into for-next
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/hda/hda_codec.c | 4 | ||||
-rw-r--r-- | sound/pci/hda/hda_proc.c | 2 | ||||
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 235 |
3 files changed, 156 insertions, 85 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d56d11ab20a3..53f64eb75ec6 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1586,12 +1586,12 @@ static void set_dig_out(struct hda_codec *codec, hda_nid_t nid, { hda_nid_t *d; - snd_hda_codec_write(codec, nid, 0, verb, val); + snd_hda_codec_write_cache(codec, nid, 0, verb, val); d = codec->slave_dig_outs; if (!d) return; for (; *d; d++) - snd_hda_codec_write(codec, *d, 0, verb, val); + snd_hda_codec_write_cache(codec, *d, 0, verb, val); } static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid, diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index e7f91c44e631..a2eba4f17e9c 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -103,7 +103,7 @@ static void print_pcm_bits(struct snd_info_buffer *buffer, unsigned int pcm) { char buf[SND_PRINT_BITS_ADVISED_BUFSIZE]; - snd_iprintf(buffer, " bits [0x%x]:", pcm); + snd_iprintf(buffer, " bits [0x%x]:", (pcm & AC_SUPPCM_RATES) >> 16); snd_print_pcm_bits(pcm, buf, sizeof(buf)); snd_iprintf(buffer, "%s\n", buf); } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7cd395a175ef..4b7dda57c0e9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -36,10 +36,12 @@ #include "hda_patch.h" #include "hda_beep.h" -#define STAC_VREF_EVENT 0x00 -#define STAC_INSERT_EVENT 0x10 -#define STAC_PWR_EVENT 0x20 -#define STAC_HP_EVENT 0x30 +enum { + STAC_VREF_EVENT = 1, + STAC_INSERT_EVENT, + STAC_PWR_EVENT, + STAC_HP_EVENT, +}; enum { STAC_REF, @@ -134,6 +136,8 @@ enum { struct sigmatel_event { hda_nid_t nid; + unsigned char type; + unsigned char tag; int data; }; @@ -2549,6 +2553,9 @@ static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol, return 0; } +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, + unsigned char type); + static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2561,7 +2568,7 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, /* check to be sure that the ports are upto date with * switch changes */ - codec->patch_ops.unsol_event(codec, (STAC_HP_EVENT | nid) << 26); + stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); return 1; } @@ -2601,8 +2608,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ * appropriately according to the pin direction */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, - (STAC_HP_EVENT | nid) << 26); + stac_issue_unsol_event(codec, nid, STAC_HP_EVENT); return 1; } @@ -3768,8 +3774,8 @@ static int stac92xx_add_jack(struct hda_codec *codec, #endif } -static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, - int data) +static int stac_add_event(struct sigmatel_spec *spec, hda_nid_t nid, + unsigned char type, int data) { struct sigmatel_event *event; @@ -3778,32 +3784,59 @@ static int stac92xx_add_event(struct sigmatel_spec *spec, hda_nid_t nid, if (!event) return -ENOMEM; event->nid = nid; + event->type = type; + event->tag = spec->events.used; event->data = data; - return 0; + return event->tag; } -static int stac92xx_event_data(struct hda_codec *codec, hda_nid_t nid) +static struct sigmatel_event *stac_get_event(struct hda_codec *codec, + hda_nid_t nid, unsigned char type) { struct sigmatel_spec *spec = codec->spec; - struct sigmatel_event *events = spec->events.list; - if (events) { - int i; - for (i = 0; i < spec->events.used; i++) - if (events[i].nid == nid) - return events[i].data; + struct sigmatel_event *event = spec->events.list; + int i; + + for (i = 0; i < spec->events.used; i++, event++) { + if (event->nid == nid && event->type == type) + return event; } - return 0; + return NULL; } -static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, - unsigned int event) +static struct sigmatel_event *stac_get_event_from_tag(struct hda_codec *codec, + unsigned char tag) { - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | event | nid)); + struct sigmatel_spec *spec = codec->spec; + struct sigmatel_event *event = spec->events.list; + int i; + + for (i = 0; i < spec->events.used; i++, event++) { + if (event->tag == tag) + return event; } + return NULL; +} + +static void enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, + unsigned int type) +{ + struct sigmatel_event *event; + int tag; + + if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + return; + event = stac_get_event(codec, nid, type); + if (event) + tag = event->tag; + else + tag = stac_add_event(codec->spec, nid, type, 0); + if (tag < 0) + return; + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | tag); } static int is_nid_hp_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) @@ -3829,10 +3862,14 @@ static void stac92xx_power_down(struct hda_codec *codec) AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } +static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, + int enable); + static int stac92xx_init(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int gpio; int i; snd_hda_sequence_write(codec, spec->init); @@ -3843,12 +3880,22 @@ static int stac92xx_init(struct hda_codec *codec) snd_hda_codec_write_cache(codec, spec->adc_nids[i], 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + + /* set up GPIO */ + gpio = spec->gpio_data; + /* turn on EAPD statically when spec->eapd_switch isn't set. + * otherwise, unsol event will turn it on/off dynamically + */ + if (!spec->eapd_switch) + gpio |= spec->eapd_mask; + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio); + /* set up pins */ if (spec->hp_detect) { /* Enable unsolicited responses on the HP widget */ for (i = 0; i < cfg->hp_outs; i++) { hda_nid_t nid = cfg->hp_pins[i]; - enable_pin_detect(codec, nid, STAC_HP_EVENT | nid); + enable_pin_detect(codec, nid, STAC_HP_EVENT); } /* force to enable the first line-out; the others are set up * in unsol_event @@ -3856,8 +3903,8 @@ static int stac92xx_init(struct hda_codec *codec) stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], AC_PINCTL_OUT_EN); /* fake event to set up pins */ - codec->patch_ops.unsol_event(codec, - (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); + stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], + STAC_HP_EVENT); } else { stac92xx_auto_init_multi_out(codec); stac92xx_auto_init_hp_out(codec); @@ -3878,45 +3925,48 @@ static int stac92xx_init(struct hda_codec *codec) } pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); - enable_pin_detect(codec, nid, STAC_INSERT_EVENT | nid); + enable_pin_detect(codec, nid, STAC_INSERT_EVENT); } } for (i = 0; i < spec->num_dmics; i++) stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], AC_PINCTL_IN_EN); + if (cfg->dig_out_pin) + stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, + AC_PINCTL_OUT_EN); + if (cfg->dig_in_pin) + stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, + AC_PINCTL_IN_EN); for (i = 0; i < spec->num_pwrs; i++) { - int event = is_nid_hp_pin(cfg, spec->pwr_nids[i]) - ? STAC_HP_EVENT : STAC_PWR_EVENT; - int pinctl = snd_hda_codec_read(codec, spec->pwr_nids[i], - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - int def_conf = snd_hda_codec_read(codec, spec->pwr_nids[i], - 0, AC_VERB_GET_CONFIG_DEFAULT, 0); - def_conf = get_defcfg_connect(def_conf); + hda_nid_t nid = spec->pwr_nids[i]; + int pinctl, def_conf; + + if (is_nid_hp_pin(cfg, nid) && spec->hp_detect) + continue; /* already has an unsol event */ + + pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); /* outputs are only ports capable of power management * any attempts on powering down a input port cause the * referenced VREF to act quirky. */ if (pinctl & AC_PINCTL_IN_EN) continue; + def_conf = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONFIG_DEFAULT, 0); + def_conf = get_defcfg_connect(def_conf); /* skip any ports that don't have jacks since presence * detection is useless */ - if (def_conf && def_conf != AC_JACK_PORT_FIXED) + if (def_conf != AC_JACK_PORT_COMPLEX) { + if (def_conf != AC_JACK_PORT_NONE) + stac_toggle_power_map(codec, nid, 1); continue; - enable_pin_detect(codec, spec->pwr_nids[i], event | i); - codec->patch_ops.unsol_event(codec, (event | i) << 26); + } + enable_pin_detect(codec, nid, STAC_PWR_EVENT); + stac_issue_unsol_event(codec, nid, STAC_PWR_EVENT); } if (spec->dac_list) stac92xx_power_down(codec); - if (cfg->dig_out_pin) - stac92xx_auto_set_pinctl(codec, cfg->dig_out_pin, - AC_PINCTL_OUT_EN); - if (cfg->dig_in_pin) - stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, - AC_PINCTL_IN_EN); - - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); - return 0; } @@ -4041,7 +4091,7 @@ static int no_hp_sensing(struct sigmatel_spec *spec, int i) return 0; } -static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) +static void stac92xx_hp_detect(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; @@ -4103,14 +4153,18 @@ static void stac92xx_hp_detect(struct hda_codec *codec, unsigned int res) } } -static void stac92xx_pin_sense(struct hda_codec *codec, int idx) +static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, + int enable) { struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = spec->pwr_nids[idx]; - int presence, val; - val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) - & 0x000000ff; - presence = get_hp_pin_presence(codec, nid); + unsigned int idx, val; + + for (idx = 0; idx < spec->num_pwrs; idx++) { + if (spec->pwr_nids[idx] == nid) + break; + } + if (idx >= spec->num_pwrs) + return; /* several codecs have two power down bits */ if (spec->pwr_mapping) @@ -4118,7 +4172,8 @@ static void stac92xx_pin_sense(struct hda_codec *codec, int idx) else idx = 1 << idx; - if (presence) + val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff; + if (enable) val &= ~idx; else val |= idx; @@ -4127,6 +4182,11 @@ static void stac92xx_pin_sense(struct hda_codec *codec, int idx) snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val); } +static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) +{ + stac_toggle_power_map(codec, nid, get_hp_pin_presence(codec, nid)); +} + static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) { struct sigmatel_spec *spec = codec->spec; @@ -4154,33 +4214,43 @@ static void stac92xx_report_jack(struct hda_codec *codec, hda_nid_t nid) } } +static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid, + unsigned char type) +{ + struct sigmatel_event *event = stac_get_event(codec, nid, type); + if (!event) + return; + codec->patch_ops.unsol_event(codec, (unsigned)event->tag << 26); +} + static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) { struct sigmatel_spec *spec = codec->spec; - int event = (res >> 26) & 0x70; - int nid = res >> 26 & 0x0f; + struct sigmatel_event *event; + int tag, data; + + tag = (res >> 26) & 0x7f; + event = stac_get_event_from_tag(codec, tag); + if (!event) + return; - switch (event) { + switch (event->type) { case STAC_HP_EVENT: - stac92xx_hp_detect(codec, res); + stac92xx_hp_detect(codec); /* fallthru */ case STAC_INSERT_EVENT: case STAC_PWR_EVENT: - if (nid) { - if (spec->num_pwrs > 0) - stac92xx_pin_sense(codec, nid); - stac92xx_report_jack(codec, nid); - } + if (spec->num_pwrs > 0) + stac92xx_pin_sense(codec, event->nid); + stac92xx_report_jack(codec, event->nid); break; - case STAC_VREF_EVENT: { - int data = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - int idx = stac92xx_event_data(codec, nid); + case STAC_VREF_EVENT: + data = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); /* toggle VREF state based on GPIOx status */ snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, - !!(data & (1 << idx))); + !!(data & (1 << event->data))); break; - } } } @@ -4195,8 +4265,8 @@ static int stac92xx_resume(struct hda_codec *codec) snd_hda_codec_resume_cache(codec); /* fake event to set up pins again to override cached values */ if (spec->hp_detect) - codec->patch_ops.unsol_event(codec, - (STAC_HP_EVENT | spec->autocfg.hp_pins[0]) << 26); + stac_issue_unsol_event(codec, spec->autocfg.hp_pins[0], + STAC_HP_EVENT); return 0; } @@ -4704,14 +4774,15 @@ again: switch (spec->board_config) { case STAC_HP_M4: /* Enable VREF power saving on GPIO1 detect */ + err = stac_add_event(spec, codec->afg, + STAC_VREF_EVENT, 0x02); + if (err < 0) + return err; snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); - err = stac92xx_add_event(spec, codec->afg, 0x02); - if (err < 0) - return err; + AC_USRSP_EN | err); spec->gpio_mask |= 0x02; break; } @@ -5103,14 +5174,14 @@ static int patch_stac9205(struct hda_codec *codec) stac_change_pin_config(codec, 0x20, 0x1c410030); /* Enable unsol response for GPIO4/Dock HP connection */ + err = stac_add_event(spec, codec->afg, STAC_VREF_EVENT, 0x01); + if (err < 0) + return err; snd_hda_codec_write_cache(codec, codec->afg, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - (AC_USRSP_EN | STAC_VREF_EVENT | codec->afg)); - err = stac92xx_add_event(spec, codec->afg, 0x01); - if (err < 0) - return err; + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | err); spec->gpio_dir = 0x0b; spec->eapd_mask = 0x01; |