驱动程序实现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 设备寄存器进行读写操作
参数:
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[] = {{.patible = "edt,ft5x0x_ts", 0},{.patible = "edt,ft5x0x_ts", 0},{.patible = "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 suess \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
发布评论