OpenHarmony南向之TP触摸屏

概述

Touchscreen驱动用于驱动触摸屏使其正常工作,该驱动主要完成如下工作:对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口(I2C或SPI)、设定Input相关配置、下载及更新固件等操作。

Touchscreen驱动基于HDF的Input驱动模型

Input驱动模型

Input驱动模型基于HDF驱动框架、Platform接口、OSAL接口进行开发,向上对接规范化的驱动接口HDI(Hardware Device Interface)层,通过Input-HDI层对外提供硬件能力,即上层Input Service可以通过HDI接口层获取相应的驱动能力,进而操控Touchscreen等输入设备。

基于HDF驱动框架的input驱动模型.png

Input驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。

  • Input设备管理:为各类输入设备驱动提供Input设备的注册、注销接口,同时对Input设备列表进行统一管理。
  • Input平台驱动:指各类Input设备的公共抽象驱动(例如触摸屏的公共驱动),该部分主要负责对板级硬件进行初始化、硬件中断处理、向manager注册Input设备等。
  • Input器件驱动:指各器件厂家的差异化驱动,开发者可以通过适配平台驱动预留的差异化接口进行器件驱动开发,实现器件驱动开发量最小化。
  • Input数据通道(event hub):提供一套通用的数据上报通道,各类别的Input设备驱动均可用此通道上报Input事件。
  • Input配置解析(hcs):负责对Input设备的板级配置及器件私有配置进行解析及管理。

Touchscreen驱动架构

现在以RK3568为例,来看看Touchscreen整个驱动架构

主要相关代码路径:

  • drivers/hdf_core/framework/model/input/driver/touchscreen/
  • vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs
  • vendor/hihope/rk3568/hdf_config/khdf/input/input_config.hcs

主要代码框架:

dayu200-tp-01.png

下面详细展开

hcs

先看看hcs文件

device_info.hcs

input :: host {
    hostName = "input_host";
    priority = 100;
    device_input_manager :: device {
        device0 :: deviceNode {
            policy = 2;
            priority = 100;
            preload = 0;
            permission = 0660;
            moduleName = "HDF_INPUT_MANAGER";
            serviceName = "hdf_input_host";
            deviceMatchAttr = "";
        }
    }
    device_hdf_touch :: device {
        device0 :: deviceNode {
            policy = 2;
            priority = 120;
            preload = 0;
            permission = 0660;
            moduleName = "HDF_TOUCH";
            serviceName = "hdf_input_event1";
            deviceMatchAttr = "touch_device1";
        }
    }

    device_touch_chip :: device {
        device0 :: deviceNode {
            policy = 0;
            priority = 130;
            preload = 0;
            permission = 0660;
            moduleName = "HDF_TOUCH_GT911";
            serviceName = "hdf_touch_gt911_service";
            deviceMatchAttr = "zsj_gt911_5p5";
        }
    }

    ...
}

从上面可以看出,与触摸相关的主要是3个节点,刚好与实现TS驱动模型对应:

  • HDF_INPUT_MANAGER:Input设备管理
  • HDF_TOUCH:触摸屏的公共抽象驱动
  • HDF_TOUCH_GT911:具体的Input器件驱动

后面章节会基于源码详细展开这3块

input_config.hcs

root {
    input_config {
        touchConfig {
            touch0 {
                boardConfig {
                    match_attr = "touch_device1";
                    inputAttr {
                        /* 0:touch 1:key 2:keyboard 3:mouse 4:button 5:crown 6:encoder */
                        inputType = 0;
                        solutionX = 720;
                        solutionY = 1280;
                        devName = "main_touch";
                    }
                    busConfig {
                        // 0:i2c 1:spi
                        busType = 0;
                        busNum = 1;
                        clkGpio = 86;
                        dataGpio = 87;
                        i2cClkIomux = [0x114f0048, 0x403];
                        i2cDataIomux = [0x114f004c, 0x403];
                    }
                    pinConfig {
                        rstGpio = 14;
                        intGpio = 13;
                        rstRegCfg = [0x112f0094, 0x400];
                        intRegCfg = [0x112f0098, 0x400];
                    }
                    powerConfig {
                        /* 0:unused 1:ldo 2:gpio 3:pmic */
                        vccType = 2;
                        vccNum = 20;    // gpio20
                        vccValue = 1800;
                        vciType = 1;
                        vciNum = 12;    // ldo12
                        vciValue = 3300;
                    }

                    featureConfig {
                        capacitanceTest = 0;
                        gestureMode = 0;
                        gloverMOde = 0;
                        coverMode = 0;
                        chargerMode = 0;
                        knuckleMode = 0;
                    }
                }
                chipConfig {
                    template touchChip {
                        match_attr = "";
                        chipName = "gt911";
                        vendorName = "zsj";
                        chipInfo = "AAAA11222";  // 4-ProjectName, 2-TP IC, 3-TP Module
                        /* 0:i2c 1:spi*/
                        busType = 0;
                        deviceAddr = 0x5D;
                        /* 0:None 1:Rising 2:Failing 4:High-level 8:Low-level */
                        irqFlag = 2;
                        maxSpeed = 400;
                        chipVersion = 0; //parse Coord TypeA
                        powerSequence {
                            /* [type, status, dir , delay]
                                <type> 0:none 1:vcc-1.8v 2:vci-3.3v 3:reset 4:int
                                <status> 0:off or low  1:on or high  2:no ops
                                <dir> 0:input  1:output  2:no ops
                                <delay> meanings delay xms, 20: delay 20ms
                                */
                            powerOnSeq = [4, 0, 1, 5,
                                            3, 0, 1, 10,
                                            3, 1, 1, 60,
                                            4, 2, 0, 50];
                            suspendSeq = [3, 0, 2, 10];
                            resumeSeq = [3, 1, 2, 10];
                            powerOffSeq = [3, 0, 2, 10,
                                            1, 0, 2, 20];
                        }
                    }

                    chip0 :: touchChip {
                        match_attr = "zsj_gt911_5p5";
                        chipInfo = "ZIDN45100";  // 4-ProjectName, 2-TP IC, 3-TP Module
                        chipVersion = 0; //parse point by TypeA
                    }
                    ...
                }           
                ...
            }
        }
    }
}

