[ Linux驱动炼成记 ] 12 -音频驱动TAS5754添加EQ参数

每一个带有音频播放的产品,设备初期的时候都会调试设备的EQ参数。EQ通过将声音中各频率的组成泛音等级加以修改,专为某一类音乐进行优化,增强人们的感觉。常见包括:正常、摇滚、流行、舞曲、古典、柔和、爵士、金属、重低音和自定义。1

调节音频芯片EQ参数一般是专业音响公司做的,必须有专业的设备和调音师完成,最终输出芯片配套的文件,供驱动写入。这里以TAS5754为例:

EQ参数

专业的音响设备调好EQ后给的文件,简要如下:

//可以发现都是芯片内部寄存器的一些值
reg_value base_main_Rate48_REG_xxx_program[] = {
    {0x00,0x00},
    {0x00,0x01},
//			# reg[1][3] = 0x4
    {0x03,0x04},
    {0x00,0x00},
//			# reg[0][0x3] = 0x11
    {0x03,0x11},
//			# reg[0][2] = 0x10
    {0x02,0x10},
    {0xFF,0x04},
    {0xFF,0x05},
    {0x00,0x00},
//			# reg[0][0x2b] = 0x1f
    {0x2B,0x1F},
    {0x00,0x2C},
....
};

tas5754音频芯片调完EQ参数后的值需要做简单的修改:

reg_value base_main_Rate48_REG_Section_program[] = {
    {0x00,0x00},
    {0x00,0x01},
//			# reg[1][3] = 0x4
    {0x03,0x04},
    {0x00,0x00},
//			# reg[0][0x3] = 0x11
    {0x03,0x11},
//			# reg[0][2] = 0x10
    {0x02,0x10},
    {0xFF,0x04},    // 1. 写ADC数据
    {0xFF,0x04},   //  2. 写DAC数据
    {0x00,0x00},

文件中提供了两个数组的数据,base_main_Rate48_REG_Section_program, tas5754_reg_values, 在第2处(写DAC数据),插入第二个数组的数据,同时把 {0xFF,0x04},  {0xFF,0x05}, 删掉,第二个数组就是DAC的EQ数据,因为TAS5754没有ADC,所以 {0xFF,0x04}的数据为空,不用写。
驱动写入EQ

EQ参数实际对应的都是芯片寄存器值,驱动中需要通过IIC写入到音频芯片中,由于音频芯片的EQ参数很多,需要单独在线程中写入,而不影响驱动的正常加载,这就需要内核中Workqueue机制2

  • tas5754的私有数据
// 私有数据
struct tas575x_private {
	struct snd_soc_codec *codec;
	... 
	struct workqueue_struct *workqueue;
	struct delayed_work      dwork;
	....
};
  • 创建工作队列
static int tas575x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
{
	struct tas575x_private *priv = snd_soc_codec_get_drvdata(dai->codec);
	priv->codec = dai->codec;
	priv->format = format;
	//创建工作队列
	priv->workqueue = create_singlethread_workqueue("tas575x_workqueue");
	// 创建工作,调用函数是tas575x_task
	INIT_DELAYED_WORK(&priv->dwork,tas575x_task);
	//延时5s去执行
	queue_delayed_work(priv->workqueue,&priv->dwork,5);
	
	return 0;
}
  • 工作队列的处理函数 处理函数中巧妙之处是使用了container_of这个宏来从而避免了全局变量的使用,该宏的作用就是可以根据一个结构体变量中的一个成员变量的指针来获取指向整个结构体变量的指针。
static void tas575x_task(struct work_struct *work)
{
	int i = 0;
	struct tas575x_private *priv;
	struct delayed_work *dwork = to_delayed_work(work);
	int cnt = sizeof(tas5754_reg_values)/sizeof(tas5754_reg_values[0]);
	pr_info("%s, reg cnt:%d\n", __func__, cnt);
	priv = container_of(dwork, struct tas575x_private, dwork);
	for(i = 0; i<cnt; i++){
		snd_soc_write(priv->codec, tas5754_reg_values[i].reg,tas5754_reg_values[i].val);
	}
}

  1. EQ均衡器 ↩︎
  2. workqueue 机制 ↩︎

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券