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

it2025-11-20  17

前言

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

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

下载连接

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

硬件连接

左边是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[chip_num], 46, adc_pga_dac_gain_ctrl.b8); break; case DACL1_2_HPLOUT_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 47); 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[chip_num], 47, adc_pga_dac_gain_ctrl.b8); break; case HPLOUT_OUTPUT_LEVEL_CTRL: line_hpcom_out_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 51); line_hpcom_out_ctrl.bit.if_mute = audio_ctrl->if_mute_route; line_hpcom_out_ctrl.bit.output_level = audio_ctrl->input_level; line_hpcom_out_ctrl.bit.power_status = audio_ctrl->if_powerup; tlv320aic31_write(IIC_device_addr[chip_num], 51, line_hpcom_out_ctrl.b8); break; case PGAL_2_HPLCOM_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 53); 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[chip_num], 53, adc_pga_dac_gain_ctrl.b8); break; case DACL1_2_HPLCOM_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 54); 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[chip_num], 54, adc_pga_dac_gain_ctrl.b8); break; case HPLCOM_OUTPUT_LEVEL_CTRL: line_hpcom_out_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 58); line_hpcom_out_ctrl.bit.if_mute = audio_ctrl->if_mute_route; line_hpcom_out_ctrl.bit.output_level = audio_ctrl->input_level; tlv320aic31_write(IIC_device_addr[chip_num], 58, line_hpcom_out_ctrl.b8); break; case PGAR_2_HPROUT_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 63); 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[chip_num], 63, adc_pga_dac_gain_ctrl.b8); break; case DACR1_2_HPROUT_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 64); 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[chip_num], 64, adc_pga_dac_gain_ctrl.b8); break; case HPROUT_OUTPUT_LEVEL_CTRL: line_hpcom_out_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 65); line_hpcom_out_ctrl.bit.if_mute = audio_ctrl->if_mute_route; line_hpcom_out_ctrl.bit.output_level = audio_ctrl->input_level; line_hpcom_out_ctrl.bit.power_status = audio_ctrl->if_powerup; tlv320aic31_write(IIC_device_addr[chip_num], 65, line_hpcom_out_ctrl.b8); break; case PGAR_2_HPRCOM_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 70); 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[chip_num], 70, adc_pga_dac_gain_ctrl.b8); break; case DACR1_2_HPRCOM_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 71); 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[chip_num], 71, adc_pga_dac_gain_ctrl.b8); break; case HPRCOM_OUTPUT_LEVEL_CTRL: line_hpcom_out_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 72); line_hpcom_out_ctrl.bit.if_mute = audio_ctrl->if_mute_route; line_hpcom_out_ctrl.bit.output_level = audio_ctrl->input_level; tlv320aic31_write(IIC_device_addr[chip_num], 72, line_hpcom_out_ctrl.b8); break; case PGAL_2_LEFT_LOP_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 81); 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[chip_num], 81, adc_pga_dac_gain_ctrl.b8); break; case DACL1_2_LEFT_LOP_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 82); 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[chip_num], 82, adc_pga_dac_gain_ctrl.b8); break; case LEFT_LOP_OUTPUT_LEVEL_CTRL: line_hpcom_out_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 86); line_hpcom_out_ctrl.bit.if_mute = audio_ctrl->if_mute_route; line_hpcom_out_ctrl.bit.output_level = audio_ctrl->input_level; line_hpcom_out_ctrl.bit.power_status = audio_ctrl->if_powerup; tlv320aic31_write(IIC_device_addr[chip_num], 86, line_hpcom_out_ctrl.b8); break; case PGAR_2_RIGHT_LOP_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 91); 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[chip_num], 91, adc_pga_dac_gain_ctrl.b8); break; case DACR1_2_RIGHT_LOP_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 92); 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[chip_num], 92, adc_pga_dac_gain_ctrl.b8); break; case RIGHT_LOP_OUTPUT_LEVEL_CTRL: line_hpcom_out_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 93); line_hpcom_out_ctrl.bit.if_mute = audio_ctrl->if_mute_route; line_hpcom_out_ctrl.bit.output_level = audio_ctrl->input_level; line_hpcom_out_ctrl.bit.power_status = audio_ctrl->if_powerup; tlv320aic31_write(IIC_device_addr[chip_num], 93, line_hpcom_out_ctrl.b8); break; case DACL1_2_HPROUT_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 61); 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[chip_num], 61, adc_pga_dac_gain_ctrl.b8); break; case DACL1_2_HPRCOM_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 68); 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[chip_num], 68, adc_pga_dac_gain_ctrl.b8); break; case SET_ADC_SAMPLE: in2_adc_ctrl_sample.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 2); in2_adc_ctrl_sample.bit.in2l_adc_input_level_sample = audio_ctrl->sample; tlv320aic31_write(IIC_device_addr[chip_num], 2, in2_adc_ctrl_sample.b8); break; case SET_DAC_SAMPLE: in2_adc_ctrl_sample.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 2); in2_adc_ctrl_sample.bit.in2r_adc_input_level_sample = audio_ctrl->sample; tlv320aic31_write(IIC_device_addr[chip_num], 2, in2_adc_ctrl_sample.b8); //printk("set SET_DAC_SAMPLE,audio_ctrl->sample=%x\n",audio_ctrl->sample); break; case SET_DATA_LENGTH: serial_int_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 9);; serial_int_ctrl.bit.data_length = audio_ctrl->data_length; //tlv320aic31_write(IIC_device_addr[chip_num],9,serial_int_ctrl.b8); break; case SET_TRANSFER_MODE: serial_int_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 9); serial_int_ctrl.bit.transfer_mode = audio_ctrl->trans_mode; tlv320aic31_write(IIC_device_addr[chip_num], 9, serial_int_ctrl.b8); break; case SET_CTRL_MODE: //tlv320aic31_write(IIC_device_addr[chip_num],0x1,0x80); //udelay(50); ctrl_mode.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 8); ctrl_mode.bit.bit_clock_dic_ctrl = audio_ctrl->ctrl_mode; ctrl_mode.bit.work_clock_dic_ctrl = audio_ctrl->ctrl_mode; ctrl_mode.bit.bit_work_dri_ctrl = audio_ctrl->ctrl_mode; tlv320aic31_write(IIC_device_addr[chip_num], 8, ctrl_mode.b8); #if 0 /* clock config */ if (1 == audio_ctrl->ctrl_mode || (AC31_SET_48K_SAMPLERATE != audio_ctrl->sample && AC31_SET_44_1K_SAMPLERATE != audio_ctrl->sample)) { /* aic31 as master or sampling rate is not 44.1K/48KHZ, use external 12.288MHz as MCLK input */ if ((1 == audio_ctrl->if_44100hz_series)) { /* 44.1K series sampling rate */ tlv320aic31_write(IIC_device_addr[chip_num], 3, 0x81); /* P=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 4, 0x1c); /* J=7 */ tlv320aic31_write(IIC_device_addr[chip_num], 5, 0x36); /* reg 5 and 6 set D=3500*/ tlv320aic31_write(IIC_device_addr[chip_num], 6, 0xb0); codec_datapath_setup_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 7); codec_datapath_setup_ctrl.b8 |= 0x80; /* FSref = 44.1 kHz */ tlv320aic31_write(IIC_device_addr[chip_num], 7, codec_datapath_setup_ctrl.b8); tlv320aic31_write(IIC_device_addr[chip_num], 11, 0x1); /* R=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 101, 0x0); tlv320aic31_write(IIC_device_addr[chip_num], 102, 0xc2); } else { /* not 44.1K series sampling rate */ tlv320aic31_write(IIC_device_addr[chip_num], 3, 0x81); /* P=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 4, 0x20); /* J=8 */ tlv320aic31_write(IIC_device_addr[chip_num], 5, 0x0); /* reg 5 and 6 set D=0000*/ tlv320aic31_write(IIC_device_addr[chip_num], 6, 0x0); codec_datapath_setup_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 7); codec_datapath_setup_ctrl.b8 &= 0x7f; /* FSref = 48 kHz */ tlv320aic31_write(IIC_device_addr[chip_num], 7, codec_datapath_setup_ctrl.b8); tlv320aic31_write(IIC_device_addr[chip_num], 11, 0x1); /* R=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 101, 0x0); tlv320aic31_write(IIC_device_addr[chip_num], 102, 0xc2); } } else { /* aic31 as slave, and sampling rate is 44.1K/48KHZ, BCLK as MCLK */ tlv320aic31_write(IIC_device_addr[chip_num], 102, 0x22); /* uses PLLCLK and BCLK */ codec_datapath_setup_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 7); if ((1 == audio_ctrl->if_44100hz_series)) { codec_datapath_setup_ctrl.b8 |= 0x80; /* FSref = 44.1 kHz */ } else { codec_datapath_setup_ctrl.b8 &= 0x7f; /* FSref = 48 kHz */ } tlv320aic31_write(IIC_device_addr[chip_num], 7, codec_datapath_setup_ctrl.b8); tlv320aic31_write(IIC_device_addr[chip_num], 3, 0x81); /* P=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 4, 32 << 2); /* set PLL J to 32 */ tlv320aic31_write(IIC_device_addr[chip_num], 5, 0x0); /* reg 5 and 6 set D=0000*/ tlv320aic31_write(IIC_device_addr[chip_num], 6, 0x0); tlv320aic31_write(IIC_device_addr[chip_num], 101, 0x0); /* CODEC_CLKIN uses PLLDIV_OUT */ tlv320aic31_write(IIC_device_addr[chip_num], 11, 0x2); /* R = 2 */ } #else /* clock config */ /* aic31, aiao mclk */ switch (audio_ctrl->sampleRate) { case 8000: case 16000: case 32000: { /* 32K series sampling rate */ tlv320aic31_write(IIC_device_addr[chip_num], 3, 0x81); /* P=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 4, 0x30); /* J=12 */ tlv320aic31_write(IIC_device_addr[chip_num], 5, 0x0); /* reg 5 and 6 set D=0000*/ tlv320aic31_write(IIC_device_addr[chip_num], 6, 0x0); codec_datapath_setup_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 7); codec_datapath_setup_ctrl.b8 &= 0x7f; /* FSref = 48 kHz */ tlv320aic31_write(IIC_device_addr[chip_num], 7, codec_datapath_setup_ctrl.b8); tlv320aic31_write(IIC_device_addr[chip_num], 11, 0x1); /* R=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 101, 0x0); tlv320aic31_write(IIC_device_addr[chip_num], 102, 0xc2); } break; case 12000: case 24000: case 48000: { /* 48K series sampling rate */ tlv320aic31_write(IIC_device_addr[chip_num], 3, 0x81); /* P=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 4, 0x20); /* J=8 */ tlv320aic31_write(IIC_device_addr[chip_num], 5, 0x0); /* reg 5 and 6 set D=0000*/ tlv320aic31_write(IIC_device_addr[chip_num], 6, 0x0); codec_datapath_setup_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 7); codec_datapath_setup_ctrl.b8 &= 0x7f; /* FSref = 48 kHz */ tlv320aic31_write(IIC_device_addr[chip_num], 7, codec_datapath_setup_ctrl.b8); tlv320aic31_write(IIC_device_addr[chip_num], 11, 0x1); /* R=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 101, 0x0); tlv320aic31_write(IIC_device_addr[chip_num], 102, 0xc2); } break; case 11025: case 22050: case 44100: { /* 44.1K series sampling rate */ tlv320aic31_write(IIC_device_addr[chip_num], 3, 0x81); /* P=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 4, 0x20); /* J=7 */ tlv320aic31_write(IIC_device_addr[chip_num], 5, 0x00); /* reg 5 and 6 set D=0000*/ tlv320aic31_write(IIC_device_addr[chip_num], 6, 0x00); codec_datapath_setup_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 7); codec_datapath_setup_ctrl.b8 |= 0x80; /* FSref = 44.1 kHz */ tlv320aic31_write(IIC_device_addr[chip_num], 7, codec_datapath_setup_ctrl.b8); tlv320aic31_write(IIC_device_addr[chip_num], 11, 0x1); /* R=1 */ tlv320aic31_write(IIC_device_addr[chip_num], 101, 0x0); tlv320aic31_write(IIC_device_addr[chip_num], 102, 0xc2); } break; default: printk("aic31 unsupport sampleRate %d\n", audio_ctrl->sampleRate); return -1; } #endif break; case LEFT_DAC_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 43); 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[chip_num], 43, adc_pga_dac_gain_ctrl.b8); break; case RIGHT_DAC_VOL_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 44); 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[chip_num], 44, adc_pga_dac_gain_ctrl.b8); break; case LEFT_DAC_POWER_SETUP: codec_datapath_setup_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 7); codec_datapath_setup_ctrl.bit.left_dac_datapath_ctrl = audio_ctrl->if_powerup; tlv320aic31_write(IIC_device_addr[chip_num], 7, codec_datapath_setup_ctrl.b8); dac_power_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 37); dac_power_ctrl.bit.left_dac_power_ctrl = audio_ctrl->if_powerup; tlv320aic31_write(IIC_device_addr[chip_num], 37, dac_power_ctrl.b8); break; case RIGHT_DAC_POWER_SETUP: codec_datapath_setup_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 7); codec_datapath_setup_ctrl.bit.right_dac_datapath_ctrl = audio_ctrl->if_powerup; tlv320aic31_write(IIC_device_addr[chip_num], 7, codec_datapath_setup_ctrl.b8); dac_power_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 37); dac_power_ctrl.bit.right_dac_power_ctrl = audio_ctrl->if_powerup; tlv320aic31_write(IIC_device_addr[chip_num], 37, dac_power_ctrl.b8); break; case DAC_OUT_SWITCH_CTRL: dac_output_swit_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 41); dac_output_swit_ctrl.bit.left_dac_swi_ctrl = audio_ctrl->dac_path; dac_output_swit_ctrl.bit.right_dac_swi_ctrl = audio_ctrl->dac_path; tlv320aic31_write(IIC_device_addr[chip_num], 41, dac_output_swit_ctrl.b8); break; case LEFT_ADC_PGA_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 15); 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[chip_num], 15, adc_pga_dac_gain_ctrl.b8); break; case RIGHT_ADC_PGA_CTRL: adc_pga_dac_gain_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 16); 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[chip_num], 16, adc_pga_dac_gain_ctrl.b8); break; case SET_SERIAL_DATA_OFFSET: serial_data_offset_ctrl.b8 = tlv320aic31_read(IIC_device_addr[chip_num], 10); serial_data_offset_ctrl.bit.serial_data_offset = audio_ctrl->data_offset; tlv320aic31_write(IIC_device_addr[chip_num], 10, serial_data_offset_ctrl.b8); break; case SOFT_RESET: //printk("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "invalid attribute"); soft_reset(chip_num); break; case TLV320AIC31_REG_DUMP: tlv320aic31_reg_dump(102); break; default: break; } return 0; } #ifdef CONFIG_HISI_SNAPSHOT_BOOT static int tlv320aic31_freeze(struct himedia_device* pdev) { printk(KERN_ALERT "%s %d\n", __FUNCTION__, __LINE__); return 0; } static int tlv320aic31_restore(struct himedia_device* pdev) { int i; for (i = 0; i < chip_count; i++) { if (tlv320aic31_device_init(i) < 0) { printk(KERN_ALERT "%s %d, tlv320aic31 device init fail!\n", __FUNCTION__, __LINE__); return -1; } } printk(KERN_ALERT "%s %d\n", __FUNCTION__, __LINE__); return 0; } #endif /* * The various file operations we support. */ static struct file_operations tlv320aic31_fops = { .owner = THIS_MODULE, .unlocked_ioctl = tlv320aic31_ioctl, .open = tlv320aic31_open, .release = tlv320aic31_close }; #ifdef CONFIG_HISI_SNAPSHOT_BOOT struct himedia_ops stTlv320aic31DrvOps = { .pm_freeze = tlv320aic31_freeze, .pm_restore = tlv320aic31_restore }; #else static struct miscdevice tlv320aic31_dev = { MISC_DYNAMIC_MINOR, DEV_NAME, &tlv320aic31_fops, }; #endif static int set_chip_count(const char* val, const struct kernel_param* kp) { int ret; int chip_count; ret = kstrtoint(val, 10, &chip_count); if (ret < 0) { return -EINVAL; } if (chip_count < 0 || chip_count > CHIP_NUM) { printk("chip_count%d err. \n", chip_count); return -EINVAL; } return 0; } static struct kernel_param_ops alv320_para_ops = { .set = set_chip_count, }; #if 0 module_param(chip_count, int, 0); #else module_param_cb(chip_count, &alv320_para_ops, &chip_count, 0644); #endif MODULE_PARM_DESC(chip_count, "the num we device uses the tlv320aic31,default 1"); static int tlv320aic31_reboot(struct notifier_block* self, unsigned long data, void* pdata) { unsigned int i; for (i = 0; i < chip_count; i++) { /* HPLOUT is mute */ tlv320aic31_write(IIC_device_addr[i], 51, 0x04); /* HPROUT is mute */ tlv320aic31_write(IIC_device_addr[i], 65, 0x04); } printk("Func:%s, line:%d######\n", __FUNCTION__, __LINE__); return 0; } static struct notifier_block tlv320aic31_reboot_notifier = { .notifier_call = tlv320aic31_reboot, }; static int tlv320aic31_device_init(unsigned int num) { /* inite codec configs.*/ unsigned char temp = 0; temp = tlv320aic31_read(IIC_device_addr[num], 0x2); tlv320aic31_write(IIC_device_addr[0], 0x2, 0xaa); if ( tlv320aic31_read(IIC_device_addr[num], 0x2) != 0xaa) { DPRINTK(0, "init aic31(%d) error", num); return -1; } tlv320aic31_write(IIC_device_addr[num], 0x2, temp); soft_reset(num); /* reboot_notifier */ register_reboot_notifier(&tlv320aic31_reboot_notifier); return 0; } static int tlv320aic31_device_exit(unsigned int num) { /* HPLOUT is mute */ tlv320aic31_write(IIC_device_addr[num], 51, 0x04); /* HPROUT is mute */ tlv320aic31_write(IIC_device_addr[num], 65, 0x04); return 0; } static int i2c_client_init(void) { struct i2c_adapter* i2c_adap; // tlv_aic31 use i2c0 i2c_adap = i2c_get_adapter(0); if (NULL == i2c_adap) { printk("find i2c adapter fail. \n"); return -1; } tlv_client = i2c_new_device(i2c_adap, &hi_info); i2c_put_adapter(i2c_adap); return 0; } static void i2c_client_exit(void) { i2c_unregister_device(tlv_client); } static int __init tlv320aic31_init(void) { unsigned int i, ret; #ifdef CONFIG_HISI_SNAPSHOT_BOOT snprintf(s_stTlv320aic31Device.devfs_name, sizeof(s_stTlv320aic31Device.devfs_name), DEV_NAME); s_stTlv320aic31Device.minor = HIMEDIA_DYNAMIC_MINOR; s_stTlv320aic31Device.fops = &tlv320aic31_fops; s_stTlv320aic31Device.drvops = &stTlv320aic31DrvOps; s_stTlv320aic31Device.owner = THIS_MODULE; ret = himedia_register(&s_stTlv320aic31Device); if (ret) { DPRINTK(0, "could not register tlv320aic31 device"); return -1; } #else ret = misc_register(&tlv320aic31_dev); if (ret) { DPRINTK(0, "could not register tlv320aic31 device"); return -1; } #endif i2c_client_init(); for (i = 0; i < chip_count; i++) { if (tlv320aic31_device_init(i) < 0) { goto init_fail; } } DPRINTK(1, "tlv320aic31 driver init successful!"); printk("load tlv320aic31.ko ok!\n"); return ret; init_fail: #ifdef CONFIG_HISI_SNAPSHOT_BOOT himedia_unregister(&s_stTlv320aic31Device); #else misc_deregister(&tlv320aic31_dev); #endif DPRINTK(0, "tlv320aic31 device init fail,deregister it!"); return -1; } static void __exit tlv320aic31_exit(void) { unsigned int i; for (i = 0; i < chip_count; i++) { tlv320aic31_device_exit(i); } unregister_reboot_notifier(&tlv320aic31_reboot_notifier); #ifdef CONFIG_HISI_SNAPSHOT_BOOT himedia_unregister(&s_stTlv320aic31Device); #else misc_deregister(&tlv320aic31_dev); #endif i2c_client_exit(); DPRINTK(1, "deregister tlv320aic31"); printk("rmmod tlv320aic31.ko ok!\n"); } module_init(tlv320aic31_init); module_exit(tlv320aic31_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Hisilicon");