device_info中的节点通过 deviceMatchAttrmatch_attr字段匹配配置,
chipConfig配置中主要定义了一些与实际硬件相关的信息:

  • 硬件接口的总线类型,主要有2类:SPI和I2C
  • 设备地址,这里使用的是I2C接口,所以就是I2C从设备的地址
  • 总线最高速率
  • 中断触发方式:边缘触发(上升沿、下降沿),还是电平触发(高低电平)
  • 电源相关的时序:上下电时序,休眠和唤醒时序
  • 自定义的一些info,版本等

驱动源码分析

HDF_TOUCH_GT911驱动

HDF_TOUCH_GT911驱动(touch_gt911.c)初始化(HdfGoodixChipInit)的主要过程:

//获取上面hcs中的chipConfig
chipCfg = ChipConfigInstance()  

//前面获取的配置
chipDev->chipCfg = chipCfg;  
//函数操作集,主要包括初始化,休眠唤醒,数据处理,固件更新,能力设置等接口,见后面定义  
chipDev->ops = &g_gt911ChipOps;  
chipDev->chipName = chipCfg->chipName;
chipDev->vendorName = chipCfg->vendorName;
device->priv = (void *)chipDev;
//注册 TouchChipDevice, 具体实现在后面的`HDF_TOUCH`驱动中
RegisterTouchChipDevice(chipDev) 
static struct TouchChipOps g_gt911ChipOps = {
    .Init = ChipInit,
    .Detect = ChipDetect,
    .Resume = ChipResume,
    .Suspend = ChipSuspend,
    .DataHandle = ChipDataHandle,
    .UpdateFirmware = UpdateFirmware,
    .SetAbility = SetAbility,
};

RegisterTouchChipDevice()函数的具体实现在后面的 HDF_TOUCH驱动

HDF_TOUCH驱动

HDF_TOUCH驱动(hdf_touch.c)主要有3大块

  • 驱动初始化
    部分伪代码:
//获取上面hcs中的 boardConfig
boardCfg = BoardConfigInstance(device); 

// 初始化驱动数据,Setup bus接口(这里主要是i2c)
ret = TouchDriverInit(touchDriver, boardCfg); 

//增加到驱动列表
AddTouchDriver(touchDriver); 

//对于RK平台,这里会注册一个PM的监听器,用来处理休眠和唤醒
#if defined(CONFIG_ARCH_ROCKCHIP)
    HdfTouchDriverRegisterPowerListener(device); 
#endif
  • Bind接口
    通过Bind对外提供IoService接口(Dispatch),主要有以下接口:
switch (cmd) {
    case GET_DEV_TYPE:
        ret = TouchGetDevType(touchDriver, reply);
        break;
    case SET_PWR_STATUS:
        ret = TouchSetPowerStatus(touchDriver, data);
        break;
    case GET_PWR_STATUS:
        ret = TouchGetPowerStatus(touchDriver, reply);
        break;
    case GET_CHIP_NAME:
    case GET_VENDOR_NAME:
    case GET_CHIP_INFO:
        ret = TouchGetDeviceStrInfo(touchDriver, cmd, reply);
        break;
    case GET_DEV_ATTR:
        ret = TouchGetDeviceAttr(touchDriver, reply);
        break;
    case GET_DEV_ABILITY:
        ret = TouchGetDeviceAbility(touchDriver, reply);
        break;
    case SET_GESTURE_MODE:
        ret = TouchSetGestureMode(touchDriver, data);
        break;
    case RUN_CAPAC_TEST:
        ret = TouchSelfCapacitance(touchDriver, data, reply);
        break;
    case RUN_EXTRA_CMD:
        ret = TouchRunExtraCmd(touchDriver, data);
        break;
    default:
        ret = HDF_SUCCESS;
        HDF_LOGE("%s: cmd unknown, cmd = 0x%x", __func__, cmd);
        break;
}
  • RegisterTouchChipDevice()函数实现

部分伪代码:

//绑定驱动和设备
ret = DeviceBindDriver(chipDev); 

//主要是上电操作,Detect设备,UpdateFirmware,
//配置使能中断,设置中断处理函数(坐标上报等就在里面)等操作,这里就不展开了
ret = ChipDriverInit(chipDev); 

//注册Input 设备, 具体实现在后面的 HDF_INPUT_MANAGER 驱动中
ret = RegisterInputDevice(inputDev); 

//调用chipdev的SetAbility接口
chipDev->ops->SetAbility(chipDev);  

HDF_INPUT_MANAGER驱动

HDF_INPUT_MANAGER驱动(hdf_input_device_manager.c),这里我们主要看下
RegisterInputDevice()函数的实现

部分伪代码:

    //分配设备ID
    ret = AllocDeviceID(inputDev);

    //创建设备节点
    ret = CreateDeviceNode(inputDev);

    //分配相关的buf,主要是pkgBuf和eventBuf
    ret = AllocPackageBuffer(inputDev); 

#ifndef __LITEOS_M__
    //初始化Event的工作队列,
    ret = InitEventWorkQueue(inputDev);

#endif // __LITEOS_M__
    //加入Input设备列表
    AddInputDevice(inputDev); 

参考