驱动程序实现i2c通讯-39
Posted 杨斌并
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了驱动程序实现i2c通讯-39相关的知识,希望对你有一定的参考价值。
驱动程序实现i2c通讯
i2c对寄存器的读写
在 I2C 设备驱动中首先要完成 i2c_driver 结构体的创建、初始化和注册,当设备和驱动匹配成功后,就会执行 probe 函数,probe 函数中就是执行字符设备驱动的一套流程。
一般需要在 probe 函数里面初始化 I2C 设备,要初始化 I2C 设备就必须能够对 I2C 设备寄存器进行读写操作,这里就要用到 i2c_transfer 函数了。i2c_transfer 函数最终会调用 I2C 适配器中 i2c_algorithm 里面的 master_xfer 函数,对于 I.MX6U 而言就是 i2c_imx_xfer 这个函数。
- i2c_transfer 函数
原型如下
int i2c_transfer(struct i2c_adapter *adap,struct i2c_msg *msgs,int num)
作用:
能够对 I2C 设备寄存器进行读写操作
参数:
函数 | int i2c_transfer(struct i2c_adapter *adap,struct i2c_msg *msgs,int num) |
---|---|
adap | 所使用的 I2C 适配器,i2c_client 会保存其对应的 i2c_adapter。 |
msgs | I2C 要发送的一个或多个消息 |
num | 消息数量,也就是 msgs 的数量 |
返回值 | 负值,失败,其他非负值,发送的 msgs 数量 |
i2c传递树据的数据包
- 我们重点来看一下 msgs 这个参数,这是一个 i2c_msg 类型的指针参数,I2C 进行数据收发说白了就是消息的传递,Linux内核使用i2c_msg 结构体来描述一个消息。
- i2c_msg 结构体定义在include/uapi/linux/i2c.h 文件中,结构体内容如下
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_STOP 0x8000 /* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART 0x4000 /* if I2C_FUNC_NOSTART */
#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 */
__u16 len; /* msg length */
__u8 *buf; /* pointer to msg data */
};
代码
- i2c_client.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
static struct i2c_client * ft5x06_client;
static void ft5x06_write_reg(u8 reg_addr, u8 data, u8 len);
static void ft5x06_write_reg(u8 reg_addr, u8 data, u8 len){
u8 buff[256];
struct i2c_msg msgs[] = {
[0] = {
.addr = ft5x06_client->addr,
.flags = 0,
.len = len + 1,
.buf = buff,
},
// [1] = {
// .addr = ft5x06_client->addr,
// .flags = 1,
// .len = sizeof(data),
// .buf = &data,
// }
};
buff[0] = reg_addr;
memcpy(&buff[1], &data, len);
i2c_transfer(ft5x06_client->adapter, msgs, 1);
}
static int ft5x06_read_reg(u8 reg_addr);
static int ft5x06_read_reg(u8 reg_addr){
u8 data;
struct i2c_msg msgs[] = {
[0] = {
.addr = ft5x06_client->addr,
.flags = 0,
.len = sizeof(reg_addr),
.buf = ®_addr,
},
[1] = {
.addr = ft5x06_client->addr,
.flags = 1,
.len = sizeof(data),
.buf = &data,
}
};
i2c_transfer(ft5x06_client->adapter, msgs, 2);
return data;
}
struct of_device_id ft5x06_id[] = {
{.compatible = "edt,ft5x0x_ts", 0},
{.compatible = "edt,ft5x0x_ts", 0},
{.compatible = "edt,ft5x0x_ts", 0},
{}
};
struct i2c_device_id ft5x06_id_ts[] = {
{"xxxxx", 0},
{},
};
int ft5x06_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id){
int ret;
printk("this is ft5x06_probe \\n ");
ft5x06_client = i2c_client;//因为我们要在别的函数里面用到这个client,所以我们要把他们复制进来
//地址为0x80的寄存器里面写入0x4b的数据
ft5x06_write_reg(0x80, 0x4a, 1);
ret = ft5x06_read_reg(0x80);
printk("ret is %#x \\n", ret);
return 0;
}
int ft5x06_remove(struct i2c_client *i2c_client){
printk("ft5x06_remove \\n ");
return 0;
}
static struct i2c_driver ft5x06_driver = {
.probe = ft5x06_probe,
.remove = ft5x06_remove,
.id_table = ft5x06_id_ts,
.driver = {
.owner = THIS_MODULE,
.name = "ft5x06_test",
.of_match_table = ft5x06_id,
},
};
static int ft5x06_driver_init(void){
int ret;
printk("ft5x06_driver_init \\n");
ret = i2c_add_driver(&ft5x06_driver);
if (ret < 0)
{
printk("i2c_add_driver is error \\n ");
return ret ;
}
printk("i2c_add_driver is success \\n");
return 0;
}
static void ft5x06_driver_exit(void){
printk("ft5x06_driver_exit \\n");
i2c_del_driver(&ft5x06_driver);
}
module_init(ft5x06_driver_init);
module_exit(ft5x06_driver_exit);
MODULE_LICENSE("GPL");
以上是关于驱动程序实现i2c通讯-39的主要内容,如果未能解决你的问题,请参考以下文章
stm32103C8T6通过I2C接口实现温湿度(AHT20)的采集与OLED显示