-
Notifications
You must be signed in to change notification settings - Fork 36
8 How to init IIS and IIC to make wm8960 chip play wav file
limingth edited this page May 19, 2012
·
7 revisions
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
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
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
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
[FriendlyLEG-TINY210]# md 0xeee30000
eee30000: 00000000 00000000 00000000 00000000 ................
eee30010: 00000000 此处死机
[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
[ 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 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 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)
}
/* 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;
}
/* 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;
}