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, >911Stat, 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, >911Stat, 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