1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2019, 2024 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_common.h"
10 #include "fsl_ft6x06.h"
11 
12 typedef struct _ft6x06_touch_point
13 {
14     uint8_t XH;
15     uint8_t XL;
16     uint8_t YH;
17     uint8_t YL;
18     uint8_t WEIGHT;
19     uint8_t MISC;
20 } ft6x06_touch_point_t;
21 
22 typedef struct _ft6x06_touch_data
23 {
24     uint8_t GEST_ID;
25     uint8_t TD_STATUS;
26     ft6x06_touch_point_t TOUCH[FT6X06_MAX_TOUCHES];
27 } ft6x06_touch_data_t;
28 
29 #define TOUCH_POINT_GET_EVENT(T) ((touch_event_t)((T).XH >> 6))
30 #define TOUCH_POINT_GET_ID(T)    ((T).YH >> 4)
31 #define TOUCH_POINT_GET_X(T)     ((((T).XH & 0x0f) << 8) | (T).XL)
32 #define TOUCH_POINT_GET_Y(T)     ((((T).YH & 0x0f) << 8) | (T).YL)
33 
34 #if FT6X06_USE_CMSIS_DRIVER
FT6X06_EventHandler(ft6x06_handle_t * handle,uint32_t i2c_event)35 void FT6X06_EventHandler(ft6x06_handle_t *handle, uint32_t i2c_event)
36 {
37     handle->i2c_event          = i2c_event;
38     handle->i2c_event_received = true;
39 }
40 
FT_6X06_WaitEvent(ft6x06_handle_t * handle)41 static uint32_t FT_6X06_WaitEvent(ft6x06_handle_t *handle)
42 {
43     uint32_t i2c_event;
44 
45     while (!(handle->i2c_event_received))
46         ;
47 
48     i2c_event                  = handle->i2c_event;
49     handle->i2c_event_received = false;
50 
51     return i2c_event;
52 }
53 #endif /* FT6X06_USE_CMSIS_DRIVER */
54 
55 #if (FT6X06_USE_CMSIS_DRIVER)
FT6X06_Init(ft6x06_handle_t * handle,ARM_DRIVER_I2C * i2c_driver)56 status_t FT6X06_Init(ft6x06_handle_t *handle, ARM_DRIVER_I2C *i2c_driver)
57 {
58     status_t status = kStatus_Success;
59     uint8_t i2c_buf[2];
60 
61     assert(handle);
62     assert(i2c_driver);
63 
64     if (!handle || !i2c_driver)
65     {
66         return kStatus_InvalidArgument;
67     }
68 
69     handle->i2c_driver = i2c_driver;
70 
71     /* clear transfer structure and buffer */
72     memset(handle->touch_buf, 0, FT6X06_TOUCH_DATA_LEN);
73 
74     /* set device mode to normal operation */
75     i2c_buf[0] = 0; /* mode register address */
76     i2c_buf[1] = 0; /* normal operation mode */
77 
78     if (handle->i2c_driver->MasterTransmit(FT6X06_I2C_ADDRESS, i2c_buf, 2, false) != ARM_DRIVER_OK)
79     {
80         status = kStatus_Fail;
81     }
82     else if (FT_6X06_WaitEvent(handle) != ARM_I2C_EVENT_TRANSFER_DONE)
83     {
84         status = kStatus_Fail;
85     }
86 
87     return status;
88 }
89 #else  /* !FT6X06_USE_CMSIS_DRIVER */
FT6X06_Init(ft6x06_handle_t * handle,const ft6x06_config_t * config)90 status_t FT6X06_Init(ft6x06_handle_t *handle, const ft6x06_config_t *config)
91 {
92     assert(handle != NULL);
93 
94     handle->I2C_SendFunc    = config->I2C_SendFunc;
95     handle->I2C_ReceiveFunc = config->I2C_ReceiveFunc;
96     /* clear transfer structure and buffer */
97     memset(handle->touch_buf, 0, FT6X06_TOUCH_DATA_LEN);
98 
99     /* set device mode to normal operation */
100     return handle->I2C_SendFunc(FT6X06_I2C_ADDRESS, 0, 1, (const uint8_t[]){0U}, 1);
101 }
102 #endif /* FT6X06_USE_CMSIS_DRIVER */
103 
FT6X06_Denit(ft6x06_handle_t * handle)104 status_t FT6X06_Denit(ft6x06_handle_t *handle)
105 {
106     assert(handle);
107 
108     if (!handle)
109     {
110         return kStatus_InvalidArgument;
111     }
112 
113 #if FT6X06_USE_CMSIS_DRIVER
114     handle->i2c_driver = NULL;
115 #endif /* FT6X06_USE_CMSIS_DRIVER */
116     return kStatus_Success;
117 }
118 
119 #if FT6X06_USE_CMSIS_DRIVER
FT6X06_ReadTouchData(ft6x06_handle_t * handle)120 status_t FT6X06_ReadTouchData(ft6x06_handle_t *handle)
121 {
122     status_t status = kStatus_Success;
123     uint8_t i2c_buf[1];
124 
125     assert(handle);
126 
127     if (!handle || !(handle->i2c_driver))
128     {
129         return kStatus_InvalidArgument;
130     }
131 
132     i2c_buf[0] = F6X06_TOUCH_DATA_SUBADDR;
133 
134     if (handle->i2c_driver->MasterTransmit(FT6X06_I2C_ADDRESS, i2c_buf, 1, true) != ARM_DRIVER_OK)
135     {
136         status = kStatus_Fail;
137     }
138     else if (FT_6X06_WaitEvent(handle) != ARM_I2C_EVENT_TRANSFER_DONE)
139     {
140         status = kStatus_Fail;
141     }
142     else if (handle->i2c_driver->MasterReceive(FT6X06_I2C_ADDRESS, handle->touch_buf, FT6X06_TOUCH_DATA_LEN, false) !=
143              ARM_DRIVER_OK)
144     {
145         status = kStatus_Fail;
146     }
147     else if (FT_6X06_WaitEvent(handle) != ARM_I2C_EVENT_TRANSFER_DONE)
148     {
149         status = kStatus_Fail;
150     }
151 
152     return status;
153 }
154 #else  /* !FT6X06_USE_CMSIS_DRIVER */
FT6X06_ReadTouchData(ft6x06_handle_t * handle)155 status_t FT6X06_ReadTouchData(ft6x06_handle_t *handle)
156 {
157     return handle->I2C_ReceiveFunc(FT6X06_I2C_ADDRESS, F6X06_TOUCH_DATA_SUBADDR, 1, handle->touch_buf,
158                                    FT6X06_TOUCH_DATA_LEN);
159 }
160 #endif /* FT6X06_USE_CMSIS_DRIVER */
161 
FT6X06_GetSingleTouch(ft6x06_handle_t * handle,touch_event_t * touch_event,int * touch_x,int * touch_y)162 status_t FT6X06_GetSingleTouch(ft6x06_handle_t *handle, touch_event_t *touch_event, int *touch_x, int *touch_y)
163 {
164     status_t status;
165     touch_event_t touch_event_local;
166 
167     status = FT6X06_ReadTouchData(handle);
168 
169     if (status == kStatus_Success)
170     {
171         ft6x06_touch_data_t *touch_data = (ft6x06_touch_data_t *)(void *)(handle->touch_buf);
172 
173         if (touch_event == NULL)
174         {
175             touch_event = &touch_event_local;
176         }
177         *touch_event = TOUCH_POINT_GET_EVENT(touch_data->TOUCH[0]);
178 
179         /* Update coordinates only if there is touch detected */
180         if ((*touch_event == kTouch_Down) || (*touch_event == kTouch_Contact))
181         {
182             if (touch_x)
183             {
184                 *touch_x = TOUCH_POINT_GET_X(touch_data->TOUCH[0]);
185             }
186             if (touch_y)
187             {
188                 *touch_y = TOUCH_POINT_GET_Y(touch_data->TOUCH[0]);
189             }
190         }
191     }
192 
193     return status;
194 }
195 
FT6X06_GetMultiTouch(ft6x06_handle_t * handle,int * touch_count,touch_point_t touch_array[FT6X06_MAX_TOUCHES])196 status_t FT6X06_GetMultiTouch(ft6x06_handle_t *handle, int *touch_count, touch_point_t touch_array[FT6X06_MAX_TOUCHES])
197 {
198     status_t status;
199 
200     status = FT6X06_ReadTouchData(handle);
201 
202     if (status == kStatus_Success)
203     {
204         ft6x06_touch_data_t *touch_data = (ft6x06_touch_data_t *)(void *)(handle->touch_buf);
205         int i;
206 
207         /* check for valid number of touches - otherwise ignore touch information...
208            workaround added msy */
209         if (touch_data->TD_STATUS > FT6X06_MAX_TOUCHES)
210             touch_data->TD_STATUS = 0;
211 
212         /* Decode number of touches */
213         if (touch_count)
214         {
215             *touch_count = touch_data->TD_STATUS;
216         }
217 
218         /* Decode valid touch points */
219         for (i = 0; i < touch_data->TD_STATUS; i++)
220         {
221             touch_array[i].TOUCH_ID    = TOUCH_POINT_GET_ID(touch_data->TOUCH[i]);
222             touch_array[i].TOUCH_EVENT = TOUCH_POINT_GET_EVENT(touch_data->TOUCH[i]);
223             touch_array[i].TOUCH_X     = TOUCH_POINT_GET_X(touch_data->TOUCH[i]);
224             touch_array[i].TOUCH_Y     = TOUCH_POINT_GET_Y(touch_data->TOUCH[i]);
225         }
226 
227         /* Clear vacant elements of touch_array */
228         for (; i < FT6X06_MAX_TOUCHES; i++)
229         {
230             touch_array[i].TOUCH_ID    = 0;
231             touch_array[i].TOUCH_EVENT = kTouch_Reserved;
232             touch_array[i].TOUCH_X     = 0;
233             touch_array[i].TOUCH_Y     = 0;
234         }
235     }
236 
237     return status;
238 }
239