该笔记是在学习电容触摸相关知识的时候说记录的笔记,总的来说,这是这个相对比较综合的时候,会设计到IIC驱动设备,中断驱动,input子系统。这些在前面的已经进行学习过了,因为笔者有一款传感器需要些,也是需要设计到上述相关的知识。而本实验中除此之外还需要补充一个触摸协议MT协议。
Type A:适用于触摸点不能被区分或者追踪,此类型的设备上报原始数据(这种现在用的很少)。
Type B:适用于有硬件追踪并能区分触摸点的触摸设备,此类型设备通过 slot 更新某一个
触摸点的信息,FT5426 就属于此类型,一般的多点电容触摸屏 IC 都有此能力。
在产生中断后,一般是通过中断的的处理上报(耗时的操作放到下半部或者是通过中断线程化处理)
该模式不能识别多指滑动轨迹,只能将点上报,所以现在已经用得不多叻,就只简单介绍一下。
//通过input子系统进行上报,一个点一个点的上报
static irqreturn_t st1232_ts_irq_handler(int irq, void *dev_id)
{
.....
ret = st1232_ts_read_data(ts);
if (ret < 0)
goto end;
/* multi touch protocol */
for (i = 0; i < MAX_FINGERS; i++)
{
if (!finger[i].is_valid)
continue;
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, finger[i].t);
input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);
input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].y);
input_mt_sync(input_dev);
count++;
}
.....
/* SYN_REPORT */
input_sync(input_dev);
end:
return IRQ_HANDLED;
}
该模式的上报可以理解为分组上报,每一组会关联一个ID,通过这个ID去区分当前有几条触摸的线。上报的方式如下:
1 ABS_MT_SLOT 0 //上报 ABS_MT_SLOT 事件
2 ABS_MT_TRACKING_ID 45 //关联的ID 来完成对触摸点的添加、替换或删除input_mt_report_slot_state
3 ABS_MT_POSITION_X x[0] //上报触摸点 0 的 X-Y 轴坐标,使input_report_abs
4 ABS_MT_POSITION_Y y[0]
5 ABS_MT_SLOT 1
6 ABS_MT_TRACKING_ID 46
7 ABS_MT_POSITION_X x[1]
8 ABS_MT_POSITION_Y y[1]
9 SYN_REPORT
static void ili210x_report_events(struct input_dev *input, const struct touchdata *touchdata)
{
int i;
bool touch;
unsigned int x, y;
const struct finger *finger;
for (i = 0; i < MAX_TOUCHES; i++)
{
input_mt_slot(input, i); //上报事件
finger = &touchdata->finger[i];
touch = touchdata->status & (1 << i);
input_mt_report_slot_state(input, MT_TOOL_FINGER, touch); //上报关联触摸ID,区分不同ID组的
if (touch)
{
x = finger->x_low | (finger->x_high << 8);
y = finger->y_low | (finger->y_high << 8);
input_report_abs(input, ABS_MT_POSITION_X, x); //上报
input_report_abs(input, ABS_MT_POSITION_Y, y);
}
}
input_mt_report_pointer_emulation(input, false);
input_sync(input); //上报处理
}
接下来就是抄一套软件框架,写的时候好有个参考,其实也就是和IIC总线设备差不多,在probe和remove多了部分input和MT相关的初始化注册/注销。
/* 设备树匹配表 */
static const struct i2c_device_id xxx_ts_id[] =
{
{ "xxx", 0, },
{ /* sentinel */ }
};
/* 设备树匹配表 */
static const struct of_device_id xxx_of_match[] =
{
{ .compatible = "xxx", },
{ /* sentinel */ }
};
/* i2c 驱动结构体 */
static struct i2c_driver ft5x06_ts_driver =
{
.driver = {
.owner = THIS_MODULE,
.name = "edt_ft5x06",
.of_match_table = of_match_ptr(xxx_of_match),
},
.id_table = xxx_ts_id,
.probe = xxx_ts_probe,
.remove = xxx_ts_remove,
};
/*
* @description : 驱动入口函数
* @param : 无
* @return : 无
*/
static int __init xxx_init(void)
{
int ret = 0;
ret = i2c_add_driver(&xxx_ts_driver);
return ret;
}
/*
* @description : 驱动出口函数
* @param : 无
* @return : 无
*/
static void __exit xxx_exit(void)
{
i2c_del_driver(&ft5x06_ts_driver);
}
module_init(xxx_init);
module_exit(xxx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("your name");
static int xxx_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct input_dev *input;
/* 1、初始化 I2C */
......
/* 2,申请中断, */
devm_request_threaded_irq(&client->dev, client->irq, NULL,
xxx_handler, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
client->name, &xxx);
......
/* 3,input 设备申请与初始化 */
input = devm_input_allocate_device(&client->dev);
input->name = client->name;
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
......
/* 4,初始化 input 和 MT */
__set_bit(EV_ABS, input->evbit);
__set_bit(BTN_TOUCH, input->keybit);
input_set_abs_params(input, ABS_X, 0, width, 0, 0);
input_set_abs_params(input, ABS_Y, 0, height, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_X,0, width, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y,0, height, 0, 0);
input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
......
/* 5,注册 input_dev */
input_register_device(input);
......
}