全系列传送门
Linux嵌入式驱动开发01——第一个驱动Hello World(附源码)
Linux嵌入式驱动开发06——第一个相对完整的驱动实践编写
Linux嵌入式驱动开发07——GPIO驱动过程记录(飞凌开发板)
Linux嵌入式驱动开发11——平台总线模型修改为设备树实例
Linux嵌入式驱动开发12——pinctl和gpio子系统实践操作
Linux嵌入式驱动开发13——ioctl接口(gpio控制使用)
Linux嵌入式驱动开发14——中断的原理以及按键中断的实现(tasklet中断下文)
I2C简介
ls /dev
这里拿我们的七寸LVDS屏幕的触摸芯片为例子,通过底座的原理图,可以看到LVDS使用了I2C3的接口
i2c-dev.h
打开文件
/include/uapi/linux/i2c-dev.h
i2c_rdwr_ioctl_data 结构体代码如下所示
/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
struct i2c_msg __user *msgs; /* pointers to i2c_msgs */
__u32 nmsgs; /* number of i2c_msgs */
};
第一个结构体成员就是我们要发送的数据包的指针
第二个结构体成员是我们发送的数据包的个数
i2c.h
接下俩看一下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 */
};
TSC2007
通过底版的原理图,可以看到触摸芯片为TSC2007
I2C从设备地址 —— regtsc2007的7位设备地址是由A0, A1两个引脚的连接方式确定的,在 Datasheet 有给出说明。
7位地址中,D7~D5为高3位,所以地址高位为100,即为4。由于A1, A0两个引脚接地,所以 D4~D1为1000,即为8。
因此,这7位地址应该是0x48:
代码测试
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
int fd;
int i2c_read_data(unsigned int slave_addr, unsigned char reg_addr)
{
unsigned char data;
int ret;
struct i2c_rdwr_ioctl_data i2c_read_lcd;
struct i2c_msg msg[2] = {
[0] = { //第一个数据包
.addr = slave_addr, //从机地址
.flags = 0, //flags=1表示写操作,这里写的就是从机的寄存器地址
.buf = ®_addr, //要发送的数据
.len = sizeof(reg_addr),
},
[1] = { //第二个数据包
.addr = slave_addr,
.flags = 1, //进行读的操作
.buf = &data,
.len = sizeof(reg_addr),
},
};
i2c_read_lcd.msgs = msg;
i2c_read_lcd.nmsgs = 2;
ret = ioctl(fd, I2C_RDWR, &i2c_read_lcd);
if(ret < 0){
perror("ioctl error/n");
return ret;
}
return data;
}
int main(int argc, char *argv[])
{
int TD_STATUS;
fd = open("/dev/i2c-3", O_RDWR); // 打开节点时候触发open函数
if(fd < 0){
perror("open error\n"); // perror在应用中打印
return fd;
}
while(1){
TD_STATUS = i2c_read_data(0x48, 0x02);
printf("TD_STATUS value is %d\n", TD_STATUS);
sleep(1);
}
return 0;
}
TD_STATUS = i2c_read_data(0x48, 0x02);这句代码有问题,我没有找到tsc2007对应的触摸寄存器的位置,所以就读不到数
不过问题不大,这只是其中一种方法,还有其他的方法,现在主流的方法是使用设备树
设备树
在设备树文件中,搜索tsc2007,看到i2c3下面的节点,就是我们的触摸芯片的节点
打开开发板,查看目录
/sys/bus/i2c/devices/
因为我们已经知道了是0x48地址,所以打开2-0048,然后cat name