Przeglądaj źródła

ALSA: HDA patch_via.c: Second S/PDIF (HDMI) support

The VT1702 and VT1708S have a second S/PDIF output which is used to
connect to a HDMI transmitter.  This patch adds support for it.

Signed-off-by: Harald Welte <HaraldWelte@viatech.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Harald Welte 16 lat temu
rodzic
commit
98aa34c050
1 zmienionych plików z 80 dodań i 1 usunięć
  1. 80 1
      sound/pci/hda/patch_via.c

+ 80 - 1
sound/pci/hda/patch_via.c

@@ -34,6 +34,7 @@
 /* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support        */
 /* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support        */
 /* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin             */
 /* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin             */
 /* 2008-04-09  Lydia Wang  Add Independent HP feature                        */
 /* 2008-04-09  Lydia Wang  Add Independent HP feature                        */
+/* 2008-05-28  Lydia Wang  Add second S/PDIF Out support for VT1702	     */
 /*                                                                           */
 /*                                                                           */
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
 
@@ -122,9 +123,11 @@ struct via_spec {
 	char *stream_name_digital;
 	char *stream_name_digital;
 	struct hda_pcm_stream *stream_digital_playback;
 	struct hda_pcm_stream *stream_digital_playback;
 	struct hda_pcm_stream *stream_digital_capture;
 	struct hda_pcm_stream *stream_digital_capture;
+	struct hda_pcm_stream *stream_extra_digital_playback;
 
 
 	/* playback */
 	/* playback */
 	struct hda_multi_out multiout;
 	struct hda_multi_out multiout;
+	hda_nid_t extra_dig_out_nid;
 
 
 	/* capture */
 	/* capture */
 	unsigned int num_adc_nids;
 	unsigned int num_adc_nids;
@@ -136,7 +139,7 @@ struct via_spec {
 	unsigned int cur_mux[3];
 	unsigned int cur_mux[3];
 
 
 	/* PCM information */
 	/* PCM information */
-	struct hda_pcm pcm_rec[2];
+	struct hda_pcm pcm_rec[3];
 
 
 	/* dynamic controls, init_verbs and input_mux */
 	/* dynamic controls, init_verbs and input_mux */
 	struct auto_pin_cfg autocfg;
 	struct auto_pin_cfg autocfg;
@@ -664,6 +667,36 @@ static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 					     stream_tag, format, substream);
 					     stream_tag, format, substream);
 }
 }
 
 
+/* setup SPDIF output stream */
+static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid,
+				 unsigned int stream_tag, unsigned int format)
+{
+	/* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+	if (codec->spdif_ctls & AC_DIG1_ENABLE)
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+				    codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
+	snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
+	/* turn on again (if needed) */
+	if (codec->spdif_ctls & AC_DIG1_ENABLE)
+		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
+				    codec->spdif_ctls & 0xff);
+}
+
+static int via_extra_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+					struct hda_codec *codec,
+					unsigned int stream_tag,
+					unsigned int format,
+					struct snd_pcm_substream *substream)
+{
+	struct via_spec *spec = codec->spec;
+
+	mutex_lock(&codec->spdif_mutex);
+	setup_dig_playback_stream(codec, spec->extra_dig_out_nid, stream_tag,
+				  format);
+	mutex_unlock(&codec->spdif_mutex);
+	return 0;
+}
+
 /*
 /*
  * Analog capture
  * Analog capture
  */
  */
@@ -769,6 +802,13 @@ static int via_build_controls(struct hda_codec *codec)
 		if (err < 0)
 		if (err < 0)
 			return err;
 			return err;
 		spec->multiout.share_spdif = 1;
 		spec->multiout.share_spdif = 1;
+
+		if (spec->extra_dig_out_nid) {
+			err = snd_hda_create_spdif_out_ctls(codec,
+						    spec->extra_dig_out_nid);
+			if (err < 0)
+				return err;
+		}
 	}
 	}
 	if (spec->dig_in_nid) {
 	if (spec->dig_in_nid) {
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
 		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
@@ -814,6 +854,17 @@ static int via_build_pcms(struct hda_codec *codec)
 		}
 		}
 	}
 	}
 
 
