Commit | Line | Data |
---|---|---|
9a10eb21 WN |
1 | /* |
2 | * Universal Interface for Intel High Definition Audio Codec | |
3 | * | |
4 | * HD audio interface patch for NVIDIA HDMI codecs | |
5 | * | |
6 | * Copyright (c) 2008 NVIDIA Corp. All rights reserved. | |
7 | * Copyright (c) 2008 Wei Ni <wni@nvidia.com> | |
8 | * | |
9 | * | |
10 | * This driver is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation; either version 2 of the License, or | |
13 | * (at your option) any later version. | |
14 | * | |
15 | * This driver is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 | */ | |
24 | ||
25 | #include <linux/init.h> | |
26 | #include <linux/delay.h> | |
27 | #include <linux/slab.h> | |
28 | #include <sound/core.h> | |
29 | #include "hda_codec.h" | |
30 | #include "hda_local.h" | |
31 | ||
079d88cc WF |
32 | #define MAX_HDMI_CVTS 1 |
33 | #define MAX_HDMI_PINS 1 | |
34 | ||
35 | #include "patch_hdmi.c" | |
36 | ||
37 | static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = { | |
38 | "NVIDIA HDMI", | |
39 | }; | |
40 | ||
f0613d57 | 41 | /* define below to restrict the supported rates and formats */ |
491dc043 | 42 | /* #define LIMITED_RATE_FMT_SUPPORT */ |
f0613d57 | 43 | |
25045705 WN |
44 | enum HDACodec { |
45 | HDA_CODEC_NVIDIA_MCP7X, | |
46 | HDA_CODEC_NVIDIA_MCP89, | |
47 | HDA_CODEC_NVIDIA_GT21X, | |
48 | HDA_CODEC_INVALID | |
9a10eb21 WN |
49 | }; |
50 | ||
a3d6ab97 WN |
51 | #define Nv_VERB_SET_Channel_Allocation 0xF79 |
52 | #define Nv_VERB_SET_Info_Frame_Checksum 0xF7A | |
53 | #define Nv_VERB_SET_Audio_Protection_On 0xF98 | |
54 | #define Nv_VERB_SET_Audio_Protection_Off 0xF99 | |
55 | ||
25045705 WN |
56 | #define nvhdmi_master_con_nid_7x 0x04 |
57 | #define nvhdmi_master_pin_nid_7x 0x05 | |
a3d6ab97 | 58 | |
25045705 WN |
59 | #define nvhdmi_master_con_nid_89 0x04 |
60 | #define nvhdmi_master_pin_nid_89 0x05 | |
61 | ||
62 | static hda_nid_t nvhdmi_con_nids_7x[4] = { | |
a3d6ab97 WN |
63 | /*front, rear, clfe, rear_surr */ |
64 | 0x6, 0x8, 0xa, 0xc, | |
65 | }; | |
66 | ||
25045705 | 67 | static struct hda_verb nvhdmi_basic_init_7x[] = { |
a3d6ab97 WN |
68 | /* set audio protect on */ |
69 | { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, | |
9a10eb21 | 70 | /* enable digital output on pin widget */ |
a3d6ab97 WN |
71 | { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, |
72 | { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, | |
73 | { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, | |
74 | { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, | |
75 | { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, | |
9a10eb21 WN |
76 | {} /* terminator */ |
77 | }; | |
78 | ||
f0613d57 TI |
79 | #ifdef LIMITED_RATE_FMT_SUPPORT |
80 | /* support only the safe format and rate */ | |
81 | #define SUPPORTED_RATES SNDRV_PCM_RATE_48000 | |
82 | #define SUPPORTED_MAXBPS 16 | |
83 | #define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE | |
84 | #else | |
85 | /* support all rates and formats */ | |
86 | #define SUPPORTED_RATES \ | |
87 | (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ | |
88 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ | |
89 | SNDRV_PCM_RATE_192000) | |
90 | #define SUPPORTED_MAXBPS 24 | |
91 | #define SUPPORTED_FORMATS \ | |
92 | (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) | |
93 | #endif | |
94 | ||
9a10eb21 WN |
95 | /* |
96 | * Controls | |
97 | */ | |
98 | static int nvhdmi_build_controls(struct hda_codec *codec) | |
99 | { | |
079d88cc | 100 | struct hdmi_spec *spec = codec->spec; |
9a10eb21 | 101 | int err; |
25045705 | 102 | int i; |
9a10eb21 | 103 | |
25045705 WN |
104 | if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) |
105 | || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { | |
106 | for (i = 0; i < codec->num_pcms; i++) { | |
107 | err = snd_hda_create_spdif_out_ctls(codec, | |
108 | spec->cvt[i]); | |
109 | if (err < 0) | |
110 | return err; | |
111 | } | |
112 | } else { | |
113 | err = snd_hda_create_spdif_out_ctls(codec, | |
114 | spec->multiout.dig_out_nid); | |
115 | if (err < 0) | |
116 | return err; | |
117 | } | |
9a10eb21 WN |
118 | |
119 | return 0; | |
120 | } | |
121 | ||
122 | static int nvhdmi_init(struct hda_codec *codec) | |
123 | { | |
079d88cc | 124 | struct hdmi_spec *spec = codec->spec; |
25045705 WN |
125 | int i; |
126 | if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) | |
127 | || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { | |
128 | for (i = 0; spec->pin[i]; i++) { | |
129 | hdmi_enable_output(codec, spec->pin[i]); | |
130 | snd_hda_codec_write(codec, spec->pin[i], 0, | |
131 | AC_VERB_SET_UNSOLICITED_ENABLE, | |
132 | AC_USRSP_EN | spec->pin[i]); | |
133 | } | |
134 | } else { | |
135 | snd_hda_sequence_write(codec, nvhdmi_basic_init_7x); | |
136 | } | |
9a10eb21 WN |
137 | return 0; |
138 | } | |
139 | ||
25045705 WN |
140 | static void nvhdmi_free(struct hda_codec *codec) |
141 | { | |
079d88cc | 142 | struct hdmi_spec *spec = codec->spec; |
25045705 WN |
143 | int i; |
144 | ||
145 | if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) | |
146 | || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { | |
147 | for (i = 0; i < spec->num_pins; i++) | |
148 | snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); | |
149 | } | |
150 | ||
151 | kfree(spec); | |
152 | } | |
153 | ||
9a10eb21 WN |
154 | /* |
155 | * Digital out | |
156 | */ | |
157 | static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | |
a3d6ab97 WN |
158 | struct hda_codec *codec, |
159 | struct snd_pcm_substream *substream) | |
9a10eb21 | 160 | { |
079d88cc | 161 | struct hdmi_spec *spec = codec->spec; |
9a10eb21 WN |
162 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); |
163 | } | |
164 | ||
25045705 | 165 | static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo, |
a3d6ab97 WN |
166 | struct hda_codec *codec, |
167 | struct snd_pcm_substream *substream) | |
9a10eb21 | 168 | { |
079d88cc | 169 | struct hdmi_spec *spec = codec->spec; |
a3d6ab97 WN |
170 | int i; |
171 | ||
25045705 | 172 | snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, |
a3d6ab97 WN |
173 | 0, AC_VERB_SET_CHANNEL_STREAMID, 0); |
174 | for (i = 0; i < 4; i++) { | |
175 | /* set the stream id */ | |
25045705 | 176 | snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, |
a3d6ab97 WN |
177 | AC_VERB_SET_CHANNEL_STREAMID, 0); |
178 | /* set the stream format */ | |
25045705 | 179 | snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, |
a3d6ab97 WN |
180 | AC_VERB_SET_STREAM_FORMAT, 0); |
181 | } | |
182 | ||
9a10eb21 WN |
183 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); |
184 | } | |
185 | ||
a3d6ab97 WN |
186 | static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo, |
187 | struct hda_codec *codec, | |
188 | struct snd_pcm_substream *substream) | |
189 | { | |
079d88cc | 190 | struct hdmi_spec *spec = codec->spec; |
a3d6ab97 WN |
191 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); |
192 | } | |
193 | ||
25045705 WN |
194 | static int nvhdmi_dig_playback_pcm_prepare_8ch_89(struct hda_pcm_stream *hinfo, |
195 | struct hda_codec *codec, | |
196 | unsigned int stream_tag, | |
197 | unsigned int format, | |
198 | struct snd_pcm_substream *substream) | |
199 | { | |
200 | hdmi_set_channel_count(codec, hinfo->nid, | |
201 | substream->runtime->channels); | |
202 | ||
203 | hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); | |
204 | ||
ea87d1c4 | 205 | return hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); |
25045705 WN |
206 | } |
207 | ||
a3d6ab97 WN |
208 | static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, |
209 | struct hda_codec *codec, | |
210 | unsigned int stream_tag, | |
211 | unsigned int format, | |
212 | struct snd_pcm_substream *substream) | |
213 | { | |
214 | int chs; | |
215 | unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id; | |
216 | int i; | |
217 | ||
218 | mutex_lock(&codec->spdif_mutex); | |
219 | ||
220 | chs = substream->runtime->channels; | |
221 | chan = chs ? (chs - 1) : 1; | |
222 | ||
223 | switch (chs) { | |
224 | default: | |
225 | case 0: | |
226 | case 2: | |
227 | chanmask = 0x00; | |
228 | break; | |
229 | case 4: | |
230 | chanmask = 0x08; | |
231 | break; | |
232 | case 6: | |
233 | chanmask = 0x0b; | |
234 | break; | |
235 | case 8: | |
236 | chanmask = 0x13; | |
237 | break; | |
238 | } | |
239 | dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT; | |
240 | dataDCC2 = 0x2; | |
241 | ||
242 | /* set the Audio InforFrame Channel Allocation */ | |
243 | snd_hda_codec_write(codec, 0x1, 0, | |
244 | Nv_VERB_SET_Channel_Allocation, chanmask); | |
245 | ||
246 | /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ | |
247 | if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) | |
248 | snd_hda_codec_write(codec, | |
25045705 | 249 | nvhdmi_master_con_nid_7x, |
a3d6ab97 WN |
250 | 0, |
251 | AC_VERB_SET_DIGI_CONVERT_1, | |
252 | codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); | |
253 | ||
254 | /* set the stream id */ | |
25045705 | 255 | snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, |
a3d6ab97 WN |
256 | AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); |
257 | ||
258 | /* set the stream format */ | |
25045705 | 259 | snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, |
a3d6ab97 WN |
260 | AC_VERB_SET_STREAM_FORMAT, format); |
261 | ||
262 | /* turn on again (if needed) */ | |
263 | /* enable and set the channel status audio/data flag */ | |
264 | if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { | |
265 | snd_hda_codec_write(codec, | |
25045705 | 266 | nvhdmi_master_con_nid_7x, |
a3d6ab97 WN |
267 | 0, |
268 | AC_VERB_SET_DIGI_CONVERT_1, | |
269 | codec->spdif_ctls & 0xff); | |
270 | snd_hda_codec_write(codec, | |
25045705 | 271 | nvhdmi_master_con_nid_7x, |
a3d6ab97 WN |
272 | 0, |
273 | AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); | |
274 | } | |
275 | ||
276 | for (i = 0; i < 4; i++) { | |
277 | if (chs == 2) | |
278 | channel_id = 0; | |
279 | else | |
280 | channel_id = i * 2; | |
281 | ||
282 | /* turn off SPDIF once; | |
283 | *otherwise the IEC958 bits won't be updated | |
284 | */ | |
285 | if (codec->spdif_status_reset && | |
286 | (codec->spdif_ctls & AC_DIG1_ENABLE)) | |
287 | snd_hda_codec_write(codec, | |
25045705 | 288 | nvhdmi_con_nids_7x[i], |
a3d6ab97 WN |
289 | 0, |
290 | AC_VERB_SET_DIGI_CONVERT_1, | |
291 | codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); | |
292 | /* set the stream id */ | |
293 | snd_hda_codec_write(codec, | |
25045705 | 294 | nvhdmi_con_nids_7x[i], |
a3d6ab97 WN |
295 | 0, |
296 | AC_VERB_SET_CHANNEL_STREAMID, | |
297 | (stream_tag << 4) | channel_id); | |
298 | /* set the stream format */ | |
299 | snd_hda_codec_write(codec, | |
25045705 | 300 | nvhdmi_con_nids_7x[i], |
a3d6ab97 WN |
301 | 0, |
302 | AC_VERB_SET_STREAM_FORMAT, | |
303 | format); | |
304 | /* turn on again (if needed) */ | |
305 | /* enable and set the channel status audio/data flag */ | |
306 | if (codec->spdif_status_reset && | |
307 | (codec->spdif_ctls & AC_DIG1_ENABLE)) { | |
308 | snd_hda_codec_write(codec, | |
25045705 | 309 | nvhdmi_con_nids_7x[i], |
a3d6ab97 WN |
310 | 0, |
311 | AC_VERB_SET_DIGI_CONVERT_1, | |
312 | codec->spdif_ctls & 0xff); | |
313 | snd_hda_codec_write(codec, | |
25045705 | 314 | nvhdmi_con_nids_7x[i], |
a3d6ab97 WN |
315 | 0, |
316 | AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); | |
317 | } | |
318 | } | |
319 | ||
320 | /* set the Audio Info Frame Checksum */ | |
321 | snd_hda_codec_write(codec, 0x1, 0, | |
322 | Nv_VERB_SET_Info_Frame_Checksum, | |
323 | (0x71 - chan - chanmask)); | |
324 | ||
325 | mutex_unlock(&codec->spdif_mutex); | |
326 | return 0; | |
327 | } | |
328 | ||
329 | static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, | |
330 | struct hda_codec *codec, | |
331 | unsigned int stream_tag, | |
332 | unsigned int format, | |
333 | struct snd_pcm_substream *substream) | |
9a10eb21 | 334 | { |
079d88cc | 335 | struct hdmi_spec *spec = codec->spec; |
9a10eb21 | 336 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, |
a3d6ab97 | 337 | format, substream); |
9a10eb21 WN |
338 | } |
339 | ||
25045705 WN |
340 | static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = { |
341 | .substreams = 1, | |
342 | .channels_min = 2, | |
25045705 | 343 | .ops = { |
bbbe3390 | 344 | .open = hdmi_pcm_open, |
25045705 | 345 | .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89, |
25045705 WN |
346 | }, |
347 | }; | |
348 | ||
349 | static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = { | |
a3d6ab97 WN |
350 | .substreams = 1, |
351 | .channels_min = 2, | |
352 | .channels_max = 8, | |
25045705 | 353 | .nid = nvhdmi_master_con_nid_7x, |
f0613d57 TI |
354 | .rates = SUPPORTED_RATES, |
355 | .maxbps = SUPPORTED_MAXBPS, | |
356 | .formats = SUPPORTED_FORMATS, | |
a3d6ab97 WN |
357 | .ops = { |
358 | .open = nvhdmi_dig_playback_pcm_open, | |
25045705 | 359 | .close = nvhdmi_dig_playback_pcm_close_8ch_7x, |
a3d6ab97 WN |
360 | .prepare = nvhdmi_dig_playback_pcm_prepare_8ch |
361 | }, | |
362 | }; | |
363 | ||
364 | static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = { | |
9a10eb21 WN |
365 | .substreams = 1, |
366 | .channels_min = 2, | |
367 | .channels_max = 2, | |
25045705 | 368 | .nid = nvhdmi_master_con_nid_7x, |
f0613d57 TI |
369 | .rates = SUPPORTED_RATES, |
370 | .maxbps = SUPPORTED_MAXBPS, | |
371 | .formats = SUPPORTED_FORMATS, | |
9a10eb21 WN |
372 | .ops = { |
373 | .open = nvhdmi_dig_playback_pcm_open, | |
a3d6ab97 WN |
374 | .close = nvhdmi_dig_playback_pcm_close_2ch, |
375 | .prepare = nvhdmi_dig_playback_pcm_prepare_2ch | |
9a10eb21 WN |
376 | }, |
377 | }; | |
378 | ||
25045705 WN |
379 | static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec) |
380 | { | |
079d88cc | 381 | struct hdmi_spec *spec = codec->spec; |
25045705 WN |
382 | struct hda_pcm *info = spec->pcm_rec; |
383 | int i; | |
384 | ||
385 | codec->num_pcms = spec->num_cvts; | |
386 | codec->pcm_info = info; | |
387 | ||
388 | for (i = 0; i < codec->num_pcms; i++, info++) { | |
389 | unsigned int chans; | |
390 | ||
391 | chans = get_wcaps(codec, spec->cvt[i]); | |
392 | chans = get_wcaps_channels(chans); | |
393 | ||
394 | info->name = nvhdmi_pcm_names[i]; | |
395 | info->pcm_type = HDA_PCM_TYPE_HDMI; | |
396 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] | |
397 | = nvhdmi_pcm_digital_playback_8ch_89; | |
398 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; | |
399 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; | |
400 | } | |
401 | ||
402 | return 0; | |
403 | } | |
404 | ||
405 | static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec) | |
9a10eb21 | 406 | { |
079d88cc | 407 | struct hdmi_spec *spec = codec->spec; |
25045705 | 408 | struct hda_pcm *info = spec->pcm_rec; |
9a10eb21 WN |
409 | |
410 | codec->num_pcms = 1; | |
411 | codec->pcm_info = info; | |
412 | ||
413 | info->name = "NVIDIA HDMI"; | |
ec4e86ba | 414 | info->pcm_type = HDA_PCM_TYPE_HDMI; |
a3d6ab97 | 415 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] |
25045705 | 416 | = nvhdmi_pcm_digital_playback_8ch_7x; |
a3d6ab97 WN |
417 | |
418 | return 0; | |
419 | } | |
420 | ||
421 | static int nvhdmi_build_pcms_2ch(struct hda_codec *codec) | |
422 | { | |
079d88cc | 423 | struct hdmi_spec *spec = codec->spec; |
25045705 | 424 | struct hda_pcm *info = spec->pcm_rec; |
a3d6ab97 WN |
425 | |
426 | codec->num_pcms = 1; | |
427 | codec->pcm_info = info; | |
428 | ||
429 | info->name = "NVIDIA HDMI"; | |
430 | info->pcm_type = HDA_PCM_TYPE_HDMI; | |
431 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] | |
432 | = nvhdmi_pcm_digital_playback_2ch; | |
9a10eb21 WN |
433 | |
434 | return 0; | |
435 | } | |
436 | ||
25045705 WN |
437 | static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = { |
438 | .build_controls = nvhdmi_build_controls, | |
439 | .build_pcms = nvhdmi_build_pcms_8ch_89, | |
440 | .init = nvhdmi_init, | |
441 | .free = nvhdmi_free, | |
079d88cc | 442 | .unsol_event = hdmi_unsol_event, |
25045705 | 443 | }; |
9a10eb21 | 444 | |
25045705 | 445 | static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { |
a3d6ab97 | 446 | .build_controls = nvhdmi_build_controls, |
25045705 | 447 | .build_pcms = nvhdmi_build_pcms_8ch_7x, |
a3d6ab97 WN |
448 | .init = nvhdmi_init, |
449 | .free = nvhdmi_free, | |
450 | }; | |
451 | ||
452 | static struct hda_codec_ops nvhdmi_patch_ops_2ch = { | |
9a10eb21 | 453 | .build_controls = nvhdmi_build_controls, |
a3d6ab97 | 454 | .build_pcms = nvhdmi_build_pcms_2ch, |
9a10eb21 WN |
455 | .init = nvhdmi_init, |
456 | .free = nvhdmi_free, | |
457 | }; | |
458 | ||
25045705 WN |
459 | static int patch_nvhdmi_8ch_89(struct hda_codec *codec) |
460 | { | |
079d88cc | 461 | struct hdmi_spec *spec; |
25045705 WN |
462 | int i; |
463 | ||
464 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | |
465 | if (spec == NULL) | |
466 | return -ENOMEM; | |
467 | ||
468 | codec->spec = spec; | |
469 | spec->codec_type = HDA_CODEC_NVIDIA_MCP89; | |
38faddb1 | 470 | spec->old_pin_detect = 1; |
25045705 | 471 | |
079d88cc | 472 | if (hdmi_parse_codec(codec) < 0) { |
25045705 WN |
473 | codec->spec = NULL; |
474 | kfree(spec); | |
475 | return -EINVAL; | |
476 | } | |
477 | codec->patch_ops = nvhdmi_patch_ops_8ch_89; | |
478 | ||
479 | for (i = 0; i < spec->num_pins; i++) | |
480 | snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); | |
481 | ||
482 | init_channel_allocations(); | |
483 | ||
484 | return 0; | |
485 | } | |
486 | ||
487 | static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) | |
a3d6ab97 | 488 | { |
079d88cc | 489 | struct hdmi_spec *spec; |
a3d6ab97 WN |
490 | |
491 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | |
492 | if (spec == NULL) | |
493 | return -ENOMEM; | |
494 | ||
495 | codec->spec = spec; | |
496 | ||
497 | spec->multiout.num_dacs = 0; /* no analog */ | |
498 | spec->multiout.max_channels = 8; | |
25045705 WN |
499 | spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; |
500 | spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; | |
38faddb1 | 501 | spec->old_pin_detect = 1; |
a3d6ab97 | 502 | |
25045705 | 503 | codec->patch_ops = nvhdmi_patch_ops_8ch_7x; |
a3d6ab97 WN |
504 | |
505 | return 0; | |
506 | } | |
507 | ||
508 | static int patch_nvhdmi_2ch(struct hda_codec *codec) | |
9a10eb21 | 509 | { |
079d88cc | 510 | struct hdmi_spec *spec; |
9a10eb21 WN |
511 | |
512 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | |
513 | if (spec == NULL) | |
514 | return -ENOMEM; | |
515 | ||
516 | codec->spec = spec; | |
517 | ||
a3d6ab97 | 518 | spec->multiout.num_dacs = 0; /* no analog */ |
9a10eb21 | 519 | spec->multiout.max_channels = 2; |
25045705 WN |
520 | spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; |
521 | spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; | |
38faddb1 | 522 | spec->old_pin_detect = 1; |
9a10eb21 | 523 | |
a3d6ab97 | 524 | codec->patch_ops = nvhdmi_patch_ops_2ch; |
9a10eb21 WN |
525 | |
526 | return 0; | |
527 | } | |
528 | ||
529 | /* | |
530 | * patch entries | |
531 | */ | |
1289e9e8 | 532 | static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { |
9cf2657d SW |
533 | { .id = 0x10de0002, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, |
534 | { .id = 0x10de0003, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, | |
535 | { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, | |
536 | { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, | |
537 | { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, | |
538 | { .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
539 | { .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
540 | { .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi_8ch_89 }, | |
541 | { .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
542 | { .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
543 | { .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
544 | { .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
545 | { .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
546 | { .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
547 | { .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
548 | { .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
549 | { .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
550 | { .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
551 | { .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
552 | { .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
553 | { .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
554 | { .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
555 | { .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
556 | { .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi_8ch_89 }, | |
557 | { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, | |
558 | { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, | |
9a10eb21 WN |
559 | {} /* terminator */ |
560 | }; | |
1289e9e8 TI |
561 | |
562 | MODULE_ALIAS("snd-hda-codec-id:10de0002"); | |
f8ff035e | 563 | MODULE_ALIAS("snd-hda-codec-id:10de0003"); |
e2e527ae | 564 | MODULE_ALIAS("snd-hda-codec-id:10de0005"); |
f84e3e91 | 565 | MODULE_ALIAS("snd-hda-codec-id:10de0006"); |
1289e9e8 | 566 | MODULE_ALIAS("snd-hda-codec-id:10de0007"); |
e933e9e5 | 567 | MODULE_ALIAS("snd-hda-codec-id:10de000a"); |
ea823c08 TI |
568 | MODULE_ALIAS("snd-hda-codec-id:10de000b"); |
569 | MODULE_ALIAS("snd-hda-codec-id:10de000c"); | |
25045705 | 570 | MODULE_ALIAS("snd-hda-codec-id:10de000d"); |
9cf2657d SW |
571 | MODULE_ALIAS("snd-hda-codec-id:10de0010"); |
572 | MODULE_ALIAS("snd-hda-codec-id:10de0011"); | |
573 | MODULE_ALIAS("snd-hda-codec-id:10de0012"); | |
574 | MODULE_ALIAS("snd-hda-codec-id:10de0013"); | |
575 | MODULE_ALIAS("snd-hda-codec-id:10de0014"); | |
576 | MODULE_ALIAS("snd-hda-codec-id:10de0018"); | |
577 | MODULE_ALIAS("snd-hda-codec-id:10de0019"); | |
578 | MODULE_ALIAS("snd-hda-codec-id:10de001a"); | |
579 | MODULE_ALIAS("snd-hda-codec-id:10de001b"); | |
580 | MODULE_ALIAS("snd-hda-codec-id:10de001c"); | |
581 | MODULE_ALIAS("snd-hda-codec-id:10de0040"); | |
582 | MODULE_ALIAS("snd-hda-codec-id:10de0041"); | |
583 | MODULE_ALIAS("snd-hda-codec-id:10de0042"); | |
584 | MODULE_ALIAS("snd-hda-codec-id:10de0043"); | |
585 | MODULE_ALIAS("snd-hda-codec-id:10de0044"); | |
ea823c08 TI |
586 | MODULE_ALIAS("snd-hda-codec-id:10de0067"); |
587 | MODULE_ALIAS("snd-hda-codec-id:10de8001"); | |
1289e9e8 TI |
588 | |
589 | MODULE_LICENSE("GPL"); | |
25045705 | 590 | MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec"); |
1289e9e8 TI |
591 | |
592 | static struct hda_codec_preset_list nvhdmi_list = { | |
593 | .preset = snd_hda_preset_nvhdmi, | |
594 | .owner = THIS_MODULE, | |
595 | }; | |
596 | ||
597 | static int __init patch_nvhdmi_init(void) | |
598 | { | |
599 | return snd_hda_add_codec_preset(&nvhdmi_list); | |
600 | } | |
601 | ||
602 | static void __exit patch_nvhdmi_exit(void) | |
603 | { | |
604 | snd_hda_delete_codec_preset(&nvhdmi_list); | |
605 | } | |
606 | ||
607 | module_init(patch_nvhdmi_init) | |
608 | module_exit(patch_nvhdmi_exit) |