3线接口与wm8976声卡驱动

JZ2440使用WM9876声卡,其硬件原理图:

    其控制接口有2线和3线模式,有MODE管脚决定,高电平为3线模式,低电平为2线模式,我们这里MODE接高电平,
使用3线接口模式。
    3线接口不是L3接口,但与L3接口相似,s3c2410-uda1341.c已经有了L3接口的操作,但没有3线接口的操作,我们把
L3接口的操作修改一下支持3线接口,用3线接口接到的那三个GPIO来模拟3线接口的时序,把对3线的操作抽象出来。

3线信号:
CSB:
SCLK:位时钟(芯片BCK脚)(一时钟一位数据)
SD:数据
说明:
    every rising dege of SCLK in one data bit from the SDIN pin. A rising dege on CSB/GPIO1 pin 
latches in a complete control word consisting of the last 16 bits.
    每次传输16位,传完第16位后,产生一个CSB上升沿,代表一次数据传输完毕。每位数据在SCLK的上升沿传输。
3线控制信号一个控制字由16 bit组成,这 16 bit 数据的含义:前7位(bit 15 : bit 9):是地址选择位,选择芯
片的那个寄存器操作。余下9位(bit 8 : bit 0)是数据位,写到寄存器对应的各位。
    传输顺序是先高位后低位,与UDA1341顺序相反。
3线控制信号的数据发送时序图:

对s3c2410-uda1341.c文件进行修改,完成下面3步,使支持3线接口:

1、添加wm8976写寄存器函数wm8976_write_reg(),根据时序图,用与3线相接的GPIO模拟数据发送时的时序。

static void wm8976_write_reg(unsigned char reg, unsigned int data)
{int i;unsigned long flags;unsigned short val = (reg << 9) | (data & 0x1ff);// 将寄存器和数据合并成16bit//首先把三条线都输出为高电平s3c2410_gpio_setpin(S3C2410_GPB2,1);//S3C2410_GPB2:L3MODEs3c2410_gpio_setpin(S3C2410_GPB3,1);//S3C2410_GPB3: L3DATAs3c2410_gpio_setpin(S3C2410_GPB4,1);//S3C2410_GPB4: L3CLOCKlocal_irq_save(flags); // 先关中断//将合并好的16位数据,依次发出,在时钟的上升沿获得数据for (i = 0; i < 16; i++) { // WM8976是先发出bit15位if (val & (1<<15)) // 如果是第15位{// 先给L3CLOCK上升沿,然后拉高L3DATA线s3c2410_gpio_setpin(S3C2410_GPB4,0);// 同上,L3DATA拉高s3c2410_gpio_setpin(S3C2410_GPB3,1); udelay(1); // 延时一会// 拉高L3CLOCKs3c2410_gpio_setpin(S3C2410_GPB4,1); }else{  	// 先给L3CLOCK上升沿,过段时间拉低L3DATA线s3c2410_gpio_setpin(S3C2410_GPB4,0);s3c2410_gpio_setpin(S3C2410_GPB3,0);udelay(1);s3c2410_gpio_setpin(S3C2410_GPB4,1); }val = val << 1; // 左移一位,发出下一位的寄存器数据}//还需要wm8976_write_reg()最后加上:s3c2410_gpio_setpin(S3C2410_GPB2,0);// 拉低L3MODEudelay(1); // 延时一会s3c2410_gpio_setpin(S3C2410_GPB2,1);// S3C2410_GPB2:L3MODE// 为稳定,拉高L3DATA线s3c2410_gpio_setpin(S3C2410_GPB3,1);s3c2410_gpio_setpin(S3C2410_GPB4,1);// 同上,拉高L3CLOCKlocal_irq_restore(flags); // 开中断
}

2、添加芯片初始化函数init_wm8976(),往哪个寄存器写什么值,写寄存器的顺序,参考芯片手册page88:

 

