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