aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ca0106
diff options
context:
space:
mode:
authorJames Courtier-Dutton <James@superbug.co.uk>2006-04-09 08:01:34 -0400
committerJaroslav Kysela <perex@suse.cz>2006-06-22 15:32:35 -0400
commit6129daaa0d2b84c0e376b6b17b3d3740c4d1d1ca (patch)
tree8a043f22709ffa613f44a4bc1d3aeed256f488cf /sound/pci/ca0106
parent52ab3f3dc711eeccbfbcc5d4f5c5d9b9ff59650f (diff)
[ALSA] ca0106: Add analog capture controls.
Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
Diffstat (limited to 'sound/pci/ca0106')
-rw-r--r--sound/pci/ca0106/ca0106.h4
-rw-r--r--sound/pci/ca0106/ca0106_main.c44
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c152
3 files changed, 186 insertions, 14 deletions
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h
index c8131ea92ed6..9cb66c59f523 100644
--- a/sound/pci/ca0106/ca0106.h
+++ b/sound/pci/ca0106/ca0106.h
@@ -537,9 +537,9 @@
537#endif 537#endif
538 538
539#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux 539#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux
540#define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used)
540#define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux 541#define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux
541#define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux 542#define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux
542#define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used)
543#define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux 543#define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux
544 544
545#define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ 545#define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */
@@ -604,6 +604,8 @@ struct snd_ca0106 {
604 u32 spdif_bits[4]; /* s/pdif out setup */ 604 u32 spdif_bits[4]; /* s/pdif out setup */
605 int spdif_enable; 605 int spdif_enable;
606 int capture_source; 606 int capture_source;
607 int i2c_capture_source;
608 u8 i2c_capture_volume[4][2];
607 int capture_mic_line_in; 609 int capture_mic_line_in;
608 610
609 struct snd_dma_buffer buffer; 611 struct snd_dma_buffer buffer;
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index fd8bfebfbd54..3762f58384e0 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -326,6 +326,7 @@ int snd_ca0106_spi_write(struct snd_ca0106 * emu,
326 return 0; 326 return 0;
327} 327}
328 328
329/* The ADC does not support i2c read, so only write is implemented */
329int snd_ca0106_i2c_write(struct snd_ca0106 *emu, 330int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
330 u32 reg, 331 u32 reg,
331 u32 value) 332 u32 value)
@@ -340,6 +341,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
340 } 341 }
341 342
342 tmp = reg << 25 | value << 16; 343 tmp = reg << 25 | value << 16;
344 // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
343 /* Not sure what this I2C channel controls. */ 345 /* Not sure what this I2C channel controls. */
344 /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ 346 /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */
345 347
@@ -348,8 +350,9 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu,
348 350
349 for (retry = 0; retry < 10; retry++) { 351 for (retry = 0; retry < 10; retry++) {
350 /* Send the data to i2c */ 352 /* Send the data to i2c */
351 tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); 353 //tmp = snd_ca0106_ptr_read(emu, I2C_A, 0);
352 tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); 354 //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
355 tmp = 0;
353 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); 356 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
354 snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); 357 snd_ca0106_ptr_write(emu, I2C_A, 0, tmp);
355 358
@@ -1200,6 +1203,22 @@ static unsigned int spi_dac_init[] = {
1200 0x1400, 1203 0x1400,
1201}; 1204};
1202 1205
1206static unsigned int i2c_adc_init[][2] = {
1207 { 0x17, 0x00 }, /* Reset */
1208 { 0x07, 0x00 }, /* Timeout */
1209 { 0x0b, 0x22 }, /* Interface control */
1210 { 0x0c, 0x22 }, /* Master mode control */
1211 { 0x0d, 0x08 }, /* Powerdown control */
1212 { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */
1213 { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */
1214 { 0x10, 0x7b }, /* ALC Control 1 */
1215 { 0x11, 0x00 }, /* ALC Control 2 */
1216 { 0x12, 0x32 }, /* ALC Control 3 */
1217 { 0x13, 0x00 }, /* Noise gate control */
1218 { 0x14, 0xa6 }, /* Limiter control */
1219 { 0x15, ADC_MUX_LINEIN }, /* ADC Mixer control */
1220};
1221
1203static int __devinit snd_ca0106_create(struct snd_card *card, 1222static int __devinit snd_ca0106_create(struct snd_card *card,
1204 struct pci_dev *pci, 1223 struct pci_dev *pci,
1205 struct snd_ca0106 **rchip) 1224 struct snd_ca0106 **rchip)
@@ -1361,7 +1380,12 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
1361 snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */ 1380 snd_ca0106_ptr_write(chip, CAPTURE_SOURCE, 0x0, 0x333300e4); /* Select MIC, Line in, TAD in, AUX in */
1362 chip->capture_source = 3; /* Set CAPTURE_SOURCE */ 1381 chip->capture_source = 3; /* Set CAPTURE_SOURCE */
1363 1382
1364 if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */ 1383 if (chip->details->gpio_type == 2) { /* The SB0410 and SB0413 use GPIO differently. */
1384 /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
1385 outl(0x0, chip->port+GPIO);
1386 //outl(0x00f0e000, chip->port+GPIO); /* Analog */
1387 outl(0x005f5301, chip->port+GPIO); /* Analog */
1388 } else if (chip->details->gpio_type == 1) { /* The SB0410 and SB0413 use GPIO differently. */
1365 /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */ 1389 /* FIXME: Still need to find out what the other GPIO bits do. E.g. For digital spdif out. */
1366 outl(0x0, chip->port+GPIO); 1390 outl(0x0, chip->port+GPIO);
1367 //outl(0x00f0e000, chip->port+GPIO); /* Analog */ 1391 //outl(0x00f0e000, chip->port+GPIO); /* Analog */
@@ -1379,7 +1403,19 @@ static int __devinit snd_ca0106_create(struct snd_card *card,
1379 outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ 1403 outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */
1380 1404
1381 if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ 1405 if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */
1382 snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ 1406 int size, n;
1407
1408 size = ARRAY_SIZE(i2c_adc_init);
1409 //snd_printk("I2C:array size=0x%x\n", size);
1410 for (n=0; n < size; n++) {
1411 snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]);
1412 }
1413 for (n=0; n < 4; n++) {
1414 chip->i2c_capture_volume[n][0]= 0xcf;
1415 chip->i2c_capture_volume[n][1]= 0xcf;
1416 }
1417 chip->i2c_capture_source=2; /* Line in */
1418 //snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */
1383 } 1419 }
1384 if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */ 1420 if (chip->details->spi_dac == 1) { /* The SB0570 use SPI to control DAC. */
1385 int size, n; 1421 int size, n;
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 06fe055674fb..8a5833317b0a 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -171,6 +171,62 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
171 return change; 171 return change;
172} 172}
173 173
174static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
175 struct snd_ctl_elem_info *uinfo)
176{
177 static char *texts[6] = {
178 "Phone", "Mic", "Line in", "Aux"
179 };
180
181 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
182 uinfo->count = 1;
183 uinfo->value.enumerated.items = 4;
184 if (uinfo->value.enumerated.item > 3)
185 uinfo->value.enumerated.item = 3;
186 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
187 return 0;
188}
189
190static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
191 struct snd_ctl_elem_value *ucontrol)
192{
193 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
194
195 ucontrol->value.enumerated.item[0] = emu->i2c_capture_source;
196 return 0;
197}
198
199static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
200 struct snd_ctl_elem_value *ucontrol)
201{
202 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
203 unsigned int source_id;
204 unsigned int ngain, ogain;
205 int change = 0;
206 u32 source;
207 /* If the capture source has changed,
208 * update the capture volume from the cached value
209 * for the particular source.
210 */
211 source_id = ucontrol->value.enumerated.item[0] ;
212 change = (emu->i2c_capture_source != source_id);
213 if (change) {
214 snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
215 ngain = emu->i2c_capture_volume[source_id][0]; /* Left */
216 ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */
217 if (ngain != ogain)
218 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff));
219 ngain = emu->i2c_capture_volume[source_id][1]; /* Left */
220 ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Left */
221 if (ngain != ogain)
222 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
223 source = 1 << source_id;
224 snd_ca0106_i2c_write(emu, ADC_MUX, source); /* Set source */
225 emu->i2c_capture_source = source_id;
226 }
227 return change;
228}
229
174static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol, 230static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
175 struct snd_ctl_elem_info *uinfo) 231 struct snd_ctl_elem_info *uinfo)
176{ 232{
@@ -207,16 +263,16 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
207 if (change) { 263 if (change) {
208 emu->capture_mic_line_in = val; 264 emu->capture_mic_line_in = val;
209 if (val) { 265 if (val) {
210 snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ 266 //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
211 tmp = inl(emu->port+GPIO) & ~0x400; 267 tmp = inl(emu->port+GPIO) & ~0x400;
212 tmp = tmp | 0x400; 268 tmp = tmp | 0x400;
213 outl(tmp, emu->port+GPIO); 269 outl(tmp, emu->port+GPIO);
214 snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC); 270 //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_MIC);
215 } else { 271 } else {
216 snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_PHONE); /* Mute input */ 272 //snd_ca0106_i2c_write(emu, ADC_MUX, 0); /* Mute input */
217 tmp = inl(emu->port+GPIO) & ~0x400; 273 tmp = inl(emu->port+GPIO) & ~0x400;
218 outl(tmp, emu->port+GPIO); 274 outl(tmp, emu->port+GPIO);
219 snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN); 275 //snd_ca0106_i2c_write(emu, ADC_MUX, ADC_MUX_LINEIN);
220 } 276 }
221 } 277 }
222 return change; 278 return change;
@@ -225,7 +281,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol,
225static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata = 281static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata =
226{ 282{
227 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 283 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
228 .name = "Mic/Line in Capture", 284 .name = "Shared Mic/Line in Capture Switch",
229 .info = snd_ca0106_capture_mic_line_in_info, 285 .info = snd_ca0106_capture_mic_line_in_info,
230 .get = snd_ca0106_capture_mic_line_in_get, 286 .get = snd_ca0106_capture_mic_line_in_get,
231 .put = snd_ca0106_capture_mic_line_in_put 287 .put = snd_ca0106_capture_mic_line_in_put
@@ -329,15 +385,81 @@ static int snd_ca0106_volume_put(struct snd_kcontrol *kcontrol,
329 return 1; 385 return 1;
330} 386}
331 387
388static int snd_ca0106_i2c_volume_info(struct snd_kcontrol *kcontrol,
389 struct snd_ctl_elem_info *uinfo)
390{
391 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
392 uinfo->count = 2;
393 uinfo->value.integer.min = 0;
394 uinfo->value.integer.max = 255;
395 return 0;
396}
397
398static int snd_ca0106_i2c_volume_get(struct snd_kcontrol *kcontrol,
399 struct snd_ctl_elem_value *ucontrol)
400{
401 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
402 int source_id;
403
404 source_id = kcontrol->private_value;
405
406 ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0];
407 ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1];
408 return 0;
409}
410
411static int snd_ca0106_i2c_volume_put(struct snd_kcontrol *kcontrol,
412 struct snd_ctl_elem_value *ucontrol)
413{
414 struct snd_ca0106 *emu = snd_kcontrol_chip(kcontrol);
415 unsigned int ogain;
416 unsigned int ngain;
417 int source_id;
418 int change = 0;
419
420 source_id = kcontrol->private_value;
421 ogain = emu->i2c_capture_volume[source_id][0]; /* Left */
422 ngain = ucontrol->value.integer.value[0];
423 if (ngain > 0xff)
424 return 0;
425 if (ogain != ngain) {
426 if (emu->i2c_capture_source == source_id)
427 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) );
428 emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0];
429 change = 1;
430 }
431 ogain = emu->i2c_capture_volume[source_id][1]; /* Right */
432 ngain = ucontrol->value.integer.value[1];
433 if (ngain > 0xff)
434 return 0;
435 if (ogain != ngain) {
436 if (emu->i2c_capture_source == source_id)
437 snd_ca0106_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff));
438 emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1];
439 change = 1;
440 }
441
442 return change;
443}
444
332#define CA_VOLUME(xname,chid,reg) \ 445#define CA_VOLUME(xname,chid,reg) \
333{ \ 446{ \
334 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ 447 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
335 .info = snd_ca0106_volume_info, \ 448 .info = snd_ca0106_volume_info, \
336 .get = snd_ca0106_volume_get, \ 449 .get = snd_ca0106_volume_get, \
337 .put = snd_ca0106_volume_put, \ 450 .put = snd_ca0106_volume_put, \
338 .private_value = ((chid) << 8) | (reg) \ 451 .private_value = ((chid) << 8) | (reg) \
339} 452}
340 453
454#define I2C_VOLUME(xname,chid) \
455{ \
456 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
457 .info = snd_ca0106_i2c_volume_info, \
458 .get = snd_ca0106_i2c_volume_get, \
459 .put = snd_ca0106_i2c_volume_put, \
460 .private_value = chid \
461}
462
341 463
342static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { 464static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
343 CA_VOLUME("Analog Front Playback Volume", 465 CA_VOLUME("Analog Front Playback Volume",
@@ -361,6 +483,11 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
361 CA_VOLUME("CAPTURE feedback Playback Volume", 483 CA_VOLUME("CAPTURE feedback Playback Volume",
362 1, CAPTURE_CONTROL), 484 1, CAPTURE_CONTROL),
363 485
486 I2C_VOLUME("Phone Capture Volume", 0),
487 I2C_VOLUME("Mic Capture Volume", 1),
488 I2C_VOLUME("Line in Capture Volume", 2),
489 I2C_VOLUME("Aux Capture Volume", 3),
490
364 { 491 {
365 .access = SNDRV_CTL_ELEM_ACCESS_READ, 492 .access = SNDRV_CTL_ELEM_ACCESS_READ,
366 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 493 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -378,12 +505,19 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = {
378 }, 505 },
379 { 506 {
380 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 507 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
381 .name = "Capture Source", 508 .name = "Digital Capture Source",
382 .info = snd_ca0106_capture_source_info, 509 .info = snd_ca0106_capture_source_info,
383 .get = snd_ca0106_capture_source_get, 510 .get = snd_ca0106_capture_source_get,
384 .put = snd_ca0106_capture_source_put 511 .put = snd_ca0106_capture_source_put
385 }, 512 },
386 { 513 {
514 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
515 .name = "Capture Source",
516 .info = snd_ca0106_i2c_capture_source_info,
517 .get = snd_ca0106_i2c_capture_source_get,
518 .put = snd_ca0106_i2c_capture_source_put
519 },
520 {
387 .iface = SNDRV_CTL_ELEM_IFACE_PCM, 521 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
388 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), 522 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
389 .count = 4, 523 .count = 4,