[alsa-devel] HDA: STAC92xx: [PATCH v2] : add support for missing features + fix two bugs in new dynamic powersave mode
Hi,
This is new version of my patchset to improve STAC driver. I fixed all issues you told me about.
Note that I also fixed two bugs in hda driver itself, and this is why I didn't have sound after resume-from ram.
Best regards, Maxim Levitsky
From 90380fbb9865dda45a5be8085ef556f3ce203244 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky maximlevitsky@gmail.com Date: Mon, 3 Sep 2007 14:01:52 +0300 Subject: [PATCH] fix a race in dynamic power managment
codec->power_transition is supposed to be true while codec is going to be shut off if in the mean time somebody calls snd_hda_power_up, hda_power_work will not shut down the codec, but nether will clear codec->power_transition, thus it stays on forever. Fix this
Signed-off-by: Maxim Levitsky maximlevitsky@gmail.com --- pci/hda/hda_codec.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/pci/hda/hda_codec.c b/pci/hda/hda_codec.c index 46d4253..08104e2 100644 --- a/pci/hda/hda_codec.c +++ b/pci/hda/hda_codec.c @@ -2195,8 +2195,10 @@ static void hda_power_work(struct work_struct *work) struct hda_codec *codec = container_of(work, struct hda_codec, power_work.work);
- if (!codec->power_on || codec->power_count) + if (!codec->power_on || codec->power_count) { + codec->power_transition = 0; return; + }
hda_call_codec_suspend(codec); if (codec->bus->ops.pm_notify)
From 3d4f5b6dcf586277ca6ca4ea86068e01566c58c0 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky maximlevitsky@gmail.com Date: Mon, 3 Sep 2007 14:10:11 +0300 Subject: [PATCH] Fix resume logic, when dynamic power managment is on
Comment in hda_intel.c states that "the explicit resume is needed only when POWER_SAVE isn't set", but this is not true. There is no code that will automaticly power up the codec on resume, but only code that powers it up when user accesses it. So if user leaves a sound playing, codec will not be powered
To fix that I check if there are any codecs that should be powered codec->power_count, and if so I power them up together with main controller.
Signed-off-by: Maxim Levitsky maximlevitsky@gmail.com --- pci/hda/hda_codec.c | 16 +++++++++++++--- pci/hda/hda_codec.h | 4 ++++ pci/hda/hda_intel.c | 8 ++++---- 3 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/pci/hda/hda_codec.c b/pci/hda/hda_codec.c index 08104e2..e594de0 100644 --- a/pci/hda/hda_codec.c +++ b/pci/hda/hda_codec.c @@ -2787,7 +2787,6 @@ int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) return 0; }
-#ifndef CONFIG_SND_HDA_POWER_SAVE /** * snd_hda_resume - resume the codecs * @bus: the HDA bus @@ -2803,10 +2802,21 @@ int snd_hda_resume(struct hda_bus *bus) struct hda_codec *codec;
list_for_each_entry(codec, &bus->codec_list, list) { - hda_call_codec_resume(codec); + if (snd_hda_codec_needs_resume(codec)) + hda_call_codec_resume(codec); } return 0; } -#endif /* !CONFIG_SND_HDA_POWER_SAVE */ +#ifdef CONFIG_SND_HDA_POWER_SAVE +int snd_hda_codecs_inuse(struct hda_bus *bus) +{ + struct hda_codec *codec;
+ list_for_each_entry(codec, &bus->codec_list, list) { + if (snd_hda_codec_needs_resume(codec)) + return 1; + } + return 0; +} +#endif #endif diff --git a/pci/hda/hda_codec.h b/pci/hda/hda_codec.h index ca157e5..2bce925 100644 --- a/pci/hda/hda_codec.h +++ b/pci/hda/hda_codec.h @@ -686,9 +686,13 @@ int snd_hda_resume(struct hda_bus *bus); #ifdef CONFIG_SND_HDA_POWER_SAVE void snd_hda_power_up(struct hda_codec *codec); void snd_hda_power_down(struct hda_codec *codec); +#define snd_hda_codec_needs_resume(codec) codec->power_count +int snd_hda_codecs_inuse(struct hda_bus *bus); #else static inline void snd_hda_power_up(struct hda_codec *codec) {} static inline void snd_hda_power_down(struct hda_codec *codec) {} +#define snd_hda_codec_needs_resume(codec) 1 +#define snd_hda_codecs_inuse(bus) 1 #endif
#endif /* __SOUND_HDA_CODEC_H */ diff --git a/pci/hda/hda_intel.c b/pci/hda/hda_intel.c index 3d06ecc..72fd345 100644 --- a/pci/hda/hda_intel.c +++ b/pci/hda/hda_intel.c @@ -1586,11 +1586,11 @@ static int azx_resume(struct pci_dev *pci) if (azx_acquire_irq(chip, 1) < 0) return -EIO; azx_init_pci(chip); -#ifndef CONFIG_SND_HDA_POWER_SAVE - /* the explicit resume is needed only when POWER_SAVE isn't set */ - azx_init_chip(chip); + + if (snd_hda_codecs_inuse(chip->bus)) + azx_init_chip(chip); + snd_hda_resume(chip->bus); -#endif snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; }
From 3292af8a515804fa8ad7452a3384ea523511c16f Mon Sep 17 00:00:00 2001 From: Maxim Levitsky maximlevitsky@gmail.com Date: Mon, 3 Sep 2007 14:12:56 +0300 Subject: [PATCH] add support for swapping center/LFE channels
Center\LFE channels are located on same jack, so it can be usefull to swap them
Signed-off-by: Maxim Levitsky maximlevitsky@gmail.com --- pci/hda/patch_sigmatel.c | 76 +++++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/pci/hda/patch_sigmatel.c b/pci/hda/patch_sigmatel.c index b4a1d73..297f740 100644 --- a/pci/hda/patch_sigmatel.c +++ b/pci/hda/patch_sigmatel.c @@ -146,6 +146,7 @@ struct sigmatel_spec {
/* i/o switches */ unsigned int io_switch[2]; + unsigned int clfe_swap;
struct hda_pcm pcm_rec[2]; /* PCM information */
@@ -1406,6 +1407,36 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ return 1; }
+#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info + +static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + ucontrol->value.integer.value[0] = spec->clfe_swap; + return 0; +} + +static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + hda_nid_t nid = kcontrol->private_value & 0xff; + + if (spec->clfe_swap == ucontrol->value.integer.value[0]) + return 0; + + spec->clfe_swap = ucontrol->value.integer.value[0]; + + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, + spec->clfe_swap ? 0x4 : 0x0); + + return 1; +} + #define STAC_CODEC_IO_SWITCH(xname, xpval) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -1416,17 +1447,28 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ .private_value = xpval, \ }
+#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = 0, \ + .info = stac92xx_clfe_switch_info, \ + .get = stac92xx_clfe_switch_get, \ + .put = stac92xx_clfe_switch_put, \ + .private_value = xpval, \ + }
enum { STAC_CTL_WIDGET_VOL, STAC_CTL_WIDGET_MUTE, STAC_CTL_WIDGET_IO_SWITCH, + STAC_CTL_WIDGET_CLFE_SWITCH };
static struct snd_kcontrol_new stac92xx_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), STAC_CODEC_IO_SWITCH(NULL, 0), + STAC_CODEC_CLFE_SWITCH(NULL, 0), };
/* add dynamic controls */ @@ -1620,7 +1662,7 @@ static int create_controls(struct sigmatel_spec *spec, const char *pfx, hda_nid_ }
/* add playback controls from the parsed DAC table */ -static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, +static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) { static const char *chname[4] = { @@ -1629,6 +1671,10 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, hda_nid_t nid; int i, err;
+ struct sigmatel_spec *spec = codec->spec; + unsigned int wid_caps; + + for (i = 0; i < cfg->line_outs; i++) { if (!spec->multiout.dac_nids[i]) continue; @@ -1643,6 +1689,18 @@ static int stac92xx_auto_create_multi_out_ctls(struct sigmatel_spec *spec, err = create_controls(spec, "LFE", nid, 2); if (err < 0) return err; + + wid_caps = get_wcaps(codec, nid); + + if (wid_caps & AC_WCAP_LR_SWAP) { + err = stac92xx_add_control(spec, + STAC_CTL_WIDGET_CLFE_SWITCH, + "Swap Center/LFE Playback Switch", nid); + + if (err < 0) + return err; + } + } else { err = create_controls(spec, chname[i], nid, 3); if (err < 0) @@ -1895,9 +1953,19 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out if ((err = stac92xx_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) return err;
- if ((err = stac92xx_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg)) < 0 || - (err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) + err = stac92xx_auto_create_multi_out_ctls(codec, &spec->autocfg); + + if (err < 0) + return err; + + err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); + + if (err < 0) + return err; + + err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); + + if (err < 0) return err;
if (spec->num_dmics > 0)
From ea1a7a5a8113f8c39db8391226adbbe383f03355 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky maximlevitsky@gmail.com Date: Mon, 3 Sep 2007 14:18:17 +0300 Subject: [PATCH] add support for analog loopback to STAC9204/9205/922x/927x
The analog loopback routes the sound just before it enters ADC0 to output of DAC0
Signed-off-by: Maxim Levitsky maximlevitsky@gmail.com --- pci/hda/patch_sigmatel.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 58 insertions(+), 0 deletions(-)
diff --git a/pci/hda/patch_sigmatel.c b/pci/hda/patch_sigmatel.c index 297f740..c94775c 100644 --- a/pci/hda/patch_sigmatel.c +++ b/pci/hda/patch_sigmatel.c @@ -147,6 +147,7 @@ struct sigmatel_spec { /* i/o switches */ unsigned int io_switch[2]; unsigned int clfe_swap; + unsigned int aloopback;
struct hda_pcm pcm_rec[2]; /* PCM information */
@@ -296,6 +297,49 @@ static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); }
+#define stac92xx_aloopback_info snd_ctl_boolean_mono_info + +static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + + ucontrol->value.integer.value[0] = spec->aloopback; + return 0; +} + +static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int dac_mode; + + if (spec->aloopback == ucontrol->value.integer.value[0]) + return 0; + + spec->aloopback = ucontrol->value.integer.value[0]; + + + dac_mode = snd_hda_codec_read(codec, codec->afg, 0, + kcontrol->private_value & 0xFFFF, 0x0); + + if (spec->aloopback) { + snd_hda_power_up(codec); + dac_mode |= 0x40; + } else { + snd_hda_power_down(codec); + dac_mode &= ~0x40; + } + + snd_hda_codec_write_cache(codec, codec->afg, 0, + kcontrol->private_value >> 16, dac_mode); + + return 1; +} + + static struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -346,6 +390,17 @@ static struct hda_verb stac9205_core_init[] = { .put = stac92xx_mux_enum_put, \ }
+#define STAC_ANALOG_LOOPBACK(verb_read,verb_write) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Analog Loopback", \ + .count = 1, \ + .info = stac92xx_aloopback_info, \ + .get = stac92xx_aloopback_get, \ + .put = stac92xx_aloopback_put, \ + .private_value = verb_read | (verb_write << 16), \ + } +
static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), @@ -377,6 +432,7 @@ static struct snd_kcontrol_new stac922x_mixer[] = { /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac9227_mixer[] = { STAC_INPUT_SOURCE, + STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), { } /* end */ @@ -384,6 +440,7 @@ static struct snd_kcontrol_new stac9227_mixer[] = {
static struct snd_kcontrol_new stac927x_mixer[] = { STAC_INPUT_SOURCE, + STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -400,6 +457,7 @@ static struct snd_kcontrol_new stac9205_mixer[] = { .put = stac92xx_dmux_enum_put, }, STAC_INPUT_SOURCE, + STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT),
From f1a1841750108ec025c807f1ae3718d55baa8d00 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky maximlevitsky@gmail.com Date: Mon, 3 Sep 2007 14:24:47 +0300 Subject: [PATCH] make volume knob, the master volume for sigmatel codecs that support it
VolumeKnob is present on most sigmatel codecs, it allows to decrease volume of all DACs at once, it is a kind of post-procesing volume. Note that all output amps of sigmatel only decrease volume, and all input amps only increase volume
Signed-off-by: Maxim Levitsky maximlevitsky@gmail.com --- pci/hda/patch_sigmatel.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 48 insertions(+), 0 deletions(-)
diff --git a/pci/hda/patch_sigmatel.c b/pci/hda/patch_sigmatel.c index c94775c..a2b1dd5 100644 --- a/pci/hda/patch_sigmatel.c +++ b/pci/hda/patch_sigmatel.c @@ -339,6 +339,39 @@ static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, return 1; }
+static int stac92xx_volknob_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 127; + return 0; +} + +static int stac92xx_volknob_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = kcontrol->private_value; + return 0; +} + +static int stac92xx_volknob_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + + if (kcontrol->private_value == ucontrol->value.integer.value[0]) + return 0; + + kcontrol->private_value = ucontrol->value.integer.value[0]; + + snd_hda_codec_write_cache(codec, 0x24, 0, + AC_VERB_SET_VOLUME_KNOB_CONTROL, + kcontrol->private_value | 0x80); + return 1; +} +
static struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ @@ -401,6 +434,17 @@ static struct hda_verb stac9205_core_init[] = { .private_value = verb_read | (verb_write << 16), \ }
+#define STAC_VOLKNOB \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Master Playback Volume", \ + .count = 1, \ + .info = stac92xx_volknob_info, \ + .get = stac92xx_volknob_get, \ + .put = stac92xx_volknob_put, \ + .private_value = 127, \ + } +
static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), @@ -423,6 +467,7 @@ static struct snd_kcontrol_new stac925x_mixer[] = { /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac922x_mixer[] = { STAC_INPUT_SOURCE, + STAC_VOLKNOB, HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), @@ -432,6 +477,7 @@ static struct snd_kcontrol_new stac922x_mixer[] = { /* This needs to be generated dynamically based on sequence */ static struct snd_kcontrol_new stac9227_mixer[] = { STAC_INPUT_SOURCE, + STAC_VOLKNOB, STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), @@ -440,6 +486,7 @@ static struct snd_kcontrol_new stac9227_mixer[] = {
static struct snd_kcontrol_new stac927x_mixer[] = { STAC_INPUT_SOURCE, + STAC_VOLKNOB, STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), @@ -458,6 +505,7 @@ static struct snd_kcontrol_new stac9205_mixer[] = { }, STAC_INPUT_SOURCE, STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), + STAC_VOLKNOB, HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT),
From a9771c6b2f84583c5154cdc8e266cdaab3076720 Mon Sep 17 00:00:00 2001 From: Maxim Levitsky maximlevitsky@gmail.com Date: Mon, 3 Sep 2007 14:27:57 +0300 Subject: [PATCH] Fix support for sigmatel codecs that have 2 or more ADCs
1) Create seperate mixer controls for each ADC 2) Make number of substreams of capture PCM device be equal to number of ADCs
Signed-off-by: Maxim Levitsky maximlevitsky@gmail.com --- pci/hda/patch_sigmatel.c | 97 +++++++++++++++++++++++++++------------------- 1 files changed, 57 insertions(+), 40 deletions(-)
diff --git a/pci/hda/patch_sigmatel.c b/pci/hda/patch_sigmatel.c index a2b1dd5..6dffa54 100644 --- a/pci/hda/patch_sigmatel.c +++ b/pci/hda/patch_sigmatel.c @@ -413,11 +413,11 @@ static struct hda_verb stac9205_core_init[] = { {} };
-#define STAC_INPUT_SOURCE \ +#define STAC_INPUT_SOURCE(cnt) \ { \ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = "Input Source", \ - .count = 1, \ + .count = cnt, \ .info = stac92xx_mux_enum_info, \ .get = stac92xx_mux_enum_get, \ .put = stac92xx_mux_enum_put, \ @@ -449,7 +449,7 @@ static struct hda_verb stac9205_core_init[] = { static struct snd_kcontrol_new stac9200_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), - STAC_INPUT_SOURCE, + STAC_INPUT_SOURCE(1), HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Mux Volume", 0x0c, 0, HDA_OUTPUT), @@ -457,58 +457,68 @@ static struct snd_kcontrol_new stac9200_mixer[] = { };
static struct snd_kcontrol_new stac925x_mixer[] = { - STAC_INPUT_SOURCE, + STAC_INPUT_SOURCE(1), HDA_CODEC_VOLUME("Capture Volume", 0x09, 0, HDA_OUTPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0, HDA_OUTPUT), HDA_CODEC_VOLUME("Capture Mux Volume", 0x0f, 0, HDA_OUTPUT), { } /* end */ };
-/* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac922x_mixer[] = { - STAC_INPUT_SOURCE, +static struct snd_kcontrol_new stac9205_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Input Source", + .count = 1, + .info = stac92xx_dmux_enum_info, + .get = stac92xx_dmux_enum_get, + .put = stac92xx_dmux_enum_put, + }, + STAC_INPUT_SOURCE(2), + STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), STAC_VOLKNOB, - HDA_CODEC_VOLUME("Capture Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mux Capture Volume", 0x12, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x1b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x19, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x1c, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1e, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x1A, 0x0, HDA_OUTPUT), + { } /* end */ };
/* This needs to be generated dynamically based on sequence */ -static struct snd_kcontrol_new stac9227_mixer[] = { - STAC_INPUT_SOURCE, +static struct snd_kcontrol_new stac922x_mixer[] = { + STAC_INPUT_SOURCE(2), STAC_VOLKNOB, - STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x17, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x17, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x12, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x13, 0x0, HDA_OUTPUT), { } /* end */ };
+ static struct snd_kcontrol_new stac927x_mixer[] = { - STAC_INPUT_SOURCE, + STAC_INPUT_SOURCE(3), STAC_VOLKNOB, STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB), - HDA_CODEC_VOLUME("InMux Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("InVol Capture Volume", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1b, 0x0, HDA_OUTPUT), - { } /* end */ -};
-static struct snd_kcontrol_new stac9205_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Input Source", - .count = 1, - .info = stac92xx_dmux_enum_info, - .get = stac92xx_dmux_enum_get, - .put = stac92xx_dmux_enum_put, - }, - STAC_INPUT_SOURCE, - STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0), - STAC_VOLKNOB, - HDA_CODEC_VOLUME("InMux Capture Volume", 0x19, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("InVol Capture Volume", 0x1b, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("ADCMux Capture Switch", 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x0, 0x18, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x0, 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x0, 0x15, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x1, 0x19, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x1, 0x1c, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x1, 0x16, 0x0, HDA_OUTPUT), + + HDA_CODEC_VOLUME_IDX("Capture Volume", 0x2, 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 0x2, 0x1d, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME_IDX("Mux Capture Volume", 0x2, 0x17, 0x0, HDA_OUTPUT), { } /* end */ };
@@ -1410,10 +1420,9 @@ static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { };
static struct hda_pcm_stream stac92xx_pcm_analog_capture = { - .substreams = 2, .channels_min = 2, .channels_max = 2, - /* NID is set in stac92xx_build_pcms */ + /* NID + .substreams is set in stac92xx_build_pcms */ .ops = { .prepare = stac92xx_capture_pcm_prepare, .cleanup = stac92xx_capture_pcm_cleanup @@ -1432,6 +1441,7 @@ static int stac92xx_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_playback; info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_analog_capture; info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adcs;
if (spec->alt_switch) { codec->num_pcms++; @@ -2478,6 +2488,7 @@ static int patch_stac9200(struct hda_codec *codec) spec->mux_nids = stac9200_mux_nids; spec->num_muxes = 1; spec->num_dmics = 0; + spec->num_adcs = 1;
spec->init = stac9200_core_init; spec->mixer = stac9200_mixer; @@ -2529,6 +2540,7 @@ static int patch_stac925x(struct hda_codec *codec) spec->adc_nids = stac925x_adc_nids; spec->mux_nids = stac925x_mux_nids; spec->num_muxes = 1; + spec->num_adcs = 1; switch (codec->vendor_id) { case 0x83847632: /* STAC9202 */ case 0x83847633: /* STAC9202D */ @@ -2632,6 +2644,7 @@ static int patch_stac922x(struct hda_codec *codec) spec->adc_nids = stac922x_adc_nids; spec->mux_nids = stac922x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); spec->num_dmics = 0;
spec->init = stac922x_core_init; @@ -2700,22 +2713,25 @@ static int patch_stac927x(struct hda_codec *codec) spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = d965_core_init; - spec->mixer = stac9227_mixer; + spec->mixer = stac927x_mixer; break; case STAC_D965_5ST: spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = d965_core_init; - spec->mixer = stac9227_mixer; + spec->mixer = stac927x_mixer; break; default: spec->adc_nids = stac927x_adc_nids; spec->mux_nids = stac927x_mux_nids; spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); + spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); spec->num_dmics = 0; spec->init = stac927x_core_init; spec->mixer = stac927x_mixer; @@ -2776,6 +2792,7 @@ static int patch_stac9205(struct hda_codec *codec) }
spec->adc_nids = stac9205_adc_nids; + spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids); spec->mux_nids = stac9205_mux_nids; spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); spec->dmic_nids = stac9205_dmic_nids;
At Mon, 3 Sep 2007 15:14:57 +0300, Maxim Levitsky wrote:
Hi,
This is new version of my patchset to improve STAC driver. I fixed all issues you told me about.
Note that I also fixed two bugs in hda driver itself, and this is why I didn't have sound after resume-from ram.
Thanks! I applied them to HG tree now.
Takashi
On Monday 03 September 2007 16:34:12 Takashi Iwai wrote:
At Mon, 3 Sep 2007 15:14:57 +0300, Maxim Levitsky wrote:
Hi,
This is new version of my patchset to improve STAC driver. I fixed all issues you told me about.
Note that I also fixed two bugs in hda driver itself, and this is why I didn't have sound after resume-from ram.
Thanks! I applied them to HG tree now.
Takashi
Thanks a lot, If I find another bug/missing feature I will work on that too.
Best regards, Maxim Levitsky
participants (2)
-
Maxim Levitsky
-
Takashi Iwai