blob: aefce3ed89a35a5447ab23056dbf0196d2da68f1 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Source for:
2 * Cypress TrueTouch(TM) Standard Product I2C touchscreen driver.
3 * drivers/input/touchscreen/cyttsp-i2c.c
4 *
5 * Copyright (C) 2009, 2010 Cypress Semiconductor, Inc.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2, and only version 2, as published by the
10 * Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 * Cypress reserves the right to make changes without further notice
22 * to the materials described herein. Cypress does not assume any
23 * liability arising out of the application described herein.
24 *
25 * Contact Cypress Semiconductor at www.cypress.com
26 *
27 */
28
29#include <linux/delay.h>
30#include <linux/init.h>
31#include <linux/module.h>
32#include <linux/i2c.h>
33#include <linux/input.h>
34#include <linux/slab.h>
35#include <linux/gpio.h>
36#include <linux/irq.h>
37#include <linux/interrupt.h>
38#include <linux/timer.h>
39#include <linux/workqueue.h>
40#include <linux/byteorder/generic.h>
41#include <linux/bitops.h>
42#include <linux/pm_runtime.h>
43#include <linux/firmware.h>
44#include <linux/mutex.h>
45#include <linux/regulator/consumer.h>
46#ifdef CONFIG_HAS_EARLYSUSPEND
47#include <linux/earlysuspend.h>
48#endif /* CONFIG_HAS_EARLYSUSPEND */
49
50#define CY_DECLARE_GLOBALS
51
52#include <linux/cyttsp.h>
53
54uint32_t cyttsp_tsdebug1 = 0xff;
55module_param_named(tsdebug1, cyttsp_tsdebug1, uint, 0664);
56
57#define FW_FNAME_LEN 40
Mohan Pallaka9c050f12011-09-29 18:17:35 +053058#define TTSP_BUFF_SIZE 50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059
60/* CY TTSP I2C Driver private data */
61struct cyttsp {
62 struct i2c_client *client;
63 struct input_dev *input;
64 struct work_struct work;
65 struct timer_list timer;
66 struct mutex mutex;
67 char phys[32];
68 struct cyttsp_platform_data *platform_data;
69 u8 num_prv_st_tch;
Amy Malocheedd5fd72011-06-22 18:50:21 -070070 u16 fw_start_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071 u16 act_trk[CY_NUM_TRK_ID];
72 u16 prv_st_tch[CY_NUM_ST_TCH_ID];
73 u16 prv_mt_tch[CY_NUM_MT_TCH_ID];
74 u16 prv_mt_pos[CY_NUM_TRK_ID][2];
75 atomic_t irq_enabled;
76 bool cyttsp_update_fw;
77 bool cyttsp_fwloader_mode;
78 bool is_suspended;
79 struct regulator **vdd;
80 char fw_fname[FW_FNAME_LEN];
81#ifdef CONFIG_HAS_EARLYSUSPEND
82 struct early_suspend early_suspend;
83#endif /* CONFIG_HAS_EARLYSUSPEND */
84};
85static u8 irq_cnt; /* comparison counter with register valuw */
86static u32 irq_cnt_total; /* total interrupts */
87static u32 irq_err_cnt; /* count number of touch interrupts with err */
88#define CY_IRQ_CNT_MASK 0x000000FF /* mapped for sizeof count in reg */
89#define CY_IRQ_CNT_REG 0x00 /* tt_undef[0]=reg 0x1B - Gen3 only */
90
91#ifdef CONFIG_HAS_EARLYSUSPEND
92static void cyttsp_early_suspend(struct early_suspend *handler);
93static void cyttsp_late_resume(struct early_suspend *handler);
94#endif /* CONFIG_HAS_EARLYSUSPEND */
95
96static struct workqueue_struct *cyttsp_ts_wq;
97
98
99/* ****************************************************************************
100 * Prototypes for static functions
101 * ************************************************************************** */
102static void cyttsp_xy_worker(struct work_struct *work);
103static irqreturn_t cyttsp_irq(int irq, void *handle);
104static int cyttsp_inlist(u16 prev_track[],
105 u8 cur_trk_id, u8 *prev_loc, u8 num_touches);
106static int cyttsp_next_avail_inlist(u16 cur_trk[],
107 u8 *new_loc, u8 num_touches);
108static int cyttsp_putbl(struct cyttsp *ts, int show,
109 int show_status, int show_version, int show_cid);
110static int __devinit cyttsp_probe(struct i2c_client *client,
111 const struct i2c_device_id *id);
112static int __devexit cyttsp_remove(struct i2c_client *client);
113static int cyttsp_resume(struct device *dev);
114static int cyttsp_suspend(struct device *dev);
115
116/* Static variables */
117static struct cyttsp_gen3_xydata_t g_xy_data;
118static struct cyttsp_bootloader_data_t g_bl_data;
119static struct cyttsp_sysinfo_data_t g_sysinfo_data;
120static const struct i2c_device_id cyttsp_id[] = {
121 { CY_I2C_NAME, 0 }, { }
122};
123static u8 bl_cmd[] = {
124 CY_BL_FILE0, CY_BL_CMD, CY_BL_EXIT,
125 CY_BL_KEY0, CY_BL_KEY1, CY_BL_KEY2,
126 CY_BL_KEY3, CY_BL_KEY4, CY_BL_KEY5,
127 CY_BL_KEY6, CY_BL_KEY7};
128
129MODULE_DEVICE_TABLE(i2c, cyttsp_id);
130
Anirudh Ghayal84e51192011-09-03 08:05:25 +0530131#ifdef CONFIG_PM
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132static const struct dev_pm_ops cyttsp_pm_ops = {
Anirudh Ghayal84e51192011-09-03 08:05:25 +0530133#ifndef CONFIG_HAS_EARLYSUSPEND
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134 .suspend = cyttsp_suspend,
135 .resume = cyttsp_resume,
Anirudh Ghayal84e51192011-09-03 08:05:25 +0530136#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137};
Anirudh Ghayal84e51192011-09-03 08:05:25 +0530138#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139
140static struct i2c_driver cyttsp_driver = {
141 .driver = {
142 .name = CY_I2C_NAME,
143 .owner = THIS_MODULE,
Anirudh Ghayal84e51192011-09-03 08:05:25 +0530144#ifdef CONFIG_PM
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 .pm = &cyttsp_pm_ops,
Anirudh Ghayal84e51192011-09-03 08:05:25 +0530146#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147 },
148 .probe = cyttsp_probe,
149 .remove = __devexit_p(cyttsp_remove),
150 .id_table = cyttsp_id,
151};
152
153MODULE_LICENSE("GPL");
154MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen driver");
155MODULE_AUTHOR("Cypress");
156
157static ssize_t cyttsp_irq_status(struct device *dev,
158 struct device_attribute *attr, char *buf)
159{
160 struct i2c_client *client = container_of(dev, struct i2c_client, dev);
161 struct cyttsp *ts = i2c_get_clientdata(client);
Mohan Pallaka9c050f12011-09-29 18:17:35 +0530162 return snprintf(buf, TTSP_BUFF_SIZE, "%u\n",
163 atomic_read(&ts->irq_enabled));
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164}
165
166static ssize_t cyttsp_irq_enable(struct device *dev,
167 struct device_attribute *attr,
168 const char *buf, size_t size)
169{
170 struct i2c_client *client = container_of(dev, struct i2c_client, dev);
171 struct cyttsp *ts = i2c_get_clientdata(client);
172 int err = 0;
173 unsigned long value;
174
175 if (size > 2)
176 return -EINVAL;
177
178 err = strict_strtoul(buf, 10, &value);
179 if (err != 0)
180 return err;
181
182 switch (value) {
183 case 0:
184 if (atomic_cmpxchg(&ts->irq_enabled, 1, 0)) {
185 pr_info("touch irq disabled!\n");
186 disable_irq_nosync(ts->client->irq);
187 }
188 err = size;
189 break;
190 case 1:
191 if (!atomic_cmpxchg(&ts->irq_enabled, 0, 1)) {
192 pr_info("touch irq enabled!\n");
193 enable_irq(ts->client->irq);
194 }
195 err = size;
196 break;
197 default:
198 pr_info("cyttsp_irq_enable failed -> irq_enabled = %d\n",
199 atomic_read(&ts->irq_enabled));
200 err = -EINVAL;
201 break;
202 }
203
204 return err;
205}
206
Praveena Pachipulusu8b621e42011-08-10 18:17:07 +0530207static DEVICE_ATTR(irq_enable, 0664, cyttsp_irq_status, cyttsp_irq_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208
209static ssize_t cyttsp_fw_show(struct device *dev,
210 struct device_attribute *attr, char *buf)
211{
Mohan Pallaka9c050f12011-09-29 18:17:35 +0530212 return snprintf(buf, TTSP_BUFF_SIZE, "%d.%d.%d\n", g_bl_data.appid_lo,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 g_bl_data.appver_hi, g_bl_data.appver_lo);
214}
215
Praveena Pachipulusu8b621e42011-08-10 18:17:07 +0530216static DEVICE_ATTR(cyttsp_fw_ver, 0664, cyttsp_fw_show, NULL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700217
218/* firmware flashing block */
219#define BLK_SIZE 16
220#define DATA_REC_LEN 64
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700221#define BLK_SEED 0xff
222#define RECAL_REG 0x1b
223
224enum bl_commands {
225 BL_CMD_WRBLK = 0x39,
226 BL_CMD_INIT = 0x38,
227 BL_CMD_TERMINATE = 0x3b,
228};
229/* TODO: Add key as part of platform data */
230#define KEY_CS (0 + 1 + 2 + 3 + 4 + 5 + 6 + 7)
231#define KEY {0, 1, 2, 3, 4, 5, 6, 7}
232
233static const char _key[] = KEY;
234#define KEY_LEN sizeof(_key)
235
236static int rec_cnt;
237struct fw_record {
238 u8 seed;
239 u8 cmd;
240 u8 key[KEY_LEN];
241 u8 blk_hi;
242 u8 blk_lo;
243 u8 data[DATA_REC_LEN];
244 u8 data_cs;
245 u8 rec_cs;
246};
247#define fw_rec_size (sizeof(struct fw_record))
248
249struct cmd_record {
250 u8 reg;
251 u8 seed;
252 u8 cmd;
253 u8 key[KEY_LEN];
254};
255#define cmd_rec_size (sizeof(struct cmd_record))
256
257static struct fw_record data_record = {
258 .seed = BLK_SEED,
259 .cmd = BL_CMD_WRBLK,
260 .key = KEY,
261};
262
263static const struct cmd_record terminate_rec = {
264 .reg = 0,
265 .seed = BLK_SEED,
266 .cmd = BL_CMD_TERMINATE,
267 .key = KEY,
268};
269static const struct cmd_record initiate_rec = {
270 .reg = 0,
271 .seed = BLK_SEED,
272 .cmd = BL_CMD_INIT,
273 .key = KEY,
274};
275
276#define BL_REC1_ADDR 0x0780
277#define BL_REC2_ADDR 0x07c0
Mohan Pallaka1cef4a02011-08-01 11:48:42 +0530278#define BL_CHECKSUM_MASK 0x01
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279
280#define ID_INFO_REC ":40078000"
281#define ID_INFO_OFFSET_IN_REC 77
282
283#define REC_START_CHR ':'
284#define REC_LEN_OFFSET 1
285#define REC_ADDR_HI_OFFSET 3
286#define REC_ADDR_LO_OFFSET 5
287#define REC_TYPE_OFFSET 7
288#define REC_DATA_OFFSET 9
289#define REC_LINE_SIZE 141
290
Mohan Pallaka04b7f792011-09-29 18:17:35 +0530291#define NUM_CHAR_IN_HEX 2
292#define ID_INFO_REC_LEN 9
293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294static int cyttsp_soft_reset(struct cyttsp *ts)
295{
296 int retval = 0, tries = 0;
297 u8 host_reg = CY_SOFT_RESET_MODE;
298
299 do {
300 retval = i2c_smbus_write_i2c_block_data(ts->client,
301 CY_REG_BASE, sizeof(host_reg), &host_reg);
302 if (retval < 0)
303 msleep(20);
304 } while (tries++ < 10 && (retval < 0));
305
306 if (retval < 0) {
307 pr_err("%s: failed\n", __func__);
308 return retval;
309 }
310
311 tries = 0;
312 do {
313 msleep(20);
314 cyttsp_putbl(ts, 1, true, true, false);
315 } while (g_bl_data.bl_status != 0x10 &&
316 g_bl_data.bl_status != 0x11 &&
317 tries++ < 100);
318
319 if (g_bl_data.bl_status != 0x11 && g_bl_data.bl_status != 0x10)
320 return -EINVAL;
321
322 return 0;
323}
324
325static void cyttsp_exit_bl_mode(struct cyttsp *ts)
326{
327 int retval, tries = 0;
328
329 do {
330 retval = i2c_smbus_write_i2c_block_data(ts->client,
331 CY_REG_BASE, sizeof(bl_cmd), bl_cmd);
332 if (retval < 0)
333 msleep(20);
334 } while (tries++ < 10 && (retval < 0));
335}
336
337static void cyttsp_set_sysinfo_mode(struct cyttsp *ts)
338{
339 int retval, tries = 0;
340 u8 host_reg = CY_SYSINFO_MODE;
341
342 do {
343 retval = i2c_smbus_write_i2c_block_data(ts->client,
344 CY_REG_BASE, sizeof(host_reg), &host_reg);
345 if (retval < 0)
346 msleep(20);
347 } while (tries++ < 10 && (retval < 0));
348
349 /* wait for TTSP Device to complete switch to SysInfo mode */
350 if (!(retval < 0)) {
351 retval = i2c_smbus_read_i2c_block_data(ts->client,
352 CY_REG_BASE,
353 sizeof(struct cyttsp_sysinfo_data_t),
354 (u8 *)&g_sysinfo_data);
355 } else
356 pr_err("%s: failed\n", __func__);
357}
358
359static void cyttsp_set_opmode(struct cyttsp *ts)
360{
361 int retval, tries = 0;
362 u8 host_reg = CY_OP_MODE;
363
364 do {
365 retval = i2c_smbus_write_i2c_block_data(ts->client,
366 CY_REG_BASE, sizeof(host_reg), &host_reg);
367 if (retval < 0)
368 msleep(20);
369 } while (tries++ < 10 && (retval < 0));
370}
371
372static int str2uc(char *str, u8 *val)
373{
374 char substr[3];
375 unsigned long ulval;
376 int rc;
377
Mohan Pallaka04b7f792011-09-29 18:17:35 +0530378 if (!str)
379 return -EINVAL;
380
381 if (strnlen(str, NUM_CHAR_IN_HEX) < 2)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 return -EINVAL;
383
384 substr[0] = str[0];
385 substr[1] = str[1];
386 substr[2] = '\0';
387
388 rc = strict_strtoul(substr, 16, &ulval);
389 if (rc != 0)
390 return rc;
391
392 *val = (u8) ulval;
393
394 return 0;
395}
396
397static int flash_block(struct cyttsp *ts, u8 *blk, int len)
398{
399 int retval, i, tries = 0;
400 char buf[(2 * (BLK_SIZE + 1)) + 1];
401 char *p = buf;
402
403 for (i = 0; i < len; i++, p += 2)
Mohan Pallaka9c050f12011-09-29 18:17:35 +0530404 snprintf(p, TTSP_BUFF_SIZE, "%02x", blk[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 pr_debug("%s: size %d, pos %ld payload %s\n",
406 __func__, len, (long)0, buf);
407
408 do {
409 retval = i2c_smbus_write_i2c_block_data(ts->client,
410 CY_REG_BASE, len, blk);
411 if (retval < 0)
412 msleep(20);
413 } while (tries++ < 20 && (retval < 0));
414
415 if (retval < 0) {
416 pr_err("%s: failed\n", __func__);
417 return retval;
418 }
419
420 return 0;
421}
422
423static int flash_command(struct cyttsp *ts, const struct cmd_record *record)
424{
425 return flash_block(ts, (u8 *)record, cmd_rec_size);
426}
427
428static void init_data_record(struct fw_record *rec, unsigned short addr)
429{
430 addr >>= 6;
431 rec->blk_hi = (addr >> 8) & 0xff;
432 rec->blk_lo = addr & 0xff;
433 rec->rec_cs = rec->blk_hi + rec->blk_lo +
434 (unsigned char)(BLK_SEED + BL_CMD_WRBLK + KEY_CS);
435 rec->data_cs = 0;
436}
437
Amy Malocheedd5fd72011-06-22 18:50:21 -0700438static int check_record(struct cyttsp *ts, u8 *rec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700439{
440 int rc;
441 u16 addr;
442 u8 r_len, type, hi_off, lo_off;
443
444 rc = str2uc(rec + REC_LEN_OFFSET, &r_len);
445 if (rc < 0)
446 return rc;
447
448 rc = str2uc(rec + REC_TYPE_OFFSET, &type);
449 if (rc < 0)
450 return rc;
451
452 if (*rec != REC_START_CHR || r_len != DATA_REC_LEN || type != 0)
453 return -EINVAL;
454
455 rc = str2uc(rec + REC_ADDR_HI_OFFSET, &hi_off);
456 if (rc < 0)
457 return rc;
458
459 rc = str2uc(rec + REC_ADDR_LO_OFFSET, &lo_off);
460 if (rc < 0)
461 return rc;
462
463 addr = (hi_off << 8) | lo_off;
464
Amy Malocheedd5fd72011-06-22 18:50:21 -0700465 if (addr >= ts->fw_start_addr || addr == BL_REC1_ADDR
466 || addr == BL_REC2_ADDR)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 return 0;
468
469 return -EINVAL;
470}
471
472static struct fw_record *prepare_record(u8 *rec)
473{
474 int i, rc;
475 u16 addr;
476 u8 hi_off, lo_off;
477 u8 *p;
478
479 rc = str2uc(rec + REC_ADDR_HI_OFFSET, &hi_off);
480 if (rc < 0)
481 return ERR_PTR((long) rc);
482
483 rc = str2uc(rec + REC_ADDR_LO_OFFSET, &lo_off);
484 if (rc < 0)
485 return ERR_PTR((long) rc);
486
487 addr = (hi_off << 8) | lo_off;
488
489 init_data_record(&data_record, addr);
490 p = rec + REC_DATA_OFFSET;
491 for (i = 0; i < DATA_REC_LEN; i++) {
492 rc = str2uc(p, &data_record.data[i]);
493 if (rc < 0)
494 return ERR_PTR((long) rc);
495 data_record.data_cs += data_record.data[i];
496 data_record.rec_cs += data_record.data[i];
497 p += 2;
498 }
499 data_record.rec_cs += data_record.data_cs;
500
501 return &data_record;
502}
503
504static int flash_record(struct cyttsp *ts, const struct fw_record *record)
505{
506 int len = fw_rec_size;
507 int blk_len, rc;
508 u8 *rec = (u8 *)record;
509 u8 data[BLK_SIZE + 1];
510 u8 blk_offset;
511
512 for (blk_offset = 0; len; len -= blk_len) {
513 data[0] = blk_offset;
514 blk_len = len > BLK_SIZE ? BLK_SIZE : len;
515 memcpy(data + 1, rec, blk_len);
516 rec += blk_len;
517 rc = flash_block(ts, data, blk_len + 1);
518 if (rc < 0)
519 return rc;
520 blk_offset += blk_len;
521 }
522 return 0;
523}
524
525static int flash_data_rec(struct cyttsp *ts, u8 *buf)
526{
527 struct fw_record *rec;
528 int rc, tries;
529
530 if (!buf)
531 return -EINVAL;
532
Amy Malocheedd5fd72011-06-22 18:50:21 -0700533 rc = check_record(ts, buf);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534
535 if (rc < 0) {
536 pr_debug("%s: record ignored %s", __func__, buf);
537 return 0;
538 }
539
540 rec = prepare_record(buf);
541 if (IS_ERR_OR_NULL(rec))
542 return PTR_ERR(rec);
543
544 rc = flash_record(ts, rec);
545 if (rc < 0)
546 return rc;
547
548 tries = 0;
549 do {
550 if (rec_cnt%2)
551 msleep(20);
552 cyttsp_putbl(ts, 4, true, false, false);
553 } while (g_bl_data.bl_status != 0x10 &&
554 g_bl_data.bl_status != 0x11 &&
555 tries++ < 100);
556 rec_cnt++;
557 return rc;
558}
559
560static int cyttspfw_flash_firmware(struct cyttsp *ts, const u8 *data,
561 int data_len)
562{
563 u8 *buf;
564 int i, j;
565 int rc, tries = 0;
566
567 /* initiate bootload: this will erase all the existing data */
568 rc = flash_command(ts, &initiate_rec);
569 if (rc < 0)
570 return rc;
571
572 do {
573 msleep(100);
574 cyttsp_putbl(ts, 4, true, false, false);
575 } while (g_bl_data.bl_status != 0x10 &&
576 g_bl_data.bl_status != 0x11 &&
577 tries++ < 100);
578
579 buf = kzalloc(REC_LINE_SIZE + 1, GFP_KERNEL);
580 if (!buf) {
581 pr_err("%s: no memory\n", __func__);
582 return -ENOMEM;
583 }
584
585 rec_cnt = 0;
586 /* flash data records */
587 for (i = 0, j = 0; i < data_len; i++, j++) {
588 if ((data[i] == REC_START_CHR) && j) {
589 buf[j] = 0;
590 rc = flash_data_rec(ts, buf);
591 if (rc < 0)
592 return rc;
593 j = 0;
594 }
595 buf[j] = data[i];
596 }
597
598 /* flash last data record */
599 if (j) {
600 buf[j] = 0;
601 rc = flash_data_rec(ts, buf);
602 if (rc < 0)
603 return rc;
604 }
605
606 kfree(buf);
607
608 /* termiate bootload */
609 tries = 0;
610 rc = flash_command(ts, &terminate_rec);
611 do {
612 msleep(100);
613 cyttsp_putbl(ts, 4, true, false, false);
614 } while (g_bl_data.bl_status != 0x10 &&
615 g_bl_data.bl_status != 0x11 &&
616 tries++ < 100);
617
618 return rc;
619}
620
621static int get_hex_fw_ver(u8 *p, u8 *ttspver_hi, u8 *ttspver_lo,
622 u8 *appid_hi, u8 *appid_lo, u8 *appver_hi,
623 u8 *appver_lo, u8 *cid_0, u8 *cid_1, u8 *cid_2)
624{
625 int rc;
626
627 p = p + ID_INFO_OFFSET_IN_REC;
628 rc = str2uc(p, ttspver_hi);
629 if (rc < 0)
630 return rc;
631 p += 2;
632 rc = str2uc(p, ttspver_lo);
633 if (rc < 0)
634 return rc;
635 p += 2;
636 rc = str2uc(p, appid_hi);
637 if (rc < 0)
638 return rc;
639 p += 2;
640 rc = str2uc(p, appid_lo);
641 if (rc < 0)
642 return rc;
643 p += 2;
644 rc = str2uc(p, appver_hi);
645 if (rc < 0)
646 return rc;
647 p += 2;
648 rc = str2uc(p, appver_lo);
649 if (rc < 0)
650 return rc;
651 p += 2;
652 rc = str2uc(p, cid_0);
653 if (rc < 0)
654 return rc;
655 p += 2;
656 rc = str2uc(p, cid_1);
657 if (rc < 0)
658 return rc;
659 p += 2;
660 rc = str2uc(p, cid_2);
661 if (rc < 0)
662 return rc;
663
664 return 0;
665}
666
667static void cyttspfw_flash_start(struct cyttsp *ts, const u8 *data,
668 int data_len, u8 *buf, bool force)
669{
670 int rc;
671 u8 ttspver_hi = 0, ttspver_lo = 0, fw_upgrade = 0;
672 u8 appid_hi = 0, appid_lo = 0;
673 u8 appver_hi = 0, appver_lo = 0;
674 u8 cid_0 = 0, cid_1 = 0, cid_2 = 0;
675 char *p = buf;
676
677 /* get hex firmware version */
678 rc = get_hex_fw_ver(p, &ttspver_hi, &ttspver_lo,
679 &appid_hi, &appid_lo, &appver_hi,
680 &appver_lo, &cid_0, &cid_1, &cid_2);
681
682 if (rc < 0) {
683 pr_err("%s: unable to get hex firmware version\n", __func__);
684 return;
685 }
686
687 /* disable interrupts before flashing */
688 if (ts->client->irq == 0)
689 del_timer(&ts->timer);
690 else
691 disable_irq(ts->client->irq);
692
693 rc = cancel_work_sync(&ts->work);
694
695 if (rc && ts->client->irq)
696 enable_irq(ts->client->irq);
697
698 /* enter bootloader idle mode */
699 rc = cyttsp_soft_reset(ts);
700
701 if (rc < 0) {
702 pr_err("%s: try entering into idle mode"
703 " second time\n", __func__);
704 msleep(1000);
705 rc = cyttsp_soft_reset(ts);
706 }
707
708 if (rc < 0) {
709 pr_err("%s: try again later\n", __func__);
710 return;
711 }
712
713
714 pr_info("Current firmware: %d.%d.%d", g_bl_data.appid_lo,
715 g_bl_data.appver_hi, g_bl_data.appver_lo);
716 pr_info("New firmware: %d.%d.%d", appid_lo, appver_hi, appver_lo);
717
718 if (force)
719 fw_upgrade = 1;
Mohan Pallaka1cef4a02011-08-01 11:48:42 +0530720 else if (!(g_bl_data.bl_status & BL_CHECKSUM_MASK) &&
721 (appid_lo == ts->platform_data->correct_fw_ver))
722 fw_upgrade = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 else
724 if ((appid_hi == g_bl_data.appid_hi) &&
725 (appid_lo == g_bl_data.appid_lo)) {
726 if (appver_hi > g_bl_data.appver_hi) {
727 fw_upgrade = 1;
728 } else if ((appver_hi == g_bl_data.appver_hi) &&
729 (appver_lo > g_bl_data.appver_lo)) {
730 fw_upgrade = 1;
731 } else {
732 fw_upgrade = 0;
733 pr_info("%s: Firmware version "
734 "lesser/equal to existing firmware, "
735 "upgrade not needed\n", __func__);
736 }
737 } else {
738 fw_upgrade = 0;
739 pr_info("%s: Firware versions do not match, "
740 "cannot upgrade\n", __func__);
741 }
742
743 if (fw_upgrade) {
744 pr_info("%s: Starting firmware upgrade\n", __func__);
745 rc = cyttspfw_flash_firmware(ts, data, data_len);
746 if (rc < 0)
747 pr_err("%s: firmware upgrade failed\n", __func__);
748 else
749 pr_info("%s: firmware upgrade success\n", __func__);
750 }
751
752 /* enter bootloader idle mode */
753 cyttsp_soft_reset(ts);
754 /* exit bootloader mode */
755 cyttsp_exit_bl_mode(ts);
756 msleep(100);
757 /* set sysinfo details */
758 cyttsp_set_sysinfo_mode(ts);
759 /* enter application mode */
760 cyttsp_set_opmode(ts);
761
762 /* enable interrupts */
763 if (ts->client->irq == 0)
764 mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
765 else
766 enable_irq(ts->client->irq);
767}
768
769static void cyttspfw_upgrade_start(struct cyttsp *ts, const u8 *data,
770 int data_len, bool force)
771{
772 int i, j;
773 u8 *buf;
774
775 buf = kzalloc(REC_LINE_SIZE + 1, GFP_KERNEL);
776 if (!buf) {
777 pr_err("%s: no memory\n", __func__);
778 return;
779 }
780
781 for (i = 0, j = 0; i < data_len; i++, j++) {
782 if ((data[i] == REC_START_CHR) && j) {
783 buf[j] = 0;
784 j = 0;
Mohan Pallaka04b7f792011-09-29 18:17:35 +0530785 if (!strncmp(buf, ID_INFO_REC,
786 strnlen(ID_INFO_REC, ID_INFO_REC_LEN))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 cyttspfw_flash_start(ts, data, data_len,
788 buf, force);
789 break;
790 }
791 }
792 buf[j] = data[i];
793 }
794
795 /* check in the last record of firmware */
796 if (j) {
797 buf[j] = 0;
Mohan Pallaka04b7f792011-09-29 18:17:35 +0530798 if (!strncmp(buf, ID_INFO_REC,
799 strnlen(ID_INFO_REC, ID_INFO_REC_LEN))) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800 cyttspfw_flash_start(ts, data, data_len,
801 buf, force);
802 }
803 }
804
805 kfree(buf);
806}
807
808static void cyttspfw_upgrade(struct device *dev, bool force)
809{
810 struct cyttsp *ts = dev_get_drvdata(dev);
811 const struct firmware *cyttsp_fw;
812 int retval = 0;
813
814 if (ts->is_suspended == true) {
815 pr_err("%s: in suspend state, resume it\n", __func__);
816 retval = cyttsp_resume(dev);
817 if (retval < 0) {
818 pr_err("%s: unable to resume\n", __func__);
819 return;
820 }
821 }
822
823 retval = request_firmware(&cyttsp_fw, ts->fw_fname, dev);
824 if (retval < 0) {
825 pr_err("%s: %s request failed(%d)\n", __func__,
826 ts->fw_fname, retval);
827 } else {
828 /* check and start upgrade */
829 cyttspfw_upgrade_start(ts, cyttsp_fw->data,
830 cyttsp_fw->size, force);
831 release_firmware(cyttsp_fw);
832 }
833}
834
835static ssize_t cyttsp_update_fw_show(struct device *dev,
836 struct device_attribute *attr, char *buf)
837{
838 struct cyttsp *ts = dev_get_drvdata(dev);
839 return snprintf(buf, 2, "%d\n", ts->cyttsp_fwloader_mode);
840}
841
842static ssize_t cyttsp_force_update_fw_store(struct device *dev,
843 struct device_attribute *attr,
844 const char *buf, size_t size)
845{
846 struct cyttsp *ts = dev_get_drvdata(dev);
847 unsigned long val;
848 int rc;
849
850 if (size > 2)
851 return -EINVAL;
852
853 rc = strict_strtoul(buf, 10, &val);
854 if (rc != 0)
855 return rc;
856
857 mutex_lock(&ts->mutex);
858 if (!ts->cyttsp_fwloader_mode && val) {
859 ts->cyttsp_fwloader_mode = 1;
860 cyttspfw_upgrade(dev, true);
861 ts->cyttsp_fwloader_mode = 0;
862 }
863 mutex_unlock(&ts->mutex);
864 return size;
865}
866
Praveena Pachipulusu8b621e42011-08-10 18:17:07 +0530867static DEVICE_ATTR(cyttsp_force_update_fw, 0664, cyttsp_update_fw_show,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700868 cyttsp_force_update_fw_store);
869
870static ssize_t cyttsp_update_fw_store(struct device *dev,
871 struct device_attribute *attr,
872 const char *buf, size_t size)
873{
874 struct cyttsp *ts = dev_get_drvdata(dev);
875 unsigned long val;
876 int rc;
877
878 if (size > 2)
879 return -EINVAL;
880
881 rc = strict_strtoul(buf, 10, &val);
882 if (rc != 0)
883 return rc;
884
885 mutex_lock(&ts->mutex);
886 if (!ts->cyttsp_fwloader_mode && val) {
887 ts->cyttsp_fwloader_mode = 1;
888 cyttspfw_upgrade(dev, false);
889 ts->cyttsp_fwloader_mode = 0;
890 }
891 mutex_unlock(&ts->mutex);
892
893 return size;
894}
895
Praveena Pachipulusu8b621e42011-08-10 18:17:07 +0530896static DEVICE_ATTR(cyttsp_update_fw, 0664, cyttsp_update_fw_show,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 cyttsp_update_fw_store);
898
899static ssize_t cyttsp_fw_name_show(struct device *dev,
900 struct device_attribute *attr, char *buf)
901{
902 struct cyttsp *ts = dev_get_drvdata(dev);
903 return snprintf(buf, FW_FNAME_LEN - 1, "%s\n", ts->fw_fname);
904}
905
906static ssize_t cyttsp_fw_name_store(struct device *dev,
907 struct device_attribute *attr,
908 const char *buf, size_t size)
909{
910 struct cyttsp *ts = dev_get_drvdata(dev);
911
912 if (size > FW_FNAME_LEN - 1)
913 return -EINVAL;
914
Mohan Pallaka9c050f12011-09-29 18:17:35 +0530915 strlcpy(ts->fw_fname, buf, size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 if (ts->fw_fname[size-1] == '\n')
917 ts->fw_fname[size-1] = 0;
918
919 return size;
920}
921
Praveena Pachipulusu8b621e42011-08-10 18:17:07 +0530922static DEVICE_ATTR(cyttsp_fw_name, 0664, cyttsp_fw_name_show,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 cyttsp_fw_name_store);
924
925/* The cyttsp_xy_worker function reads the XY coordinates and sends them to
926 * the input layer. It is scheduled from the interrupt (or timer).
927 */
928void cyttsp_xy_worker(struct work_struct *work)
929{
930 struct cyttsp *ts = container_of(work, struct cyttsp, work);
931 u8 id, tilt, rev_x, rev_y;
932 u8 i, loc;
933 u8 prv_tch; /* number of previous touches */
934 u8 cur_tch; /* number of current touches */
935 u16 tmp_trk[CY_NUM_MT_TCH_ID];
936 u16 snd_trk[CY_NUM_MT_TCH_ID];
937 u16 cur_trk[CY_NUM_TRK_ID];
938 u16 cur_st_tch[CY_NUM_ST_TCH_ID];
939 u16 cur_mt_tch[CY_NUM_MT_TCH_ID];
940 /* if NOT CY_USE_TRACKING_ID then
941 * only uses CY_NUM_MT_TCH_ID positions */
942 u16 cur_mt_pos[CY_NUM_TRK_ID][2];
943 /* if NOT CY_USE_TRACKING_ID then
944 * only uses CY_NUM_MT_TCH_ID positions */
945 u8 cur_mt_z[CY_NUM_TRK_ID];
946 u8 curr_tool_width;
947 u16 st_x1, st_y1;
948 u8 st_z1;
949 u16 st_x2, st_y2;
950 u8 st_z2;
951 s32 retval;
952
953 cyttsp_xdebug("TTSP worker start 1:\n");
954
955 /* get event data from CYTTSP device */
956 i = CY_NUM_RETRY;
957 do {
958 retval = i2c_smbus_read_i2c_block_data(ts->client,
959 CY_REG_BASE,
960 sizeof(struct cyttsp_gen3_xydata_t), (u8 *)&g_xy_data);
961 } while ((retval < CY_OK) && --i);
962
963 if (retval < CY_OK) {
964 /* return immediately on
965 * failure to read device on the i2c bus */
966 goto exit_xy_worker;
967 }
968
969 cyttsp_xdebug("TTSP worker start 2:\n");
970
971 /* compare own irq counter with the device irq counter */
972 if (ts->client->irq) {
973 u8 host_reg;
974 u8 cur_cnt;
975 if (ts->platform_data->use_hndshk) {
976
977 host_reg = g_xy_data.hst_mode & CY_HNDSHK_BIT ?
978 g_xy_data.hst_mode & ~CY_HNDSHK_BIT :
979 g_xy_data.hst_mode | CY_HNDSHK_BIT;
980 retval = i2c_smbus_write_i2c_block_data(ts->client,
981 CY_REG_BASE, sizeof(host_reg), &host_reg);
982 }
983 cur_cnt = g_xy_data.tt_undef[CY_IRQ_CNT_REG];
984 irq_cnt_total++;
985 irq_cnt++;
986 if (irq_cnt != cur_cnt) {
987 irq_err_cnt++;
988 cyttsp_debug("i_c_ER: dv=%d fw=%d hm=%02X t=%lu te=%lu\n", \
989 irq_cnt, \
990 cur_cnt, g_xy_data.hst_mode, \
991 (unsigned long)irq_cnt_total, \
992 (unsigned long)irq_err_cnt);
993 } else {
994 cyttsp_debug("i_c_ok: dv=%d fw=%d hm=%02X t=%lu te=%lu\n", \
995 irq_cnt, \
996 cur_cnt, g_xy_data.hst_mode, \
997 (unsigned long)irq_cnt_total, \
998 (unsigned long)irq_err_cnt);
999 }
1000 irq_cnt = cur_cnt;
1001 }
1002
1003 /* Get the current num touches and return if there are no touches */
1004 if ((GET_BOOTLOADERMODE(g_xy_data.tt_mode) == 1) ||
1005 (GET_HSTMODE(g_xy_data.hst_mode) != CY_OK)) {
1006 u8 host_reg, tries;
1007 /* the TTSP device has suffered spurious reset or mode switch */
1008 cyttsp_debug( \
1009 "Spurious err opmode (tt_mode=%02X hst_mode=%02X)\n", \
1010 g_xy_data.tt_mode, g_xy_data.hst_mode);
1011 cyttsp_debug("Reset TTSP Device; Terminating active tracks\n");
1012 /* terminate all active tracks */
1013 cur_tch = CY_NTCH;
1014 /* reset TTSP part and take it back out of Bootloader mode */
1015 /* reset TTSP Device back to bootloader mode */
1016 host_reg = CY_SOFT_RESET_MODE;
1017 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
1018 sizeof(host_reg), &host_reg);
1019 /* wait for TTSP Device to complete reset back to bootloader */
1020 tries = 0;
1021 do {
1022 mdelay(1);
1023 cyttsp_putbl(ts, 1, false, false, false);
1024 } while (g_bl_data.bl_status != 0x10 &&
1025 g_bl_data.bl_status != 0x11 &&
1026 tries++ < 100);
1027 retval = cyttsp_putbl(ts, 1, true, true, true);
1028 /* switch back to operational mode */
1029 /* take TTSP device out of bootloader mode;
1030 * switch back to TrueTouch operational mode */
1031 if (!(retval < CY_OK)) {
1032 int tries;
1033 retval = i2c_smbus_write_i2c_block_data(ts->client,
1034 CY_REG_BASE,
1035 sizeof(bl_cmd), bl_cmd);
1036 /* wait for TTSP Device to complete
1037 * switch to Operational mode */
1038 tries = 0;
1039 do {
1040 mdelay(100);
1041 cyttsp_putbl(ts, 2, false, false, false);
1042 } while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
1043 tries++ < 100);
1044 cyttsp_putbl(ts, 2, true, false, false);
1045 }
1046 goto exit_xy_worker;
1047 } else {
1048 cur_tch = GET_NUM_TOUCHES(g_xy_data.tt_stat);
1049 if (IS_LARGE_AREA(g_xy_data.tt_stat)) {
1050 /* terminate all active tracks */
1051 cur_tch = CY_NTCH;
1052 cyttsp_debug("Large obj detect (tt_stat=0x%02X). Terminate act trks\n", \
1053 g_xy_data.tt_stat);
1054 } else if (cur_tch > CY_NUM_MT_TCH_ID) {
1055 /* if the number of fingers on the touch surface
1056 * is more than the maximum then
1057 * there will be no new track information
1058 * even for the original touches.
1059 * Therefore, terminate all active tracks.
1060 */
1061 cur_tch = CY_NTCH;
1062 cyttsp_debug("Num touch err (tt_stat=0x%02X). Terminate act trks\n", \
1063 g_xy_data.tt_stat);
1064 }
1065 }
1066
1067 /* set tool size */
1068 curr_tool_width = CY_SMALL_TOOL_WIDTH;
1069
1070 /* translate Gen2 interface data into comparable Gen3 data */
1071 if (ts->platform_data->gen == CY_GEN2) {
1072 struct cyttsp_gen2_xydata_t *pxy_gen2_data;
1073 pxy_gen2_data = (struct cyttsp_gen2_xydata_t *)(&g_xy_data);
1074
1075 /* use test data? */
1076 cyttsp_testdat(&g_xy_data, &tt_gen2_testray, \
1077 sizeof(struct cyttsp_gen3_xydata_t));
1078
Mohan Pallaka727225f2011-08-18 11:09:49 +05301079 if (ts->platform_data->disable_ghost_det &&
1080 (cur_tch == CY_GEN2_GHOST))
1081 cur_tch = CY_GEN2_2TOUCH;
1082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001083 if (pxy_gen2_data->evnt_idx == CY_GEN2_NOTOUCH) {
1084 cur_tch = 0;
1085 } else if (cur_tch == CY_GEN2_GHOST) {
1086 cur_tch = 0;
1087 } else if (cur_tch == CY_GEN2_2TOUCH) {
1088 /* stuff artificial track ID1 and ID2 */
1089 g_xy_data.touch12_id = 0x12;
1090 g_xy_data.z1 = CY_MAXZ;
1091 g_xy_data.z2 = CY_MAXZ;
1092 cur_tch--; /* 2 touches */
1093 } else if (cur_tch == CY_GEN2_1TOUCH) {
1094 /* stuff artificial track ID1 and ID2 */
1095 g_xy_data.touch12_id = 0x12;
1096 g_xy_data.z1 = CY_MAXZ;
1097 g_xy_data.z2 = CY_NTCH;
1098 if (pxy_gen2_data->evnt_idx == CY_GEN2_TOUCH2) {
1099 /* push touch 2 data into touch1
1100 * (first finger up; second finger down) */
1101 /* stuff artificial track ID1 for touch2 info */
1102 g_xy_data.touch12_id = 0x20;
1103 /* stuff touch 1 with touch 2 coordinate data */
1104 g_xy_data.x1 = g_xy_data.x2;
1105 g_xy_data.y1 = g_xy_data.y2;
1106 }
1107 } else {
1108 cur_tch = 0;
1109 }
1110 } else {
1111 /* use test data? */
1112 cyttsp_testdat(&g_xy_data, &tt_gen3_testray, \
1113 sizeof(struct cyttsp_gen3_xydata_t));
1114 }
1115
1116
1117
1118 /* clear current active track ID array and count previous touches */
1119 for (id = 0, prv_tch = CY_NTCH;
1120 id < CY_NUM_TRK_ID; id++) {
1121 cur_trk[id] = CY_NTCH;
1122 prv_tch += ts->act_trk[id];
1123 }
1124
1125 /* send no events if no previous touches and no new touches */
1126 if ((prv_tch == CY_NTCH) &&
1127 ((cur_tch == CY_NTCH) ||
1128 (cur_tch > CY_NUM_MT_TCH_ID))) {
1129 goto exit_xy_worker;
1130 }
1131
1132 cyttsp_debug("prev=%d curr=%d\n", prv_tch, cur_tch);
1133
1134 for (id = 0; id < CY_NUM_ST_TCH_ID; id++) {
1135 /* clear current single touches array */
1136 cur_st_tch[id] = CY_IGNR_TCH;
1137 }
1138
1139 /* clear single touch positions */
1140 st_x1 = CY_NTCH;
1141 st_y1 = CY_NTCH;
1142 st_z1 = CY_NTCH;
1143 st_x2 = CY_NTCH;
1144 st_y2 = CY_NTCH;
1145 st_z2 = CY_NTCH;
1146
1147 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1148 /* clear current multi-touches array and
1149 * multi-touch positions/z */
1150 cur_mt_tch[id] = CY_IGNR_TCH;
1151 }
1152
1153 if (ts->platform_data->use_trk_id) {
1154 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1155 cur_mt_pos[id][CY_XPOS] = 0;
1156 cur_mt_pos[id][CY_YPOS] = 0;
1157 cur_mt_z[id] = 0;
1158 }
1159 } else {
1160 for (id = 0; id < CY_NUM_TRK_ID; id++) {
1161 cur_mt_pos[id][CY_XPOS] = 0;
1162 cur_mt_pos[id][CY_YPOS] = 0;
1163 cur_mt_z[id] = 0;
1164 }
1165 }
1166
1167 /* Determine if display is tilted */
1168 if (FLIP_DATA(ts->platform_data->flags))
1169 tilt = true;
1170 else
1171 tilt = false;
1172
1173 /* Check for switch in origin */
1174 if (REVERSE_X(ts->platform_data->flags))
1175 rev_x = true;
1176 else
1177 rev_x = false;
1178
1179 if (REVERSE_Y(ts->platform_data->flags))
1180 rev_y = true;
1181 else
1182 rev_y = false;
1183
1184 if (cur_tch) {
1185 struct cyttsp_gen2_xydata_t *pxy_gen2_data;
1186 struct cyttsp_gen3_xydata_t *pxy_gen3_data;
1187 switch (ts->platform_data->gen) {
1188 case CY_GEN2: {
1189 pxy_gen2_data =
1190 (struct cyttsp_gen2_xydata_t *)(&g_xy_data);
1191 cyttsp_xdebug("TTSP Gen2 report:\n");
1192 cyttsp_xdebug("%02X %02X %02X\n", \
1193 pxy_gen2_data->hst_mode, \
1194 pxy_gen2_data->tt_mode, \
1195 pxy_gen2_data->tt_stat);
1196 cyttsp_xdebug("%04X %04X %02X %02X\n", \
1197 pxy_gen2_data->x1, \
1198 pxy_gen2_data->y1, \
1199 pxy_gen2_data->z1, \
1200 pxy_gen2_data->evnt_idx);
1201 cyttsp_xdebug("%04X %04X %02X\n", \
1202 pxy_gen2_data->x2, \
1203 pxy_gen2_data->y2, \
1204 pxy_gen2_data->tt_undef1);
1205 cyttsp_xdebug("%02X %02X %02X\n", \
1206 pxy_gen2_data->gest_cnt, \
1207 pxy_gen2_data->gest_id, \
1208 pxy_gen2_data->gest_set);
1209 break;
1210 }
1211 case CY_GEN3:
1212 default: {
1213 pxy_gen3_data =
1214 (struct cyttsp_gen3_xydata_t *)(&g_xy_data);
1215 cyttsp_xdebug("TTSP Gen3 report:\n");
1216 cyttsp_xdebug("%02X %02X %02X\n", \
1217 pxy_gen3_data->hst_mode,
1218 pxy_gen3_data->tt_mode,
1219 pxy_gen3_data->tt_stat);
1220 cyttsp_xdebug("%04X %04X %02X %02X", \
1221 pxy_gen3_data->x1,
1222 pxy_gen3_data->y1,
1223 pxy_gen3_data->z1, \
1224 pxy_gen3_data->touch12_id);
1225 cyttsp_xdebug("%04X %04X %02X\n", \
1226 pxy_gen3_data->x2, \
1227 pxy_gen3_data->y2, \
1228 pxy_gen3_data->z2);
1229 cyttsp_xdebug("%02X %02X %02X\n", \
1230 pxy_gen3_data->gest_cnt, \
1231 pxy_gen3_data->gest_id, \
1232 pxy_gen3_data->gest_set);
1233 cyttsp_xdebug("%04X %04X %02X %02X\n", \
1234 pxy_gen3_data->x3, \
1235 pxy_gen3_data->y3, \
1236 pxy_gen3_data->z3, \
1237 pxy_gen3_data->touch34_id);
1238 cyttsp_xdebug("%04X %04X %02X\n", \
1239 pxy_gen3_data->x4, \
1240 pxy_gen3_data->y4, \
1241 pxy_gen3_data->z4);
1242 break;
1243 }
1244 }
1245 }
1246
1247 /* process the touches */
1248 switch (cur_tch) {
1249 case 4: {
1250 g_xy_data.x4 = be16_to_cpu(g_xy_data.x4);
1251 g_xy_data.y4 = be16_to_cpu(g_xy_data.y4);
1252 if (tilt)
1253 FLIP_XY(g_xy_data.x4, g_xy_data.y4);
1254
1255 if (rev_x) {
1256 g_xy_data.x4 = INVERT_X(g_xy_data.x4,
1257 ts->platform_data->panel_maxx);
1258 if (g_xy_data.x4 < 0)
1259 pr_debug("X value is negative. Please configure"
1260 " maxx in platform data structure\n");
1261 }
1262 if (rev_y) {
1263 g_xy_data.y4 = INVERT_X(g_xy_data.y4,
1264 ts->platform_data->panel_maxy);
1265 if (g_xy_data.y4 < 0)
1266 pr_debug("Y value is negative. Please configure"
1267 " maxy in platform data structure\n");
1268
1269 }
1270 id = GET_TOUCH4_ID(g_xy_data.touch34_id);
1271 if (ts->platform_data->use_trk_id) {
1272 cur_mt_pos[CY_MT_TCH4_IDX][CY_XPOS] =
1273 g_xy_data.x4;
1274 cur_mt_pos[CY_MT_TCH4_IDX][CY_YPOS] =
1275 g_xy_data.y4;
1276 cur_mt_z[CY_MT_TCH4_IDX] = g_xy_data.z4;
1277 } else {
1278 cur_mt_pos[id][CY_XPOS] = g_xy_data.x4;
1279 cur_mt_pos[id][CY_YPOS] = g_xy_data.y4;
1280 cur_mt_z[id] = g_xy_data.z4;
1281 }
1282 cur_mt_tch[CY_MT_TCH4_IDX] = id;
1283 cur_trk[id] = CY_TCH;
1284 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
1285 CY_NUM_TRK_ID) {
1286 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
1287 st_x1 = g_xy_data.x4;
1288 st_y1 = g_xy_data.y4;
1289 st_z1 = g_xy_data.z4;
1290 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1291 } else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
1292 st_x2 = g_xy_data.x4;
1293 st_y2 = g_xy_data.y4;
1294 st_z2 = g_xy_data.z4;
1295 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1296 }
1297 }
1298 cyttsp_xdebug("4th XYZ:% 3d,% 3d,% 3d ID:% 2d\n\n", \
1299 g_xy_data.x4, g_xy_data.y4, g_xy_data.z4, \
1300 (g_xy_data.touch34_id & 0x0F));
1301 /* do not break */
1302 }
1303 case 3: {
1304 g_xy_data.x3 = be16_to_cpu(g_xy_data.x3);
1305 g_xy_data.y3 = be16_to_cpu(g_xy_data.y3);
1306 if (tilt)
1307 FLIP_XY(g_xy_data.x3, g_xy_data.y3);
1308
1309 if (rev_x) {
1310 g_xy_data.x3 = INVERT_X(g_xy_data.x3,
1311 ts->platform_data->panel_maxx);
1312 if (g_xy_data.x3 < 0)
1313 pr_debug("X value is negative. Please configure"
1314 " maxx in platform data structure\n");
1315
1316 }
1317 if (rev_y) {
1318 g_xy_data.y3 = INVERT_X(g_xy_data.y3,
1319 ts->platform_data->panel_maxy);
1320 if (g_xy_data.y3 < 0)
1321 pr_debug("Y value is negative. Please configure"
1322 " maxy in platform data structure\n");
1323
1324 }
1325 id = GET_TOUCH3_ID(g_xy_data.touch34_id);
1326 if (ts->platform_data->use_trk_id) {
1327 cur_mt_pos[CY_MT_TCH3_IDX][CY_XPOS] =
1328 g_xy_data.x3;
1329 cur_mt_pos[CY_MT_TCH3_IDX][CY_YPOS] =
1330 g_xy_data.y3;
1331 cur_mt_z[CY_MT_TCH3_IDX] = g_xy_data.z3;
1332 } else {
1333 cur_mt_pos[id][CY_XPOS] = g_xy_data.x3;
1334 cur_mt_pos[id][CY_YPOS] = g_xy_data.y3;
1335 cur_mt_z[id] = g_xy_data.z3;
1336 }
1337 cur_mt_tch[CY_MT_TCH3_IDX] = id;
1338 cur_trk[id] = CY_TCH;
1339 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
1340 CY_NUM_TRK_ID) {
1341 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
1342 st_x1 = g_xy_data.x3;
1343 st_y1 = g_xy_data.y3;
1344 st_z1 = g_xy_data.z3;
1345 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1346 } else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
1347 st_x2 = g_xy_data.x3;
1348 st_y2 = g_xy_data.y3;
1349 st_z2 = g_xy_data.z3;
1350 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1351 }
1352 }
1353 cyttsp_xdebug("3rd XYZ:% 3d,% 3d,% 3d ID:% 2d\n", \
1354 g_xy_data.x3, g_xy_data.y3, g_xy_data.z3, \
1355 ((g_xy_data.touch34_id >> 4) & 0x0F));
1356 /* do not break */
1357 }
1358 case 2: {
1359 g_xy_data.x2 = be16_to_cpu(g_xy_data.x2);
1360 g_xy_data.y2 = be16_to_cpu(g_xy_data.y2);
1361 if (tilt)
1362 FLIP_XY(g_xy_data.x2, g_xy_data.y2);
1363
1364 if (rev_x) {
1365 g_xy_data.x2 = INVERT_X(g_xy_data.x2,
1366 ts->platform_data->panel_maxx);
1367 if (g_xy_data.x2 < 0)
1368 pr_debug("X value is negative. Please configure"
1369 " maxx in platform data structure\n");
1370 }
1371 if (rev_y) {
1372 g_xy_data.y2 = INVERT_X(g_xy_data.y2,
1373 ts->platform_data->panel_maxy);
1374 if (g_xy_data.y2 < 0)
1375 pr_debug("Y value is negative. Please configure"
1376 " maxy in platform data structure\n");
1377 }
1378 id = GET_TOUCH2_ID(g_xy_data.touch12_id);
1379 if (ts->platform_data->use_trk_id) {
1380 cur_mt_pos[CY_MT_TCH2_IDX][CY_XPOS] =
1381 g_xy_data.x2;
1382 cur_mt_pos[CY_MT_TCH2_IDX][CY_YPOS] =
1383 g_xy_data.y2;
1384 cur_mt_z[CY_MT_TCH2_IDX] = g_xy_data.z2;
1385 } else {
1386 cur_mt_pos[id][CY_XPOS] = g_xy_data.x2;
1387 cur_mt_pos[id][CY_YPOS] = g_xy_data.y2;
1388 cur_mt_z[id] = g_xy_data.z2;
1389 }
1390 cur_mt_tch[CY_MT_TCH2_IDX] = id;
1391 cur_trk[id] = CY_TCH;
1392 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
1393 CY_NUM_TRK_ID) {
1394 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
1395 st_x1 = g_xy_data.x2;
1396 st_y1 = g_xy_data.y2;
1397 st_z1 = g_xy_data.z2;
1398 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1399 } else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
1400 st_x2 = g_xy_data.x2;
1401 st_y2 = g_xy_data.y2;
1402 st_z2 = g_xy_data.z2;
1403 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1404 }
1405 }
1406 cyttsp_xdebug("2nd XYZ:% 3d,% 3d,% 3d ID:% 2d\n", \
1407 g_xy_data.x2, g_xy_data.y2, g_xy_data.z2, \
1408 (g_xy_data.touch12_id & 0x0F));
1409 /* do not break */
1410 }
1411 case 1: {
1412 g_xy_data.x1 = be16_to_cpu(g_xy_data.x1);
1413 g_xy_data.y1 = be16_to_cpu(g_xy_data.y1);
1414 if (tilt)
1415 FLIP_XY(g_xy_data.x1, g_xy_data.y1);
1416
1417 if (rev_x) {
1418 g_xy_data.x1 = INVERT_X(g_xy_data.x1,
1419 ts->platform_data->panel_maxx);
1420 if (g_xy_data.x1 < 0)
1421 pr_debug("X value is negative. Please configure"
1422 " maxx in platform data structure\n");
1423 }
1424 if (rev_y) {
1425 g_xy_data.y1 = INVERT_X(g_xy_data.y1,
1426 ts->platform_data->panel_maxy);
1427 if (g_xy_data.y1 < 0)
1428 pr_debug("Y value is negative. Please configure"
1429 " maxy in platform data structure");
1430 }
1431 id = GET_TOUCH1_ID(g_xy_data.touch12_id);
1432 if (ts->platform_data->use_trk_id) {
1433 cur_mt_pos[CY_MT_TCH1_IDX][CY_XPOS] =
1434 g_xy_data.x1;
1435 cur_mt_pos[CY_MT_TCH1_IDX][CY_YPOS] =
1436 g_xy_data.y1;
1437 cur_mt_z[CY_MT_TCH1_IDX] = g_xy_data.z1;
1438 } else {
1439 cur_mt_pos[id][CY_XPOS] = g_xy_data.x1;
1440 cur_mt_pos[id][CY_YPOS] = g_xy_data.y1;
1441 cur_mt_z[id] = g_xy_data.z1;
1442 }
1443 cur_mt_tch[CY_MT_TCH1_IDX] = id;
1444 cur_trk[id] = CY_TCH;
1445 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
1446 CY_NUM_TRK_ID) {
1447 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
1448 st_x1 = g_xy_data.x1;
1449 st_y1 = g_xy_data.y1;
1450 st_z1 = g_xy_data.z1;
1451 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1452 } else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
1453 st_x2 = g_xy_data.x1;
1454 st_y2 = g_xy_data.y1;
1455 st_z2 = g_xy_data.z1;
1456 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1457 }
1458 }
1459 cyttsp_xdebug("1st XYZ:% 3d,% 3d,% 3d ID:% 2d\n", \
1460 g_xy_data.x1, g_xy_data.y1, g_xy_data.z1, \
1461 ((g_xy_data.touch12_id >> 4) & 0x0F));
1462 break;
1463 }
1464 case 0:
1465 default:{
1466 break;
1467 }
1468 }
1469
1470 /* handle Single Touch signals */
1471 if (ts->platform_data->use_st) {
1472 cyttsp_xdebug("ST STEP 0 - ST1 ID=%d ST2 ID=%d\n", \
1473 cur_st_tch[CY_ST_FNGR1_IDX], \
1474 cur_st_tch[CY_ST_FNGR2_IDX]);
1475 if (cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) {
1476 /* reassign finger 1 and 2 positions to new tracks */
1477 if (cur_tch > 0) {
1478 /* reassign st finger1 */
1479 if (ts->platform_data->use_trk_id) {
1480 id = CY_MT_TCH1_IDX;
1481 cur_st_tch[CY_ST_FNGR1_IDX] = cur_mt_tch[id];
1482 } else {
1483 id = GET_TOUCH1_ID(g_xy_data.touch12_id);
1484 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1485 }
1486 st_x1 = cur_mt_pos[id][CY_XPOS];
1487 st_y1 = cur_mt_pos[id][CY_YPOS];
1488 st_z1 = cur_mt_z[id];
1489 cyttsp_xdebug("ST STEP 1 - ST1 ID=%3d\n", \
1490 cur_st_tch[CY_ST_FNGR1_IDX]);
1491 if ((cur_tch > 1) &&
1492 (cur_st_tch[CY_ST_FNGR2_IDX] >
1493 CY_NUM_TRK_ID)) {
1494 /* reassign st finger2 */
1495 if (cur_tch > 1) {
1496 if (ts->platform_data->use_trk_id) {
1497 id = CY_MT_TCH2_IDX;
1498 cur_st_tch[CY_ST_FNGR2_IDX] = cur_mt_tch[id];
1499 } else {
1500 id = GET_TOUCH2_ID(g_xy_data.touch12_id);
1501 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1502 }
1503 st_x2 = cur_mt_pos[id][CY_XPOS];
1504 st_y2 = cur_mt_pos[id][CY_YPOS];
1505 st_z2 = cur_mt_z[id];
1506 cyttsp_xdebug("ST STEP 2 - ST2 ID=%3d\n", \
1507 cur_st_tch[CY_ST_FNGR2_IDX]);
1508 }
1509 }
1510 }
1511 } else if (cur_st_tch[CY_ST_FNGR2_IDX] > CY_NUM_TRK_ID) {
1512 if (cur_tch > 1) {
1513 /* reassign st finger2 */
1514 if (ts->platform_data->use_trk_id) {
1515 /* reassign st finger2 */
1516 id = CY_MT_TCH2_IDX;
1517 cur_st_tch[CY_ST_FNGR2_IDX] =
1518 cur_mt_tch[id];
1519 } else {
1520 /* reassign st finger2 */
1521 id = GET_TOUCH2_ID(g_xy_data.touch12_id);
1522 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1523 }
1524 st_x2 = cur_mt_pos[id][CY_XPOS];
1525 st_y2 = cur_mt_pos[id][CY_YPOS];
1526 st_z2 = cur_mt_z[id];
1527 cyttsp_xdebug("ST STEP 3 - ST2 ID=%3d\n", \
1528 cur_st_tch[CY_ST_FNGR2_IDX]);
1529 }
1530 }
1531 /* if the 1st touch is missing and there is a 2nd touch,
1532 * then set the 1st touch to 2nd touch and terminate 2nd touch
1533 */
1534 if ((cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) &&
1535 (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID)) {
1536 st_x1 = st_x2;
1537 st_y1 = st_y2;
1538 st_z1 = st_z2;
1539 cur_st_tch[CY_ST_FNGR1_IDX] =
1540 cur_st_tch[CY_ST_FNGR2_IDX];
1541 cur_st_tch[CY_ST_FNGR2_IDX] =
1542 CY_IGNR_TCH;
1543 }
1544 /* if the 2nd touch ends up equal to the 1st touch,
1545 * then just report a single touch */
1546 if (cur_st_tch[CY_ST_FNGR1_IDX] ==
1547 cur_st_tch[CY_ST_FNGR2_IDX]) {
1548 cur_st_tch[CY_ST_FNGR2_IDX] =
1549 CY_IGNR_TCH;
1550 }
1551 /* set Single Touch current event signals */
1552 if (cur_st_tch[CY_ST_FNGR1_IDX] < CY_NUM_TRK_ID) {
1553 input_report_abs(ts->input,
1554 ABS_X, st_x1);
1555 input_report_abs(ts->input,
1556 ABS_Y, st_y1);
1557 input_report_abs(ts->input,
1558 ABS_PRESSURE, st_z1);
1559 input_report_key(ts->input,
1560 BTN_TOUCH,
1561 CY_TCH);
1562 input_report_abs(ts->input,
1563 ABS_TOOL_WIDTH,
1564 curr_tool_width);
1565 cyttsp_debug("ST->F1:%3d X:%3d Y:%3d Z:%3d\n", \
1566 cur_st_tch[CY_ST_FNGR1_IDX], \
1567 st_x1, st_y1, st_z1);
1568 if (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID) {
1569 input_report_key(ts->input, BTN_2, CY_TCH);
1570 input_report_abs(ts->input, ABS_HAT0X, st_x2);
1571 input_report_abs(ts->input, ABS_HAT0Y, st_y2);
1572 cyttsp_debug("ST->F2:%3d X:%3d Y:%3d Z:%3d\n", \
1573 cur_st_tch[CY_ST_FNGR2_IDX],
1574 st_x2, st_y2, st_z2);
1575 } else {
1576 input_report_key(ts->input,
1577 BTN_2,
1578 CY_NTCH);
1579 }
1580 } else {
1581 input_report_abs(ts->input, ABS_PRESSURE, CY_NTCH);
1582 input_report_key(ts->input, BTN_TOUCH, CY_NTCH);
1583 input_report_key(ts->input, BTN_2, CY_NTCH);
1584 }
1585 /* update platform data for the current single touch info */
1586 ts->prv_st_tch[CY_ST_FNGR1_IDX] = cur_st_tch[CY_ST_FNGR1_IDX];
1587 ts->prv_st_tch[CY_ST_FNGR2_IDX] = cur_st_tch[CY_ST_FNGR2_IDX];
1588
1589 }
1590
1591 /* handle Multi-touch signals */
1592 if (ts->platform_data->use_mt) {
1593 if (ts->platform_data->use_trk_id) {
1594 /* terminate any previous touch where the track
1595 * is missing from the current event */
1596 for (id = 0; id < CY_NUM_TRK_ID; id++) {
1597 if ((ts->act_trk[id] != CY_NTCH) &&
1598 (cur_trk[id] == CY_NTCH)) {
1599 input_report_abs(ts->input,
1600 ABS_MT_TRACKING_ID,
1601 id);
1602 input_report_abs(ts->input,
1603 ABS_MT_TOUCH_MAJOR,
1604 CY_NTCH);
1605 input_report_abs(ts->input,
1606 ABS_MT_WIDTH_MAJOR,
1607 curr_tool_width);
1608 input_report_abs(ts->input,
1609 ABS_MT_POSITION_X,
1610 ts->prv_mt_pos[id][CY_XPOS]);
1611 input_report_abs(ts->input,
1612 ABS_MT_POSITION_Y,
1613 ts->prv_mt_pos[id][CY_YPOS]);
1614 CY_MT_SYNC(ts->input);
1615 ts->act_trk[id] = CY_NTCH;
1616 ts->prv_mt_pos[id][CY_XPOS] = 0;
1617 ts->prv_mt_pos[id][CY_YPOS] = 0;
1618 }
1619 }
1620 /* set Multi-Touch current event signals */
1621 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1622 if (cur_mt_tch[id] < CY_NUM_TRK_ID) {
1623 input_report_abs(ts->input,
1624 ABS_MT_TRACKING_ID,
1625 cur_mt_tch[id]);
1626 input_report_abs(ts->input,
1627 ABS_MT_TOUCH_MAJOR,
1628 cur_mt_z[id]);
1629 input_report_abs(ts->input,
1630 ABS_MT_WIDTH_MAJOR,
1631 curr_tool_width);
1632 input_report_abs(ts->input,
1633 ABS_MT_POSITION_X,
1634 cur_mt_pos[id][CY_XPOS]);
1635 input_report_abs(ts->input,
1636 ABS_MT_POSITION_Y,
1637 cur_mt_pos[id][CY_YPOS]);
1638 CY_MT_SYNC(ts->input);
1639 ts->act_trk[id] = CY_TCH;
1640 ts->prv_mt_pos[id][CY_XPOS] =
1641 cur_mt_pos[id][CY_XPOS];
1642 ts->prv_mt_pos[id][CY_YPOS] =
1643 cur_mt_pos[id][CY_YPOS];
1644 }
1645 }
1646 } else {
1647 /* set temporary track array elements to voids */
1648 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1649 tmp_trk[id] = CY_IGNR_TCH;
1650 snd_trk[id] = CY_IGNR_TCH;
1651 }
1652
1653 /* get what is currently active */
1654 for (i = 0, id = 0;
1655 id < CY_NUM_TRK_ID && i < CY_NUM_MT_TCH_ID;
1656 id++) {
1657 if (cur_trk[id] == CY_TCH) {
1658 /* only incr counter if track found */
1659 tmp_trk[i] = id;
1660 i++;
1661 }
1662 }
1663 cyttsp_xdebug("T1: t0=%d, t1=%d, t2=%d, t3=%d\n", \
1664 tmp_trk[0], tmp_trk[1], tmp_trk[2], \
1665 tmp_trk[3]);
1666 cyttsp_xdebug("T1: p0=%d, p1=%d, p2=%d, p3=%d\n", \
1667 ts->prv_mt_tch[0], ts->prv_mt_tch[1], \
1668 ts->prv_mt_tch[2], ts->prv_mt_tch[3]);
1669
1670 /* pack in still active previous touches */
1671 for (id = 0, prv_tch = 0;
1672 id < CY_NUM_MT_TCH_ID; id++) {
1673 if (tmp_trk[id] < CY_NUM_TRK_ID) {
1674 if (cyttsp_inlist(ts->prv_mt_tch,
1675 tmp_trk[id], &loc,
1676 CY_NUM_MT_TCH_ID)) {
1677 loc &= CY_NUM_MT_TCH_ID - 1;
1678 snd_trk[loc] = tmp_trk[id];
1679 prv_tch++;
1680 cyttsp_xdebug("inlist s[%d]=%d t[%d]=%d l=%d p=%d\n", \
1681 loc, snd_trk[loc], \
1682 id, tmp_trk[id], \
1683 loc, prv_tch);
1684 } else {
1685 cyttsp_xdebug("not inlist s[%d]=%d t[%d]=%d l=%d \n", \
1686 id, snd_trk[id], \
1687 id, tmp_trk[id], \
1688 loc);
1689 }
1690 }
1691 }
1692 cyttsp_xdebug("S1: s0=%d, s1=%d, s2=%d, s3=%d p=%d\n", \
1693 snd_trk[0], snd_trk[1], snd_trk[2], \
1694 snd_trk[3], prv_tch);
1695
1696 /* pack in new touches */
1697 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1698 if (tmp_trk[id] < CY_NUM_TRK_ID) {
1699 if (!cyttsp_inlist(snd_trk, tmp_trk[id], &loc, CY_NUM_MT_TCH_ID)) {
1700 cyttsp_xdebug("not inlist t[%d]=%d l=%d\n", \
1701 id, tmp_trk[id], loc);
1702 if (cyttsp_next_avail_inlist(snd_trk, &loc, CY_NUM_MT_TCH_ID)) {
1703 loc &= CY_NUM_MT_TCH_ID - 1;
1704 snd_trk[loc] = tmp_trk[id];
1705 cyttsp_xdebug("put inlist s[%d]=%d t[%d]=%d\n",
1706 loc, snd_trk[loc], id, tmp_trk[id]);
1707 }
1708 } else {
1709 cyttsp_xdebug("is in list s[%d]=%d t[%d]=%d loc=%d\n", \
1710 id, snd_trk[id], id, tmp_trk[id], loc);
1711 }
1712 }
1713 }
1714 cyttsp_xdebug("S2: s0=%d, s1=%d, s2=%d, s3=%d\n", \
1715 snd_trk[0], snd_trk[1],
1716 snd_trk[2], snd_trk[3]);
1717
1718 /* sync motion event signals for each current touch */
1719 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1720 /* z will either be 0 (NOTOUCH) or
1721 * some pressure (TOUCH) */
1722 cyttsp_xdebug("MT0 prev[%d]=%d temp[%d]=%d send[%d]=%d\n", \
1723 id, ts->prv_mt_tch[id], \
1724 id, tmp_trk[id], \
1725 id, snd_trk[id]);
1726 if (snd_trk[id] < CY_NUM_TRK_ID) {
1727 input_report_abs(ts->input,
1728 ABS_MT_TOUCH_MAJOR,
1729 cur_mt_z[snd_trk[id]]);
1730 input_report_abs(ts->input,
1731 ABS_MT_WIDTH_MAJOR,
1732 curr_tool_width);
1733 input_report_abs(ts->input,
1734 ABS_MT_POSITION_X,
1735 cur_mt_pos[snd_trk[id]][CY_XPOS]);
1736 input_report_abs(ts->input,
1737 ABS_MT_POSITION_Y,
1738 cur_mt_pos[snd_trk[id]][CY_YPOS]);
1739 CY_MT_SYNC(ts->input);
1740 cyttsp_debug("MT1->TID:%2d X:%3d Y:%3d Z:%3d touch-sent\n", \
1741 snd_trk[id], \
1742 cur_mt_pos[snd_trk[id]][CY_XPOS], \
1743 cur_mt_pos[snd_trk[id]][CY_YPOS], \
1744 cur_mt_z[snd_trk[id]]);
1745 } else if (ts->prv_mt_tch[id] < CY_NUM_TRK_ID) {
1746 /* void out this touch */
1747 input_report_abs(ts->input,
1748 ABS_MT_TOUCH_MAJOR,
1749 CY_NTCH);
1750 input_report_abs(ts->input,
1751 ABS_MT_WIDTH_MAJOR,
1752 curr_tool_width);
1753 input_report_abs(ts->input,
1754 ABS_MT_POSITION_X,
1755 ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS]);
1756 input_report_abs(ts->input,
1757 ABS_MT_POSITION_Y,
1758 ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS]);
1759 CY_MT_SYNC(ts->input);
1760 cyttsp_debug("MT2->TID:%2d X:%3d Y:%3d Z:%3d lift off-sent\n", \
1761 ts->prv_mt_tch[id], \
1762 ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS], \
1763 ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS], \
1764 CY_NTCH);
1765 } else {
1766 /* do not stuff any signals for this
1767 * previously and currently
1768 * void touches */
1769 cyttsp_xdebug("MT3->send[%d]=%d - No touch - NOT sent\n", \
1770 id, snd_trk[id]);
1771 }
1772 }
1773
1774 /* save current posted tracks to
1775 * previous track memory */
1776 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1777 ts->prv_mt_tch[id] = snd_trk[id];
1778 if (snd_trk[id] < CY_NUM_TRK_ID) {
1779 ts->prv_mt_pos[snd_trk[id]][CY_XPOS] =
1780 cur_mt_pos[snd_trk[id]][CY_XPOS];
1781 ts->prv_mt_pos[snd_trk[id]][CY_YPOS] =
1782 cur_mt_pos[snd_trk[id]][CY_YPOS];
1783 cyttsp_xdebug("MT4->TID:%2d X:%3d Y:%3d Z:%3d save for previous\n", \
1784 snd_trk[id], \
1785 ts->prv_mt_pos[snd_trk[id]][CY_XPOS], \
1786 ts->prv_mt_pos[snd_trk[id]][CY_YPOS], \
1787 CY_NTCH);
1788 }
1789 }
1790 for (id = 0; id < CY_NUM_TRK_ID; id++)
1791 ts->act_trk[id] = CY_NTCH;
1792 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1793 if (snd_trk[id] < CY_NUM_TRK_ID)
1794 ts->act_trk[snd_trk[id]] = CY_TCH;
1795 }
1796 }
1797 }
1798
1799 /* handle gestures */
1800 if (ts->platform_data->use_gestures) {
1801 if (g_xy_data.gest_id) {
1802 input_report_key(ts->input,
1803 BTN_3, CY_TCH);
1804 input_report_abs(ts->input,
1805 ABS_HAT1X, g_xy_data.gest_id);
1806 input_report_abs(ts->input,
1807 ABS_HAT2Y, g_xy_data.gest_cnt);
1808 }
1809 }
1810
1811 /* signal the view motion event */
1812 input_sync(ts->input);
1813
1814 for (id = 0; id < CY_NUM_TRK_ID; id++) {
1815 /* update platform data for the current MT information */
1816 ts->act_trk[id] = cur_trk[id];
1817 }
1818
1819exit_xy_worker:
1820 if (cyttsp_disable_touch) {
1821 /* Turn off the touch interrupts */
1822 cyttsp_debug("Not enabling touch\n");
1823 } else {
1824 if (ts->client->irq == 0) {
1825 /* restart event timer */
1826 mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
1827 } else {
1828 /* re-enable the interrupt after processing */
1829 enable_irq(ts->client->irq);
1830 }
1831 }
1832 return;
1833}
1834
1835static int cyttsp_inlist(u16 prev_track[], u8 cur_trk_id,
1836 u8 *prev_loc, u8 num_touches)
1837{
1838 u8 id = 0;
1839
1840 *prev_loc = CY_IGNR_TCH;
1841
1842 cyttsp_xdebug("IN p[%d]=%d c=%d n=%d loc=%d\n", \
1843 id, prev_track[id], cur_trk_id, \
1844 num_touches, *prev_loc);
1845 for (id = 0, *prev_loc = CY_IGNR_TCH;
1846 (id < num_touches); id++) {
1847 cyttsp_xdebug("p[%d]=%d c=%d n=%d loc=%d\n", \
1848 id, prev_track[id], cur_trk_id, \
1849 num_touches, *prev_loc);
1850 if (prev_track[id] == cur_trk_id) {
1851 *prev_loc = id;
1852 break;
1853 }
1854 }
1855 cyttsp_xdebug("OUT p[%d]=%d c=%d n=%d loc=%d\n", \
1856 id, prev_track[id], cur_trk_id, num_touches, *prev_loc);
1857
1858 return ((*prev_loc < CY_NUM_TRK_ID) ? true : false);
1859}
1860
1861static int cyttsp_next_avail_inlist(u16 cur_trk[],
1862 u8 *new_loc, u8 num_touches)
1863{
1864 u8 id;
1865
1866 for (id = 0, *new_loc = CY_IGNR_TCH;
1867 (id < num_touches); id++) {
1868 if (cur_trk[id] > CY_NUM_TRK_ID) {
1869 *new_loc = id;
1870 break;
1871 }
1872 }
1873
1874 return ((*new_loc < CY_NUM_TRK_ID) ? true : false);
1875}
1876
1877/* Timer function used as dummy interrupt driver */
1878static void cyttsp_timer(unsigned long handle)
1879{
1880 struct cyttsp *ts = (struct cyttsp *) handle;
1881
1882 cyttsp_xdebug("TTSP Device timer event\n");
1883
1884 /* schedule motion signal handling */
1885 queue_work(cyttsp_ts_wq, &ts->work);
1886
1887 return;
1888}
1889
1890
1891
1892/* ************************************************************************
1893 * ISR function. This function is general, initialized in drivers init
1894 * function
1895 * ************************************************************************ */
1896static irqreturn_t cyttsp_irq(int irq, void *handle)
1897{
1898 struct cyttsp *ts = (struct cyttsp *) handle;
1899
1900 cyttsp_xdebug("%s: Got IRQ\n", CY_I2C_NAME);
1901
1902 /* disable further interrupts until this interrupt is processed */
1903 disable_irq_nosync(ts->client->irq);
1904
1905 /* schedule motion signal handling */
1906 queue_work(cyttsp_ts_wq, &ts->work);
1907 return IRQ_HANDLED;
1908}
1909
1910/* ************************************************************************
1911 * Probe initialization functions
1912 * ************************************************************************ */
1913static int cyttsp_putbl(struct cyttsp *ts, int show,
1914 int show_status, int show_version, int show_cid)
1915{
1916 int retval = CY_OK;
1917
1918 int num_bytes = (show_status * 3) + (show_version * 6) + (show_cid * 3);
1919
1920 if (show_cid)
1921 num_bytes = sizeof(struct cyttsp_bootloader_data_t);
1922 else if (show_version)
1923 num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 3;
1924 else
1925 num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 9;
1926
1927 if (show) {
1928 retval = i2c_smbus_read_i2c_block_data(ts->client,
1929 CY_REG_BASE, num_bytes, (u8 *)&g_bl_data);
1930 if (show_status) {
1931 cyttsp_debug("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X\n", \
1932 show, \
1933 g_bl_data.bl_file, \
1934 g_bl_data.bl_status, \
1935 g_bl_data.bl_error, \
1936 g_bl_data.blver_hi, g_bl_data.blver_lo, \
1937 g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo);
1938 }
1939 if (show_version) {
1940 cyttsp_debug("BL%d: ttspver=0x%02X%02X appid=0x%02X%02X appver=0x%02X%02X\n", \
1941 show, \
1942 g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
1943 g_bl_data.appid_hi, g_bl_data.appid_lo, \
1944 g_bl_data.appver_hi, g_bl_data.appver_lo);
1945 }
1946 if (show_cid) {
1947 cyttsp_debug("BL%d: cid=0x%02X%02X%02X\n", \
1948 show, \
1949 g_bl_data.cid_0, \
1950 g_bl_data.cid_1, \
1951 g_bl_data.cid_2);
1952 }
1953 }
1954
1955 return retval;
1956}
1957
1958#ifdef CY_INCLUDE_LOAD_FILE
1959#define CY_MAX_I2C_LEN 256
1960#define CY_MAX_TRY 10
1961#define CY_BL_PAGE_SIZE 16
1962#define CY_BL_NUM_PAGES 5
1963static int cyttsp_i2c_wr_blk_chunks(struct cyttsp *ts, u8 command,
1964 u8 length, const u8 *values)
1965{
1966 int retval = CY_OK;
1967 int block = 1;
1968
1969 u8 dataray[CY_MAX_I2C_LEN];
1970
1971 /* first page already includes the bl page offset */
1972 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
1973 CY_BL_PAGE_SIZE+1, values);
1974 values += CY_BL_PAGE_SIZE+1;
1975 length -= CY_BL_PAGE_SIZE+1;
1976
1977 /* rem blocks require bl page offset stuffing */
1978 while (length &&
1979 (block < CY_BL_NUM_PAGES) &&
1980 !(retval < CY_OK)) {
1981 udelay(43*2); /* TRM * 2 */
1982 dataray[0] = CY_BL_PAGE_SIZE*block;
1983 memcpy(&dataray[1], values,
1984 length >= CY_BL_PAGE_SIZE ?
1985 CY_BL_PAGE_SIZE : length);
1986 retval = i2c_smbus_write_i2c_block_data(ts->client,
1987 CY_REG_BASE,
1988 length >= CY_BL_PAGE_SIZE ?
1989 CY_BL_PAGE_SIZE + 1 : length+1, dataray);
1990 values += CY_BL_PAGE_SIZE;
1991 length = length >= CY_BL_PAGE_SIZE ?
1992 length - CY_BL_PAGE_SIZE : 0;
1993 block++;
1994 }
1995
1996 return retval;
1997}
1998
1999static int cyttsp_bootload_app(struct cyttsp *ts)
2000{
2001 int retval = CY_OK;
2002 int i, tries;
2003 u8 host_reg;
2004
2005 cyttsp_debug("load new firmware \n");
2006 /* reset TTSP Device back to bootloader mode */
2007 host_reg = CY_SOFT_RESET_MODE;
2008 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
2009 sizeof(host_reg), &host_reg);
2010 /* wait for TTSP Device to complete reset back to bootloader */
2011 tries = 0;
2012 do {
2013 mdelay(1);
2014 cyttsp_putbl(ts, 3, false, false, false);
2015 } while (g_bl_data.bl_status != 0x10 &&
2016 g_bl_data.bl_status != 0x11 &&
2017 tries++ < 100);
2018 cyttsp_debug("load file - tver=0x%02X%02X a_id=0x%02X%02X aver=0x%02X%02X\n", \
2019 cyttsp_fw_tts_verh, cyttsp_fw_tts_verl, \
2020 cyttsp_fw_app_idh, cyttsp_fw_app_idl, \
2021 cyttsp_fw_app_verh, cyttsp_fw_app_verl);
2022
2023 /* download new TTSP Application to the Bootloader */
2024 if (!(retval < CY_OK)) {
2025 i = 0;
2026 /* send bootload initiation command */
2027 if (cyttsp_fw[i].Command == CY_BL_INIT_LOAD) {
2028 g_bl_data.bl_file = 0;
2029 g_bl_data.bl_status = 0;
2030 g_bl_data.bl_error = 0;
2031 retval = i2c_smbus_write_i2c_block_data(ts->client,
2032 CY_REG_BASE,
2033 cyttsp_fw[i].Length, cyttsp_fw[i].Block);
2034 /* delay to allow bl to get ready for block writes */
2035 i++;
2036 tries = 0;
2037 do {
2038 mdelay(100);
2039 cyttsp_putbl(ts, 4, false, false, false);
2040 } while (g_bl_data.bl_status != 0x10 &&
2041 g_bl_data.bl_status != 0x11 &&
2042 tries++ < 100);
2043 cyttsp_debug("wait init f=%02X, s=%02X, e=%02X t=%d\n", \
2044 g_bl_data.bl_file, g_bl_data.bl_status, \
2045 g_bl_data.bl_error, tries);
2046 /* send bootload firmware load blocks */
2047 if (!(retval < CY_OK)) {
2048 while (cyttsp_fw[i].Command == CY_BL_WRITE_BLK) {
2049 retval = cyttsp_i2c_wr_blk_chunks(ts,
2050 CY_REG_BASE,
2051 cyttsp_fw[i].Length,
2052 cyttsp_fw[i].Block);
2053 cyttsp_xdebug("BL DNLD Rec=% 3d Len=% 3d Addr=%04X\n", \
2054 cyttsp_fw[i].Record, \
2055 cyttsp_fw[i].Length, \
2056 cyttsp_fw[i].Address);
2057 i++;
2058 if (retval < CY_OK) {
2059 cyttsp_debug("BL fail Rec=%3d retval=%d\n", \
2060 cyttsp_fw[i-1].Record, \
2061 retval);
2062 break;
2063 } else {
2064 tries = 0;
2065 cyttsp_putbl(ts, 5, false, false, false);
2066 while (!((g_bl_data.bl_status == 0x10) &&
2067 (g_bl_data.bl_error == 0x20)) &&
2068 !((g_bl_data.bl_status == 0x11) &&
2069 (g_bl_data.bl_error == 0x20)) &&
2070 (tries++ < 100)) {
2071 mdelay(1);
2072 cyttsp_putbl(ts, 5, false, false, false);
2073 }
2074 }
2075 }
2076
2077 if (!(retval < CY_OK)) {
2078 while (i < cyttsp_fw_records) {
2079 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
2080 cyttsp_fw[i].Length,
2081 cyttsp_fw[i].Block);
2082 i++;
2083 tries = 0;
2084 do {
2085 mdelay(100);
2086 cyttsp_putbl(ts, 6, true, false, false);
2087 } while (g_bl_data.bl_status != 0x10 &&
2088 g_bl_data.bl_status != 0x11 &&
2089 tries++ < 100);
2090 cyttsp_debug("wait term f=%02X, s=%02X, e=%02X t=%d\n", \
2091 g_bl_data.bl_file, \
2092 g_bl_data.bl_status, \
2093 g_bl_data.bl_error, \
2094 tries);
2095 if (retval < CY_OK)
2096 break;
2097 }
2098 }
2099 }
2100 }
2101 }
2102
2103 /* reset TTSP Device back to bootloader mode */
2104 host_reg = CY_SOFT_RESET_MODE;
2105 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
2106 sizeof(host_reg), &host_reg);
2107 /* wait for TTSP Device to complete reset back to bootloader */
2108 tries = 0;
2109 do {
2110 mdelay(1);
2111 cyttsp_putbl(ts, 3, false, false, false);
2112 } while (g_bl_data.bl_status != 0x10 &&
2113 g_bl_data.bl_status != 0x11 &&
2114 tries++ < 100);
2115
2116 /* set arg2 to non-0 to activate */
2117 retval = cyttsp_putbl(ts, 8, true, true, true);
2118
2119 return retval;
2120}
2121#else
2122static int cyttsp_bootload_app(struct cyttsp *ts)
2123{
2124 cyttsp_debug("no-load new firmware \n");
2125 return CY_OK;
2126}
2127#endif /* CY_INCLUDE_LOAD_FILE */
2128
2129
2130static int cyttsp_power_on(struct cyttsp *ts)
2131{
2132 int retval = CY_OK;
2133 u8 host_reg;
2134 int tries;
2135
2136 cyttsp_debug("Power up \n");
2137
2138 /* check if the TTSP device has a bootloader installed */
2139 host_reg = CY_SOFT_RESET_MODE;
2140 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
2141 sizeof(host_reg), &host_reg);
2142 tries = 0;
2143 do {
2144 mdelay(1);
2145
2146 /* set arg2 to non-0 to activate */
2147 retval = cyttsp_putbl(ts, 1, true, true, true);
2148 cyttsp_info("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X R=%d\n", \
2149 101, \
2150 g_bl_data.bl_file, g_bl_data.bl_status, \
2151 g_bl_data.bl_error, \
2152 g_bl_data.blver_hi, g_bl_data.blver_lo, \
2153 g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo,
2154 retval);
2155 cyttsp_info("BL%d: tver=%02X%02X a_id=%02X%02X aver=%02X%02X\n", \
2156 102, \
2157 g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
2158 g_bl_data.appid_hi, g_bl_data.appid_lo, \
2159 g_bl_data.appver_hi, g_bl_data.appver_lo);
2160 cyttsp_info("BL%d: c_id=%02X%02X%02X\n", \
2161 103, \
2162 g_bl_data.cid_0, g_bl_data.cid_1, g_bl_data.cid_2);
2163 } while (!(retval < CY_OK) &&
2164 !GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
2165 !(g_bl_data.bl_file == CY_OP_MODE + CY_LOW_PWR_MODE) &&
2166 tries++ < 100);
2167
2168 /* is bootloader missing? */
2169 if (!(retval < CY_OK)) {
2170 cyttsp_xdebug("Ret=%d Check if bootloader is missing...\n", \
2171 retval);
2172 if (!GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
2173 /* skip all bl and sys info and go to op mode */
2174 if (!(retval < CY_OK)) {
2175 cyttsp_xdebug("Bl is missing (ret=%d)\n", \
2176 retval);
2177 host_reg = CY_OP_MODE/* + CY_LOW_PWR_MODE*/;
2178 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
2179 sizeof(host_reg), &host_reg);
2180 /* wait for TTSP Device to complete switch to
2181 * Operational mode */
2182 mdelay(1000);
2183 goto bypass;
2184 }
2185 }
2186 }
2187
2188
2189 /* take TTSP out of bootloader mode; go to TrueTouch operational mode */
2190 if (!(retval < CY_OK)) {
2191 cyttsp_xdebug1("exit bootloader; go operational\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192 tries = 0;
2193 do {
Anirudh Ghayalab2754e2011-08-22 12:39:31 +05302194 msleep(100);
2195 retval = i2c_smbus_write_i2c_block_data(ts->client,
2196 CY_REG_BASE, sizeof(bl_cmd), bl_cmd);
2197 if (retval == CY_OK)
2198 break;
2199 } while (tries++ < 5);
2200
2201 if (retval == CY_OK) {
2202 tries = 0;
2203 do {
2204 msleep(100);
2205 cyttsp_putbl(ts, 4, true, false, false);
2206 cyttsp_info("BL%d: f=%02X s=%02X err=%02X" \
2207 "bl=%02X%02X bld=%02X%02X\n", 104, \
2208 g_bl_data.bl_file, \
2209 g_bl_data.bl_status, \
2210 g_bl_data.bl_error, \
2211 g_bl_data.blver_hi, \
2212 g_bl_data.blver_lo, \
2213 g_bl_data.bld_blver_hi, \
2214 g_bl_data.bld_blver_lo);
2215 } while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
2216 tries++ < 5);
2217 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002218 }
2219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002220 if (!(retval < CY_OK) &&
2221 cyttsp_app_load()) {
2222 if (CY_DIFF(g_bl_data.ttspver_hi, cyttsp_tts_verh()) ||
2223 CY_DIFF(g_bl_data.ttspver_lo, cyttsp_tts_verl()) ||
2224 CY_DIFF(g_bl_data.appid_hi, cyttsp_app_idh()) ||
2225 CY_DIFF(g_bl_data.appid_lo, cyttsp_app_idl()) ||
2226 CY_DIFF(g_bl_data.appver_hi, cyttsp_app_verh()) ||
2227 CY_DIFF(g_bl_data.appver_lo, cyttsp_app_verl()) ||
2228 CY_DIFF(g_bl_data.cid_0, cyttsp_cid_0()) ||
2229 CY_DIFF(g_bl_data.cid_1, cyttsp_cid_1()) ||
2230 CY_DIFF(g_bl_data.cid_2, cyttsp_cid_2()) ||
2231 cyttsp_force_fw_load()) {
2232 cyttsp_debug("blttsp=0x%02X%02X flttsp=0x%02X%02X force=%d\n", \
2233 g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
2234 cyttsp_tts_verh(), cyttsp_tts_verl(), \
2235 cyttsp_force_fw_load());
2236 cyttsp_debug("blappid=0x%02X%02X flappid=0x%02X%02X\n", \
2237 g_bl_data.appid_hi, g_bl_data.appid_lo, \
2238 cyttsp_app_idh(), cyttsp_app_idl());
2239 cyttsp_debug("blappver=0x%02X%02X flappver=0x%02X%02X\n", \
2240 g_bl_data.appver_hi, g_bl_data.appver_lo, \
2241 cyttsp_app_verh(), cyttsp_app_verl());
2242 cyttsp_debug("blcid=0x%02X%02X%02X flcid=0x%02X%02X%02X\n", \
2243 g_bl_data.cid_0, \
2244 g_bl_data.cid_1, \
2245 g_bl_data.cid_2, \
2246 cyttsp_cid_0(), \
2247 cyttsp_cid_1(), \
2248 cyttsp_cid_2());
2249 /* enter bootloader to load new app into TTSP Device */
2250 retval = cyttsp_bootload_app(ts);
2251 /* take TTSP device out of bootloader mode;
2252 * switch back to TrueTouch operational mode */
2253 if (!(retval < CY_OK)) {
2254 retval = i2c_smbus_write_i2c_block_data(ts->client,
2255 CY_REG_BASE,
2256 sizeof(bl_cmd), bl_cmd);
2257 /* wait for TTSP Device to complete
2258 * switch to Operational mode */
2259 tries = 0;
2260 do {
2261 mdelay(100);
2262 cyttsp_putbl(ts, 9, false, false, false);
2263 } while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
2264 tries++ < 100);
2265 cyttsp_putbl(ts, 9, true, false, false);
2266 }
2267 }
2268 }
2269
2270bypass:
2271 /* switch to System Information mode to read versions
2272 * and set interval registers */
2273 if (!(retval < CY_OK)) {
2274 cyttsp_debug("switch to sysinfo mode \n");
2275 host_reg = CY_SYSINFO_MODE;
2276 retval = i2c_smbus_write_i2c_block_data(ts->client,
2277 CY_REG_BASE, sizeof(host_reg), &host_reg);
2278 /* wait for TTSP Device to complete switch to SysInfo mode */
2279 mdelay(100);
2280 if (!(retval < CY_OK)) {
2281 retval = i2c_smbus_read_i2c_block_data(ts->client,
2282 CY_REG_BASE,
2283 sizeof(struct cyttsp_sysinfo_data_t),
2284 (u8 *)&g_sysinfo_data);
2285 cyttsp_debug("SI2: hst_mode=0x%02X mfg_cmd=0x%02X mfg_stat=0x%02X\n", \
2286 g_sysinfo_data.hst_mode, \
2287 g_sysinfo_data.mfg_cmd, \
2288 g_sysinfo_data.mfg_stat);
2289 cyttsp_debug("SI2: bl_ver=0x%02X%02X\n", \
2290 g_sysinfo_data.bl_verh, \
2291 g_sysinfo_data.bl_verl);
2292 cyttsp_debug("SI2: sysinfo act_int=0x%02X tch_tmout=0x%02X lp_int=0x%02X\n", \
2293 g_sysinfo_data.act_intrvl, \
2294 g_sysinfo_data.tch_tmout, \
2295 g_sysinfo_data.lp_intrvl);
2296 cyttsp_info("SI%d: tver=%02X%02X a_id=%02X%02X aver=%02X%02X\n", \
2297 102, \
2298 g_sysinfo_data.tts_verh, \
2299 g_sysinfo_data.tts_verl, \
2300 g_sysinfo_data.app_idh, \
2301 g_sysinfo_data.app_idl, \
2302 g_sysinfo_data.app_verh, \
2303 g_sysinfo_data.app_verl);
2304 cyttsp_info("SI%d: c_id=%02X%02X%02X\n", \
2305 103, \
2306 g_sysinfo_data.cid[0], \
2307 g_sysinfo_data.cid[1], \
2308 g_sysinfo_data.cid[2]);
2309 if (!(retval < CY_OK) &&
2310 (CY_DIFF(ts->platform_data->act_intrvl,
2311 CY_ACT_INTRVL_DFLT) ||
2312 CY_DIFF(ts->platform_data->tch_tmout,
2313 CY_TCH_TMOUT_DFLT) ||
2314 CY_DIFF(ts->platform_data->lp_intrvl,
2315 CY_LP_INTRVL_DFLT))) {
2316 if (!(retval < CY_OK)) {
2317 u8 intrvl_ray[sizeof(ts->platform_data->act_intrvl) +
2318 sizeof(ts->platform_data->tch_tmout) +
2319 sizeof(ts->platform_data->lp_intrvl)];
2320 u8 i = 0;
2321
2322 intrvl_ray[i++] =
2323 ts->platform_data->act_intrvl;
2324 intrvl_ray[i++] =
2325 ts->platform_data->tch_tmout;
2326 intrvl_ray[i++] =
2327 ts->platform_data->lp_intrvl;
2328
2329 cyttsp_debug("SI2: platinfo act_intrvl=0x%02X tch_tmout=0x%02X lp_intrvl=0x%02X\n", \
2330 ts->platform_data->act_intrvl, \
2331 ts->platform_data->tch_tmout, \
2332 ts->platform_data->lp_intrvl);
2333 /* set intrvl registers */
2334 retval = i2c_smbus_write_i2c_block_data(
2335 ts->client,
2336 CY_REG_ACT_INTRVL,
2337 sizeof(intrvl_ray), intrvl_ray);
2338 mdelay(CY_DLY_SYSINFO);
2339 }
2340 }
2341 }
2342 /* switch back to Operational mode */
2343 cyttsp_debug("switch back to operational mode \n");
2344 if (!(retval < CY_OK)) {
2345 host_reg = CY_OP_MODE/* + CY_LOW_PWR_MODE*/;
2346 retval = i2c_smbus_write_i2c_block_data(ts->client,
2347 CY_REG_BASE,
2348 sizeof(host_reg), &host_reg);
2349 /* wait for TTSP Device to complete
2350 * switch to Operational mode */
2351 mdelay(100);
2352 }
2353 }
2354 /* init gesture setup;
2355 * this is required even if not using gestures
2356 * in order to set the active distance */
2357 if (!(retval < CY_OK)) {
2358 u8 gesture_setup;
2359 cyttsp_debug("init gesture setup \n");
2360 gesture_setup = ts->platform_data->gest_set;
2361 retval = i2c_smbus_write_i2c_block_data(ts->client,
2362 CY_REG_GEST_SET,
2363 sizeof(gesture_setup), &gesture_setup);
2364 mdelay(CY_DLY_DFLT);
2365 }
2366
2367 if (!(retval < CY_OK))
2368 ts->platform_data->power_state = CY_ACTIVE_STATE;
2369 else
2370 ts->platform_data->power_state = CY_IDLE_STATE;
2371
2372 cyttsp_debug("Retval=%d Power state is %s\n", \
2373 retval, \
2374 ts->platform_data->power_state == CY_ACTIVE_STATE ? \
2375 "ACTIVE" : "IDLE");
2376
2377 return retval;
2378}
2379
2380static int cyttsp_power_device(struct cyttsp *ts, bool on)
2381{
2382 int rc = 0, i;
2383 const struct cyttsp_regulator *reg_info =
2384 ts->platform_data->regulator_info;
2385 u8 num_reg = ts->platform_data->num_regulators;
2386
2387 if (!reg_info) {
2388 pr_err("regulator pdata not specified\n");
2389 return -EINVAL;
2390 }
2391
2392 if (on == false) /* Turn off the regulators */
2393 goto ts_reg_disable;
2394
2395 ts->vdd = kzalloc(num_reg * sizeof(struct regulator *), GFP_KERNEL);
2396 if (!ts->vdd) {
2397 pr_err("unable to allocate memory\n");
2398 return -ENOMEM;
2399 }
2400
2401 for (i = 0; i < num_reg; i++) {
2402 ts->vdd[i] = regulator_get(&ts->client->dev, reg_info[i].name);
2403 if (IS_ERR(ts->vdd[i])) {
2404 rc = PTR_ERR(ts->vdd[i]);
2405 pr_err("%s:regulator get failed rc=%d\n",
2406 __func__, rc);
2407 goto error_vdd;
2408 }
2409
2410 if (regulator_count_voltages(ts->vdd[i]) > 0) {
2411 rc = regulator_set_voltage(ts->vdd[i],
2412 reg_info[i].min_uV, reg_info[i].max_uV);
2413 if (rc) {
2414 pr_err("%s: regulator_set_voltage"
2415 "failed rc =%d\n", __func__, rc);
2416 regulator_put(ts->vdd[i]);
2417 goto error_vdd;
2418 }
2419 }
2420
2421 rc = regulator_set_optimum_mode(ts->vdd[i],
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05302422 reg_info[i].hpm_load_uA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002423 if (rc < 0) {
2424 pr_err("%s: regulator_set_optimum_mode failed rc=%d\n",
2425 __func__, rc);
2426
2427 regulator_set_voltage(ts->vdd[i], 0,
2428 reg_info[i].max_uV);
2429 regulator_put(ts->vdd[i]);
2430 goto error_vdd;
2431 }
2432
2433 rc = regulator_enable(ts->vdd[i]);
2434 if (rc) {
2435 pr_err("%s: regulator_enable failed rc =%d\n",
2436 __func__, rc);
2437 regulator_set_optimum_mode(ts->vdd[i], 0);
2438 regulator_set_voltage(ts->vdd[i], 0,
2439 reg_info[i].max_uV);
2440 regulator_put(ts->vdd[i]);
2441 goto error_vdd;
2442 }
2443 }
2444
2445 return rc;
2446
2447ts_reg_disable:
2448 i = ts->platform_data->num_regulators;
2449error_vdd:
2450 while (--i >= 0) {
2451 if (regulator_count_voltages(ts->vdd[i]) > 0)
2452 regulator_set_voltage(ts->vdd[i], 0,
2453 reg_info[i].max_uV);
2454 regulator_set_optimum_mode(ts->vdd[i], 0);
2455 regulator_disable(ts->vdd[i]);
2456 regulator_put(ts->vdd[i]);
2457 }
2458 kfree(ts->vdd);
2459 return rc;
2460}
2461
2462/* cyttsp_initialize: Driver Initialization. This function takes
2463 * care of the following tasks:
2464 * 1. Create and register an input device with input layer
2465 * 2. Take CYTTSP device out of bootloader mode; go operational
2466 * 3. Start any timers/Work queues. */
2467static int cyttsp_initialize(struct i2c_client *client, struct cyttsp *ts)
2468{
2469 struct input_dev *input_device;
2470 int error = 0;
2471 int retval = CY_OK;
2472 u8 id;
2473
2474 /* Create the input device and register it. */
2475 input_device = input_allocate_device();
2476 if (!input_device) {
2477 error = -ENOMEM;
2478 cyttsp_xdebug1("err input allocate device\n");
2479 goto error_free_device;
2480 }
2481
2482 if (!client) {
2483 error = ~ENODEV;
2484 cyttsp_xdebug1("err client is Null\n");
2485 goto error_free_device;
2486 }
2487
2488 if (!ts) {
2489 error = ~ENODEV;
2490 cyttsp_xdebug1("err context is Null\n");
2491 goto error_free_device;
2492 }
2493
2494 ts->input = input_device;
2495 input_device->name = CY_I2C_NAME;
2496 input_device->phys = ts->phys;
2497 input_device->dev.parent = &client->dev;
2498
2499 /* init the touch structures */
2500 ts->num_prv_st_tch = CY_NTCH;
2501 for (id = 0; id < CY_NUM_TRK_ID; id++) {
2502 ts->act_trk[id] = CY_NTCH;
2503 ts->prv_mt_pos[id][CY_XPOS] = 0;
2504 ts->prv_mt_pos[id][CY_YPOS] = 0;
2505 }
2506
2507 for (id = 0; id < CY_NUM_MT_TCH_ID; id++)
2508 ts->prv_mt_tch[id] = CY_IGNR_TCH;
2509
2510 for (id = 0; id < CY_NUM_ST_TCH_ID; id++)
2511 ts->prv_st_tch[id] = CY_IGNR_TCH;
2512
2513 set_bit(EV_SYN, input_device->evbit);
2514 set_bit(EV_KEY, input_device->evbit);
2515 set_bit(EV_ABS, input_device->evbit);
2516 set_bit(BTN_TOUCH, input_device->keybit);
2517 set_bit(BTN_2, input_device->keybit);
2518 if (ts->platform_data->use_gestures)
2519 set_bit(BTN_3, input_device->keybit);
2520
2521 input_set_abs_params(input_device, ABS_X, ts->platform_data->disp_minx,
2522 ts->platform_data->disp_maxx, 0, 0);
2523 input_set_abs_params(input_device, ABS_Y, ts->platform_data->disp_miny,
2524 ts->platform_data->disp_maxy, 0, 0);
2525 input_set_abs_params(input_device,
2526 ABS_TOOL_WIDTH, 0, CY_LARGE_TOOL_WIDTH, 0 , 0);
2527 input_set_abs_params(input_device,
2528 ABS_PRESSURE, 0, CY_MAXZ, 0, 0);
2529 input_set_abs_params(input_device,
2530 ABS_HAT0X, 0, ts->platform_data->panel_maxx, 0, 0);
2531 input_set_abs_params(input_device,
2532 ABS_HAT0Y, 0, ts->platform_data->panel_maxy, 0, 0);
2533 if (ts->platform_data->use_gestures) {
2534 input_set_abs_params(input_device,
2535 ABS_HAT1X, 0, CY_MAXZ, 0, 0);
2536 input_set_abs_params(input_device,
2537 ABS_HAT1Y, 0, CY_MAXZ, 0, 0);
2538 }
2539 if (ts->platform_data->use_mt) {
2540 input_set_abs_params(input_device, ABS_MT_POSITION_X,
2541 ts->platform_data->disp_minx,
2542 ts->platform_data->disp_maxx, 0, 0);
2543 input_set_abs_params(input_device, ABS_MT_POSITION_Y,
2544 ts->platform_data->disp_miny,
2545 ts->platform_data->disp_maxy, 0, 0);
2546 input_set_abs_params(input_device,
2547 ABS_MT_TOUCH_MAJOR, 0, CY_MAXZ, 0, 0);
2548 input_set_abs_params(input_device,
2549 ABS_MT_WIDTH_MAJOR, 0, CY_LARGE_TOOL_WIDTH, 0, 0);
2550 if (ts->platform_data->use_trk_id) {
2551 input_set_abs_params(input_device,
2552 ABS_MT_TRACKING_ID, 0, CY_NUM_TRK_ID, 0, 0);
2553 }
2554 }
2555
2556 /* set dummy key to make driver work with virtual keys */
2557 input_set_capability(input_device, EV_KEY, KEY_PROG1);
2558
2559 cyttsp_info("%s: Register input device\n", CY_I2C_NAME);
2560 error = input_register_device(input_device);
2561 if (error) {
2562 cyttsp_alert("%s: Failed to register input device\n", \
2563 CY_I2C_NAME);
2564 retval = error;
2565 goto error_free_device;
2566 }
2567
2568 /* Prepare our worker structure prior to setting up the timer/ISR */
2569 INIT_WORK(&ts->work, cyttsp_xy_worker);
2570
2571 if (gpio_is_valid(ts->platform_data->resout_gpio)) {
2572 /* configure touchscreen reset out gpio */
2573 retval = gpio_request(ts->platform_data->resout_gpio,
2574 "cyttsp_resout_gpio");
2575 if (retval) {
2576 pr_err("%s: unable to request reset gpio %d\n",
2577 __func__, ts->platform_data->resout_gpio);
2578 goto error_free_device;
2579 }
2580
2581 retval = gpio_direction_output(
2582 ts->platform_data->resout_gpio, 1);
2583 if (retval) {
2584 pr_err("%s: unable to set direction for gpio %d\n",
2585 __func__, ts->platform_data->resout_gpio);
2586 goto error_resout_gpio_dir;
2587 }
2588 }
2589
2590 if (gpio_is_valid(ts->platform_data->sleep_gpio)) {
2591 /* configure touchscreen reset out gpio */
2592 retval = gpio_request(ts->platform_data->sleep_gpio,
2593 "cy8c_sleep_gpio");
2594 if (retval) {
2595 pr_err("%s: unable to request sleep gpio %d\n",
2596 __func__, ts->platform_data->sleep_gpio);
2597 goto error_sleep_gpio_req;
2598 }
2599
2600 retval = gpio_direction_output(
2601 ts->platform_data->sleep_gpio, 0);
2602 if (retval) {
2603 pr_err("%s: unable to set direction for gpio %d\n",
2604 __func__, ts->platform_data->resout_gpio);
2605 goto error_sleep_gpio_dir;
2606 }
2607 }
2608
2609 if (gpio_is_valid(ts->platform_data->irq_gpio)) {
2610 /* configure touchscreen irq gpio */
2611 retval = gpio_request(ts->platform_data->irq_gpio,
2612 "ts_irq_gpio");
2613 if (retval) {
2614 pr_err("%s: unable to request gpio [%d]\n", __func__,
2615 ts->platform_data->irq_gpio);
2616 goto error_irq_gpio_req;
2617 }
2618 retval = gpio_direction_input(ts->platform_data->irq_gpio);
2619 if (retval) {
2620 pr_err("%s: unable to set_direction for gpio [%d]\n",
2621 __func__, ts->platform_data->irq_gpio);
2622 goto error_irq_gpio_dir;
2623 }
2624 }
2625
2626 if (ts->platform_data->regulator_info) {
2627 retval = cyttsp_power_device(ts, true);
2628 if (retval) {
2629 pr_err("%s: Unable to power device %d\n",
2630 __func__, retval);
2631 goto error_irq_gpio_dir;
2632 }
2633 }
2634
2635 /* Power on the chip and make sure that I/Os are set as specified
2636 * in the platform */
2637 if (ts->platform_data->init) {
2638 retval = ts->platform_data->init(client);
2639 if (retval) {
2640 pr_err("%s: ts init failed\n", __func__);
2641 goto error_power_device;
2642 }
2643 }
2644
2645 msleep(100);
2646
2647 /* check this device active by reading first byte/register */
2648 retval = i2c_smbus_read_byte_data(ts->client, 0x01);
2649 if (retval < 0) {
2650 pr_err("%s: i2c sanity check failed\n", __func__);
2651 goto error_power_device;
2652 }
2653
2654 retval = cyttsp_power_on(ts);
2655 if (retval < 0) {
2656 pr_err("%s: cyttsp_power_on failed\n", __func__);
2657 goto error_power_device;
2658 }
2659
2660 /* Timer or Interrupt setup */
2661 if (ts->client->irq == 0) {
2662 cyttsp_info("Setting up timer\n");
2663 setup_timer(&ts->timer, cyttsp_timer, (unsigned long) ts);
2664 mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
2665 } else {
2666 cyttsp_info("Setting up interrupt\n");
2667 /* request_irq() will also call enable_irq() */
2668 error = request_irq(client->irq, cyttsp_irq,
2669 IRQF_TRIGGER_FALLING,
2670 client->dev.driver->name, ts);
2671 if (error) {
2672 cyttsp_alert("error: could not request irq\n");
2673 retval = error;
2674 goto error_power_device;
2675 }
2676 }
2677
2678 irq_cnt = 0;
2679 irq_cnt_total = 0;
2680 irq_err_cnt = 0;
2681
2682 atomic_set(&ts->irq_enabled, 1);
2683 retval = device_create_file(&ts->client->dev, &dev_attr_irq_enable);
2684 if (retval < CY_OK) {
2685 cyttsp_alert("File device creation failed: %d\n", retval);
2686 retval = -ENODEV;
2687 goto error_free_irq;
2688 }
2689
2690 retval = device_create_file(&client->dev, &dev_attr_cyttsp_fw_ver);
2691 if (retval) {
2692 cyttsp_alert("sysfs entry for firmware version failed\n");
2693 goto error_rm_dev_file_irq_en;
2694 }
2695
2696 ts->cyttsp_fwloader_mode = 0;
2697 retval = device_create_file(&client->dev, &dev_attr_cyttsp_update_fw);
2698 if (retval) {
2699 cyttsp_alert("sysfs entry for firmware update failed\n");
2700 goto error_rm_dev_file_fw_ver;
2701 }
2702
2703 retval = device_create_file(&client->dev,
2704 &dev_attr_cyttsp_force_update_fw);
2705 if (retval) {
2706 cyttsp_alert("sysfs entry for force firmware update failed\n");
2707 goto error_rm_dev_file_update_fw;
2708 }
2709 if (ts->platform_data->correct_fw_ver) {
2710 if (g_bl_data.appid_lo != ts->platform_data->correct_fw_ver)
Mohan Pallaka1cef4a02011-08-01 11:48:42 +05302711 pr_warn("%s: Invalid firmware version detected;"
2712 " Please update.\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002713 }
2714
2715 retval = device_create_file(&client->dev,
2716 &dev_attr_cyttsp_fw_name);
2717 if (retval) {
2718 cyttsp_alert("sysfs entry for file name selection failed\n");
2719 goto error_rm_dev_file_fupdate_fw;
2720 }
2721
2722 cyttsp_info("%s: Successful registration\n", CY_I2C_NAME);
2723
2724 goto success;
2725
2726error_rm_dev_file_fupdate_fw:
2727 device_remove_file(&client->dev, &dev_attr_cyttsp_force_update_fw);
2728error_rm_dev_file_update_fw:
2729 device_remove_file(&client->dev, &dev_attr_cyttsp_update_fw);
2730error_rm_dev_file_fw_ver:
2731 device_remove_file(&client->dev, &dev_attr_cyttsp_fw_ver);
2732error_rm_dev_file_irq_en:
2733 device_remove_file(&client->dev, &dev_attr_irq_enable);
2734error_free_irq:
2735 if (ts->client->irq)
2736 free_irq(client->irq, ts);
2737error_power_device:
2738 if (ts->platform_data->regulator_info)
2739 cyttsp_power_device(ts, false);
2740error_irq_gpio_dir:
2741 if (gpio_is_valid(ts->platform_data->irq_gpio))
2742 gpio_free(ts->platform_data->irq_gpio);
2743error_irq_gpio_req:
2744 if (gpio_is_valid(ts->platform_data->sleep_gpio))
2745 gpio_direction_output(ts->platform_data->sleep_gpio, 1);
2746error_sleep_gpio_dir:
2747 if (gpio_is_valid(ts->platform_data->sleep_gpio))
2748 gpio_free(ts->platform_data->sleep_gpio);
2749error_sleep_gpio_req:
2750 if (gpio_is_valid(ts->platform_data->resout_gpio))
2751 gpio_direction_output(ts->platform_data->resout_gpio, 0);
2752error_resout_gpio_dir:
2753 if (gpio_is_valid(ts->platform_data->resout_gpio))
2754 gpio_free(ts->platform_data->resout_gpio);
2755error_free_device:
2756 if (input_device)
2757 input_free_device(input_device);
2758
2759success:
2760 return retval;
2761}
2762
2763/* I2C driver probe function */
2764static int __devinit cyttsp_probe(struct i2c_client *client,
2765 const struct i2c_device_id *id)
2766{
2767 struct cyttsp *ts;
2768 int error;
2769 int retval = CY_OK;
2770
2771 cyttsp_info("Start Probe 1.2\n");
2772
2773 /* allocate and clear memory */
2774 ts = kzalloc(sizeof(struct cyttsp), GFP_KERNEL);
2775 if (ts == NULL) {
2776 cyttsp_xdebug1("err kzalloc for cyttsp\n");
2777 retval = -ENOMEM;
2778 }
2779
2780 /* Enable runtime PM ops, start in ACTIVE mode */
2781 error = pm_runtime_set_active(&client->dev);
2782 if (error < 0)
2783 dev_dbg(&client->dev, "unable to set runtime pm state\n");
2784 pm_runtime_enable(&client->dev);
2785
2786 if (!(retval < CY_OK)) {
2787 /* register driver_data */
2788 ts->client = client;
2789 ts->platform_data = client->dev.platform_data;
2790
2791 if (ts->platform_data->fw_fname)
Mohan Pallaka9c050f12011-09-29 18:17:35 +05302792 strlcpy(ts->fw_fname, ts->platform_data->fw_fname,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002793 FW_FNAME_LEN - 1);
2794 else
Mohan Pallaka9c050f12011-09-29 18:17:35 +05302795 strlcpy(ts->fw_fname, "cyttsp.hex", FW_FNAME_LEN - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002796
Amy Malocheedd5fd72011-06-22 18:50:21 -07002797 if (ts->platform_data->gen == CY_GEN3) {
2798 ts->fw_start_addr = 0x0b00;
2799 } else if (ts->platform_data->gen == CY_GEN2) {
2800 ts->fw_start_addr = 0x0880;
2801 } else {
2802 pr_err("%s: unsupported cypress chip\n", __func__);
2803 kfree(ts);
2804 return -EINVAL;
2805 }
2806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002807 i2c_set_clientdata(client, ts);
2808
2809 error = cyttsp_initialize(client, ts);
2810 if (error) {
2811 cyttsp_xdebug1("err cyttsp_initialize\n");
2812 if (ts != NULL) {
2813 /* deallocate memory */
2814 kfree(ts);
2815 }
2816/*
2817 i2c_del_driver(&cyttsp_driver);
2818*/
Mohan Pallaka04b7f792011-09-29 18:17:35 +05302819 return -ENODEV;
2820 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002821 }
2822
2823#ifdef CONFIG_HAS_EARLYSUSPEND
2824 if (!(retval < CY_OK)) {
2825 ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
2826 ts->early_suspend.suspend = cyttsp_early_suspend;
2827 ts->early_suspend.resume = cyttsp_late_resume;
2828 register_early_suspend(&ts->early_suspend);
2829 }
2830#endif /* CONFIG_HAS_EARLYSUSPEND */
2831 device_init_wakeup(&client->dev, ts->platform_data->wakeup);
2832 mutex_init(&ts->mutex);
2833
2834 cyttsp_info("Start Probe %s\n", \
2835 (retval < CY_OK) ? "FAIL" : "PASS");
2836
2837 return retval;
2838}
2839
Anirudh Ghayal909dcfd2011-09-08 13:35:53 +05302840#ifdef CONFIG_PM
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05302841static int cyttsp_regulator_lpm(struct cyttsp *ts, bool on)
2842{
2843 int rc = 0, i;
2844 const struct cyttsp_regulator *reg_info =
2845 ts->platform_data->regulator_info;
2846 u8 num_reg = ts->platform_data->num_regulators;
2847
2848 if (on == false)
2849 goto regulator_hpm;
2850
2851 for (i = 0; i < num_reg; i++) {
2852 rc = regulator_set_optimum_mode(ts->vdd[i],
2853 reg_info[i].lpm_load_uA);
2854 if (rc < 0) {
2855 pr_err("%s: regulator_set_optimum failed rc = %d\n",
2856 __func__, rc);
2857 goto fail_regulator_lpm;
2858 }
2859
2860 }
2861
2862 return 0;
2863
2864regulator_hpm:
2865 for (i = 0; i < num_reg; i++) {
2866 rc = regulator_set_optimum_mode(ts->vdd[i],
2867 reg_info[i].hpm_load_uA);
2868 if (rc < 0) {
2869 pr_err("%s: regulator_set_optimum failed"
2870 "rc = %d\n", __func__, rc);
2871 goto fail_regulator_hpm;
2872 }
2873 }
2874
2875 return 0;
2876
2877fail_regulator_lpm:
2878 while (i--)
2879 regulator_set_optimum_mode(ts->vdd[i],
2880 reg_info[i].hpm_load_uA);
2881
2882 return rc;
2883
2884fail_regulator_hpm:
2885 while (i--)
2886 regulator_set_optimum_mode(ts->vdd[i],
2887 reg_info[i].lpm_load_uA);
2888
2889 return rc;
2890}
2891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002892/* Function to manage power-on resume */
2893static int cyttsp_resume(struct device *dev)
2894{
2895 struct cyttsp *ts = dev_get_drvdata(dev);
2896 int retval = CY_OK;
2897
2898 cyttsp_debug("Wake Up\n");
2899
2900 if (ts->is_suspended == false) {
2901 pr_err("%s: in wakeup state\n", __func__);
2902 return 0;
2903 }
2904
2905 if (device_may_wakeup(dev)) {
2906 if (ts->client->irq)
2907 disable_irq_wake(ts->client->irq);
2908 return 0;
2909 }
2910
2911 /* re-enable the interrupt prior to wake device */
2912 if (ts->client->irq)
2913 enable_irq(ts->client->irq);
2914
2915 if (ts->platform_data->use_sleep &&
2916 (ts->platform_data->power_state != CY_ACTIVE_STATE)) {
2917 if (ts->platform_data->resume)
2918 retval = ts->platform_data->resume(ts->client);
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05302919 else
2920 retval = cyttsp_regulator_lpm(ts, false);
Amy Maloche13dcf552011-08-22 15:38:44 -07002921 /* take TTSP device out of bootloader mode;
2922 * switch back to TrueTouch operational mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002923 if (!(retval < CY_OK)) {
Amy Maloche13dcf552011-08-22 15:38:44 -07002924 int tries = 0;
2925 do {
2926 msleep(100);
2927 retval = i2c_smbus_write_i2c_block_data(
2928 ts->client, CY_REG_BASE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929 sizeof(bl_cmd), bl_cmd);
Amy Maloche13dcf552011-08-22 15:38:44 -07002930 if (retval == CY_OK)
2931 break;
2932 } while (tries++ < 2);
2933 /* wait for TTSP Device to complete
2934 * switch to Operational mode */
2935 tries = 0;
2936 do {
2937 msleep(100);
2938 cyttsp_putbl(ts, 16, false, false, false);
2939 } while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
2940 tries++ < 2);
2941 cyttsp_putbl(ts, 16, true, false, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002942 }
2943 }
2944
2945 if (!(retval < CY_OK) &&
2946 (GET_HSTMODE(g_bl_data.bl_file) == CY_OK)) {
2947 ts->platform_data->power_state = CY_ACTIVE_STATE;
2948
2949 /* re-enable the timer after resuming */
2950 if (ts->client->irq == 0)
2951 mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
2952 } else
2953 retval = -ENODEV;
2954
2955 ts->is_suspended = false;
2956 cyttsp_debug("Wake Up %s\n", \
2957 (retval < CY_OK) ? "FAIL" : "PASS");
2958
2959 return retval;
2960}
2961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002962/* Function to manage low power suspend */
2963static int cyttsp_suspend(struct device *dev)
2964{
2965 struct cyttsp *ts = dev_get_drvdata(dev);
2966 u8 sleep_mode = CY_OK;
2967 int retval = CY_OK;
2968
2969 cyttsp_debug("Enter Sleep\n");
2970
2971 if (ts->is_suspended == true) {
2972 pr_err("%s: in sleep state\n", __func__);
2973 return 0;
2974 }
2975
2976 mutex_lock(&ts->mutex);
2977 if (ts->cyttsp_fwloader_mode) {
2978 pr_err("%s:firmware upgrade mode:"
2979 "suspend not allowed\n", __func__);
2980 mutex_unlock(&ts->mutex);
2981 return -EBUSY;
2982 }
2983 mutex_unlock(&ts->mutex);
2984
2985 if (device_may_wakeup(dev)) {
2986 if (ts->client->irq)
2987 enable_irq_wake(ts->client->irq);
2988 return 0;
2989 }
2990
2991 /* disable worker */
2992 if (ts->client->irq == 0)
2993 del_timer(&ts->timer);
2994 else
2995 disable_irq_nosync(ts->client->irq);
2996 retval = cancel_work_sync(&ts->work);
2997
2998 if (retval)
2999 enable_irq(ts->client->irq);
3000
3001 if (!(retval < CY_OK)) {
3002 if (ts->platform_data->use_sleep &&
3003 (ts->platform_data->power_state == CY_ACTIVE_STATE)) {
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05303004 if (ts->platform_data->suspend) {
3005 retval =
3006 ts->platform_data->suspend(ts->client);
3007 } else {
3008 retval = cyttsp_regulator_lpm(ts, true);
3009 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003010 if (ts->platform_data->use_sleep & CY_USE_DEEP_SLEEP_SEL)
3011 sleep_mode = CY_DEEP_SLEEP_MODE;
3012 else
3013 sleep_mode = CY_LOW_PWR_MODE;
3014
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05303015 if (!(retval < CY_OK)) {
3016 retval =
3017 i2c_smbus_write_i2c_block_data(ts->client,
3018 CY_REG_BASE,
3019 sizeof(sleep_mode), &sleep_mode);
3020 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003021 }
3022 }
3023
3024 if (!(retval < CY_OK)) {
3025 if (sleep_mode == CY_DEEP_SLEEP_MODE)
3026 ts->platform_data->power_state = CY_SLEEP_STATE;
3027 else if (sleep_mode == CY_LOW_PWR_MODE)
3028 ts->platform_data->power_state = CY_LOW_PWR_STATE;
3029 }
3030
3031 ts->is_suspended = true;
3032 cyttsp_debug("Sleep Power state is %s\n", \
3033 (ts->platform_data->power_state == CY_ACTIVE_STATE) ? \
3034 "ACTIVE" : \
3035 ((ts->platform_data->power_state == CY_SLEEP_STATE) ? \
3036 "SLEEP" : "LOW POWER"));
3037
3038 return retval;
3039}
Anirudh Ghayal84e51192011-09-03 08:05:25 +05303040#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003041
3042/* registered in driver struct */
3043static int __devexit cyttsp_remove(struct i2c_client *client)
3044{
3045 /* clientdata registered on probe */
3046 struct cyttsp *ts = i2c_get_clientdata(client);
3047 int err;
3048
3049 cyttsp_alert("Unregister\n");
3050
3051 pm_runtime_set_suspended(&client->dev);
3052 pm_runtime_disable(&client->dev);
3053
3054 device_init_wakeup(&client->dev, 0);
3055 device_remove_file(&ts->client->dev, &dev_attr_irq_enable);
3056 device_remove_file(&client->dev, &dev_attr_cyttsp_fw_ver);
3057 device_remove_file(&client->dev, &dev_attr_cyttsp_update_fw);
3058 device_remove_file(&client->dev, &dev_attr_cyttsp_force_update_fw);
3059 device_remove_file(&client->dev, &dev_attr_cyttsp_fw_name);
3060
3061 /* Start cleaning up by removing any delayed work and the timer */
3062 if (cancel_delayed_work((struct delayed_work *)&ts->work) < CY_OK)
3063 cyttsp_alert("error: could not remove work from workqueue\n");
3064
3065 /* free up timer or irq */
3066 if (ts->client->irq == 0) {
3067 err = del_timer(&ts->timer);
3068 if (err < CY_OK)
3069 cyttsp_alert("error: failed to delete timer\n");
3070 } else
3071 free_irq(client->irq, ts);
3072
3073 if (ts->platform_data->regulator_info)
3074 cyttsp_power_device(ts, false);
3075
3076#ifdef CONFIG_HAS_EARLYSUSPEND
3077 unregister_early_suspend(&ts->early_suspend);
3078#endif /* CONFIG_HAS_EARLYSUSPEND */
3079
3080 mutex_destroy(&ts->mutex);
3081
3082 if (gpio_is_valid(ts->platform_data->sleep_gpio)) {
3083 gpio_direction_output(ts->platform_data->sleep_gpio, 1);
3084 gpio_free(ts->platform_data->sleep_gpio);
3085 }
3086
3087 if (gpio_is_valid(ts->platform_data->resout_gpio)) {
3088 gpio_direction_output(ts->platform_data->resout_gpio, 0);
3089 gpio_free(ts->platform_data->resout_gpio);
3090 }
3091
3092 if (gpio_is_valid(ts->platform_data->irq_gpio))
3093 gpio_free(ts->platform_data->irq_gpio);
3094
3095 /* housekeeping */
3096 if (ts != NULL)
3097 kfree(ts);
3098
3099 cyttsp_alert("Leaving\n");
3100
3101 return 0;
3102}
3103
3104#ifdef CONFIG_HAS_EARLYSUSPEND
3105static void cyttsp_early_suspend(struct early_suspend *handler)
3106{
3107 struct cyttsp *ts;
3108
3109 ts = container_of(handler, struct cyttsp, early_suspend);
3110 cyttsp_suspend(&ts->client->dev);
3111}
3112
3113static void cyttsp_late_resume(struct early_suspend *handler)
3114{
3115 struct cyttsp *ts;
3116
3117 ts = container_of(handler, struct cyttsp, early_suspend);
3118 cyttsp_resume(&ts->client->dev);
3119}
3120#endif /* CONFIG_HAS_EARLYSUSPEND */
3121
3122static int cyttsp_init(void)
3123{
3124 int ret;
3125
3126 cyttsp_info("Cypress TrueTouch(R) Standard Product\n");
3127 cyttsp_info("I2C Touchscreen Driver (Built %s @ %s)\n", \
3128 __DATE__, __TIME__);
3129
3130 cyttsp_ts_wq = create_singlethread_workqueue("cyttsp_ts_wq");
3131 if (cyttsp_ts_wq == NULL) {
3132 cyttsp_debug("No memory for cyttsp_ts_wq\n");
3133 return -ENOMEM;
3134 }
3135
3136 ret = i2c_add_driver(&cyttsp_driver);
3137
3138 return ret;
3139}
3140
3141static void cyttsp_exit(void)
3142{
3143 if (cyttsp_ts_wq)
3144 destroy_workqueue(cyttsp_ts_wq);
3145 return i2c_del_driver(&cyttsp_driver);
3146}
3147
3148module_init(cyttsp_init);
3149module_exit(cyttsp_exit);
3150MODULE_FIRMWARE("cyttsp.fw");
3151