1 /* drivers/input/touchscreen/goodix_tool.c
2 *
3 * 2010 - 2014 Goodix Technology.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be a reference
11 * to you, when you are integrating the GOODiX's CTP IC into your system,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * Version: 1.4
17 * Release Date: 2015/07/10
18 */
19
20 #include <linux/delay.h>
21 #include <linux/uaccess.h>
22 #include <linux/proc_fs.h>
23 #include <generated/utsrelease.h>
24 #include "gt1x_generic.h"
25
26 static ssize_t gt1x_tool_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos);
27 static ssize_t gt1x_tool_write(struct file *filp, const char *buffer, size_t count, loff_t *ppos);
28
29
30 static int gt1x_tool_release(struct inode *inode, struct file *filp);
31 static int gt1x_tool_open(struct inode *inode, struct file *file);
32
33 #pragma pack(1)
34 typedef struct {
35 u8 wr;
36 u8 flag;
37 u8 flag_addr[2];
38 u8 flag_val;
39 u8 flag_relation;
40 u16 circle;
41 u8 times;
42 u8 retry;
43 u16 delay;
44 u16 data_len;
45 u8 addr_len;
46 u8 addr[2];
47 u8 res[3];
48 u8 *data;
49 } st_cmd_head;
50 #pragma pack()
51 st_cmd_head cmd_head;
52
53 s32 DATA_LENGTH;
54 s8 IC_TYPE[16] = "GT1X";
55
56 #define UPDATE_FUNCTIONS
57 #define DATA_LENGTH_UINT 512
58 #define CMD_HEAD_LENGTH (sizeof(st_cmd_head) - sizeof(u8 *))
59
60 static char procname[20] = { 0 };
61
62 static struct proc_dir_entry *gt1x_tool_proc_entry;
63 static const struct proc_ops gt1x_tool_fops = {
64 .proc_read = gt1x_tool_read,
65 .proc_write = gt1x_tool_write,
66 .proc_open = gt1x_tool_open,
67 .proc_release = gt1x_tool_release,
68 };
69
set_tool_node_name(char * procname)70 static void set_tool_node_name(char *procname)
71 {
72
73 int v0 = 0, v1 = 0, v2 = 0;
74
75 sscanf(UTS_RELEASE, "%d.%d.%d", &v0, &v1, &v2);
76 sprintf(procname, "gmnode%02d%02d%02d", v0, v1, v2);
77 }
78
gt1x_init_tool_node(void)79 int gt1x_init_tool_node(void)
80 {
81 memset(&cmd_head, 0, sizeof(cmd_head));
82 /*if the first operation is read, will return fail.*/
83 cmd_head.wr = 1;
84 cmd_head.data = kzalloc(DATA_LENGTH_UINT, GFP_KERNEL);
85 if (NULL == cmd_head.data) {
86 GTP_ERROR("Apply for memory failed.");
87 return -1;
88 }
89 GTP_INFO("Alloc memory size:%d.", DATA_LENGTH_UINT);
90 DATA_LENGTH = DATA_LENGTH_UINT - GTP_ADDR_LENGTH;
91
92 set_tool_node_name(procname);
93
94 gt1x_tool_proc_entry = proc_create(procname, 0755, NULL, >1x_tool_fops);
95 if (gt1x_tool_proc_entry == NULL) {
96 GTP_ERROR("CAN't create proc entry /proc/%s.", procname);
97 return -1;
98 } else {
99 GTP_INFO("Created proc entry /proc/%s.", procname);
100 }
101 return 0;
102 }
103
gt1x_deinit_tool_node(void)104 void gt1x_deinit_tool_node(void)
105 {
106 remove_proc_entry(procname, NULL);
107 kfree(cmd_head.data);
108 cmd_head.data = NULL;
109 }
110
tool_i2c_read(u8 * buf,u16 len)111 static s32 tool_i2c_read(u8 *buf, u16 len)
112 {
113 u16 addr = (buf[0] << 8) + buf[1];
114 if (!gt1x_i2c_read(addr, &buf[2], len)) {
115 return 1;
116 }
117 return -1;
118 }
119
tool_i2c_write(u8 * buf,u16 len)120 static s32 tool_i2c_write(u8 *buf, u16 len)
121 {
122 u16 addr = (buf[0] << 8) + buf[1];
123 if (!gt1x_i2c_write(addr, &buf[2], len - 2)) {
124 return 1;
125 }
126 return -1;
127 }
128
relation(u8 src,u8 dst,u8 rlt)129 static u8 relation(u8 src, u8 dst, u8 rlt)
130 {
131 u8 ret = 0;
132
133 switch (rlt) {
134 case 0:
135 ret = (src != dst) ? true : false;
136 break;
137
138 case 1:
139 ret = (src == dst) ? true : false;
140 GTP_DEBUG("equal:src:0x%02x dst:0x%02x ret:%d.", src, dst, (s32) ret);
141 break;
142
143 case 2:
144 ret = (src > dst) ? true : false;
145 break;
146
147 case 3:
148 ret = (src < dst) ? true : false;
149 break;
150
151 case 4:
152 ret = (src & dst) ? true : false;
153 break;
154
155 case 5:
156 ret = (!(src | dst)) ? true : false;
157 break;
158
159 default:
160 ret = false;
161 break;
162 }
163
164 return ret;
165 }
166
167 /*******************************************************
168 Function:
169 Comfirm function.
170 Input:
171 None.
172 Output:
173 Return write length.
174 ********************************************************/
comfirm(void)175 static u8 comfirm(void)
176 {
177 s32 i = 0;
178 u8 buf[32];
179
180 memcpy(buf, cmd_head.flag_addr, cmd_head.addr_len);
181
182 for (i = 0; i < cmd_head.times; i++) {
183 if (tool_i2c_read(buf, 1) <= 0) {
184 GTP_ERROR("Read flag data failed!");
185 return -1;
186 }
187
188 if (true == relation(buf[GTP_ADDR_LENGTH], cmd_head.flag_val, cmd_head.flag_relation)) {
189 GTP_DEBUG("value at flag addr:0x%02x.", buf[GTP_ADDR_LENGTH]);
190 GTP_DEBUG("flag value:0x%02x.", cmd_head.flag_val);
191 break;
192 }
193
194 msleep(cmd_head.circle);
195 }
196
197 if (i >= cmd_head.times) {
198 GTP_ERROR("Didn't get the flag to continue!");
199 return -1;
200 }
201
202 return 0;
203 }
204
205 /*******************************************************
206 Function:
207 Goodix tool write function.
208 Input:
209 standard proc write function param.
210 Output:
211 Return write length.
212 ********************************************************/
gt1x_tool_write(struct file * filp,const char __user * buff,size_t len,loff_t * data)213 static ssize_t gt1x_tool_write(struct file *filp, const char __user *buff, size_t len, loff_t *data)
214 {
215 u64 ret = 0;
216 GTP_DEBUG_FUNC();
217 GTP_DEBUG_ARRAY((u8 *) buff, len);
218
219 ret = copy_from_user(&cmd_head, buff, CMD_HEAD_LENGTH);
220 if (ret) {
221 GTP_ERROR("copy_from_user failed.");
222 }
223
224 GTP_DEBUG("wr :0x%02x.", cmd_head.wr);
225 /*
226 GTP_DEBUG("flag:0x%02x.", cmd_head.flag);
227 GTP_DEBUG("flag addr:0x%02x%02x.", cmd_head.flag_addr[0], cmd_head.flag_addr[1]);
228 GTP_DEBUG("flag val:0x%02x.", cmd_head.flag_val);
229 GTP_DEBUG("flag rel:0x%02x.", cmd_head.flag_relation);
230 GTP_DEBUG("circle :%d.", (s32)cmd_head.circle);
231 GTP_DEBUG("times :%d.", (s32)cmd_head.times);
232 GTP_DEBUG("retry :%d.", (s32)cmd_head.retry);
233 GTP_DEBUG("delay :%d.", (s32)cmd_head.delay);
234 GTP_DEBUG("data len:%d.", (s32)cmd_head.data_len);
235 GTP_DEBUG("addr len:%d.", (s32)cmd_head.addr_len);
236 GTP_DEBUG("addr:0x%02x%02x.", cmd_head.addr[0], cmd_head.addr[1]);
237 GTP_DEBUG("len:%d.", (s32)len);
238 GTP_DEBUG("buf[20]:0x%02x.", buff[CMD_HEAD_LENGTH]);
239 */
240
241 if (1 == cmd_head.wr) {
242 u16 addr, data_len, pos;
243
244 if (1 == cmd_head.flag) {
245 if (comfirm()) {
246 GTP_ERROR("[WRITE]Comfirm fail!");
247 return -1;
248 }
249 } else if (2 == cmd_head.flag) {
250 /*Need interrupt!*/
251 }
252
253 addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1];
254 data_len = cmd_head.data_len;
255 pos = 0;
256 while (data_len > 0) {
257 len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len;
258 ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH + pos], len);
259 if (ret) {
260 GTP_ERROR("[WRITE]copy_from_user failed.");
261 return -1;
262 }
263 cmd_head.data[0] = ((addr >> 8) & 0xFF);
264 cmd_head.data[1] = (addr & 0xFF);
265
266 GTP_DEBUG_ARRAY(cmd_head.data, len + GTP_ADDR_LENGTH);
267
268 if (tool_i2c_write(cmd_head.data, len + GTP_ADDR_LENGTH) <= 0) {
269 GTP_ERROR("[WRITE]Write data failed!");
270 return -1;
271 }
272 addr += len;
273 pos += len;
274 data_len -= len;
275 }
276
277 if (cmd_head.delay) {
278 msleep(cmd_head.delay);
279 }
280 return cmd_head.data_len + CMD_HEAD_LENGTH;
281 } else if (3 == cmd_head.wr) { /* gt1x unused */
282 memcpy(IC_TYPE, cmd_head.data, min((u16)sizeof(IC_TYPE), cmd_head.data_len));
283 return cmd_head.data_len + CMD_HEAD_LENGTH;
284 } else if (5 == cmd_head.wr) { /* ? */
285 /*memcpy(IC_TYPE, cmd_head.data, cmd_head.data_len);*/
286 return cmd_head.data_len + CMD_HEAD_LENGTH;
287 } else if (7 == cmd_head.wr) { /* disable irq! */
288 gt1x_irq_disable();
289 #if GTP_ESD_PROTECT
290 gt1x_esd_switch(SWITCH_OFF);
291 #endif
292 return CMD_HEAD_LENGTH;
293 } else if (9 == cmd_head.wr) { /* enable irq! */
294 gt1x_irq_enable();
295 #if GTP_ESD_PROTECT
296 gt1x_esd_switch(SWITCH_ON);
297 #endif
298 return CMD_HEAD_LENGTH;
299 } else if (17 == cmd_head.wr) {
300 ret = copy_from_user(&cmd_head.data[GTP_ADDR_LENGTH], &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
301 if (ret) {
302 GTP_ERROR("copy_from_user failed.");
303 return -1;
304 }
305
306 if (cmd_head.data[GTP_ADDR_LENGTH]) {
307 GTP_DEBUG("gtp enter rawdiff.");
308 gt1x_rawdiff_mode = true;
309 } else {
310 gt1x_rawdiff_mode = false;
311 GTP_DEBUG("gtp leave rawdiff.");
312 }
313
314 return CMD_HEAD_LENGTH;
315 } else if (11 == cmd_head.wr) {
316 gt1x_enter_update_mode();
317 } else if (13 == cmd_head.wr) {
318 gt1x_leave_update_mode();
319 } else if (15 == cmd_head.wr) {
320 struct task_struct *thrd = NULL;
321 memset(cmd_head.data, 0, cmd_head.data_len + 1);
322 memcpy(cmd_head.data, &buff[CMD_HEAD_LENGTH], cmd_head.data_len);
323 GTP_DEBUG("update firmware, filename: %s", cmd_head.data);
324 thrd = kthread_run(gt1x_update_firmware, (void *)cmd_head.data, "GT1x FW Update");
325 if (IS_ERR(thrd)) {
326 return PTR_ERR(thrd);
327 }
328 }
329 return CMD_HEAD_LENGTH;
330 }
331
332 static u8 devicecount;
gt1x_tool_open(struct inode * inode,struct file * file)333 static int gt1x_tool_open(struct inode *inode, struct file *file)
334 {
335 if (devicecount > 0) {
336 return -ERESTARTSYS;
337 GTP_ERROR("tools open failed!");
338 }
339 devicecount++;
340 return 0;
341 }
342
gt1x_tool_release(struct inode * inode,struct file * filp)343 static int gt1x_tool_release(struct inode *inode, struct file *filp)
344 {
345 devicecount--;
346 return 0;
347 }
348 /*******************************************************
349 Function:
350 Goodix tool read function.
351 Input:
352 standard proc read function param.
353 Output:
354 Return read length.
355 ********************************************************/
gt1x_tool_read(struct file * filp,char __user * buffer,size_t count,loff_t * ppos)356 static ssize_t gt1x_tool_read(struct file *filp, char __user *buffer, size_t count, loff_t *ppos)
357 {
358 GTP_DEBUG_FUNC();
359 if (*ppos) {
360 GTP_DEBUG("[PARAM]size: %zd, *ppos: %d", count, (int)*ppos);
361 *ppos = 0;
362 return 0;
363 }
364
365 if (cmd_head.wr % 2) {
366 GTP_ERROR("[READ] invaild operator fail!");
367 return -1;
368 } else if (!cmd_head.wr) {
369 /* general i2c read */
370 u16 addr, data_len, len, loc;
371
372 if (1 == cmd_head.flag) {
373 if (comfirm()) {
374 GTP_ERROR("[READ]Comfirm fail!");
375 return -1;
376 }
377 } else if (2 == cmd_head.flag) {
378 /*Need interrupt!*/
379 }
380
381 addr = (cmd_head.addr[0] << 8) + cmd_head.addr[1];
382 data_len = cmd_head.data_len;
383 loc = 0;
384
385 GTP_DEBUG("[READ] ADDR:0x%04X.", addr);
386 GTP_DEBUG("[READ] Length: %d", data_len);
387
388 if (cmd_head.delay) {
389 msleep(cmd_head.delay);
390 }
391
392 while (data_len > 0) {
393 len = data_len > DATA_LENGTH ? DATA_LENGTH : data_len;
394 cmd_head.data[0] = (addr >> 8) & 0xFF;
395 cmd_head.data[1] = (addr & 0xFF);
396 if (tool_i2c_read(cmd_head.data, len) <= 0) {
397 GTP_ERROR("[READ]Read data failed!");
398 return -1;
399 }
400 memcpy(&buffer[loc], &cmd_head.data[GTP_ADDR_LENGTH], len);
401 data_len -= len;
402 addr += len;
403 loc += len;
404 GTP_DEBUG_ARRAY(&cmd_head.data[GTP_ADDR_LENGTH], len);
405 }
406 *ppos += cmd_head.data_len;
407 return cmd_head.data_len;
408 } else if (2 == cmd_head.wr) {
409 GTP_DEBUG("Return ic type:%s len:%d.", buffer, (s32) cmd_head.data_len);
410 return -1;
411 } else if (4 == cmd_head.wr) {
412 /* read fw update progress */
413 buffer[0] = update_info.progress >> 8;
414 buffer[1] = update_info.progress & 0xff;
415 buffer[2] = update_info.max_progress >> 8;
416 buffer[3] = update_info.max_progress & 0xff;
417 *ppos += 4;
418 return 4;
419 } else if (6 == cmd_head.wr) {
420 /*Read error code!*/
421 return -1;
422 } else if (8 == cmd_head.wr) {
423 /* Read driver version */
424 s32 tmp_len;
425 tmp_len = strlen(GTP_DRIVER_VERSION);
426 memcpy(buffer, GTP_DRIVER_VERSION, tmp_len);
427 buffer[tmp_len] = 0;
428 *ppos += tmp_len + 1;
429 return (tmp_len + 1);
430 }
431 *ppos += cmd_head.data_len;
432 return cmd_head.data_len;
433 }
434