[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>
This commit is contained in:
parent
da04b128cf
commit
7199acdc74
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
|
||||
* Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
|
||||
* Version: 0.0.20
|
||||
* Version: 0.0.21
|
||||
*
|
||||
* FEATURES currently supported:
|
||||
* See ca0106_main.c for features.
|
||||
|
@ -45,6 +45,8 @@
|
|||
* Added I2C and SPI registers. Filled in interrupt enable.
|
||||
* 0.0.20
|
||||
* Added GPIO info for SB Live 24bit.
|
||||
* 0.0.21
|
||||
* Implement support for Line-in capture on SB Live 24bit.
|
||||
*
|
||||
*
|
||||
* This code was initally based on code from ALSA's emu10k1x.c which is:
|
||||
|
@ -475,9 +477,56 @@
|
|||
/* Causes interrupts based on timer intervals. */
|
||||
#define SPI 0x7a /* SPI: Serial Interface Register */
|
||||
#define I2C_A 0x7b /* I2C Address. 32 bit */
|
||||
#define I2C_0 0x7c /* I2C Data Port 0. 32 bit */
|
||||
#define I2C_1 0x7d /* I2C Data Port 1. 32 bit */
|
||||
#define I2C_D0 0x7c /* I2C Data Port 0. 32 bit */
|
||||
#define I2C_D1 0x7d /* I2C Data Port 1. 32 bit */
|
||||
//I2C values
|
||||
#define I2C_A_ADC_ADD_MASK 0x000000fe //The address is a 7 bit address
|
||||
#define I2C_A_ADC_RW_MASK 0x00000001 //bit mask for R/W
|
||||
#define I2C_A_ADC_TRANS_MASK 0x00000010 //Bit mask for I2c address DAC value
|
||||
#define I2C_A_ADC_ABORT_MASK 0x00000020 //Bit mask for I2C transaction abort flag
|
||||
#define I2C_A_ADC_LAST_MASK 0x00000040 //Bit mask for Last word transaction
|
||||
#define I2C_A_ADC_BYTE_MASK 0x00000080 //Bit mask for Byte Mode
|
||||
|
||||
#define I2C_A_ADC_ADD 0x00000034 //This is the Device address for ADC
|
||||
#define I2C_A_ADC_READ 0x00000001 //To perform a read operation
|
||||
#define I2C_A_ADC_START 0x00000100 //Start I2C transaction
|
||||
#define I2C_A_ADC_ABORT 0x00000200 //I2C transaction abort
|
||||
#define I2C_A_ADC_LAST 0x00000400 //I2C last transaction
|
||||
#define I2C_A_ADC_BYTE 0x00000800 //I2C one byte mode
|
||||
|
||||
#define I2C_D_ADC_REG_MASK 0xfe000000 //ADC address register
|
||||
#define I2C_D_ADC_DAT_MASK 0x01ff0000 //ADC data register
|
||||
|
||||
#define ADC_TIMEOUT 0x00000007 //ADC Timeout Clock Disable
|
||||
#define ADC_IFC_CTRL 0x0000000b //ADC Interface Control
|
||||
#define ADC_MASTER 0x0000000c //ADC Master Mode Control
|
||||
#define ADC_POWER 0x0000000d //ADC PowerDown Control
|
||||
#define ADC_ATTEN_ADCL 0x0000000e //ADC Attenuation ADCL
|
||||
#define ADC_ATTEN_ADCR 0x0000000f //ADC Attenuation ADCR
|
||||
#define ADC_ALC_CTRL1 0x00000010 //ADC ALC Control 1
|
||||
#define ADC_ALC_CTRL2 0x00000011 //ADC ALC Control 2
|
||||
#define ADC_ALC_CTRL3 0x00000012 //ADC ALC Control 3
|
||||
#define ADC_NOISE_CTRL 0x00000013 //ADC Noise Gate Control
|
||||
#define ADC_LIMIT_CTRL 0x00000014 //ADC Limiter Control
|
||||
#define ADC_MUX 0x00000015 //ADC Mux offset
|
||||
|
||||
#if 0
|
||||
/* FIXME: Not tested yet. */
|
||||
#define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain
|
||||
#define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB
|
||||
#define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute
|
||||
#define ADC_MUTE 0x000000c0 //Value to mute ADC
|
||||
#define ADC_OSR 0x00000008 //Mask for ADC oversample rate select
|
||||
#define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock
|
||||
#define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter
|
||||
#define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window
|
||||
#endif
|
||||
|
||||
#define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux
|
||||
#define ADC_MUX_MIC 0x00000002 //Value to select Mic at ADC Mux
|
||||
#define ADC_MUX_LINEIN 0x00000004 //Value to select LineIn at ADC Mux
|
||||
#define ADC_MUX_PHONE 0x00000001 //Value to select TAD at ADC Mux (Not used)
|
||||
#define ADC_MUX_AUX 0x00000008 //Value to select Aux at ADC Mux
|
||||
|
||||
#define SET_CHANNEL 0 /* Testing channel outputs 0=Front, 1=Center/LFE, 2=Unknown, 3=Rear */
|
||||
#define PCM_FRONT_CHANNEL 0
|
||||
|
@ -513,6 +562,7 @@ typedef struct {
|
|||
char * name;
|
||||
int ac97;
|
||||
int gpio_type;
|
||||
int i2c_adc;
|
||||
} ca0106_details_t;
|
||||
|
||||
// definition of the chip-specific record
|
||||
|
@ -555,3 +605,6 @@ void snd_ca0106_ptr_write(ca0106_t *emu,
|
|||
unsigned int chn,
|
||||
unsigned int data);
|
||||
|
||||
int snd_ca0106_i2c_write(ca0106_t *emu, u32 reg, u32 value);
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
|
||||
* Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
|
||||
* Version: 0.0.22
|
||||
* Version: 0.0.23
|
||||
*
|
||||
* FEATURES currently supported:
|
||||
* Front, Rear and Center/LFE.
|
||||
|
@ -77,6 +77,8 @@
|
|||
* Add SPDIF capture using optional digital I/O module for SB Live 24bit. (Analog capture does not yet work.)
|
||||
* 0.0.22
|
||||
* Add support for MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97. From kiksen, bug #901
|
||||
* 0.0.23
|
||||
* Implement support for Line-in capture on SB Live 24bit.
|
||||
*
|
||||
* BUGS:
|
||||
* Some stability problems when unloading the snd-ca0106 kernel module.
|
||||
|
@ -173,15 +175,18 @@ static ca0106_details_t ca0106_chip_details[] = {
|
|||
/* New Sound Blaster Live! 7.1 24bit. This does not have an AC97. 53SB041000001 */
|
||||
{ .serial = 0x10061102,
|
||||
.name = "Live! 7.1 24bit [SB0410]",
|
||||
.gpio_type = 1 } ,
|
||||
.gpio_type = 1,
|
||||
.i2c_adc = 1 } ,
|
||||
/* New Dell Sound Blaster Live! 7.1 24bit. This does not have an AC97. */
|
||||
{ .serial = 0x10071102,
|
||||
.name = "Live! 7.1 24bit [SB0413]",
|
||||
.gpio_type = 1 } ,
|
||||
.gpio_type = 1,
|
||||
.i2c_adc = 1 } ,
|
||||
/* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
|
||||
{ .serial = 0x10091462,
|
||||
.name = "MSI K8N Diamond MB [SB0438]",
|
||||
.gpio_type = 1 } ,
|
||||
.gpio_type = 1,
|
||||
.i2c_adc = 1 } ,
|
||||
{ .serial = 0,
|
||||
.name = "AudigyLS [Unknown]" }
|
||||
};
|
||||
|
@ -257,6 +262,59 @@ void snd_ca0106_ptr_write(ca0106_t *emu,
|
|||
spin_unlock_irqrestore(&emu->emu_lock, flags);
|
||||
}
|
||||
|
||||
int snd_ca0106_i2c_write(ca0106_t *emu,
|
||||
u32 reg,
|
||||
u32 value)
|
||||
{
|
||||
u32 tmp;
|
||||
int timeout=0;
|
||||
int status;
|
||||
int retry;
|
||||
if ((reg > 0x7f) || (value > 0x1ff))
|
||||
{
|
||||
snd_printk("i2c_write: invalid values.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
tmp = reg << 25 | value << 16;
|
||||
snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp);
|
||||
snd_ca0106_ptr_write(emu, I2C_D1, 0, tmp);
|
||||
|
||||
for(retry=0;retry<10;retry++)
|
||||
{
|
||||
/* Send the data to i2c */
|
||||
tmp = snd_ca0106_ptr_read(emu, I2C_A, 0);
|
||||
tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
|
||||
tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
|
||||
snd_ca0106_ptr_write(emu, I2C_A, 0, tmp);
|
||||
|
||||
/* Wait till the transaction ends */
|
||||
while(1)
|
||||
{
|
||||
status = snd_ca0106_ptr_read(emu, I2C_A, 0);
|
||||
//snd_printk("I2C:status=0x%x\n", status);
|
||||
timeout++;
|
||||
if((status & I2C_A_ADC_START)==0)
|
||||
break;
|
||||
|
||||
if(timeout>1000)
|
||||
break;
|
||||
}
|
||||
//Read back and see if the transaction is successful
|
||||
if((status & I2C_A_ADC_ABORT)==0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(retry==10)
|
||||
{
|
||||
snd_printk("Writing to ADC failed!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void snd_ca0106_intr_enable(ca0106_t *emu, unsigned int intrenb)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
@ -1177,6 +1235,10 @@ static int __devinit snd_ca0106_create(snd_card_t *card,
|
|||
//outl(0x00000009, chip->port+HCFG);
|
||||
outl(HCFG_AC97 | HCFG_AUDIOENABLE, chip->port+HCFG); /* AC97 2.0, Enable outputs. */
|
||||
|
||||
if (chip->details->i2c_adc == 1) { /* The SB0410 and SB0413 use I2C to control ADC. */
|
||||
snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); /* Enable Line-in capture. MIC in currently untested. */
|
||||
}
|
||||
|
||||
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL,
|
||||
chip, &ops)) < 0) {
|
||||
snd_ca0106_free(chip);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2004 James Courtier-Dutton <James@superbug.demon.co.uk>
|
||||
* Driver CA0106 chips. e.g. Sound Blaster Audigy LS and Live 24bit
|
||||
* Version: 0.0.17
|
||||
* Version: 0.0.18
|
||||
*
|
||||
* FEATURES currently supported:
|
||||
* See ca0106_main.c for features.
|
||||
|
@ -39,7 +39,9 @@
|
|||
* Modified Copyright message.
|
||||
* 0.0.17
|
||||
* Add iec958 file in proc file system to show status of SPDIF in.
|
||||
*
|
||||
* 0.0.18
|
||||
* Implement support for Line-in capture on SB Live 24bit.
|
||||
*
|
||||
* This code was initally based on code from ALSA's emu10k1x.c which is:
|
||||
* Copyright (c) by Francisco Moraes <fmoraes@nc.rr.com>
|
||||
*
|
||||
|
@ -407,6 +409,20 @@ static void snd_ca0106_proc_reg_write(snd_info_entry_t *entry,
|
|||
}
|
||||
}
|
||||
|
||||
static void snd_ca0106_proc_i2c_write(snd_info_entry_t *entry,
|
||||
snd_info_buffer_t * buffer)
|
||||
{
|
||||
ca0106_t *emu = entry->private_data;
|
||||
char line[64];
|
||||
unsigned int reg, val;
|
||||
while (!snd_info_get_line(buffer, line, sizeof(line))) {
|
||||
if (sscanf(line, "%x %x", ®, &val) != 2)
|
||||
continue;
|
||||
if ((reg <= 0x7f) || (val <= 0x1ff)) {
|
||||
snd_ca0106_i2c_write(emu, reg, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int __devinit snd_ca0106_proc_init(ca0106_t * emu)
|
||||
{
|
||||
|
@ -429,6 +445,13 @@ int __devinit snd_ca0106_proc_init(ca0106_t * emu)
|
|||
entry->c.text.write_size = 64;
|
||||
entry->c.text.write = snd_ca0106_proc_reg_write;
|
||||
entry->mode |= S_IWUSR;
|
||||
// entry->private_data = emu;
|
||||
}
|
||||
if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) {
|
||||
snd_info_set_text_ops(entry, emu, 1024, snd_ca0106_proc_i2c_write);
|
||||
entry->c.text.write_size = 64;
|
||||
entry->c.text.write = snd_ca0106_proc_i2c_write;
|
||||
entry->mode |= S_IWUSR;
|
||||
// entry->private_data = emu;
|
||||
}
|
||||
if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry))
|
||||
|
|
Loading…
Reference in New Issue