blob: 4aa4796c4dc622d58fdb78e8d519ef98f1e8e731 [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;
938
Mohan Pallaka07a08072011-10-21 13:04:21 +0530939 cyttsp_xdebug("TTSP handler start 1:\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940
941 /* get event data from CYTTSP device */
942 i = CY_NUM_RETRY;
943 do {
944 retval = i2c_smbus_read_i2c_block_data(ts->client,
945 CY_REG_BASE,
946 sizeof(struct cyttsp_gen3_xydata_t), (u8 *)&g_xy_data);
947 } while ((retval < CY_OK) && --i);
948
949 if (retval < CY_OK) {
950 /* return immediately on
951 * failure to read device on the i2c bus */
Mohan Pallaka07a08072011-10-21 13:04:21 +0530952 goto exit_xy_handler;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700953 }
954
Mohan Pallaka07a08072011-10-21 13:04:21 +0530955 cyttsp_xdebug("TTSP handler start 2:\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700956
957 /* compare own irq counter with the device irq counter */
958 if (ts->client->irq) {
959 u8 host_reg;
960 u8 cur_cnt;
961 if (ts->platform_data->use_hndshk) {
962
963 host_reg = g_xy_data.hst_mode & CY_HNDSHK_BIT ?
964 g_xy_data.hst_mode & ~CY_HNDSHK_BIT :
965 g_xy_data.hst_mode | CY_HNDSHK_BIT;
966 retval = i2c_smbus_write_i2c_block_data(ts->client,
967 CY_REG_BASE, sizeof(host_reg), &host_reg);
968 }
969 cur_cnt = g_xy_data.tt_undef[CY_IRQ_CNT_REG];
970 irq_cnt_total++;
971 irq_cnt++;
972 if (irq_cnt != cur_cnt) {
973 irq_err_cnt++;
974 cyttsp_debug("i_c_ER: dv=%d fw=%d hm=%02X t=%lu te=%lu\n", \
975 irq_cnt, \
976 cur_cnt, g_xy_data.hst_mode, \
977 (unsigned long)irq_cnt_total, \
978 (unsigned long)irq_err_cnt);
979 } else {
980 cyttsp_debug("i_c_ok: dv=%d fw=%d hm=%02X t=%lu te=%lu\n", \
981 irq_cnt, \
982 cur_cnt, g_xy_data.hst_mode, \
983 (unsigned long)irq_cnt_total, \
984 (unsigned long)irq_err_cnt);
985 }
986 irq_cnt = cur_cnt;
987 }
988
989 /* Get the current num touches and return if there are no touches */
990 if ((GET_BOOTLOADERMODE(g_xy_data.tt_mode) == 1) ||
991 (GET_HSTMODE(g_xy_data.hst_mode) != CY_OK)) {
992 u8 host_reg, tries;
993 /* the TTSP device has suffered spurious reset or mode switch */
994 cyttsp_debug( \
995 "Spurious err opmode (tt_mode=%02X hst_mode=%02X)\n", \
996 g_xy_data.tt_mode, g_xy_data.hst_mode);
997 cyttsp_debug("Reset TTSP Device; Terminating active tracks\n");
998 /* terminate all active tracks */
999 cur_tch = CY_NTCH;
1000 /* reset TTSP part and take it back out of Bootloader mode */
1001 /* reset TTSP Device back to bootloader mode */
1002 host_reg = CY_SOFT_RESET_MODE;
1003 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
1004 sizeof(host_reg), &host_reg);
1005 /* wait for TTSP Device to complete reset back to bootloader */
1006 tries = 0;
1007 do {
1008 mdelay(1);
1009 cyttsp_putbl(ts, 1, false, false, false);
1010 } while (g_bl_data.bl_status != 0x10 &&
1011 g_bl_data.bl_status != 0x11 &&
1012 tries++ < 100);
1013 retval = cyttsp_putbl(ts, 1, true, true, true);
1014 /* switch back to operational mode */
1015 /* take TTSP device out of bootloader mode;
1016 * switch back to TrueTouch operational mode */
1017 if (!(retval < CY_OK)) {
1018 int tries;
1019 retval = i2c_smbus_write_i2c_block_data(ts->client,
1020 CY_REG_BASE,
1021 sizeof(bl_cmd), bl_cmd);
1022 /* wait for TTSP Device to complete
1023 * switch to Operational mode */
1024 tries = 0;
1025 do {
1026 mdelay(100);
1027 cyttsp_putbl(ts, 2, false, false, false);
1028 } while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
1029 tries++ < 100);
1030 cyttsp_putbl(ts, 2, true, false, false);
1031 }
Mohan Pallaka07a08072011-10-21 13:04:21 +05301032 goto exit_xy_handler;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 } else {
1034 cur_tch = GET_NUM_TOUCHES(g_xy_data.tt_stat);
1035 if (IS_LARGE_AREA(g_xy_data.tt_stat)) {
1036 /* terminate all active tracks */
1037 cur_tch = CY_NTCH;
1038 cyttsp_debug("Large obj detect (tt_stat=0x%02X). Terminate act trks\n", \
1039 g_xy_data.tt_stat);
1040 } else if (cur_tch > CY_NUM_MT_TCH_ID) {
1041 /* if the number of fingers on the touch surface
1042 * is more than the maximum then
1043 * there will be no new track information
1044 * even for the original touches.
1045 * Therefore, terminate all active tracks.
1046 */
1047 cur_tch = CY_NTCH;
1048 cyttsp_debug("Num touch err (tt_stat=0x%02X). Terminate act trks\n", \
1049 g_xy_data.tt_stat);
1050 }
1051 }
1052
1053 /* set tool size */
1054 curr_tool_width = CY_SMALL_TOOL_WIDTH;
1055
1056 /* translate Gen2 interface data into comparable Gen3 data */
1057 if (ts->platform_data->gen == CY_GEN2) {
1058 struct cyttsp_gen2_xydata_t *pxy_gen2_data;
1059 pxy_gen2_data = (struct cyttsp_gen2_xydata_t *)(&g_xy_data);
1060
1061 /* use test data? */
1062 cyttsp_testdat(&g_xy_data, &tt_gen2_testray, \
1063 sizeof(struct cyttsp_gen3_xydata_t));
1064
Mohan Pallaka727225f2011-08-18 11:09:49 +05301065 if (ts->platform_data->disable_ghost_det &&
1066 (cur_tch == CY_GEN2_GHOST))
1067 cur_tch = CY_GEN2_2TOUCH;
1068
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069 if (pxy_gen2_data->evnt_idx == CY_GEN2_NOTOUCH) {
1070 cur_tch = 0;
1071 } else if (cur_tch == CY_GEN2_GHOST) {
1072 cur_tch = 0;
1073 } else if (cur_tch == CY_GEN2_2TOUCH) {
1074 /* stuff artificial track ID1 and ID2 */
1075 g_xy_data.touch12_id = 0x12;
1076 g_xy_data.z1 = CY_MAXZ;
1077 g_xy_data.z2 = CY_MAXZ;
1078 cur_tch--; /* 2 touches */
1079 } else if (cur_tch == CY_GEN2_1TOUCH) {
1080 /* stuff artificial track ID1 and ID2 */
1081 g_xy_data.touch12_id = 0x12;
1082 g_xy_data.z1 = CY_MAXZ;
1083 g_xy_data.z2 = CY_NTCH;
1084 if (pxy_gen2_data->evnt_idx == CY_GEN2_TOUCH2) {
1085 /* push touch 2 data into touch1
1086 * (first finger up; second finger down) */
1087 /* stuff artificial track ID1 for touch2 info */
1088 g_xy_data.touch12_id = 0x20;
1089 /* stuff touch 1 with touch 2 coordinate data */
1090 g_xy_data.x1 = g_xy_data.x2;
1091 g_xy_data.y1 = g_xy_data.y2;
1092 }
1093 } else {
1094 cur_tch = 0;
1095 }
1096 } else {
1097 /* use test data? */
1098 cyttsp_testdat(&g_xy_data, &tt_gen3_testray, \
1099 sizeof(struct cyttsp_gen3_xydata_t));
1100 }
1101
1102
1103
1104 /* clear current active track ID array and count previous touches */
1105 for (id = 0, prv_tch = CY_NTCH;
1106 id < CY_NUM_TRK_ID; id++) {
1107 cur_trk[id] = CY_NTCH;
1108 prv_tch += ts->act_trk[id];
1109 }
1110
1111 /* send no events if no previous touches and no new touches */
1112 if ((prv_tch == CY_NTCH) &&
1113 ((cur_tch == CY_NTCH) ||
1114 (cur_tch > CY_NUM_MT_TCH_ID))) {
Mohan Pallaka07a08072011-10-21 13:04:21 +05301115 goto exit_xy_handler;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116 }
1117
1118 cyttsp_debug("prev=%d curr=%d\n", prv_tch, cur_tch);
1119
1120 for (id = 0; id < CY_NUM_ST_TCH_ID; id++) {
1121 /* clear current single touches array */
1122 cur_st_tch[id] = CY_IGNR_TCH;
1123 }
1124
1125 /* clear single touch positions */
1126 st_x1 = CY_NTCH;
1127 st_y1 = CY_NTCH;
1128 st_z1 = CY_NTCH;
1129 st_x2 = CY_NTCH;
1130 st_y2 = CY_NTCH;
1131 st_z2 = CY_NTCH;
1132
1133 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1134 /* clear current multi-touches array and
1135 * multi-touch positions/z */
1136 cur_mt_tch[id] = CY_IGNR_TCH;
1137 }
1138
1139 if (ts->platform_data->use_trk_id) {
1140 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1141 cur_mt_pos[id][CY_XPOS] = 0;
1142 cur_mt_pos[id][CY_YPOS] = 0;
1143 cur_mt_z[id] = 0;
1144 }
1145 } else {
1146 for (id = 0; id < CY_NUM_TRK_ID; id++) {
1147 cur_mt_pos[id][CY_XPOS] = 0;
1148 cur_mt_pos[id][CY_YPOS] = 0;
1149 cur_mt_z[id] = 0;
1150 }
1151 }
1152
1153 /* Determine if display is tilted */
1154 if (FLIP_DATA(ts->platform_data->flags))
1155 tilt = true;
1156 else
1157 tilt = false;
1158
1159 /* Check for switch in origin */
1160 if (REVERSE_X(ts->platform_data->flags))
1161 rev_x = true;
1162 else
1163 rev_x = false;
1164
1165 if (REVERSE_Y(ts->platform_data->flags))
1166 rev_y = true;
1167 else
1168 rev_y = false;
1169
1170 if (cur_tch) {
1171 struct cyttsp_gen2_xydata_t *pxy_gen2_data;
1172 struct cyttsp_gen3_xydata_t *pxy_gen3_data;
1173 switch (ts->platform_data->gen) {
1174 case CY_GEN2: {
1175 pxy_gen2_data =
1176 (struct cyttsp_gen2_xydata_t *)(&g_xy_data);
1177 cyttsp_xdebug("TTSP Gen2 report:\n");
1178 cyttsp_xdebug("%02X %02X %02X\n", \
1179 pxy_gen2_data->hst_mode, \
1180 pxy_gen2_data->tt_mode, \
1181 pxy_gen2_data->tt_stat);
1182 cyttsp_xdebug("%04X %04X %02X %02X\n", \
1183 pxy_gen2_data->x1, \
1184 pxy_gen2_data->y1, \
1185 pxy_gen2_data->z1, \
1186 pxy_gen2_data->evnt_idx);
1187 cyttsp_xdebug("%04X %04X %02X\n", \
1188 pxy_gen2_data->x2, \
1189 pxy_gen2_data->y2, \
1190 pxy_gen2_data->tt_undef1);
1191 cyttsp_xdebug("%02X %02X %02X\n", \
1192 pxy_gen2_data->gest_cnt, \
1193 pxy_gen2_data->gest_id, \
1194 pxy_gen2_data->gest_set);
1195 break;
1196 }
1197 case CY_GEN3:
1198 default: {
1199 pxy_gen3_data =
1200 (struct cyttsp_gen3_xydata_t *)(&g_xy_data);
1201 cyttsp_xdebug("TTSP Gen3 report:\n");
1202 cyttsp_xdebug("%02X %02X %02X\n", \
1203 pxy_gen3_data->hst_mode,
1204 pxy_gen3_data->tt_mode,
1205 pxy_gen3_data->tt_stat);
1206 cyttsp_xdebug("%04X %04X %02X %02X", \
1207 pxy_gen3_data->x1,
1208 pxy_gen3_data->y1,
1209 pxy_gen3_data->z1, \
1210 pxy_gen3_data->touch12_id);
1211 cyttsp_xdebug("%04X %04X %02X\n", \
1212 pxy_gen3_data->x2, \
1213 pxy_gen3_data->y2, \
1214 pxy_gen3_data->z2);
1215 cyttsp_xdebug("%02X %02X %02X\n", \
1216 pxy_gen3_data->gest_cnt, \
1217 pxy_gen3_data->gest_id, \
1218 pxy_gen3_data->gest_set);
1219 cyttsp_xdebug("%04X %04X %02X %02X\n", \
1220 pxy_gen3_data->x3, \
1221 pxy_gen3_data->y3, \
1222 pxy_gen3_data->z3, \
1223 pxy_gen3_data->touch34_id);
1224 cyttsp_xdebug("%04X %04X %02X\n", \
1225 pxy_gen3_data->x4, \
1226 pxy_gen3_data->y4, \
1227 pxy_gen3_data->z4);
1228 break;
1229 }
1230 }
1231 }
1232
1233 /* process the touches */
1234 switch (cur_tch) {
1235 case 4: {
1236 g_xy_data.x4 = be16_to_cpu(g_xy_data.x4);
1237 g_xy_data.y4 = be16_to_cpu(g_xy_data.y4);
1238 if (tilt)
1239 FLIP_XY(g_xy_data.x4, g_xy_data.y4);
1240
1241 if (rev_x) {
1242 g_xy_data.x4 = INVERT_X(g_xy_data.x4,
1243 ts->platform_data->panel_maxx);
1244 if (g_xy_data.x4 < 0)
1245 pr_debug("X value is negative. Please configure"
1246 " maxx in platform data structure\n");
1247 }
1248 if (rev_y) {
1249 g_xy_data.y4 = INVERT_X(g_xy_data.y4,
1250 ts->platform_data->panel_maxy);
1251 if (g_xy_data.y4 < 0)
1252 pr_debug("Y value is negative. Please configure"
1253 " maxy in platform data structure\n");
1254
1255 }
1256 id = GET_TOUCH4_ID(g_xy_data.touch34_id);
1257 if (ts->platform_data->use_trk_id) {
1258 cur_mt_pos[CY_MT_TCH4_IDX][CY_XPOS] =
1259 g_xy_data.x4;
1260 cur_mt_pos[CY_MT_TCH4_IDX][CY_YPOS] =
1261 g_xy_data.y4;
1262 cur_mt_z[CY_MT_TCH4_IDX] = g_xy_data.z4;
1263 } else {
1264 cur_mt_pos[id][CY_XPOS] = g_xy_data.x4;
1265 cur_mt_pos[id][CY_YPOS] = g_xy_data.y4;
1266 cur_mt_z[id] = g_xy_data.z4;
1267 }
1268 cur_mt_tch[CY_MT_TCH4_IDX] = id;
1269 cur_trk[id] = CY_TCH;
1270 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
1271 CY_NUM_TRK_ID) {
1272 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
1273 st_x1 = g_xy_data.x4;
1274 st_y1 = g_xy_data.y4;
1275 st_z1 = g_xy_data.z4;
1276 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1277 } else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
1278 st_x2 = g_xy_data.x4;
1279 st_y2 = g_xy_data.y4;
1280 st_z2 = g_xy_data.z4;
1281 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1282 }
1283 }
1284 cyttsp_xdebug("4th XYZ:% 3d,% 3d,% 3d ID:% 2d\n\n", \
1285 g_xy_data.x4, g_xy_data.y4, g_xy_data.z4, \
1286 (g_xy_data.touch34_id & 0x0F));
1287 /* do not break */
1288 }
1289 case 3: {
1290 g_xy_data.x3 = be16_to_cpu(g_xy_data.x3);
1291 g_xy_data.y3 = be16_to_cpu(g_xy_data.y3);
1292 if (tilt)
1293 FLIP_XY(g_xy_data.x3, g_xy_data.y3);
1294
1295 if (rev_x) {
1296 g_xy_data.x3 = INVERT_X(g_xy_data.x3,
1297 ts->platform_data->panel_maxx);
1298 if (g_xy_data.x3 < 0)
1299 pr_debug("X value is negative. Please configure"
1300 " maxx in platform data structure\n");
1301
1302 }
1303 if (rev_y) {
1304 g_xy_data.y3 = INVERT_X(g_xy_data.y3,
1305 ts->platform_data->panel_maxy);
1306 if (g_xy_data.y3 < 0)
1307 pr_debug("Y value is negative. Please configure"
1308 " maxy in platform data structure\n");
1309
1310 }
1311 id = GET_TOUCH3_ID(g_xy_data.touch34_id);
1312 if (ts->platform_data->use_trk_id) {
1313 cur_mt_pos[CY_MT_TCH3_IDX][CY_XPOS] =
1314 g_xy_data.x3;
1315 cur_mt_pos[CY_MT_TCH3_IDX][CY_YPOS] =
1316 g_xy_data.y3;
1317 cur_mt_z[CY_MT_TCH3_IDX] = g_xy_data.z3;
1318 } else {
1319 cur_mt_pos[id][CY_XPOS] = g_xy_data.x3;
1320 cur_mt_pos[id][CY_YPOS] = g_xy_data.y3;
1321 cur_mt_z[id] = g_xy_data.z3;
1322 }
1323 cur_mt_tch[CY_MT_TCH3_IDX] = id;
1324 cur_trk[id] = CY_TCH;
1325 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
1326 CY_NUM_TRK_ID) {
1327 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
1328 st_x1 = g_xy_data.x3;
1329 st_y1 = g_xy_data.y3;
1330 st_z1 = g_xy_data.z3;
1331 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1332 } else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
1333 st_x2 = g_xy_data.x3;
1334 st_y2 = g_xy_data.y3;
1335 st_z2 = g_xy_data.z3;
1336 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1337 }
1338 }
1339 cyttsp_xdebug("3rd XYZ:% 3d,% 3d,% 3d ID:% 2d\n", \
1340 g_xy_data.x3, g_xy_data.y3, g_xy_data.z3, \
1341 ((g_xy_data.touch34_id >> 4) & 0x0F));
1342 /* do not break */
1343 }
1344 case 2: {
1345 g_xy_data.x2 = be16_to_cpu(g_xy_data.x2);
1346 g_xy_data.y2 = be16_to_cpu(g_xy_data.y2);
1347 if (tilt)
1348 FLIP_XY(g_xy_data.x2, g_xy_data.y2);
1349
1350 if (rev_x) {
1351 g_xy_data.x2 = INVERT_X(g_xy_data.x2,
1352 ts->platform_data->panel_maxx);
1353 if (g_xy_data.x2 < 0)
1354 pr_debug("X value is negative. Please configure"
1355 " maxx in platform data structure\n");
1356 }
1357 if (rev_y) {
1358 g_xy_data.y2 = INVERT_X(g_xy_data.y2,
1359 ts->platform_data->panel_maxy);
1360 if (g_xy_data.y2 < 0)
1361 pr_debug("Y value is negative. Please configure"
1362 " maxy in platform data structure\n");
1363 }
1364 id = GET_TOUCH2_ID(g_xy_data.touch12_id);
1365 if (ts->platform_data->use_trk_id) {
1366 cur_mt_pos[CY_MT_TCH2_IDX][CY_XPOS] =
1367 g_xy_data.x2;
1368 cur_mt_pos[CY_MT_TCH2_IDX][CY_YPOS] =
1369 g_xy_data.y2;
1370 cur_mt_z[CY_MT_TCH2_IDX] = g_xy_data.z2;
1371 } else {
1372 cur_mt_pos[id][CY_XPOS] = g_xy_data.x2;
1373 cur_mt_pos[id][CY_YPOS] = g_xy_data.y2;
1374 cur_mt_z[id] = g_xy_data.z2;
1375 }
1376 cur_mt_tch[CY_MT_TCH2_IDX] = id;
1377 cur_trk[id] = CY_TCH;
1378 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
1379 CY_NUM_TRK_ID) {
1380 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
1381 st_x1 = g_xy_data.x2;
1382 st_y1 = g_xy_data.y2;
1383 st_z1 = g_xy_data.z2;
1384 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1385 } else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
1386 st_x2 = g_xy_data.x2;
1387 st_y2 = g_xy_data.y2;
1388 st_z2 = g_xy_data.z2;
1389 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1390 }
1391 }
1392 cyttsp_xdebug("2nd XYZ:% 3d,% 3d,% 3d ID:% 2d\n", \
1393 g_xy_data.x2, g_xy_data.y2, g_xy_data.z2, \
1394 (g_xy_data.touch12_id & 0x0F));
1395 /* do not break */
1396 }
1397 case 1: {
1398 g_xy_data.x1 = be16_to_cpu(g_xy_data.x1);
1399 g_xy_data.y1 = be16_to_cpu(g_xy_data.y1);
1400 if (tilt)
1401 FLIP_XY(g_xy_data.x1, g_xy_data.y1);
1402
1403 if (rev_x) {
1404 g_xy_data.x1 = INVERT_X(g_xy_data.x1,
1405 ts->platform_data->panel_maxx);
1406 if (g_xy_data.x1 < 0)
1407 pr_debug("X value is negative. Please configure"
1408 " maxx in platform data structure\n");
1409 }
1410 if (rev_y) {
1411 g_xy_data.y1 = INVERT_X(g_xy_data.y1,
1412 ts->platform_data->panel_maxy);
1413 if (g_xy_data.y1 < 0)
1414 pr_debug("Y value is negative. Please configure"
1415 " maxy in platform data structure");
1416 }
1417 id = GET_TOUCH1_ID(g_xy_data.touch12_id);
1418 if (ts->platform_data->use_trk_id) {
1419 cur_mt_pos[CY_MT_TCH1_IDX][CY_XPOS] =
1420 g_xy_data.x1;
1421 cur_mt_pos[CY_MT_TCH1_IDX][CY_YPOS] =
1422 g_xy_data.y1;
1423 cur_mt_z[CY_MT_TCH1_IDX] = g_xy_data.z1;
1424 } else {
1425 cur_mt_pos[id][CY_XPOS] = g_xy_data.x1;
1426 cur_mt_pos[id][CY_YPOS] = g_xy_data.y1;
1427 cur_mt_z[id] = g_xy_data.z1;
1428 }
1429 cur_mt_tch[CY_MT_TCH1_IDX] = id;
1430 cur_trk[id] = CY_TCH;
1431 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] <
1432 CY_NUM_TRK_ID) {
1433 if (ts->prv_st_tch[CY_ST_FNGR1_IDX] == id) {
1434 st_x1 = g_xy_data.x1;
1435 st_y1 = g_xy_data.y1;
1436 st_z1 = g_xy_data.z1;
1437 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1438 } else if (ts->prv_st_tch[CY_ST_FNGR2_IDX] == id) {
1439 st_x2 = g_xy_data.x1;
1440 st_y2 = g_xy_data.y1;
1441 st_z2 = g_xy_data.z1;
1442 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1443 }
1444 }
1445 cyttsp_xdebug("1st XYZ:% 3d,% 3d,% 3d ID:% 2d\n", \
1446 g_xy_data.x1, g_xy_data.y1, g_xy_data.z1, \
1447 ((g_xy_data.touch12_id >> 4) & 0x0F));
1448 break;
1449 }
1450 case 0:
1451 default:{
1452 break;
1453 }
1454 }
1455
1456 /* handle Single Touch signals */
1457 if (ts->platform_data->use_st) {
1458 cyttsp_xdebug("ST STEP 0 - ST1 ID=%d ST2 ID=%d\n", \
1459 cur_st_tch[CY_ST_FNGR1_IDX], \
1460 cur_st_tch[CY_ST_FNGR2_IDX]);
1461 if (cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) {
1462 /* reassign finger 1 and 2 positions to new tracks */
1463 if (cur_tch > 0) {
1464 /* reassign st finger1 */
1465 if (ts->platform_data->use_trk_id) {
1466 id = CY_MT_TCH1_IDX;
1467 cur_st_tch[CY_ST_FNGR1_IDX] = cur_mt_tch[id];
1468 } else {
1469 id = GET_TOUCH1_ID(g_xy_data.touch12_id);
1470 cur_st_tch[CY_ST_FNGR1_IDX] = id;
1471 }
1472 st_x1 = cur_mt_pos[id][CY_XPOS];
1473 st_y1 = cur_mt_pos[id][CY_YPOS];
1474 st_z1 = cur_mt_z[id];
1475 cyttsp_xdebug("ST STEP 1 - ST1 ID=%3d\n", \
1476 cur_st_tch[CY_ST_FNGR1_IDX]);
1477 if ((cur_tch > 1) &&
1478 (cur_st_tch[CY_ST_FNGR2_IDX] >
1479 CY_NUM_TRK_ID)) {
1480 /* reassign st finger2 */
1481 if (cur_tch > 1) {
1482 if (ts->platform_data->use_trk_id) {
1483 id = CY_MT_TCH2_IDX;
1484 cur_st_tch[CY_ST_FNGR2_IDX] = cur_mt_tch[id];
1485 } else {
1486 id = GET_TOUCH2_ID(g_xy_data.touch12_id);
1487 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1488 }
1489 st_x2 = cur_mt_pos[id][CY_XPOS];
1490 st_y2 = cur_mt_pos[id][CY_YPOS];
1491 st_z2 = cur_mt_z[id];
1492 cyttsp_xdebug("ST STEP 2 - ST2 ID=%3d\n", \
1493 cur_st_tch[CY_ST_FNGR2_IDX]);
1494 }
1495 }
1496 }
1497 } else if (cur_st_tch[CY_ST_FNGR2_IDX] > CY_NUM_TRK_ID) {
1498 if (cur_tch > 1) {
1499 /* reassign st finger2 */
1500 if (ts->platform_data->use_trk_id) {
1501 /* reassign st finger2 */
1502 id = CY_MT_TCH2_IDX;
1503 cur_st_tch[CY_ST_FNGR2_IDX] =
1504 cur_mt_tch[id];
1505 } else {
1506 /* reassign st finger2 */
1507 id = GET_TOUCH2_ID(g_xy_data.touch12_id);
1508 cur_st_tch[CY_ST_FNGR2_IDX] = id;
1509 }
1510 st_x2 = cur_mt_pos[id][CY_XPOS];
1511 st_y2 = cur_mt_pos[id][CY_YPOS];
1512 st_z2 = cur_mt_z[id];
1513 cyttsp_xdebug("ST STEP 3 - ST2 ID=%3d\n", \
1514 cur_st_tch[CY_ST_FNGR2_IDX]);
1515 }
1516 }
1517 /* if the 1st touch is missing and there is a 2nd touch,
1518 * then set the 1st touch to 2nd touch and terminate 2nd touch
1519 */
1520 if ((cur_st_tch[CY_ST_FNGR1_IDX] > CY_NUM_TRK_ID) &&
1521 (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID)) {
1522 st_x1 = st_x2;
1523 st_y1 = st_y2;
1524 st_z1 = st_z2;
1525 cur_st_tch[CY_ST_FNGR1_IDX] =
1526 cur_st_tch[CY_ST_FNGR2_IDX];
1527 cur_st_tch[CY_ST_FNGR2_IDX] =
1528 CY_IGNR_TCH;
1529 }
1530 /* if the 2nd touch ends up equal to the 1st touch,
1531 * then just report a single touch */
1532 if (cur_st_tch[CY_ST_FNGR1_IDX] ==
1533 cur_st_tch[CY_ST_FNGR2_IDX]) {
1534 cur_st_tch[CY_ST_FNGR2_IDX] =
1535 CY_IGNR_TCH;
1536 }
1537 /* set Single Touch current event signals */
1538 if (cur_st_tch[CY_ST_FNGR1_IDX] < CY_NUM_TRK_ID) {
1539 input_report_abs(ts->input,
1540 ABS_X, st_x1);
1541 input_report_abs(ts->input,
1542 ABS_Y, st_y1);
1543 input_report_abs(ts->input,
1544 ABS_PRESSURE, st_z1);
1545 input_report_key(ts->input,
1546 BTN_TOUCH,
1547 CY_TCH);
1548 input_report_abs(ts->input,
1549 ABS_TOOL_WIDTH,
1550 curr_tool_width);
1551 cyttsp_debug("ST->F1:%3d X:%3d Y:%3d Z:%3d\n", \
1552 cur_st_tch[CY_ST_FNGR1_IDX], \
1553 st_x1, st_y1, st_z1);
1554 if (cur_st_tch[CY_ST_FNGR2_IDX] < CY_NUM_TRK_ID) {
1555 input_report_key(ts->input, BTN_2, CY_TCH);
1556 input_report_abs(ts->input, ABS_HAT0X, st_x2);
1557 input_report_abs(ts->input, ABS_HAT0Y, st_y2);
1558 cyttsp_debug("ST->F2:%3d X:%3d Y:%3d Z:%3d\n", \
1559 cur_st_tch[CY_ST_FNGR2_IDX],
1560 st_x2, st_y2, st_z2);
1561 } else {
1562 input_report_key(ts->input,
1563 BTN_2,
1564 CY_NTCH);
1565 }
1566 } else {
1567 input_report_abs(ts->input, ABS_PRESSURE, CY_NTCH);
1568 input_report_key(ts->input, BTN_TOUCH, CY_NTCH);
1569 input_report_key(ts->input, BTN_2, CY_NTCH);
1570 }
1571 /* update platform data for the current single touch info */
1572 ts->prv_st_tch[CY_ST_FNGR1_IDX] = cur_st_tch[CY_ST_FNGR1_IDX];
1573 ts->prv_st_tch[CY_ST_FNGR2_IDX] = cur_st_tch[CY_ST_FNGR2_IDX];
1574
1575 }
1576
1577 /* handle Multi-touch signals */
1578 if (ts->platform_data->use_mt) {
1579 if (ts->platform_data->use_trk_id) {
1580 /* terminate any previous touch where the track
1581 * is missing from the current event */
1582 for (id = 0; id < CY_NUM_TRK_ID; id++) {
1583 if ((ts->act_trk[id] != CY_NTCH) &&
1584 (cur_trk[id] == CY_NTCH)) {
1585 input_report_abs(ts->input,
1586 ABS_MT_TRACKING_ID,
1587 id);
1588 input_report_abs(ts->input,
1589 ABS_MT_TOUCH_MAJOR,
1590 CY_NTCH);
1591 input_report_abs(ts->input,
1592 ABS_MT_WIDTH_MAJOR,
1593 curr_tool_width);
1594 input_report_abs(ts->input,
1595 ABS_MT_POSITION_X,
1596 ts->prv_mt_pos[id][CY_XPOS]);
1597 input_report_abs(ts->input,
1598 ABS_MT_POSITION_Y,
1599 ts->prv_mt_pos[id][CY_YPOS]);
1600 CY_MT_SYNC(ts->input);
1601 ts->act_trk[id] = CY_NTCH;
1602 ts->prv_mt_pos[id][CY_XPOS] = 0;
1603 ts->prv_mt_pos[id][CY_YPOS] = 0;
1604 }
1605 }
1606 /* set Multi-Touch current event signals */
1607 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1608 if (cur_mt_tch[id] < CY_NUM_TRK_ID) {
1609 input_report_abs(ts->input,
1610 ABS_MT_TRACKING_ID,
1611 cur_mt_tch[id]);
1612 input_report_abs(ts->input,
1613 ABS_MT_TOUCH_MAJOR,
1614 cur_mt_z[id]);
1615 input_report_abs(ts->input,
1616 ABS_MT_WIDTH_MAJOR,
1617 curr_tool_width);
1618 input_report_abs(ts->input,
1619 ABS_MT_POSITION_X,
1620 cur_mt_pos[id][CY_XPOS]);
1621 input_report_abs(ts->input,
1622 ABS_MT_POSITION_Y,
1623 cur_mt_pos[id][CY_YPOS]);
1624 CY_MT_SYNC(ts->input);
1625 ts->act_trk[id] = CY_TCH;
1626 ts->prv_mt_pos[id][CY_XPOS] =
1627 cur_mt_pos[id][CY_XPOS];
1628 ts->prv_mt_pos[id][CY_YPOS] =
1629 cur_mt_pos[id][CY_YPOS];
1630 }
1631 }
1632 } else {
1633 /* set temporary track array elements to voids */
1634 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1635 tmp_trk[id] = CY_IGNR_TCH;
1636 snd_trk[id] = CY_IGNR_TCH;
1637 }
1638
1639 /* get what is currently active */
1640 for (i = 0, id = 0;
1641 id < CY_NUM_TRK_ID && i < CY_NUM_MT_TCH_ID;
1642 id++) {
1643 if (cur_trk[id] == CY_TCH) {
1644 /* only incr counter if track found */
1645 tmp_trk[i] = id;
1646 i++;
1647 }
1648 }
1649 cyttsp_xdebug("T1: t0=%d, t1=%d, t2=%d, t3=%d\n", \
1650 tmp_trk[0], tmp_trk[1], tmp_trk[2], \
1651 tmp_trk[3]);
1652 cyttsp_xdebug("T1: p0=%d, p1=%d, p2=%d, p3=%d\n", \
1653 ts->prv_mt_tch[0], ts->prv_mt_tch[1], \
1654 ts->prv_mt_tch[2], ts->prv_mt_tch[3]);
1655
1656 /* pack in still active previous touches */
1657 for (id = 0, prv_tch = 0;
1658 id < CY_NUM_MT_TCH_ID; id++) {
1659 if (tmp_trk[id] < CY_NUM_TRK_ID) {
1660 if (cyttsp_inlist(ts->prv_mt_tch,
1661 tmp_trk[id], &loc,
1662 CY_NUM_MT_TCH_ID)) {
1663 loc &= CY_NUM_MT_TCH_ID - 1;
1664 snd_trk[loc] = tmp_trk[id];
1665 prv_tch++;
1666 cyttsp_xdebug("inlist s[%d]=%d t[%d]=%d l=%d p=%d\n", \
1667 loc, snd_trk[loc], \
1668 id, tmp_trk[id], \
1669 loc, prv_tch);
1670 } else {
1671 cyttsp_xdebug("not inlist s[%d]=%d t[%d]=%d l=%d \n", \
1672 id, snd_trk[id], \
1673 id, tmp_trk[id], \
1674 loc);
1675 }
1676 }
1677 }
1678 cyttsp_xdebug("S1: s0=%d, s1=%d, s2=%d, s3=%d p=%d\n", \
1679 snd_trk[0], snd_trk[1], snd_trk[2], \
1680 snd_trk[3], prv_tch);
1681
1682 /* pack in new touches */
1683 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1684 if (tmp_trk[id] < CY_NUM_TRK_ID) {
1685 if (!cyttsp_inlist(snd_trk, tmp_trk[id], &loc, CY_NUM_MT_TCH_ID)) {
1686 cyttsp_xdebug("not inlist t[%d]=%d l=%d\n", \
1687 id, tmp_trk[id], loc);
1688 if (cyttsp_next_avail_inlist(snd_trk, &loc, CY_NUM_MT_TCH_ID)) {
1689 loc &= CY_NUM_MT_TCH_ID - 1;
1690 snd_trk[loc] = tmp_trk[id];
1691 cyttsp_xdebug("put inlist s[%d]=%d t[%d]=%d\n",
1692 loc, snd_trk[loc], id, tmp_trk[id]);
1693 }
1694 } else {
1695 cyttsp_xdebug("is in list s[%d]=%d t[%d]=%d loc=%d\n", \
1696 id, snd_trk[id], id, tmp_trk[id], loc);
1697 }
1698 }
1699 }
1700 cyttsp_xdebug("S2: s0=%d, s1=%d, s2=%d, s3=%d\n", \
1701 snd_trk[0], snd_trk[1],
1702 snd_trk[2], snd_trk[3]);
1703
1704 /* sync motion event signals for each current touch */
1705 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1706 /* z will either be 0 (NOTOUCH) or
1707 * some pressure (TOUCH) */
1708 cyttsp_xdebug("MT0 prev[%d]=%d temp[%d]=%d send[%d]=%d\n", \
1709 id, ts->prv_mt_tch[id], \
1710 id, tmp_trk[id], \
1711 id, snd_trk[id]);
1712 if (snd_trk[id] < CY_NUM_TRK_ID) {
1713 input_report_abs(ts->input,
1714 ABS_MT_TOUCH_MAJOR,
1715 cur_mt_z[snd_trk[id]]);
1716 input_report_abs(ts->input,
1717 ABS_MT_WIDTH_MAJOR,
1718 curr_tool_width);
1719 input_report_abs(ts->input,
1720 ABS_MT_POSITION_X,
1721 cur_mt_pos[snd_trk[id]][CY_XPOS]);
1722 input_report_abs(ts->input,
1723 ABS_MT_POSITION_Y,
1724 cur_mt_pos[snd_trk[id]][CY_YPOS]);
1725 CY_MT_SYNC(ts->input);
1726 cyttsp_debug("MT1->TID:%2d X:%3d Y:%3d Z:%3d touch-sent\n", \
1727 snd_trk[id], \
1728 cur_mt_pos[snd_trk[id]][CY_XPOS], \
1729 cur_mt_pos[snd_trk[id]][CY_YPOS], \
1730 cur_mt_z[snd_trk[id]]);
1731 } else if (ts->prv_mt_tch[id] < CY_NUM_TRK_ID) {
1732 /* void out this touch */
1733 input_report_abs(ts->input,
1734 ABS_MT_TOUCH_MAJOR,
1735 CY_NTCH);
1736 input_report_abs(ts->input,
1737 ABS_MT_WIDTH_MAJOR,
1738 curr_tool_width);
1739 input_report_abs(ts->input,
1740 ABS_MT_POSITION_X,
1741 ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS]);
1742 input_report_abs(ts->input,
1743 ABS_MT_POSITION_Y,
1744 ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS]);
1745 CY_MT_SYNC(ts->input);
1746 cyttsp_debug("MT2->TID:%2d X:%3d Y:%3d Z:%3d lift off-sent\n", \
1747 ts->prv_mt_tch[id], \
1748 ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_XPOS], \
1749 ts->prv_mt_pos[ts->prv_mt_tch[id]][CY_YPOS], \
1750 CY_NTCH);
1751 } else {
1752 /* do not stuff any signals for this
1753 * previously and currently
1754 * void touches */
1755 cyttsp_xdebug("MT3->send[%d]=%d - No touch - NOT sent\n", \
1756 id, snd_trk[id]);
1757 }
1758 }
1759
1760 /* save current posted tracks to
1761 * previous track memory */
1762 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1763 ts->prv_mt_tch[id] = snd_trk[id];
1764 if (snd_trk[id] < CY_NUM_TRK_ID) {
1765 ts->prv_mt_pos[snd_trk[id]][CY_XPOS] =
1766 cur_mt_pos[snd_trk[id]][CY_XPOS];
1767 ts->prv_mt_pos[snd_trk[id]][CY_YPOS] =
1768 cur_mt_pos[snd_trk[id]][CY_YPOS];
1769 cyttsp_xdebug("MT4->TID:%2d X:%3d Y:%3d Z:%3d save for previous\n", \
1770 snd_trk[id], \
1771 ts->prv_mt_pos[snd_trk[id]][CY_XPOS], \
1772 ts->prv_mt_pos[snd_trk[id]][CY_YPOS], \
1773 CY_NTCH);
1774 }
1775 }
1776 for (id = 0; id < CY_NUM_TRK_ID; id++)
1777 ts->act_trk[id] = CY_NTCH;
1778 for (id = 0; id < CY_NUM_MT_TCH_ID; id++) {
1779 if (snd_trk[id] < CY_NUM_TRK_ID)
1780 ts->act_trk[snd_trk[id]] = CY_TCH;
1781 }
1782 }
1783 }
1784
1785 /* handle gestures */
1786 if (ts->platform_data->use_gestures) {
1787 if (g_xy_data.gest_id) {
1788 input_report_key(ts->input,
1789 BTN_3, CY_TCH);
1790 input_report_abs(ts->input,
1791 ABS_HAT1X, g_xy_data.gest_id);
1792 input_report_abs(ts->input,
1793 ABS_HAT2Y, g_xy_data.gest_cnt);
1794 }
1795 }
1796
1797 /* signal the view motion event */
1798 input_sync(ts->input);
1799
1800 for (id = 0; id < CY_NUM_TRK_ID; id++) {
1801 /* update platform data for the current MT information */
1802 ts->act_trk[id] = cur_trk[id];
1803 }
1804
Mohan Pallaka07a08072011-10-21 13:04:21 +05301805exit_xy_handler:
1806 /* restart event timer */
1807 if (ts->client->irq == 0)
1808 mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 return;
1810}
1811
1812static int cyttsp_inlist(u16 prev_track[], u8 cur_trk_id,
1813 u8 *prev_loc, u8 num_touches)
1814{
1815 u8 id = 0;
1816
1817 *prev_loc = CY_IGNR_TCH;
1818
1819 cyttsp_xdebug("IN p[%d]=%d c=%d n=%d loc=%d\n", \
1820 id, prev_track[id], cur_trk_id, \
1821 num_touches, *prev_loc);
1822 for (id = 0, *prev_loc = CY_IGNR_TCH;
1823 (id < num_touches); id++) {
1824 cyttsp_xdebug("p[%d]=%d c=%d n=%d loc=%d\n", \
1825 id, prev_track[id], cur_trk_id, \
1826 num_touches, *prev_loc);
1827 if (prev_track[id] == cur_trk_id) {
1828 *prev_loc = id;
1829 break;
1830 }
1831 }
1832 cyttsp_xdebug("OUT p[%d]=%d c=%d n=%d loc=%d\n", \
1833 id, prev_track[id], cur_trk_id, num_touches, *prev_loc);
1834
1835 return ((*prev_loc < CY_NUM_TRK_ID) ? true : false);
1836}
1837
1838static int cyttsp_next_avail_inlist(u16 cur_trk[],
1839 u8 *new_loc, u8 num_touches)
1840{
1841 u8 id;
1842
1843 for (id = 0, *new_loc = CY_IGNR_TCH;
1844 (id < num_touches); id++) {
1845 if (cur_trk[id] > CY_NUM_TRK_ID) {
1846 *new_loc = id;
1847 break;
1848 }
1849 }
1850
1851 return ((*new_loc < CY_NUM_TRK_ID) ? true : false);
1852}
1853
1854/* Timer function used as dummy interrupt driver */
1855static void cyttsp_timer(unsigned long handle)
1856{
1857 struct cyttsp *ts = (struct cyttsp *) handle;
1858
1859 cyttsp_xdebug("TTSP Device timer event\n");
1860
1861 /* schedule motion signal handling */
Mohan Pallaka07a08072011-10-21 13:04:21 +05301862 cyttsp_xy_handler(ts);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863
1864 return;
1865}
1866
1867
1868
1869/* ************************************************************************
1870 * ISR function. This function is general, initialized in drivers init
1871 * function
1872 * ************************************************************************ */
1873static irqreturn_t cyttsp_irq(int irq, void *handle)
1874{
1875 struct cyttsp *ts = (struct cyttsp *) handle;
1876
1877 cyttsp_xdebug("%s: Got IRQ\n", CY_I2C_NAME);
1878
Mohan Pallaka07a08072011-10-21 13:04:21 +05301879 cyttsp_xy_handler(ts);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001880
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001881 return IRQ_HANDLED;
1882}
1883
1884/* ************************************************************************
1885 * Probe initialization functions
1886 * ************************************************************************ */
1887static int cyttsp_putbl(struct cyttsp *ts, int show,
1888 int show_status, int show_version, int show_cid)
1889{
1890 int retval = CY_OK;
1891
1892 int num_bytes = (show_status * 3) + (show_version * 6) + (show_cid * 3);
1893
1894 if (show_cid)
1895 num_bytes = sizeof(struct cyttsp_bootloader_data_t);
1896 else if (show_version)
1897 num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 3;
1898 else
1899 num_bytes = sizeof(struct cyttsp_bootloader_data_t) - 9;
1900
1901 if (show) {
1902 retval = i2c_smbus_read_i2c_block_data(ts->client,
1903 CY_REG_BASE, num_bytes, (u8 *)&g_bl_data);
1904 if (show_status) {
1905 cyttsp_debug("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X\n", \
1906 show, \
1907 g_bl_data.bl_file, \
1908 g_bl_data.bl_status, \
1909 g_bl_data.bl_error, \
1910 g_bl_data.blver_hi, g_bl_data.blver_lo, \
1911 g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo);
1912 }
1913 if (show_version) {
1914 cyttsp_debug("BL%d: ttspver=0x%02X%02X appid=0x%02X%02X appver=0x%02X%02X\n", \
1915 show, \
1916 g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
1917 g_bl_data.appid_hi, g_bl_data.appid_lo, \
1918 g_bl_data.appver_hi, g_bl_data.appver_lo);
1919 }
1920 if (show_cid) {
1921 cyttsp_debug("BL%d: cid=0x%02X%02X%02X\n", \
1922 show, \
1923 g_bl_data.cid_0, \
1924 g_bl_data.cid_1, \
1925 g_bl_data.cid_2);
1926 }
1927 }
1928
1929 return retval;
1930}
1931
1932#ifdef CY_INCLUDE_LOAD_FILE
1933#define CY_MAX_I2C_LEN 256
1934#define CY_MAX_TRY 10
1935#define CY_BL_PAGE_SIZE 16
1936#define CY_BL_NUM_PAGES 5
1937static int cyttsp_i2c_wr_blk_chunks(struct cyttsp *ts, u8 command,
1938 u8 length, const u8 *values)
1939{
1940 int retval = CY_OK;
1941 int block = 1;
1942
1943 u8 dataray[CY_MAX_I2C_LEN];
1944
1945 /* first page already includes the bl page offset */
1946 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
1947 CY_BL_PAGE_SIZE+1, values);
1948 values += CY_BL_PAGE_SIZE+1;
1949 length -= CY_BL_PAGE_SIZE+1;
1950
1951 /* rem blocks require bl page offset stuffing */
1952 while (length &&
1953 (block < CY_BL_NUM_PAGES) &&
1954 !(retval < CY_OK)) {
1955 udelay(43*2); /* TRM * 2 */
1956 dataray[0] = CY_BL_PAGE_SIZE*block;
1957 memcpy(&dataray[1], values,
1958 length >= CY_BL_PAGE_SIZE ?
1959 CY_BL_PAGE_SIZE : length);
1960 retval = i2c_smbus_write_i2c_block_data(ts->client,
1961 CY_REG_BASE,
1962 length >= CY_BL_PAGE_SIZE ?
1963 CY_BL_PAGE_SIZE + 1 : length+1, dataray);
1964 values += CY_BL_PAGE_SIZE;
1965 length = length >= CY_BL_PAGE_SIZE ?
1966 length - CY_BL_PAGE_SIZE : 0;
1967 block++;
1968 }
1969
1970 return retval;
1971}
1972
1973static int cyttsp_bootload_app(struct cyttsp *ts)
1974{
1975 int retval = CY_OK;
1976 int i, tries;
1977 u8 host_reg;
1978
1979 cyttsp_debug("load new firmware \n");
1980 /* reset TTSP Device back to bootloader mode */
1981 host_reg = CY_SOFT_RESET_MODE;
1982 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
1983 sizeof(host_reg), &host_reg);
1984 /* wait for TTSP Device to complete reset back to bootloader */
1985 tries = 0;
1986 do {
1987 mdelay(1);
1988 cyttsp_putbl(ts, 3, false, false, false);
1989 } while (g_bl_data.bl_status != 0x10 &&
1990 g_bl_data.bl_status != 0x11 &&
1991 tries++ < 100);
1992 cyttsp_debug("load file - tver=0x%02X%02X a_id=0x%02X%02X aver=0x%02X%02X\n", \
1993 cyttsp_fw_tts_verh, cyttsp_fw_tts_verl, \
1994 cyttsp_fw_app_idh, cyttsp_fw_app_idl, \
1995 cyttsp_fw_app_verh, cyttsp_fw_app_verl);
1996
1997 /* download new TTSP Application to the Bootloader */
1998 if (!(retval < CY_OK)) {
1999 i = 0;
2000 /* send bootload initiation command */
2001 if (cyttsp_fw[i].Command == CY_BL_INIT_LOAD) {
2002 g_bl_data.bl_file = 0;
2003 g_bl_data.bl_status = 0;
2004 g_bl_data.bl_error = 0;
2005 retval = i2c_smbus_write_i2c_block_data(ts->client,
2006 CY_REG_BASE,
2007 cyttsp_fw[i].Length, cyttsp_fw[i].Block);
2008 /* delay to allow bl to get ready for block writes */
2009 i++;
2010 tries = 0;
2011 do {
2012 mdelay(100);
2013 cyttsp_putbl(ts, 4, false, false, false);
2014 } while (g_bl_data.bl_status != 0x10 &&
2015 g_bl_data.bl_status != 0x11 &&
2016 tries++ < 100);
2017 cyttsp_debug("wait init f=%02X, s=%02X, e=%02X t=%d\n", \
2018 g_bl_data.bl_file, g_bl_data.bl_status, \
2019 g_bl_data.bl_error, tries);
2020 /* send bootload firmware load blocks */
2021 if (!(retval < CY_OK)) {
2022 while (cyttsp_fw[i].Command == CY_BL_WRITE_BLK) {
2023 retval = cyttsp_i2c_wr_blk_chunks(ts,
2024 CY_REG_BASE,
2025 cyttsp_fw[i].Length,
2026 cyttsp_fw[i].Block);
2027 cyttsp_xdebug("BL DNLD Rec=% 3d Len=% 3d Addr=%04X\n", \
2028 cyttsp_fw[i].Record, \
2029 cyttsp_fw[i].Length, \
2030 cyttsp_fw[i].Address);
2031 i++;
2032 if (retval < CY_OK) {
2033 cyttsp_debug("BL fail Rec=%3d retval=%d\n", \
2034 cyttsp_fw[i-1].Record, \
2035 retval);
2036 break;
2037 } else {
2038 tries = 0;
2039 cyttsp_putbl(ts, 5, false, false, false);
2040 while (!((g_bl_data.bl_status == 0x10) &&
2041 (g_bl_data.bl_error == 0x20)) &&
2042 !((g_bl_data.bl_status == 0x11) &&
2043 (g_bl_data.bl_error == 0x20)) &&
2044 (tries++ < 100)) {
2045 mdelay(1);
2046 cyttsp_putbl(ts, 5, false, false, false);
2047 }
2048 }
2049 }
2050
2051 if (!(retval < CY_OK)) {
2052 while (i < cyttsp_fw_records) {
2053 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
2054 cyttsp_fw[i].Length,
2055 cyttsp_fw[i].Block);
2056 i++;
2057 tries = 0;
2058 do {
2059 mdelay(100);
2060 cyttsp_putbl(ts, 6, true, false, false);
2061 } while (g_bl_data.bl_status != 0x10 &&
2062 g_bl_data.bl_status != 0x11 &&
2063 tries++ < 100);
2064 cyttsp_debug("wait term f=%02X, s=%02X, e=%02X t=%d\n", \
2065 g_bl_data.bl_file, \
2066 g_bl_data.bl_status, \
2067 g_bl_data.bl_error, \
2068 tries);
2069 if (retval < CY_OK)
2070 break;
2071 }
2072 }
2073 }
2074 }
2075 }
2076
2077 /* reset TTSP Device back to bootloader mode */
2078 host_reg = CY_SOFT_RESET_MODE;
2079 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
2080 sizeof(host_reg), &host_reg);
2081 /* wait for TTSP Device to complete reset back to bootloader */
2082 tries = 0;
2083 do {
2084 mdelay(1);
2085 cyttsp_putbl(ts, 3, false, false, false);
2086 } while (g_bl_data.bl_status != 0x10 &&
2087 g_bl_data.bl_status != 0x11 &&
2088 tries++ < 100);
2089
2090 /* set arg2 to non-0 to activate */
2091 retval = cyttsp_putbl(ts, 8, true, true, true);
2092
2093 return retval;
2094}
2095#else
2096static int cyttsp_bootload_app(struct cyttsp *ts)
2097{
2098 cyttsp_debug("no-load new firmware \n");
2099 return CY_OK;
2100}
2101#endif /* CY_INCLUDE_LOAD_FILE */
2102
2103
2104static int cyttsp_power_on(struct cyttsp *ts)
2105{
2106 int retval = CY_OK;
2107 u8 host_reg;
2108 int tries;
2109
2110 cyttsp_debug("Power up \n");
2111
2112 /* check if the TTSP device has a bootloader installed */
2113 host_reg = CY_SOFT_RESET_MODE;
2114 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
2115 sizeof(host_reg), &host_reg);
2116 tries = 0;
2117 do {
2118 mdelay(1);
2119
2120 /* set arg2 to non-0 to activate */
2121 retval = cyttsp_putbl(ts, 1, true, true, true);
2122 cyttsp_info("BL%d: f=%02X s=%02X err=%02X bl=%02X%02X bld=%02X%02X R=%d\n", \
2123 101, \
2124 g_bl_data.bl_file, g_bl_data.bl_status, \
2125 g_bl_data.bl_error, \
2126 g_bl_data.blver_hi, g_bl_data.blver_lo, \
2127 g_bl_data.bld_blver_hi, g_bl_data.bld_blver_lo,
2128 retval);
2129 cyttsp_info("BL%d: tver=%02X%02X a_id=%02X%02X aver=%02X%02X\n", \
2130 102, \
2131 g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
2132 g_bl_data.appid_hi, g_bl_data.appid_lo, \
2133 g_bl_data.appver_hi, g_bl_data.appver_lo);
2134 cyttsp_info("BL%d: c_id=%02X%02X%02X\n", \
2135 103, \
2136 g_bl_data.cid_0, g_bl_data.cid_1, g_bl_data.cid_2);
2137 } while (!(retval < CY_OK) &&
2138 !GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
2139 !(g_bl_data.bl_file == CY_OP_MODE + CY_LOW_PWR_MODE) &&
2140 tries++ < 100);
2141
2142 /* is bootloader missing? */
2143 if (!(retval < CY_OK)) {
2144 cyttsp_xdebug("Ret=%d Check if bootloader is missing...\n", \
2145 retval);
2146 if (!GET_BOOTLOADERMODE(g_bl_data.bl_status)) {
2147 /* skip all bl and sys info and go to op mode */
2148 if (!(retval < CY_OK)) {
2149 cyttsp_xdebug("Bl is missing (ret=%d)\n", \
2150 retval);
2151 host_reg = CY_OP_MODE/* + CY_LOW_PWR_MODE*/;
2152 retval = i2c_smbus_write_i2c_block_data(ts->client, CY_REG_BASE,
2153 sizeof(host_reg), &host_reg);
2154 /* wait for TTSP Device to complete switch to
2155 * Operational mode */
2156 mdelay(1000);
2157 goto bypass;
2158 }
2159 }
2160 }
2161
2162
2163 /* take TTSP out of bootloader mode; go to TrueTouch operational mode */
2164 if (!(retval < CY_OK)) {
2165 cyttsp_xdebug1("exit bootloader; go operational\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002166 tries = 0;
2167 do {
Anirudh Ghayalab2754e2011-08-22 12:39:31 +05302168 msleep(100);
2169 retval = i2c_smbus_write_i2c_block_data(ts->client,
2170 CY_REG_BASE, sizeof(bl_cmd), bl_cmd);
2171 if (retval == CY_OK)
2172 break;
2173 } while (tries++ < 5);
2174
2175 if (retval == CY_OK) {
2176 tries = 0;
2177 do {
2178 msleep(100);
2179 cyttsp_putbl(ts, 4, true, false, false);
2180 cyttsp_info("BL%d: f=%02X s=%02X err=%02X" \
2181 "bl=%02X%02X bld=%02X%02X\n", 104, \
2182 g_bl_data.bl_file, \
2183 g_bl_data.bl_status, \
2184 g_bl_data.bl_error, \
2185 g_bl_data.blver_hi, \
2186 g_bl_data.blver_lo, \
2187 g_bl_data.bld_blver_hi, \
2188 g_bl_data.bld_blver_lo);
2189 } while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
2190 tries++ < 5);
2191 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192 }
2193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194 if (!(retval < CY_OK) &&
2195 cyttsp_app_load()) {
2196 if (CY_DIFF(g_bl_data.ttspver_hi, cyttsp_tts_verh()) ||
2197 CY_DIFF(g_bl_data.ttspver_lo, cyttsp_tts_verl()) ||
2198 CY_DIFF(g_bl_data.appid_hi, cyttsp_app_idh()) ||
2199 CY_DIFF(g_bl_data.appid_lo, cyttsp_app_idl()) ||
2200 CY_DIFF(g_bl_data.appver_hi, cyttsp_app_verh()) ||
2201 CY_DIFF(g_bl_data.appver_lo, cyttsp_app_verl()) ||
2202 CY_DIFF(g_bl_data.cid_0, cyttsp_cid_0()) ||
2203 CY_DIFF(g_bl_data.cid_1, cyttsp_cid_1()) ||
2204 CY_DIFF(g_bl_data.cid_2, cyttsp_cid_2()) ||
2205 cyttsp_force_fw_load()) {
2206 cyttsp_debug("blttsp=0x%02X%02X flttsp=0x%02X%02X force=%d\n", \
2207 g_bl_data.ttspver_hi, g_bl_data.ttspver_lo, \
2208 cyttsp_tts_verh(), cyttsp_tts_verl(), \
2209 cyttsp_force_fw_load());
2210 cyttsp_debug("blappid=0x%02X%02X flappid=0x%02X%02X\n", \
2211 g_bl_data.appid_hi, g_bl_data.appid_lo, \
2212 cyttsp_app_idh(), cyttsp_app_idl());
2213 cyttsp_debug("blappver=0x%02X%02X flappver=0x%02X%02X\n", \
2214 g_bl_data.appver_hi, g_bl_data.appver_lo, \
2215 cyttsp_app_verh(), cyttsp_app_verl());
2216 cyttsp_debug("blcid=0x%02X%02X%02X flcid=0x%02X%02X%02X\n", \
2217 g_bl_data.cid_0, \
2218 g_bl_data.cid_1, \
2219 g_bl_data.cid_2, \
2220 cyttsp_cid_0(), \
2221 cyttsp_cid_1(), \
2222 cyttsp_cid_2());
2223 /* enter bootloader to load new app into TTSP Device */
2224 retval = cyttsp_bootload_app(ts);
2225 /* take TTSP device out of bootloader mode;
2226 * switch back to TrueTouch operational mode */
2227 if (!(retval < CY_OK)) {
2228 retval = i2c_smbus_write_i2c_block_data(ts->client,
2229 CY_REG_BASE,
2230 sizeof(bl_cmd), bl_cmd);
2231 /* wait for TTSP Device to complete
2232 * switch to Operational mode */
2233 tries = 0;
2234 do {
2235 mdelay(100);
2236 cyttsp_putbl(ts, 9, false, false, false);
2237 } while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
2238 tries++ < 100);
2239 cyttsp_putbl(ts, 9, true, false, false);
2240 }
2241 }
2242 }
2243
2244bypass:
2245 /* switch to System Information mode to read versions
2246 * and set interval registers */
2247 if (!(retval < CY_OK)) {
2248 cyttsp_debug("switch to sysinfo mode \n");
2249 host_reg = CY_SYSINFO_MODE;
2250 retval = i2c_smbus_write_i2c_block_data(ts->client,
2251 CY_REG_BASE, sizeof(host_reg), &host_reg);
2252 /* wait for TTSP Device to complete switch to SysInfo mode */
2253 mdelay(100);
2254 if (!(retval < CY_OK)) {
2255 retval = i2c_smbus_read_i2c_block_data(ts->client,
2256 CY_REG_BASE,
2257 sizeof(struct cyttsp_sysinfo_data_t),
2258 (u8 *)&g_sysinfo_data);
2259 cyttsp_debug("SI2: hst_mode=0x%02X mfg_cmd=0x%02X mfg_stat=0x%02X\n", \
2260 g_sysinfo_data.hst_mode, \
2261 g_sysinfo_data.mfg_cmd, \
2262 g_sysinfo_data.mfg_stat);
2263 cyttsp_debug("SI2: bl_ver=0x%02X%02X\n", \
2264 g_sysinfo_data.bl_verh, \
2265 g_sysinfo_data.bl_verl);
2266 cyttsp_debug("SI2: sysinfo act_int=0x%02X tch_tmout=0x%02X lp_int=0x%02X\n", \
2267 g_sysinfo_data.act_intrvl, \
2268 g_sysinfo_data.tch_tmout, \
2269 g_sysinfo_data.lp_intrvl);
2270 cyttsp_info("SI%d: tver=%02X%02X a_id=%02X%02X aver=%02X%02X\n", \
2271 102, \
2272 g_sysinfo_data.tts_verh, \
2273 g_sysinfo_data.tts_verl, \
2274 g_sysinfo_data.app_idh, \
2275 g_sysinfo_data.app_idl, \
2276 g_sysinfo_data.app_verh, \
2277 g_sysinfo_data.app_verl);
2278 cyttsp_info("SI%d: c_id=%02X%02X%02X\n", \
2279 103, \
2280 g_sysinfo_data.cid[0], \
2281 g_sysinfo_data.cid[1], \
2282 g_sysinfo_data.cid[2]);
2283 if (!(retval < CY_OK) &&
2284 (CY_DIFF(ts->platform_data->act_intrvl,
2285 CY_ACT_INTRVL_DFLT) ||
2286 CY_DIFF(ts->platform_data->tch_tmout,
2287 CY_TCH_TMOUT_DFLT) ||
2288 CY_DIFF(ts->platform_data->lp_intrvl,
2289 CY_LP_INTRVL_DFLT))) {
2290 if (!(retval < CY_OK)) {
2291 u8 intrvl_ray[sizeof(ts->platform_data->act_intrvl) +
2292 sizeof(ts->platform_data->tch_tmout) +
2293 sizeof(ts->platform_data->lp_intrvl)];
2294 u8 i = 0;
2295
2296 intrvl_ray[i++] =
2297 ts->platform_data->act_intrvl;
2298 intrvl_ray[i++] =
2299 ts->platform_data->tch_tmout;
2300 intrvl_ray[i++] =
2301 ts->platform_data->lp_intrvl;
2302
2303 cyttsp_debug("SI2: platinfo act_intrvl=0x%02X tch_tmout=0x%02X lp_intrvl=0x%02X\n", \
2304 ts->platform_data->act_intrvl, \
2305 ts->platform_data->tch_tmout, \
2306 ts->platform_data->lp_intrvl);
2307 /* set intrvl registers */
2308 retval = i2c_smbus_write_i2c_block_data(
2309 ts->client,
2310 CY_REG_ACT_INTRVL,
2311 sizeof(intrvl_ray), intrvl_ray);
2312 mdelay(CY_DLY_SYSINFO);
2313 }
2314 }
2315 }
2316 /* switch back to Operational mode */
2317 cyttsp_debug("switch back to operational mode \n");
2318 if (!(retval < CY_OK)) {
2319 host_reg = CY_OP_MODE/* + CY_LOW_PWR_MODE*/;
2320 retval = i2c_smbus_write_i2c_block_data(ts->client,
2321 CY_REG_BASE,
2322 sizeof(host_reg), &host_reg);
2323 /* wait for TTSP Device to complete
2324 * switch to Operational mode */
2325 mdelay(100);
2326 }
2327 }
2328 /* init gesture setup;
2329 * this is required even if not using gestures
2330 * in order to set the active distance */
2331 if (!(retval < CY_OK)) {
2332 u8 gesture_setup;
2333 cyttsp_debug("init gesture setup \n");
2334 gesture_setup = ts->platform_data->gest_set;
2335 retval = i2c_smbus_write_i2c_block_data(ts->client,
2336 CY_REG_GEST_SET,
2337 sizeof(gesture_setup), &gesture_setup);
2338 mdelay(CY_DLY_DFLT);
2339 }
2340
2341 if (!(retval < CY_OK))
2342 ts->platform_data->power_state = CY_ACTIVE_STATE;
2343 else
2344 ts->platform_data->power_state = CY_IDLE_STATE;
2345
2346 cyttsp_debug("Retval=%d Power state is %s\n", \
2347 retval, \
2348 ts->platform_data->power_state == CY_ACTIVE_STATE ? \
2349 "ACTIVE" : "IDLE");
2350
2351 return retval;
2352}
2353
2354static int cyttsp_power_device(struct cyttsp *ts, bool on)
2355{
2356 int rc = 0, i;
2357 const struct cyttsp_regulator *reg_info =
2358 ts->platform_data->regulator_info;
2359 u8 num_reg = ts->platform_data->num_regulators;
2360
2361 if (!reg_info) {
2362 pr_err("regulator pdata not specified\n");
2363 return -EINVAL;
2364 }
2365
2366 if (on == false) /* Turn off the regulators */
2367 goto ts_reg_disable;
2368
2369 ts->vdd = kzalloc(num_reg * sizeof(struct regulator *), GFP_KERNEL);
2370 if (!ts->vdd) {
2371 pr_err("unable to allocate memory\n");
2372 return -ENOMEM;
2373 }
2374
2375 for (i = 0; i < num_reg; i++) {
2376 ts->vdd[i] = regulator_get(&ts->client->dev, reg_info[i].name);
2377 if (IS_ERR(ts->vdd[i])) {
2378 rc = PTR_ERR(ts->vdd[i]);
2379 pr_err("%s:regulator get failed rc=%d\n",
2380 __func__, rc);
2381 goto error_vdd;
2382 }
2383
2384 if (regulator_count_voltages(ts->vdd[i]) > 0) {
2385 rc = regulator_set_voltage(ts->vdd[i],
2386 reg_info[i].min_uV, reg_info[i].max_uV);
2387 if (rc) {
2388 pr_err("%s: regulator_set_voltage"
2389 "failed rc =%d\n", __func__, rc);
2390 regulator_put(ts->vdd[i]);
2391 goto error_vdd;
2392 }
2393 }
2394
2395 rc = regulator_set_optimum_mode(ts->vdd[i],
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05302396 reg_info[i].hpm_load_uA);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002397 if (rc < 0) {
2398 pr_err("%s: regulator_set_optimum_mode failed rc=%d\n",
2399 __func__, rc);
2400
2401 regulator_set_voltage(ts->vdd[i], 0,
2402 reg_info[i].max_uV);
2403 regulator_put(ts->vdd[i]);
2404 goto error_vdd;
2405 }
2406
2407 rc = regulator_enable(ts->vdd[i]);
2408 if (rc) {
2409 pr_err("%s: regulator_enable failed rc =%d\n",
2410 __func__, rc);
2411 regulator_set_optimum_mode(ts->vdd[i], 0);
2412 regulator_set_voltage(ts->vdd[i], 0,
2413 reg_info[i].max_uV);
2414 regulator_put(ts->vdd[i]);
2415 goto error_vdd;
2416 }
2417 }
2418
2419 return rc;
2420
2421ts_reg_disable:
2422 i = ts->platform_data->num_regulators;
2423error_vdd:
2424 while (--i >= 0) {
2425 if (regulator_count_voltages(ts->vdd[i]) > 0)
2426 regulator_set_voltage(ts->vdd[i], 0,
2427 reg_info[i].max_uV);
2428 regulator_set_optimum_mode(ts->vdd[i], 0);
2429 regulator_disable(ts->vdd[i]);
2430 regulator_put(ts->vdd[i]);
2431 }
2432 kfree(ts->vdd);
2433 return rc;
2434}
2435
2436/* cyttsp_initialize: Driver Initialization. This function takes
2437 * care of the following tasks:
2438 * 1. Create and register an input device with input layer
2439 * 2. Take CYTTSP device out of bootloader mode; go operational
2440 * 3. Start any timers/Work queues. */
2441static int cyttsp_initialize(struct i2c_client *client, struct cyttsp *ts)
2442{
2443 struct input_dev *input_device;
2444 int error = 0;
2445 int retval = CY_OK;
2446 u8 id;
2447
2448 /* Create the input device and register it. */
2449 input_device = input_allocate_device();
2450 if (!input_device) {
2451 error = -ENOMEM;
2452 cyttsp_xdebug1("err input allocate device\n");
2453 goto error_free_device;
2454 }
2455
2456 if (!client) {
2457 error = ~ENODEV;
2458 cyttsp_xdebug1("err client is Null\n");
2459 goto error_free_device;
2460 }
2461
2462 if (!ts) {
2463 error = ~ENODEV;
2464 cyttsp_xdebug1("err context is Null\n");
2465 goto error_free_device;
2466 }
2467
2468 ts->input = input_device;
2469 input_device->name = CY_I2C_NAME;
2470 input_device->phys = ts->phys;
2471 input_device->dev.parent = &client->dev;
2472
2473 /* init the touch structures */
2474 ts->num_prv_st_tch = CY_NTCH;
2475 for (id = 0; id < CY_NUM_TRK_ID; id++) {
2476 ts->act_trk[id] = CY_NTCH;
2477 ts->prv_mt_pos[id][CY_XPOS] = 0;
2478 ts->prv_mt_pos[id][CY_YPOS] = 0;
2479 }
2480
2481 for (id = 0; id < CY_NUM_MT_TCH_ID; id++)
2482 ts->prv_mt_tch[id] = CY_IGNR_TCH;
2483
2484 for (id = 0; id < CY_NUM_ST_TCH_ID; id++)
2485 ts->prv_st_tch[id] = CY_IGNR_TCH;
2486
2487 set_bit(EV_SYN, input_device->evbit);
2488 set_bit(EV_KEY, input_device->evbit);
2489 set_bit(EV_ABS, input_device->evbit);
2490 set_bit(BTN_TOUCH, input_device->keybit);
2491 set_bit(BTN_2, input_device->keybit);
2492 if (ts->platform_data->use_gestures)
2493 set_bit(BTN_3, input_device->keybit);
2494
2495 input_set_abs_params(input_device, ABS_X, ts->platform_data->disp_minx,
2496 ts->platform_data->disp_maxx, 0, 0);
2497 input_set_abs_params(input_device, ABS_Y, ts->platform_data->disp_miny,
2498 ts->platform_data->disp_maxy, 0, 0);
2499 input_set_abs_params(input_device,
2500 ABS_TOOL_WIDTH, 0, CY_LARGE_TOOL_WIDTH, 0 , 0);
2501 input_set_abs_params(input_device,
2502 ABS_PRESSURE, 0, CY_MAXZ, 0, 0);
2503 input_set_abs_params(input_device,
2504 ABS_HAT0X, 0, ts->platform_data->panel_maxx, 0, 0);
2505 input_set_abs_params(input_device,
2506 ABS_HAT0Y, 0, ts->platform_data->panel_maxy, 0, 0);
2507 if (ts->platform_data->use_gestures) {
2508 input_set_abs_params(input_device,
2509 ABS_HAT1X, 0, CY_MAXZ, 0, 0);
2510 input_set_abs_params(input_device,
2511 ABS_HAT1Y, 0, CY_MAXZ, 0, 0);
2512 }
2513 if (ts->platform_data->use_mt) {
2514 input_set_abs_params(input_device, ABS_MT_POSITION_X,
2515 ts->platform_data->disp_minx,
2516 ts->platform_data->disp_maxx, 0, 0);
2517 input_set_abs_params(input_device, ABS_MT_POSITION_Y,
2518 ts->platform_data->disp_miny,
2519 ts->platform_data->disp_maxy, 0, 0);
2520 input_set_abs_params(input_device,
2521 ABS_MT_TOUCH_MAJOR, 0, CY_MAXZ, 0, 0);
2522 input_set_abs_params(input_device,
2523 ABS_MT_WIDTH_MAJOR, 0, CY_LARGE_TOOL_WIDTH, 0, 0);
2524 if (ts->platform_data->use_trk_id) {
2525 input_set_abs_params(input_device,
2526 ABS_MT_TRACKING_ID, 0, CY_NUM_TRK_ID, 0, 0);
2527 }
2528 }
2529
2530 /* set dummy key to make driver work with virtual keys */
2531 input_set_capability(input_device, EV_KEY, KEY_PROG1);
2532
2533 cyttsp_info("%s: Register input device\n", CY_I2C_NAME);
2534 error = input_register_device(input_device);
2535 if (error) {
2536 cyttsp_alert("%s: Failed to register input device\n", \
2537 CY_I2C_NAME);
2538 retval = error;
2539 goto error_free_device;
2540 }
2541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542 if (gpio_is_valid(ts->platform_data->resout_gpio)) {
2543 /* configure touchscreen reset out gpio */
2544 retval = gpio_request(ts->platform_data->resout_gpio,
2545 "cyttsp_resout_gpio");
2546 if (retval) {
2547 pr_err("%s: unable to request reset gpio %d\n",
2548 __func__, ts->platform_data->resout_gpio);
2549 goto error_free_device;
2550 }
2551
2552 retval = gpio_direction_output(
2553 ts->platform_data->resout_gpio, 1);
2554 if (retval) {
2555 pr_err("%s: unable to set direction for gpio %d\n",
2556 __func__, ts->platform_data->resout_gpio);
2557 goto error_resout_gpio_dir;
2558 }
2559 }
2560
2561 if (gpio_is_valid(ts->platform_data->sleep_gpio)) {
2562 /* configure touchscreen reset out gpio */
2563 retval = gpio_request(ts->platform_data->sleep_gpio,
2564 "cy8c_sleep_gpio");
2565 if (retval) {
2566 pr_err("%s: unable to request sleep gpio %d\n",
2567 __func__, ts->platform_data->sleep_gpio);
2568 goto error_sleep_gpio_req;
2569 }
2570
2571 retval = gpio_direction_output(
2572 ts->platform_data->sleep_gpio, 0);
2573 if (retval) {
2574 pr_err("%s: unable to set direction for gpio %d\n",
2575 __func__, ts->platform_data->resout_gpio);
2576 goto error_sleep_gpio_dir;
2577 }
2578 }
2579
2580 if (gpio_is_valid(ts->platform_data->irq_gpio)) {
2581 /* configure touchscreen irq gpio */
2582 retval = gpio_request(ts->platform_data->irq_gpio,
2583 "ts_irq_gpio");
2584 if (retval) {
2585 pr_err("%s: unable to request gpio [%d]\n", __func__,
2586 ts->platform_data->irq_gpio);
2587 goto error_irq_gpio_req;
2588 }
2589 retval = gpio_direction_input(ts->platform_data->irq_gpio);
2590 if (retval) {
2591 pr_err("%s: unable to set_direction for gpio [%d]\n",
2592 __func__, ts->platform_data->irq_gpio);
2593 goto error_irq_gpio_dir;
2594 }
2595 }
2596
2597 if (ts->platform_data->regulator_info) {
2598 retval = cyttsp_power_device(ts, true);
2599 if (retval) {
2600 pr_err("%s: Unable to power device %d\n",
2601 __func__, retval);
2602 goto error_irq_gpio_dir;
2603 }
2604 }
2605
2606 /* Power on the chip and make sure that I/Os are set as specified
2607 * in the platform */
2608 if (ts->platform_data->init) {
2609 retval = ts->platform_data->init(client);
2610 if (retval) {
2611 pr_err("%s: ts init failed\n", __func__);
2612 goto error_power_device;
2613 }
2614 }
2615
2616 msleep(100);
2617
2618 /* check this device active by reading first byte/register */
2619 retval = i2c_smbus_read_byte_data(ts->client, 0x01);
2620 if (retval < 0) {
2621 pr_err("%s: i2c sanity check failed\n", __func__);
2622 goto error_power_device;
2623 }
2624
2625 retval = cyttsp_power_on(ts);
2626 if (retval < 0) {
2627 pr_err("%s: cyttsp_power_on failed\n", __func__);
2628 goto error_power_device;
2629 }
2630
2631 /* Timer or Interrupt setup */
2632 if (ts->client->irq == 0) {
2633 cyttsp_info("Setting up timer\n");
2634 setup_timer(&ts->timer, cyttsp_timer, (unsigned long) ts);
2635 mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
2636 } else {
2637 cyttsp_info("Setting up interrupt\n");
Mohan Pallaka07a08072011-10-21 13:04:21 +05302638 error = request_threaded_irq(client->irq, NULL, cyttsp_irq,
2639 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002640 client->dev.driver->name, ts);
2641 if (error) {
2642 cyttsp_alert("error: could not request irq\n");
2643 retval = error;
2644 goto error_power_device;
2645 }
2646 }
2647
2648 irq_cnt = 0;
2649 irq_cnt_total = 0;
2650 irq_err_cnt = 0;
2651
2652 atomic_set(&ts->irq_enabled, 1);
2653 retval = device_create_file(&ts->client->dev, &dev_attr_irq_enable);
2654 if (retval < CY_OK) {
2655 cyttsp_alert("File device creation failed: %d\n", retval);
2656 retval = -ENODEV;
2657 goto error_free_irq;
2658 }
2659
2660 retval = device_create_file(&client->dev, &dev_attr_cyttsp_fw_ver);
2661 if (retval) {
2662 cyttsp_alert("sysfs entry for firmware version failed\n");
2663 goto error_rm_dev_file_irq_en;
2664 }
2665
2666 ts->cyttsp_fwloader_mode = 0;
2667 retval = device_create_file(&client->dev, &dev_attr_cyttsp_update_fw);
2668 if (retval) {
2669 cyttsp_alert("sysfs entry for firmware update failed\n");
2670 goto error_rm_dev_file_fw_ver;
2671 }
2672
2673 retval = device_create_file(&client->dev,
2674 &dev_attr_cyttsp_force_update_fw);
2675 if (retval) {
2676 cyttsp_alert("sysfs entry for force firmware update failed\n");
2677 goto error_rm_dev_file_update_fw;
2678 }
2679 if (ts->platform_data->correct_fw_ver) {
2680 if (g_bl_data.appid_lo != ts->platform_data->correct_fw_ver)
Mohan Pallaka1cef4a02011-08-01 11:48:42 +05302681 pr_warn("%s: Invalid firmware version detected;"
2682 " Please update.\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002683 }
2684
2685 retval = device_create_file(&client->dev,
2686 &dev_attr_cyttsp_fw_name);
2687 if (retval) {
2688 cyttsp_alert("sysfs entry for file name selection failed\n");
2689 goto error_rm_dev_file_fupdate_fw;
2690 }
2691
2692 cyttsp_info("%s: Successful registration\n", CY_I2C_NAME);
2693
2694 goto success;
2695
2696error_rm_dev_file_fupdate_fw:
2697 device_remove_file(&client->dev, &dev_attr_cyttsp_force_update_fw);
2698error_rm_dev_file_update_fw:
2699 device_remove_file(&client->dev, &dev_attr_cyttsp_update_fw);
2700error_rm_dev_file_fw_ver:
2701 device_remove_file(&client->dev, &dev_attr_cyttsp_fw_ver);
2702error_rm_dev_file_irq_en:
2703 device_remove_file(&client->dev, &dev_attr_irq_enable);
2704error_free_irq:
2705 if (ts->client->irq)
2706 free_irq(client->irq, ts);
2707error_power_device:
2708 if (ts->platform_data->regulator_info)
2709 cyttsp_power_device(ts, false);
2710error_irq_gpio_dir:
2711 if (gpio_is_valid(ts->platform_data->irq_gpio))
2712 gpio_free(ts->platform_data->irq_gpio);
2713error_irq_gpio_req:
2714 if (gpio_is_valid(ts->platform_data->sleep_gpio))
2715 gpio_direction_output(ts->platform_data->sleep_gpio, 1);
2716error_sleep_gpio_dir:
2717 if (gpio_is_valid(ts->platform_data->sleep_gpio))
2718 gpio_free(ts->platform_data->sleep_gpio);
2719error_sleep_gpio_req:
2720 if (gpio_is_valid(ts->platform_data->resout_gpio))
2721 gpio_direction_output(ts->platform_data->resout_gpio, 0);
2722error_resout_gpio_dir:
2723 if (gpio_is_valid(ts->platform_data->resout_gpio))
2724 gpio_free(ts->platform_data->resout_gpio);
2725error_free_device:
2726 if (input_device)
2727 input_free_device(input_device);
2728
2729success:
2730 return retval;
2731}
2732
2733/* I2C driver probe function */
2734static int __devinit cyttsp_probe(struct i2c_client *client,
2735 const struct i2c_device_id *id)
2736{
2737 struct cyttsp *ts;
2738 int error;
2739 int retval = CY_OK;
2740
2741 cyttsp_info("Start Probe 1.2\n");
2742
2743 /* allocate and clear memory */
2744 ts = kzalloc(sizeof(struct cyttsp), GFP_KERNEL);
2745 if (ts == NULL) {
2746 cyttsp_xdebug1("err kzalloc for cyttsp\n");
2747 retval = -ENOMEM;
2748 }
2749
2750 /* Enable runtime PM ops, start in ACTIVE mode */
2751 error = pm_runtime_set_active(&client->dev);
2752 if (error < 0)
2753 dev_dbg(&client->dev, "unable to set runtime pm state\n");
2754 pm_runtime_enable(&client->dev);
2755
2756 if (!(retval < CY_OK)) {
2757 /* register driver_data */
2758 ts->client = client;
2759 ts->platform_data = client->dev.platform_data;
2760
2761 if (ts->platform_data->fw_fname)
Mohan Pallaka9c050f12011-09-29 18:17:35 +05302762 strlcpy(ts->fw_fname, ts->platform_data->fw_fname,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002763 FW_FNAME_LEN - 1);
2764 else
Mohan Pallaka9c050f12011-09-29 18:17:35 +05302765 strlcpy(ts->fw_fname, "cyttsp.hex", FW_FNAME_LEN - 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766
Amy Malocheedd5fd72011-06-22 18:50:21 -07002767 if (ts->platform_data->gen == CY_GEN3) {
2768 ts->fw_start_addr = 0x0b00;
2769 } else if (ts->platform_data->gen == CY_GEN2) {
2770 ts->fw_start_addr = 0x0880;
2771 } else {
2772 pr_err("%s: unsupported cypress chip\n", __func__);
2773 kfree(ts);
2774 return -EINVAL;
2775 }
2776
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002777 i2c_set_clientdata(client, ts);
2778
2779 error = cyttsp_initialize(client, ts);
2780 if (error) {
2781 cyttsp_xdebug1("err cyttsp_initialize\n");
2782 if (ts != NULL) {
2783 /* deallocate memory */
2784 kfree(ts);
2785 }
2786/*
2787 i2c_del_driver(&cyttsp_driver);
2788*/
Mohan Pallaka04b7f792011-09-29 18:17:35 +05302789 return -ENODEV;
2790 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002791 }
2792
2793#ifdef CONFIG_HAS_EARLYSUSPEND
2794 if (!(retval < CY_OK)) {
2795 ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
2796 ts->early_suspend.suspend = cyttsp_early_suspend;
2797 ts->early_suspend.resume = cyttsp_late_resume;
2798 register_early_suspend(&ts->early_suspend);
2799 }
2800#endif /* CONFIG_HAS_EARLYSUSPEND */
2801 device_init_wakeup(&client->dev, ts->platform_data->wakeup);
2802 mutex_init(&ts->mutex);
2803
2804 cyttsp_info("Start Probe %s\n", \
2805 (retval < CY_OK) ? "FAIL" : "PASS");
2806
2807 return retval;
2808}
2809
Anirudh Ghayal909dcfd2011-09-08 13:35:53 +05302810#ifdef CONFIG_PM
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05302811static int cyttsp_regulator_lpm(struct cyttsp *ts, bool on)
2812{
2813 int rc = 0, i;
2814 const struct cyttsp_regulator *reg_info =
2815 ts->platform_data->regulator_info;
2816 u8 num_reg = ts->platform_data->num_regulators;
2817
2818 if (on == false)
2819 goto regulator_hpm;
2820
2821 for (i = 0; i < num_reg; i++) {
2822 rc = regulator_set_optimum_mode(ts->vdd[i],
2823 reg_info[i].lpm_load_uA);
2824 if (rc < 0) {
2825 pr_err("%s: regulator_set_optimum failed rc = %d\n",
2826 __func__, rc);
2827 goto fail_regulator_lpm;
2828 }
2829
2830 }
2831
2832 return 0;
2833
2834regulator_hpm:
2835 for (i = 0; i < num_reg; i++) {
2836 rc = regulator_set_optimum_mode(ts->vdd[i],
2837 reg_info[i].hpm_load_uA);
2838 if (rc < 0) {
2839 pr_err("%s: regulator_set_optimum failed"
2840 "rc = %d\n", __func__, rc);
2841 goto fail_regulator_hpm;
2842 }
2843 }
2844
2845 return 0;
2846
2847fail_regulator_lpm:
2848 while (i--)
2849 regulator_set_optimum_mode(ts->vdd[i],
2850 reg_info[i].hpm_load_uA);
2851
2852 return rc;
2853
2854fail_regulator_hpm:
2855 while (i--)
2856 regulator_set_optimum_mode(ts->vdd[i],
2857 reg_info[i].lpm_load_uA);
2858
2859 return rc;
2860}
2861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002862/* Function to manage power-on resume */
2863static int cyttsp_resume(struct device *dev)
2864{
2865 struct cyttsp *ts = dev_get_drvdata(dev);
2866 int retval = CY_OK;
2867
2868 cyttsp_debug("Wake Up\n");
2869
2870 if (ts->is_suspended == false) {
2871 pr_err("%s: in wakeup state\n", __func__);
2872 return 0;
2873 }
2874
2875 if (device_may_wakeup(dev)) {
2876 if (ts->client->irq)
2877 disable_irq_wake(ts->client->irq);
2878 return 0;
2879 }
2880
2881 /* re-enable the interrupt prior to wake device */
2882 if (ts->client->irq)
2883 enable_irq(ts->client->irq);
2884
2885 if (ts->platform_data->use_sleep &&
2886 (ts->platform_data->power_state != CY_ACTIVE_STATE)) {
2887 if (ts->platform_data->resume)
2888 retval = ts->platform_data->resume(ts->client);
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05302889 else
2890 retval = cyttsp_regulator_lpm(ts, false);
Amy Maloche13dcf552011-08-22 15:38:44 -07002891 /* take TTSP device out of bootloader mode;
2892 * switch back to TrueTouch operational mode */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002893 if (!(retval < CY_OK)) {
Amy Maloche13dcf552011-08-22 15:38:44 -07002894 int tries = 0;
2895 do {
2896 msleep(100);
2897 retval = i2c_smbus_write_i2c_block_data(
2898 ts->client, CY_REG_BASE,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002899 sizeof(bl_cmd), bl_cmd);
Amy Maloche13dcf552011-08-22 15:38:44 -07002900 if (retval == CY_OK)
2901 break;
2902 } while (tries++ < 2);
2903 /* wait for TTSP Device to complete
2904 * switch to Operational mode */
2905 tries = 0;
2906 do {
2907 msleep(100);
2908 cyttsp_putbl(ts, 16, false, false, false);
2909 } while (GET_BOOTLOADERMODE(g_bl_data.bl_status) &&
2910 tries++ < 2);
2911 cyttsp_putbl(ts, 16, true, false, false);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002912 }
2913 }
2914
2915 if (!(retval < CY_OK) &&
2916 (GET_HSTMODE(g_bl_data.bl_file) == CY_OK)) {
2917 ts->platform_data->power_state = CY_ACTIVE_STATE;
2918
2919 /* re-enable the timer after resuming */
2920 if (ts->client->irq == 0)
2921 mod_timer(&ts->timer, jiffies + TOUCHSCREEN_TIMEOUT);
2922 } else
2923 retval = -ENODEV;
2924
2925 ts->is_suspended = false;
2926 cyttsp_debug("Wake Up %s\n", \
2927 (retval < CY_OK) ? "FAIL" : "PASS");
2928
2929 return retval;
2930}
2931
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002932/* Function to manage low power suspend */
2933static int cyttsp_suspend(struct device *dev)
2934{
2935 struct cyttsp *ts = dev_get_drvdata(dev);
2936 u8 sleep_mode = CY_OK;
2937 int retval = CY_OK;
2938
2939 cyttsp_debug("Enter Sleep\n");
2940
2941 if (ts->is_suspended == true) {
2942 pr_err("%s: in sleep state\n", __func__);
2943 return 0;
2944 }
2945
2946 mutex_lock(&ts->mutex);
2947 if (ts->cyttsp_fwloader_mode) {
2948 pr_err("%s:firmware upgrade mode:"
2949 "suspend not allowed\n", __func__);
2950 mutex_unlock(&ts->mutex);
2951 return -EBUSY;
2952 }
2953 mutex_unlock(&ts->mutex);
2954
2955 if (device_may_wakeup(dev)) {
2956 if (ts->client->irq)
2957 enable_irq_wake(ts->client->irq);
2958 return 0;
2959 }
2960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961 if (ts->client->irq == 0)
2962 del_timer(&ts->timer);
2963 else
Mohan Pallaka07a08072011-10-21 13:04:21 +05302964 disable_irq(ts->client->irq);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002965
2966 if (!(retval < CY_OK)) {
2967 if (ts->platform_data->use_sleep &&
2968 (ts->platform_data->power_state == CY_ACTIVE_STATE)) {
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05302969 if (ts->platform_data->suspend) {
2970 retval =
2971 ts->platform_data->suspend(ts->client);
2972 } else {
2973 retval = cyttsp_regulator_lpm(ts, true);
2974 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002975 if (ts->platform_data->use_sleep & CY_USE_DEEP_SLEEP_SEL)
2976 sleep_mode = CY_DEEP_SLEEP_MODE;
2977 else
2978 sleep_mode = CY_LOW_PWR_MODE;
2979
Anirudh Ghayalf9929b12011-09-07 15:57:36 +05302980 if (!(retval < CY_OK)) {
2981 retval =
2982 i2c_smbus_write_i2c_block_data(ts->client,
2983 CY_REG_BASE,
2984 sizeof(sleep_mode), &sleep_mode);
2985 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002986 }
2987 }
2988
2989 if (!(retval < CY_OK)) {
2990 if (sleep_mode == CY_DEEP_SLEEP_MODE)
2991 ts->platform_data->power_state = CY_SLEEP_STATE;
2992 else if (sleep_mode == CY_LOW_PWR_MODE)
2993 ts->platform_data->power_state = CY_LOW_PWR_STATE;
2994 }
2995
2996 ts->is_suspended = true;
2997 cyttsp_debug("Sleep Power state is %s\n", \
2998 (ts->platform_data->power_state == CY_ACTIVE_STATE) ? \
2999 "ACTIVE" : \
3000 ((ts->platform_data->power_state == CY_SLEEP_STATE) ? \
3001 "SLEEP" : "LOW POWER"));
3002
3003 return retval;
3004}
Anirudh Ghayal84e51192011-09-03 08:05:25 +05303005#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006
3007/* registered in driver struct */
3008static int __devexit cyttsp_remove(struct i2c_client *client)
3009{
3010 /* clientdata registered on probe */
3011 struct cyttsp *ts = i2c_get_clientdata(client);
3012 int err;
3013
3014 cyttsp_alert("Unregister\n");
3015
3016 pm_runtime_set_suspended(&client->dev);
3017 pm_runtime_disable(&client->dev);
3018
3019 device_init_wakeup(&client->dev, 0);
3020 device_remove_file(&ts->client->dev, &dev_attr_irq_enable);
3021 device_remove_file(&client->dev, &dev_attr_cyttsp_fw_ver);
3022 device_remove_file(&client->dev, &dev_attr_cyttsp_update_fw);
3023 device_remove_file(&client->dev, &dev_attr_cyttsp_force_update_fw);
3024 device_remove_file(&client->dev, &dev_attr_cyttsp_fw_name);
3025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003026 /* free up timer or irq */
3027 if (ts->client->irq == 0) {
3028 err = del_timer(&ts->timer);
3029 if (err < CY_OK)
3030 cyttsp_alert("error: failed to delete timer\n");
3031 } else
3032 free_irq(client->irq, ts);
3033
3034 if (ts->platform_data->regulator_info)
3035 cyttsp_power_device(ts, false);
3036
3037#ifdef CONFIG_HAS_EARLYSUSPEND
3038 unregister_early_suspend(&ts->early_suspend);
3039#endif /* CONFIG_HAS_EARLYSUSPEND */
3040
3041 mutex_destroy(&ts->mutex);
3042
3043 if (gpio_is_valid(ts->platform_data->sleep_gpio)) {
3044 gpio_direction_output(ts->platform_data->sleep_gpio, 1);
3045 gpio_free(ts->platform_data->sleep_gpio);
3046 }
3047
3048 if (gpio_is_valid(ts->platform_data->resout_gpio)) {
3049 gpio_direction_output(ts->platform_data->resout_gpio, 0);
3050 gpio_free(ts->platform_data->resout_gpio);
3051 }
3052
3053 if (gpio_is_valid(ts->platform_data->irq_gpio))
3054 gpio_free(ts->platform_data->irq_gpio);
3055
3056 /* housekeeping */
3057 if (ts != NULL)
3058 kfree(ts);
3059
3060 cyttsp_alert("Leaving\n");
3061
3062 return 0;
3063}
3064
3065#ifdef CONFIG_HAS_EARLYSUSPEND
3066static void cyttsp_early_suspend(struct early_suspend *handler)
3067{
3068 struct cyttsp *ts;
3069
3070 ts = container_of(handler, struct cyttsp, early_suspend);
3071 cyttsp_suspend(&ts->client->dev);
3072}
3073
3074static void cyttsp_late_resume(struct early_suspend *handler)
3075{
3076 struct cyttsp *ts;
3077
3078 ts = container_of(handler, struct cyttsp, early_suspend);
3079 cyttsp_resume(&ts->client->dev);
3080}
3081#endif /* CONFIG_HAS_EARLYSUSPEND */
3082
3083static int cyttsp_init(void)
3084{
3085 int ret;
3086
3087 cyttsp_info("Cypress TrueTouch(R) Standard Product\n");
3088 cyttsp_info("I2C Touchscreen Driver (Built %s @ %s)\n", \
3089 __DATE__, __TIME__);
3090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003091 ret = i2c_add_driver(&cyttsp_driver);
3092
3093 return ret;
3094}
3095
3096static void cyttsp_exit(void)
3097{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003098 return i2c_del_driver(&cyttsp_driver);
3099}
3100
3101module_init(cyttsp_init);
3102module_exit(cyttsp_exit);
3103MODULE_FIRMWARE("cyttsp.fw");
3104