3 |
* Universal interface for Audio Codec '97 |
* Universal interface for Audio Codec '97 |
4 |
* |
* |
5 |
* For more details look to AC '97 component specification revision 2.2 |
* For more details look to AC '97 component specification revision 2.2 |
6 |
* by Intel Corporation (http://developer.intel.com). |
* by Intel Corporation (http://developer.intel.com) and to datasheets |
7 |
|
* for specific codecs. |
8 |
* |
* |
9 |
* |
* |
10 |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
29 |
#include <linux/slab.h> |
#include <linux/slab.h> |
30 |
#include <sound/core.h> |
#include <sound/core.h> |
31 |
#include <sound/pcm.h> |
#include <sound/pcm.h> |
32 |
|
#include <sound/control.h> |
33 |
#include <sound/ac97_codec.h> |
#include <sound/ac97_codec.h> |
|
#include <sound/asoundef.h> |
|
|
#include <sound/initval.h> |
|
34 |
#include "ac97_patch.h" |
#include "ac97_patch.h" |
35 |
|
#include "ac97_id.h" |
36 |
|
#include "ac97_local.h" |
37 |
|
|
38 |
|
#define chip_t ac97_t |
39 |
|
|
40 |
/* |
/* |
41 |
* Chip specific initialization |
* Chip specific initialization |
42 |
*/ |
*/ |
43 |
|
|
44 |
|
static int patch_build_controls(ac97_t * ac97, const snd_kcontrol_new_t *controls, int count) |
45 |
|
{ |
46 |
|
int idx, err; |
47 |
|
|
48 |
|
for (idx = 0; idx < count; idx++) |
49 |
|
if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&controls[idx], ac97))) < 0) |
50 |
|
return err; |
51 |
|
return 0; |
52 |
|
} |
53 |
|
|
54 |
|
/* The following snd_ac97_ymf753_... items added by David Shust (dshust@shustring.com) */ |
55 |
|
|
56 |
|
/* It is possible to indicate to the Yamaha YMF753 the type of speakers being used. */ |
57 |
|
static int snd_ac97_ymf753_info_speaker(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
58 |
|
{ |
59 |
|
static char *texts[3] = { |
60 |
|
"Standard", "Small", "Smaller" |
61 |
|
}; |
62 |
|
|
63 |
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
64 |
|
uinfo->count = 1; |
65 |
|
uinfo->value.enumerated.items = 3; |
66 |
|
if (uinfo->value.enumerated.item > 2) |
67 |
|
uinfo->value.enumerated.item = 2; |
68 |
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
69 |
|
return 0; |
70 |
|
} |
71 |
|
|
72 |
|
static int snd_ac97_ymf753_get_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
73 |
|
{ |
74 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
75 |
|
unsigned short val; |
76 |
|
|
77 |
|
val = ac97->regs[AC97_YMF753_3D_MODE_SEL]; |
78 |
|
val = (val >> 10) & 3; |
79 |
|
if (val > 0) /* 0 = invalid */ |
80 |
|
val--; |
81 |
|
ucontrol->value.enumerated.item[0] = val; |
82 |
|
return 0; |
83 |
|
} |
84 |
|
|
85 |
|
static int snd_ac97_ymf753_put_speaker(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
86 |
|
{ |
87 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
88 |
|
unsigned short val; |
89 |
|
|
90 |
|
if (ucontrol->value.enumerated.item[0] > 2) |
91 |
|
return -EINVAL; |
92 |
|
val = (ucontrol->value.enumerated.item[0] + 1) << 10; |
93 |
|
return snd_ac97_update(ac97, AC97_YMF753_3D_MODE_SEL, val); |
94 |
|
} |
95 |
|
|
96 |
|
static const snd_kcontrol_new_t snd_ac97_ymf753_controls_speaker = |
97 |
|
{ |
98 |
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
99 |
|
.name = "3D Control - Speaker", |
100 |
|
.info = snd_ac97_ymf753_info_speaker, |
101 |
|
.get = snd_ac97_ymf753_get_speaker, |
102 |
|
.put = snd_ac97_ymf753_put_speaker, |
103 |
|
}; |
104 |
|
|
105 |
|
/* It is possible to indicate to the Yamaha YMF753 the source to direct to the S/PDIF output. */ |
106 |
|
static int snd_ac97_ymf753_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
107 |
|
{ |
108 |
|
static char *texts[2] = { "AC-Link", "A/D Converter" }; |
109 |
|
|
110 |
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
111 |
|
uinfo->count = 1; |
112 |
|
uinfo->value.enumerated.items = 2; |
113 |
|
if (uinfo->value.enumerated.item > 1) |
114 |
|
uinfo->value.enumerated.item = 1; |
115 |
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
116 |
|
return 0; |
117 |
|
} |
118 |
|
|
119 |
|
static int snd_ac97_ymf753_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
120 |
|
{ |
121 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
122 |
|
unsigned short val; |
123 |
|
|
124 |
|
val = ac97->regs[AC97_YMF753_DIT_CTRL2]; |
125 |
|
ucontrol->value.enumerated.item[0] = (val >> 1) & 1; |
126 |
|
return 0; |
127 |
|
} |
128 |
|
|
129 |
|
static int snd_ac97_ymf753_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
130 |
|
{ |
131 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
132 |
|
unsigned short val; |
133 |
|
|
134 |
|
if (ucontrol->value.enumerated.item[0] > 1) |
135 |
|
return -EINVAL; |
136 |
|
val = ucontrol->value.enumerated.item[0] << 1; |
137 |
|
return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0002, val); |
138 |
|
} |
139 |
|
|
140 |
|
/* The AC'97 spec states that the S/PDIF signal is to be output at pin 48. |
141 |
|
The YMF753 will output the S/PDIF signal to pin 43, 47 (EAPD), or 48. |
142 |
|
By default, no output pin is selected, and the S/PDIF signal is not output. |
143 |
|
There is also a bit to mute S/PDIF output in a vendor-specific register. */ |
144 |
|
static int snd_ac97_ymf753_spdif_output_pin_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
145 |
|
{ |
146 |
|
static char *texts[3] = { "Disabled", "Pin 43", "Pin 48" }; |
147 |
|
|
148 |
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
149 |
|
uinfo->count = 1; |
150 |
|
uinfo->value.enumerated.items = 3; |
151 |
|
if (uinfo->value.enumerated.item > 2) |
152 |
|
uinfo->value.enumerated.item = 2; |
153 |
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
154 |
|
return 0; |
155 |
|
} |
156 |
|
|
157 |
|
static int snd_ac97_ymf753_spdif_output_pin_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
158 |
|
{ |
159 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
160 |
|
unsigned short val; |
161 |
|
|
162 |
|
val = ac97->regs[AC97_YMF753_DIT_CTRL2]; |
163 |
|
ucontrol->value.enumerated.item[0] = (val & 0x0008) ? 2 : (val & 0x0020) ? 1 : 0; |
164 |
|
return 0; |
165 |
|
} |
166 |
|
|
167 |
|
static int snd_ac97_ymf753_spdif_output_pin_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
168 |
|
{ |
169 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
170 |
|
unsigned short val; |
171 |
|
|
172 |
|
if (ucontrol->value.enumerated.item[0] > 2) |
173 |
|
return -EINVAL; |
174 |
|
val = (ucontrol->value.enumerated.item[0] == 2) ? 0x0008 : |
175 |
|
(ucontrol->value.enumerated.item[0] == 1) ? 0x0020 : 0; |
176 |
|
return snd_ac97_update_bits(ac97, AC97_YMF753_DIT_CTRL2, 0x0028, val); |
177 |
|
/* The following can be used to direct S/PDIF output to pin 47 (EAPD). |
178 |
|
snd_ac97_write_cache(ac97, 0x62, snd_ac97_read(ac97, 0x62) | 0x0008); */ |
179 |
|
} |
180 |
|
|
181 |
|
static const snd_kcontrol_new_t snd_ac97_ymf753_controls_spdif[3] = { |
182 |
|
{ |
183 |
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
184 |
|
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
185 |
|
.info = snd_ac97_ymf753_spdif_source_info, |
186 |
|
.get = snd_ac97_ymf753_spdif_source_get, |
187 |
|
.put = snd_ac97_ymf753_spdif_source_put, |
188 |
|
}, |
189 |
|
{ |
190 |
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
191 |
|
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Output Pin", |
192 |
|
.info = snd_ac97_ymf753_spdif_output_pin_info, |
193 |
|
.get = snd_ac97_ymf753_spdif_output_pin_get, |
194 |
|
.put = snd_ac97_ymf753_spdif_output_pin_put, |
195 |
|
}, |
196 |
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",NONE,NONE) "Mute", AC97_YMF753_DIT_CTRL2, 2, 1, 1) |
197 |
|
}; |
198 |
|
|
199 |
|
static int patch_yamaha_ymf753_3d(ac97_t * ac97) |
200 |
|
{ |
201 |
|
snd_kcontrol_t *kctl; |
202 |
|
int err; |
203 |
|
|
204 |
|
if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) |
205 |
|
return err; |
206 |
|
strcpy(kctl->id.name, "3D Control - Wide"); |
207 |
|
kctl->private_value = AC97_3D_CONTROL | (9 << 8) | (7 << 16); |
208 |
|
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); |
209 |
|
if ((err = snd_ctl_add(ac97->card, snd_ac97_cnew(&snd_ac97_ymf753_controls_speaker, ac97))) < 0) |
210 |
|
return err; |
211 |
|
snd_ac97_write_cache(ac97, AC97_YMF753_3D_MODE_SEL, 0x0c00); |
212 |
|
return 0; |
213 |
|
} |
214 |
|
|
215 |
|
static int patch_yamaha_ymf753_post_spdif(ac97_t * ac97) |
216 |
|
{ |
217 |
|
int err; |
218 |
|
|
219 |
|
if ((err = patch_build_controls(ac97, snd_ac97_ymf753_controls_spdif, ARRAY_SIZE(snd_ac97_ymf753_controls_spdif))) < 0) |
220 |
|
return err; |
221 |
|
return 0; |
222 |
|
} |
223 |
|
|
224 |
|
static struct snd_ac97_build_ops patch_yamaha_ymf753_ops = { |
225 |
|
.build_3d = patch_yamaha_ymf753_3d, |
226 |
|
.build_post_spdif = patch_yamaha_ymf753_post_spdif |
227 |
|
}; |
228 |
|
|
229 |
int patch_yamaha_ymf753(ac97_t * ac97) |
int patch_yamaha_ymf753(ac97_t * ac97) |
230 |
{ |
{ |
231 |
/* Patch for Yamaha YMF753, Copyright (c) by David Shust, dshust@shustring.com. |
/* Patch for Yamaha YMF753, Copyright (c) by David Shust, dshust@shustring.com. |
235 |
By default, no output pin is selected, and the S/PDIF signal is not output. |
By default, no output pin is selected, and the S/PDIF signal is not output. |
236 |
There is also a bit to mute S/PDIF output in a vendor-specific register. |
There is also a bit to mute S/PDIF output in a vendor-specific register. |
237 |
*/ |
*/ |
238 |
|
ac97->build_ops = &patch_yamaha_ymf753_ops; |
239 |
ac97->caps |= AC97_BC_BASS_TREBLE; |
ac97->caps |= AC97_BC_BASS_TREBLE; |
240 |
ac97->caps |= 0x04 << 10; /* Yamaha 3D enhancement */ |
ac97->caps |= 0x04 << 10; /* Yamaha 3D enhancement */ |
241 |
return 0; |
return 0; |
247 |
* added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717. |
* added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717. |
248 |
*/ |
*/ |
249 |
|
|
|
#define AC97_WM97XX_FMIXER_VOL 0x72 |
|
|
#define AC97_WM9704_RMIXER_VOL 0x74 |
|
|
#define AC97_WM9704_TEST 0x5a |
|
|
#define AC97_WM9704_RPCM_VOL 0x70 |
|
|
#define AC97_WM9711_OUT3VOL 0x16 |
|
|
|
|
250 |
int patch_wolfson03(ac97_t * ac97) |
int patch_wolfson03(ac97_t * ac97) |
251 |
{ |
{ |
252 |
/* This is known to work for the ViewSonic ViewPad 1000 |
/* This is known to work for the ViewSonic ViewPad 1000 |
301 |
return 0; |
return 0; |
302 |
} |
} |
303 |
|
|
304 |
|
static int patch_sigmatel_stac9700_3d(ac97_t * ac97) |
305 |
|
{ |
306 |
|
snd_kcontrol_t *kctl; |
307 |
|
int err; |
308 |
|
|
309 |
|
if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) |
310 |
|
return err; |
311 |
|
strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); |
312 |
|
kctl->private_value = AC97_3D_CONTROL | (3 << 16); |
313 |
|
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); |
314 |
|
return 0; |
315 |
|
} |
316 |
|
|
317 |
|
static int patch_sigmatel_stac9708_3d(ac97_t * ac97) |
318 |
|
{ |
319 |
|
snd_kcontrol_t *kctl; |
320 |
|
int err; |
321 |
|
|
322 |
|
if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) |
323 |
|
return err; |
324 |
|
strcpy(kctl->id.name, "3D Control Sigmatel - Depth"); |
325 |
|
kctl->private_value = AC97_3D_CONTROL | (3 << 16); |
326 |
|
if ((err = snd_ctl_add(ac97->card, kctl = snd_ac97_cnew(&snd_ac97_controls_3d[0], ac97))) < 0) |
327 |
|
return err; |
328 |
|
strcpy(kctl->id.name, "3D Control Sigmatel - Rear Depth"); |
329 |
|
kctl->private_value = AC97_3D_CONTROL | (2 << 8) | (3 << 16); |
330 |
|
snd_ac97_write_cache(ac97, AC97_3D_CONTROL, 0x0000); |
331 |
|
return 0; |
332 |
|
} |
333 |
|
|
334 |
|
static const snd_kcontrol_new_t snd_ac97_sigmatel_4speaker = |
335 |
|
AC97_SINGLE("Sigmatel 4-Speaker Stereo Playback Switch", AC97_SIGMATEL_DAC2INVERT, 2, 1, 0); |
336 |
|
|
337 |
|
static const snd_kcontrol_new_t snd_ac97_sigmatel_phaseinvert = |
338 |
|
AC97_SINGLE("Sigmatel Surround Phase Inversion Playback Switch", AC97_SIGMATEL_DAC2INVERT, 3, 1, 0); |
339 |
|
|
340 |
|
static const snd_kcontrol_new_t snd_ac97_sigmatel_controls[] = { |
341 |
|
AC97_SINGLE("Sigmatel DAC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 1, 1, 0), |
342 |
|
AC97_SINGLE("Sigmatel ADC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 0, 1, 0) |
343 |
|
}; |
344 |
|
|
345 |
|
static int patch_sigmatel_stac97xx_specific(ac97_t * ac97) |
346 |
|
{ |
347 |
|
int err; |
348 |
|
|
349 |
|
snd_ac97_write_cache(ac97, AC97_SIGMATEL_ANALOG, snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) & ~0x0003); |
350 |
|
if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 1)) |
351 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[0], 1)) < 0) |
352 |
|
return err; |
353 |
|
if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0)) |
354 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_controls[1], 1)) < 0) |
355 |
|
return err; |
356 |
|
if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 2)) |
357 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_4speaker, 1)) < 0) |
358 |
|
return err; |
359 |
|
if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_DAC2INVERT, 3)) |
360 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_sigmatel_phaseinvert, 1)) < 0) |
361 |
|
return err; |
362 |
|
return 0; |
363 |
|
} |
364 |
|
|
365 |
|
static struct snd_ac97_build_ops patch_sigmatel_stac9700_ops = { |
366 |
|
.build_3d = patch_sigmatel_stac9700_3d, |
367 |
|
.build_specific = patch_sigmatel_stac97xx_specific |
368 |
|
}; |
369 |
|
|
370 |
|
static struct snd_ac97_build_ops patch_sigmatel_stac9708_ops = { |
371 |
|
.build_3d = patch_sigmatel_stac9708_3d, |
372 |
|
.build_specific = patch_sigmatel_stac97xx_specific |
373 |
|
}; |
374 |
|
|
375 |
|
int patch_sigmatel_stac9700(ac97_t * ac97) |
376 |
|
{ |
377 |
|
ac97->build_ops = &patch_sigmatel_stac9700_ops; |
378 |
|
return 0; |
379 |
|
} |
380 |
|
|
381 |
int patch_sigmatel_stac9708(ac97_t * ac97) |
int patch_sigmatel_stac9708(ac97_t * ac97) |
382 |
{ |
{ |
383 |
unsigned int codec72, codec6c; |
unsigned int codec72, codec6c; |
384 |
|
|
385 |
|
ac97->build_ops = &patch_sigmatel_stac9708_ops; |
386 |
|
|
387 |
codec72 = snd_ac97_read(ac97, AC97_SIGMATEL_BIAS2) & 0x8000; |
codec72 = snd_ac97_read(ac97, AC97_SIGMATEL_BIAS2) & 0x8000; |
388 |
codec6c = snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG); |
codec6c = snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG); |
389 |
|
|
405 |
|
|
406 |
int patch_sigmatel_stac9721(ac97_t * ac97) |
int patch_sigmatel_stac9721(ac97_t * ac97) |
407 |
{ |
{ |
408 |
|
ac97->build_ops = &patch_sigmatel_stac9700_ops; |
409 |
if (snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) == 0) { |
if (snd_ac97_read(ac97, AC97_SIGMATEL_ANALOG) == 0) { |
410 |
// patch for SigmaTel |
// patch for SigmaTel |
411 |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba); |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba); |
420 |
int patch_sigmatel_stac9744(ac97_t * ac97) |
int patch_sigmatel_stac9744(ac97_t * ac97) |
421 |
{ |
{ |
422 |
// patch for SigmaTel |
// patch for SigmaTel |
423 |
|
ac97->build_ops = &patch_sigmatel_stac9700_ops; |
424 |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba); |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba); |
425 |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */ |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */ |
426 |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba); |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba); |
432 |
int patch_sigmatel_stac9756(ac97_t * ac97) |
int patch_sigmatel_stac9756(ac97_t * ac97) |
433 |
{ |
{ |
434 |
// patch for SigmaTel |
// patch for SigmaTel |
435 |
|
ac97->build_ops = &patch_sigmatel_stac9700_ops; |
436 |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba); |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC1, 0xabba); |
437 |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */ |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_CIC2, 0x0000); /* is this correct? --jk */ |
438 |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba); |
snd_ac97_write_cache(ac97, AC97_SIGMATEL_BIAS1, 0xabba); |
441 |
return 0; |
return 0; |
442 |
} |
} |
443 |
|
|
444 |
|
static const snd_kcontrol_new_t snd_ac97_cirrus_controls_spdif[2] = { |
445 |
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CSR_SPDIF, 15, 1, 0), |
446 |
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "AC97-SPSA", AC97_CSR_ACMODE, 0, 3, 0) |
447 |
|
}; |
448 |
|
|
449 |
|
static int patch_cirrus_build_spdif(ac97_t * ac97) |
450 |
|
{ |
451 |
|
int err; |
452 |
|
|
453 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0) |
454 |
|
return err; |
455 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[0], 1)) < 0) |
456 |
|
return err; |
457 |
|
switch (ac97->id & AC97_ID_CS_MASK) { |
458 |
|
case AC97_ID_CS4205: |
459 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_cirrus_controls_spdif[1], 1)) < 0) |
460 |
|
return err; |
461 |
|
break; |
462 |
|
} |
463 |
|
/* set default PCM S/PDIF params */ |
464 |
|
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ |
465 |
|
snd_ac97_write_cache(ac97, AC97_CSR_SPDIF, 0x0a20); |
466 |
|
return 0; |
467 |
|
} |
468 |
|
|
469 |
|
static struct snd_ac97_build_ops patch_cirrus_ops = { |
470 |
|
.build_spdif = patch_cirrus_build_spdif |
471 |
|
}; |
472 |
|
|
473 |
int patch_cirrus_spdif(ac97_t * ac97) |
int patch_cirrus_spdif(ac97_t * ac97) |
474 |
{ |
{ |
475 |
/* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers. |
/* Basically, the cs4201/cs4205/cs4297a has non-standard sp/dif registers. |
483 |
- sp/dif ssource select is in 0x5e bits 0,1. |
- sp/dif ssource select is in 0x5e bits 0,1. |
484 |
*/ |
*/ |
485 |
|
|
486 |
|
ac97->build_ops = &patch_cirrus_ops; |
487 |
ac97->flags |= AC97_CS_SPDIF; |
ac97->flags |= AC97_CS_SPDIF; |
488 |
ac97->rates[AC97_RATES_SPDIF] &= ~SNDRV_PCM_RATE_32000; |
ac97->rates[AC97_RATES_SPDIF] &= ~SNDRV_PCM_RATE_32000; |
489 |
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ |
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ |
499 |
return patch_cirrus_spdif(ac97); |
return patch_cirrus_spdif(ac97); |
500 |
} |
} |
501 |
|
|
502 |
|
static const snd_kcontrol_new_t snd_ac97_conexant_controls_spdif[1] = { |
503 |
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), AC97_CXR_AUDIO_MISC, 3, 1, 0), |
504 |
|
}; |
505 |
|
|
506 |
|
static int patch_conexant_build_spdif(ac97_t * ac97) |
507 |
|
{ |
508 |
|
int err; |
509 |
|
|
510 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_controls_spdif[0], 3)) < 0) |
511 |
|
return err; |
512 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_conexant_controls_spdif[0], 1)) < 0) |
513 |
|
return err; |
514 |
|
/* set default PCM S/PDIF params */ |
515 |
|
/* consumer,PCM audio,no copyright,no preemphasis,PCM coder,original,48000Hz */ |
516 |
|
snd_ac97_write_cache(ac97, AC97_CXR_AUDIO_MISC, |
517 |
|
snd_ac97_read(ac97, AC97_CXR_AUDIO_MISC) & ~(AC97_CXR_SPDIFEN|AC97_CXR_COPYRGT|AC97_CXR_SPDIF_MASK)); |
518 |
|
return 0; |
519 |
|
} |
520 |
|
|
521 |
|
static struct snd_ac97_build_ops patch_conexant_ops = { |
522 |
|
.build_spdif = patch_conexant_build_spdif |
523 |
|
}; |
524 |
|
|
525 |
int patch_conexant(ac97_t * ac97) |
int patch_conexant(ac97_t * ac97) |
526 |
{ |
{ |
527 |
|
ac97->build_ops = &patch_conexant_ops; |
528 |
ac97->flags |= AC97_CX_SPDIF; |
ac97->flags |= AC97_CX_SPDIF; |
529 |
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ |
ac97->ext_id |= AC97_EI_SPDIF; /* force the detection of spdif */ |
530 |
return 0; |
return 0; |
650 |
return 0; |
return 0; |
651 |
} |
} |
652 |
|
|
653 |
|
static const snd_kcontrol_new_t snd_ac97_controls_ad1885[] = { |
654 |
|
AC97_SINGLE("Digital Mono Direct", AC97_AD_MISC, 11, 1, 0), |
655 |
|
AC97_SINGLE("Digital Audio Mode", AC97_AD_MISC, 12, 1, 0), |
656 |
|
AC97_SINGLE("Low Power Mixer", AC97_AD_MISC, 14, 1, 0), |
657 |
|
AC97_SINGLE("Zero Fill DAC", AC97_AD_MISC, 15, 1, 0), |
658 |
|
}; |
659 |
|
|
660 |
|
static int patch_ad1885_specific(ac97_t * ac97) |
661 |
|
{ |
662 |
|
int err; |
663 |
|
|
664 |
|
if ((err = patch_build_controls(ac97, snd_ac97_controls_ad1885, ARRAY_SIZE(snd_ac97_controls_ad1885))) < 0) |
665 |
|
return err; |
666 |
|
return 0; |
667 |
|
} |
668 |
|
|
669 |
|
static struct snd_ac97_build_ops patch_ad1885_build_ops = { |
670 |
|
.build_specific = &patch_ad1885_specific |
671 |
|
}; |
672 |
|
|
673 |
int patch_ad1885(ac97_t * ac97) |
int patch_ad1885(ac97_t * ac97) |
674 |
{ |
{ |
675 |
unsigned short jack; |
unsigned short jack; |
681 |
/* turn off jack sense bits D8 & D9 */ |
/* turn off jack sense bits D8 & D9 */ |
682 |
jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF); |
jack = snd_ac97_read(ac97, AC97_AD_JACK_SPDIF); |
683 |
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300); |
snd_ac97_write_cache(ac97, AC97_AD_JACK_SPDIF, jack | 0x0300); |
684 |
|
|
685 |
|
ac97->build_ops = &patch_ad1885_build_ops; |
686 |
return 0; |
return 0; |
687 |
} |
} |
688 |
|
|
695 |
return 0; |
return 0; |
696 |
} |
} |
697 |
|
|
698 |
|
static int snd_ac97_ad1980_spdif_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
699 |
|
{ |
700 |
|
static char *texts[2] = { "AC-Link", "A/D Converter" }; |
701 |
|
|
702 |
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
703 |
|
uinfo->count = 1; |
704 |
|
uinfo->value.enumerated.items = 2; |
705 |
|
if (uinfo->value.enumerated.item > 1) |
706 |
|
uinfo->value.enumerated.item = 1; |
707 |
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
708 |
|
return 0; |
709 |
|
} |
710 |
|
|
711 |
|
static int snd_ac97_ad1980_spdif_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
712 |
|
{ |
713 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
714 |
|
unsigned short val; |
715 |
|
|
716 |
|
val = ac97->regs[AC97_AD_SERIAL_CFG]; |
717 |
|
ucontrol->value.enumerated.item[0] = (val >> 2) & 1; |
718 |
|
return 0; |
719 |
|
} |
720 |
|
|
721 |
|
static int snd_ac97_ad1980_spdif_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
722 |
|
{ |
723 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
724 |
|
unsigned short val; |
725 |
|
|
726 |
|
if (ucontrol->value.enumerated.item[0] > 1) |
727 |
|
return -EINVAL; |
728 |
|
val = ucontrol->value.enumerated.item[0] << 2; |
729 |
|
return snd_ac97_update_bits(ac97, AC97_AD_SERIAL_CFG, 0x0004, val); |
730 |
|
} |
731 |
|
|
732 |
|
static const snd_kcontrol_new_t snd_ac97_ad1980_spdif_source = { |
733 |
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
734 |
|
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
735 |
|
.info = snd_ac97_ad1980_spdif_source_info, |
736 |
|
.get = snd_ac97_ad1980_spdif_source_get, |
737 |
|
.put = snd_ac97_ad1980_spdif_source_put, |
738 |
|
}; |
739 |
|
|
740 |
|
static int patch_ad1980_post_spdif(ac97_t * ac97) |
741 |
|
{ |
742 |
|
return patch_build_controls(ac97, &snd_ac97_ad1980_spdif_source, 1); |
743 |
|
} |
744 |
|
|
745 |
|
static struct snd_ac97_build_ops patch_ad1980_build_ops = { |
746 |
|
.build_post_spdif = &patch_ad1980_post_spdif |
747 |
|
}; |
748 |
|
|
749 |
int patch_ad1980(ac97_t * ac97) |
int patch_ad1980(ac97_t * ac97) |
750 |
{ |
{ |
751 |
unsigned short misc; |
unsigned short misc; |
752 |
|
|
753 |
patch_ad1881(ac97); |
patch_ad1881(ac97); |
754 |
|
ac97->build_ops = &patch_ad1980_build_ops; |
755 |
/* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */ |
/* Switch FRONT/SURROUND LINE-OUT/HP-OUT default connection */ |
756 |
/* it seems that most vendors connect line-out connector to headphone out of AC'97 */ |
/* it seems that most vendors connect line-out connector to headphone out of AC'97 */ |
757 |
misc = snd_ac97_read(ac97, AC97_AD_MISC); |
misc = snd_ac97_read(ac97, AC97_AD_MISC); |
759 |
return 0; |
return 0; |
760 |
} |
} |
761 |
|
|
762 |
|
static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = { |
763 |
|
AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0), |
764 |
|
AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0), |
765 |
|
AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0), |
766 |
|
AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0), |
767 |
|
/* 4: Analog Input To Surround */ |
768 |
|
/* 5: Analog Input To Center/LFE */ |
769 |
|
/* 6: Independent Master Volume Right */ |
770 |
|
/* 7: Independent Master Volume Left */ |
771 |
|
/* 8: reserved */ |
772 |
|
AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), |
773 |
|
AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), |
774 |
|
#if 0 /* always set in patch_alc650 */ |
775 |
|
AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0), |
776 |
|
AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0), |
777 |
|
AC97_SINGLE("Surround DAC Switch", AC97_ALC650_SURR_DAC_VOL, 15, 1, 1), |
778 |
|
AC97_DOUBLE("Surround DAC Volume", AC97_ALC650_SURR_DAC_VOL, 8, 0, 31, 1), |
779 |
|
AC97_SINGLE("Center/LFE DAC Switch", AC97_ALC650_LFE_DAC_VOL, 15, 1, 1), |
780 |
|
AC97_DOUBLE("Center/LFE DAC Volume", AC97_ALC650_LFE_DAC_VOL, 8, 0, 31, 1), |
781 |
|
#endif |
782 |
|
}; |
783 |
|
|
784 |
|
static const snd_kcontrol_new_t snd_ac97_control_alc650_mic = |
785 |
|
AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0); |
786 |
|
|
787 |
|
static int snd_ac97_alc650_mic_gpio_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) |
788 |
|
{ |
789 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
790 |
|
ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; |
791 |
|
return 0; |
792 |
|
} |
793 |
|
|
794 |
|
static int snd_ac97_alc650_mic_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) |
795 |
|
{ |
796 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
797 |
|
int change; |
798 |
|
change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, |
799 |
|
ucontrol->value.integer.value[0] ? (1 << 10) : 0); |
800 |
|
if (change) { |
801 |
|
/* GPIO0 write for mic */ |
802 |
|
snd_ac97_update_bits(ac97, 0x76, 0x01, |
803 |
|
ucontrol->value.integer.value[0] ? 0 : 0x01); |
804 |
|
/* GPIO0 high for mic */ |
805 |
|
snd_ac97_update_bits(ac97, 0x78, 0x100, |
806 |
|
ucontrol->value.integer.value[0] ? 0 : 0x100); |
807 |
|
} |
808 |
|
return change; |
809 |
|
} |
810 |
|
|
811 |
|
static const snd_kcontrol_new_t snd_ac97_control_alc650_mic_gpio = { |
812 |
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
813 |
|
.name = "Mic As Center/LFE", |
814 |
|
.info = snd_ac97_info_single, |
815 |
|
.get = snd_ac97_alc650_mic_gpio_get, |
816 |
|
.put = snd_ac97_alc650_mic_gpio_put, |
817 |
|
.private_value = (1 << 16), /* for info */ |
818 |
|
}; |
819 |
|
|
820 |
|
static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { |
821 |
|
AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), |
822 |
|
AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0), |
823 |
|
AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0), |
824 |
|
}; |
825 |
|
|
826 |
|
static int patch_alc650_specific(ac97_t * ac97) |
827 |
|
{ |
828 |
|
int err; |
829 |
|
|
830 |
|
if ((err = patch_build_controls(ac97, snd_ac97_controls_alc650, ARRAY_SIZE(snd_ac97_controls_alc650))) < 0) |
831 |
|
return err; |
832 |
|
if ((err = patch_build_controls(ac97, |
833 |
|
ac97->spec.dev_flags ? |
834 |
|
&snd_ac97_control_alc650_mic : |
835 |
|
&snd_ac97_control_alc650_mic_gpio, 1)) < 0) |
836 |
|
return err; |
837 |
|
if (ac97->ext_id & AC97_EI_SPDIF) { |
838 |
|
if ((err = patch_build_controls(ac97, snd_ac97_spdif_controls_alc650, ARRAY_SIZE(snd_ac97_spdif_controls_alc650))) < 0) |
839 |
|
return err; |
840 |
|
} |
841 |
|
return 0; |
842 |
|
} |
843 |
|
|
844 |
|
static struct snd_ac97_build_ops patch_alc650_ops = { |
845 |
|
.build_specific = patch_alc650_specific |
846 |
|
}; |
847 |
|
|
848 |
int patch_alc650(ac97_t * ac97) |
int patch_alc650(ac97_t * ac97) |
849 |
{ |
{ |
850 |
unsigned short val; |
unsigned short val; |
851 |
int spdif = 0; |
int spdif = 0; |
852 |
|
|
853 |
/* FIXME: set the above 1 if we can detect the chip rev.E correctly. |
/* FIXME: set the below 1 if we can detect the chip rev.E correctly. |
854 |
* this is used for switching mic and center/lfe, which needs |
* this is used for switching mic and center/lfe, which needs |
855 |
* resetting GPIO0 level on the older revision. |
* resetting GPIO0 level on the older revision. |
856 |
*/ |
*/ |
857 |
|
ac97->build_ops = &patch_alc650_ops; |
858 |
ac97->spec.dev_flags = 0; |
ac97->spec.dev_flags = 0; |
859 |
|
|
860 |
/* check spdif */ |
/* check spdif (should be only on rev.E) */ |
861 |
if (ac97->spec.dev_flags) { |
val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); |
862 |
val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); |
if (val & AC97_EA_SPCV) |
863 |
if (val & AC97_EA_SPCV) |
spdif = 1; |
864 |
spdif = 1; |
|
|
} |
|
865 |
if (spdif) { |
if (spdif) { |
866 |
/* enable spdif in */ |
/* enable spdif in */ |
867 |
snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, |
snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, |
898 |
return 0; |
return 0; |
899 |
} |
} |
900 |
|
|
901 |
|
static const snd_kcontrol_new_t snd_ac97_cm9738_controls[] = { |
902 |
|
AC97_SINGLE("Line-In As Surround", AC97_CM9738_VENDOR_CTRL, 10, 1, 0), |
903 |
|
AC97_SINGLE("Duplicate Front", AC97_CM9738_VENDOR_CTRL, 13, 1, 0), |
904 |
|
}; |
905 |
|
|
906 |
|
static int patch_cm9738_specific(ac97_t * ac97) |
907 |
|
{ |
908 |
|
return patch_build_controls(ac97, snd_ac97_cm9738_controls, ARRAY_SIZE(snd_ac97_cm9738_controls)); |
909 |
|
} |
910 |
|
|
911 |
|
static struct snd_ac97_build_ops patch_cm9738_ops = { |
912 |
|
.build_specific = patch_cm9738_specific |
913 |
|
}; |
914 |
|
|
915 |
|
int patch_cm9738(ac97_t * ac97) |
916 |
|
{ |
917 |
|
ac97->build_ops = &patch_cm9738_ops; |
918 |
|
return 0; |
919 |
|
} |
920 |
|
|
921 |
|
static int snd_ac97_cmedia_spdif_playback_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) |
922 |
|
{ |
923 |
|
static char *texts[] = { "Analog", "Digital" }; |
924 |
|
|
925 |
|
uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
926 |
|
uinfo->count = 1; |
927 |
|
uinfo->value.enumerated.items = 2; |
928 |
|
if (uinfo->value.enumerated.item > 1) |
929 |
|
uinfo->value.enumerated.item = 1; |
930 |
|
strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); |
931 |
|
return 0; |
932 |
|
} |
933 |
|
|
934 |
|
static int snd_ac97_cmedia_spdif_playback_source_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
935 |
|
{ |
936 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
937 |
|
unsigned short val; |
938 |
|
|
939 |
|
val = ac97->regs[AC97_CM9739_SPDIF_CTRL]; |
940 |
|
ucontrol->value.enumerated.item[0] = (val >> 1) & 0x01; |
941 |
|
return 0; |
942 |
|
} |
943 |
|
|
944 |
|
static int snd_ac97_cmedia_spdif_playback_source_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
945 |
|
{ |
946 |
|
ac97_t *ac97 = snd_kcontrol_chip(kcontrol); |
947 |
|
|
948 |
|
return snd_ac97_update_bits(ac97, AC97_CM9739_SPDIF_CTRL, |
949 |
|
0x01 << 1, |
950 |
|
(ucontrol->value.enumerated.item[0] & 0x01) << 1); |
951 |
|
} |
952 |
|
|
953 |
|
static const snd_kcontrol_new_t snd_ac97_cm9739_controls_spdif[] = { |
954 |
|
/* BIT 0: SPDI_EN - always true */ |
955 |
|
{ /* BIT 1: SPDIFS */ |
956 |
|
.iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
957 |
|
.name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", |
958 |
|
.info = snd_ac97_cmedia_spdif_playback_source_info, |
959 |
|
.get = snd_ac97_cmedia_spdif_playback_source_get, |
960 |
|
.put = snd_ac97_cmedia_spdif_playback_source_put, |
961 |
|
}, |
962 |
|
/* BIT 2: IG_SPIV */ |
963 |
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Valid Switch", AC97_CM9739_SPDIF_CTRL, 2, 1, 0), |
964 |
|
/* BIT 3: SPI2F */ |
965 |
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,NONE) "Monitor", AC97_CM9739_SPDIF_CTRL, 3, 1, 0), |
966 |
|
/* BIT 4: SPI2SDI */ |
967 |
|
AC97_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), AC97_CM9739_SPDIF_CTRL, 4, 1, 0), |
968 |
|
/* BIT 8: SPD32 - 32bit SPDIF - not supported yet */ |
969 |
|
}; |
970 |
|
|
971 |
|
static const snd_kcontrol_new_t snd_ac97_cm9739_controls[] = { |
972 |
|
AC97_SINGLE("Line-In As Surround", AC97_CM9739_MULTI_CHAN, 10, 1, 0), |
973 |
|
}; |
974 |
|
|
975 |
|
static int patch_cm9739_specific(ac97_t * ac97) |
976 |
|
{ |
977 |
|
return patch_build_controls(ac97, snd_ac97_cm9739_controls, ARRAY_SIZE(snd_ac97_cm9739_controls)); |
978 |
|
} |
979 |
|
|
980 |
|
static int patch_cm9739_post_spdif(ac97_t * ac97) |
981 |
|
{ |
982 |
|
return patch_build_controls(ac97, snd_ac97_cm9739_controls_spdif, ARRAY_SIZE(snd_ac97_cm9739_controls_spdif)); |
983 |
|
} |
984 |
|
|
985 |
|
static struct snd_ac97_build_ops patch_cm9739_ops = { |
986 |
|
.build_specific = patch_cm9739_specific, |
987 |
|
.build_post_spdif = patch_cm9739_post_spdif |
988 |
|
}; |
989 |
|
|
990 |
int patch_cm9739(ac97_t * ac97) |
int patch_cm9739(ac97_t * ac97) |
991 |
{ |
{ |
992 |
unsigned short val; |
unsigned short val; |
993 |
|
|
994 |
|
ac97->build_ops = &patch_cm9739_ops; |
995 |
|
|
996 |
/* check spdif */ |
/* check spdif */ |
997 |
val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); |
val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); |
998 |
if (val & AC97_EA_SPCV) { |
if (val & AC97_EA_SPCV) { |
1016 |
return 0; |
return 0; |
1017 |
} |
} |
1018 |
|
|
1019 |
|
static const snd_kcontrol_new_t snd_ac97_controls_vt1616[] = { |
1020 |
|
AC97_SINGLE("DC Offset removal", 0x5a, 10, 1, 0), |
1021 |
|
AC97_SINGLE("Alternate Level to Surround Out", 0x5a, 15, 1, 0), |
1022 |
|
AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0), |
1023 |
|
AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0), |
1024 |
|
}; |
1025 |
|
|
1026 |
|
static int patch_vt1616_specific(ac97_t * ac97) |
1027 |
|
{ |
1028 |
|
int err; |
1029 |
|
|
1030 |
|
if (snd_ac97_try_bit(ac97, 0x5a, 9)) |
1031 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[0], 1)) < 0) |
1032 |
|
return err; |
1033 |
|
if ((err = patch_build_controls(ac97, &snd_ac97_controls_vt1616[1], ARRAY_SIZE(snd_ac97_controls_vt1616) - 1)) < 0) |
1034 |
|
return err; |
1035 |
|
return 0; |
1036 |
|
} |
1037 |
|
|
1038 |
|
static struct snd_ac97_build_ops patch_vt1616_ops = { |
1039 |
|
.build_specific = patch_vt1616_specific |
1040 |
|
}; |
1041 |
|
|
1042 |
|
int patch_vt1616(ac97_t * ac97) |
1043 |
|
{ |
1044 |
|
ac97->build_ops = &patch_vt1616_ops; |
1045 |
|
return 0; |
1046 |
|
} |