- 1、I2C协议解读
I2C一共有两根线,一条时钟线SCL,一条数据线SDA
总线空闲状态时,这两根线一般被上面所接的上拉电阻拉高,保持着高电平
总线上连接的每一个从设备都有一个从设备地址,占7个bit位
I2C总线数据传输速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s
2、I2C时序
如下图所示,当SCL为高电平时,SDA由高到低的跳变,表示产生一个起始条件;当时钟线SCL高电平期间,读取数据线SDA上的电平大小,为一个bit的数据,读8次即一个byte的数据(11010000);当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA线,回传给主设备一个应答位;当SCL为高而SDA由低到高的跳变,表示产生一个停止条件;
3、I2C电路
I2c0的引脚接音频芯片的i2c控制引脚
4、从设备I2C的dts(设备树)设置
5、通过I2C读写音频寄存器的值
/*
i2c_test
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "lpf_i2c"
struct i2c_client *i2c_test;
struct test_device{
int major;
struct class *class;
struct device *dev;
};
struct test_device *i2c_test_device;
int test_device_open(struct inode *inode,struct file *filp)
{
printk("---------LPF:%s----------n",__func__);
return 0;
}
int test_device_release(struct inode *inode,struct file *filp)
{
printk("---------LPF:%s----------n",__func__);
return 0;
}
static const struct file_operations test_device_fops={
.owner = THIS_MODULE,
.open = test_device_open,
.release = test_device_release,
};
static void i2c_test_write(struct i2c_client *client,uint8_t regaddr, uint8_t *data)
{
struct i2c_msg msgs[2];
int i;
int ret;
__u8 buffer[2];
__u8 read_data[1];
buffer[0] = regaddr;
buffer[1] = *data;
for(i=0;i<2;i++){ //写寄存器 write:0x30+ack 0x04+ack 0x02+ack
if(i == 0){
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 2;
msgs[0].buf = buffer;
}else{ //读寄存器 write:0x30+ack 0x04+ack read:0x31+ack 0x02+nak
msgs[0].addr = client->addr;
msgs[0].flags = 0;
msgs[0].len = 1;
msgs[0].buf = ®addr;
msgs[1].addr = client->addr;
msgs[1].flags = 1;
msgs[1].len = 1;
msgs[1].buf= read_data;
}
//参数1 ---- i2c_adapter对象地址
//参数2 ---- 数据包的地址:struct i2c_msg
//参数3 ---- 数据包的个数
//返回值---- 成功:数据包的个数,失败:负数
if(i==0){
ret = i2c_transfer(client->adapter, msgs,1);
if(ret<0){
printk("------LPF:i2c error ret = %d client->addr = %#x -------n",
ret,client->addr);
}
}else{
ret = i2c_transfer(client->adapter, msgs,2);
if(ret<0){
printk("------LPF:i2c error ret = %d client->addr = %#x -------n",
ret,client->addr);
}
}
msleep(10);
}
}
static ssize_t echo_test_device_value(struct device *dev,struct device_attribute *attr, const char *buf, size_t len)
{
uint8_t data= 0x02; //要向寄存器写入的值
uint8_t regaddr= 0x04; //寄存器地址
printk("---------LPF:%s----------n",__func__);
/*将应用空间传递的(char *)类型数据转换为内核空间10进制整形 */
//value = simple_strtoul(buf, NULL, 16);
i2c_test_write(i2c_test,regaddr,&data);
return len;
}
static ssize_t cat_test_device_value(struct device *dev,struct device_attribute *attr, char *buf)
{
printk("---------LPF:%s----------n",__func__);
return 0;
}
static DEVICE_ATTR(test_device_value, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP ,cat_test_device_value, echo_test_device_value);
static int i2c_test_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int ret;
printk("------LPF:%s------n",__func__);
i2c_test=kzalloc(sizeof(struct i2c_client),GFP_KERNEL);
if(!i2c_test){
printk("------LPF:kzlloc failed!------n");
ret = -ENOMEM;
}
i2c_test=client;
/*空间申请*/
i2c_test_device = kzalloc(sizeof(struct test_device),GFP_KERNEL);
if(IS_ERR(i2c_test_device)){
printk("-------LPF-%s:kzalloc i2c_test_device failed!--------n",__func__);
ret = PTR_ERR(i2c_test_device);
goto err_i2c_test_kzalloc;
}
/* 设备号申请*/
i2c_test_device->major = register_chrdev(0, "test_device_major", &test_device_fops);
if(i2c_test_device->major < 0){
printk("-------LPF-%s:failed to creat i2c_test_device->major-------n",__func__);
ret = -EINVAL;
goto err_kzalloc;
}
/*创建设备类*/
i2c_test_device->class = class_create(THIS_MODULE, "test_device_class");
if(IS_ERR(i2c_test_device->class)){
printk("-------LPF-%s:failed to creat i2c_test_device->class--------n",__func__);
ret = PTR_ERR(i2c_test_device->class);
goto err_register;
}
/*创建test_device_device设备节点文件*/
i2c_test_device->dev = device_create(i2c_test_device->class,NULL,MKDEV(i2c_test_device->major, 0),NULL,"test_device_device");
if(IS_ERR(i2c_test_device->dev)){
printk("-------LPF-%s:failed to creat i2c_test_device->dev--------n",__func__);
ret = PTR_ERR(i2c_test_device->dev);
goto err_device_create;
}
/* 在 设备目录下创建一个test_device_value属性文件 /sys/class/test_device_class/test_device_device/test_device_value */
ret=sysfs_create_file(&(i2c_test_device->dev->kobj), &dev_attr_test_device_value.attr);
if(ret != 0){
printk("-------LPF-%s:failed to creat sysfs_create_file ret:%d--------n",__func__,ret);
goto err_sysfs_create_file;
}
return ret;
err_sysfs_create_file:
device_destroy(i2c_test_device->class,MKDEV(i2c_test_device->major, 0));
err_device_create:
class_destroy(i2c_test_device->class);
err_register:
unregister_chrdev(i2c_test_device->major,"digital_tube_major");
err_kzalloc:
kfree(i2c_test_device);
err_i2c_test_kzalloc:
kfree(i2c_test);
return ret;
}
static int i2c_test_exit(struct i2c_client *client)
{
printk("---------LPF:%s----------n",__func__);
return 0;
}
static const struct of_device_id i2c_test_of_match[] = {
{ .compatible = "ti,tlv320aic3111" }, //驱动会去dts匹配compatible属性,执行probe函数
{ },
};
static const struct i2c_device_id i2c_test_id[] = {
{ "tlv320aic3111" },
{ },
};
static struct i2c_driver i2c_test_driver = {
.driver = {
.name = DEVICE_NAME,
.of_match_table = i2c_test_of_match,
},
.probe = i2c_test_probe,
.remove = i2c_test_exit,
.id_table = i2c_test_id, //必须填充id_table,不然probe回调失败
};
module_i2c_driver(i2c_test_driver);
/*
module_i2c_driver(i2c_test_driver)展开如下:
module_i2c_driver(i2c_test_driver)
static int __int i2c_test_driver_init(void)
{
return i2c_register_driver(&i2c_test_driver);
}
module_init(i2c_test_driver_init);
static void __exit adxl34x_driver_exit(void)
{
return i2c_del_driver(&adxl34x_driver);
}
module_exit(i2c_test_driver_exit);
*/
MODULE_LICENSE("GPL");
MODULE_VERSION("4.4");
MODULE_AUTHOR("lpf");
MODULE_DESCRIPTION("i2c test driver");
6、I2C时序抓取结果
向音频芯片的0X04寄存器成功写入0X02的值,并读出寄存器的值
0x30-8位(从设备地址7位(dts里的0x18)+1位读写位(写是0) 0x31-8位(从设备地址7位(dts里的0x18)+1位读写位(读是1)
写寄存器 write:0x30+ack 0x04+ack 0x02+ack
struct i2c_msg msgs[1];
__u8 buffer[2];
buffer[0]=0x04;
buffer[1]=0x02;
msgs[0].addr = client->addr;
msgs[0].flags = 0; //0表示写
msgs[0].len = 2; //先写寄存器地址0x04,再向0x04执行的寄存器赋值0x02
msgs[0].buf = buffer;
i2c_transfer(client->adapter, msgs,1);
读寄存器 write:0x30+ack 0x04+ack read:0x31+ack 0x02+nak
struct i2c_msg msgs[2];
__u8 buffer[1];
buffer[1]=0x04;
__u8 read_data[1];
msgs[0].addr = client->addr; //从设备地址
msgs[0].flags = 0; //读寄存器需要先写寄存器的地址
msgs[0].len = 1;
msgs[0].buf = buffer; //寄存器地址
msgs[1].addr = client->addr;
msgs[1].flags = 1; //写完再读
msgs[1].len = 1;
msgs[1].buf= read_data; //读出来的值保存在这里
i2c_transfer(client->adapter, msgs,2);
|
|
2022-3-9 16:01:53
评论
举报
|
|
|