imx6ull——多点电容触摸

电容触摸寄存器

在这里插入图片描述
在这里插入图片描述
触点最多5个
在这里插入图片描述

触摸屏实现由 IIC驱动、中断驱动、 input子系统组成

触摸屏类型Type A和 Type B

Type A:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据 (此类型在实际使
用中非常少!
Type B:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot更新某一个
触摸点的信息, FT5426就属于此类型,一般的多点电容触摸屏 IC都有此能力。

Type B和 Type A相比最大的区别就是 Type B可以区分出触摸点, 因此可以减少发送到用户空间的数据。

Type A触摸点数据上报时序

 ABS_MT_POSITION_X x[0]  //第一个点x
 ABS_MT_POSITION_Y y[0]  //第一个点y
 SYN_MT_REPORT  //报告前一个	可以读取,后一个可以开始,使用 input_mt_sync触发此事件
 ABS_MT_POSITION_X x[1] 
 ABS_MT_POSITION_Y y[1] 
 SYN_MT_REPORT       // input_event(dev, EV_SYN, SYN_MT_REPORT, 0);
 SYN_REPORT

Type A设备,内核驱动 需要一次性将触摸屏上所有的触摸点信息全部上报,每个触摸点的信息在本次上报事件流中的顺序不重要,因为事件的过滤和手指(触摸点 )跟踪是在内核空间处理的。

Type B触摸点数据上报时序

 ABS_MT_SLOT 0 //表示要上报第一个ID,input_mt_solt
 ABS_MT_TRACKING_ID 45 //自动分配ID,给ID赋值-1,表示删除此点
 ABS_MT_POSITION_X x[0] 
 ABS_MT_POSITION_Y y[0] 
 ABS_MT_SLOT 1 
 ABS_MT_TRACKING_ID 46 
 ABS_MT_POSITION_X x[1] 
 ABS_MT_POSITION_Y y[1] 
 SYN_REPORT

Type B使用 slot协议区分具体的触摸点, slot需要用到 ABS_MT_TRACKING_ID消息,这个 ID需要硬件提供,或者通过原始数据计算出来。
Type B设备驱动需要给每个识别出来的触摸点分配一个 slot,后面使用这个 slot来上报触摸点信息。可以通过 slot的 ABS_MT_TRACKING_ID来新增、替换或删除触摸点。一个非负数的 ID表示一个有效的触摸点, -1这个 ID表示未使用 slot。一个以前不存在的 ID表示这是一个新加的触摸点,一个 ID如果再也不存在了就表示删除了。
有些设备识别或追踪的 触摸点信息要比他上报的多,这些设备驱动应该给硬件上报的每个触摸点分配一个 Type B的 slot。一旦检测到某一个 slot关联的触摸点 ID发生了变化,驱动就应该改变这个 slot的 ABS_MT_TRACKING_ID,使这个 slot失效。如果硬件设备追踪到了比他正在上报的还要多的触摸点,那么驱动程序应该发送 BTN_TOOL_*TAP消息

多点电容驱动框架

  1. 接口采用I2C传输数据
  2. 使用中断采集触摸点数据
  3. 需要从触摸屏寄存器读取数据,使用input子系统
  4. typeB类型读取数据,MT协议上报数据(MT属于input子系统)

设备树填写

FT5426触摸芯片用到了 4个 IO,一个复位 IO、一个中断 IO、 I2C2的 SCL和 SDA

中断

&iomuxc下

		/*touch */
		pinctrl_tsc: tscgrp {  
			fsl,pins = < 
			 MX6UL_PAD_GPIO1_IO09__GPIO1_IO09 0xF080 /* TSC_INT */ 
			  >;  
		};

复位

&iomuxc_snvs下

		/* MT RET*/
		pinctrl_tsc_reset: tsc_reset{  
			fsl,pins = < 
			 MX6ULL_PAD_SNVS_TAMPER9__GPIO5_IO09 0x10B0 
			  >; 
		 };

I2C SCL,SDA

		pinctrl_i2c2: i2c2grp {
			fsl,pins = <
				MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
				MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
			>;
		};

I2C下的设备FT5426

位于 &i2c2{ }中

&i2c2 {
	clock_frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c2>;
	status = "okay";

 	/* touch FT5426 */
 		ft5426: ft5426@38 {
   	   	compatible = "edt,edt-ft5426";
     	reg = <0x38>;  /* 器件地址 */
      	pinctrl-names = "default";
    		pinctrl-0 = <&pinctrl_tsc    /* 中断节点 */
                    &pinctrl_tsc_reset >;   /* 复位节点 */
     	interrupt-parent = <&gpio1>;  /* GPIO组为 GPIO1 */
      	interrupts = <9 0>; /* GPIO1组的 IOI09,0为触发方式(上升沿,下降沿等,没查到 */
      	reset-gpios = <&gpio5 9 GPIO_ACTIVE_LOW>;  
      	interrupt-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>; 
 	};
 	.........
 	.........
};

驱动编写

1. I2C驱动编写

#include <linux/module.h>
#include <linux/ratelimit.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/input/edt-ft5x06.h>
#include <linux/i2c.h>

/* ft5426 设备结构体*/
struct ft5426_dev
{
    void *private_data;
};

struct ft5426_dev ft5426;

static int ft5x06_read_regs(struct ft5x06_dev *dev, u8 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;
}

static s32 ft5x06_write_regs(struct ft5x06_dev *dev, u8 reg, u8 *buf, u8 len)
{
	u8 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);
}

