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