linux驱动之I2C

目录

 1. I2C驱动层次结构图

 2. struct i2c_driver结构体

 3. struct i2c_client结构体

 3. 数据收发相关函数

 4. I2c应用层驱动

 

 1. I2C驱动层次结构图

linux驱动之I2C_第1张图片

 I2C主机控制器驱动(adapter):一般由SOC厂家负责设计实现,用于控制I2C主机控制器发出时序信号;

I2C Core:为上层提供统一的API接口和对其他模块进行注册和注销管理等;

I2C设备驱动(Client):调用I2C Core提供的统一API,根据I2C设备的访问规范,控制I2C控制器发出不同的时序信号,对I2C设备进行访问;该驱动称为内核层I2C设备驱动;

i2c-dev:将I2C主机控制器实现为一个字符设备,应用程序可直接通过访问/dev/i2c-N来访问I2C主机控制器,从而对I2C设备发起访问; 称为应用层I2C设备驱动

2. struct i2c_driver结构体

该结构体用于表示i2c设备驱动; 

struct i2c_driver {
    //我们实例化什么样的i2c设备
	unsigned int class;

    //总线添加和移除时回调函数
	int (*attach_adapter)(struct i2c_adapter *) __deprecated;
	int (*detach_adapter)(struct i2c_adapter *) __deprecated;

    //设备绑定和解绑回调函数
	int (*probe)(struct i2c_client *, const struct i2c_device_id *);
	int (*remove)(struct i2c_client *);

    //关机,挂起,恢复时回调函数
	void (*shutdown)(struct i2c_client *);
	int (*suspend)(struct i2c_client *, pm_message_t mesg);
	int (*resume)(struct i2c_client *);

	//警报回调,例如SMBus警报协议
	void (*alert)(struct i2c_client *, unsigned int data);

    //总线信号回调
	int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);

    //设备驱动模型驱动
	struct device_driver driver;
    //此驱动程序支持的I2C设备列表
	const struct i2c_device_id *id_table;

	/* Device detection callback for automatic device creation */
	int (*detect)(struct i2c_client *, struct i2c_board_info *);
	const unsigned short *address_list;
	struct list_head clients;
};

 常用的API:

//添加i2c设备驱动

int i2c_register_driver(struct module *, struct i2c_driver *);

#define i2c_add_driver(driver) \
    i2c_register_driver(THIS_MODULE, driver)

//删除i2c设备驱动
void i2c_del_driver(struct i2c_driver *);

可用宏简写上述两API;参数为已填充好的struct i2c_driver变量;

#define module_i2c_driver(__i2c_driver) \
    module_driver(__i2c_driver, i2c_add_driver, \
            i2c_del_driver)

 示例:

static struct i2c_driver ltc4151_driver = {
	.driver = {
		.name	= "ltc4151",
	},
	.probe		= ltc4151_probe,
	.remove		= ltc4151_remove,
	.id_table	= ltc4151_id,
};

module_i2c_driver(ltc4151_driver);

 3. struct i2c_client结构体

该结构体用于表示i2c从设备; 

struct i2c_client {
	unsigned short flags;		
/*
#define I2C_CLIENT_PEC	0x04		//用于包错误检查
#define I2C_CLIENT_TEN	0x10		//十位的芯片地址			
#define I2C_CLIENT_WAKE	0x80		//for board_info; true iff can wake 
*/

    //连接到父适配器的I2C总线上使用的地址。
	unsigned short addr;		

    //指示设备的类型,通常是一个通用的芯片名称,足以隐藏第二来源和兼容版本
	char name[I2C_NAME_SIZE];

    //适配器
	struct i2c_adapter *adapter;	
    //设备驱动
	struct i2c_driver *driver;	
    //设备
	struct device dev;		
    //指示此设备生成的IRQ
	int irq;			
	struct list_head detected;
};

常用 API:

void *i2c_get_clientdata(const struct i2c_client *dev);

