Linux下 TP(触摸屏)驱动的框架分析

 TP驱动也就是触摸屏驱动,一般触摸屏分为电阻屏或者电容屏,现在大多数都是电容屏。涉及:中断--->IIC 子系统--->input子系统。一般的流程是当手指接触到屏幕时,会在cpu产生一个中断,中断下半部通过IIC总线,从TP的IC中读取相关的信息,在经过 Input 子系统 再对这些数据进行分析,以决定调用哪个事件。

什么是中断:linux下的中断_Croxd的博客-CSDN博客

IIC 子系统:(以GT9XX为例)

  • 基础知识:
    • 三根通信线:SCL、SDA、GND,是同步、串行、电平、低速、近距离的总线式结构,支持多个设备挂接在同一条总线上。
    • 主从式结构,通信双方必须一个为主(master)一个为从(slave),主设备掌握每次通信的主动权,从设备按照主设备的节奏被动响应。每个从设备在总线中有唯一的地址(slave address),主设备通过从地址找到自己要通信的从设备(本质是广播)。
    • I2C主要用途就是主SoC和外围设备之间的通信,最大优势是可以在总线上扩展多个外围设备的支持。常见的各种物联网传感器芯片(如gsensor、温度、湿度、光强度、酸碱度、烟雾浓度、压力等)均使用I2C接口和主SoC进行连接。
    • 电容触摸屏芯片的多个引脚构成2个接口。一个接口是I2C的,负责和主SoC连接(本身作为从设备),主SoC通过该接口初始化及控制电容触摸屏芯片、芯片通过该接口向SoC汇报触摸事件的信息(触摸坐标等),我们使用电容触摸屏时重点关注的是这个接口;另一个接口是电容触摸板的管理接口,电容触摸屏芯片通过该接口来控制触摸板硬件。该接口是电容触摸屏公司关心的,他们的触摸屏芯片内部固件编程要处理这部分,我们使用电容触摸屏的人并不关心这里。
  • 理解IIC四个关键结构体:i2c_client 的注册信息是通过 i2c_adapter 注册时 从 i2c_register_board_info() 的i2c_board_info结构体获取 I2C设备信息.里面包含了从机的地址。(不过现在参数的传递用设备树传递比较方便)
    (1)struct i2c_adapter                IIC适配器
    (2)struct i2c_algorithm             IIC算法,时序
    (3)struct i2c_client                   IIC(从机)设备信息
    (4)struct i2c_driver                  IIC(从机)设备驱动
  • 调用初始化代码 module_init (goodix_ts_init) ----> i2c_add_driver(&goodix_ts_driver) IIC驱动的注册 ----> goodix_ts_driver ----> of_match_table ----> goodix_match_table
  • goodix_ts_probe ()。goodix_match_table.compatible = "goodix,gt9xx" 与 DTSI 文件中的 compatible 一致 ,则执行 probe
    • i2c_check_functionality (client->adapter, I2C_FUNC_I2C)。 IIC适配器的能力测试,如果适配器不够,则发生错误退出
    • gtp_parse_dt (&client->dev)。 从dst设备树获取 INT 中断、RST 引脚的信息
    • INIT_WORK (&ts->work, goodix_ts_work_func)。 初始化创建工作队列,中断触发后,事件处理放在下半部,调用队列中的goodix_ts_work_func函数,计算上报坐标值
    • gtp_request_io_port (ts)。 向系统申请所需的io口:INT、RST
    • gtp_get_chip_type (ts)。 当读取到IC是CHIP_TYPE_GT9F类型时,才会进行初始化下载。HIP_TYPE_GT9F: 内部是Nor Flash,必须每次都要download.CHIP_TYPE_GT9: 内部是Nand Flash,除非需要更新配置文件,否则不需要每次下载.
    • gtp_i2c_test (client)。 测试IIC通讯是否正常
    • gtp_read_version (client, &version_info)。 获取版本信息
    • gtp_init_panel (ts)。 初始化tp固件参数
    • gtp_esd_switch (client, SWITCH_ON)。 esd防静电开启
    • gup_init_update_proc (ts)。 创建一条更新TP固件的线程
    • gtp_request_input_dev (ts)。 注册到 input 输入子系统中去
      • input_allocate_device():为输入设备分配相应的空间
      • ts->input_dev->evbit[0] = BIT_MASK(EV_SYN) | BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) ;   申明功能:支持同步、按键、绝对坐标
      • input_set_capability(ts->input_dev, EV_KEY, touch_key_array[index]);   //如果有按键,害的申明能够处理的按键事件,这里指的是菜单键,HMOE剑和返回键
      • input_set_capability(ts->input_dev, EV_KEY, KEY_POWER);    如果定义滑动唤醒,那就申明电源事件
      • input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, ts->abs_x_max, 0, 0);     多点触摸信息是以ABS_MT承载并按一定顺序发送,如ABS_MT_POSITION_X,ABS_MT_POSITION_Y,然后通过调用 input_mt_sync() 产生一个 SYN_MT_REPORT event 来标记一个点的结束,并且一帧的数据报完需要 input_sync();
      • input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0)    触摸的方向可以由 ABS_MT_TOUCH_MAJOR、ABS_MT_WIDTH_MAJOR、ABS_MT_MT_MAJOR 提供
      • input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 255, 0, 0);     用来支持硬件跟踪多点信息,即该店属于哪一条线等
      • input_register_device(ts->input_dev)  注册input子系统
    • gtp_request_irq(ts);  //请求中断
      • request_irq(ts->client->irq, goodix_ts_irq_handler,irq_table[ts->int_trigger_type], ts->client->name,  ts);   中断申请函数,指定了中断线与绑定的函数是 goodix_ts_irq_handler,如果发生中断该函数就会被调用。参数1:中断线:2:中断函数,3:触发方式:4:设备名,5:私有数据。
        • queue_work(goodix_wq, &ts->work);  
          • goodix_wq: goodix_wq=create_singlethread_workqueue("goodix_wq");  //在函数 goodix_ts_init中,创建工作队列和工作线程,初始化时创建线程
          • &ts->work:NIT_WORK(&ts->work,goodix_ts_work_func);  在工作队列&ts->work中增加 goodix_ts_work_func任务。也就是当中断函数触发时,执行中断函数goodix_ts_irq_handler(),中断函数里面对队列调度,调用队列中的goodix_ts_work_func(),坐标点的计算、上报、多点处理都在这个函数中执行。
      • goodix_ts_timer_handler()。如果资源有限或者其他因素导致申请失败,那么会采用轮询机制来处理。轮询机制是定义一个定时器来处理,hrtimer 是一种高精度定时器,定时器到期就会调用这个函数。接着调用 hrtimer_start()开启定时器功能。
    • init_wr_node(client);     //如果创建了读写节点接口,基于这个节点的接口,方便用户层与内核通讯
    • epay_pindev_register(&ts->pindev);  // 注册为 PIN 输入设备
    • ts->tp_power_status = 1;    //到这边设置为1说明全部初始化 probe成功

input 子系统:

  • 事件处理层:input event,处理核心层传输过来的数据处理成用户说理解的方式,即用 event 结构体方式呈现给用户。 
  • 核心层:为设备驱动层提供规范的接口,把设备驱动层获取得到的数据传送给事件处理层。
  • 设备驱动层:实现对硬件设备的读写访问、中断设置,把触摸的坐标信息通过调用核心层的接口传递给事件处理层。这部分就是驱动工程师所要做的内容。

你可能感兴趣的:(驱动,Linux,linux,stm32)