Linux音频驱动之五:UDA1341芯片操作接口

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_38696651/article/details/89432183

本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记

一. uda1341的硬件信息

CPU通过L3接口控制uda1341芯片,分别是:
L3DATA: 数据线
L3MODE: 模式控制线,置0时,地址模式;置1时,数据模式
L3CLOCK: 时钟线

  • 地址模式:
    data[7:2]:表示的是设备地址,UDA1341TS芯片的设备地址是 000101
    data[1:0]:表示的是传输类型
    在这里插入图片描述
    00:地址寄存器,音量,低音增强,高音,峰值检测
    扩展寄存器地址,AGC控制,MIC灵敏度控制等
    01:读回峰值信息
    10: STATUS状态信息,复位、时钟、数据输入格式(数据位宽)等

STATUS控制,地址是:00010110 = 0x16
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

data0控制:地址是:00010100 = 0x14
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

data1控制,地址是:00010101 = 0x15
在这里插入图片描述

三. uda1341的写控制函数

写控制函数定义如下:

static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
  • 将value保存在cache[reg]中。
uda134x_write_reg_cache(codec, reg, value);
  • 根据传入的reg值,写地址。
  • UDA134X_EA000 ~ UDA134X_EA111属于扩展地址,也属于data[0:0]
    发送地址是:(5 << 2) | 0 ),发送地址时,L3MODE引脚拉低,地址模式。
    发送扩展地址,扩展地址最多有8个,但是扩展地址的最高两位为1,所以地址要与上0xc0
#define UDA134X_EXTADDR_PREFIX	0xC0
addr =  (reg | UDA134X_EXTADDR_PREFIX);
ret = l3_write(&pd->l3, UDA134X_DATA0_ADDR, &addr, 1);

发送扩展数据,扩展数据的高三位都是1,所以要在原来value上加0xe0

#define UDA134X_EXTDATA_PREFIX	0xE0
data = (value | UDA134X_EXTDATA_PREFIX);
ret = l3_write(&pd->l3, addr, &data, 1);

发送扩展地址和发送扩展数据,实际上都是发送数据,L3MODE引脚要拉高,选择数据模式。
在这里插入图片描述

  • UDA134X_STATUS0和UDA134X_STATUS1属于data[1:0]
    发送地址是:(5 << 2) | 2 )
    发送数据:
#define UDA134X_STATUS_ADDR	((UDA134X_L3ADDR << 2) | 2)
addr = UDA134X_STATUS_ADDR;
ret = l3_write(&pd->l3, addr, &data, 1);
  • UDA134X_DATA000,UDA134X_DATA001,UDA134X_DATA010属于data[0:0]
    发送地址是:(5 << 2) | 0 )
    发送数据:
#define UDA134X_L3ADDR	5
#define UDA134X_DATA0_ADDR	((UDA134X_L3ADDR << 2) | 0)
addr = UDA134X_DATA0_ADDR;
ret = l3_write(&pd->l3, addr, &data, 1);
  • UDA134X_DATA1属于data[0:1]
    发送地址是:(5 << 2) | 1 )
    发送数据:
#define UDA134X_L3ADDR	5
#define UDA134X_DATA1_ADDR	((UDA134X_L3ADDR << 2) | 1)
addr = UDA134X_DATA1_ADDR;
ret = l3_write(&pd->l3, addr, &data, 1);
四. uda1341的复位操作

发送地址:(5 << 2) | 2 )
发送数据:value | (1<<6)

五. uda1341的静音操作

发送地址:(5 << 2) | 0 )
发送数据:value | (1<<2)

六. uda1341的时钟设置

1.设置系统时钟
uda1341支持三种系统时钟, 512fs, 384fs,256fs
2.uda1341支持的采样率为:8000,11025,16000,22050,32000,44100,48000
3.则系统时钟的范围是:256 * 8000 <= freq <= 512 * 48000

2.设置时钟调用函数uda134x_set_dai_sysclk

static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct uda134x_priv *uda134x = codec->private_data;

	pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
		 clk_id, freq, dir);

	/* Anything between 256fs*8Khz and 512fs*48Khz should be acceptable
	   because the codec is slave. Of course limitations of the clock
	   master (the IIS controller) apply.
	   We'll error out on set_hw_params if it's not OK */
	if ((freq >= (256 * 8000)) && (freq <= (512 * 48000))) {
		uda134x->sysclk = freq;
		return 0;
	}

	printk(KERN_ERR "%s unsupported sysclk\n", __func__);
	return -EINVAL;
}

在这里系统时钟并没有真正的设置下去,而是保存到了uda134x->sysclk变量中,留在后面设置。

七. 设置支持数据格式

