海思3531d下的tlv320aix3101音频驱动及sample

本文档详细介绍了在海思hi3531dv100芯片上针对TLV320AIX3101音频编解码器的驱动及sample程序的实现过程,包括硬件连接、驱动配置和sample程序的主要部分,如采集播放线程和声卡配置。作者分享了官方SDK中不完善之处的改进,并提供了自定义的驱动调整方案。
摘要由CSDN通过智能技术生成

前言

目前一直在使用海思的hi3531dv100芯片,声卡已经调过tlv320aic3254和tlv320aix3101

官方SDK中 mpp/extdrv中提供了一个文件夹tlv320aic31,但是部分设置并不是很完美,因此根据自己硬件的不同,做了部分调整

下载连接

https://download.csdn.net/download/whitefish520/13010312

硬件连接

1

左边是I2S和I2C

右边是输入和输出

声卡驱动

/*
 *
 * Copyright (c) 2006 Hisilicon Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 *
 *
 * History:
 *      10-April-2006 create this file
 */


#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/slab.h>
//#include <linux/smp_lock.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#ifndef CONFIG_HISI_SNAPSHOT_BOOT
#include <linux/miscdevice.h>
#endif
#include <linux/delay.h>

#include <linux/proc_fs.h>
#include <linux/poll.h>

#include <asm/bitops.h>
#include <asm/uaccess.h>
#include <asm/irq.h>

#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/reboot.h>
#include <linux/notifier.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#include "tlv320aic31.h"
#include "tlv320aic31_def.h"

#ifdef CONFIG_HISI_SNAPSHOT_BOOT
#include "himedia.h"
#endif

#define CHIP_NUM 1
#define DEV_NAME "tlv320aic31"
#define DEBUG_LEVEL 1
#define DPRINTK(level,fmt,args...) do{ if(level < DEBUG_LEVEL)\
            printk(KERN_INFO "%s [%s ,%d]: " fmt "\n",DEV_NAME,__FUNCTION__,__LINE__,##args);\
    }while(0)

unsigned int IIC_device_addr[CHIP_NUM] = {
   0x30};

static struct i2c_board_info hi_info =
{
   
    I2C_BOARD_INFO("tlv320aic31", 0x30),
};

static struct i2c_client* tlv_client;


static unsigned int  open_cnt = 0;
static int chip_count = 1;

#ifdef CONFIG_HISI_SNAPSHOT_BOOT
static struct himedia_device s_stTlv320aic31Device;
#endif

static int tlv320aic31_device_init(unsigned int num);

int tlv320aic31_write(unsigned char chip_addr, unsigned char reg_addr, unsigned char value)
{
   
    int ret;
    unsigned char buf[2];
    struct i2c_client* client = tlv_client;

    buf[0] = reg_addr;
    buf[1] = value;

    ret = i2c_master_send(client, buf, 2);
    return ret;
}

int tlv320aic31_read(unsigned char chip_addr, unsigned char reg_addr)
{
   
    int ret_data = 0xFF;
    int ret;
    struct i2c_client* client = tlv_client;
    unsigned char buf[2];

    buf[0] = reg_addr;
    ret = i2c_master_recv(client, buf, 1);
    if (ret >= 0)
    {
   
        ret_data = buf[0];
    }
    return ret_data;
}

