aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ca0106/ca0106_mixer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/ca0106/ca0106_mixer.c')
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c263
1 files changed, 195 insertions, 68 deletions
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 3025ed1b6e1e..ad2888705d2a 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -75,6 +75,84 @@
75 75
76#include "ca0106.h" 76#include "ca0106.h"
77 77
78static void ca0106_spdif_enable(struct snd_ca0106 *emu)
79{
80 unsigned int val;
81
82 if (emu->spdif_enable) {
83 /* Digital */
84 snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
85 snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
86 val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000;
87 snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
88 val = inl(emu->port + GPIO) & ~0x101;
89 outl(val, emu->port + GPIO);
90
91 } else {
92 /* Analog */
93 snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
94 snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
95 val = snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000;
96 snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0, val);
97 val = inl(emu->port + GPIO) | 0x101;
98 outl(val, emu->port + GPIO);
99 }
100}
101
102static void ca0106_set_capture_source(struct snd_ca0106 *emu)
103{
104 unsigned int val = emu->capture_source;
105 unsigned int source, mask;
106 source = (val << 28) | (val << 24) | (val << 20) | (val << 16);
107 mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
108 snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
109}
110
111static void ca0106_set_i2c_capture_source(struct snd_ca0106 *emu,
112 unsigned int val, int force)
113{
114 unsigned int ngain, ogain;
115 u32 source;
116
117 snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
118 ngain = emu->i2c_capture_volume[val][0]; /* Left */
119 ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
120 if (force || ngain != ogain)
121 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ngain & 0xff);
122 ngain = emu->i2c_capture_volume[val][1]; /* Right */
123 ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */
124 if (force || ngain != ogain)
125 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ngain & 0xff);
126 source = 1 << val;
127 snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
128 emu->i2c_capture_source = val;
129}
130
131static void ca0106_set_capture_mic_line_in(struct snd_ca0106 *emu)
132{
133 u32 tmp;
134
135 if (emu->capture_mic_line_in) {
136 /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
137 tmp = inl(emu->port+GPIO) & ~0x400;
138 tmp = tmp | 0x400;
139 outl(tmp, emu->port+GPIO);
140 /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); */
141 } else {
142 /* snd_ca0106_i2c_write(emu, ADC_MUX, 0); */ /* Mute input */
143 tmp = inl(emu->port+GPIO) & ~0x400;
144 outl(tmp, emu->port+GPIO);
145 /* snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); */
146 }
147}
148
149static void ca0106_set_spdif_bits(struct snd_ca0106 *emu, int idx)
150{
151 snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, emu->spdif_str_bits[idx]);
152}
153
154/*
155 */
78static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1); 156static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale1, -5175, 25, 1);
79static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1); 157static const DECLARE_TLV_DB_SCALE(snd_ca0106_db_scale2, -10350, 50, 1);
80 158
@@ -95,30 +173,12 @@ static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol,
95 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 173 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
96 unsigned int val; 174 unsigned int val;
97 int change = 0; 175 int change = 0;
98 u32 mask;
99 176
100 val = !!ucontrol->value.integer.value[0]; 177 val = !!ucontrol->value.integer.value[0];
101 change = (emu->spdif_enable != val); 178 change = (emu->spdif_enable != val);
102 if (change) { 179 if (change) {
103 emu->spdif_enable = val; 180 emu->spdif_enable = val;
104 if (val) { 181 ca0106_spdif_enable(emu);
105 /* Digital */
106 snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
107 snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x0b000000);
108 snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
109 snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) & ~0x1000);
110 mask = inl(emu->port + GPIO) & ~0x101;
111 outl(mask, emu->port + GPIO);
112
113 } else {
114 /* Analog */
115 snd_ca0106_ptr_write(emu, SPDIF_SELECT1, 0, 0xf);
116 snd_ca0106_ptr_write(emu, SPDIF_SELECT2, 0, 0x000f0000);
117 snd_ca0106_ptr_write(emu, CAPTURE_CONTROL, 0,
118 snd_ca0106_ptr_read(emu, CAPTURE_CONTROL, 0) | 0x1000);
119 mask = inl(emu->port + GPIO) | 0x101;
120 outl(mask, emu->port + GPIO);
121 }
122 } 182 }
123 return change; 183 return change;
124} 184}
@@ -154,8 +214,6 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
154 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 214 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
155 unsigned int val; 215 unsigned int val;
156 int change = 0; 216 int change = 0;
157 u32 mask;
158 u32 source;
159 217
160 val = ucontrol->value.enumerated.item[0] ; 218 val = ucontrol->value.enumerated.item[0] ;
161 if (val >= 6) 219 if (val >= 6)
@@ -163,9 +221,7 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
163 change = (emu->capture_source != val); 221 change = (emu->capture_source != val);
164 if (change) { 222 if (change) {
165 emu->capture_source = val; 223 emu->capture_source = val;
166 source = (val << 28) | (val << 24) | (val << 20) | (val << 16); 224 ca0106_set_capture_source(emu);
167 mask = snd_ca0106_ptr_read(emu, CAPTURE_SOURCE, 0) & 0xffff;
168 snd_ca0106_ptr_write(emu, CAPTURE_SOURCE, 0, source | mask);
169 } 225 }
170 return change; 226 return change;
171} 227}
@@ -200,9 +256,7 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
200{ 256{
201 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 257 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
202 unsigned int source_id; 258 unsigned int source_id;
203 unsigned int ngain, ogain;
204 int change = 0; 259 int change = 0;
205 u32 source;
206 /* If the capture source has changed, 260 /* If the capture source has changed,
207 * update the capture volume from the cached value 261 * update the capture volume from the cached value
208 * for the particular source. 262 * for the particular source.
@@ -212,18 +266,7 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
212 return -EINVAL; 266 return -EINVAL;
213 change = (emu->i2c_capture_source != source_id); 267 change = (emu->i2c_capture_source != source_id);
214 if (change) { 268 if (change) {
215 snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */ 269 ca0106_set_i2c_capture_source(emu, source_id, 0);
216 ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
217 ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
218 if (ngain != ogain)
219 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
220 ngain = emu->i2c_capture_volume[source_id][1]; /* Left */
221 ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */
222 if (ngain != ogain)
223 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
224 source = 1 << source_id;
225 snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
226 emu->i2c_capture_source = source_id;
227 } 270 }
228 return change; 271 return change;
229} 272}
@@ -271,7 +314,6 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
271 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 314 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
272 unsigned int val; 315 unsigned int val;
273 int change = 0; 316 int change = 0;
274 u32 tmp;
275 317
276 val = ucontrol->value.enumerated.item[0] ; 318 val = ucontrol->value.enumerated.item[0] ;
277 if (val > 1) 319 if (val > 1)
@@ -279,18 +321,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
279 change = (emu->capture_mic_line_in != val); 321 change = (emu->capture_mic_line_in != val);
280 if (change) { 322 if (change) {
281 emu->capture_mic_line_in = val; 323 emu->capture_mic_line_in = val;
282 if (val) { 324 ca0106_set_capture_mic_line_in(emu);
283 //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
284 tmp = inl(emu->port+GPIO) & ~0x400;
285 tmp = tmp | 0x400;
286 outl(tmp, emu->port+GPIO);
287 //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
288 } else {
289 //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
290 tmp = inl(emu->port+GPIO) & ~0x400;
291 outl(tmp, emu->port+GPIO);
292 //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
293 }
294 } 325 }
295 return change; 326 return change;
296} 327}
@@ -322,16 +353,33 @@ static int snd_ca0106_spdif_info(struct snd_kcontrol *kcontrol,
322 return 0; 353 return 0;
323} 354}
324 355
325static int snd_ca0106_spdif_get(struct snd_kcontrol *kcontrol, 356static void decode_spdif_bits(unsigned char *status, unsigned int bits)
357{
358 status[0] = (bits >> 0) & 0xff;
359 status[1] = (bits >> 8) & 0xff;
360 status[2] = (bits >> 16) & 0xff;
361 status[3] = (bits >> 24) & 0xff;
362}
363
364static int snd_ca0106_spdif_get_default(struct snd_kcontrol *kcontrol,
326 struct snd_ctl_elem_value *ucontrol) 365 struct snd_ctl_elem_value *ucontrol)
327{ 366{
328 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 367 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
329 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 368 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
330 369
331 ucontrol->value.iec958.status[0] = (emu->spdif_bits[idx] >> 0) & 0xff; 370 decode_spdif_bits(ucontrol->value.iec958.status,
332 ucontrol->value.iec958.status[1] = (emu->spdif_bits[idx] >> 8) & 0xff; 371 emu->spdif_bits[idx]);
333 ucontrol->value.iec958.status[2] = (emu->spdif_bits[idx] >> 16) & 0xff; 372 return 0;
334 ucontrol->value.iec958.status[3] = (emu->spdif_bits[idx] >> 24) & 0xff; 373}
374
375static int snd_ca0106_spdif_get_stream(struct snd_kcontrol *kcontrol,
376 struct snd_ctl_elem_value *ucontrol)
377{
378 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
379 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
380
381 decode_spdif_bits(ucontrol->value.iec958.status,
382 emu->spdif_str_bits[idx]);
335 return 0; 383 return 0;
336} 384}
337 385
@@ -345,24 +393,48 @@ static int snd_ca0106_spdif_get_mask(struct snd_kcontrol *kcontrol,
345 return 0; 393 return 0;
346} 394}
347 395
348static int snd_ca0106_spdif_put(struct snd_kcontrol *kcontrol, 396static unsigned int encode_spdif_bits(unsigned char *status)
397{
398 return ((unsigned int)status[0] << 0) |
399 ((unsigned int)status[1] << 8) |
400 ((unsigned int)status[2] << 16) |
401 ((unsigned int)status[3] << 24);
402}
403
404static int snd_ca0106_spdif_put_default(struct snd_kcontrol *kcontrol,
349 struct snd_ctl_elem_value *ucontrol) 405 struct snd_ctl_elem_value *ucontrol)
350{ 406{
351 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol); 407 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
352 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); 408 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
353 int change;
354 unsigned int val; 409 unsigned int val;
355 410
356 val = (ucontrol->value.iec958.status[0] << 0) | 411 val = encode_spdif_bits(ucontrol->value.iec958.status);
357 (ucontrol->value.iec958.status[1] << 8) | 412 if (val != emu->spdif_bits[idx]) {
358 (ucontrol->value.iec958.status[2] << 16) |
359 (ucontrol->value.iec958.status[3] << 24);
360 change = val != emu->spdif_bits[idx];
361 if (change) {
362 snd_ca0106_ptr_write(emu, SPCS0 + idx, 0, val);
363 emu->spdif_bits[idx] = val; 413 emu->spdif_bits[idx] = val;
414 /* FIXME: this isn't safe, but needed to keep the compatibility
415 * with older alsa-lib config
416 */
417 emu->spdif_str_bits[idx] = val;
418 ca0106_set_spdif_bits(emu, idx);
419 return 1;
364 } 420 }
365 return change; 421 return 0;
422}
423
424static int snd_ca0106_spdif_put_stream(struct snd_kcontrol *kcontrol,
425 struct snd_ctl_elem_value *ucontrol)
426{
427 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
428 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
429 unsigned int val;
430
431 val = encode_spdif_bits(ucontrol->value.iec958.status);
432 if (val != emu->spdif_str_bits[idx]) {
433 emu->spdif_str_bits[idx] = val;
434 ca0106_set_spdif_bits(emu, idx);
435 return 1;
436 }
437 return 0;
366} 438}
367 439
368static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol, 440static int snd_ca0106_volume_info(struct snd_kcontrol *kcontrol,
@@ -573,8 +645,16 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
573 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 645 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
574 .count = 4, 646 .count = 4,
575 .info = snd_ca0106_spdif_info, 647 .info = snd_ca0106_spdif_info,
576 .get = snd_ca0106_spdif_get, 648 .get = snd_ca0106_spdif_get_default,
577 .put = snd_ca0106_spdif_put 649 .put = snd_ca0106_spdif_put_default
650 },
651 {
652 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
653 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
654 .count = 4,
655 .info = snd_ca0106_spdif_info,
656 .get = snd_ca0106_spdif_get_stream,
657 .put = snd_ca0106_spdif_put_stream
578 }, 658 },
579}; 659};
580 660
@@ -773,3 +853,50 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
773 return 0; 853 return 0;
774} 854}
775 855
856#ifdef CONFIG_PM
857struct ca0106_vol_tbl {
858 unsigned int channel_id;
859 unsigned int reg;
860};
861
862static struct ca0106_vol_tbl saved_volumes[NUM_SAVED_VOLUMES] = {
863 { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2 },
864 { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME2 },
865 { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME2 },
866 { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME2 },
867 { CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME1 },
868 { CONTROL_REAR_CHANNEL, PLAYBACK_VOLUME1 },
869 { CONTROL_CENTER_LFE_CHANNEL, PLAYBACK_VOLUME1 },
870 { CONTROL_UNKNOWN_CHANNEL, PLAYBACK_VOLUME1 },
871 { 1, CAPTURE_CONTROL },
872};
873
874void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip)
875{
876 int i;
877
878 /* save volumes */
879 for (i = 0; i < NUM_SAVED_VOLUMES; i++)
880 chip->saved_vol[i] =
881 snd_ca0106_ptr_read(chip, saved_volumes[i].reg,
882 saved_volumes[i].channel_id);
883}
884
885void snd_ca0106_mixer_resume(struct snd_ca0106 *chip)
886{
887 int i;
888
889 for (i = 0; i < NUM_SAVED_VOLUMES; i++)
890 snd_ca0106_ptr_write(chip, saved_volumes[i].reg,
891 saved_volumes[i].channel_id,
892 chip->saved_vol[i]);
893
894 ca0106_spdif_enable(chip);
895 ca0106_set_capture_source(chip);
896 ca0106_set_i2c_capture_source(chip, chip->i2c_capture_source, 1);
897 for (i = 0; i < 4; i++)
898 ca0106_set_spdif_bits(chip, i);
899 if (chip->details->i2c_adc)
900 ca0106_set_capture_mic_line_in(chip);
901}
902#endif /* CONFIG_PM */