1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2019 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 
FT6X06_EventHandler(ft6x06_handle_t * handle,uint32_t i2c_event)34 void FT6X06_EventHandler(ft6x06_handle_t *handle, uint32_t i2c_event)
35 {
36     handle->i2c_event          = i2c_event;
37     handle->i2c_event_received = true;
38 }
39 
FT_6X06_WaitEvent(ft6x06_handle_t * handle)40 static uint32_t FT_6X06_WaitEvent(ft6x06_handle_t *handle)
41 {
42     uint32_t i2c_event;
43 
44     while (!(handle->i2c_event_received))
45         ;
46 
47     i2c_event                  = handle->i2c_event;
48     handle->i2c_event_received = false;
49 
50     return i2c_event;
51 }
52 
FT6X06_Init(ft6x06_handle_t * handle,ARM_DRIVER_I2C * i2c_driver)53 status_t FT6X06_Init(ft6x06_handle_t *handle, ARM_DRIVER_I2C *i2c_driver)
54 {
55     status_t status = kStatus_Success;
56     uint8_t i2c_buf[2];
57 
58     assert(handle);
59     assert(i2c_driver);
60 
61     if (!handle || !i2c_driver)
62     {
63         return kStatus_InvalidArgument;
64     }
65 
66     handle->i2c_driver = i2c_driver;
67 
68     /* clear transfer structure and buffer */
69     memset(handle->touch_buf, 0, FT6X06_TOUCH_DATA_LEN);
70 
71     /* set device mode to normal operation */
72     i2c_buf[0] = 0; /* mode register address */
73     i2c_buf[1] = 0; /* normal operation mode */
74 
75     if (handle->i2c_driver->MasterTransmit(FT6X06_I2C_ADDRESS, i2c_buf, 2, false) != ARM_DRIVER_OK)
76     {
77         status = kStatus_Fail;
78     }
79     else if (FT_6X06_WaitEvent(handle) != ARM_I2C_EVENT_TRANSFER_DONE)
80     {
81         status = kStatus_Fail;
82     }
83 
84     return status;
85 }
86 
FT6X06_Denit(ft6x06_handle_t * handle)87 status_t FT6X06_Denit(ft6x06_handle_t *handle)
88 {
89     assert(handle);
90 
91     if (!handle)
92     {
93         return kStatus_InvalidArgument;
94     }
95 
96     handle->i2c_driver = NULL;
97     return kStatus_Success;
98 }
99 
FT6X06_ReadTouchData(ft6x06_handle_t * handle)100 status_t FT6X06_ReadTouchData(ft6x06_handle_t *handle)
101 {
102     status_t status = kStatus_Success;
103     uint8_t i2c_buf[1];
104 
105     assert(handle);
106 
107     if (!handle || !(handle->i2c_driver))
108     {
109         return kStatus_InvalidArgument;
110     }
111 
112     i2c_buf[0] = F6X06_TOUCH_DATA_SUBADDR;
113 
114     if (handle->i2c_driver->MasterTransmit(FT6X06_I2C_ADDRESS, i2c_buf, 1, true) != ARM_DRIVER_OK)
115     {
116         status = kStatus_Fail;
117     }
118     else if (FT_6X06_WaitEvent(handle) != ARM_I2C_EVENT_TRANSFER_DONE)
119     {
120         status = kStatus_Fail;
121     }
122     else if (handle->i2c_driver->MasterReceive(FT6X06_I2C_ADDRESS, handle->touch_buf, FT6X06_TOUCH_DATA_LEN, false) !=
123              ARM_DRIVER_OK)
124     {
125         status = kStatus_Fail;
126     }
127     else if (FT_6X06_WaitEvent(handle) != ARM_I2C_EVENT_TRANSFER_DONE)
128     {
129         status = kStatus_Fail;
130     }
131 
132     return status;
133 }
134 
FT6X06_GetSingleTouch(ft6x06_handle_t * handle,touch_event_t * touch_event,int * touch_x,int * touch_y)135 status_t FT6X06_GetSingleTouch(ft6x06_handle_t *handle, touch_event_t *touch_event, int *touch_x, int *touch_y)
136 {
137     status_t status;
138     touch_event_t touch_event_local;
139 
140     status = FT6X06_ReadTouchData(handle);
141 
142     if (status == kStatus_Success)
143     {
144         ft6x06_touch_data_t *touch_data = (ft6x06_touch_data_t *)(void *)(handle->touch_buf);
145 
146         if (touch_event == NULL)
147         {
148             touch_event = &touch_event_local;
149         }
150         *touch_event = TOUCH_POINT_GET_EVENT(touch_data->TOUCH[0]);
151 
152         /* Update coordinates only if there is touch detected */
153         if ((*touch_event == kTouch_Down) || (*touch_event == kTouch_Contact))
154         {
155             if (touch_x)
156             {
157                 *touch_x = TOUCH_POINT_GET_X(touch_data->TOUCH[0]);
158             }
159             if (touch_y)
160             {
161                 *touch_y = TOUCH_POINT_GET_Y(touch_data->TOUCH[0]);
162             }
163         }
164     }
165 
166     return status;
167 }
168 
FT6X06_GetMultiTouch(ft6x06_handle_t * handle,int * touch_count,touch_point_t touch_array[FT6X06_MAX_TOUCHES])169 status_t FT6X06_GetMultiTouch(ft6x06_handle_t *handle, int *touch_count, touch_point_t touch_array[FT6X06_MAX_TOUCHES])
170 {
171     status_t status;
172 
173     status = FT6X06_ReadTouchData(handle);
174 
175     if (status == kStatus_Success)
176     {
177         ft6x06_touch_data_t *touch_data = (ft6x06_touch_data_t *)(void *)(handle->touch_buf);
178         int i;
179 
180         /* check for valid number of touches - otherwise ignore touch information...
181            workaround added msy */
182         if (touch_data->TD_STATUS > FT6X06_MAX_TOUCHES)
183             touch_data->TD_STATUS = 0;
184 
185         /* Decode number of touches */
186         if (touch_count)
187         {
188             *touch_count = touch_data->TD_STATUS;
189         }
190 
191         /* Decode valid touch points */
192         for (i = 0; i < touch_data->TD_STATUS; i++)
193         {
194             touch_array[i].TOUCH_ID    = TOUCH_POINT_GET_ID(touch_data->TOUCH[i]);
195             touch_array[i].TOUCH_EVENT = TOUCH_POINT_GET_EVENT(touch_data->TOUCH[i]);
196             touch_array[i].TOUCH_X     = TOUCH_POINT_GET_X(touch_data->TOUCH[i]);
197             touch_array[i].TOUCH_Y     = TOUCH_POINT_GET_Y(touch_data->TOUCH[i]);
198         }
199 
200         /* Clear vacant elements of touch_array */
201         for (; i < FT6X06_MAX_TOUCHES; i++)
202         {
203             touch_array[i].TOUCH_ID    = 0;
204             touch_array[i].TOUCH_EVENT = kTouch_Reserved;
205             touch_array[i].TOUCH_X     = 0;
206             touch_array[i].TOUCH_Y     = 0;
207         }
208     }
209 
210     return status;
211 }
212