Skip to content

8 How to init IIS and IIC to make wm8960 chip play wav file

limingth edited this page May 19, 2012 · 7 revisions

pin -> signals

Audio_Xi2sSCLK0 [13]
Audio_Xi2sCDCLK0 [13]
Audio_Xi2sLRCK0 [13]
Audio_Xi2sSDO0_0 [1]
Audio_Xi2sSDI0 [1]

Xi2s0SCLK  GPI[0] 
Xi2s0CDCLK  GPI[1] 
Xi2s0LRCK  GPI[2] 
Xi2s0SDI  GPI[3] 
Xi2s0SDO[0]  GPI[4] 
Xi2s0SDO[1]  GPI[5] 
Xi2s0SDO[2]  GPI[6] 

GPICON  0xE020_0220 
GPIDAT  0xE020_0224 
GPIPUD  0xE020_0228 
GPIDRV  0xE020_022C 

SFR of GPIO and IIS

GPIO

Port Group GPI Control Register (GPICON, R/W, Address = 0xE020_0220) 
GPICON  Bit  Description  Initial State 
GPICON[6]   [27:24]   0010 = I2S_0_SDO[2]  0010  
GPICON[5]   [23:20]   0010 = I2S_0_SDO[1]  0010  
GPICON[4]   [19:16]   0010 = I2S_0_SDO[0]  
			0011 = PCM_0_SOUT 	0010  
GPICON[3]   [15:12]   0010 = I2S_0_SDI 
			0011 = PCM_0_SIN 	0010  
GPICON[2]   [11:8]   0010 = I2S_0_LRCK 
			0011 = PCM_0_FSYNC 	0010  
GPICON[1]   [7:4]   0010 = I2S_0_CDCLK 
			0011 = PCM_0_EXTCLK 	0010  
GPICON[0]   [3:0]   0010 = I2S_0_SCLK 
			0011 = PCM_0_SCLK 	0010  

IIS

Register  Address 
IISCON  0xEEE3_0000 
IISMOD  0xEEE3_0004 
IISFIC  0xEEE3_0008 
IISPSR  0xEEE3_000C 
IISTXD  0xEEE3_0010 
IISRXD  0xEEE3_0014 
IISFICS  0xEEE3_0018 
IISTXDS  0xEEE3_001C 

IIC Signals

Xi2cSCL0
Xi2cSDA0

XI2C0SDA 
XI2C0SCL 

Xi2c0SDA  GPD1[0]  I2C0_SDA 
Xi2c0SCL  GPD1[1]  I2C0_SCL 

GPD1CON[1]   [7:4]   
	0000 = Input     
	0001 = Output 
	0010 = I2C0_SCL 
	0011 ~ 1110 = Reserved 
	1111 = GPD1_INT[1] 
	0000  

GPD1CON[0]   [3:0]   
	0000 = Input     
	0001 = Output 
	0010 = I2C0_SDA 
	0011 ~ 1110 = Reserved 
	1111 = GPD1_INT[0] 
	0000  

uboot 启动后,IIS 寄存器的配置值:

[FriendlyLEG-TINY210]# md 0xeee30000
eee30000: 00000000 00000000 00000000 00000000    ................
eee30010: 00000000 此处死机

Linux 启动后,IIS 寄存器的配置值:

[root@FriendlyARM /tmp]# ./sfr 0xeee30000 256
addr = 0xeee30000, size = 256 
SFR addr = 0xeee30000, size = 0x100
eee30000 : 8050cc91      100       40        0 
eee30010 :        0        0        0        0 
eee30020 :        0        0 7fff0000        0 
eee30030 :        0        0        0        0 

Linux 上运行 QTopia 视频播放程序 之后再次查看 IIS 配置值:

[   54.517075] ASoC_mini210: SCLK=67738000 PSR=6 RCLK=11289600 RFS=256 BFS=32
[root@FriendlyARM /]# ./sfr 0xeee30000 64
addr = 0xeee30000, size = 64
SFR addr = 0xeee30000, size = 0x40
eee30000 : 8050c185      600     3f40     8500
eee30010 :        0        0        0        0
eee30020 :        0        0 7fff0000        0

结论: 播放 44.1Khz wav 时,BFS = 32fs, RFS = 256fs, RCLK = 44.1*256 = 11289600, PSR = 6 (5+1), 
SCLK = 67.738Mhz

此时查看 EPLL 配置,发现 0xa8430303 -> EPLL = 67Mhz ,说明 Linux 使用 EPLL 作为 IIS 的输入时钟
[root@FriendlyARM /]# ./sfr 0xe0100000 100   
e0100100 : a07d0301        0 a29b0c01        0
e0100110 : a8430303     bcee        0        0
e0100120 : a06c0603        0        0        0
e0100130 :        0        0        0        0
e0100140 :        0        0        0        0
e0100150 :        0        0        0        0
e0100160 :        0        0        0        0
e0100170 :        0        0        0        0
e0100180 :        0        0        0        0
begin to write vmem+4

总结 IIS 时钟产生过程

// IIS clock init
	// step 1: EPLL output 67.7Mhz (see p361 of s5pv210.pdf)
	// EPLL_CON0/ EPLL_CON1, R/W, Address = 0xE010_0110/0xE010_0114)
	// FOUT = (MDIV+K/65536) X FIN / (PDIV X 2SDIV)
	// Fout = (0x43+0.7)*24M / (3*2^3) = 80*24M/24 = 67.7Mhz