static int ft5x06_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    printk("ft5426_probe!\r\n");
    return 0;
}
static int ft5x06_ts_remove(struct i2c_client *client)
{	
    return 0;
}
/*
 *  传统驱动匹配表
 */ 
static const struct i2c_device_id ft5x06_ts_id[] = {
	{ "edt-ft5206", 0, },
	{ "edt-ft5426", 0, },
	{ /* sentinel */ }
};

/*
 * 设备树匹配表 
 */
static const struct of_device_id ft5x06_of_match[] = {
	{ .compatible = "edt,edt-ft5206", },
	{ .compatible = "edt,edt-ft5426", },
	{ /* sentinel */ }
};

/* i2c驱动结构体 */	
static struct i2c_driver ft5x06_ts_driver = {
	.driver = {
		.owner = THIS_MODULE,
		.name = "edt_ft5x06",
		.of_match_table = of_match_ptr(ft5x06_of_match),
	},
	.id_table = ft5x06_ts_id,
	.probe    = ft5x06_ts_probe,
	.remove   = ft5x06_ts_remove,
};


/*设备入口函数*/
static int __init ft5x06_init(void)
{
    int ret=0;
    ret=i2c_add_driver(&ft5x06_ts_driver);
    return ret;
}

/*设备出口函数*/
static void __exit ft5x06_exit(void)
{
    i2c_del_driver(&ft5x06_ts_driver);
}

module_init(ft5x06_init);
module_exit(ft5x06_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("LIU");

2. 中断和复位

  1. 设备结构体
struct ft5426_dev
{
	struct device_node	*nd; 				/* 设备节点 		*/
	int irq_pin,reset_pin;					/* 中断和复位IO		*/
	int irqnum;								/* 中断号    		*/
	void *private_data;						/* 私有数据 		*/
	struct i2c_client *client;				/* I2C客户端 		*/
};
  1. probe 函数

复位初始化

/* 初始化复位*/
static int ft5x06_ts_reset(struct i2c_client *client, struct ft5x06_dev *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,
					"edt-ft5x06 reset");
		if (ret) {
			return ret;
		}

		msleep(5);
		gpio_set_value(dev->reset_pin, 1);	/* 输出高电平,停止复位 */
		msleep(300);
	}

	return 0;
}

中断处理函数

/*中断处理函数*/
static irqreturn_t ft5x06_handler(int irq, void *dev_id)
{
    printk("ft5x06_handler\r\n");
     return IRQ_HANDLED;
}

中断初始化

static int ft5x06_ts_irq(struct i2c_client *client, struct ft5x06_dev *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, "edt-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, &ft5x06);
	if (ret) {
		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
		return ret;
	}

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值