summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2008-11-25 12:01:58 +0100
committerTakashi Iwai <tiwai@suse.de>2008-11-25 12:01:58 +0100
commit3de78ef5c743f4963f4374a3deb236e4cc0393fa (patch)
treeeafd1c73897fd7ddba6ba500d675b8f21c7e5915 /sound
parent799834ec1a74e464f0039cb344faa3608f19fec2 (diff)
parentc6e4c66613c2bb040e53bb04006c277992cc8f4b (diff)
Merge branch 'topic/hda' into for-next
Diffstat (limited to 'sound')
-rw-r--r--sound/pci/hda/hda_codec.c4
-rw-r--r--sound/pci/hda/hda_proc.c2
-rw-r--r--sound/pci/hda/patch_sigmatel.c235
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;