调试WM9714音频通道切换

转载自:http://blog.csdn.net/willand1981/article/details/5608447

 

WM9714的耳机跟喇叭通道切换由寄存器软件控制,跟之前电视里面插入耳机让功放直接拉低关掉外音的方式有点差别。通过设置WM9714的0X1C寄存器的值来切换,其中设置耳机时为0X00A0,设置喇叭时为0X1200。

      电路中有外部上拉固定EINT11为高电平,通过插入耳机将这个外中断EINT11拉低来触发中断,再进行WM9714的寄存器控制。首先在WM9713.C中wm9713_soc_probe()中,添加初始化通道设置和注册中断。

#define HdPhone_EintPin  IRQ_EINT(11)
#define HdPhone_GpioPin   S3C64XX_GPN(11) 
#define OUTPUT_VALUE_HP      (0x00a0)
#define OUTPUT_VALUE_SPK (0x1200)

static int wm9713_soc_probe(struct platform_device *pdev)

{

     ......

     s3c_gpio_cfgpin(HdPhone_GpioPin, S3C_GPIO_SFN(2));        //配置GPIO11为外中断
     s3c_gpio_setpull(HdPhone_GpioPin, S3C_GPIO_PULL_NONE);  //不上拉也不下拉,硬件默认拉高
     set_irq_type(HdPhone_EintPin, IRQ_TYPE_EDGE_BOTH);      //插入跟拔出耳机都会触发中断

     if(readl(S3C64XX_GPNDAT)&(1<<11))                                    //如果上电默认是喇叭,设置通道;否则设置耳机
    { 
            ac97_write(codec, AC97_REC_GAIN, OUTPUT_VALUE_SPK);
     }
     else
     {                                                                   
             ac97_write(codec, AC97_REC_GAIN, OUTPUT_VALUE_HP);
      }

      ret = request_irq(HdPhone_EintPin, s3c6400_9713HdSp_irq,    //给EINT11注册中断和中断处理函数,参数包括中断方式,
                     IRQF_DISABLED, "HdphonSpeak", NULL);                    //中断名

      if(ret<0)                                                                                       //如果注册不成功,执行GOTO
     {
             printk(KERN_ERR "request_irq(s3c6400_9713HdSp_irq) failed !!!/n");
             goto irq_err;
      }

      .........

 irq_err:
      free_irq(HdPhone_EintPin,NULL);                                                 //释放中断

      .........

}

中断handler如下:

static irqreturn_t s3c6400_9713HdSp_irq(int irq, void *dev_id)
{
       struct snd_soc_codec *codec = wm9713_dai->codec;          //获取系统的codec
       writel(readl(S3C64XX_EINT0MASK)|(1<<11),S3C64XX_EINT0MASK); //disable EINT0 Interrupt before deal it
       writel(1<<11,S3C64XX_EINT0PEND);                                    //disable Interrupt

       if(readl(S3C64XX_GPNDAT)&(1<<11))                                   //如果是喇叭,否则是耳机
       {
              ac97_write(codec, AC97_REC_GAIN, OUTPUT_VALUE_SPK);
        }
        else
        { 
               ac97_write(codec, AC97_REC_GAIN, OUTPUT_VALUE_HP);
         }

         writel(readl(S3C64XX_EINT0MASK)&(~(1<<11)),S3C64XX_EINT0MASK); //Enable Interrupt after deal it
         return IRQ_HANDLED;
}

     以上即OK,在实际中还发现一个问题,插拔耳机切通道一直正常,但是第一次开机和仅仅用喇叭播放时喇叭不出声,也就是说一直需要耳机触发后喇叭跟耳机才会出声?通过测试波形,发现有耳机输入波形跟切换正常;但是功放输入会没有波形,估计还是切换通道的问题,查找后原因在于播放声音时,Entered s3c6400_ac97_hifi_prepare()中,判断SNDRV_PCM_STREAM_PLAYBACK会将0X1C寄存器写成0XAA,把喇叭所需的0X1200覆盖,屏蔽这句即可。可通过在s3c6400_ac97_trigger()中,设置打印语句:

