• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# TOUCHSCREEN<a name="ZH-CN_TOPIC_0000001052857350"></a>
2
3-   [概述](#section175431838101617)
4    -   [接口说明](#section17667171301711)
5
6-   [开发指导](#section65745222184)
7    -   [开发步骤](#section865734181916)
8
9-   [开发实例](#section263714411191)
10    -   [设备描述配置](#section18249155619195)
11    -   [板级配置及器件私有配置](#section3571192072014)
12    -   [添加器件驱动](#section6356758162015)
13
14
15## 概述<a name="section175431838101617"></a>
16
17-   **Touchscreen驱动主要任务**
18
19    Touchscreen驱动用于驱动触摸屏使其正常工作,该驱动主要完成如下工作:对触摸屏驱动IC进行上电、配置硬件管脚并初始化其状态、注册中断、配置通信接口(I2C或SPI)、设定input相关配置、下载及更新固件等操作。
20
21
22-   **Touchscreen驱动层次说明**
23
24    本节主要介绍基于input驱动模型开发touchscreen器件驱动,其整体的框架模型如[图1](#fig6251184817261)。
25
26    Input驱动模型基于HDF驱动框架、PLATFORM接口、OSAL接口进行开发,向上对接规范化的驱动接口HDI(Hardware Driver Interface)层,通过Input-HDI层对外提供硬件能力,即上层input service可以通过HDI接口层获取相应的驱动能力,进而操控touchscreen等输入设备。
27
28
29**图 1**  基于HDF驱动框架的input驱动模型<a name="fig6251184817261"></a>
30![](figure/基于HDF驱动框架的input驱动模型.png "基于HDF驱动框架的input驱动模型")
31
32-   **Input驱动模型介绍**
33
34    Input驱动模型核心部分由设备管理层、公共驱动层、器件驱动层组成。器件产生的数据借助平台数据通道能力从内核传递到用户态,驱动模型通过配置文件适配不同器件及硬件平台,提高开发者的器件驱动开发效率。如下部分为模型各部分的说明:
35
36    (1)input设备管理:为各类输入设备驱动提供input设备的注册、注销接口,同时统一管理input设备列表;
37
38    (2)input平台驱动:指各类input设备的公共抽象驱动(例如触摸屏的公共驱动),负责对板级硬件进行初始化、硬件中断处理、向manager注册input设备等;
39
40    (3)input器件驱动:指各器件厂家的差异化驱动,通过适配平台驱动预留的差异化接口,实现器件驱动开发量最小化;
41
42    (4)input数据通道:提供一套通用的数据上报通道,各类别的input设备驱动均可用此通道上报input事件;
43
44    (5)input配置解析:负责对input设备的板级配置及器件私有配置进行解析及管理。
45
46
47-   **基于HDF驱动框架开发器件驱动的优势**
48
49    在HDF(Hardware Driver Foundation)[驱动管理框架](driver-hdf-development.md)的基础上,input驱动模型调用OSAL接口层和Platfom接口层提供的基础接口进行开发,包括bus通信接口、操作系统原生接口(memory、lock、thread、timer等)。由于OSAL接口和Platform接口屏蔽了芯片平台差异,所以基于input驱动模型实现的touchscreen驱动可以进行跨平台、跨OS迁移,以便逐步实现驱动的一次开发,多端部署。
50
51
52### 接口说明<a name="section17667171301711"></a>
53
54Touchscreen器件的硬件接口相对简单,根据PIN脚的属性,可以简单分为如下三类:
55
56-   电源接口
57-   IO控制接口
58-   通信接口
59
60**图 2**  Touchscreen器件常用管脚<a name="fig1290384314416"></a>
61![](figure/Touchscreen器件常用管脚.png "Touchscreen器件常用管脚")
62
63如上图所示的三类接口,分别做简要说明如下:
64
651.  **电源接口**
66    -   LDO\_1P8:1.8v数字电路
67    -   LDO\_3P3:3.3v模拟电路
68
69        通常情况下,touchscreen驱动IC和LCD驱动IC是相互分离的,这种情况下,touchscreen驱动IC一般同时需要1.8v和3.3v两路供电。随着芯片演进,业内已有touchscreen驱动IC和LCD驱动IC集成在一颗IC中的芯片案例,对touchscreen而言,只需要关注1.8v供电即可,其内部需要的3.3v电源,会在驱动IC内部从LCD的VSP电源(典型值5.5V)中分出来。
70
712.  **IO控制接口**
72    -   Reset:reset管脚,用于在系统休眠、唤醒时,由主机侧对驱动IC进行复位操作。
73    -   INT:中断管脚,需要在驱动初始化时,配置为输入上拉状态。在驱动IC检测到外部触摸信号后,通过操作中断管脚来触发中断,器件驱动则会在中断处理函数中进行报点数据读取等操作。
74
753.  **通信接口**
76    -   I2C:由于touchscreen的报点数据量相对较少,所以一般选用I2C方式传输数据。I2C的具体协议及对应操作接口,可以参考Platform接口层中的[“I2C”使用指南](driver-platform-i2c-des.md#section1695201514281)。
77    -   SPI:部分厂商,由于需要传递的数据不止报点坐标,而是需要获取基础容值,数据量较大,所以会选用SPI通信方式。SPI的具体协议及对应操作接口,可以参考Platform接口层中的[“SPI” 使用指南](driver-platform-spi-des.md#section71363452477)。
78
79
80## 开发指导<a name="section65745222184"></a>
81
82Input驱动模型是基于HDF框架、Platform接口和OSAL接口开发,不区分操作系统和芯片平台,为touchscreen等输入器件提供统一的驱动开发架构。
83
84-   如下以touchscreen器件驱动为例,说明input驱动模型的完整加载流程:
85
86    (1)设备描述配置:由开发者参考已有模板进行设备描述配置,包括驱动加载顺序、板级硬件信息、器件私有数据信息等。
87
88    (2)加载input设备管理驱动:input设备管理驱动由HDF驱动加载,完成设备manager的创建并对其初始化。
89
90    (3)加载平台驱动:平台驱动由HDF框架加载,主要完成板级配置解析及硬件初始化,并提供器件注册接口。
91
92    (4)加载器件驱动:器件驱动也由HDF框架加载,完成器件设备的实例化,包括器件私有配置解析和平台预留的差异化接口适配。
93
94    (5)器件设备向平台驱动注册:将实例化的器件设备向平台驱动注册,实现设备和驱动的绑定,并完成中断注册、上下电等器件初始化工作。
95
96    (6)input设备注册:在器件初始化完成后,实例化input设备,并将其注册到input manager进行管理。
97
98
99### 开发步骤<a name="section865734181916"></a>
100
1011.  设备描述配置
102
103    目前Input驱动基于HDF驱动框架编写,驱动的加载启动由HDF驱动管理框架统一处理。首先需要在对应的配置文件中,将驱动信息注册进去,如是否加载、加载优先级,此后HDF驱动框架会逐一启动注册过的驱动模块。驱动的相关配置请参考[HDF驱动框架配置指导](driver-hdf-development.md#section1969312275533)。
104
1052.  板级配置及Touchscreen器件私有配置
106
107    配置对应的IO管脚功能,例如对单板上为touchscreen设计预留的I2C Pin脚,需设置对应的寄存器,使其选择I2C的通信功能。
108
1093.  实现器件差异化适配接口
110
111    根据硬件单板设计的通信接口,使用Platform接口层提供的管脚操作接口配置对应的复位管脚、中断管脚以及电源操作,对于GPIO的操作,可参考[GPIO操作接口指导](driver-platform-gpio-des.md#section259614242196)
112
113
114## 开发实例<a name="section263714411191"></a>
115
116本实例提供touchscreen驱动开发示例,并简要对具体关键点进行开发说明。
117
118### 设备描述配置<a name="section18249155619195"></a>
119
120如下配置主要包含input驱动模型各模块层级信息,具体原理可参考[HDF驱动开发指南](driver-hdf-development.md),HDF框架依据该配置信息实现对Input模型各模块的依次加载等。
121
122```
123input :: host {
124            hostName = "input_host";
125            priority = 100;
126            device_input_manager :: device {
127                device0 :: deviceNode {
128                    policy = 2;        // 向外发布服务
129                    priority = 100;    // 加载优先级,在input模块内,manager模块优先级应为最高
130                    preload = 0;       // 加载该驱动 0:加载 1:不加载
131                    permission = 0660;
132                    moduleName = "HDF_INPUT_MANAGER";
133                    serviceName = "input_dev_manager";
134                    deviceMatchAttr = "";
135                }
136            }
137            device_hdf_touch :: device {
138                device0 :: deviceNode {
139                    policy = 2;
140                    priority = 120;
141                    preload = 0;
142                    permission = 0660;
143                    moduleName = "HDF_TOUCH";
144                    serviceName = "event1";
145                    deviceMatchAttr = "touch_device1";
146                }
147            }
148
149            device_touch_chip :: device {
150                device0 :: deviceNode {
151                    policy = 0;
152                    priority = 130;
153                    preload = 0;
154                    permission = 0660;
155                    moduleName = "HDF_TOUCH_SAMPLE";
156                    serviceName = "hdf_touch_sample_service";
157                    deviceMatchAttr = "zsj_sample_5p5";
158                }
159            }
160}
161```
162
163### 板级配置及器件私有配置<a name="section3571192072014"></a>
164
165如下配置包含板级硬件配置及器件私有数据配置,实际业务开发时,可根据具体需求增删及修改如下配置文件信息。
166
167```
168root {
169    input_config {
170        touchConfig {
171            touch0 {
172                boardConfig {
173                    match_attr = "touch_device1";
174                    inputAttr {
175                        inputType = 0;           // 0代表触摸屏
176                        solutionX = 480;
177                        solutionY = 960;
178                        devName = "main_touch";  // 设备名称
179                    }
180                    busConfig {
181                        busType = 0;             // 0代表I2C
182                        busNum = 6;
183                        clkGpio = 86;
184                        dataGpio = 87;
185                        i2cClkIomux = [0x114f0048, 0x403];  // i2c_clk对应pin的寄存器配置
186                        i2cDataIomux = [0x114f004c, 0x403]; // i2c_data对应pin的寄存器配置
187                    }
188                    pinConfig {
189                        rstGpio = 3;
190                        intGpio = 4;
191                        rstRegCfg = [0x112f0094, 0x400];  // reset对应pin的寄存器配置
192                        intRegCfg = [0x112f0098, 0x400];  // interrupt对应pin的寄存器配置
193                    }
194                    powerConfig {
195                        vccType = 2;       // 1代表LDO、2代表GPIO、3代表PMIC
196                        vccNum = 20;       // GPIO号为20
197                        vccValue = 1800;   // 电压幅值为1800mV
198                        vciType = 1;
199                        vciNum = 12;
200                        vciValue = 3300;
201                    }
202                    featureConfig {
203                        capacitanceTest = 0;
204                        gestureMode = 0;
205                        gloverMOde = 0;
206                        coverMode = 0;
207                        chargerMode = 0;
208                        knuckleMode = 0;
209                    }
210                }
211                chipConfig {
212                    template touchChip {
213                        match_attr = "";
214                        chipName = "sample";
215                        vendorName = "zsj";
216                        chipInfo = "AAAA11222";  // 1~4字符代表产品名,5~6字符代表IC型号,7~9字符代表模型型号
217                        busType = 0;
218                        deviceAddr = 0x5D;
219                        irqFlag = 2;             // 1代表上升沿触发,2代表下降沿触发,4代表高电平触发,8代表低电平触发
220                        maxSpeed = 400;
221                        chipVersion = 0;
222                        powerSequence {
223                            /* 上电时序的配置含义说明:
224                               [类型, 状态, 方向 , 延时]
225                               <type> 0代表空,1代表vcc电源(1.8V),2代表VCI电源(3.3V),3代表复位管脚,4代表中断管脚
226                               <status> 0代表下电或拉低,1代表上电或拉高,2代表无操作
227                               <dir> 0代表输入方向,1代表输出方向,2代表无操作
228                               <delay> 代表延时多少毫秒, 例如20代表延时20ms
229                             */
230                            powerOnSeq = [4, 0, 1, 0,
231                                         3, 0, 1, 10,
232                                         3, 1, 2, 60,
233                                         4, 2, 0, 0];
234                            suspendSeq = [3, 0, 2, 10];
235                            resumeSeq = [3, 1, 2, 10];
236                            powerOffSeq = [3, 0, 2, 10,
237                                           1, 0, 2, 20];
238                        }
239                    }
240                    chip0 :: touchChip {
241                        match_attr = "zsj_sample_5p5";
242                        chipInfo = "ZIDN45100";
243                        chipVersion = 0;
244                    }
245                }
246            }
247        }
248    }
249}
250```
251
252### 添加器件驱动<a name="section6356758162015"></a>
253
254在器件驱动中,主要实现了平台预留的差异化接口,以器件数据获取及解析进行示例说明。具体开发过程,需要根据实际使用的单板及器件进行适配。
255
256```
257/* 将从器件中读取到的报点数据解析为坐标 */
258static void ParsePointData(ChipDevice *device, FrameData *frame, uint8_t *buf, uint8_t pointNum)
259{
260    int32_t resX = device->driver->boardCfg->attr.resolutionX;
261    int32_t resY = device->driver->boardCfg->attr.resolutionY;
262
263    for (int32_t i = 0; i < pointNum; i++) {
264        frame->fingers[i].y = (buf[GT_POINT_SIZE * i + GT_X_LOW] & ONE_BYTE_MASK) |
265                              ((buf[GT_POINT_SIZE * i + GT_X_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);
266        frame->fingers[i].x = (buf[GT_POINT_SIZE * i + GT_Y_LOW] & ONE_BYTE_MASK) |
267                              ((buf[GT_POINT_SIZE * i + GT_Y_HIGH] & ONE_BYTE_MASK) << ONE_BYTE_OFFSET);
268        frame->fingers[i].valid = true;
269    }
270}
271/* 从器件中获取报点数据 */
272static int32_t ChipDataHandle(ChipDevice *device)
273{
274    int32_t ret;
275    uint8_t touchStatus = 0;
276    uint8_t pointNum;
277    uint8_t buf[GT_POINT_SIZE * MAX_SUPPORT_POINT] = {0};
278    InputI2cClient *i2cClient = &device->driver->i2cClient;
279    uint8_t reg[GT_ADDR_LEN] = {0};
280    FrameData *frame = &device->driver->frameData;
281    reg[0] = (GT_BUF_STATE_ADDR >> ONE_BYTE_OFFSET) & ONE_BYTE_MASK;
282    reg[1] = GT_BUF_STATE_ADDR & ONE_BYTE_MASK;
283    ret = InputI2cRead(i2cClient, reg, GT_ADDR_LEN, &touchStatus, 1);
284    if (ret < 0 || touchStatus == GT_EVENT_INVALID) {
285        return HDF_FAILURE;
286    }
287    OsalMutexLock(&device->driver->mutex);
288    (void)memset_s(frame, sizeof(FrameData), 0, sizeof(FrameData));
289    if (touchStatus == GT_EVENT_UP) {
290        frame->realPointNum = 0;
291        frame->definedEvent = TOUCH_UP;
292        goto exit;
293    }
294    reg[0] = (GT_X_LOW_BYTE_BASE >> ONE_BYTE_OFFSET) & ONE_BYTE_MASK;
295    reg[1] = GT_X_LOW_BYTE_BASE & ONE_BYTE_MASK;
296    pointNum = touchStatus & GT_FINGER_NUM_MASK;
297    if (pointNum <= 0 || pointNum > MAX_SUPPORT_POINT) {
298        HDF_LOGE("%s: pointNum is invalid, %d", __func__, pointNum);
299        (void)ChipCleanBuffer(i2cClient);
300        OsalMutexUnlock(&device->driver->mutex);
301        return HDF_FAILURE;
302    }
303    frame->realPointNum = pointNum;
304    frame->definedEvent = TOUCH_DOWN;
305    /* 从寄存器中读取报点值 */
306    (void)InputI2cRead(i2cClient, reg, GT_ADDR_LEN, buf, GT_POINT_SIZE * pointNum);
307    /* 解析报点值 */
308    ParsePointData(device, frame, buf, pointNum);
309exit:
310    OsalMutexUnlock(&device->driver->mutex);
311    if (ChipCleanBuffer(i2cClient) != HDF_SUCCESS) {
312        return HDF_FAILURE;
313    }
314    return HDF_SUCCESS;
315}
316
317static struct TouchChipOps g_sampleChipOps = {
318    .Init = ChipInit,
319    .Detect = ChipDetect,
320    .Resume = ChipResume,
321    .Suspend = ChipSuspend,
322    .DataHandle = ChipDataHandle,
323};
324
325static TouchChipCfg *ChipConfigInstance(struct HdfDeviceObject *device)
326{
327    TouchChipCfg *chipCfg = (TouchChipCfg *)OsalMemAlloc(sizeof(TouchChipCfg));
328    if (chipCfg == NULL) {
329        HDF_LOGE("%s: instance chip config failed", __func__);
330        return NULL;
331    }
332    (void)memset_s(chipCfg, sizeof(TouchChipCfg), 0, sizeof(TouchChipCfg));
333    /* 解析器件私有配置 */
334    if (ParseTouchChipConfig(device->property, chipCfg) != HDF_SUCCESS) {
335        HDF_LOGE("%s: parse chip config failed", __func__);
336        OsalMemFree(chipCfg);
337        chipCfg = NULL;
338    }
339    return chipCfg;
340}
341
342static ChipDevice *ChipDeviceInstance(void)
343{
344    ChipDevice *chipDev = (ChipDevice *)OsalMemAlloc(sizeof(ChipDevice));
345    if (chipDev == NULL) {
346        HDF_LOGE("%s: instance chip device failed", __func__);
347        return NULL;
348    }
349    (void)memset_s(chipDev, sizeof(ChipDevice), 0, sizeof(ChipDevice));
350    return chipDev;
351}
352
353static void FreeChipConfig(TouchChipCfg *config)
354{
355    if (config->pwrSeq.pwrOn.buf != NULL) {
356        OsalMemFree(config->pwrSeq.pwrOn.buf);
357    }
358    if (config->pwrSeq.pwrOff.buf != NULL) {
359        OsalMemFree(config->pwrSeq.pwrOff.buf);
360    }
361    OsalMemFree(config);
362}
363
364static int32_t HdfSampleChipInit(struct HdfDeviceObject *device)
365{
366    TouchChipCfg *chipCfg = NULL;
367    ChipDevice *chipDev = NULL;
368    HDF_LOGE("%s: enter", __func__);
369    if (device == NULL) {
370        return HDF_ERR_INVALID_PARAM;
371    }
372    /* 器件私有配置解析 */
373    chipCfg = ChipConfigInstance(device);
374    if (chipCfg == NULL) {
375        return HDF_ERR_MALLOC_FAIL;
376    }
377    /* 器件设备实例化 */
378    chipDev = ChipDeviceInstance();
379    if (chipDev == NULL) {
380        goto freeCfg;
381    }
382    chipDev->chipCfg = chipCfg;
383    chipDev->ops = &g_sampleChipOps;
384    chipDev->chipName = chipCfg->chipName;
385    chipDev->vendorName = chipCfg->vendorName;
386
387   /* 器件设备注册到平台驱动 */
388    if (RegisterChipDevice(chipDev) != HDF_SUCCESS) {
389        goto freeDev;
390    }
391    HDF_LOGI("%s: exit succ, chipName = %s", __func__, chipCfg->chipName);
392    return HDF_SUCCESS;
393
394freeDev:
395    OsalMemFree(chipDev);
396freeCfg:
397    FreeChipConfig(chipCfg);
398    return HDF_FAILURE;
399}
400
401struct HdfDriverEntry g_touchSampleChipEntry = {
402    .moduleVersion = 1,
403    .moduleName = "HDF_TOUCH_SAMPLE",
404    .Init = HdfSampleChipInit,
405};
406
407HDF_INIT(g_touchSampleChipEntry);
408```
409
410