前言
简单追了下 MTK TouchPanel 驱动的框架
框架
平台流程
【mtk touchpanel 驱动流程】:
//
// Mtk_tpd.c (kernel-3.18\drivers\input\touchscreen\mediatek)
late_initcall(tpd_probe_init);
tpd_probe_init(void)
// Mtk_tpd.c (kernel-3.18\drivers\input\touchscreen\mediatek)
// 创建一个单线程工作队列,启动工作线程
tpd_device_init();
// 创建单线程工作队列
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);
//
// Mtk_tpd.c (kernel-3.18\drivers\input\touchscreen\mediatek)
tpd_init_work_callback(struct work_struct *work)
/
// 注册 platform driver 设备
// 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,
// /
// // struct of_device_id touch_of_match[] = {
// // { .compatible = "mediatek,mt6570-touch", },
// // { .compatible = "mediatek,mt6735-touch", },
// // { .compatible = "mediatek,mt6580-touch", },
// // { .compatible = "mediatek,mt8173-touch", },
// // { .compatible = "mediatek,mt6755-touch", },
// // { .compatible = "mediatek,mt6757-touch", },
// // { .compatible = "mediatek,mt6797-touch", },
// // { .compatible = "mediatek,mt8163-touch", },
// // { .compatible = "mediatek,mt8127-touch", },
// // { .compatible = "mediatek,mt2701-touch", },
// // { .compatible = "mediatek,mt7623-touch", },
// // {},
// // };
// },
// };
/
// dts 相关设置
// touch: touch {
// compatible = "mediatek,mt6755-touch";
// // VTOUCH-supply = <&mt_pmic_vgp1_ldo_reg>;
// };
// &touch {
// /
// // 上报点分辨率
// tpd-resolution = <1080 1920>;
// /
// // 虚拟按键
// 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_pins_eint_as_int>;
// pinctrl-2 = <&ctp_pins_eint_output0>;
// pinctrl-3 = <&ctp_pins_eint_output1>;
// pinctrl-4 = <&ctp_pins_rst_output0>;
// pinctrl-5 = <&ctp_pins_rst_output1>;
// status = "okay";
// };
platform_driver_register(&tpd_driver)
/
// Mtk_tpd.c (kernel-3.18\drivers\input\touchscreen\mediatek)
tpd_probe(struct platform_device *pdev)
/
// 1. 注册杂项设备
// static struct miscdevice tpd_misc_device = {
// .minor = MISC_DYNAMIC_MINOR,
// .name = "touch",
// .fops = &tpd_fops,
// /
// // static const struct file_operations tpd_fops = {
// // // .owner = THIS_MODULE,
// // .open = tpd_misc_open,
// // .release = tpd_misc_release,
// // .unlocked_ioctl = tpd_unlocked_ioctl,
// // #ifdef CONFIG_COMPAT
// // .compat_ioctl = tpd_compat_ioctl,
// // #endif
// // };
// };
misc_register(&tpd_misc_device)
/
// 2.【获得 dts 相关引脚配置 pinctrl】
tpd_get_gpio_info(pdev);
pinctrl1 = devm_pinctrl_get(&pdev->dev);
pins_default = pinctrl_lookup_state(pinctrl1, "default");
eint_as_int = pinctrl_lookup_state(pinctrl1, "state_eint_as_int");
eint_output0 = pinctrl_lookup_state(pinctrl1, "state_eint_output0");
eint_output1 = pinctrl_lookup_state(pinctrl1, "state_eint_output1");
rst_output0 = pinctrl_lookup_state(pinctrl1, "state_rst_output0");
rst_output1 = pinctrl_lookup_state(pinctrl1, "state_rst_output1");
// 3. 分配 mtk 封装的 tp 数据结构
tpd = kmalloc(sizeof(struct tpd_device), GFP_KERNEL);
// 4. 分配分配输入子系统
tpd->dev = input_allocate_device();
///
// 5. 处理 touch panel 报点旋转
if (0 == strncmp(CONFIG_MTK_LCM_PHYSICAL_ROTATION, "90", 2)
|| 0 == strncmp(CONFIG_MTK_LCM_PHYSICAL_ROTATION, "270", 3))
TPD_RES_Y = DISP_GetScreenWidth();
TPD_RES_X = DISP_GetScreenHeight();
///
// 6. 相关报点参数设置
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;
//
// 7. 设置输入设备 TP 上报事件类型
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);
//
// 8.【调用第三方驱动注册的的 init 函数】
for (i = 1; i < TP_DRV_MAX_COUNT; i++)
if (tpd_driver_list[i].tpd_device_name != NULL) {
//
// 主要注册 i2c 设备驱动,设置 tp 虚拟按键属性
tpd_driver_list[i].tpd_local_init();
/
// Focaltech_core.c (kernel-3.18\drivers\input\touchscreen\mediatek\focaltech_touch_ft3427)
tpd_local_init(void)
///
// 初始化 TP 使用的 reglator:上电 2.8v
fts_power_init()
tpd->tpd_dev->of_node = of_find_compatible_node(NULL, NULL, "mediatek,mt6755-touch");
if (tpd->tpd_dev->of_node)
tpd->reg = regulator_get(tpd->tpd_dev, "vtouch");
retval = regulator_set_voltage(tpd->reg, 2800000, 2800000);
///
// 注册 i2c device
i2c_add_driver(&tpd_i2c_driver)
//
// 设置 tp 设置
if (tpd_dts_data.use_tpd_button)
tpd_button_setting(tpd_dts_data.tpd_key_num, tpd_dts_data.tpd_key_local, tpd_dts_data.tpd_key_dim_local);
tpd_keycnt = keycnt;
memcpy(tpd_keys, keys, keycnt * 4);
memcpy(tpd_keys_dim, keys_dim, keycnt * 4 * 4);
/
// tpd_load_status 是在具体 TP 驱动中的 probe 函数中设置的
// 【TP 初始化成功后,会设置此位】
if (tpd_load_status == 1)
// 【设置当前使用的 tp 】
g_tpd_drv = &tpd_driver_list[i];
}
/
// 9. 如果没有注册 tp 驱动,则调用默认的 R 电阻屏驱动
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();
}
}
// 10. 调用当前使用的 tp 驱动的 resume() 函数
touch_resume_workqueue = create_singlethread_workqueue("touch_resume");
INIT_WORK(&touch_resume_work, touch_resume_workqueue_callback);
// Mtk_tpd.c (kernel-3.18\drivers\input\touchscreen\mediatek)
touch_resume_workqueue_callback(struct work_struct *work)
g_tpd_drv->resume(NULL);
///
// 11. 注册内核通知链,监听 fb_notifier,应该会在相应的屏的驱动里面进行通知调用
// 【在这里进行 TP 的唤醒和休眠操作】
tpd_fb_notifier.notifier_call = tpd_fb_notifier_callback;
tpd_fb_notifier_callback(struct notifier_block *self, unsigned long event, void *data)
// 参数:谁调用谁传
/
// 直接传个指针过来了。。。
evdata = data;
blank = *(int *)evdata->data;
//
// 进行 TP 的唤醒,休眠操作
switch (blank)
case FB_BLANK_UNBLANK:
if (g_tpd_drv && tpd_suspend_flag)
err = queue_work(touch_resume_workqueue, &touch_resume_work);
case FB_BLANK_POWERDOWN:
if (g_tpd_drv && !tpd_suspend_flag)
// 取消唤醒工作队列
err = cancel_work_sync(&touch_resume_work);
///
// 调用第三方驱动的 suspend 挂起函数
g_tpd_drv->suspend(NULL);
//
// 注册通知链
fb_register_client(&tpd_fb_notifier)
//
// 设置输入设备 TP 上报事件
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);
/
// 注册输入设备
input_register_device(tpd->dev)
tpd_register_flag = 1;
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);
第三方流程
【TouchPanel 初始化流程】:
module_init(tpd_driver_init);
tpd_driver_init(void)
///
// Mtk_tpd.c (kernel-3.18\drivers\input\touchscreen\mediatek)
// 获得 dts 设备树中与 touch 相关的配置项
// 保存在 tpd_dts_data 全局变量中
tpd_get_dts_info();
// 匹配 dts 设备树中的节点
// struct of_device_id touch_of_match[] = {
// { .compatible = "mediatek,mt6570-touch", },
// { .compatible = "mediatek,mt6735-touch", },
// { .compatible = "mediatek,mt6580-touch", },
// { .compatible = "mediatek,mt8173-touch", },
// { .compatible = "mediatek,mt6755-touch", },
// { .compatible = "mediatek,mt6757-touch", },
// { .compatible = "mediatek,mt6797-touch", },
// { .compatible = "mediatek,mt8163-touch", },
// { .compatible = "mediatek,mt8127-touch", },
// { .compatible = "mediatek,mt2701-touch", },
// { .compatible = "mediatek,mt7623-touch", },
// {},
// };
/
// dts 相关设置
// touch: touch {
// compatible = "mediatek,mt6755-touch";
// // VTOUCH-supply = <&mt_pmic_vgp1_ldo_reg>;
// };
// &touch {
// /
// // 上报点分辨率
// tpd-resolution = <1080 1920>;
// /
// // 虚拟按键
// 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_pins_eint_as_int>;
// pinctrl-2 = <&ctp_pins_eint_output0>;
// pinctrl-3 = <&ctp_pins_eint_output1>;
// pinctrl-4 = <&ctp_pins_rst_output0>;
// pinctrl-5 = <&ctp_pins_rst_output1>;
// status = "okay";
// };
node1 = of_find_matching_node(node1, touch_of_match);
/
// 获得平台中 dts 中的数据,保存在 tpd_dts_data 全局变量中
if (node1)
of_property_read_u32(node1, "【tpd-max-touch-num】", &tpd_dts_data.touch_max_num);
of_property_read_u32(node1, "【use-tpd-button】", &tpd_dts_data.use_tpd_button);
of_property_read_u32_array(node1, "【tpd-resolution】", tpd_dts_data.tpd_resolution, ARRAY_SIZE(tpd_dts_data.tpd_resolution));
if (tpd_dts_data.use_tpd_button)
of_property_read_u32(node1, "【tpd-key-num】", &tpd_dts_data.tpd_key_num);
of_property_read_u32_array(node1, "【tpd-key-local】",tpd_dts_data.tpd_key_local, ARRAY_SIZE(tpd_dts_data.tpd_key_local));
of_property_read_u32_array(node1, "【tpd-key-dim-local】",key_dim_local, ARRAY_SIZE(key_dim_local));
of_property_read_u32(node1, "【tpd-filter-enable】", &tpd_dts_data.touch_filter.enable);
if (tpd_dts_data.touch_filter.enable)
of_property_read_u32(node1, "【tpd-filter-pixel-density】",&tpd_dts_data.touch_filter.pixel_density);
of_property_read_u32_array(node1, "【tpd-filter-custom-prameters】",(u32 *)tpd_dts_data.touch_filter.W_W, ARRAY_SIZE(tpd_dts_data.touch_filter.W_W));
of_property_read_u32_array(node1, "【tpd-filter-custom-speed】",tpd_dts_data.touch_filter.VECLOCITY_THRESHOLD,ARRAY_SIZE(tpd_dts_data.touch_filter.VECLOCITY_THRESHOLD));
//
// 注册 tpd 驱动
// 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,
// .attrs = {
// .attr = fts_attrs,
// .num = ARRAY_SIZE(fts_attrs),
// },
// };
tpd_driver_add(&tpd_device_driver)
/
// Mtk_tpd.c (z:\work\e266l_cmcc\kernel-3.18\drivers\input\touchscreen\mediatek)
tpd_driver_add(struct tpd_driver_t *tpd_drv)
tpd_drv->tpd_have_button = tpd_dts_data.use_tpd_button;
// tpd_driver_list[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;
// 将要注册的结构体放到 tpd_driver_list[] 全局数组中
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;
}
/
// 当在 tpd_common_probe.c 中调用 .tpd_local_init() 函数指针时,会注册一个 i2c device
tpd_local_init(void)
///
// 初始化 TP 使用的 reglator:上电 2.8v
fts_power_init()
tpd->tpd_dev->of_node = of_find_compatible_node(NULL, NULL, "mediatek,mt6755-touch");
if (tpd->tpd_dev->of_node)
tpd->reg = regulator_get(tpd->tpd_dev, "vtouch");
retval = regulator_set_voltage(tpd->reg, 2800000, 2800000);
///
// 注册 i2c device
// static struct i2c_driver tpd_i2c_driver = {
// .driver = {
// .name = FTS_DRIVER_NAME,
// .of_match_table = of_match_ptr(fts_dt_match),
// ///
// // 【兼容原理】:所有的 sensor 都指定匹配此设备节点
// // 在所进入的 i2c probe() 函数中强制转换 i2c 地址
// // 这就需要要兼容的多个驱动中需要检测当前初始化的是
// // 哪颗芯片的
// // static const struct of_device_id fts_dt_match[] = {
// // {.compatible = "mediatek,cap_touch"},
// // {},
// // };
// },
// .probe = tpd_probe,
// .remove = tpd_remove,
// .id_table = fts_tpd_id,
// .detect = tpd_i2c_detect,
// };
i2c_add_driver(&tpd_i2c_driver)
//
// 设置 tp 设置
if (tpd_dts_data.use_tpd_button)
tpd_button_setting(tpd_dts_data.tpd_key_num, tpd_dts_data.tpd_key_local, tpd_dts_data.tpd_key_dim_local);
tpd_keycnt = keycnt;
memcpy(tpd_keys, keys, keycnt * 4);
memcpy(tpd_keys_dim, keys_dim, keycnt * 4 * 4);
//
// 进入 i2c probe 函数
tpd_probe(struct i2c_client *client, const struct i2c_device_id *id)
///
// 兼容处理
if (fts_i2c_client->addr != FTS_I2C_SLAVE_ADDR)
fts_i2c_client->addr = FTS_I2C_SLAVE_ADDR;
///
// 通过 pinctrl 设置中断引脚
tpd_gpio_as_int(tpd_int_gpio_number);
if (pin == 1)
pinctrl_select_state(pinctrl1, eint_as_int);
///
// 获得 dts 中与中断相关设置,然后申请中断,设置中断处理函数
// 【TP 中断处理函数】:主要是唤醒 TP 工作队列
tpd_irq_registration(client);
///
// 获得 dts 中相应项
// struct of_device_id touch_of_match[] = {
// { .compatible = "mediatek,mt6570-touch", },
// { .compatible = "mediatek,mt6735-touch", },
// { .compatible = "mediatek,mt6580-touch", },
// { .compatible = "mediatek,mt8173-touch", },
// { .compatible = "mediatek,mt6755-touch", },
// { .compatible = "mediatek,mt6757-touch", },
// { .compatible = "mediatek,mt6797-touch", },
// { .compatible = "mediatek,mt8163-touch", },
// { .compatible = "mediatek,mt8127-touch", },
// { .compatible = "mediatek,mt2701-touch", },
// { .compatible = "mediatek,mt7623-touch", },
// {},
// };
node = of_find_matching_node(node, touch_of_match);
//
// 获得 dts 中与中断相关设置,然后申请中断,设置中断处理函数
// 【TP 中断处理函数】:主要是唤醒 TP 工作队列
if (node)
of_property_read_u32_array(node, "debounce", ints, ARRAY_SIZE(ints));
gpio_set_debounce(ints[0], ints[1]);
ft_touch_irq = irq_of_parse_and_map(node, 0);
ret = request_irq(ft_touch_irq, tpd_eint_interrupt_handler, IRQF_TRIGGER_FALLING, "TOUCH_PANEL-eint", NULL);
/
// 【TP 中断处理函数】:主要是唤醒 TP 工作队列
tpd_eint_interrupt_handler(int irq, void *dev_id)
// 设置中断标志
tpd_flag = 1;
// 唤醒睡眠在 waiter 等待队列上的进程
wake_up_interruptible(&waiter);
// 关中断,先不能进行中断处理
fts_irq_disable();
disable_irq_nosync(ft_touch_irq);
/
// 初始化 i2c,只是进行 dma 内存分配用的
fts_i2c_init();
fts_i2c_msg_dma_alloct();
if (NULL == g_dma_buff_va)
tpd->dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
g_dma_buff_va = (u8 *) dma_alloc_coherent(&tpd->dev->dev, DMA_BUFFER_LENGTH, &g_dma_buff_pa, GFP_KERNEL);
///
// 返回 chip type, 检查芯片 hid?
// 【核心】获得更新函数指针
fts_ctpm_get_upgrade_array();
// 奇怪的函数,只是返回固定数组中的值
fts_get_chip_types();
struct ft_chip_t ctype[] = FTS_CHIP_TYPE_MAPPING;
chip_types = ctype[ic_type];
/
// 检查芯片 ?
fts_ctpm_i2c_hid2std(fts_i2c_client);
buf[0] = 0xeb;
buf[1] = 0xaa;
buf[2] = 0x09;
bRet = fts_i2c_write(client, buf, 3);
fts_i2c_read(client, buf, 0, buf, 3);
if ((0xeb == buf[0]) && (0xaa == buf[1]) && (0x08 == buf[2]))
// 【核心】获得更新函数指针
// 对应的函数指针位于:Focaltech_upgrade_ft8006.c (focaltech_touch_ft3427\focaltech_flash)
memcpy(&fts_updatefun_curr, &fts_updatefun, sizeof(struct fts_upgrade_fun));
///
// 注册 input 需要上报的,手势 键值
// 创建 sys 下手势相关的节点
fts_gesture_init(tpd->dev, client);
input_set_capability(input_dev, EV_KEY, KEY_POWER);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_U);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_UP);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_DOWN);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_LEFT);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_RIGHT);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_O);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_E);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_M);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_L);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_W);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_S);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_V);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_Z);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_C);
__set_bit(KEY_GESTURE_RIGHT, input_dev->keybit);
__set_bit(KEY_GESTURE_LEFT, input_dev->keybit);
__set_bit(KEY_GESTURE_UP, input_dev->keybit);
__set_bit(KEY_GESTURE_DOWN, input_dev->keybit);
__set_bit(KEY_GESTURE_U, input_dev->keybit);
__set_bit(KEY_GESTURE_O, input_dev->keybit);
__set_bit(KEY_GESTURE_E, input_dev->keybit);
__set_bit(KEY_GESTURE_M, input_dev->keybit);
__set_bit(KEY_GESTURE_W, input_dev->keybit);
__set_bit(KEY_GESTURE_L, input_dev->keybit);
__set_bit(KEY_GESTURE_S, input_dev->keybit);
__set_bit(KEY_GESTURE_V, input_dev->keybit);
__set_bit(KEY_GESTURE_C, input_dev->keybit);
__set_bit(KEY_GESTURE_Z, input_dev->keybit);
///
// 创建 sys 下节点
fts_create_gesture_sysfs(client);
fts_gesture_data.mode = 0;
fts_gesture_data.active = 0;
///
// TP 上的距感初始化
// 设置标志,创建 sys 下节点
// 注册距感到 hwmsen 中管理,这是老接口
fts_proximity_init(client);
// 设置标志,创建 sys 下节点
fts_proximity_data.detect = 1;
err = sysfs_create_group(&client->dev.kobj, &fts_touch_proximity_group);
/
// 注册距感,这是老接口
obj_ps.polling = 0; // interrupt mode
obj_ps.sensor_operate = fts_ps_operate;
err = hwmsen_attach(ID_PROXIMITY, &obj_ps);
///
// 初始化 MTK 封装 input 的,应该用于批量上报的接口
input_mt_init_slots(tpd->dev, tpd_dts_data.touch_max_num, INPUT_MT_DIRECT);
///
// 通过 pinctrl 复位 TP, 只是复位 rst 引脚
fts_reset_proc(200);
tpd_gpio_output(tpd_rst_gpio_number, 0);
msleep(20);
tpd_gpio_output(tpd_rst_gpio_number, 1);
//
// 通过 i2c 读取寄存器芯片 chip id
fts_wait_tp_to_valid(client);
do {
ret = fts_i2c_read_reg(client, FTS_REG_CHIP_ID, ®_value);
}while ((cnt * INTERVAL_READ_REG) < TIMEOUT_READ_REG);
/
tpd_load_status = 1;
//
// 创建 sys 下节点, 用于升级检测什么的
fts_create_sysfs(client);
//
// // 【get the fw version、
// example:cat fw_version
// static DEVICE_ATTR(fts_fw_version, S_IRUGO | S_IWUSR, fts_tpfwver_show, fts_tpfwver_store);
//
// // 【upgrade from *.i】
// example: echo 1 > fw_update
// static DEVICE_ATTR(fts_fw_update, S_IRUGO | S_IWUSR, fts_fwupdate_show, fts_fwupdate_store);
//
// // 【read and write register】
// read example: echo 88 > rw_reg ---read register 0x88
// write example:echo 8807 > rw_reg ---write 0x07 into register 0x88
//
// note:the number of input must be 2 or 4.if it not enough,please fill in the 0.
// static DEVICE_ATTR(fts_rw_reg, S_IRUGO | S_IWUSR, fts_tprwreg_show, fts_tprwreg_store);
//
// //【upgrade from app.bin】
// example:echo "*_app.bin" > upgrade_app
// static DEVICE_ATTR(fts_upgrade_app, S_IRUGO | S_IWUSR, fts_fwupgradeapp_show, fts_fwupgradeapp_store);
// static DEVICE_ATTR(fts_driver_version, S_IRUGO | S_IWUSR, fts_driverversion_show, fts_driverversion_store);
// static DEVICE_ATTR(fts_dump_reg, S_IRUGO | S_IWUSR, fts_dumpreg_show, fts_dumpreg_store);
// static DEVICE_ATTR(fts_show_log, S_IRUGO | S_IWUSR, fts_show_log_show, fts_show_log_store);
// static DEVICE_ATTR(fts_module_config, S_IRUGO | S_IWUSR, fts_module_config_show, fts_module_config_store);
// #if FTS_ESDCHECK_EN
// static DEVICE_ATTR(fts_esd_check, S_IRUGO | S_IWUSR, fts_esdcheck_show, fts_esdcheck_store);
// #endif
err = sysfs_create_group(&client->dev.kobj, &fts_attribute_group);
//
// 初始化一个工作队列,里面通过 input 事件上报触摸事件
fts_point_report_check_init();
///
// 初始化一个工作队列,里面通过 mtk 封装的 input 事件上报触摸事件
INIT_DELAYED_WORK(&fts_point_report_check_work, fts_point_report_check_func);
fts_point_report_check_func(struct work_struct *work)
for (finger_count = 0; finger_count < FTS_MAX_POINTS; finger_count++)
input_mt_slot(fts_input_dev, finger_count);
input_mt_report_slot_state(fts_input_dev, MT_TOOL_FINGER, false);
input_report_key(fts_input_dev, BTN_TOUCH, 0);
input_sync(fts_input_dev);
/
// 创建工作队列
fts_point_report_check_workqueue = create_workqueue("fts_point_report_check_func_wq");
// 创建 sys 结点, 用于显示当前触摸屏的工作状态: charge / cover / glove
fts_ex_mode_init(client);
g_fts_mode_flag.fts_glove_mode_flag = false;
g_fts_mode_flag.fts_cover_mode_flag = false;
g_fts_mode_flag.fts_charger_mode_flag = false;
err = sysfs_create_group(&client->dev.kobj, &fts_touch_mode_group);
// 创建 /proc 下的调试节点
fts_create_apk_debug_channel(client);
// TP 的工作线程
// 设置调度优先级
// 如果使用虚拟按键的话,先清按键
// 设置调度策略
// 循环:
// 设置当前进程睡眠,等待唤醒
// 工作线程被唤醒,设置进程状态为运行态
// 检查手势功能是否使能,
// 如果手势使能了,那就通过 i2c 读取手势相关寄存器值
// 根据 gesture_id 转换成要通知应用层的 手势值
// 通过 uevent 发送给应用层
// 调用 sysfs_notify() 通知链
// 解析寄存器,将获得的手势值保存在缓存中
// TP 上距感相关数据获取:旧接口,通过 hwsen 上报
// 通过 mtk 封装的 input 事件上报触摸事件
// 设置 esd 标志位,表示当前处理中断处理中:interrupt don't add debug message
// 通过 i2c 读取相关报点值
// 解析 i2c 读取的寄存器值,获得相应的手势值
// 读取寄存器成功,开始上报键值
// 如果有虚拟按键,则通过 input 事件上报:按下松开事件
// 通过 input 上报触摸和手势按键值
// 上报完成后,可以进行 esd 复位了,通过 ese 退出中断了
//
thread_tpd = kthread_run(touch_event_handler, 0, TPD_DEVICE);
/
// 初始化 esd 工作队列, 切换 esd 线程工作状态
///
// esd 工作函数:esdcheck_func()
// 首先检查 lcd 是否复位过,如果复位过,则需要恢复 TP 工作状态
// 如果 lcd 已经复位了,则需要恢复 TP 状态
// 恢复 TP 工作状态
// 轮询通过 i2c 获取芯片 ID
// 芯片状态恢复,之前是处于:
// 1. 手套模式
// 2. 恢复模式
// 3. 充电模式
// 通过 i2c 恢复之前的 TP 中的 PSENSOR 状态
// 通过 i2c 复位手势寄存器
// 通过 input 系统,上报 resume 之前的所有 TP 手势
// 然后进行 esd 策略检查:
// 1. 检查是否在中断中,如果是直接返回
// 2. 检查电源状态,如果在挂起状态,则不需要做检查
// 3. 检查是否有 proc_debug 状态,如果有的话,不需要检查 esd
// 4. 在工厂模式,不需要检查 esd
// 5. 通过 i2c 获得芯片 ID
// 6. 如果能获得芯片 ID, 则获得工作状态计数:0x91, 如果没有改变,则需要复位
// 7. 如果不能获得芯片 ID,则需要进行硬件复位了
// pinctrl 控制 TP 的 rst 脚进行复位
// 恢复 TP 的工作状态
// 然后启动 esd 检查工作队列
fts_esdcheck_init();
///
// 使能 TP 中断
fts_irq_enable();
enable_irq(ft_touch_irq);
// 创建一个工作队列:
// 先关中断,停 esd 检查工作队列
// 通过 I2c 更新 TP/LCM 的 固件
// 恢复中断,启去 esd 检查工作队列
fts_ctpm_upgrade_init();
//
// 创建一些 sys 节点用于测试
fts_test_init(client);
杂项
TouchPanel A_B 协议
Type A: 常按会一直报点
Type B: 常按只报一次点,过滤相同点
由于使用了通知链,所以休眠顺序为:屏-->TP
所以会有灭屏后,还会有短时间存在报点的问题,正常现象。