基于RK3328-I2C读写芯片寄存器

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 <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/irq.h>

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/of_device.h>
#include <linux/device.h>



#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 = &regaddr;
				
			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);

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/QQ135102692/article/details/114400739