summaryrefslogtreecommitdiffstats
path: root/sound/pci/hda/patch_sigmatel.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-01-22 09:34:48 +0100
committerTakashi Iwai <tiwai@suse.de>2013-01-22 14:12:44 +0100
commit42875479b21e8f38ad1d7b09cde8906c41f17bf8 (patch)
treea002436c7e72df2fe14fae1cd26b99c69c4eb933 /sound/pci/hda/patch_sigmatel.c
parentALSA: hda - Disable HP auto-mute during independent HP mode (diff)
downloadlinux-42875479b21e8f38ad1d7b09cde8906c41f17bf8.tar.xz
linux-42875479b21e8f38ad1d7b09cde8906c41f17bf8.zip
ALSA: hda - Revive SPDIF mux for IDT/STAC codecs
The stuff that was dropped while transition to the generic parser is now recovered. 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.c101
1 files changed, 101 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index c53b6f9f2ca8..0aa0ceba0806 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -177,6 +177,7 @@ struct sigmatel_spec {
unsigned int headset_jack:1; /* 4-pin headset jack (hp + mono mic) */
unsigned int volknob_init:1; /* special volume-knob initialization */
unsigned int powerdown_adcs:1;
+ unsigned int have_spdif_mux:1;
/* gpio lines */
unsigned int eapd_mask;
@@ -211,6 +212,11 @@ struct sigmatel_spec {
/* beep widgets */
hda_nid_t anabeep_nid;
hda_nid_t digbeep_nid;
+
+ /* SPDIF-out mux */
+ const char * const *spdif_labels;
+ struct hda_input_mux spdif_mux;
+ unsigned int cur_smux[2];
};
#define AC_VERB_IDT_SET_POWER_MAP 0x7ec
@@ -885,6 +891,85 @@ static int stac_beep_switch_ctl(struct hda_codec *codec)
#endif
/*
+ * SPDIF-out mux controls
+ */
+
+static int stac_smux_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct sigmatel_spec *spec = codec->spec;
+ return snd_hda_input_mux_info(&spec->spdif_mux, uinfo);
+}
+
+static int stac_smux_enum_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;
+ unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
+ return 0;
+}
+
+static int stac_smux_enum_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 smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+ return snd_hda_input_mux_put(codec, &spec->spdif_mux, ucontrol,
+ spec->gen.autocfg.dig_out_pins[smux_idx],
+ &spec->cur_smux[smux_idx]);
+}
+
+static struct snd_kcontrol_new stac_smux_mixer = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "IEC958 Playback Source",
+ /* count set later */
+ .info = stac_smux_enum_info,
+ .get = stac_smux_enum_get,
+ .put = stac_smux_enum_put,
+};
+
+static const char * const stac_spdif_labels[] = {
+ "Digital Playback", "Analog Mux 1", "Analog Mux 2", NULL
+};
+
+static int stac_create_spdif_mux_ctls(struct hda_codec *codec)
+{
+ struct sigmatel_spec *spec = codec->spec;
+ struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+ const char * const *labels = spec->spdif_labels;
+ struct snd_kcontrol_new *kctl;
+ int i, num_cons;
+
+ if (cfg->dig_outs < 1)
+ return 0;
+
+ num_cons = snd_hda_get_num_conns(codec, cfg->dig_out_pins[0]);
+ if (num_cons <= 1)
+ return 0;
+
+ if (!labels)
+ labels = stac_spdif_labels;
+ for (i = 0; i < num_cons; i++) {
+ if (snd_BUG_ON(!labels[i]))
+ return -EINVAL;
+ snd_hda_add_imux_item(&spec->spdif_mux, labels[i], i, NULL);
+ }
+
+ kctl = snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_smux_mixer);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->count = cfg->dig_outs;
+
+ return 0;
+}
+
+/*
*/
static const struct hda_verb stac9200_core_init[] = {
@@ -3475,6 +3560,12 @@ static int stac_parse_auto_config(struct hda_codec *codec)
return -ENOMEM;
}
+ if (spec->have_spdif_mux) {
+ err = stac_create_spdif_mux_ctls(codec);
+ if (err < 0)
+ return err;
+ }
+
stac_init_power_map(codec);
return 0;
@@ -3744,6 +3835,7 @@ static int patch_stac92hd73xx(struct hda_codec *codec)
spec = codec->spec;
spec->linear_tone_beep = 0;
spec->gen.mixer_nid = 0x1d;
+ spec->have_spdif_mux = 1;
num_dacs = snd_hda_get_num_conns(codec, 0x0a) - 1;
if (num_dacs < 3 || num_dacs > 5) {
@@ -3885,6 +3977,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec)
spec->linear_tone_beep = 0;
spec->gen.own_eapd_ctl = 1;
spec->gen.mixer_nid = 0x17;
+ spec->have_spdif_mux = 1;
codec->patch_ops = stac_patch_ops;
@@ -3988,6 +4081,11 @@ static int patch_stac922x(struct hda_codec *codec)
return 0;
}
+static const char * const stac927x_spdif_labels[] = {
+ "Digital Playback", "ADAT", "Analog Mux 1",
+ "Analog Mux 2", "Analog Mux 3", NULL
+};
+
static int patch_stac927x(struct hda_codec *codec)
{
struct sigmatel_spec *spec;
@@ -4000,6 +4098,8 @@ static int patch_stac927x(struct hda_codec *codec)
spec = codec->spec;
spec->linear_tone_beep = 1;
spec->gen.own_eapd_ctl = 1;
+ spec->have_spdif_mux = 1;
+ spec->spdif_labels = stac927x_spdif_labels;
spec->digbeep_nid = 0x23;
@@ -4058,6 +4158,7 @@ static int patch_stac9205(struct hda_codec *codec)
spec = codec->spec;
spec->linear_tone_beep = 1;
spec->gen.own_eapd_ctl = 1;
+ spec->have_spdif_mux = 1;
spec->digbeep_nid = 0x23;