前言
目前一直在使用海思的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