blob: f4ebba784936e71e02fd42e23a2b267adadc0520 [file] [log] [blame]
xigualud25de432019-05-21 17:35:41 +08001/*
2 * cyttsp5_debug.c
3 * Parade TrueTouch(TM) Standard Product V5 Debug 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 "cyttsp5_regs.h"
30
31#define CYTTSP5_DEBUG_NAME "cyttsp5_debug"
32
33struct cyttsp5_debug_data {
34 struct device *dev;
35 struct cyttsp5_sysinfo *si;
36 uint32_t interrupt_count;
37 uint32_t formated_output;
38 struct mutex sysfs_lock;
39 u8 pr_buf[CY_MAX_PRBUF_SIZE];
40};
41
42static struct cyttsp5_core_commands *cmd;
43
44static struct cyttsp5_module debug_module;
45
46static inline struct cyttsp5_debug_data *cyttsp5_get_debug_data(
47 struct device *dev)
48{
49 return cyttsp5_get_module_data(dev, &debug_module);
50}
51
52/*
53 * This function provide output of combined xy_mode and xy_data.
54 * Required by TTHE.
55 */
56static void cyttsp5_pr_buf_op_mode(struct cyttsp5_debug_data *dd, u8 *pr_buf,
57 struct cyttsp5_sysinfo *si, u8 cur_touch)
58{
59 const char fmt[] = "%02X ";
60 int max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
61 u8 report_id = si->xy_mode[2];
62 int header_size = 0;
63 int report_size = 0;
64 int total_size = 0;
65 int i, k;
66
67 if (report_id == si->desc.tch_report_id) {
68 header_size = si->desc.tch_header_size;
69 report_size = cur_touch * si->desc.tch_record_size;
70 } else if (report_id == si->desc.btn_report_id) {
71 header_size = BTN_INPUT_HEADER_SIZE;
72 report_size = BTN_REPORT_SIZE;
73 }
74 total_size = header_size + report_size;
75
76 pr_buf[0] = 0;
77 for (i = k = 0; i < header_size && i < max; i++, k += 3)
78 scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, si->xy_mode[i]);
79
80 for (i = 0; i < report_size && i < max; i++, k += 3)
81 scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, si->xy_data[i]);
82
83 pr_info("%s=%s%s\n", "cyttsp5_OpModeData", pr_buf,
84 total_size <= max ? "" : CY_PR_TRUNCATED);
85}
86
87static void cyttsp5_debug_print(struct device *dev, u8 *pr_buf, u8 *sptr,
88 int size, const char *data_name)
89{
90 int i, j;
91 int elem_size = sizeof("XX ") - 1;
92 int max = (CY_MAX_PRBUF_SIZE - 1) / elem_size;
93 int limit = size < max ? size : max;
94
95 if (limit < 0)
96 limit = 0;
97
98 pr_buf[0] = 0;
99 for (i = j = 0; i < limit; i++, j += elem_size)
100 scnprintf(pr_buf + j, CY_MAX_PRBUF_SIZE - j, "%02X ", sptr[i]);
101
102 if (size)
103 pr_info("%s[0..%d]=%s%s\n", data_name, size - 1, pr_buf,
104 size <= max ? "" : CY_PR_TRUNCATED);
105 else
106 pr_info("%s[]\n", data_name);
107}
108
109static void cyttsp5_debug_formated(struct device *dev, u8 *pr_buf,
110 struct cyttsp5_sysinfo *si, u8 num_cur_tch)
111{
112 u8 report_id = si->xy_mode[2];
113 int header_size = 0;
114 int report_size = 0;
115 u8 data_name[] = "touch[99]";
116 int max_print_length = 20;
117 int i;
118
119 if (report_id == si->desc.tch_report_id) {
120 header_size = si->desc.tch_header_size;
121 report_size = num_cur_tch * si->desc.tch_record_size;
122 } else if (report_id == si->desc.btn_report_id) {
123 header_size = BTN_INPUT_HEADER_SIZE;
124 report_size = BTN_REPORT_SIZE;
125 }
126
127 /* xy_mode */
128 cyttsp5_debug_print(dev, pr_buf, si->xy_mode, header_size, "xy_mode");
129
130 /* xy_data */
131 if (report_size > max_print_length) {
132 pr_info("xy_data[0..%d]:\n", report_size);
133 for (i = 0; i < report_size - max_print_length;
134 i += max_print_length) {
135 cyttsp5_debug_print(dev, pr_buf, si->xy_data + i,
136 max_print_length, " ");
137 }
138 if (report_size - i)
139 cyttsp5_debug_print(dev, pr_buf, si->xy_data + i,
140 report_size - i, " ");
141 } else {
142 cyttsp5_debug_print(dev, pr_buf, si->xy_data, report_size,
143 "xy_data");
144 }
145
146 /* touches */
147 if (report_id == si->desc.tch_report_id) {
148 for (i = 0; i < num_cur_tch; i++) {
149 scnprintf(data_name, sizeof(data_name) - 1,
150 "touch[%u]", i);
151 cyttsp5_debug_print(dev, pr_buf,
152 si->xy_data + (i * si->desc.tch_record_size),
153 si->desc.tch_record_size, data_name);
154 }
155 }
156
157 /* buttons */
158 if (report_id == si->desc.btn_report_id)
159 cyttsp5_debug_print(dev, pr_buf, si->xy_data, report_size,
160 "button");
161}
162
163/* read xy_data for all touches for debug */
164static int cyttsp5_xy_worker(struct cyttsp5_debug_data *dd)
165{
166 struct device *dev = dd->dev;
167 struct cyttsp5_sysinfo *si = dd->si;
168 u8 report_reg = si->xy_mode[TOUCH_COUNT_BYTE_OFFSET];
169 u8 num_cur_tch = GET_NUM_TOUCHES(report_reg);
170 uint32_t formated_output;
171
172 mutex_lock(&dd->sysfs_lock);
173 dd->interrupt_count++;
174 formated_output = dd->formated_output;
175 mutex_unlock(&dd->sysfs_lock);
176
177 /* Interrupt */
178 pr_info("Interrupt(%u)\n", dd->interrupt_count);
179
180 if (formated_output)
181 cyttsp5_debug_formated(dev, dd->pr_buf, si, num_cur_tch);
182 else
183 /* print data for TTHE */
184 cyttsp5_pr_buf_op_mode(dd, dd->pr_buf, si, num_cur_tch);
185
186 pr_info("\n");
187
188 return 0;
189}
190
191static int cyttsp5_debug_attention(struct device *dev)
192{
193 struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
194 struct cyttsp5_sysinfo *si = dd->si;
195 u8 report_id = si->xy_mode[2];
196 int rc = 0;
197
198 if (report_id != si->desc.tch_report_id
199 && report_id != si->desc.btn_report_id)
200 return 0;
201
202 /* core handles handshake */
203 rc = cyttsp5_xy_worker(dd);
204 if (rc < 0)
205 dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
206
207 return rc;
208}
209
210static ssize_t cyttsp5_interrupt_count_show(struct device *dev,
211 struct device_attribute *attr, char *buf)
212{
213 struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
214 int val;
215
216 mutex_lock(&dd->sysfs_lock);
217 val = dd->interrupt_count;
218 mutex_unlock(&dd->sysfs_lock);
219
220 return scnprintf(buf, CY_MAX_PRBUF_SIZE, "Interrupt Count: %d\n", val);
221}
222
223static ssize_t cyttsp5_interrupt_count_store(struct device *dev,
224 struct device_attribute *attr, const char *buf, size_t size)
225{
226 struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
227
228 mutex_lock(&dd->sysfs_lock);
229 dd->interrupt_count = 0;
230 mutex_unlock(&dd->sysfs_lock);
231 return size;
232}
233
234static DEVICE_ATTR(int_count, S_IRUSR | S_IWUSR,
235 cyttsp5_interrupt_count_show, cyttsp5_interrupt_count_store);
236
237static ssize_t cyttsp5_formated_output_show(struct device *dev,
238 struct device_attribute *attr, char *buf)
239{
240 struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
241 int val;
242
243 mutex_lock(&dd->sysfs_lock);
244 val = dd->formated_output;
245 mutex_unlock(&dd->sysfs_lock);
246
247 return scnprintf(buf, CY_MAX_PRBUF_SIZE,
248 "Formated debug output: %x\n", val);
249}
250
251static ssize_t cyttsp5_formated_output_store(struct device *dev,
252 struct device_attribute *attr, const char *buf, size_t size)
253{
254 struct cyttsp5_debug_data *dd = cyttsp5_get_debug_data(dev);
255 unsigned long value;
256 int rc;
257
258 rc = kstrtoul(buf, 10, &value);
259 if (rc < 0) {
260 dev_err(dev, "%s: Invalid value\n", __func__);
261 return size;
262 }
263
264 /* Expecting only 0 or 1 */
265 if (value != 0 && value != 1) {
266 dev_err(dev, "%s: Invalid value %lu\n", __func__, value);
267 return size;
268 }
269
270 mutex_lock(&dd->sysfs_lock);
271 dd->formated_output = value;
272 mutex_unlock(&dd->sysfs_lock);
273 return size;
274}
275
276static DEVICE_ATTR(formated_output, S_IRUSR | S_IWUSR,
277 cyttsp5_formated_output_show, cyttsp5_formated_output_store);
278
279static int cyttsp5_debug_probe(struct device *dev, void **data)
280{
281 struct cyttsp5_debug_data *dd;
282 int rc;
283
284 /* get context and debug print buffers */
285 dd = kzalloc(sizeof(*dd), GFP_KERNEL);
286 if (!dd) {
287 rc = -ENOMEM;
288 goto cyttsp5_debug_probe_alloc_failed;
289 }
290
291 rc = device_create_file(dev, &dev_attr_int_count);
292 if (rc) {
293 dev_err(dev, "%s: Error, could not create int_count\n",
294 __func__);
295 goto cyttsp5_debug_probe_create_int_count_failed;
296 }
297
298 rc = device_create_file(dev, &dev_attr_formated_output);
299 if (rc) {
300 dev_err(dev, "%s: Error, could not create formated_output\n",
301 __func__);
302 goto cyttsp5_debug_probe_create_formated_failed;
303 }
304
305 mutex_init(&dd->sysfs_lock);
306 dd->dev = dev;
307 *data = dd;
308
309 dd->si = cmd->request_sysinfo(dev);
310 if (!dd->si) {
311 dev_err(dev, "%s: Fail get sysinfo pointer from core\n",
312 __func__);
313 rc = -ENODEV;
314 goto cyttsp5_debug_probe_sysinfo_failed;
315 }
316
317 rc = cmd->subscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_DEBUG_NAME,
318 cyttsp5_debug_attention, CY_MODE_OPERATIONAL);
319 if (rc < 0) {
320 dev_err(dev, "%s: Error, could not subscribe attention cb\n",
321 __func__);
322 goto cyttsp5_debug_probe_subscribe_failed;
323 }
324
325 return 0;
326
327cyttsp5_debug_probe_subscribe_failed:
328cyttsp5_debug_probe_sysinfo_failed:
329 device_remove_file(dev, &dev_attr_formated_output);
330cyttsp5_debug_probe_create_formated_failed:
331 device_remove_file(dev, &dev_attr_int_count);
332cyttsp5_debug_probe_create_int_count_failed:
333 kfree(dd);
334cyttsp5_debug_probe_alloc_failed:
335 dev_err(dev, "%s failed.\n", __func__);
336 return rc;
337}
338
339static void cyttsp5_debug_release(struct device *dev, void *data)
340{
341 struct cyttsp5_debug_data *dd = data;
342 int rc;
343
344 rc = cmd->unsubscribe_attention(dev, CY_ATTEN_IRQ, CYTTSP5_DEBUG_NAME,
345 cyttsp5_debug_attention, CY_MODE_OPERATIONAL);
346 if (rc < 0) {
347 dev_err(dev, "%s: Error, could not un-subscribe attention\n",
348 __func__);
349 goto cyttsp5_debug_release_exit;
350 }
351
352cyttsp5_debug_release_exit:
353 device_remove_file(dev, &dev_attr_formated_output);
354 device_remove_file(dev, &dev_attr_int_count);
355 kfree(dd);
356}
357
358static struct cyttsp5_module debug_module = {
359 .name = CYTTSP5_DEBUG_NAME,
360 .probe = cyttsp5_debug_probe,
361 .release = cyttsp5_debug_release,
362};
363
364static int __init cyttsp5_debug_init(void)
365{
366 int rc;
367
368 cmd = cyttsp5_get_commands();
369 if (!cmd)
370 return -EINVAL;
371
372 rc = cyttsp5_register_module(&debug_module);
373 if (rc < 0) {
374 pr_err("%s: Error, failed registering module\n",
375 __func__);
376 return rc;
377 }
378
379 pr_info("%s: Parade TTSP Debug Driver (Built %s) rc=%d\n",
380 __func__, CY_DRIVER_VERSION, rc);
381 return 0;
382}
383module_init(cyttsp5_debug_init);
384
385static void __exit cyttsp5_debug_exit(void)
386{
387 cyttsp5_unregister_module(&debug_module);
388}
389module_exit(cyttsp5_debug_exit);
390
391MODULE_LICENSE("GPL");
392MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Debug Driver");
393MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");