void i2c_set_clientdata(struct i2c_client *dev, void *data)

 3. 数据收发相关函数

 //作用:向I2c从设备写数据;

//I2c设备的地址包含在client中,要写的数据为buf,写的字节数为count;

int i2c_master_send(const struct i2c_client *client, const char *buf, int count);

//作用:向I2c从设备读数据; 参数同上;
int i2c_master_recv(const struct i2c_client *client, char *buf,int count);

将几个读写操作合并在一起执行的函数; 

/*

        adap:执行写操作的I2c主机控制器;

        msgs:消息数组;

        num:消息的数量;

*/

int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);

 struct i2c_msg结构体如下:

struct i2c_msg {
	__u16 addr;	/* slave address (从设备地址)*/
	__u16 flags;//操作的标志,如下
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
#define I2C_M_16BIT_REG		0x0002	/* indicate reg bit-width is 16bit */
#define I2C_M_16BIT_DATA	0x0008	/* indicate data bit-width is 16bit */

	__u16 len;		/* msg length	消息长度			*/
	__u8 *buf;		/* pointer to msg data	指向消息数据的指针		*/
};

 内核驱动框架


//用于设备树匹配
const struct of_device_id	of_mpu6050_id[] = {
	{
		.compatible = "mpu6050, 0",
	},
	{},	
};


static struct i2c_driver mpu6050_drv = {
	.probe = mpu6050_drv_probe,
	.remove= mpu6050_drv_remove,
	.driver = {
		.name = "mpu6050",//随便写,出现在/sys/bus/i2c/driver/ 下
		.of_match_table = of_match_ptr(of_mpu6050_id),
	},

	.id_table = mpu6050_id_table,
};

#if 0
static int __init mpu6050_drv_init(void)
{
	return i2c_add_driver(&mpu6050_drv);
}

static void __exit mpu6050_drv_exit(void)
{
	i2c_del_driver(&mpu6050_drv);
}

module_init(mpu6050_drv_init);
moudle_exit(mpu6050_drv_exit);
#else
mpdule_i2c_driver(mpu6050_drv);
#endif
MODULE_LICENSE("GPL");

4. I2c应用层驱动

 内核需要配置:

Device Drivers -->

        -*- I2C support -->

                <*> I2C device interface

 应用层驱动主要调用所对应的Linux驱动为drivers/i2c/i2c-dev.c中; 

应用层流程:

{
    int ret = -1;
	struct i2c_msg msg[2];
	unsigned char buf[4] = {0};
	struct i2c_rdwr_ioctl_data rdwr = {0};
	unsigned int data;
	
	int fd = open(I2C_NAME,O_RDWR);
	if(0 > fd){
		printf("open %s failed\n",I2C_NAME);
		goto ERR0;
	}

	ret = ioctl(fd, I2C_SLAVE_FORCE, DEV_READ_ADDR);
	if(0 > ret){
		printf("ioctl I2C_SLAVE_FORCE 0x%x failed\n",DEV_READ_ADDR);
		goto ERR1;
	}

	msg[0].addr = DEV_READ_ADDR;
	msg[0].flags = 0;
	msg[0].len = 0x1;
	msg[0].buf = buf;

	msg[1].addr = DEV_READ_ADDR;
	msg[1].flags = 0;
	msg[1].flags |= I2C_M_RD;
	msg[1].len = 0x1;
	msg[1].buf = buf;

	rdwr.msgs = &msg[0];
	rdwr.nmsgs = (__u32)2;

	buf[0] = reg_addr & 0xff;
	
	ret = ioctl(fd, I2C_RDWR, &rdwr);
	if(0 > ret){
		printf("ioctl I2C_RDWR failed\n");
		goto ERR1;
	}

	data = buf[0];
	
	printf("0x%x: 0x%x\n", reg_addr, data);
	
ERR1:
	close(fd);
ERR0:
	return ret;
}

你可能感兴趣的:(#,kernel-I2C,linux驱动)