1.uda1341支持的格式如下:

(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE)
  1. 设置数据格式调用的函数是uda134x_set_dai_fmt
static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
	struct snd_soc_codec *codec = codec_dai->codec;
	struct uda134x_priv *uda134x = codec->private_data;

	pr_debug("%s fmt: %08X\n", __func__, fmt);

	/* codec supports only full slave mode */
	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
		printk(KERN_ERR "%s unsupported slave mode\n", __func__);
		return -EINVAL;
	}

	/* no support for clock inversion */
	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
		printk(KERN_ERR "%s unsupported clock inversion\n", __func__);
		return -EINVAL;
	}

	/* We can't setup DAI format here as it depends on the word bit num */
	/* so let's just store the value for later */
	uda134x->dai_fmt = fmt;

	return 0;
}
八. uda1341设置bias(猜测是电源)等级

SND_SOC_BIAS_ON等级:
把ADC, DAC打开
发送地址:(5 << 2) | 2 )
发送数据:0x83
在这里插入图片描述
SND_SOC_BIAS_PREPARE等级:

pd->power(1);
for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++)
    codec->write(codec, i, *cache++);

SND_SOC_BIAS_STANDBY等级:
发送地址:(5 << 2) | 2 )
发送数据:value & ~(0x03)

SND_SOC_BIAS_OFF等级:

pd->power(0);
九. 设置硬件参数

设置硬件参数调用的函数是uda134x_hw_params

  • 设置芯片的系统时钟的除数,512, 384,256
switch (uda134x->sysclk / params_rate(params)) 
{
	case 512:
		break;
	case 384:
		hw_params |= (1<<4);
		break;
	case 256:
		hw_params |= (1<<5);
		break;
	default:
		printk(KERN_ERR "%s unsupported fs\n", __func__);
		return -EINVAL;
}

在这里插入图片描述
发送数据:384fs(vaule | (1 << 4)) 256fs(value | 1 << 5)

  • 设置数据模式
switch (uda134x->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) 
{
	case SND_SOC_DAIFMT_I2S:
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		switch (params_format(params)) {
		case SNDRV_PCM_FORMAT_S16_LE:
			hw_params |= (1<<1);
			break;
		case SNDRV_PCM_FORMAT_S18_3LE:
			hw_params |= (1<<2);
			break;
		case SNDRV_PCM_FORMAT_S20_3LE:
			hw_params |= ((1<<2) | (1<<1));
			break;
		default:
			printk(KERN_ERR "%s unsupported format (right)\n",
			       __func__);
			return -EINVAL;
		}
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		hw_params |= (1<<3);
		break;
	default:
		printk(KERN_ERR "%s unsupported format\n", __func__);
		return -EINVAL;
}

SND_SOC_DAIFMT_I2S:0
SND_SOC_DAIFMT_RIGHT_J和SND_SOC_DAIFMT_LEFT_J模式参考下图
在这里插入图片描述

十. Linux UDA1341芯片接口注册
static struct snd_soc_dai_ops uda134x_dai_ops = {
	.startup	= uda134x_startup,
	.shutdown	= uda134x_shutdown,
	.hw_params	= uda134x_hw_params,
	.digital_mute	= uda134x_mute,
	.set_sysclk	= uda134x_set_dai_sysclk,
	.set_fmt	= uda134x_set_dai_fmt,
};
struct snd_soc_dai uda134x_dai = {
	.name = "UDA134X",
	/* playback capabilities */
	.playback = {
		.stream_name = "Playback",
		.channels_min = 1,
		.channels_max = 2,
		.rates = UDA134X_RATES,
		.formats = UDA134X_FORMATS,
	},
	/* capture capabilities */
	.capture = {
		.stream_name = "Capture",
		.channels_min = 1,
		.channels_max = 2,
		.rates = UDA134X_RATES,
		.formats = UDA134X_FORMATS,
	},
	/* pcm operations */
	.ops = &uda134x_dai_ops,
};
  • 注册时间:在启动内核是调用uda134x_init函数。在uda134x_init函数中注册UDA1341接口。
static int __init uda134x_init(void)
{
	return snd_soc_register_dai(&uda134x_dai);
}
module_init(uda134x_init);

跟I2S的接口注册一样,注册到一个dai_list的全局链表中,dai_list链表中是各种各样的dai接口。

十一. 总结
  • uda134x_dai接口在内核起来时注册。
  • uda134x_dai接口包含对UDA1341芯片的时钟,传输模式等硬件设置,一个硬件参数操作集uda134x_dai_ops。

参考博客:
https://blog.csdn.net/gqb_driver/article/details/8551551

猜你喜欢

转载自blog.csdn.net/weixin_38696651/article/details/89432183