sample 程序

主程序

/****************************************************************************** * function : Ai -> Ao ******************************************************************************/ extern SAMPLE_AI_S gs_stSampleAi[AI_DEV_MAX_NUM*AIO_MAX_CHN_NUM]; extern void *SAMPLE_COMM_AUDIO_AiProc_modby_glx(void *parg); HI_S32 SAMPLE_AUDIO_Aip2_Aop0(HI_VOID) { HI_S32 s32Ret, i; HI_S32 s32AiChnCnt; HI_S32 s32AoChnCnt; AUDIO_DEV AiDev = SAMPLE_AUDIO_TLV320_AI_DEV; AUDIO_DEV AoDev = SAMPLE_AUDIO_TLV320_AO_DEV; AI_CHN AiChn = 0; AO_CHN AoChn = 0; AIO_ATTR_S stAioAttr; stAioAttr.enSamplerate = AUDIO_SAMPLE_RATE_48000; stAioAttr.enBitwidth = AUDIO_BIT_WIDTH_16; //对于aic3254和aic3101主从均能正常工作 stAioAttr.enWorkmode = AIO_MODE_I2S_MASTER; //stAioAttr.enWorkmode = AIO_MODE_I2S_SLAVE; //使用mono两个单声道也可以播立体声,本例使用两个线程送数据,可能出现左右不同声现象 //一定要用的话,建议只开一个线程往两个通道送数据 //stAioAttr.enSoundmode = AUDIO_SOUND_MODE_MONO; stAioAttr.enSoundmode = AUDIO_SOUND_MODE_STEREO; stAioAttr.u32EXFlag = 1; //缓存不能太小,否则播放线程可能在特定时间拿不到数据,造成播放声音出现断续 stAioAttr.u32FrmNum = 300; stAioAttr.u32PtNumPerFrm = 320; //设置为STEREO时,通道一定要保证为偶数,如2 stAioAttr.u32ChnCnt = 2; stAioAttr.u32ClkChnCnt = 2; //16bit 扩展 stAioAttr.u32ClkSel = 1; /* config audio codec */ s32Ret = SAMPLE_COMM_AUDIO_CfgTlv320(&stAioAttr); if (HI_SUCCESS != s32Ret) { SAMPLE_DBG(s32Ret); return HI_FAILURE; } /* enable AI channle */ s32AiChnCnt = stAioAttr.u32ChnCnt >> stAioAttr.enSoundmode; g_u32AiCnt = s32AiChnCnt; g_u32AiDev = AiDev; s32Ret = HI_MPI_AI_SetPubAttr(AiDev, &stAioAttr); if (s32Ret) { printf("%s: HI_MPI_AI_SetPubAttr(%d) failed with %#x\n", __FUNCTION__, AiDev, s32Ret); return s32Ret; } s32Ret = HI_MPI_AI_Enable(AiDev); if (s32Ret) { printf("%s: HI_MPI_AI_Enable(%d) failed with %#x\n", __FUNCTION__, AiDev, s32Ret); return s32Ret; } for (i = 0; i < s32AiChnCnt; i++) { s32Ret = HI_MPI_AI_EnableChn(AiDev, i); if (s32Ret) { printf("%s: HI_MPI_AI_EnableChn(%d,%d) failed with %#x\n", __FUNCTION__, AiDev, i, s32Ret); return s32Ret; } } /* enable AO channle */ stAioAttr.u32ChnCnt = stAioAttr.u32ChnCnt>2 ? 2: stAioAttr.u32ChnCnt; s32AoChnCnt = stAioAttr.u32ChnCnt >> stAioAttr.enSoundmode; g_u32AoCnt = s32AoChnCnt; g_u32AoDev = AoDev; s32Ret = HI_MPI_AO_SetPubAttr(AoDev, &stAioAttr); if (HI_SUCCESS != s32Ret) { printf("%s: HI_MPI_AO_SetPubAttr(%d) failed with %#x!\n", __FUNCTION__, \ AoDev, s32Ret); return HI_FAILURE; } s32Ret = HI_MPI_AO_Enable(AoDev); if (HI_SUCCESS != s32Ret) { printf("%s: HI_MPI_AO_Enable(%d) failed with %#x!\n", __FUNCTION__, AoDev, s32Ret); return HI_FAILURE; } for (i = 0; i < s32AoChnCnt; i++) { s32Ret = HI_MPI_AO_EnableChn(AoDev, i); if (HI_SUCCESS != s32Ret) { printf("%s: HI_MPI_AO_EnableChn(%d) failed with %#x!\n", __FUNCTION__, i, s32Ret); return HI_FAILURE; } } /* create file for save frames*/ FILE *pfd[s32AoChnCnt]; for (i = 0; i < s32AoChnCnt; i++) { HI_CHAR aszFileName[128]; sprintf(aszFileName, "audio_chn%d.%s", i, SAMPLE_AUDIO_Pt2Str(PT_LPCM)); pfd[i] = fopen(aszFileName, "w+"); if (NULL == pfd) { printf("%s: open file %s failed\n", __FUNCTION__, aszFileName); return -1; } printf("open stream file:\"%s\" ok\n", aszFileName); } /* AI to AO channel */ for (i=0; i<g_u32AoCnt; i++) { AiChn = i; AoChn = i; SAMPLE_AI_S *pstAi = NULL; pstAi = &gs_stSampleAi[AiDev*AIO_MAX_CHN_NUM + AiChn]; pstAi->bSendAenc = HI_FALSE; pstAi->bSendAo = HI_TRUE; pstAi->bStart= HI_TRUE; pstAi->AiDev = AiDev; pstAi->AiChn = AiChn; pstAi->AoDev = AoDev; pstAi->AoChn = AoChn; pstAi->pfd = pfd[i]; pthread_create(&pstAi->stAiPid, 0, SAMPLE_COMM_AUDIO_AiProc_modby_glx, pstAi); if (s32Ret != HI_SUCCESS) { SAMPLE_DBG(s32Ret); return HI_FAILURE; } } printf("\nplease press twice ENTER to exit this sample\n"); getchar(); getchar(); for (i=0; i<g_u32AoCnt; i++) { AiChn = i; s32Ret = SAMPLE_COMM_AUDIO_DestoryTrdAi(AiDev, AiChn); if (s32Ret != HI_SUCCESS) { SAMPLE_DBG(s32Ret); return HI_FAILURE; } } s32Ret = SAMPLE_COMM_AUDIO_StopAi(AiDev, s32AiChnCnt, HI_FALSE, HI_FALSE); if (s32Ret != HI_SUCCESS) { SAMPLE_DBG(s32Ret); return HI_FAILURE; } s32Ret = SAMPLE_COMM_AUDIO_StopAo(AoDev, s32AoChnCnt, HI_TRUE, HI_FALSE); if (s32Ret != HI_SUCCESS) { SAMPLE_DBG(s32Ret); return HI_FAILURE; } return HI_SUCCESS; }

采集播放线程

/****************************************************************************** * function : get frame from Ai, send it to Ao, and save as lpcm ******************************************************************************/ void *SAMPLE_COMM_AUDIO_AiProc_modby_glx(void *parg) { HI_S32 s32Ret; HI_S32 AiFd; SAMPLE_AI_S *pstAiCtl = (SAMPLE_AI_S *)parg; AUDIO_FRAME_S stFrame; fd_set read_fds; struct timeval TimeoutVal; AI_CHN_PARAM_S stAiChnPara; prctl(PR_SET_NAME, "hi_SAMPLE_AiProc", 0, 0, 0); s32Ret = HI_MPI_AI_GetChnParam(pstAiCtl->AiDev, pstAiCtl->AiChn, &stAiChnPara); if (HI_SUCCESS != s32Ret) { printf("%s: Get ai chn param failed\n", __FUNCTION__); return NULL; } stAiChnPara.u32UsrFrmDepth = 30; s32Ret = HI_MPI_AI_SetChnParam(pstAiCtl->AiDev, pstAiCtl->AiChn, &stAiChnPara); if (HI_SUCCESS != s32Ret) { printf("%s: set ai chn param failed\n", __FUNCTION__); return NULL; } FD_ZERO(&read_fds); AiFd = HI_MPI_AI_GetFd(pstAiCtl->AiDev, pstAiCtl->AiChn); FD_SET(AiFd,&read_fds); while (pstAiCtl->bStart) { TimeoutVal.tv_sec = 1; TimeoutVal.tv_usec = 0; FD_ZERO(&read_fds); FD_SET(AiFd,&read_fds); s32Ret = select(AiFd+1, &read_fds, NULL, NULL, &TimeoutVal); if (s32Ret < 0) { break; } else if (0 == s32Ret) { printf("%s: get ai frame select time out\n", __FUNCTION__); break; } if (FD_ISSET(AiFd, &read_fds)) { /* get frame from ai chn */ s32Ret = HI_MPI_AI_GetFrame(pstAiCtl->AiDev, pstAiCtl->AiChn, &stFrame, NULL, HI_FALSE); if (HI_SUCCESS != s32Ret ) { printf("%s: HI_MPI_AI_GetFrame(%d, %d), failed with %#x!\n",\ __FUNCTION__, pstAiCtl->AiDev, pstAiCtl->AiChn, s32Ret); pstAiCtl->bStart = HI_FALSE; return NULL; } /* send frame to ao */ if (HI_TRUE == pstAiCtl->bSendAo) { s32Ret = HI_MPI_AO_SendFrame(pstAiCtl->AoDev, pstAiCtl->AoChn, &stFrame, 1000); if (HI_SUCCESS != s32Ret ) { printf("%s: HI_MPI_AO_SendFrame(%d, %d), failed with %#x!\n",\ __FUNCTION__, pstAiCtl->AoDev, pstAiCtl->AoChn, s32Ret); pstAiCtl->bStart = HI_FALSE; return NULL; } } /* 注意,无论是fwrite 还是 write, 都带缓存或者预写机制 缓存满时将一次性写入硬盘或FLASH,这一次耗时将会很长,将导致此线程阻塞,音频输出卡顿 */ /* save origin pcm frame to file */ //fwrite(stFrame.pVirAddr[0],1,stFrame.u32Len, pstAiCtl->pfd); /* finally you must release the stream */ s32Ret = HI_MPI_AI_ReleaseFrame(pstAiCtl->AiDev, pstAiCtl->AiChn, &stFrame, NULL); if (HI_SUCCESS != s32Ret ) { printf("%s: HI_MPI_AI_ReleaseFrame(%d, %d), failed with %#x!\n",\ __FUNCTION__, pstAiCtl->AiDev, pstAiCtl->AiChn, s32Ret); pstAiCtl->bStart = HI_FALSE; return NULL; } } } pstAiCtl->bStart = HI_FALSE; fclose(pstAiCtl->pfd); return NULL; }

声卡配置

HI_S32 SAMPLE_Tlv320_CfgAudio(AIO_ATTR_S *pstAioAttr) { /* 重要:执行此codec配置程序,需要先确保codec驱动程序已经正常加载 */ /* 如果需要切换codec 1. 需要修改 mpp/sample/Makefile.param中的ACODEC_TYPE后, make clean, 重新编译此程序 2. 需要重新加载对应的驱动 2.1 先卸载之前用的codec驱动 rmmod tlv320aic31 rmmod tlv320aic32x4 2.2 如果选择aic3254 insmod /komod/extdrv/tlv320aic32x4.ko 2.3 如果选择aic3101 insmod /komod/extdrv/tlv320aic31.ko 2.4 选择性修改开机脚本 vi /komod/load3531d 此脚本中 insert_audio 和 remove_audio 函数,执行了驱动的加载与卸载 此脚本文件开机后会在/etc/init.d/rcS中运行 */ AIO_MODE_E enWorkmode = pstAioAttr->enWorkmode; AUDIO_SAMPLE_RATE_E enSample = pstAioAttr->enSamplerate; #if (defined HI_ACODEC_TYPE_TLV320AIC31) HI_S32 s32Samplerate; Audio_Ctrl audio_ctrl; int s_fdTlv = -1; HI_BOOL bPCMmode = HI_FALSE; HI_BOOL bMaster = HI_FALSE; /* if true, set tlv320aic3101 as master mode*/ HI_BOOL b44100HzSeries = HI_FALSE; printf("config TLV320AIC31\n"); if (AUDIO_SAMPLE_RATE_8000 == enSample) { s32Samplerate = AC31_SET_8K_SAMPLERATE; } else if (AUDIO_SAMPLE_RATE_12000 == enSample) { s32Samplerate = AC31_SET_12K_SAMPLERATE; } else if (AUDIO_SAMPLE_RATE_11025 == enSample) { b44100HzSeries = HI_TRUE; s32Samplerate = AC31_SET_11_025K_SAMPLERATE; } else if (AUDIO_SAMPLE_RATE_16000 == enSample) { s32Samplerate = AC31_SET_16K_SAMPLERATE; } else if (AUDIO_SAMPLE_RATE_22050 == enSample) { b44100HzSeries = HI_TRUE; s32Samplerate = AC31_SET_22_05K_SAMPLERATE; } else if (AUDIO_SAMPLE_RATE_24000 == enSample) { s32Samplerate = AC31_SET_24K_SAMPLERATE; } else if (AUDIO_SAMPLE_RATE_32000 == enSample) { s32Samplerate = AC31_SET_32K_SAMPLERATE; } else if (AUDIO_SAMPLE_RATE_44100 == enSample) { b44100HzSeries = HI_TRUE; s32Samplerate = AC31_SET_44_1K_SAMPLERATE; } else if (AUDIO_SAMPLE_RATE_48000 == enSample) { s32Samplerate = AC31_SET_48K_SAMPLERATE; } else { printf("SAMPLE_Tlv320_CfgAudio(), not support enSample:%d\n",enSample); return -1; } if(AIO_MODE_I2S_MASTER == enWorkmode) { bPCMmode = HI_FALSE; bMaster = HI_FALSE; } else if(AIO_MODE_I2S_SLAVE == enWorkmode) { bPCMmode = HI_FALSE; bMaster = HI_TRUE; } else if((AIO_MODE_PCM_MASTER_NSTD == enWorkmode)||(AIO_MODE_PCM_MASTER_STD == enWorkmode)) { bPCMmode = HI_TRUE; bMaster = HI_FALSE; } else if((AIO_MODE_PCM_SLAVE_NSTD == enWorkmode)||(AIO_MODE_PCM_SLAVE_STD == enWorkmode)) { bPCMmode = HI_TRUE; bMaster = HI_TRUE; } else { printf("SAMPLE_Tlv320_CfgAudio(), not support workmode:%d\n\n",enWorkmode); } s_fdTlv = open(TLV320_FILE,O_RDWR); if (s_fdTlv < 0) { printf("can't open codec device, %s\n", TLV320_FILE); return -1; } // 重置codec, 并按默认方式初始化 audio_ctrl.chip_num = 0; if (ioctl(s_fdTlv,SOFT_RESET,&audio_ctrl)) { printf("tlv320aic31 SOFT_RESET error\n"); close(s_fdTlv); return -1; } // 设置主从模式, 音频采样率 audio_ctrl.ctrl_mode = bMaster; audio_ctrl.sampleRate = enSample; audio_ctrl.if_44100hz_series = b44100HzSeries; if (ioctl(s_fdTlv,SET_CTRL_MODE,&audio_ctrl)) { printf("tlv320aic31 SET_CTRL_MODE error\n"); close(s_fdTlv); return -1; } // 数据传输方式为 I2S, 目前不支持其它方式 audio_ctrl.trans_mode = bPCMmode; if (ioctl(s_fdTlv, SET_TRANSFER_MODE, &audio_ctrl)) { printf("tlv320aic31 SET_CTRL_MODE error\n"); close(s_fdTlv); return -1; } // 设置ADC和DAC采样率 audio_ctrl.sample = s32Samplerate; if (ioctl(s_fdTlv, SET_DAC_SAMPLE, &audio_ctrl)) { printf("tlv320aic31 SET_DAC_SAMPLE error\n"); close(s_fdTlv); return -1; } if (ioctl(s_fdTlv, SET_ADC_SAMPLE, &audio_ctrl)) { printf("tlv320aic31 SET_ADC_SAMPLE error\n"); close(s_fdTlv); return -1; } // DAC enable audio_ctrl.if_powerup = 1; if (ioctl(s_fdTlv, LEFT_DAC_POWER_SETUP, &audio_ctrl)) { printf("tlv320aic31 LEFT_DAC_POWER_SETUP error\n"); close(s_fdTlv); return -1; } if (ioctl(s_fdTlv, RIGHT_DAC_POWER_SETUP, &audio_ctrl)) { printf("tlv320aic31 RIGHT_DAC_POWER_SETUP error\n"); close(s_fdTlv); return -1; } // 播放总音量(DAC音量) audio_ctrl.if_mute_route = 0; //1 - mute, 0 - not mute audio_ctrl.input_level = 0; //参数范围:0-127, 对应于0dB ~ -63.5dB, 注意给的值越大,声音越小 if (ioctl(s_fdTlv, LEFT_DAC_VOL_CTRL, &audio_ctrl)) { printf("tlv320aic31 LEFT_DAC_VOL_CTRL error\n"); close(s_fdTlv); return -1; } if (ioctl(s_fdTlv, RIGHT_DAC_VOL_CTRL, &audio_ctrl)) { printf("tlv320aic31 RIGHT_DAC_VOL_CTRL error\n"); close(s_fdTlv); return -1; } //凤凰端子 接口 播放设置:静音、音量、使能 audio_ctrl.if_mute_route = 1; //1 - not mute, 0 - power up audio_ctrl.input_level = 9; //参数范围 : 0 ~ 9, means 0-9dB audio_ctrl.if_powerup = 1; //1 - power up, 0 - power down if (ioctl(s_fdTlv, HPLOUT_OUTPUT_LEVEL_CTRL, &audio_ctrl)) { printf("tlv320aic31 HPLOUT_OUTPUT_LEVEL_CTRL error\n"); close(s_fdTlv); return -1; } if (ioctl(s_fdTlv, HPLCOM_OUTPUT_LEVEL_CTRL, &audio_ctrl)) { printf("tlv320aic31 HPLCOM_OUTPUT_LEVEL_CTRL error\n"); close(s_fdTlv); return -1; } //3.5mm 接口 播放设置:静音、音量、使能 audio_ctrl.if_mute_route = 1; //1 - not mute, 0 - power up audio_ctrl.input_level = 9; //参数范围 : 0 ~ 9, means 0-9dB audio_ctrl.if_powerup = 1; //1 - power up, 0 - power down if (ioctl(s_fdTlv, HPROUT_OUTPUT_LEVEL_CTRL, &audio_ctrl)) { printf("tlv320aic31 HPROUT_OUTPUT_LEVEL_CTRL error\n"); close(s_fdTlv); return -1; } if (ioctl(s_fdTlv, HPRCOM_OUTPUT_LEVEL_CTRL, &audio_ctrl)) { printf("tlv320aic31 HPRCOM_OUTPUT_LEVEL_CTRL error\n"); close(s_fdTlv); return -1; } /* 关于AIC3101 目前硬件上有点特殊情况, 此处做了对应处理 这个codec有6个输入端口,其中LINE2L和LINE2R,目前连接的是3.5mm接口,它们的连接方式只能是单端,不支持差分方式 单端就是,传输模拟音频只需要两根线,一根信号线,一根地线 另外4个端口,是可以配置为全差分的连接方式 全差分就是,左右声道需要4根线传输模拟音频,一个声道两根线,音频信号是两根线上电压的差值 其中LINE1LP和LINE1RP是支持配置为单端模式的,但是LINE1LM和LINE1RM是只支持差分方式 目前硬件的连接是LINE1LP和LINE1LM接到凤凰端子,LINE1RP和LINE1RM保留接口(目前没焊) 凤凰端子一般输入的是左右声道的信号,并不是麦克风的那种差分信号 因为LINE1LM不能配置为单端,所以音频输入只接凤凰端子的情况下,只有左声道是正常声音,右声道是噪音 考虑到这种情况,目前的处理是将左声道的声音,连接到输出端口的左右声道上,保证输出正常的立体声,丢弃输入的右声道数据 */ /* LINE2L(3.5mm) ---> left ADC \ /-----> left DAC ---> HPLOUT / HPROUT LINE1LP(凤凰端子) ---> left ADC ----------> LINE1RP(预留) ---> left ADC / \-----> right DAC ---> HPLCOM / HPRCOM LINE2R(3.5mm) ---> right ADC |* 从此处断掉 LINE1LM(凤凰端子) ---> right ADC |* 从此处断掉 LINE1RM(预留) ---> right ADC |* 从此处断掉 图中HPLOUT和HPLCOM是凤凰端子的输出口,HPROUT和HPRCOM是3.5mm的输出口 */ close(s_fdTlv); printf("Set aic31 ok: bMaster = %d, enWorkmode = %d, enSamplerate = %d\n", bMaster, enWorkmode, enSample); #elif (defined HI_ACODEC_TYPE_TLV320AIC32x4) int s_fdTlv = -1; Audio_Ctrl audio_ctrl; printf("config TLV320AIC32x4\n"); if (AUDIO_SAMPLE_RATE_8000 == enSample) { audio_ctrl.interface.sample_rate = AIC32x4_SAMPLE_RATE_8K; } else if (AUDIO_SAMPLE_RATE_12000 == enSample) { audio_ctrl.interface.sample_rate = AIC32x4_SAMPLE_RATE_12K; } else if (AUDIO_SAMPLE_RATE_11025 == enSample) { audio_ctrl.interface.sample_rate = AIC32x4_SAMPLE_RATE_11K; } else if (AUDIO_SAMPLE_RATE_16000 == enSample) { audio_ctrl.interface.sample_rate = AIC32x4_SAMPLE_RATE_16K; } else if (AUDIO_SAMPLE_RATE_22050 == enSample) { audio_ctrl.interface.sample_rate = AIC32x4_SAMPLE_RATE_22K; } else if (AUDIO_SAMPLE_RATE_24000 == enSample) { audio_ctrl.interface.sample_rate = AIC32x4_SAMPLE_RATE_24K; } else if (AUDIO_SAMPLE_RATE_32000 == enSample) { audio_ctrl.interface.sample_rate = AIC32x4_SAMPLE_RATE_32K; } else if (AUDIO_SAMPLE_RATE_44100 == enSample) { audio_ctrl.interface.sample_rate = AIC32x4_SAMPLE_RATE_44K; } else if (AUDIO_SAMPLE_RATE_48000 == enSample) { audio_ctrl.interface.sample_rate = AIC32x4_SAMPLE_RATE_48K; } else { printf("SAMPLE_Tlv320aix32x4_CfgAudio(), not support enSample:%d\n",enSample); return -1; } if(AIO_MODE_I2S_MASTER == enWorkmode) { audio_ctrl.interface.transfer_mode = AIC32x4_TRANSFER_MODE_I2S; audio_ctrl.interface.master_slave_mode = AIC32x4_SLAVE_MODE; } else if(AIO_MODE_I2S_SLAVE == enWorkmode) { audio_ctrl.interface.transfer_mode = AIC32x4_TRANSFER_MODE_I2S; audio_ctrl.interface.master_slave_mode = AIC32x4_MASTER_MODE; } else { printf("SAMPLE_Tlv320aic32x4_CfgAudio(), not support workmode:%d\n\n",enWorkmode); return -1; } s_fdTlv = open(TLV320_FILE,O_RDWR); if (s_fdTlv < 0) { printf("can't open tlv320aic32x4,%s\n", TLV320_FILE); return -1; } if (ioctl(s_fdTlv,SOFT_RESET,&audio_ctrl)) { printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "tlv320aic32x4 reset failed"); } /* set sample rate */ if (ioctl(s_fdTlv,SAMPLE_RATE, &audio_ctrl)) { printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "tlv320aic32x4 set master/slave mode failed"); } /* set master/slave mode*/ if (ioctl(s_fdTlv,MASTER_SLAVE_MODE, &audio_ctrl)) { printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "tlv320aic32x4 set master/slave mode failed"); } /* set data transfer mode*/ if (ioctl(s_fdTlv,TRANSFER_MODE, &audio_ctrl)) { printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "tlv320aic32x4 set data transfer mode failed"); } /* set bitwidth*/ if(pstAioAttr->enBitwidth == AUDIO_BIT_WIDTH_16) { audio_ctrl.interface.bit_width = AIC32x4_BIT_WIDTH_16B; audio_ctrl.interface.chn_num = pstAioAttr->u32ChnCnt; if (ioctl(s_fdTlv,BIT_WIDTH, &audio_ctrl)) { printf("[Func]:%s [Line]:%d [Info]:%s\n", __FUNCTION__, __LINE__, "tlv320aic32x4 set bitwidth failed"); } } else { printf("SAMPLE_Tlv320aic32x4_CfgAudio(), just support bitwidth 16bits\n"); return -1; } #endif return 0; }
最新回复(0)