void tlv320aic31_reg_dump(unsigned int reg_num)
{
   
    unsigned int i = 0;
    for (i = 0; i < reg_num; i++)
    {
   
        printk("reg%03d = 0x%02x | ", i, tlv320aic31_read(IIC_device_addr[0], i));
        if ((i + 1) % 8 == 0)
        {
   
            printk("\n");
        }
    }
    printk("\n");
}
void soft_reset(unsigned int chip_num)
{
   
    // soft reset
    tlv320aic31_write(IIC_device_addr[chip_num], 1,0x80);
    msleep(10);

    // sample
    tlv320aic31_write(IIC_device_addr[chip_num], 2, 0x00);

    // PLL enable 
    tlv320aic31_write(IIC_device_addr[chip_num], 3, 0x81);/* P=1 Q=16*/
    tlv320aic31_write(IIC_device_addr[chip_num], 4, 0x20);/* J=8 */
    tlv320aic31_write(IIC_device_addr[chip_num], 5, 0x00);
    tlv320aic31_write(IIC_device_addr[chip_num], 6, 0x00);

    // left and right DAC open
    tlv320aic31_write(IIC_device_addr[chip_num], 7,  0x0a);/* 48 kHz */

    // ctrl mode
    tlv320aic31_write(IIC_device_addr[chip_num], 8,  0x00);/* slave mode */

    // Audio Serial Data Interface Control
    tlv320aic31_write(IIC_device_addr[chip_num], 9,  0x00);/* I2S mode,16bit */

    // Data offset = 0 bit clocks 
    tlv320aic31_write(IIC_device_addr[chip_num], 10, 0x00);

    // Audio Codec Digital Filter Control Register
    tlv320aic31_write(IIC_device_addr[chip_num], 12, 0x50);
    tlv320aic31_write(IIC_device_addr[chip_num], 14, 0x00);

    // The ADC PGA is not muted.
    tlv320aic31_write(IIC_device_addr[chip_num], 15, 0x00);
    tlv320aic31_write(IIC_device_addr[chip_num], 16, 0x00);

    // LINE2L connected to the left ADC PGA
    tlv320aic31_write(IIC_device_addr[chip_num], 17,  0x0f);
    // LINE2R connected to the right ADC PGA
    tlv320aic31_write(IIC_device_addr[chip_num], 18,  0xf0);

    // LINE1LP is configured in single-ended mode
    // LINE1L connected to the left-ADC PGA
    // Left-ADC channel is powered up
    tlv320aic31_write(IIC_device_addr[chip_num], 19,  0x04);

    // LINE1RP is configured in single-ended mode
    tlv320aic31_write(IIC_device_addr[chip_num], 21,  0x78);

    // LINE1RP is configured in single-ended mode
    // LINE1R connected to the right-ADC PGA
    // Right-ADC channel is powered up
    tlv320aic31_write(IIC_device_addr[chip_num], 22,  0x04);

    // LINE1LP is configured in single-ended mode
    tlv320aic31_write(IIC_device_addr[chip_num], 24,  0x78);

    // Left DAC is powered up
    // Right DAC is powered up
    // HPLCOM is configured as independent single-ended output
    tlv320aic31_write(IIC_device_addr[chip_num], 37, 0xe0);

    // HPRCOM is configured as independent single-ended output
    tlv320aic31_write(IIC_device_addr[chip_num], 38, 0x10);

    // Left-DAC output selects DAC_L1 path,
    // Right-DAC output selects DAC_R1 path
    tlv320aic31_write(IIC_device_addr[chip_num], 41, 0x00);

    // PGA_L is routed to HPLOUT
    tlv320aic31_write(IIC_device_addr[chip_num], 46, 0x00);
    // DAC_L1 is routed to HPLOUT
    tlv320aic31_write(IIC_device_addr[chip_num], 47, 0x80);
    // PGA_R is routed to HPLOUT
    tlv320aic31_write(IIC_device_addr[chip_num], 49, 0x00);
    // DAC_R1 is routed to HPLOUT
    tlv320aic31_write(IIC_device_addr[chip_num], 50, 0x00);
    // HPLOUT is not muted, HPLOUT is fully powered up
    tlv320aic31_write(IIC_device_addr[chip_num], 51, 0x0f);

    // PGA_L is routed to HPLCOM.
    tlv320aic31_write(IIC_device_addr[chip_num], 53, 0x00);
    // DAC_L1 is routed to HPLCOM
    tlv320aic31_write(IIC_device_addr[chip_num], 54, 0x80);
    // PGA_R is routed to HPLCOM
    tlv320aic31_write(IIC_device_addr[chip_num], 56, 0x00);
    // DAC_R1 is routed to HPLCOM
    tlv320aic31_write(IIC_device_addr[chip_num], 57, 0x00);
    // HPLCOM is not muted, HPLCOM is fully powered up
    tlv320aic31_write(IIC_device_addr[chip_num], 58, 0x0f);

    // PGA_L is routed to HPROUT
    tlv320aic31_write(IIC_device_addr[chip_num], 60, 0x00);
    // DAC_L1 is routed to HPROUT
    tlv320aic31_write(IIC_device_addr[chip_num], 61, 0x80);
    // PGA_R is routed to HPROUT
    tlv320aic31_write(IIC_device_addr[chip_num], 63, 0x00);
    // DAC_R1 is routed to HPROUT
    tlv320aic31_write(IIC_device_addr[chip_num], 64, 0x00);
    // HPROUT is not muted, HPROUT is fully powered up
    tlv320aic31_write(IIC_device_addr[chip_num], 65, 0x0f);

    // PGA_L is routed to HPRCOM
    tlv320aic31_write(IIC_device_addr[chip_num], 67, 0x00);
    // DAC_L1 is routed to HPRCOM
    tlv320aic31_write(IIC_device_addr[chip_num], 68, 0x80);
    // PGA_R is routed to HPRCOM
    tlv320aic31_write(IIC_device_addr[chip_num], 70, 0x00);
    // DAC_R1 is routed to HPRCOM
    tlv320aic31_write(IIC_device_addr[chip_num], 71, 0x00);
    // HPRCOM is not muted, HPRCOM is fully powered up
    tlv320aic31_write(IIC_device_addr[chip_num], 72, 0x0f);  

    // The left-DAC channel is not muted.
    tlv320aic31_write(IIC_device_addr[chip_num], 43, 0x00);

    // The right-DAC channel is not muted
    tlv320aic31_write(IIC_device_addr[chip_num], 44, 0x00);
}

