📄 uda1380.c
字号:
/****** * * FileName: uda1380.c * * Version: 0.10 * * Date: 2005-03-20 * * Copyright (C) 2005 Shenzhen Newenjoy Technology Co,.LTD. * * Designed by Yinshenk < Email: yinshenk@21cn.com > * * Philips UDA1380 Audio drive device for Samsuang S3C2410 Linux 4.8.XX * configure. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License. * *****************************************************************************/#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/poll.h>#include <linux/interrupt.h>#include <linux/errno.h>#include <linux/sound.h>#include <linux/soundcard.h>#include <linux/pm.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/hardware.h>#include <asm/semaphore.h>#include <asm/dma.h>#include <asm/arch/cpu_s3c2410.h>#include "2410addr.h"#include "2410lib.h"#include "def.h"#include "2410iic.h"#include "uda1380.h"/* * Samsung S3C2410 core and Philips UDA1380 Audio Hardware circuit * connecter description (From S3C2410 to UDA1380 ). * * I2C Bus circuit connect part: * IIC_SDA/GPE15 ---> L3Data * IIC_SCL/GPE14 ---> L3Clock * * I2S Bus circuirt connect part: * IIS_SDO/IIS_SDI/GPE4 ---> DATA1 * IIS_SDI/nSS0/GPE3 ---> DATA0 * CDCLK/GPE2 ---> SYSCLK * IIS_SCLK/GPE1 ---> BCKI * IIS_LRCK/GPE0 ---> WSI * * other: * L3MODE ---> (GND) * SEL_L3_IIC ---> (VCC) */#undef DEBUG#ifdef DEBUG#define DPRINTK( x... ) printk( ##x )#else#define DPRINTK( x... )#endif/* * This drive device program value and paremeter description. *****************************************************************************/#define UDA1380_ADDR 0x30 // Philips UDA1380 Audio device address.#define MUTE (0x1 << 2)#define NO_DE_EMPHASIS (0x10 << 3)#define DE_EMPHASIS_32 (0x11 << 3)#define DE_EMPHASIS_441 (0x12 << 3)#define DE_EMPHASIS_48 (0x13 << 3)#define GPIO_L3CLOCK (GPIO_MODE_OUT | GPIO_PULLUP_DIS | GPIO_B4)#define GPIO_L3DATA (GPIO_MODE_OUT | GPIO_PULLUP_DIS | GPIO_B3)#define GPIO_L3MODE (GPIO_MODE_OUT | GPIO_PULLUP_DIS | GPIO_B2)#define AUDIO_NAME "UDA1380"#define AUDIO_NAME_VERBOSE "UDA1380 audio driver"#define AUDIO_FMT_MASK (AFMT_S16_LE)#define AUDIO_FMT_DEFAULT (AFMT_S16_LE)#define AUDIO_CHANNELS_DEFAULT 2#define AUDIO_RATE_DEFAULT 22050#define AUDIO_NBFRAGS_DEFAULT 8#define AUDIO_FRAGSIZE_DEFAULT 8192#define S_CLOCK_FREQ 384 // frequency #define PCM_ABS(a) (a < 0 ? -a : a)/* define audio managment struction */typedef struct { int size; // buffer size char *start; // point to actual buffer dma_addr_t dma_addr; // physical buffer address struct semaphore sem; // down before touching the buffer int master; // owner for buffer allocation, contain size when true} audio_buf_t;/* define audio data stream managment struction */typedef struct { audio_buf_t *buffers; // pointer to audio buffer structures audio_buf_t *buf; // current buffer used by read/write u_int buf_idx; // index for the pointer above u_int fragsize; // fragment i.e. buffer size u_int nbfrags; // nbr of fragments dmach_t dma_ch; // DMA channel (channel2 for audio)} audio_stream_t;static audio_stream_t output_stream;#define NEXT_BUF(_s_,_b_) { \ (_s_)->_b_##_idx++; \ (_s_)->_b_##_idx %= (_s_)->nbfrags; \ (_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; }static u_int audio_rate; //static int audio_channels; //static int audio_fmt; //static u_int audio_fragsize; //static u_int audio_nbfrags; //static int audio_rd_refcount; //static int audio_wr_refcount; //#define audio_active (audio_rd_refcount | audio_wr_refcount)static int audio_dev_dsp; //static int audio_dev_mixer; //static int audio_mix_modcnt; //static int uda1380_volume; //static u8 uda_sampling; ///***** S.Yin insert program begin 2005-3-20 **********/static char _iicData[IICBUFSIZE];static volatile int _iicDataCount;static volatile int _iicStatus;static volatile int _iicControl;static int _iicPt;U32 uda1380_data;static int delayLoopCount = FCLK/10000/10;/* digital master volume control register */#define DEF_VOLUME 20unsigned long rtc_r_GPECON; // Port E control register.unsigned long rtc_r_GPEUP; // Port E pull-up disable register.unsigned long r_IICCON; // I2C Bus control register.unsigned long r_IICSTAT; // I2C Bus status register.unsigned long r_IICADD; // I2C Bus address register.unsigned long r_IICDS; // I2C Bus Tx/Rx data shift register.#define rGPECON (*(volatile unsigned long *)rtc_r_GPECON) //Port E control#define rGPEUP (*(volatile unsigned long *)rtc_r_GPEUP) //Pull-up control E#define rIICCON (*(volatile unsigned char *)r_IICCON) //IIC control#define rIICSTAT (*(volatile unsigned char *)r_IICSTAT) //IIC status#define rIICADD (*(volatile unsigned char *)r_IICADD) //IIC address#define rIICDS (*(volatile unsigned char *)r_IICDS) //IIC data shift /* Philips UDA1380 synchronization or Initialization infomation */static struct uda1380_reg_info { unsigned short num; // Reigisters. unsigned short default_value; // parameter.} uda1380_reg_info[] = { { REG0, REG0_EN_ADC|REG0_EN_DAC|REG0_EN_INT|REG0_EN_DEC|REG0_SC_384FS|REG0_ADC_USE_SYSCLK|REG0_DAC_USE_SYSCLK }, { I2S_REG, (FMT_I2S << I2S_REG_SFORO_SHIFT)|(FMT_I2S << I2S_REG_SFORI_SHIFT | (1<< 6)) }, { PWR_REG, PWR_REG_PON_DAC|PWR_REG_PON_BIAS }, { MASTER_VOL_REG, 0x4040 }, { MIXER_VOL_REG, 0xaa }, { MBT_REG, 0xaa}, { MMCDM_REG, 0x0 }, { MIXER_CTL_REG, 0x70 }, { DEC_VOL_REG, 0xaa }, { DPM_REG, 0xaa }, { DEC_ADC_REG, 0xaa }, { DEC_AGC_REG, 0xaa },}; /** S.Yin insert program end 2005-03-20 ****//* * function program part of the Philips UDA1380 audio. *****************************************************************************//***** S.Yin insert program begin 2005-03-20 **********//** * I2C Bus control register address set. */int rtc_address_map(void){ rtc_r_GPECON=(unsigned long)__ioremap(0x56000040,4,0); // rtc_r_GPEUP =(unsigned long)__ioremap(0x56000048,4,0); // r_IICCON =(unsigned long)__ioremap(0x54000000,4,0); // r_IICSTAT =(unsigned long)__ioremap(0x54000004,4,0); // r_IICADD =(unsigned long)__ioremap(0x54000008,4,0); // r_IICDS =(unsigned long)__ioremap(0x5400000c,4,0); // return 0;}/** * Delay control. * time=0: adjust the Delay function by WatchDog timer. * time>0: the number of loop time resolution of time is 100us. */void Delay(int time){ int i, adjust = 0; // define value. if ( time == 0 ) { // time = 200; // reset paremeter. adjust = 1; // delayLoopCount = 400; // //PCLK/1M,Watch-dog disable,1/64,interrupt disable,reset disable rWTCON = ((PCLK/1000000-1)<<8)|(2<<3); // rWTDAT = 0xffff; //for first update rWTCNT = 0xffff; //resolution=64us @any PCLK rWTCON = ((PCLK/1000000-1)<<8)|(2<<3)|(1<<5); //Watch-dog timer start } for ( ; time > 0; time-- ) // Delay. for ( i = 0; i < delayLoopCount; i++ ); // if ( adjust == 1 ) { // loop counter. rWTCON = ((PCLK/1000000-1)<<8)|(2<<3); // // Watch-dog timer stop i = 0xffff - rWTCNT; // 1count->64us, 200*400 cycle runtime = 64*i us delayLoopCount = 8000000/(i*64); // 200*400:64*i=1*x:100 -> x=80000*100/(64*i) }}/** * Check ACK and Pending bit. */int AckPoll( U8 slvAddr ){ int i; // define value. while ( 1 ) { // rIICDS = slvAddr; // Write slave address to rIICDS. rIICSTAT = 0xf0; // Write 0xf0 (M/T start) to rIICSTAT. rIICCON = 0xe0; // Resumes IIC operation. Delay(2); // Wait until stop condtion is in effect. for ( i = 0; i < 1000; i ++ ) { // _iicStatus = rIICSTAT; // To check if _iicStatus is changed if ( !(_iicStatus & 0x1 )) { // CHeck ACK flag received.// printk("ACK is received................\n"); return 0; // Normal return when ACK is received. } if ( i > 256 ) // Check time over. return 5; // Error return. } } return 2; // Error return.}/** * I2C bus write an slave address to client device. */int WriteInitByte( U8 slvAddr ){ int i; // define value. rIICDS = slvAddr; // Write slave address to rIICDS. for ( i = 0; i < 20; i ++ ); // rIICSTAT = 0xf0; // Write 0xf0 (M/T start) to rIICSTAT. Delay(2); // Delay. The data of the rIICDS is transmitted. for ( i = 0; i < 2000; i ++ ) { // The data of the rIICDS is shifted to SDA, and error check. _iicControl = rIICCON; // if (( _iicControl & 0x10 ) > 0 ) // ACK period and then interrupt is pending. return 0; // Normal out. if ( i > 1000 ) // Timeout. return 1; // Stop or Error return. } return 2; // Error return.}/** * I2C Bus write an data to client device ( Master Transmitted Mode Operation ). */int _Wr2410Iic( U8 slvAddr, U8 addr, U32 wdata ){ int i; // define value. /* Configured. Initialize. */ _iicData[0] = addr; // Set register address. _iicData[1] = wdata / 256; // Set data high tybe. _iicData[2] = wdata & 0xff; // Set data low tybe. _iicPt = 0; // Define data pointer. _iicDataCount = 3; // Set received data counter. /* IIC-Bus send initialize tybe (device address) */ if ( WriteInitByte( slvAddr ) > 0 ) // return 1; // /* IIC-Bus send register address and data */ while ( _iicDataCount ) { // rIICDS = _iicData[_iicPt]; // Write slave address to rIICDS. for ( i = 0; i < 20; i ++ ); // rIICCON = 0xe0; // CLear pending bit to resumes IIC operation. _iicPt += 1; // Counter pointer. _iicDataCount -= 1; // Data counter. Delay(2); // Delay. The data of the rIICDS is transmitted. for ( i = 0; i < 1000; i ++ ) { // Error status process. _iicControl = rIICCON; // if (( _iicControl & 0x10 ) > 0 ) // ACK period and then interrupt is pending. break; // normal out. if ( i > 256 ) // Timeout. return 2; // Stop or Error return. } } rIICSTAT = 0xd0; // Write 0xd0 (M/T STOP) to rIICSTAT. rIICCON = 0xe0; // Clear pending to resumes IIC operation. Delay(50); // Wait until stop condtion is in effect. /* Write completed oparation check. */ i = AckPoll( slvAddr ); // Check ACK flag bit. rIICSTAT = 0xd0; // Master Tx condition, Stop(Write), Output Enable rIICCON = 0xe0; // Resumes IIC operation. Delay(2); // Wait until stop condtion is in effect. return i; // return.}/** * I2C Bus read an data from client device( Master receive mode ). * (program is not normal or have error) */int _Rd2410Iic( U8 slvAddr, U8 addr ){ int i, readControl; // define value. /* Read oparation initialize */ _iicPt = 0; // define pointer. _iicDataCount = 1 * 2; // Data counter (word). if ( _iicDataCount > IICBUFSIZE ) // Check data counter. return 1; // Error return. /* IIC-Bus send initialize tybe */ if ( WriteInitByte( slvAddr ) > 0 ) // return 2; // /* IIC-Bus send register address */ rIICDS = addr; // Write slave address to rIICDS. for ( i = 0; i < 10; i ++ ); // rIICCON = 0xe0; // Clear pending bit. Delay(10); // The data of the IICDS (slave address) is transmitted, Delay. for ( i = 0; i < 2000; i ++ ) { // Error status process. _iicControl = rIICCON; // if (( _iicControl & 0x10 ) > 0 ) // ACK period and then interrupt is pending. break; // Normal out. if ( i > 1000 ) // Timeout. return 3; // Error return, or STOP. } /* IIC-Bus send slave address */ rIICDS = slvAddr | 0x01; // Write register address to rIICDS.. for ( i = 0; i < 20; i ++ ); // rIICSTAT = 0xb0; // Writ 0xb0 (M/R, START) to rIICSTAT. Delay(2); // The data of the IICDS (slave address) is transmitted, Delay. for ( i = 0; i < 2000; i ++ ) { // Error status process. _iicControl = rIICCON; // if (( _iicControl & 0x10 ) > 0 ) // ACK period and then interrupt is pending. break; // Normal out. if ( i > 1000 ) // Timeout. return 4; // Error return, or STOP. } /* IIC-Bus read data */ readControl = 1000; // Timeout contrl counter. while ( _iicDataCount ) { // Data number completed.. _iicControl = rIICCON; // if (( _iicControl & 0x10 ) > 0 ) { // ACK period and then interrupt is pending. _iicData[_iicPt] = rIICDS; // Read a new data from rIICDS. Delay(2); // The data of the IICDS (slave address) is transmitted, Delay. rIICCON = 0xe0; //Clear pending bit. Resumes IIC operation with ACK _iicPt += 1; // Data pointer. _iicDataCount -= 1; // Data counter. readControl = 1000; // Timeout control register reset. } if ( (readControl--) <= 0 ) // Check timeout. return 5; // Error return, orSTOP. } rIICSTAT = 0xd0; // Writ 0xb0 (M/R, STOP) to rIICSTAT. rIICCON = 0xe0; // Clear pending bit. Delay(2); // Wait until stop condtion is in effect. /* Read completed oparation check. */ i = AckPoll( slvAddr ); // Check ACK flag bit. rIICSTAT = 0xd0; // Master Tx condition, Stop(Write), Output Enable rIICCON = 0xe0; // Resumes IIC operation. Delay(2); // Wait until stop condtion is in effect. return i; // return.}/***** S.Yin insrt program end 2005-03-20 *****//***** S.Yin close this part program begin 2005-03-20 *****static void uda1341_l3_address(u8 data){ int i; int flags; local_irq_save(flags);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -