失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > i.MX 6ULL 驱动开发 二十四:多点触摸屏

i.MX 6ULL 驱动开发 二十四:多点触摸屏

时间:2020-11-17 04:44:57

相关推荐

i.MX 6ULL 驱动开发 二十四:多点触摸屏

一、多点触摸(MT)协议

Linux 驱动开发 六十六:多点触控(MT)协议_lqonlylove的博客-CSDN博客

二、FT5426原理

见官方手册。

三、Linux 下电容触摸屏驱动框架

1、驱动总线

FT5426使用I2C接口进行通信。

2、触摸信息上报机制

触摸点信息使用input子系统完成数据上报。

3、ABS_MT 事件

#define ABS_MT_SLOT0x2f/* MT slot being modified */#define ABS_MT_TOUCH_MAJOR0x30/* Major axis of touching ellipse */#define ABS_MT_TOUCH_MINOR0x31/* Minor axis (omit if circular) */#define ABS_MT_WIDTH_MAJOR0x32/* Major axis of approaching ellipse */#define ABS_MT_WIDTH_MINOR0x33/* Minor axis (omit if circular) */#define ABS_MT_ORIENTATION0x34/* Ellipse orientation */#define ABS_MT_POSITION_X0x35/* Center X touch position */#define ABS_MT_POSITION_Y0x36/* Center Y touch position */#define ABS_MT_TOOL_TYPE0x37/* Type of touching device */#define ABS_MT_BLOB_ID0x38/* Group a set of packets as a blob */#define ABS_MT_TRACKING_ID0x39/* Unique ID of initiated contact */#define ABS_MT_PRESSURE0x3a/* Pressure on contact area */#define ABS_MT_DISTANCE0x3b/* Contact hover distance */#define ABS_MT_TOOL_X0x3c/* Center X tool position */#define ABS_MT_TOOL_Y0x3d/* Center Y tool position */

ABS_MT事件定义在:include\uapi\linux\input.h文件中。

四、Linux 下 API 接口

1、隔离触摸点信息

/** dev:具体的 input_dev 设备。*/static inline void input_mt_sync(struct input_dev *dev){input_event(dev, EV_SYN, SYN_MT_REPORT, 0);}

2、上报事件槽

/** dev:具体的 input_dev 设备。* slot:触摸槽信息*/static inline void input_mt_slot(struct input_dev *dev, int slot){input_event(dev, EV_ABS, ABS_MT_SLOT, slot);}

3、初始化事件槽

/** dev:具体的 input_dev 设备。* num_slots:SLOT 数量(触摸点数量)* flags:标志位*/int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,unsigned int flags);

4、为 slot 关联一个 ID

/** dev:具体的 input_dev 设备。* tool_type:触摸类型* active:ture(连续触摸)、flase(触摸点抬起)*/void input_mt_report_slot_state(struct input_dev *dev,unsigned int tool_type, bool active)

5、上报触摸点坐标

/** dev:具体的 input_dev 设备。* code:上报数据类型:ABS_MT_POSITION_X(x轴坐标信息)、ABS_MT_POSITION_Y(y轴坐标信息)* value:坐标值*/static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value){input_event(dev, EV_ABS, code, value);}

6、上报触摸点数量

/** dev:具体的 input_dev 设备。* use_count:触摸点数量*/void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count);

7、Type A 触摸点信息上报时序

ABS_MT_POSITION_X x[0] # 使用 input_report_abs 上传 x 轴坐标ABS_MT_POSITION_Y y[0]# 使用 input_report_abs 上传 y 轴坐标SYN_MT_REPORT# 使用 input_mt_sync 完成ABS_MT_POSITION_X x[1]ABS_MT_POSITION_Y y[1]SYN_MT_REPORTSYN_REPORT# 使用 input_sync 实现

8、Type B 触摸点信息上报时序

ABS_MT_SLOT 0# 使用 input_mt_slot 上报事件槽信息ABS_MT_TRACKING_ID 45# 使用 input_mt_report_slot_state 添加触摸点ABS_MT_POSITION_X x[0]# 使用 input_report_abs 上传 x 轴坐标ABS_MT_POSITION_Y y[0]# 使用 input_report_abs 上传 y 轴坐标ABS_MT_SLOT 1ABS_MT_TRACKING_ID 46ABS_MT_POSITION_X x[1]ABS_MT_POSITION_Y y[1]SYN_REPORT# 使用 input_sync 实现

五、驱动编写思路

1、搭建 I2C 驱动框架

#include "linux/init.h"#include "linux/module.h"#include "linux/printk.h"#include "linux/i2c.h"#include "linux/miscdevice.h"#include "linux/fs.h"#include "linux/delay.h"#include "asm-generic/uaccess.h"typedef struct{}newchrdev_t;newchrdev_t newchrdev;/** @description: i2c驱动的probe函数,当驱动与*设备匹配以后此函数就会执行* @param - client : i2c设备* @param - id: i2c设备ID* @return: 0,成功;其他负值,失败*/static int ft5426_probe(struct i2c_client *client, const struct i2c_device_id *id){int ret = 0;printk("ft5426_probe!\r\n");return ret;}/** @description: i2c驱动的remove函数,移除i2c驱动的时候此函数会执行* @param - client : i2c设备* @return: 0,成功;其他负值,失败*/static int ft5426_remove(struct i2c_client *client){int ret = 0;printk("ft5426_remove!\r\n");return ret;}/* 传统匹配方式ID列表 */static const struct i2c_device_id ft5426_id[] = {{"focaltech,ft5426", 0}, {}};/* 设备树匹配列表 */static const struct of_device_id ft5426_of_match[] = {{.compatible = "focaltech,ft5426" },{/* Sentinel */ }};/* i2c驱动结构体 */static struct i2c_driver ft5426_driver = {.probe = ft5426_probe,.remove = ft5426_remove,.driver = {.owner = THIS_MODULE,.name = "ft5426",.of_match_table = ft5426_of_match, },.id_table = ft5426_id,};/** @description: 驱动入口函数* @param : 无* @return : 无*/static int __init ft5426_init(void){int ret = 0;ret = i2c_add_driver(&ft5426_driver);return ret;}/** @description: 驱动出口函数* @param : 无* @return : 无*/static void __exit ft5426_exit(void){i2c_del_driver(&ft5426_driver);}/* module_i2c_driver(ft5426_driver) */module_init(ft5426_init);module_exit(ft5426_exit);MODULE_LICENSE("GPL");

2、添加中断处理

#include "linux/init.h"#include "linux/module.h"#include "linux/printk.h"#include "linux/i2c.h"#include "linux/miscdevice.h"#include "linux/fs.h"#include "linux/delay.h"#include "asm-generic/uaccess.h"#include "linux/of_gpio.h"#include "linux/gpio.h"#include "linux/interrupt.h"typedef struct{struct i2c_client *client;/* i2c设备 */int irq_pin,reset_pin;/* 中断引脚和复位引脚 */int irqnum; /* 中断号 */}newchrdev_t;newchrdev_t newchrdev;/** @description: 复位FT5X06* @param - client : 要操作的i2c* @param - multidev: 自定义的multitouch设备* @return: 0,成功;其他负值,失败*/static int ft5x06_reset(struct i2c_client *client, newchrdev_t *dev){int ret = 0;if (gpio_is_valid(dev->reset_pin)) {/* 检查IO是否有效 *//* 申请复位IO,并且默认输出低电平 */ret = devm_gpio_request_one(&client->dev,dev->reset_pin, GPIOF_OUT_INIT_LOW,"ft5x06 reset");if (ret) {return ret;}msleep(5);gpio_set_value(dev->reset_pin, 1);/* 输出高电平,停止复位 */msleep(300);}return 0;}/** @description: FT5X06中断服务函数* @param - irq : 中断号 * @param - dev_id: 设备结构。* @return : 中断执行结果*/static irqreturn_t ft5x06_handler(int irq, void *dev_id){return 0;}/** @description: FT5x06中断初始化* @param - client : 要操作的i2c* @param - multidev: 自定义的multitouch设备* @return: 0,成功;其他负值,失败*/static int ft5x06_ts_irq(struct i2c_client *client, newchrdev_t *dev){int ret = 0;/* 1,申请中断GPIO */if (gpio_is_valid(dev->irq_pin)) {ret = devm_gpio_request_one(&client->dev, dev->irq_pin,GPIOF_IN, "ft5x06 irq");if (ret) {dev_err(&client->dev,"Failed to request GPIO %d, error %d\n",dev->irq_pin, ret);return ret;}}/* 2,申请中断,client->irq就是IO中断, */ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,ft5x06_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,client->name, &newchrdev);if (ret) {dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");return ret;}return 0;}/** @description: i2c驱动的probe函数,当驱动与*设备匹配以后此函数就会执行* @param - client : i2c设备* @param - id: i2c设备ID* @return: 0,成功;其他负值,失败*/static int ft5426_probe(struct i2c_client *client, const struct i2c_device_id *id){int ret = 0;newchrdev.client = client;printk("ft5426_probe!\r\n");/* 1、获取设备树中的中断和复位引脚*/newchrdev.irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);newchrdev.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);/* 2、初始化 ft5426 复位引脚 */ret = ft5x06_reset(newchrdev.client,&newchrdev);if(ret < 0) {goto fail;}/* 3、初始化中断 */ft5x06_ts_irq(newchrdev.client,&newchrdev);return 0;fail:return ret;}/** @description: i2c驱动的remove函数,移除i2c驱动的时候此函数会执行* @param - client : i2c设备* @return: 0,成功;其他负值,失败*/static int ft5426_remove(struct i2c_client *client){int ret = 0;printk("ft5426_remove!\r\n");return ret;}/* 传统匹配方式ID列表 */static const struct i2c_device_id ft5426_id[] = {{"focaltech,ft5426", 0}, {}};/* 设备树匹配列表 */static const struct of_device_id ft5426_of_match[] = {{.compatible = "focaltech,ft5426" },{/* Sentinel */ }};/* i2c驱动结构体 */static struct i2c_driver ft5426_driver = {.probe = ft5426_probe,.remove = ft5426_remove,.driver = {.owner = THIS_MODULE,.name = "ft5426",.of_match_table = ft5426_of_match, },.id_table = ft5426_id,};/** @description: 驱动入口函数* @param : 无* @return : 无*/static int __init ft5426_init(void){int ret = 0;ret = i2c_add_driver(&ft5426_driver);return ret;}/** @description: 驱动出口函数* @param : 无* @return : 无*/static void __exit ft5426_exit(void){i2c_del_driver(&ft5426_driver);}/* module_i2c_driver(ft5426_driver) */module_init(ft5426_init);module_exit(ft5426_exit);MODULE_LICENSE("GPL");

3、添加 input 子系统框架

#include "linux/init.h"#include "linux/module.h"#include "linux/printk.h"#include "linux/i2c.h"#include "linux/miscdevice.h"#include "linux/fs.h"#include "linux/delay.h"#include "asm-generic/uaccess.h"#include "linux/of_gpio.h"#include "linux/gpio.h"#include "linux/interrupt.h"#include "linux/input.h"#include "linux/input/mt.h"#define MAX_SUPPORT_POINTS5/* 5点触摸 */typedef struct{struct i2c_client *client;/* i2c设备 */int irq_pin,reset_pin;/* 中断引脚和复位引脚 */int irqnum; /* 中断号 */struct input_dev *input; /* input 输入结构体 */}newchrdev_t;newchrdev_t newchrdev;/** @description: 复位FT5X06* @param - client : 要操作的i2c* @param - multidev: 自定义的multitouch设备* @return: 0,成功;其他负值,失败*/static int ft5x06_reset(struct i2c_client *client, newchrdev_t *dev){int ret = 0;if (gpio_is_valid(dev->reset_pin)) {/* 检查IO是否有效 *//* 申请复位IO,并且默认输出低电平 */ret = devm_gpio_request_one(&client->dev,dev->reset_pin, GPIOF_OUT_INIT_LOW,"ft5x06 reset");if (ret) {return ret;}msleep(5);gpio_set_value(dev->reset_pin, 1);/* 输出高电平,停止复位 */msleep(300);}return 0;}/** @description: FT5X06中断服务函数* @param - irq : 中断号 * @param - dev_id: 设备结构。* @return : 中断执行结果*/static irqreturn_t ft5x06_handler(int irq, void *dev_id){return 0;}/** @description: FT5x06中断初始化* @param - client : 要操作的i2c* @param - multidev: 自定义的multitouch设备* @return: 0,成功;其他负值,失败*/static int ft5x06_irq(struct i2c_client *client, newchrdev_t *dev){int ret = 0;/* 1,申请中断GPIO */if (gpio_is_valid(dev->irq_pin)) {ret = devm_gpio_request_one(&client->dev, dev->irq_pin,GPIOF_IN, "ft5x06 irq");if (ret) {dev_err(&client->dev,"Failed to request GPIO %d, error %d\n",dev->irq_pin, ret);return ret;}}/* 2,申请中断,client->irq就是IO中断, */ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,ft5x06_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,client->name, &newchrdev);if (ret) {dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");return ret;}return 0;}/** @description: i2c驱动的probe函数,当驱动与*设备匹配以后此函数就会执行* @param - client : i2c设备* @param - id: i2c设备ID* @return: 0,成功;其他负值,失败*/static int ft5426_probe(struct i2c_client *client, const struct i2c_device_id *id){int ret = 0;newchrdev.client = client;printk("ft5426_probe!\r\n");/* 1、获取设备树中的中断和复位引脚*/newchrdev.irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);newchrdev.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);/* 2、初始化 ft5426 复位引脚 */ret = ft5x06_reset(newchrdev.client,&newchrdev);if(ret < 0) {goto fail;}/* 3、初始化中断 */ft5x06_irq(newchrdev.client,&newchrdev);/* 4、初始化input子系统 */newchrdev.input = devm_input_allocate_device(&client->dev);if (!newchrdev.input) {ret = -ENOMEM;goto fail;}newchrdev.input->name = client->name;newchrdev.input->id.bustype = BUS_I2C;newchrdev.input->dev.parent = &client->dev;__set_bit(EV_KEY, newchrdev.input->evbit);__set_bit(EV_ABS, newchrdev.input->evbit);__set_bit(BTN_TOUCH, newchrdev.input->keybit);input_set_abs_params(newchrdev.input, ABS_X, 0, 1024, 0, 0);input_set_abs_params(newchrdev.input, ABS_Y, 0, 600, 0, 0);input_set_abs_params(newchrdev.input, ABS_MT_POSITION_X,0, 1024, 0, 0);input_set_abs_params(newchrdev.input, ABS_MT_POSITION_Y,0, 600, 0, 0);ret = input_mt_init_slots(newchrdev.input, MAX_SUPPORT_POINTS, 0);if (ret) {goto fail;}ret = input_register_device(newchrdev.input);if (ret)goto fail;return 0;fail:return ret;}/** @description: i2c驱动的remove函数,移除i2c驱动的时候此函数会执行* @param - client : i2c设备* @return: 0,成功;其他负值,失败*/static int ft5426_remove(struct i2c_client *client){int ret = 0;printk("ft5426_remove!\r\n");return ret;}/* 传统匹配方式ID列表 */static const struct i2c_device_id ft5426_id[] = {{"focaltech,ft5426", 0}, {}};/* 设备树匹配列表 */static const struct of_device_id ft5426_of_match[] = {{.compatible = "focaltech,ft5426" },{/* Sentinel */ }};/* i2c驱动结构体 */static struct i2c_driver ft5426_driver = {.probe = ft5426_probe,.remove = ft5426_remove,.driver = {.owner = THIS_MODULE,.name = "ft5426",.of_match_table = ft5426_of_match, },.id_table = ft5426_id,};/** @description: 驱动入口函数* @param : 无* @return : 无*/static int __init ft5426_init(void){int ret = 0;ret = i2c_add_driver(&ft5426_driver);return ret;}/** @description: 驱动出口函数* @param : 无* @return : 无*/static void __exit ft5426_exit(void){i2c_del_driver(&ft5426_driver);}/* module_i2c_driver(ft5426_driver) */module_init(ft5426_init);module_exit(ft5426_exit);MODULE_LICENSE("GPL");

4、初始化 FT5426

5、上报触摸点信息

六、添加设备树

1、确定FT5426使用的 I2C 引脚

通信接口使用I2C2

INTGPIO1_IO09

RSTGPIO5_IO09

2、添加pinctrl子系统相关配置

pinctrl_tsc: tscgrp {fsl,pins = </* 7寸RGB屏幕,FT5426 */MX6UL_PAD_GPIO1_IO09__GPIO1_IO090xF080 /* TSC_INT */>;};

pinctrl_tsc_reset: tsc_reset {fsl,pins = <MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x10B0>;};

3、添加FT5426相关配置

&i2c2 {clock_frequency = <100000>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c2>;status = "okay";……ft5426: ft5426@38 {compatible = "focaltech,ft5426";reg = <0x38>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_tsc&pinctrl_tsc_reset >; interrupt-parent = <&gpio1>; interrupts = <9 0>; reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>; interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;status = "okay";};……};

4、确定引脚是否冲突

5、编译

onlylove@ubuntu:~/my/linux/linux-imx-4.1.15$ make dtbsCHKinclude/config/kernel.releaseCHKinclude/generated/uapi/linux/version.hCHKinclude/generated/utsrelease.hmake[1]: 'include/generated/mach-types.h' is up to date.CHKinclude/generated/bounds.hCHKinclude/generated/asm-offsets.hCALL scripts/checksyscalls.shDTCarch/arm/boot/dts/imx6ull-alientek-emmc.dtbDTCarch/arm/boot/dts/imx6ull-alientek-nand.dtbonlylove@ubuntu:~/my/linux/linux-imx-4.1.15$

6、测试

# pwd/proc/device-tree/soc/aips-bus@02100000## ls#address-cells lcdif@021c8000 serial@021f0000#size-cellsmmdc@021b0000 serial@021f4000adc@02198000 name serial@021fc000compatible ocotp-ctrl@021bc000 usb@02184000csi@021c4000 pxp@021cc000 usb@02184200csu@021c0000 qspi@021e0000 usbmisc@02184800ethernet@02188000 rangesusdhc@02190000i2c@021a0000 reg usdhc@02194000i2c@021a4000 romcp@021ac000 weim@021b8000i2c@021a8000 serial@021e8000i2c@021f8000 serial@021ec000## cd i2c@021a4000## ls#address-cells compatible name reg#size-cellsft5426@38 ov5640@3c statusclock_frequency gt9147@14 pinctrl-0 wm8960@1aclocks interrupts pinctrl-names## cd ft5426@38/## lscompatible interrupts pinctrl-namesstatusinterrupt-gpios name reginterrupt-parent pinctrl-0 reset-gpios## cat compatiblefocaltech,ft5426##

七、驱动编写

1、驱动源码

#include "linux/init.h"#include "linux/module.h"#include "linux/printk.h"#include "linux/i2c.h"#include "linux/miscdevice.h"#include "linux/fs.h"#include "linux/delay.h"#include "asm-generic/uaccess.h"#include "linux/of_gpio.h"#include "linux/gpio.h"#include "linux/interrupt.h"#include "linux/input.h"#include "linux/input/mt.h"#define MAX_SUPPORT_POINTS5/* 5点触摸 */#define TOUCH_EVENT_DOWN0x00/* 按下 */#define TOUCH_EVENT_UP0x01/* 抬起 */#define TOUCH_EVENT_ON0x02/* 接触 */#define TOUCH_EVENT_RESERVED0x03/* 保留 *//* FT5X06寄存器相关宏定义 */#define FT5X06_TD_STATUS_REG0X02/*状态寄存器地址 */#define FT5x06_DEVICE_MODE_REG0X00 /* 模式寄存器 */#define FT5426_IDG_MODE_REG0XA4/* 中断模式*/#define FT5X06_READLEN29/* 要读取的寄存器个数 */typedef struct{struct i2c_client *client;/* i2c设备 */int irq_pin,reset_pin;/* 中断引脚和复位引脚 */int irqnum; /* 中断号 */struct input_dev *input; /* input 输入结构体 */}newchrdev_t;newchrdev_t newchrdev;/** @description: 复位FT5X06* @param - client : 要操作的i2c* @param - multidev: 自定义的multitouch设备* @return: 0,成功;其他负值,失败*/static int ft5x06_reset(struct i2c_client *client, newchrdev_t *dev){int ret = 0;if (gpio_is_valid(dev->reset_pin)) {/* 检查IO是否有效 *//* 申请复位IO,并且默认输出低电平 */ret = devm_gpio_request_one(&client->dev,dev->reset_pin, GPIOF_OUT_INIT_LOW,"ft5x06 reset");if (ret) {return ret;}msleep(5);gpio_set_value(dev->reset_pin, 1);/* 输出高电平,停止复位 */msleep(300);}return 0;}/** @description: 向ft5x06多个寄存器写入数据* @param - dev: ft5x06设备* @param - reg: 要写入的寄存器首地址* @param - val: 要写入的数据缓冲区* @param - len: 要写入的数据长度* @return : 操作结果*/static int ft5x06_write_regs(newchrdev_t *dev, unsigned char reg, unsigned char *buf, unsigned char len){unsigned char b[256];struct i2c_msg msg;struct i2c_client *client = (struct i2c_client *)dev->client;b[0] = reg;/* 寄存器首地址 */memcpy(&b[1],buf,len);/* 将要写入的数据拷贝到数组b里面 */msg.addr = client->addr;/* ft5x06地址 */msg.flags = 0;/* 标记为写数据 */msg.buf = b;/* 要写入的数据缓冲区 */msg.len = len + 1;/* 要写入的数据长度 */return i2c_transfer(client->adapter, &msg, 1);}/** @description: 向ft5x06指定寄存器写入指定的值,写一个寄存器* @param - dev: ft5x06设备* @param - reg: 要写的寄存器* @param - data: 要写入的值* @return : 无*/static void ft5x06_write_reg(newchrdev_t *dev, unsigned char reg, unsigned char data){unsigned char buf = 0;buf = data;ft5x06_write_regs(dev, reg, &buf, 1);}/** @description: 从FT5X06读取多个寄存器数据* @param - dev: ft5x06设备* @param - reg: 要读取的寄存器首地址* @param - val: 读取到的数据* @param - len: 要读取的数据长度* @return : 操作结果*/static int ft5x06_read_regs(newchrdev_t *dev, unsigned char reg, void *val, int len){int ret;struct i2c_msg msg[2];struct i2c_client *client = (struct i2c_client *)dev->client;/* msg[0]为发送要读取的首地址 */msg[0].addr = client->addr;/* ft5x06地址 */msg[0].flags = 0;/* 标记为发送数据 */msg[0].buf = &reg;/* 读取的首地址 */msg[0].len = 1;/* reg长度*//* msg[1]读取数据 */msg[1].addr = client->addr;/* ft5x06地址 */msg[1].flags = I2C_M_RD;/* 标记为读取数据*/msg[1].buf = val;/* 读取数据缓冲区 */msg[1].len = len;/* 要读取的数据长度*/ret = i2c_transfer(client->adapter, msg, 2);if(ret == 2) {ret = 0;} else {ret = -EREMOTEIO;}return ret;}/** @description: FT5X06中断服务函数* @param - irq : 中断号 * @param - dev_id: 设备结构。* @return : 中断执行结果*/static irqreturn_t ft5x06_handler(int irq, void *dev_id){newchrdev_t *multidata = dev_id;u8 rdbuf[29];int i, type, x, y, id;int offset, tplen;int ret;bool down;offset = 1; /* 偏移1,也就是0X02+1=0x03,从0X03开始是触摸值 */tplen = 6;/* 一个触摸点有6个寄存器来保存触摸值 */memset(rdbuf, 0, sizeof(rdbuf));/* 清除 *//* 读取FT5X06触摸点坐标从0X02寄存器开始,连续读取29个寄存器 */ret = ft5x06_read_regs(multidata, FT5X06_TD_STATUS_REG, rdbuf, FT5X06_READLEN);if (ret) {goto fail;}/* 上报每一个触摸点坐标 */for (i = 0; i < MAX_SUPPORT_POINTS; i++) {u8 *buf = &rdbuf[i * tplen + offset];/* 以第一个触摸点为例,寄存器TOUCH1_XH(地址0X03),各位描述如下:* bit7:6 Event flag 0:按下 1:释放 2:接触 3:没有事件* bit5:4 保留* bit3:0 X轴触摸点的11~8位。*/type = buf[0] >> 6;/* 获取触摸类型 */if (type == TOUCH_EVENT_RESERVED)continue;/* 我们所使用的触摸屏和FT5X06是反过来的 */x = ((buf[2] << 8) | buf[3]) & 0x0fff;y = ((buf[0] << 8) | buf[1]) & 0x0fff;/* 以第一个触摸点为例,寄存器TOUCH1_YH(地址0X05),各位描述如下:* bit7:4 Touch ID 触摸ID,表示是哪个触摸点* bit3:0 Y轴触摸点的11~8位。*/id = (buf[2] >> 4) & 0x0f;down = type != TOUCH_EVENT_UP;input_mt_slot(multidata->input, id);input_mt_report_slot_state(multidata->input, MT_TOOL_FINGER, down);if (!down)continue;input_report_abs(multidata->input, ABS_MT_POSITION_X, x);input_report_abs(multidata->input, ABS_MT_POSITION_Y, y);}input_mt_report_pointer_emulation(multidata->input, true);input_sync(multidata->input);fail:return IRQ_HANDLED;}/** @description: FT5x06中断初始化* @param - client : 要操作的i2c* @param - multidev: 自定义的multitouch设备* @return: 0,成功;其他负值,失败*/static int ft5x06_irq(struct i2c_client *client, newchrdev_t *dev){int ret = 0;/* 1,申请中断GPIO */if (gpio_is_valid(dev->irq_pin)) {ret = devm_gpio_request_one(&client->dev, dev->irq_pin,GPIOF_IN, "ft5x06 irq");if (ret) {dev_err(&client->dev,"Failed to request GPIO %d, error %d\n",dev->irq_pin, ret);return ret;}}/* 2,申请中断,client->irq就是IO中断, */ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,ft5x06_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,client->name, &newchrdev);if (ret) {dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");return ret;}return 0;}/** @description: i2c驱动的probe函数,当驱动与*设备匹配以后此函数就会执行* @param - client : i2c设备* @param - id: i2c设备ID* @return: 0,成功;其他负值,失败*/static int ft5426_probe(struct i2c_client *client, const struct i2c_device_id *id){int ret = 0;newchrdev.client = client;printk("ft5426_probe!\r\n");/* 1、获取设备树中的中断和复位引脚*/newchrdev.irq_pin = of_get_named_gpio(client->dev.of_node, "interrupt-gpios", 0);newchrdev.reset_pin = of_get_named_gpio(client->dev.of_node, "reset-gpios", 0);/* 2、初始化 ft5426 复位引脚 */ret = ft5x06_reset(newchrdev.client,&newchrdev);if(ret < 0) {goto fail;}/* 3、初始化中断 */ft5x06_irq(newchrdev.client,&newchrdev);/* 4、初始化input子系统 */newchrdev.input = devm_input_allocate_device(&client->dev);if (!newchrdev.input) {ret = -ENOMEM;goto fail;}newchrdev.input->name = client->name;newchrdev.input->id.bustype = BUS_I2C;newchrdev.input->dev.parent = &client->dev;__set_bit(EV_KEY, newchrdev.input->evbit);__set_bit(EV_ABS, newchrdev.input->evbit);__set_bit(BTN_TOUCH, newchrdev.input->keybit);input_set_abs_params(newchrdev.input, ABS_X, 0, 1024, 0, 0);input_set_abs_params(newchrdev.input, ABS_Y, 0, 600, 0, 0);input_set_abs_params(newchrdev.input, ABS_MT_POSITION_X,0, 1024, 0, 0);input_set_abs_params(newchrdev.input, ABS_MT_POSITION_Y,0, 600, 0, 0);ret = input_mt_init_slots(newchrdev.input, MAX_SUPPORT_POINTS, 0);if (ret) {goto fail;}ret = input_register_device(newchrdev.input);if (ret)goto fail;/* 5、初始化 ft5426 */ft5x06_write_reg(&newchrdev, FT5x06_DEVICE_MODE_REG, 0); /* 进入正常模式 */ft5x06_write_reg(&newchrdev, FT5426_IDG_MODE_REG, 1); /* FT5426中断模式*/return 0;fail:return ret;}/** @description: i2c驱动的remove函数,移除i2c驱动的时候此函数会执行* @param - client : i2c设备* @return: 0,成功;其他负值,失败*/static int ft5426_remove(struct i2c_client *client){int ret = 0;printk("ft5426_remove!\r\n");return ret;}/* 传统匹配方式ID列表 */static const struct i2c_device_id ft5426_id[] = {{"focaltech,ft5426", 0}, {}};/* 设备树匹配列表 */static const struct of_device_id ft5426_of_match[] = {{.compatible = "focaltech,ft5426" },{/* Sentinel */ }};/* i2c驱动结构体 */static struct i2c_driver ft5426_driver = {.probe = ft5426_probe,.remove = ft5426_remove,.driver = {.owner = THIS_MODULE,.name = "ft5426",.of_match_table = ft5426_of_match, },.id_table = ft5426_id,};/** @description: 驱动入口函数* @param : 无* @return : 无*/static int __init ft5426_init(void){int ret = 0;ret = i2c_add_driver(&ft5426_driver);return ret;}/** @description: 驱动出口函数* @param : 无* @return : 无*/static void __exit ft5426_exit(void){i2c_del_driver(&ft5426_driver);}/* module_i2c_driver(ft5426_driver) */module_init(ft5426_init);module_exit(ft5426_exit);MODULE_LICENSE("GPL");

2、测试

# lsft5426.ko## ls -l /dev/input/total 0crw-r----- 1 rootroot 13, 64 Jan 1 00:00 event0crw-r----- 1 rootroot 13, 65 Jan 1 00:00 event1crw-r----- 1 rootroot 13, 63 Jan 1 00:00 mice## insmod ft5426.koft5426_probe!input: ft5426 as /devices/platform/soc/2100000.aips-bus/21a4000.i2c/i2c-1/1-0038/input/input2## rmmod ft5426.koft5426_remove!## insmod ft5426.koft5426_probe!input: ft5426 as /devices/platform/soc/2100000.aips-bus/21a4000.i2c/i2c-1/1-0038/input/input3## ls -l /dev/input/total 0crw-r----- 1 rootroot 13, 64 Jan 1 00:00 event0crw-r----- 1 rootroot 13, 65 Jan 1 00:00 event1crw-r----- 1 rootroot 13, 66 Jan 1 01:20 event2crw-r----- 1 rootroot 13, 63 Jan 1 00:00 micecrw-r----- 1 rootroot 13, 32 Jan 1 01:20 mouse0## hexdump /dev/input/random: nonblocking pool is initialized# hexdump /dev/input/event3hexdump: /dev/input/event3: No such file or directory# hexdump /dev/input/event20000000 130e 0000 165c 0004 0003 0039 0000 00000000010 130e 0000 165c 0004 0003 0035 01bd 00000000020 130e 0000 165c 0004 0003 0036 0195 00000000030 130e 0000 165c 0004 0001 014a 0001 00000000040 130e 0000 165c 0004 0003 0000 01bd 00000000050 130e 0000 165c 0004 0003 0001 0195 00000000060 130e 0000 165c 0004 0000 0000 0000 00000000070 130e 0000 de2f 0004 0003 0039 ffff ffff0000080 130e 0000 de2f 0004 0001 014a 0000 00000000090 130e 0000 de2f 0004 0000 0000 0000 000000000a0 130f 0000 bb6e 0004 0003 0039 0001 000000000b0 130f 0000 bb6e 0004 0003 0035 01be 000000000c0 130f 0000 bb6e 0004 0003 0036 019b 000000000d0 130f 0000 bb6e 0004 0001 014a 0001 000000000e0 130f 0000 bb6e 0004 0003 0000 01be 000000000f0 130f 0000 bb6e 0004 0003 0001 019b 00000000100 130f 0000 bb6e 0004 0000 0000 0000 00000000110 130f 0000 ff0b 0005 0003 0039 ffff ffff0000120 130f 0000 ff0b 0005 0001 014a 0000 00000000130 130f 0000 ff0b 0005 0000 0000 0000 0000^C## rmmod ft5426.koft5426_remove!#

八、tslib 移植

九、使用内核自带的ft5x06驱动

如果觉得《i.MX 6ULL 驱动开发 二十四:多点触摸屏》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。