📄 s3c24xx-uda1341.c
字号:
local_irq_save ( flags );
s3c2410_gpio_setpin ( S3C2410_GPB2, 0 );
s3c2410_gpio_setpin ( S3C2410_GPB4, 1 );
udelay ( 1 );
for ( i = 0; i < 8; i++ )
{
if ( data & 0x1 )
{
s3c2410_gpio_setpin ( S3C2410_GPB4, 0 );
s3c2410_gpio_setpin ( S3C2410_GPB3, 1 );
udelay ( 1 );
s3c2410_gpio_setpin ( S3C2410_GPB4, 1 );
}
else
{
s3c2410_gpio_setpin ( S3C2410_GPB4, 0 );
s3c2410_gpio_setpin ( S3C2410_GPB3, 0 );
udelay ( 1 );
s3c2410_gpio_setpin ( S3C2410_GPB4, 1 );
}
data >>= 1;
}
s3c2410_gpio_setpin ( S3C2410_GPB2, 1 );
s3c2410_gpio_setpin ( S3C2410_GPB4, 1 );
local_irq_restore ( flags );
}
static void uda1341_l3_data ( u8 data )
{
int i;
unsigned long flags;
local_irq_save ( flags );
udelay ( 1 );
for ( i = 0; i < 8; i++ )
{
if ( data & 0x1 )
{
s3c2410_gpio_setpin ( S3C2410_GPB4, 0 );
s3c2410_gpio_setpin ( S3C2410_GPB3, 1 );
udelay ( 1 );
s3c2410_gpio_setpin ( S3C2410_GPB4, 1 );
}
else
{
s3c2410_gpio_setpin ( S3C2410_GPB4, 0 );
s3c2410_gpio_setpin ( S3C2410_GPB3, 0 );
udelay ( 1 );
s3c2410_gpio_setpin ( S3C2410_GPB4, 1 );
}
data >>= 1;
}
local_irq_restore ( flags );
}
static void init_s3c24xx_iis_bus ( void )
{
__raw_writel ( 0, iis_base + S3C2410_IISPSR );
__raw_writel ( 0, iis_base + S3C2410_IISCON );
__raw_writel ( 0, iis_base + S3C2410_IISMOD );
__raw_writel ( 0, iis_base + S3C2410_IISFCON );
clk_disable ( iis_clock );
}
static int iispsr_value ( int s_bit_clock, int sample_rate )
{
int i, prescaler = 0;
unsigned long tmpval;
unsigned long tmpval384;
unsigned long tmpval384min = 0xffff;
tmpval384 = clk_get_rate ( iis_clock ) / s_bit_clock;
for ( i = 0; i < 32; i++ )
{
tmpval = tmpval384 / ( i + 1 );
if ( PCM_ABS ( ( sample_rate - tmpval ) ) < tmpval384min )
{
tmpval384min = PCM_ABS ( ( sample_rate - tmpval ) );
prescaler = i;
}
}
return prescaler;
}
static void audio_set_dsp_speed ( long val )
{
unsigned int prescaler;
prescaler = ( IISPSR_A ( iispsr_value ( S_CLOCK_FREQ, val ) )
| IISPSR_B ( iispsr_value ( S_CLOCK_FREQ, val ) ) );
__raw_writel ( prescaler, iis_base + S3C2410_IISPSR );
dbg ( dbg_debug, PFX "audio_set_dsp_speed:%ld prescaler:%i\n", val, prescaler );
}
static void s3c24xx_uda1341_set_samplerate( struct s3c24xx_uda1341 *chip, long rate )
{
/*
* We have the following clock sources:
* 4.096 MHz, 5.6245 MHz, 11.2896 MHz, 12.288 MHz
* Those can be divided either by 256, 384 or 512.
* This makes up 12 combinations for the following samplerates...
*/
if (rate >= 48000)
rate = 48000;
else if (rate >= 44100)
rate = 44100;
else if (rate >= 32000)
rate = 32000;
else if (rate >= 29400)
rate = 29400;
else if (rate >= 24000)
rate = 24000;
else if (rate >= 22050)
rate = 22050;
else if (rate >= 21970)
rate = 21970;
else if (rate >= 16000)
rate = 16000;
else if (rate >= 14647)
rate = 14647;
else if (rate >= 10985)
rate = 10985;
else if (rate >= 10666)
rate = 10666;
else
rate = 8000;
audio_set_dsp_speed( rate );
chip -> samplerate = rate;
}
static void init_uda1341 ( void )
{
/* GPB 4: L3CLOCK */
/* GPB 3: L3DATA */
/* GPB 2: L3MODE */
unsigned long flags;
int uda1341_volume = 62 - ( ( DEF_VOLUME * 61 ) / 100 );
int uda1341_boost = 0;
local_irq_save ( flags );
s3c2410_gpio_setpin ( S3C2410_GPB2, 1 );//L3MODE=1
s3c2410_gpio_setpin ( S3C2410_GPB4, 1 );//L3CLOCK=1
local_irq_restore ( flags );
uda1341_l3_address ( UDA1341_REG_STATUS );
uda1341_l3_data ( 0x40 | STAT0_SC_384FS | STAT0_IF_MSB | STAT0_DC_FILTER ); // reset uda1341
uda1341_l3_data ( STAT1 | STAT1_ADC_ON | STAT1_DAC_ON );
uda1341_l3_address ( UDA1341_REG_DATA0 );
//uda1341_l3_data ( DATA0 | DATA0_VOLUME ( 0 ) ); // maximum volume
uda1341_l3_data ( DATA0 | DATA0_VOLUME ( uda1341_volume ) ); // maximum volume
uda1341_l3_data ( DATA1 | DATA1_BASS ( uda1341_boost ) | DATA1_TREBLE ( 0 ) );
uda1341_l3_data ( ( DATA2 | DATA2_DEEMP_NONE ) &~ ( DATA2_MUTE ) );
uda1341_l3_data ( EXTADDR ( EXT2 ) );
uda1341_l3_data ( EXTDATA ( EXT2_MIC_GAIN ( 0x6 ) ) | EXT2_MIXMODE_CH1 );//input channel 1 select(input channel 2 off)
}
static void init_s3c2410_iis_bus_rx ( void )
{
unsigned int iiscon, iismod, iisfcon;
char *dstr;
//Kill everything...
__raw_writel ( 0, iis_base + S3C2410_IISPSR );
__raw_writel ( 0, iis_base + S3C2410_IISCON );
__raw_writel ( 0, iis_base + S3C2410_IISMOD );
__raw_writel ( 0, iis_base + S3C2410_IISFCON );
clk_enable ( iis_clock );
iiscon = iismod = iisfcon = 0;
//Setup basic stuff
iiscon |= S3C2410_IISCON_PSCEN; // Enable prescaler
iiscon |= S3C2410_IISCON_IISEN; // Enable interface
iismod |= S3C2410_IISMOD_MASTER; // Set interface to Master Mode
iismod |= S3C2410_IISMOD_LR_LLOW; // Low for left channel
iismod |= S3C2410_IISMOD_MSB; // IIS format
iismod |= S3C2410_IISMOD_16BIT; // Serial data bit/channel is 16 bit
iismod |= S3C2410_IISMOD_384FS; // Master clock freq = 384 fs
iismod |= S3C2410_IISMOD_32FS; // 32 fs
iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE; //Enable RX Fifo
//iisfcon |= S3C2410_IISFCON_TXDMA; //Set RX FIFO acces mode to DMA
iiscon |= S3C2410_IISCON_RXDMAEN | S3C2410_IISCON_IISEN; //Enable RX DMA service request
//iiscon |= S3C2410_IISCON_TXIDLE; //Set TX channel idle
iiscon &= ( ~S3C2410_IISCON_RXIDLE );
iismod |= S3C2410_IISMOD_RXMODE; //Set RX Mode
iismod |= S3C2410_IISMOD_TXMODE; //Set TX Mode
dstr = "RX";
//iiscon has to be set last - it enables the interface
__raw_writel ( iismod, iis_base + S3C2410_IISMOD );
__raw_writel ( iisfcon, iis_base + S3C2410_IISFCON );
__raw_writel ( iiscon, iis_base + S3C2410_IISCON );
}
static void init_s3c2410_iis_bus_tx ( void )
{
unsigned int iiscon, iismod, iisfcon;
char *dstr;
//Kill everything...
__raw_writel ( 0, iis_base + S3C2410_IISPSR );
__raw_writel ( 0, iis_base + S3C2410_IISCON );
__raw_writel ( 0, iis_base + S3C2410_IISMOD );
__raw_writel ( 0, iis_base + S3C2410_IISFCON );
clk_enable ( iis_clock );
iiscon = iismod = iisfcon = 0;
//Setup basic stuff
iiscon |= S3C2410_IISCON_PSCEN; // Enable prescaler
iiscon |= S3C2410_IISCON_IISEN; // Enable interface
iismod |= S3C2410_IISMOD_MASTER; // Set interface to Master Mode
iismod |= S3C2410_IISMOD_LR_LLOW; // Low for left channel
iismod |= S3C2410_IISMOD_MSB; // MSB format
iismod |= S3C2410_IISMOD_16BIT; // Serial data bit/channel is 16 bit
iismod |= S3C2410_IISMOD_384FS; // Master clock freq = 384 fs
iismod |= S3C2410_IISMOD_32FS; // 32 fs
iisfcon |= S3C2410_IISFCON_RXDMA; //Set RX FIFO acces mode to DMA
iisfcon |= S3C2410_IISFCON_TXDMA; //Set TX FIFO acces mode to DMA
iiscon |= S3C2410_IISCON_TXDMAEN | S3C2410_IISCON_IISEN; //Enable TX DMA service request
//iiscon |= S3C2410_IISCON_RXIDLE; //Set RX channel idle
iiscon &= ( ~S3C2410_IISCON_TXIDLE ); //Unset TX channel idle
iisfcon |= S3C2410_IISFCON_TXENABLE; //Enable TX Fifo
iismod |= S3C2410_IISMOD_TXMODE; //Set TX Mode
iismod |= S3C2410_IISMOD_RXMODE; //Set RX Mode
dstr = "TX";
//iiscon has to be set last - it enables the interface
__raw_writel ( iismod, iis_base + S3C2410_IISMOD );
__raw_writel ( iisfcon, iis_base + S3C2410_IISFCON );
__raw_writel ( iiscon, iis_base + S3C2410_IISCON );
}
static int s3c24xx_uda1341_free( struct s3c24xx_uda1341 *chip )
{
kfree( chip );
return 0;
}
static int s3c24xx_uda1341_dev_free( struct snd_device *device )
{
struct s3c24xx_uda1341 *chip = device -> device_data;
return s3c24xx_uda1341_free( chip );
}
int uda1341_chip_init( struct s3c24xx_uda1341 * );
static int __devinit snd_card_s3c24xx_uda1341_init( struct snd_card *card,
struct platform_device *pdev,
struct s3c24xx_uda1341 *chip)
{
int err;
unsigned long flags;
static struct snd_device_ops ops =
{
.dev_free = s3c24xx_uda1341_dev_free,
};
local_irq_save ( flags );
/* GPB 4: L3CLOCK, OUTPUT */
s3c2410_gpio_cfgpin ( S3C2410_GPB4, S3C2410_GPB4_OUTP );
s3c2410_gpio_pullup ( S3C2410_GPB4, 1 );
/* GPB 3: L3DATA, OUTPUT */
s3c2410_gpio_cfgpin ( S3C2410_GPB3, S3C2410_GPB3_OUTP );
s3c2410_gpio_pullup ( S3C2410_GPB3, 1 );
/* GPB 2: L3MODE, OUTPUT */
s3c2410_gpio_cfgpin ( S3C2410_GPB2, S3C2410_GPB2_OUTP );
s3c2410_gpio_pullup ( S3C2410_GPB2, 1 );
/* GPE 3: I2SSDI */
s3c2410_gpio_cfgpin ( S3C2410_GPE3, S3C2410_GPE3_I2SSDI );
s3c2410_gpio_pullup ( S3C2410_GPE3, 0 );
/* GPE 0: I2SLRCK */
s3c2410_gpio_cfgpin ( S3C2410_GPE0, S3C2410_GPE0_I2SLRCK );
s3c2410_gpio_pullup ( S3C2410_GPE0, 0 );
/* GPE 1: I2SSCLK */
s3c2410_gpio_cfgpin ( S3C2410_GPE1, S3C2410_GPE1_I2SSCLK );
s3c2410_gpio_pullup ( S3C2410_GPE1, 0 );
/* GPE 2: CDCLK */
s3c2410_gpio_cfgpin ( S3C2410_GPE2, S3C2410_GPE2_CDCLK );
s3c2410_gpio_pullup ( S3C2410_GPE2, 0 );
/* GPE 4: I2SSDO */
s3c2410_gpio_cfgpin ( S3C2410_GPE4, S3C2410_GPE4_I2SSDO );
s3c2410_gpio_pullup ( S3C2410_GPE4, 0 );
local_irq_restore ( flags );
init_s3c24xx_iis_bus();
init_uda1341();
if ( ( err = snd_device_new( card, SNDRV_DEV_CODEC, chip, &ops ) ) < 0 )
{
dbg( dbg_err, PFX "failed to invoke snd_device_new\n" );
goto init_free_chip;
}
snd_card_set_dev( card, &pdev -> dev );
return 0;
init_free_chip:
s3c24xx_uda1341_free( chip );
return err;
}
/* Mixer Module */
#if MIXER_EN
/* transfer 8bit integer into string with binary representation */
static void int2str_bin8(uint8_t val, char *buf)
{
const int size = sizeof(val) * 8;
int i;
for (i= 0; i < size; i++){
*(buf++) = (val >> (size - 1)) ? '1' : '0';
val <<= 1;
}
*buf = '\0'; //end the string with zero
}
/*
* UDA1341 Codec Settings
*/
static int snd_uda1341_codec_write( struct s3c24xx_uda1341 *chip, unsigned short reg, unsigned short val )
{
struct uda1341 *uda = chip -> chip_data;
unsigned char buf[ 2 ] = { 0xc0, 0xe0 };
uda -> regs[ reg ] = val;
if ( uda -> active )
{
if ( IS_DATA0( reg ) )
{
uda1341_l3_address( UDA1341_REG_DATA0 );
uda1341_l3_data( val );
}
else if ( IS_DATA1( reg ) )
{
uda1341_l3_address( UDA1341_REG_DATA1 );
uda1341_l3_data( val );
}
else if ( IS_STATUS( reg ) )
{
uda1341_l3_address( UDA1341_REG_STATUS );
uda1341_l3_data( val );
}
else if ( IS_EXTEND( reg ) )
{
uda1341_l3_address( UDA1341_REG_DATA0 );
buf[ 0 ] |= ( reg - ext0 ) & 0x07;
buf[ 1 ] |= val;
uda1341_l3_data( buf[ 0 ] );
uda1341_l3_data( buf[ 1 ] );
}
}
else
{
dbg( dbg_err, PFX "UDA1341 codec not active!\n" );
}
return 0;
}
static int snd_uda1341_codec_read( struct s3c24xx_uda1341 *chip, unsigned short reg )
{
//todo
return 0;
}
static inline int snd_uda1341_valid_reg( struct s3c24xx_uda1341 *chip, unsigned short reg )
{
return reg < uda1341_reg_last;
}
static int snd_uda1341_update_bits( struct s3c24xx_uda1341 *chip, unsigned short reg,
unsigned short mask, unsigned short shift,
unsigned short value, int flush )
{
int change;
unsigned short old, new;
struct uda1341 *uda = chip -> chip_data;
if ( ! snd_uda1341_valid_reg( chip, reg ) )
{
return -EINVAL;
}
spin_lock( &uda -> reg_lock );
old = uda -> regs[ reg ];
new = ( old & ~( mask << shift ) ) | ( value << shift );
change = ( old != new );
if ( change )
{
if ( flush )
{
uda -> write( chip, reg, new );
}
uda -> regs[ reg ] = new;
}
spin_unlock( &uda -> reg_lock );
return change;
}
static int snd_uda1341_cfg_write(struct s3c24xx_uda1341 *chip, unsigned short what,
unsigned short value, int flush)
{
struct uda1341 *uda = chip -> chip_data;
int ret = 0;
#ifdef CONFIG_PM
int reg;
#endif
#if 0
printk(KERN_DEBUG "cfg_write what: %d value: %d\n", what, value);
#endif
uda->cfg[what] = value;
switch(what) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -