diff options
author | James Courtier-Dutton <James@superbug.co.uk> | 2005-05-27 16:07:23 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2005-06-22 06:27:06 -0400 |
commit | 7199acdc74dc16d2e75f83b8c65301ad19c40ef3 (patch) | |
tree | 923cbbe39b3e82e3f24ffcc04dce864995d6a199 /sound | |
parent | da04b128cf0d74dd4cab270c53d9264e70f9203e (diff) |
[ALSA] Implement support for Line-in capture on SB Live 24bit.
CA0106 driver
Notes: MIC capture not tested yet.
Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/ca0106/ca0106.h | 61 | ||||
-rw-r--r-- | sound/pci/ca0106/ca0106_main.c | 70 | ||||
-rw-r--r-- | sound/pci/ca0106/ca0106_proc.c | 27 |
3 files changed, 148 insertions, 10 deletions
diff --git a/sound/pci/ca0106/ca0106.h b/sound/pci/ca0106/ca0106.h index c623858428cd..67e56a530b22 100644 --- a/sound/pci/ca0106/ca0106.h +++ b/sound/pci/ca0106/ca0106.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> |
3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit | 3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit |
4 | * Version: 0.0.20 | 4 | * Version: 0.0.21 |
5 | * | 5 | * |
6 | * FEATURES currently supported: | 6 | * FEATURES currently supported: |
7 | * See ca0106_main.c for features. | 7 | * See ca0106_main.c for features. |
@@ -45,6 +45,8 @@ | |||
45 | * Added I2C and SPI registers. Filled in interrupt enable. | 45 | * Added I2C and SPI registers. Filled in interrupt enable. |
46 | * 0.0.20 | 46 | * 0.0.20 |
47 | * Added GPIO info for SB Live 24bit. | 47 | * Added GPIO info for SB Live 24bit. |
48 | * 0.0.21 | ||
49 | * Implement support for Line-in capture on SB Live 24bit. | ||
48 | * | 50 | * |
49 | * | 51 | * |
50 | * This code was initally based on code from ALSA's emu10k1x.c which is: | 52 | * This code was initally based on code from ALSA's emu10k1x.c which is: |
@@ -475,9 +477,56 @@ | |||
475 | /* Causes interrupts based on timer intervals. */ | 477 | /* Causes interrupts based on timer intervals. */ |
476 | #define SPI 0x7a /* SPI: Serial Interface Register */ | 478 | #define SPI 0x7a /* SPI: Serial Interface Register */ |
477 | #define I2C_A 0x7b /* I2C Address. 32 bit */ | 479 | #define I2C_A 0x7b /* I2C Address. 32 bit */ |
478 | #define I2C_0 0x7c /* I2C Data Port 0. 32 bit */ | 480 | #define I2C_D0 0x7c /* I2C Data Port 0. 32 bit */ |
479 | #define I2C_1 0x7d /* I2C Data Port 1. 32 bit */ | 481 | #define I2C_D1 0x7d /* I2C Data Port 1. 32 bit */ |
480 | 482 | //I2C values | |
483 | #define I2C_A_ADC_ADD_MASK 0x000000fe //The address is a 7 bit address | ||
484 | #define I2C_A_ADC_RW_MASK 0x00000001 //bit mask for R/W | ||
485 | #define I2C_A_ADC_TRANS_MASK 0x00000010 //Bit mask for I2c address DAC value | ||
486 | #define I2C_A_ADC_ABORT_MASK 0x00000020 //Bit mask for I2C transaction abort flag | ||
487 | #define I2C_A_ADC_LAST_MASK 0x00000040 //Bit mask for Last word transaction | ||
488 | #define I2C_A_ADC_BYTE_MASK 0x00000080 //Bit mask for Byte Mode | ||
489 | |||
490 | #define I2C_A_ADC_ADD 0x00000034 //This is the Device address for ADC | ||
491 | #define I2C_A_ADC_READ 0x00000001 //To perform a read operation | ||
492 | #define I2C_A_ADC_START 0x00000100 //Start I2C transaction | ||
493 | #define I2C_A_ADC_ABORT 0x00000200 //I2C transaction abort | ||
494 | #define I2C_A_ADC_LAST 0x00000400 //I2C last transaction | ||
495 | #define I2C_A_ADC_BYTE 0x00000800 //I2C one byte mode | ||
496 | |||
497 | #define I2C_D_ADC_REG_MASK 0xfe000000 //ADC address register | ||
498 | #define I2C_D_ADC_DAT_MASK 0x01ff0000 //ADC data register | ||
499 | |||
500 | #define ADC_TIMEOUT 0x00000007 //ADC Timeout Clock Disable | ||
501 | #define ADC_IFC_CTRL 0x0000000b //ADC Interface Control | ||
502 | #define ADC_MASTER 0x0000000c //ADC Master Mode Control | ||
503 | #define ADC_POWER 0x0000000d //ADC PowerDown Control | ||
504 | #define ADC_ATTEN_ADCL 0x0000000e //ADC Attenuation ADCL | ||
505 | #define ADC_ATTEN_ADCR 0x0000000f //ADC Attenuation ADCR | ||
506 | #define ADC_ALC_CTRL1 0x00000010 //ADC ALC Control 1 | ||
507 | #define ADC_ALC_CTRL2 0x00000011 //ADC ALC Control 2 | ||
508 | #define ADC_ALC_CTRL3 0x00000012 //ADC ALC Control 3 | ||
509 | #define ADC_NOISE_CTRL 0x00000013 //ADC Noise Gate Control | ||
510 | #define ADC_LIMIT_CTRL 0x00000014 //ADC Limiter Control | ||
511 | #define ADC_MUX 0x00000015 //ADC Mux offset | ||
512 | |||
513 | #if 0 | ||
514 | /* FIXME: Not tested yet. */ | ||
515 | #define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain | ||
516 | #define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB | ||
517 | #define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute | ||
518 | #define ADC_MUTE 0x000000c0 //Value to mute ADC | ||
519 | #define ADC_OSR 0x00000008 //Mask for ADC oversample rate select | ||
520 | #define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock | ||
521 | #define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter | ||
522 | #define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window | ||
523 | #endif | ||
524 | |||
525 | #define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux | ||
526 | #define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux | ||
527 | #define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux | ||
528 | #define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used) | ||
529 | #define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux | ||
481 | 530 | ||
482 | #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ | 531 | #define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */ |
483 | #define PCM_FRONT_CHANNEL 0 | 532 | #define PCM_FRONT_CHANNEL 0 |
@@ -513,6 +562,7 @@ typedef struct { | |||
513 | char * name; | 562 | char * name; |
514 | int ac97; | 563 | int ac97; |
515 | int gpio_type; | 564 | int gpio_type; |
565 | int i2c_adc; | ||
516 | } ca0106_details_t; | 566 | } ca0106_details_t; |
517 | 567 | ||
518 | // definition of the chip-specific record | 568 | // definition of the chip-specific record |
@@ -555,3 +605,6 @@ void snd_ca0106_ptr_write(ca0106_t *emu, | |||
555 | unsigned int chn, | 605 | unsigned int chn, |
556 | unsigned int data); | 606 | unsigned int data); |
557 | 607 | ||
608 | int snd_ca0106_i2c_write(ca0106_t *emu, u32 reg, u32 value); | ||
609 | |||
610 | |||
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index a56e68ea87bc..58d9026c8ca6 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> |
3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit | 3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit |
4 | * Version: 0.0.22 | 4 | * Version: 0.0.23 |
5 | * | 5 | * |
6 | * FEATURES currently supported: | 6 | * FEATURES currently supported: |
7 | * Front, Rear and Center/LFE. | 7 | * Front, Rear and Center/LFE. |
@@ -77,6 +77,8 @@ | |||
77 | * Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.) | 77 | * Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.) |
78 | * 0.0.22 | 78 | * 0.0.22 |
79 | * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 | 79 | * Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901 |
80 | * 0.0.23 | ||
81 | * Implement support for Line-in capture on SB Live 24bit. | ||
80 | * | 82 | * |
81 | * BUGS: | 83 | * BUGS: |
82 | * Some stability problems when unloading the snd-ca0106 kernel module. | 84 | * Some stability problems when unloading the snd-ca0106 kernel module. |
@@ -173,15 +175,18 @@ static ca0106_details_t ca0106_chip_details[] = { | |||
173 | /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ | 175 | /* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */ |
174 | { .serial = 0x10061102, | 176 | { .serial = 0x10061102, |
175 | .name = "Live! 7.1 24bit [SB0410]", | 177 | .name = "Live! 7.1 24bit [SB0410]", |
176 | .gpio_type = 1 } , | 178 | .gpio_type = 1, |
179 | .i2c_adc = 1 } , | ||
177 | /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ | 180 | /* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */ |
178 | { .serial = 0x10071102, | 181 | { .serial = 0x10071102, |
179 | .name = "Live! 7.1 24bit [SB0413]", | 182 | .name = "Live! 7.1 24bit [SB0413]", |
180 | .gpio_type = 1 } , | 183 | .gpio_type = 1, |
184 | .i2c_adc = 1 } , | ||
181 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ | 185 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ |
182 | { .serial = 0x10091462, | 186 | { .serial = 0x10091462, |
183 | .name = "MSI K8N Diamond MB [SB0438]", | 187 | .name = "MSI K8N Diamond MB [SB0438]", |
184 | .gpio_type = 1 } , | 188 | .gpio_type = 1, |
189 | .i2c_adc = 1 } , | ||
185 | { .serial = 0, | 190 | { .serial = 0, |
186 | .name = "AudigyLS [Unknown]" } | 191 | .name = "AudigyLS [Unknown]" } |
187 | }; | 192 | }; |
@@ -257,6 +262,59 @@ void snd_ca0106_ptr_write(ca0106_t *emu, | |||
257 | spin_unlock_irqrestore(&emu->emu_lock, flags); | 262 | spin_unlock_irqrestore(&emu->emu_lock, flags); |
258 | } | 263 | } |
259 | 264 | ||
265 | int snd_ca0106_i2c_write(ca0106_t *emu, | ||
266 | u32 reg, | ||
267 | u32 value) | ||
268 | { | ||
269 | u32 tmp; | ||
270 | int timeout=0; | ||
271 | int status; | ||
272 | int retry; | ||
273 | if ((reg > 0x7f) || (value > 0x1ff)) | ||
274 | { | ||
275 | snd_printk("i2c_write: invalid values.\n"); | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | |||
279 | tmp = reg << 25 | value << 16; | ||
280 | snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); | ||
281 | snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp); | ||
282 | |||
283 | for(retry=0;retry<10;retry++) | ||
284 | { | ||
285 | /* Send the data to i2c */ | ||
286 | tmp = snd_ca0106_ptr_read(emu, I2C_A, 0); | ||
287 | tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); | ||
288 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); | ||
289 | snd_ca0106_ptr_write(emu, I2C_A, 0, tmp); | ||
290 | |||
291 | /* Wait till the transaction ends */ | ||
292 | while(1) | ||
293 | { | ||
294 | status = snd_ca0106_ptr_read(emu, I2C_A, 0); | ||
295 | //snd_printk("I2C:status=0x%x\n", status); | ||
296 | timeout++; | ||
297 | if((status & I2C_A_ADC_START)==0) | ||
298 | break; | ||
299 | |||
300 | if(timeout>1000) | ||
301 | break; | ||
302 | } | ||
303 | //Read back and see if the transaction is successful | ||
304 | if((status & I2C_A_ADC_ABORT)==0) | ||
305 | break; | ||
306 | } | ||
307 | |||
308 | if(retry==10) | ||
309 | { | ||
310 | snd_printk("Writing to ADC failed!\n"); | ||
311 | return -EINVAL; | ||
312 | } | ||
313 | |||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | |||
260 | static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) | 318 | static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) |
261 | { | 319 | { |
262 | unsigned long flags; | 320 | unsigned long flags; |
@@ -1177,6 +1235,10 @@ static int __devinit snd_ca0106_create(snd_card_t *card, | |||
1177 | //outl(0x00000009, chip->port+HCFG); | 1235 | //outl(0x00000009, chip->port+HCFG); |
1178 | outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ | 1236 | outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */ |
1179 | 1237 | ||
1238 | if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */ | ||
1239 | snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */ | ||
1240 | } | ||
1241 | |||
1180 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, | 1242 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, |
1181 | chip, &ops)) < 0) { | 1243 | chip, &ops)) < 0) { |
1182 | snd_ca0106_free(chip); | 1244 | snd_ca0106_free(chip); |
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 3e5161a32363..1c9cc821d1b9 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> | 2 | * Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk> |
3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit | 3 | * Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit |
4 | * Version: 0.0.17 | 4 | * Version: 0.0.18 |
5 | * | 5 | * |
6 | * FEATURES currently supported: | 6 | * FEATURES currently supported: |
7 | * See ca0106_main.c for features. | 7 | * See ca0106_main.c for features. |
@@ -39,7 +39,9 @@ | |||
39 | * Modified Copyright message. | 39 | * Modified Copyright message. |
40 | * 0.0.17 | 40 | * 0.0.17 |
41 | * Add iec958 file in proc file system to show status of SPDIF in. | 41 | * Add iec958 file in proc file system to show status of SPDIF in. |
42 | * | 42 | * 0.0.18 |
43 | * Implement support for Line-in capture on SB Live 24bit. | ||
44 | * | ||
43 | * This code was initally based on code from ALSA's emu10k1x.c which is: | 45 | * This code was initally based on code from ALSA's emu10k1x.c which is: |
44 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> | 46 | * Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com> |
45 | * | 47 | * |
@@ -407,6 +409,20 @@ static void snd_ca0106_proc_reg_write(snd_info_entry_t *entry, | |||
407 | } | 409 | } |
408 | } | 410 | } |
409 | 411 | ||
412 | static void snd_ca0106_proc_i2c_write(snd_info_entry_t *entry, | ||
413 | snd_info_buffer_t * buffer) | ||
414 | { | ||
415 | ca0106_t *emu = entry->private_data; | ||
416 | char line[64]; | ||
417 | unsigned int reg, val; | ||
418 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | ||
419 | if (sscanf(line, "%x %x", ®, &val) != 2) | ||
420 | continue; | ||
421 | if ((reg <= 0x7f) || (val <= 0x1ff)) { | ||
422 | snd_ca0106_i2c_write(emu, reg, val); | ||
423 | } | ||
424 | } | ||
425 | } | ||
410 | 426 | ||
411 | int __devinit snd_ca0106_proc_init(ca0106_t * emu) | 427 | int __devinit snd_ca0106_proc_init(ca0106_t * emu) |
412 | { | 428 | { |
@@ -431,6 +447,13 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu) | |||
431 | entry->mode |= S_IWUSR; | 447 | entry->mode |= S_IWUSR; |
432 | // entry->private_data = emu; | 448 | // entry->private_data = emu; |
433 | } | 449 | } |
450 | if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { | ||
451 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write); | ||
452 | entry->c.text.write_size = 64; | ||
453 | entry->c.text.write = snd_ca0106_proc_i2c_write; | ||
454 | entry->mode |= S_IWUSR; | ||
455 | // entry->private_data = emu; | ||
456 | } | ||
434 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) | 457 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) |
435 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read2); | 458 | snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_reg_read2); |
436 | return 0; | 459 | return 0; |