]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Takashi Iwai <tiwai@suse.de> |
2 | Subject: ALSA: hda - Slave SPDIF support | |
3 | Patch-mainline: 2.6.28-rc1 | |
4 | References: | |
5 | ||
6 | Add the support of slave SPDIF outputs for multiple SPDIF devices. | |
7 | ||
8 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
9 | ||
10 | --- | |
11 | --- | |
12 | sound/pci/hda/hda_codec.c | 72 ++++++++++++++++++++++++++----------- | |
13 | sound/pci/hda/hda_codec.h | 89 +++++++++++++++++++++++++++++++++++++++++++--- | |
14 | sound/pci/hda/hda_local.h | 15 ++++--- | |
15 | 3 files changed, 146 insertions(+), 30 deletions(-) | |
16 | ||
17 | --- a/sound/pci/hda/hda_codec.c | |
18 | +++ b/sound/pci/hda/hda_codec.c | |
19 | @@ -1430,6 +1430,29 @@ static unsigned int convert_to_spdif_sta | |
20 | return sbits; | |
21 | } | |
22 | ||
23 | +/* set digital convert verbs both for the given NID and its slaves */ | |
24 | +static void set_dig_out(struct hda_codec *codec, hda_nid_t nid, | |
25 | + int verb, int val) | |
26 | +{ | |
27 | + hda_nid_t *d; | |
28 | + | |
29 | + snd_hda_codec_write(codec, nid, 0, verb, val); | |
30 | + d = codec->slave_dig_outs; | |
31 | + if (!d) | |
32 | + return; | |
33 | + for (; *d; d++) | |
34 | + snd_hda_codec_write(codec, *d, 0, verb, val); | |
35 | +} | |
36 | + | |
37 | +static inline void set_dig_out_convert(struct hda_codec *codec, hda_nid_t nid, | |
38 | + int dig1, int dig2) | |
39 | +{ | |
40 | + if (dig1 != -1) | |
41 | + set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_1, dig1); | |
42 | + if (dig2 != -1) | |
43 | + set_dig_out(codec, nid, AC_VERB_SET_DIGI_CONVERT_2, dig2); | |
44 | +} | |
45 | + | |
46 | static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, | |
47 | struct snd_ctl_elem_value *ucontrol) | |
48 | { | |
49 | @@ -1448,14 +1471,8 @@ static int snd_hda_spdif_default_put(str | |
50 | change = codec->spdif_ctls != val; | |
51 | codec->spdif_ctls = val; | |
52 | ||
53 | - if (change) { | |
54 | - snd_hda_codec_write_cache(codec, nid, 0, | |
55 | - AC_VERB_SET_DIGI_CONVERT_1, | |
56 | - val & 0xff); | |
57 | - snd_hda_codec_write_cache(codec, nid, 0, | |
58 | - AC_VERB_SET_DIGI_CONVERT_2, | |
59 | - val >> 8); | |
60 | - } | |
61 | + if (change) | |
62 | + set_dig_out_convert(codec, nid, val & 0xff, (val >> 8) & 0xff); | |
63 | ||
64 | mutex_unlock(&codec->spdif_mutex); | |
65 | return change; | |
66 | @@ -1487,9 +1504,7 @@ static int snd_hda_spdif_out_switch_put( | |
67 | change = codec->spdif_ctls != val; | |
68 | if (change) { | |
69 | codec->spdif_ctls = val; | |
70 | - snd_hda_codec_write_cache(codec, nid, 0, | |
71 | - AC_VERB_SET_DIGI_CONVERT_1, | |
72 | - val & 0xff); | |
73 | + set_dig_out_convert(codec, nid, val & 0xff, -1); | |
74 | /* unmute amp switch (if any) */ | |
75 | if ((get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) && | |
76 | (val & AC_DIG1_ENABLE)) | |
77 | @@ -2583,14 +2598,31 @@ static void setup_dig_out_stream(struct | |
78 | unsigned int stream_tag, unsigned int format) | |
79 | { | |
80 | /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ | |
81 | - if (codec->spdif_ctls & AC_DIG1_ENABLE) | |
82 | - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | |
83 | - codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); | |
84 | + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) | |
85 | + set_dig_out_convert(codec, nid, | |
86 | + codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff, | |
87 | + -1); | |
88 | snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); | |
89 | + if (codec->slave_dig_outs) { | |
90 | + hda_nid_t *d; | |
91 | + for (d = codec->slave_dig_outs; *d; d++) | |
92 | + snd_hda_codec_setup_stream(codec, *d, stream_tag, 0, | |
93 | + format); | |
94 | + } | |
95 | /* turn on again (if needed) */ | |
96 | - if (codec->spdif_ctls & AC_DIG1_ENABLE) | |
97 | - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | |
98 | - codec->spdif_ctls & 0xff); | |
99 | + if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) | |
100 | + set_dig_out_convert(codec, nid, | |
101 | + codec->spdif_ctls & 0xff, -1); | |
102 | +} | |
103 | + | |
104 | +static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) | |
105 | +{ | |
106 | + snd_hda_codec_cleanup_stream(codec, nid); | |
107 | + if (codec->slave_dig_outs) { | |
108 | + hda_nid_t *d; | |
109 | + for (d = codec->slave_dig_outs; *d; d++) | |
110 | + snd_hda_codec_cleanup_stream(codec, *d); | |
111 | + } | |
112 | } | |
113 | ||
114 | /* | |
115 | @@ -2602,7 +2634,7 @@ int snd_hda_multi_out_dig_open(struct hd | |
116 | mutex_lock(&codec->spdif_mutex); | |
117 | if (mout->dig_out_used == HDA_DIG_ANALOG_DUP) | |
118 | /* already opened as analog dup; reset it once */ | |
119 | - snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); | |
120 | + cleanup_dig_out_stream(codec, mout->dig_out_nid); | |
121 | mout->dig_out_used = HDA_DIG_EXCLUSIVE; | |
122 | mutex_unlock(&codec->spdif_mutex); | |
123 | return 0; | |
124 | @@ -2697,7 +2729,7 @@ int snd_hda_multi_out_analog_prepare(str | |
125 | stream_tag, format); | |
126 | } else { | |
127 | mout->dig_out_used = 0; | |
128 | - snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); | |
129 | + cleanup_dig_out_stream(codec, mout->dig_out_nid); | |
130 | } | |
131 | } | |
132 | mutex_unlock(&codec->spdif_mutex); | |
133 | @@ -2748,7 +2780,7 @@ int snd_hda_multi_out_analog_cleanup(str | |
134 | mout->extra_out_nid[i]); | |
135 | mutex_lock(&codec->spdif_mutex); | |
136 | if (mout->dig_out_nid && mout->dig_out_used == HDA_DIG_ANALOG_DUP) { | |
137 | - snd_hda_codec_cleanup_stream(codec, mout->dig_out_nid); | |
138 | + cleanup_dig_out_stream(codec, mout->dig_out_nid); | |
139 | mout->dig_out_used = 0; | |
140 | } | |
141 | mutex_unlock(&codec->spdif_mutex); | |
142 | --- a/sound/pci/hda/hda_codec.h | |
143 | +++ b/sound/pci/hda/hda_codec.h | |
144 | @@ -90,6 +90,14 @@ enum { | |
145 | #define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c | |
146 | /* f20: AFG/MFG */ | |
147 | #define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 | |
148 | +#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d | |
149 | +#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e | |
150 | +#define AC_VERB_GET_HDMI_ELDD 0x0f2f | |
151 | +#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30 | |
152 | +#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31 | |
153 | +#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 | |
154 | +#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 | |
155 | +#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 | |
156 | ||
157 | /* | |
158 | * SET verbs | |
159 | @@ -121,7 +129,14 @@ enum { | |
160 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d | |
161 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e | |
162 | #define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f | |
163 | +#define AC_VERB_SET_EAPD 0x788 | |
164 | #define AC_VERB_SET_CODEC_RESET 0x7ff | |
165 | +#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d | |
166 | +#define AC_VERB_SET_HDMI_DIP_INDEX 0x730 | |
167 | +#define AC_VERB_SET_HDMI_DIP_DATA 0x731 | |
168 | +#define AC_VERB_SET_HDMI_DIP_XMIT 0x732 | |
169 | +#define AC_VERB_SET_HDMI_CP_CTRL 0x733 | |
170 | +#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 | |
171 | ||
172 | /* | |
173 | * Parameter IDs | |
174 | @@ -143,6 +158,7 @@ enum { | |
175 | #define AC_PAR_GPIO_CAP 0x11 | |
176 | #define AC_PAR_AMP_OUT_CAP 0x12 | |
177 | #define AC_PAR_VOL_KNB_CAP 0x13 | |
178 | +#define AC_PAR_HDMI_LPCM_CAP 0x20 | |
179 | ||
180 | /* | |
181 | * AC_VERB_PARAMETERS results (32bit) | |
182 | @@ -171,6 +187,8 @@ enum { | |
183 | #define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ | |
184 | #define AC_WCAP_POWER (1<<10) /* power control */ | |
185 | #define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ | |
186 | +#define AC_WCAP_CP_CAPS (1<<12) /* content protection */ | |
187 | +#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */ | |
188 | #define AC_WCAP_DELAY (0xf<<16) | |
189 | #define AC_WCAP_DELAY_SHIFT 16 | |
190 | #define AC_WCAP_TYPE (0xf<<20) | |
191 | @@ -206,9 +224,20 @@ enum { | |
192 | /* Input converter SDI select */ | |
193 | #define AC_SDI_SELECT (0xf<<0) | |
194 | ||
195 | -/* Unsolicited response */ | |
196 | +/* Unsolicited response control */ | |
197 | #define AC_UNSOL_TAG (0x3f<<0) | |
198 | #define AC_UNSOL_ENABLED (1<<7) | |
199 | +#define AC_USRSP_EN AC_UNSOL_ENABLED | |
200 | + | |
201 | +/* Unsolicited responses */ | |
202 | +#define AC_UNSOL_RES_TAG (0x3f<<26) | |
203 | +#define AC_UNSOL_RES_TAG_SHIFT 26 | |
204 | +#define AC_UNSOL_RES_SUBTAG (0x1f<<21) | |
205 | +#define AC_UNSOL_RES_SUBTAG_SHIFT 21 | |
206 | +#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ | |
207 | +#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ | |
208 | +#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ | |
209 | +#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */ | |
210 | ||
211 | /* Pin widget capabilies */ | |
212 | #define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ | |
213 | @@ -222,6 +251,10 @@ enum { | |
214 | * but is marked reserved in the Intel HDA specification. | |
215 | */ | |
216 | #define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ | |
217 | +/* Note: The same bit as LR_SWAP is newly defined as HDMI capability | |
218 | + * in HD-audio specification | |
219 | + */ | |
220 | +#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */ | |
221 | #define AC_PINCAP_VREF (0x37<<8) | |
222 | #define AC_PINCAP_VREF_SHIFT 8 | |
223 | #define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ | |
224 | @@ -272,6 +305,22 @@ enum { | |
225 | #define AC_KNBCAP_NUM_STEPS (0x7f<<0) | |
226 | #define AC_KNBCAP_DELTA (1<<7) | |
227 | ||
228 | +/* HDMI LPCM capabilities */ | |
229 | +#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */ | |
230 | +#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */ | |
231 | +#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */ | |
232 | +#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */ | |
233 | +#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */ | |
234 | +#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */ | |
235 | +#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */ | |
236 | +#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */ | |
237 | +#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */ | |
238 | +#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */ | |
239 | +#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */ | |
240 | +#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */ | |
241 | +#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ | |
242 | +#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ | |
243 | + | |
244 | /* | |
245 | * Control Parameters | |
246 | */ | |
247 | @@ -317,18 +366,44 @@ enum { | |
248 | #define AC_PINCTL_OUT_EN (1<<6) | |
249 | #define AC_PINCTL_HP_EN (1<<7) | |
250 | ||
251 | -/* Unsolicited response - 8bit */ | |
252 | -#define AC_USRSP_EN (1<<7) | |
253 | - | |
254 | /* Pin sense - 32bit */ | |
255 | #define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) | |
256 | #define AC_PINSENSE_PRESENCE (1<<31) | |
257 | +#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */ | |
258 | ||
259 | /* EAPD/BTL enable - 32bit */ | |
260 | #define AC_EAPDBTL_BALANCED (1<<0) | |
261 | #define AC_EAPDBTL_EAPD (1<<1) | |
262 | #define AC_EAPDBTL_LR_SWAP (1<<2) | |
263 | ||
264 | +/* HDMI ELD data */ | |
265 | +#define AC_ELDD_ELD_VALID (1<<31) | |
266 | +#define AC_ELDD_ELD_DATA 0xff | |
267 | + | |
268 | +/* HDMI DIP size */ | |
269 | +#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */ | |
270 | +#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */ | |
271 | + | |
272 | +/* HDMI DIP index */ | |
273 | +#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */ | |
274 | +#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */ | |
275 | + | |
276 | +/* HDMI DIP xmit (transmit) control */ | |
277 | +#define AC_DIPXMIT_MASK (0x3<<6) | |
278 | +#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */ | |
279 | +#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */ | |
280 | +#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */ | |
281 | + | |
282 | +/* HDMI content protection (CP) control */ | |
283 | +#define AC_CPCTRL_CES (1<<9) /* current encryption state */ | |
284 | +#define AC_CPCTRL_READY (1<<8) /* ready bit */ | |
285 | +#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */ | |
286 | +#define AC_CPCTRL_STATE (3<<0) /* current CP request state */ | |
287 | + | |
288 | +/* Converter channel <-> HDMI slot mapping */ | |
289 | +#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */ | |
290 | +#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */ | |
291 | + | |
292 | /* configuration default - 32bit */ | |
293 | #define AC_DEFCFG_SEQUENCE (0xf<<0) | |
294 | #define AC_DEFCFG_DEF_ASSOC (0xf<<4) | |
295 | @@ -650,9 +725,15 @@ struct hda_codec { | |
296 | unsigned int spdif_status; /* IEC958 status bits */ | |
297 | unsigned short spdif_ctls; /* SPDIF control bits */ | |
298 | unsigned int spdif_in_enable; /* SPDIF input enable? */ | |
299 | + hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ | |
300 | ||
301 | struct snd_hwdep *hwdep; /* assigned hwdep device */ | |
302 | ||
303 | + /* misc flags */ | |
304 | + unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each | |
305 | + * status change | |
306 | + * (e.g. Realtek codecs) | |
307 | + */ | |
308 | #ifdef CONFIG_SND_HDA_POWER_SAVE | |
309 | unsigned int power_on :1; /* current (global) power-state */ | |
310 | unsigned int power_transition :1; /* power-state in transition */ | |
311 | --- a/sound/pci/hda/hda_local.h | |
312 | +++ b/sound/pci/hda/hda_local.h | |
313 | @@ -368,12 +368,15 @@ int snd_hda_parse_pin_def_config(struct | |
314 | #define AMP_OUT_UNMUTE 0xb000 | |
315 | #define AMP_OUT_ZERO 0xb000 | |
316 | /* pinctl values */ | |
317 | -#define PIN_IN 0x20 | |
318 | -#define PIN_VREF80 0x24 | |
319 | -#define PIN_VREF50 0x21 | |
320 | -#define PIN_OUT 0x40 | |
321 | -#define PIN_HP 0xc0 | |
322 | -#define PIN_HP_AMP 0x80 | |
323 | +#define PIN_IN (AC_PINCTL_IN_EN) | |
324 | +#define PIN_VREFHIZ (AC_PINCTL_IN_EN | AC_PINCTL_VREF_HIZ) | |
325 | +#define PIN_VREF50 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_50) | |
326 | +#define PIN_VREFGRD (AC_PINCTL_IN_EN | AC_PINCTL_VREF_GRD) | |
327 | +#define PIN_VREF80 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_80) | |
328 | +#define PIN_VREF100 (AC_PINCTL_IN_EN | AC_PINCTL_VREF_100) | |
329 | +#define PIN_OUT (AC_PINCTL_OUT_EN) | |
330 | +#define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN) | |
331 | +#define PIN_HP_AMP (AC_PINCTL_HP_EN) | |
332 | ||
333 | /* | |
334 | * get widget capabilities |