aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2007-04-05 08:51:48 -0400
committerJaroslav Kysela <perex@suse.cz>2007-05-11 10:55:56 -0400
commit6b97eb45f2edca51250b6c1e3142801f069245fe (patch)
treebe20e5e69f05499091ee9d83005b2712babb5431 /sound/pci/hda
parentf9ab2b1c3ab5345f9003bf7ebc1eaa0f9b8cf99e (diff)
[ALSA] hda-codec - Fix SPDIF output
Fix SPDIF output (at least on Realtek codecs). The DIGI_CONVERT verbs have to be reset before the PCM stream is set up. Otherwise the digital setup is screwed up. Also, check the AMP capability before setting AMP of the digital out widget. Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/hda_codec.c44
-rw-r--r--sound/pci/hda/hda_local.h5
-rw-r--r--sound/pci/hda/patch_analog.c14
-rw-r--r--sound/pci/hda/patch_atihdmi.c14
-rw-r--r--sound/pci/hda/patch_cmedia.c14
-rw-r--r--sound/pci/hda/patch_conexant.c15
-rw-r--r--sound/pci/hda/patch_realtek.c14
-rw-r--r--sound/pci/hda/patch_sigmatel.c14
-rw-r--r--sound/pci/hda/patch_via.c14
9 files changed, 134 insertions, 14 deletions
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index e768187465e3..2c2fcdc72fcf 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -1114,10 +1114,14 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, struct sn
1114 change = codec->spdif_ctls != val; 1114 change = codec->spdif_ctls != val;
1115 if (change || codec->in_resume) { 1115 if (change || codec->in_resume) {
1116 codec->spdif_ctls = val; 1116 codec->spdif_ctls = val;
1117 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, val & 0xff); 1117 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
1118 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, 1118 val & 0xff);
1119 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | 1119 if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
1120 AC_AMP_SET_OUTPUT | ((val & 1) ? 0 : 0x80)); 1120 snd_hda_codec_write(codec, nid, 0,
1121 AC_VERB_SET_AMP_GAIN_MUTE,
1122 AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT |
1123 AC_AMP_SET_OUTPUT |
1124 ((val & 1) ? 0 : 0x80));
1121 } 1125 }
1122 mutex_unlock(&codec->spdif_mutex); 1126 mutex_unlock(&codec->spdif_mutex);
1123 return change; 1127 return change;
@@ -1886,6 +1890,21 @@ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *i
1886 * Multi-channel / digital-out PCM helper functions 1890 * Multi-channel / digital-out PCM helper functions
1887 */ 1891 */
1888 1892
1893/* setup SPDIF output stream */
1894static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid,
1895 unsigned int stream_tag, unsigned int format)
1896{
1897 /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
1898 if (codec->spdif_ctls & AC_DIG1_ENABLE)
1899 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
1900 codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff);
1901 snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format);
1902 /* turn on again (if needed) */
1903 if (codec->spdif_ctls & AC_DIG1_ENABLE)
1904 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1,
1905 codec->spdif_ctls & 0xff);
1906}
1907
1889/* 1908/*
1890 * open the digital out in the exclusive mode 1909 * open the digital out in the exclusive mode
1891 */ 1910 */
@@ -1901,6 +1920,18 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mo
1901 return 0; 1920 return 0;
1902} 1921}
1903 1922
1923int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
1924 struct hda_multi_out *mout,
1925 unsigned int stream_tag,
1926 unsigned int format,
1927 struct snd_pcm_substream *substream)
1928{
1929 mutex_lock(&codec->spdif_mutex);
1930 setup_dig_out_stream(codec, mout->dig_out_nid, stream_tag, format);
1931 mutex_unlock(&codec->spdif_mutex);
1932 return 0;
1933}
1934
1904/* 1935/*
1905 * release the digital out 1936 * release the digital out
1906 */ 1937 */
@@ -1942,9 +1973,8 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_o
1942 snd_hda_is_supported_format(codec, mout->dig_out_nid, format) && 1973 snd_hda_is_supported_format(codec, mout->dig_out_nid, format) &&
1943 ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) { 1974 ! (codec->spdif_status & IEC958_AES0_NONAUDIO)) {
1944 mout->dig_out_used = HDA_DIG_ANALOG_DUP; 1975 mout->dig_out_used = HDA_DIG_ANALOG_DUP;
1945 /* setup digital receiver */ 1976 setup_dig_out_stream(codec, mout->dig_out_nid,
1946 snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 1977 stream_tag, format);
1947 stream_tag, 0, format);
1948 } else { 1978 } else {
1949 mout->dig_out_used = 0; 1979 mout->dig_out_used = 0;
1950 snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0); 1980 snd_hda_codec_setup_stream(codec, mout->dig_out_nid, 0, 0, 0);
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h
index 39718d6cdadd..3505a670995f 100644
--- a/sound/pci/hda/hda_local.h
+++ b/sound/pci/hda/hda_local.h
@@ -148,6 +148,11 @@ struct hda_multi_out {
148 148
149int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout); 149int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout);
150int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout); 150int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout);
151int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
152 struct hda_multi_out *mout,
153 unsigned int stream_tag,
154 unsigned int format,
155 struct snd_pcm_substream *substream);
151int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, 156int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout,
152 struct snd_pcm_substream *substream); 157 struct snd_pcm_substream *substream);
153int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, 158int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout,
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 9c241ccf6907..fa194f21282f 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -192,6 +192,17 @@ static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
192 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 192 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
193} 193}
194 194
195static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
196 struct hda_codec *codec,
197 unsigned int stream_tag,
198 unsigned int format,
199 struct snd_pcm_substream *substream)
200{
201 struct ad198x_spec *spec = codec->spec;
202 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
203 format, substream);
204}
205
195/* 206/*
196 * Analog capture 207 * Analog capture
197 */ 208 */
@@ -250,7 +261,8 @@ static struct hda_pcm_stream ad198x_pcm_digital_playback = {
250 .nid = 0, /* fill later */ 261 .nid = 0, /* fill later */
251 .ops = { 262 .ops = {
252 .open = ad198x_dig_playback_pcm_open, 263 .open = ad198x_dig_playback_pcm_open,
253 .close = ad198x_dig_playback_pcm_close 264 .close = ad198x_dig_playback_pcm_close,
265 .prepare = ad198x_dig_playback_pcm_prepare
254 }, 266 },
255}; 267};
256 268
diff --git a/sound/pci/hda/patch_atihdmi.c b/sound/pci/hda/patch_atihdmi.c
index 831469d3a923..b89db1be4a0f 100644
--- a/sound/pci/hda/patch_atihdmi.c
+++ b/sound/pci/hda/patch_atihdmi.c
@@ -94,6 +94,17 @@ static int atihdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
94 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 94 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
95} 95}
96 96
97static int atihdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
98 struct hda_codec *codec,
99 unsigned int stream_tag,
100 unsigned int format,
101 struct snd_pcm_substream *substream)
102{
103 struct atihdmi_spec *spec = codec->spec;
104 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
105 format, substream);
106}
107
97static struct hda_pcm_stream atihdmi_pcm_digital_playback = { 108static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
98 .substreams = 1, 109 .substreams = 1,
99 .channels_min = 2, 110 .channels_min = 2,
@@ -101,7 +112,8 @@ static struct hda_pcm_stream atihdmi_pcm_digital_playback = {
101 .nid = 0x2, /* NID to query formats and rates and setup streams */ 112 .nid = 0x2, /* NID to query formats and rates and setup streams */
102 .ops = { 113 .ops = {
103 .open = atihdmi_dig_playback_pcm_open, 114 .open = atihdmi_dig_playback_pcm_open,
104 .close = atihdmi_dig_playback_pcm_close 115 .close = atihdmi_dig_playback_pcm_close,
116 .prepare = atihdmi_dig_playback_pcm_prepare
105 }, 117 },
106}; 118};
107 119
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
index 5b9d3a31a1ae..3c722e667bc8 100644
--- a/sound/pci/hda/patch_cmedia.c
+++ b/sound/pci/hda/patch_cmedia.c
@@ -497,6 +497,17 @@ static int cmi9880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
497 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 497 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
498} 498}
499 499
500static int cmi9880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
501 struct hda_codec *codec,
502 unsigned int stream_tag,
503 unsigned int format,
504 struct snd_pcm_substream *substream)
505{
506 struct cmi_spec *spec = codec->spec;
507 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
508 format, substream);
509}
510
500/* 511/*
501 * Analog capture 512 * Analog capture
502 */ 513 */
@@ -556,7 +567,8 @@ static struct hda_pcm_stream cmi9880_pcm_digital_playback = {
556 /* NID is set in cmi9880_build_pcms */ 567 /* NID is set in cmi9880_build_pcms */
557 .ops = { 568 .ops = {
558 .open = cmi9880_dig_playback_pcm_open, 569 .open = cmi9880_dig_playback_pcm_open,
559 .close = cmi9880_dig_playback_pcm_close 570 .close = cmi9880_dig_playback_pcm_close,
571 .prepare = cmi9880_dig_playback_pcm_prepare
560 }, 572 },
561}; 573};
562 574
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index efb95dc2d6db..2349b5eb5aaa 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -136,6 +136,18 @@ static int conexant_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
136 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 136 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
137} 137}
138 138
139static int conexant_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
140 struct hda_codec *codec,
141 unsigned int stream_tag,
142 unsigned int format,
143 struct snd_pcm_substream *substream)
144{
145 struct conexant_spec *spec = codec->spec;
146 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
147 stream_tag,
148 format, substream);
149}
150
139/* 151/*
140 * Analog capture 152 * Analog capture
141 */ 153 */
@@ -194,7 +206,8 @@ static struct hda_pcm_stream conexant_pcm_digital_playback = {
194 .nid = 0, /* fill later */ 206 .nid = 0, /* fill later */
195 .ops = { 207 .ops = {
196 .open = conexant_dig_playback_pcm_open, 208 .open = conexant_dig_playback_pcm_open,
197 .close = conexant_dig_playback_pcm_close 209 .close = conexant_dig_playback_pcm_close,
210 .prepare = conexant_dig_playback_pcm_prepare
198 }, 211 },
199}; 212};
200 213
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 4243c6b491fc..d3f7a3dab1c4 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -1916,6 +1916,17 @@ static int alc880_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
1916 return snd_hda_multi_out_dig_open(codec, &spec->multiout); 1916 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
1917} 1917}
1918 1918
1919static int alc880_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
1920 struct hda_codec *codec,
1921 unsigned int stream_tag,
1922 unsigned int format,
1923 struct snd_pcm_substream *substream)
1924{
1925 struct alc_spec *spec = codec->spec;
1926 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
1927 stream_tag, format, substream);
1928}
1929
1919static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, 1930static int alc880_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
1920 struct hda_codec *codec, 1931 struct hda_codec *codec,
1921 struct snd_pcm_substream *substream) 1932 struct snd_pcm_substream *substream)
@@ -1984,7 +1995,8 @@ static struct hda_pcm_stream alc880_pcm_digital_playback = {
1984 /* NID is set in alc_build_pcms */ 1995 /* NID is set in alc_build_pcms */
1985 .ops = { 1996 .ops = {
1986 .open = alc880_dig_playback_pcm_open, 1997 .open = alc880_dig_playback_pcm_open,
1987 .close = alc880_dig_playback_pcm_close 1998 .close = alc880_dig_playback_pcm_close,
1999 .prepare = alc880_dig_playback_pcm_prepare
1988 }, 2000 },
1989}; 2001};
1990 2002
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 6dd4822dbec0..612d355b9e01 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -814,6 +814,17 @@ static int stac92xx_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
814 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 814 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
815} 815}
816 816
817static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
818 struct hda_codec *codec,
819 unsigned int stream_tag,
820 unsigned int format,
821 struct snd_pcm_substream *substream)
822{
823 struct sigmatel_spec *spec = codec->spec;
824 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
825 stream_tag, format, substream);
826}
827
817 828
818/* 829/*
819 * Analog capture callbacks 830 * Analog capture callbacks
@@ -848,7 +859,8 @@ static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
848 /* NID is set in stac92xx_build_pcms */ 859 /* NID is set in stac92xx_build_pcms */
849 .ops = { 860 .ops = {
850 .open = stac92xx_dig_playback_pcm_open, 861 .open = stac92xx_dig_playback_pcm_open,
851 .close = stac92xx_dig_playback_pcm_close 862 .close = stac92xx_dig_playback_pcm_close,
863 .prepare = stac92xx_dig_playback_pcm_prepare
852 }, 864 },
853}; 865};
854 866
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 2b11ac8689b9..ba32d1e52cb8 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -377,6 +377,17 @@ static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
377 return snd_hda_multi_out_dig_close(codec, &spec->multiout); 377 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
378} 378}
379 379
380static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
381 struct hda_codec *codec,
382 unsigned int stream_tag,
383 unsigned int format,
384 struct snd_pcm_substream *substream)
385{
386 struct via_spec *spec = codec->spec;
387 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
388 stream_tag, format, substream);
389}
390
380/* 391/*
381 * Analog capture 392 * Analog capture
382 */ 393 */
@@ -433,7 +444,8 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = {
433 /* NID is set in via_build_pcms */ 444 /* NID is set in via_build_pcms */
434 .ops = { 445 .ops = {
435 .open = via_dig_playback_pcm_open, 446 .open = via_dig_playback_pcm_open,
436 .close = via_dig_playback_pcm_close 447 .close = via_dig_playback_pcm_close,
448 .prepare = via_dig_playback_pcm_prepare
437 }, 449 },
438}; 450};
439 451