/*
 *	device open. set counter
 */
static int tlv320aic31_open(struct inode* inode, struct file* file)
{
   
    if (0 == open_cnt++)
    {
   
        return 0;
    }
    return -1 ;
}

/*
 *	Close device, Do nothing!
 */
static int tlv320aic31_close(struct inode* inode , struct file* file)
{
   
    open_cnt--;
    return 0;
}

//static int tlv320aic31_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
static long tlv320aic31_ioctl(struct file* file, unsigned int cmd, unsigned long arg)
{
   
    unsigned int __user* argp = (unsigned int __user*)arg;
    unsigned int chip_num;
    Audio_Ctrl temp;
    Audio_Ctrl* audio_ctrl;
    Codec_Datapath_Setup_Ctrl codec_datapath_setup_ctrl;
    DAC_OUTPUT_SWIT_CTRL dac_output_swit_ctrl;
    DAC_POWER_CTRL dac_power_ctrl;
    In1_Adc_Ctrl in1_adc_ctrl ;
    In2_Adc_Ctrl_Sample in2_adc_ctrl_sample ;
    Adc_Pga_Dac_Gain_Ctrl adc_pga_dac_gain_ctrl;
    Line_Hpcom_Out_Ctrl line_hpcom_out_ctrl;
    Serial_Int_Ctrl serial_int_ctrl;
    Serial_Data_Offset_Ctrl serial_data_offset_ctrl;
    Ctrl_Mode ctrl_mode;

    if (argp != NULL)
    {
   
        if (copy_from_user(&temp, argp, sizeof(Audio_Ctrl)))
        {
   
            return -EFAULT;
        }
    }
    audio_ctrl = (Audio_Ctrl*)(&temp);
    chip_num = audio_ctrl->chip_num;
    switch (cmd)
    {
   
        case IN2LR_2_LEFT_ADC_CTRL:
            in2_adc_ctrl_sample.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 17);
            in2_adc_ctrl_sample.bit.in2l_adc_input_level_sample = audio_ctrl->input_level;
            tlv320aic31_write(IIC_device_addr[chip_num], 17, in2_adc_ctrl_sample.b8);
            break;
        case IN2LR_2_RIGTH_ADC_CTRL:
            in2_adc_ctrl_sample.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 18);
            in2_adc_ctrl_sample.bit.in2r_adc_input_level_sample = audio_ctrl->input_level;
            tlv320aic31_write(IIC_device_addr[chip_num], 18, in2_adc_ctrl_sample.b8);

            break;
        case IN1L_2_LEFT_ADC_CTRL:
            in1_adc_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 19);
            in1_adc_ctrl.bit.in1_adc_input_level = audio_ctrl->input_level;
            in1_adc_ctrl.bit.adc_ch_power_ctrl = audio_ctrl->if_powerup;
            tlv320aic31_write(IIC_device_addr[chip_num], 19, in1_adc_ctrl.b8);
            break;
        case IN1R_2_RIGHT_ADC_CTRL:
            in1_adc_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 22);
            in1_adc_ctrl.bit.in1_adc_input_level = audio_ctrl->input_level;
            in1_adc_ctrl.bit.adc_ch_power_ctrl = audio_ctrl->if_powerup;
            tlv320aic31_write(IIC_device_addr[chip_num], 22, in1_adc_ctrl.b8);
            break;
        case PGAL_2_HPLOUT_VOL_CTRL:
            adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 46);
            adc_pga_dac_gain_ctrl.bit.if_mute_route = audio_ctrl->if_mute_route;
            adc_pga_dac_gain_ctrl.bit.input_vol_level_ctrl = audio_ctrl->input_level;
            tlv320aic31_write(IIC_device_addr
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值