#define EPLL_CON0  	(*(volatile unsigned int *)0xe0100110)
#define EPLL_CON1  	(*(volatile unsigned int *)0xe0100114)
	EPLL_CON0 = 0xa8430303;		// MPLL_FOUT = 67.7Mhz
	EPLL_CON1 = 0xbcee;		// from linux kernel setting
	
	// step 2: MUX_EPLL = 1 -> SCLK_EPLL = 67.7Mhz (see p361 of s5pv210.pdf)
	// CLK_SRC0, R/W, Address = 0xE010_0200
	// 0xe0100200: 10001111
	// EPLL_SEL  [8]  Control MUXEPLL (0:FINPLL, 1:FOUTEPLL) 
#define CLK_SRC0  	(*(volatile unsigned int *)0xE0100200)		
	CLK_SRC0 = 0x10001111;
	
	// step 3: Mux_I2S  AUDIO subsystem clock selection (see P1868 P1875 of s5pv210.pdf)
#define CLK_CON  	(*(volatile unsigned int *)0xEEE10000)	
	CLK_CON = 0x1;		// 1 = FOUT_EPLL 		MUXI2S_A 00 = Main CLK 	
	
	// IIS SFRs		
	// step 4:	Divider of IIS (67.7 -> 11.289Mhz)
	// N + 1 = (67.7Mhz) / (256 * 44.1Khz) = 5.99
	// IISCDCLK  11.289Mhz = 44.1K * 256fs 
	// IISSCLK    1.4112Mhz = 44.1K * 32fs
	// IISLRCLK   44.1Khz
	N = 5;
	IISPSR = 1<<15 | N<<8;

下一步解决 IIC 和 WM8960 驱动

/* IIC bus - SCL & SDA 2 signals -> GPD1_0 & GDP1_1 -> GPD0CON */
void IIC_init(void)
{
	// set GPIO pin function as IICSCL, IICSDA
	GPD1CON |= 0x22;                //GPD1CON[1]  0010 = I2C0_SCL  , GPD1CON[0]  0010 = I2C0_SDA 
	GPD1PUD |= 0x5;              //Pull-down enable
	
	// Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt, Transmit clock value Tx clock=IICCLK/16
	IICCON  = (1<<7) | (0<<6) | (1<<5) | (0xf);	
	
	// Enable IIC bus
	//IICADD  = 0x10;                    // no use if s5pv210 is a IIC master
	IICSTAT = 0x10;                    //IIC bus data output enable(Rx/Tx)
}	

IIC master 工作模式下写 WM8960 的接口 IIC_write

/* slave_addr -> WM8960 device addr; addr -> WM8960 reg addr, data -> value */
void IIC_write(int slave_addr, int addr, int data)
{
	IICDS = slave_addr;
	IICSTAT = 0xf0;
	while ((IICCON & 0x10) == 0);	// INT
	while ((IICSTAT & 0x1));	// ACK
	
	// 7 bit addr & 9 bit data
	IICDS = addr<<1 | ((data>>8) & 0x0001);
	IICCON = 0xaf;
	while ((IICCON & 0x10) == 0);	// INT
	while ((IICSTAT & 0x1));	// ACK
		
	IICDS = (data & 0x00FF);
	IICCON = 0xaf;
	while ((IICCON & 0x10) == 0);	// INT
	while ((IICSTAT & 0x1));	// ACK
	
	IICSTAT = 0xd0;	// stop write
	IICCON = 0xaf;

	return;
}

WM8960 初始化配置

/* 0x34 is WM8960 IIC slave address */
void WM8960_init(void)
{
#define WM8960_DEVICE_ADDR		0x34
	// reset
	IIC_write(WM8960_DEVICE_ADDR, 0xf, 0x0);

	// power1 2 3
	IIC_write(WM8960_DEVICE_ADDR, 0x19, 1<<8 | 1<<7 | 1<<6);
	IIC_write(WM8960_DEVICE_ADDR, 0x1a, 1<<8 | 1<<7 | 1<<6 | 1<<5 | 1<<4 | 1<<3);
	IIC_write(WM8960_DEVICE_ADDR, 0x2F, 1<<3 | 1<<2);
	
	// clock
	IIC_write(WM8960_DEVICE_ADDR, 0x4, 0x0);		// CLKSEL = 0 : no PLL -> SYSCLK using MCLK 

	// no mute	ok
	IIC_write(WM8960_DEVICE_ADDR, 0x5, 0x0);			// set no mute
	//IIC_write(WM8960_DEVICE_ADDR, 0x5, 0x08);		// set mute 
	
	// audio interface
	IIC_write(WM8960_DEVICE_ADDR, 0x7, 0x2);			// 00 = 16bits,  10 = IIS format
		
	// volume +6db	ok
	IIC_write(WM8960_DEVICE_ADDR, 0x2, 0xFF | 0x100);			// WM8960_LOUT1
	IIC_write(WM8960_DEVICE_ADDR, 0x3, 0xFF | 0x100);			// WM8960_ROUT1

	IIC_write(WM8960_DEVICE_ADDR, 0xa, 0xFF | 0x100);		// Left DAC volume
	IIC_write(WM8960_DEVICE_ADDR, 0xb, 0xFF | 0x100);		// Right DAC volume
	
	// mixer control
	IIC_write(WM8960_DEVICE_ADDR, 0x22, 1<<8 | 1<<7);		// Left output mixer control
	IIC_write(WM8960_DEVICE_ADDR, 0x25, 1<<8 | 1<<7);		// Right output mixer control
	
	return;
}