📄 linux-at91rm9200-i2s.c
字号:
#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 <asm/uaccess.h>
#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/semaphore.h>
#include <asm/arch/AT91RM9200_SSC.h>
#include <asm/arch/AT91RM9200_TC.h>
#undef DEBUG
#ifdef DEBUG
#define DPRINTK( x... ) printk( ##x )
#else
#define DPRINTK( x... )
#endif
/* UDA1341 Register bits */
#define UDA1341_ADDR 0x14
#define UDA1341_REG_DATA0 (UDA1341_ADDR + 0)
#define UDA1341_REG_STATUS (UDA1341_ADDR + 2)
/* status control */
#define STAT0 (0x00)
#define STAT0_RST (1 << 6)
#define STAT0_SC_MASK (3 << 4)
#define STAT0_SC_512FS (0 << 4)
#define STAT0_SC_384FS (1 << 4)
#define STAT0_SC_256FS (2 << 4)
#define STAT0_IF_MASK (7 << 1)
#define STAT0_IF_I2S (0 << 1)
#define STAT0_IF_LSB16 (1 << 1)
#define STAT0_IF_LSB18 (2 << 1)
#define STAT0_IF_LSB20 (3 << 1)
#define STAT0_IF_MSB (4 << 1)
#define STAT0_IF_LSB16MSB (5 << 1)
#define STAT0_IF_LSB18MSB (6 << 1)
#define STAT0_IF_LSB20MSB (7 << 1)
#define STAT0_DC_FILTER (1 << 0)
#define STAT0_DC_NO_FILTER (0 << 0)
#define STAT1 (0x80)
#define STAT1_DAC_GAIN (1 << 6) /* gain of DAC */
#define STAT1_ADC_GAIN (1 << 5) /* gain of ADC */
#define STAT1_ADC_POL (1 << 4) /* polarity of ADC */
#define STAT1_DAC_POL (1 << 3) /* polarity of DAC */
#define STAT1_DBL_SPD (1 << 2) /* double speed playback */
#define STAT1_ADC_ON (1 << 1) /* ADC powered */
#define STAT1_DAC_ON (1 << 0) /* DAC powered */
/* data0 direct control */
#define DATA0 (0x00)
#define DATA0_VOLUME_MASK (0x3f)
#define DATA0_VOLUME(x) (x)
#define DATA1 (0x40)
#define DATA1_BASS(x) ((x) << 2)
#define DATA1_BASS_MASK (15 << 2)
#define DATA1_TREBLE(x) ((x))
#define DATA1_TREBLE_MASK (3)
#define DATA2 (0x80)
#define DATA2_PEAKAFTER (0x1 << 5)
#define DATA2_DEEMP_NONE (0x0 << 3)
#define DATA2_DEEMP_32KHz (0x1 << 3)
#define DATA2_DEEMP_44KHz (0x2 << 3)
#define DATA2_DEEMP_48KHz (0x3 << 3)
#define DATA2_MUTE (0x1 << 2)
#define DATA2_FILTER_FLAT (0x0 << 0)
#define DATA2_FILTER_MIN (0x1 << 0)
#define DATA2_FILTER_MAX (0x3 << 0)
/* data0 extend control */
#define EXTADDR(n) (0xc0 | (n))
#define EXTDATA(d) (0xe0 | (d))
#define EXT0 0
#define EXT0_CH1_GAIN(x) (x)
#define EXT1 1
#define EXT1_CH2_GAIN(x) (x)
#define EXT2 2
#define EXT2_MIC_GAIN_MASK (7 << 2)
#define EXT2_MIC_GAIN(x) ((x) << 2)
#define EXT2_MIXMODE_DOUBLEDIFF (0)
#define EXT2_MIXMODE_CH1 (1)
#define EXT2_MIXMODE_CH2 (2)
#define EXT2_MIXMODE_MIX (3)
#define EXT4 4
#define EXT4_AGC_ENABLE (1 << 4)
#define EXT4_INPUT_GAIN_MASK (3)
#define EXT4_INPUT_GAIN(x) ((x) & 3)
#define EXT5 5
#define EXT5_INPUT_GAIN(x) ((x) >> 2)
#define EXT6 6
#define EXT6_AGC_CONSTANT_MASK (7 << 2)
#define EXT6_AGC_CONSTANT(x) ((x) << 2)
#define EXT6_AGC_LEVEL_MASK (3)
#define EXT6_AGC_LEVEL(x) (x)
#define AUDIO_NAME "UDA1341"
#define AUDIO_NAME_VERBOSE "UDA1341 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 DFT_VOLUME 100
//static struct device *this_dev;
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 */
int dma_size;
} audio_buf_t;
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) */
int dma_ch;
} audio_stream_t;
static audio_stream_t output_stream;
static audio_stream_t input_stream; /* input */
static unsigned short rd_buf_tail;
static unsigned short wr_buf_tail;
static u_int play_dma_running;
#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_dev_dsp;
static int audio_dev_mixer;
static int audio_rd_refcount;
static int audio_wr_refcount;
#define audio_active (audio_rd_refcount | audio_wr_refcount)
static int uda1341_volume;
static int uda1341_boost;
static int mixer_igain = 0x4; /* -6db*/
#define L3MOD_HI() //__raw_writel(__raw_readl(S3C2410_GPBDAT)|(1<<2), S3C2410_GPBDAT)
#define L3MOD_LOW() //__raw_writel(__raw_readl(S3C2410_GPBDAT)&~(1<<2), S3C2410_GPBDAT)
#define L3DAT_HI() //__raw_writel(__raw_readl(S3C2410_GPBDAT)|(1<<3), S3C2410_GPBDAT)
#define L3DAT_LOW() //__raw_writel(__raw_readl(S3C2410_GPBDAT)&~(1<<3), S3C2410_GPBDAT)
#define L3CLK_HI() //__raw_writel(__raw_readl(S3C2410_GPBDAT)|(1<<4), S3C2410_GPBDAT)
#define L3CLK_LOW() //__raw_writel(__raw_readl(S3C2410_GPBDAT)&~(1<<4), S3C2410_GPBDAT)
static void uda1341_l3_address(u8 data)
{
int i;
unsigned long flags;
local_irq_save(flags);
L3MOD_LOW();//write_gpio_bit(GPIO_L3MODE, 0);
L3DAT_LOW();//write_gpio_bit(GPIO_L3DATA, 0);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
for (i = 0; i < 8; i++) {
if (data & 0x1) {
L3CLK_LOW();//write_gpio_bit(GPIO_L3CLOCK, 0);
udelay(1);
L3DAT_HI(); //write_gpio_bit(GPIO_L3DATA, 1);
udelay(1);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
} else {
L3CLK_LOW();//write_gpio_bit(GPIO_L3CLOCK, 0);
udelay(1);
L3DAT_LOW();//write_gpio_bit(GPIO_L3DATA, 0);
udelay(1);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
}
data >>= 1;
}
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
udelay(1);
local_irq_restore(flags);
}
static void uda1341_l3_data(u8 data)
{
int i;
unsigned long flags;
local_irq_save(flags);
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
udelay(1);
L3MOD_LOW();//write_gpio_bit(GPIO_L3MODE, 0);
udelay(1);
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
for (i = 0; i < 8; i++) {
if (data & 0x1) {
L3CLK_LOW();//write_gpio_bit(GPIO_L3CLOCK, 0);
udelay(1);
L3DAT_HI(); //write_gpio_bit(GPIO_L3DATA, 1);
udelay(1);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
} else {
L3CLK_LOW();//write_gpio_bit(GPIO_L3CLOCK, 0);
udelay(1);
L3DAT_LOW();//write_gpio_bit(GPIO_L3DATA, 0);
udelay(1);
L3CLK_HI(); //write_gpio_bit(GPIO_L3CLOCK, 1);
udelay(1);
}
data >>= 1;
}
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
L3MOD_LOW();//write_gpio_bit(GPIO_L3MODE, 0);
udelay(1);
L3MOD_HI(); //write_gpio_bit(GPIO_L3MODE, 1);
local_irq_restore(flags);
}
struct iis_psr_val {
__u32 rate;
__u16 psr;
__u16 fs;
};
#ifdef CONFIG_ARCH_AT91RM9200DK_203MHz
#ifdef CONFIG_ARCH_AT91RM9200DK_MCK_DIV_2
//CPU clock=203212800, MCK=101606400
static struct iis_psr_val iis_psr_para[] = {
{8000, 200, 256}, //256fs
{11025, 144, 384}, //384fs
{16000, 96, 384}, //384fs
{22050, 72, 384}, //384fs
{24000, 64, 256}, //256fs
{32000, 48, 384}, //384fs
{44100, 36, 384}, //384fs
{48000, 32, 256} //256fs
};
#else
//CPU clock=202752000, MCK=67737600
static struct iis_psr_val iis_psr_para[] = {
{8000, 128, 256}, //256
{11025, 96, 384}, //384
{16000, 64, 256}, //256
{22050, 48, 384}, //384
{24000, 40, 256}, //256
{32000, 32, 256}, //256
{44100, 24, 384}, //384
{48000, 24, 384} //384
};
#endif
#else
#ifdef CONFIG_ARCH_AT91RM9200DK_MCK_DIV_2
//CPU clock=180633600, MCK=90316800
static struct iis_psr_val iis_psr_para[] = {
{8000, 176, 256}, //256
{11025, 128, 256}, //256
{16000, 88, 256}, //256
{22050, 64, 256}, //256
{24000, 56, 256}, //256
{32000, 48, 384}, //384
{44100, 32, 256}, //256
{48000, 32, 256} //256
};
#else
//CPU clock=180633600, MCK=60211200
static struct iis_psr_val iis_psr_para[] = {
{8000, 116, 128}, //128
{11025, 84, 384}, //384
{16000, 60, 384}, //384
{22050, 44, 128}, //128
{24000, 40, 256}, //256
{32000, 28, 128}, //128
{44100, 20, 128}, //128
{48000, 20, 128} //128
};
#endif
#endif
static int audio_set_dsp_speed(__u32 val);
static void init_s3c2410_iis_bus_rx(void)
{
AT91PS_SSC pSSC = (AT91PS_SSC)AT91C_VA_BASE_SSC2;
((AT91PS_SYS)AT91C_VA_BASE_SYS)->PMC_PCER = (1<<AT91C_ID_SSC2)|(1<<AT91C_ID_TC1);
pSSC->SSC_PTCR = (1<<1)|(1<<9); //disable PDC tx and rx
pSSC->SSC_RCR = 0;
pSSC->SSC_RNCR = 0;
pSSC->SSC_CR = (1<<15); //software reset
udelay(20);
// 22.05 KHz
audio_set_dsp_speed(audio_rate);
pSSC->SSC_RCMR = AT91C_SSC_CKS_TK
| AT91C_SSC_CKO_CONTINOUS
| AT91C_SSC_START_FALL_RF
| (AT91C_SSC_STTDLY&(1<<16))
| (AT91C_SSC_PERIOD&(15<<24));
pSSC->SSC_RFMR = (AT91C_SSC_DATLEN&15)
| AT91C_SSC_MSBF
| (AT91C_SSC_DATNB&(1<<8))
| (AT91C_SSC_FSLEN&(15<<16))
| AT91C_SSC_FSOS_NEGATIVE
| (AT91C_SSC_FSEDGE&0);
pSSC->SSC_PTCR = (1<<0); //ebable PDC rx
pSSC->SSC_CR = (1<<0); //enable rx
pSSC->SSC_IDR = 0xffffffff; //disable all irq
pSSC->SSC_IER = AT91C_SSC_ENDRX; //enable endrx irq
}
static void init_s3c2410_iis_bus_tx(void)
{
AT91PS_SSC pSSC = (AT91PS_SSC)AT91C_VA_BASE_SSC2;
((AT91PS_SYS)AT91C_VA_BASE_SYS)->PMC_PCER = (1<<AT91C_ID_SSC2)|(1<<AT91C_ID_TC1);
pSSC->SSC_PTCR = (1<<1)|(1<<9); //disable PDC tx and rx
pSSC->SSC_TCR = 0;
pSSC->SSC_TNCR = 0;
pSSC->SSC_CR = (1<<15); //software reset
udelay(20);
// 22.05 KHz , 256fs
audio_set_dsp_speed(audio_rate);
pSSC->SSC_TCMR = AT91C_SSC_CKS_DIV
| AT91C_SSC_CKO_CONTINOUS
| AT91C_SSC_START_FALL_RF
| (AT91C_SSC_STTDLY&(1<<16))
| (AT91C_SSC_PERIOD&(15<<24));
pSSC->SSC_TFMR = (AT91C_SSC_DATLEN&15)
| AT91C_SSC_MSBF
| (AT91C_SSC_DATNB&(1<<8))
| (AT91C_SSC_FSLEN&(15<<16))
| AT91C_SSC_FSOS_NEGATIVE
| (AT91C_SSC_FSEDGE&0);
pSSC->SSC_PTCR = (1<<8); //ebable PDC tx
pSSC->SSC_CR = (1<<8); //enable tx
pSSC->SSC_IDR = 0xffffffff; //disable all irq
pSSC->SSC_IER = AT91C_SSC_ENDTX; //enable endtx irq
}
static void audio_clear_buf(audio_stream_t * s)
{
DPRINTK("audio_clear_buf\n");
if (s->buffers) {
int frag;
for (frag = 0; frag < s->nbfrags; frag++) {
if (!s->buffers[frag].master)
continue;
consistent_free(s->buffers[frag].start,
s->buffers[frag].master,
s->buffers[frag].dma_addr);
}
kfree(s->buffers);
s->buffers = NULL;
}
s->buf_idx = 0;
s->buf = NULL;
}
static int audio_setup_buf(audio_stream_t * s)
{
int frag;
int dmasize = 0;
char *dmabuf = 0;
dma_addr_t dmaphys = 0;
if (s->buffers)
return -EBUSY;
wr_buf_tail = rd_buf_tail = play_dma_running = 0;
s->nbfrags = audio_nbfrags;
s->fragsize = audio_fragsize;
s->buffers = (audio_buf_t *)
kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL);
if (!s->buffers)
goto err;
memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags);
for (frag = 0; frag < s->nbfrags; frag++) {
audio_buf_t *b = &s->buffers[frag];
if (!dmasize) {
dmasize = (s->nbfrags - frag) * s->fragsize;
do {
dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA,
dmasize, &dmaphys);
if (!dmabuf)
dmasize -= s->fragsize;
} while (!dmabuf && dmasize);
if (!dmabuf)
goto err;
b->master = dmasize;
}
b->start = dmabuf;
b->dma_addr = dmaphys;
sema_init(&b->sem, 1);
DPRINTK("buf %d: start %p dma %d\n", frag, b->start, b->dma_addr);
dmabuf += s->fragsize;
dmaphys += s->fragsize;
dmasize -= s->fragsize;
}
s->buf_idx = 0;
s->buf = &s->buffers[0];
return 0;
err:
printk(AUDIO_NAME ": unable to allocate audio memory\n ");
audio_clear_buf(s);
return -ENOMEM;
}
/*
static void iisin_dma_done_handler(int irq, void *dev_id, struct pt_regs *regs)
{
AT91PS_SSC pSSC = AT91C_VA_BASE_SSC2;
audio_stream_t *s = &input_stream;
// printk(KERN_DEBUG"%d\n", input_stream.buf_idx);
if(s->buffers) {
audio_buf_t *b = s->buffers+rd_buf_tail;
rd_buf_tail++;
if(rd_buf_tail>=s->nbfrags)
rd_buf_tail = 0;
// __raw_writel(s->buffers[rd_buf_tail].dma_addr, DIDST1);
// __raw_writel(2, DMTRIG1);
pSSC->RPR = s->buffers[rd_buf_tail].dma_addr;
pSSC->RCR = s->fragsize>>1;
if(s->buf_idx==rd_buf_tail) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -