本文转载自:http://blog.csdn.net/bi511304183/article/details/9303259

平台信息:
内核:linux2.6/linux3.0
系统:android/android4.0

平台:samsung exynos 4210、exynos 4412 、exynos 5250

以goodix的gt8105为例

一、总体架构

硬件部分:先看一个总体的图吧,其实触摸屏原理也比较简单,触摸屏和主控芯片间的联系,如下主要有三部分:

1、IIC部分,初始化gt8105的数据和传回主控制的坐标位置信息就是通过IIC这条线传输的;

2、INT,当gt8105初触摸时,会发出中断通知主控接收信息(坐标数据);

3、gt8105电源、复位这一部分,不同芯片有所不同,可以根据触摸屏芯片来配置。

 软件部分:

 二、电容触摸屏的主要参数(这部分面试的时候也许有人会问的)

记得刚出来找工作时有人问我一些问题,我答不上来,现在感觉很清晰(那时候刚毕业IIC我都说不全)
1、IIC
(1)、clk370KHz~400KHz;
(2)、触摸屏工作在从模式,这个比较简单;
2、电容检测频率,也就是每秒检测的次数:(大概)
(1)、单指≥100Hz;
(2)、五指≥80Hz;
(3)、十指≥60Hz。
3、手指按下,没抬起时触发多少中断?
            中断个数也就是检测频率,按下没提起一直有中断。这样我们就可有判断单点、划线之类的操作;
4、校准功能、自动校准(有个别电容屏没有的,用软件校准)
(1)、初始化校准
             不同的温度、湿度及物理空间结构均会影响到电容传感器在闲置状态的基准值。一般电容触摸屏会在初始化的 200ms内根据环境情况自动获得新的检测基准。完成触摸屏检测的初始化。
(2)、 自动温漂补偿
              温度、湿度或灰尘等环境因素的缓慢变化,也会影响到电容传感器在闲置状态的基准值。实时检测各点数据的变化,对历史数据进行统计分析,由此来修正检测基准。从而降低环境变化对触摸屏检测的影响。    
5、推荐工作条件(环境温度为 25°C,VDD=2.8V)

参数

最小值

典型值

最大值

单位

模拟AVDD(参考AGND)

2.5

2.8

3.6

V

数字DVDD(参考DGND)

2.5

2.8

3.6

V

电源纹波

50(注意电池、充电器的影响)

mV

工作温度

-20

+25

+85

工作湿度

-

-

95

%

三、硬件接口电路:

如下图:

SDA

IIC数据 要上拉电阻,为1K;

SCL

IIC 时钟(400KHz)

TP_EN

使能脚(gt8105为高电平)

INT

中断(一直点到触摸屏时中断是一直发出的)

VCC

3.3V 这个电压一直有

GND

软件部分,整体流程如下:


三、IIC配置

设备到芯片的数据、初始化值都是从这条总线上传输的,首先我们要配置这个条总线,

/linux/arch/arm/mach-exynos/mach-smdkv310.c,这个因平台而已,地址右移也跟情况而定,如果本来就是7bit的地址就不用移位。

  1. static struct i2c_board_info i2c_devs5[] __initdata = {
  2. #if CONFIG_TOUCHSCREEN_GT8105
  3. {
  4. I2C_BOARD_INFO("Goodix-TS", (0xaa>>1)),
  5. .irq = IRQ_EINT(5),
  6. }
  7. #endif
  8. };
  1. static struct i2c_board_info i2c_devs5[] __initdata = {
  2. #if CONFIG_TOUCHSCREEN_GT8105
  3. {
  4. I2C_BOARD_INFO("Goodix-TS", (0xaa>>1)),
  5. .irq = IRQ_EINT(5),
  6. }
  7. #endif
  8. };

四、电源、复位(使能脚)

1、电源

3.3V的电源是一直有的,这个硬件上给就行了。

2、复位(时能脚),这个因触摸屏而已,gt8105工作时要高电平。

