input子系统下的多点触摸协议称为MT协议,其文档为:Documentation/input/multitouch-protocol.txt。
MT协议被分为两种类型,取决于硬件的兼容性:
触摸点的信息通过一系列的ABS_MT事件上报给Linux内核,定义在文件include/uapi/linux/input.h
中:
#define ABS_MT_SLOT 0x2f /* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
#define ABS_MT_POSITION_X 0x35 /* Center X touch position */
#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
其中最常用的是:
FT5x06系列是单芯片电容触摸板控制器IC,内部带有一个8bit的MCU,支持2.8’‘到8.9’‘的触摸屏,区别如下:
其内部框图如下:
与主控制器的连接示意图如下:
串行接口支持I2C(最大400KHz)和SPI,I2C的通信格式如下:
本文使用的是正点原子7’'RGB屏幕,分辨率1024*600,触摸屏及其驱动IC集成在屏幕上,通过FPC排线与imx6ull开发板相连:
imx6ull底板的排线连接情况如下:
可以看出:触摸屏IC接在I2C2接口上,RST复位引脚接在SNVS_TAMPER9这个引脚上,中断引脚接在GPIO1_IO09上。
Linux内核已经集成了很多电容触摸IC的驱动文件,针对FT5426触摸IC,驱动文件为:drivers/input/touchscreen/edt-ft5x06.c。
此驱动源码在正点原子的开发板上不能直接使用,正点原子官方对其进行了修改,修改的地方如下。
(1)edt_ft5x06_i2c_ts_probe_dt 设备树解析函数
增加触摸IC中断引脚使用的gpio:
(2)edt_ft5x06_ts_probe 挂载函数
看上去像是600不是64的倍数,所以选择在驱动里写死:
驱动ic的中断引脚需要设置gpio:
(3)edt_ft5x06_ts_isr 触摸中断处理函数
此函数修改的地方有点多,截取部分:
(4)EDT_RAW_DATA_RETRIES
查看该文件下的makefile:
需要开启该宏来使能驱动,进入menuconfig界面,按/
,搜索该宏定义位置:
按照帮助文档给出,使能该驱动:
配置修改后保存退出,生成新的.config文件,重新编译内核后,将修改同步到开发板配置文件 。
需要先屏幕冲突的已有节点,见后面第5节记录的问题。
驱动添加完成后,还需要添加与之匹配的设备树节点,根据兼容性查找对应的绑定文档:
找到绑定文档为:Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt,其中给出的i2c示例节点为:
polytouch: edt-ft5x06@38 {
compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
reg = <0x38>;
pinctrl-names = "default";
pinctrl-0 = <&edt_ft5x06_pins>;
interrupt-parent = <&gpio2>;
interrupts = <5 0>;
reset-gpios = <&gpio2 6 1>;
wake-gpios = <&gpio4 9 0>;
};
根据绑定文档,在开发板的设备树中 i2c2 节点下,添加自己的节点:
polytouch: edt-ft5x06@38 {
compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
reg = <0x38>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ft5x06>;
interrupt-parent = <&gpio1>;
interrupts = <9 0>;
reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;
interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
};
在pinctrl节点下,添加edt_ft5x06_pins描述:
pinctrl_ft5x06: ft5x06grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0xF080
MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x10B0
>;
};
修改完成,重新编译设备树。
使用新的内核和设备树启动,查看启动日志input子系统相关:
查看input输入设备的节点:
这里我另外还注册了按键为回车键,所以会有三个输入设备,根据启动顺序,触摸屏应该是event1。
查看触摸屏数据:
hexdump /dev/input/event1
执行此命令后,开始点击触摸屏,就会输出数据。如果无数据,则表示驱动有问题。
解决:
(2)问题2
问题分析:gpio1-09已被申请,肯定是没有屏蔽干净。
FT5x06的核心是一个i2c设备,所以整个驱动都是基于i2c驱动框架所写:
兼容性如下:
static int edt_ft5x06_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
}
(1)复位引脚、中断引脚相关操作
获取设备树节点中的gpio引脚信息:
该函数中会调用gpio子系统,操作上一步拿到的复位引脚,复位ic,实现如下:
接下来申请中断引脚对应的gpio:
(2)I2C设备操作
检测ft5x06版本号:
该函数实现如下:
i2c读写函数封装为edt_ft5x06_ts_readwrite,实现如下:
(3)input子系统操作
(4)注册gpio引脚中断
中断函数为edt_ft5x06_ts_isr,在该函数中完成触摸事件的上报。
(5)注册输入设备