1 /*
2 * cyttsp5_test_device_access_api.c
3 * Parade TrueTouch(TM) Standard Product V5 Device Access API test module.
4 * For use with Parade touchscreen controllers.
5 * Supported parts include:
6 * CYTMA5XX
7 * CYTMA448
8 * CYTMA445A
9 * CYTT21XXX
10 * CYTT31XXX
11 *
12 * Copyright (C) 2015 Parade Technologies
13 * Copyright (C) 2012-2015 Cypress Semiconductor
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * version 2, and only version 2, as published by the
18 * Free Software Foundation.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
26 *
27 */
28
29 #include <linux/module.h>
30 #include <linux/cyttsp5_device_access-api.h>
31 #include <asm/unaligned.h>
32
33 #define BUFFER_SIZE 256
34
35 #define COMMAND_GET_SYSTEM_INFO 2
36 #define COMMAND_SUSPEND_SCANNING 3
37 #define COMMAND_RESUME_SCANNING 4
38 #define COMMAND_GET_PARAMETER 5
39 #define COMMAND_SET_PARAMETER 6
40
41 #define PARAMETER_ACTIVE_DISTANCE_2 0x0B
42
43 struct tt_output_report {
44 __le16 reg_address;
45 __le16 length;
46 u8 report_id;
47 u8 reserved;
48 u8 command;
49 u8 parameters[0];
50 } __packed;
51
52 struct tt_input_report {
53 __le16 length;
54 u8 report_id;
55 u8 reserved;
56 u8 command;
57 u8 return_data[0];
58 } __packed;
59
prepare_tt_output_report(struct tt_output_report * out,u16 length,u8 command)60 static int prepare_tt_output_report(struct tt_output_report *out,
61 u16 length, u8 command)
62 {
63 put_unaligned_le16(0x04, &out->reg_address);
64 put_unaligned_le16(5 + length, &out->length);
65
66 out->report_id = 0x2f;
67 out->reserved = 0x00;
68 out->command = command;
69
70 return 7 + length;
71 }
72
check_and_parse_tt_input_report(struct tt_input_report * in,u16 * length,u8 * command)73 static int check_and_parse_tt_input_report(struct tt_input_report *in,
74 u16 *length, u8 *command)
75 {
76 if (in->report_id != 0x1f)
77 return -EINVAL;
78
79 *length = get_unaligned_le16(&in->length);
80 *command = in->command & 0x7f;
81
82 return 0;
83 }
84
prepare_get_system_info_report(u8 * buf)85 static int prepare_get_system_info_report(u8 *buf)
86 {
87 struct tt_output_report *out = (struct tt_output_report *)buf;
88
89 return prepare_tt_output_report(out, 0, COMMAND_GET_SYSTEM_INFO);
90 }
91
check_get_system_info_response(u8 * buf,u16 read_length)92 static int check_get_system_info_response(u8 *buf, u16 read_length)
93 {
94 struct tt_input_report *in = (struct tt_input_report *)buf;
95 u16 length = 0;
96 u8 command = 0;
97
98 if (read_length != 51)
99 return -EINVAL;
100
101 if (check_and_parse_tt_input_report(in, &length, &command)
102 || command != COMMAND_GET_SYSTEM_INFO
103 || length != 51)
104 return -EINVAL;
105
106 pr_info("PIP Major Version: %d\n", in->return_data[0]);
107 pr_info("PIP Minor Version: %d\n", in->return_data[1]);
108 pr_info("Touch Firmware Product Id: %d\n",
109 get_unaligned_le16(&in->return_data[2]));
110 pr_info("Touch Firmware Major Version: %d\n", in->return_data[4]);
111 pr_info("Touch Firmware Minor Version: %d\n", in->return_data[5]);
112 pr_info("Touch Firmware Internal Revision Control Number: %d\n",
113 get_unaligned_le32(&in->return_data[6]));
114 pr_info("Customer Specified Firmware/Configuration Version: %d\n",
115 get_unaligned_le16(&in->return_data[10]));
116 pr_info("Bootloader Major Version: %d\n", in->return_data[12]);
117 pr_info("Bootloader Minor Version: %d\n", in->return_data[13]);
118 pr_info("Family ID: 0x%02x\n", in->return_data[14]);
119 pr_info("Revision ID: 0x%02x\n", in->return_data[15]);
120 pr_info("Silicon ID: 0x%02x\n",
121 get_unaligned_le16(&in->return_data[16]));
122 pr_info("Parade Manufacturing ID[0]: 0x%02x\n", in->return_data[18]);
123 pr_info("Parade Manufacturing ID[1]: 0x%02x\n", in->return_data[19]);
124 pr_info("Parade Manufacturing ID[2]: 0x%02x\n", in->return_data[20]);
125 pr_info("Parade Manufacturing ID[3]: 0x%02x\n", in->return_data[21]);
126 pr_info("Parade Manufacturing ID[4]: 0x%02x\n", in->return_data[22]);
127 pr_info("Parade Manufacturing ID[5]: 0x%02x\n", in->return_data[23]);
128 pr_info("Parade Manufacturing ID[6]: 0x%02x\n", in->return_data[24]);
129 pr_info("Parade Manufacturing ID[7]: 0x%02x\n", in->return_data[25]);
130 pr_info("POST Result Code: 0x%02x\n",
131 get_unaligned_le16(&in->return_data[26]));
132
133 pr_info("Number of X Electrodes: %d\n", in->return_data[28]);
134 pr_info("Number of Y Electrodes: %d\n", in->return_data[29]);
135 pr_info("Panel X Axis Length: %d\n",
136 get_unaligned_le16(&in->return_data[30]));
137 pr_info("Panel Y Axis Length: %d\n",
138 get_unaligned_le16(&in->return_data[32]));
139 pr_info("Panel X Axis Resolution: %d\n",
140 get_unaligned_le16(&in->return_data[34]));
141 pr_info("Panel Y Axis Resolution: %d\n",
142 get_unaligned_le16(&in->return_data[36]));
143 pr_info("Panel Pressure Resolution: %d\n",
144 get_unaligned_le16(&in->return_data[38]));
145 pr_info("X_ORG: %d\n", in->return_data[40]);
146 pr_info("Y_ORG: %d\n", in->return_data[41]);
147 pr_info("Panel ID: %d\n", in->return_data[42]);
148 pr_info("Buttons: 0x%02x\n", in->return_data[43]);
149 pr_info("BAL SELF MC: 0x%02x\n", in->return_data[44]);
150 pr_info("Max Number of Touch Records per Refresh Cycle: %d\n",
151 in->return_data[45]);
152
153 return 0;
154 }
155
prepare_get_parameter_report(u8 * buf,u8 parameter_id)156 static int prepare_get_parameter_report(u8 *buf, u8 parameter_id)
157 {
158 struct tt_output_report *out = (struct tt_output_report *)buf;
159
160 out->parameters[0] = parameter_id;
161
162 return prepare_tt_output_report(out, 1, COMMAND_GET_PARAMETER);
163 }
164
check_get_parameter_response(u8 * buf,u16 read_length,u32 * parameter_value)165 static int check_get_parameter_response(u8 *buf, u16 read_length,
166 u32 *parameter_value)
167 {
168 struct tt_input_report *in = (struct tt_input_report *)buf;
169 u16 length = 0;
170 u8 command = 0;
171 u32 param_value = 0;
172 u8 param_id;
173 u8 param_size = 0;
174
175 if (read_length != 8 && read_length != 9 && read_length != 11)
176 return -EINVAL;
177
178 if (check_and_parse_tt_input_report(in, &length, &command)
179 || command != COMMAND_GET_PARAMETER
180 || (length != 8 && length != 9 && length != 11))
181 return -EINVAL;
182
183 param_id = in->return_data[0];
184
185 param_size = in->return_data[1];
186
187 if (param_size == 1)
188 param_value = in->return_data[2];
189 else if (param_size == 2)
190 param_value = get_unaligned_le16(&in->return_data[2]);
191 else if (param_size == 4)
192 param_value = get_unaligned_le32(&in->return_data[2]);
193 else
194 return -EINVAL;
195
196 pr_info("%s: Parameter ID: 0x%02x Value: 0x%02x\n",
197 __func__, param_id, param_value);
198
199 if (parameter_value)
200 *parameter_value = param_value;
201
202 return 0;
203 }
204
prepare_set_parameter_report(u8 * buf,u8 parameter_id,u8 parameter_size,u32 parameter_value)205 static int prepare_set_parameter_report(u8 *buf, u8 parameter_id,
206 u8 parameter_size, u32 parameter_value)
207 {
208 struct tt_output_report *out = (struct tt_output_report *)buf;
209
210 out->parameters[0] = parameter_id;
211 out->parameters[1] = parameter_size;
212
213 if (parameter_size == 1)
214 out->parameters[2] = (u8)parameter_value;
215 else if (parameter_size == 2)
216 put_unaligned_le16(parameter_value, &out->parameters[2]);
217 else if (parameter_size == 4)
218 put_unaligned_le32(parameter_value, &out->parameters[2]);
219 else
220 return -EINVAL;
221
222 return prepare_tt_output_report(out, 2 + parameter_size,
223 COMMAND_SET_PARAMETER);
224 }
225
check_set_parameter_response(u8 * buf,u16 read_length)226 static int check_set_parameter_response(u8 *buf, u16 read_length)
227 {
228 struct tt_input_report *in = (struct tt_input_report *)buf;
229 u16 length = 0;
230 u8 command = 0;
231 u8 param_id;
232 u8 param_size = 0;
233
234 if (read_length != 7)
235 return -EINVAL;
236
237 if (check_and_parse_tt_input_report(in, &length, &command)
238 || command != COMMAND_SET_PARAMETER
239 || length != 7)
240 return -EINVAL;
241
242 param_id = in->return_data[0];
243 param_size = in->return_data[1];
244
245 pr_info("%s: Parameter ID: 0x%02x Size: 0x%02x\n",
246 __func__, param_id, param_size);
247
248 return 0;
249 }
250
prepare_suspend_scanning_report(u8 * buf)251 static int prepare_suspend_scanning_report(u8 *buf)
252 {
253 struct tt_output_report *out = (struct tt_output_report *)buf;
254
255 return prepare_tt_output_report(out, 0, COMMAND_SUSPEND_SCANNING);
256 }
257
check_suspend_scanning_response(u8 * buf,u16 read_length)258 static int check_suspend_scanning_response(u8 *buf, u16 read_length)
259 {
260 struct tt_input_report *in = (struct tt_input_report *)buf;
261 u16 length = 0;
262 u8 command = 0;
263
264 if (read_length != 5)
265 return -EINVAL;
266
267 if (check_and_parse_tt_input_report(in, &length, &command)
268 || command != COMMAND_SUSPEND_SCANNING
269 || length != 5)
270 return -EINVAL;
271
272 return 0;
273 }
274
prepare_resume_scanning_report(u8 * buf)275 static int prepare_resume_scanning_report(u8 *buf)
276 {
277 struct tt_output_report *out = (struct tt_output_report *)buf;
278
279 return prepare_tt_output_report(out, 0, COMMAND_RESUME_SCANNING);
280 }
281
check_resume_scanning_response(u8 * buf,u16 read_length)282 static int check_resume_scanning_response(u8 *buf, u16 read_length)
283 {
284 struct tt_input_report *in = (struct tt_input_report *)buf;
285 u16 length = 0;
286 u8 command = 0;
287
288 if (read_length != 5)
289 return -EINVAL;
290
291 if (check_and_parse_tt_input_report(in, &length, &command)
292 || command != COMMAND_RESUME_SCANNING
293 || length != 5)
294 return -EINVAL;
295
296 return 0;
297 }
298
cyttsp5_user_command_async_cont(const char * core_name,u16 read_len,u8 * read_buf,u16 write_len,u8 * write_buf,u16 actual_read_length,int rc)299 void cyttsp5_user_command_async_cont(const char *core_name,
300 u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf,
301 u16 actual_read_length, int rc)
302 {
303 if (rc) {
304 pr_err("%s: suspend scan fails\n", __func__);
305 goto exit;
306 }
307
308 rc = check_suspend_scanning_response(read_buf, actual_read_length);
309 if (rc) {
310 pr_err("%s: check suspend scanning response fails\n", __func__);
311 goto exit;
312 }
313
314 pr_info("%s: suspend scanning succeeds\n", __func__);
315 exit:
316 return;
317 }
318
319 /* Read and write buffers */
320 static u8 write_buf[BUFFER_SIZE];
321 static u8 read_buf[BUFFER_SIZE];
322
323 static uint active_distance;
324 module_param(active_distance, uint, 0);
325
cyttsp5_test_device_access_api_init(void)326 static int __init cyttsp5_test_device_access_api_init(void)
327 {
328 u32 initial_active_distance;
329 u16 actual_read_len;
330 int write_len;
331 int rc;
332
333 pr_info("%s: Enter\n", __func__);
334
335 /* CASE 1: Run get system information */
336 write_len = prepare_get_system_info_report(write_buf);
337
338 rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
339 read_buf, write_len, write_buf,
340 &actual_read_len);
341 if (rc)
342 goto exit;
343
344 rc = check_get_system_info_response(read_buf, actual_read_len);
345 if (rc)
346 goto exit;
347
348 /* CASE 2: Run get parameter (Active distance) */
349 write_len = prepare_get_parameter_report(write_buf,
350 PARAMETER_ACTIVE_DISTANCE_2);
351
352 rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
353 read_buf, write_len, write_buf,
354 &actual_read_len);
355 if (rc)
356 goto exit;
357
358 rc = check_get_parameter_response(read_buf, actual_read_len,
359 &initial_active_distance);
360 if (rc)
361 goto exit;
362
363 pr_info("%s: Initial Active Distance: %d\n",
364 __func__, initial_active_distance);
365
366 /* CASE 3: Run set parameter (Active distance) */
367 write_len = prepare_set_parameter_report(write_buf,
368 PARAMETER_ACTIVE_DISTANCE_2, 1,
369 active_distance);
370
371 rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
372 read_buf, write_len, write_buf,
373 &actual_read_len);
374 if (rc)
375 goto exit;
376
377 rc = check_set_parameter_response(read_buf, actual_read_len);
378 if (rc)
379 goto exit;
380
381 pr_info("%s: Active Distance set to %d\n", __func__, active_distance);
382
383 /* CASE 4: Run get parameter (Active distance) */
384 write_len = prepare_get_parameter_report(write_buf,
385 PARAMETER_ACTIVE_DISTANCE_2);
386
387 rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
388 read_buf, write_len, write_buf,
389 &actual_read_len);
390 if (rc)
391 goto exit;
392
393 rc = check_get_parameter_response(read_buf, actual_read_len,
394 &active_distance);
395 if (rc)
396 goto exit;
397
398 pr_info("%s: New Active Distance: %d\n", __func__, active_distance);
399
400 /* CASE 5: Run suspend scanning asynchronously */
401 write_len = prepare_suspend_scanning_report(write_buf);
402
403 preempt_disable();
404 rc = cyttsp5_device_access_user_command_async(NULL,
405 sizeof(read_buf), read_buf, write_len, write_buf,
406 cyttsp5_user_command_async_cont);
407 preempt_enable();
408 if (rc)
409 goto exit;
410 exit:
411 return rc;
412 }
413 module_init(cyttsp5_test_device_access_api_init);
414
cyttsp5_test_device_access_api_exit(void)415 static void __exit cyttsp5_test_device_access_api_exit(void)
416 {
417 u16 actual_read_len;
418 int write_len;
419 int rc;
420
421 /* CASE 6: Run resume scanning */
422 write_len = prepare_resume_scanning_report(write_buf);
423
424 rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
425 read_buf, write_len, write_buf,
426 &actual_read_len);
427 if (rc)
428 goto exit;
429
430 rc = check_resume_scanning_response(read_buf, actual_read_len);
431 if (rc)
432 goto exit;
433
434 pr_info("%s: resume scanning succeeds\n", __func__);
435 exit:
436 return;
437 }
438 module_exit(cyttsp5_test_device_access_api_exit);
439
440 MODULE_LICENSE("GPL");
441 MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Device Access Driver API Tester");
442 MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
443