for (temp =0x00;temp<=0x7e;temp+=0x02)
     s3c6400_ac97_read(0,temp);

将CMD=1开始播放音频时9714的寄存器值全部读出,作出判断依据。

 ==================WIN CE的做法===============================================

初始化执行中:

Irq = IRQ_EINT11;                                     //中断GPIO

DWORD  m_dwSysintrHPSense = NULL;    //耳机切换标志
HANDLE  m_hHPSenseInterrupt = NULL;   //耳机切换中断句柄

HANDLE  m_hHPSenseInterruptThread;    //耳机切换中断线程句柄

if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &Irq, sizeof(DWORD), &m_dwSysintrHPSense, sizeof(DWORD), NULL))                               //GPIO作中断控制注册
{
        WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : HP sense IOCTL_HAL_REQUEST_SYSINTR Failed/n/r")));
        m_dwSysintrHPSense = SYSINTR_UNDEFINED;
        return FALSE;
}

m_hHPSenseInterrupt = CreateEvent(NULL, FALSE, FALSE, NULL);     //初始化中断句柄
if (m_hHPSenseInterrupt == NULL)

{
        WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : HP sense CreateEvent() Failed /n/r")));
        return(FALSE);
}

if (!InterruptInitialize(m_dwSysintrHPSense, m_hHPSenseInterrupt, NULL, 0))   //绑定中断句柄和标志
{
       WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : HP sense InterruptInitialize() Failed /n/r")));
       return FALSE;
}

m_hHPSenseInterruptThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0,
        (LPTHREAD_START_ROUTINE)CallInterruptThreadHPSense, this, 0, NULL);  //创建中断线程

if (m_hHPSenseInterruptThread == NULL)   //如果没有创建成功线程,返回。

{
       WAV_ERR((_T("[WAV:ERR] InitInterruptThread() : HP sense CreateThread() Failed /n/r")));
       return FALSE;
}

void CallInterruptThreadHPSense(HardwareContext *pHWContext)
{
       pHWContext->InterruptThreadHPSense();    //通过硬件上下文调用中断处理函数
}

中断处理函数:

void HardwareContext::InterruptThreadHPSense()

{

       ......

       if(!(g_pGPIOReg->GPNDAT & (1<<11)))     //如果插入耳机
       {
              WriteCodecRegister(WM9713_OUTPUT_MUX, OUTPUT_VALUE_HP);
              RETAILMSG(AC97_HP_DEBUG,(_T("[WAV:] HeadPhone OUTPUT/n/r")));
        }

        while(TRUE)
        {

               WaitForSingleObject(m_hHPSenseInterrupt, INFINITE);   //线程等待中断发生

               g_pGPIOReg->EINT0MASK |= (0x1<<11);    // Mask EINT9, Clear Interrupt Pending
               g_pGPIOReg->EINT0PEND = (0x1<<11);   // Clear pending EINT9

               if(g_pGPIOReg->GPNDAT & (1<<11))
              {
                      WriteCodecRegister(WM9713_OUTPUT_MUX, OUTPUT_VALUE_SPK);
                      RETAILMSG(AC97_HP_DEBUG,(_T("[WAV:] SPEAK OUTPUT/n/r")));
               }
               else
               {
                       WriteCodecRegister(WM9713_OUTPUT_MUX, OUTPUT_VALUE_HP);
                        RETAILMSG(AC97_HP_DEBUG,(_T("[WAV:] HeadPhone OUTPUT/n/r")));
                }
                InterruptDone(m_dwSysintrHPSense);
                g_pGPIOReg->EINT0MASK &= ~(0x1<<11);    // Unmask EINT9, Enable Interrupt

          }

          ......
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值