1 /*
2 * Copyright 2019-2020,2024 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 if (NULL != config->intPinFunc)
90 {
91 config->intPinFunc(kGT911_IntPinPullDown);
92 }
93 if (NULL != config->pullResetPinFunc)
94 {
95 config->pullResetPinFunc(false);
96 }
97
98 /* >= 10ms. */
99 handle->timeDelayMsFunc(20);
100
101 if (kGT911_I2cAddrAny == config->i2cAddrMode)
102 {
103 if (NULL != config->pullResetPinFunc)
104 {
105 config->pullResetPinFunc(true);
106 }
107
108 /* >= 55ms */
109 handle->timeDelayMsFunc(55);
110
111 if (NULL != config->intPinFunc)
112 {
113 config->intPinFunc(kGT911_IntPinInput);
114 }
115
116 /* Try address 0 */
117 handle->i2cAddr = GT911_I2C_ADDRESS0;
118 status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_ID, GT911_REG_ADDR_SIZE, (uint8_t *)&deviceID, 4);
119
120 if (kStatus_Success != status)
121 {
122 /* Try address 1 */
123 handle->i2cAddr = GT911_I2C_ADDRESS1;
124 status =
125 handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_ID, GT911_REG_ADDR_SIZE, (uint8_t *)&deviceID, 4);
126
127 if (kStatus_Success != status)
128 {
129 return status;
130 }
131 }
132 }
133 else
134 {
135 if (kGT911_I2cAddrMode1 == config->i2cAddrMode)
136 {
137 config->intPinFunc(kGT911_IntPinPullUp);
138 handle->i2cAddr = GT911_I2C_ADDRESS1;
139 }
140 else
141 {
142 handle->i2cAddr = GT911_I2C_ADDRESS0;
143 }
144
145 /* >= 100us */
146 handle->timeDelayMsFunc(1);
147
148 config->pullResetPinFunc(true);
149
150 /* >= 5ms */
151 handle->timeDelayMsFunc(5);
152
153 config->intPinFunc(kGT911_IntPinPullDown);
154
155 /* >= 50ms */
156 handle->timeDelayMsFunc(50);
157
158 config->intPinFunc(kGT911_IntPinInput);
159
160 status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_ID, GT911_REG_ADDR_SIZE, (uint8_t *)&deviceID, 4);
161 if (kStatus_Success != status)
162 {
163 return status;
164 }
165 }
166
167 /* Verify the device. */
168 if (deviceID != 0x00313139U)
169 {
170 return kStatus_Fail;
171 }
172
173 /* Initialize the IC. */
174 status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_CONFIG_ADDR, GT911_REG_ADDR_SIZE, gt911Config,
175 GT911_CONFIG_SIZE);
176 if (kStatus_Success != status)
177 {
178 return status;
179 }
180
181 /*
182 * GT911 driver gets the original firmware from touch panel control IC, modify
183 * the configuration, then set it to the IC again. The original firmware
184 * read from the touch IC must be correct, otherwise setting wrong firmware
185 * to the touch IC will break it.
186 */
187 if (true != GT911_VerifyFirmware(gt911Config))
188 {
189 return kStatus_Fail;
190 }
191
192 handle->resolutionX = ((uint16_t)gt911Config[GT911_REG_XH - GT911_CONFIG_ADDR]) << 8U;
193 handle->resolutionX += gt911Config[GT911_REG_XL - GT911_CONFIG_ADDR];
194 handle->resolutionY = ((uint16_t)gt911Config[GT911_REG_YH - GT911_CONFIG_ADDR]) << 8U;
195 handle->resolutionY += gt911Config[GT911_REG_YL - GT911_CONFIG_ADDR];
196
197 /* Only update the firmware if necessary. */
198 if ((gt911Config[GT911_REG_TOUCH_NUM - GT911_CONFIG_ADDR] & 0x0F) != (config->touchPointNum & 0x0FU) ||
199 (gt911Config[GT911_REG_MODULE_SWITCH1 - GT911_CONFIG_ADDR] & GT911_MODULE_SWITCH_INT_MASK) !=
200 (uint8_t)(config->intTrigMode))
201 {
202 gt911Config[GT911_REG_TOUCH_NUM - GT911_CONFIG_ADDR] = (config->touchPointNum) & 0x0FU;
203 gt911Config[GT911_REG_MODULE_SWITCH1 - GT911_CONFIG_ADDR] &= (uint8_t)(~GT911_MODULE_SWITCH_INT_MASK);
204 gt911Config[GT911_REG_MODULE_SWITCH1 - GT911_CONFIG_ADDR] |= (uint8_t)(config->intTrigMode);
205
206 gt911Config[GT911_CONFIG_SIZE - 2U] = GT911_GetFirmwareCheckSum(gt911Config);
207 gt911Config[GT911_CONFIG_SIZE - 1U] = 1U; /* Mark the firmware as valid. */
208
209 status = handle->I2C_SendFunc(handle->i2cAddr, GT911_CONFIG_ADDR, GT911_REG_ADDR_SIZE, gt911Config,
210 GT911_CONFIG_SIZE);
211 }
212
213 return status;
214 }
215
GT911_Deinit(gt911_handle_t * handle)216 status_t GT911_Deinit(gt911_handle_t *handle)
217 {
218 handle->pullResetPinFunc(false);
219 return kStatus_Success;
220 }
221
GT911_ReadRawTouchData(gt911_handle_t * handle,uint8_t * touchPointNum)222 static status_t GT911_ReadRawTouchData(gt911_handle_t *handle, uint8_t *touchPointNum)
223 {
224 status_t status;
225 uint8_t gt911Stat;
226
227 status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_STAT, GT911_REG_ADDR_SIZE, >911Stat, 1);
228 if (kStatus_Success != status)
229 {
230 *touchPointNum = 0;
231 return status;
232 }
233
234 *touchPointNum = gt911Stat & GT911_STAT_POINT_NUMBER_MASK;
235
236 if (0U != (gt911Stat & GT911_STAT_BUF_MASK))
237 {
238 if (*touchPointNum > 0U)
239 {
240 status = handle->I2C_ReceiveFunc(handle->i2cAddr, GT911_REG_FIRST_POINT, GT911_REG_ADDR_SIZE,
241 (void *)handle->pointReg, (*touchPointNum) * sizeof(gt911_point_reg_t));
242 }
243
244 /* Must set the status register to 0 after read. */
245 gt911Stat = 0;
246 status = handle->I2C_SendFunc(handle->i2cAddr, GT911_REG_STAT, GT911_REG_ADDR_SIZE, >911Stat, 1);
247 }
248 else
249 {
250 status = kStatus_TOUCHPANEL_NotReady;
251 }
252
253 return status;
254 }
255
GT911_GetSingleTouch(gt911_handle_t * handle,int * touch_x,int * touch_y)256 status_t GT911_GetSingleTouch(gt911_handle_t *handle, int *touch_x, int *touch_y)
257 {
258 status_t status;
259 uint8_t touchPointNum;
260
261 status = GT911_ReadRawTouchData(handle, &touchPointNum);
262
263 if (kStatus_Success == status)
264 {
265 if (touchPointNum > 0U)
266 {
267 *touch_x =
268 (int)(uint16_t)((uint16_t)handle->pointReg[0].lowX + (((uint16_t)handle->pointReg[0].highX) << 8U));
269 *touch_y =
270 (int)(uint16_t)((uint16_t)handle->pointReg[0].lowY + (((uint16_t)handle->pointReg[0].highY) << 8U));
271 }
272 else
273 {
274 status = (status_t)kStatus_TOUCHPANEL_NotTouched;
275 }
276 }
277 else
278 {
279 status = kStatus_Fail;
280 }
281
282 return status;
283 }
284
GT911_GetMultiTouch(gt911_handle_t * handle,uint8_t * touch_count,touch_point_t touch_array[])285 status_t GT911_GetMultiTouch(gt911_handle_t *handle, uint8_t *touch_count, touch_point_t touch_array[])
286 {
287 status_t status;
288 uint32_t i;
289 uint8_t desiredTouchPointNum;
290 uint8_t actualTouchPointNum;
291
292 status = GT911_ReadRawTouchData(handle, &actualTouchPointNum);
293
294 if (kStatus_Success == status)
295 {
296 desiredTouchPointNum = *touch_count;
297
298 if (0U == actualTouchPointNum)
299 {
300 status = (status_t)kStatus_TOUCHPANEL_NotTouched;
301 }
302 else if (actualTouchPointNum > desiredTouchPointNum)
303 {
304 actualTouchPointNum = desiredTouchPointNum;
305 }
306 else
307 {
308 /* MISRA compatible. */
309 }
310
311 for (i = 0; i < actualTouchPointNum; i++)
312 {
313 touch_array[i].valid = true;
314 touch_array[i].touchID = handle->pointReg[i].id;
315 touch_array[i].x = handle->pointReg[i].lowX + (((uint16_t)handle->pointReg[i].highX) << 8U);
316 touch_array[i].y = handle->pointReg[i].lowY + (((uint16_t)handle->pointReg[i].highY) << 8U);
317 }
318
319 for (; i < desiredTouchPointNum; i++)
320 {
321 touch_array[i].valid = false;
322 }
323 }
324 else
325 {
326 status = kStatus_Fail;
327 }
328
329 *touch_count = actualTouchPointNum;
330
331 return status;
332 }
333
GT911_GetResolution(gt911_handle_t * handle,int * resolutionX,int * resolutionY)334 status_t GT911_GetResolution(gt911_handle_t *handle, int *resolutionX, int *resolutionY)
335 {
336 *resolutionX = (int)handle->resolutionX;
337 *resolutionY = (int)handle->resolutionY;
338
339 return kStatus_Success;
340 }
341