diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-01-22 09:34:48 +0100 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-01-22 14:12:44 +0100 |
commit | 42875479b21e8f38ad1d7b09cde8906c41f17bf8 (patch) | |
tree | a002436c7e72df2fe14fae1cd26b99c69c4eb933 /sound | |
parent | 92603c594579e744a13b06efbbebb126db254655 (diff) | |
download | op-kernel-dev-42875479b21e8f38ad1d7b09cde8906c41f17bf8.zip op-kernel-dev-42875479b21e8f38ad1d7b09cde8906c41f17bf8.tar.gz |
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')
-rw-r--r-- | sound/pci/hda/patch_sigmatel.c | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index c53b6f9..0aa0ceb 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; |