static void init_wm8976(void)
{uda1341_volume = 57;uda1341_boost = 0;/* software reset */wm8976_write_reg(0, 0);/* OUT2的左/右声道打开* 左/右通道输出混音打开* 左/右DAC打开*/wm8976_write_reg(0x3, 0x6f);wm8976_write_reg(0x1, 0x1f);//biasen,BUFIOEN.VMIDSEL=11b  wm8976_write_reg(0x2, 0x185);//ROUT1EN LOUT1EN, inpu PGA enable ,ADC enablewm8976_write_reg(0x6, 0x0);//SYSCLK=MCLK  wm8976_write_reg(0x4, 0x10);//16bit 		wm8976_write_reg(0x2B,0x10);//BTL OUTPUT  wm8976_write_reg(0x9, 0x50);//Jack detect enable  wm8976_write_reg(0xD, 0x21);//Jack detect  wm8976_write_reg(0x7, 0x01);//Jack detect 
}

3、修改一下音量的调节,也是往某个寄存器写值实现。音量值范围:ioctl:0-100,对应芯片:63-0。要调一下比例。

 

static int smdk2410_mixer_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg)
{int ret;long val = 0;switch (cmd) {case SOUND_MIXER_INFO:{mixer_info info;strncpy(info.id, "UDA1341", sizeof(info.id));strncpy(info.name,"Philips UDA1341", sizeof(info.name));info.modify_counter = audio_mix_modcnt;return copy_to_user((void *)arg, &info, sizeof(info));}case SOUND_OLD_MIXER_INFO:{_old_mixer_info info;strncpy(info.id, "UDA1341", sizeof(info.id));strncpy(info.name,"Philips UDA1341", sizeof(info.name));return copy_to_user((void *)arg, &info, sizeof(info));}case SOUND_MIXER_READ_STEREODEVS:return put_user(0, (long *) arg);case SOUND_MIXER_READ_CAPS:val = SOUND_CAP_EXCL_INPUT;return put_user(val, (long *) arg);case SOUND_MIXER_WRITE_VOLUME:ret = get_user(val, (long *) arg);if (ret)return ret;/* ioctl: val越大表示音量越大, 0-最小, 100-最大* UDA1341: 寄存器的值越小音量越大* WM8976: 52,53号寄存器bit[5:0]表示音量, 值越大音量越大, 0-63*/uda1341_volume = (((val & 0xff) + 1) * 63) / 100;wm8976_write_reg(52, (1<<8)|uda1341_volume);wm8976_write_reg(53, (1<<8)|uda1341_volume);//uda1341_l3_address(UDA1341_REG_DATA0);//uda1341_l3_data(uda1341_volume);break;case SOUND_MIXER_READ_VOLUME:val = (uda1341_volume * 100) / 63;return put_user(val, (long *) arg);case SOUND_MIXER_READ_IGAIN:val = ((31- mixer_igain) * 100) / 31;return put_user(val, (int *) arg);case SOUND_MIXER_WRITE_IGAIN:ret = get_user(val, (int *) arg);if (ret)return ret;mixer_igain = 31 - (val * 31 / 100);/* use mixer gain channel 1*///uda1341_l3_address(UDA1341_REG_DATA0);//uda1341_l3_data(EXTADDR(EXT0));//uda1341_l3_data(EXTDATA(EXT0_CH1_GAIN(mixer_igain)));break;default:DPRINTK("mixer ioctl %u unknown\n", cmd);return -ENOSYS;}audio_mix_modcnt++;return 0;
}

把修改好的s3c2410-uda1341.c另存为s3c-wm8976.c。

测试:
1. 确定内核里已经配置了sound\soc\s3c24xx\s3c2410-uda1341.c
-> Device Drivers
  -> Sound
    -> Advanced Linux Sound Architecture  // 兼容OSS
      -> Advanced Linux Sound Architecture
        -> System on Chip audio support
        <*> I2S of the Samsung S3C24XX chips
2. 修改sound/soc/s3c24xx/Makefile
obj-y += s3c2410-uda1341.o
改为:
obj-y += s3c-wm8976.o   
3. make uImage
   使用新内核启动
4. ls -l /dev/dsp /dev/mixer
5. 播放:
   在WINDOWS PC里找一个wav文件,放到开发板根文件系统里
   cat Windows.wav > /dev/dsp
6. 录音:
   cat /dev/dsp > sound.bin  
   然后对着麦克风说话
   ctrl+c退出

   cat sound.bin > /dev/dsp  // 就可以听到录下的声音   

参考文章:L3接口与UDA1341声卡测试点击打开链接

 

 

 

 

 

 

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部