+	if (spec->extra_dig_out_nid) {
+		codec->num_pcms++;
+		info++;
+		info->name = spec->stream_name_digital;
+		info->pcm_type = HDA_PCM_TYPE_HDMI;
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+				*(spec->stream_extra_digital_playback);
+		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
+				spec->extra_dig_out_nid;
+	}
+
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2466,6 +2517,16 @@ static struct hda_pcm_stream vt1708S_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
+static struct hda_pcm_stream vt1708S_pcm_extra_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in via_build_pcms */
+	.ops = {
+		.prepare = via_extra_dig_playback_pcm_prepare
+	},
+};
+
 /* fill in the dac_nids table from the parsed pin configuration */
 /* fill in the dac_nids table from the parsed pin configuration */
 static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
 static int vt1708S_auto_fill_dac_nids(struct via_spec *spec,
 				     const struct auto_pin_cfg *cfg)
 				     const struct auto_pin_cfg *cfg)
@@ -2702,6 +2763,8 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec)
 	if (spec->autocfg.dig_out_pin)
 	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
 		spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID;
 
 
+	spec->extra_dig_out_nid = 0x15;
+
 	if (spec->kctl_alloc)
 	if (spec->kctl_alloc)
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
 
@@ -2753,6 +2816,8 @@ static int patch_vt1708S(struct hda_codec *codec)
 
 
 	spec->stream_name_digital = "VT1708S Digital";
 	spec->stream_name_digital = "VT1708S Digital";
 	spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
 	spec->stream_digital_playback = &vt1708S_pcm_digital_playback;
+	spec->stream_extra_digital_playback =
+					&vt1708S_pcm_extra_digital_playback;
 
 
 	if (!spec->adc_nids && spec->input_mux) {
 	if (!spec->adc_nids && spec->input_mux) {
 		spec->adc_nids = vt1708S_adc_nids;
 		spec->adc_nids = vt1708S_adc_nids;
@@ -2867,6 +2932,16 @@ static struct hda_pcm_stream vt1702_pcm_digital_playback = {
 	},
 	},
 };
 };
 
 
+static struct hda_pcm_stream vt1702_pcm_extra_digital_playback = {
+	.substreams = 1,
+	.channels_min = 2,
+	.channels_max = 2,
+	/* NID is set in via_build_pcms */
+	.ops = {
+		.prepare = via_extra_dig_playback_pcm_prepare
+	},
+};
+
 /* fill in the dac_nids table from the parsed pin configuration */
 /* fill in the dac_nids table from the parsed pin configuration */
 static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
 static int vt1702_auto_fill_dac_nids(struct via_spec *spec,
 				     const struct auto_pin_cfg *cfg)
 				     const struct auto_pin_cfg *cfg)
@@ -3018,6 +3093,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec)
 	if (spec->autocfg.dig_out_pin)
 	if (spec->autocfg.dig_out_pin)
 		spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
 		spec->multiout.dig_out_nid = VT1702_DIGOUT_NID;
 
 
+	spec->extra_dig_out_nid = 0x1B;
+
 	if (spec->kctl_alloc)
 	if (spec->kctl_alloc)
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 		spec->mixers[spec->num_mixers++] = spec->kctl_alloc;
 
 
@@ -3071,6 +3148,8 @@ static int patch_vt1702(struct hda_codec *codec)
 
 
 	spec->stream_name_digital = "VT1702 Digital";
 	spec->stream_name_digital = "VT1702 Digital";
 	spec->stream_digital_playback = &vt1702_pcm_digital_playback;
 	spec->stream_digital_playback = &vt1702_pcm_digital_playback;
+	spec->stream_extra_digital_playback =
+					&vt1702_pcm_extra_digital_playback;
 
 
 	if (!spec->adc_nids && spec->input_mux) {
 	if (!spec->adc_nids && spec->input_mux) {
 		spec->adc_nids = vt1702_adc_nids;
 		spec->adc_nids = vt1702_adc_nids;