MT6853 android11 TP fts_ts 驱动框架解析
环境:
MT6853 Android11 focaltech_touch HD720 5寸tp
一、TP代码分析
1、硬件参数设置
在dts文件中,对照硬件接口,修改对应GPIO设置,还有TP的虚拟键坐标、分辨率等参数信息
//cust_mt6853_touch_1080x1920.dtsi
&touch {tpd-resolution = <720 1280>;lcm-resolution = <720 1280>;use-tpd-button = <0>;tpd-key-num = <3>;tpd-key-local = <139 172 158 0>;tpd-key-dim-local = <90 883 100 40 230 883 100 40 370 883 100 40 0 0 0 0>;tpd-max-touch-num = <5>;tpd-filter-enable = <1>;tpd-filter-pixel-density = <146>;tpd-filter-custom-prameters = <0 0 0 0 0 0 0 0 0 0 0 0>;tpd-filter-custom-speed = <0 0 0>;pinctrl-names = "default", "state_eint_as_int","state_eint_output0", "state_eint_output1","state_rst_output0", "state_rst_output1";pinctrl-0 = <&ctp_pins_default>;pinctrl-1 = <&ctp_ts_eint_as_int>;pinctrl-2 = <&ctp_ts_eint_output0>;pinctrl-3 = <&ctp_ts_eint_output1>;pinctrl-4 = <&ctp_ts_rst_output0>;pinctrl-5 = <&ctp_ts_rst_output1>;status = "okay";};..........
文件mtk_tpd.c是TP设备驱动的入口,可以通过分析本文件简单捋一下代码结构。
首先,是通过platform_driver_register注册一个设备驱动:
//mtk_tpd.c
static void tpd_init_work_callback(struct work_struct *work){TPD_DEBUG("MediaTek touch panel driver init\n");if (platform_driver_register(&tpd_driver) != 0)TPD_DMESG("unable to register touch panel driver.\n");}static int __init tpd_device_init(void){int res = 0;tpd_init_workqueue = create_singlethread_workqueue("mtk-tpd");INIT_WORK(&tpd_init_work, tpd_init_work_callback);res = queue_work(tpd_init_workqueue, &tpd_init_work);if (!res)pr_info("tpd : touch device init failed res:%d\n", res);return 0;}
//设备驱动结构体
static struct platform_driver tpd_driver = {.remove = tpd_remove,.shutdown = NULL,.probe = tpd_probe,.driver = {.name = TPD_DEVICE,.pm = &tpd_pm_ops,.owner = THIS_MODULE,.of_match_table = touch_of_match,},};
我们看一下这个设备驱动的probe函数:
//mtk_tpd.c
static int tpd_probe(struct platform_device *pdev)
{
......
//首先,注册了一个杂项设备
if (misc_register(&tpd_misc_device)){pr_err("mtk_tpd: tpd_misc_device register failedn");}
//读取dts中相关gpio等设置
tpd_get_gpio_info(pdev);
//在内存中为输入设备结构体分配一个空间,并对结构体成员进行初始化
tpd = kmalloc(sizeof(struct tpd_device), GFP_KERNEL);if (tpd == NULL)return -ENOMEM;memset(tpd, 0, sizeof(struct tpd_device));tpd->dev = input_allocate_device();if (tpd->dev == NULL) {kfree(tpd);return -ENOMEM;}
//看下是否存在横屏竖用,TP也要跟着LCD进行横竖转换
#ifdef CONFIG_MTK_LCM_PHYSICAL_ROTATIONif (0 == strncmp(CONFIG_MTK_LCM_PHYSICAL_ROTATION, "90", 2) || 0 == strncmp(CONFIG_MTK_LCM_PHYSICAL_ROTATION, "270", 3)){#ifdef CONFIG_MTK_FB /*Fix build errors,as some projects cannot support these apis while bring up*/TPD_RES_Y = DISP_GetScreenWidth();TPD_RES_X = DISP_GetScreenHeight();#endif}else#endif{#ifdef CONFIG_CUSTOM_LCM_X#ifndef CONFIG_MTK_FPGA#ifdef CONFIG_MTK_FB /*Fix build errors,as some projects cannot support these apis while bring up*/TPD_RES_X = DISP_GetScreenWidth();TPD_RES_Y = DISP_GetScreenHeight();#endif#endif#else#ifdef CONFIG_LCM_WIDTHret = kstrtoul(CONFIG_LCM_WIDTH, 0, &tpd_res_x);if (ret < 0) {pr_err("Touch down get lcm_x failed");return ret;}TPD_RES_X = tpd_res_x;ret = kstrtoul(CONFIG_LCM_HEIGHT, 0, &tpd_res_x);*/if (ret < 0) {pr_err("Touch down get lcm_y failed");return ret;}TPD_RES_Y = tpd_res_y;#endif#endif}
//设置输入设备参数,包括时间类型等;
tpd_mode = TPD_MODE_NORMAL;tpd_mode_axis = 0;tpd_mode_min = TPD_RES_Y / 2;tpd_mode_max = TPD_RES_Y;tpd_mode_keypad_tolerance = TPD_RES_X * TPD_RES_X / 1600;
//初始化输入设备结构
tpd->dev->name = TPD_DEVICE;set_bit(EV_ABS, tpd->dev->evbit);set_bit(EV_KEY, tpd->dev->evbit);set_bit(ABS_X, tpd->dev->absbit);set_bit(ABS_Y, tpd->dev->absbit);set_bit(ABS_PRESSURE, tpd->dev->absbit);#if !defined(CONFIG_MTK_S3320) && !defined(CONFIG_MTK_S3320_47)&& !defined(CONFIG_MTK_S3320_50) && !defined(CONFIG_MTK_MIT200)&& !defined(CONFIG_TOUCHSCREEN_SYNAPTICS_S3528) && !defined(CONFIG_MTK_S7020)set_bit(BTN_TOUCH, tpd->dev->keybit);#endif /* CONFIG_MTK_S3320 */set_bit(INPUT_PROP_DIRECT, tpd->dev->propbit);
//将注册到的platform_device保存到创建的输入设备中;
tpd->tpd_dev = &pdev->dev;
//遍历tpd_driver_list,找到当前在用TP;
for (i = 1; i < TP_DRV_MAX_COUNT; i++){if (tpd_driver_list[i].tpd_device_name != NULL){tpd_driver_list[i].tpd_local_init();if (tpd_load_status == 1){TPD_DMESG("[mtk-tpd]tpd_probe, tpd_driver_name=%sn",tpd_driver_list[i].tpd_device_name);g_tpd_drv = &tpd_driver_list[i];break;}}}
//如果tpd_driver_list中所有TP都初始化失败,强制使用index=0的TP;
if (g_tpd_drv == NULL){if (tpd_driver_list[0].tpd_device_name != NULL){g_tpd_drv = &tpd_driver_list[0];/* touch_type:0: r-touch, 1: C-touch */touch_type = 0;g_tpd_drv->tpd_local_init();TPD_DMESG("[mtk-tpd]Generic touch panel drivern");} else {TPD_DMESG("[mtk-tpd]cap touch and Generic touch both are not loaded!!n");return 0;}}
//为TP工作创建一个工作队列;
touch_resume_workqueue = create_singlethread_workqueue("touch_resume");INIT_WORK(&touch_resume_work, touch_resume_workqueue_callback);
//设置背光通知的回调函数,以便在亮屏时唤醒TP,或者息屏后关闭TP;
tpd_fb_notifier.notifier_call = tpd_fb_notifier_callback;if (fb_register_client(&tpd_fb_notifier))TPD_DMESG("register fb_notifier fail!n");
//设置TP相关参数;
if (touch_type == 1){set_bit(ABS_MT_TRACKING_ID, tpd->dev->absbit);set_bit(ABS_MT_TOUCH_MAJOR, tpd->dev->absbit);set_bit(ABS_MT_TOUCH_MINOR, tpd->dev->absbit);set_bit(ABS_MT_POSITION_X, tpd->dev->absbit);set_bit(ABS_MT_POSITION_Y, tpd->dev->absbit);input_set_abs_params(tpd->dev, ABS_MT_POSITION_X, 0, TPD_RES_X, 0, 0);input_set_abs_params(tpd->dev, ABS_MT_POSITION_Y, 0, TPD_RES_Y, 0, 0);#if defined(CONFIG_MTK_S3320) || defined(CONFIG_MTK_S3320_47)|| defined(CONFIG_MTK_S3320_50) || defined(CONFIG_MTK_MIT200)|| defined(CONFIG_TOUCHSCREEN_SYNAPTICS_S3528) || defined(CONFIG_MTK_S7020)input_set_abs_params(tpd->dev, ABS_MT_PRESSURE, 0, 255, 0, 0);input_set_abs_params(tpd->dev, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0);input_set_abs_params(tpd->dev, ABS_MT_WIDTH_MINOR, 0, 15, 0, 0);input_mt_init_slots(tpd->dev, 10, 0);#elseinput_set_abs_params(tpd->dev, ABS_MT_TOUCH_MAJOR, 0, 100, 0, 0);input_set_abs_params(tpd->dev, ABS_MT_TOUCH_MINOR, 0, 100, 0, 0);#endif /* CONFIG_MTK_S3320 */TPD_DMESG("Cap touch panel drivern");}input_set_abs_params(tpd->dev, ABS_X, 0, TPD_RES_X, 0, 0);input_set_abs_params(tpd->dev, ABS_Y, 0, TPD_RES_Y, 0, 0);input_abs_set_res(tpd->dev, ABS_X, TPD_RES_X);input_abs_set_res(tpd->dev, ABS_Y, TPD_RES_Y);input_set_abs_params(tpd->dev, ABS_PRESSURE, 0, 255, 0, 0);input_set_abs_params(tpd->dev, ABS_MT_TRACKING_ID, 0, 10, 0, 0);
//注册输入设备
if (input_register_device(tpd->dev))TPD_DMESG("input_register_device failed.(tpd)n");elsetpd_register_flag = 1;
//如果TP支持虚拟按键,还要进行虚拟按键的初始化;
if (g_tpd_drv->tpd_have_button)tpd_button_init();
//创建用于调试用的节点文件
if (g_tpd_drv->attrs.num)tpd_create_attributes(&pdev->dev, &g_tpd_drv->attrs);return 0;}
执行完probe函数,TP的设备节点就创建好了。
在probe中,查找当前使用TP是通过遍历一个支持列表—tpd_driver_list实现的,这个列表的元素是TP操作的具体函数组成的结构体,定义在:
//tpd.hstruct tpd_driver_t {char *tpd_device_name; //TP名字int (*tpd_local_init)(void); //TP初始化void (*suspend)(struct device *h);//TP休眠void (*resume)(struct device *h);//TP唤醒int tpd_have_button;//是否有虚拟按键struct tpd_attrs attrs;//创建节点文件};
不同的TP都是要实现这个结构体中的内容,完成TP应有的工作。
tpd_driver_list这个列表时通过调用函数tpd_driver_add来添加元素的:
//mtk_tpd.c
int tpd_driver_add(struct tpd_driver_t *tpd_drv){......tpd_drv->tpd_have_button = tpd_dts_data.use_tpd_button;//如果是电阻屏,强制放到列表index=0位置;if (strcmp(tpd_drv->tpd_device_name, "generic") == 0) {tpd_driver_list[0].tpd_device_name = tpd_drv->tpd_device_name;tpd_driver_list[0].tpd_local_init = tpd_drv->tpd_local_init;tpd_driver_list[0].suspend = tpd_drv->suspend;tpd_driver_list[0].resume = tpd_drv->resume;tpd_driver_list[0].tpd_have_button = tpd_drv->tpd_have_button;return 0;}//如果是电容屏,放到列表尾;for (i = 1; i < TP_DRV_MAX_COUNT; i++) {if (tpd_driver_list[i].tpd_device_name == NULL) {tpd_driver_list[i].tpd_device_name = tpd_drv->tpd_device_name;tpd_driver_list[i].tpd_local_init = tpd_drv->tpd_local_init;tpd_driver_list[i].suspend = tpd_drv->suspend;tpd_driver_list[i].resume = tpd_drv->resume;tpd_driver_list[i].tpd_have_button = tpd_drv->tpd_have_button;tpd_driver_list[i].attrs = tpd_drv->attrs;break;}//若列表中已经有了这个TP,不再重复添加;if (strcmp(tpd_driver_list[i].tpd_device_name, tpd_drv->tpd_device_name) == 0)return 1;}return 0;}
另外,probe函数中还注册了一个背光通知回调函数,用于控制TP随背光变化调整工作方式,回调函数如下:
//mtk_tpd.c
static int tpd_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data){......switch (blank) {//背光被点亮通知case FB_BLANK_UNBLANK:TPD_DMESG("LCD ON Notifyn");if (g_tpd_drv && tpd_suspend_flag) {//通过工作队列方式,调用TP的唤醒函数err = queue_work(touch_resume_workqueue, &touch_resume_work);if (!err) {TPD_DMESG("start touch_resume_workqueue failedn");return err;}}break;//背光被熄灭通知case FB_BLANK_POWERDOWN:TPD_DMESG("LCD OFF Notifyn");if (g_tpd_drv){//先取消工作队列,避免逻辑混乱err = cancel_work_sync(&touch_resume_work);if (!err)TPD_DMESG("cancel touch_resume_workqueue err = %dn", err);//直接调用TP的休眠函数g_tpd_drv->suspend(NULL);tpd_suspend_flag = 1;}break;default:break;}return 0;}
TP的设备驱动基本结构就是这些。
3、TP模组驱动
TP设备驱动搭好了TP驱动的架构,不同的TP模组按照这个架构,主要是实现结构体 tpd_driver_t 中内容,然后通过函数 tpd_driver_add 加入到驱动列表中。下面就以一个实例—focaltech_touch,看一下TP模组的驱动代码。
首先,通过 module_init 和 module_exit 实现模组的初始化和退出:
//focaltech_core.c
static int __init tpd_driver_init(void){FTS_FUNC_ENTER();FTS_INFO("Driver version: %s", FTS_DRIVER_VERSION);tpd_get_dts_info();if (tpd_dts_data.touch_max_num < 2)tpd_dts_data.touch_max_num = 2;else if (tpd_dts_data.touch_max_num > FTS_MAX_POINTS_SUPPORT)tpd_dts_data.touch_max_num = FTS_MAX_POINTS_SUPPORT;FTS_INFO("tpd max touch num:%d", tpd_dts_data.touch_max_num);#if FTS_PSENSOR_ENfts_proximity_init();#endifif (tpd_driver_add(&tpd_device_driver) < 0)FTS_ERROR("[TPD]: Add FTS Touch driver failed!!");FTS_FUNC_EXIT();return 0;}static void __exit tpd_driver_exit(void){FTS_FUNC_ENTER();tpd_driver_remove(&tpd_device_driver);FTS_FUNC_EXIT();}module_init(tpd_driver_init);module_exit(tpd_driver_exit);
static struct tpd_driver_t tpd_device_driver = {.tpd_device_name = FTS_DRIVER_NAME,.tpd_local_init = tpd_local_init,.suspend = tpd_suspend,.resume = tpd_resume,};
其中,tpd_local_init 源码如下:
//focaltech_core.c
static int fts_ts_driver_init(void){//添加一个I2C驱动,用于和TP通信return i2c_add_driver(&fts_ts_driver);}static int tpd_local_init(void){int ret = 0;FTS_FUNC_ENTER();ret = fts_ts_driver_init();...................//电容屏tpd_type_cap = 1;FTS_FUNC_EXIT();return 0;}
可以看出,添加I2C驱动的操作,是 tpd_local_init 的重点,fts_ts_driver实现如下:
//focaltech_core.c
static const struct i2c_device_id fts_ts_id[] = {{FTS_DRIVER_NAME, 0}, {},};static const struct of_device_id fts_dt_match[] = {{.compatible = "mediatek,cap_touch"}, {},};MODULE_DEVICE_TABLE(of, fts_dt_match);static struct i2c_driver fts_ts_driver = {.probe = fts_ts_probe,.remove = fts_ts_remove,.driver = {.name = FTS_DRIVER_NAME,.owner = THIS_MODULE,.of_match_table = of_match_ptr(fts_dt_match),},.id_table = fts_ts_id,.detect = fts_ts_detect,};
还是要读一下probe函数:
//focaltech_core.c
static int fts_ts_probe(struct i2c_client *client,const struct i2c_device_id *id){......//赋值I2C地址if (client->addr != FTS_I2C_SLAVE_ADDR) {FTS_INFO("[TPD]Change i2c addr 0x%02x to %x", client->addr,FTS_I2C_SLAVE_ADDR);client->addr = FTS_I2C_SLAVE_ADDR;FTS_INFO("[TPD]i2c addr=0x%x\n", client->addr);}ret = fts_input_init(ts_data);if (ret) {FTS_ERROR("input initialize fail");goto err_input_init;}//配置GPIOret = fts_gpio_configure(ts_data);if (ret) {FTS_ERROR("configure the gpios fail");goto err_gpio_config;}//配置上电#if FTS_POWER_SOURCE_CUST_ENret = fts_power_source_init(ts_data);if (ret) {FTS_ERROR("fail to get power(regulator)");goto err_power_init;}#endif//控制reset#if (!FTS_CHIP_IDC)fts_reset_proc(200);#endif//定义与上层交互的读写接口ret = fts_create_apk_debug_channel(ts_data);if (ret)FTS_ERROR("create apk debug node fail");//通过I2C读取TP数据、解析TP数据、上报TP数据#if FTS_POINT_REPORT_CHECK_ENret = fts_point_report_check_init(ts_data);if (ret)FTS_ERROR("init point report check fail");#endif//注册中断ret = fts_irq_registration(ts_data);if (ret) {FTS_ERROR("request irq failed");goto err_irq_req;}tpd_load_status = 1;}读一下fts_input_init函数//注册输入设备static int fts_input_init(struct fts_ts_data *ts_data){int ret = 0;int key_num = 0;struct fts_ts_platform_data *pdata = ts_data->pdata;struct input_dev *input_dev;FTS_FUNC_ENTER();//申请一个输入设备input_dev = input_allocate_device();if (!input_dev) {FTS_ERROR("Failed to allocate memory for input device");return -ENOMEM;}//初始化、注册输入设备input_dev->name = FTS_DRIVER_NAME;input_dev->id.bustype = BUS_I2C;input_dev->dev.parent = ts_data->dev;input_set_drvdata(input_dev, ts_data);//设置TP相关参数;__set_bit(EV_SYN, input_dev->evbit);__set_bit(EV_ABS, input_dev->evbit);__set_bit(EV_KEY, input_dev->evbit);__set_bit(BTN_TOUCH, input_dev->keybit);__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);if (pdata->have_key) {FTS_INFO("set key capabilities");for (key_num = 0; key_num < pdata->key_number; key_num++)input_set_capability(input_dev, EV_KEY,pdata->keys[key_num]);}#if FTS_MT_PROTOCOL_B_ENinput_mt_init_slots(input_dev, pdata->max_touch_number,INPUT_MT_DIRECT);#elseinput_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 0x0F, 0, 0);#endifinput_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min,pdata->x_max, 0, 0);input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min,pdata->y_max, 0, 0);input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0);#if FTS_REPORT_PRESSURE_ENinput_set_abs_params(input_dev, ABS_MT_PRESSURE, 0, 0xFF, 0, 0);#endif//注册输入设备ret = input_register_device(input_dev);if (ret) {FTS_ERROR("Input device registration failed");input_set_drvdata(input_dev, NULL);input_free_device(input_dev);input_dev = NULL;return ret;}ts_data->input_dev = input_dev;FTS_FUNC_EXIT();return 0;}//拉高复位脚static int fts_gpio_configure(struct fts_ts_data *ts_data){tpd_gpio_output(ts_data->pdata->reset_gpio, 1);return 0;}//给TP上电static int fts_power_source_init(struct fts_ts_data *ts_data){int ret = 0;FTS_FUNC_ENTER();ts_data->vdd = regulator_get(tpd->tpd_dev, "vtouch");if (IS_ERR_OR_NULL(ts_data->vdd)) {ret = PTR_ERR(ts_data->vdd);FTS_ERROR("get vdd regulator failed,ret=%d", ret);return ret;}if (regulator_count_voltages(ts_data->vdd) > 0) {ret = regulator_set_voltage(ts_data->vdd, FTS_VTG_MIN_UV,FTS_VTG_MAX_UV);if (ret) {FTS_ERROR("vdd regulator set_vtg failed ret=%d", ret);regulator_put(ts_data->vdd);return ret;}}ts_data->power_disabled = true;ret = fts_power_source_ctrl(ts_data, ENABLE);if (ret)FTS_ERROR("fail to enable power(regulator)");FTS_FUNC_EXIT();return ret;}//控制RESET脚,使TP复位一下int fts_reset_proc(int hdelayms){FTS_DEBUG("tp reset");tpd_gpio_output(fts_data->pdata->reset_gpio, 0);msleep(20);tpd_gpio_output(fts_data->pdata->reset_gpio, 1);if (hdelayms)msleep(hdelayms);return 0;}//定义与上层交互的读写接口static const struct file_operations fts_proc_fops = {.owner = THIS_MODULE, .read = fts_debug_read, .write = fts_debug_write,};int fts_create_apk_debug_channel(struct fts_ts_data *ts_data){struct ftxxxx_proc *proc = &ts_data->proc;#if 1proc->proc_entry = proc_create(PROC_NAME, 0777, NULL, &fts_proc_fops);if (proc->proc_entry == NULL) {FTS_ERROR("create proc entry fail");return -ENOMEM;}#elseproc->proc_entry = create_proc_entry(PROC_NAME, 0777, NULL);if (proc->proc_entry == NULL) {FTS_ERROR("create proc entry fail");return -ENOMEM;}proc->proc_entry->write_proc = fts_debug_write;proc->proc_entry->read_proc = fts_debug_read;#endifFTS_INFO("Create proc entry success!");return 0;}int fts_point_report_check_init(struct fts_ts_data *ts_data){FTS_FUNC_ENTER();if (ts_data->ts_workqueue) {INIT_DELAYED_WORK(&ts_data->prc_work, fts_prc_func);} else {FTS_ERROR("fts workqueue is NULL, can't run point report check function");return -EINVAL;}FTS_FUNC_EXIT();return 0;}int fts_point_report_check_init(struct fts_ts_data *ts_data){FTS_FUNC_ENTER();if (ts_data->ts_workqueue) {INIT_DELAYED_WORK(&ts_data->prc_work, fts_prc_func);} else {FTS_ERROR("fts workqueue is NULL, can't run point report check function");return -EINVAL;}FTS_FUNC_EXIT();return 0;}int fts_point_report_check_init(struct fts_ts_data *ts_data){FTS_FUNC_ENTER();if (ts_data->ts_workqueue) {INIT_DELAYED_WORK(&ts_data->prc_work, fts_prc_func);} else {FTS_ERROR("fts workqueue is NULL, can't run point report check function");return -EINVAL;}FTS_FUNC_EXIT();return 0;}int fts_point_report_check_init(struct fts_ts_data *ts_data){FTS_FUNC_ENTER();if (ts_data->ts_workqueue) {INIT_DELAYED_WORK(&ts_data->prc_work, fts_prc_func);} else {FTS_ERROR("fts workqueue is NULL, can't run point report check function");return -EINVAL;}FTS_FUNC_EXIT();return 0;}//work处理函数,上报数据static void fts_prc_func(struct work_struct *work){struct fts_ts_data *ts_data =container_of(work, struct fts_ts_data, prc_work.work);struct input_dev *input_dev = ts_data->input_dev;#if FTS_MT_PROTOCOL_B_ENu32 finger_count = 0;u32 max_touches = fts_data->pdata->max_touch_number;#endifFTS_FUNC_ENTER();mutex_lock(&ts_data->report_mutex);#if FTS_MT_PROTOCOL_B_ENfor (finger_count = 0; finger_count < max_touches; finger_count++) {input_mt_slot(input_dev, finger_count);input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, false);}#elseinput_mt_sync(input_dev);#endifinput_report_key(input_dev, BTN_TOUCH, 0);input_sync(input_dev);mutex_unlock(&ts_data->report_mutex);FTS_FUNC_EXIT();}int fts_point_report_check_init(struct fts_ts_data *ts_data){FTS_FUNC_ENTER();//init workif (ts_data->ts_workqueue) {INIT_DELAYED_WORK(&ts_data->prc_work, fts_prc_func);} else {FTS_ERROR("fts workqueue is NULL, can't run point report check function");return -EINVAL;}FTS_FUNC_EXIT();return 0;}//中断注册static int fts_irq_registration(struct fts_ts_data *ts_data){int ret = 0;struct device_node *node = NULL;//查找指定节点,获取相关参数node = of_find_matching_node(node, touch_of_match);if (node == NULL) {FTS_ERROR("Can not find touch eint device node!");return -ENODATA;}//运行一个线程ts_data->thread_tpd = kthread_run(touch_event_handler, 0, TPD_DEVICE);if (IS_ERR_OR_NULL(ts_data->thread_tpd)) {ret = PTR_ERR(ts_data->thread_tpd);FTS_ERROR("create kernel thread_tpd fail,ret:%d", ret);ts_data->thread_tpd = NULL;return ret;}//设置中断,包括中断号、中断回调、中断触发方式等;tpd_gpio_as_int(ts_data->pdata->irq_gpio);ts_data->irq = irq_of_parse_and_map(node, 0);ts_data->pdata->irq_gpio_flags = IRQF_TRIGGER_FALLING;FTS_INFO("irq:%d, flag:%x", ts_data->irq,ts_data->pdata->irq_gpio_flags);ret = request_irq(ts_data->irq, fts_irq_handler,ts_data->pdata->irq_gpio_flags, FTS_DRIVER_NAME,ts_data);return ret;}看下中断回调函数:static irqreturn_t fts_irq_handler(int irq, void *data){tpd_flag = 1;wake_up_interruptible(&waiter);//唤醒等待队列return IRQ_HANDLED;}可以看到,中断回调只是EINT中断的上半部,上半部只是唤醒了一个等待队列。fts_irq_registration函数中创建了一个线程,ENIT中断的下半部放在这个线程中执行:static DECLARE_WAIT_QUEUE_HEAD(waiter); //声明并创建一个等待队列static int touch_event_handler(void *unused){struct sched_param param = {.sched_priority = RTPM_PRIO_TPD};//设置线程调度策略为:时间片轮转实时调度;sched_setscheduler(current, SCHED_RR, ¶m);do {set_current_state(TASK_INTERRUPTIBLE);//等待等待队列被唤醒;wait_event_interruptible(waiter, tpd_flag != 0);tpd_flag = 0;set_current_state(TASK_RUNNING);#if FTS_PSENSOR_ENif (fts_proximity_readdata(fts_data) == 0)continue;#endif//通过I2C读取TP数据、解析TP数据、上报TP数据fts_irq_read_report();} while (!kthread_should_stop());return 0;}//通过I2C读取TP数据、解析TP数据、上报TP数据static void fts_irq_read_report(void){int ret = 0;struct fts_ts_data *ts_data = fts_data;#if FTS_ESDCHECK_ENfts_esdcheck_set_intr(1);#endif#if FTS_POINT_REPORT_CHECK_ENfts_prc_queue_work(ts_data);#endif//读取解析TP数据ret = fts_read_parse_touchdata(ts_data);if (ret == 0) {mutex_lock(&ts_data->report_mutex);#if FTS_MT_PROTOCOL_B_ENfts_input_report_b(ts_data);//上报TP数据#elsefts_input_report_a(ts_data);#endifmutex_unlock(&ts_data->report_mutex);}#if FTS_ESDCHECK_ENfts_esdcheck_set_intr(0);#endif}看到这里,TP通过中断上报数据的流程就清晰了。 最后,我们再看看TP的休眠和唤醒都做了什么:focaltech_core.c//休眠函数static void tpd_suspend(struct device *dev){int ret = 0;struct fts_ts_data *ts_data = fts_data;FTS_FUNC_ENTER();if (ts_data->suspended) {FTS_INFO("Already in suspend state");return;}if (ts_data->fw_loading) {FTS_INFO("fw upgrade in process, can't suspend");return;}#if FTS_PSENSOR_ENif (fts_proximity_suspend() == 0) {fts_release_all_finger();ts_data->suspended = true;return;}#endif#if FTS_ESDCHECK_ENfts_esdcheck_suspend();#endifif (ts_data->gesture_mode) {fts_gesture_suspend(ts_data);} else {fts_irq_disable();// //通过I2C,控制TP进入休眠模式ret = fts_write_reg(FTS_REG_POWER_MODE,FTS_REG_POWER_MODE_SLEEP);if (ret < 0)FTS_ERROR("set TP to sleep mode fail, ret=%d", ret);if (!ts_data->ic_info.is_incell) {#if FTS_POWER_SOURCE_CUST_ENret = fts_power_source_suspend(ts_data);if (ret < 0)FTS_ERROR("power enter suspend fail");#endif}}fts_release_all_finger();ts_data->suspended = true;FTS_FUNC_EXIT();}//唤醒函数static void tpd_resume(struct device *dev){struct fts_ts_data *ts_data = fts_data;FTS_FUNC_ENTER();if (!ts_data->suspended) {FTS_DEBUG("Already in awake state");return;}#if FTS_PSENSOR_ENif (fts_proximity_resume() == 0) {ts_data->suspended = false;return;}#endiffts_release_all_finger();if (!ts_data->ic_info.is_incell) {#if FTS_POWER_SOURCE_CUST_ENfts_power_source_resume(ts_data);#endiffts_reset_proc(200); //控制RESET脚复位TP}fts_wait_tp_to_valid();fts_ex_mode_recovery(ts_data);#if FTS_ESDCHECK_ENfts_esdcheck_resume();#endifif (ts_data->gesture_mode)fts_gesture_resume(ts_data);elsefts_irq_enable(); //使能EINT中断ts_data->suspended = false;FTS_FUNC_EXIT();}
至此,TP驱动的核心代码就很清晰了。