在:linux3.0/drivers/input/touchscreen/goodix_touch.h中

  1. #define          RESETPIN_CFG          s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_OUTPUT)
  2. #define          RESETPIN_SET0           gpio_direction_output(EXYNOS4_GPB(4),0)
  3. #define          RESETPIN_SET1          gpio_direction_output(EXYNOS4_GPB(4),1)
  4. static void goodix_reset(void)
  5. {
  6. int err;
  7. err = gpio_request(EXYNOS4_GPB(4), "GPX1");
  8. if (err)
  9. printk(KERN_ERR "#### failed to request GPB_4 ####\n");
  10. RESETPIN_CFG; //配置管脚功能
  11. RESETPIN_SET0;//管脚拉低
  12. mdelay(20); //延时
  13. RESETPIN_SET1;//管脚拉高
  14. mdelay(60);
  15. gpio_free(EXYNOS4_GPB(4));
  16. }
  1. #define          RESETPIN_CFG          s3c_gpio_cfgpin(EXYNOS4_GPB(4), S3C_GPIO_OUTPUT)
  2. #define          RESETPIN_SET0           gpio_direction_output(EXYNOS4_GPB(4),0)
  3. #define          RESETPIN_SET1          gpio_direction_output(EXYNOS4_GPB(4),1)
  4. static void goodix_reset(void)
  5. {
  6. int err;
  7. err = gpio_request(EXYNOS4_GPB(4), "GPX1");
  8. if (err)
  9. printk(KERN_ERR "#### failed to request GPB_4 ####\n");
  10. RESETPIN_CFG; //配置管脚功能
  11. RESETPIN_SET0;//管脚拉低
  12. mdelay(20); //延时
  13. RESETPIN_SET1;//管脚拉高
  14. mdelay(60);
  15. gpio_free(EXYNOS4_GPB(4));
  16. }

五、中断配置

在:linux3.0/drivers/input/touchscreen/goodix_touch.h中

  1. #define INT_PORT EXYNOS4_GPX0(5)
  2. #ifdef INT_PORT
  3. #define TS_INT                     IRQ_EINT(5)//中断引脚,中断号
  4. #define INT_CFG           S3C_GPIO_SFN(0x0F)
  5. #else
  6. 在:linux3.0/drivers/input/touchscreen/goodix_touch.h中 中断申请
  7. #ifdef INT_PORT
  8. client->irq=TS_INT;
  9. if (client->irq)
  10. {
  11. ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,client->name, ts);
  12. #endif
  1. #define INT_PORT EXYNOS4_GPX0(5)
  2. #ifdef INT_PORT
  3. #define TS_INT                     IRQ_EINT(5)//中断引脚,中断号
  4. #define INT_CFG           S3C_GPIO_SFN(0x0F)
  5. #else
  6. 在:linux3.0/drivers/input/touchscreen/goodix_touch.h中 中断申请
  7. #ifdef INT_PORT
  8. client->irq=TS_INT;
  9. if (client->irq)
  10. {
  11. ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,client->name, ts);
  12. #endif

上面三部完成了触摸屏工作的最基本配置,保证IIC、上电、INT正常,触摸屏就可以工作。

六、驱动程序分析(完整代码见 goodix_touch.c/goodix_touch.h

驱动有几个比较重要的部分:probe函数分析;中断申请、工作队列调度;中断下半部函数的执行,坐标值计算、上报。

1、probe函数分析

  1. static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
  2. {
  3. struct goodix_ts_data *ts;
  4. …………
  5. // 1,分配触摸屏结构内核空间;
  6. ts = kzalloc(sizeof(*ts), GFP_KERNEL);
  7. …………
  8. // 2,初始化工作队列,这个比较重要,中断触发后,调用队列中的goodix_ts_work_func函数,计算上报坐标值;
  9. INIT_WORK(&ts->work, goodix_ts_work_func);
  10. …………
  11. // 3, 触摸芯片初始化;
  12. for(retry=0; retry<3; retry++)
  13. {
  14. ret=goodix_init_panel(ts);
  15. …………
  16. }
  17. //4、触摸屏复位,拉高;
  18. goodix_reset();
  19. #ifdef INT_PORT
  20. // 5,中断申请,TS_INT就是我们所设定的中断脚;
  21. client->irq=TS_INT;
  22. ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,
  23. client->name, ts);
  24. ………………
  25. #endif
  26. // 6、分配input驱动内核空间;
  27. ts->input_dev = input_allocate_device();
  28. // 7,input初始化参数设定,我们在前面提到Linux与Android 多点触摸协议里有对这部分说明;
  29. ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
  30. ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
  31. ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);                                                             // absolute coor (x,y)
  32. #ifdef HAVE_TOUCH_KEY
  33. for(retry = 0; retry < MAX_KEY_NUM; retry++)
  34. {
  35. input_set_capability(ts->input_dev,EV_KEY,touch_key_array[retry]);
  36. }
  37. #endif
  38. input_set_abs_params(ts->input_dev, ABS_X, 0, ts->abs_x_max, 0, 0);
  39. input_set_abs_params(ts->input_dev, ABS_Y, 0, ts->abs_y_max, 0, 0);
  40. input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0);
  41. //8、这部分针对触摸屏参数设定;
  42. #ifdef GOODIX_MULTI_TOUCH
  43. input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
  44. input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
  45. input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);
  46. input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0);
  47. input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, ts->max_touch_num, 0, 0);
  48. #endif
  49. //9、触摸屏版本信息设定;
  50. sprintf(ts->phys, "input/ts");
  51. ts->input_dev->name = goodix_ts_name;
  52. ts->input_dev->phys = ts->phys;
  53. ts->input_dev->id.bustype = BUS_I2C;
  54. ts->input_dev->id.vendor = 0xDEAD;
  55. ts->input_dev->id.product = 0xBEEF;
  56. ts->input_dev->id.version = 10427;          //screen firmware version
  57. //10,对于input子系统来说,这个是重头戏了,只有注册了input子系统,其他的才有做用;
  58. ret = input_register_device(ts->input_dev);
  59. ………………
  60. // 11,对睡眠唤醒操作;
  61. #ifdef CONFIG_HAS_EARLYSUSPEND
  62. ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
  63. ts->early_suspend.suspend = goodix_ts_early_suspend;
  64. ts->early_suspend.resume = goodix_ts_late_resume;
  65. register_early_suspend(&ts->early_suspend);
  66. #endif
  67. ………………
  68. }
  1. static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
  2. {
  3. struct goodix_ts_data *ts;
  4. …………
  5. // 1,分配触摸屏结构内核空间;
  6. ts = kzalloc(sizeof(*ts), GFP_KERNEL);
  7. …………
  8. // 2,初始化工作队列,这个比较重要,中断触发后,调用队列中的goodix_ts_work_func函数,计算上报坐标值;
  9. INIT_WORK(&ts->work, goodix_ts_work_func);
  10. …………
  11. // 3, 触摸芯片初始化;
  12. for(retry=0; retry<3; retry++)
  13. {
  14. ret=goodix_init_panel(ts);
  15. …………
  16. }
  17. //4、触摸屏复位,拉高;
  18. goodix_reset();
  19. #ifdef INT_PORT
  20. // 5,中断申请,TS_INT就是我们所设定的中断脚;
  21. client->irq=TS_INT;
  22. ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,
  23. client->name, ts);
  24. ………………
  25. #endif
  26. // 6、分配input驱动内核空间;
  27. ts->input_dev = input_allocate_device();
  28. // 7,input初始化参数设定,我们在前面提到Linux与Android 多点触摸协议里有对这部分说明;
  29. ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;
  30. ts->input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
  31. ts->input_dev->absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);                                                             // absolute coor (x,y)
  32. #ifdef HAVE_TOUCH_KEY
  33. for(retry = 0; retry < MAX_KEY_NUM; retry++)
  34. {
  35. input_set_capability(ts->input_dev,EV_KEY,touch_key_array[retry]);
  36. }
  37. #endif
  38. input_set_abs_params(ts->input_dev, ABS_X, 0, ts->abs_x_max, 0, 0);
  39. input_set_abs_params(ts->input_dev, ABS_Y, 0, ts->abs_y_max, 0, 0);
  40. input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0);
  41. //8、这部分针对触摸屏参数设定;
  42. #ifdef GOODIX_MULTI_TOUCH
  43. input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
  44. input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
  45. input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);
  46. input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, ts->abs_y_max, 0, 0);
  47. input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, ts->max_touch_num, 0, 0);
  48. #endif
  49. //9、触摸屏版本信息设定;
  50. sprintf(ts->phys, "input/ts");
  51. ts->input_dev->name = goodix_ts_name;
  52. ts->input_dev->phys = ts->phys;
  53. ts->input_dev->id.bustype = BUS_I2C;
  54. ts->input_dev->id.vendor = 0xDEAD;
  55. ts->input_dev->id.product = 0xBEEF;
  56. ts->input_dev->id.version = 10427;          //screen firmware version
  57. //10,对于input子系统来说,这个是重头戏了,只有注册了input子系统,其他的才有做用;
  58. ret = input_register_device(ts->input_dev);
  59. ………………
  60. // 11,对睡眠唤醒操作;
  61. #ifdef CONFIG_HAS_EARLYSUSPEND
  62. ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
  63. ts->early_suspend.suspend = goodix_ts_early_suspend;
  64. ts->early_suspend.resume = goodix_ts_late_resume;
  65. register_early_suspend(&ts->early_suspend);
  66. #endif
  67. ………………
  68. }

