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