1 /*
2  * Copyright 2019-2020 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_gt911.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 /*! @brief GT911 I2C address. */
14 #define GT911_I2C_ADDRESS0 (0x5D)
15 #define GT911_I2C_ADDRESS1 (0x14)
16 
17 #define GT911_REG_ADDR_SIZE 2
18 
19 /*! @brief GT911 registers. */
20 #define GT911_REG_ID             0x8140U
21 #define GT911_CONFIG_ADDR        0x8047U
22 #define GT911_REG_XL             0x8048U
23 #define GT911_REG_XH             0x8049U
24 #define GT911_REG_YL             0x804AU
25 #define GT911_REG_YH             0x804BU
26 #define GT911_REG_TOUCH_NUM      0x804CU
27 #define GT911_REG_CONFIG_VERSION 0x8047U
28 #define GT911_REG_MODULE_SWITCH1 0x804DU
29 #define GT911_REG_STAT           0x814EU
30 #define GT911_REG_FIRST_POINT    0x814FU
31 
32 #define GT911_STAT_BUF_MASK          (1U << 7U)
33 #define GT911_STAT_POINT_NUMBER_MASK (0xFU << 0U)
34 #define GT911_MODULE_SWITCH_X2Y_MASK (1U << 3U)
35 #define GT911_MODULE_SWITCH_INT_MASK (3U << 0U)
36 
37 #define GT911_CONFIG_SIZE (186U)
38 
39 /*******************************************************************************
40  * Prototypes
41  ******************************************************************************/
42 /* Verify firmware, return true if pass. */
43 static bool GT911_VerifyFirmware(const uint8_t *firmware);
44 static uint8_t GT911_GetFirmwareCheckSum(const uint8_t *firmware);
45 
46 /*******************************************************************************
47  * Variables
48  ******************************************************************************/
49 
50 /*******************************************************************************
51  * Code
52  ******************************************************************************/
GT911_GetFirmwareCheckSum(const uint8_t * firmware)53 static uint8_t GT911_GetFirmwareCheckSum(const uint8_t *firmware)
54 {
55     uint8_t sum = 0;
56     uint16_t i  = 0;
57 
58     for (i = 0; i < GT911_CONFIG_SIZE - 2U; i++)
59     {
60         sum += (*firmware);
61         firmware++;
62     }
63 
64     return (~sum + 1U);
65 }
66 
GT911_VerifyFirmware(const uint8_t * firmware)67 static bool GT911_VerifyFirmware(const uint8_t *firmware)
68 {
69     return ((firmware[GT911_REG_CONFIG_VERSION - GT911_CONFIG_ADDR] != 0U) &&
70             (GT911_GetFirmwareCheckSum(firmware) == firmware[GT911_CONFIG_SIZE - 2U]));
71 }
72 
GT911_Init(gt911_handle_t * handle,const gt911_config_t * config)73 status_t GT911_Init(gt911_handle_t *handle, const gt911_config_t *config)
74 {
75     status_t status;
76     uint32_t deviceID;
77     uint8_t gt911Config[GT911_CONFIG_SIZE];
78 
79     assert(NULL != handle);
80 
81     (void)memset(handle, 0, sizeof(*handle));
82 
83     handle->I2C_SendFunc     = config->I2C_SendFunc;
84     handle->I2C_ReceiveFunc  = config->I2C_ReceiveFunc;
85     handle->timeDelayMsFunc  = config->timeDelayMsFunc;
86     handle->pullResetPinFunc = config->pullResetPinFunc;
87 
88     /* Reset the panel and set the I2C address mode. */
89     config->intPinFunc(kGT911_IntPinPullDown);
90     config->pullResetPinFunc(false);
91 
92     /* >= 10ms. */
93     handle->timeDelayMsFunc(20);
94 
95     if (kGT911_I2cAddrAny == config->i2cAddrMode)
96     {
97         config->pullResetPinFunc(true);
98 
99         /* >= 55ms */
100         handle->timeDelayMsFunc(55);
101 
102         config->intPinFunc(kGT911_IntPinInput);
103 
104         /* Try address 0 */
105         handle->i2cAddr = GT911_I2C_ADDRESS0;
106         status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_ID, GT911_REG_ADDR_SIZE, (uint8_t *)&deviceID, 4);
107 
108         if (kStatus_Success != status)
109         {
110             /* Try address 1 */
111             handle->i2cAddr = GT911_I2C_ADDRESS1;
112             status =
113                 handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_ID, GT911_REG_ADDR_SIZE, (uint8_t *)&deviceID, 4);
114 
115             if (kStatus_Success != status)
116             {
117                 return status;
118             }
119         }
120     }
121     else
122     {
123         if (kGT911_I2cAddrMode1 == config->i2cAddrMode)
124         {
125             config->intPinFunc(kGT911_IntPinPullUp);
126             handle->i2cAddr = GT911_I2C_ADDRESS1;
127         }
128         else
129         {
130             handle->i2cAddr = GT911_I2C_ADDRESS0;
131         }
132 
133         /* >= 100us */
134         handle->timeDelayMsFunc(1);
135 
136         config->pullResetPinFunc(true);
137 
138         /* >= 5ms */
139         handle->timeDelayMsFunc(5);
140 
141         config->intPinFunc(kGT911_IntPinPullDown);
142 
143         /* >= 50ms */
144         handle->timeDelayMsFunc(50);
145 
146         config->intPinFunc(kGT911_IntPinInput);
147 
148         status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_ID, GT911_REG_ADDR_SIZE, (uint8_t *)&deviceID, 4);
149         if (kStatus_Success != status)
150         {
151             return status;
152         }
153     }
154 
155     /* Verify the device. */
156     if (deviceID != 0x00313139U)
157     {
158         return kStatus_Fail;
159     }
160 
161     /* Initialize the IC. */
162     status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_CONFIG_ADDR, GT911_REG_ADDR_SIZE, gt911Config,
163                                      GT911_CONFIG_SIZE);
164     if (kStatus_Success != status)
165     {
166         return status;
167     }
168 
169     /*
170      * GT911 driver gets the original firmware from touch panel control IC, modify
171      * the configuration, then set it to the IC again. The original firmware
172      * read from the touch IC must be correct, otherwise setting wrong firmware
173      * to the touch IC will break it.
174      */
175     if (true != GT911_VerifyFirmware(gt911Config))
176     {
177         return kStatus_Fail;
178     }
179 
180     handle->resolutionX = ((uint16_t)gt911Config[GT911_REG_XH - GT911_CONFIG_ADDR]) << 8U;
181     handle->resolutionX += gt911Config[GT911_REG_XL - GT911_CONFIG_ADDR];
182     handle->resolutionY = ((uint16_t)gt911Config[GT911_REG_YH - GT911_CONFIG_ADDR]) << 8U;
183     handle->resolutionY += gt911Config[GT911_REG_YL - GT911_CONFIG_ADDR];
184 
185     gt911Config[GT911_REG_TOUCH_NUM - GT911_CONFIG_ADDR] = (config->touchPointNum) & 0x0FU;
186 
187     gt911Config[GT911_REG_MODULE_SWITCH1 - GT911_CONFIG_ADDR] &= (uint8_t)(~GT911_MODULE_SWITCH_INT_MASK);
188     gt911Config[GT911_REG_MODULE_SWITCH1 - GT911_CONFIG_ADDR] |= (uint8_t)(config->intTrigMode);
189 
190     gt911Config[GT911_CONFIG_SIZE - 2U] = GT911_GetFirmwareCheckSum(gt911Config);
191     gt911Config[GT911_CONFIG_SIZE - 1U] = 1U; /* Mark the firmware as valid. */
192 
193     return handle->I2C_SendFunc(handle->i2cAddr, GT911_CONFIG_ADDR, GT911_REG_ADDR_SIZE, gt911Config,
194                                 GT911_CONFIG_SIZE);
195 }
196 
GT911_Deinit(gt911_handle_t * handle)197 status_t GT911_Deinit(gt911_handle_t *handle)
198 {
199     handle->pullResetPinFunc(false);
200     return kStatus_Success;
201 }
202 
GT911_ReadRawTouchData(gt911_handle_t * handle,uint8_t * touchPointNum)203 static status_t GT911_ReadRawTouchData(gt911_handle_t *handle, uint8_t *touchPointNum)
204 {
205     status_t status;
206     uint8_t gt911Stat;
207 
208     status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_STAT, GT911_REG_ADDR_SIZE, &gt911Stat, 1);
209     if (kStatus_Success != status)
210     {
211         *touchPointNum = 0;
212         return status;
213     }
214 
215     *touchPointNum = gt911Stat & GT911_STAT_POINT_NUMBER_MASK;
216 
217     if (0U != (gt911Stat & GT911_STAT_BUF_MASK))
218     {
219         if (*touchPointNum > 0U)
220         {
221             status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_FIRST_POINT, GT911_REG_ADDR_SIZE,
222                                              (void *)handle->pointReg, (*touchPointNum) * sizeof(gt911_point_reg_t));
223         }
224 
225         /* Must set the status register to 0 after read. */
226         gt911Stat = 0;
227         status    = handle->I2C_SendFunc(handle->i2cAddr, GT911_REG_STAT, GT911_REG_ADDR_SIZE, &gt911Stat, 1);
228     }
229 
230     return status;
231 }
232 
GT911_GetSingleTouch(gt911_handle_t * handle,int * touch_x,int * touch_y)233 status_t GT911_GetSingleTouch(gt911_handle_t *handle, int *touch_x, int *touch_y)
234 {
235     status_t status;
236     uint8_t touchPointNum;
237 
238     status = GT911_ReadRawTouchData(handle, &touchPointNum);
239 
240     if (kStatus_Success == status)
241     {
242         if (touchPointNum > 0U)
243         {
244             *touch_x =
245                 (int)(uint16_t)((uint16_t)handle->pointReg[0].lowX + (((uint16_t)handle->pointReg[0].highX) << 8U));
246             *touch_y =
247                 (int)(uint16_t)((uint16_t)handle->pointReg[0].lowY + (((uint16_t)handle->pointReg[0].highY) << 8U));
248         }
249         else
250         {
251             status = (status_t)kStatus_TOUCHPANEL_NotTouched;
252         }
253     }
254     else
255     {
256         status = kStatus_Fail;
257     }
258 
259     return status;
260 }
261 
GT911_GetMultiTouch(gt911_handle_t * handle,uint8_t * touch_count,touch_point_t touch_array[])262 status_t GT911_GetMultiTouch(gt911_handle_t *handle, uint8_t *touch_count, touch_point_t touch_array[])
263 {
264     status_t status;
265     uint32_t i;
266     uint8_t desiredTouchPointNum;
267     uint8_t actualTouchPointNum;
268 
269     status = GT911_ReadRawTouchData(handle, &actualTouchPointNum);
270 
271     if (kStatus_Success == status)
272     {
273         desiredTouchPointNum = *touch_count;
274 
275         if (0U == actualTouchPointNum)
276         {
277             status = (status_t)kStatus_TOUCHPANEL_NotTouched;
278         }
279         else if (actualTouchPointNum > desiredTouchPointNum)
280         {
281             actualTouchPointNum = desiredTouchPointNum;
282         }
283         else
284         {
285             /* MISRA compatible. */
286         }
287 
288         for (i = 0; i < actualTouchPointNum; i++)
289         {
290             touch_array[i].valid   = true;
291             touch_array[i].touchID = handle->pointReg[i].id;
292             touch_array[i].x       = handle->pointReg[i].lowX + (((uint16_t)handle->pointReg[i].highX) << 8U);
293             touch_array[i].y       = handle->pointReg[i].lowY + (((uint16_t)handle->pointReg[i].highY) << 8U);
294         }
295 
296         for (; i < desiredTouchPointNum; i++)
297         {
298             touch_array[i].valid = false;
299         }
300     }
301     else
302     {
303         status = kStatus_Fail;
304     }
305 
306     *touch_count = actualTouchPointNum;
307 
308     return status;
309 }
310 
GT911_GetResolution(gt911_handle_t * handle,int * resolutionX,int * resolutionY)311 status_t GT911_GetResolution(gt911_handle_t *handle, int *resolutionX, int *resolutionY)
312 {
313     *resolutionX = (int)handle->resolutionX;
314     *resolutionY = (int)handle->resolutionY;
315 
316     return kStatus_Success;
317 }
318