aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/ca0106
diff options
context:
space:
mode:
authorJames Courtier-Dutton <James@superbug.co.uk>2005-05-27 16:07:23 -0400
committerJaroslav Kysela <perex@suse.cz>2005-06-22 06:27:06 -0400
commit7199acdc74dc16d2e75f83b8c65301ad19c40ef3 (patch)
tree923cbbe39b3e82e3f24ffcc04dce864995d6a199 /sound/pci/ca0106
parentda04b128cf0d74dd4cab270c53d9264e70f9203e (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/pci/ca0106')
-rw-r--r--sound/pci/ca0106/ca0106.h61
-rw-r--r--sound/pci/ca0106/ca0106_main.c70
-rw-r--r--sound/pci/ca0106/ca0106_proc.c27
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
608int 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
265int 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
260static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb) 318static 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
412static 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", &reg, &val) != 2)
420 continue;
421 if ((reg <= 0x7f) || (val <= 0x1ff)) {
422 snd_ca0106_i2c_write(emu, reg, val);
423 }
424 }
425}
410 426
411int __devinit snd_ca0106_proc_init(ca0106_t * emu) 427int __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;