(1)、分配触摸屏结构内核空间;

  1. struct goodix_ts_data {
  2. uint16_t addr;
  3. uint8_t bad_data;
  4. struct i2c_client *client;
  5. struct input_dev *input_dev;
  6. int use_reset;                    //use RESET flag
  7. int use_irq;                    //use EINT flag
  8. int read_mode;                    //read moudle mode,20110221 by andrew
  9. struct hrtimer timer;
  10. struct work_struct work;
  11. char phys[32];
  12. int retry;
  13. struct early_suspend early_suspend;
  14. int (*power)(struct goodix_ts_data * ts, int on);
  15. uint16_t abs_x_max;
  16. uint16_t abs_y_max;
  17. uint8_t max_touch_num;
  18. uint8_t int_trigger_type;
  19. uint8_t green_wake_mode;
  20. };
  1. struct goodix_ts_data {
  2. uint16_t addr;
  3. uint8_t bad_data;
  4. struct i2c_client *client;
  5. struct input_dev *input_dev;
  6. int use_reset;                    //use RESET flag
  7. int use_irq;                    //use EINT flag
  8. int read_mode;                    //read moudle mode,20110221 by andrew
  9. struct hrtimer timer;
  10. struct work_struct work;
  11. char phys[32];
  12. int retry;
  13. struct early_suspend early_suspend;
  14. int (*power)(struct goodix_ts_data * ts, int on);
  15. uint16_t abs_x_max;
  16. uint16_t abs_y_max;
  17. uint8_t max_touch_num;
  18. uint8_t int_trigger_type;
  19. uint8_t green_wake_mode;
  20. };

(2)、初始化工作队列,这个比较重要,中断触发后,调用队列中的goodix_ts_work_func函数,计算上报坐标值;这个和中断申请一起分析;

(3)、触摸芯片初始化;

对触摸芯片寄存器的初始化,这里面对中断方式设定等,一般芯片厂的FAE在调试的时候会修改这里面的值,这个也是因芯片而异,有的在驱动里做,可以直接改;有的直接做成固件了,那部分要FAE帮忙了。

  1. uint8_t cfg_info_group1[] =
  2. {
  3. 0x65,0x00,0x25,0x80,0x19,0x00,0x00,0x2C,0x11,0x11,0x32,0x02,0x08,0x10,0x20,0x00,
  4. 0x00,0x88,0x88,0x88,0x03,0x13,0x32,0x64,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
  5. 0x08,0x09,0x0A,0x0B,0x0C,0xFF,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
  6. 0x17,0x18,0x19,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  7. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  8. 0x00,0x00,0x00,0x00
  9. };
  1. uint8_t cfg_info_group1[] =
  2. {
  3. 0x65,0x00,0x25,0x80,0x19,0x00,0x00,0x2C,0x11,0x11,0x32,0x02,0x08,0x10,0x20,0x00,
  4. 0x00,0x88,0x88,0x88,0x03,0x13,0x32,0x64,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
  5. 0x08,0x09,0x0A,0x0B,0x0C,0xFF,0x0D,0x0E,0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
  6. 0x17,0x18,0x19,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  7. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  8. 0x00,0x00,0x00,0x00
  9. };

(4)、触摸屏复位,拉高;

gt8015在工作时要拉高,所以我们做一个拉低—延时--拉高的操作;

(5)、中断申请,TS_INT就是我们所设定的中断脚,和(2)一起后面分析;

(6)、分配input驱动内核空间;

  1. ts->input_dev= input_allocate_device();
  1. ts->input_dev= input_allocate_device();

(7)、input初始化参数设定,我们在前面提到Linux与Android 多点触摸协议里有对这部分说明;(8)、这部分针对触摸屏参数设定;

(9)、触摸屏版本信息设定;

  1. cat /proc/bus/input/devices时可以看到下面信息(这个是pixcir的触摸屏)
  2. I: Bus=0018 Vendor=0000 Product=0000 Version=0000
  3. N: Name="pixcir-ts"
  4. P: Phys=
  5. S: Sysfs=/devices/platform/s3c2440-i2c.5/i2c-5/5-005c/input/input3
  6. U: Uniq=
  7. H: Handlers=kbd event3
  8. B: PROP=0
  9. B: EV=b
  10. B: KEY=400 0 0 0 0 1000 40000800 0 0 0 0
  11. B: ABS=2650000 1000000
  1. cat /proc/bus/input/devices时可以看到下面信息(这个是pixcir的触摸屏)
  2. I: Bus=0018 Vendor=0000 Product=0000 Version=0000
  3. N: Name="pixcir-ts"
  4. P: Phys=
  5. S: Sysfs=/devices/platform/s3c2440-i2c.5/i2c-5/5-005c/input/input3
  6. U: Uniq=
  7. H: Handlers=kbd event3
  8. B: PROP=0
  9. B: EV=b
  10. B: KEY=400 0 0 0 0 1000 40000800 0 0 0 0
  11. B: ABS=2650000 1000000

(10)、对于input子系统来说,这个是重头戏了,驱动注册到input子系统;

  1. input_register_device(ts->input_dev);
  1. input_register_device(ts->input_dev);

(11),触摸屏睡眠唤醒操作,这部分不做详细说明,感兴趣的可以看下……

2、中断申请、工作队列调度

(1)、中断申请

  1. ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,
  2. client->name, ts);
  3. 第一个参数: 中断号,client->irq,client->irq=TS_INT;
  4. #define TS_INT                     IRQ_EINT(5)对应到我们要申请的中断;
  5. 第二个参数:中断执行函数,goodix_ts_irq_handler ;
  6. 第三个参数:中断触发方式:上升沿触发、下降沿触发、高电平触发、低电平触发
  7. IRQ_TYPE_EDGE_RISING,
  8. IRQ_TYPE_EDGE_FALLING,
  9. IRQ_TYPE_LEVEL_LOW,
  10. IRQ_TYPE_LEVEL_HIGH
  11. 第四个参数:
  12. 第五个参数:
  1. ret = request_irq(client->irq, goodix_ts_irq_handler , IRQ_TYPE_EDGE_RISING|IRQ_TYPE_EDGE_FALLING,
  2. client->name, ts);
  3. 第一个参数: 中断号,client->irq,client->irq=TS_INT;
  4. #define TS_INT                     IRQ_EINT(5)对应到我们要申请的中断;
  5. 第二个参数:中断执行函数,goodix_ts_irq_handler ;
  6. 第三个参数:中断触发方式:上升沿触发、下降沿触发、高电平触发、低电平触发
  7. IRQ_TYPE_EDGE_RISING,
  8. IRQ_TYPE_EDGE_FALLING,
  9. IRQ_TYPE_LEVEL_LOW,
  10. IRQ_TYPE_LEVEL_HIGH
  11. 第四个参数:
  12. 第五个参数:

(2)、中断处理函数 goodix_ts_irq_handler

  1. static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
  2. {
  3. struct goodix_ts_data *ts = dev_id;
  4. queue_work(goodix_wq, &ts->work);
  5. return IRQ_HANDLED;
  6. }
  1. static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
  2. {
  3. struct goodix_ts_data *ts = dev_id;
  4. queue_work(goodix_wq, &ts->work);
  5. return IRQ_HANDLED;
  6. }

看下queue_work()这个函数中的两个参数:

a、goodix_wq

  1. goodix_wq=create_singlethread_workqueue("goodix_wq");                    //createa work queue and worker thread
  1. goodix_wq=create_singlethread_workqueue("goodix_wq");                    //createa work queue and worker thread

在函数 goodix_ts_init中,创建工作队列和工作线程,初始化时创建线程。

b、&ts->work

在函数goodix_ts_probe()中:

  1. INIT_WORK(&ts->work,goodix_ts_work_func);
  1. INIT_WORK(&ts->work,goodix_ts_work_func);

在工作队列&ts->work中增加 goodix_ts_work_func任务。

也就是当中断函数触发时,执行中断函数goodix_ts_irq_handler(),中断函数里面对队列调度,调用队列中的goodix_ts_work_func()函数。

3、中断下半部函数的执行goodix_ts_work_func()函数

这就是核心部分,坐标点的计算、上报、多点处理都在这个函数中执行。

  1. static void goodix_ts_work_func(struct work_struct *work)
  2. {
  3. int ret=-1;
  4. int tmp = 0;
  5. uint8_t point_data[(1-READ_COOR_ADDR)+1+2+5*MAX_FINGER_NUM+1]={ 0 }; //read address(1byte)+key index(1byte)+point mask(2bytes)+5bytes*MAX_FINGER_NUM+coor checksum(1byte)
  6. uint8_t check_sum = 0;
  7. uint16_t finger_current = 0;
  8. uint16_t finger_bit = 0;
  9. unsigned int count = 0, point_count = 0;
  10. unsigned int position = 0;
  11. uint8_t track_id[MAX_FINGER_NUM] = {0};
  12. unsigned int input_x = 0;
  13. unsigned int input_y = 0;
  14. unsigned int input_w = 0;
  15. unsigned char index = 0;
  16. unsigned char touch_num = 0;
  17. struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work);
  18. if(g_enter_isp)return;
  19. COORDINATE_POLL:
  20. if((ts->int_trigger_type> 1)&& (gpio_get_value(INT_PORT) != (ts->int_trigger_type&0x01)))
  21. {
  22. goto NO_ACTION;
  23. }
  24. if( tmp > 9) {
  25. dev_info(&(ts->client->dev), "I2C transfer error,touchscreen stop working.\n");
  26. goto XFER_ERROR ;
  27. }
  28. if(ts->bad_data)
  29. msleep(20);
  30. point_data[0] = READ_COOR_ADDR;                    //read coor address
  31. //1、读取触摸屏值,手指数、坐标值等;
  32. ret=i2c_read_bytes(ts->client, point_data, ((1-READ_COOR_ADDR)+1+2+5*ts->max_touch_num+1));
  33. …………
  34. //2、判断是否有手指按下;
  35. finger_current = (point_data[3 - READ_COOR_ADDR]<<8) + point_data[2 – READ_COOR_ADDR];
  36. if(finger_current)//3、如果有手指按下
  37. {
  38. point_count = 0, finger_bit = finger_current;
  39. //3,循环判断有多少手指按下;
  40. for(count = 0; (finger_bit != 0) && (count < ts->max_touch_num); count++)//cal how many point touch currntly
  41. {
  42. if(finger_bit & 0x01)
  43. {
  44. track_id[point_count] = count;
  45. point_count++;
  46. }
  47. finger_bit >>= 1;
  48. }
  49. //4、把按下手指数赋给touch_num;
  50. touch_num = point_count;
  51. //5、计算坐标值;
  52. check_sum = point_data[2 - READ_COOR_ADDR] + point_data[3 - READ_COOR_ADDR];                               //cal coor checksum
  53. count = 4 - READ_COOR_ADDR;
  54. for(point_count *= 5; point_count > 0; point_count--)
  55. check_sum += point_data[count++];
  56. check_sum += point_data[count];
  57. if(check_sum != 0)                              //checksum verify error
  58. {
  59. printk("coor checksum error!\n");
  60. if(ts->int_trigger_type> 1)
  61. goto COORDINATE_POLL;
  62. else
  63. goto XFER_ERROR;
  64. }
  65. }
  66. //6、读取值坐标值上报;
  67. if(touch_num)
  68. {
  69. //7、touch_num为按下手指个数,依次循环读取;
  70. for(index=0; index<touch_num; index++)
  71. {
  72. position = 4 - READ_COOR_ADDR + 5*index;
  73. //8、读出X的值;
  74. input_x = (unsigned int) (point_data[position]<<8) + (unsigned int)( point_data[position+1]);
  75. //9、读出Y的值;
  76. input_y = (unsigned int)(point_data[position+2]<<8) + (unsigned int) (point_data[position+3]);
  77. input_w =(unsigned int) (point_data[position+4]);
  78. //10、如果读出值超出范围,退出;
  79. if((input_x > ts->abs_x_max)||(input_y > ts->abs_y_max))
  80. continue;
  81. //11、下面的函数依次上报坐标, input_mt_sync单点同步
  82. input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
  83. input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
  84. input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
  85. input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
  86. input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, track_id[index]);
  87. input_mt_sync(ts->input_dev);
  88. }
  89. }
  90. //12、没有触摸时,初始值为0;
  91. else
  92. {
  93. input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
  94. input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
  95. input_mt_sync(ts->input_dev);
  96. }
  97. //13、同步多点值;
  98. input_sync(ts->input_dev);
  99. if(ts->int_trigger_type> 1)
  100. {
  101. msleep(POLL_TIME);
  102. goto COORDINATE_POLL;
  103. }
  104. goto END_WORK_FUNC;
  105. NO_ACTION:
  106. END_WORK_FUNC:
  107. XFER_ERROR:
  108. return;
  109. }
  1. static void goodix_ts_work_func(struct work_struct *work)
  2. {
  3. int ret=-1;
  4. int tmp = 0;
  5. uint8_t point_data[(1-READ_COOR_ADDR)+1+2+5*MAX_FINGER_NUM+1]={ 0 }; //read address(1byte)+key index(1byte)+point mask(2bytes)+5bytes*MAX_FINGER_NUM+coor checksum(1byte)
  6. uint8_t check_sum = 0;
  7. uint16_t finger_current = 0;
  8. uint16_t finger_bit = 0;
  9. unsigned int count = 0, point_count = 0;
  10. unsigned int position = 0;
  11. uint8_t track_id[MAX_FINGER_NUM] = {0};
  12. unsigned int input_x = 0;
  13. unsigned int input_y = 0;
  14. unsigned int input_w = 0;
  15. unsigned char index = 0;
  16. unsigned char touch_num = 0;
  17. struct goodix_ts_data *ts = container_of(work, struct goodix_ts_data, work);
  18. if(g_enter_isp)return;
  19. COORDINATE_POLL:
  20. if((ts->int_trigger_type> 1)&& (gpio_get_value(INT_PORT) != (ts->int_trigger_type&0x01)))
  21. {
  22. goto NO_ACTION;
  23. }
  24. if( tmp > 9) {
  25. dev_info(&(ts->client->dev), "I2C transfer error,touchscreen stop working.\n");
  26. goto XFER_ERROR ;
  27. }
  28. if(ts->bad_data)
  29. msleep(20);
  30. point_data[0] = READ_COOR_ADDR;                    //read coor address
  31. //1、读取触摸屏值,手指数、坐标值等;
  32. ret=i2c_read_bytes(ts->client, point_data, ((1-READ_COOR_ADDR)+1+2+5*ts->max_touch_num+1));
  33. …………
  34. //2、判断是否有手指按下;
  35. finger_current = (point_data[3 - READ_COOR_ADDR]<<8) + point_data[2 – READ_COOR_ADDR];
  36. if(finger_current)//3、如果有手指按下
  37. {
  38. point_count = 0, finger_bit = finger_current;
  39. //3,循环判断有多少手指按下;
  40. for(count = 0; (finger_bit != 0) && (count < ts->max_touch_num); count++)//cal how many point touch currntly
  41. {
  42. if(finger_bit & 0x01)
  43. {
  44. track_id[point_count] = count;
  45. point_count++;
  46. }
  47. finger_bit >>= 1;
  48. }
  49. //4、把按下手指数赋给touch_num;
  50. touch_num = point_count;
  51. //5、计算坐标值;
  52. check_sum = point_data[2 - READ_COOR_ADDR] + point_data[3 - READ_COOR_ADDR];                               //cal coor checksum
  53. count = 4 - READ_COOR_ADDR;
  54. for(point_count *= 5; point_count > 0; point_count--)
  55. check_sum += point_data[count++];
  56. check_sum += point_data[count];
  57. if(check_sum != 0)                              //checksum verify error
  58. {
  59. printk("coor checksum error!\n");
  60. if(ts->int_trigger_type> 1)
  61. goto COORDINATE_POLL;
  62. else
  63. goto XFER_ERROR;
  64. }
  65. }
  66. //6、读取值坐标值上报;
  67. if(touch_num)
  68. {
  69. //7、touch_num为按下手指个数,依次循环读取;
  70. for(index=0; index<touch_num; index++)
  71. {
  72. position = 4 - READ_COOR_ADDR + 5*index;
  73. //8、读出X的值;
  74. input_x = (unsigned int) (point_data[position]<<8) + (unsigned int)( point_data[position+1]);
  75. //9、读出Y的值;
  76. input_y = (unsigned int)(point_data[position+2]<<8) + (unsigned int) (point_data[position+3]);
  77. input_w =(unsigned int) (point_data[position+4]);
  78. //10、如果读出值超出范围,退出;
  79. if((input_x > ts->abs_x_max)||(input_y > ts->abs_y_max))
  80. continue;
  81. //11、下面的函数依次上报坐标, input_mt_sync单点同步
  82. input_report_abs(ts->input_dev, ABS_MT_POSITION_X, input_x);
  83. input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, input_y);
  84. input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, input_w);
  85. input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w);
  86. input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, track_id[index]);
  87. input_mt_sync(ts->input_dev);
  88. }
  89. }
  90. //12、没有触摸时,初始值为0;
  91. else
  92. {
  93. input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
  94. input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
  95. input_mt_sync(ts->input_dev);
  96. }
  97. //13、同步多点值;
  98. input_sync(ts->input_dev);
  99. if(ts->int_trigger_type> 1)
  100. {
  101. msleep(POLL_TIME);
  102. goto COORDINATE_POLL;
  103. }
  104. goto END_WORK_FUNC;
  105. NO_ACTION:
  106. END_WORK_FUNC:
  107. XFER_ERROR:
  108. return;
  109. }

总的来数,当我们手指按下是,不管是单个手指,还是多个手指,坐标值和一些信息存储到触摸芯片的相应寄存器中,然后再通过IIC读出,送到主控中就可以了,其他事情就是android去处理了。

如下图所示,规格书中坐标及重量:XY坐标缓存寄存器的高低位:

中断触发--中断函数--工作队列调度--功能函数执行

转载自xubin341719, 感谢xubin341719的无私的奉献

Android TP(三)【转】的更多相关文章

  1. Android动画 三种动画

    Android可以使用三种动画 Frame Animation-帧动画 ,就像GIF图片,通过一系列Drawable依次显示来模拟动画的效果 Tween Animation-补间动画,给出两个关键帧, ...

  2. 【转】Android LCD(三):Samsung LCD接口篇

    关键词:android LCD控制器 Framebuffer PWM  平台信息:内核:linux2.6/linux3.0系统:android/android4.0 平台:samsung exynos ...

  3. 【转】android camera(三):camera V4L2 FIMC

    关键词:android  camera CMM 模组 camera参数  CAMIF   V4L2  平台信息:内核:linux系统:android 平台:S5PV310(samsung exynos ...

  4. Android tp的虚拟按键(virtual key)处理

    Android tp的虚拟按键处理 现在在越来越多的Android的手机都是虚拟按键来操作,但是对于开发者来说可能会关心Android对虚拟按键如何处理的.对Linux熟悉的人可能会说,it's ea ...

  5. Android LCD(三):Samsung LCD接口篇

    关键词:android LCD控制器 Framebuffer PWM  平台信息: 内核:linux2.6/linux3.0 系统:android/android4.0  平台:samsung exy ...

  6. Android中三种超实用的滑屏方式汇总(转载)

    Android中三种超实用的滑屏方式汇总   现如今主流的Android应用中,都少不了左右滑动滚屏这项功能,(貌似现在好多人使用智能机都习惯性的有事没事的左右滑屏,也不知道在干什么...嘿嘿),由于 ...

  7. Android Studio(三):设置Android Studio编码

    Android Studio相关博客: Android Studio(一):介绍.安装.配置 Android Studio(二):快捷键设置.插件安装 Android Studio(三):设置Andr ...

  8. 我的Android第三章

    先看效果图. 点击之后出变成 按钮内容改变了,并且弹出一个小提示 下面我们就来看看如何实现这个小案例 1)先打开string.xml文件,把要定义的字符串资源放置在里面 2)然后我们要画页面,基本An ...

  9. Android入门(三)Activity-生命周期与启动模式

    原文链接:http://www.orlion.ga/432/ 一.活动的生命周期 1.返回栈 Android中的活动是可以重叠的,我们每启动一个新的活动,就会覆盖在原活动之上,然后点击Back键会销毁 ...

