⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c24xx-uda1341.c

📁 扬创2440平台上的ALSA音频驱动程序( for Linux-2.6.26.5 )。驱动使用说明和ALSA Lib的编译过程都在压缩包内
💻 C
📖 第 1 页 / 共 5 页
字号:

	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 + -