随机推荐

  1. 并发编程学习笔记(8)----ThreadLocal的使用及源码分析

    1. ThreadLocal的理解 ThreadLocal,顾名思义,就是线程的本地变量,ThreadLocal会为每个线程创建一个本地变量副本,使得使用ThreadLocal管理的变量在多线程的环境 ...

  2. 梦想MxWeb3D,三维CAD协同设计平台 2019.04.09更新

    SDK开发包下载地址: http://www.mxdraw.com/ndetail_10140.html 在线演示网址: http://www.mxdraw.com:3000/ 1.  增加上传dwg ...

  3. 出生年 (15 分) C解法

    出生年 以上是新浪微博中一奇葩贴:"我出生于1988年,直到25岁才遇到4个数字都不相同的年份."也就是说,直到2013年才达到"4个数字都不相同"的要求.本题 ...

  4. 【loj6184】无心行挽(虚树+倍增)

    题目链接:https://loj.ac/problem/6184 每次询问给一些关键点,询问树上每个点离最近的关键点的距离(以后称为f(u))最大值是多少. 询问数比较大,但 \sum{K} 和n是一 ...

  5. Swoft 新手向教程 - 通过 Docker 搭建一个开发环境

    本系列文章将从使用层面介绍 Swoft 框架的使用及业务开发,面向初中级的 PHPer Swoft首个基于 Swoole 原生协程的新时代 PHP 高性能协程全栈组件化框架,内置协程网络服务器及常用的 ...

  6. C. Day at the Beach

    codeforces 599c C. Day at the Beach One day Squidward, Spongebob and Patrick decided to go to the be ...

  7. hdu 1533KM算法

    #include<stdio.h> #include<string.h> #include<math.h> #define inf 0x3fffffff #defi ...

  8. 写给对<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">迷惑不解的小伙伴

    1.X-UA-Compatible X-UA-Compatible是自从IE8新加的一个设置,对于IE8以下的浏览器是不识别的. 通过在meta中设置X-UA-Compatible的值,可以指定网页的 ...

  9. [SDOI2011]打地鼠

    题目描述 打地鼠是这样的一个游戏:地面上有一些地鼠洞,地鼠们会不时从洞里探出头来很短时间后又缩回洞中.玩家的目标是在地鼠伸出头时,用锤子砸其头部,砸到的地鼠越多分数也就越高. 游戏中的锤子每次只能打一 ...

  10. CF899F. Letters Removing

    给一个字符串支持以下操作:区间删除某个特定字符.最后输出字符串.n,m<=200000. 这题我居然不会可以回家了.. 首先,单点删除,选个平衡树比如set. 然后,他给的下标是会随删除操作变化 ...